
This is the third of my Quick N Dirty plugin posts. In the second post I showed how to access the post object and alter the post content before saving it back to the database. This plugin will also access to the post object, but this time I will use it to exclude posts from being displayed on the home page.
The hook I am going to use for this plugin is the_posts filter. This filter is called when a list of posts is pulled from the WordPress database ready to be displayed on screen.
The filter passes an array of post objects to the function which gives us the opportunity to carry out mass edits, add posts, or, as in this case, remove posts in certain circumstances.
What I want to do is to make sure that posts in my General category do not appear on the home page. I want them as part of my feed, as an added sweetener for subscribing, and I want them as part of my single post and my archives.
Here’s the plugin, I will explain more at the bottom:
[php]
/*
Plugin Name: Quick N Dirty Post Exclusion
Plugin URI: [insert the plugin uri here]
Description: Removes posts from the home page
Author: Andrew Rickmann
Version: 1
Author URI: http://www.wp-fun.co.uk
*/
//call the filter
//the_posts is called when a list of posts is retrieved from the database
//qnd_post_exclusion is the function
//1 is the priority, 1 runs first, 10 last
add_filter('the_posts', 'qnd_post_exclusion' , 1 );
function qnd_post_exclusion( $posts ){
//only apply this if we are looking at the home page
if ( !is_home() ) { return $posts; }
//create an array to hold the posts we want to show
$new_posts = array();
//loop through all the post objects
foreach( $posts as $post ){
//for each object get an array of applicable categories
$cats = get_the_category( $post->ID );
//create a variable that determins if this post should be included
//the default is true, i.e. include the post
$include = true;
//loop through all the categories applicable to the post
foreach( $cats as $cat) {
//if the post is assigned to our undesirable category then do not include it
if ( $cat->name == 'General' ) { $include = false; }
}
//if we want to include it then add the post object to the new posts array
if ( $include === true ) { $new_posts[] = $post; }
}
//send the new post array back to be used by WordPress
return $new_posts;
}
?>
By now the add_filter function should be fairly familiar so I won’t dwell on it. It shows the the hook, the function to be used, and specifies that it should run with the highest priority. I have chosen high priority so that any plugins that follow on that might modify the content of the post are saved the trouble of modifying a post that will later be removed. Aside from that the priority isn’t too relevant here.
The usual template functions is_home, is_feed, is_archive, etc will work at this point and so I have used is_home to restrict the plugin to posts displayed on the home page. If we are not dealing with the home page then the function will simply return the original array of posts. It is essential that it does return the array. Not returning the array is the same as filtering out every post, leaving no posts at all.
When the function is called it is passed an array of post objects. We use the post ID in each case to get an array of the categories the post is assigned to using the function below:
[php]get_the_category( $post->ID );
We then iterate through this array and if our chosen category is not in the array for each post we add the post to a new array . When we are done it is this array that is passed back to WordPress to continue its journey toward screen.
Note: If you copy the content of this plugin you will need to replace all the quote marks as WordPress replaces them with fancy ones.
(__)
`
Andrew Rickmann
I have had a play with this now and I think the only way is to get into the SQL. Found_posts just returns a string.
You might this post useful that I saw today: http://wpengineer.com/quick-tipps-for-wordpress...
(__)
`
Robert Griffin
Yeah, I really don't have time either. I'll be keeping an eye out here in case you do, or when I am bored, I will give it another go.
(__)
`
Andrew Rickmann
Are you sure your filter left enough posts remaining to be paged? It is worth checking, perhaps echoing out a count of the posts array before you end the filter to make sure.
I think found_posts is just a count of the number of posts and found_posts_query may be the sql so a foreach loop wouldn't work there.
It may be possible to use post_results to figure out which posts you will be left with, i.e. by putting the ID in an array, then use found_posts to change the number of posts it thinks it has found, then finally use the_posts to actually filter the posts. Unfortunately I don't have the time to try it out at the moment.
(__)
`
Robert Griffin
I had some time to play with the 'post_results'. When I used the same code it didn't show any paging at all. Only the first 5 posts in my case. When it is used in the 'the_posts' I get pagnation like before but I can see my other posts. From what I can see, this is the first place you can manipulate the returned posts.
Any filter I tried before that would would get errors on the foreach loop. I am new to filters and it scares me each time. I tried found_posts_query and found_posts but both gave me errors on the foreach.
Your filter works fine, and it looks like it is the first filter to use like this. Since my filter process is too complicated for a SQL query, it is probably best. Although, you would think that you could adjust the paging limit somehow.
(__)
`
realsol
The combo between the shortcode the 'the_content' and the custom field in the 'the_posts' work great. I was just concerned about speed over putting it in the theme. Really , I don't see any difference. I was trying so many filter plugins it forced me into purchasing a MySQL container on my host, thinking it was just wordpressMU. But after I got rid of those and wrote my own, my strain on the server went away. Don't really need a MySQL container after all.
I will check out the filter you are talking about and see if it helps with the pages and let you know. It really is like on the back burner right now, since there are enough posts that show that it doesn't make too much difference.
I'll let you know what happens, since you might also want to use it on your front page.
(__)
`
Andrew Rickmann
That's quite a list of possible outcomes and I can see why a basic filter won't do it. I would say that filter the_posts is the right approach, you just need to fix the paging.
I must admit that I have never looked into how the paging works, so this isn't definite but in query.php, in wp-includes there are some more filters you might like to try.
First there is a post filter earlier on in the process which you should be able to simply replace with the one in my post above. This is posts_results. This seems to be the first process that happens immediately after the query so ought to be before any paging is calculated.
Beside that there are a few more that might relate to paging so you might want to take a look through that file and figure out how it all works.
(__)
`
Robert Griffin
Thanks again. I hope I am not junking up you blog.
I am not sure a query would do. I like you wanted some info not seen to the average visitor. I have looked at many plug-ins, most left behind database entry's (another day). What I basically did, using your code example is created a plug-in that uses both a custom field and a short-code called user_access. I allow you to set levels against this. If used in a post you can hide, or show information based on whether the user is logged-in, logged-out,user lever, user name, or any php true false code you can think of in the shortcode. This allows me to display or hide portions of the post based on my custom criteria.
If used as a custom field, same usage applies, but to the whole post.
I really couldn't find anything out there that would let me do everything and that seemed wordpressmu friendly.
Because of the different options, I probably couldn't adjust the query since I can base it on so many things, like only show if a user is level 2, has edit rights, and is in a certain category, all from a shortcode or custom field.
While a plug-in is more transferable (I can use it in many different themes and blogs since I don't have to edit the theme) I want it to be quick. The plug-ins I tried, many really slowed things down. That why I wasn't sure if a plug-in or some code would be the quickest. I thought a plug-in would happen before the loop, but that is fine as long as performance doesn't lag. It doesn't appear to so far, but its really a virgin blog.
(__)
`
Andrew Rickmann
If you don't actually need a plugin then the best route would be to use query_posts right above the loop. Check out http://codex.wordpress.org/Template_Tags/query_... this explains how to do it.
(__)
`
Robert Griffin
Thanks for the response. I was filtering within the theme just below the loop statement. From what you said above, does this mean the theme is actually formatting all of the posts prior to me hiding them? I was just calling 'continue' as the second line in the loop before, thus, if I was hiding the post, no further processing was being done by the theme. It would just move on to the next post. I thought by using a plugin, I would be grabbing the post prior to the theme, thus cutting out some of the processing and formatting the theme does, since it would never see the hidden posts.
Would it be faster then to just leave my code in the them rather than calling it from the 'the_posts' filter?
(__)
`
Andrew Rickmann
Robert, the problem is that this takes the array at the last moment before it is output, after all the paging has been generated so this method will always have that problem.
It would be better to intercept the query before hand, perhaps by using the template_redirect hook and, depending on what is being requested, running a new query_posts() as shown in Multiple Loops example 1 on this page: http://codex.wordpress.org/The_Loop
(__)
`
Robert Griffin
I was looking for a good example for the filter(the_posts) and this was perfect. I was filtering each post but within my theme. I wanted to be able to do it as a plug-in but didn't know where to start.
My only problem is I am restricting my posts to 10 per page. It seems that when you hide a post, WordPress doesn't realize it and still counts the post as one of the 10. So if I am hiding 9 of the first 10 posts, I get a nextpage after the first post. Is there a way to tell WordPress to also exclude this post from the pagecount?
Thanks.