0

I have a taxonomy project_category, and I want the URLs to appear as:

https://www.example.com/{$term_slug}-web-design/

I can achieve this with rewrite rules, but the problem I'm running in to is that some pages also contain -web-design at the end of their URL.

Is it possible to set up a rewrite rule that first checks if a matching term exists, and if so, rewrite to that term, otherwise rewrite to a page whether it exists or not?

My current theory is to somehow attach an additional query variable to the taxonomy terms, but I'm not sure how to do that or if that'd even work.

/**
 * Register the "Project" post type.
 *
 * @return void
 */
function prefix_register_project_post_type(): void {
    // ...

    register_taxonomy("project_category", "project", [
        // ...
        "rewrite" => ["slug" => "%project_category%-web-design"],
        // ...
    ]);

    // ...
}
add_action("init", "prefix_register_project_post_type");

/**
 * Fix "project_category" slugs
 *
 * @param string $url
 * @param WP_Term $term
 * @param string $taxonomy
 * @return string
 */
function prefix_term_link_project_category(string $url, WP_Term $term, string $taxonomy): string {
    if ($taxonomy !== "project_category") {
        return $url;
    }

    return home_url("/{$term->slug}-web-design/");
}
add_filter("term_link", "prefix_term_link_project_category", 10, 3);

/**
 * Rewrite `/{$term_name}-web-design/{$term-name}` to `/{$term_name}-web-design/`
 *
 * @return void
 */
function prefix_project_category_slug_rewrite(): void {
    add_rewrite_rule("(.+)-web-design/?$", "index.php?taxonomy=project_category&term=$1", "top");
}
add_action("init", "prefix_project_category_slug_rewrite");
4
  • you can't know in advance at the rewrite stage if the query args the rewrite generates are going to match something, and it also doesn't help avoid the problem when someone creates a page with a slug that clashes either. WP matches the rule that matches first not the rule that matches best.
    – Tom J Nowell
    Jan 10 at 15:45
  • also this isn't the only solution to this problem, you could ask how to prevent people using -web-design on the end of a slug or to change it on save, so that the scenario you're trying to solve never happens in the first place
    – Tom J Nowell
    Jan 10 at 15:46
  • also note that term_link like the post link version changes the URL that gets output on the frontend, and can influence canonical redirecting, but it doesn't change the rewrite rules. It's like someone going through a book just before it goes to the book store to find every mention of an address and putting a sticker with a new address over it, it's not the same as moving house
    – Tom J Nowell
    Jan 10 at 15:48
  • Okay, sounds like this isn't possible at all then, annoying but understandable. I have other ideas on how to achieve this using page templates if I must. Regarding your second comment, this is for our own website, so this isn't something a client is requesting, this is something we'd like to do ourselves, so adding a "don't do this" filter wouldn't really help. And your third - yes, I know term_link doesn't handle rewrites; that's why there's a rewrite rule filter below that. The rewrite is working, it just conflicts with pages, that's all my question is about. Jan 10 at 16:08

1 Answer 1

1

Figured out a solution! This intercepts the query at parse_request, checks if a page with a matching slug exists, and if so, changes the request to a page request.

/**
 * Fix rewrite conflicts between "project_category" and "page"
 *
 * @param WP $query
 * @return WP
 */
function prefix_parse_request_fix_rewrite_conflicts_project_category(WP $query): WP {
    if (isset($query->query_vars["project_category"])) {
        $path = preg_replace("/\//", "", $_SERVER["REQUEST_URI"]);

        if (get_page_by_path($path, OBJECT, "page")) {
            unset($query->query_vars["project_category"]);
            $query->query_vars["pagename"] = $path;
        }
    }

    return $query;
}
add_action("parse_request", "prefix_parse_request_fix_rewrite_conflicts_project_category");

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.