Replacing a filter in a Twenty Twelve Child Theme

I was asked a few weeks ago:

I’m trying to change the order of the <title> tag so it reads “site title | page title” instead of the standard “page title | site title”. I know it’s bad SEO, but the client is adamant this is what he wants!

Now, Twenty Twelve sets up the title tag on your page using a filter function in it’s functions.php file. The header.php simple contains this code:

[php]
&lt;title&gt;&lt;?php wp_title( ‘|’, true, ‘right’ ); ?&gt;&lt;/title&gt;
[/php]

The function in functions.php looks like this:

[php]
function twentytwelve_wp_title( $title, $sep ) {
global $paged, $page;

if ( is_feed() )
return $title;

// Add the site name.
$title .= get_bloginfo( ‘name’ );

// Add the site description for the home/front page.
$site_description = get_bloginfo( ‘description’, ‘display’ );
if ( $site_description &amp;&amp; ( is_home() || is_front_page() ) )
$title = "$title $sep $site_description";

// Add a page number if necessary.
if ( $paged &gt;= 2 || $page &gt;= 2 )
$title = "$title $sep " . sprintf( __( ‘Page %s’, ‘twentytwelve’ ), max( $paged, $page ) );

return $title;
}
add_filter( ‘wp_title’, ‘twentytwelve_wp_title’, 10, 2 );
[/php]

Twenty Twelve adds it’s function to the 'wp_title' filter.

One possibility: Add a second filter

One solution might be to add your own filter to the chain in your child theme; set it on a lower priority so that it runs after Twenty Twelve’s function; and change the title tag that way. In this particular case — swapping the order of the two parts — that might be quite hard. Theoretically, you could split the title on the separator character ($sep) and swap the two halves. But that assumes the separator character will never appear in either the site name or a page/post title. Hmmm… quite risky.

A better solution: Replace the filter

A better solution is to replace the filter in your Twenty Twelve child theme with your own. You need to hook your own function to the filter in your child theme’s functions.php file. Remember you can’t use the same function name as Twenty Twelve. You could do it like this:

[php]
add_filter( ‘wp_title’, ‘z1_twentytwelve_wp_title’, 10, 2 );
function z1_twentytwelve_wp_title( $title, $sep ) {
global $paged, $page;

if ( is_feed() )
return $title;

//strip out separator already added by wp_title()
$title = str_replace( $sep, ”, $title);

// Add the site description for the home/front page.
$site_description = get_bloginfo( ‘description’, ‘display’ );
if ( $site_description &amp;&amp; ( is_home() || is_front_page() ) )
$title = "$site_description";

// Add a page number if necessary.
if ( $paged &gt;= 2 || $page &gt;= 2 )
$title = "$title $sep " . sprintf( __( ‘Page %s’, ‘twentytwelve’ ), max( $paged, $page ) );

// Add the site name before the rest.
$title = get_bloginfo( ‘name’ ) . ‘ ‘ . $sep . ‘ ‘ . $title;

return $title;
}
[/php]

Note: I’ve given my function a unique name by prefixing it with ‘z1_’, and I’ve also kept the same priority. I’ll be removing Twenty Twelve’s function so it doesn’t matter.

Removing the original hooked function

In order to remove a filter we simply call remove_filter() with the same parameters as the add_filter call.

[php]
remove_filter( ‘wp_title’, ‘twentytwelve_wp_title’, 10, 2 );
[/php]

However, your child theme’s functions.php runs before Twenty Twelve’s does. That means that when your call to remove_filter() runs, Twenty Twelve hasn’t yet called add_filter(). It won’t work because there’s nothing to remove!

Instead you need to hook a new function to the after_setup_theme action and call remove_filter() from there.

[php]
add_action( ‘after_setup_theme’, ‘z1_turnoff_twentytwelve_title’ );
function z1_turnoff_twentytwelve_title() {
remove_filter( ‘wp_title’, ‘twentytwelve_wp_title’, 10, 2 );
}
[/php]

Huh? What’s that doing?

Here I’ve created a new function z1_turnoff_twentytwelve_title() and hooked that to the after_setup_theme action, where I can now call remove_filter().
In other words the sequence of events for replacing a filter in a Twenty Twelve child theme goes like this:

  1. WordPress does all it’s start up stuff and calls your child theme’s functions.php.
  2. Your child theme adds a filter for wp_title, and hooks a function to the after_setup_theme action.
  3. WordPress calls Twenty Twelve’s functions.php which also adds a filter for ‘wp_title’.
  4. WordPress runs do_action('after_setup_theme') (because the theme is now set up).
  5. Your function hooked to that action gets called…
  6. … and it removes the Twenty Twelve filter!
  7. Leaving your filter in place.

See http://pastebin.com/hFWgc1p4 for a complete example.

The take away

It can be tricky understanding that code outside any function definitions in your files (functions.php or plugin files) is executed by PHP as soon as the file is loaded and parsed. Which is completely different from when WordPress calls your functions in those files. Often that immediate execution by PHP is far too early unless it is simply hooking on to filters and actions. That’s one of the reasons the filters and actions system works the way it does, so that WordPress will call your code exactly when you want it to, rather than when PHP loads it.

I hope that helps some of you out there. If you have any questions about this, please ask below. If you have other WordPress questions you want answering, let me know in the comments below.