Custom post types & advanced custom fields in Genesis (part 2)

Setting up the custom fields

Continuing on from the first part of this two part article where we set up a custom events post type, below we’ll look at adding custom fields with the Advanced Custom Fields plugin.

The first step is to install and activate Advanced Custom Fields. Then, add a new group (give it a name of your choice, for example Event Details).

Advanced Custom Fields group set up screenshot

We’ll create one field for now, in which a date can be selected. That date represents the date that the event is considered a past event, and once that date is reached, we then want the event to show up on a different page. To set this new field, give it a label such as Event End Date. The field name will be automatically generated. Set the field type to Date Picker and add some instructions, such as ‘Mark the date at which the event will be considered a past event’. Mark whether or not you want this as a required field, and make sure you’re happy with the default date format.

In the location box, set the rule to show this field group if the post type is equal to events, and under options set the style to standard.

Advanced Custom Fields location and options screenshot

Now we need to add the functionality that begins the process of separating past events from current/future events. We do this by modifying the pre_get_posts action hook, adding a meta query and creating a $compare variable to compare today’s date with the date selected. At the same time we can also use pre_get_posts to add a limit to the number of posts we want to show per page. This functionality is added to functions.php, as pre_get_posts won’t work if used on template pages.

In our functions.php file we add the following:

/** Customising the custom post type query (comparing today's
 * date with the date selected, and only showing a maximum of 3 posts per page)
 */
function event_post_order( $query ){
    // if this is not an admin screen,
    // and is the event post type archive
    // and is the main query
    if( ! is_admin()
        && $query->is_post_type_archive( 'events' )
        && $query->is_main_query() ){

        // if this is a past events view
        // set compare to before today,
        // otherwise set to today or later
        $compare = isset( $query->query_vars['is_past'] ) ? '<' : '>=';

        // add the meta query and use the $compare var
        $today = date( 'Y-m-d' );
        $meta_query = array( array( 
            'key' => 'event_end_date', // this is the field name for the date picker field
            'value' => $today,
            'compare' => $compare,
            'type' => 'DATE'
        ) );
        // set the meta_query argument to equal the $meta_query array created above
        $query->set( 'meta_query', $meta_query );
        // set the posts per page to 3
        $query->set( 'posts_per_page', '3' );
    }
}
add_action( 'pre_get_posts', 'event_post_order' );

Now for the juicy part. To create a separate page for past events, we need to set up a rewrite tag and a rewrite rule:

//This function creates a page (past) to show all 'events' post types whose end-dates have passed.
function event_archive_rewrites(){

    add_rewrite_tag( '%is_past%','([^&]+)' );
    add_rewrite_rule(
        'events/past/page/([0-9]+)/?$',
        'index.php?post_type=events&paged=$matches[1]&is_past=true',
        'top'
    );
    add_rewrite_rule(
        'events/past/?$',
        'index.php?post_type=events&is_past=true',
        'top'
    );

}
add_action( 'init', 'event_archive_rewrites' );

Looking good! Credit goes to Milo for the basis of the previous two code snippets.

Now for the final touch. In our Genesis theme, the title of our past events page is still showing up as Events – all we’ve done is change the url, so apart from now only showing past events, everything else will be the same. We can easily change that title to Past Events with the following code snippet in functions.php:

function event_archive_url() {
	
	$url = $_SERVER['REQUEST_URI'];

	// if 'events/past' exists in the url, then add text to the beginning of the title
	if (strpos($url,'events/past') !== false) {
   ?>
   <style>
     .archive-title::before {
       content: "Past";
      }
   </style>
   <?php 
   }
 } 

add_action( 'init', 'event_archive_url' );

The end result is a custom events post type with a custom field that will allow users to select an ‘expiry’ date on the event, after which events show on a ‘Past Events’ page, cleanly separating current & future events from past events.

By Karen Attfield

Happiness Engineer

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.