Events Manager: Better permalinks

Events Manager, the WordPress plugin, supports permalinks but they are not very configurable. With some code that you add to your theme file you can have the ability to this.

Background information

By default Events Manager only allows a constant prefix in the permalinks. Some people would like to have permalinks that includes the category of the event, the location of the event or the date of the event, or all of these.
Like the permalinks you use for the WordPress permalinks, the code will use tags for the Events Manager permalinks, and just like the core tags they will be surrounded by the percentage character (%).
For the sake of keeping this article readable, I’ll only be working on the permalinks for events, but the code can be extended to be used with the locations permalinks as well.

The code

Setup action and filter hooks

We will be using an action and filter hook.

add_action('init', 'actionAVH_EM_generate_rewrite_tags', 10);
add_filter('post_type_link', 'filterAVH_EM_get_permalink', 10, 4);

The action will introduce the new tags to be used for the permalinks.
The filter is used to correctly display the permalinks in a post. It will replace the tags with the correct content.

Generate the new tags

The Event Manager plugin has several items that you might want to have displayed in the permalink.

/**
 * Setup permalinks tags
 *
 * Create new tags.
 */
function actionAVH_EM_generate_rewrite_tags ()
{
	/**
	 * Rewrite tags that can be used in permalink structures.
	 *
	 * These are translated into the regular expressions stored in
	 * {@link WP_Rewrite::$rewritereplace} and are rewritten to the
	 * query variables listed in {@link WP_Rewrite::$queryreplace}.
	 *
	 * @var array
	 */
	$rewritecode = array(
		'%event_year%',
		'%event_monthnum%',
		'%event_day%',
		'%event_hour%',
		'%event_minute%',
		'%event_second%',
		'%event_name%',
		'%event_owner%',
		'%event_location%',
	);

	/**
	 * Regular expressions to be substituted into rewrite rules in place
	 * of rewrite tags, see {@link WP_Rewrite::$rewritecode}.
	 *
	 * @var array
	 */
	$rewritereplace = array(
		'([0-9]{4})',
		'([0-9]{1,2})',
		'([0-9]{1,2})',
		'([0-9]{1,2})',
		'([0-9]{1,2})',
		'([0-9]{1,2})',
		'([^/]+)',
		'([^/]+)',
		'([^/]+)',
	);

	/**
	 * Query variables that rewrite tags map to, see {@link WP_Rewrite::$rewritecode}.
	 *
	 * @var array
	 */
	$queryreplace = array(
		'event_year=',
		'event_monthnum=',
		'event_day=',
		'event_hour=',
		'event_minute=',
		'event_second=',
		'event=',
		'event_owner=',
		'location=',
	);
	/**
	 * Add new rewrite placeholders
	 */
	foreach ($rewritecode as $index => $placeholder) {
		$regex=$rewritereplace[$index];
		$query_var = $queryreplace[$index];
		add_rewrite_tag($placeholder, $regex, $query_var);
	}
}

Information:

  • Lines 20-28: These are the new tags you can use in the permalinks

Create permalinks

/**
 * Setup full permalink for current custom post of Events Manager
 *
 * @param string $post_link The current permalinks
 * @param object $post The post
 * @param boolean $leavename
 * @param boolean $sample
 * @return Ambigous <string, mixed>
 */
function filterAVH_EM_get_permalink ($post_link, $post, $leavename, $sample)
{
	switch ( $post->post_type )
	{
		case EM_POST_TYPE_EVENT:

			$EM_Event = em_get_event($post->ID, $search_by = 'post_id');
			$rewritecode_wordpress = array('%year%','%monthnum%','%day%','%hour%','%minute%','%second%','%category%');
			$rewritecode_events = array('%event_year%','%event_monthnum%','%event_day%','%event_hour%','%event_minute%','%event_second%','%event_owner%', '%event_location%');
			$rewritecode = array_merge($rewritecode_wordpress, $rewritecode_events);

			if ( '' != $post_link && !in_array($EM_Event->post_status, array('draft','pending','auto-draft')) ) {
				$unixtime = strtotime($EM_Event->post_date);
				$unixtime_start = strtotime($EM_Event->event_start_date . ' ' . $EM_Event->event_start_time);

				$category = '';
				if ( strpos($post_link, '%category%') !== false ) {

					$EM_Categories = $EM_Event->get_categories();
					if ( $EM_Categories->categories ) {
						usort($EM_Categories->categories, '_usort_terms_by_ID'); // order by ID
						$category_object = $EM_Categories->categories[0];
						$category_object = get_term($category_object, EM_TAXONOMY_CATEGORY);
						$category = $category_object->slug;
						if ( isset($category_object->parent) ) {
							$parent = $category_object->parent;
							$category = avh_EM_get_parents($parent, false, '/', true, array(), EM_TAXONOMY_CATEGORY) . $category;
						}
					}
				}

				$eventlocation = '';
				if ( strpos($post_link, '%event_location%') !== false ) {
					$EM_Location = em_get_location($EM_Event->location_id);
					$eventlocation = $EM_Location->location_slug;
				}
				$author = '';
				if ( strpos($post_link, '%event_owner%') !== false ) {
					$authordata = get_userdata($EM_Event->event_owner);
					$author = $authordata->user_nicename;
				}

				$date = explode(" ", date('Y m d H i s', $unixtime));
				$rewritereplace_wordpress = array($date[0],$date[1],$date[2],$date[3],$date[4],$date[5],$category);

				$date = explode(" ", date('Y m d H i s', $unixtime_start));
				$rewritereplace_event = array($date[0],$date[1],$date[2],$date[3],$date[4],$date[5],$author, $eventlocation);

				$rewritereplace = array_merge($rewritereplace_wordpress, $rewritereplace_event);
				$post_link = str_replace($rewritecode, $rewritereplace, $post_link);
				$post_link = user_trailingslashit($post_link, 'single');
			} else { // if they're not using the fancy permalink option. We should never come here!
				$post_link = home_url('?event=' . $EM_Event->event_slug);
			}
			break;
	}
	return $post_link;
}

Information

  • Line 17: We still can use some of the original WordPress codes as well.
  • Line 23: For the event date tags we use the start date and time of the event.
  • Lines 26-39: Get the categories of the event. We use the core tag %category% for this purpose. The code gets the assigned category with the lowest ID and it’s parents.
  • Lines 34-37: Get the parents of the category. Uses a function which is described later in this article. If you don’t want the parents, remove this part of the code.

Retrieve category parents with separator.

This function is almost an exact duplicate of the WordPress function get_category_parents, with the exception that we supply the taxonomy of the category.

/**
 * Retrieve category parents with separator.
 *
 *
 * @param int $id Category ID.
 * @param bool $link Optional, default is false. Whether to format with link.
 * @param string $separator Optional, default is '/'. How to separate categories.
 * @param bool $nicename Optional, default is false. Whether to use nice name for display.
 * @param array $visited Optional. Already linked to categories to prevent duplicates.
 * @param string $taxonomy The taxonomy we need to use.
 * @return string|WP_Error A list of category parents on success, WP_Error on failure.
 */
function avh_EM_get_parents ($id, $link = false, $separator = '/', $nicename = false, $visited = array(), $taxonomy)
{
	$chain = '';
	$parent = get_term($id, $taxonomy);
	if ( is_wp_error($parent) )
		return $parent;

	if ( $nicename ) {
		$name = $parent->slug;
	} else {
		$name = $parent->name;
	}

	if ( $parent->parent && ( $parent->parent != $parent->term_id ) && !in_array($parent->parent, $visited) ) {
		$visited[] = $parent->parent;
		$chain .= get_category_parents($parent->parent, $link, $separator, $nicename, $visited);
	}

	if ( $link ) {
		$chain .= '<a href="' . esc_url(get_category_link($parent->term_id)) . '" title="' . esc_attr(sprintf(__("View all posts in %s"), $parent->name)) . '">' . $name . '</a>' . $separator;
	} else {
		$chain .= $name . $separator;
	}
	return $chain;
}

That’s all the code we need.

Implementation

Go to the screen where you can setup the Events Manager permalinks, Events->Settings->Pages->Permalink slugs and add a tag after your current slug.
Important note:You must keep a constant, like the default “Events”, at the beginning.

Examples:
The event “Long Exposures..” is filed in the category “Lecture” which is a child of the category “Club”
Permalink slug:

events/%category%

URL:

http://foo.int/events/club/lecture/long-exposures-for-landscape-photography-2013/

The event “Long Exposures..” is being held in the “Hilton Hotel”
Permalink slug:

events/%event_location%

URL:

http://foo.int/events/hilton-hotel/long-exposures-for-landscape-photography-2013/

The event “Long Exposures..” is being held on January 5, 2014
Permalink slug:

events/%event_year%/%event_monthnum%

URL:

http://foo.int/events/2014/01/long-exposures-for-landscape-photography-2013/

As noted, this code doesn’t include anything for the Locations permalink. I will write this code, but not post it here on the site. I will post it on GitHub, and will update this post with a link.

This article is filed under the categories Development » WordPress » Code Snippet and has the following tag associated with it: .
  • Hi Peter

    Thank you for this tutorial of building nicer permalinks. I implemented your code in our website, but unfortunately, all the events details get the same link. You can see our events and the links here: http://194.150.248.224/~randach/aktuelles/veranstaltungen/. any ideas, why it is not working as assumed?

    Best regards
    Christoph

  • D. Ch.

    Hi. Thank you for the contribution. It would be helpful to know where you need to insert these codes. Not clear where to put each code, if functions.php plugin or where. Thank you.

    • I actually created a plugin for this. It’s not in the WordPress repository but you can find it on github (https://github.com/petervanderdoes/avh-em-permalinks)

      • D. Ch.

        Thanks, I think a fantastic initiative and something necessary. Unfortunately it gives me an error. I do not get that functions as it comes out this type of error, tested in several different wp: Fatal error: Interface ‘AvhEmPermalinkContractsFoundationApplicationInterface’ not found in /home/comuna1n/public_html/web/blog/wp-content/plugins/avh-em-permalinks-develop/app/Avh/EmPermalink/Application.php on line 20