Setting Up Custom Category URL Structures in ExpressionEngine
We just finished up a particularly fun project, Casillas, Inc. They’re an amazing custom furniture maker in California. In an odd turn of events, we actually did very little design for the site and became the “backend guys” if you will. As we got into how we wanted the site to be structured we realized that because of the product names (all numbers) we needed to use the category that the product was part of in the URL structure. So for example it would read:
http://site.com/products/sofas/10-123/
And if the user accesses:
http://site.com/products/sofas/
Then all the sofas get shown. Back one more and all the categories. Great! Now how in the world do we do that with ExpressionEngine?
First Problem
By default, EE uses either the category ID number to display all the entries in that category:
http://site.com/products/C12
Or you can turn on URL titles and choose your “trigger” word. So if category was the trigger the URL would be:
http://site.com/products/category/sofas
Hence, we need to figure out how to remove the category trigger.
Second Problem
We want the URL title of the entry (the product number in this case) to immediately follow the category name. And we want that URL scheme to be the permanent location of the product. Because this isn’t how EE works out of the box, there is potential to trip us up down the road and make it hard to create those permalinks reliably. Can we do it? You bet we can!

The Solution
As you can see in the diagram above, we’re going to harness the power of segment variables to make our magic happen. What are segments? Well, it’s pretty easy. Segment 1 is the first section in your URL after your .com, Segment 2 is the next and so on. EE will handle up to 9! I hope I hope I never have to use that many.
First, we need to setup our template group (products in this case) and then on the index template inside that group we begin our work. We’re actually going to manage to put all of this in one template using if statements. Yep, that blew my mind the first time, too. Keep in mind that all this code has been stripped down to bare minimum to keep it easier to follow. My template code for this page was pretty large with all the HTML markup in it.
We’ll start with the categories page:
{if segment_2=="" AND segment_3==""}
{exp:weblog:categories weblog="products" style="linear"}
<p><a href="{path="products/{category_url_title}"}">
{category_name}</a></p>
{/exp:weblog:categories}
Here we tell EE that if Segment 2 and 3 are empty, we use this part of the template. Then we use the weblog:categories tag to list the categories and make them links.
Second is the category entries page:
{if:elseif segment_2!="" AND segment_3==""}
{exp:query sql="SELECT cat_id FROM exp_categories WHERE
cat_url_title = '{segment_2}'"}
{exp:weblog:entries weblog="products" category="{cat_id}"}
<p><a href="{title_permalink={segment_1}/{segment_2}}">
{title}</a></p>
{/exp:weblog:entries}
{/exp:query}
Here we continue the if statement by saying that if Segment 2 has something in it and Segment 3 is empty we use this part of the template. Add to that a little SQL Query magic to pull the category ID from the category URL and then you can start making your links to the products. Notice you need to pass the category ID to the weblog loop and then you can use the title permalink in conjunction with the first two segment variables.
And finally the single entry:
{if:elseif segment_3!=""}
{exp:weblog:entries weblog="products" limit="1"
url_title="{segment_3}"}
Call whatever custom fields you have here
{/exp:weblog:entries}
{/if}
If Segment 3 is populated then we look for the entry inside it and pull the data. It gets more complicated after that to use permalinks and title paths, but we didn’t run into an issue we couldn’t get past. And don’t forget, you can go to http://casillasinc.com/products/ and click around to see how it works. Also, before you think I’m a mad genius or something, this is based on some excellent work by a guy named “TheStig” in the EE forums. The only credit I can take is for making it a little easier to understand
.
Due to line breaks and such I’ve put all of the above together for you in one file so it will be easy to get started. Have fun!
Download: the template code.
Edit: Be aware that next/previous linking and pagination won’t work with this method. For next/previous linking this might help: Nearby Entries

.(JavaScript must be enabled to view this email address)
Jun 12, 2009
2
earph
Jun 15, 2009
.(JavaScript must be enabled to view this email address)
Jun 17, 2009
4
.(JavaScript must be enabled to view this email address)
Jun 17, 2009
.(JavaScript must be enabled to view this email address)
Jun 17, 2009
6
.(JavaScript must be enabled to view this email address)
Jul 07, 2009
.(JavaScript must be enabled to view this email address)
Jul 07, 2009
8
vlado varbanov
Jul 23, 2009
.(JavaScript must be enabled to view this email address)
Jul 23, 2009
10
earph
Jul 23, 2009
.(JavaScript must be enabled to view this email address)
Jul 23, 2009
12
earph
Jul 23, 2009
.(JavaScript must be enabled to view this email address)
Jul 23, 2009
14
.(JavaScript must be enabled to view this email address)
Jul 26, 2009
15
.(JavaScript must be enabled to view this email address)
Aug 07, 2009
.(JavaScript must be enabled to view this email address)
Aug 07, 2009
17
Nathan
Sep 09, 2009
18
Ty
Oct 06, 2009
.(JavaScript must be enabled to view this email address)
Oct 06, 2009
20
.(JavaScript must be enabled to view this email address)
Dec 08, 2009
.(JavaScript must be enabled to view this email address)
Dec 08, 2009
22
brad
Jan 15, 2010
.(JavaScript must be enabled to view this email address)
Jan 15, 2010
24
brad
Jan 16, 2010
.(JavaScript must be enabled to view this email address)
Jan 16, 2010