On This Page...
Last updated March 8th, 2023 at 09:34 am
The Scenario:
My client wants to display on his site information about trade shows at which his company will be exhibiting. I know there are lots of event plugins out there, but most of the ones I know about would be overkill for our needs. So, I created a must-use custom Events plugin for this client. One of the requirements was to show both current and past events and to segregate them on the main events “landing” page.
I tried making this happen using the standard WordPress archive page, but I couldn’t. I think this is because of the way the archive engine loops through the posts. Or maybe I just didn’t know how to do it. Anyway, I created a new page to be the acting archive page.
The Desired Result:
Here’s how the desired Events “archive” page looks on 5/24/22:
Note that current events (those whose end dates are on or after the current date) appear at the top of the page in ascending date order, while Past events appear at the bottom of the page in descending date order.
Code for registering the Events Custom Events Plugin Post Type:
I created a file called cpt-events.php
in the mu-plugins folder, and here is the code for registering the “events” custom post type. (I used GenerateWP to generate some of this code, and then I did some search/replace in my editor to finish it up.)
<?php function register_cpt_wbox_events() { $labels = array( 'name' => _x( 'wanderBOX Event', 'Post Type General Name', 'text_domain' ), 'singular_name' => _x( 'Events', 'Post Type Singular Name', 'text_domain' ), 'menu_name' => __( 'Events', 'text_domain' ), 'name_admin_bar' => __( 'Events', 'text_domain' ), 'archives' => __( 'Event Archives', 'text_domain' ), 'attributes' => __( 'Event Attributes', 'text_domain' ), 'parent_item_colon' => __( 'Parent Event:', 'text_domain' ), 'all_items' => __( 'All Events', 'text_domain' ), 'add_new_item' => __( 'Add New Event', 'text_domain' ), 'add_new' => __( 'Add New', 'text_domain' ), 'new_item' => __( 'New Event', 'text_domain' ), 'edit_item' => __( 'Edit Event', 'text_domain' ), 'update_item' => __( 'Update Event', 'text_domain' ), 'view_Event' => __( 'View Event', 'text_domain' ), 'view_Events' => __( 'View Events', 'text_domain' ), 'search_Events' => __( 'Search Event', 'text_domain' ), 'not_found' => __( 'Not found', 'text_domain' ), 'not_found_in_trash' => __( 'Not found in Trash', 'text_domain' ), 'featured_image' => __( 'Featured Image', 'text_domain' ), 'set_featured_image' => __( 'Set featured image', 'text_domain' ), 'remove_featured_image' => __( 'Remove featured image', 'text_domain' ), 'use_featured_image' => __( 'Use as featured image', 'text_domain' ), 'insert_into_Event' => __( 'Insert into Event', 'text_domain' ), 'uploaded_to_this_Event' => __( 'Uploaded to this Event', 'text_domain' ), 'Events_list' => __( 'Events list', 'text_domain' ), 'Events_list_navigation' => __( 'Events list navigation', 'text_domain' ), 'filter_Events_list' => __( 'Filter Events list', 'text_domain' ), ); $rewrite = array('slug' => 'events'); $args = array( 'label' => __( 'Events', 'text_domain' ), 'labels' => $labels, 'supports' => array( 'title', 'editor', 'thumbnail', 'page-attributes' ), 'taxonomies' => array( 'event_cat', 'event_tag' ), 'hierarchical' => false, 'public' => true, 'show_ui' => true, 'show_in_menu' => true, 'menu_position' => 5, 'show_in_admin_bar' => true, 'show_in_nav_menus' => true, 'can_export' => true, 'has_archive' => false, 'exclude_from_search' => false, 'publicly_queryable' => true, 'capability_type' => 'post', 'rewrite' => $rewrite, ); register_post_type( 'wb_event', $args ); } add_action( 'init', 'register_cpt_wbox_events', 0 );
Because I’m not using the standard/default WordPress archive page for this post type, I set the ‘has_archive’ argument to ‘false’ on line 46. I also added the ‘rewrite’ argument on line 50 to change the slug of the acting archive page to ‘events’ (see line 32) instead of ‘wb_event’, which is the actual post type.
Code for rendering Events landing page:
function wb_all_events_render($content) { // Fuggetaboutit if not proper page if ( ! is_page('events') ) return $content; $date_format = 'n/j/Y'; // can be changed // *** CURRENT Events Loop // Call to get all CURRENT events. Send params for sort and which. $events = wb_all_events_get('asc', 'current'); $content .= '<div class="events__current">'; $content .= '<h2>Current Events</h2>'; if ( ! $events ) { $content .= '<p>There are no current events to show. Please check back often.</p>'; } else { $content .= '<p>Here are current and upcoming events. Click on image or event name to view details.</p>'; $content .= '<div class="all-events__wrap">'; $content .= wb_all_events_loop($events); $content .= '</div><!-- all-events__wrap -->'; $content .= '</div><!-- events__current -->'; } // *** PAST Events Loop $events = wb_all_events_get('desc', 'past'); $content .= '<div class="events__past">'; $content .= '<h2>Past Events</h2>'; if ( ! $events ) { $content .= '<p>There are no past events to show.</p>'; } else { $content .= '<p>Here are past events. Click on image or event name to view details.</p>'; $content .= '<div class="all-events__wrap">'; $content .= wb_all_events_loop($events); $content .= '</div><!-- all-events__wrap -->'; $content .= '</div><!-- events__current -->'; } return $content; } add_filter('the_content', 'wb_all_events_render');
Notes:
- Line 3: If the slug of the current page is not ‘events’ (defined when I registered the CPT), then return the existing content.
- Line 9: Here we’re in the Current events loop. So, this line calls the wb_all_events_get function (see below), with two parameters: ‘sort order’ (in this case ‘asc’) and ‘which’ (in this case ‘current’).
- Line 24: Here we’re in the Past events loop. So, this line calls the wb_all_events_get function with the ‘sort order’ parameter set to ‘desc’ and the ‘which’ parameter set to ‘past’.
- Line 32: This is where the meat comes in. See below.
- Line 38: I’m filtering the ‘the_content’ filter hook.
Code for fetching all posts for the Custom Events Plugin:
This is the code for fetching and returning the events that are rendered by the function displayed above.
<?php function wb_all_events_get($sort_order, $which) { $date_compare = date('Y-m-d'); // Operator must be changed depending on whether we're looking for 'current' or 'past' events. // For 'current', we want end_date >= today; for 'past', we want end_date < today. switch ( $which ) { case 'current': $compare = '>='; break; case 'past': $compare = '<'; break; } $args = array( 'post_type' => 'wb_event', 'meta_query' => array( 'key' => 'end_date', 'compare' => $compare, 'value' => $date_compare, 'type' => 'DATETIME', ), 'meta_key' => 'start_date', 'orderby' => 'meta_value', 'order' => $sort_order, 'numberposts' => -1, ); $event_posts = get_posts($args); return $event_posts; }
Notes:
This function uses the WordPress meta_query class, which allows filtering results by object metadata. (I’m using Advanced Custom Fields Pro for the custom fields.)
- Line 2: Note the arguments
$sort_order
and$which
. This variable appears on line 25; the$which
value is used to set the$compare
variable, used in theswitch
section below. - Line 3: The
$date_compare
variable sets the date to which each event’send_date
will be compared (in line 19). While I was testing my code, I changed this value several times to make sure the Current/Past logic was working properly. - Line 7: The
switch
operator, inside of which I’m using themeta_query
class. - Line 28: Call to the WordPress
get_posts
function, using the arguments defined in lines 16-26.
The All Events Loop
Here is the code for displaying the events — it’s the meat from lines 17 and 32 of the code above.
function wb_all_events_loop($events) { $date_format = 'n/j/Y'; $output = ''; foreach ($events as $event ) { $id = $event->ID; $event_title = $event->post_title; $location = get_post_meta($id, 'location_name', true); $city = get_post_meta($id, 'city', true); $state = get_post_meta($id, 'state', true); $start_date = get_post_meta($id, 'start_date', true); $end_date = get_post_meta($id, 'end_date', true); $thumb = get_the_post_thumbnail( $id, 'medium', array( 'class' => 'alignright')); $title_attribute = 'View Details about ' . $event->post_title; $output .= '<div class="event__wrap">'; $output .= '<div class="event__featured-image"><a title="' . $title_attribute . ' " href="' . get_the_permalink($id) . '">' . $thumb . '</a></div>'; $output .= '<h2 class="event__title"><a title="'.$title_attribute.'" href="'.get_the_permalink($id).'">'. $event_title . '</a></h2>'; $output .= '<div class="archive__event-meta">'; //$content .= '<div>'. $location . '</div>'; $output .= '<div class="city-state">'. $city . ', ' . $state . '</div>'; $output .= '<div class="event-date">'. date($date_format, strtotime($start_date)) . ' - ' . date($date_format, strtotime($end_date)) . '</div>'; $output .= '</div>'; $output .= '</div>'; } return $output; }
The function receives the array of events (past or current) and then loops through each event, grabbing the value of each custom field using the WordPress get_post_meta()
function. Then the output is assembled and returned to the calling function.
Comments/Questions?
I welcome your comments and questions.
Leave a Reply