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:


So you need a way to:

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:



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):


But it will not match URLs like:


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:

  1. navigate to Pages > Master Pages
  2. Select a master page
  3. Add the URL pattern you want

To add routes to an editable content page:

  1. navigate to Pages
  2. Select an existing page or create a new one
  3. Go to the Location tab
  4. 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:


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.


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:


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:

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.