TL;DR
- Are positive lookaheads valid regex in WordPress add_rewrite_rule functions? I have one detailed below that doesn't seem to work although appearing valid.
- Is it possible to rewrite a WordPress custom post type post slug so that multiple posts can have the same post name, but be differentiated by their assigned category?
The Setup:
- WordPress install
- 3 pages - 'foo', 'bar', and 'baz'
- 3 categories - 'foo', 'bar', and 'baz'
- Custom post type - 'qux'
- Posts in 'qux' are assigned 1 category - either 'foo', 'bar', or 'baz'
- Once assigned a category, a custom post slug should read '/[category]/[custom-post-name]/, appearing to be a child of the similarly-named page
The Problem
Posts assigned to different categories in 'qux' can have the same name, e.g. there can be post 'norf'[1] assigned to 'foo' and post 'norf'[2] assigned to 'bar'.
Obviously WordPress doesn't allow duplicate page slugs, so I've appended posts that have the same name with category modifiers (e.g. 'norf-fo' (post 'norf' assigned to 'foo') and 'norf-br' (post 'norf' assigned to 'bar')). This gives me '/foo/norf-fo/' and '/bar/norf-br/' on the front-end. My question is how do I use WordPress' rewrite API to attain '/foo/norf/' and '/bar/norf/'?
My Solution So Far
I've managed to get the URL displaying correctly in the editor by using the following:
function replace_link( $link, $post = 0 ) {
if ( $post->post_type == 'qux' && in_category( array( 'foo', 'bar', 'baz' )) ) {
$terms = get_the_terms( $post->ID, 'category' );
if ( $terms && ! is_wp_error( $terms ) ) :
$links = array();
foreach ( $terms as $term ) {
$links[] = $term->name;
}
$links = str_replace(' ', '-', $links);
endif;
if (in_array("foo", $links)) {
return home_url('foo/'. str_replace('-fo', '', $post->post_name) .'/');
}
if (in_array("bar", $links)) {
return home_url('bar/' . str_replace('-br', '', $post->post_name) .'/');
}
if (in_array("baz", $links)) {
return home_url('baz/'. str_replace('-bz', '', $post->post_name) .'/');
}
} else {
return $link;
}
}
add_filter('post_type_link', 'replace_link', 1, 3);
This works fine, but my understanding is that this is only a superficial change (please correct me if I'm wrong). I've then used the following rewrite rules:
function custom_rewrite_rule_fo() {
add_rewrite_rule('foo\/(.+?)(?=-fo)','index.php?latest_work=$matches[1]','top');
}
add_action('init', 'custom_rewrite_rule_fo', 10, 0);
function custom_rewrite_rule_br() {
add_rewrite_rule('bar\/(.+?)(?=-br)','index.php?latest_work=$matches[1]','top');
}
add_action('init', 'custom_rewrite_rule_br', 10, 0);
function custom_rewrite_rule_bz() {
add_rewrite_rule('baz\/(.+?)(?=-bz)','index.php?latest_work=$matches[1]','top');
}
add_action('init', 'custom_rewrite_rule_bz', 10, 0);
I've tested the regex in various online testers and it seems to work (see https://regex101.com/r/tL1iV4/1).
WordPress however doesn't, and on viewing the pages, it rewites to '/qux/norf-fo/' and '/qux/norf-br/' etc. I've come to conclusion that this is because WordPress' regex doesn't support positive lookahead, which I've used.
I assume that it's purely down to my poor regex skills, but I've tried many many permutations, and don't seem to be getting anywhere... Any help greatly appreciated! :)