Как фильтровать поля Carbon Fields в WP_Meta_Query

  1. Главная
  2. Блог
  3. WordPress
  4. Как фильтровать поля Carbon Fields в WP_Meta_Query

Carbon Fields (далее по тексту — CF) — это библиотека для работы с мета-полями. Про него я писал в этой статье. И нам, как разработчикам, часто нужно находить записи по этим полям. Если речь про текстовые поля — там все просто. А если это ассоциации или комплексные поля — то уже нет. Рассмотрим фильтрацию по всем типовым полям carbon fields через meta_query

Эта статья касается последних версий CF. Если вы работаете с версией CF 1.x, то вам эта статья не подойдет.

Если не хотите читать многобукв, сразу переходите к подразделу «Решение» по интересующему вас полю 🙂

Фильтрация простых текстовых полей

Здесь нет ничего особенного. Текстовые поля фильтруются точно так-же, как если-бы вы их создали используя штатные средства WordPress мета-полей. Так можно фильтровать любые поля, за исключением полей типа Association, Map и Complex — о них мы поговорим ниже.

Но давайте все равно рассмотрим пример работы с простыми полями CF.

Решение 1

Тут работаем с простым текстовым полем. Создадим его:

Container::make( 'post_meta', 'Полезное' )
    ->where( 'post_type', '=', 'page' )
    ->add_fields( array(
        Field::make( 'text', 'product_weight', 'Вес товара в граммах' ),
    ) );

Допустим, нам нужно найти товары весом 100 грамм. И хотя CF поле с именем «product_weight» запишет как «_product_weight», мы все равно можем найти нужные записи вот так:

$results = new WP_Query( array(
    'post_type' => 'page',
    'meta_query' => array(
        array(
            'key' => 'product_weight',
            'value' => 100,
        ),
    ),
) );

Решение 2

Здесь работаем с полем типа «rich_text». Это классический редактор контента WordPress. Создадим поле:

Container::make( 'post_meta', 'Полезное' )
    ->where( 'post_type', '=', 'page' )
    ->add_fields( array(
        Field::make( 'rich_text', 'preview_description', 'Превью описание' ),
    ) );

Логично, что искать записи с полным соответствием содержимого этого поля не нужно. Оно создано для объемного контента, а ищем обычно мы по отдельным словам и фразам. Мы можем найти страницы, у которых в этом поле есть слово, например, «скидка». Давайте сделаем это:

$results = new WP_Query( array(
    'post_type' => 'page',
    'meta_query' => array(
        array(
            'key' => 'preview_description',
            'compare' => 'LIKE',
            'value' => "%скидка%",
        ),
    ),
) );

Фильтрация поля типа Association

Если попытаться фильтровать записи по полям типа association как обычные, текстовые поля — то ничего не получится. Это связано с тем, как CF сохраняет данные этих полей. Рассмотрим всю ситуацию.

Представим, что у нас есть такой контейнер с ассоциативным полем:

Container::make( 'post_meta', 'Полезное' )
    ->where( 'post_type', '=', 'page' )
    ->add_fields( array(
        Field::make( 'association', 'useful', 'Полезные записи' )
            ->set_types( array(
                array(
                    'type' => 'post',
                    'post_type' => 'post',
                ),
            ) ),
    ) );

Предполагается, что на страницах мы можем выводить какие-то конкретные записи через этот интерфейс.

Добавим несколько записей на страницу:

Информация мета-полей записей типа WP_Post, как и положено, сохраняется в таблице wp_postmeta. Посмотрим, в каком виде эта информация сохранилась:

Как видим, для одной ассоциации CF создает 4 записи в БД. Содержимое мета-ключа отличается от того, что мы видим обычно, не говоря уже о названии мета-ключа. Из-за особенностей хранения данных для таких полей, фильтровать их как обычно у нас не получится. Хотя в некоторых случаях с этим тоже можно работать.

Решение

После такого может показаться, что решение сложное, либо что нужно костылировать костыльные костыли. На деле решение простейшее 🙂

Получим страницы, у которых указана определенная запись:

$results = new WP_Query( array(
    'post_type' => 'page',
    'meta_query' => array(
        array(
            'key' => 'useful',
            'carbon_field_property' => 'id', //Ключевое в условии meta_query указать этот параметр
            'compare' => '==',
            'value' => 213,
        ),
    ),
) );

Таким образом, мы получим страницы, в которых есть запись с ID 213.

Тут, кстати, работать можно также как с обычными мета-полями. Например, можно получить страницы, в которых есть несколько нужных нам записей, при помощи оператора IN:

$results = new WP_Query( array(
    'post_type' => 'page',
    'meta_query' => array(
        array(
            'key' => 'useful',
            'carbon_field_property' => 'id',
            'compare' => 'IN',
            'value' => array( //В массиве указываем ID записей, которые должны быть указаны в поле
                32,
                7879,
                74
            ),
        ),
    ),
) );

Фильтрация поля типа Map

Тут всё тоже самое как с ассоциациями. Создадим поле map:

Container::make( 'post_meta', 'Полезное' )
    ->where( 'post_type', '=', 'page' )
    ->add_fields( array(
        Field::make( 'map', 'map_point', 'Точка на карте' )
    ) );

Решение

Получим все записи, с полем «map_point»,у которых долгота больше значения «-2»:

$results = new WP_Query( array(
    'post_type' => 'page',
    'meta_query' => array(
        array(
            'key' => 'map_point',
            'carbon_field_property' => 'lng',
            'compare' => '>',
            'value' => -2,
        ),
    ),
) );

Фильтрация поля типа Complex

Такое поле тоже может ввести в замешательство из-за своей специфики: в нем может быть огромное множество полей, в том числе и полей типа Complex и так до бесконечности.

Предположим, что у нас есть повторяющееся поле «Города»

Container::make( 'post_meta', 'Дополнительно' )
    ->where( 'post_type', '=', 'post' )
    ->add_fields( array(
        Field::make( 'complex', 'cities', 'Города' )
            ->add_fields( array(
                Field::make( 'text', 'city_name', 'Название города' ),
            ) )
    ) );

Решение

Вот так мы можем отфильтровать записи с определенными городами:

$results = new WP_Query( array(
    'post_type' => 'post',
    'meta_query' => array(
        array(
            'key' => 'cities/city_name',
            'value' => "Калининград",
        ),
    ),
) );

Да, тут тоже всё проще пареной репы 🙂

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

Заключение

Надеюсь, статья была полезна 🙂

Спасибо пользователям официального форума Carbon Fields, за подсказку по фильтрации полей типа association. Часть информации по фильтрации поля association взята отсюда — https://community.carbonfields.net/t/querying-association-fields/53

Также информацию для примеров брал из официальной документации CF — https://docs.carbonfields.net/learn/advanced-topics/queries.html — обращайтесь к ней, там могут появляться новые примеры.

На этом всё. Успехов!