Использование post__in и post__not_in вместе?

2 авг. 2013 г., 05:13:30
Просмотры: 22.6K
Голосов: 1

Я пытаюсь показать только те посты, которые пользователь еще не видел, вот так:

$exclude = array(1,2,3);
$include = array(3,4,5);
$args = array(
  'post_type'           => 'post',
  'post_status'         => 'publish',
  'posts_per_page'      => 30,
  'post__in'            => $include,
  'post__not_in'        => $exclude,
  'orderby'             => 'post__in',            
  'tax_query'           => array(
        'relation' => 'AND',
         array(
            'taxonomy'  => 'category',
            'field'     => 'slug',
            'terms'     => array($category_names),
            'operator'  => 'IN'
         ),
         array(
            'taxonomy'  => 'category',
            'field'     => 'ID',
            'terms'     => array($category_ids),
            'operator'  => 'NOT IN'
         )
  )
);
$posts = get_posts($args);

Я ожидаю, что это вернет посты 4 и 5, но возвращаются 3, 4 и 5.

Как установить приоритет между параметрами 'post__in' и 'post__not_in'?

Я знаю, что мог бы использовать array_diff() для переменных $exclude и $include, но реальность сложнее, чем в этом вопросе. У меня есть много разных массивов для сравнения, и некоторые из них многомерные. Я также включаю и исключаю определенные таксономии.

Я также думаю, что другим легче читать, если это запрос WP_Query или $wpdb, чем множество строк PHP для получения параметров запроса.

Кроме того, если array_diff равен пустому массиву, то запрос фактически возвращает посты, а не пустой результат.

Возможно, лучший способ - это использовать вызов $wpdb или найти способ использовать meta_query из WP_Query для поля ID поста?

4
Комментарии

Не могли бы вы объяснить сложную реальность?

s_ha_dum s_ha_dum
2 авг. 2013 г. 06:13:38

Обновлено, чтобы объяснить, почему я по возможности не хочу использовать array_diff. Думаю, подход через $wpdb может быть лучшим вариантом.

Drew Baker Drew Baker
2 авг. 2013 г. 08:22:19

@DrewBaker Я до сих пор ничего не понимаю. Вы говорите: У меня есть много разных массивов для сравнения, и некоторые из них многомерные Но чтобы использовать include и exclude, нужно передать плоский массив id. Так вы делаете какую-то логику для извлечения двух плоских массивов из разных и многомерных массивов? Если да, то вы можете запустить array_diff, и если результат пуст, использовать условие if и не выполнять запрос: $posts = ! empty($diff) ? get_posts($args) : array();

gmazzap gmazzap
2 авг. 2013 г. 12:40:56

Хорошо, я понял, что вы говорите. Я воспользуюсь array_diff(). Спасибо!

Drew Baker Drew Baker
2 авг. 2013 г. 20:18:19
Все ответы на вопрос 2
2

post__in и post__not_in являются взаимоисключающими параметрами.

Примечание: нельзя использовать post__in и post__not_in в одном запросе.

http://codex.wordpress.org/Class_Reference/WP_Query

Как сформулирован ваш вопрос, очевидным решением (которое вы отвергаете) является использование array_diff.

Если это решение действительно не подходит, вам понадобится фильтр для posts_where (скорее всего), который обеспечит нужную логику запроса. Поскольку вы не объяснили, в чем именно заключается "более сложная реальность", невозможно предположить, какой должна быть эта логика.

Но вот пример фильтра posts_where:

function smbd_cats_by_days ($where = '') {
    // global $days_limit; // если это переменная
    // $days_limit = DAYS_LIMIT; // если это константа
    // $days_limit = get_option('days_limit',100);
    // вам нужно раскомментировать одну из строк выше,
    // в зависимости от выбранного механизма
    $where .= " AND post_date < '" . date('y-m-d', strtotime("-{$days_limit} days")) . "'";
    return $where;
}
add_filter('posts_where', 'smbd_cats_by_days');

Основываясь на правке вопроса и этом заявлении о намерениях:

Я пытаюсь показывать только те записи, которые пользователь еще не видел...

Напишите PHP-код для создания массива записей, которые пользователь уже видел, и исключите их с помощью post__not_in. Ваша попытка включить всю логику в запрос только усложняет ситуацию.

Я также считаю, что другим разработчикам будет проще читать код, если это будет WP_Query или вызов $wpdb, а не множество строк PHP, которые в итоге просто формируют параметр запроса.

Когда вы напишете фильтры и/или SQL для включения всей логики в запрос, это не станет более "читаемым", да и изначально такой подход вызывает сомнения. Вы пытаетесь сделать это сложным путем. WP_Query не предназначен для сложной логики, а сложная логика в SQL трудна для написания и понимания даже в лучшие дни.

2 авг. 2013 г. 06:25:02
Комментарии

или, возможно, posts_join http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_join

gmazzap gmazzap
2 авг. 2013 г. 06:29:52

Спасибо, я понял. Тогда я использую array_diff(). Спасибо. Я проголосовал за этот ответ, так как вы потрудились ответить на мой плохой вопрос.

Drew Baker Drew Baker
2 авг. 2013 г. 20:19:02
4

Параметры exclude и include нельзя использовать вместе, этот код используется в ядре, поэтому нужно выбрать что-то одно.

...
if ( ! empty($r['include']) ) {
  $incposts = wp_parse_id_list( $r['include'] );
  $r['posts_per_page'] = count($incposts);  // только количество включенных записей
  $r['post__in'] = $incposts;
} elseif ( ! empty($r['exclude']) )
...

Запрос $wpdb будет простым, если нужны только те аргументы, которые вы указали.

Этот способ прост, но если не сработает, сможете объяснить почему?

$exclude = array(1,2,3);
$include = array(3,4,5);
$args = array(
    'post_type'         => 'post',
    'post_status'       => 'publish',
    'posts_per_page'    => 30,
    'post__in'          => array_diff($include, $exclude),
)
$posts = get_posts($args);
2 авг. 2013 г. 05:40:23
Комментарии

Я знаю, что мог бы использовать array_diff() для переменных $exclude и $include, но реальность сложнее этого вопроса. Это должно быть сделано в запросе.

s_ha_dum s_ha_dum
2 авг. 2013 г. 06:11:43

@s_ha_dum Извините, моя ошибка. Я не могу поставить минус вашему ответу.

gmazzap gmazzap
2 авг. 2013 г. 06:13:02

Я обновил запрос, чтобы учесть все используемые параметры. Возможно, запрос через $wpdb будет лучшим вариантом.

Drew Baker Drew Baker
2 авг. 2013 г. 08:29:26

Я не мог понять, почему мой запрос не работает, пока не прочитал Кодекс о WP_Query. Можно использовать только post__in или post__not_in. Нельзя применять их вместе в одном запросе. Я нашел это решение, и должен сказать, что это гениальный обходной путь.

Michael Ecklund Michael Ecklund
1 нояб. 2017 г. 18:15:43