Как я могу создать meta_query с массивом как meta_field?

16

Вот аргументы для моего запроса:

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        array(
            'key' => 'topics',
            'value' => 'sports',
        )
    )
);

Это работает, когда topicsэто строка, но не когда это массив. Я хотел бы, чтобы этот запрос работал, когда, topicsнапример,array( 'sports', 'nonprofit', etc. )

Есть ли способ создать мета-запросы с массивами в качестве meta_key?

mike23
источник
Пожалуйста, уточните - вы имеете в виду, что хранимое значение "themes" является массивом? Или что сохраненное значение является строкой, и вы хотите передать несколько терминов в запрос в массиве?
MathSmath
@MathSmath, я имею в виду, что сохраненное значение является массивом.
mike23

Ответы:

31

Подача запроса массивом возможных значений

Если значение в базе данных является строкой и вы хотите передать запросу несколько значений:

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        array(
            'key' => 'topics',
            'value' => array ( 'sports', 'nonprofit', 'community' ),
            'compare' => 'IN'
        )
    )
);

Поиск определенного значения в сериализованном массиве данных

Если значение в базе данных представляет собой массив из нескольких тем, и вы хотите найти одну тему в этом массиве (обратите внимание, что массив в базе данных может быть извлечен как таковой, но живет в базе данных в сериализованной форме, которая является строка также):

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        array(
            'key' => 'topics',
            'value' => 'sports',
            'compare' => 'LIKE'
        )
    )
);

Использование 'LIKE' в качестве значения для сравнения не является такой четкой инструкцией, как вы могли бы надеяться, но это лучший вариант.

Кроме того, единственной другой опцией будет получение всех сообщений, для которых заданы мета-ключи « themes », и повторение их вручную или, другими словами, проверка значения в цикле и отображение сообщений в указанном условии.

Йоханнес Пилле
источник
14

Чтобы уйти от ответа Йоханнеса, поскольку это сериализованный массив, если вам случается хранить что-то вроде идентификатора пользователя (что было в моем случае), вам, возможно, придется обрабатывать его немного по-другому.

Сообщение мета было сохранено как:

array( "1", "23", "99");

Так что да, они целые числа, но через update_post_metaних они были сохранены как строки.

'meta_query' => array(
            array(
                    'key'     => 'my_meta_key',
                    'value'   => serialize( strval( 1 ) ),
                    'compare' => 'LIKE'
                )
            )

Таким образом, вы фактически сравниваете LIKE с сериализованной строковой версией того, что вы ищете. Я потратил пару часов, пытаясь заставить что-то подобное работать, и пока это было лучшее, что я мог придумать.

sMyles
источник
Сериализация (strval (1)) решила мою проблему, спасибо
Behzad
Наткнулся сегодня на этот старый ответ случайно. Мне нравится ваше дополнение. +1
Йоханнес Пилле
Я только что столкнулся с этим, мое дело в том, что мне нужно получить все сообщения, где user_id не находится в массиве, но вышеупомянутое решение не работает, поэтому я сделал это так: 'meta_query' => array( array( 'key' => 'my_meta_key', 'value' => ':' . $user_id . ';', 'compare' => 'NOT LIKE' ) ) потому что при сериализации все значения сохраняются как: ' :значение;'
Бобз
4

Еще одно небольшое улучшение от ответа @sMyles.

У меня были случаи, когда идентификаторы были сохранены как в виде строк (например, когда взяты из ввода формы) и как целые числа (например update_post_meta($post_id, authorized_users', array(get_current_user_id()));). Это похоже на хорошо известную проблему, wp_set_object_terms()когда вы можете использовать идентификаторы терминов для установки терминов, но если вы сначала не приведете их к целым числам, у вас будет 50% шанс создать новые термины с этими числами в качестве их имен. вместо.

Это может привести к тому, что они будут по-разному храниться в сериализованном массиве, как видно из выдержек из такого случая из базы данных моего тестового сайта:

a:1:{i:0;s:1:"1";} // 's' for 'string', also note the double quotes
a:1:{i:0;i:1;} // 'i' for 'integer', no quotes

Оба из вышеперечисленных, при подаче через print_r()будет отображаться как

Array
(
    [0] => 1
)

Чтобы исправить это, я внес небольшую поправку в строку, meta_queryдобавив relationи другую версию запроса, которая преобразует значение как целое число вместо строки.

Вот окончательный результат:

        'meta_query' => array(
            'relation' => 'OR', // Lets it know that either of the following is acceptable
            array(
                'key' => 'bcm_enm_authorized_users',
                'value'   => serialize(strval(get_current_user_id())), // Saved as string
                'compare' => 'LIKE'
            ),
            array(
                'key' => 'bcm_enm_authorized_users',
                'value'   => serialize(intval(get_current_user_id())), // Saved as integer
                'compare' => 'LIKE'
            ),
        ),

РЕДАКТИРОВАТЬ: Просто понял, что этот метод может столкнуться с риском столкновения с индексами массива, что может позволить кому-то незаконный доступ к материалам, если они не в массиве, но их идентификатор пользователя отображается в виде индекса. Таким образом, хотя это работает, если у вас есть обсуждаемая проблема, лучше убедиться, что любые значения, которые вы хотите найти, приводятся в виде строк перед их сохранением, чтобы вы могли вместо этого использовать метод @sMyles.

Кадзи
источник
Это должен быть выбранный ответ, самый надежный
Амин
2

Я бы пошел за ответ Йоханнеса. Тем не менее, я хочу улучшить это, потому что используя этот meta_query, вы встретите такой случай

ваша ценность

array('sports','movies', 'sports2');

когда вы ищете

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        array(
            'key' => 'topics',
            'value' => 'sports',
            'compare' => 'LIKE'
        )
    )
);

тогда результат вернет оба «спорт» и «спорт2».

Чтобы это исправить, измените аргументы meta_query на

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        array(
            'key' => 'topics',
            'value' => 'sports";',
            'compare' => 'LIKE'
        )
    )
);

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

Если элементы в значении являются числом, вам просто нужно удалить двойную кавычку "

$args = array(
        'post_type' => 'news',
        'meta_query' => array(
            array(
                'key' => 'topics',
                'value' => '1;',
                'compare' => 'LIKE'
            )
        )
    );
Ха Доан Нгок
источник
1

Я боролся с чем-то похожим сегодня. Мне нужно запросить поле отношения ACF (Advanced Custom Fields) с несколькими связанными пользователями (массив).

После обновления поля через php запрос не работал. После обновления через ACF UI запрос сработал.

Проблема заключалась в том, что мой php-код установил значения отношений как int-values, а пользовательский интерфейс - строковые значения. Чтобы убедиться, что оба работают, я использую этот запрос сейчас (в соответствии с примером здесь):

$args = array(
    'post_type' => 'news',
    'meta_query' => array(
        'relation' => 'OR',
        array(
            'key' => 'topics',
            'value' => '1;',  // works for int-array
            'compare' => 'LIKE'
        ),
        array(
            'key' => 'topics',
            'value' => '"1"',  // works for string-array
            'compare' => 'LIKE'
        ),
    )
);
Джулиан Старк
источник