Dlaczego w niektórych 404 pętla nie jest pusta?

10

Natknąłem się na dziwny problem.

Załóżmy, że masz dostęp do losowego adresu URL o głębokości co najmniej trzech poziomów:

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

To is_404()jest true. Na razie w porządku. Ale z jakiegoś powodu sprawdzane są ostatnie posty.

$wp_query->request

jest

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

Który wtedy oczywiście have_posts()powraca truei tak dalej. Czy ktoś może to wyjaśnić?

Co do tej pory się dowiedziałem:

Powodem, dla którego uruchamia się tylko na trzech lub więcej poziomach głębokości, jest to, że wcześniej WP szuka postów i załączników, które w jakiś sposób skutkują jakimś innym zachowaniem.

Wygląda na to, że chociaż WP rozpoznaje żądanie jako 404 w pewnym momencie, pobiera najnowsze posty. Z pomocą @kaiser i @GM wyśledziłem to gdzieś z /wp-includes/class-wp.php:608

Kraftner
źródło
Jeśli nie dodasz kodu strony, ciężko ci będzie pomóc
Tomás Cot
3
To nie jest specyficzne dla mojego kodu. Zachowuje się tak w przypadku zupełnie nowej instalacji ze wszystkimi domyślnymi motywami.
kraftner
czy możesz wymienić co najmniej jeden motyw, w moim niestandardowym motywie nie działa? czy używasz określonych parametrów? czy zmieniłeś ślimaki? jakiej wersji WP używasz?
Tomás Cot
Naprawdę każdy. Ale jeśli chcesz, wypróbuj Twenty Eleven.
kraftner
Przepraszam za wszystkie pytania, myślałem, że posty są wyświetlane.
Tomás Cot

Odpowiedzi:

9

Możesz być zaskoczony, ale nie ma w tym nic dziwnego.

Przede wszystkim wyjaśnijmy, że w WordPress, gdy odwiedzasz frontendowy URL, wywołujesz zapytanie. Zawsze.

To zapytanie jest tylko standardem WP_Query, podobnie jak te uruchamiane przez:

$query = new WP_Query( $args );

Jest tylko jedna różnica: $argszmienne są generowane przez WordPress przy użyciu WP::parse_request()metody. Metoda ta polega tylko na sprawdzeniu adresu URL i reguł przepisywania oraz przekonwertowaniu adresu URL na tablicę argumentów.

Ale co się stanie, gdy ta metoda nie będzie w stanie tego zrobić, ponieważ adres URL jest nieprawidłowy? Argument zapytania jest po prostu taką tablicą:

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

(Źródło tutaj i tutaj ).

Tak więc tablica jest przekazywana do WP_Query.

Teraz spróbuj zrobić:

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

Czy jesteś zaskoczony, że zapytanie jest dokładnie tym w OP? Nie jestem.

Więc,

  1. parse_request() buduje tablicę z kluczem błędu
  2. Tablica jest przekazywana do WP_Query, która po prostu ją uruchamia
  3. handle_404()uruchamiany po zapytaniu, sprawdza 'error'parametr i ustawia wartość is_404()true

Tak, have_post()i is_404()nie są powiązane. Problem polega na tym, że WP_Querynie ma systemu do zwarcia zapytania, gdy coś pójdzie nie tak, więc po zbudowaniu obiektu przekaż mu kilka argumentów, a zapytanie zostanie uruchomione ...

Edytować:

Istnieją 2 sposoby rozwiązania tego problemu:

  • Utwórz 404.phpszablon; WordPress załaduje to na 404 adresy URL i tam nie musisz sprawdzaćhave_posts()
  • Wymuś $wp_querypustkę na 404, coś w stylu:

    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
źródło
4
Dodałbym, że powodem tego zazwyczaj nie jest to, że 404 jest zwykle wynikiem zapytania . Ale w tym przypadku wynika to z niedopasowanej reguły przepisywania ( $wp->matched_rule), ale zapytanie wciąż przechodzi przez ruchy, ponieważ nie zwraca na to uwagi.
Rarst
+1. Tak, zapytanie nie zwraca na to uwagi, a przy obecnym kodzie nie może zwracać na to uwagi, ponieważ nie ma sposobu, aby go zatrzymać. Jako przykład, gdy kwerenda dotyczy niepoprawnej systematyki, WordPress jest ustawiony WHERE 1=0w sql, ponieważ nie może zatrzymać zapytania, więc wymuś zapytanie, które nic nie zwraca ... @Rarst
gmazzap
Dobra, teraz rozumiem. Pozostaje więc prawdziwe pytanie, dlaczego, u diabła, WP_Query zakłada domyślne zapytanie o otrzymywanie postów, gdy nie są przekazywane żadne uzasadnione argumenty, gdy tylko zwracanie niczego nie ma większego sensu?
kraftner
2
@kraftner, jak powiedział WordPress, nie może uniknąć uruchomienia zapytania, a gdy nie ma żadnych argumentów możliwych do rezonowania, istnieją 2 możliwości: uruchom zapytanie, które na pewno nic nie zwraca (np. w przypadku zapytania o nieprawidłową taksonomię, patrz komentarz powyżej) lub uruchom zapytanie domyślne . Dlaczego w tym przypadku WP wybiera to drugie pytanie, które należy zapytać o rdzeń programisty :)
gmazzap
@ TomásCot Pewnie, ale jeśli się nie powiedzie, chciałbym, żeby naprawdę zawiódł i nie zwrócił czegoś zupełnie niezwiązanego. W każdym razie wszystko się wyjaśniło i muszę tylko zrobić dodatkową is_404()kontrolę.
kraftner