Spring Sale! Save 30% on all books w/ code: PLANET24
Web Dev + WordPress + Security

WordPress pre_get_posts + Combined Category Archives

This is a quick post following from the latest redesign of my WordPress plugins website, Plugin Planet. There, I make use of WordPress great query functionality to display archives of multiple categories. For example, here is the combined archive for BBQ Pro and Docs. So that category archive displays all documentation posts for BBQ Pro. Likewise for other categories, for example here is the combined archive for Banhammer Pro and Tutorials. That category archive displays all tutorial posts for Banhammer Pro. These combined category archives are used for all pro plugins.

Contents

Combining categories via URL

To get a better idea of how it works, consider the following URL:

https://plugin-planet.com/category/docs+bbq-pro/

Combining the categories docs and bbq-pro, gives us the archive view for BBQ Pro Documentation. Another quick example:

https://plugin-planet.com/category/tuts+banhammer-pro/

Combining the categories tuts and banhammer-pro, gives us the archive view for Banhammer Pro Tutorials.

The trick here is to use the plus sign + to combine category slugs in the URL. You can combine any number of categories, and awesome WordPress will output the correct posts. Incidentally, WordPress also will output RSS and Atom feeds when /feed/ is appended to the URL. For example:

https://plugin-planet.com/category/tuts+blackhole-pro/feed/

That calls up the RSS feed for the combined category archive for all Blackhole Pro tutorials. For more information, check out What is My WordPress Feed URL?

Modifying combined category queries

All good so far. But I also need to modify the query of my combined category archives. Specifically, I want to customize the number of posts that are displayed for various category views. For single-category archives, WordPress makes this easy:

function shapeSpace_set_posts_per_category($query) {
	
	if (!is_admin() && $query->is_main_query() && $query->is_category()) {
		
		if (is_category('news'))  $query->set('posts_per_page', 5);
		if (is_category('docs'))  $query->set('posts_per_page', 6);
		if (is_category('tuts'))  $query->set('posts_per_page', 8);
		if (is_category('forum')) $query->set('posts_per_page', 8);
		
	}
	
}
add_filter('pre_get_posts', 'shapeSpace_set_posts_per_category');

This code snippet uses the filter hook pre_get_posts and the function is_category() to match specific individual categories and set the desired number of posts displayed per page. This is routine stuff. No surprises here.

Problem with combined categories

The problem is when you try using is_category() with multiple category names. It just doesn’t work. So you can check if the category is any single category slug like docs or tuts. But you can’t check if the category is a combined category like docs+bbq-pro or tuts+bbq-pro. For example if we try the following query:

https://plugin-planet.com/category/tuts+blackhole-pro/

..the result is a bunch of errors like:

PHP Notice: Trying to get property 'slug' of non-object in /wp-includes/class-wp-query.php on line 3765
PHP Notice: Trying to get property 'name' of non-object in /wp-includes/class-wp-query.php on line 3763
PHP Notice: Trying to get property 'term_id' of non-object in /wp-includes/class-wp-query.php on line 3761

Workaround solution

So back to Plugin Planet and my silly desire to customize the number of posts per combined-category archive page. How to make it work? The solution is to workaround is_category() with some alternate PHP logic:

function shapeSpace_set_posts_per_category($q) {
	
	if (!is_admin() && $q->is_main_query()) {
		
		$vars = $q->query_vars;
		
		$cat = isset($vars['category_name']) ? $vars['category_name'] : null;
		
		if (stripos($cat, 'news')  !== false) $q->set('posts_per_page', 5);
		if (stripos($cat, 'docs')  !== false) $q->set('posts_per_page', 6);
		if (stripos($cat, 'tuts')  !== false) $q->set('posts_per_page', 8);
		if (stripos($cat, 'forum') !== false) $q->set('posts_per_page', 8);
		
	}
	
}
add_filter('pre_get_posts', 'shapeSpace_set_posts_per_category');

Basically this alternate technique replaces is_category() with query_vars category_name, which then is checked using PHP’s stripos(). I encourage you to compare this alternate code with the original technique. This code has been in place at Plugin Planet for over a year now and seems to be working perfectly.

Better solutions?

If you have a better solution for modifying combined category queries with WordPress, please share in the comments below (if open), or send a quick email via my contact form. Thank you kindly :)

About the Author
Jeff Starr = Creative thinker. Passionate about free and open Web.
WP Themes In Depth: Build and sell awesome WordPress themes.
Welcome
Perishable Press is operated by Jeff Starr, a professional web developer and book author with two decades of experience. Here you will find posts about web development, WordPress, security, and more »
Banhammer: Protect your WordPress site against threats.
Thoughts
I live right next door to the absolute loudest car in town. And the owner loves to drive it.
8G Firewall now out of beta testing, ready for use on production sites.
It's all about that ad revenue baby.
Note to self: encrypting 500 GB of data on my iMac takes around 8 hours.
Getting back into things after a bit of a break. Currently 7° F outside. Chillz.
2024 is going to make 2020 look like a vacation. Prepare accordingly.
First snow of the year :)
Newsletter
Get news, updates, deals & tips via email.
Email kept private. Easy unsubscribe anytime.