I’ve hit another small rock in my current project!

I’m trying to list (and link) to the archive page for the top 4 most used terms for a custom post type. I have this;


..which is along the right lines but I can’t seem to find a way to pin this down to a specific post type. There is one taxonomy called “trade” across 6 custom post types on the website, I need to find out the top 4 for each one. I started looking through the tables and found I could probably query by the post type, and order by the “count” column in the wp_term_taxonomy table. However, that is really pushing my limits with MySQL because I don’t know an efficient way to write what seems to be such a complex query.

I’ve been on this for 4hrs or so now, I don’t think the penny is going to down without some help!

Thanks for taking a look...

2 Answers 2


I if were you, I'd have two options in my mind. Both hinge on the fact thsi is an inherently expensive computation and no mysql trickery will reduce the load with the data you have.


Option 1, do it the expensive way and store the data for a rainy day

You're going to have to swallow the cost of calculating this, but you don't have to do it over and over again. Calculate it the long expensive way and save the post IDs in a transient with a long expiration time. You'll have a one time hit followed by it running super fast until the transient runs out.

For bonus points, do the calculation in a wp-cron task once a day and set the expiration time to two days,

Option 2, create helper data

You have 1 taxonomy and 6 post types occupying it. To get around this, create another taxonomy, a hidden taxonomy with no GUI. This taxonomy will only be attached to your desired post type.

Then, hook into the term creation/deletion/assignment hooks, and use them to duplicate the taxonomy data but only for that post type. That way when you want to do your list, you query the second hidden taxonomy, which acts as a cache of sorts. All the hard work of figuring out which term has how many is done as you make the changes

Just because you don't know how to handle the data you have performantly, doesn't mean there is a solution, but changing the data made available to you can sometimes make a world of difference, and that doesn't always mean adding more cache.

Here's a crude example on cloning a taxonomy:

class Clone_Taxonomy {
    public $from = '';
    public $to = '';
    public function __construct($from, $to){
        $this->from = $from;
        $this->to = $to;
        add_action( 'set_object_terms', array(&$this,'sync_set_object_terms'),100,6);

    public function sync_set_object_terms($object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids){
        if($taxonomy == $this->from){
            // duplicate to ovum_research_authors taxonomy
            //$terms2 = array();
            $r = wp_set_object_terms( $object_id, $terms, $this->to, $append );
                // things failed for whatever reason


$clone_tax = new Clone_Taxonomy('taxonomy1','taxonomy2');

Place a second check after checking the taxonomy to figure out which post type it is and if the post type matches, clone the term, else don't.

  • I have attached a “hidden” taxonomy to one of the custom post types for testing. I’m now trying to structure a WP_Query to get posts from both taxonomies (which I expected to be easy) but I can’t even get the basic one to work! See this example;
    – Dan
    Apr 15, 2012 at 15:18
  • $args = array( 'post_type' => 'pt_plumbers', 'tax_query'=>array( 'taxonomy'=>'trade', 'field'=>'slug', 'term'=>'boiler-installation' ) );
    – Dan
    Apr 15, 2012 at 15:18
  • make your taxonomy public for dev purposes and test that the automatic addition and deletion of terms is working, and that those terms are being assigned and unassigned from posts so they match the real taxonomy. It's not enough to simply register a second taxonomy hidden away
    – Tom J Nowell
    Apr 15, 2012 at 16:53
  • Hook into created_term, delete_term, edited_term to create the secondary taxonomy terms and keep them updated when the primary ones are created/edited/deleted, and then use the set_object_terms so that when a post is assigned terms in the primary taxonomy, it's also assigned terms of the same slug in the secondary taxonomy ( if it's of that post type )
    – Tom J Nowell
    Apr 15, 2012 at 16:58
  • When you do your queries, query the secondary helper/hidden taxonomy, not the primary public one. The hidden one should hold the same data ( but only for the post type you want to query )
    – Tom J Nowell
    Apr 15, 2012 at 16:58

So, after much time spent on this I seem to have found a method that works for me. I took Tom’s cloning idea and his advice and made a second taxonomy that sits our of view but can still be queried.

This is me registering the unique taxonomies in my plugin file using a loop linked to an array with various bits of data;

foreach($all_post_types as $trade){
    $cpt = $trade['post_type_name'];
    $tax_args = array(
       'query_var' => $cpt,
       'public' => 0,
       'labels' => array( // set up the labels for this 
          'name' => $trade['plural'].' Hidden'

Once that’s made I added this is my functions.php file so I could add the additional data to the new taxonomies by copying (or cloning as Tom Suggested) the terms from the main taxonomy. There is probably a more efficient way of writing some of this, but this seems to be as far as my PHP goes right now...

function add_hidden_tax($post_ID) {
global $wpdb;
$post_type = get_post_type($post_ID);
//print_r( $post_type );
if($post_type == 'pt_builders' 
|| $post_type == 'pt_carpenters'
|| $post_type == 'pt_decorators'
|| $post_type == 'pt_electricians'
|| $post_type == 'pt_gardeners'
|| $post_type == 'pt_plumbers'
    $current_terms = get_the_terms($post_ID,'trade');
    //make an array to hold the terms to be cloned...
    $to_be_cloned = array();
        foreach($current_terms as $key){
            $to_be_cloned[] =  $key->name;  
    wp_set_object_terms($post_ID,$to_be_cloned,$post_type.'_tax',0);//the false statement overriddes the current terms with each save, instead of just adding to them.  
add_action('save_post', 'add_hidden_tax’);

This works well for me as the terms are automatically written AND updated with any custom post publish or revision.

Finally I can query my top 4 terms and link to the archive pages;

$term_args = array(
                        'number' => 4,
                        'orderby' => 'count',
                        'order' => 'DESC'
                        $terms = get_terms(array('pt_carpenters_tax'),$term_args);
                        if($terms != ''){
                            echo '<ul class="green_arrows">';
                            foreach($terms as $skill){
                                echo '<li><a href="/trade/'. $skill->slug .'">'. $skill->name .'</a></li>';
                            echo '</ul>';

Perhaps I could do this a better way, but whatever - it works :D

Many thanks to Tom for his repeated input.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.