WordPress Plugin: Remove Posts in Category From Homepage

By  on  
WordPress Plugin

Being a WordPress user for some time, I've always wanted to create a WordPress plugin but I've hesitated.  I've not run into an issue that I couldn't find an existing plugin for, and the thought of maintenance on a WordPress plugin seemed daunting because I only use WordPress for this blog.  With an added feature to my redesign, however, I found the perfect use case:  preventing posts in a giving category from displaying on the homepage.  I've detailed the PHP snippet for preventing posts in a category from the homepage, but that only works within the theme that hosts the functions.php file.  By creating the Remove Posts in Category From Homepage plugin, this functionality now works across all themes!

The Setup

The goal was to ensure the plugin was as lightweight and simple as possible.  Other goals included:

  • Encompassing all plugin code in one file
  • Using only one database record;  to do this, we'll keep an array of categories which should be prevented from hitting the homepage
  • Allowing the ability to toggle this option on the "Add Category" and "Edit Category" pages

Achieving these goals became simple due to WordPress' awesome plugin API.

The PHP

I'll explain the PHP code step by step.  We start out by defining a few important variables:

$RCFH_LOOP_LABEL = 'Remove from main loop';
$RCFH_LOOP_DESCRIPTION = 'Check this box if you would like posts in this category to be prevented from displaying within the main loop.';
$RCFH_LOOP_OPTION_KEY = 'remove-loop-cats';

The first two variables will be used in the "Add Category" and "Edit Category" forms, while the last var represents the option name we'll use to set and get categories in the database.  Next we add a checkbox to the "Edit Category" screen:

<?php
	// Add the extra field to the EDIT category page
	add_action('category_edit_form_fields', 'rcfh_loop_field_edit');
	function rcfh_loop_field_edit($term) {
		global $RCFH_LOOP_LABEL, $RCFH_LOOP_DESCRIPTION, $RCFH_LOOP_OPTION_KEY;

		$value = get_option($RCFH_LOOP_OPTION_KEY);
		if(!$value) {
			$value = array();
		}

		$checked = in_array($term->term_id, $value);
 ?>
	<tr class="form-field">
		<th scope="row" valign="top"><label for="removeMainLoop"><?php _e($RCFH_LOOP_LABEL); ?></label></th>
		<td>
			<input type="checkbox" name="remove-loop" id="removeMainLoop"<?php echo $checked ? ' checked="checked"' : ''; ?> value="1" /><br />
			<span class="description"><?php _e($RCFH_LOOP_DESCRIPTION); ?></span>
		</td>
	</tr>
<?php } ?>

The cl_loop_field_edit function, which is executed during the category_edit_form_fields action, retrieves the option value and checks to see if the given category ID is in the list of categories which shouldn't display on the homepage - if so, the checkbox is checked.

The next step is adding the same form field to the "Add Category" screen:

<?php
	// Add the extra field to the ADD category page
	add_action('category_add_form_fields', 'rcfh_loop_field_create');
	function rcfh_loop_field_create() { 
		global $RCFH_LOOP_LABEL, $RCFH_LOOP_DESCRIPTION;
?>
	<div class="form-field">
		<label for="removeMainLoop"><?php _e($RCFH_LOOP_LABEL); ?></label>
		<input type="checkbox" name="remove-loop" id="removeMainLoop" value="1" />
		<p><?php _e($RCFH_LOOP_DESCRIPTION); ?></p>
	</div>
<?php } ?>

With the checkbox added to both forms, the next step is creating a function which saves the value of the checkbox during add and edit transactions.  The function, named cl_save_loop_value, will execute during edit_category and create_category actions:

// Add action for saving extra category information
add_action('edit_category', 'rcfh_save_loop_value');
add_action('create_category', 'rcfh_save_loop_value');
function rcfh_save_loop_value($id) {
	global $RCFH_LOOP_OPTION_KEY;

	$value = get_option($RCFH_LOOP_OPTION_KEY);
	if(!$value) {
		$value = array();
	}

	// Add or remove the value
	if(isset($_POST['remove-loop'])) {
		array_push($value, $id);
	}
	else {
		$value = array_diff($value, array($id));
	}

	// Ensure no duplicates, just for cleanliness
	$value = array_unique(array_values($value));

	// Save
	update_option($RCFH_LOOP_OPTION_KEY, $value);
}

You'll note that some cleanup is done at the end to ensure there are no duplicate category keys in the array.  Also know that WordPress serializes the array before placing it in the database.  The last step is creating a pre_get_posts action function to prevent posts in the selected categories from displaying in the main loop:

// Filter for removing said category posts from main loop
add_action('pre_get_posts', 'rcfh_prevent_posts');
function rcfh_prevent_posts($query) {
	global $RCFH_LOOP_OPTION_KEY;

	// Only remove categories if it's the main query/homepage
	if($query->is_home() && $query->is_main_query()) {
		$value = get_option($RCFH_LOOP_OPTION_KEY);

		// Modify query to remove posts which shouldn't be shown
		if(count($value)) {
			$query->set('cat', '-'.implode(',-', $value));
		}
	}
}

And with that, the plugin is complete!  There's a fair amount of PHP but all the user needs to do is enable the plugin and toggle checkboxes!

Taking the time to finally create a WordPress plugin was worth it.  I gained appreciation for the numerous WordPress plugin creators out there, and I got better acquainted with WordPress' hook/action system.  Hopefully you find this plugin useful and you find inspiration to have a go at creating your own plugin!

Recent Features

  • By
    Chris Coyier&#8217;s Favorite CodePen Demos

    David asked me if I'd be up for a guest post picking out some of my favorite Pens from CodePen. A daunting task! There are so many! I managed to pick a few though that have blown me away over the past few months. If you...

  • By
    Animated 3D Flipping Menu with CSS

    CSS animations aren't just for basic fades or sliding elements anymore -- CSS animations are capable of much more.  I've showed you how you can create an exploding logo (applied with JavaScript, but all animation is CSS), an animated Photo Stack, a sweet...

Incredible Demos

  • By
    Highlight Table Rows, Columns, and Cells Using MooTools 1.2.3

    Row highlighting and individual cell highlighting in tables is pretty simple in every browser that supports :hover on all elements (basically everything except IE6). Column highlighting is a bit more difficult. Luckily MooTools 1.2.3 makes the process easy. The XHTML A normal table. The cells...

  • By
    Introducing MooTools ScrollSide

    This post is a proof of concept post -- the functionality is yet to be perfected. Picture this: you've found yourself on a website that uses horizontal scrolling instead of vertical scrolling. It's an artistic site so you accept that the site scrolls left to right.

Discussion

  1. Great contribution to wordpress community :)

  2. Great plugin. Thanks.

  3. Great plugin.
    I think using is_front_page() on the condition instate of is_home() will give it more flexibility.

  4. Useful plugin, thanks for info.

  5. nev

    Hey man you saved my bacon – thanks tons

  6. Troels

    How about the other way around? Having only the posts with a certain category showing up on the homepage? Is that possible?

    • Absolutely, just remove the “-” from this code:

      $query->set('cat', '-'.implode(',-', $value));

  7. I would like the category to show in RSS but not the wordpress homepage. Is there an option for this?

  8. never mind I should have installed plugin first :D now I see that there is a separate option.
    Thanks for a simple compact and very useful plugin.

  9. Holy smokes – it works! What a great plugin. Thanks – very much.

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!