2
votes

TL;DR

  1. 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.
  2. 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! :)

1

1 Answers

-1
votes

Found a much simpler solution which satisfies all my URL needs...

Instead of 1 custom post type of 'qux', I've instead opted for 3 custom post types - 'foo', 'bar', and 'baz'. Each of the 3 custom post type archive pages serve in place of the old static pages of the same name.

Once the new CPTs were set up, I used https://wordpress.org/plugins/post-type-switcher/ to move posts from 'qux' into their respective new CPTs depending on their assigned category.

If anyone has the answers to my original questions at the top of the page I'm still curious though! :)