Rewrite custom post type url’s adding meta box values

I’ve got these custom post types (CPT) and meta boxes:

  • Movies (CPT)
    • Genre (Meta box)
  • Genres (CPT)

If one movie is called Die hard then I want the permalink to be:
/genres/action/die-hard

This is easily fixed by setting the movie-CPT to ‘rewrite’ => false and use this code instead:

add_action('init', 'rb_add_rewrite_rules');
add_filter('post_type_link', 'rb_create_permalinks', 10, 3);

function rb_add_rewrite_rules() {
    global $wp_rewrite;
    $wp_rewrite->add_rewrite_tag('%movies%', '([^/]+)', 'movies=');
    $wp_rewrite->add_rewrite_tag('%genre%', '([^/]+)', 'genre=');

    $wp_rewrite->add_permastruct('movies', '/genres/%genre%/%movies%', false);
}

function rb_create_permalinks($permalink, $post, $leavename) {
    $no_data = 'no-data';
    $post_id = $post->ID;

    if($post->post_type != 'movies' || empty($permalink) || in_array($post->post_status, array('draft', 'pending', 'auto-draft')))
    return $permalink;

    $event_id = get_post_meta($post_id, 'genre', true);
    $var1 = basename(get_permalink($event_id));
    $var1 = sanitize_title($var1);

    if(!$var1)
        $var1 = $no_data;

    $permalink = str_replace('%genre%', $var1, $permalink);

    return $permalink;
}

Ok, here’s the problem. Both the Die Hard permalink and the archive-genres.php (displaying all the genres) is looking good, but the single-genres.php isn’t found – instead, going to /genres/action will display the index.php code.

I guess the problem is that my rewrites collide, maybe it’s not possible to do this:

‘movies’ CPT permalink

/custom base name/custom field meta box value)/'movies' CPT post name

‘genres’ CPT permalink

/custom post type name (same value as the custom base name above!!)/'genres' CPT post name

How can I make WordPress use single-genres.php for /genres/action etc?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

It sounds like you’re very close here and your only remaining issue is that your permalinks for genres and movies collide.

'movies' CPT permalink
/genres/%custom field meta box value%/%movie%/

'genres' CPT permalink
/genres/%genre%/

The issue here is using the add_permastruct. When it creates the rules for movies, they look something like this:

genres/([^/]+)/([^/]+)(/[0-9]+)?/?$
  => index.php?genre=$matches[1]&movies=$matches[2]&page=$matches[3]

The way request processing works in WordPress, you can’t set multiple post types in the same URL — WordPress stops after the first one. That is, they can be in the pretty URL, but not in the “ugly” one that generates the request and query. Any rewrite rules with movies= cannot contain genre=. Below is the full, exhausting overhaul of rb_add_rewrite_rules. You can pull out any rules you may not need like the attachment urls, feed urls, etc. As always when making rewrite changes, be sure to flush your permalinks by going to Settings->Permalinks and clicking “Save Changes”. Also, make sure 'rewrite' => false is set on both custom post types.

function rb_add_rewrite_rules() {
    add_rewrite_rule( 'genres/[^/]+/[^/]+/attachment/([^/]+)/?$', 'index.php?attachment=$matches[1]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/[^/]+/attachment/([^/]+)/trackback/?$', 'index.php?attachment=$matches[1]&tb=1', 'top' );
    add_rewrite_rule( 'genres/[^/]+/[^/]+/attachment/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$', 'index.php?attachment=$matches[1]&feed=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/[^/]+/attachment/([^/]+)/(feed|rdf|rss|rss2|atom)/?$', 'index.php?attachment=$matches[1]&feed=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/[^/]+/attachment/([^/]+)/comment-page-([0-9]{1,})/?$', 'index.php?attachment=$matches[1]&cpage=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/([^/]+)/trackback/?$', 'index.php?movies=$matches[1]&tb=1', 'top' );
    add_rewrite_rule( 'genres/[^/]+/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$', 'index.php?movies=$matches[1]&feed=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/([^/]+)/(feed|rdf|rss|rss2|atom)/?$', 'index.php?movies=$matches[1]&feed=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/([^/]+)/page/?([0-9]{1,})/?$', 'index.php?&movies=$matches[1]&paged=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/([^/]+)(/[0-9]+)?/?$', 'index.php?movies=$matches[1]&page=$matches[3]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/[^/]+/([^/]+)/?$', 'index.php?attachment=$matches[1]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/[^/]+/([^/]+)/trackback/?$', 'index.php?attachment=$matches[1]&tb=1', 'top' );
    add_rewrite_rule( 'genres/[^/]+/[^/]+/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$', 'index.php?attachment=$matches[1]&feed=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/[^/]+/([^/]+)/(feed|rdf|rss|rss2|atom)/?$', 'index.php?attachment=$matches[1]&feed=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/[^/]+/([^/]+)/comment-page-([0-9]{1,})/?$', 'index.php?attachment=$matches[1]&cpage=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/attachment/([^/]+)/?$', 'index.php?attachment=$matches[1]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/attachment/([^/]+)/trackback/?$', 'index.php?attachment=$matches[1]&tb=1', 'top' );
    add_rewrite_rule( 'genres/[^/]+/attachment/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$', 'index.php?attachment=$matches[1]&feed=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/attachment/([^/]+)/(feed|rdf|rss|rss2|atom)/?$', 'index.php?attachment=$matches[1]&feed=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/attachment/([^/]+)/comment-page-([0-9]{1,})/?$', 'index.php?attachment=$matches[1]&cpage=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/([^/]+)/trackback/?$', 'index.php?genre=$matches[1]&tb=1', 'top' );
    add_rewrite_rule( 'genres/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$', 'index.php?genre=$matches[1]&feed=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/([^/]+)/(feed|rdf|rss|rss2|atom)/?$', 'index.php?genre=$matches[1]&feed=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/([^/]+)/page/?([0-9]{1,})/?$', 'index.php?genre=$matches[1]&paged=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/([^/]+)(/[0-9]+)?/?$', 'index.php?genre=$matches[1]&page=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/([^/]+)/?$', 'index.php?attachment=$matches[1]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/([^/]+)/trackback/?$', 'index.php?attachment=$matches[1]&tb=1', 'top' );
    add_rewrite_rule( 'genres/[^/]+/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$', 'index.php?attachment=$matches[1]&feed=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/([^/]+)/(feed|rdf|rss|rss2|atom)/?$', 'index.php?attachment=$matches[1]&feed=$matches[2]', 'top' );
    add_rewrite_rule( 'genres/[^/]+/([^/]+)/comment-page-([0-9]{1,})/?$', 'index.php?attachment=$matches[1]&cpage=$matches[2]', 'top' );
}

Method 2

I think you’re taking the wrong approach in terms of data structure. You should create a custom taxonomy called Genres, and bind your movies CPT to the Genres custom taxonomy, and then select which Genres the movie belongs to.

To address questions about your existing code. single-XXX.php template is used to display content from the CPT called XXX. So in order to display movies, you should use single-movies.php. And address content specifically for a particular post_meta, you can do the following:

if(get_post_meta($post_id, 'genres', false) == 'action') {
   //Do Stuff Here
}


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

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x