WordPress Query: ORDER BY CASE WHEN - php

I want to first display the posts that match a particular meta_key => cr_id and order those by another 'meta_key' => 'cr_list_price' and then display the rests of the posts that are also ordered by 'meta_key' => 'cr_list_price'.
This is my current code which does everything I want except show the posts where cr_id = 4.
$args = array(
'post_type' => 'properties',
'paged' => get_query_var( 'paged' ),
'meta_query' => array(
array(
'key' => 'cr_list_price',
'value' => array($minPrice, $maxPrice),
'type' => 'numeric',
'compare' => 'BETWEEN'
),
array(
'key' => 'cr_prop_bed',
'value' => $beds,
'compare' => '>='
),
),
'orderby' => 'meta_value_num',
'meta_key' => 'cr_list_price'
);
$loop = new WP_Query( $args );
If I was using raw MySQL I'd do something like ORDER BY CASE WHEN in my query, however I'm not sure how or if I can accomplish this with WordPress.

I wonder if you could add a filter to the query by adding that little extension on there. I'm thinking maybe posts_orderby
Function
function filter_case($orderby = '') {
$orderby .= 'CASE WHEN [some conditions]';
return $orderby;
}
Before Query
add_filter( 'posts_orderby', 'filter_case' );
$wp_query = new WP_Query($args);
remove_filter( 'posts_orderby', 'filter_case' );
I cant gaurantee this will work first time but it could be worked on if you think it's worth pursuing? List of WP_Query filters are here.

Related

How to optimize slowly custom WP Query for Product Bundles?

I am trying to troubleshoot my WP Query for the second day and I am getting tired and need help. I managed to make it work, but very slow (needs 5s to load instead of about 0.5s).
My problem: I need to move the unavailable products to the end of WP Query, and sort the rest by sorting in the "menu_order" panel.
I'm using the Product Bundles plugin, which doesn't use "_stock_status" but has its own meta_key "_wc_pb_bundled_items_stock_status", which for 1/4 of the sets is populated with "instock" and "outofstock" values. I have no idea why this is not the case with 100% of the products. When a product becomes unavailable, it has "_stock_status" = instock, but an additional "_wc_pb_bundled_items_stock_status" = outofstock appears.
I guess if this worked 100% smoothly, I could just sort the "_wc_pb_bundled_items_stock_status" meta_key ascendingly and additionally use "menu_order" sorting.
My code:
<?php
$paged = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
$args = array(
'post_type' => 'product',
'posts_per_page' => 18,
'paged' => $paged,
'product_cat' => 'zestawy',
'meta_query' => array(
'relation' => 'OR',
'instock_default_order' => array(
'relation' => 'OR',
array(
'key' => '_wc_pb_bundled_items_stock_status',
'value' => 'instock',
'compare' => '=',
),
array(
'key' => '_stock_status',
'value' => 'instock',
'compare' => '=',
),
),
'outofstock_order' => array(
array(
'key' => '_wc_pb_bundled_items_stock_status',
'value' => 'outofstock',
'compare' => '=',
),
)
),
'orderby' => array(
'_wc_pb_bundled_items_stock_status' => 'DESC',
'menu_order' => 'ASC',
),
);
$wp_query = new WP_Query( $args );
?>
I started reading about how to optimize this code and used the "pre_get_posts" function. This reduced the page load time from 5s to 4s, but the effect is still poor. After many attempts and changes I managed to write this code:
function instock_bundle_query($query){
if ( is_product_category('zestawy') && $query->is_main_query() ) {
$query->set('meta_query', array(
'instock_default_order' => array(
'relation' => 'OR',
array (
'key' => '_wc_pb_bundled_items_stock_status',
'compare' => 'NOT EXISTS',
),
array (
'key' => '_wc_pb_bundled_items_stock_status',
'compare' => 'EXISTS',
),
)
));
$query->set('orderby',array(
'meta_value' => 'ASC',
'menu_order' => 'ASC'
));
}};
add_action( 'pre_get_posts', 'instock_bundle_query' );
Which works much faster, but does not work properly. Unavailable products are at the end of the list, but bundles that do not have meta_key "_wc_pb_bundled_items_stock_status" are displayed first, followed by those that have the meta_key "instock". Is there any way to improve this?

Display Wordpress post list, sorted by an ACF field using a shortcode

I need to display a list of posts, ordered by an ACF date picker field (end_date). This is essentially an ‘ending soon’ list. I’m using the Divi theme and so would like to have this as a shortcode I can use to place the list anywhere within the builder.
My PHP is pretty basic so any help would be greatly appreciated.The below did not work, probably I’m sure for very obvious reasons that are above my ability.
function sort_query_order( $query ) {
$currentdate = date("Y-m-d",mktime(0,0,0,date("m"),date("d"),date("Y")));
$wp_query = new WP_Query( array (
'post_type' => 'post',
'meta_query'=> array(
array(
'key' => 'end_date',
'compare' => '>',
'value' => $currentdate,
'type' => 'DATE',
)),
'meta_key' => 'end_date',
'orderby' => 'meta_value',
'order' => 'ASC',
'posts_per_page' => 12,
'paged' => $paged,
)
);
}
add_shortcode( 'ending_posts', 'sort_query_order' );

Wordpress ordered by two custom fields meta_key's

I have a Woocomerce query working with one meta_key ( 'countdown_date' or 'hour' ).
It sorts the products by a custom 'meta_key' => 'countdown_date' or 'hour' and orders them using 'orderby' => 'meta_value_num'.
I need to join two meta_key's together. ('hour' key only returns the first two ints of a 24hr time).
Result required, products ordered by two custom fields countdown_date and hour
$args = array(
'posts_per_page' => 20,
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => 'live-events'
)),
'post_type' => 'product',
'meta_key' => 'countdown_date',
// need to add second meta key here 'meta_key' => 'hour',
'orderby' => 'meta_value_num',
'order' => 'ASC'
);
$the_query = new WP_Query( $args );
I've looked at loads of similar questions with no results.
Two loops seems overkill and adding the meta_query is not working for me.
Any help would be great. :)
Full working code in the answer below from #Rene_Korss
Could i get a hand add this to functions.php so that the archive will sort the same way as the custom loop.
Below is a simplified version of the function i've got working. I need to add the two meta_key's here too.
add_filter('woocommerce_get_catalog_ordering_args','wdm_change_ordering',10,1);
function wdm_change_ordering($args) {
if(is_product_category()) {
$args['meta_key'] = 'countdown_date';
// need to add second meta key here $args['meta_key'] = 'hour',
$args['orderby'] = 'meta_value';
$args['order'] = 'ASC';
}
return $args;
}
Add both meta keys to meta_query and set orderby to meta_value. Then you can replace it with posts_orderby hook.
<?php
// Override orderby if orderby value = 'meta_value'
function orderby_countdown_date_and_hour( $orderby ){
return str_replace( 'meta_value', 'meta_value, mt1.meta_value', $orderby );
}
$args = array(
'post_type' => 'product',
'posts_per_page' => 20,
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => 'live-events'
)
),
'meta_query' => array(
array(
'key' => 'countdown_date',
'value' => '',
'compare' => '!='
),
array(
'key' => 'hour',
'value' => '',
'compare' => '!='
)
),
'orderby' => 'meta_value',
'order' => 'ASC'
);
// Replace orderby
add_filter( 'posts_orderby', 'orderby_countdown_date_and_hour' );
// Query
$the_query = new WP_Query( $args );
// Remove our orderby
remove_filter( 'posts_orderby', 'orderby_countdown_date_and_hour' );
This results in
ORDER BY dbprefix_postmeta.meta_value, mt1.meta_value ASC
which means
ORDER BY countdown_date, hour ASC

Ordering Wordpress posts by multiple meta values

Using get_posts(), I need to first retrieve posts that fall on a certain day (the day is set by a custom field - just the date, not time). I do this by using a meta key/value. Then, I need to order these posts based on the time of day (which is a separate custom field, just time, not date). So essentially I need to pull in all the events that fall on a given day, and order them according to the time.
First I grab the day, using a custom field:
if ( get_field('festival_day') ) {
$day_stamp = get_field('festival_day');
}
Then I set my arguments for the query:
$args = array(
'posts_per_page' => -1,
'post_type' => 'event',
'meta_key' => 'event_date',
'meta_value' => $day_stamp
);
$events = get_posts( $args );
So.. the question is, how do I query the other custom field (which is the start time), and then sort by that time? The time field key is event_start_time.
Thanks!
You can user WP_Query to retrieve your events and you can query it something like below:
$args = array(
'post_type' => 'event',
'order' => 'DESC',
'orderby' => 'meta_value',
'meta_key' => 'event_start_time',
'meta_query' => array(
array(
'key' => 'event_start_time',
'value' => 'yourValue_here',
'compare' => '>='
),
array(
'key' => 'event_date',
'value' => $day_stamp,
'compare' => '='
)
)
);
$query = new WP_Query( $args );
UNTESTED but it should work.
Check this code, it should work to sort your post according to time from resulting post of day.
$args = array(
'post_type' => 'post',
'posts_per_page' => -1,
'meta_key' => 'event_start_time',
'orderby' => 'meta_value_num',
'order' => 'ASC',
'meta_query'=> array(
array(
'key' => 'event_date',
'value' => $day_stamp,
'compare' => 'IN'
)
)
);
$the_query = new WP_Query( $args );
if ( $the_query->have_posts() ) {
echo '<ul>';
while ( $the_query->have_posts() ) {
$the_query->the_post();
echo '<li>'. get_the_title().'</li>';
}
echo '</ul>';
} else {
// no posts found
}

Wordpress query by multiple metaboxes and order by date

So here is my query:
$args = array(
'post_type' => 'Event',
'posts_per_page' => 1000,
'meta_key' => 'event_informations_show_on_the_homepage',
'meta_value' => 'Show on the homepage',
'meta_compare' => '==',
'meta_key' => 'event_informations_date',
'orderby' => 'meta_value_num',
'order' => 'ASC'
);
$loop = new WP_Query( $args );
I want to select all posts that have the metabox event_informations_show_on_the_homepage and the value of the metabox event_informations_show_on_the_homepage and order by the date metabox which is stored as a timestamp and is called event_informations_date.
What am I doing wrong?
Hopefully I'm not barking up the wrong tree here.
You can use the key 'meta_query' to filter posts by multiple meta keys like so:
$args = array(
'post_type' => 'Event',
'posts_per_page' => 1000,
'orderby' => 'meta_value_num',
'order' => 'ASC',
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'event_informations_show_on_the_homepage',
'value' => 'yes',
),
array(
'key' => 'event_informations_date',
'value' => 'yes',
)
)
);
$query = new WP_Query( $args );
What WordPress is doing here is creating multiple wheres against the same column by using innerjoins on the same table, each time using a different alias. It's pretty cool & is probably the fastest way to query like that.
For more information see here: http://codex.wordpress.org/Class_Reference/WP_Query#Custom_Field_Parameters
Hope this helps :)

Categories