Matching Slugs Across Multiple URL Segments
This post will discuss matching slugs that span multiple URL segments on both standard Perch and Perch Runway.
How is this useful?
It is common to structure a section of a website (particular e-commerce websites) to display categorised items with URLs like so:
/shop
/shop/footwear
/shop/footwear/running
So you need a way to:
- allow an arbitrary number of URL segments to come after a specified path e.g.
/shop
- be able to get the values of these URL segment so you can handle things programmatically
Standard Perch
Given that standard Perch does not have a front controller, we will add a .htaccess
rewrite rule. I will assume you already have a /shop.php
page.
Allow everything
The simple way is to allow everything after the /shop
:
RewriteEngine On
RewriteRule ^shop/(.*)$ /shop.php?path=$1 [L]
The above allows everything after /shop
, not just slugs. So all of the below is supported:
/shop/slug-segment
/shop/slug-segment/another-slug
/shop/slug-segment/another-slug/slug-3
/shop/slug,segment
/shop/slug.segm,,,,,e.html/another-slug.php
/shop/slug-segment/another...,slug/.json
Allow slugs only
If you want to strictly support URL segments that matches a slug format including Latin characters, hyphens and numbers, you can use this rewrite rule instead:
RewriteEngine On
RewriteRule ^shop/([a-z0-9\-%\+]+(\/[a-z0-9\-%\+]+)*)/?$ /shop.php?path=$1 [L]
The above matches one or more slug segments like the below (with and without a trailing slash):
/shop/slug-segment
/shop/slug-segment/another-slug
/shop/slug-segment/another-slug/slug-3
But it will not match URLs like:
/shop/slug,segment
/shop/slug.segm,,,,,e.html/another-slug.php
/shop/slug-segment/another...,slug/.json
Perch Runway
For Perch Runway, we will use its routing features instead of writing .htaccess
rules.
Master Page
I will assume you already have a master page for /shop
. This could be perch/templates/pages/shop.php
.
Master Page vs Editable Content Page
You can add routes directly to a master page or to an editable content page. To learn about the difference read Master Page vs Editable Content Page
To add routes to a master page:
- navigate to Pages > Master Pages
- Select a master page
- Add the URL pattern you want
To add routes to an editable content page:
- navigate to Pages
- Select an existing page or create a new one
- Go to the Location tab
- Add the URL pattern you want
The URL pattern
Perch Runway comes with built-in tokens you can use for your URL patterns.
Allow everything
The easy was is to add a URL pattern that matches everything after /shop
using the *
token:
shop/[*:path]
Allow slugs only: slug token
If you need to strictly support segments with slugs, you have two option. The first is to add multiple URL patterns using the built-in slug
token. With this option you need to know beforehand how many levels you want to support.
shop/[slug:path]
shop/[slug/slug:path]
shop/[slug/slug/slug:path]
Allow slugs only: custom token
Alternatively, you can add a custom token to your Runway config file perch/config/runway.php
:
'routing_tokens' => [
'path' => '[a-z0-9\-%\+]+(\/[a-z0-9\-%\+]+)*$',
]
With the custom token in place, you can use a single URL pattern:
shop/[path:path]
Using the dyanmic path
Now that the /shop
page supports an arbitrary number of URL segment, we need to read the value in order to handle things programmatically. Both the standard Perch .htaccess
rewrite rule and the Perch Runway URL pattern enable us to get the value with perch_get('path')
:
$path = perch_get('path');
If you are unsure why this is, you can read:
- perch_get() documentation
- The article Utility function: perch_get()
- Runway’s Named Segments documentaion
How you proceed from here depends on your content structure, what each URL segment represents and how you want things to behave. Being comfortable with PHP and Perch will help a lot. Here is some tips to get you started:
// can be a string like `footwear/running`
$path = perch_get('path');
If you have a category set called products
which contains the category products/footwear/running/
, you can build the category path like so:
$category_path = 'products/' . $path . '/';
Following our example, perch_get('path')
will return false
if you are on /shop
. So don’t assume you always have a path:
$path = perch_get('path');
if($path) {
// you have a path
}
You can break the path into parts and assign the values to an array:
$path_parts = explode('/', $path);
You can get the last segment from the array (may represent a category or product slug depending on your structure):
$last_slug = end($path_parts);
Given you are handling things programmatically, you will need to programmatically respond with a 404 where appropriate. And if you need to list sub-categories without their parent category, read Listing Sub-Categories.