Использование $wpdb для запроса постов с meta_value, содержащим текущий post_id
Я пытаюсь использовать $wpdb для получения списка постов из базы данных, где meta_value в таблице wp_postmeta содержит текущий post_ID в кавычках, например: "10".
Кавычки используются, чтобы убедиться, что 10 не совпадет с 100 и т.д.
Мне удалось заставить это работать, когда я вставляю точное значение meta_value, например: a:1:{i:0;s:2:"10";}, однако запрос также возвращает все ревизии, а не только последнюю версию поста.
Вот код, который я сейчас использую:
$id = get_the_ID();
$rows = $wpdb->get_results($wpdb->prepare(
"
SELECT *
FROM wp_postmeta
WHERE meta_key LIKE %s
AND meta_value = %s
",
'roles_%_production',
'%"' . $id . '"%'
));
// цикл по результатам
if( $rows ) {
......
}
Буду благодарен за любые идеи.
Спасибо
В вашем коде вы получаете не 'список записей', как вы говорите, а список строк из таблицы метаданных. Если вам действительно нужно получить список записей, используйте WP_Query
с параметром meta_query
.
Например:
$id = '10'; // десериализованное значение
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'roles_%_production',
'value' => $id,
'compare' => 'LIKE'
)
)
);
$query = new WP_Query( $args );
$rows = $query->get_posts();
Если вы хотите использовать $wpdb (хотя я не знаю, зачем вам это), правильный запрос будет выглядеть примерно так:
<?php
$id = '10'; // десериализованное значение
global $wpdb;
$rows = $wpdb->get_col( $wpdb->prepare(
"SELECT DISTINCT $wpdb->posts.ID FROM $wpdb->posts, $wpdb->postmeta
WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id AND
$wpdb->posts.post_status = 'publish' AND
$wpdb->posts.post_type = 'post' AND
$wpdb->postmeta.meta_key = %s AND
meta_value = %s",
'roles_%_production',
$id
) );
?>
$rows
будет содержать массив ID записей. Я внес это изменение, чтобы придать смысл использованию $wpdb. Если вам нужно получить все поля, используйте SELECT *
вместо SELECT DISTINCT $wpdb->posts.ID
, $wpdb->get_results
вместо $wpdb->get_col
и добавьте строку GROUP BY $wpdb->posts.ID
в запрос.

Два замечания:
Поиск метаданных
Правило простое: Сериализованные метаданные (например, массив, преобразованный в a:1:{i:0;s:2:"10";}
) не предназначены для поиска. Вам придется преобразовать ваш набор данных в отдельные значения, чтобы можно было выполнять корректный поиск с помощью meta_query
.
Единственный действительно работающий способ поиска — это запросить все данные, затем десериализовать их, отобразить, если они соответствуют вашим критериям, или пропустить. На Stack Overflow достаточно обсуждений и вопросов/ответов, которые охватывают эту тему.
Подготовленные выражения
Существует функция like_escape()
, которую нужно использовать следующим образом:
"%".like_escape( $string )."%"
Причина, по которой нужно добавлять символы %
до и после строки, проста: вы сами решаете, должен ли LIKE
выполняться с обеих сторон или только с одной (начало, конец, обе стороны).

Кавычки нужны для того, чтобы 10 не соответствовало также 100 и т.д.
У меня получается заставить это работать, когда я вставляю точное значение мета-поля, например: a:1:{i:0;s:2:"10";}
Это происходит потому, что в вашем WHERE-запросе вы использовали =
, в то время как значение содержит %
. Использование оператора LIKE
вместо этого решит данную конкретную проблему. Измените meta_value = %s
на meta_value LIKE %s
, и ваш запрос будет работать так же, как если бы вы использовали полную сериализованную строку.
Также возвращаются все ревизии, а не только самая последняя запись.
Убедитесь, что вы указываете правильный тип записи и статус при выполнении запроса. Если вы хотите включить все записи, кроме ревизий, вам нужно обязательно присоединить таблицу posts (перед вашим оператором WHERE
).
LEFT JOIN $wpdb->posts ON $wpdb->posts.ID = $wpdb->postmeta.post_id
и добавьте следующую строку в ваш оператор WHERE
(связав через AND
).
$wpdb->posts.post_type NOT IN ('revision')
