ทำไมลูปไม่ว่างเปล่าใน 404 บางช่วง


10

ฉันเจอปัญหาแปลก ๆ

สมมติว่าคุณเข้าถึง URL แบบสุ่มสามระดับขึ้นไปที่อยู่ลึก:

http://example.com/a/b/c
http://example.com/a/b/c/d
...

จากนั้นคือis_404() trueจนถึงตอนนี้ดีมาก แต่ด้วยเหตุผลบางอย่างโพสต์ล่าสุดจะถูกสอบถาม

$wp_query->request

คือ

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID 
    FROM wp_posts 
    WHERE 1=1 
        AND wp_posts.post_type = 'post' 
        AND (
            wp_posts.post_status    = 'publish' 
            OR wp_posts.post_status = 'private'
            ) 
    ORDER BY wp_posts.post_date DESC 
    LIMIT 0, 5

ซึ่งแน่นอนว่าจะhave_posts()กลับมาtrueและอื่น ๆ มีคนอธิบายเรื่องนี้ได้ไหม

สิ่งที่ฉันพบ:

เหตุผลที่เตะในระดับลึกสามหรือมากกว่านั้นคือก่อนที่ WP นั้นจะค้นหาโพสต์และสิ่งที่แนบซึ่งส่งผลให้เกิดพฤติกรรมอื่น

ดูเหมือนว่าแม้ว่า WP จะรับรู้การร้องขอเป็น 404 ณ จุดหนึ่งก็จะดึงกระทู้ล่าสุด ด้วยความช่วยเหลือจาก@kaiserและ@GMฉันได้ติดตามเรื่องนี้ไปยังที่อื่นจาก/wp-includes/class-wp.php:608


หากคุณไม่ได้เพิ่มรหัสของหน้าคือจะเป็นเรื่องยากที่จะช่วยให้คุณ
Tomás Cot

3
นี่ไม่ใช่รหัสเฉพาะของฉัน ทำงานเช่นนี้ในการติดตั้งใหม่พร้อมธีมเริ่มต้นทั้งหมดเช่นกัน
Kraftner

คุณสามารถตั้งชื่อธีมอย่างน้อยหนึ่งธีมในธีมที่กำหนดเองของฉันไม่ทำงานได้หรือไม่ คุณใช้พารามิเตอร์เฉพาะหรือไม่ คุณเปลี่ยนทากแล้วหรือยัง? คุณใช้ WP รุ่นใด
Tomás Cot

จริง ๆ แต่ลองยี่สิบเอ็ดถ้าคุณชอบ
Kraftner

ขออภัยสำหรับคำถามทั้งหมดที่ฉันคิดว่าโพสต์กำลังแสดง
Tomás Cot

คำตอบ:


9

คุณอาจประหลาดใจ แต่ไม่มีอะไรแปลก ๆ ที่นั่น

ก่อนอื่นเรามาอธิบายให้ชัดเจนก่อนว่าใน WordPress เมื่อคุณไปที่ URL ส่วนหน้าคุณจะต้องทำการสืบค้น เสมอ.

แบบสอบถามนั้นเป็นเพียงมาตรฐานWP_Queryเช่นเดียวกับที่เรียกใช้ผ่าน:

$query = new WP_Query( $args );

มีความแตกต่างเพียงอย่างเดียว: $argsตัวแปรถูกสร้างโดย WordPress โดยใช้WP::parse_request()วิธีการ สิ่งที่วิธีการทำคือเพียงแค่ดูที่ URL และที่กฎการเขียนใหม่และแปลง URL เป็นอาร์เรย์ของข้อโต้แย้ง

แต่จะเกิดอะไรขึ้นเมื่อวิธีการนั้นไม่สามารถทำได้เนื่องจาก URL ไม่ถูกต้อง แบบสอบถาม args เป็นเพียงอาร์เรย์เช่นนี้:

array( 'error' => '404' );

(แหล่งที่มาที่นี่และที่นี่ )

WP_Queryดังนั้นอาร์เรย์ที่ส่งผ่านไป

ตอนนี้ลองทำ:

$query = new WP_Query( array( 'error' => '404' ) );
var_dump( $query->request );

คุณประหลาดใจไหมที่ข้อความค้นหานั้นตรงกับข้อความใน OP ฉันไม่.

ดังนั้น,

  1. parse_request() สร้างอาร์เรย์ด้วยคีย์ข้อผิดพลาด
  2. อาร์เรย์นั้นถูกส่งผ่านไปยังWP_Queryที่เพิ่งเรียกใช้
  3. handle_404()ที่ทำงานหลังจากแบบสอบถามให้ดูที่'error'พารามิเตอร์และตั้งค่าis_404()เป็นจริง

ดังนั้นhave_post()และis_404()ไม่เกี่ยวข้อง ปัญหาคือWP_Queryไม่มีระบบลัดวงจรเคียวรีเมื่อเกิดข้อผิดพลาดดังนั้นเมื่อสร้างวัตถุแล้วให้ผ่าน args ไปบางส่วนและเคียวรีจะรัน ...

แก้ไข:

มี 2 ​​วิธีในการเอาชนะปัญหานี้:

  • สร้าง404.phpเทมเพลต WordPress จะโหลดมันบน 404 URL และคุณไม่จำเป็นต้องตรวจสอบhave_posts()
  • บังคับ$wp_queryให้ว่างใน 404 สิ่งที่ต้องการ:

    add_action( 'wp', function() {
        global $wp_query;
        if ( $wp_query->is_404() ) {
            $wp_query->init();
            $wp_query->is_404 = true; // init() reset 404 too
        }
    } );
    

4
ฉันจะเพิ่มว่าเหตุผลที่ว่านี้ไม่ได้เกิดขึ้นโดยทั่วไปคือ 404 มักจะส่งผลของแบบสอบถาม แต่ในกรณีนี้มันเป็นผลมาจากกฎการเขียนซ้ำที่ไม่ตรงกัน ( $wp->matched_rule) แต่ข้อความค้นหายังคงผ่านการเคลื่อนไหวเพราะมันไม่ได้สนใจสิ่งนั้น
Rarst

+1 ใช่แบบสอบถามไม่ได้สนใจมันและด้วยรหัสปัจจุบันมันไม่สามารถใส่ใจได้เพราะไม่มีวิธีที่จะหยุดมันได้ ตัวอย่างเช่นเมื่อมีการสอบถามอนุกรมวิธานที่ไม่ถูกต้องมีการตั้งค่า WordPress WHERE 1=0ใน sql เพราะมันไม่สามารถหยุดการสืบค้นได้ดังนั้นบังคับให้เคียวรีที่ส่งคืนไม่มีอะไรเลย ... @Rarst
gmazzap

โอเคตอนนี้ฉันเข้าใจแล้ว ดังนั้นคำถามที่แท้จริงที่ยังคงอยู่คือเหตุผลที่ว่าทำไม WP_Query จึงถือว่าคำถามเริ่มต้นของการโพสต์เมื่อผ่านไม่มีข้อโต้แย้งที่สมเหตุสมผลเมื่อเพิ่งกลับไม่มีอะไรจะทำให้รู้สึกมากขึ้น?
Kraftner

2
@ kraftner ตามที่กล่าวไว้ WordPress ไม่สามารถหลีกเลี่ยงการเรียกใช้การสืบค้นและเมื่อไม่มีข้อโต้แย้งที่เป็นกันเองมี 2 ตัวเลือก: เรียกใช้การสืบค้นที่แน่ใจว่าจะไม่ส่งคืนสิ่งใด (เช่นเมื่อมีการสอบถามอนุกรมวิธานที่ไม่ถูกต้อง . ทำไมในกรณีนี้ WP เลือกอันหลังคือ Q ที่ควรถูกถามถึง core devs :)
gmazzap

@ TomásCotแน่นอน แต่ถ้ามันล้มเหลวฉันต้องการให้มันล้มเหลวจริงๆและไม่คืนสิ่งที่ไม่เกี่ยวข้องทั้งหมด อย่างไรก็ตามตอนนี้สิ่งต่าง ๆ ถูกล้างออกไปและฉันแค่ต้องทำการis_404()ตรวจสอบเพิ่มเติม
Kraftner
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.