WP_Query и использование переменной для 'cat'=> в массиве аргументов = баг WordPress?
Для целей этого обсуждения, вот версия моего запроса в category.php:
wp_reset_query();
$category_id = get_cat_ID(single_cat_title('', false));
$my_query = new WP_Query(array(
'posts_per_page' => SOME_DEFINED_VALUE,
'cat' => $category_id,
'paged' => ( get_query_var('paged') ? get_query_var('paged') : 1 ),
'post_type' => array('post','post_custom_1','post_custom_2','post_custom_3')
));
// print_r($my_query);
Если коротко, это не работает. Вот что я заметил.
Когда я делаю print_r($my_query), я вижу query_vars в первой строке. Они не соответствуют моим аргументам массива. Например, posts_per_page возвращается к какому-то другому значению (не к КОНСТАНТЕ), а список post_type больше не включает post (который должен быть).
Если я удаляю строку с 'cat'=> или жестко прописываю значение ('cat'=> 3), тогда всё работает как ожидается. Оставшиеся query_vars отображаются в print_r. Всё хорошо :)
Я пробовал следующее, но безуспешно:
- Сделать переменную КОНСТАНТОЙ, как posts_per_page (которая не вызывает проблем).
- Конкатенация кавычек вокруг числа $category_id - Результат такой же, как и без кавычек. Не работает.
- 'cat' => array($category_id) - Появилась ошибка - Система не приняла массив.
Есть ли у кого-нибудь предложения?
Вот что "сработало" (читай: я мог использовать мой $category_id, и это не испортило остальные аргументы в массиве WP_Query()).
'cat' => '"-'$category_id'"',
То есть, я мог использовать отрицание ID категории. Безумно, правда?
Если я не смогу решить это правильно, я собираюсь использовать строку с разделителями-запятыми всех моих отрицаемых категорий, вырезать текущую категорию и использовать эту строку для запроса. Другими словами, если мои категории были A, B и C, вместо запроса для A (как можно было бы ожидать)
'cat' => A
Я собираюсь сделать запрос для не B, не C.
'cat' => -B,-C
Надеюсь, есть менее хакерское решение. Я потратил на это слишком много часов, и я достаточно отчаялся, чтобы использовать этот хак и закончить с этим. Тем не менее, это точно похоже на баг в ядре. Да, я использую 3.5.1 (или мы уже на .2 или .3?). Суть в том, что я на последней версии (и это делало то же самое в 3.2.x).
Кстати, я видел эту проблему, описанную в других местах (например, на форумах WP). Одно решение предлагало сделать массив аргументов не массивом, а строкой. Даже если это возможно с WP_Query, как бы я сделал список/массив для post_types в виде строки? И наконец, если я делаю что-то неправильно, то страница помощи в Codex нуждается в обновлении, да?
Помогите. :)

Где/как вы определяете $category_id
?
См. документацию Codex по параметрам категорий для WP_Query()
. WP_Query()
ожидает, что ID категорий будут переданы как целые числа, а не как строки:
- Если
$category_id
— это целое число, передайте его в параметр'cat'
. - Если
$category_id
— это массив (ID категорий, опять же как целые числа), передайте его в параметр'category__in'

Спасибо @Chip. Вот эта строка, прямо перед запросом:
$category_id = get_cat_ID(single_cat_title('', false));
Если я выведу её на экран, она там и выглядит корректно. Фактически, query_vars действительно содержит 'cat' => но проблема в том, что per_page и post_types ведут себя странно. Я не использую необъявленную переменную или неправильный тип. Насколько я могу судить, это не проблема. Есть другие предложения? Ещё раз спасибо.

И что возвращает эта строка? Попробуйте var_dump( $category_id )
.

Я добавил/протестировал это: $category_id = (int)get_cat_ID(single_cat_title('', false)); var_dump( $category_id ); и WP_Query игнорирует мои аргументы и использует что-то по умолчанию. Хорошая попытка, но насколько я могу судить, проблема не в типе (строка или число). И если я оберну целочисленную $var в '"'.$var.'"', это НЕ работает. НО '"-'.$var.'"'; работает. НЕ = ОК, иначе мои аргументы сбрасываются и используется что-то по умолчанию (?)

Так что, просто на всякий случай, попробуй привести тип $category_id
к целому числу?

Думаю, это связано с тем, как вы получаете категорию. Я настроил эту функцию в блоге, над которым работаю; $category_id
всегда равен 0.
Чтобы проверить, я использую эту строку для $category_id
:
global $post;
$category_id = get_the_category($post->ID)[0]->term_id;
Простой способ получить первую категорию, назначенную записи.
После этого запрос работает корректно, и параметр cat
в запросе заполняется.

Спасибо, @Simon. Позволь мне немного уточнить. 'cat' => $var работает (вроде бы). Он появляется в query_var. Однако, когда я использую переменную $var для этого присвоения, другие вещи начинают вести себя странно (например, posts_per_page, post_type и т.д.). Ошибки нет. Проблема в том, что массив аргументов, который я использую в WP_Query(), не совпадает с тем, что я вижу в print_r() *когда пытаюсь присвоить 'cat' => через переменную $var. Да, попробуй разобраться в этом :) Также, когда я пытаюсь использовать упомянутую тобой строку кода, я получаю: Parse error: syntax error, unexpected '[' . ??

Я добавил global $post
, думаю, это то, что вызывает ошибку парсинга, извини.
В своих тестах я не заметил никаких проблем, кроме пустого $category_id
.
Просто замечу, я не использую print_r, который сложно читать, а использую плагин console, который позволяет просматривать переменные в консоли firebug. Это очень удобно и делает чтение намного проще.

Ну...Я сам добавил global $post; в первый раз и всё равно получил ошибку. Наверное, поэтому я и спрашивал. Странно, да?

Хорошо, это должно работать только на одной странице, а не на странице категории, извините, что упустил это! Это интересно, но, вероятно, есть объяснение вашей проблеме.

Я проверил ваш исходный код на странице category.php, и он работает правильно. Никаких проблем с post_type или post_per_page.

Еще раз спасибо, @Simon. Я подозреваю, что есть какая-то "утечка" добавления в другой части темы. Я не занимался созданием, я только отвечаю за улучшения. Но даже так, это баг ядра WP, на мой взгляд. Я должен либо получить ошибку / запрос должен завершиться неудачей, либо получить результаты на основе аргументов запроса. В текущем состоянии я получаю случайный запрос при определенном (но законном) условии (например, 'cat' => $var). Вопрос: Вряд ли баг в WP будет исправлен в ближайшее время, так что насчет поиска обходного пути / решения? Есть мысли? Еще раз спасибо.

Попробуйте сменить тему, чтобы проверить поведение и согласованность возвращаемых результатов. Поскольку у меня и у другого участника всё работает, я предполагаю, что ошибка не в ядре, а в каком-то другом хуке темы или плагина.

Снова спасибо, @Simon. Хотелось бы, чтобы всё было так просто, как смена темы, но здесь задействованы дополнительные пользовательские типы записей и другие элементы, встроенные в эту кастомную тему. Я задаю запрос. Делаю запрос. WP использует другой набор аргументов. Даже если это другой плагин и т.д., это всё равно баг (с моей точки зрения). Нелогично разрешать плагинам и т.д. вмешиваться, но не давать возможности понять, какой именно отвечает за "отклонение" запроса и подмену аргументов. Это не внушает доверия к WP_Query, согласны? Более того... 'cat' => -1,-3,-4 работает, а 'cat' => 2 — нет. Разве это не баг? :(

Кстати, оказалось, что "отрицательный" хак тоже не совсем работает. next_posts_link() отображается на последней странице. Это наводит меня на мысль, что используется другой набор аргументов, не тот, который я передаю со своей строкой "исключающих категорий" и другими параметрами. Теперь я в тупике.

Привет @Simon - Спасибо за подсказку / толчок. В конце концов я нашел add_action( 'pre_get_posts', 'function_to_modify_the_query_in_category_php'). Да, эта функция изменяла стандартные параметры запроса. Почему в category.php тоже был код - не уверен. Очевидно, я отвлекся. Тем не менее, это не объясняет, почему 'cat'=> $var вызывал странности. Жестко заданное значение работало нормально, а переменная - нет. Это все еще кажется довольно странным, как будто это баг. Но, опять же, я тут хорошо облажался, да? Еще раз спасибо за помощь.

Пожалуйста, @Chief Alchemist. pre_get_posts
был правильным вариантом для такого поведения.

К слову... для всех, кто это читает... пожалуйста, комментируйте свой код. Вы никогда не знаете, кому еще придется с ним работать. Простое "аргументы этого запроса изменяются функцией: xyz() в functions.php" сэкономило бы мне кучу времени. 10 секунд могут сэкономить кому-то - включая вас самих - часы работы.

Я протестировал вашу функцию, и она работает нормально, так что, вероятно, у вас ошибка в другом коде темы или конфликт с плагином. Или, возможно, ваш цикл настроен неверно.
Для справки: я тестировал следующий код в category.php
в теме twentyeleven, вывод был корректным, без ошибок.
wp_reset_query();
define("SOME_DEFINED_VALUE", 5);
$category_id = get_cat_ID(single_cat_title('', false));
$my_query = new WP_Query(array(
'posts_per_page' => SOME_DEFINED_VALUE,
'cat' => $category_id,
'paged' => ( get_query_var('paged') ? get_query_var('paged') : 1 ),
'post_type' => array('post','post_custom_1','post_custom_2','post_custom_3')
));
var_dump($my_query);

Привет @Wyck - Да, я склоняюсь к такому же мнению. То есть, проблема где-то в другом месте. Я предполагаю это потому, что значения по умолчанию (те, на которые мой массив arg заменяется каким-то другим набором значений query_arr) должны откуда-то браться, верно? Но именно для этого я и использую we_reset. Это должно оставить меня с чистого листа, так? И даже в этом случае, почему установка 'cat'=> (и насколько я могу судить, только этот параметр) с переменной $var может быть проблемой. Такой уровень странности кажется мне серьезным багом. Тебе как? Все это сказано... есть какие-то мысли по решению? Или как найти ошибку / дыру в теме?

Проверь этот шаблон на наличие других циклов или подключения других частей шаблонов (include
или get_template_part
), отключи их и посмотри, сработает ли это, удали виджеты из загрузки, отключи плагины, проверь, не перехватывает ли кто-то запрос через pre_get_posts
, проверь, не использует ли кто-то еще твой $my_query
(измени имя).

Когда я разбил ваш код на управляемые части для анализа, я обнаружил, что проблема, скорее всего, связана со строкой "paged" в массиве.
wp_reset_query();
$category_id = get_cat_ID(single_cat_title('', false));
$paged = ( get_query_var('paged') ) ? get_query_var('paged') : 1 ;
$query = array(
'posts_per_page' => 5,
'cat' => $category_id,
'paged' => $paged ,
'post_type' => array('post','custom_1','custom_2','custom_3')
);
$loop = new WP_Query( $query);
print_r($loop);
Как видите, я добавил дополнительные скобки вокруг первого get_query_var
, чтобы это стало правильным тернарным оператором. Я проверил это на своем тестовом стенде, и всё работало отлично.
С уважением, Анди

Спасибо, @Andy Killen. К сожалению, это не помогло. Похоже, проблема где-то ещё в теме. Хотя я ожидал, что wp_reset_query() даст мне чистый лист, верно? Но когда 'cat' присваивается через $val, WP начинает искать какой-то другой набор аргументов. И эти аргументы действительно похожи на те, которые сайт использует в другом месте. Что я не понимаю — почему? Почему он не использует те аргументы, которые я ему передаю? И главное — раз у меня нет реальных ошибок, как мне попытаться локализовать эту "утечку"? Любые предложения были бы очень ценны. Спасибо!

Я согласен с Wyck (комментарий ниже), скорее всего, проблема в другом плагине или вашей теме. Попробуйте отключить все плагины и проверить снова. Если это не поможет, попробуйте поместить ваш categories.php в тему twentyten или подобную и проверить там.
wp_reset_query() не так критичен в этой ситуации. Можно рассматривать это как вложенный цикл внутри стандартного, если хотите — раз вы используете свою переменную для хранения цикла, это не так важно.

А что, если я просто сделаю обычный SQL-запрос? Это не добавит лишней нагрузки, верно? Просто мне кажется, что к тому времени, как я найду источник "утечки" — а возможно, мне это и не удастся, ведь использование переменной для триггера "бага" само по себе странно — я мог бы просто написать SQL-запрос и не париться с WP_Query() и его проблемами.
