I have two widgets, one shows News while the other shows everything except News (We'll call the second one Blog). The blog portion is currently working correctly.
The News posts are either categorized as In the News
OR have the custom post meta in-the-news
, set to 1. It's important to note that not all posts will have the custom post meta defined.
The main problem I am facing is that I need to compare post meta based on whether the post is categorized one way or another.
I may need to do a custom database query for this behavior, at least for the News. Is it possible to do a custom query and convert it to a standard WP_Query object?
What I have tried
Query for News.
Problem: Only shows posts within category 75 that have in-the-news = 1
.
Desired result: Show all posts from category 75 regardless of the value of in-the-news
, and any additional posts from outside the category which have 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' => '',
),
)
));
Here is the query for the Blog:
This query appears to be working correctly, showing all posts outside of category 75, and hiding posts with 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' => '',
),
)
));
Solution
Thanks to s_ha_dum
for the amazing examples, here is the final query I am using. The logic here is that we do a custom MySQL query for an array of post IDs, then do a standard WP_Query using the returned IDs.
Note: The logic here was a bit more complicated than the original post. Basically, we originally had "News" and "Blog". But now we also have "Risk". Also, the in-the-news
post meta was changed to show-in-blog
as we reverse the functionality. I can't expect anyone else to ever understand the reasoning for this in the first place, as even I think it is ridiculous (But the client wants it, so be it!)
Here is my query, for the "Blog" widget. Slight variations are made for the "News" area. I'm not sure if the query could be cleaned up. I'm also not sure if it's a bad idea to perform so many SELECTs within the same query.
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');
WP_Query
, you could set yourpost__in
parameter viapre_get_posts
filter, a little bit similar to the filter used by s_ha_dum..