最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

url rewriting - Can't change first part of URL rewrite for custom post type

programmeradmin2浏览0评论

I have successfully created a custom post type with a URL rewrite that changes URLs from:

domain/post-type/slug

To:

domain/some-string/custom-field-value-1/custom-field-value-2/slug

This is working, but there have been some changes to my project that require me to do this instead:

domain/some-string/custom-field-value-1/custom-field-value-2/slug
domain/some-other-string/custom-field-value-1/custom-field-value-2/slug

Essentially, the first part of the path needs to be dynamic so that both "some-string" and "some-other-string" are valid.

I've updated the rewrite rules to accommodate this change, and those pages do work correctly, but none of the other pages on the site (except the front page) work at all. I'm seeing the header and footer, but no content.

Here's the relevant section of my custom post type registration:

'rewrite' => array(
    'slug' => '%keyterms%/%community%/%address%',
    'with_front' => false,
)

And here's my code:

function inventory_rewrite_tags() {
    add_rewrite_tag('%keyterms%', '(.*)');
    add_rewrite_tag('%community%', '(.*)');
    add_rewrite_tag('%address%', '(.*)');
}
add_action('init', 'inventory_rewrite_tags');

function inventory_link_rewrite($link, $post) {
    if($post->post_type === 'inventory') {
        $community = get_field('community', $post->ID);
        $address = get_field('address', $post->ID);
        $possession_terms = wp_get_post_terms($post->ID, 'possession');
        $build_type_terms = wp_get_post_terms($post->ID, 'build_type');
        $ownership_terms = wp_get_post_terms($post->ID, 'ownership');

        // Add keyterm
        if($ownership_terms[0]->slug == 'rental') {
            $link = str_replace('%keyterms%/', 'apartments-for-rent/', $link);
        } else {
            $link = str_replace('%keyterms%/', 'homes-for-sale/', $link);
        }

        // Add community
        if($community) {
            $link = str_replace('%community%/', $community[0]->post_name . '/', $link);
        } else {
            $link = $possession_terms ? str_replace('%community%/', $possession_terms[0]->slug . '/', $link) : $link;
        }

        // Add address
        if($address) {
            $link = str_replace('%address%/', sanitize_title($address) . '/', $link);
        } else {
            $link = $build_type_terms ? str_replace('%address%/', $build_type_terms[0]->slug . '/', $link) : $link;
        }
    }
    return $link;
}
add_filter('post_link', 'inventory_link_rewrite', 10, 2);

Unfortunately creating a second post type is not an option.

I have successfully created a custom post type with a URL rewrite that changes URLs from:

domain/post-type/slug

To:

domain/some-string/custom-field-value-1/custom-field-value-2/slug

This is working, but there have been some changes to my project that require me to do this instead:

domain/some-string/custom-field-value-1/custom-field-value-2/slug
domain/some-other-string/custom-field-value-1/custom-field-value-2/slug

Essentially, the first part of the path needs to be dynamic so that both "some-string" and "some-other-string" are valid.

I've updated the rewrite rules to accommodate this change, and those pages do work correctly, but none of the other pages on the site (except the front page) work at all. I'm seeing the header and footer, but no content.

Here's the relevant section of my custom post type registration:

'rewrite' => array(
    'slug' => '%keyterms%/%community%/%address%',
    'with_front' => false,
)

And here's my code:

function inventory_rewrite_tags() {
    add_rewrite_tag('%keyterms%', '(.*)');
    add_rewrite_tag('%community%', '(.*)');
    add_rewrite_tag('%address%', '(.*)');
}
add_action('init', 'inventory_rewrite_tags');

function inventory_link_rewrite($link, $post) {
    if($post->post_type === 'inventory') {
        $community = get_field('community', $post->ID);
        $address = get_field('address', $post->ID);
        $possession_terms = wp_get_post_terms($post->ID, 'possession');
        $build_type_terms = wp_get_post_terms($post->ID, 'build_type');
        $ownership_terms = wp_get_post_terms($post->ID, 'ownership');

        // Add keyterm
        if($ownership_terms[0]->slug == 'rental') {
            $link = str_replace('%keyterms%/', 'apartments-for-rent/', $link);
        } else {
            $link = str_replace('%keyterms%/', 'homes-for-sale/', $link);
        }

        // Add community
        if($community) {
            $link = str_replace('%community%/', $community[0]->post_name . '/', $link);
        } else {
            $link = $possession_terms ? str_replace('%community%/', $possession_terms[0]->slug . '/', $link) : $link;
        }

        // Add address
        if($address) {
            $link = str_replace('%address%/', sanitize_title($address) . '/', $link);
        } else {
            $link = $build_type_terms ? str_replace('%address%/', $build_type_terms[0]->slug . '/', $link) : $link;
        }
    }
    return $link;
}
add_filter('post_link', 'inventory_link_rewrite', 10, 2);

Unfortunately creating a second post type is not an option.

Share Improve this question asked Nov 19, 2019 at 23:00 hmakeinhmakein 686 bronze badges 3
  • But ideally, the first part of the path (which is the rewrite base) should be static - i.e. something-static/%keyterms%/ and not just %keyterms%/. Otherwise, you'd run into 404 errors because of rewrite conflicts. – Sally CJ Commented Nov 20, 2019 at 0:50
  • That seems to be the case. Is there a way around it? – hmakein Commented Nov 20, 2019 at 15:13
  • Sorry, I had not actually looked thoroughly on your code.. but anyway, see my answer and let me know. – Sally CJ Commented Nov 20, 2019 at 23:49
Add a comment  | 

1 Answer 1

Reset to default 1

The problem is with that add_rewrite_tag('%keyterms%', '(.*)'), which results in rewrite conflicts because the generated rewrite rules would match http://example/(anything-here) and that (anything-here) can be a Page (post type page) slug, hence http://example/page-slug would not work — you wouldn't get a 404 error page, but the proper Page wouldn't be displayed, either.

So looking at your code, instead of using that (.*) (which matches anything), you should instead specify the exact value, which in your case is either apartments-for-rent or homes-for-sale:

add_rewrite_tag('%keyterms%', '(apartments-for-rent|homes-for-sale)');

That should work, but be sure to flush the rewrite rules — just visit the permalink settings page.

UPDATE

Sorry, I wasn't aware WordPress isn't retaining the RegEx for all rewrite rules, specifically for attachments where WordPress removes the brackets (( and )):

// Relevant code in WP_Rewrite::generate_rewrite_rules().
$submatchbase = str_replace( array( '(', ')' ), '', $match );

And I know you changed the RegEx to ([aehomnprt]+s-for-[aelnrst]+) which does work, although not as precise as the (apartments-for-rent|homes-for-sale).

So apart from the alternate RegEx, you can make (apartments-for-rent|homes-for-sale) works like so (this code would go in the theme functions file):

add_filter( 'rewrite_rules_array', 'fix_inventory_rewrite_rules' );
function fix_inventory_rewrite_rules( $rules ) {
    $rules2 = [];
    $values = 'apartments-for-rent|homes-for-sale';

    $_re = $values . '/';
    $my_re = preg_quote( $_re, '/' );
    foreach ( $rules as $regex => $query ) {
        if ( preg_match( '/^' . $my_re . '/', $regex ) ) {
            $regex = str_replace( $_re, '(' . $values . ')/', $regex );
        }
        $rules2[ $regex ] = $query;
    }

    return $rules2;
}
发布评论

评论列表(0)

  1. 暂无评论