Пользовательский запрос с исключением категории и "белым списком" после меты
У меня есть два виджета, один показывает Новости , а другой показывает все, кроме новостей (мы назовем второй Блог ). Часть блога в настоящее время работает правильно.
Новостные сообщения либо классифицируются как In the News
, ЛИБО имеют пользовательскую мету публикации in-the-news
, равную 1. Важно отметить, что не для всех сообщений будет определена пользовательская мета-запись.
Основная проблема, с которой я сталкиваюсь, заключается в том, что мне нужно сравнить мета-пост на основе относится ли сообщение к той или иной категории.
Возможно, мне потребуется выполнить пользовательский запрос базы данных для такого поведения, по крайней мере, для новостей. Возможно ли выполнить пользовательский запрос и преобразовать его в стандартный объект WP_Query?
Что я пробовал
Запрос на Новости.
Проблема: показывает только сообщения в категории 75, которые имеют in-the-news = 1
.
Желаемый результат: Показать все сообщения из категории 75 независимо от значение in-the-news
и любые дополнительные сообщения из-за пределов категории, которые имеют in-the-news = 1
query_posts(array(
'ignore_sticky_posts' => true,
'posts_per_page' => 3,
'cat' => "75", // Only posts within category 75 (News)
// Including posts tagged to show "In the News"
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'in-the-news',
'value' => '1',
'compare' => '=',
),
array(
'key' => 'in-the-news',
'compare' => 'NOT EXISTS',
'value' => '',
),
)
));
Вот запрос для блога :
Этот запрос, похоже, работает правильно, показывает все записи за пределами категории 75 и скрывает записи с in-the-news = 1
.
query_posts(array(
'ignore_sticky_posts' => true,
'posts_per_page' => 3,
'cat' => "-75", // All posts EXCLUDING those in category 75 (News)
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'in-the-news',
'value' => '0',
'compare' => '=',
),
array(
'key' => 'in-the-news',
'compare' => 'NOT EXISTS',
'value' => '',
),
)
));
Решение
Спасибо s_ha_dum
за удивительные примеры, вот последний запрос, который я использую. Логика здесь заключается в том, что мы выполняем пользовательский запрос MySQL для массива идентификаторов сообщений, а затем выполняем стандартный WP_Query с использованием возвращенных идентификаторов.
Примечание: Логика здесь была немного сложнее, чем в исходном сообщении. В принципе, у нас изначально были "Новости" и "Блог". Но теперь у нас тоже есть "Риск". Кроме того, мета-запись in-the-news
была изменена на show-in-blog
, поскольку мы изменили функциональность. Я не могу ожидать, что кто-то еще когда-либо поймет причины этого в первую очередь, так как даже я думаю, что это смешно (Но клиент этого хочет, так тому и быть!)
Вот мой запрос, для Виджет "Блог". Небольшие изменения сделаны для области "Новости". Я не уверен, можно ли очистить запрос. Я также не уверен, что это плохая идея - выполнять так много выборок в одном запросе.
global $wpdb;
$query = // Splitting the SQL query to it's own code block for syntax highlighting!
SELECT `ID`
FROM {$wpdb->posts} posts
WHERE (
/* Exclude posts in News (94)
Ignore show-in-blog option for News here,
as News is displayed on the same page */
94 NOT IN (
SELECT `term_taxonomy_id`
FROM {$wpdb->term_relationships}
WHERE `object_id` = posts.`ID`
)
AND
/* Exclude posts in Risk (96),
But show Risk posts that have the postmeta "show-in-blog" */
(
96 NOT IN (
SELECT `term_taxonomy_id`
FROM {$wpdb->term_relationships}
WHERE `object_id` = posts.`ID`
)
OR
(
96 IN (
SELECT `term_taxonomy_id`
FROM {$wpdb->term_relationships}
WHERE `object_id` = posts.`ID`
)
AND
1 IN (
SELECT `meta_value`
FROM {$wpdb->postmeta}
WHERE
`meta_key` = 'show-in-blog'
AND `post_id` = posts.`ID`
)
) /* OR */
) /* AND */
) /* WHERE */
ORDER BY `post_date` DESC;
$args = array(
// Only include IDs returned by the above query
'post__in' => $wpdb->get_col( $query ),
'posts_per_page' => 10,
);
$wp_query = new WP_Query( $args );
get_template_part('loop', 'frontpage');
1 answers
Можно ли выполнить пользовательский запрос и преобразовать его в стандартный Объект WP_Query?
Да. Вы можете сделать что-то вроде...
$post_ids = $wpdb->get_col("SELECT ID FROM {$wpdb->posts} WHERE ....");
$posts_qry = new WP_Query(array('post__in'=> $posts_ids,'orderby' => 'post__in'));
Второй запрос сохранит порядок результатов по сравнению с первым.
Я совершенно уверен, что вы не можете выполнить этот первый запрос с помощью WP_Query
или любой другой функции. Логика слишком сложна. Вам понадобится предложение JOIN
или WHERE
, которое WP_Query
не поддерживает. К сожалению, написание этого SQL
будет тоже сложно, просто чтобы получить категорию.
Полностью рукописный запрос, конечно, ваш первый вариант. Лучшее, что я могу сделать без рукописного ввода SQL
, это:
$post_ids = new WP_Query(array(
'fields' => 'ids',
'ignore_sticky_posts' => true,
'posts_per_page' => 3,
'cat' => "75", // Only posts within category 75 (News)
));
$post_ids_2 = new WP_Query(array(
'fields' => 'ids',
'ignore_sticky_posts' => true,
'posts_per_page' => 3,
'post__not_in' => $post_ids->posts,
'meta_query' => array(
array(
'key' => '_edit_lock',
'value' => '0',
'compare' => '=',
),
)
));
$post_ids = $post_ids->posts + $post_ids_2->posts;
$posts_qry = new WP_Query(array('post__in'=> $posts_ids,'orderby' => 'post__in'));
Это 3 запроса (ой), и заказ может быть проблемой, если вы беспокоитесь об этом.
Другой вариант - изменить запрос с помощью нескольких фильтров. Аргументы WP_Query
будут касаться части in-the-news = 1
.
$post_ids_v3 = new WP_Query(array(
'ignore_sticky_posts' => true,
'posts_per_page' => 20,
'my_variable' => true,
// Including posts tagged to show "In the News"
'meta_query' => array(
array(
'key' => 'in-the-news',
'value' => '1',
'compare' => '=',
)
)
));
Обратите внимание, что вы опускаете свою категорию компонент и передача дополнительного неофициального параметра с именем my_variable
. Я не знаю, является ли передача дополнительных переменных, подобных этой, преднамеренной, поэтому имейте в виду, что это может быть неофициальным поведением. Вы собираетесь использовать это для добавления компонента категории в запрос с двумя фильтрами.
function posts_join_wpse_98652($join,$qry) {
global $wpdb;
if (true === $qry->get('my_variable')) {
$join .= " JOIN {$wpdb->term_relationships} ON ({$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id)";
}
return $join;
}
add_filter('posts_join','posts_join_wpse_98652',1,2);
function posts_where_wpse_98652($where,$qry) {
global $wpdb;
if (true === $qry->get('my_variable')) {
$where .= " OR {$wpdb->term_relationships}.term_taxonomy_id IN (75)";
}
return $where;
}
add_filter('posts_where','posts_where_wpse_98652',1,2);
Это даже близко не проверено, но, похоже, работает, когда я пытаюсь. Тем не менее, такие вещи бывает трудно исправить, возможно, я совершил ошибку. Едва проверенный. Возможно, глючит. Предостережение опустошитель. Никаких возвратов.