Interesting Custom Post Type Slug with Taxonomy and Custom Field

The question:

I have created a custom post type called “events” and have also created a custom taxonomy which only shows up on this specific post type through which the admin must select an “event category” (terms).

Currently on the public site when the event detail page is requested it looks like this:

Additionally, on the public side a web browser can access just a specific event category to view all associating events where the url looks like this:

Both of the above situations currently works fine.

The problem I am having is that I would like to customize the URL slug for the event details page as follows:

Instead of having the event detail page slug being built from the entered title I would like for it to include the taxonomy term and a specific custom field. In end effect I would like for it to look like this:<taxonomy-term>-event-title-<custom-field>/
  • <taxonomy-term> is the event category (the way I programed the metabox the admin is only able to select a single term).
  • <custom-field> is a specific custom field the user is required to enter before the event post can be saved.

Does anyone know how I might go about doing this correctly? All my experiments have led nowhere.

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

Well if I had thought about how much work with was going to be before writing it, you wouldn’t be able to get me points right now. 🙂 Needless to say, it’s rather involved (though I don’t think it really should have to be, but it is what it is.)

First off, you can’t (easily) do it like you wanted; the problem is how to differentiate between these two URLs:

  • Event Type = “Day Time”, Event
    Title = “For a Change”

  • Event Type = “Day”, Event Title =
    “Time For a Change”

Both would have a portion of their URLs looking like this and how could we tell which is which?


So, I modified your pattern to use tildes (~) as separators and that works fine:<taxonomy-term>~event-title~<custom-field>/

Anyway, I wrote a plugin that does what you need. It does the following things:

  1. It sets the rewrite rule in the the plugin activation hook using $wp_rewrite->add_rule().

  2. It applys the pattern to create actual event post links using the 'post_type_link' hook, and

  3. It simplifes editing of the URL slug by using the 'get_sample_permalink_html' hook (I didn’t try to show the full URL because it would have been too tricky for something I’m writing for free. 🙂

So here’s what the edit screen looks like:

Interesting Custom Post Type Slug with Taxonomy and Custom Field

Which produces this view on the front end:

Interesting Custom Post Type Slug with Taxonomy and Custom Field

And here ya go with the plugin code (let me know if you have questions, but not toooo many. ;-):

Plugin Name: SEO URLs for Events
if (!class_exists('SeoUrlsForEvents')) {
  class SeoUrlsForEvents {
    static function on_load() {
      add_action('init', array(__CLASS__,'init'));
      add_filter('post_type_link', array(__CLASS__,'post_type_link'),10,4);
    static function get_sample_permalink_html($sample, $post_id, $new_title, $new_slug) {
      $post = get_post($post_id);
      if ($post->post_type=='event') {
        $post_slug = self::make_post_slug($post);
        if ($post_slug) {
          $sample = str_replace('<strong>Permalink:</strong>','<strong>Permalink Slug:</strong>',$sample);
          $sample = preg_replace('#(<span id="sample-permalink">).+?(<span id="editable-post-name" title="Click to edit this part of the permalink">).+?</span>/</span>#Us',"$1$2{$post->post_name}</span></span>",$sample);
          $permalink = get_post_permalink($id);
          $sample = preg_replace("#(<span id='view-post-btn'><a href=').+?(' class='button' target='_blank'>View Post</a></span>)#","$1{$permalink}$2",$sample);
      return $sample;
    static function make_post_slug($post) {
      $post_slug = false;
      $post = (object)$post;
      if ($post->post_type=='event') {
        $when = get_post_meta($post->ID,'when',true);
        if (!empty($when)) { // If we don't have a when, use default
          $types = wp_get_object_terms($post->ID,'event-type');
          if (count($types)) // If we don't have an event-type, use default else use the first one
            $post_slug = "{$types[0]->slug}~{$post->post_name}~{$when}/";
      return $post_slug;
    static function post_type_link($post_link, $post, $leavename, $sample) {
      if ($post->post_type=='event' && $sample) {
        $post_link = '%event%';
      } else {
        $post_slug = self::make_post_slug($post);
        if ($post_slug) {
          $post_link = get_bloginfo('wpurl') . '/events/' . $post_slug;
      return $post_link;
    static function activate() {
      global $wp_rewrite;
      $wp_rewrite->add_rule('events/([^~]+)~([^~]+)~([^/]+)','index.php?post_type=event&taxonomy=event-type&term=$matches[1]&name=$matches[2]&meta_key=when&meta_value=$matches[3]', 'top');
    static function init() {
          'label'           => 'Events',
          'public'          => true,
          'rewrite'         => array('slug' => 'events'),
          'hierarchical'    => false,
          'supports'        => array('title','editor','custom-fields'),
      register_taxonomy('event-type', 'event', array(
        'hierarchical'    => false,
        'label'           => 'Event Types',
        'rewrite'         => array('slug' => 'event-types' ),

All methods was sourced from or, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment