Orderby meta_value ส่งคืนโพสต์ที่มี meta_key อยู่แล้วเท่านั้น


10

ฉันมี wp_query ต่อไปนี้:

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

ผลสะท้อน = 10 เพราะมีเพียง 10 โพสต์ด้วยnews meta_key = custom_author_nameแต่มีnewsโพสต์หลายร้อยรายการที่ไม่มีแถว post_meta พร้อม meta_key เฉพาะนั้น โปรดสังเกตว่า meta_query ไม่มีส่วนเกี่ยวข้อง ไม่มีการกำหนด meta_value เนื่องจากฉันพยายามเรียงลำดับโพสต์ตาม meta_key เท่านั้นและไม่กรองตาม meta_value

ไม่ควรสั่งซื้อโดยเลือกโพสต์ทั้งหมด? และเพียงแค่สั่งพวกเขา?

ถ้าใช่เหตุใดจึงมีการกรองผลลัพธ์ หากไม่พบ meta_key ทำไมไม่ใช้เพียงสตริงว่างหรือตรงกันทั้งหมด

ถ้าไม่ทำไมล่ะ

ถ้าฉันป้อน meta_key ให้กับทุกโพสต์ข่าว (แม้ว่าจะเป็นสตริงว่าง) ฉันก็จะได้ผลลัพธ์ตามที่คาดหวัง แต่ดูเหมือนว่าจะมีแถวของตารางจำนวนมากที่ไม่จำเป็นต้องอยู่ที่นั่น

คำตอบ:


10

ตามที่ระบุไว้ในคำตอบ @ Ambroseya ของมันควรจะทำงานเช่นนั้น เมื่อคุณประกาศข้อความค้นหาเมตาแม้ว่าคุณจะไม่ได้มองหาค่าที่เฉพาะเจาะจงก็จะค้นหาเฉพาะโพสต์ด้วยคีย์เมตาที่ประกาศ หากคุณต้องการรวมโพสต์ทั้งหมดเรียงลำดับพวกเขาด้วยเมตาคีย์ใช้รหัสต่อไปนี้:

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

สิ่งนี้ใช้การสืบค้นเมตาขั้นสูงที่ค้นหาโพสต์ที่ทำและไม่มีการประกาศเมตาคีย์ เนื่องจากหนึ่งในEXISTSนั้นเป็นอันดับแรกเมื่อคุณเรียงลำดับmeta_valueมันจะใช้คิวรีแรก


3
สิ่งนี้ไม่ได้เปลี่ยนลำดับเลยสำหรับฉันเมื่อฉันใช้'orderby' => 'meta_value'มันจะเปลี่ยนลำดับ แต่ก็ไม่มีอะไรเกี่ยวข้องกับเขตข้อมูลเมตาจริง
Jake

3

ฉันพยายามที่จะใช้คำตอบ @Manny Fleurmond และเหมือน @Jake ฉันไม่สามารถได้รับมันในการทำงานแม้หลังจากการแก้ไขพิมพ์ผิดที่ควรจะเป็น'orderby' => 'meta_key' 'orderby' => 'meta_value'(และเพื่อความสมบูรณ์ก็ควรจะ'posts_per_page'ได้'post_per_page'แต่ไม่ได้ส่งผลกระทบต่อปัญหาการถูกมองที่.)

ถ้าคุณดูที่แบบสอบถาม SQL ที่สร้างขึ้นจริงโดยคำตอบของ @Manny Fleurmond (แก้ไขข้อผิดพลาด) นี่คือสิ่งที่คุณได้รับ:

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

สิ่งนี้แสดงให้เห็นถึงวิธีที่ WP ทำการแยกวิเคราะห์ vars แบบสอบถาม: มันกำลังสร้างตารางสำหรับแต่ละ meta_query clause แล้วหาวิธีที่จะเข้าร่วมและสิ่งที่จะสั่งซื้อ การสั่งซื้อจะทำงานได้ดีถ้าคุณใช้เพียงประโยคเดียว'compare' => 'EXISTS'แต่เข้าร่วม'compare' => 'NOT EXISTS'ข้อที่สองกับ OR (ตามที่เราต้อง) ทำให้การสั่งซื้อยุ่งเหยิง ผลลัพธ์คือ LEFT JOIN ถูกใช้เพื่อเข้าร่วมทั้ง clause / table แรกและ clause / table ที่สอง - และวิธีที่ WP รวมทุกอย่างเข้าด้วยกันหมายความว่าตารางที่สร้างโดยใช้'compare' => 'EXISTS'นั้นถูกเติมด้วย meta_values ​​จากฟิลด์ที่กำหนดเองใด ๆ'custom_author_name'ฟิลด์ที่เราสนใจดังนั้นฉันคิดว่าการเรียงลำดับคำสั่ง / ตารางนั้นจะให้ผลลัพธ์ที่ต้องการหาก post_type เฉพาะของ 'news' มีเฉพาะฟิลด์ที่กำหนดเองเท่านั้น

ทางออกที่ทำงานกับสถานการณ์ของฉันคือการสั่งซื้อโดยข้ออื่น ๆ / ตาราง - ไม่มีอยู่อย่างใดอย่างหนึ่ง ดูเหมือนว่าฉันรู้ตัวง่ายทวน แต่เนื่องจากวิธี WP วิเคราะห์คำ vars แบบสอบถามมันเป็นตารางนี้ที่meta_valueมีประชากรเพียงโดยฟิลด์ที่กำหนดเองที่เราอยู่หลังจาก

(วิธีเดียวที่ฉันคิดว่านี่คือการใช้งานการเทียบเท่าของแบบสอบถามนี้สำหรับกรณีของฉัน:

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

สิ่งที่ฉันทำคือเปลี่ยนคอลัมน์ที่จะแสดงและลบประโยค GROUP BY นี่แสดงให้ฉันเห็นว่าเกิดอะไรขึ้น - คอลัมน์ postmeta.meta_value กำลังดึงค่าจาก meta_keys ทั้งหมดในขณะที่คอลัมน์ mt1.meta_value กำลังดึงเฉพาะ meta_values ​​จากเขตข้อมูลข่าวที่กำหนดเอง)

การแก้ไขปัญหา

@Manny Fleurmond พูดว่ามันเป็นประโยคแรกที่ใช้สำหรับออร์เดอร์บายดังนั้นคำตอบคือเพียงแค่สลับรอบคำสั่งโดยให้สิ่งนี้:

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

หรือคุณสามารถสร้างส่วนเชื่อมโยงคำสั่งและลำดับโดยคีย์ที่เกี่ยวข้องเช่น:

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

มันคุ้มค่าที่ชี้ให้เห็นว่าถ้าคีย์เมตาcustom_author_nameมีการตั้งค่าและล้างแล้วว่าmeta_keyจะตอบสนองต่อและผลกระทบที่จะเป็นไปได้ว่าผู้ที่จะได้รับการฟองขึ้นควบคู่ไปกับการโพสต์ที่จะมีEXISTS custom_author_nameในกรณีของฉันฉันมีช่องทำเครื่องหมายดังนั้นฉันจึงใช้"value" => "1"แทนEXISTSแต่สตริงจะต้องใช้วิธีอื่น
djb

1

นั่นเป็นวิธีการทำงานจริง

หากคุณต้องการทำเช่นนั้นโดยไม่เพิ่มแถวของตารางคุณจะต้องทำสองแบบสอบถาม หนึ่งที่มี meta_key ที่มีผลลัพธ์ที่ จำกัด และอื่น ๆ ที่ได้รับทั้งรายการ; จากนั้นใช้ PHP เพื่อเปรียบเทียบผลลัพธ์แบบสอบถามทั้งสอง (อาจลบผลลัพธ์ meta_key จากแบบสอบถามอื่นเพื่อลบรายการที่ซ้ำกันหรืออะไรก็ตามที่เหมาะสมในการตั้งค่าของคุณ)


0

น่าเสียดายที่นั่นไม่ใช่วิธีการใช้WP_Queryงาน ทันทีที่คุณเพิ่มองค์ประกอบ "meta" คุณจะสร้างตัวกรองชนิดหนึ่ง ถ่ายโอนข้อมูล$query->requestแล้วคุณจะเห็นสิ่งที่ฉันหมายถึง

ประการที่สองWP_Queryไม่รองรับการสั่งซื้อโดยใช้เมตาคีย์เลย คุณสามารถสั่งซื้อด้วยค่าเมตาสำหรับคีย์เฉพาะ แต่ไม่สามารถกำหนดได้ด้วยตัวเอง อีกครั้งให้ทิ้งคิวรีเพื่อดูว่าฉันหมายถึงอะไร คุณจะสังเกตเห็นว่าองค์ประกอบ "คำสั่งซื้อ" เลื่อนออกหากคุณลอง

วิธีที่สะอาดที่สุดในการทำให้สิ่งนี้ทำงานได้ในความคิดของฉันคือตัวกรองสั้น ๆ สองสามตัว:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.