Option 1: Enable the post type archives and use a post type archive template.
-
Enable the archives; e.g. when registering the post type using
register_post_type():register_post_type( 'shop', [ 'has_archive' => 'shop', // the archives are accessible at example.com/shop // ... ] ); -
Then create a custom archive template just for that post type; i.e.
archive-shop.php. -
And you can use
add_rewrite_rule()to rewriteexample.com/shop/category/<category slug>toexample.com/?category_name=<category slug>&post_type=shop:// This should be called in `init`. add_rewrite_rule( '^shop/category/([^/]+)/?$', 'index.php?category_name=$matches[1]&post_type=shop', 'top' ); -
You’d need to use the
pre_get_postshook to filter the main WordPress query (since I could see you’re using some custom query vars/values). But in the archive template, you wouldn’t need the customWP_Queryquery (i.e.$shop = new WP_Query).
Option 2: If you need to use a custom Page which displays posts in the custom post type.
And by “custom Page”, I’m referring to a post having the type page. Also, the advantage of using this option is that you don’t need to enable the default post type archives.
-
So firstly, get the ID of the page which is using the custom template (
template-shop.php). -
You’d use
add_rewrite_rule()to rewriteexample.com/shop/category/<category slug>toexample.com/?shop_cat=<category slug>&page_id=<page ID>— “shop_cat” can be changed to other non-reserved name, but you’ll also need to change the name in step #3 & #4 below:// This should be called in `init`. add_rewrite_rule( '^shop/category/([^/]+)/?$', // Make sure to use the correct Page ID. 'index.php?shop_cat=$matches[1]&page_id=2', 'top' ); -
You’d use the
query_varshook to add theshop_catvariable to the public WordPress query vars:add_filter( 'query_vars', function ( $vars ) { $vars[] = 'shop_cat'; return $vars; } ); -
In
template-shop.phpor wherever necessary, just callget_query_var( 'shop_cat' )to retrieve the category slug from the URL:$args = array( 'post_type' => array( 'shop' ), 'order' => 'ASC', 'posts_per_page' => -1, ); if ( $category = get_query_var( 'shop_cat' ) ) { $args['category_name'] = $category; } $shop = new WP_Query( $args );
Last but not least, there are other variations to both the above options, but the ones I provided should help you get started.