✨feature: Allow sorting by event date via API
This commit is contained in:
+239
-116
@@ -6,47 +6,48 @@
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom post type for events.
|
||||
*/
|
||||
function events_register_post_type() {
|
||||
$labels = array(
|
||||
'name' => _x( 'Events', 'post type general name', 'aa-events' ),
|
||||
'singular_name' => _x( 'Event', 'post type singular name', 'aa-events' ),
|
||||
'menu_name' => _x( 'Events', 'admin menu', 'aa-events' ),
|
||||
'name_admin_bar' => _x( 'Event', 'add new on admin bar', 'aa-events' ),
|
||||
'add_new' => _x( 'Add New', 'event', 'aa-events' ),
|
||||
'add_new_item' => __( 'Add New Event', 'aa-events' ),
|
||||
'new_item' => __( 'New Event', 'aa-events' ),
|
||||
'edit_item' => __( 'Edit Event', 'aa-events' ),
|
||||
'view_item' => __( 'View Event', 'aa-events' ),
|
||||
'all_items' => __( 'All Events', 'aa-events' ),
|
||||
'search_items' => __( 'Search Events', 'aa-events' ),
|
||||
'parent_item_colon' => __( 'Parent Events:', 'aa-events' ),
|
||||
'not_found' => __( 'No events found.', 'aa-events' ),
|
||||
'not_found_in_trash' => __( 'No events found in Trash.', 'aa-events' ),
|
||||
);
|
||||
$labels = array(
|
||||
'name' => _x( 'Events', 'post type general name', 'aa-events' ),
|
||||
'singular_name' => _x( 'Event', 'post type singular name', 'aa-events' ),
|
||||
'menu_name' => _x( 'Events', 'admin menu', 'aa-events' ),
|
||||
'name_admin_bar' => _x( 'Event', 'add new on admin bar', 'aa-events' ),
|
||||
'add_new' => _x( 'Add New', 'event', 'aa-events' ),
|
||||
'add_new_item' => __( 'Add New Event', 'aa-events' ),
|
||||
'new_item' => __( 'New Event', 'aa-events' ),
|
||||
'edit_item' => __( 'Edit Event', 'aa-events' ),
|
||||
'view_item' => __( 'View Event', 'aa-events' ),
|
||||
'all_items' => __( 'All Events', 'aa-events' ),
|
||||
'search_items' => __( 'Search Events', 'aa-events' ),
|
||||
'parent_item_colon' => __( 'Parent Events:', 'aa-events' ),
|
||||
'not_found' => __( 'No events found.', 'aa-events' ),
|
||||
'not_found_in_trash' => __( 'No events found in Trash.', 'aa-events' ),
|
||||
);
|
||||
|
||||
$args = array(
|
||||
'labels' => $labels,
|
||||
'public' => true,
|
||||
'publicly_queryable' => true,
|
||||
'show_ui' => true,
|
||||
'show_in_menu' => true,
|
||||
'query_var' => true,
|
||||
'rewrite' => array( 'slug' => 'events' ),
|
||||
'capability_type' => 'post',
|
||||
'has_archive' => true,
|
||||
'hierarchical' => false,
|
||||
'menu_position' => 5,
|
||||
'supports' => array( 'title', 'editor', 'author', 'thumbnail' ),
|
||||
'menu_icon' => 'dashicons-calendar-alt',
|
||||
);
|
||||
$args = array(
|
||||
'labels' => $labels,
|
||||
'public' => true,
|
||||
'publicly_queryable' => true,
|
||||
'show_ui' => true,
|
||||
'show_in_menu' => true,
|
||||
'show_in_rest' => true,
|
||||
'query_var' => true,
|
||||
'rewrite' => array( 'slug' => 'events' ),
|
||||
'capability_type' => 'post',
|
||||
'has_archive' => true,
|
||||
'hierarchical' => false,
|
||||
'menu_position' => 5,
|
||||
'supports' => array( 'title', 'editor', 'author', 'thumbnail' ),
|
||||
'menu_icon' => 'dashicons-calendar-alt',
|
||||
);
|
||||
|
||||
register_post_type( 'event', $args );
|
||||
register_post_type( 'event', $args );
|
||||
}
|
||||
add_action( 'init', 'events_register_post_type' );
|
||||
|
||||
@@ -54,30 +55,30 @@ add_action( 'init', 'events_register_post_type' );
|
||||
* Register a custom taxonomy for event types.
|
||||
*/
|
||||
function events_register_event_type_taxonomy() {
|
||||
$labels = array(
|
||||
'name' => 'Event Types',
|
||||
'singular_name' => 'Event Type',
|
||||
'search_items' => 'Search Event Types',
|
||||
'all_items' => 'All Event Types',
|
||||
'parent_item' => 'Parent Event Type',
|
||||
'parent_item_colon' => 'Parent Event Type:',
|
||||
'edit_item' => 'Edit Event Type',
|
||||
'update_item' => 'Update Event Type',
|
||||
'add_new_item' => 'Add New Event Type',
|
||||
'new_item_name' => 'New Event Type Name',
|
||||
'menu_name' => 'Event Types',
|
||||
);
|
||||
$labels = array(
|
||||
'name' => 'Event Types',
|
||||
'singular_name' => 'Event Type',
|
||||
'search_items' => 'Search Event Types',
|
||||
'all_items' => 'All Event Types',
|
||||
'parent_item' => 'Parent Event Type',
|
||||
'parent_item_colon' => 'Parent Event Type:',
|
||||
'edit_item' => 'Edit Event Type',
|
||||
'update_item' => 'Update Event Type',
|
||||
'add_new_item' => 'Add New Event Type',
|
||||
'new_item_name' => 'New Event Type Name',
|
||||
'menu_name' => 'Event Types',
|
||||
);
|
||||
|
||||
$args = array(
|
||||
'hierarchical' => true,
|
||||
'labels' => $labels,
|
||||
'show_ui' => true,
|
||||
'show_admin_column' => true,
|
||||
'query_var' => true,
|
||||
'rewrite' => array( 'slug' => 'event-type' ),
|
||||
);
|
||||
$args = array(
|
||||
'hierarchical' => true,
|
||||
'labels' => $labels,
|
||||
'show_ui' => true,
|
||||
'show_admin_column' => true,
|
||||
'query_var' => true,
|
||||
'rewrite' => array( 'slug' => 'event-type' ),
|
||||
);
|
||||
|
||||
register_taxonomy( 'event_type', array( 'event' ), $args );
|
||||
register_taxonomy( 'event_type', array( 'event' ), $args );
|
||||
}
|
||||
add_action( 'init', 'events_register_event_type_taxonomy' );
|
||||
|
||||
@@ -85,34 +86,34 @@ add_action( 'init', 'events_register_event_type_taxonomy' );
|
||||
* Register a custom taxonomy for event tags.
|
||||
*/
|
||||
function events_register_event_tag_taxonomy() {
|
||||
$labels = array(
|
||||
'name' => _x( 'Event Tags', 'taxonomy general name', 'aa-events' ),
|
||||
'singular_name' => _x( 'Event Tag', 'taxonomy singular name', 'aa-events' ),
|
||||
'search_items' => __( 'Search Event Tags', 'aa-events' ),
|
||||
'all_items' => __( 'All Event Tags', 'aa-events' ),
|
||||
'parent_item' => null,
|
||||
'parent_item_colon' => null,
|
||||
'edit_item' => __( 'Edit Event Tag', 'aa-events' ),
|
||||
'update_item' => __( 'Update Event Tag', 'aa-events' ),
|
||||
'add_new_item' => __( 'Add New Event Tag', 'aa-events' ),
|
||||
'new_item_name' => __( 'New Event Tag Name', 'aa-events' ),
|
||||
'separate_items_with_commas' => __( 'Separate event tags with commas', 'aa-events' ),
|
||||
'add_or_remove_items' => __( 'Add or remove event tags', 'aa-events' ),
|
||||
'choose_from_most_used' => __( 'Choose from the most used event tags', 'aa-events' ),
|
||||
'not_found' => __( 'No event tags found.', 'aa-events' ),
|
||||
'menu_name' => __( 'Event Tags', 'aa-events' ),
|
||||
);
|
||||
$labels = array(
|
||||
'name' => _x( 'Event Tags', 'taxonomy general name', 'aa-events' ),
|
||||
'singular_name' => _x( 'Event Tag', 'taxonomy singular name', 'aa-events' ),
|
||||
'search_items' => __( 'Search Event Tags', 'aa-events' ),
|
||||
'all_items' => __( 'All Event Tags', 'aa-events' ),
|
||||
'parent_item' => null,
|
||||
'parent_item_colon' => null,
|
||||
'edit_item' => __( 'Edit Event Tag', 'aa-events' ),
|
||||
'update_item' => __( 'Update Event Tag', 'aa-events' ),
|
||||
'add_new_item' => __( 'Add New Event Tag', 'aa-events' ),
|
||||
'new_item_name' => __( 'New Event Tag Name', 'aa-events' ),
|
||||
'separate_items_with_commas' => __( 'Separate event tags with commas', 'aa-events' ),
|
||||
'add_or_remove_items' => __( 'Add or remove event tags', 'aa-events' ),
|
||||
'choose_from_most_used' => __( 'Choose from the most used event tags', 'aa-events' ),
|
||||
'not_found' => __( 'No event tags found.', 'aa-events' ),
|
||||
'menu_name' => __( 'Event Tags', 'aa-events' ),
|
||||
);
|
||||
|
||||
$args = array(
|
||||
'hierarchical' => false,
|
||||
'labels' => $labels,
|
||||
'show_ui' => true,
|
||||
'show_admin_column' => true,
|
||||
'query_var' => true,
|
||||
'rewrite' => array( 'slug' => 'event-tag' ),
|
||||
);
|
||||
$args = array(
|
||||
'hierarchical' => false,
|
||||
'labels' => $labels,
|
||||
'show_ui' => true,
|
||||
'show_admin_column' => true,
|
||||
'query_var' => true,
|
||||
'rewrite' => array( 'slug' => 'event-tag' ),
|
||||
);
|
||||
|
||||
register_taxonomy( 'event_tag', array( 'event' ), $args );
|
||||
register_taxonomy( 'event_tag', array( 'event' ), $args );
|
||||
}
|
||||
add_action( 'init', 'events_register_event_tag_taxonomy' );
|
||||
|
||||
@@ -123,14 +124,17 @@ add_action( 'init', 'events_register_event_tag_taxonomy' );
|
||||
* @return array The modified columns.
|
||||
*/
|
||||
function events_add_admin_columns( $columns ) {
|
||||
$new_columns = array();
|
||||
foreach ( $columns as $key => $value ) {
|
||||
$new_columns[ $key ] = $value;
|
||||
if ( 'title' === $key ) {
|
||||
$new_columns['event_datetime'] = __( 'Event Date & Time', 'aa-events' );
|
||||
}
|
||||
}
|
||||
return $new_columns;
|
||||
$new_columns = array();
|
||||
|
||||
foreach ( $columns as $key => $value ) {
|
||||
$new_columns[ $key ] = $value;
|
||||
|
||||
if ( 'title' === $key ) {
|
||||
$new_columns['event_datetime'] = __( 'Event Date & Time', 'aa-events' );
|
||||
}
|
||||
}
|
||||
|
||||
return $new_columns;
|
||||
}
|
||||
add_filter( 'manage_edit-event_columns', 'events_add_admin_columns' );
|
||||
|
||||
@@ -141,12 +145,13 @@ add_filter( 'manage_edit-event_columns', 'events_add_admin_columns' );
|
||||
* @param int $post_id The ID of the post.
|
||||
*/
|
||||
function events_display_admin_column_content( $column, $post_id ) {
|
||||
if ( 'event_datetime' === $column ) {
|
||||
$datetime = get_field( 'event_datetime', $post_id );
|
||||
if ( $datetime ) {
|
||||
echo esc_html( gmdate( 'F j, Y g:i a', strtotime( $datetime ) ) );
|
||||
}
|
||||
}
|
||||
if ( 'event_datetime' === $column ) {
|
||||
$datetime = get_field( 'event_datetime', $post_id );
|
||||
|
||||
if ( $datetime ) {
|
||||
echo esc_html( gmdate( 'F j, Y g:i a', strtotime( $datetime ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
add_action( 'manage_event_posts_custom_column', 'events_display_admin_column_content', 10, 2 );
|
||||
|
||||
@@ -157,28 +162,130 @@ add_action( 'manage_event_posts_custom_column', 'events_display_admin_column_con
|
||||
* @return array The modified sortable columns.
|
||||
*/
|
||||
function events_make_admin_column_sortable( $columns ) {
|
||||
$columns['event_datetime'] = 'event_datetime';
|
||||
return $columns;
|
||||
$columns['event_datetime'] = 'event_datetime';
|
||||
return $columns;
|
||||
}
|
||||
add_filter( 'manage_edit-event_sortable_columns', 'events_make_admin_column_sortable' );
|
||||
|
||||
/**
|
||||
* Map of sortable meta keys and their types.
|
||||
*
|
||||
* Key is the meta_key; value is the meta type used for sorting.
|
||||
* Supported types include 'NUMERIC', 'CHAR', 'DATE', 'DATETIME'.
|
||||
* Extend this list to allow additional meta-key sorting.
|
||||
*
|
||||
* @return array<string,string>
|
||||
*/
|
||||
function events_get_sortable_meta_map() {
|
||||
return array(
|
||||
'event_datetime' => 'DATETIME',
|
||||
// Alias often used externally; map to same type.
|
||||
'event_start_date' => 'DATETIME',
|
||||
// Add more allowed meta keys here as needed, for example:
|
||||
// 'event_capacity' => 'NUMERIC',
|
||||
// 'venue' => 'CHAR',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle sorting by the custom column.
|
||||
*
|
||||
* @param WP_Query $query The WordPress query object.
|
||||
*/
|
||||
function events_sort_by_custom_column( $query ) {
|
||||
if ( ! is_admin() || ! $query->is_main_query() ) {
|
||||
return;
|
||||
}
|
||||
if ( ! is_admin() || ! $query->is_main_query() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'event_datetime' === $query->get( 'orderby' ) ) {
|
||||
$query->set( 'meta_key', 'event_datetime' );
|
||||
$query->set( 'orderby', 'meta_value' );
|
||||
}
|
||||
$orderby = $query->get( 'orderby' );
|
||||
$map = events_get_sortable_meta_map();
|
||||
|
||||
if ( isset( $map[ $orderby ] ) ) {
|
||||
$meta_type = strtoupper( $map[ $orderby ] );
|
||||
$query->set( 'meta_key', $orderby );
|
||||
if ( 'NUMERIC' === $meta_type ) {
|
||||
$query->set( 'orderby', 'meta_value_num' );
|
||||
} else {
|
||||
$query->set( 'orderby', 'meta_value' );
|
||||
$query->set( 'meta_type', $meta_type );
|
||||
}
|
||||
}
|
||||
}
|
||||
add_action( 'pre_get_posts', 'events_sort_by_custom_column' );
|
||||
|
||||
/**
|
||||
* Extend REST API to allow ordering events by meta value.
|
||||
* Adds support for `orderby=meta_value|meta_value_num` and `meta_key`.
|
||||
*
|
||||
* @param array $params The existing REST API collection parameters.
|
||||
* @return array The modified REST API collection parameters.
|
||||
*/
|
||||
function events_rest_extend_collection_params( $params ) {
|
||||
if ( isset( $params['orderby']['enum'] ) && is_array( $params['orderby']['enum'] ) ) {
|
||||
$params['orderby']['enum'][] = 'meta_value';
|
||||
$params['orderby']['enum'][] = 'meta_value_num';
|
||||
}
|
||||
|
||||
$params['meta_key'] = array(
|
||||
'description' => __( 'Meta key to order by.', 'aa-events' ),
|
||||
'type' => 'string',
|
||||
'sanitize_callback' => 'sanitize_key',
|
||||
'validate_callback' => function ( $value ) {
|
||||
return is_string( $value ) && '' !== $value;
|
||||
},
|
||||
);
|
||||
|
||||
// Optional: allow specifying meta_type when using orderby=meta_value.
|
||||
$params['meta_type'] = array(
|
||||
'description' => __( 'Meta type used for ordering.', 'aa-events' ),
|
||||
'type' => 'string',
|
||||
'enum' => array( 'NUMERIC', 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', 'UNSIGNED' ),
|
||||
);
|
||||
|
||||
return $params;
|
||||
}
|
||||
add_filter( 'rest_event_collection_params', 'events_rest_extend_collection_params' );
|
||||
|
||||
/**
|
||||
* Apply REST meta ordering to the WP_Query args for events.
|
||||
*
|
||||
* @param array $args The prepared query args.
|
||||
* @param WP_REST_Request $request The REST request.
|
||||
* @return array
|
||||
*/
|
||||
function events_rest_adjust_query_for_meta_ordering( $args, $request ) {
|
||||
$orderby = $request->get_param( 'orderby' );
|
||||
$meta_key = $request->get_param( 'meta_key' );
|
||||
$meta_type = $request->get_param( 'meta_type' );
|
||||
|
||||
if ( in_array( $orderby, array( 'meta_value', 'meta_value_num' ), true ) && $meta_key ) {
|
||||
// Allow simple aliasing of requested meta keys to real keys used in DB.
|
||||
$aliases = array(
|
||||
'event_start_date' => 'event_datetime',
|
||||
);
|
||||
if ( isset( $aliases[ $meta_key ] ) ) {
|
||||
$meta_key = $aliases[ $meta_key ];
|
||||
}
|
||||
|
||||
$args['meta_key'] = $meta_key;
|
||||
$args['orderby'] = $orderby;
|
||||
|
||||
// If meta_type explicitly provided (and using meta_value), apply it.
|
||||
if ( $meta_type && 'meta_value' === $orderby ) {
|
||||
$args['meta_type'] = strtoupper( $meta_type );
|
||||
} elseif ( function_exists( 'events_get_sortable_meta_map' ) ) {
|
||||
// Otherwise, try to infer from our whitelist map for convenience.
|
||||
$map = events_get_sortable_meta_map();
|
||||
if ( isset( $map[ $meta_key ] ) && 'meta_value' === $orderby ) {
|
||||
$args['meta_type'] = strtoupper( $map[ $meta_key ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
add_filter( 'rest_event_query', 'events_rest_adjust_query_for_meta_ordering', 10, 2 );
|
||||
|
||||
/**
|
||||
* Set default sort order for event post type by event_datetime ascending.
|
||||
* Applies to both admin and frontend queries.
|
||||
@@ -186,22 +293,38 @@ add_action( 'pre_get_posts', 'events_sort_by_custom_column' );
|
||||
* @param WP_Query $query The WordPress query object.
|
||||
*/
|
||||
function events_set_default_sort_order( $query ) {
|
||||
// Only modify main queries for event post type
|
||||
if ( ! $query->is_main_query() ) {
|
||||
return;
|
||||
}
|
||||
// Only modify main queries for event post type
|
||||
if ( ! $query->is_main_query() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Admin list table
|
||||
if ( is_admin() && $query->get( 'post_type' ) === 'event' ) {
|
||||
if ( ! $query->get( 'orderby' ) ) {
|
||||
$query->set( 'meta_key', 'event_datetime' );
|
||||
$query->set( 'orderby', 'meta_value' );
|
||||
$query->set( 'order', 'ASC' );
|
||||
}
|
||||
}
|
||||
// Admin list table
|
||||
if ( is_admin() && $query->get( 'post_type' ) === 'event' ) {
|
||||
if ( ! $query->get( 'orderby' ) ) {
|
||||
$query->set( 'meta_key', 'event_datetime' );
|
||||
$query->set( 'orderby', 'meta_value' );
|
||||
$query->set( 'order', 'ASC' );
|
||||
}
|
||||
}
|
||||
|
||||
// Frontend: event archives and taxonomies
|
||||
if ( ! is_admin() && $query->get( 'post_type' ) === 'event' ) {
|
||||
$map = events_get_sortable_meta_map();
|
||||
$orderby = $query->get( 'orderby' );
|
||||
|
||||
// If a known meta key is explicitly requested via orderby, honor it.
|
||||
if ( isset( $map[ $orderby ] ) ) {
|
||||
$meta_type = strtoupper( $map[ $orderby ] );
|
||||
$query->set( 'meta_key', $orderby );
|
||||
if ( 'NUMERIC' === $meta_type ) {
|
||||
$query->set( 'orderby', 'meta_value_num' );
|
||||
} else {
|
||||
$query->set( 'orderby', 'meta_value' );
|
||||
$query->set( 'meta_type', $meta_type );
|
||||
}
|
||||
return; // Do not apply defaults if explicit meta sort requested.
|
||||
}
|
||||
|
||||
// Main event archive: newest first (descending by date/time)
|
||||
if ( $query->is_post_type_archive( 'event' ) ) {
|
||||
if ( ! $query->get( 'orderby' ) ) {
|
||||
|
||||
Reference in New Issue
Block a user