Sorting custom taxonomy term page in WordPress

I have created a custom post type for a product with two custom taxonomies, “colour” and “style”. Products are tagged in both of these. When you go to the taxonomy term page it works as it should i.e. if you go to /colour/blue it lists all blue products.

What I want to happen is when you go to /colour/blue is lists all blue products BUT groups them by the second taxonomy “style” showing the first three products with a read more link.

Read More

So

Blue > Product Style 1

  • Product 1
  • Product 2
  • Product 3

See More..

Blue > Product Style 2

  • Product 3
  • Product 4
  • Product 5

See More..

Does anyone know if this is possible?

Current code is this, I’ve created a taxonomy template for the term taxonomy-colour.php

<?php get_header(); ?>

<main role="main" class="blinds">

    <h1 class="main-product-title">Products</h1>

    <!-- section -->
    <section class="main-product-content">

        <h2><?php $term = get_term_by( 'slug', get_query_var( 'term' ), get_query_var( 'taxonomy' ) ); echo $term->name; ?></h2>

        <?php if (have_posts()): while (have_posts()) : the_post(); ?>

            <!-- article -->
            <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
                <!-- post image -->
                <?php if ( has_post_thumbnail()) : // Check if thumbnail exists ?>

                        <?php the_post_thumbnail(array(720,400)); // Declare pixel size you need inside the array ?>

                <?php endif; ?>
                <!-- /post thumbnail -->

                <!-- post title -->
                <h4><a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>"><?php the_title(); ?></a></h4>
                <!-- /post title -->

                <p><a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>">View ></a></p>

            </article>

            <!-- /article -->

        <?php endwhile; ?>

        <?php else: ?>

            <!-- article -->
            <article>
                <h2><?php _e( 'Sorry, nothing to display.', 'html5blank' ); ?></h2>
            </article>
            <!-- /article -->

        <?php endif; ?>

        <?php get_template_part('pagination'); ?>

    </section>
    <!-- /section -->

    <div class="sidebar-wrapper">
        <?php if(!function_exists('dynamic_sidebar') || !dynamic_sidebar('product-sidebar')) ?>
    </div>

</main>

Related posts

2 comments

  1. As stated in comments, you need to use usort() on the the_posts filter to sort your posts according to needs.

    You can try the following: (NOTE: The following code is untested and requires PHP 5.4+ due to array dereferencing)

    add_filter( 'the_posts', function ( $posts, $q ) 
    {
        if (    $q->is_main_query() // Target only the main query
              && $q->is_tax( 'colour' ) // Only target the colour taxonomy term pages
        ) {
            /**
             * There is a bug in usort that will most probably never get fixed. In some instances
             * the following PHP warning is displayed 
    
             * usort(): Array was modified by the user comparison function
             * @see https://bugs.php.net/bug.php?id=50688
    
             * The only workaround is to suppress the error reporting
             * by using the @ sign before usort
             */      
            @usort( $posts, function ( $a, $b )
            {
                // Use term name for sorting. We will sort by style taxonomy term
                $array_a = get_the_terms( $a->ID, 'style' );
                $array_b = get_the_terms( $b->ID, 'style' );
    
                // Add protection if posts don't have any terms, add them last in queue
                if ( empty( $array_a ) || is_wp_error( $array_a ) ) {
                    $array_a = 'zzz'; // Make sure to add posts without terms last
                } else {
                    $array_a = $array_a[0]->name;
                }
    
                // Add protection if posts don't have any terms, add them last in queue
                if ( empty( $array_b ) || is_wp_error( $array_b ) ) {
                    $array_b = 'zzz'; // Make sure to add posts without terms last
                } else {
                    $array_b = $array_b[0]->name;
                }
    
                /**
                 * Sort by term name, if term name is the same sort by post date
                 * You can adjust this to sort by post title or any other WP_Post property_exists
                 */
                if ( $array_a != $array_b ) { 
                    // Choose the one sorting order that fits your needs
                    return strcasecmp( $array_a, $array_b ); // Sort term alphabetical ASC 
                    //return strcasecmp( $array_b, $array_a ); // Sort term alphabetical DESC
                } else {
                    return $a->post_date < $b->post_date; // Not sure about the comparitor, also try >
                }
            });
        }
        return $posts;
    }, 10, 2 ); 
    
  2. The first thing to do is to get the available style terms for your current taxonomy term. For that you can get all the posts IDs of your current taxonomy then get the style terms from them using wp_get_object_terms. Then you loop through them, query three posts that have both of those taxonomy terms (colour and style).

    Here is an example that you can use for your case:

    <?php
    // get the term...
    $term = get_term_by( 'slug', get_query_var( 'term' ), get_query_var( 'taxonomy' ) );
    
    // get all posts from this term and store the IDs
    $term_posts = get_posts(array('tax_query' => array(array(
        'taxonomy' => get_query_var('taxonomy'),
        'terms' => $term->ID
    ))));
    $term_posts_IDs = array();
    foreach ($term_posts as $term_post) {
        $term_posts_IDs[] = $term_post->ID;
    }
    
    // get the available styles from this set of posts
    $styles = wp_get_object_terms($term_posts_IDs, 'style');
    
    ?>
    <h2><?php echo $term->name; ?></h2>
    <?php 
    if(!empty($styles)): // styles are availables for this term
        foreach($styles as $style):
            ?>
            <h3><?php echo $term->name; ?> &gt; <?php echo $style->name; ?></h3>
            <?php
            // get the first three products with colour + style
            $tax_posts = get_posts(array(
                'posts_per_page' => 3,
                'tax_query' => array(
                    'relation' => 'AND',
                    array(
                        'taxonomy' => get_query_var('taxonomy'),
                        'terms' => $term->ID
                    ),
                    array(
                        'taxonomy' => 'style',
                        'terms' => $style->ID
                    )
                )
            ));
            ?>
            <ul>
            <?php foreach($tax_posts as $tax_post): ?>
                <li><?php echo $tax_post->post_title; ?></li>
            <?php endforeach; ?>
            </ul>
            <!-- ... link to your style taxonomy template here ... -->
        <?pgpp endforeach ; ?>
    <?php else : ?>
        <!-- ... default behaviour ... -->
    <?php endif; ?>
    

    You’ll have to build your read more link by sending the style term and the colour term to your style taxonomy template.

Comments are closed.