One of the very first things people tend to learn when writing plugins is how to attach custom HTML to the bottom of their WordPress posts using the filter called “the_content”. This is good, as it is an extremely useful filter, but rarely do tutorials really explain how to use this filter well, and how to avoid some potentially major problems when using it in your plugins. I’m going to walk you through the basics and also demonstrate some more advanced applications, and talk to you about problems that can be caused when using this filter.

The typical code that you will see intro plugin development tutorials show usually looks about like this:

1
2
3
4
5
6
function pippin_filter_content_sample($content) {
	$new_content = '<p>This is added to the bottom of all post and page content</p>';
	$content = $content . $new_content;
	return $content;
}
add_filter('the_content', 'pippin_filter_content_sample');

With this function active in your theme or plugin, any time the the_content() function is called, the text “This is added to the bottom of all post and page content” will be appended to the end.

There are a few minor and major issues with function. Let’s look at how we correct these.

Problem number 1: while there is nothing syntactically wrong with this function, we can improve it by cutting away some of the unnecessary code. There is really no reason for this line:

$content = $content . $new_content;

Instead of doing that, we should just attach our $new_content variable directly to the $content variable in the return statement, like so:

return $content . $new_content;

You could even go a little further and do just this:

return $content . '<p>This is added to the bottom of all post and page content</p>';

They will both result in the same thing, but I prefer the first of the two methods and it is just slightly easier to read, especially when you have much larger functions.

Problem number 2: the first problem was more of a good coding practice kind of problem, this second one is much more major. Have you ever seen a plugin, particularly social sharing plugins, that adds some form of content to posts and/or pages, and for some reason the content appears in weird places, such as sidebars or footers, and also on every single page, including archives? This is typically because the developer has not take the time to ensure that their extra content, be it social icons or something else, only gets added in the appropriate place. The most common place to append content is at the end of a post when viewing the single post.

To update our code and fix problem #2, we need to use some conditional tags. First let’s start with is_single().

1
2
3
4
5
6
7
8
function pippin_filter_content_sample($content) {
	if(is_single()) {
		$new_content = '<p>This is added to the bottom of all post content</p>';
		$content .= $new_content;	
	}	
	return $content;
}
add_filter('the_content', 'pippin_filter_content_sample');

By adding the is_single() conditional check, we ensure that out extra content only gets appended when we are on a single post page. But what if we want to add content to both single posts and pages? And perhaps custom post types? Then we need to use is_singular():

1
2
3
4
5
6
7
8
function pippin_filter_content_sample($content) {
	if(is_singular()) {
		$new_content = '<p>This is added to the bottom of all post and page content, as well as custom post types.</p>';
		$content .= $new_content;	
	}	
	return $content;
}
add_filter('the_content', 'pippin_filter_content_sample');

Looks pretty good right? Actually no, there is still a major problem with this code. The thing that you must understand and acknowledge is that the “the_content” filter may NOT only get applied when we call the_content(). Often times plugin and theme developers will use something like the following to help format their custom queries:

echo apply_filters('the_content', $custom_content_here);

Doing this will pass whatever content is stored in the $custom_content_here variable and perform all of the nice formatting that we expect with the the_content() function. This also means that our pippin_filter_content_sample() function will attach its custom content to this other text as well, and that’s not good.

In order to solve this problem, we can use one more conditional tag. The is_main_query() function was introduced in WordPress 3.3 and allows us to check whether we are currently inside of the main post query. The main post query can be thought of as the primary post loop that displays the main content for the post/page or archive. By using this tag, our filter will NOT get applied to any custom loops in sidebars, footers, or elsewhere, even if they use this:

apply_filters('the_content' . . .

Our final function, which should play well with everything, looks like this:

1
2
3
4
5
6
7
8
function pippin_filter_content_sample($content) {
	if( is_singular() && is_main_query() ) {
		$new_content = '<p>This is added to the bottom of all post and page content, as well as custom post types.</p>';
		$content .= $new_content;	
	}	
	return $content;
}
add_filter('the_content', 'pippin_filter_content_sample');

When building your own plugins and themes, do not forget to think about what other developer’s plugins and themes may be doing. You should always try to eliminate as many possible conflicts before they even happen, and making sure that you use these kind of filters correctly is a great place to start.

  1. Arek

    Well, I found the answer by this post. The is_main_quey ia very useful since the additional content alwyas show up in my related post. Thanks for the code!

  2. Luke

    Thank you very much for this nice content about the_content 🙂

Leave a Reply

Error: Please enter a valid email address

Error: Invalid email

Error: Please enter your first name

Error: Please enter your last name

Error: Please enter a username

Error: Please enter a password

Error: Please confirm your password

Error: Password and password confirmation do not match