Nilai meta_value hanya mengembalikan pos yang memiliki meta_key yang ada

10

Saya punya wp_query berikut:

$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;

gema = 10 hasil karena hanya ada 10 newsposting dengan a meta_key = custom_author_name. Tetapi ada ratusan newsposting yang tidak memiliki baris post_meta dengan meta_key tertentu. Harap perhatikan, bahwa tidak ada meta_query yang terlibat. Tidak ada meta_value yang ditetapkan, karena saya hanya mencoba mengurutkan posting berdasarkan meta_key, dan tidak memfilter berdasarkan meta_value.

Bukankah seharusnya Orderby memilih semua posting? dan hanya memesannya?

Jika demikian mengapa hasilnya disaring? Jika meta_key tidak ditemukan, mengapa tidak menggunakan string kosong saja, atau cocokkan semua?

Jika tidak, mengapa tidak?

Jika saya memasukkan meta_key ke setiap posting berita (meskipun itu adalah string kosong) maka saya mendapatkan hasil yang diharapkan. Tapi itu sepertinya banyak baris tabel yang tidak perlu ada di sana.

gdaniel
sumber

Jawaban:

10

Seperti yang dinyatakan dalam jawaban @ ambroseya, seharusnya berfungsi seperti itu. Setelah Anda menyatakan permintaan meta, bahkan jika Anda tidak mencari nilai tertentu, itu hanya akan meminta posting dengan kunci meta yang dideklarasikan. Jika Anda ingin memasukkan semua posting, sortir dengan kunci meta, gunakan kode berikut:

$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;

Apa yang dilakukan adalah menggunakan kueri meta lanjutan yang mencari posting yang dilakukan dan tidak memiliki kunci meta yang dideklarasikan. Karena yang EXISTSpertama adalah, ketika Anda mengurutkan berdasarkan meta_value, itu akan menggunakan permintaan pertama.

Manny Fleurmond
sumber
3
Ini tidak mengubah urutan sama sekali untuk saya, ketika saya menggunakan 'orderby' => 'meta_value', itu mengubah urutan, tetapi tidak ada hubungannya dengan bidang meta yang sebenarnya.
Jake
3

Saya mencoba menerapkan jawaban @Manny Fleurmond dan menyukai @Jake saya tidak bisa membuatnya bekerja bahkan setelah memperbaiki kesalahan ketik yang 'orderby' => 'meta_key'seharusnya 'orderby' => 'meta_value'. (Dan untuk kelengkapannya seharusnya 'posts_per_page'tidak 'post_per_page'tetapi itu tidak mempengaruhi masalah yang sedang dilihat.)

Jika Anda melihat kueri SQL yang sebenarnya dihasilkan oleh jawaban @Manny Fleurmond (setelah memperbaiki kesalahan ketik) inilah yang Anda dapatkan:

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

Ini menggambarkan cara WP mem-parsing kueri vars: itu membuat tabel untuk setiap klausa meta_query, kemudian mencari cara untuk bergabung dengan mereka dan apa yang harus dipesan. Pemesanan akan berfungsi dengan baik jika Anda hanya menggunakan satu klausa dengan 'compare' => 'EXISTS', tetapi bergabung dengan 'compare' => 'NOT EXISTS'klausa kedua dengan ATAU (karena kami harus) mengacaukan pemesanan. Hasilnya adalah LEFT JOIN digunakan untuk bergabung dengan klausa / tabel pertama dan klausa / tabel kedua - dan cara WP menyatukan semuanya berarti bahwa tabel yang dibuat menggunakan 'compare' => 'EXISTS'sebenarnya diisi dengan meta_values ​​dari bidang kustom APA PUN, bukan hanya 'custom_author_name'bidang yang kami minati. Jadi saya pikir memesan dengan klausa / tabel itu hanya akan memberikan hasil yang diinginkan jika post_type khusus dari 'berita' hanya memiliki satu bidang khusus.

Solusi yang bekerja untuk situasi saya adalah memesan dengan klausa lain / tabel - yang TIDAK ADA. Tampaknya kontra-intuitif, saya tahu, tetapi karena cara WP mem-parsing kueri vars inilah tabel ini tempat meta_valuedihuni hanya oleh bidang kustom yang kita kejar.

(Satu-satunya cara saya menemukan ini adalah dengan menjalankan yang setara dengan permintaan ini untuk kasus saya:

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

Yang saya lakukan adalah mengubah kolom yang ditampilkan dan menghapus klausa GROUP BY. Ini kemudian menunjukkan kepada saya apa yang sedang terjadi - bahwa kolom postmeta.meta_value menarik nilai dari semua meta_keys, sedangkan kolom mt1.meta_value hanya menarik meta_values ​​dari bidang kustom berita.)

Solusinya

Seperti yang dikatakan @Manny Fleurmond, ini adalah klausa pertama yang digunakan untuk orderby, jadi jawabannya adalah dengan menukar babak klausa, dengan memberikan ini:

$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);

Atau Anda dapat membuat array asosiatif klausa dan memesan dengan kunci yang sesuai, seperti:

$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);
jlad26
sumber
Perlu ditunjukkan bahwa jika meta key custom_author_namediset dan kemudian tidak disetel, itu meta_keyakan merespons EXISTSdan efeknya adalah mereka akan digelembungkan di samping postingan yang memiliki a custom_author_name. Dalam kasus saya, saya memiliki kotak centang jadi saya menggunakan "value" => "1"bukan EXISTS, tetapi string akan membutuhkan pendekatan yang berbeda.
djb
1

Sebenarnya itu cara kerjanya.

Jika Anda ingin melakukannya tanpa menambahkan baris tabel, Anda harus melakukan dua kueri. Satu dengan meta_key yang memiliki hasil terbatas, dan lainnya yang mendapat seluruh daftar; kemudian gunakan PHP untuk membandingkan dua hasil permintaan (mungkin menghapus hasil meta_key dari permintaan lain untuk menghapus duplikat, atau apa pun yang masuk akal dalam pengaturan Anda).

ambroseya
sumber
0

Sayangnya, itu bukan cara WP_Querykerjanya. Segera setelah Anda menambahkan komponen "meta" itu, Anda telah membuat semacam filter. Buang $query->requestdan Anda akan melihat apa yang saya maksud.

Kedua, sama WP_Querysekali tidak mendukung pemesanan dengan kunci meta . Anda dapat memesan dengan nilai meta untuk kunci tertentu tetapi tidak dengan kunci itu sendiri. Sekali lagi, buang permintaan untuk melihat apa yang saya maksud. Anda akan melihat bahwa komponen "pesanan" keluar jika Anda mencoba.

Menurut saya, cara paling bersih untuk menjalankannya adalah beberapa filter pendek:

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
s_ha_dum
sumber