Exclude categories from Loop, queries, widgets, post navigation

Excluding categories with pre_get_posts()

I found that excluding a category via pre_get_posts() and set_query_var() would work fine except for widgets. The Recent Post Widget would only exclude the category when using $query->set() instead.

<?php
/**
 * Does NOT apply to the Recent Posts widget. 
 */
function glck1403271109_exclude_categories( $query ) {

    $excluded = array( '1', '2' );

    if( ! is_admin() )
        set_query_var( 'category__not_in', $excluded );
}    
add_filter( 'pre_get_posts', 'glck1403271109_exclude_categories' );


/**
 * Does apply to the Recent Posts widget. 
 */
function glck1403271122_exclude_categories( $query ) {

    $excluded = array( '1', '2' );

    if( ! is_admin() )
        $query->set( 'category__not_in', $excluded );
}
add_filter( 'pre_get_posts', 'glck1403271122_exclude_categories' );

Excluding categories from queries and widgets

Excluding categories from queries and widgets took me a couple of functions I wrapped into a mini plugin. The code can be found in a Gist here.

Excluding categories from post navigation (next/prev_post_link())

next/prev_post_link() and their underlying get_ functions all rely on get_adjacent_post() which up to today (WordPress 3.9.1) does not use WP-Query, but fixes its own SQL query. Trac Ticket #26937 aims to get get_adjacent_post() to use WP_Query, but it might take a while until we’re there.

Excluding categories from next/prev_post_link() in my case could sufficiently be achieved passing category IDs to be excluded directly to the function. I’m sure this could also be down from a plugin interacting with get_adjacent_post() directly. Here’s my take for the template tag. Checking for glckprss_exclude_categories__category_names() from the previously mentioned mini plugin, of course, makes only sense when the latter is in use.

<?php
/**
 * Exclude categories from prev/next post links.
 *
 * $exclude  (array) - category slugs to retrieve IDs from
 * $excluded (array) - category IDs to be excluded
 */
$exclude  = array();
$excluded = array();

// Mini plugin active?
if( function_exists( 'glckprss_exclude_categories__category_names' ) ) {

    $exclude = glckprss_exclude_categories__category_names();

else {

    $exclude  = array(
            get_category_by_slug( 'my-category' ),
            get_category_by_slug( 'my-other-category' )
            );
}

// Retrieve IDs
foreach( $exclude as $category ) {

    if( $category )
        $excluded[] = absint( $category->term_id );
}

/* Next Post */
next_post_link( '%link', '%title', false, $excluded );

/* Previous post */
previous_post_link( '%link', '%title', false, $excluded );

Menus

For my use case it wasn’t necessary to exclude categories from menus as I had custom menus only, so I haven’t investigated in that direction. I’m pretty sure pre_get_posts() gets a grip on menu items, though, doesn’t it?

Thanks for reading all this, appreciate any comments!

Leave a Comment