Mengapa loop tidak kosong pada 404-an?

10

Saya menemukan masalah aneh.

Katakanlah Anda mengakses url acak, tiga level atau lebih dalam:

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

Lalu is_404()adalah true. Sejauh ini baik. Tetapi untuk beberapa alasan posting terakhir dipertanyakan.

$wp_query->request

adalah

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

Yang kemudian tentu saja membuat have_posts()kembali truedan seterusnya. Adakah yang bisa menjelaskan hal ini?

Apa yang saya temukan sejauh ini:

Alasan yang hanya menendang tiga tingkat atau lebih dalam adalah bahwa sebelum WP mencari posting dan lampiran yang entah bagaimana menghasilkan beberapa perilaku lain.

Tampaknya meskipun WP mengakui permintaan tersebut sebagai 404 pada satu titik, tetapi kemudian mengambil pos terbaru. Dengan bantuan dari @kaiser dan @GM saya telah melacaknya sampai di suatu tempat dari /wp-includes/class-wp.php:608

pembuat kraftner
sumber
Jika Anda tidak menambahkan kode halaman akan sulit membantu Anda
Tomás Cot
3
Ini tidak spesifik untuk kode saya. Berperilaku seperti ini pada instalasi baru dengan semua tema default juga.
kraftner
dapatkah Anda menyebutkan setidaknya satu tema, di tema khusus saya tidak berfungsi? apakah Anda menggunakan parameter tertentu? Sudahkah Anda mengganti siput? WP versi apa yang Anda gunakan?
Tomás Cot
Benar-benar ada Tetapi coba Twenty Eleven jika Anda suka.
kraftner
Maaf untuk semua pertanyaan, saya pikir posting ditampilkan.
Tomás Cot

Jawaban:

9

Anda mungkin terkejut, tetapi tidak ada yang aneh di sana.

Pertama-tama mari kita perjelas bahwa di WordPress ketika Anda mengunjungi URL frontend Anda memicu kueri. Selalu.

Kueri itu hanya standar WP_Query, seperti yang dijalankan melalui:

$query = new WP_Query( $args );

Hanya ada satu perbedaan: $argsvariabel dihasilkan oleh WordPress menggunakan WP::parse_request()metode ini. Apa yang dilakukan metode itu hanyalah melihat URL, dan pada aturan penulisan ulang, dan mengonversi URL menjadi array argumen.

Tetapi apa yang terjadi ketika metode itu tidak dapat melakukannya karena URL tersebut tidak valid? Argumen kueri hanyalah array seperti ini:

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

(Sumber sini dan sini ).

Jadi array itu diteruskan ke WP_Query.

Sekarang coba lakukan:

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

Apakah Anda terkejut bahwa kueri itu persis dengan yang ada di OP? Bukan saya.

Begitu,

  1. parse_request() membangun sebuah array dengan kunci kesalahan
  2. Array itu diteruskan ke WP_Query, yang menjalankannya
  3. handle_404()yang berjalan setelah kueri, melihat 'error'parameter dan set is_404()ke true

Jadi, have_post()dan is_404()tidak berhubungan. Masalahnya adalah bahwa WP_Querytidak memiliki sistem untuk hubungan pendek permintaan ketika ada masalah, jadi setelah objek dibangun, berikan beberapa argumen padanya dan permintaan akan berjalan ...

Edit:

Ada 2 cara untuk mengatasi masalah ini:

  • Buat 404.phptemplat; WordPress akan memuatnya di 404 URL dan di sana Anda tidak perlu memeriksanyahave_posts()
  • Paksa $wp_querykosong pada 404, sesuatu seperti:

    add_action( 'wp', function() {
        global $wp_query;
        if ( $wp_query->is_404() ) {
            $wp_query->init();
            $wp_query->is_404 = true; // init() reset 404 too
        }
    } );
gmazzap
sumber
4
Saya akan menambahkan bahwa alasan bahwa ini tidak terjadi biasanya adalah bahwa 404 biasanya hasil dari permintaan . Tetapi dalam kasus ini adalah hasil dari aturan penulisan ulang yang tak tertandingi ( $wp->matched_rule), tetapi permintaan masih melalui gerakan karena tidak memperhatikan hal itu.
Paling jarang
+1. Ya, kueri tidak memperhatikannya, dan dengan kode saat ini kueri tidak dapat memperhatikan, karena tidak ada cara untuk menghentikannya. Sebagai contoh ketika taksonomi yang tidak valid ditanyai WordPress diatur WHERE 1=0dalam sql karena tidak dapat menghentikan permintaan, maka paksa permintaan yang tidak menghasilkan apa-apa ... @Rarst
gmazzap
Oke sekarang saya mengerti. Jadi pertanyaan sebenarnya yang tersisa adalah mengapa WP_Query tidak menerima permintaan default untuk mendapatkan posting ketika tidak ada argumen yang masuk akal ketika hanya mengembalikan tidak ada yang masuk akal?
kraftner
2
@kraftner seperti yang dikatakan WordPress tidak dapat menghindari kueri berjalan, dan ketika tidak ada argumen yang beresonansi ada 2 pilihan: jalankan kueri yang pasti tidak menghasilkan apa-apa (seperti ketika taksonomi yang tidak valid ditanyai pertanyaan, lihat komentar di atas) atau jalankan kueri default . Mengapa dalam hal ini WP memilih yang terakhir adalah Q yang harus ditanyakan kepada
pengembang
@ TomásCot Tentu tetapi jika gagal saya ingin benar-benar gagal dan tidak mengembalikan sesuatu yang sama sekali tidak terkait. Bagaimanapun, semuanya beres sekarang dan saya hanya perlu melakukan pemeriksaan tambahan is_404().
kraftner