Wordpress 按自定义字段查询订单缺失帖子

问题描述 投票:0回答:4

这是我当前的查询:

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

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

提前致谢!

php mysql wordpress custom-fields
4个回答
6
投票

问题是,只要您在条件中提到

INNER JOIN
,WordPress 就会在
wp_postmeta
表中添加
meta_key
。解决该问题的一种方法是在
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
会从您的结果中删除任何没有优先顺序的帖子。

从您的

meta_*
中删除
query_posts
相关条件:

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 

它可以满足您的需求。


1
投票

我需要在 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;
}

1
投票

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

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
功能)

希望这对某人有帮助!


-1
投票

最简单的方法是使用

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);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.