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 — обращайтесь к ней, там могут появляться новые примеры.
На этом всё. Успехов!