Yesterday, I used a fairly crude mechanism for overriding a single line in a template. I added my own version of the file to my child theme – thereby clobbering the entire template. Take a look – there are monkeys. Today, I’ll do the same work with a little more precision. It’s time for the scalpel.
Let’s remind ourselves of the line I want to override:
<header class="entry-header">
<?php the_title( '<h2 class="entry-title">', '</h2>' ); ?>
<?php twentyseventeen_edit_link( get_the_ID() ); ?>
</header>
<!-- .entry-header -->
The first clue that we might be able to do some pinpoint works lies with that function call to the_title()
. If you see a function call – especially one which seems to invoke the core – there’s a good chance that a filter will be involved. There are two complementary avenues to take from that point. The first is to look at source (which is always a good idea anyway – reading source code is a great way to learn about a system, and to pick up new tricks too). You should also refer to the functions and filters documentation.
Here’s how I discover the function in source code:
$ grep -r 'function the_title(' site/wp/*
site/wp/wp-includes/post-template.php:function the_title( $before = '', $after = '', $echo = true ) {
Looking at post-template.php
I find this:
function the_title( $before = '', $after = '', $echo = true ) {
$title = get_the_title();
//...
which leads me to
function get_the_title( $post = 0 ) {
// (much snipped)
return apply_filters( 'the_title', $title, $id );
}
Bingo! there is a filter! That’s probably enough to get me where I need to go, but it’s worth taking a look at the filter documentation for ‘the_title’:
the_title is a filter applied to the post title retrieved from the database, prior to printing on the screen. In some cases (such as when the_title [function] is used), the title can be suppressed by returning a false value (e.g. NULL, FALSE or the empty string) from the filter function.
A quick aside for the uninitiated. There are a couple of related features which help to make WordPress so flexible and extensible: actions and filters. Actions give theme and plugin writers the chance to perform custom tasks when key events occur. Similarly, filters allow us to alter data.
In this case, the get_the_title()
function would like to return the variable $title
. But, very kindly, it calls apply_filters()
, which will invoke any filter functions attached to the provided hook label (the_title
). So get_the_title()
sends $title
off to be amended by any number of filtering functions before returning the result of those calls.
So how do I associate a method or function with the_title
filter hook? I just need to call add_filter()
. This accepts the filter hook string (the_title
in this case), a reference to something callable (most often a function name), the number of arguments the callback should accept, and, optionally, the priority at which the callback should be run (lower numbered callbacks attached to a filter hook get called first).
Let’s try it out. First off I delete my overriding template from yesterday’s example. Then I open up my child theme’s functions.php
file (wp-content/themes/twentyseventeen-gi-child/functions.php
. Here is my proof of concept:
add_filter(
"the_title",
function($title, $id=null) {
return "the monkey say: {$title}";
},
10,
2
);
I’m using an anonymous function here. I have rarely seen these used in WordPress-related code – perhaps because there is a strong preference for backward compatibility in the WordPress community. Anyway, I think you can guess what this example will do. Let’s take a look anyway.
Well, that proves I can alter post titles (and pages are just a type of post in WordPress) but my work isn’t done. Yes, yes, I should can it with the monkeys and suppress the titles altogether. But that’s not all. In addition to a surfeit of monkeys, my anonymous function is also over-eager. It will apply itself to all posts in the system, stifling or decorating the titles of blog articles for example:
Time to rein it in:
class GiTheme {
private static $inst = null;
private function __construct() {
add_filter("the_title", array($this, "suppressFrontPageTitle"), 10, 2);
}
public function getInstance() {
if (is_null(self::$inst)) {
self::$inst = new self();
}
return self::$inst;
}
public function suppressFrontPageTitle($title, $id=null) {
if (is_page() && twentyseventeen_is_frontpage()) {
return null;
}
return $title;
}
}
GiTheme::getInstance();
This is not that much more complicated than my previous example. First of all I have tucked my filter function into a class. I like to keep functions and global variables to a minimum. Here I opt for a singleton (ping me if you want more on singleton – or, hint, buy my book!) – which means I have no dangerous global variables and my methods are hidden away where their names cannot accidentally clash with functions in plugins.
Within suppressFrontPageTitle()
, my filter method, I narrow the possible situations in which my filter operation is activated. As you might expect is_page() only returns true
for pages. The twentyseventeen_is_frontpage()
function is similarly predictable – it returns true
only when we’re on the Twenty Seventeen front page. If those conditions are not met, I return $title
unmolested. Which means a blog screen keeps its fields:
Otherwise, it’s curtains for titles.
photo credit: Dan Nguyen @ New York City IT’SUGAR and Seventeen, together via photopin (license)