Is there a downside of using wp_defer_term_counting?

The question:

I have a WordPress database with over 2 million posts. Whenever I insert a new post I have to call wp_set_object_terms which takes over two seconds to execute. I came across this post that recommends calling wp_defer_term_counting to skip the term counting.

Are there serious consequences to the functioning of WordPress if I use this approach?

Here’s the code from the post just in case the link goes dead:

function insert_many_posts(){
  $tasks = get_default_tasks(); 
  for ($tasks as $task){
     $post = array(
       'post_title' => $task[content],
       'post_author' => $current_user->ID,
       'post_content' => '',
       'post_type' => 'bpc_default_task',
       'post_status' => 'publish'
     $task_id = wp_insert_post( $post );

     if ( $task[category] )
        //Make sure we're passing an int as the term so it isn't mistaken for a slug
        wp_set_object_terms( $task_id, array( intval( $category ) ), 'bpc_category' );

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

Here are some thoughts on the issue, but please note that this is by no means a conclusive answer as there may be some things I have overlooked however this should give you an insight to the potential gotchas.

Yes, technically there could be consequences.

Where calling wp_defer_term_counting(true) becomes truly beneficial is when for instance you are performing a mass insertion to the database of posts and assigned terms to each object as part of the process.

In such a case you would do the following:

wp_defer_term_counting(true); //defer counting terms

//mass insertion or posts and assignment of terms here

wp_defer_term_counting(false); //count terms after completing business logic

Now in your case, if you are only inserting one post at a time, then deferring term counting will still benefit you however by not call wp_defer_term_counting(false) after your operation could leave you and or other parties involved with the request in a bind if you rely upon the term count for any other logic/processing, conditional or otherwise.

To explain further, let’s say you do the following:

Assume we have 3 terms within a taxonomy called product_cat, the IDs for those terms are 1 (term name A), 2 (term name B) and 3 (term name C) respectively.

Each of the above terms already has a term count of 5 (just for the example).

Then this happens…

wp_defer_term_counting(true); //defer counting terms

$post_id = wp_insert_post($data);

wp_set_object_terms($post_id, array(1, 2, 3), 'product_cat');

Then later in your logic you decide to fetch the term because you want to assess the amount of objects associated with that term and perform some other action based on the result.

So you do this…

$terms = get_the_terms($post_id, 'product_cat');

//let's just grab the first term object off the array of returned results
//for the sake of this example $terms[0] relates to term_id 1 (A)
echo $terms[0]->count; //result 5

//dump output of $terms above
array (
  0 => 
     'term_id' => 1,
     'name' => 'A',
     'slug' => 'a',
     'term_group' => 0,
     'term_taxonomy_id' => 1,
     'taxonomy' => 'product_cat',
     'description' => '',
     'parent' => 0,
     'count' => 5, //notice term count still equal to 5 instead of 6
     'filter' => 'raw',

In the case of our example, we said that term name A (term_id 1) already has 5 objects associated with it, in otherwords already has a term count of 5.

So we would expect the count parameter on the returned object above to be 6 but because you did not call wp_defer_term_counting(false) after your operation, the term counts were not updated for the terms applicable (term A, B or C).

Therefore that is the consequence of calling wp_defer_term_counting(true) without calling wp_defer_term_counting(false) after your operation.

Now the question is of course, does this effect you? What if you have no need to call get_the_terms or perform some action that retrieves the term where by you use the count value to perform some other operation? Well in that case great, no problem for you.

But… what if someone else is hooked onto set_object_terms action in the wp_set_object_terms() function and they are relying upon the term count being correct? Now you see where the consequences could arise.

Or what if after the request has terminated, another request is performed that retrieves a taxonomy term and makes use of the count property in their business logic? That could be a problem.

While it may sound far fetched that count values could be of much harm, we cannot assume the way such data will be used based on our own philosophy.

Also as mentioned in the alternate answer, the count as seen on the taxonomy list table will not be updated either.

In fact the only way to update term counts after you defer term counting and your request has ended is to manually call wp_update_term_count($terms, $taxonomy) or wait until someone adds a term for the given taxonomy either via the taxonomy UI or programmatically.

Food for thought.

Method 2

This should be relatively safe as an operation. This is deferring the counting of terms that appears on the Edit Taxonomy page. So, it doesn’t appear that there would be any serious consequences.

All methods was sourced from or, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment