FortySeven Media

Kick Awesome Web Design, Graphic Design & Media Creation

Setting Up Custom Category URL Structures in ExpressionEngine

Wednesday, May 20, 2009 ~ 3:48 pm

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!

Category URL explanation

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 wink.

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

  • Social Web
  • E-mail

Your Email:*  

Your Name:*

               To:*

Submit the word you see below*

Posted by (JavaScript must be enabled to view this email address) in Design ~ ExpressionEngine ~ (64) Comments ~

Nice solution guys! Thank you for sharing this - I’m on the same stage, dialing with categories and category segments

I really like the insight you guys give into your work flow and design process. It’s always a pleasure reading blog posts such as this. Please keep them coming.

Nice post.

Isn’t the following a little redundant?

{if segment_2==”” AND segment_3==”“}

If segment_2 has nothing, then 100% of the time segment_3 will have nothing. You many only need to check for something in segment_2 there.

Thanks for taking the time to share that.

I tend to put in a closing if:else in to cover any unexpected glitches or unforseen enventualities; but then I’m a bit of a belt and braces sort of guy… wink

Why not use if !segment_2 AND !segment_3, this basically does if NOT segment, i.e if segment doesn’t exsits.

@Ryan It made sense to me at the time, but you’re probably right about not having to check for 3. I’ll have to test it out. @Josh interesting..is that a sort of shorthand? I hadn’t run across that before.

awesome! thanks. that answers up some quasi nagging questions i’ve had about the url structures in EE.

I’ve been using this exact same method for quite a few category-based sites recently.

The other method I’ve also used to achieve the same sort of thing is to use the Structure module from nGen Software.

In this case, using Low Seg2Cat would help with the use of {segment_2_category_id}. Then you don’t even need to use the query module.

I agree about Low’s Seg2Cat - you’ll never need the query module for this sort of thing again if you use that very handy extension. Your category entries block would be as simple as:

{if:elseif segment_2!=”” AND segment_3==”“}
  {exp:weblog:entries weblog=“products” category=”{segment_2_cat_id}”}
      [url=”{title_permalink={segment_1}/{segment_2}}”]
      {title}[/url]
{/exp:weblog:entries}

Man, I’m telling you there are so many modules/plugins/extensions that I’m just now running across that could have made my life easier. EE’s really starting to mature as a platform. Thanks for the Low Seg2Cat tip guys!

Pretty slick method to get that done, and great reading through the comments to come up with a few ways to refine it! Thanks for the post.

Great writeup and another shoutout for Seg2Cat - one thing I’ve run into handling categories this way is having to add a bunch of conditionals for the search results (and google sitemaps) to handle the custom paths correctly and insert the category name. Just curious how you’re handling that in the search results on this site?

@Mike All I did was use the categories tag in the href path:

{categories limit=“1”}
{site_url}products/{category_url_title}/{url_title}/
{/categories}

Granted, I’m not sure how that would work if more than one category was assigned to an entry, but in this case that won’t happen so it’s cool.

Great article!  Exactly what I’ve been looking for, but I’m having a hard time getting rid of the “index.php” before the template_group.  I normally use the “remove index.php” .htaccess method, but it’s not working with the “path”.

What am I missing?

I had to go to Control Panel Home › Admin › System Preferences › General Configuration and delete the name of the site’s index page.

It’s working great now…

Actually, no that didn’t work.  It removed the index.php, but the page quit working.  Sorry for blowing up your comments section.  I know this isn’t a forum.

Hah no problem earph smile. So I would take it back to basics first. Can you access something like http://site.com/template_group without the index.php?

False alarm… removing the index.php from the system preferences DID work!

Sweeeet glad to hear it!

I noticed that {exp:weblog:next_entry} & {exp:weblog:prev_entry} won’t show up in the “single entry” section.  I assume this has something to do with the URL path.

Any ideas on how to get it work?

I don’t see why it would have anything to do with that. Have you checked out the docs page on them?  I noticed in one of the comments it said they have to be outside of the weblog loop. http://expressionengine.com/docs/modules/weblog/entry_linking.html

Yes, I did see that and tried it with the tags outside of the weblog loop, but didn’t fix it.  Kind of weird, huh?

Did you try it on a plain vanilla test page? Include all the parameters? You might have to tell it that the url_title is in segment 3 like we did in the weblog loop above.

Yes, I’ve tried {exp:weblog:next_entry url_title=”{segment_3}, both within the main weblog loop and outside the loop.  No dice.

 1 2 3 >

Leave Your Thoughts Behind

Name*

Email*

Website

Smileys

  Remember my personal information

  Notify me of follow-up comments?

Submit the word you see below*

Live Preview

 
Separator
Design Hope for Startups 2009
Stuff we Love

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.

archives

Rad Deals
Apryl Lynn - With This Breath

Apryl Lynn
With This Breath

Buy in iTunes
Tweets
profile image

@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

Thu 9:53 | Follow
profile image

I've noticed I'm not noticing my spelling errors. I need more sleep.

Thu 9:40 | Follow
Tweets
Recommended

ExpressionEngine

Basecamp