首先按元键查询排序列表(如果存在),然后按标题显示按元顺序排序的其余帖子


22

我正在开发一个自定义分类术语页面模板,在该模板中,我们希望与该术语相关的项目按发布日期(自定义日期字段)进行排序-如果同一天有多个项目(格式如YYYY-MM- DD),然后按标题对它们进行排序,如果尚未填写自定义字段(旧项目),则最后按标题进行排序。

因此,我使用WP_query尝试了一百种不同的方式,它确实返回了我想要的大多数结果-但是在这种情况下,它仅返回具有publication_date的meta_key的项。所有其他项目都将被忽略并且不会显示。我使用“或”的关系尝试了meta_query,并将publication_date比较为EXISTS和NOT EXISTS,但是为我返回了0个结果。

此外,该站点仍在运行3.5.2,并且他们不想升级。

这是我最近的查询,使我获得具有按正确顺序显示的publication_date自定义字段的帖子:

$term = get_queried_object(); // find the term of the taxonomy page we are on
$wp_query = new WP_Query( array(
'post_type' => 'resource',
'tax_query' => array(
    array(
        'taxonomy' => 'resource_types',
        'field' => 'slug',
        'terms' => $term->name,
    )), 

'meta_key' => 'publication_date',
'orderby' => 'meta_value_num',
'order' => 'DESC',
'paged' => $paged,
'posts_per_page' => '10',
));

我也尝试过使用wpdb并运行SQL查询,但是我真的不确定如何完成我想做的事情。如果有人可以帮助我,那就太好了!

提前致谢。


令人惊讶的是meta_query方法不起作用,但是再次重申,如果没有设置meta_key,就无法通过meta_query对meta值进行排序。
sanchothefat

我认为那是我遇到的问题。我终于得到了一个元查询工作:'meta_query' => array( 'relation' => 'OR', array( //check to see if date has been filled out 'key' => 'publication_date', 'compare' => '!=', 'value' => date('Y-m-d'), ), array( //if no date has been added show these posts too 'key' => 'publication_date', 'value' => date('Y-m-d'), 'compare' => 'NOT EXISTS' ) ),但排序不起作用:\
CSSgirl

是的,不幸的是,排序依赖于在tax_query外部设置了meta_key。我在下面的回答可能会有所帮助。
sanchothefat

Answers:


19

谢谢你们每一个人的帮助!

最后,下面的查询为我提供了我想要的结果-首先按照“ publication_date”的自定义字段显示帖子并对其进行排序-按日期进行排序,以及是否有多个相同的日期(例如,标记为4 2013年6月),它将按标题对它们进行排序。然后,在遍历所有填写了“发布日期”的帖子之后,它将再次按标题字母顺序遍历其余帖子。

这使我在同一查询中设置结果集,并保持分页:

$term = get_queried_object();
the_post();
$wp_query = new WP_Query( array(
'post_type' => 'resource',
    'tax_query' => array(
        array(
            'taxonomy' => 'resource_types',
            'field' => 'slug',
            'terms' => $term->name,
        )),
 'meta_query' => array(
       'relation' => 'OR',
        array( //check to see if date has been filled out
                'key' => 'publication_date',
                'compare' => '=',
                'value' => date('Y-m-d')
            ),
          array( //if no date has been added show these posts too
                'key' => 'publication_date',
                'value' => date('Y-m-d'),
                'compare' => 'NOT EXISTS'
            )
        ),
'meta_key' => 'publication_date',
'orderby' => 'meta_value title',
'order' => 'ASC',
'paged' => $paged,
'posts_per_page' => '10',
));

1
真好 我从没想过要meta_query在同一键上运行两个!
GhostToast 2013年

5
对我来说(使用WordPress 4.1.1),如果我meta_key自动设置它,即使使用也不包含它NOT EXISTS。我真的希望我做错了什么。
瑞安·泰勒

1
@RyanTaylor或此处相同-不能在查询中设置meta_key,以使其正常工作,但即使未设置meta键,它也确实按meta值正确排序。
jammypeach '16

2
如上所述,对于WP 4.1+,请删除或注释掉'meta_key' => 'publication_date',
MikeiLL,2016年

7

几年后,CSSGirl发布的代码对我不起作用,因为有些帖子没有元密钥或元密钥为空,所以我必须要做的是按日期对所有帖子进行排序并首先显示带有meta键值的显示:

$args          = array(
'post_type'   => $type,
'post_status' => 'publish',
'nopaging'    => TRUE,
'meta_query'  => array(
    'relation' => 'OR',
    array(
        'key'     => $meta_key,
        'compare' => 'NOT EXISTS',
    ),
    array(
        'relation' => 'OR',
        array(
            'key'   => $meta_key,
            'value' => 'on',
        ),
        array(
            'key'     => $meta_key,
            'value'   => 'on',
            'compare' => '!=',
        ),
    ),
),
'orderby'     => array( 'meta_value' => 'DESC', 'date' => 'DESC' ),
);

1

我认为您需要执行2个单独的循环。您可以捕获在第一个循环中找到的所有帖子,并将它们轻松地从第二个循环中排除:

$found_posts = array();
while($loop->have_posts()): $loop->the_post();
    // loop stuff
    $found_posts[] = get_the_id();
endwhile;

wp_reset_query();

$args = array(
    // other args
    'post__not_in' => $found_posts,
);

然后运行第二个循环。


现在尝试这个,谢谢。会让您知道它是否有效!
CSSgirl 2013年

1
这有效-但它打破了分页-知道如何使它起作用吗?这是现在的样子:echo paginate_links( array( 'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ), 'format' => '?page=%#%', 'current' => max( 1, get_query_var('paged') ), 'total' => $publication_query->max_num_pages, 'prev_text' => __('Previous |'), 'next_text' => __('| Next'), ) );
CSSgirl 2013年

嗯 不是我能想到的。
GhostToast 2013年

1

您是否有任何理由不能强制仅具有空值的每个帖子都必须存在publication_date元键?

因此,在save_post操作中,无论$_POST值是否为空,您都将添加/更新元密钥。

您将需要运行一个更新脚本来循环浏览您的旧帖子,并使用空值添加密钥,例如:

add_action( 'admin_init', 'update_old_posts' );
function update_old_posts() {
    if ( ! isset( $_GET[ 'update_old_posts' ] ) )
         return;

    foreach( get_posts() as $post ) {
        if ( false === get_post_meta( $post->ID, 'publication_date', true ) ) {
             update_post_meta( $post->ID, 'publication_date', '' );
             echo "Updated {$post->post_title} <br />";
        }
    }

    die;
}

通过浏览到http://example.com/wp-admin/?update_old_posts来运行它

然后,您可以使用相同的查询。您可能想要添加一个额外的过滤器,以使您可以按不同的方向按不同的列进行排序,这对我来说按日期按降序排序和标题按升序排序是有意义的。

add_filter( 'posts_orderby', 'multicolumn_orderby', 10, 2 );
function multicolumn_orderby( $orderby, $query ) {
    global $wpdb;

    // check it's the right query
    if ( $query->get( 'meta_key' ) == 'publication_date' ) {
         $orderby = "$wpdb->postmeta.meta_value+0 DESC, $wpdb->posts.post_title ASC";
    }

    return $orderby;
}

嗯,我没想到。我将尝试一下,看看效果如何,谢谢!
CSSgirl 2013年

0

我创建了一个自定义where子句。我$wp_query->request在主循环之前就使用它进行了测试,我不太了解SQL,但这似乎可以解决问题。

add_action('pre_get_posts', 'add_trending_sort', 11, 1);
function add_trending_sort($query){
  if(!$query->is_main_query())
    return;

  //Overwrite query arguments
  $query->set('meta_query', array(
    array(
      'key' => 'TRENDING',
      //'value' => 'asdfasdf',//may need a value for older versions of WordPress
      'compare' => 'NOT EXISTS',
    )
  ));
  $query->set('orderby', 'meta_value_num date');
  $query->set('order', 'DESC');
}

add_filter('posts_where', 'add_trending_where');
function add_trending_where($where = ''){
  global $wpdb, $wp_query;
  if(!$wp_query->is_main_query())//Not sure if this really works.  Should be OK
    return $where;

  $where .= " OR ( $wpdb->postmeta.meta_key = 'TRENDING' )";

  // Don't run this twice
  remove_filter('posts_where', 'add_trending_where');

  return $where;
}

或者,您可以设置compare'EXISTS'并将add_trending_where中的行更改为$where .= " OR ($wpdb->postmeta.post_id IS NULL)";。然后,您只需要在一处更改键的值即可。再说一次,$wp_query->request如果您想更好地理解或调整它,请回声并玩转。

编辑:我只是注意到如果meta_key在查询上设置了这是行不通的。您可以根据需要使用$query->set('meta_key', NULL);

编辑2:我使用上面的方法。由于某种原因,它不是一开始的(也许设置了meta_key……我不知道)。

add_action('pre_get_posts', 'add_trending_sort', 11, 1);
function add_trending_sort($query){
  // Bail if not the main "hidden" query, as opposed to a 'new WP_Query()' call
  if(!$query->is_main_query())
    return;

  // Set meta_query to get shares for orderby, and also get non-shared content.
  $query->set('meta_query', array(
    'relation' => 'OR',
    array(
      'key' => 'TRENDING',
      'compare' => 'NOT EXISTS',
    ),
    array(
      'key' => 'TRENDING',
      'compare' => 'EXISTS',
    )
  ));
  //$query->set('meta_key', NULL);
  $query->set('orderby', array('meta_value_num' => 'DESC', 'date' => 'DESC'));
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.