Запрос всех записей, где мета-ключ не существует
Я пытаюсь составить запрос для получения всех записей, где определенный meta_key
не существует, чтобы затем создать его.
У меня возникли проблемы с поиском этих записей, так как тестируемый запрос, похоже, не работает.
Вот код, который я использую для попытки получить эти записи:
$args = array(
'posts_per_page' => 18,
'cat'=>1955,
'post_status'=>'publish',
'meta_query' => array(
array(
'key' => 'colors',
'compare' => 'NOT EXISTS'
),
));
query_posts($args);
Это не возвращает ничего, если нет записей с ключом colors
, но возвращает ids
записей с ключом colors
, когда этот ключ присутствует (противоположное тому, что мне нужно). Я пробовал использовать EXIST
, но безуспешно.
Буду признателен, если кто-то подскажет правильный способ создания нужного мне запроса.
Спасибо!

Я провел дополнительные тесты и, честно говоря, не вижу причин, почему это не должно работать (если только приведенный выше код не является фрагментом, а реальный код соответствует моим примерам ниже). Однако я обнаружил пару моментов, которые могут направить вас в правильное русло.
1) Сам по себе этот meta_query эквивалентен условию "colors IS NULL", т.е. он вернет записи, у которых этот ключ не установлен в таблице postmeta. Это показано выше, и это должно было работать.
'meta_query' => array(
array(
'key' => 'colors',
'compare' => 'NOT EXISTS' // это должно работать...
),
)
2) До WordPress 3.9 установка индекса 'relation' в значение 'OR' меняет это условие. Оно возвращает противоположный результат. Не спрашивайте меня почему. Это особенно важно при выполнении нескольких meta-запросов. Это означает, что изначально невозможно сделать запрос для записей, у которых ключ 'colors' установлен в значение 'blue' (или любое другое) или не установлен вообще. Запрос ниже проигнорирует первое условие и вернет только те записи, которые соответствуют второму условию.
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'colors',
'compare' => 'NOT EXISTS' // не работает
),
array(
'key' => 'colors',
'value' => 'blue'
)
)
3) Однако мы можем обмануть WordPress, заставив его использовать первое условие, если мы установим 'value'. Это значение не должно быть релевантным (оно игнорируется, насколько я знаю), но оно должно быть установлено, чтобы условие NOT EXISTS
имело какой-либо эффект.
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'colors',
'compare' => 'NOT EXISTS', // работает!
'value' => '' // Это игнорируется, но необходимо...
),
array(
'key' => 'colors',
'value' => 'blue'
)
)
Это было актуально до WordPress 3.9. Если вы все еще используете более старую версию, это рабочее решение.

Спасибо! И извините за задержку. В итоге я использовал запрос, но в ближайшие часы протестирую ваше решение, чтобы можно было вернуться к нему. Если это сработает, мы сможем помочь и другим. Дам знать, как только проверю. Ещё раз спасибо!

Хорошо написано и подтверждено, что добавление пустого значения возвращает ожидаемые результаты. Скорее всего, это непреднамеренно, возможно стоит проверить trac.wordpress.org на наличие уже созданного тикета. Если его нет, то ошибка воспроизводима.

Спасибо за отличное объяснение и решение, как обойти WP :) Потребовалось время, чтобы добраться сюда - теперь хочется поставить плюс хотя бы 10 раз (если бы только можно было ;))

Если я использую сравнение EXISTS, к сожалению, значение не игнорируется в новых версиях WP (проверено в 4.2.2)

Обратите внимание на orderby meta_key
, который также может быть в вашем запросе! Wordpress жестко прописывает WHERE meta_key = value
для сортировки по мета-полю!

"Баг" с EXISTS
и NOT EXISTS
, который требовал указания значения, был исправлен в WP 3.9

trex005 прав: "(Примечание: Из-за бага #23268, значение обязательно для корректной работы сравнений NOT EXISTS до версии 3.9. Вы должны указать какую-либо строку для параметра value. Пустая строка или NULL НЕ сработают. Однако, любая другая строка подойдет и НЕ появится в вашем SQL при использовании NOT EXISTS. Нужно вдохновение? Как насчет 'bug #23268'.)"
