How to order by two different things at once in a query in WordPress

I am having a little problem. I am trying to get the latest 12 post by a custom meta field. Out of those 12 posts, I want to order them by post date. So first I pull 12 posts out using a custom meta field and ordering them to find the latest through the meta field. Once I have them, then I want to re-order them with latest post. Here is my current code, I don't know how I can put two order-bys in one query... $recentEpisodes12 = new WP_Query(array( 'posts_per_page' => 12, 'post_type' => 'post', 'meta_key' => 'air_date', 'order' => 'DESC', 'orderby' => 'meta_value_num', 'meta_query' => array( array( 'key' => 'air_date', ), array( 'key' => 'already_aired', 'value' => 'yes', 'compare' => '=' ) ), ));

Comment (3)

Jese Leos

August 10, 2024

Verified user

So if you want to order them by post date, why do you need a meta field for that? Once you get the 12 latest posts by meta value, is the air_date somehow different from the post date? Worth noting: posts_per_page doesn't limit the total number of returns. It just tells WordPress when to split into a new page. Something like this should work based on what you described in your original post. // Post Criteria $post_criteria = array( 'posts_per_page' => 12, // Don't paginate until after 12 posts 'orderby' => 'post_date', // Order by post date 'order' => 'DESC', // Order them reverse chronologically (ie. get the newest first) 'meta_key' => 'air_date', // Only get posts with this meta key 'meta_value' => 'meta_value_num', // And this meta value (only needed if you have multiple possible values for the meta key and just want one) 'post_type' => 'post', // Only get posts 'post_status' => 'publish'); // Only get posts that are published (ie. no drafts, etc.) // Get posts matching criteria $posts = get_posts( $post_criteria ); // Discard posts after the 12th one $posts = array_slice($posts, 0, 12); // If you wanted to reverse them to display // chronologically, uncomment this variable. # $posts = array_reverse($posts); // For each post foreach ($posts as $post) { // Basic variables // See a full list here: http://codex.wordpress.org/Function_Reference/get_post#Return $id = $post->ID; $title = $post->post_title; $url = get_permalink($id); $content = $post->post_content; // Do stuff with the posts here. }

Jese Leos

August 10, 2024

Verified user

In WordPress 4.2 and up, ordering by one or more custom fields was made much easier. See this link for examples: https://make.wordpress.org/core/2015/03/30/query-improvements-in-wp-4-2-orderby-and-meta_query/ You can even order one column ASC and another DESC by passing an array to orderby now: 'orderby' => array( 'city_clause' => 'ASC', 'state_clause' => 'DESC', ),

Jese Leos

August 10, 2024

Verified user

According to the Codex, you simply need to separate them by a space: Multiple 'orderby' values Display pages ordered by 'title' and 'menu_order'. (title is dominant): $query = new WP_Query( array( 'post_type' => 'page', 'orderby' => 'title menu_order', 'order' => 'ASC' ) ); In your case, that would look like: 'orderby' => 'meta_value_num date' EDIT: Okay, it seems like you're trying to do something a bit more complex here. This is how I interpret it, correct my if I'm wrong: Order by air_date (in descending order, newest first). Keep only the 12 newest items according to air_date. Order the resulting 12 items by date. What orderby does is basically: Order by air_date. If any items have identical air_date values, order those by date. Keep only the top 12 items. The difference is that you only want to distinguish by air_date, whereas the normal usage of orderby uses both criteria to determine which items end up in the result. I don't know an easy way to solve this, though. However, since you only want to change the display order of the resulting items, you could just sort those yourself. You can use get_posts instead of WP_Query and sort the results array using PHP's usort $posts = get_posts(...); usort($posts, '__sort_by_date_desc'); function __sort_by_date_desc($a, $b) { // Make timestamps from MySQL datetime values $a_date = mysql2date('U', $a->post_date); $b_date = mysql2date('U', $b->post_date); // Descending order, swap these for ascending return $b_date - $a_date; }

You’ll be in good company