ORDER BY wp_POST wp_Query中的自定义列名

时间:2016-09-18 作者:Rupesh Arora

我已经做了很多研发工作;但在任何地方都找不到合适的答案。如果我需要进行mysql查询,那么这对我来说是一个非常小的任务。但尽管如此,我在WP并没有很好的实践经验,所以对问题的解决感到非常沮丧。

How to sort a wp_query by custom column that I added in wp_posts table.

    $args = array(
    /*\'base\'               => \'%_%\',
    \'format\'             => \'?paged=%#%\',
    \'total\'              => 1,
    \'current\'            => 0,
    \'show_all\'           => false,
    \'end_size\'           => 1,
    \'mid_size\'           => 2,
    \'prev_next\'          => true,
    \'prev_text\'          => __(\'« Previous\'),
    \'next_text\'          => __(\'Next »\'),
    \'type\'               => \'plain\',
    \'add_args\'           => false,
    \'add_fragment\'       => \'\',
    \'before_page_number\' => \'\',
    \'after_page_number\'  => \'\'*/
    \'posts_per_page\' => 10,
    \'post_type\' => array(\'food\', \'buffets\'),
    \'meta_key\'  => \'post_priority\',
    \'orderby\'   => \'meta_value_num\',    
    \'order\'  => \'ASC\'

);
当我尝试使用这个时,实际上是按wp\\U Posteta表订购的wp_postmeta.meta_value+0表示按Posteta表订购,而不是wp\\U post表Post_priority is my custom column in wp_post table

以下是我得到的查询结果:

"SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts 
INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) 
WHERE 1=1 AND ( \\n wp_postmeta.meta_key = \'post_priority\'\\n) 
AND wp_posts.post_type IN (\'food\', \'buffets\') 
AND (wp_posts.post_status = \'publish\' OR wp_posts.post_author = 2 
AND wp_posts.post_status = \'private\')
GROUP BY wp_posts.ID 
ORDER BY wp_postmeta.meta_value+0 
ASC LIMIT 0, 10","posts"

2 个回复
SO网友:LeMike

我已经调查过了你的问题是WP_Query::parse_orderby() 作用用户Otto喜欢指出的是,您喜欢用作订单的所有内容都在那里进行了清理。不幸的是,它没有可以连接的过滤器。是的,如果你能在每个get\\U帖子中花费高昂的加入费用,那么最好使用一些meta\\u字段。如果没有,请记住menu_order 只要您不处理nav_menu_item 职位类型。

无论如何,我找到了两种解决方案,并想在这里分享。有关更多详细信息,请阅读https://wp-includes.org/296/custom-wp_posts-column-sortable/

扩展WP\\u Query最简洁的方法是编写自己的查询类:

<?php

class Enhanced_Post_Table_Query extends \\WP_Query {

  /**
   * Extend order clause with own columns.
   *
   * @param string $order_by
   *
   * @return bool|false|string
   */
  protected function parse_orderby( $order_by ) {
    $parent_orderby = parent::parse_orderby( $order_by );

    if ( $parent_orderby ) {
      // WordPress knew what to do => keep it like that
      return $parent_orderby;
    }

    // whitelist some fields we extended
    $additional_allowed = array(
      \'something\',
    );

    if ( ! in_array( $order_by, $additional_allowed, true ) ) {
      // not allowed column => early exit here
      return false;
    }

    // Default: order by post field.
    global $wpdb;

    return $wpdb->posts . \'.post_\' . sanitize_key( $order_by );
  }
}
现在,您可以使用自定义字段运行查询和排序:

$get_posts = new Enhanced_Post_Table_Query;

$get_posts->query(
  array(
    \'orderby\' => \'something\'
  )
);
延迟筛选以覆盖内容,虽然有点脏,但它可以工作。由于没有直接的过滤器,因此您可以选择一个更晚的过滤器并操作查询(越晚越脏):

<?php

/**
 * Add custom wp_posts column for sorting.
 *
 * @param string   $order_clause SQL-Clause for ordering.
 * @param WP_Query $query        Query object.
 *
 * @return string Order clause like "wp_posts.post_foo DESC" or similar.
 */
function custom_column_sort_filter( $order_clause, $query ) {

  // whitelist some fields we extended
  $additional_allowed = array(
    \'something\',
  );

  if (
    ! in_array(
      $query->get(\'orderby\'),
      $additional_allowed,
      true
    )
  ) {
    // unknown column => keep it as before
    return $order_clause;
  }

  global $wpdb;

  return $wpdb->posts
         . \'.post_\'
         . sanitize_key( $query->get(\'orderby\') )
       . \' \' . $query->get( \'order\' );

}

add_filter( \'posts_orderby\', \'custom_column_sort_filter\', 10, 2 );
现在,几乎每次调用get\\u posts都会了解您的自定义列:

get_posts(
  [
    \'orderby\'          => \'something\',
    // IMPORTANT:
    \'suppress_filters\' => false,
  ]
);
但仅当设置了“suppress\\u filters”时。这应该被每个插件使用。通过preg\\u replace有更多的解决方案,但这些解决方案都很晚了,用REGEXP替换总是肮脏和危险的。

我希望你能做到这一点!

SO网友:Otto

您告诉它按meta\\u值排序,所以它是按meta值排序的。wp posts表中没有“post\\u priority”列,因此无法按其排序。“orderby”的允许值不是无限的,它们是一个固定集。

您不能修改核心表并期望代码了解它。Posteta表的全部原因是允许您插入任意元数据,而不是修改表以使其具有代码不知道的列。

删除额外的列,并将数据存储为Posteta。将meta\\u键设置为“priority”,将meta\\u值设置为priority值。然后您的查询就会工作。