• Skip to main content
  • Skip to primary sidebar
  • Skip to footer

nSiteful Web Builders

Building a Better Web - One Site at a Time.

  • Home
  • About
    • Testimonials
    • Resources
  • Web Sites
  • Online Marketing
  • WordPress Support
    • Customized WordPress Training
    • 60-for-60 Sessions
  • Web Applications
  • Blog
    • Archive Listing Minimalistic
    • Blog Articles Grouped by Category
    • Case Studies
    • General
    • Portfolio
    • Reviews
    • Snippets
    • Techniques
  • Contact Jeff
    • Purchase Retainer Consulting Hours
    • About Retainer Consulting Hours

By Jeff Cohan, May 24, 2022

How to Create a Simple Custom Events Plugin

On This Page...

  • The Scenario:
  • The Desired Result:
  • Code for registering the Events Custom Events Plugin Post Type:
  • Code for rendering Events landing page:
  • Code for fetching all posts for the Custom Events Plugin:
  • The All Events Loop
  • Comments/Questions?
  • Related Posts

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:

Events Landing Page

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 the switch section below.
  • Line 3: The $date_compare variable sets the date to which each event’s end_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 the meta_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.

Related Posts

  1. Use Custom Fields to Hide Stale Posts
  2. Dive Into WordPress Custom Post Types – Part 2
  3. Dive Into WordPress Custom Post Types – Part 3
  4. I Built a WordPress Plugin for Downloadable Files
  5. Create a Custom Shortcode to Display a MemberPress Membership Price ANYWHERE on Your Website
  • Choose the best match.

Written by Jeff Cohan · Categorized: Snippets · Tagged: Custom Fields, Custom Post Types, WordPress

  • Choose the best match.

Reader Interactions

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Primary Sidebar

mailchimp signup

Subscribe to get notified when new articles are published. Unsubscribe any time. No spam. I promise. Check out my newsletter archives.

social

Twitter Facebook LinkedIn

Recent Articles

  • Use Case for Custom Post Type: “In The News” March 10, 2023
  • Create a Custom Shortcode to Display a MemberPress Membership Price ANYWHERE on Your Website February 5, 2023
  • Avoid Direct Styling; Use CSS Instead September 21, 2022
  • Blog Tags: What They Are (and What They’re Not) August 5, 2022
  • How to Create a Simple Custom Events Plugin May 24, 2022

Filter By Category/Tag

Categories

  • Case Studies (7)
  • General (61)
  • Portfolio (5)
  • Reviews (12)
  • Snippets (16)
  • Techniques (38)

Popular Tags

Advanced Custom Fields Blogging Child Themes Content Marketing CSS CSS Grid Customer Service Custom Fields Custom Post Types Diagnostics Facebook FooGallery Genesis Gutenberg HTML Images iPhone Libra Live Chat Marketing Media MemberPress MemberPress Courses mu-plugins MySQL Photo Gallery php Pinterest Plugins Post Formats Pricing Project Management Security SEO Seth Godin Shortcodes Social Networking Surveys Taxonomies Trello Twitter Video Web design Web forms WordPress

siteground wp hosting

Web Hosting

wp101

EasyWordPresstutorialvideosforbeginners.
MemberPress CTA

Footer

Background

Web Sites | WordPress Support | Web Applications.

Formally trained in liberal arts and education (I have a B.A. in Government from Harvard and studied Secondary Education at Rutgers Graduate School), I have honed my skills in the communication arts and sciences as a teacher, trainer, instructional designer, writer, photographer, calligrapher, helpdesk manager, database programmer, and multimedia developer.

(I've also been a group counselor, waiter, bartender, bicycle messenger boy, computer salesman, carpenter's helper, financial analyst, and school board president.)

Tech

Systems since 1983.
Web sites since 1994.
PHP since 2001.
WordPress since 2007.

Contact

770-772-5134
Email Jeff
Send Money
All Ways

Copyright 2023, nSiteful Web Builders, Inc.

 

Subscribe

Pardon the interruption. I know popups can be annoying. But I’d love to have you as a subscriber.

Sign up to be notified when new articles are published. Unsubscribe any time.

* indicates required

Powered by MailChimp

×