FortySeven Media

Jonathan Longnecker

Jonathan Longnecker

May 20, 2009

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!

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

Share the Love

FortySeven Media
Did you know?

Besides designing websites, FortySeven Media also makes the Kick Awesome Show and is currently working on Kicktastic - a project to tell you how we’re making more money. Sign up if you’re interested.

Comments

  1. First, great EE code! I’ve been using it quite a bit.
    Second, I’m having a similar problem to Andy Krier’s with the {switch} tag. Apparently it doesn’t work inside of the {exp:Query} tags (on the Category Entries page). I also couldn’t find the “SwitchPlus” plugin anywhere, and I’m also on EE 2.0. Any help/ideas? Thanks!

  2. Hey Richard,

    Glad you’ve found this setup helpful! We obviously wrote this a while ago, so I’d check out http://devot-ee.com/ for something like switchplus. There might even be a better way to get the category other than the sql query.  Check back through the comments if you have a minute, I remember someone suggesting something else.

  3. Thanks for the feedback, Jonathan!

    Actually, I discovered why the {switch} wasn’t working within the {exp:query} tag. Apparently {switch} takes the count of the outer tag pair, so in order to get around it, you need to embed the template:

    {exp:query}
    {embed channel:entries template code, and pass the {cat_id} variable}
    {/exp:query}

    And this works.

  4. Ahh sweet; it’s amazing how often embedding works smile

  5. Amazing article…really helpful

    I ran into the issue of pagination failing with this however. On looking around it seems the plugin Low Seg2Cat solves this issue. Well it has so far anyway. Hope it helps someone.

    Thanks,
    Ian

  6. Good news Ian, thanks for sharing!

  7. Actually, I was wrong, the pagination still fails due to,  i think, the way the urls are structured. My limited programming skills may be at fault here but….

    Does anyone know the syntax for a conditional that can check for the url being a typical pagination url suffix and not a typical entry url?

    www.example.com/template_name/category_url/p10 for example:

    Something like, for example?

    {if segment_3 != contain “P**”}

    Therefore, we may have a way to show certain results/pages based on what {segment_3} suggested in the URL, with the P removed (not sure how) for example:

    {exp:channel:entries channel=“products” category=”{segment_2_category_id}” entry_id_from=”{segment_3 minus the P}” entry_id_to=”{total_results}}

    Could this work???

  8. Ho appena libro segnato il tuo blog su Digg e Stumble Upon. Mi piace leggere i vostri commenti.

  9. Hey guys !
    I was wondering how would this work with Multy Language module ? The module adds a /fr, / it or /de in the url and if I go to the product page I’ll get a 404. However if I add /fr/index.php/ i can get to the page

  10. @william if you’re using EE2 look into Freebie. Let’s EE ignore segments but you can still use them to grab valuable data.

  11. Awesome ! I’ll check it out. Thanks

  12. nice post.

  13. I don’t know if you guys still reply to these old posts, but I guess we’ll find out wink

    I came across this blogpost, looking to solve the exact same problem that you guys had. I also checked out the finished product over at Casillas, Inc, and found that their site have been hacked. Not cool, and quite sad to look at.

    Thanks for taking the time to share insight into EE and custom URL-structures.

  14. @Martin Berglund They didn’t get hacked, just went out of business. It’s a long saga, but the site does live on in another form. I just can’t tell you where smile

  15. @Jonathan Longnecker Aha, I see smile Good to know I was wrong.

  16. More Comments:   ‹ First  < 2 3 4

Leave Your Thoughts Behind

Remember my personal information