Orderby meta_value chỉ trả về các bài đăng có meta_key hiện có


10

Tôi có wp_query sau đây:

$args = array(
    'post_type' => 'news',
    'orderby' => 'meta_key',
    'order' => 'ASC',
    'meta_key'=>'custom_author_name',
    'post_per_page'=>-1
);

$query = new WP_Query($args);

echo $query->found_posts;

echo = 10 kết quả vì chỉ có 10 newsbài viết với a meta_key = custom_author_name. Nhưng có hàng trăm newsbài đăng không có hàng post_meta với meta_key cụ thể đó. Xin lưu ý rằng không có meta_query liên quan. Không có meta_value nào được chỉ định, vì tôi chỉ cố gắng sắp xếp các bài đăng theo meta_key chứ không lọc theo meta_value.

Không nên đặt hàng chọn tất cả các bài viết? và chỉ cần đặt hàng chúng?

Nếu vậy tại sao kết quả được lọc? Nếu không tìm thấy meta_key, tại sao không sử dụng một chuỗi rỗng hoặc tất cả khớp?

Nếu không, tai sao không?

Nếu tôi nhập meta_key cho mọi bài đăng tin tức (ngay cả khi đó là một chuỗi trống) thì tôi sẽ nhận được kết quả mong đợi. Nhưng có vẻ như rất nhiều hàng trong bảng không cần phải ở đó.

Câu trả lời:


10

Như đã nêu trong câu trả lời của @ ambroseya, nó được cho là hoạt động như vậy. Khi bạn khai báo một truy vấn meta, ngay cả khi bạn không tìm kiếm một giá trị cụ thể, nó sẽ chỉ truy vấn các bài đăng có khóa meta đó được khai báo. Nếu bạn muốn bao gồm tất cả các bài đăng sắp xếp chúng theo khóa meta, hãy sử dụng mã sau đây:

$args = array(
    'post_type' => 'news',
    'orderby' => 'meta_value',
    'order' => 'ASC',
    'meta_query' => array(
        'relation' => 'OR',
        array( 
            'key'=>'custom_author_name',
            'compare' => 'EXISTS'           
        ),
        array( 
            'key'=>'custom_author_name',
            'compare' => 'NOT EXISTS'           
        )
    ),
    'posts_per_page'=>-1
);

$query = new WP_Query($args);

echo $query->found_posts;

Những gì nó làm là sử dụng một truy vấn meta nâng cao tìm kiếm các bài đăng và không có khóa meta đó được khai báo. Vì cái có EXISTStrước, nên khi bạn sắp xếp theo meta_value, nó sẽ sử dụng truy vấn đầu tiên.


3
Điều này hoàn toàn không thay đổi thứ tự đối với tôi, khi tôi sử dụng 'orderby' => 'meta_value', nó đã thay đổi thứ tự, nhưng nó không liên quan gì đến trường meta thực tế.
Jake

3

Tôi đã cố gắng áp dụng câu trả lời @Manny Fleurmond và như @Jake tôi không thể làm cho nó làm việc ngay cả sau khi sửa chữa các lỗi đánh máy mà 'orderby' => 'meta_key'nên 'orderby' => 'meta_value'. (Và cho đầy đủ nó phải 'posts_per_page'không 'post_per_page'nhưng điều đó không ảnh hưởng đến vấn đề này đang được xem xét.)

Nếu bạn nhìn vào truy vấn SQL thực sự được tạo bởi câu trả lời của @Manny Fleurmond (đã sửa lỗi chính tả) thì đây là những gì bạn nhận được:

SELECT   wp_{prefix}_posts.* FROM wp_{prefix}_posts
LEFT JOIN wp_{prefix}_postmeta ON (wp_{prefix}_posts.ID = wp_{prefix}_postmeta.post_id AND wp_{prefix}_postmeta.meta_key = 'custom_author_name' )
LEFT JOIN wp_{prefix}_postmeta AS mt1 ON ( wp_{prefix}_posts.ID = mt1.post_id )
WHERE 1=1  AND ( 
    wp_{prefix}_postmeta.post_id IS NULL 
    OR 
    mt1.meta_key = 'custom_author_name'
) AND wp_{prefix}_posts.post_type = 'news' AND
(wp_{prefix}_posts.post_status = 'publish' OR wp_{prefix}_posts.post_author = 1 AND wp_{prefix}_posts.post_status = 'private')
GROUP BY wp_{prefix}_posts.ID ORDER BY wp_{prefix}_postmeta.meta_value ASC

Điều này minh họa cách WP phân tích các vars truy vấn: nó tạo một bảng cho mỗi mệnh đề meta_query, sau đó tìm ra cách tham gia chúng và sắp xếp thứ tự. Việc đặt hàng sẽ hoạt động tốt nếu bạn chỉ sử dụng một mệnh đề duy nhất với 'compare' => 'EXISTS', nhưng việc kết hợp 'compare' => 'NOT EXISTS'mệnh đề thứ hai với OR (như chúng ta phải) làm rối trật tự. Kết quả là LEFT THAM GIA được sử dụng để tham gia cả mệnh đề / bảng đầu tiên và mệnh đề / bảng thứ hai - và cách WP đặt mọi thứ lại với nhau có nghĩa là bảng được tạo bằng cách sử dụng 'compare' => 'EXISTS'thực sự được điền với meta_values ​​từ bất kỳ trường tùy chỉnh nào, không chỉ 'custom_author_name'trường chúng tôi quan tâm. Vì vậy, tôi nghĩ rằng việc đặt hàng theo mệnh đề / bảng đó sẽ chỉ cho kết quả mong muốn nếu post_type cụ thể của 'news' chỉ có một trường tùy chỉnh duy nhất.

Giải pháp hiệu quả cho tình huống của tôi là đặt hàng theo mệnh đề / bảng khác - không phải là EXISTS. Tôi dường như phản trực giác, nhưng vì cách WP phân tích cú pháp truy vấn, đây là bảng meta_valuechỉ được điền bởi trường tùy chỉnh mà chúng ta đang theo dõi.

(Cách duy nhất tôi tìm ra điều này là bằng cách chạy tương đương với truy vấn này cho trường hợp của tôi:

SELECT   wp_{prefix}_posts.ID, wp_{prefix}_postmeta.meta_value, mt1.meta_value FROM wp_{prefix}_posts
LEFT JOIN wp_{prefix}_postmeta ON (wp_{prefix}_posts.ID = wp_{prefix}_postmeta.post_id AND wp_{prefix}_postmeta.meta_key = 'custom_author_name' )
LEFT JOIN wp_{prefix}_postmeta AS mt1 ON ( wp_{prefix}_posts.ID = mt1.post_id )
WHERE 1=1  AND ( 
    wp_{prefix}_postmeta.post_id IS NULL 
    OR 
    mt1.meta_key = 'custom_author_name'
) AND wp_{prefix}_posts.post_type = 'news' AND
(wp_{prefix}_posts.post_status = 'publish' OR wp_{prefix}_posts.post_author = 1 AND wp_{prefix}_posts.post_status = 'private')
ORDER BY wp_{prefix}_postmeta.meta_value ASC

Tất cả những gì tôi đã làm là thay đổi các cột được hiển thị và xóa mệnh đề GROUP BY. Điều này sau đó cho tôi thấy những gì đang diễn ra - rằng cột postmeta.meta_value đang kéo các giá trị từ tất cả các meta_keys, trong khi cột mt1.meta_value chỉ kéo theo meta_values ​​từ trường tùy chỉnh tin tức.)

Giải pháp

Như @Manny Fleurmond nói, đây là mệnh đề đầu tiên được sử dụng cho người đặt hàng, vì vậy câu trả lời chỉ là hoán đổi vòng mệnh đề, đưa ra điều này:

$args = array(
    'post_type' => 'news',
    'orderby' => 'meta_value',
    'order' => 'ASC',
    'meta_query' => array(
        'relation' => 'OR',
        array( 
            'key' => 'custom_author_name',
            'compare' => 'NOT EXISTS'           
        ),
        array( 
            'key' => 'custom_author_name',
            'compare' => 'EXISTS'           
        )
    ),
    'posts_per_page' => -1
);

$query = new WP_Query($args);

Ngoài ra, bạn có thể tạo các mệnh đề liên kết mảng và sắp xếp theo khóa tương ứng, như vậy:

$args = array(
    'post_type' => 'news',
    'orderby' => 'not_exists_clause',
    'order' => 'ASC',
    'meta_query' => array(
        'relation' => 'OR',
        'exists_clause' => array( 
            'key' => 'custom_author_name',
            'compare' => 'EXISTS'           
        ),
        'not_exists_clause' => array( 
            'key' => 'custom_author_name',
            'compare' => 'NOT EXISTS'           
        )
    ),
    'posts_per_page' => -1
);

$query = new WP_Query($args);

Thật đáng để chỉ ra rằng nếu khóa meta custom_author_nameđược đặt và sau đó không được đặt, điều đó meta_keysẽ đáp ứng EXISTSvà hiệu quả sẽ là những khóa đó sẽ được đưa lên cùng với các bài đăng có custom_author_name. Trong trường hợp của tôi, tôi có một hộp kiểm vì vậy tôi đang sử dụng "value" => "1"thay vì EXISTS, nhưng các chuỗi sẽ cần một cách tiếp cận khác.
djb

1

Đó thực sự là cách nó hoạt động.

Nếu bạn muốn làm điều đó mà không cần thêm các hàng của bảng, bạn sẽ phải thực hiện hai truy vấn. Một cái có meta_key có kết quả giới hạn và cái còn lại có toàn bộ danh sách; sau đó sử dụng PHP để so sánh hai kết quả truy vấn (có thể xóa kết quả meta_key khỏi truy vấn khác để loại bỏ trùng lặp hoặc bất cứ điều gì có ý nghĩa trong cài đặt của bạn).


0

Thật không may, đó không phải là cách làm WP_Queryviệc. Ngay sau khi bạn thêm thành phần "meta" đó, bạn đã tạo một loại bộ lọc. Dump $query->requestvà bạn sẽ thấy những gì tôi có ý nghĩa.

Thứ hai, WP_Querykhông hỗ trợ đặt hàng bởi một khóa meta nào cả. Bạn có thể đặt hàng theo một giá trị meta cho một khóa cụ thể nhưng không có chính nó. Một lần nữa, kết xuất truy vấn để xem những gì tôi có ý nghĩa. Bạn sẽ nhận thấy rằng các thành phần "đặt hàng" sẽ bị loại bỏ nếu bạn thử.

Theo tôi, cách sạch nhất để làm việc này là một vài bộ lọc ngắn:

function join_meta_wpse_188287($join) {
  remove_filter('posts_join','join_meta_wpse_188287');
  global $wpdb;
  return ' INNER JOIN '.$wpdb->postmeta.' ON ('.$wpdb->posts.'.ID = '.$wpdb->postmeta.'.post_id)';
}
add_filter('posts_join','join_meta_wpse_188287');

function orderby_meta_wpse_188287($orderby) {
  remove_filter('posts_orderby','orderby_meta_wpse_188287');
  global $wpdb;
  return $wpdb->postmeta.'.meta_key ASC';
}
add_filter('posts_orderby','orderby_meta_wpse_188287');

$args = array(
    'post_type' => 'news',
    'post_per_page'=>-1
);
$q = new WP_Query($args);
var_dump($q->request); // debug
var_dump(wp_list_pluck($q->posts,'post_title')); // debug
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.