0

I have been told here that having my data saved as metadata is creating slow queries.

I'm starting to convert all data used to sort my posts to taxonomy data. I've converted all the data stored in 'wpcf-release-year' to a taxonomy called 'release-year' and have created terms for every year.

Now I'd like to sort posts by release-year. I can't seem to find a way to get this to work with my new taxonomy. Here's my old code

$my_query_args = array( 
    'posts_per_page' => -1,
    'post_type' => 'release',
    'meta_key'       => 'wpcf-release-year', //I want this to be my taxonomy instead of the meta data
    'orderby'        => array(
        'meta_value_num' => 'ASC',
        'title' => 'ASC',
    ),               
    'tax_query' => $release_type_query,
);

How can I refer to the taxonomy term instead of the meta-key in this code? I've tried using the name meta_key => 'release-year' but that made all the posts dissapear. Do I need to add a new tax query? I'm not sure what to do. Thanks!

2
  • 1
    Did you try actually using orderby as just a string? 'orderby' => 'meta_value_num' . The ASC is actually a separate arg value order.
    – rudtek
    Commented Oct 4, 2022 at 16:18
  • i tried both 'orderby' => 'release-year' and meta_key' => 'release-year', 'orderby' => 'meta_value_num'. The first orders them by title. The second shows no results.
    – DJZEEGLER
    Commented Oct 4, 2022 at 16:24

3 Answers 3

2

You can't order by taxonomy terms, the very concept breaks down when you try to handle posts that have multiple terms in a taxonomy. You may know that only 1 term will ever be selected but WP_Query isn't built that way.

Instead, keep your taxonomy so that you retain all the performance/theming/Admin UI benefits, but also save the information in post meta so that you can sort. This way you get the best of both worlds, and you can automate updating the post meta when the terms change. This also lets you use post meta sorting with tax_query.

While this does lead to duplication the cost is minimal, and the performance gains are very real. You may even decide to store data in the future that's only ever used to improve performance, e.g. intermediate pre-calculated data, or buckets ( e.g. storing a price in post meta, but putting the posts into predefined buckets such as $100-$150 )

4
  • So I'm reading that the slowest part of the meta queries will be where the query is looking for the post ID in metadata. If I convert all of these metadata fields to taxonomies, I will have a vast improvement in my system. However, I can leave metadata like 'year' as metadata, since sorting is what metadata is used for. Is this correct?
    – DJZEEGLER
    Commented Oct 4, 2022 at 18:35
  • 1
    you can store it as both, query the taxonomy term, sort by the meta. Think of it like a filing cabinet, post meta is like searching every single file int he cabinet one by one until you find what you wanted everytime. Taxonomies are when you've grouped similar files together under dividers with labels so you can go straight o the section and only have to search 10 files instead of 1000. You wouldn't put all the files information on the divider because that makes dividers slow and useless, and you wouldn't organise files in a way that forced you to read them all
    – Tom J Nowell
    Commented Oct 5, 2022 at 11:20
  • Ok, got it. Taxonomies make queries smaller by automatically filtering out irrelevant results. If I choose wise places to use taxonomies, I can dramatically shrink the amount of information the queries on my site need, and let them be filtered by their metatdata like intended.
    – DJZEEGLER
    Commented Oct 5, 2022 at 20:44
  • 1
    Not smaller, just faster, the term/taxonomy tables are structured in a way that makes searches/filters/grouping fast and scalable. Meta tables are structured in a way that makes fetches fast, but not searches. Fetching the terms of a post is fast but not quite as fast as post meta, and post meta can store larger data
    – Tom J Nowell
    Commented Oct 7, 2022 at 12:19
1

There's a lot to unpack here so I'm going to give it my best shot.

Your basic code I would change to this:

$my_query_args = array( 
    'posts_per_page' => -1,
    'post_type' => 'release',
    'meta_key'       => 'release-year',
    'orderby'        => 'meta_value_num',
    'order'          => 'ASC',              
    'tax_query' => $release_type_query,
);

I changed your meta key to your custom taxonomy release-year. Additionally I stripped your orderby arg to just sort by numbers.

This will ONLY work if all your terms in release-year are actually all numbers.

This being said...what you're doing doesn't seem to make sense. I think using post meta is a MUCH better option. If the above doesn't work Check this question: Using wp_query is it possible to orderby taxonomy?

1
  • post meta may be great when viewing a release post, but not when filtering searching/grouping. Post meta is fastest when you know in advance what the post ID is going to be, which makes it super fast. But if you try to do the inverse the performance scales very poorly, hence taxonomies
    – Tom J Nowell
    Commented Oct 4, 2022 at 17:19
1

Actually, it IS possible to get the main query to sort by taxonomy... it just isn't really pretty. First and foremost: this will work by manipulating the query that is executed by WordPress. If you don't know your way around the WordPress database, i would probably not recommend doing this because you could f up your website. But let's get into the meat of things, okay?

Step 1: Add the Filter

First and foremost, i am assuming that you want to order the "releases" on the "release"-Post-Type-Archive.

To change the SQL-Query performed by WordPress directly, you can use the filter "posts_clauses", which you can get more information on here.

To add the filter only on the archive of the custom post type, we will use the pre_get_posts filter like this:

add_action('pre_get_posts','setup_my_query_interception');

function setup_my_query_interception($query){
    if( !is_admin() && $query->is_post_type_archive( 'release' ) && $query->is_main_query() ){
     add_filter( 'posts_clauses', 'order_by_taxonomy_intercept_query_clauses', 20, 1 );
  }
}

The Database Query Pieces will now be sent to our function order_by_taxonomy_intercept_query_clauses (which will be in step 2) before being executed.

Step 2: Change the query

We have to extend the MySQL Query to include the term and taxonomy tables. We use the Filter-Function order_by_taxonomy_intercept_query_clauses for this.

function order_by_taxonomy_intercept_query_clauses($pieces){
        global $wpdb;
        $pieces['join'].=" LEFT JOIN $wpdb->term_relationships trt ON ($wpdb->posts.ID = trt.object_id) LEFT JOIN $wpdb->term_taxonomy ttt ON (trt.term_taxonomy_id = ttt.term_taxonomy_id) INNER JOIN $wpdb->terms termts ON (termts.term_id = ttt.term_id)";
        $pieces['where'].=" AND ttt.taxonomy = 'release-year'";
        $pieces['orderby']="termts.name ASC, ".$pieces['orderby'];
        //Remove the filter so it only runs once in our main query
        remove_filter('posts_clauses', 'order_by_taxonomy_intercept_query_clauses');
        return $pieces;
}

Step 3: Success!

Your Releases will now be ordered by release-year.

Happy Coding!

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.