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


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
        }
    } );

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.