ฉันควรใช้ Pre Get กระทู้หรือ WP_Query


29

ฉันมีคำถามต่อไปนี้ซึ่งฉันโทรหาในเทมเพลต taxonomy.php ผ่านทาง query_brands_geo('dealers', 'publish', '1', $taxtype, $geo, $brands);

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

ถ้าเป็นเช่นนั้นฉันจะสร้าง pre_get_posts และส่งตัวแปรและข้อความค้นหาของฉันด้านล่างได้อย่างไร

function my_custom_query($posttype, $poststatus, $paidvalue, $taxtype, $geo, $brands) {
   global $wp_query; 
   $wp_query = new WP_Query();
   $args = array( 
      'post_type' => $posttype, 
      'post_status' => array($poststatus), 
      'orderby' => 'rand', 
      'posts_per_page' => 30, 
      'meta_query' => array( 
         array( 
            'key' => 'wpcf-paid', 
            'value' => array($paidvalue), 
            'compare' => 'IN', 
            ) 
      ), 
      'tax_query' => array( 
         'relation' => 'AND', 
         array( 
            'taxonomy' => $taxtype, 
            'field' => 'slug', 
            'terms' => $geo 
         ), 
         array( 
            'taxonomy' => 'brands', 
            'field' => 'slug', 
            'terms' => $brands 
         ) 
      ) 
   ); 

   return $wp_query->query($args); 
} 

คำตอบ:


14

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

function custom_pre_get_posts($query, $posttype='dealers', $poststatus='publish', $paidvalue='1', $taxtype='any_default_value', $geo='any_default_value', $brands='any_default_value') {

    // filter your request here.
    if($query->is_category) {

        $args = array(
            'post_type' => $posttype,
            'post_status' => array($poststatus),
            'orderby' => 'rand',
            'posts_per_page' => 30,
            'meta_query' => array(
                array(
                    'key' => 'wpcf-paid',
                    'value' => array($paidvalue),
                    'compare' => 'IN',
                )
            ),
            'tax_query' => array(
                'relation' => 'AND',
                array(
                    'taxonomy' => $taxtype,
                    'field' => 'slug',
                    'terms' => $geo
                ),
                array(
                    'taxonomy' => 'brands',
                    'field' => 'slug',
                    'terms' => $brands
                )
            )
        );
        $query->query_vars = $args;
    }
}
add_action('pre_get_posts', 'custom_pre_get_posts');

ขอบคุณมากสำหรับคำตอบ มันมีประโยชน์มาก คำถามด่วนหนึ่งข้อ ฉันวางฟังก์ชันไว้ในไฟล์ theme.php ของฉัน ฉันเรียกใช้ฟังก์ชันนี้ custom_pre_get_posts ($ query) จาก taxonomy.php ของฉัน ใน taxonomy.php ฉันตั้งค่าตัวแปร $ posttype, $ post_status, $ geo, $ brand, $ taxtype และเรียกใช้สองลูปเปลี่ยนตัวแปรเหล่านี้ มีวิธีการส่งผ่านตัวแปรในฟังก์ชั่นข้างต้นจาก taxonomy.php หรือไม่ เมื่อฉันลอง custom_pre_get_posts ($ query, 'ดีลเลอร์', 'เผยแพร่', '1', $ taxtype, $ geo, $ brands); ฉันได้รับอาร์กิวเมนต์ที่ขาดหายไป 2 ถึง 7 สำหรับ custom_pre_get_posts () ฉันถือว่าเนื่องจาก add_action ???
user1609391

1
ฉันสมมติว่าคุณเปลี่ยน custom_pre_get_posts เพื่อยอมรับอาร์กิวเมนต์ที่เหลือ ใช่คุณได้รับข้อผิดพลาดเนื่องจาก add_action add_action เรียกใช้ฟังก์ชันนี้โดยใช้อาร์กิวเมนต์ตัวเดียว (เช่น $ query) คุณควรให้ค่าปริยายของอาร์กิวเมนต์อื่นเพื่อหลีกเลี่ยงข้อผิดพลาดของอาร์กิวเมนต์ เช่น ($ posttype = null, $ poststatus = null ... ) เพื่อให้สามารถเรียกใช้ได้อย่างถูกต้องโดย add_action
MR

MR ขอบคุณสำหรับการตอบกลับ ฉันอ่านข้อมูลเกี่ยวกับการเพิ่มและฉันเห็นว่าฉันควรกำหนดหมายเลขลำดับความสำคัญและอาร์กิวเมนต์ ดังนั้นฉันจึงเปลี่ยนการกระทำเพิ่มเป็น <code> add_action ('pre_get_posts', 'custom_pre_get_posts', 10,7); </code> จากนั้นในหน้า taxonomy.php ของฉันฉัน <code> do_action ('pre_get_post', $ query, ' ดีลเลอร์ ',' เผยแพร่ ',' 1 ', $ taxtype, $ geo, $ brands); </code> แต่ฉันยังคงได้รับข้อผิดพลาดเดียวกัน ฉันไม่แน่ใจว่าจะใส่ค่าเริ่มต้นไว้ที่ไหน ฉันลองใช้ google แต่ไม่พบข้อมูลอ้างอิง คุณช่วยให้ข้อมูลเพิ่มเติมเล็กน้อยเกี่ยวกับวิธีจัดการกับสิ่งนี้ได้ไหม
user1609391

ขอบคุณสำหรับคำตอบและตัวอย่าง แต่ฉันคิดว่าฉันอาจพยายามใช้ pre_get_posts เมื่อฉันควรจะทำแบบสอบถาม wordpress ใหม่ ฉันพยายามบันทึกข้อความค้นหา แต่ในกรณีของฉันอาจเป็นไปไม่ได้ เหตุผลที่เป็นข้อโต้แย้งทั้งหมดที่คุณตั้งไว้ในพารามิเตอร์ฉันต้องการที่จะส่งไปยังฟังก์ชั่นจากไฟล์ taxonomy.php ของฉัน ดังนั้น $ Paidvalue =” 1” อาจเป็น 1 หรือ 0 ขึ้นอยู่กับเงื่อนไขที่ฉันกำลังดำเนินการใน taxonomy.php ดูเหมือนว่า pre_get_posts ด้านบนไฟทันทีเมื่อโหลดหน้าเว็บแม้ว่าฉันจะไม่เรียกใช้ฟังก์ชันในไฟล์ taxonomy.php ของฉันก็ตาม ฉันเห็นสิ่งนี้ถูกต้องหรือไม่
user1609391

3
คำตอบนี้ไม่สมเหตุสมผลอย่างที่เขียนไว้ในปัจจุบัน คุณจะเขียนทับค่าใด ๆ ภายใน$wp_queryวัตถุและสิ่งต่างๆจะล้มเหลวอย่างสมบูรณ์ นอกเหนือจากนั้นมันก็ไม่เป็นความจริงที่pre_get_postsจะรันการสอบถามเพิ่มเติม ...
Kaiser

10

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

หลัก WP_Query และฟิลเตอร์ของมัน

ครั้งแรกภายใน WordPress ใช้query_posts()(เสื้อคลุมบาง ๆ รอบ ๆWP_Queryที่ไม่ควรนำมาใช้ในรูปแบบหรือปลั๊กอิน) WP_Queryที่จะทำ สิ่งนี้WP_Queryทำหน้าที่เป็นลูป / คิวรีหลัก แบบสอบถามนี้จะทำงานผ่านตัวกรองและการดำเนินการจำนวนมากจนกว่าสตริงแบบสอบถาม SQL จริงจะถูกสร้างขึ้น pre_get_postsหนึ่งในนั้นคือ คนอื่น ๆ ที่posts_clauses, posts_whereฯลฯ ที่ยังช่วยให้คุณสามารถที่จะสกัดกั้นกระบวนการสร้างสตริงแบบสอบถาม

มองลึกลงไปในสิ่งที่เกิดขึ้นภายในแกนกลาง

WordPress เรียกใช้wp()ฟังก์ชัน (ในwp-includes/functions.php), ซึ่งเรียก$wp->main()( $wpเป็นวัตถุของคลาส WP, ซึ่งกำหนดไว้wp-includes/class-wp.php) สิ่งนี้บอกให้ WordPress:

  1. แยก URL เป็นข้อกำหนดการสืบค้นโดยใช้WP->parse_request()- เพิ่มเติมจากด้านล่าง
  2. ตั้งค่าตัวแปร is_ ทั้งหมดที่ใช้โดยแท็กแบบมีเงื่อนไขโดยใช้$wp_query->parse_query()( $wp_queryเป็นวัตถุclass WP_Queryซึ่งกำหนดไว้ในwp-includes/query.php) โปรดทราบว่าแม้ว่าชื่อของฟังก์ชั่นนี้ในกรณีนี้WP_Query->parse_queryจะไม่ทำการแยกวิเคราะห์ใด ๆ สำหรับเราเนื่องจากมันทำมาก่อนWP->parse_request()แล้ว
  3. แปลงข้อกำหนดการสืบค้นเป็นแบบสอบถามฐานข้อมูล MySQL และเรียกใช้แบบสอบถามฐานข้อมูลเพื่อรับรายการโพสต์ในฟังก์ชั่น WP_Query-> get_posts () บันทึกการโพสต์ในวัตถุ $ wp_query ที่จะใช้ในการวนรอบ WordPress

แหล่งCodex

ข้อสรุป

หากคุณต้องการแก้ไขข้อความค้นหาหลักจริงๆคุณสามารถใช้ตัวกรองได้หลากหลาย เพียงใช้$query->set( 'some_key', 'some_value' );เพื่อเปลี่ยนข้อมูลที่นั่นหรือใช้$query->get( 'some_key' );เพื่อดึงข้อมูลเพื่อทำการตรวจสอบตามเงื่อนไข การทำเช่นนี้จะช่วยให้คุณไม่ต้องทำแบบสอบถามที่สองเนื่องจากคุณกำลังแก้ไขแบบสอบถาม SQL เท่านั้น

หากคุณต้องทำแบบสอบถามเพิ่มเติมให้ไปกับWP_Queryวัตถุ นี่จะเพิ่มแบบสอบถามอื่นไปยังฐานข้อมูล

ตัวอย่าง

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

class My_Book_Query extends WP_Query
{
    function __construct( $args = array() )
    {
        // Forced/default args
        $args = array_merge( $args, array(
            'posts_per_page' => -1
        ) );

        add_filter( 'posts_fields', array( $this, 'posts_fields' ) );

        parent::__construct( $args );
    }

    public function posts_fields( $sql )
    {
        return "{$sql}, {$GLOBALS['wpdb']->terms}.name AS 'book_category'";
    }
}

จากนั้นคุณสามารถเรียกใช้คิวรีที่สอง / เพิ่มเติมเช่นที่คุณเห็นในตัวอย่างต่อไปนี้ อย่าลืมรีเซ็ตแบบสอบถามของคุณในภายหลัง

$book_query = new My_Book_Query();
if ( $book_query->have_posts() )
{
    while ( $book_query->have_posts() )
    {
        $book_query->the_post();
        # ...do stuff...
    } // endwhile;
    wp_reset_postdata();
} // endif;

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