Title: WP_Query sort by multiple custom fields
Last modified: January 17, 2024

---

# WP_Query sort by multiple custom fields

 *  [Bas van der Togt](https://wordpress.org/support/users/basvandertogt/)
 * (@basvandertogt)
 * [2 years, 4 months ago](https://wordpress.org/support/topic/wp_query-sort-by-multiple-custom-fields/)
 * I have a custom post type with two acf fields, ‘type’ (options are: news and 
   event) and ‘date’.
   On the archive page i want to query the results by first showing
   the upcoming events (ASC) and then all news (DESC).With the help of Google i 
   found several solutions. For example [https://facetwp.com/wp_query-sort-by-multiple-custom-fields/](https://facetwp.com/wp_query-sort-by-multiple-custom-fields/)
 * Code below is my variant but it does not work. If i debug the query the order
   by clause is missing at all. Does anybody know what i am doing wrong?
 *     ```wp-block-code
       add_action('pre_get_posts', function ($query) {
           if (!is_admin() and $query->is_archive('news') and $query->is_main_query()) {
               $meta_query = [];
   
               $meta_query[] = [
                   'relation' => 'OR',
                   'event_clause' => [
                       'relation' => 'AND',
                       [
                           'key' => 'type',
                           'value' => 'event',
                           'compare' => '=',
                       ],
                       [
                           'key' => 'from',
                           'value' => date('Ymd'),
                           'compare' => '>',
                           'type' => 'DATE'
                       ],
                   ],
                   'news_clause' => [
                       'relation' => 'AND',
                       [
                           'key' => 'type',
                           'value' => 'news',
                           'compare' => '='
                       ],
                   ]
               ];
   
               $orderby = [
                   'event_clause' => 'ASC',
                   'news_clause' => 'DESC'
               ];
   
               $query->set('meta_query', $meta_query);
               $query->set('orderby', $orderby);
           }
       });
       ```
   
 * Debug query:
 *     ```wp-block-code
       SELECT SQL_CALC_FOUND_ROWS wp_posts.* FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) INNER JOIN wp_postmeta AS mt1 ON ( wp_posts.ID = mt1.post_id ) INNER JOIN wp_postmeta AS mt2 ON ( wp_posts.ID = mt2.post_id ) INNER JOIN wp_postmeta AS mt3 ON ( wp_posts.ID = mt3.post_id ) WHERE 1=1 AND ( ( ( ( wp_postmeta.meta_key = 'type' AND wp_postmeta.meta_value = 'event' ) AND ( mt1.meta_key = 'from' AND CAST(mt1.meta_value AS DATE) > '20240117' ) ) OR ( ( mt2.meta_key = 'type' AND mt2.meta_value = 'news' ) AND ( mt3.meta_key = 'from' AND CAST(mt3.meta_value AS DATE) > '0' ) ) ) ) AND ((wp_posts.post_type = 'news' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'acf-disabled' OR wp_posts.post_status = 'archived' OR wp_posts.post_status = 'private'))) GROUP BY wp_posts.ID LIMIT 0, 100
       ```
   
 * It’s missing the order by clause.
    -  This topic was modified 2 years, 4 months ago by [Bas van der Togt](https://wordpress.org/support/users/basvandertogt/).
    -  This topic was modified 2 years, 4 months ago by [Bas van der Togt](https://wordpress.org/support/users/basvandertogt/).

Viewing 10 replies - 1 through 10 (of 10 total)

 *  [Milimo Emmanuel](https://wordpress.org/support/users/manuell/)
 * (@manuell)
 * [2 years, 4 months ago](https://wordpress.org/support/topic/wp_query-sort-by-multiple-custom-fields/#post-17350989)
 * Hello [@basvandertogt](https://wordpress.org/support/users/basvandertogt/).
 * I will divide the answer in two parts:
 * Based on the debug query:
    - **The `orderby` clause is indeed missing.** This aligns with the issue you’ve
      described.
    - **The query structure is consistent with the code you provided.** It correctly
      filters for events and news based on the <code class=””>type and <code class
      =””>from meta fields.
    - **The `GROUP BY wp_posts.ID` clause is likely redundant.** It’s usually unnecessary
      for standard post queries as posts are already unique by ID.
 * **
   I’ve identified a few potential issues and adjustments in your code:
    1. **Incorrect `orderby` Reference:**You’re using named clauses in <code class=””
       >meta_query, but you need to reference those same names in <code class=””>orderby.
       Change the <code class=””>orderby array to:
 *     ```wp-block-code
       $orderby = [
           'type_clause' => 'ASC',  // Reference the named clause correctly
           'date' => 'ASC',         // Sort events by date within the 'event_clause'
           'date' => 'DESC',        // Sort news by date within the 'news_clause'
       ];
       ```
   
 * 2. The <code class=””>news_clause condition <code class=””>[‘value’ => 0, ‘compare’
   => ‘>’] is likely unnecessary as all valid dates should be greater than 0. Consider
   removing it for efficiency:
 *     ```wp-block-code
       'news_clause' => [
           'relation' => 'AND',
           [
               'key' => 'type',
               'value' => 'news',
               'compare' => '='
           ],
           // Remove the condition for 'from'
       ]
       ```
   
 * 3. **Potential Issue with `date` Field:** If the <code class=””>date field stores
   dates as numbers (e.g., Unix timestamps), use <code class=””>meta_value_num in
   <code class=””>orderby:
 *     ```wp-block-code
       $orderby = [
           // ...
           'date' => 'meta_value_num',
       ];
       ```
   
 * Here is an updated code (try and see if it works):
 *     ```wp-block-code
       add_action('pre_get_posts', function ($query) {
           if (!is_admin() and $query->is_archive('news') and $query->is_main_query()) {
               $meta_query = [];
   
               $meta_query[] = [
                   'relation' => 'OR',
                   'event_clause' => [
                       'relation' => 'AND',
                       [
                           'key' => 'type',
                           'value' => 'event',
                           'compare' => '=',
                       ],
                       [
                           'key' => 'from',
                           'value' => date('Ymd'),
                           'compare' => '>',
                           'type' => 'DATE'
                       ],
                   ],
                   'news_clause' => [
                       'relation' => 'AND',
                       [
                           'key' => 'type',
                           'value' => 'news',
                           'compare' => '='
                       ],
                       // Potentially remove the 'from' condition here
                   ]
               ];
   
               $orderby = [
                   'type_clause' => 'ASC',
                   'date' => 'ASC',  // For events within 'event_clause'
                   'date' => 'DESC', // For news within 'news_clause'
               ];
   
               $query->set('meta_query', $meta_query);
               $query->set('orderby', $orderby);
           }
       });
       ```
   
 * Kindly it is not a guarantee this will work, and I have worked with the code 
   you provided. Let me know thanks!
 *  [Alan Fuller](https://wordpress.org/support/users/alanfuller/)
 * (@alanfuller)
 * [2 years, 4 months ago](https://wordpress.org/support/topic/wp_query-sort-by-multiple-custom-fields/#post-17351000)
 * I asked an AI assistant it said
 * Currently, WordPress does not support sorting by multiple meta keys directly 
   using the ‘orderby’ parameter. You can sort by a single meta key, or use a filter
   to adjust the ‘ORDER BY’ part of the SQL query manually.
   A correct setup for 
   sorting by a single meta key would look like:
 * $orderby = array(
   ‘meta_key’ => ‘event_clause’,‘orderby’ => ‘meta_value_num’,‘
   order’ => ‘ASC’);$query->set(‘orderby’, $orderby);
 * In this example, the query would be sorted by the numerical value of the event_clause
   meta key in ascending order.
   If you need to sort by multiple meta keys (like 
   your ‘event_clause’ and ‘news_clause’), you would need to make use of the ‘posts_orderby’
   hook to modify the SQL query directly.Using this hook, you can add sorting conditions
   for additional meta keys to your query. Please keep in mind that directly modifying
   the query can have implications for security and performance, and thus should
   be done with care.Here is an example of how you could use the hook:
 * add_filter(‘posts_orderby’**, **function ($orderby_statement) {
   $orderby_statement
   = “wp_postmeta.meta_key = ‘event_clause’ ASC,wp_postmeta.meta_key = ‘news_clause’
   DESC”**; return $orderby_statement;});
 * Remember, always validate and escape inputs, and protect your code from SQL injection
   when altering queries manually.
 *  [Milimo Emmanuel](https://wordpress.org/support/users/manuell/)
 * (@manuell)
 * [2 years, 4 months ago](https://wordpress.org/support/topic/wp_query-sort-by-multiple-custom-fields/#post-17351016)
 * To add to his response **While WordPress doesn’t have a built-in way to sort 
   by multiple meta keys using the `orderby` parameter, **this one of the ways to
   use:
 * Sorting by a Single Meta Key: If one meta key takes priority, use <code class
   =””>meta_key and <code class=””>orderby directly:
 *     ```wp-block-code
       $args = array(
           'meta_key' => 'primary_meta_key',
           'orderby' => 'meta_value_num', // For numerical values
           'order' => 'ASC', // Or 'DESC'
       );
       $query = new WP_Query($args);
       ```
   
 * I believe this works. Note there are other ways such as <code class=””>posts_orderby
   filter, the one above is one am conversant with.
    -  This reply was modified 2 years, 4 months ago by [Milimo Emmanuel](https://wordpress.org/support/users/manuell/).
    -  This reply was modified 2 years, 4 months ago by [Milimo Emmanuel](https://wordpress.org/support/users/manuell/).
 *  [Milimo Emmanuel](https://wordpress.org/support/users/manuell/)
 * (@manuell)
 * [2 years, 4 months ago](https://wordpress.org/support/topic/wp_query-sort-by-multiple-custom-fields/#post-17351029)
 * Some of the code might not show well, there is an issue with the blocks on my
   side.
 *  Thread Starter [Bas van der Togt](https://wordpress.org/support/users/basvandertogt/)
 * (@basvandertogt)
 * [2 years, 4 months ago](https://wordpress.org/support/topic/wp_query-sort-by-multiple-custom-fields/#post-17351119)
 * Thanks for the replies but none of them is a working solution.
 * orderby meta_query should be possible since 4.2 see [https://make.wordpress.org/core/2015/03/30/query-improvements-in-wp-4-2-orderby-and-meta_query/](https://make.wordpress.org/core/2015/03/30/query-improvements-in-wp-4-2-orderby-and-meta_query/)
 *  Moderator [bcworkz](https://wordpress.org/support/users/bcworkz/)
 * (@bcworkz)
 * [2 years, 4 months ago](https://wordpress.org/support/topic/wp_query-sort-by-multiple-custom-fields/#post-17351655)
 * I think the problem is that there are two different key names used in ‘event_clause’
   sub-array. WP doesn’t know which to use for ordering so fails to do anything 
   at all. In any working examples I’ve seen there were always only one key per 
   sub-array.
 * I recommend using the “posts_orderby” filter to provide the necessary ORDER BY
   clause using proper MySQL syntax.
 *  [Albert Bretado](https://wordpress.org/support/users/abretado1985/)
 * (@abretado1985)
 * [2 years, 4 months ago](https://wordpress.org/support/topic/wp_query-sort-by-multiple-custom-fields/#post-17351995)
 * Try this:
 *     ```wp-block-code
       add_action('pre_get_posts', function ($query) {
           if (!is_admin() and $query->is_archive('news') and $query->is_main_query()) {
               $meta_query = [];
   
               $meta_query[] = [
                   'relation' => 'OR',
                   [
                       'event_clause' => [
                           'key' => 'type',
                           'value' => 'event',
                           'compare' => '=',
                       ],
                       'date_clause' => [
                           'key' => 'date',
                           'value' => date('Ymd'),
                           'compare' => '>',
                           'type' => 'DATE'
                       ],
                   ],
                   [
                       'news_clause' => [
                           'key' => 'type',
                           'value' => 'news',
                           'compare' => '='
                       ],
                   ]
               ];
   
               $orderby = [
                   'event_clause' => 'ASC',
                   'date_clause' => 'ASC',
                   'news_clause' => 'DESC'
               ];
   
               $query->set('meta_query', $meta_query);
               $query->set('orderby', $orderby);
           }
       });
       ```
   
 * Updated the structure of the meta query to include ‘date_clause’ for events. 
   This will ensure that events are sorted by both ‘type’ and ‘date’. Added ‘date_clause’
   to the ‘orderby’ array to sort events by date as well.
   This should display upcoming
   events first in ascending order and then display news in descending order.
 *  Thread Starter [Bas van der Togt](https://wordpress.org/support/users/basvandertogt/)
 * (@basvandertogt)
 * [2 years, 4 months ago](https://wordpress.org/support/topic/wp_query-sort-by-multiple-custom-fields/#post-17352159)
 * Thank you [@abretado1985](https://wordpress.org/support/users/abretado1985/)
 * I have an order by clause now but the ordering is not right yet.
 * SELECT SQL_CALC_FOUND_ROWS wp_posts.* FROM wp_posts INNER JOIN wp_postmeta ON(
   wp_posts.ID = wp_postmeta.post_id ) INNER JOIN wp_postmeta AS mt1 ON ( wp_posts.
   ID = mt1.post_id ) INNER JOIN wp_postmeta AS mt2 ON ( wp_posts.ID = mt2.post_id)
   WHERE 1=1 AND ( ( ( ( wp_postmeta.meta_key = ‘type’ AND wp_postmeta.meta_value
   = ‘event’ ) AND ( mt1.meta_key = ‘from’ AND CAST(mt1.meta_value AS DATE) > ‘20240117’))
   OR ( ( mt2.meta_key = ‘type’ AND mt2.meta_value = ‘news’ ) ) ) ) AND ((wp_posts.
   post_type = ‘news’ AND (wp_posts.post_status = ‘publish’ OR wp_posts.post_status
   = ‘acf-disabled’ OR wp_posts.post_status = ‘archived’ OR wp_posts.post_status
   = ‘private’))) GROUP BY wp_posts.ID ORDER BY CAST(wp_postmeta.meta_value AS CHAR)
   ASC, CAST(mt1.meta_value AS DATE) ASC, CAST(mt2.meta_value AS CHAR) DESC LIMIT
   0, 100
 * returns first the news ASC and then events ASC
 * i want to have first events ASC en then news DESC
    -  This reply was modified 2 years, 4 months ago by [Bas van der Togt](https://wordpress.org/support/users/basvandertogt/).
    -  This reply was modified 2 years, 4 months ago by [Bas van der Togt](https://wordpress.org/support/users/basvandertogt/).
    -  This reply was modified 2 years, 4 months ago by [Bas van der Togt](https://wordpress.org/support/users/basvandertogt/).
 *  [Albert Bretado](https://wordpress.org/support/users/abretado1985/)
 * (@abretado1985)
 * [2 years, 4 months ago](https://wordpress.org/support/topic/wp_query-sort-by-multiple-custom-fields/#post-17352235)
 * Maybe I am not understanding your request. You want to show events in ASC followed
   by News DESC, as two separate lists? If so, try this:
 *     ```wp-block-code
       add_action('pre_get_posts', function ($query) {
           if (!is_admin() && $query->is_archive('news') && $query->is_main_query()) {
               // Disable the main query
               $query->set('posts_per_page', 0);
   
               // Query for events
               $events_query = new WP_Query([
                   'post_type' => 'news',
                   'meta_key' => 'type',
                   'meta_value' => 'event',
                   'orderby' => 'date',
                   'order' => 'ASC',
                   // Add other necessary arguments
               ]);
   
               // Query for news
               $news_query = new WP_Query([
                   'post_type' => 'news',
                   'meta_key' => 'type',
                   'meta_value' => 'news',
                   'orderby' => 'date',
                   'order' => 'DESC',
                   // Add other necessary arguments
               ]);
   
               // Combine results
               $combined_posts = array_merge($events_query->posts, $news_query->posts);
   
               // Override the main query
               $query->posts = $combined_posts;
               $query->post_count = count($combined_posts);
           }
       });
       ```
   
 *  Thread Starter [Bas van der Togt](https://wordpress.org/support/users/basvandertogt/)
 * (@basvandertogt)
 * [2 years, 4 months ago](https://wordpress.org/support/topic/wp_query-sort-by-multiple-custom-fields/#post-17353255)
 * [@abretado1985](https://wordpress.org/support/users/abretado1985/) I need a single
   query because of pagination.
 * Its a single post_type named ‘news’. The post type has two acf fields ‘type’ (
   news/event) and ‘date’. I want to show the upcoming events ASC first and then
   all news DESC.

Viewing 10 replies - 1 through 10 (of 10 total)

The topic ‘WP_Query sort by multiple custom fields’ is closed to new replies.

 * In: [Developing with WordPress](https://wordpress.org/support/forum/wp-advanced/)
 * 10 replies
 * 5 participants
 * Last reply from: [Bas van der Togt](https://wordpress.org/support/users/basvandertogt/)
 * Last activity: [2 years, 4 months ago](https://wordpress.org/support/topic/wp_query-sort-by-multiple-custom-fields/#post-17353255)
 * Status: not resolved

## Topics

### Topics with no replies

### Non-support topics

### Resolved topics

### Unresolved topics

### All topics
