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?
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.
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!

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
Share This Entry with Your Favorite Social Networking Sites.Technically, next_entry and prev_entry should only show up on single entry pages. Since the if statement is creating the URL dynamically and only swapping out template code, perhaps the system doesn’t recognize the page as a “single post” and therefore doesn’t display the next/prev links.
That’s very possible; sorry I haven’t been more help :(.
i have tried out but wont work. Help me a bit
Thanks
@Honest I don’t really know what’s not working for you?
Great post! This works great for simple cases where there is only a top-level category that each post belongs to…. I do have a question however…
How would I go about doing this for posts that are listed in multiple categories? What about for sub-categories?
Thanks
@Mike For multiple categories I honestly have no idea unless you somehow just had it pick one, but depending on what you’re doing that’s not very helpful. For sub-categories, check out the link in my article to the forums. I believe the original version had support for sub-categories using a plugin or extension.
right guys, I’ve played around and found that Next / prev entry linking is not working as the pagination on a category view, which is maybe because the dynamically builded segments.
This becomes serious issue for me as I keen to use the next / previous and pagination on a product catalog
@Vlado, you may want to file a ticket/bug with the EE guys. Like I said, this obviously isn’t the standard way of putting pages together so they would know why it isn’t working.
I’ve started a few threads in EE forum in regards to the “next/prev” issue, but have yet to find a solution. Most of the threads have ended with the conclusion that it’s just not possible. I’ve tried alternate methods, but no luck there either. If you any of you figure out this problem, PLEASE let me know.
Hey earph, is there not a way to pull a SQL query and just manually grab it out of the database?
Possibly, the problem is that I’m not that technically advanced (more of a css guy) and wouldn’t know how to pull that off. It sounds like it would work though, if you have an idea on how to do it.
I’m afraid I’m not that advanced either. I’m like you, more of a HTML/CSS guy who uses EE and attempts to bend it to my will, but when it comes to writing SQL queries and PHP I don’t understand the syntax well enough. That’s why I love me some EE forums!
Boom! (sound of my head exploding). Thanks.
How did you remove the ‘category’ trigger? (Or am I missing something obvious)
You technically don’t remove it; you just bypass it with the if statements and sql query.
Hi.
Thanks for this, i have been looking for a way to sort the URL’s out like this. And to get an insight into your project is also useful, always keen to see how other people overcome similar problems.
Just a heads up, the search bar on the products page is half cut off: http://casillasinc.com/products/
Thanks again!
What’s your current thinking on use of category URL’s then Jon or anybody, tool of choice?
I also don’t have access to URL rewriting and have to use the ? query strings on setting in the CP. Is this a problem with anything mentioned here or in the comments?
I recenlty started using blogengine.net and something that stood out right away is that it has nice categories tagging that is easy to use.
I’m far from being a big dotnet fan though.
@Ty, sorry man I’m not really following what your question is. Category URL’s are cool, but only really if you’ve got one category assigned to each entry. Otherwise you end up with duplicate content, right? I think it’s a very specific case.
Hi,
I made category structure like this, but now I am facing pagination.
Can you guide me how to add pagination code to this code.
Thanks,
Tejas
@Tejas, based on this comment thread pagination and next/previous linking don’t seem to work with this method. In theory some sort of SQL Query could help you find and link to the next post, but I don’t know the syntax. Sorry I can’t be of more help.
On the Categories Entries page what variable are you using to return the h1? For example the “Sofas” heading on http://casillasinc.com/products/sofas/
Is the documentation of this somewhere, I looked briefly but could not find anything?
@brad we’re using something to the effect of this:
{exp:weblog:entries weblog=“weblog_name” category=”{cat_id}” dynamic=“off” orderby=“title” sort=“asc” style=“linear” limit=“1”}<h1>{categories limit=“1”}{category_name}{/categories}</h1>{/exp:weblog:entries}
Kind of manual, but it works
Right, that’s what I was forgetting the {categories} variable pair.
I found another solution right after I asked (always happens). I adjusted the query to also select cat_name and print that out before the weblog:entries tag. i.e.
{exp:query sql=“SELECT cat_id, cat_name FROM exp_categories WHERE cat_url_title = ‘{segment_3}’”}
<h1>{cat_name}</h1>
Thanks.
@brad, Nicely done, sir! That’s much cleaner.
BestChristianDesign is helping give churches inspiration for their next project. Good call, guys.
Seth Godin reminds us to enjoy and take advantage of the uphills.
Stop announcing your new project. Just do it.
Rock and Roll people, Rock and Roll.
To all you staff designers out there, here’s a link for you. (via @ryanlascano)
Fascinating look into the music business.
Derek Sivers posts some great advice about balancing your life.
@ryanirelan Hate that, too. Was hoping it would grow on me but too many panes all over the place. Too much like my desktop :D
I've noticed I'm not noticing my spelling errors. I need more sleep.
The best Content Management System for designers. Feature rich, completely customizable, and easily extendable.
Basecamp is the smarter, easier, more elegant way to collaborate on your internal and client projects.
(JavaScript must be enabled to view this email address)
June 12, 2009
Sorry, I’m flying blind here without code, but you might want to make sure you’re passing the weblog name, maybe entry ID, limit, etc…
I’ve honestly never used the next/previous links like that before so I’m not sure what their limitations are.