Пока разрабатывал фильтр таксономий по полям ACF (Advanced Custom Fields) для одного из проектов, столкнулся со следующей проблемой. Мне нужно было вывести и сделать множественный выбор полей ACF с последующей фильтрацией данных после выбора пользователем разных вариантов. Выводил список категорий через функцию WordPress — get_terms($args);
, затем выводил полученные категории через foreach.
Код следующий:
$args = array(
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'acf-filed-name',
'value' => '$_GET['filter']['acf-field-name']',
'compare' => 'LIKE'
)
)
);
$categories = get_terms($args);
Все в общем-то было хорошо, но когда в meta_query было несколько массивов, например, больше 4, то метод сравнения LIKE ломал сайт, так как нагрузка на сервер была колоссальная. Методы сравнения через = или другие сравнения не давали никакого результата.
Все дело в том, что значение поля ACF с множественным выбором записывается в бд как сериализованный массив, я начал искать и ничего не нашел в документации ACF про данную проблему с множеством массивов внутри meta_query.
Пример сохраненных в бд метаданных находится в сериализованном массиве, подобном приведенному ниже:
a:4:{i:0;s:7:"acf-field-name";i:1;s:15:"acf-field-two";i:2;s:4:"acf-more-v";i:3;s:14:"acf-type-f";}
В документации писали только про 2-3 массива, но не более и метод сравнения там был LIKE.
Решение проблемы:
$args = array(
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'acf-field-name',
'value' => '"(' . implode('|', $_GET['filter']['acf-field-name']) . ')"',
'compare' => 'REGEXP'
),
array(
'key' => 'acf-field-two',
'value' => '"(' . implode('|', $_GET['filter']['acf-field-two']) . ')"',
'compare' => 'REGEXP'
)
)
);
$categories = get_terms($args);
Поскольку метаданные сериализованы в столбце базы данных и технически представлены в виде строки, можно выполнить сравнение с помощью REGEXP.
Если ваши значения «value» содержат специальные символы, которые должны быть экранированы для корректного REGEXP, используйте функцию preg_quote. В противном случае это решение должно работать на все сто процентов.
Сравнение через REGEXP работает гораздо быстрее, чем LIKE и так сильно не нагружает сервер хостинга.
Протестировано на WordPress 6.2 (PHP 8.2).
Дата создания статьи: 08.05.2023
Рубрика: Веб-разработка