เรียงตามค่าเมตา แต่รวมถึงโพสต์ที่ไม่มี


37

ฉันแก้ไขการค้นหา WP ในตัวโดยใช้pre_get_postsตัวกรองทำให้ผู้ใช้สามารถเรียงลำดับโพสต์ (รวมถึงโพสต์ที่กำหนดเองจำนวนมาก) ตามเขตข้อมูลที่แตกต่างกัน

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

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

ฉันรู้วิธีเรียงลำดับมากกว่าหนึ่งฟิลด์ แต่นั่นไม่ได้ช่วย

ขอบคุณ

ดูเหมือนว่าฉันไม่ใช่คนเดียวที่มีคำถามนี้: วิธีรวมโพสต์ทั้งที่มี & ไม่มี meta_key บางรายการใน args สำหรับ wp_query หรือไม่ แต่ก็ไม่มีทางออก

ปรับปรุง

ฉันลองคำตอบแล้ว แต่ไม่แน่ใจว่าฉันเข้าใจถูกต้องหรือไม่นี่คือสิ่งที่ฉันมีตอนนี้:

<?php
function my_stuff ($qry) {
    $qry->set('meta_query', array(array(
        'key' => 'item_price', 
        'value' => '', 
        'compare' => 'NOT EXISTS'
    )));

    $qry->set('orderby', 'meta_value date'); # Sorting works with meta_value as well as meta_value_num - I've tried both
    $qry->set('order', 'ASC DESC');
    $qry->set('meta_key', 'item_price');
}

ค่าเมตาคือตัวเลข (ใช้เพื่อเก็บราคาตามชื่อที่แนะนำ)

อัปเดต 2

ฉันได้แสดงความคิดเห็นเกี่ยวกับการสั่งซื้อและตอนนี้ที่ฉันมีคือ:

<?php
$qry->set('meta_query', array(array(
    'key' => 'item_price', 
    'value' => '', 
    'compare' => 'NOT EXISTS'
)));

ด้วยรหัสนี้ดูเหมือนว่าแบบสอบถามจะส่งคืนโพสต์ทั้งหมดที่ไม่มีitem_priceคีย์และไม่มีโพสต์ที่มีอยู่ IE ปัญหากลับตอนนี้

ถ้าฉันเพิ่มในรหัสการสั่งซื้อเช่นกันฉันจะได้รับผลลัพธ์ 0

แก้ไข: ... สามปีต่อมา ... : PI มีปัญหานี้อีกครั้ง ฉันลองคำตอบทั้งหมดที่ได้รับ แต่ก็ไม่ทำงาน ไม่แน่ใจว่าทำไมบางคนถึงคิดว่าพวกเขาทำงาน แต่พวกเขาไม่ได้ทำงานให้ฉันอย่างน้อย

วิธีแก้ปัญหาที่ฉันใช้คือการใช้save_postตัวกรองทำให้แน่ใจว่าโพสต์ทั้งหมดมีฟิลด์ที่กำหนดเองที่ฉันต้องการเรียงลำดับ มันน่ารำคาญนิดหน่อยที่ฉันต้องทำ แต่ตราบใดที่คุณทำตั้งแต่เนิ่น ๆ คุณอาจจะไม่มีปัญหา

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

add_action('save_post', function ($postId) {
    add_post_meta($postId, '_sleek_view_count', 0, true);
});

กรุณาแสดงรหัสของคุณ ทำให้ง่ายต่อการตอบ
ไกเซอร์

แม่: meta_queryและtax_queryมีเสมอarray( array() )ที่พวกเขารวมอาร์เรย์หลาย ประการที่สอง - ตามที่ระบุไว้ในคำตอบของฉัน - คุณต้องใช้meta_value_numสำหรับตัวเลข มันอาจจำเป็นต้องกำหนดจริง ๆmeta_value_num(ดูWP_Queryรายการหน้า -Codex) ที่ผ่านมาก็ไม่ได้ทำให้ความรู้สึกที่จะorderอยู่ในASC และ DESCทิศทาง มันเป็นไปไม่ได้. คั่นพื้นที่ทำงานเฉพาะสำหรับorderbyและคุณไม่สามารถบอกได้ว่ามันจะเรียงลำดับแรกและครั้งที่สองASC DESCนั่นคือสิ่งที่posts_clausesตัวกรองมีไว้เพื่อ
kaiser

และตรวจสอบให้แน่ใจว่าmeta_value_numรายการของคุณเป็นตัวเลขจริง เห็นบ่อยเกินไปว่ามีคนระบุว่าเป็นตัวเลข แต่ในความเป็นจริงการบันทึกเป็นสตริงในฐานข้อมูล
kaiser

ขอบคุณสำหรับความช่วยเหลือของคุณฉันจะลองและกลับไปหาคุณ เหตุผลASC DESCก็คือเพื่อให้มันเรียงลำดับmeta_valueในASCและdateในDESCเท่าที่ฉันสามารถบอกได้ว่ามันทำงาน
powerbuoy

1
@Howdy_McGee ที่ถูกต้อง โพสต์ที่กำหนดเองของฉันบางประเภทมีชุดค่านี้ บางคนทำไม่ได้ และโพสต์ในประเภทโพสต์ (เช่นโพสต์และหน้า) ไม่ ดังนั้นเมื่อใดก็ตามที่ฉันพยายามเรียงลำดับในฟิลด์ที่กำหนดเองโพสต์เฉพาะกับฟิลด์ที่กำหนดเองปรากฏขึ้น
powerbuoy

คำตอบ:


4

มีสองวิธีแก้ปัญหาที่เป็นไปได้นี้:

1. โพสต์ทั้งหมดมีเมตา

ทางออกที่ดีที่สุดที่ฉันได้พบที่นี่คือการให้ส่วนที่เหลือของการโพสต์ / ผลิตภัณฑ์ราคาของ 0 คุณสามารถทำได้ด้วยตนเองหรือวนรอบโพสต์ทั้งหมดและถ้าราคาว่างแล้วอัปเดต

เพื่อให้การจัดการนี้ในอนาคตคุณสามารถขอsave_postและให้พวกเขามีค่าเมื่อพวกเขาถูกเพิ่มครั้งแรก (เฉพาะถ้าว่างเปล่า)

2. แบบสอบถามหลายรายการ

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

จากนั้นคุณสามารถพิมพ์ผลลัพธ์สองรายการแยกกันและคุณจะได้ผลลัพธ์ที่ต้องการ


1
สามปีต่อมาและฉันมีปัญหาเดียวกันอีกครั้ง: P ต้องใช้save_postวิธีนี้ (ฉันได้อัปเดตคำถามของฉันด้วยรหัสที่ฉันใช้)
powerbuoy

10

Easy Peasy เพิ่งทดสอบปี 2018 ที่ใช้ในการผลิตปัจจุบัน

$query->set( 'meta_query', array(
    'relation' => 'OR',
    array(
        'key' => 'custom_meta_key', 
        'compare' => 'EXISTS'
    ),
    array(
        'key' => 'custom_meta_key', 
        'compare' => 'NOT EXISTS'
    )
) );
$query->set( 'orderby', 'meta_value title' ); 

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

ตัวอย่างการปฏิบัติ

/**
 * Modifies query before retrieving posts. Sets the 
 * `meta_query` and `orderby` param when no `orderby` 
 * param is set, (default ordering).
 * 
 * @param   WP_Query  $query  The full `WP_Query` object.
 * @return  void
 */
function example_post_ordering( $query ) {

    // if not in wp-admin, 
    // and the query is the main query, 
    // and the query is not a singular query, 
    // and the query does not have an orderby param set...
    // Note: check for post types, etc. here as desired.
    if ( ! is_admin() 
    && $query->is_main_query() 
    && ! $query->is_singular() 
    && empty( $query->get( 'orderby' ) ) ) {

        // Setting just `meta_key` is not sufficient, as this 
        // will ignore posts that do not yet, or never will have 
        // a value for the specified key. This meta query will 
        // register the `meta_key` for ordering, but will not 
        // ignore those posts without a value for this key.
        $query->set( 'meta_query', array(
            'relation' => 'OR',
            array(
                'key' => 'custom_meta_key', 
                'compare' => 'EXISTS'
            ),
            array(
                'key' => 'custom_meta_key', 
                'compare' => 'NOT EXISTS'
            )
        ) );

        // Order by the meta value, then by the title if multiple 
        // posts share the same value for the provided meta key.
        // Use `meta_value_num` if the meta values are numeric.
        $query->set( 'orderby', 'meta_value title' );
    }

}

add_action( 'pre_get_posts', 'example_post_ordering', 10 );

สิ่งนี้จะเรียงลำดับการโพสต์ตามcustom_meta_keyค่าเริ่มต้นและจะไม่ข้ามโพสต์โดยไม่มีค่าสำหรับคีย์นั้น


เพียงแค่จากการอ่านรหัสทั้งหมดที่ดูเหมือนว่าจะทำคือการได้รับการโพสต์ที่มีcustom_meta_keyและได้รับการโพสต์ Whick ไม่custom_meta_keyได้ อย่าลังเลที่จะรวมตัวอย่างการทำงานจริงกับการเรียงลำดับ
powerbuoy

1
คุณถูกต้องนั่นคือทั้งหมดที่ทำ แต่บรรทัดด้านล่างมีหน้าที่รับผิดชอบในการสั่งซื้อโดย meta_value (ของคีย์ meta ที่ถูกสอบถาม) $query->set( 'orderby', 'meta_value title' );(เรียงตามค่าเมตาจากนั้นตามชื่อเมื่อโพสต์หลายรายการมีค่าเดียวกันสำหรับคีย์เมตา) สิ่งนี้ควรทำในpre_get_postsเบ็ดโดยใช้$queryตัวแปรส่งผ่าน โปรดจำไว้ว่าคำถามที่ถามคือวิธีการสั่งซื้อตามค่าเมตาขณะที่ไม่สนใจโพสต์ที่ไม่มีค่าสำหรับเมตาคีย์นั้น
noahmason

@powerbuoy ดูตัวอย่างการปฏิบัติที่ปรับปรุงแล้ว
noahmason

เอาล่ะฉันจะปล่อยมันไปในครั้งต่อไปที่ฉันกำลังประสบปัญหานี้
powerbuoy

1
ทำงานให้ฉันในการget_posts()โทรที่กำหนดเองเพื่อผลักโพสต์ด้วย_featuredเมตาไปด้านบนจากนั้นเรียงตามวันที่หลังจากนั้น ขอบคุณ!
natebeaty

8

วิธีนี้จะส่งคืนโพสต์ทั้งหมดรวมถึงโพสต์ที่มีและไม่มีการร้องขอmeta_keyแต่จะทำสิ่งแปลก ๆ เมื่อสั่งซื้อ

add_action('pre_get_posts', 'my_stuff');
function my_stuff ($qry) {
    $qry->set(
        'meta_query',
        array(
            'relation' => 'OR', # Matches to this meta_query should be added to those matching the 'meta_key' query
            array(
                'key' => 'item_price', 
                'value' => 'bug #23268', 
                'compare' => 'NOT EXISTS'
            )
        )
    );

    $qry->set('orderby', 'meta_value date'); # Sorting works with meta_value as well as meta_value_num - I've tried both
    $qry->set('order', 'ASC DESC');
    $qry->set('meta_key', 'item_price');
}

ฉันพบสิ่งนี้โดยเล่นซอกับคำตอบที่แตกต่างกันสำหรับคำถามนี้และวิเคราะห์SQL ที่สร้างขึ้นผ่านการลองผิดลองถูก ดูเหมือนว่าการตั้งค่าให้array('meta_query' => array('relation' => 'OR'))ผลลัพธ์ที่เหมาะสมLEFT JOINแทนที่จะINNER JOINเป็นสิ่งที่จำเป็นในการรวมโพสต์ที่ขาดเมทาดาทา การระบุการNOT EXISTSป้องกันส่วนWHEREคำสั่งจากการกรองโพสต์ที่ขาดเขตข้อมูลเมตา สำหรับกรณีนี้WP_QuerySQL ที่สร้างขึ้น (เพิ่มการเยื้อง / การขึ้นบรรทัดใหม่):

SELECT SQL_CALC_FOUND_ROWS
    wp_posts.ID
    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
    LEFT JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id AND mt1.meta_key = 'item_price')
    WHERE 1=1
    AND ( wp_term_relationships.term_taxonomy_id IN (2) )
    AND wp_posts.post_type = 'post'
    AND (wp_posts.post_status = 'publish'
        OR wp_posts.post_status = 'private')
    AND (wp_postmeta.meta_key = 'item_price'
        -- Oh look, here we give SQL permission to choose a random
        -- row from wp_postmeta when this particular post is missing
        -- 'item_price':
        OR  mt1.post_id IS NULL )
    GROUP BY wp_posts.ID
    ORDER BY wp_postmeta.meta_value,wp_posts.post_date DESC
    LIMIT 0, 10

ผลที่ได้คือรายชื่อของโพสต์ที่มี meta_value ของและผู้ที่ขาดหายไปitem_price item_priceโพสต์ทั้งหมดที่มีitem_priceจะได้รับการสั่งซื้ออย่างถูกต้องเทียบกับแต่ละอื่น ๆ แต่การโพสต์หายไปitem_priceจะใช้บางสุ่มอื่น ๆมูลค่าเมตา (พูด_edit_lastซึ่งดูเหมือนว่าจะ1ค่อนข้างบ่อยในฐานข้อมูลหรือเมตาดาต้า WordPress ภายในอื่น ๆ ที่เป็นพลสมบูรณ์ของฉัน) สำหรับด้านwp_postmeta.meta_valueในORDER BYข้อ ดังนั้นในขณะที่วิธีนี้อยู่ใกล้และอาจทำงานได้กับข้อมูลบางอย่าง แต่มันก็เสีย ดังนั้นทั้งหมดที่ฉันสามารถพูดคือถ้าitem_priceค่าของคุณเกิดขึ้นไม่ขัดแย้งกับเขตข้อมูลเมตาแบบสุ่ม MySQL เลือกโพสต์ที่ขาดหายไปitem_priceสิ่งนี้อาจใช้ได้ดีสำหรับคุณ หากสิ่งที่คุณต้องการคือการรับประกันว่าโพสต์ของคุณด้วยitem_priceมีการสั่งซื้ออย่างถูกต้องเมื่อเทียบกับแต่ละอื่น ๆ โดยไม่คำนึงถึงการสั่งซื้อโพสต์อื่น ๆ มันอาจจะตกลง แต่ฉันคิดว่านี่เป็นเพียงข้อบกพร่องใน WordPress โปรดแก้ไขฉันฉันหวังว่าฉันผิดและมีวิธีการที่อยู่นี้ ;-)

ดูเหมือนว่าสำหรับINNER JOIN wp_postmeta, MySQL กำลังเลือกแถวสุ่มจากหลายpostmetaแถวที่เกี่ยวข้องกับการโพสต์เมื่อmeta_keyหายไปจากการโพสต์ที่กำหนด จากมุมมองของ SQL เราต้องคิดหาวิธีที่จะบอก WordPress ORDER BY mt1.meta_valueเพื่อการส่งออก คอลัมน์นี้ได้อย่างถูกต้องNULLเมื่อเราร้องขอจะหายไปซึ่งแตกต่างจากmeta_key wp_postmeta.meta_valueถ้าเราสามารถทำเช่นนั้น SQL จะเรียงลำดับNULL(รายการที่หายไป) เหล่านี้ก่อนค่าอื่น ๆ ทำให้เรามีคำสั่งที่ชัดเจน: อันดับแรกโพสต์ทั้งหมดหายไปในฟิลด์ postmeta โดยเฉพาะอันดับที่สองมีโพสต์ที่มีฟิลด์ แต่ที่เป็นปัญหาทั้งหมด: 'orderby' => 'meta_value'สามารถอ้างถึง'meta_key' => 'item_price' และ unaliased wp_postmetaอยู่เสมอINNER JOINแทนที่จะเคยLEFT JOINมีความหมายwp_postmeta.meta_valueและwp_postmeta.meta_keyสามารถไม่เคยNULLเป็น

ดังนั้นฉันคิดว่าฉันต้องบอกว่ามันเป็นไปไม่ได้กับ wordpress ในตัวWP_Queryเพราะตอนนี้มันเป็นเอกสาร (ใน wordpress-3.9.1) ตื๊อ ดังนั้นถ้าคุณต้องการจริงการทำงานอย่างถูกต้องคุณอาจจะต้องขอเข้าสู่ WordPress อื่น ๆ และแก้ไข SQL สร้างโดยตรง


ดูมีแนวโน้มมาก! ฉันจะลองในครั้งต่อไปที่ฉันมีปัญหานี้ ฉันต้องการให้คำตอบกับคุณในตอนนี้ แต่ต้องการยืนยันว่าใช้ได้กับฉันก่อน
powerbuoy

สิ่งนี้ทำให้ทุกอย่างไม่ปรากฏสำหรับฉัน ไม่มีอะไรแสดงให้เห็นหลังจากใช้งานสิ่งนี้
Jake

@ Jake เหมือนกันที่นี่ มีปัญหานี้อีกครั้งในวันนี้และลองสิ่งนี้ ส่งคืนผลลัพธ์ 0 รายการ
powerbuoy

คุณใช้ wordpress รุ่นไหน? ฉันคิดว่าโพสต์นี้อธิบายถึงวิธีการใช้ API ภายในที่ไม่มีเอกสารซึ่ง wordpress ไม่รองรับและอาจทำงานได้ก็ต่อเมื่อคุณใช้ wordpress-3.9.1 หรือมีหลายรุ่นที่เกินกว่านั้น
binki

2

ฉันคิดว่าฉันมีทางออก

คุณสามารถใช้สองmeta_keyรายการหนึ่งรายการที่โพสต์ทั้งหมดมี(like "_thumbnail_id")และmeta_keyคุณต้องการใช้เป็นตัวกรอง

ดังนั้นคุณ args:

$qry->set(
    'meta_query',
    array(
        'relation' => 'OR',
        array(
            'key' => 'item_price', 
            'value' => '', 
            'compare' => 'EXISTS'
        ),
        array(
            'key' => 'item_price', 
            'value' => '', 
            'compare' => 'EXISTS'
        )
    )
);

$qry->set('orderby', 'meta_value date'); # Sorting works with meta_value as well as meta_value_num - I've tried both
$qry->set('order', 'ASC DESC');
$qry->set('meta_key', 'item_price');

1
ปัญหาของที่นี่คือการเปรียบเทียบสตริงที่ว่างเปล่าลบออกและมัน'value' => '', ยังทำงานได้เปรียบเทียบที่สองควรNOT EXISTSและไม่จำเป็นต้องมีคำสั่งชุดสุดท้าย
nodws

2

ปัญหาที่ทุกคนในที่นี้เกี่ยวข้องกับการเรียงลำดับของการสืบค้นเมตา ในการจัดเรียงอย่างถูกต้องคุณจะต้องใส่ข้อความค้นหา "NOT EXISTS" ก่อนหน้าแบบสอบถาม"EXISTS"

เหตุผลนี้เป็นเพราะ WordPress ใช้ meta_value ของคำสั่ง "LEFT JOIN" ครั้งสุดท้ายในประโยค "ORDER BY"

ตัวอย่างเช่น:

$pageQuery = new WP_Query([
    'meta_query' => [
        'relation' => 'OR',
        ['key' => 'item_price', 'compare' => 'NOT EXISTS'], // this comes first!
        ['key' => 'item_price', 'compare' => 'EXISTS'],
    ],
    'order' => 'DESC',
    'orderby' => 'meta_value_num',
    'post_status' => 'publish',
    'post_type' => 'page',
    'posts_per_page' => 10,
]);

1

หากเหมาะสมคุณสามารถเพิ่มค่าเมตาเริ่มต้นในแต่ละครั้งที่บันทึกหรืออัปเดตโพสต์หากไม่มีค่าเมตา

function addDefaultMetaValue($post_id) {
    add_post_meta($post_id, 'item_price', 0, true);
}
add_action('save_post', 'addDefaultMetaValue');

หากคุณใช้ประเภทโพสต์ที่กำหนดเองให้แทนที่add_action('save_post', 'addDefaultMetaValue');ด้วยadd_action('save_post_{post_type}', 'addDefaultMetaValue');เช่นadd_action('save_post_product', 'addDefaultMetaValue');


1

ฉันมีปัญหาด้วยตัวเองสำหรับค่าเมตาตัวเลขและชี้ให้เห็นว่าลำดับของแบบสอบถามก็มีความสำคัญเช่นกัน สำหรับฉันNOT EXISTSแบบสอบถามจะต้องเป็นคนแรก

ตัวอย่าง:

$query->set( 'orderby', 'meta_value_num' );
$query->set( 'meta_query', [
    'relation' => 'OR',
    [ 'key' => 'your_meta_name', 'compare' => 'NOT EXISTS' ],
    [
        'key' => 'your_meta_name',
        'compare' => 'EXISTS',
    ],
] );

ยังเป็นสิ่งสำคัญเพื่อให้ได้ทิศทางที่ถูกต้องสำหรับค่าตัวเลขเป็นทั่วไปจะได้รับการตั้งค่าให้’orderby’ ’meta_value_num’มิฉะนั้นคุณจะได้ผลลัพธ์ที่แปลกประหลาดสำหรับค่าตัวเลขเช่น:

1, 2, 20, 21, 3, 4, 5 ...

แทน:

1, 2, 3, 4, 5 … 20, 21


1

ฉันยังพบปัญหาที่คล้ายกันและวิธีแก้ไขปัญหาต่อไปนี้ช่วยฉันด้วย:

$args = array(
'post_type' => 'kosh_products',
'posts_per_page' => -1,
'meta_query' => array(
    'relation' => 'OR',
    'category_sort_order' => array(
        'key' => '_sort_order',
        'compare' => 'EXISTS'
    ),
    'category_sort_order_not_exists' => array(
        'key' => '_sort_order',
        'compare' => 'NOT EXISTS'
    ), 
),
'orderby' => array( 
    'category_sort_order' => 'ASC',
    'date' => 'ASC'
));
$query = new WP_Query( $args );

ฉันพบคำอธิบายเกี่ยวกับ WordPress Codex ที่มีชื่อ " 'orderby' ที่มีหลาย 'meta_key's ": https://codex.wordpress.org/Class_Reference/WP_Query#Order_.26_Orderby_Parameters ป้อนคำอธิบายรูปภาพที่นี่


0

มีorderbyคุณค่าที่เป็นไปได้meta_valueสำหรับสิ่งนั้น

$query = new WP_Query( array ( 
    'meta_key'   => 'your_keys_name',
    'orderby'    => 'meta_value',
    'order'      => 'DESC',
    'meta_query' => array( array(
         'key'     => 'your_meta_key',
         'value'   => '',
         'compare' => 'NOT EXISTS',
         // 'type'    => 'CHAR',
    ) )
) );

หากคุณมีค่าตัวเลขให้ใช้meta_value_numแทน

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


ขอบคุณสำหรับคำตอบของคุณโปรดตรวจสอบคำถามที่อัปเดตของฉันฉันไม่แน่ใจว่าฉันเข้าใจคุณอย่างถูกต้อง
powerbuoy

ฉันยังไม่ได้ทำให้งานนี้ดังนั้นหากคุณมีทางออกฉันชอบที่จะรู้ว่าสิ่งที่ฉันทำผิด นอกจากนี้ฉันได้ตั้งค่าความนิยมบน SO หากคุณต้องการอ้างสิทธิ์: stackoverflow.com/questions/17016770/…
powerbuoy

1
สองสิ่ง. 'your_keys_name'และ'your_meta_key'ทั้งคู่ควรเป็นสตริงเดียวกันแทนที่จะแตกต่างกันมิฉะนั้นดูเหมือนว่าคุณเข้าใจผิดคำถาม ประการที่สองฉันทดสอบสิ่งนี้ในการตั้งค่าในพื้นที่และไม่รวมโพสต์ใด ๆ ที่มีคีย์อยู่ (ผ่านmeta_query) และไม่รวมโพสต์ที่คีย์หายไป (ผ่านmeta_key) ทำให้ไม่มีโพสต์ที่แสดง อย่างไรก็ตามคำตอบนี้เป็นขั้นตอนต่อสิ่งที่คำอย่างน้อย ;-)
binki

1
โอ้น่าสนใจคำตอบนี้ไม่ทำงานถ้าคุณเพียงแค่เพิ่มการ'relation' => 'OR' meta_queryสิ่งแปลกประหลาด o_o
binki

@binki เพียงแค่แก้ไขคำถามของฉันและเปลี่ยนบิตที่คุณคิดว่าควรจะเปลี่ยน นี้เป็นชุมชนที่ขับเคลื่อนเว็บไซต์ :)
Kaiser

0

ผมคิดว่าสิ่ง @kaiser ได้พยายามที่จะทำคือจะบอกแบบสอบถามที่จะกลับมาโพสต์ทั้งหมดที่มีคีย์ meta ที่โดยใช้การจัดเรียงของหุ่นที่เงื่อนไขจะไม่ได้กรองใด ๆ ของผู้โพสต์ ดังนั้นถ้าคุณรู้ว่าค่าทั้งหมดของคุณสามารถใช้ฟิลด์ที่กำหนดเองคือ x, y, z คุณสามารถพูดว่า "WHERE meta_key IN (x, y, z) " แต่ความคิดคือคุณสามารถหลีกเลี่ยงปัญหานั้นด้วยกันโดยพูด! = (' ') :

$query = new WP_Query( array ( 
    'orderby'    => 'meta_value_num',
    'order'      => 'DESC',
    'meta_query' => array( array(
         'key'     => 'item_price',
         'value'   => '',
         'compare' => '!=',
    ) )
) );

ยังไม่ได้ทดสอบ แต่รู้สึกว่ามันคุ้มค่าลอง :-)


1
ไม่สามารถทดสอบได้ในขณะนี้ แต่ค่อนข้างแน่ใจว่าจะส่งคืนโพสต์ที่มีการตั้งค่า item_price เท่านั้นและไม่ใช่ ''
powerbuoy

0

ฉันลงเอยด้วยการแฮ็ค (IMHO) สักหน่อย แต่มันก็ทำงานให้ฉันได้ในกรณีของฉัน

คุณสามารถขอลงในตัวกรองposts_join_pagedและposts_order โดยเพื่ออัพเดตสตริงการเข้าร่วมและการสั่งซื้อ สิ่งนี้จะช่วยให้คุณสามารถเรียงลำดับตามสิ่งที่คุณต้องการตราบเท่าที่คุณเข้าร่วมก่อนแทนที่จะเป็น WP_Query โดยสมมติว่าฟิลด์นั้นมีอยู่สำหรับโพสต์นั้น ๆ จากนั้นคุณสามารถลบmeta_key, orderbyและ `สั่งซื้อจาก args WP_Query ของคุณ

ด้านล่างเป็นตัวอย่าง ที่ด้านบนของแต่ละฟังก์ชั่นฉันต้องหลบหนีสำหรับบางกรณีเพราะมันจะเพิ่มสิ่งนี้กับทุกสิ่งที่ใช้ WP_Query คุณอาจต้องปรับเปลี่ยนให้เหมาะสมกับความต้องการเฉพาะของคุณ

เอกสารเกี่ยวกับตัวกรองสองตัวนี้ไม่มีเรื่องเศร้าดังนั้นโชคดี! :)

add_filter('posts_join_paged', 'edit_join', 999, 2);
add_filter('posts_orderby', 'edit_orderby', 999, 2);

/**
 * Edit join
 *
 * @param string $join_paged_statement
 * @param WP_Query $wp_query
 * @return string
 */
function edit_join($join_paged_statement, $wp_query)
{
    global $wpdb;
    if (
        !isset($wp_query->query)
        || $wp_query->is_page
        || $wp_query->is_admin
        || (isset($wp_query->query['post_type']) && $wp_query->query['post_type'] != 'my_custom_post_type')
    ) {
        return $join_paged_statement;
    }

    $join_to_add = "
        LEFT JOIN {$wpdb->prefix}postmeta AS my_custom_meta_key
            ON ({$wpdb->prefix}posts.ID = my_custom_meta_key.post_id
                AND my_custom_meta_key.meta_key = 'my_custom_meta_key')
    ";

    // Only add if it's not already in there
    if (strpos($join_paged_statement, $join_to_add) === false) {
        $join_paged_statement = $join_paged_statement . $join_to_add;
    }

    return $join_paged_statement;
}

/** 
 * Edit orderby
 *
 * @param string $orderby_statement
 * @param WP_Query $wp_query
 * @return string
 */
function edit_orderby($orderby_statement, $wp_query)
{
    if (
        !isset($wp_query->query)
        || $wp_query->is_page
        || $wp_query->is_admin
        || (isset($wp_query->query['post_type']) && $wp_query->query['post_type'] != 'my_custom_post_type')
    ) {
        return $orderby_statement;
    }

    $orderby_statement = "my_custom_meta_key.meta_value DESC";

    return $orderby_statement;
}

รหัสใช้งานได้ แต่ meta_value ถูกจัดการเป็นสตริง ดังนั้น 6 ได้รับการจัดอันดับสูงกว่า 50 การแก้ไขใด ๆ ที่เป็นไปได้ที่จะถือเป็นตัวเลข?
Drivingralle

@Drivingralle cast(my_custom_meta_key.meta_value as unsigned) DESCควรใช้เล่ห์เหลี่ยม ...
tfrommen

1
ขอบคุณ @tfrommen $orderby_statement = "cast(my_custom_meta_key.meta_value as unsigned) DESC";ใช้งานได้ดี
Drivingralle

0

วิธีนี้ใช้ได้ผลสำหรับฉัน:

add_action( 'pre_get_posts', 'orden_portfolio' );
function orden_portfolio( $query ) {

    if( ! is_admin() ) {

        $query->set( 'orderby', 'meta_value_num' );
        $query->set( 'order', 'ASC' );
        $query->set( 'meta_query', [
            'relation' => 'OR',
            [ 
                'key' => 'ce_orden', 
                'compare' => 'NOT EXISTS' ],
            [
                'key' => 'ce_orden',
                'compare' => 'EXISTS',
            ],
        ] );

        return $query;

    }

}

อย่างไรก็ตามโซลูชันนี้จะแสดงระเบียนที่มี meta_value เป็นศูนย์ก่อน โซลูชันอื่นนี้แสดงคำสั่งซื้อ ASC และค่า Null ในตอนท้าย:

function custom_join($join) {
    global $wpdb;

    if( ! is_admin() ) {
        $join .= $wpdb->prepare(
        ' LEFT JOIN ' . $wpdb->postmeta . ' cpm ON cpm.post_id = ' . $wpdb->posts . '.ID AND cpm.meta_key = %s'
        , 'ce_orden' );
    }

    return $join;
}

add_filter('posts_join','custom_join');

function custom_orderby($orderby_statement){
    global $wpdb;

    if ( ! is_admin() ) {
        $orderby_statement = "CAST( COALESCE(cpm.meta_value,99999) as SIGNED INTEGER) ASC";
    }

    return $orderby_statement;
}

add_filter('posts_orderby','custom_orderby', 10, 2 ); 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.