I have a Structure - Products - that contains multiple products, and each product contains different sub pages (details, pricing, etc).

One section of the Structure is Details which is under each product.

The url structure is /products/{product}/details where {product} is the various products in the Structure.

Details entry has an Entries field in it called Details that contains entries from a Channel that I'm essentially using as a data silo called Product Details that stores details about the various products.

This all works fine and if I load an entry at /products/x-product/details I have access to the Details associated with the Details entry as expected.

As part of this particular template, I want to be able to have a fourth segment like:

/products/x-product/details/specific-detail -- where specific-detail is the slug of a specific channel detail

I've setup a route like so in config/routes.php:

'products/<entrySlug:{slug}>/details/<detailSlug>' => ['template' => 'products/_types/details']

And it loads the the details template fine...however... the details template extends a main layout that is used across the entire site, and that layout uses the entry variable which it is saying doesn't exist.

I need the Details entry var from the Structure to load as the entry, and for the final route (detailSlug) to be passed through unchanged/ignored to the details template so that I can just grab it via craft.app.request.getSegment() function and process/use it accordingly inside the template.

I could obviously do this with a url param, but I want to be able to do it with an actual segment for various reasons (one being SEO).

UPDATE: OK, so I think I'm getting close -- I can maybe reset the "entry" variable to the Details entry -- but is there a way to grab a specific child of an entry in a Structure if all I have is the slug of the Parent? So like set entry = craft.entries.section('products').slug("product-x").child("details") ?

I know that specifc query won't work...but is there something like that? Consider the structure looks like:

- Product 1
  -- Details
  -- Pricing
  -- etc
- Product 2
  -- Details
  -- Pricing
  -- etc

UPDATE 2: I've figured out a way to grab the specific entry I need and reset the entry var -- but some of the fields are null -- I did a dd on it, and I can see it's the correct object (correct ID and all) -- but my matrix field and entries fields are null. My other custom fields (text fields) are there and have the correct info in them.

This is the queries I ended up with:

{% set parentProduct = craft.entries.section('products').level(2).slug(productSegment).one() %}
{% set entry = craft.entries.section('products').level(3).descendantOf(parentProduct).slug("details").one() %}
  • 1
    Noting re: null values when dumping an Entry object—this is the expected behavior, and not a consequence of your approach. I believe it's just a limitation of the Query classes (the initial value for Relation and Matrix fields) and how PHP represents them as strings when debugging. Calling entry.flexibleContent.all(), will get the data you're looking for! Feb 12, 2022 at 18:38
  • Also worth noting that you can do a generic sort of "protection" routine in your layout so that when entry is not defined on a particular template (like the 404 page), it will just exit silently—this could be at output time (<meta name="description" content="{{ entry.shortDescription ?? 'My default description!' }}">), or guarding an entire block of output ({% if entry is defined %} ... {% endif %}). Feb 12, 2022 at 18:41

1 Answer 1


So this is REAL ugly I think...and perhaps there's a better way to do it, but this is what I ended up with. Again, I've only been working with craft for a few weeks, so please tell me if there is a better way.

{% set productSegment = craft.app.request.getSegment(2) %}
{% set productDetailSegment = craft.app.request.getSegment(4)  %}

{% if productDetailSegment is not null %}
    {% set parentProduct = craft.entries.section('products').level(2).slug(productSegment).one() %}
    {% set entry = craft.entries.section('products').level(3).descendantOf(parentProduct).slug("details").with(['flexibleContent','productDetails']).one() %}
{% endif %}

The with function was the key to getting my missing Matrix and Entries fields.

This successfully resets my entry var so that it exists in the correct context.

Again, if there's a better way to do this with routing (as I said initially -- someway of ignoring the final segment without losing the entry var -- PLEASE point me in the right direction, because this seems really kludgy).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.