Filtering ‘the_title’ with option to return subhead?

Problem:

The WordPress iPhone app (and other WordPress-related smartphone apps) do not allow for much other than the Title and Body fields (i.e. no access to custom fields).

Goal:

My current project requires that we give our mobile bloggers the option to include a subhead with their mobile (and desktop) posts.

Read More

Solution:

I’d like to use an optional delimiter in the title. Example:

Main headline | Secondary headline

Screen shot:

enter image description here

Where the | is the delimiter that separates main title:

Main headline

… from the subheadline:

Secondary headline

Code requirements:

All built-in, and plugin, code that use “title”-getting WP methods should always return the half before the delimiter (using example from above):

Main headline

In other words, by default, no title-getting functions will ever return:

| Secondary headline

My code so far:

The code immediately below is a simple starting point.

As you can see, I’m filtering the_title and removing:

| Secondary headline

/**
 * Head/deck handling.
 *
 * Unaltered title (no quotes): "Main headline | Secondary headline"
 *
 * @see http://stackoverflow.com/a/16279114/922323
 * @see http://core.trac.wordpress.org/browser/tags/3.5.1/wp-includes/post-template.php#L118
 * @see https://wordpress.stackexchange.com/questions/45589/
 */

function foo_the_title($title, $id) {

    return trim(current(explode('|', $title))); // Returns: "Main headline".

}

add_filter('the_title', 'foo_the_title', 10, 2);

By doing the above, I avoid having to worry about any other functions spitting out the delimiter (and the stuff following it), right? I’m assuming all “title”-getting functions/methods will be affected by the filter the_title? Maybe I’m missing a corner case here? UPDATE: I found a corner case: wp_title() … Makes me wonder what else is out there?

Question(s):

Heres where I’m stuck.

How can I write a custom function (or filter/other) that will return the second half of the title?

I was playing with this:

function foo_the_subheadline() {

    return apply_filters('the_title', '  My Custom Title (tm)  | after the stuff    ');

}

Obviously, that’s not doing anything useful (I need the ability to manipulate the code/$title variable in foo_the_title()).

For example, what I’d really like to do is something like this (pseudo code follows, do not use in real world):

function foo_the_title($title, $id, $part = 'current') {

    return trim($part(explode('|', $title)));

}

add_filter('the_title', 'foo_the_title', 10, 3);

function foo_get_me_the_subheadline() {

    foo_the_title(pass the title here, pass the id?, 'end'); // Using variable function: http://php.net/manual/en/functions.variable-functions.php

}

Conclusion:

Well, honestly, I’m hoping ya’ll can help me find a conclusion. 🙂


UPDATE (2013/05/14):

See my answer below.

Thoughts:

  • Could the fundamental logic be improved?
  • Are there any alternative approaches that could work better?

Related posts

2 comments

  1. I am not sure I understand your issue right, but my guess is your conundrum – how to get to the title that is unchanged by your filter, if you are filtering it everywhere?

    You can use get_post_field() function to get a raw copy of it from the post object.

    However instead of messing with output (and making your saved data dependent on filters being present) I would recommend to work on splitting a title when saving post – assign first part to title as usual and tuck away second part into custom field.

  2. Based on this awesome tip by @Rarst:

    You can use get_post_field() function to get a raw copy of it from the post object.

    Here’s a (possible) solution I’ve just now slapped together:

    /**
     * Head/deck handling.
     *
     * Unaltered example title (no quotes): "First half | Second half"
     *
     * @see http://stackoverflow.com/a/16279114/922323
     * @see http://core.trac.wordpress.org/browser/tags/3.5.1/wp-includes/post-template.php#L118
     * @see https://wordpress.stackexchange.com/questions/45589/
     * @see https://wordpress.stackexchange.com/questions/99039/
     */
    
    /**
     * Private helper function to return a title or deck from the title field.
     *
     * @param $title { string } The `post_title`.
     * @param $part { string } One of "current" or "end". Default: 'current'.
     * @param $delim { string } Delimiter that separates title from deck.
     * @return { string } Title before or after delimiter.
     */
    
    function _foo_the_title_and_deck($title, $part = 'current', $delim = '|') {
    
        # ((if there's no delim) ? (if the deck is requested return an empty string, otherwise return the unaltered title) : return the filtered title or deck)
        return (( ! strpos($title, $delim)) ? (($part == 'end') ? '' : $title) : trim($part(explode($delim, $title))));
    
    }
    
    /**
     * Filter the `post_title`.
     *
     * @param $title { string } The post title.
     * @return { string } The filterd post title.
     */
    
    function foo_the_title($title) {
    
        return _foo_the_title_and_deck($title);
    
    }
    
    # Filter `the_title`:
    add_filter('the_title', 'foo_the_title', 10, 1); // Is "10" an optimal priority in this case?
    
    # Filter `single_post_title`:
    add_filter('single_post_title', 'foo_the_title', 10, 1); // IBID?
    
    /**
     * Filter the "deck" from the `post_title`.
     *
     * @param $post_id { integer } Optional post ID. Default: FALSE.
     * @return { string } The deck from the post's title.
     */
    
    function foo_the_deck($post_id = FALSE) {
    
        # Use or get the $post_id:
        $post_id = ($post_id) ? $post_id : get_the_ID();
    
        return _foo_the_title_and_deck(get_post_field('post_title', $post_id), 'end');
    
    }
    
    /**
     * Check for the existence of a deck.
     *
     * @param $post_id { integer } Optional post ID. Default: FALSE.
     * @return { boolean } TRUE if deck exists, otherwise FALSE.
     */
    
    function foo_has_deck($post_id = FALSE) {
    
        if (foo_the_deck($post_id)) return TRUE;
    
    }
    

    Usage on template level:

    <h1><?=the_title()?></h1>
    
    <?php if (foo_has_deck()): ?>
    
        <h2 class="sh4"><?=foo_the_deck()?></h2>
    
    <?php endif; ?>
    

    It appears to work! Though, I haven’t had time yet to do thorough testing.

    Ideas for improvement:

    1. Convert to simple OOP “must use” plugin. See 2013/05/15 update below.
    2. Incorporate add_filters that account for other functions not affected by the_title, like wp_title(). Thanks to @DanStefancu’s comment, I’ve covered this corner case by filtering single_post_title.
    3. Other?

    2013/05/15 UPDATE

    I’ve created a plugin for this code and put it here (I’m open to feedback). It’s my first WP plugin, ever, (I know it could be considerably improved) so please be kind. 🙂

Comments are closed.