Meta запрос с булевым значением true/false

31 июл. 2013 г., 18:23:12
Просмотры: 33.7K
Голосов: 18

Я пытаюсь отобразить все объекты недвижимости для аренды, сначала показывая все свободные объекты, а затем все, которые уже арендованы. Есть произвольный тип записи 'rent' с произвольным мета-полем для цены аренды (_price_rented), которое является чекбоксом (возвращает true или false... true, если объект УЖЕ арендован). Мне нужно изменить запрос, чтобы показывать все объекты, причем сначала доступные (не арендованные) объекты, а затем арендованные.

Вот мой запрос:

$ts_properties = new WP_Query( 
    array( 
    'post_type' => 'rent', 
    'paged' => $paged, 
    'posts_per_page' => -1,
    'meta_key' => '_price_rented',
    'orderby' => 'meta_value',
    'order' => 'DESC',
    'meta_query' => array(
        array(
        'key' => '_price_rented',
        'value' => false,
        'type' => 'BOOLEAN',
        ),
    ) 
) 
);

По какой-то причине этот запрос показывает все объекты, которые УЖЕ арендованы. Когда я меняю значение с 'false' на 'true' в meta_query, он не показывает никаких объектов.

Затем я подумал, что возвращаемое значение либо false (для объектов, которые арендованы), либо NULL (для объектов, которые НЕ арендованы), но я не уверен, как делать запрос для результата NULL (не false). Я добавил аргумент 'compare' в meta_query и установил значение '!=', но это тоже не сработало.

РЕДАКТИРОВАНИЕ: var_dump возвращает следующее для доступной, не арендованной квартиры: string(0) "" и для недоступной, арендованной квартиры: string(1) "1"

11
Комментарии

использовать значения 1 и 0, возможно?

reikyoushin reikyoushin
31 июл. 2013 г. 18:24:55

meta_query type => string . Возможные значения: 'NUMERIC', 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', 'UNSIGNED'. Значение по умолчанию: 'CHAR'.

iEmanuele iEmanuele
31 июл. 2013 г. 18:29:01

@reikyoushin: использование '1' возвращает все арендованные объекты, а '0' не возвращает ни одного объекта.

Kegan Quimby Kegan Quimby
31 июл. 2013 г. 18:29:45

@iEmanuele: изменение этого, похоже, не дает эффекта (я думал то же самое). Я увидел это в статье: http://thethemefoundry.com/blog/query-posts-wordpress-false-null-meta-value/

Kegan Quimby Kegan Quimby
31 июл. 2013 г. 18:30:44

Я имею в виду использовать 1 и 0 для значений вместо булевых, тогда вам не нужен meta_query.. вам просто нужно сортировать по 'meta_key' => '_price_rented', 'orderby' => 'meta_value', 'order' => 'ASC',

reikyoushin reikyoushin
31 июл. 2013 г. 18:37:10

Установлено ли _price_rented для обоих значений true и false, или только для true? Проверьте базу данных, пожалуйста. Я спросил, потому что неотмеченный чекбокс вообще не передается через POST, поэтому мне интересно, установлено ли значение вообще для таких случаев.

s_ha_dum s_ha_dum
31 июл. 2013 г. 18:45:55

Удалите 'meta_key' => '_price_rented' из базового массива. Возможно, WP_Meta_Query путается из-за наличия обоих. Кстати, BOOLEAN не является допустимым значением и будет сброшен до CHAR, который используется по умолчанию. А если вы используете NUMERIC, попробуйте переключиться на SIGNED. Также убедитесь, что вы выполнили var_dump( get_post_meta( get_the_ID(), '_price_rented', true ) ); и добавили вывод этого кода в ваш вопрос. И если это "true" или "false", то установите value внутри этого массива как строку (в кавычках).

kaiser kaiser
31 июл. 2013 г. 19:06:52

@s_ha_dum оно устанавливается только в "true", если флажок не снят, в противном случае возвращается пустая строка "0".

Kegan Quimby Kegan Quimby
31 июл. 2013 г. 19:38:08

@kaiser var_dump возвращает следующее для доступной, не арендованной квартиры: string(0) "" а для недоступной, арендованной квартиры: string(1) "1"

Kegan Quimby Kegan Quimby
31 июл. 2013 г. 19:40:04

Смотрите решение в ответе.

kaiser kaiser
31 июл. 2013 г. 19:57:51

@KeganQuimby есть какие-то успехи по этому вопросу?

kaiser kaiser
19 авг. 2013 г. 20:35:15
Показать остальные 6 комментариев
Все ответы на вопрос 4
0
12

Кратко: Эта проблема, скорее всего, возникает, когда логическое поле создается как необязательное. Вы можете исправить это, сделав поле обязательным или используя более сложный запрос для получения значений по умолчанию.

Подробности:

Здесь есть две проблемы с представлением данных: первая — какие значения используются для представления true/false, а вторая — сохраняется ли поле вообще, если оно имеет значение по умолчанию (обычно false).

Часть 1: Я изучил SQL, генерируемый WP_Meta_Query для сравнений с true и false, и обнаружил, что для true он подставляет '1', а для false — '' (пустую строку). Поэтому, если вы выполняете запросы с сравнением фактических значений true и false, данные в базе должны соответствовать этому. В частности, не стоит записывать '0' для false. Возможно, надежнее использовать 0 и 1 (так делают многие конструкторы форм). Но проверьте, что записывается в базу, и учитывайте это при построении запроса.

Часть 2: Предположим, что false — значение по умолчанию. Найти записи со значением true легко:

... 'meta_key' => 'my_key', 'meta_value' => 1 (или true)

Но обратная ситуация сложнее: значение может быть false, а может вообще отсутствовать. Такое бывает, если поле было необязательным в форме — тогда, пока пользователь явно не установит или не изменит его, оно не добавится в базу. Заметим, что если вы используете только get_post_meta, всё будет работать нормально: возврат false или отсутствие значения дадут одинаковый результат.

Но при использовании WP_Query всё не так просто. (Или, если есть простой способ, я его пока не нашёл).

У вас есть два (или, возможно, три) варианта:

  1. Убедитесь, что поле всегда явно инициализируется реальным значением. В некоторых конструкторах форм это делается через обязательное поле со значением по умолчанию. Тогда можно проверять ...'meta_value' => 0.

  2. Выполнить два запроса: первый проверяет значение false, второй — отсутствие значения. Их можно объединить в один WP_Query:

    meta_query => array(
       'relation' => 'OR',
        array(
            'key'     => 'my_key',
            'value'   => 0,
            'compare' => '='
        ),
        array(
            'key'     => 'my_key',
            'compare' => 'NOT EXISTS',
        ),
    )
    

Такой запрос, вероятно, не самый эффективный. В зависимости от многих факторов, может быть лучше получить все объекты и отфильтровать их в своём коде.

  1. Можно использовать "отсутствие значения" как false. Для этого, когда значение должно быть false, нужно удалять мета-значение, а не обновлять его.

В этом случае простой запрос с 'NOT EXISTS' будет надёжно возвращать правильные объекты. (Я не думаю, что многие конструкторы форм или плагины поддерживают такое поведение, поэтому я бы использовал его только в полностью кастомном коде.)

13 нояб. 2016 г. 08:34:00
0

WP_Meta_Query — это в некотором роде "не очень стабильная" часть ядра WordPress, и если не быть очень внимательным, она может легко сломаться из-за путаницы.

Когда вы выполняете new WP_Query() с аргументами meta_query => array() или их эквивалентами в виде одиночных пар ключ/значение, то в дело вступает new WP_Meta_Query(), за которым сразу же следует парсинг.

$this->meta_query = new WP_Meta_Query();
$this->meta_query->parse_query_vars( $q );

Допустимые значения

При запросе метаданных есть опция bool. Если вы её используете, то она вернётся к CHAR, который является значением по умолчанию, так как массив допустимых значений выглядит так:

'NUMERIC', 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', 'UNSIGNED'

где NUMERIC будет сброшен в SIGNED.

Отладка

Существует множество фильтров, которые могут повлиять на процесс сохранения записи, поэтому первое, что нужно сделать — проверить различные значения внутри цикла:

var_dump( get_post_meta( get_the_ID(), '_price_rented', true ) );

Затем, в зависимости от возвращаемого значения, вам либо придётся использовать SIGNED, если результат 0 или 1, либо "true" или "false", если результат — строка. Если это действительно булево значение, я всё равно рекомендую использовать string, чтобы убедиться, что оно пройдёт через $GLOBALS['wpdb'], который может передавать только строки %s и цифры %d.

Дополнительные замечания

Сегодня я обновил запись в Codex для WP_Meta_Query и увидел, что существует множество различных выводов (добавляющих множество ненужных JOINS, которые обсуждаются в Trac здесь и здесь с без единичным патчем, перенесённым в ядро). (Последующий тикет для частей AND здесь). Суть в том, что можно использовать комбинацию аргументов meta_* вместе с массивом meta_query и его подмассивами. Результат практически неизвестен, если не сделать дамп, поэтому ИМХО лучше использовать либо один, либо другой способ добавления входных данных. Особенно когда вы используете только meta_key, так как в некоторых случаях это приводит к "запросу только по ключу".

Решение

Как указано в комментариях:

(...) var_dump возвращает следующее для доступной, неарендованной квартиры: string(0) "", а для недоступной, арендованной квартиры: string(1) "1"

Теперь meta_query должен использовать

'meta_query' => array( 'relation' => 'OR', array(
    'meta_key'     => '_price_rented',
    'meta_value'   => '1',
    'meta_compare' => '='
) );

Если вы хотите получить "недоступные, арендованные квартиры" или используйте '!=' для получения "неарендованных" квартир.

Примечание: Возможные значения для meta_compare'=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'NOT EXISTS', 'REGEXP', 'NOT REGEXP' или 'RLIKE'. Значение по умолчанию — '='.

31 июл. 2013 г. 19:28:18
0

Я столкнулся с той же проблемой и после часа поиска обнаружил значения "NOT EXISTS" и "EXISTS" (только в WP >= 3.5). Так что нет необходимости запрашивать значение метаполя — достаточно проверить, существует ли meta_key:

'meta_key'     =>   '_price_rented'  ,
'meta_compare' =>   'NOT EXISTS'     ,

Это отлично работает в моём случае.

11 дек. 2013 г. 12:58:12
0

return false записывается как 0, return true записывается как 1

Поэтому просто добавьте value="1" к вашему input type checkbox, чтобы при отправке формы передавалось значение "1" при отмеченном чекбоксе, а не стандартное "on"

В вашем meta query просто делайте как обычно:

array(
  'key'     => 'your_key',
  'value'   => 'your_value',
  'compare' => '='
)
11 дек. 2024 г. 19:21:38