WordPress PHP - How do I sort category/archive results by a specific "meta_key" value?
I previously made a post here: How do I sort by a custom field without manually creating a new page?
However, I believe I asked the wrong question (and I may still be asking the wrong question). Actually think I may need a complex query that will display posts ordered by a meta value. The site is using a theme called "AgentPress". I believe passing params via the URL bar may be too simplistic for what I need.
Honestly I like the way the current category pages display (formatting, etc.), I simply need to "short-circuit" the pr开发者_JS百科ocess so that any category/archive page is sorted by the meta_key for the "property price" as opposed to the date of entry. If there is a simple, more "WordPress-y" mechanism for doing this, I'm all ears. Please be explicit about where to place the code, etc.
FYI, at this point it's clear that passing "order=ASC" and "order=DESC" in the URL works. However, it seems that nothing I do with "meta_key" or anything related has any effect.
Thanks in advance.
You can add a filter on pre_get_posts
hook.
Put this code in functions.php
(in your theme dir) :
add_filter('pre_get_posts', 'pre_get_posts_hook' );
function pre_get_posts_hook($wp_query) {
if (is_category() || is_archive())
{
$wp_query->set( 'orderby', 'meta_value_num' );
$wp_query->set( 'meta_key', 'price' );
$wp_query->set( 'order', 'ASC' );
return $wp_query;
}
}
You can use meta_value
instead of meta_value_num
(available with v2.8), but I assume that price is a numeric value.
If you find you lose your navigation menu, I updated @soju's answer as follows:
add_filter('pre_get_posts', 'pre_get_posts_hook' );
function pre_get_posts_hook($wp_query) {
if ( is_archive() && $wp_query->is_main_query() ) { //edited this line
$wp_query->set( 'orderby', 'meta_value_num' );
$wp_query->set( 'meta_key', 'price' );
$wp_query->set( 'order', 'ASC' );
return $wp_query;
}
}
Then the filter won't affect your nav menu
I believe you will find this functionality under a class called PostsOrderedByMetaQuery that extends WP_Query and accepts new arguments 'orderby_meta_key' and 'orderby_order'
class PostsOrderedByMetaQuery extends WP_Query {
var $posts_ordered_by_meta = true;
var $orderby_order = 'ASC';
var $orderby_meta_key;
function __construct($args=array()) {
add_filter('posts_join',array(&$this,'posts_join'),10,2);
add_filter('posts_orderby',array(&$this,'posts_orderby'),10,2);
$this->posts_ordered_by_meta = true;
$this->orderby_meta_key = $args['orderby_meta_key'];
unset($args['orderby_meta_key']);
if (!empty($args['orderby_order'])) {
$this->orderby_order = $args['orderby_order'];
unset($args['orderby_order']);
}
parent::query($args);
}
function posts_join($join,$query) {
if (isset($query->posts_ordered_by_meta)) {
global $wpdb;
$join .=<<<SQL
INNER JOIN {$wpdb->postmeta} postmeta_price ON postmeta_price.post_id={$wpdb->posts}.ID
AND postmeta_price.meta_key='{$this->orderby_meta_key}'
SQL;
}
return $join;
}
function posts_orderby($orderby,$query) {
if (isset($query->posts_ordered_by_meta)) {
global $wpdb;
$orderby = "postmeta_price.meta_value {$this->orderby_order}";
}
return $orderby;
}
}
You would call it like this:
$thirtydays = date('Y/m/d', strtotime('+30 days'));
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$query = new PostsOrderedByMetaQuery(array
(
'post_type' => array('post', 'real-estate'),
'meta_key' => 'Time Available',
'meta_compare' => '<=',
'meta_value' => $thirtydays,
'paged' => $paged,
'orderby_meta_key' => 'Price',
'orderby_order' => 'DESC',
));
foreach($query->posts as $post)
{
echo " {$post->post_title}\n";
}
You can copy the PostsOrderedByMetaQuery class to your theme's functions.php file, or you can use it within a .php file of a plugin you may be writing.
精彩评论