Search code examples
wordpresstimber

How can I modify post titles before Timber::render?


I'm trying to avoid widows/orphans in my post titles that appear throughout my site by modifying the {{ post.title }} output in single.php before it is rendered in my single.twig template.

I'd like to use something like this PHP to insert a nonbreaking space:

$title = preg_replace( '|([^\s])\s+([^\s]+)\s*$|', '$1 $2', $title);

What's the proper way to get a post title (or all posts titles), and send them back to the Timber context before I use Timber::render()?


Solution

  • The title() method for a Timber Post object is mostly just a pass-through for Wordpress' own the_title() function.

    Here is the relevant code for the title() method:

    public function title() {
        if ( $rd = $this->get_revised_data_from_method('title') ) {
            return $rd;
        }
        return apply_filters('the_title', $this->post_title, $this->ID);
    }
    

    Ignoring the if statement (it's there to help with updating the preview for a post), the method simply gets the post's title from the database and applies the Wordpress the_title filter to it.

    That means you can modify your title output by modifying the the_title filter. This previous StackOverflow answer provides a good summary of how to use it:

    https://wordpress.stackexchange.com/questions/305706/how-to-change-the-blog-title-with-add-filter-details-below

    I have not tested the code below, but I think something like this should work given your requirements:

    add_filter('the_title', 'modify_all_titles', 10, 2);
    
    function modify_all_titles($title, $id) {
      return preg_replace( '|([^\s])\s+([^\s]+)\s*$|', '$1 $2', $title);
    }
    

    It's important to note that this will change ALL titles for ALL posts in every place that the_title() or {{ post.title }} is used on the site. If you want to limit the change to certain situations, you have two options:

    1. Use conditionals inside your filter function to modify the title (or not) differently in different circumstances. For example, you could apply your modifications only on a specific custom post type while returning the default title in all other instances.

    2. Define a new context value for your modified title value and use that instead of post.title in your twig template.

    For example, in your PHP template file you could add the following after $context and $post have been defined but before Timber::render():

    $context['custom_title'] = preg_replace( '|([^\s])\s+([^\s]+)\s*$|', '$1 $2', $title);
    

    Then in your Twig file, you can use {{ custom_title }} instead of {{ post.title }}.

    Finally, if you're into object oriented PHP, you could extend the Timber/Post class to define your own title() method. The details for that approach are outside the scope of this question, but may be worth looking into if you want to harness the full power of Timber.