Sometime we want to hide a post from wordpress home page. One not-so-good alternative is to create it as a page. One drawback of that approach is that it does not have tags, categories and will not come in tag/category browse pages. This article will cover how this can be achieved if there is any performance impact.
How posts are displayed in wordpress
By default when we hit home page and navigate, wordpress queries wp_posts table and its a simple query since all post are included. Here is how a query (not verbatim) looks like:
SELECT wp_posts.ID FROM wp_posts WHERE wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') ORDER BY wp_posts.post_date DESC LIMIT 0, 10
To be able to prevent some posts from appearing on home page (or RSS feed, etc.) this query needs to be modified.
Using WP hide post plugin
WP hide post plugin is a good plugin which let you achieve these functionalities. Here is how the wordpress post edit admin UI looks like when plugin is instaled and activated.
Here is what plugin doc says:
WP hide post enables a user to control the visibility of items on the blog by making posts and pages selectively hidden in different views throughout the blog, such as on the front page, category pages, search results, etc…
The plugin was last updated on 2010-1-3. So I was initially little worried about using it. But it is pretty simple and worked nicely. Moreover its a good idea to understand how plugin is doing it so that one can fix things if needed.
How WP hide post plugin works
The plugin adds a filter to posts_join_pages which adds a join clause in query to get posts from wp_posts table (on wp_post_options).
add_filter('posts_join_paged', 'wphp_query_posts_join');
Here is how the query for showing posts on home page looks like if you use the plugin:
SELECT wp_posts.ID FROM wp_posts LEFT JOIN wp_postmeta wphptbl ON wp_posts.ID = wphptbl.post_id and wphptbl.meta_key like '_wplp_%' AND ((wp_posts.post_type = 'post' AND wphptbl.meta_key = '_wplp_post_front' ) OR (wp_posts.post_type = 'page' AND wphptbl.meta_key <> '_wplp_page_flags' AND wphptbl.meta_key not like '_wplp_%' ))
Note that this will add little overhead to query in terms of performance. Also post will still apear in sitemap and other browse pages.
Performance and other approaches
Since the query to get posts is on two tables, there will be some (very little if number of posts are not too many) performance impact. If your blog posts are under 10000 or so and you are using some caching plugin like W3 total cache, then the impact can be pretty much neglected for all practical purpose.
In case you are obsessed about performance, then you may want to explore adding a filter to posts_where_pages
and excluding the post ids which are in php code itself. You may have to auto generate that part of php code using some automated script and your own workflow.
function some_function_to_exclude_posts_in_where($where) { // code to append ID not in (id1, id2, id3) to $where } add_filter('posts_where_paged', 'some_function_to_exclude_posts_in_where');
This approach may be harder to maintain and not recommended. But I think its good to be aware of all feasible options.