How to filter posts that appear on your WordPress blog


As requested by a reader, I’ll write down the steps required to hide posts from a certain category unless a visitor has a specific cookie set.

The said posts will be hidden from :
– Main page, and all sub-pages
– Archives
– RSS (except the RSS on general comments, didn’t find how yet)
– Widgets
– Search results

You can make it work for almost anything with a little piece of code. More details below.


What you need :
– Full admin rights on your blog, and FTP access.
– The ability to execute PHP code from within WordPress (because WordPress strips any PHP code it sees by default). This is only needed if you’d like to make it work for widgets, or other things which require interaction from within WordPress (the admin area, for example). Anything else is fine, as we will directly modify PHP files.
– A good source code editor. I personally recommend Notepad++.
– A decent knowledge on how to read and write code ! If you don’t even know what “if then else” means in scripting language, then forget about this topic^^

What is also recommended :
– Some knowledge of how WordPress works, and the structure (tree) of where the WordPress files are located, from within your FTP.
– Patience. The theme you use is most likely not the same one as mine, so there may be some things which will be different. You’ll have to adapt yourself to what you’ll see.
– You need to understand what you are doing ! Brainless copy/paste is a very bad idea. I’ll try to make it “easy-to-understand” for people who are not very knowledgeable in scripting languages.

I don’t claim to be an expert regarding WordPress’ functions, and my knowledge of it is quite limited.
However, I’ll try to explain things as best as I can.
I’ll work by memory here, so if you think I omitted something, feel free to comment about it.
Something important to note : We will never edit any of WordPress’ core files. Not only is this dangerous if you’re not careful, but your changes may dissapear if you update your WordPress’ installation.
We will only edit your theme’s files.
Make sure you backup all of your theme’s files if you plan on updating your theme ! Otherwise you’ll most likely loose everything you’ve done !


    • Step 1 : Editing header.php

File location : /wp-content/themes/your_theme_name/header.php

When a page is displayed to your visitors, it is “constructed” using 3 PHP files :

  • header.php
  • index.php
  • footer.php
  • The header usually contains the information neeeded to display your blog’s logo and menus. This is also where you’ll call most of your JS and CSS files as well.

    Here, we’re gonna add a few Javascript functions to read and set cookies for our visitors. We will use these cookies to know if content should be filtered for a specific visitor, or not.

    In my case, I made it so that when a user clicks on an image, it calls a Javascript function to change the value of a cookie from 0 to 1, or 1 to 0. If the cookie is set to 1, posts featuring 18+ content will be visible. if set to 0, all 18+ content will be hidden.

    First, have a look at the Javascript code below :

    <script type="text/javascript">
    function wpmc_toggle_visibility() {
    var mc_cookieValue = readCookie("wpmc_visibility");
    	if ( mc_cookieValue == 1 ) {
    	createCookie(0);
    	alert('Mature content is now hidden.\n\nPlease wait while the page reloads itself.');
    	location.reload(true);
    	}
    	else if ( mc_cookieValue == 0 ) {
    	createCookie(1);
    	alert('Mature content is now visible.\n\nPlease wait while the page reloads itself.');
    	location.reload(true);
    	}
    	else {
    	createCookie(0);
    	alert('Mature content is now hidden.\n\nPlease wait while the page reloads itself.');
    	location.reload(true);
    	}
    return null;
    }
    function createCookie(value) {
    	var date = new Date();
    	date.setTime(date.getTime()+(31*3600000*24)); 
    	var expires = "; expires="+date.toGMTString();	
    	document.cookie = "wpmc_visibility"+"="+value+expires+"; path=/";
    }	
    function readCookie(name) {
    	var nameEQ = name + "=";
    	var ca = document.cookie.split(';');
    	for(var i=0;i < ca.length;i++) {
    		var c = ca[i];
    		while (c.charAt(0)==' ') c = c.substring(1,c.length);
    		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    	}
    	return (0);
    }
    </script>

    When you call the function wpmc_toggle_visibility (clicking on a button, for example), it will check the cookie stored on the visitor’s machine to see if the filter is set to 0 or 1. If no cookie is found, then we’ll create one for the user.

    Let’s take a look at a part of the code above :

    
    var mc_cookieValue = readCookie("wpmc_visibility");
    if ( mc_cookieValue == 1 ) {
    createCookie(0);
    alert('Mature content is now hidden.\n\nPlease wait while the page reloads itself.');
    location.reload(true);
    }
    

    Explanation : We first define a variable called mc_cookieValue, whose value is the result returned by the function readCookie.
    The readCookie function reads a user’s cookie whose name matches the name you gave the function (as a parameter) :

    
    function readCookie(name) {
    	var nameEQ = name + "=";
    	var ca = document.cookie.split(';');
    	for(var i=0;i < ca.length;i++) {
    		var c = ca[i];
    		while (c.charAt(0)==' ') c = c.substring(1,c.length);
    		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    	}
    	return (0);
    }
    

    In my case, it will search for a cookie named “wpmc_visibility“. If the cookie is found, it will return its value. If not, it will return 0.

    Then, if the result returned is 1, we call the createCookie function, with 0 as parameter. Keep in mind that we want to “toggle” the visibility status, so when the value is 1, we change it to 0, and vice-versa.
    The function is called “createCookie” but in fact it also updates the existing cookie, so don’t mind the name too much.
    The function createCookie creates or updates a cookie named “wpmc_visibility“. You can change the expiration date of the cookie to whatever value you’d like.
    If you’re not familiar on how cookies are handled with Javascript, you may want to search for things like “Javascript create cookie” on google, or something like that.
    You can also change the name wpmc_visibility to whatever name you want, but remember to change it everywhere it is needed.
    After we’ve created/updated the cookie’s value, we display an alert window to tell the user that 18+ content is now visible/hidden, and we force a page refresh to reflect the changes on the posts’ visibility.

    Okay, done with the coding. Now, we need this code to be inserted in the header.php file.
    You can insert the code just as it is, or export it to a .js file, and then call the js file using something like :

    <script type="text/javascript" src="path_to_your_js_file"></script>

    Either way, you need to insert this inside the <head> tag of your header.php file.


      • Step 2 : Creating the filtered category

    This tutorial is about hiding posts from a specific category.
    So.. we need that category, right? ;)

    In my case, the category I wanted to hide was named “18+“. The good point is, all children categories of that one will also be hidden by the filter.

    Just go ahead in your WordPress admin area, click on the “Posts” tab, then on “Categories”, and create your new category.


      • Step 3 : Editing functions.php

    File location : /wp-content/themes/your_theme_name/functions.php

    In this file, we will add functions that will “hook” into WordPress and change the way it does its stuff.
    In our case, we’re gonna add some “filter” functions.

    Go ahead and paste these 3 PHP functions before the existing functions :

    //--------------------------------------------------------------
    // BEGIN - Zana Functions - Mature Content
    //--------------------------------------------------------------
    function SearchFilter($query) {
    	if ( ( isset($_COOKIE['wpmc_visibility']) && ($_COOKIE['wpmc_visibility'] == '0') ) || (!isset($_COOKIE['wpmc_visibility']) ) ) {
    		if ($query->is_search) {
    			$wpmc_id = get_cat_id('18+');
    			$query->set('cat','-'.$wpmc_id);
    		}
    	} //endif mature content
    	return $query;
    }
    add_filter('pre_get_posts','SearchFilter');
    //--------------------------------------------------------------
    function FeedFilter($query) {
    	if ( ( isset($_COOKIE['wpmc_visibility']) && ($_COOKIE['wpmc_visibility'] == '0') ) || (!isset($_COOKIE['wpmc_visibility']) ) ) {
    		if ($query->is_feed) {
    		$wpmc_id = get_cat_id('18+');
    		$query->set('cat','-'.$wpmc_id);
    		}
    	} //endif mature content
    	return $query;
    }
    add_filter('pre_get_posts','FeedFilter');
    //--------------------------------------------------------------
    function ArchiveFilter($query) {
    	if ( ( isset($_COOKIE['wpmc_visibility']) && ($_COOKIE['wpmc_visibility'] == '0') ) || (!isset($_COOKIE['wpmc_visibility']) ) ) {
    		if ($query->is_archive) {
    		$wpmc_id = get_cat_id('18+');
    		$query->set('cat','-'.$wpmc_id);
    		}
    	} //endif mature content
    	return $query;
    }
    add_filter('pre_get_posts','ArchiveFilter');
    //--------------------------------------------------------------
    // END - Zana Functions - Mature Content
    //--------------------------------------------------------------
    

    These 3 functions will be called whenever WordPress makes a database query. They will “hook” into the query process and modify the content returned.
    Let’s have a look at the first function (the other ones work the same way) :

    function SearchFilter($query) {
    	if ( ( isset($_COOKIE['wpmc_visibility']) && ($_COOKIE['wpmc_visibility'] == '0') ) || (!isset($_COOKIE['wpmc_visibility']) ) ) {
    		if ($query->is_search) {
    			$wpmc_id = get_cat_id('18+');
    			$query->set('cat','-'.$wpmc_id);
    		}
    	} //endif mature content
    	return $query;
    }
    

    The SearchFilter function will change the content returned by the database’s query whenever the origin of the query is a “search”, this means : Everytime a visitor uses you blog’s search box.
    The first two lines check if the user does NOT have the wpmc_visibility cookie we talked earlier, or if it exists but is set to 0.
    In this case, this means we need to filter the content he/she is gonna see (ie : hide all posts from the category defined earlier).
    The ($query->is_search) part checks if the query originates from a “search”.
    If so, it will remove the 18+ category from the search results. Details about the process can be found here, although the code is pretty self-explanatory. You can even exclude multiple categories if you’d like.

    Notice the following line of code after the end of the function :

    add_filter('pre_get_posts','SearchFilter');

    This line is very important, because it tells WordPress to actually use the function we just wrote (writing a function is useless if you don’t call it ;))
    The first parameter is the Action reference, the second is our function’s name.

    “So, what do I need to modify in those 3 functions?”
    Simply change the three “18+” with the name of your category. Eventually change the wpmc_visibility string to match your cookie’s name.

    You’ll notice that my code is not optimized. We could easily combine the three functions into one by changing the

    if ($query->is_search) {

    to

    if ($query->is_search || $query->is_feed || $query->is_archive) {

    for example.
    The functions were split to have a better understanding.
    You can find more function references here.


      • Step 4 : Editing index.php

    File location : /wp-content/themes/your_theme_name/index.php

    Okay, so we’ve filtered content for RSS feeds, Search and Archives. But we’re missing something important, right?
    Yes, the posts on normal pages ! We haven’t filtered them yet.

    Important note : I believe there is a way to directly filter them using another filter in functions.php with the right function reference. I was too lazy to look into it, but feel free to try things around ;)

    In your index.php, after this line :

    <?php get_header() ?>

    add the following code :

    <?php
    global $query_string;
    
    if (( isset($_COOKIE['wpmc_visibility']) && ($_COOKIE['wpmc_visibility'] == '0') ) || (!isset($_COOKIE['wpmc_visibility']) )) {
    	$wpmc_id = get_cat_id('18+');
    	$wmpc_q = $query_string . "&cat=-" . $wpmc_id . "&posts_per_page=10";
    	query_posts($wmpc_q);
    }
    ?>
    

    Again, replace 18+ (and eventually wpmc_visibility) with the right stuff.
    This will, if the user has the (cookie) mature filter set to 0, query posts from the database, with the 18+ category excluded from the results.
    Also, notice the following piece of code :

    &posts_per_page=10

    What does this mean? Simple : In my WordPress admin area, I’ve set pages to contain 14 posts each.
    Why? Because if both normal content and 18+ content are shown, 18+ posts from the main page may rapidly push non-18+ posts to the second page.
    What I’m doing here is displaying 10 posts per page if 18+ content is hidden. If it’s not hidden, then WordPress will return the default amount of posts per pages : 14 (the number defined in your admin area).

    This is a purely personal preference. If you want to display the same amount of posts regardless of the filter’s status, just replace

    $wmpc_q = $query_string . "&cat=-" . $wpmc_id . "&posts_per_page=10";

    with

    $wmpc_q = $query_string . "&cat=-" . $wpmc_id;



      • Step 5 : Triggering your filter

    Alright, the filter is complete ! Now all we need is an event that will trigger a change in the filter.
    There are many ways to do this. Here I chose a very classic way : Clicking on an image.
    Here’s the “button” from my filter :

    The way to implement it is quite simple :

    <input type="image" title="title_for_your_image" src="path_to_your_image" onClick="wpmc_toggle_visibility();"/>

    Note the input type set to image, and the call to our Javascript function “wpmc_toggle_visibility” from Step 1 when the image is clicked.


      • Step 6 : Customizing widgets with the filter

    I’ll keep it simple here, with this piece of code, which lists categories based on the filter.
    Just insert this PHP code into a “Text” widget for example, and you’re good to go.
    However, remember what I said at the start : You need the ability to execute PHP from within WordPress to do this !
    Being admin doesn’t mean that you can execute PHP inside WordPress either.
    Anyway, here’s the code. If you’ve read everything I said before, you should instantly understand what this code does :

    <ul>
    <?php
    if ( ( isset($_COOKIE['wpmc_visibility']) && ($_COOKIE['wpmc_visibility'] == '0') ) || (!isset($_COOKIE['wpmc_visibility']) ) ) {
    	$wg_mature_id = get_cat_id('18+');
    	wp_list_categories('exclude='.$wg_mature_id);
    }
    else {
    	wp_list_categories();
    }
    ?>
    </ul>





    Well, that’s it ! You can use your filter almost anywhere you want, with just the following codes :

    
    // If user has the filter (cookie) set to 0 or not set (Show limited content) :
    if ( ( isset($_COOKIE['wpmc_visibility']) && ($_COOKIE['wpmc_visibility'] == '0') ) || (!isset($_COOKIE['wpmc_visibility']) ) ) {
    	// Do some stuff here
    }
    

    or

    
    // If user has the filter (cookie) set to 1 (Show all content) :
    if ( isset($_COOKIE['wpmc_visibility']) && $_COOKIE['wpmc_visibility'] == '1' ) {
    	// Do some stuff here
    }
    
    1. You no need to explain this so clearly like that @@ Thanks you so much. I've just done the plugin that allow admin to choose which category can show in front page, archive, feeds, and styles. I think i will spend a day on finding the way to integrate ur code (using cookie) with my plugin, thanks again :D

        • Zana
        • July 15th, 2011 - 14:43:16 PST

        I've made it this way because the post is public, thus seen by everyone.
        Since each individual has a different knowledge level regarding WordPress and "how to code", it's better to make it as much detailed as possible.
        Could've just thrown the code away, but that's not my style ;)

    1. No trackbacks yet.



    Notify me of followup comments via e-mail.
    You can also subscribe without commenting.

    Subscribe to Posts

    Email: