WordPress WP QUERY with OR condition - wordpress

On my website, there are a couple of custom post types with default blog posts. On the blog posts, there are many categories.
One of the post types is webinar. I like to query all posts from the post type webinar and those blog posts that have category id 43
I tried following way but does not work.
1:
$query = new WP_Query(array(
'post_type' => array('webinar'), // I need all post from webinar
'cat' => '43', // I need all blog post under this category (Post type post category id 43)
);
Result: No post found
2:
$query = new WP_Query(array(
'post_type' => array('webinar','post'), // I need all post from webinar
'cat' => '43', // I need all blog post under this category (Post type post category id 43)
);
Result: Only posts of category id 43, no post from post types webinar
I need something like the following:
$query = new WP_Query(array(
array(
'relation' => 'OR',
array(
'post_type' => array('webinar')
),
array(
'post_type' => 'post',
'cat' => '43'
)
)
));
How can I do this?

Solution 1
// This could be cached in the site option
// in case this code will take a long time.
$webinar_terms = get_terms([
'taxonomy' => '{webinar_tax_name}',
'hide_empty' => true,
]);
$allowed_terms_ids = [];
foreach ( $webinar_terms as $term )
{
$allowed_terms_ids[] = $term->term_id;
}
// Add post cat to allowed terms.
$allowed_terms_ids[] = 43;
$query = new WP_Query([
'post_type' => ['webinar','post'],
'cat' => $allowed_terms_ids,
]);
NOTE
This will work only in case all webinar posts will be assigned to at least 1 {webinar_tax_name} term.
Solution 2
You may use posts_request hook and update SQL for 1 of your queries in your example. But I would prefer 1st solution as it will be more clear for other devs.

$posts = get_posts([
'post_type' => 'webinar',
'post_status' => 'publish',
'numberposts' => -1
]);

$post_data = get_posts( [
'post_type' => ['webinar', 'post'],
'posts_per_page' => - 1,
'tax_query' => array(
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => '43'
),
] );
Would something like this work? I have not tested this so may need playing with a bit.
If you dont want to use get_posts then can always use new WP_Query but will need to ammend

Related

Merge multiple WP_Query results into an array with no duplicates

I have a custom post type with its own custom template, and I want to display blog posts that are related to the custom post type title. However, I want to display a referenced post first, then search for any posts with tags, and then find relevant posts after that. Any one of these could result in no results or many. The total number of posts I want to display is 6.
`
$searchtag = strtolower(get_the_title());
$arg1 = array(
'post_type' => 'post',
'p' => $post_id,
);
$arg2 = array(
'post_type' => 'post',
'tag' => $searchtag,
'post_status' => 'publish',
'orderby' => 'post_date',
'order' => 'desc',
'posts_per_page' => 6,
);
$arg3 = array(
'post_type' => 'post',
's' => $searchtag,
'post_status' => 'publish',
'orderby' => 'relevance',
'posts_per_page' => 6,
);
// Get the posts
$query1 = new wp_query( $arg1 );
$query2 = new wp_query( $arg2 );
$query3 = new wp_query( $arg3 );
$related_query = new wp_query();
// Merge the unique posts
$related_query->posts = array_merge($query1->posts, $query2->posts, $query3->posts);
$related_query->post_count = $query1->post_count + $query2->post_count + $query3->post_count;
if($related_query->have_posts):
`
I read an article that stated that using post__not_in was taxing on the database and I should not incorporate it.
Do I need to add logic if the query->post_count = 0?
How can I maintain the order but ensure that there are no duplicates displayed?
I get duplicates in these results currently. I'd like to eliminate them while keeping the order of the posts by query1, then query2 then query3... displaying the first 6 posts.
The better way is make 3 queries with parameter:
'fields' => 'ids'
and there:
$postIds1 = get_posts($args1);
when merge got data:
$postIds = array_merge(array(0), $postIds1, $postIds2, $postIds3);
and when make forth request with
'post__in' => $postIds

Wordpress output links to previous and next posts from custom query

I'm using the advanced custom fields plugin for wordpress to create a group of custom post types that have a date set within them.
I'm trying to show the previous post, and the next post, based on the date stored in the custom field. The links need to link to posts that have a date set in the future (so don't show links to posts with dates that have gone by)/
I can get a list of all the posts that are in the future, and out put these using the following code;
<?php
$rightnow = current_time('Ymd');
$args = array(
'post_type' => 'Courses',
'posts_per_page' => '25',
'meta_query' => array(
array(
'key' => 'date_of_the_course_single_day',
'compare' => '>=',
'value' => $rightnow,
)
),
'meta_key' => 'date_of_the_course_single_day',
'orderby' => 'meta_value',
'order' => 'ASC',
'post_status' => 'publish'
);
$posts = get_posts($args);
foreach ( $posts as $post ) {
?>
Output details of post here....
<?php
}
?>
What I thought I could do, is the get the current post's position in the array, to then get details of the posts one before and one after... but I haven't got a clue how to do this.
I've experimented with the wordpress next_post_link and previous_post_link functions, but these seem to work based on when the post was added to wordpress, rather than based on my custom date field.
Am I going about this the complete wrong way? Any tips or pointers would be much appreciated!
Use WP_Query plus paginate_links
$rightnow = current_time('Ymd');
// Query Args
$args = array(
'post_type' => 'Courses',
'posts_per_page' => '25',
'meta_query' => array( array(
'key' => 'date_of_the_course_single_day',
'compare' => '>=',
'value' => $rightnow,
) ),
'meta_key' => 'date_of_the_course_single_day',
'orderby' => 'meta_value',
'order' => 'ASC',
'post_status' => 'publish'
);
$query = new WP_QUery( $arg );
$posts = $query->get_posts();
// Paginate Args
$page_args = array(
'base' => 'your_custom_page_url'.'%_%', // Make sure you got this current depending on your setup
'format' => '/%#%', // requires pretty permalinks
'total' => $query->max_num_pages,
'current' => 0,
'prev_text' => __('«'),
'next_text' => __('»'),
);
foreach ( $posts as $post ) {
// Output
}
echo paginate_links( $page_args );
You have to verify that the base and format of paginate args are correct of it won't properly worked.

WP_Query Woocommerce products that belong in distinct multiple categories only tax_query

I'm using WP_Query for Woocommerce products in attempt to query products in a particular category. This is the syntax that worked for me -
$args = array(
'posts_per_page' => -1,
'product_cat' => 'category-slug-here',
'post_type' => 'product',
'orderby' => 'title',
);
$the_query = new WP_Query( $args );
// The Loop
while ( $the_query->have_posts() ) {
$the_query->the_post();
echo '' . get_the_title() . '<br /><br />';
}
wp_reset_postdata();
This returns data, but I want to pass an ID, not a category slug, to filter and I want to find products that exist in multiple categories only.
The argument product_cat is not native to WP_Query (at least that I can find), so I'm assuming this is something custom to Woocommerce. Through their documentation, I haven't been able to find anything that will allow me to filter by category ID, nor use an AND condition for this filtering.
Using cat, the array of tax_query, and category__and have not yielded any results. Essentially, I would like to query all products that exist in both category ID 102, and 115. If I have to use slugs, I'm sure there is a way around getting that info based on the ID I have, but I'd like to avoid 2 queries to filter by multiple categories.
Does anyone know how to accomplish this?
UPDATE: I have learned that separating category slugs by commas in the product_cat argument will produce an "OR" effect, so it will combine distinct products from both, but this is not what I am looking for. So, for example:
'product_cat' => 'category-slug1, category-slug2'
will return products from both categories in total, but I am still searching for a way to find distinct products that ONLY belong to both, or multiple, categories.
Wow, so after hours of banging my head, this is how I was able to solve this -
$args = array(
'posts_per_page' => -1,
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => 'category-slug1'
),
array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => 'category-slug2'
)
),
'post_type' => 'product',
'orderby' => 'title',
);
$the_query = new WP_Query( $args );
This takes advantage of the tax_query argument, including the relation => 'AND' to make sure the product falls under BOTH categories.
Hope this helps someone in the future.
I was also not able to figure out how to pass an ID, rather than a slug (although I'm sure there's a way), but here's the function to retrieve the slug based on an ID:
$terms = get_term($YOURID, 'product_cat');
$theslug = $terms->slug;
From the WordPress codex on WP_Query for Category Parameters:
equivalent of OR
$args = array( 'product_cat' => 'category-slug1,category-slug2' );
equivalent of AND
$args = array( 'product_cat' => 'category-slug1+category-slug2' );
e.g.
$query = new WP_Query( $args );
To query by category_ID this is what worked for me.
// First obtain term id:
//...
$all_categories = get_categories( $args );
$cat_ids = array();
foreach ($all_categories as $cat)
{
array_push($cat_ids, $cat->term_id);
}
//Now use ids from array:
$args = array(
'posts_per_page' => -1,
'post_type' => 'product',
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'id',
'terms' => $cat_ids
)
)
);
Inside a 'tax_query' array's array you can specify an 'operator' to be performed on the query. You can achieve what you want using the 'AND' operator.
$args = array(
'posts_per_page' => -1,
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => array( 'category-slug1', 'category-slug2' )
'operator => 'AND',
),
),
'post_type' => 'product',
'orderby' => 'title',
);
$the_query = new WP_Query( $args );
All of the products selected by this query will match the provided 'terms'. See this link for more info: https://codex.wordpress.org/Class_Reference/WP_Query#Taxonomy_Parameters
In case the link ever breaks, here's the relevant info:
operator (string) - Operator to test. Possible values are 'IN', 'NOT IN', 'AND', 'EXISTS' and 'NOT EXISTS'. Default value is 'IN'.

Where to enter custom fields meta_key for customized archives?

I have a post_type called books, which has custom fields for author name, publisher name, etc.
I want to create pages where publisher or authors are grouped. For example, "Penguin" or "McGraw Hill". When a user clicks on "Penguin" out of the Publisher dropdown, she should see all the books by Penguin for example.
To do this, I want to try a query like this:
$args = array(
'meta_key' => 'publisher'
,'meta_key_value' => 'Penguin'
,'taxonomy' => 'book'
,'orderby' => 'date'
,'posts_per_page' => 48
,'paged' => get_query_var('page')
);
$my_query = new WP_Query( $args );
My question is: where should I put this query? In the "category.php" or "archive.php"? And what will the link in the header look like?
Thanks!
Neither. You should put this in 'archive-book.php'. You can generate your link using get_post_type_archive_link and your link (without pretty permalinks) will look like '?post_type=book'.
You should also set up your query like so:
$args = array(
'meta_key' => 'publisher',
'meta_key_value' => 'Penguin',
'post_type' => 'book',
'orderby' => 'date',
'posts_per_page' => 48,
'paged' => get_query_var('page')
);
$my_query = new WP_Query( $args );
'book' in your case is not a Taxonomy, but rather a Custom Post Type. Let me know if this helps.

Query posts by custom taxonomy ID

I have a custom post type called portfolio and a custom taxonomy called build-type (acting as categories)
I am trying to query portfolio posts by build-type ID e.g. all Portfolio posts in "Hotels" (id=4 for that taxonomy)
// gets the ID from a custom field to show posts on a specific page
$buildType = get_post_meta($post->ID, 'build_type_id', true);
// run query
query_posts(array(
'post_type' => 'portfolio',
'showposts' => -1,
'tax_query' => array(
'taxonomy' => 'build-type',
'terms' => $buildType,
'field' => 'term_id'
),
'orderby' => 'title',
'order' => 'ASC'
));
Currently it's calling all portfolio posts and not just those with the build-type ID
For 'field' => 'term_id' should I be using term_id, tag_ID, id or something else?
Anyone know how to get this working?
Thanks in advance!
I solved it with help from: https://wordpress.stackexchange.com/questions/30476/query-posts-by-custom-taxonomy-id
tax-query needs to be an array of arrays
The final solution is:
// gets the ID from a custom field to show posts on a specific page
$buildType = get_post_meta($post->ID, 'build_type_id', true);
// run query
query_posts(array(
'post_type' => 'portfolio',
'showposts' => -1,
'tax_query' => array(
array(
'taxonomy' => 'build-type',
'terms' => $buildType,
'field' => 'term_id',
)
),
'orderby' => 'title',
'order' => 'ASC' )
);
On github here:
https://gist.github.com/1275191
I'm not a WP-gury and I have invested hours and hours trying to solve the same problem. Eventually I found this blog post: http://richardsweeney.com/blog/wordpress-3-0-custom-queries-post-types-and-taxonomies/
The answer is somewhat semi-bad: apparently you can't filter like this for custom post types (it is only possible for posts), which is a shame!
What I did work was this:
$args['custom_tax'] = 'custom_tax_slug';
query_posts($args);
Hope it helps!
//Mike

Resources