I've created a simple CPT named shop
which contains some shop items. After that I've added category
support to it which works fine ('taxonomies' => array( 'category' )
). Then I created template-shop.php
where I keep all my logic (I use template
because I have multilingual support via polylang
).
So lets say that currently my URL looks like: www.foo/shop
And now I want to "filter" my categories and I currently use the URL params to filter:
<?php
$current_url = strtok($_SERVER["REQUEST_URI"], '?');
// if param category exists filter by it
if (isset($_GET['category'])) {
$category = $_GET['category'];
$args = array (
'post_type' => array( 'shop' ),
'order' => 'ASC',
'posts_per_page' => -1,
'category_name' => $category
);
} else {
$args = array (
'post_type' => array( 'shop' ),
'order' => 'ASC',
'posts_per_page' => -1
);
}
$shop = new WP_Query( $args );
?>
And it works fine
www.foo/shop/?category=bar
www.foo/shop/?category=baz
etc.
My question is - can I somehow "update" the logic so the URLs looks better? I'd wanted to for it to be:
www.foo/shop/category/bar
www.foo/shop/category/baz
etc.
Or something like that.
I've created a simple CPT named shop
which contains some shop items. After that I've added category
support to it which works fine ('taxonomies' => array( 'category' )
). Then I created template-shop.php
where I keep all my logic (I use template
because I have multilingual support via polylang
).
So lets say that currently my URL looks like: www.foo/shop
And now I want to "filter" my categories and I currently use the URL params to filter:
<?php
$current_url = strtok($_SERVER["REQUEST_URI"], '?');
// if param category exists filter by it
if (isset($_GET['category'])) {
$category = $_GET['category'];
$args = array (
'post_type' => array( 'shop' ),
'order' => 'ASC',
'posts_per_page' => -1,
'category_name' => $category
);
} else {
$args = array (
'post_type' => array( 'shop' ),
'order' => 'ASC',
'posts_per_page' => -1
);
}
$shop = new WP_Query( $args );
?>
And it works fine
www.foo/shop/?category=bar
www.foo/shop/?category=baz
etc.
My question is - can I somehow "update" the logic so the URLs looks better? I'd wanted to for it to be:
www.foo/shop/category/bar
www.foo/shop/category/baz
etc.
Or something like that.
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/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 rewrite example/shop/category/<category slug>
to example/?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_posts
hook 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 custom WP_Query
query (i.e. $shop = new WP_Query
).
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 rewrite example/shop/category/<category slug>
to example/?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_vars
hook to add the shop_cat
variable to the public WordPress query vars:
add_filter( 'query_vars', function ( $vars ) {
$vars[] = 'shop_cat';
return $vars;
} );
In template-shop.php
or wherever necessary, just call get_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.