Thread tagged as: Runway

404 Routing in Runway for a Catalogue

Firstly I should say I have somewhat limited experience with routing, and it may be that I'm doing something fundamentally incorrect.

What I'm trying to do:

  • Display a multi-levelled catalogue, e.g.
  • Use a different template, depending on the 'level,' e.g. a subcategory page will have a different template to category
  • Display a 404 if the category does not exist

The problem

Everything works fine apart from I'm not really sure how to get a 404 to display. The issue is that if you go to a URL that doesn't exist, the page attempts to render but with nothing showing (instead of a 404), so if you go to something like you'll see the header of the page, but the content is blank because nothing was found in the routing.

How can I display a 404 if the category is not found? I've thought of maybe outputting all the categories in a PHP array and checking against that but not sure if it's the most performant way.

Here is a stripped down version of my code so you can see my logic:

<?php if (perch_get('level4')) {
        /* GROUP LEVEL 4
        e.g. /catalogue/carpet-tiles/andover/009
        <?php perch_collection('Catalogue Samples', [
            'sort'      => 'name', 
            'filter'    => 'name',
            'match'     => 'eq',
            'value'     => perch_get('level4'),
            'category'  => 'catalogue/' . perch_get('level2') . '/' . perch_get('level3'),
            'template'  => 'catalogue_samples/_sample_detail.html'
        ]); ?>
<?php } elseif (perch_get('level3')) {
        /* GROUP LEVEL 3
        e.g. /catalogue/carpet-tiles/andover
        <?php perch_collection('Catalogue Samples', [
            'sort'      => 'name',
            'category'  => 'catalogue/' . perch_get('level2') . '/' . perch_get('level3') . '/',
            'template'  => 'catalogue_samples/_sample_grid.html'
        ]); ?>
<?php } elseif (perch_get('level2')) {
        /* GROUP LEVEL 2
        e.g. /catalogue/carpet-tiles
        <?php perch_categories([
            'set'       => 'catalogue',
            'template'  => 'catalogue/_2nd_level_categories.html',
            'filter'    => 'catPath',
            'match'     => 'regex',
            'value'     => 'catalogue/' . perch_get('level2') . '/'
        ]); ?>
<?php } else {
        /* GROUP LEVEL 1
        e.g. /catalogue
        <?php perch_categories([
            'set' => 'catalogue',
            'template' => 'catalogue/_top_level_categories.html'
        ]); ?>
<?php } ?>

My routing looks something like this:

Jay George

Jay George 2 points

  • 3 years ago
Hussein Al Hammad

Hussein Al Hammad 105 points
Registered Developer

Hi Jay

Something like this may work for your set up:

if(perch_get('level2')) $catPath = 'catalogue/'.perch_get('level2').'/';
if(perch_get('level3')) $catPath .= perch_get('level3').'/';
if(perch_get('level4')) $catPath .= perch_get('level4').'/';

$cat = perch_category($catPath, [
  'skip-template' => true,

if($cat) {
  // you have a real category
} else {

That's great, my actual solution was very slightly different but this was a perfect starting point!

FYI for anyone visiting in future, initially the PerchSystem::redirect('/404'); was not working for me. I realised this was because I had <?php if (!defined('PERCH_RUNWAY')) include($_SERVER['DOCUMENT_ROOT'].'/perch/runtime.php'); ?> at the top of the master page, which needed to be removed.