While talking to Amanda who’s website I build over at Authentic Alignment Wellness we discussed how it would be nice to show off upcoming events with as little effort as possible on her end.

This requires a few steps

  • Easy event setup on the wordpress backend
  • Only the next event upcoming is shown off
  • If no events are upcoming show a default placeholder

Custom Post Type

I didn’t want events to be posts I wanted them to be events so I dropped in a custom post type into my functions.php file

function wporg_custom_post_type()
{
  register_post_type('flaxen_event',
    array(
      'labels'		=> array(
        'name'			=> __('Events'),
        'singular_name'	=> __('Events'),
      ),
      'public'			=> true,
      'has_archive'	=> true,
      'rewrite'		=> array( 'slug' => 'events' ),
    )
  );
}
add_action('init', 'wporg_custom_post_type');

Meta Dates

Custom post types are still using the classic wordpress editor so I had to add meta boxes the old way, this is a pretty big block of code so I’ll break it up into manageable chunks but this all goes into the functions.php file or a required file from it

Register the Meta Boxes

function event_date_add_post_meta_boxes() {

  add_meta_box(
    'event-date', // Unique ID
    'Event Date', // Title
    'event_date_render_metabox', // Callback function
    'flaxen_event', // post
    'normal', // Context
    'default' // Priority
  );
}
add_action( 'add_meta_boxes', 'event_date_add_post_meta_boxes' );

Defaults

function event_date_defaults() {
  return array(
    'start_date_m'	=> 'default',
    'start_date_d'	=> 'default',
    'start_date_o'	=> 'default',
    'end_date_m'	=> 'default',
    'end_date_d'	=> 'default',
    'end_date_o'	=> 'default',
  );
}

Render the meta box

function event_date_render_metabox() {
  // Variables
  global $post; // Get the current post data
  $saved = get_post_meta( $post->ID, 'event_date', true ); // Get the saved values
  $defaults = event_date_defaults(); // Get the default values
  $event_date = wp_parse_args( $saved, $defaults ); // Merge the two in case any fields don't exist in the saved data
  ?>

Create the inputs

Start with an opening and a variable for the current month

<fieldset>
    <div class="wrap">
      <?php $em = date("m"); ?> <!-- used with an if this month is -->

      <p>When does this event start.</p>

The Month

<select id="event_date[start_date_m]" name="event_date[start_date_m]">
				<!-- check if there has been a month set and its this month else if month has not been set but its currently this month then its also selected -->
				<option value="01" <?php if ( $event_date['start_date_m'] == '01' ) { echo "selected"; } elseif ( $event_date['start_date_m'] == 'default ' && $em == 1) { echo "selected"; } ?>>01-Jan</option> 
				<option value="02" <?php if ( $event_date['start_date_m'] == '02' ) { echo "selected"; } elseif ( $event_date['start_date_m'] == 'default ' && $em == 2) { echo "selected"; } ?>>02-Feb</option>
				<option value="03" <?php if ( $event_date['start_date_m'] == '03' ) { echo "selected"; } elseif ( $event_date['start_date_m'] == 'default ' && $em == 3) { echo "selected"; } ?>>03-Mar</option>
				<option value="04" <?php if ( $event_date['start_date_m'] == '04' ) { echo "selected"; } elseif ( $event_date['start_date_m'] == 'default ' && $em == 4) { echo "selected"; } ?>>04-Apr</option>
				<option value="05" <?php if ( $event_date['start_date_m'] == '05' ) { echo "selected"; } elseif ( $event_date['start_date_m'] == 'default ' && $em == 5) { echo "selected"; } ?>>05-May</option>
				<option value="06" <?php if ( $event_date['start_date_m'] == '06' ) { echo "selected"; } elseif ( $event_date['start_date_m'] == 'default ' && $em == 6) { echo "selected"; } ?>>06-Jun</option>
				<option value="07" <?php if ( $event_date['start_date_m'] == '07' ) { echo "selected"; } elseif ( $event_date['start_date_m'] == 'default ' && $em == 7) { echo "selected"; } ?>>07-Jul</option>
				<option value="08" <?php if ( $event_date['start_date_m'] == '08' ) { echo "selected"; } elseif ( $event_date['start_date_m'] == 'default ' && $em == 8) { echo "selected"; } ?>>08-Aug</option>
				<option value="09" <?php if ( $event_date['start_date_m'] == '09' ) { echo "selected"; } elseif ( $event_date['start_date_m'] == 'default ' && $em == 9) { echo "selected"; } ?>>09-Sep</option>
				<option value="10" <?php if ( $event_date['start_date_m'] == '10' ) { echo "selected"; } elseif ( $event_date['start_date_m'] == 'default ' && $em == 10) { echo "selected"; } ?>>10-Oct</option>
				<option value="11" <?php if ( $event_date['start_date_m'] == '11' ) { echo "selected"; } elseif ( $event_date['start_date_m'] == 'default ' && $em == 11) { echo "selected"; } ?>>11-Nov</option>
				<option value="12" <?php if ( $event_date['start_date_m'] == '12' ) { echo "selected"; } elseif ( $event_date['start_date_m'] == 'default ' && $em == 12) { echo "selected"; } ?>>12-Dec</option>
			</select>

The Day and Year

<input id="event_date[start_date_d]" name="event_date[start_date_d]" type="text" size="2" maxlength="2" autocomplete="off" value="<?php if ($event_date['start_date_d'] != 'default') { echo $event_date['start_date_d']; } else { echo date("d"); } ?>">
      ,
      <input id="event_date[start_date_o]" name="event_date[start_date_o]" type="text" size="4" maxlength="4" autocomplete="off" value="<?php if ($event_date['start_date_o'] != 'default') { echo $event_date['start_date_o']; } else { echo date("o"); } ?>">
    </div>

Repeat for end dates

But then also close up with a nonce for security

<div class="wrap">
      <?php $tomorrow = date("d") + 1; ?>

      <p>When does this event finish.</p>
      <select id="event_date[end_date_m]" name="event_date[end_date_m]">
        <option value="01" <?php if ( $event_date['end_date_m'] == '01' ) { echo "selected"; } elseif ( $event_date['end_date_m'] == 'default ' && $em == 1) { echo "selected"; } ?>>01-Jan</option> 
        <option value="02" <?php if ( $event_date['end_date_m'] == '02' ) { echo "selected"; } elseif ( $event_date['end_date_m'] == 'default ' && $em == 2) { echo "selected"; } ?>>02-Feb</option>
        <option value="03" <?php if ( $event_date['end_date_m'] == '03' ) { echo "selected"; } elseif ( $event_date['end_date_m'] == 'default ' && $em == 3) { echo "selected"; } ?>>03-Mar</option>
        <option value="04" <?php if ( $event_date['end_date_m'] == '04' ) { echo "selected"; } elseif ( $event_date['end_date_m'] == 'default ' && $em == 4) { echo "selected"; } ?>>04-Apr</option>
        <option value="05" <?php if ( $event_date['end_date_m'] == '05' ) { echo "selected"; } elseif ( $event_date['end_date_m'] == 'default ' && $em == 5) { echo "selected"; } ?>>05-May</option>
        <option value="06" <?php if ( $event_date['end_date_m'] == '06' ) { echo "selected"; } elseif ( $event_date['end_date_m'] == 'default ' && $em == 6) { echo "selected"; } ?>>06-Jun</option>
        <option value="07" <?php if ( $event_date['end_date_m'] == '07' ) { echo "selected"; } elseif ( $event_date['end_date_m'] == 'default ' && $em == 7) { echo "selected"; } ?>>07-Jul</option>
        <option value="08" <?php if ( $event_date['end_date_m'] == '08' ) { echo "selected"; } elseif ( $event_date['end_date_m'] == 'default ' && $em == 8) { echo "selected"; } ?>>08-Aug</option>
        <option value="09" <?php if ( $event_date['end_date_m'] == '09' ) { echo "selected"; } elseif ( $event_date['end_date_m'] == 'default ' && $em == 9) { echo "selected"; } ?>>09-Sep</option>
        <option value="10" <?php if ( $event_date['end_date_m'] == '10' ) { echo "selected"; } elseif ( $event_date['end_date_m'] == 'default ' && $em == 10) { echo "selected"; } ?>>10-Oct</option>
        <option value="11" <?php if ( $event_date['end_date_m'] == '11' ) { echo "selected"; } elseif ( $event_date['end_date_m'] == 'default ' && $em == 11) { echo "selected"; } ?>>11-Nov</option>
        <option value="12" <?php if ( $event_date['end_date_m'] == '12' ) { echo "selected"; } elseif ( $event_date['end_date_m'] == 'default ' && $em == 12) { echo "selected"; } ?>>12-Dec</option>
      </select>

      <input id="event_date[end_date_d]" name="event_date[end_date_d]" type="text" size="2" maxlength="2" autocomplete="off" value="<?php if ($event_date['end_date_d'] != 'default') { echo $event_date['end_date_d']; } else { echo $tomorrow; } ?>">
      ,
      <input id="event_date[end_date_o]" name="event_date[end_date_o]" type="text" size="4" maxlength="4" autocomplete="off" value="<?php if ($event_date['end_date_o'] != 'default') { echo $event_date['end_date_o']; } else { echo date("o"); } ?>">
    </div>
  </fieldset>

  ?php
  // This validates that submission came from the actual dashboard and not the front end or a remote server.
  wp_nonce_field( 'event_date_metabox_nonce', 'event_date_metabox_process' );
}

Save the Metabox

function event_date_save_metabox( $post_id, $post ) {
  // Verify that our security field exists. If not, bail.
  if ( !isset( $_POST['event_date_metabox_process'] ) ) return;
  // Verify data came from edit/dashboard screen
  if ( !wp_verify_nonce( $_POST['event_date_metabox_process'], 'event_date_metabox_nonce' ) ) {
    return $post->ID;
  }

  if ( !isset( $_POST['event_date'] ) ) {
    return $post->ID;
  }

  // Verify user has permission to edit post
  if ( !current_user_can( 'edit_post', $post->ID )) {
    return $post->ID;
  }

  $sanitized = array();
  // Loop through each of our fields
  foreach ( $_POST['event_date'] as $key => $date ) {
    // Sanitize the data and push it to our new array
    // `wp_filter_post_kses` strips our dangerous server values
    // and allows through anything you can include a post.
    $sanitized[$key] = wp_filter_post_kses( $date );
  }
  // Save our submissions to the database
  update_post_meta( $post->ID, 'event_date', $sanitized );
}
add_action( 'save_post', 'event_date_save_metabox', 1, 2 );

By this point we have a custom post type on the backend where we can add start and end dates to the custom meta boxes that will save and we can return to them

Create an array with IDs and dates

Now I loop the latest ten events and build an array with that info but I don’t write anything to the page so I suggest putting this right above where it will be implemented, in my case the header.php file.

<?php
$date_now = new DateTime(); // current time date, note this cant be used with an echo $date_now needs print_r($date_now);

$stack = array(); // build an empty array to add event dates to

// query for events
$args = [
  'post_type'			=> 'flaxen_event',
  'posts_per_page'	=> 10,
];

// run the events in a loop this doesnt print anything just builds an array
$loop = new WP_Query($args);
while ($loop->have_posts()) {
  $loop->the_post();

  $meta = get_post_meta( $post->ID, 'event_date', false ); // grab the dates meta
  $data = $meta[0]; // this ends up as an array in an array it might be possible to remove this step but for now its needed

  // create variables for the date portions
  $mon = $data['start_date_m'];
  $da = $data['start_date_d'];
  $yea = $data['start_date_o'];

  // create a date with the variables as one
  $eventdate = new DateTime("$mon/$da/$yea"); // runs month / day / year 13/12/2016 

  $event_id = get_the_id();
  
  $stack[$event_id] = $eventdate; // add the dates as a value to the array with the ID as the key
  
} // while have events

Sort the stack

There are a number of ways of sorting arrays in php the one I am using here is sort as it orders the values without resetting the keys

asort($stack); // ascending sort is oldest to newest and doesnt alter the keys

Print the next event

At this point we have everything in order we just need to print the title of the upcoming event

foreach ( $stack as $key => $value ) {
  if ($date_now < $value) {
    $title = get_post($key)->post_title; // the events title
    ?>
    <p><?php echo $title; ?></p>
    <?php break; // stop looping once we find something in the future
  } // if the events in the future
} // loop of all events

If no upcoming events

We need to have the fallback incase we don’t have an event coming up

$last = array_key_last ($stack);

if ($date_now > $stack[$last]) { ?>
  <p>Start With a Free Discovery Session</p>
<?php } ?>