Использование $wpdb для запроса постов с meta_value, содержащим текущий post_id

4 авг. 2013 г., 09:20:14
Просмотры: 15.7K
Голосов: 3

Я пытаюсь использовать $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 ) {
        ......
        }

Буду благодарен за любые идеи.

Спасибо

0
Все ответы на вопрос 3
1

В вашем коде вы получаете не 'список записей', как вы говорите, а список строк из таблицы метаданных. Если вам действительно нужно получить список записей, используйте 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 в запрос.

4 авг. 2013 г. 11:29:04
Комментарии

Согласен. Использование WP_Post — правильный подход.

Cedon Cedon
31 июл. 2017 г. 04:16:36
0

Два замечания:

Поиск метаданных

Правило простое: Сериализованные метаданные (например, массив, преобразованный в a:1:{i:0;s:2:"10";}) не предназначены для поиска. Вам придется преобразовать ваш набор данных в отдельные значения, чтобы можно было выполнять корректный поиск с помощью meta_query.

Единственный действительно работающий способ поиска — это запросить все данные, затем десериализовать их, отобразить, если они соответствуют вашим критериям, или пропустить. На Stack Overflow достаточно обсуждений и вопросов/ответов, которые охватывают эту тему.

Подготовленные выражения

Существует функция like_escape(), которую нужно использовать следующим образом:

"%".like_escape( $string )."%"

Причина, по которой нужно добавлять символы % до и после строки, проста: вы сами решаете, должен ли LIKE выполняться с обеих сторон или только с одной (начало, конец, обе стороны).

4 авг. 2013 г. 14:51:57
0

Кавычки нужны для того, чтобы 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')
31 июл. 2017 г. 04:10:03