Step 1: Add the code (correct place)
Paste this inside your theme’s functions.php or a custom plugin:
Step 2: Set Query ID in Elementor
Go to your Loop Grid / Posts widget:
- Open Query settings
-
Set Query ID = event_upcoming
👉 Without this, your code will NOT run.
Step 3: Make sure ACF field is correct
- Field name:
start_date - Format:
Y-m-d(VERY important)
If your format is like d/m/Y → sorting will break.
Step 4: Clear cache
After adding code:
- Clear site cache
- Clear Elementor cache
(Elementor → Tools → Regenerate CSS & Data)
/**
* Order Elementor query by upcoming events first, then past events.
* Upcoming events sorted ascending (soonest first).
* Past events sorted descending (most recent first).
*
* Usage: Add query ID "event_upcoming" to your Elementor Posts widget.
*/
add_action( 'elementor/query/event_upcoming', function( $query ) {
global $wpdb;
$today = current_time( 'Y-m-d' ); // Use WordPress time, not PHP date()
$callback = null;
$callback = function( $clauses, $wp_query ) use ( $today, $wpdb, $query, &$callback ) {
// Only apply to this specific query
if ( $wp_query !== $query ) {
return $clauses;
}
// Remove filter immediately after it runs — don't affect other queries
remove_filter( 'posts_clauses', $callback, 10 );
// Add JOIN only if not already joined
if ( strpos( $clauses['join'], 'meta_key_start_date' ) === false ) {
$clauses['join'] .= $wpdb->prepare(
" LEFT JOIN {$wpdb->postmeta} AS meta_key_start_date
ON {$wpdb->posts}.ID = meta_key_start_date.post_id
AND meta_key_start_date.meta_key = %s ",
'start_date'
);
}
$clauses['orderby'] = $wpdb->prepare(
"CASE WHEN meta_key_start_date.meta_value >= %s THEN 0 ELSE 1 END,
CASE WHEN meta_key_start_date.meta_value >= %s
THEN meta_key_start_date.meta_value END ASC,
CASE WHEN meta_key_start_date.meta_value < %s
THEN meta_key_start_date.meta_value END DESC",
$today,
$today,
$today
);
return $clauses;
};
add_filter( 'posts_clauses', $callback, 10, 2 );
} );