2
votes

I'm having the following problem. I have set up a Wordpress site with WooCommerce to serve a webshop with only books.

I have created some product attributes that are based on taxonomies like 'publisher' and 'author' (as multiple products can share an author or a publisher)

I would like to be able to sort my products not only on the Woocommerce default fields like 'title' and 'price' but also on these taxonomy fields. Say for example: order by Author ASC or order by publisher DESC

As far as I have discovered there is no way to do this with Wordpress core functions. Some say this is because it makes no sense to sort by taxonomy fields, but with the above example I can't understand why you don't want to sort by for example author.

I have played around with sortby meta_value, but this is just querying the direct postmeta, not the taxonomies.

I have knowledge of php, so any solutions involving additional code in my functions.php file will do.

1

1 Answers

1
votes

I found out a way how to solve this: https://gist.github.com/jayarnielsen/12f3a586900aa6759639

I slightly modified the code so it equals the way Woocommerce uses to sort by the system fields "title" and "price" which is adding a url query-param named "sortby" a value structured like this: "field"-"direction" So to sort by a product property called "pa_tax1" ascending you'll need to add to the url: sortby=pa_tax1-asc

add_filter('posts_clauses', 'posts_clauses_with_tax', 10, 2);
function posts_clauses_with_tax( $clauses, $wp_query ) {
    global $wpdb;

    // Array of taxonomies you want to sort on
    // in case of Woocommerce Properties, be sure to add the pa_ prefix
    $taxonomies = array('pa_tax1', 'pa_tax2', 'pa_tax3');

    // If no orderby query param is found, do nothing
    if( !isset($wp_query->query['orderby']) ) {
        return $clauses;
    }

    // Explode the orderby query-param
    $orderQuery = explode('-', $wp_query->query['orderby']);
    $orderBy = [];
    $orderBy['field'] = $orderQuery[0];
    $orderBy['direction'] = (isset($orderQuery[1])) ? strtoupper($orderQuery[1]) : 'ASC';

    // Only add clauses, if the sortby field is in our array
    if( in_array($orderBy['field'], $taxonomies) ) {
        $clauses['join'] .= "
            LEFT OUTER JOIN {$wpdb->term_relationships} AS rel2 ON {$wpdb->posts}.ID = rel2.object_id
            LEFT OUTER JOIN {$wpdb->term_taxonomy} AS tax2 ON rel2.term_taxonomy_id = tax2.term_taxonomy_id
            LEFT OUTER JOIN {$wpdb->terms} USING (term_id)
        ";

        $clauses['where'] .= " AND (taxonomy = '".$orderBy['field']."' OR taxonomy IS NULL)";
        $clauses['groupby'] = "rel2.object_id";
        $clauses['orderby']  = "GROUP_CONCAT({$wpdb->terms}.name ORDER BY name ASC) ";
        $clauses['orderby'] .= ( 'ASC' == strtoupper( $orderBy['direction'] ) ) ? 'ASC' : 'DESC';

        return $clauses;
    }
    else {
        return $clauses;
    }
}