0

I have a problem with nested permalink. I have a structure of urls like that:

Catalog -> Category -> Product

My urls are:

  • www.domain.com/catalogs (for archive catalog)
  • www.domain.com/catalogs/%catalog% (for single catalog page with the list of categories)
  • www.domain.com/catalogs/%catalog%/%category% (for single category page with the list of products)
  • www.domain.com/catalogs/%catalog%/%category%/%product% (for single product page)

In the WP Backoffice and Frontoffice all url are correct, the only problem that I have is when I visit the product page, for example:

www.domain.com/catalogs/catalog-001/category-001/product-001

There I receive the 404 error. My code is the following:

add_action( 'init', 'ab_create_catalog_taxonomy' );

function ab_create_catalog_taxonomy() {
    $labels = array(
        'name'              => _x( 'Catalogs', 'taxonomy general name', 'autoblok' ),
        'singular_name'     => _x( 'Catalog', 'taxonomy singular name', 'autoblok' ),
        'search_items'      => __( 'Search Catalogs', 'autoblok' ),
        'all_items'         => __( 'All Catalogs', 'autoblok' ),
        'parent_item'       => __( 'Parent Catalog', 'autoblok' ),
        'parent_item_colon' => __( 'Parent Catalog:', 'autoblok' ),
        'edit_item'         => __( 'Edit Catalog', 'autoblok' ),
        'update_item'       => __( 'Update Catalog', 'autoblok' ),
        'add_new_item'      => __( 'Add New Catalog', 'autoblok' ),
        'new_item_name'     => __( 'New Catalog Name', 'autoblok' ),
        'menu_name'         => __( 'Catalog', 'autoblok' ),
    );

    $args = array(
        'labels'            => $labels,
        'hierarchical'      => false,
        'public'            => true,
        'show_ui'           => true,
        'show_admin_column' => true,
        'show_in_nav_menus' => true,
        'show_tagcloud'     => false,
        'query_var'         => true,
        'rewrite'           => array(
            'slug' => 'catalogs',
        ),
    );

    register_taxonomy( 'catalog', array( 'category', 'product' ), $args );
}

add_action( 'init', 'ab_create_category_post_type' );

function ab_create_category_post_type() {
    $labels = array(
        'name'          => _x( 'Categories', 'Post Type General Name', 'autoblok' ),
        'singular_name' => _x( 'Category', 'Post Type Singular Name', 'autoblok' ),
        'add_new'       => __( 'Add new', 'autoblok' ),
        'add_new_item'  => __( 'Add new category', 'autoblok' ),
        'edit_item'     => __( 'Edit category', 'autoblok' ),
        'new_item'      => __( 'New category', 'autoblok' ),
        'view_item'     => __( 'View category', 'autoblok' ),
        'view_items'    => __( 'View categories', 'autoblok' ),
        'search_items'  => __( 'Search category', 'autoblok' ),
        'all_items'     => __( 'All categories', 'autoblok' )
    );

    $args = array(
        'label'               => __( 'categories', 'autoblok' ),
        'description'         => __( 'Category List', 'autoblok' ),
        'labels'              => $labels,
        'supports'            => array(
            'title',
            'custom-fields'
        ),
        'hierarchical'        => true,
        'public'              => true,
        'can_export'          => true,
        'has_archive'         => true,
        'menu_position'       => 20,
        'exclude_from_search' => false,
        'capability_type'     => 'page',
        'rewrite'             => array(
            'slug' => __( 'catalogs/%catalog%', 'autoblok' ),
        ),
    );

    register_post_type( 'category', $args );
}

add_action( 'init', 'ab_create_product_post_type' );

function ab_create_product_post_type() {
    $labels = array(
        'name'          => _x( 'Products', 'Post Type General Name', 'autoblok' ),
        'singular_name' => _x( 'Product', 'Post Type Singular Name', 'autoblok' ),
        'add_new'       => __( 'Add new', 'autoblok' ),
        'add_new_item'  => __( 'Add new product', 'autoblok' ),
        'edit_item'     => __( 'Edit product', 'autoblok' ),
        'new_item'      => __( 'New product', 'autoblok' ),
        'view_item'     => __( 'View product', 'autoblok' ),
        'view_items'    => __( 'View products', 'autoblok' ),
        'search_items'  => __( 'Search product', 'autoblok' ),
        'all_items'     => __( 'All products', 'autoblok' )
    );

    $args = array(
        'label'               => __( 'products', 'autoblok' ),
        'description'         => __( 'Product List', 'autoblok' ),
        'labels'              => $labels,
        'supports'            => array(
            'title',
            'custom-fields'
        ),
        'hierarchical'        => false,
        'public'              => true,
        'can_export'          => true,
        'has_archive'         => true,
        'menu_position'       => 20,
        'exclude_from_search' => false,
        'capability_type'     => 'page',
        'rewrite'             => array(
            'slug' => __( 'catalogs/%catalog%/%category%', 'autoblok' ),
        ),
    );

    register_post_type( 'product', $args );
}

add_filter( 'post_type_link', 'ab_category_post_link', 1, 3 );

// Rewrite Category Url
function ab_category_post_link( $post_link, $post ) {
    if ( is_object( $post ) && $post->post_type === 'category' ) {
        $terms = wp_get_object_terms( $post->ID, 'catalog' );

        if ( $terms ) {
            return str_replace( '%catalog%', $terms[0]->slug, $post_link );
        }
    }

    return $post_link;
}

add_action( 'add_meta_boxes', 'ab_product_meta_boxes' );

function ab_product_meta_boxes() {
    add_meta_box( 'product-parent', 'Category', 'ab_product_attributes_meta_box', 'product', 'side', 'high' );
}

function ab_product_attributes_meta_box( $post ) {
    $pages = wp_dropdown_pages( array(
        'post_type'        => 'category',
        'selected'         => $post->post_parent,
        'name'             => 'parent_id',
        'show_option_none' => __( '(no parent)' ),
        'sort_column'      => 'menu_order, post_title',
        'echo'             => 0
    ) );

    if ( ! empty( $pages ) ) {
        echo $pages;
    }
}

add_filter( 'post_type_link', 'ab_product_post_link', 10, 3 );

function ab_product_post_link( $post_link, $post ) {
    if ( is_object( $post ) && $post->post_type === 'product' ) {
        $parent      = $post->post_parent;
        $parent_post = get_post( $parent );
        $terms       = wp_get_post_terms( $post->ID, 'catalog' );

        if ( $terms ) {
            $post_link = str_replace( '%catalog%', $terms[0]->slug, $post_link );
        }

        $post_link = str_replace( '%category%', $parent_post->post_name, $post_link );
    }

    return $post_link;
}

Here my .htaccess:

# BEGIN WordPress
RewriteEngine On
RewriteBase /wordpress/
RewriteRule ^index\.php$ - [L]

# add a trailing slash to /wp-admin
RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]

RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]
RewriteRule . index.php [L]
# END WordPress

UPDATE

Here the image from "Rewrite Analyzer" plugin:

enter image description here

3
  • The HTAccess won't be of much use, either permalinks do or don't work at that level, so focus instead on debugging your rewrite rules. Load up a plugin such as Monkeyman Rewrite rule analyser and test to see which rewrite rule matches your URL. Chances are it's probably being interpreted as a taxonomy URL because of how those works, so ordering is probably the problem, but without debugging information it's super difficult to tell from this end
    – Tom J Nowell
    Commented Feb 15, 2019 at 18:44
  • @TomJNowell great tool! I posted the image with a test
    – Mintendo
    Commented Feb 15, 2019 at 19:45
  • That implies that your rewrite rule for your product page doesn't match the URL at all, you need to work on your regular expression
    – Tom J Nowell
    Commented Feb 15, 2019 at 23:28

1 Answer 1

0

I find a solution thank you to the plugin:

Monkeyman Rewrite Rule

With this plugin I find when the rule failed, then I corrected it with these lines of code:

add_action( 'init', 'ab_category_rewrite_rules' );

function ab_category_rewrite_rules() {
    add_rewrite_tag( '%category%', '([^/]+)', 'category=' );
    add_permastruct( 'category', '/catalogs/%catalog%/%category%', false );
    add_rewrite_rule( '^category/([^/]+)/([^/]+)/?$', 'index.php?category=$matches[2]', 'top' );
}

add_action( 'init', 'ab_product_rewrite_rules' );

function ab_product_rewrite_rules() {
    add_rewrite_tag( '%product%', '([^/]+)', 'product=' );
    add_permastruct( 'product', '/catalogs/%catalog%/%category%/%product%', false );
    add_rewrite_rule( '^product/([^/]+)/([^/]+)/?$', 'index.php?product=$matches[2]', 'top' );
}

I also removed the rewrite option config on my custom post type registration function (for category and product type).

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.