Чому цикл не порожній на деяких 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 ви використовуєте?
Томаш Кот

Дійсно будь-яка. Але спробуйте двадцять одинадцять, якщо хочете.
kraftner

Вибачте за все запитання, я подумав, що повідомлення показують.
Томаш Кот

Відповіді:


9

Ви можете бути здивовані, але в цьому немає нічого дивного.

Перш за все давайте уточнимо, що в WordPress, коли ви відвідуєте URL-адресу інтерфейсу, ви запускаєте запит. Завжди.

Цей запит є просто стандартним WP_Query, як і ті, які виконуються через:

$query = new WP_Query( $args );

Є лише одна відмінність: $argsзмінні генеруються WordPress за допомогою WP::parse_request()методу. Що цей метод робить, це просто переглянути URL-адресу та правила переписання та перетворити URL-адресу в масив аргументів.

Але що станеться, коли метод не може цього зробити, оскільки URL-адреса недійсна? Аргументи запиту - це просто такий масив:

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

(Джерело тут і тут ).

Тож цей масив передається до WP_Query.

Тепер спробуйте зробити:

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

Ви здивовані, що запит саме той, що знаходиться в ОП? Я не.

Тому,

  1. parse_request() будує масив з ключем помилки
  2. Цей масив передається WP_Query, що просто запускає його
  3. handle_404()що працює після запиту, переглядає 'error'параметр і встановлює is_404()значення true

Отже, have_post()і is_404()не пов’язані між собою. Проблема полягає в тому, що WP_Queryнемає системи для короткого замикання запиту, коли щось піде не так, тож як тільки об’єкт побудований, передайте йому деякі аргументи і запит запуститься ...

Редагувати:

Є два способи подолати цю проблему:

  • Створити 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), але запит все ще проходить через рухи, оскільки він не звертає на це уваги.
Рарст

+1. Так, запит на нього не звертає уваги, і за поточним кодом він не може звернути увагу, оскільки немає можливості зупинити його. Наприклад, коли невірна таксономія запитується, що WordPress встановлюється WHERE 1=0в sql, тому що він не може зупинити запит, тому змусити запит, який нічого не повертає ... @Rarst
gmazzap

Гаразд зараз я зрозумію. Тож справжнє питання, що залишається, полягає в тому, чому, пекло, WP_Query припускає запит за замовчуванням на отримання повідомлень, коли не передано розумних аргументів, коли просто повернення нічого не мало би сенсу?
kraftner

2
@kraftner, як було сказано, WordPress не може уникнути запуску запиту, а коли немає резонансних аргументів, є два варіанти: запустити запит, який не повертає нічого (наприклад, коли невірна таксономія запитується, див. коментар вище) або запустіть запит за замовчуванням . Чому в цьому випадку WP вибирає останнє - це Q, якому слід
задати

@ TomásCot Звичайно, але, якщо це не вдасться, я б хотів, щоб він справді вийшов з ладу і не повернув щось абсолютно не пов'язане. У будь-якому випадку, речі зараз з’ясувались, і мені просто потрібно зробити додаткову is_404()перевірку.
kraftner
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.