theKing
theKing

Reputation: 844

Custom permalink structure for multiple custom post_type URLs using add_permastruct returning regular posts error / 404

In my WP v6.1, I have two custom port types: company, product and custom taxonomy country.

Desired URL structure is %country%/%company_postname% and %country%/%product_postname% respectively and below is the code for $wp_rewrite:

add_action('init', 'custom_init');

function custom_init() {

global $wp_rewrite;
$company_url = '/%country%/%company_postname%';
$product_url = '/%country%/%product_postname%';

$wp_rewrite->add_permastruct('company', $company_url, false);
$wp_rewrite->add_permastruct('product', $product_url, false);

$wp_rewrite->add_rewrite_tag("%company_postname%", '([^/]+)', "company=");
$wp_rewrite->add_rewrite_tag("%product_postname%", '([^/]+)', "product=");
}

With above code and another post_type_link filter function, I am able to generate my custom URLs. However the issue is regular post and page posts are not found returning error_404.

Regular post / page standard URL structure: www.example.com/%postname%

Have tried add_permastruct for posts & pages, but that did not worked. How do I show pages and posts while having the custom URLs for my custom posts.

Update 1 Custom posts and taxonomies were created by code.

Example of company code

function company_post_type() {

    $labels = array(
        'name' => _x('Company', 'Post Type General Name', 'text'),
    );
    $args = array(
        'labels' => $labels,
        'supports' => array('title', 'editor', 'custom-fields'),
        'taxonomies' => array('country'),
        'query_var' => true,
        'rewrite' => false
    );
    register_post_type('company', $args);
}

add_action('init', 'company_post_type', 0);

Update 2

And my post_type_link function is:

function post_type_link_function($url, $post) {

    // only if post is published
    if ('' != $url && !in_array($post->post_status, array('draft', 'pending', 'auto-draft'))) {

        // get country terms
        $terms = wp_get_object_terms($post->ID, 'country');

        // country
        if (strpos($url, '%country%') !== FALSE) {
            if (!is_wp_error($terms) && !empty($terms) && is_object($terms[0])) {
                $country = urlencode($terms[0]->slug);
                $url = str_replace('%country%', $country, $url);
            }
        }

        // post names
        $postnames = array('%company_postname%', '%product_postname%', '%postname%');
        foreach ($postnames as $postname) {
            $postname = $post->post_name;
            $url = str_replace($postnames, $postname, $url);
        }

        return $url;
    }

    return $url;
}

Update 3

When permalinks set to Plain www.example.com/?p=123, all posts, pages and custom posts are loading fine.

Update 4

I have observed that posts and pages are not using either single.php or page.php template. It is using index.php. Whereas, I have not attached any templates to these pages or posts.

Update 5 - resolved

It was due the 'rewrite' => array('slug' => '/', 'with_front' => FALSE) in the country custom taxonomy. Without this rewrite now the pages and posts are fine.

Upvotes: 6

Views: 798

Answers (1)

Moishy
Moishy

Reputation: 3648

You can use the post_type_link hook.

Add your custom post type and taxonomy with your custom rewrite:

function company_post_type() {
    
    $labels = array(
        'name' => _x('Company', 'Post Type General Name', 'text'),
    );
    
    $args = array(
        'labels' => $labels,
        'show_ui' => true,
        'public' => true,
        'publicly_queryable' => true,
        'supports' => array('title', 'editor', 'custom-fields'),
        'taxonomies' => array('country'),
        'query_var' => true,
        'rewrite' => array( 'slug' => '%country%', 'with_front' => false ),
    );
    
    register_post_type('company', $args);
    
    
    $tax_args = array(
        'hierarchical'      => true,
        'public'            => true,
        'show_ui'           => true,
        'show_admin_column' => true,
        'query_var'         => true,
        'show_in_rest'      => true,
    );

    register_taxonomy( 'country', 'company', $tax_args );

}
    
add_action('init', 'company_post_type', 0);

then we run a replace on the permalink via the hook:

function replace_post_link( $post_link, $id = 0 ){
    $post = get_post($id);
    $post_type = get_post_type( $id );
    if ( is_object( $post ) && $post_type == 'company'){
        
        $cat = 'country';
        
        $terms = wp_get_object_terms( $post->ID, $cat );
        if( $terms && !is_wp_error($terms) ){
            return str_replace( '%country%' , $terms[0]->slug , $post_link );
        }
    }
    return $post_link;  
}
add_filter( 'post_type_link', 'replace_post_link', 1, 3 );

UPDATE:

There seems to be a quirk with wordpress when using this syntax for your rewrite so you will need to preface the term with a front.

'rewrite' => array( 'slug' => 'country/%country%', 'with_front' => false )

and in the replace post link:

return str_replace( 'country/%country%', $terms[0]->slug , $post_link );

Then your URL will be:

country/%country%/%company_postname%

make sure to flush your rewrite rules when you are done by going to: Settings > Permalinks and clicking 'save changes'

Upvotes: 1

Related Questions