There are lots of ways to customize The Events Calendar, from minor CSS changes to completely overriding any of the template files with your own markup. We’re going to look at template filters- an advanced customization technique that completely bypasses the calendar’s template files, allowing you to display calendar content in any of your existing theme templates, or build your own from scratch using event data.

Meet the Template Hierarchy (aka “Template Hijack”) filter

We introduced a brand new filter in The Events Calendar 5.3:

tribe_events_views_v2_use_wp_template_hierarchy

With this template filter, we can tell The Events Calendar to use the WordPress template hierarchy for events instead of its own templates.

In this example, events are displayed with the theme’s archive template instead of the calendar template that comes with the plugin. The calendar template is a custom archive template, but using this new filter ignores that template in favor of the WordPress template hierarchy, forcing the calendar to behave like any other post archive.

Basic template filte usage

Here’s an example of the template filter at its most basic in a theme’s functions.php file:

add_filter(
  'tribe_events_views_v2_use_wp_template_hierarchy',
  function( $hijack, $template, $context, $query ) {
    if ( ! is_singular() ) {
      $hijack = true;
    }

    return $hijack;
  },
  10,
  4
);

There are four arguments in there, with $hijack being the only required one. It’s a boolean that transitions the calendar from plugin templates to theme templates when set to true.

In this basic example, we’ve wrapped the $hijack argument inside a condition that checks if the current view is not a single event post. In other words, are we looking at an event or at the calendar? If it’s not an event, then let the WordPress template hierarchy hijack the calendar and leave the individual event posts alone.

Template filter arguments

We just covered the $hijack argument, but there are three additional ones that are optional:

  • $template: The template located by WordPress (e.g. “event-single.php”)
  • $context: The immutable, global object instance that serves as the Tribe template context.
  • $query: The global $wp_query

Custom templates

The benefit of the Template Hierarchy filter is two-fold:

  1. It allows us to use your existing theme templates for calendar content.
  2. It allows us to leverage the WordPress template hierarchy to build your own archive and single templates for the calendar and events.

If we want to create a custom template in our theme for this calendar, which again is an archive of event posts, we can add a file to the theme’s root folder named archive-tribe_events.php just as you would do when creating an archive template for a custom post type. So, let’s do that!

Examples

👋 For these examples, we’re using the Twenty Twenty theme, so the images may not quite reflect what you see if you are using a different theme. Download the example files if you would like to follow along.

First, we copy the existing archive template. If you’ve worked with Twenty Twenty before, then you know it doesn’t have an archive.php file. Instead, it relies on the index.php file. That’s what we want to copy instead. But since we don’t want our copy of the template to affect the theme’s homepage or other views, let’s rename it archive-tribe_events.php.

Go ahead and remove the search section, as well as the hardcoded $archive_title and $archive_subtitle strings so it’s more obvious that we’re using the template specifically for the tribe_events custom post type. Now the archive looks a little more tailored to events.

All we changed is what displays at the top of the archive.

Awesome, let’s do the same thing, but this time with events! Again, if the calendar is a custom post type archive, then an event is a post single. That means our function will look almost identical to the last one in functions.php, but instead of checking that we’re not on a post single, we’ll check that we are on a post single:

add_filter(
  'tribe_events_views_v2_use_wp_template_hierarchy',
  function( $hijack, $template, $context, $query ) {
    if ( is_singular() ) {
      $hijack = true;
    }

    return $hijack;
  },
  10,
  4
);

See the small difference? We’re now testing for is_singular() to be true instead of ! is_singular. If we wanted to hijack the archive and single at the same time, we can combine them in the same function like this:

add_filter( 'tribe_events_views_v2_use_wp_template_hierarchy', '__return_true' );

OK, back to our example. Let’s check out our single event:

That looks fine. No, really! But do you notice something? All we’re showing is the post content and featured image. Where’s the rest of the event’s content, like the date and time, the venue, and the organizer?

The Events Calendar passes a lot of data into the event single that isn’t built into a standard template. Chances are you’re going to want those things in your template, so let’s create a new template in the theme folder that specifically displays event data.

Twenty Twenty uses singular.php for single posts. Let’s copy that and rename it using the WordPress template hierarchy format for a custom post type single, single-tribe_events.php.

We’re going to add one line of code at the very beginning of the file, right before the line with get_header();.

// Get the event w/data:
$event = tribe_get_event( get_the_ID() );

get_header();

That little line provides all the event data we need. Let’s use it to display the event title:

<main id="site-content" role="main" class="single-event">

  <h2 style="text-align:center">

    <?php
      echo sprintf(
        /* Translators: event title test string */
        esc_html__( '%1$s', 'my-textdomain' ),
        $event->title
      );
    ?>

  </h2>

  <?php

All we’re doing here is displaying the event’s title by calling the $event object, and asking for the title. We’re just testing things here, but it’s always a good idea to make strings compatible with translations, so we’ve included that in the example. Another thing to note is that we usually wouldn’t use inline CSS like this, but we are adding the CSS text-align property for the sake of presentation. Let’s take a look:

Well, we’re not going to win any design awards with this, but it’s a start! From here you should be able to:

  • Use the template filter to force events to use your theme’s templates
  • Hijack single events, event archives, or both
  • Create a specific template for the event archive and event singles
  • Access event data in the event single template.

Happy coding!