Исключить или включить идентификаторы категорий в WP_Query

У меня есть программа wordpress, которая имеет более 300 категорий.

Теперь у меня есть требование предоставить некоторую гибкость для выбора категорий. В этом случае я изначально предварительно отмечил все категории, если кто-то должен исключить категорию, которую они могут отменить.

Теперь проблема, с которой я столкнулась, – дать точные результаты по выбору категории.

Мой первый подход просто исключил все категории отмены выбора, как рев,

например: исключить 10,11,12 категории

$args = array( 'category__not_in' => array('10','11','12') ); 

Предположим, у меня есть сообщение, которое было отмечено под category 12 & 13 . Из вышеприведенного кода я не получу эту должность в результате, поскольку она исключает должности в category 12 . Но в идеале это должно быть в результатах, поскольку category 13 не была отменена.

В качестве решения я мог бы использовать опцию 'category__in' со всеми выбранными идентификаторами категорий. Но мое беспокойство в том, что список будет очень длинным, хотя он идет программно, я не уверен в служебных wp_query как у меня более 300 категорий.

У кого-то есть лучшая идея, как решить эту проблему.

Solutions Collecting From Web of "Исключить или включить идентификаторы категорий в WP_Query"

Как вы, вероятно, знаете, это категории таксономии. Когда вы используете такие аргументы, как category__in , он добавит налоговый запрос к вашему WP_Query() . Итак, ваша ситуация будет примерно такой:

 $args = array( 'post_type' => 'post', 'tax_query' => array( 'relation' => 'AND', array( 'taxonomy' => 'category', 'field' => 'term_id', 'terms' => array( 12 ), 'operator' => 'IN', ), array( 'taxonomy' => 'category', 'field' => 'term_id', 'terms' => array( 11, 12, 13 ), 'operator' => 'NOT IN', ), ), ); $query = new WP_Query( $args ); 

Здесь я бы не подумал о проблемах с производительностью. Это скорее всего ваше единственное решение, если вы не хотите напрямую запрашивать сообщения из базы данных с помощью SQL-запроса (это может немного улучшить производительность).

Предположим, что у нас есть 4 должности и 4 категории.

 +----+--------+ | ID | Post | +----+--------+ | 1 | Test 1 | | 2 | Test 2 | | 3 | Test 3 | | 4 | Test 4 | +----+--------+ +----+------------+ | ID | Category | +----+------------+ | 1 | Category 1 | | 2 | Category 2 | | 3 | Category 3 | | 4 | Category 4 | +----+------------+ +--------+------------------------+ | Post | Category | +--------+------------------------+ | Test 1 | Category 1, Category 2 | | Test 2 | Category 2 | | Test 3 | Category 3 | | Test 4 | Category 4 | +--------+------------------------+ 

Если я правильно понял ваш вопрос, вы хотите получить сообщение Test 1 с параметром category__not_in . Аргументы к вашему запросу будут выглядеть так:

 $args = array( 'category__not_in' => array(2, 3, 4) ); 

Проблема с category__not_in заключается в том, что она производит запрос NOT IN SELECT SQL.

 SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND (wp_posts.ID NOT IN ( SELECT object_id FROM wp_term_relationships WHERE term_taxonomy_id IN (2, 3, 4) )) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10 

NOT IN SELECT исключает все сообщения, включая Test 1 . Если только этот SQL будет использовать JOIN вместо NOT IN SELECT это будет работать.

 SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts LEFT JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) WHERE 1=1 AND (wp_term_relationships.term_taxonomy_id NOT IN (2, 3, 4)) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10 

Выше SQL вернет только сообщение Test 1 . Мы можем сделать небольшой трюк для создания такого запроса, используя класс WP_Query. Вместо использования параметра category__not_in замените его параметром category__in и добавьте фильтр post_where который будет напрямую модифицировать SQL для нашей цели.

 function wp_286618_get_posts() { $query = new WP_Query( array( 'post_type' => 'post', 'category__in' => array( 2, 3, 4 ) // Use `category__in` to force JOIN SQL query. ) ); return $query->get_posts(); } function wp_286618_replace_in_operator($where, $object) { $search = 'term_taxonomy_id IN'; // Search IN operator created by `category__in` parameter. $replace = 'term_taxonomy_id NOT IN'; // Replace IN operator to NOT IN $where = str_replace($search, $replace, $where); return $where; } add_filter( 'posts_where', 'wp_286618_replace_in_operator', 10, 2 ); // Add filter to replace IN operator $posts = wp_286618_get_posts(); // Will return only Test 1 post remove_filter( 'posts_where', 'wp_286618_replace_in_operator', 10, 2 ); // Remove filter to not affect other queries 

Преимущество этого решения над другими заключается в том, что мне не нужно знать идентификатор других категорий, и он будет поддерживать чистоту вашего почтового цикла.

Почему вы предварительно тикируете все категории? Разве не легче отобразить все результаты и в то же время иметь все категории без отметки? Затем, когда пользователь выбирает несколько (кто собирается выбрать 300 категорий?), Вы можете запустить запрос с category__in .

Не уверен, но я думаю, вы не можете сделать это, используя поведение / параметры по WP_Query . Поэтому, возможно, будет работать над реализацией функции, которая будет выполнять этот тест для вас после выбора всех сообщений.

Конечно, недостатком этого метода является то, что вы должны сначала выбрать все сообщения, затем отфильтровать их, но это может быть решением проблемы. Итак, вы можете сделать что-то вроде этого:

 <?php function test_categorie($cats,$ex_cats) { $test = false; //we consider that this post is excluded until we found a category that doesn't belong to the array foreach ($cats as $cat){ if(!in_array(intval($cat->term_id),$ex_cats)) { $test = true; //We can exit the loop as this post have at least one category not excluded so we can consider it break; } } return $test; } //Define the excluded categorie here $exclude_cat = array(11,12,13); $args = array( 'posts_per_page' => -1, 'post_type' => 'post', ); $the_query = new WP_Query($args ); if ( $the_query->have_posts() ) : while ( $the_query->have_posts() ) : $the_query->the_post(); //we do our test, if(false) we don't consider the post and we continue to the next if(!test_categorie(get_the_category(),$exclude_cat)) continue; /* Add you code here */ endwhile; wp_reset_postdata(); endif; ?> 

Я думаю, что я буду решать проблемы производительности, если и когда они появятся, но если вы действительно заинтересованы, включите медленный журнал запросов MySQL и используйте microtime для отслеживания того, как долго этот конкретный запрос / гидратация. Чтобы ответить на ваш вопрос, простым решением было бы использовать array_diff . Например:

 $notIn = [10, 11, 12]; $in = [11]; $args = array( 'category__not_in' => array_diff($notIn, $in) ); 

Попробуй это. Я думаю, это немного грязно, но это работает для меня хорошо!

  $skills = get_user_meta($curr_id , 'designer_skills'); $skills = array_map('intval', explode(',' , $skills[0])); $args = array( 'numberposts' => -1, 'post_type' => 'project', 'meta_query' => array( 'relation' => 'AND', array( 'key' => 'status', 'compare' => '=', 'value' => 'open' ), array( 'key' => 'payment_status', 'compare' => '=', 'value' => true ) ) ); $posts = get_posts( $args ); if ($posts) { $count = 0; foreach ($posts as $project) { if (in_array(get_the_terms( $project->ID, 'projects')[0] -> term_id , $skills)){ //implement your own code here } } }