【问题标题】:Wordpress Query order by custom field missing postsWordpress 按自定义字段查询顺序缺少帖子
【发布时间】:2012-07-04 02:52:57
【问题描述】:

这是我当前的查询:

query_posts(array_merge(array('tag' => $pagetag,'meta_key'=>priority,'orderby' =>meta_value, 'order' =>'ASC','paged' => get_query_var('paged'))));

我的问题是查询只向我显示了具有我的“元键”值的帖子,这意味着“优先级”不为 NULL。 我该如何改进这个查询,以便它仍然会按我的 meta_key 排序,但也会显示所有不为 NULL 的帖子?

提前致谢!

【问题讨论】:

    标签: mysql wordpress custom-fields


    【解决方案1】:

    问题在于,只要您在条件中提及meta_key,WordPress 就会将INNER JOIN 添加到wp_postmeta 表中。解决此问题的一种方法是在 order by 子句上添加一个过滤器,如下所示:

    function so_orderby_priority($original_orderby_statement) {
        global $wpdb;
    
        return "(SELECT $wpdb->postmeta.meta_value
                   FROM $wpdb->postmeta
                  WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id
                    AND $wpdb->postmeta.meta_key = 'priority') ASC";
    }
    
    add_filter('posts_orderby', 'so_orderby_priority');
    
    query_posts(
        array(
            'tag' => $pagetag,
            'paged' => get_query_var('paged')
        )
    );
    
    remove_filter('posts_orderby', 'so_orderby_priority');
    

    注意 MySQL 首先对 NULL 进行排序 - 如果您希望它们最后排序,请尝试这样的操作(假设您所有的优先级都按字母顺序排在 ZZZZZ 之前):

    function so_orderby_priority($original_orderby_statement) {
        global $wpdb;
    
        return "IFNULL(
                   (SELECT $wpdb->postmeta.meta_value
                      FROM $wpdb->postmeta
                     WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id
                       AND $wpdb->postmeta.meta_key = 'priority'),
                    'ZZZZZ') ASC";
    }
    

    编辑

    这里有更多解释,假设您至少了解 SQL。

    您原来的 query_posts 导致对数据库运行以下查询:

    SELECT wp_posts.*
    FROM   wp_posts
           INNER JOIN wp_term_relationships ON ( wp_posts.id = wp_term_relationships.object_id )
           INNER JOIN wp_postmeta ON ( wp_posts.id = wp_postmeta.post_id )
    WHERE  1 = 1
           AND ( wp_term_relationships.term_taxonomy_id IN ( 3 ) )
           AND wp_posts.post_type = 'post'
           AND ( wp_posts.post_status = 'publish'
                  OR wp_posts.post_status = 'private' )
           AND ( wp_postmeta.meta_key = 'priority' )
    GROUP  BY wp_posts.id
    ORDER  BY wp_postmeta.meta_value ASC
    LIMIT  0, 10; 
    

    INNER JOIN wp_postmeta 会从您的结果中删除任何没有优先级的帖子。

    从您的query_posts 中删除meta_* 相关条件:

    query_posts(
        array(
            'tag' => $pagetag,
            'paged' => get_query_var('paged')
        )
    );
    

    解决了这个问题,但排序顺序仍然错误。新的 SQL 是

    SELECT wp_posts.*
    FROM   wp_posts
           INNER JOIN wp_term_relationships ON ( wp_posts.id = wp_term_relationships.object_id )
    WHERE  1 = 1
           AND ( wp_term_relationships.term_taxonomy_id IN ( 3 ) )
           AND wp_posts.post_type = 'post'
           AND ( wp_posts.post_status = 'publish'
                  OR wp_posts.post_status = 'private' )
    GROUP  BY wp_posts.id
    ORDER  BY wp_posts.post_date DESC
    LIMIT  0, 10; 
    

    posts_orderby 过滤器允许我们更改 ORDER BY 子句:wp_posts.post_date DESC 被过滤器返回的内容替换。最终的 SQL 变为:

    SELECT wp_posts.*
    FROM   wp_posts
           INNER JOIN wp_term_relationships ON ( wp_posts.id = wp_term_relationships.object_id )
    WHERE  1 = 1
           AND ( wp_term_relationships.term_taxonomy_id IN ( 3 ) )
           AND wp_posts.post_type = 'post'
           AND ( wp_posts.post_status = 'publish'
                  OR wp_posts.post_status = 'private' )
    GROUP  BY wp_posts.id
    ORDER  BY (SELECT wp_postmeta.meta_value
               FROM   wp_postmeta
               WHERE  wp_posts.id = wp_postmeta.post_id
                      AND wp_postmeta.meta_key = 'priority') ASC
    LIMIT  0, 10 
    

    你所追求的。

    【讨论】:

    • 谢谢!工作得很好......很好的代码......但如果你能解释一下你做了什么,我会很高兴。我是 php 新手,并没有真正完全理解它......函数查询与原始查询有什么不同?过滤器到底做了什么?
    • 很高兴它有帮助。解决方案是 MySQL 而不是 PHP,因为query_posts 生成 SQL 以在幕后对数据库运行。过滤器将 SQL 中的排序顺序完全替换为按照您需要的方式对结果进行排序的代码。我将编辑我的答案以添加更多细节。
    【解决方案2】:

    我需要在 users.php 页面上为我添加的自定义列执行类似的任务,并使用我从 Hobo 修改的以下代码

    add_action('pre_user_query', 'qd_users_column_orderby');
    
    function qd_users_column_orderby($userquery){
      if('my_last_login'==$userquery->query_vars['orderby']) { //check if my cusomt meta_key is the column being sorted
    
        global $wpdb;
    
        $userquery->query_orderby = " ORDER BY(SELECT $wpdb->usermeta.meta_value
            FROM $wpdb->usermeta
            WHERE $wpdb->users.ID = $wpdb->usermeta.user_id
            AND $wpdb->usermeta.meta_key = 'my_last_login') ".($userquery->query_vars["order"] == "ASC" ? "asc " : "desc ")." , wp_users.user_login ".($userquery->query_vars["order"] == "ASC" ? "asc " : "desc ");
      }
    }
    

    希望这对需要此信息的人有所帮助。

    为了贯穿始终,完成我的个人任务所需的其余代码如下。

    add_filter('manage_users_columns', 'qd_add_user_login_column');
    
    function qd_add_user_login_column($columns) {
      $columns['my_last_login'] = 'Last Logged In';
      return $columns;
    }
    
    add_action('manage_users_custom_column',  'qd_show_user_login_column_content', 10, 3);
    
    function qd_show_user_login_column_content($value, $column_name, $user_id) {
      $user = get_userdata( $user_id );
      if ( 'my_last_login' == $column_name ){
        $lastLogin = get_the_author_meta('my_last_login', $user_id);
        if(!$lastLogin){
          return "Never";
        }else{
          date_default_timezone_set(get_option('timezone_string'));
          return date('m/d/y g:ia', $lastLogin); 
        }
      }
      return $value;
    }
    
    add_filter( 'manage_users_sortable_columns', 'qd_users_table_sorting' );
    
    function qd_users_table_sorting( $columns ) {
      $columns['my_last_login'] = 'my_last_login';
      return $columns;
    }
    

    【讨论】:

    • 我知道这个答案并不完全适合个别问题,但我想在这里简单地记录我的答案,因为我能够使用标记的答案解决我的问题
    • 这实际上帮助了我在这里偶然发现它。我将 last_login 日期作为长文本存储在用户元区域中。我还在 users.php 表中添加了 3 个新列。这是唯一一种方法(pre_user_query),它实际上可以对从元区域中提取的日期用户列进行排序。感谢您周到的回答。
    【解决方案3】:

    问题:按自定义字段排序,不排除没有为该自定义字段设置值的帖子。

    Hobo 的回答很好地解释了这一点。在这里,我将提供一个更简单的替代方案,最终在我的情况下更容易(请注意,如果需要分页,这将无法正常工作)。

    我决定在查询完成后在 PHP 中进行排序。 好的部分是我可以更好地控制具有空值的帖子的最终位置(我希望它们最后出现)。

    $query = new WP_Query($args); 
    
    //sort by rank
    function customSort($a, $b)
    {
        $a = get_field("sort_ranking", $a);
        $b = get_field("sort_ranking", $b);
    
        //handle nulls
        $a = is_numeric($a) ? $a : 9999;
        $b = is_numeric($b) ? $b : 9999;
    
        if ($a == $b) return 0;
        return ($a < $b) ? -1 : 1;
     }
     usort($query->posts, "customSort");
    

    在这里,我有一个名为 sort_ranking 的数字自定义字段,我正在使用它对 ASC 进行排序。该字段为空值的帖子被分配为 9999,以便它们最终结束。 (注意:我使用的是 ACF,因此使用了 get_field 函数)

    希望这对某人有所帮助!

    【讨论】:

      【解决方案4】:

      执行此操作的最简单方法是使用save_post 操作插入自定义字段,因此每个发布的帖子都会有自己的meta_key 和默认值。

      使用 MySQL 查询将 post_meta 添加到所有没有元的帖子。就是这样。

      如果您/任何人需要这方面的代码帮助,请回复 :)

      更新

      按照 Timusan 的要求,在更改元键名称后将此代码添加到您的 functions.php 文件中:

      add_action('save_post', 'sidati_post_views_metakey');
      
      function sidati_post_views_metakey ($post_id){
      
          /*
          * $post_id = is the post ID
          * 'sidati_post_views' => is your metakey name (sidati is prefix always nice to add your prefix)
          * 0 => the inital value
          * true => (bool) add true if you want this metakkey become unique
          */
      
          add_post_meta($post_id, 'sidati_post_views', 0, true);
      
      }
      
      
      // THIS ACTION MUST RUN ONLY ONE TIME
      add_action('init', 'sidati_allposts_must_have_this');
      
      function sidati_allposts_must_have_this(){
      
          /* Call the WordPress DataBase class */
          global $wpdb; 
      
          /* This Query will get us all the posts and pages without "sidati_post_views" metakey. */
          $ids = $wpdb->get_row("SELECT ID FROM wpdb->posts WHERE post_type IN ('post', 'page') AND post_status = 'publish' AND ID NOT IN (SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'sidati_post_views')");
      
          /* After get all posts/pages, now you need to add the meta keys (this may take a few munites if you have many posts/pages)*/
          foreach ($ids as $post_id) {
              add_post_meta($post_id, 'sidati_post_views', 0, true);
          }
      }
      

      【讨论】:

      • 从一开始就添加一些代码示例(发布您的答案时)可能会更清楚您的意思。
      猜你喜欢
      • 2015-10-24
      • 1970-01-01
      • 1970-01-01
      • 2021-06-29
      • 1970-01-01
      • 1970-01-01
      • 2012-11-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多