Paginated Taxonomy Term Archive including one post per term

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(); ?><!-- 
        --><div>
            <a href="<?php esc_url( the_permalink() ); ?>">
                <?php the_post_thumbnail ('medium'); ?>
                <h2><?php echo $term->name; ?></h2>
            </a>
        </div><?php
        endwhile; endif;

    endforeach;

endforeach;

Related posts

2 comments

  1. 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.

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

    then…

    $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();
        ?>
        <div>
        <a href="<?php esc_url( the_permalink() ); ?>">
        <?php the_post_thumbnail('medium'); ?>
        <h4><?php echo $term->name; ?></h4>
        </a>
        </div>
        <?php
        endwhile; endif;
    
      endforeach;
    
    } }
    

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

Comments are closed.