Support » Plugins and Hacks » Hacks » Order & filter by multiple taxonomies & terms

  • Hello,

    I’m currently developing a custom plugin for a website that I’m currently building. It’s an employee browser for a company website. The way it currently works is something like this:

    – It creates a custom post type: person
    – It adds several custom taxonomies to sort people: industry (“tag”, eg. IT, media, advertisement), position (“category”, eg. CEO, CTO, developer), languages (“tag”, eg. english, spanish, french), office (“category”, a city where the person works)
    – There’s archive page with all employees & a single employee.

    Here’s the problem:

    In the archive there’s an option to sort the employees either by their name (post title) or position (custom taxonomy) starting from higher ups and ending at lower level employess (eg. CEO first, then CTO etc)

    Currently this is done so that there is a custom orderby-parameter for post queries, (orderby=position). Like this:

    add_filter( 'posts_clauses', 'mc_people_order_position', 10, 2 );
    function mc_people_order_position( $clauses, $wp_query ) {
        global $wpdb;
        if( isset( $wp_query->query['orderby'] ) && 'position' == $wp_query->query['orderby'] ) {
            $clauses['join'] .= "LEFT OUTER JOIN {$wpdb->term_relationships} ON {$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id
                                 LEFT OUTER JOIN {$wpdb->term_taxonomy} USING (term_taxonomy_id)
                                 LEFT OUTER JOIN {$wpdb->terms} USING (term_id)";
            $clauses['where'] .= " AND (taxonomy = 'position' OR taxonomy IS NULL)";
            $clauses['groupby'] = "object_id";
            $clauses['orderby'] = " FIELD({$wpdb->terms}.slug, 'janitor', 'developer', 'CTO', 'COO', 'CEO') DESC, {$wpdb->terms}.slug ";
            $clauses['orderby'] .= ( 'ASC' == strtoupper( $wp_query->get( 'order' ) ) ) ? 'ASC' : 'DESC';
        return $clauses;

    This produces an SQL query something like this:

    FROM wp_posts
    LEFT OUTER JOIN wp_term_relationships ON wp_posts.ID = wp_term_relationships.object_id
    LEFT OUTER JOIN wp_term_taxonomy USING (term_taxonomy_id)
    LEFT OUTER JOIN wp_terms USING (term_id)
    WHERE 1=1
    AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 1 AND wp_posts.post_status = 'private')
    AND (wp_term_taxonomy.taxonomy = 'position')
    GROUP BY object_id
    ORDER BY FIELD(wp_terms.slug, 'janitor', 'developer', 'CTO', 'COO', 'CEO') DESC,
    wp_terms.slug ASC LIMIT 0, 21

    This works fine when there is no other taxonomy queries. However if I’d want to filter only employees in a certain specific industry for example, and also order by position this will break.

    At the moment I’m completely stuck with this, so I’m turning to the community with this. Any ideas how to either improve my current code to allow filtering by another taxonomy or any suggestions for a completely new way to do this?

    ps. I also tried tax_query (like in here but I couldn’t figure out if that can be even used to order by terms

Viewing 1 replies (of 1 total)
  • I guess I managed to solve this. Here’s the updated solution that seems to be working nicely:

    $clauses['join'] .= " INNER JOIN (SELECT {$wpdb->terms}.term_id, {$wpdb->terms}.slug, {$wpdb->term_relationships}.object_id
                        FROM {$wpdb->term_taxonomy}, {$wpdb->terms}, {$wpdb->term_relationships}
                        WHERE {$wpdb->term_taxonomy}.taxonomy = 'position'
                        AND {$wpdb->term_taxonomy}.term_id = {$wpdb->terms}.term_id
                        AND {$wpdb->term_taxonomy}.term_taxonomy_id = {$wpdb->term_relationships}.term_taxonomy_id
                        GROUP BY {$wpdb->term_relationships}.object_id
                        ) as person_position_relationship ON person_position_relationship.object_id = {$wpdb->posts}.ID";
    $clauses['groupby'] = "person_position_relationship.object_id";
    $clauses['orderby'] = " FIELD(person_position_relationship.slug, 'janitor', 'developer', 'CTO', 'COO', 'CEO') ";
    $clauses['orderby'] .= ( 'ASC' == strtoupper( $wp_query->get( 'order' ) ) ) ? 'DESC' : 'ASC';
    $clauses['orderby'] .= ", person_position_relationship.slug ";
    $clauses['orderby'] .= ( 'ASC' == strtoupper( $wp_query->get( 'order' ) ) ) ? 'ASC' : 'DESC';

    When using this with posts_clauses filter, you can probably do anything you want with other taxonomies and this only show posts with “position” taxonomy and order by them. Seems to work on my case, but probably need more testing.

Viewing 1 replies (of 1 total)
  • The topic ‘Order & filter by multiple taxonomies & terms’ is closed to new replies.