LIKE %...% Мета-запрос
У меня есть сериализованный массив в качестве мета-значения, и я пытаюсь выполнить WP Query, чтобы найти определенное значение в этом сериализованном массиве.
Вот пример поля сериализованного массива:
a:6:{i:0;s:3:"173";i:1;s:3:"172";i:2;s:3:"171";i:3...
Вот мой запрос, но он не работает: ID, которые я ищу, также являются числовыми.
$practiceArgs = array(
'post_type' => 'attorney', // тип записи: адвокат
'post_status' => 'publish', // статус: опубликовано
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'practice_area', // ключ: область практики
'value' => $post->ID,
'compare' => 'LIKE',
'type' => 'NUMERIC'
)
)
);
Я пробовал использовать 'value' => '%'.$post-ID.'%'
в моих запросах, но это тоже не работает.
У кого-нибудь был опыт работы с подобным?

Я столкнулся с такой же проблемой сегодня. В обоих наших случаях существует отличное решение. Поскольку сериализованные данные, которые мы ищем, представляют собой просто идентификаторы и всегда заключены в кавычки, нам достаточно включить кавычки в сам запрос. Это устраняет проблему ложных срабатываний при поиске.
Вам просто нужно изменить meta query следующим образом:
array(
'key' => 'practice_area',
'value' => '"'.$post->ID.'"',
'compare' => 'LIKE',
)
Таким образом, поиск будет выполняться по всему идентификатору, включая двойные кавычки до и после него в сериализованном массиве. Ложные срабатывания будут исключены.

Я однажды столкнулся с этой проблемой, и это определенно не самое приятное место. Подход, который вы используете, никогда не даст вам стабильного результата — ваш поиск будет выдавать множество ложных срабатываний (например, поиск по ID записи 43 вернет 143, 243, 1431, 1432 и т. д.).
На мой взгляд, у вас есть два варианта:
- Пересмотреть способ сохранения метаданных: используйте массивы для данных, которые нужны только при отображении записи, но не для данных, по которым нужно фильтровать записи. Для последних используйте отдельные мета-ключи в базе данных — это намного быстрее, запросы проще кодировать, и вы можете быть уверены, что полностью контролируете результаты запросов. Не беспокойтесь о слишком большом количестве строк в таблице postmeta: для этого они и существуют.
- Если по какой-то причине вам нужно хранить несколько полей в одной строке базы данных, не полагайтесь на стандартную сериализацию: используйте CSV, желательно с каким-то префиксом, чтобы избежать ложных срабатываний. Например,
"id:43,id:54,foo:bar,id:57,"
, а затем ищите 'id:{post_ID},
' (обратите внимание, что все значения должны заканчиваться запятыми, чтобы безопасно использовать двойные подстановочные знаки в LIKE-запросе). Это своего рода хак, но он надежнее, чем ваш текущий подход.
Что касается исходного вопроса, WordPress уже добавляет оба подстановочных знака при выполнении LIKE-сравнений с помощью query_posts
, так что вам ничего не нужно делать дополнительно.

В WordPress LIKE работает не так, как Mysql Like, поэтому 'value' => '%'.$post-ID.'%' не сработает.
Вы можете попробовать версию с REGEXP. Например:
'meta_query' => array(
array(
'key' => 'attorney',
'value' => '^'.$post-ID,
'compare' => 'REGEXP',
)
)
Должно искать все элементы, где attorney начинается со значения $post-ID.

Вы не можете использовать LIKE
с numeric
(по крайней мере, я почти уверен, что нельзя). numeric
попытается преобразовать всё value
в число. Это не сработает, так как значение не является числом. Это первая ошибка.
Во-вторых, чтобы передать символ %
буквально, нужно удвоить его до %%
. Примечание: я не помню точно насчёт meta_query
. Я экстраполирую из того, что требуется для передачи %
через $wpdb->prepare
. Думаю, здесь то же самое. Примечание: Оказывается, это верно только для $wpdb->prepare
. Код был отредактирован.
Я не тестировал это, так как мне нужно настроить некоторые вещи в базе данных, и у меня нет времени прямо сейчас, но думаю, что это сработает.
$practiceArgs = array(
'post_type' => 'attorney',
'post_status' => 'publish',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'practice_area',
'value' => $post->ID,
'compare' => 'LIKE'
)
)
);
Надеюсь, это поможет вам продвинуться дальше. Если не сработает, я вернусь к этому вопросу.
Примечание: Я вставил ваш (некорректный) сериализованный массив в свою базу данных и запустил приведённый выше код. Если всё настроено правильно — метаполя, типы записей и т.д. — код работает. Если у вас не срабатывает, значит, проблема в чём-то другом — возможно, вы ожидаете совпадения там, где его нет.
Я предполагаю, что у каждого из ваших записей типа 'attorney' будет массив подобного вида. Если это так, код должен работать. Однако я бы рекомендовал использовать несколько строк practice_area
вместо сериализованного массива. =
— более эффективный запрос, чем LIKE
, особенно с подстановочными знаками, и результаты должны быть точнее. Индексация (в MySQL) также будет работать лучше.

Ваш комментарий относительно '%' верен только при использовании $wpdb->prepare. При использовании query_posts использование '%' не требуется: WordPress автоматически добавляет их за вас, хотите вы этого или нет.
