I have a custom query which gets all the custom taxonomies for the custom post type and displays the latest post in each. At the moment it pulls in all the taxonomies. Is there a way I can limit the number of taxonomies displayed to a set number per page and paginate them?

// Set post type
$post_type = 'prints';

// Get all the taxonomies for this post type
$taxonomies = get_object_taxonomies( (object) array( 'post_type' => $post_type ) );

foreach( $taxonomies as $taxonomy ) : 

    // Get every "category" (term) in this taxonomy to get the respective posts
    $terms = get_terms( $taxonomy );

    foreach( $terms as $term ) : 

       // Query to show first post in taxonomy
        $posts = new WP_Query( "taxonomy=$taxonomy&term=$term->slug&posts_per_page=1" );

        if( $posts->have_posts() ): while( $posts->have_posts() ) : $posts->the_post(); ?><!-- 
            <a href="<?php esc_url( the_permalink() ); ?>">
                <?php the_post_thumbnail ('medium'); ?>
                <h2><?php echo $term->name; ?></h2>
        endwhile; endif;



2 Answers 2


As discussed in chat and as @Rarst already told you, there's no default WordPress way to accomplish

Archive of multiple taxonomies and all their terms

In fact there's no way to accomplish

Archive of single taxonomy and all its terms

in WordPress. Simply because WordPress doesn't do that - without custom SQL queries.

But there're some things you can do to simplify your approach.

As you stated the following in chat, I'll get a little bit more into detail:

In essence what I'm trying to create is an archive of categories. So for each category (custom taxonomy) I want to show a featured image from one of the posts, and the title of the category.

$taxonomies = get_object_taxonomies( get_post_type_object( 'prints' )->name, 'names' );

Note: If you set the second argument of get_object_taxonomies() to objects, you'll get the complete objects for later usage.

And get_terms() takes an array of taxonomies as first argument. So you can do the following to get all terms of all your taxonomies that are assigned to the prints CPT.

Note: If you use the second argument above and got the full objects, use wp_list_pluck() to extract the taxonomy names.

$terms = get_terms( $taxonomies, array() );

If you need to influence the order, you can use the orderby (default: name) and order (default: ASCendending) arguments in the second argument/array of the function call or use a filter:

apply_filters( 'get_terms_orderby', $orderby, $args );

As stated in the beginning, there's no default way to accomplish your target of getting a single post along the terms query. But you can still build your own SQL query. And there's a filter for that:

apply_filters( 'terms_clauses', compact( $pieces ), $taxonomies, $args );

So you can jump in, alter the query, include the posts table, etc.

add_action( 'terms_clauses', 'wpse114800_get_terms_with_posts', 20, 3 );
function wpse114800_get_terms_with_posts( $clauses, $taxonomies, $args )
    // Alter the $clauses

    return $clauses;

The result of above filter callback will alter the query build by WordPress. The default in core looks like this:

"SELECT $fields FROM $wpdb->terms AS t $join WHERE $where $orderby $order $limits"

The JOIN clause is built like the following:

"INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id"

What you'll have to do now is to JOIN the $wpdb->term_relationship likely with something like the following:

INNER JOIN $wpdb->term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id

Borrowed from wp_get_object_terms() in core.

The WHERE clause will then look likely like this:

$wpdb->prepare( "WHERE tt.taxonomy IN (%s)", "'".implode( "', '", $taxonomies)."'" )

From here on you should be able to JOIN the $wpdb->posts table on the ID and query one post per taxonomy term as well.

I'd highly recommend to somehow cache the result, add it as transient or something similar as the query can get quite slow.

  • Thanks for such a detailed response, very helpful. I followed everything perfectly up to altering the query in the filter callback, but then I'm a little lost. Could you post the full code for the filter callback at the end? I have no experience with this level of customisation. Is this last bit SQL? Sep 20, 2013 at 14:03
  • I can't, as I currently don't have a setup where I could test that. And building one would take me approx. one hour and would - including the final product/SQL query - highly exceed the amount of time I'm willing to spend on a free support route.
    – kaiser
    Sep 20, 2013 at 14:07
  • Oh ok, I had no idea. I naively thought what you posted was more or less it! I'll ask around to see if I can find some help with taking this further. Thanks so much for your help so far. Sep 20, 2013 at 14:13
  • @jasonbradberry n/p. Just var_dump() inside the callback I showed above, then maybe post your SQL question on SO.
    – kaiser
    Sep 20, 2013 at 14:21

To make pagination work you shoul pass a paged query var. Maybe in a custom page template.


$tax_per_page = 2;

$post_type = 'print';

$taxonomies = get_object_taxonomies( $post_type );

$page = get_query_var('paged') > 1 ? get_query_var('paged')-1 : 0;

$splitted_taxes = array_chunk($taxonomies, $tax_per_page);

$taxonomies_on_page = isset($splitted_taxes[$page]) ? $splitted_taxes[$page] : false;

if ($taxonomies_on_page) { foreach( $taxonomies_on_page as $taxonomy ) {

  $terms = get_terms( $taxonomy );

  foreach( $terms as $term ) : 

    $posts = new WP_Query( "taxonomy=$taxonomy&term=$term->slug&posts_per_page=1" );

    if( $posts->have_posts() ): while( $posts->have_posts() ) : $posts->the_post();
    <a href="<?php esc_url( the_permalink() ); ?>">
    <?php the_post_thumbnail('medium'); ?>
    <h4><?php echo $term->name; ?></h4>
    endwhile; endif;


} }

Note: code posted above paginate taxonomies not terms, because you ask for that in question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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