/dev

Links, Wordpress, Design and PHP. Welcome to my day job. Subscribe

Wordpress In_Category() Is Broken

In Wordpress 2.5.1 the in_category($category) function in the /wp-includes/category-template.php file is broken for posts that aren’t cached.

The applicable code is:

$categories = get_object_term_cache($post->ID, 'category');

if ( empty($categories) )
{
	$categories = wp_get_object_terms($post->ID, 'category');
}
if ( array_key_exists($category, $categories) )
	return true;
else
	return false;

The problem is that get_object_term_cache() and wp_get_object_terms() return slightly different structures. Both functions returns an array of term objects, but the array returned by get_object_term_cache() is indexed by the term_id field, while the array returned from wp_get_object_terms() is indexed by a simple incrementing value based on the number of terms returned.

As an example, let’s suppose we have a post called “Test Post” with an id of 397. This post is in three categories whose term_id’s translate to: 13, 17, and 30.

Assuming the terms are cached, if we call get_object_term_cache(397, ‘category’) we get back the following:

Array
{
	[13] = object (term_id = 13, etc..)
	[17] = object (term_id = 17, etc..)
	[30] = object(term_id = 30, etc..)
}

But if the terms aren’t cached, and we fall to calling wp_get_object_terms() we get the following:

Array
{
	[0] = object (term_id = 13, etc..)
	[1] = object (term_id = 17, etc..)
	[2] = object(term_id = 30, etc..)
}

Thus, array_key_exists($category, $categories) will succeed if the cache returns, but fail if it doesn’t. This is even worse because it can also provide false positives. Working again with our “Test Post” example, calling in_category(2), will return a false positive if it can’t pull from cache.

I reported this as a bug but according to the traq, the earliest it’s going to get in is 2.7, and that’s if they even agree it’s a problem. In the meantime, you can fix the problem by adding the following function:

function parse_categories_for_category($category, $categories)
{
	if (empty($categories))
	{
		return false;
	}

	foreach($categories as $cat)
	{
		if ($cat->term_id == $category)
		{
			return true;
		}
	}
}

And changing the in_category() function to use it like so:

$categories = get_object_term_cache($post->ID, 'category');

if ( empty($categories) )
{
	$categories = wp_get_object_terms($post->ID, 'category');
}

return parse_categories_for_category($category, $categories);

The only problem being that every time you update Wordpress you’ll have to go back and re-edit the category-template.php file. Therefore, if you can get away with it I recommend just moving the whole thing out to your template’s functions.php file, giving it a new name, and replacing any calls in your template.

“Wordpress In_Category() Is Broken” was posted on June 30th 2008 at 4:51 pm in PHP, Wordpress.

Respond to “Wordpress In_Category() Is Broken”: