Introduction to Template Routes for ExpressionEngine

I’m in the process of developing a client site on EE 2.9 and had a situation come up where I suspected the new Template Routes feature might come in handy. Reading the documentation and experimenting with some code I wasn’t immediately able to get things working - but after a few emails between using the EllisLab tech support I have it up and running. I saw some posts from other folks a bit stumped by Template Routes so I thought I would post my steps here in hopes of helping others scale the learning curve.

 

Goal: Simple URLs and Templates
In a particular template group, not using the index template, I have a multi-entry template that displays a linked list of available jobs. The specifics of a particular job are displayed using another single entry template - but I wanted to not display the single-entry template name.

I also didn’t want a ‘combined’ template that reads URLs and uses conditionals to handle both multi-entry and single-entry display.

I want separate, single-mode templates loading at a clean URL structure.

ExpressionEngine Architecture
/careers/ template group
/careers/job-openings/ multi-entry template
/careers/job-detail/ single entry template

URLs
List of available jobs:

http://mysite.com/careers/job-openings 

A “traditional” EE URL for a single job page:

http://mysite.com/careers/job-detail/1st-shift-supervisor 

Our desired URL:

http://mysite.com/careers/job-openings/1st-shift-supervisor 


Starting Point
I started by coding two templates in the typical EE fashion. The code is below - I’m keeping it simple here to focus on Template Routes. Yes, there are ways to optimize for performance and error-check if there are no open jobs but let’s leave those issues aside for this example:


Multi-entry template: careers/job-openings

<h2>Open Jobs</h2>
<
ul>
{exp:channel:entries channel="open_jobs"}
    
<li><a href="{url_title_path='careers/job-detail'}">{title}</a></li>
{/exp:channel:entries}
</ul


Single-entry template: careers/job-detail

{exp:channel:entries channel="open_jobs" limit="1"}
    
<h2>{title}</h2>
    
{sc_page_content}
{
/exp:channel:entries} 


Steps Required
From here there are three basic things we need to do to achieve our goal:

  • Enable Template Routes
  • Create a Template Route
  • Update the single-entry channel:entries tag
  • Update the multi-entry linking code


Enable Template Routes
The first thing we need to do is make sure Template Routes are enabled. In the ExpressionEngine Control Panel navigate to Design > Template Manager > Global Template Preferences and look at the first option: Enable Template Routes.

Make sure this is set to Yes.


Create a Template Route
Navigate to Design > Template Manager > Template Route Manager and find the careers/job-detail template.

Here we will need to specify the URL structure that will cause EE to load this template. Some of the arguments you can use are in the EE Documentation but for our purposes we only need to worry about a typical entry url title. We’ll use the alpha-dash rule.

Now you need to make up a variable name. You will use this variable name back in the templates both as a linking variable and as a parameter for the channel:entries tag. For our example we’ll just use “job”.  Here is my template route assigned to the job-detail template:

/careers/job-openings/{job:alpha_dash} 

I also turned on the “require all segments” setting.


Update the single-entry channel:entries tag
Here is the updated job-detail template:

{exp:channel:entries channel="open_jobs" dynamic="no" url_title="{segment:job}"}
    
<h2>{title}</h2>
    
{sc_page_content}
{
/exp:channel:entries} 

I have made two changes:

  • I have turned off the dynamic property since I no longer want the channel:entries tag to look at the displayed URL.
  • I have told the channel:entries tag which entry to pull by setting the url_title parameter to the new variable we created when setting up the route.


Update the multi-entry linking code
In ‘traditional’ EE development when you code links from a multi-entry template to a single-entry template you have to use the right variable to feed the URL title of the channel entry to the single entry template. Typically you do this with a variable like url_title_path. 

With Template Routes we are working outside of the normal URL-driven approach in EE, so we need to replace our linking variable with a new routing variable. Here is the updated careers/job-openings template:

<h2>Open Jobs</h2>
<
ul>
{exp:channel:entries channel="open_jobs" dynamic="no"}
    
<li><a href="{route="careers/job-detail" job="{url_title}"}">{title}</a></li>
{/exp:channel:entries}
</ul

In addition to changing how the link to the single-entry page is created, I also turned off the dynamic property of the channel:entries tag.


Results
With these steps completed your multi-entry template should load a list of the open jobs with links in the following fashion:

http://yoursite.com/careers/job-openings/1st-shift-super 

Clicking through should load the jobs-detail template displaying the correct job information - but still at the above URL.

We’ve used a Template Route to “catch” a requested URL that matches a certain pattern and then directed that traffic to a specific template. The name of that specific template does not appear in the URL.


Benefits
I personally don’t like dual-purpose templates that read the URL and use conditionals to display in either multi-entry or single-entry mode. They can tend to become messy to read and harder to go back to later and make changes to. The upside is that by doing the combined template you can have simpler and more readable URLS - often the primary goal for developing a template that way.

With the Template Route you can keep the two different views of the content in two different templates but still achieve the simpler URLs of the combined template approach. 

I do like using the route-based linking variable because it’s a clue to the fact that the Template Route exists. As EE adds features I worry about new development approaches making it harder to reverse-engineer a site months or years down the road but in this case I think it’ll be OK.

What use have you found for Template Routes?

 

Category Navigation

<< Previous Entry   

 

Previous Comments

Picture of Mike Lohrman

by Mike Lohrman

Date: Friday, September 12th, 2014
Comment: #1

Thanks for the writeup. I usually alternate between dual-purpose templates with conditionals, or I use the index and another “single” template for single entries. Using routes for these simple URL structure seems about even with the other methods as far as template simplicity and amount of work involved. It would be interesting to see some advanced uses of template routes. I imagine you could completely forego the template_group/template structure. No idea if there’s any benefit to doing it an alternate way.

Picture of Sean

by Sean

Date: Thursday, September 18th, 2014
Comment: #2

Thanks for the write up. I haven’t had time to look inti template routes yet. My approach had been to use a single template and switchee to determine which code displays.

However, I like using less addons so may give this approach a shot on my next build.

Picture of Chris Basnight

by Chris Basnight

Date: Tuesday, September 30th, 2014
Comment: #3

VERY nice tutorial. One comment… I found that I had to set “Segments Required” to Yes in order for what you’re calling the multi-entry template to continue to work as needed.

Mike Boyink

by Mike Boyink (Author)

Date: Tuesday, September 30th, 2014
Comment: #4

Hi Chris -

Odd, I had to setup 2 of these on the current site I’m building and didn’t need that on either multi-entry template. Being as how the Template Route is applied to the single-entry template it doesn’t seem like it should be necessary to do anything different in the parameters of the multi-entry template. But I don’t argue with working code..;)

Picture of Chris Basnight

by Chris Basnight

Date: Wednesday, October 1st, 2014
Comment: #5

A point of clarification: I had to apply the setting to my single-entry template’s route setting. Without it, my multi-entry template seemed to be being ignored. My multi-entry template is using relationships to produce the list though, so perhaps that’s a difference between your set up and mine.

At any rate, this tutorial was the boost I needed to get over the learning curve. Without this tutorial, the template routes section of the user guide wasn’t making ANY sense to me. But since following the tutorial, suddenly the user guide makes more sense.

Picture of Kevin Nicholson

by Kevin Nicholson

Date: Wednesday, October 22nd, 2014
Comment: #6

Great thanks Mike – makes sense now, wondered about how to use and trying to keep addons to a minimum also.

Picture of Szabolcs Bakos

by Szabolcs Bakos

Date: Wednesday, December 3rd, 2014
Comment: #7

Thanks for the post, very useful! I will try this method soon…

Picture of Szabolcs Bakos

by Szabolcs Bakos

Date: Friday, December 12th, 2014
Comment: #8

I have tired this tutorial step by step but something wrong.
I am getting errors:

Message: preg_match_all() [function.preg-match-all]: Compilation failed: group name must start with a non-digit at offset 28

Message: Cannot modify header information - headers already sent by…

v2.9.2 fresh clean install.

Picture of Boyink

by Boyink

Date: Friday, December 12th, 2014
Comment: #9

Not sure what to tell you - works for me.

Picture of Szabolcs Bakos

by Szabolcs Bakos

Date: Saturday, December 13th, 2014
Comment: #10

Hi Mike,

I have found the source of the problem. You are right your code is fine! There is an Expression Engine bug which caused the errors:

https://support.ellislab.com/bugs/detail/20493/custom-route-manager-rule-throwing-preg_match_all-warning

“In system/expressionengine/libraries/template_router/Route.php, change this line:

$hash = md5($variable);
to this:

$hash = ‘e’ . base_convert(sha1($variable), 16, 36); “

With out this fix your tutorial not working.

Picture of Dan

by Dan

Date: Tuesday, January 13th, 2015
Comment: #11

Thanks for a the great write-up!
I’m facing an issue with this.

When I set up my routing:
/news/{somevariable}/{someothervariable

Then when I try to use {segment_1} in my templates to see if it is set to “news” or not, it doesn’t return it and does’t come up with anything.

Any thoughts?

Thanks!
Dan

Picture of Boyink

by Boyink

Date: Tuesday, January 13th, 2015
Comment: #12

Not sure Dan…I haven’t gone that advanced with routes yet.

Picture of Nick Toye

by Nick Toye

Date: Monday, February 9th, 2015
Comment: #13

Hi again,

Thought I would have a go at this, and followed your steps, I can link to the right template and all that works, but the content on the page isn’t showing.

In my Projects (group) view (template) I have the route:

projects/{project:alpha_dash}

This is on my home page to access this template:

View Project

and this is in my view template:

{exp:channel:entries channel=“projects” dynamic=“no” url_title=”{segment:project}”}
<h2>{title}</h2>
{/exp:channel:entries}

Nothing is appearing inside that tag.

I have debug output on and nothing is standing out as wrong.  Have I misunderstood how to use this?  The docs on the EllisLab site are not very clear to me.

Nick

Picture of Boyink

by Boyink

Date: Monday, February 9th, 2015
Comment: #14

Not sure if your link got mangled…is this what you have?

<a href="{route=" project="{url_title}" class="btn btn--primary">View Project</a

If so make sure to specify the template group/template name for the path.

Picture of Nick Toye

by Nick Toye

Date: Monday, February 9th, 2015
Comment: #15

Not sure how to add a codeblock here, but this is my link code in this gist.

https://gist.github.com/NickToye/de34508137964f19bcdc

That works though, it goes to the template as expected, but the content doesn’t show up.

Picture of Boyink

by Boyink

Date: Monday, February 9th, 2015
Comment: #16

Stumped then..did you look at the bug listed in the comments above?

Picture of Nick Toye

by Nick Toye

Date: Monday, February 9th, 2015
Comment: #17

I never got any error show up. I tried the fix anyway and made no difference.

Here is my output.

https://gist.github.com/NickToye/7701e9eab0c020680a55

Picture of BSR Web

by BSR Web

Date: Tuesday, February 10th, 2015
Comment: #18

Super helpful tutorial, thank you! And @Szabolcs Bakos, thanks, too, for calling out this bug—this hit me as well.

Picture of Szabolcs Bakos

by Szabolcs Bakos

Date: Tuesday, February 10th, 2015
Comment: #19

You are welcome!

Picture of Nick Toye

by Nick Toye

Date: Wednesday, February 11th, 2015
Comment: #20

Hi,

Can you not use the default Pagination tag with this method?

Picture of Boyink

by Boyink

Date: Wednesday, February 11th, 2015
Comment: #21

Don’t know - never tried!

Picture of BSR Web

by BSR Web

Date: Monday, March 9th, 2015
Comment: #22

@Nick Toye

In case you haven’t tried this, to make this work with pagination, use the following variable in the route manager on your multi-entries template:

{page:pagination}

I just tried this and it seems to be working.

Docs: https://ellislab.com/expressionengine/user-guide/urls/template_routes.html

Picture of Boyink

by Boyink

Date: Thursday, March 12th, 2015
Comment: #23

I just ran into the Pagination issue as well. I’m using the examples straight from the EE docs and category urls worked, paginated category urls worked, but simple pagination urls didn’t work.

I found that all I had to do was order the blog/index template route ahead of blog/entry route in the template route manager.

Picture of Thang

by Thang

Date: Friday, April 17th, 2015
Comment: #24

Hi Mike,

Can I using routes in this case?

1: /template-group/category_url_title

2: /template-group/category_url_title/P20

3: /template-group/category_url_title/entry_url_title

4: /template-group/category_url_title/entry_url_title/P20

I want:
1: for listing entries have category_url_title = segment_2

2: for listing entries have category_url_title = segment_2 with pagination

3: for listing detail entry page

4: for listing detail entry page with pagination (ex: comment entries)

Thank for any advice!

Picture of Boyink

by Boyink

Date: Friday, April 17th, 2015
Comment: #25

Not sure - I haven’t used Routes that extensively.

Picture of Chris Basnight

by Chris Basnight

Date: Friday, April 17th, 2015
Comment: #26

In your situation, routes aren’t really necessary. Routes by itself won’t even do what you want (hide the /category/ segment) unless you’re cool with using the category_id instead of the category_url_title.

Categories are ‘special’ in EE sometimes. This is one of those times! I’ve just been working on a project where I’ve been using routes to create logical, pretty URLs where segment_4 was my category_url_title. I used routes to generate the url as I needed up to segment_3 and added the variable alpha_dash as segment_4. Making that work with category_url_titles was a matter of hiding the intermediary category ‘trigger’ segment: /category/. My final urls were along the lines of /templategroup/sometemplate/subsetofsome/category_url_title.

I found the Low Seg2Cat add-on did what I needed and I believe it will work for you as well. It basically gives you the ability to bypass the use of /category/ in the URL. One super big caveat with using category_url_titles is that you have to either make sure all your category_url_titles site wide are unique or you have to set Low Seg2Cat to only evaluate category groups that you need this feature for.

Picture of Thang

by Thang

Date: Friday, April 17th, 2015
Comment: #27

Thank Mike and Chris!

@Chris, your advice:

- In your situation, routes aren’t really necessary.
- Categories are ‘special’ in EE sometimes.
- About Low Seg2Cat.

That actually help me so much to buid url structure in another way.

P/S: I focus in this situation

1. /template-group/
for list all entries in all category.

2. /template-group/category/category_url_title
for list entries base on one category.

3. /template-group/category_url_title/url_title
for list content of a entry.

Picture of Chris

by Chris

Date: Wednesday, June 17th, 2015
Comment: #28

Hi Mike,
I’ve found that the forum of EE is very quite and almost dead, do you think EE is dying? I love EE but it seems like the future is dim. May you share a bit of your thoughts? Thanks,
Chris

Picture of Jim

by Jim

Date: Monday, July 20th, 2015
Comment: #29

Hey Chris,

No - it moved off the Ellis site for the most part a few years back and is firmly based in ExpressionEngineAnswers section on StackOverflow now:

http://expressionengine.stackexchange.com

Many devs starting using SO for their own support needs, so it only goes to reason that all questions would go there as well…it’s a rich resource; dig in.  ;)

Also, check the ExpressionEngine Slack group for live connections with devs; there’s a good #howdoi channel available. Apply here:

https://ellislab.com/community

Also, the second developer release of EE3 is out today - exciting new changes are afoot! It’s a great time to get into EE…

Add Your Comment

Commenting is not available in this channel entry.

Unless otherwise stated all content is © Michael Boyink of Train-ee.com & Boyink Interactive. Please don't steal - I've got kids to feed...

dy>