Tại sao vòng lặp không trống trên một số 404?


10

Tôi đã gặp một vấn đề kỳ lạ.

Giả sử bạn truy cập một url ngẫu nhiên, sâu ba cấp trở lên:

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

Sau đó is_404()true. Càng xa càng tốt. Nhưng vì một số lý do, bài viết cuối cùng được truy vấn.

$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

Mà sau đó tất nhiên làm cho have_posts()trở lại truevà như vậy. Ai đó có thể giải thích điều này?

Những gì tôi phát hiện ra cho đến nay:

Lý do chỉ bắt đầu ở ba cấp độ trở lên là vì trước đó WP tìm kiếm các bài đăng và tệp đính kèm mà bằng cách nào đó dẫn đến một số hành vi khác.

Có vẻ như mặc dù WP nhận ra yêu cầu là 404 tại một thời điểm, sau đó nó tìm nạp các bài đăng gần đây nhất. Với sự giúp đỡ từ @kaiser@GM, tôi đã theo dõi điều này xuống một nơi nào đó từ / wp-includes/ class-wp.php:608


Nếu bạn không thêm mã của trang là sẽ rất khó để giúp bạn
Tomás Cót

3
Điều này không cụ thể đối với mã của tôi. Hành vi như thế này trên một cài đặt hoàn toàn mới với tất cả các chủ đề mặc định là tốt.
kraftner

bạn có thể đặt tên cho ít nhất một chủ đề, trong chủ đề tùy chỉnh của tôi không hoạt động? bạn đang sử dụng thông số cụ thể? bạn đã thay đổi những con sên? bạn đang sử dụng phiên bản WP nào?
Tomás Cot

Thực sự bất kỳ. Nhưng hãy thử Twenty Eleven nếu bạn thích.
kraftner

Xin lỗi cho tất cả các câu hỏi, tôi nghĩ rằng bài viết đang hiển thị.
Tomás Cot

Câu trả lời:


9

Bạn có thể ngạc nhiên, nhưng không có gì lạ ở đó.

Trước hết, hãy làm rõ rằng trong WordPress khi bạn truy cập URL lối vào, bạn kích hoạt truy vấn. Luôn luôn.

Truy vấn đó chỉ là một tiêu chuẩn WP_Query, giống như các truy vấn chạy qua:

$query = new WP_Query( $args );

Chỉ có một sự khác biệt: các $argsbiến được tạo bởi WordPress bằng WP::parse_request()phương thức này. Phương pháp đó làm gì chỉ là nhìn vào URL và các quy tắc viết lại và chuyển đổi URL thành một mảng các đối số.

Nhưng điều gì xảy ra khi phương thức đó không thể thực hiện được vì URL không hợp lệ? Các truy vấn args chỉ là một mảng như thế này:

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

(Nguồn ở đâyđây ).

Vì vậy, mảng đó được truyền đến WP_Query.

Bây giờ hãy thử làm:

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

Bạn có ngạc nhiên khi truy vấn chính xác là truy vấn trong OP không? Tôi không.

Vì thế,

  1. parse_request() xây dựng một mảng với một khóa lỗi
  2. Mảng đó được truyền cho WP_Query, chỉ cần chạy nó
  3. handle_404()chạy sau truy vấn, nhìn vào 'error'tham số và đặt is_404()thành true

Vì vậy, have_post()is_404()không liên quan. Vấn đề là WP_Querykhông có hệ thống để đoản mạch truy vấn khi có sự cố, do đó, khi đối tượng được xây dựng, hãy chuyển một số đối số cho nó và truy vấn sẽ chạy ...

Biên tập:

Có 2 cách để khắc phục vấn đề này:

  • Tạo một 404.phpmẫu; WordPress sẽ tải nó trên URL 404 và ở đó bạn không phải kiểm trahave_posts()
  • Buộc $wp_queryphải trống trên 404, đại loại như:

    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
Tôi sẽ nói thêm rằng lý do điều này không xảy ra điển hình là 404 thường là kết quả của truy vấn . Nhưng trong trường hợp này, đó là kết quả của quy tắc viết lại chưa từng có ( $wp->matched_rule), nhưng truy vấn vẫn đang chuyển động vì nó không chú ý đến điều đó.
Hết

+1. Có, truy vấn không chú ý đến nó và với mã hiện tại, nó không thể chú ý, bởi vì không có cách nào để ngăn chặn nó. Ví dụ: khi phân loại không hợp lệ được truy vấn WordPress được đặt WHERE 1=0trong sql vì nó không thể dừng truy vấn nên buộc truy vấn không trả lại gì ... @Rarst
gmazzap

Được rồi bây giờ tôi hiểu rồi. Vì vậy, câu hỏi thực sự còn lại là tại sao WP_Query lại cho rằng một truy vấn mặc định về việc nhận các bài đăng khi được thông qua không có đối số hợp lý khi chỉ trả về không có ý nghĩa gì hơn?
kraftner

2
@kraftner như đã nói WordPress không thể tránh được việc chạy truy vấn và khi không có đối số có thể cộng hưởng, có 2 lựa chọn: chạy truy vấn chắc chắn không trả về gì (như khi phân loại không hợp lệ được truy vấn, xem bình luận ở trên) hoặc chạy truy vấn mặc định . Tại sao trong trường hợp này, WP chọn cái sau là Q nên được yêu cầu cho các nhà phát triển cốt lõi :)
gmazzap

@ TomásCot Chắc chắn nhưng nếu thất bại tôi muốn nó thực sự thất bại và không trả lại một cái gì đó hoàn toàn không liên quan. Dù sao, mọi thứ đã được giải tỏa và tôi chỉ cần is_404()kiểm tra thêm .
kraftner
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.