WordPress standard query sucks with multiple meta queries when orderby is set to meta key.
After a lot of headaches and time lost I wrote a custom class that allow me to better handle that sort of things. Here there is a simplified version of my class, but it hould work for your purposes:
class EventQuery {
private $args;
private $order;
private $query;
static function query( Array $args, \WP_Query $query = NULL ) {
if ( is_null( $query ) ) {
$query = new \WP_Query;
}
$class = __CLASS__;
$eventquery = new $class( $args, $query );
return $eventquery->enable()->run()->disable()->getQuery();
}
function __construct( Array $args, \WP_Query $query ) {
$this->args = $args;
$this->order = isset( $args['order'] ) && strtoupper( $args['order'] === 'DESC' )
? 'DESC'
: 'ASC';
$this->query = $query;
}
function enable() {
add_filter( 'posts_fields_request', array( $this, 'filterFiels' ) );
add_filter( 'posts_join_request', array( $this, 'filterJoin' ) );
add_filter( 'posts_where_request', array( $this, 'filterWhere' ) );
add_filter( 'posts_orderby_request', array( $this, 'filterOrder' ) );
return $this;
}
function disable() {
remove_filter( 'posts_fields_request', array( $this, 'filterFiels' ) );
remove_filter( 'posts_join_request', array( $this, 'filterJoin' ) );
remove_filter( 'posts_where_request', array( $this, 'filterWhere' ) );
remove_filter( 'posts_orderby_request', array( $this, 'filterOrder' ) );
return $this;
}
function filterFiels( $sql ) {
return $sql . ", metastartdate.meta_value as start_date";
}
function filterJoin( $sql ) {
global $wpdb;
return $sql . " INNER JOIN {$wpdb->postmeta}
AS metastartdate ON ({$wpdb->posts}.ID = metastartdate.post_id)";
}
function filterWhere( $sql ) {
return $sql . " AND metastartdate.meta_key = 'event_start_date'";
}
function filterOrder( $sql ) {
return "start_date {$this->order}";
}
function run() {
$this->query->query( $this->args );
return $this;
}
function getQuery() {
return $this->query;
}
}
It can be used like so:
$args = array (
'post_type' => 'post',
'posts_per_page' => 10,
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'event_start_date',
'value' => array( $date_1, $date_2 ),
'type' => 'numeric',
'compare' => 'BETWEEN'
),
array(
'key' => 'event_end_date',
'value' => array( $date_1, $date_2 ),
'type' => 'numeric',
'compare' => 'BETWEEN'
),
),
'orderby' => 'custom', // <-- NOTE THIS
'order' => 'ASC' // <-- AND THIS
);
$query = EventQuery::query( $args ); // return a WP_Query
if ( $query->have_posts( ) ) {
// loop here
}
Of course you can use ‘DESC’ to order by desc start date.