0

we have a situation where, for the same permalink, there could be both a page and a custom post, for example "car".

https://www.example.com/aaa/bbb/carPostID

Normally at that address there is a custom post "car". So we use add_rewrite_rule to make a specific custom post load

Example:

    add_rewrite_rule(
        '^aaa/bbb/(.*)$',
        'index.php?car=$matches[3]',
        'top'
    );

Currently if a page is created with that form of url we get 404.

We would like instead, if there is a page and there is not our custom post, that the page "wins" and is rendered.

Is it possible, for example, to concatenate two equal rules and if there is no post for the first one the second one is used?

    add_rewrite_rule(
        '^aaa/bbb/(.*)$',
        'index.php?car=$matches[3]',
        'top'
    );


    add_rewrite_rule(
        '^aaa/bbb/(.*)$',
        'index.php?page=$matches[3]',
        'top'
    );

Is it possible? Thank you

1
  • 1
    it's unlikely that this could be done using this approach since WP uses the first rewrite rule that matches, not the first rule that returns results, so there is no cascade of rules or falling back to the next rule that matches happening. That doesn't mean you can't detect the situation and prevent the 404, but not this way. Think of it this way, the rewrite rule simply tells WP to pretend the URL was actually index.php?car=XYZ when processing it, so what you asked needs to make sense and still work if they visit that ugly URL because they are the same URL as far as WP is concerned
    – Tom J Nowell
    Commented Nov 24, 2023 at 15:32

1 Answer 1

1

Since you want to check if a custom post exists and if not, then load a page, you can't simply rely on two rewrite rules because the second rule will not act as a fallback. Instead, you can handle this programmatically.

Give this a try:

First, add a custom query var to hold your potential car post/page identifier.

function custom_query_vars_filter($vars) {
  $vars[] = 'car_slug';
  return $vars;
}
add_filter('query_vars', 'custom_query_vars_filter');

Then, you can add a rewrite rule that points to this query var.

function custom_rewrite_rule() {
    add_rewrite_rule(
        '^aaa/bbb/(.*)$',
        'index.php?car_slug=$matches[1]',
        'top'
    );
}
add_action('init', 'custom_rewrite_rule');

Now, the trickier part is to determine whether to load a car post or a page. You can use the template_redirect action to handle this logic.

function custom_template_redirect() {
    $car_slug = get_query_var('car_slug');

    if ($car_slug) {
        // Check if there's a car post with this slug
        $car_post = get_page_by_path($car_slug, OBJECT, 'car');
        if ($car_post) {
            // We found a car post, so we load it
            $GLOBALS['wp_query']->query(array('post_type' => 'car', 'name' => $car_slug));
            include(get_template_directory() . '/single-car.php');
            exit;
        } else {
            // No car post found, check if there's a page
            $page = get_page_by_path($car_slug);
            if ($page) {
                // We found a page, so load it
                $GLOBALS['wp_query']->query(array('page_id' => $page->ID));
                include(get_template_directory() . '/page.php');
                exit;
            }
        }
    }
}
add_action('template_redirect', 'custom_template_redirect');

This way, it first checks if there's a custom post of type car with the given slug. If we find it, we load it. If not, we then check for a page with that slug and load it if it exists.

I hope this works on your setup.

2
  • Super, I was trying something similar. Tnx a lot! Commented Nov 27, 2023 at 10:33
  • 1
    Great to know it works for your setup! Commented Nov 27, 2023 at 10:34

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.