Debugging dynamic route pages

Hello community! I was wondering if there’s any way to debug pages accessed via dynamic routes? I’ve created a shop controller and a shop template and debugging is working well on my shop/ route. But for shop/{sku} or shop/{category} no exceptions are thrown and I get redirected to a 404 (in case an error occurs). If there are no errors the dynamic routes are working as expected (and alle necessary data is handled and passed by the controller) but debugging is a bit difficult this way. Any suggestions? Many thanks in advance!

Hi @salat. The description of your problem is a bit thin.

  • How did you define the route for shop/{sku} and shop/{category}?
  • What code does this route call, and what does it look like?
  • What do you mean by “in case an error occurs”?

Hejhej! Sorry for giving a little less information here.
That’s the route definition:

[
              'pattern' => 'shop/(:all)',
              'language' => '*',
              'action' => function ($locale, $param) {
                  $data = [
                    'param' => $param
                  ];

                  return page('shop')->render($data);
              }
          ],

My shop controller is just doing some fetching and filtering logic based on the data passed to the controller. The data then gets assigned to some variables (e.g. $product). But I realised that the controller isn’t the problem (it’s working fine). See my shop template:

<?php snippet('layout', slots: true) ?>


<?php slot('header') ?>
    <?php snippet('header', slots: true) ?>
        <?php slot('nav') ?>
            <?php snippet('nav') ?>
        <?php endslot() ?>
        <?php slot('hero') ?>
            <?php snippet('hero') ?>
        <?php endslot() ?>
    <?php endsnippet() ?>
<?php endslot() ?>

<?php slot('main') ?>
    <?php snippet('main', slots: true) ?>
        <?php slot('mainContent') ?>

        <?php if ($product): ?>
            <div>
                <?= $product?->product?->detail?->title ?>
            </div>
        <?php endif ?>
        
        <?php endslot() ?>
    <?php endsnippet() ?>
<?php endslot() ?>


If I try to render a property that doesn’t exist in $product, for example $product->test, then I just get an 404 “Page doesn’t exist” (that’s what I meant with error). Usually the standard behaviour is getting an exception and debugging info. If I add <?php throw new Exception('error') ?> in the snippet I get a 404 as well. But on the base shop/ route (instead of shop/{sku} or shop/{category}) I get an Exception.
I hope that helps clarifying the issue.

What are you calling here, field? You cannot access properties like this in Kirby.

You described two contradicting scenarios for the kind of error you’re seeing.

This would mean that when you request /shop/thing-that-doesnt-work:

  1. The browser fires a GET request for /shop/thing-that-doesnt-work.
  2. The server replies with a 301 or 302 status, and the response contains a Location header pointing to a different path.
  3. The browser then fires a GET request for that different path.
  4. And the server replies to that second request with a 404 status, and the HTML content of a page that says “Page doesn’t exist”.

This would mean that when you request /shop/thing-that-doesnt-work:

  1. The browser fires a GET request for /shop/thing-that-doesnt-work.
  2. The server replies to that request with a 404 status, and the HTML content of a page that says “Page doesn’t exist”.

Can you check in your browser devtools (in the Network panel, with the “Preserve log” option checked) which behavior you’re getting?

Overall, without access to more of the project’s code and configuration, it’s hard to tease out whatever might be happening here.

A few things I would check here:

  1. Use browser developer tools to check exactly what HTTP responses I’m getting. Redirect or no redirect? 404 response or 200 response that happens to show an error message?

  2. Check code that tries to render a page or snippet with some queried content, and which just assumes that the content will be found. What happens when said content is not found for some reason? Note that some Kirby methods can return PHP objects like a Page or Field which are basically empty of actual content (it’s not a real page or a real page field), so usually you need to check things like if ($page->some_field()->isNotEmpty()) rather than if ($page->some_field()), because the second one will always be true even if the field does not exist.

  3. Check Kirby’s configuration related to showing errors, in particular:

In one of your messages you wrote that if you purposefully throw an Exception in your code, you end up seeing your custom “Not found” page. Which sounds like:

  • You have set 'debug' => false in your config, otherwise you would see PHP errors with a trace. This is not ideal if you’re trying to debug.
  • You may have set the 'fatal' option to the slug of your “Not found” page, instead of creating a dedicated page for server errors?
  1. After all that, if you still need more precise debugging, you could use a PHP debugger with breakpoints like the one built into PhpStorm or offered by some VSCode extensions, or XDebug. Or you could debug systematically with print statements by starting at the root of where your logic is executed (here, that would be the function for your custom route, then the function for your controller, then your template), and go through your code top to bottom and add var_dump() statements to check the values. One technique I often use for quick-and-dirty debugging with PHP is to add exit to stop the PHP process completely (e.g. writing var_dump($some_value); exit;) because if you let the PHP process continue then your own code or Kirby’s logic might do something like clear the text buffer (which would remove the output from your var_dump() call) or send a HTTP redirect response (which might not clear the buffer but you’ll get redirected to a different page with a different HTML output, so it’s easy to miss the output from your print statements in the first response).

Hope this general guidance helps!