I have a custom post type products
and a custom taxonomy 'Product Categories' with the slug products
.
My goal: I'm trying to create a URL structure like so:
Product Post Type Archive: products/
Product Top-level Category Archives: products/product-category
Product Category Archives: products/product-category/product-sub-category
Product Page: products/product-category/product-sub-category/product-page
The problem:
Product pages seem to only want to use actual categories. So URL structure is looking something like products/uncategorized/product-page
. Category archive pages won't maintain the cpt base. So they turn out something like category/sub-category
.
What I've tried: Innumerous google searches, quite a few snippets (the ones I remember I'll include below), a few custom functions, and a few plugins. No avail.
I have the following code.
add_action( 'init', 'products_cpt', 0);
add_action( 'init', 'register_taxonomies', 0 );
//A custom post type for all products
function products_cpt(){
$labels = array(
'name' => _x('Products', 'Post Type General Name'),
'singular_name' => _x('Product', 'Post Type Singluar Name'),
'menu_name' => __('Products'),
'parent_item_colon' => __('Parent Product'),
'all_items' => __('All Products'),
'view_item' => __('View Product'),
'add_new_item' => __('Add New Product'),
'add_new' => __('Add New'),
'edit_item' => __('Edit Product'),
'update_item' => __('Update Product'),
'search_items' => __('Search Products'),
'not_found' => __('Not Found'),
'not_found_in_trash' => __('Not Found in Trash')
);
$supports = array(
'title',
'editor',
'excerpt',
'thumbnail',
'custom-fields',
'revisions'
);
$args = array(
'labels' => $labels,
'hierarchical' => true,
'public' => true,
'exclude_from_search' => false,
'show_in_admin_bar' => true,
'show_in_nav_menus' => true,
'publicly_queryable' => true,
'query_var' => true,
'taxonomies' => array( 'chemicals' ),
'supports' => $supports,
'has_archive' => 'products'
);
register_post_type('products', $args);
}
function register_taxonomies() {
$taxonomies = array(
'products' => array(
'Product',
'Products'
),
);
foreach($taxonomies as $slug => $name){
create_product_taxonomy($slug,$name[0],$name[1]);
}
}
function create_product_taxonomy($slug, $singular, $plural) {
$labels = array(
'name' => _x( $singular.' Categories', 'Taxonomy General Name', 'text_domain' ),
'singular_name' => _x( $singular.' Category', 'Taxonomy Singular Name', 'text_domain' ),
'menu_name' => __( $singular.' Categories', 'text_domain' ),
'all_items' => __( 'All '.$singular.' Categories', 'text_domain' ),
'parent_item' => __( 'Parent '.$singular.' Category', 'text_domain' ),
'parent_item_colon' => __( 'Parent '.$singular.' Category:', 'text_domain' ),
'new_item_name' => __( 'New '.$singular.' Category Name', 'text_domain' ),
'add_new_item' => __( 'Add New '.$singular.' Category', 'text_domain' ),
'edit_item' => __( 'Edit '.$singular.' Category', 'text_domain' ),
'update_item' => __( 'Update '.$singular.' Category', 'text_domain' ),
'view_item' => __( 'View '.$singular.' Category', 'text_domain' ),
'separate_items_with_commas' => __( 'Separate '.$singular.' Categories with commas', 'text_domain' ),
'add_or_remove_items' => __( 'Add or remove '.$singular.' Categories', 'text_domain' ),
'choose_from_most_used' => __( 'Choose from the most used '.$singular.' Categories', 'text_domain' ),
'popular_items' => __( 'Popular '.$singular.' Categories', 'text_domain' ),
'search_items' => __( 'Search '.$singular.' Categories', 'text_domain' ),
'not_found' => __( 'Not Found', 'text_domain' ),
'no_terms' => __( 'No '.$singular.' Categories', 'text_domain' ),
'items_list' => __( $singular.' Categories list', 'text_domain' ),
'items_list_navigation' => __( $singular.' Categories list navigation', 'text_domain' ),
);
$args = array(
'labels' => $labels,
'hierarchical' => true,
'public' => true,
'show_ui' => true,
'show_admin_column' => true,
'show_in_nav_menus' => true,
'show_tagcloud' => true,
'has_archive' => $plural,
'rewrite' => array(
'slug' => 'products',
'with_front' => true,
'hierarchical' => true
)
);
register_taxonomy( $slug, 'products', $args );
}
First things first, I set the permalinks setting to the following:
Next, I tried adding the following code, however it only worked for product pages. Product Category Archives still 404'd.
add_filter( 'post_type_link', 'products_post_link', 1, 3 );
function products_post_link( $post_link, $id = 0 ){
$post = get_post($id);
if ( is_object( $post ) ){
$terms = wp_get_object_terms( $post->ID, 'products_category' );
$slug_url = '';
$last_id = 0;
if( $terms ){
foreach($terms as $term) {
if ($term === reset($terms)){
foreach($terms as $termInner){
if($termInner->term_id == 0){
$slug_url .= $termInner->slug.'/';
}
}
}elseif ($term === end($terms)){
foreach($terms as $termInner){
if($termInner->parent == $last_id){
$slug_url .= $termInner->slug;
$last_id = $termInner->term_id;
}
}
}else{
foreach($terms as $termInner){
if($termInner->parent == $last_id){
$slug_url .= $termInner->slug.'/';
$last_id = $termInner->term_id;
}
}
}
}
return str_replace( '%category%' , $slug_url , $post_link );
}
}
return $post_link;
}
And this to the CPT init function:
'rewrite' => array(
'slug' => 'products/%category%',
'with_front' => false,
'hierarchical' => true,
),
I also tried the following, don't remember what happened but I remember it didn't work:
add_action('init', 'custom_resource_rewrite_rules');
function custom_resource_rewrite_rules() {
add_rewrite_rule('products/([A-Za-z0-9\-\_]+)/?', '$matches[1]', 'top');
}
I also tried playing with the term_link
filter. No bueno.
Lastly, I tried the following Plugins, also no luck.
Does anyone have a solution to this? I'm pulling my hair out.
products/product-category/product-page
?