WordPress get_the_terms by term order [bug fix]

WordPress 4.7 introduced a change to the default term order for get_the_terms()

In earlier versions of WordPress, get_the_terms( $post_id, $taxonomy_name) returned the terms in the same order in which the terms were added to the post.  But, starting with WordPress 4.7, the terms are being returned in alphabetical order by term slug.  (Note:  This is for non-hierarchical terms.  I’m not sure if this is true for hierarchical  terms.)

As you may know, get_the_terms is a convenient function for getting the terms for a specific post ID.  It is used by many plugins, and can be used for built in taxonomies like categories and post_tag or for custom taxonomies.

get_the_terms is a cached function, meaning that WordPress caches the results, so that if it’s called repeatedly, it doesn’t have to do a database query each time.  So it’s a good function to use for performance reasons.  It’s unlikely to slow your site down.  However, it doesn’t accept an orderby argument to specify how to order the results.

So, there are 3 ways to fix this problem.

Option #1: get_terms_orderby Filter

You can add a filter on get_terms_orderby

This filter allows you to alter the $orderby part of the SQL query that WordPress uses to get the terms from the database.

Assuming that author is the name of your custom taxonomy, you can use this function:

function wpcf_author_filter_terms_order( $orderby, $query_vars, $taxonomies ) {
    if ( ! empty( $query_vars['object_ids'] )
        && ! empty( $taxonomies[0] )
        && ( 1 === count( $taxonomies ) )
        && 'author' === $taxonomies[0] )
        {
            $orderby = 'tr.term_order';
        }
    return $orderby;
}

add_filter( 'get_terms_orderby', 'wpcf_author_filter_terms_order', 10, 3 );

By the way, the above code will fix this Co-Authors Plus plugin ordering issue. The Co-Authors Plus plugin creates a taxonomy named author and uses get_the_terms. This is actually where I first saw this bug, but since it is a result of a WordPress core change, I’m sure that there are many other WordPress themes and plugins in the wild with this same issue.

Keep reading if you’re curious, as this is a solution, but not the only solution.

Option #2: use wp_get_post_terms()

Alternatively, you can simply not use get_the_terms() but instead use wp_get_post_terms() which accepts a list of overrides, which means that you can specify the orderby in the third parameter.

For example,

Instead of this:

$terms = get_the_terms( $post_id, $taxonomy );

Write this:

$terms = wp_get_post_terms( $post_id, $taxonomy, array( 'orderby' => 'term_order' ) );

The reason I prefer option #1, even though it’s more complicated, is that wp_get_post_terms is an uncached function.  On a low traffic site that’s using full page caching, it may make no difference.  But if you have a site with a lot of logged in users where caching isn’t happening, I’d recommend using a more performant method.

Option #3: use wp_get_object_terms

Similar to option #2, with the same warning about it being an uncached function.

I’m running out of steam to elaborate, and I think that the codex entry on wp_get_object_terms does a pretty good just of explaining how to use this function.

Just remember my warning about no caching.  If you’d like to see how to implement some DIY caching, here’s an example I wrote.  Adding your own caching is something you can do anywhere you want in theme and plugin development.  It’s not really hard to do once you figure out the pattern.  The tricky part is to remember to delete the transients when needed — for this case, you’ll want to delete them on save_post and delete_post, which you can see how to do in my example.  If you don’t want to worry about when to delete them, you could just create short transients — like one minute or fifteen minute ones.  Having the query run every minute is way better than having it run for every page load, which could be many times per second.   For more info, check out the WordPress Transients API.  It goes into quite some detail about how to use them for caching data.

WordPress has_post_thumbnail() not working – How to fix the phantom featured image issue

I’ve spent another week working on programming custom WordPress themes, and I’d like to share a fix for the “phantom image bug.”  I just made that up.  It’s not a real WordPress core bug. But it is a real life programming problem that you might encounter, especially if you’re working with migrated content, or for some reason your database has weirdness.  (Funky database, eh?)

The typical way to check for whether a WordPress post has a featured image is to use the function has_post_thumbnail()  This function calls get_post_thumbnail_id(), which queries the database for the post meta field _thumbnail_id

If the field _thumbnail_id is not empty, has_post_thumbnail() will return true.

has_post_thumbnail() does not actually check to see whether _thumbnail_id is an actual ID of an object that exists in your database.  So, on the rare occasion, has_post_thumbnail() will return true when the post thumbnail does not actually exist.

Assuming that you’re in The Loop, you can fix this problem, by replacing:

if ( has_post_thumbnail() ) {

     // do a bunch of stuff

}

with

$featured_image_url = wp_get_attachment_url( get_post_thumbnail_id( get_the_ID() ) );

if  ( ! empty( $featured_image_url ) ) {

     // do a bunch of stuff

}

This checks to see if the actual image URL exists. In my particular case, this solved the problem.  There’s still the chance that the URL points to a file that doesn’t exist.  If that’s the issue, then this fix won’t work, and you have bigger problems.  But in that case, you’re probably seeing a broken image icon, rather than just a blank spot.

Fortunate for me, this fixed the issue with has_post_thumbnail coming back erroneously true.  Since it was returning true, an empty HTML <DIV></DIV> was being output, which was causing issues with the website’s layout.  Actually, in my case, there was also a caption appearing because there was logic written into the template that said to display a custom caption.  So it was extra ugly.

Hopefully, I’ve helped someone out here.  Probably my future self will enjoy finding this code snippet someday…

Debugging WordPress Filters, the_content Filter, and side effects

Debugging WordPress can be difficult.  That’s an understatement.  I’m sure WordPress is not unique in this difficulty, because as software systems develop and increase in complexity, layers of abstraction increase, and larger and larger parts are like black holes.  The developer doesn’t really know what’s going on, doesn’t really want to spend hours digging through the black hole, so she stops the code at key execution points to see what’s going on, to look inside of variables, to prove that the code actually stepped through those lines…

But what do you do when you can see with the debugger that the code is executing but nothing appears on the screen?   This sounds like it could be a good interview question about debugging.

The lesson I’ve learned today, is don’t be afraid of looking at a call stack!  It should be your first, not last, go-to clue.  Generate a call stack, dig through it, and get to the bottom of it…

This will give you a call stack as an associative array:

$my_callstack = debug_backtrace();

Or you could trigger an error which will give you a stack call if you have Xdebug turned on.

So, really, how could code execute but not appear on the screen?

We’re going to assume that it’s not a CSS display:none attribute or javascript removing an HTML node.  We’re going to address a pure PHP cause for code to appear executed but yet not appear on the screen.  And this is not something simple like forgetting to echo.  (Yeah, check that you echoed that statement!  Maybe the function you are calling returns the data instead of outputting it?)

One PHP cause could be that output buffering is turned on.  Which is something you would easily see in a call stack.

But a more likely WordPress cause is that the code is attached to a filter or a hook and is being called in a different context than you expected.

In today’s bug, I had attached a callable function to the_content filter.  The function I attached altered a variable that was used to keep track of some data (to be precise, it was storing post_ids to prevent their re-use).

I thought that the_content filter was only called when the_content() function was called, so I thought it would only be called once with each page load.  But using Xdebug and PhpStorm to step through the code, it was evident that my function was being called 5 times with each page load! This was causing huge logic (and data) errors, not to mention performance issues.  These errors were hard to reproduce so it created bugs that would pop up randomly.  So I googled phrases like “wordpress the_content filter being called multiple times”.

But, Google wasn’t any help.  The more I learn about any given topic, the less helpful Google results become.

I guess that makes sense.

Anyway, I found out that a Jetpack plugin was calling wp_trim_excerpt, which applies the_content filter and my code was executing but not appearing on the screen, because, in a sense, the_content’s context was related to the post excerpt.  Wow, that’s a mouthful!  So lesson learned, the_context gets filtered when you’re doing stuff with the_excerpt.

I don’t even know what Jetpack was doing with that code.  But in any case, my code was running at the wrong time, because of how WordPress works.  The context was wrong in 2 ways.  First, the plugin, and not my theme, was causing my code to run.  And second, it was working with the excerpt, not the content.   Now, the first fact, is often desirable.  You inject code with filters and action hooks because you want your code to effect WordPress core, and other WordPress themes and plugins that you didn’t write.  Yeah, kind of like spaghetti code, right?  But being able to modify other code is crucial to how WordPress works… So what makes it great also makes it difficult.  Sounds kind of like Ruby Gems?  Intertwine enough stuff and something is going to go haywire.

So, how many other plugins call functions that deal with a post excerpt or post content which causes the_content filter to run?  Probably pretty common stuff.

Be Really Careful with using the_content filter for anything that might have side effects

The Solution

function do_something_special_with_content() {
    add_filter('the_content', 'my_special_function', 10);
    the_content();
    remove_filter('the_content', 'my_special_function', 10);
}

my_special_function( $content ) {
   // do something
   return $content;
}

If you write the code that way, you’ve limited the scope of when your function will run.  That’s the goal, right?

I don’t think WordPress Core really uses “context” as a programming concept, but you’ll see the idea of a context come up often in other frameworks.  (I’m looking at you, Android.)  It helps with figuring out what should be done when. Maybe WordPress needs contexts.  Or maybe that would just make it even more confusing…

Off to more WordPress adventures.

More on Debugging WordPress

Debugging in WordPress – WP_DEBUG, WP_DEBUG_LOG, and more.