I am trying to achieve the following URL structure:

  • website.com/services/design/
  • website.com/services/design/branding/
  • website.com/services/development/
  • website.com/services/development/front-end-development/


  • /services/ is the channel index
  • /services/category/ is a category for this channel
  • /services/category/entry/ is a channel entry

And just to clarify, /services/entry/ would not work, the /category/ would be required to view an /entry/.

Has anyone used a similar setup before or know how to?

Thanks in advance.

2 Answers 2


You need 3 templates(index, .landing, .detail) under services template group.


{if segment_3}
    {if segment_3 ~ "/^P\d+/"}
        {!-- Pagination state --}


{exp:channel:entries channel="services" 
    {if segment_2_category_id} category="{segment_2_category_id}" {/if}
    disable="category_fields|member_data|trackbacks|relationships" dynamic="no" limit="10" paginate="bottom"
        <a href="{category_url_title}/{url_title}"><h1>{title}</h1></a>


{exp:channel:entries channel="services" category="{segment_2_category_id}" disable="category_fields|member_data|pagination|trackbacks|relationships" dynamic="no" url_title="{segment_3}"}
    {if no_results}{redirect="404"}{/if}

You need Low Seg2Cat for getting the segment_2_category_id based on URL. First you should download from above link and install then go ahead with my suggested code.


I have something similar to what you describe running here - the URL heavy lifting is done via these segments:


where resources is the channel, case-studies the category, and case-study-xxx is the post.

I've also set it up so that all categories / posts in the resources channel (there are 19 in use - so resources/faqs etc.) use the same shared template. To do this I use Template Routes, the Layouts system, and Low's very handy seg2cat add-on.

It works like this:

  • I've created a template group for each channel / category combination - so for example there is one called resources-casestudies.group - each with a single index.html and post.html template in.
  • I've created two Template Routes for each channel / category combination that each point to the appropriate templates in the relevant template group. So there is a template route that points /resources/case-studies to the resources-casestudies.group/index.html template, and a second that points /resources/case-studies/{post:alpha_dash} to the `resources-casestudies.group/post.html' template. For the second route you need to tick the 'segments required' flag.
  • The two templates in each channel-category template group each simply contain a single layout variable pointing to one of two common / shared templates - vis resources-casestudies.group/index.html contains simply one line - {layout="shared_templates/_resources-cat-index"}, you can guess the one for the post template...

The shared templates work like this:

  • The index template uses Low's seg2cat to get information about the category (i.e. so we can list all the relevant resources in the category). So most of the information comes from the category definition (I've added some fields to capture extra stuff) driven by this call: {exp:channel:categories style="linear" show="{segment_2_category_id}"} - the seg2cat allows you to use the category url_title in the URL rather than a category number, but remember to do this you need to set the Category URL setting to title which you do in the "URL and Path Settings" area of the System Settings CP. I actually get the rest of the listing information (i.e. the list of posts in this category) via a Low Reorder call to a reorder set with the same name as the category url_title (so {exp:low_reorder:entries set="{segment_2}"}, as this allows me to order the category entries in whatever sequence I want, but there are other ways to get this information too.
  • The post template uses a simple channel:entries call to get the information relating to the relevant posting - vis: {exp:channel:entries channel="resources" url_title="{segment_3}" dynamic="no"} - NB - dynamic="no" is important here as you don't want EE trying to work out what to show you from the URL...


It should be possible to write a super-generic pair of Template Route entries that route all the index and post calls for any resource/category pair to the same two shared templates. Something like:

/resources/{cat:alpha_dash}/ pointing to the shared index template


/resources/{cat:alpha_dash}/{post:alpha_dash} pointing to the shared post template

While this approach is consistent with the documentation, and worked at one time, turns out the Template Routes system got broken around about the time EE3 came out (so these generic routes don't work on late EE2 systems or EE3). I spent a long time (and burnt my 'free' Ellis support request) on trying to find a fix, only to be told by Ellis that fixing it would break something else in Template Routes, and so no fix was due in EE3 at least. To be honest I've not tried to EE4 to see if it works again now. It might do: in the interim the indirect fix of creating one template group for each channel / category pair works on my system (as there are only 19 categories, and these change rarely) but would be impracticable for any system with many categories, or categories that change frequently.

FWIW there are (or were) also issues to be mindful of with how Template Routes processes pagination terms in routes (again not following the documentation): if you have many entries in a category you might want to paginate the output on the template routes pointing to the index template. Again this once worked just find, but also broke around the time EE3 came out. After much discussion, Ellis Labs eventually suggested alternative template routes that look like this:


For me, this does not work either, but maybe they do in Ellis Labs systems. If pagination is important to you and you have problems, try it. I never got it to work and in the end it was easier to simply disable pagination rather than fix it: again this may now work in EE4, but not had the time/motivation yet to try and find out.


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.