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. Thanks for sharing! I needed this today and thought of this exact way of doing it, but then there was that sneaking feeling of “Maybe there’s a better way?” .. a Google later and at least I have confirmed that it’ll work grin

  2. looks great.

    I have an question.
    I have made a products weblog with category,
    ex: web/products/list/category/items name..

    and I want customiz same your product url,
    web/products/items name/

    how do I do ?

    would you share, how to made products web pages ?
    how to creat weblog ? category? template? custom fileds….

    thanks a again.

  3. @vincent I’m not quite following you. There’s code samples above in the article showing how to set it up. The template/custom fields will be totally different for every store. That’s why we use EE smile

  4. I’ll echo earph’s earlier comments, your next and previous weblog tags will fail to work with this method.

    You also need to add some fiddly php on input to get pagination to work otherwise the /P1/P2/Pn segments that EE suffixes to whatever segment you’re on will muck up your logic.

  5. @Seb, Right, though EE’s next/previous setup is pretty fiddly anyway wink Well, limited I guess. If you’re going to be putting together a store that needs pagination and next/previous linking this probably isn’t the solution for you. Like we said, a pretty limited case scenario. Thanks for reading!

  6. hi, Jonathan , that’s my fail.
    I try to use EE but it base on template system.
    the url look like http://web/products/list/category/itemName,
    I want replace the url to http://web/products/categoryName/itemName
    EE no any google way to do this, so I Google it then find your solution.

    now I got it to work. thanks a againg.
    using segment url , I fine 2 problem.
    1.next/pre article tag not work
    2. track_views

    not work.

  7. @vincent those tags won’t work because of the setup. Take a look at Nearby Entries, though. Should help with next/prev links at least. http://engaging.net/products/nearby-entries

  8. @jonathan, thanks.

  9. Hi Jonathan,

    I’ve followed your tutorial and it works great.

    Only thing, I want a mega drop down in my menu where users can have all the categories and every entry of each displayed below. I figured out that it would work with category_archive but I can’t see how to put the proper urls

    I’ve tried with category_heading and the entry tag, the category_archive tag, the category tag, the technique that you gave for search results, ... but had no luck with that :(

    Any ideas how ?

    Thanks !

    Any ideas how ?

  10. @Willa With this setup the category URL’s are changed so you’ll need to construct them yourself. We used something like this:

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

  11. Hi Jonathan and thanks for the response, works great smile

    Now that I have a big list of entry titles, do you know how I could organize them into there different categories ?

    So far I have for my drop down menu :

    {exp:channel:categories channel="products" class="nav_menu"}
    <a href="{path=" class="current"><span>{category_name}</span></a>
    {/exp:channel:categories}

    {exp
    :channel:entries channel="products" category_group="1"}
    <a href="{categories limit=“1”}{site_url}gammes/{category_url_title}/{url_title}/
    {/categories}"
    >{title}</a>
    {/exp:channel:entries} 

    How would you create a list of each categories with there related entries below ?

    Cheers,

    William

  12. @William I believe you can do something like this:

    {exp:weblog:categories weblog=“weblog” style=“linear”}
    <h3>{category_name}</h3>
    {exp:weblog:entries weblog=“blog” category=”{category_id}”  dynamic=“off”}
    <h4>{title}</h4>
    {/exp:weblog:entries}
    {/exp:weblog:categories}

    That should put the entries under their respective header. Hope that helps!

  13. Awesome !!! Thank you soooo much

  14. @William, cool. I used to do all that manually (inserting static category ID numbers) but like half my class at the last EECI told me I could just do this. Works great!

  15. Hi Jonathan,

    Thanks for the great code. I’m a bit of an EE newb and building a fairly complicated site and really want a URL structure like this. It works a treat!

    I do have a couple of questions:

    1. Giving the method you are using, how are you building your breadcrumb?

    2. Using your method, if you needed to have some single products at say, the top level (Products > 10-164) and some at a sub-level (Products > Sofas > 10-175), could your method cope with this? If yes, how would you do it as I’m very confused confused

    Thanks, Richard.

  16. @Richard, For this site, the breadcrumbs were kind of manual. Here’s the 3 types for products:

    1. Categories Entries Page

    <a href="{site_url}">Home</a>
    <
    a href="{site_url}products/">Products</a>
    {exp:weblog:entries weblog="products" limit="1" category="{cat_id}" dynamic="off" orderby="title" sort="asc" style="linear"}{categories limit="1"}{category_name}{/categories}{/exp:weblog:entries} 

    I can use the {cat_id} because of the sql query (see in article above)

    2. Product Page

    <a href="{site_url}">Home</a>
    <
    a href="{site_url}products/">Products</a>
    {categories limit="1"}<a href="{site_url}products/{category_url_title}/"{category_name}</a>{/categories}
    {title} 

    I’m not sure about your second question. I would guess you could manage some sort of if statement to check for the presence of a category and show one breadcrumb or the other? The main problem is that this whole setup assumes that each product is assigned to only one category. It kind of falls apart otherwise.

  17. Thanks for getting back to me so quickly.

    I’m doing the breadcrumb a little different, but not much. Was just curious if you managed to create it completely dynamically.

    Regarding my 2nd question, I’m still getting stuck myself. I’m actually using separate weblogs for the top level product departments and then using categories when needed.

    Think I may change this to use one weblog (products) and create categories and sub-categories, though still think I might run into issues.

    Thanks for your help.

  18. @Richard No problem. Yeah with the tag breadcrumbs and static page crumbs it was just easier to do it manually.

    RE: Categories/Sub Categories that would depend on if choosing a sub-cagtegory also adds the entry to the parent category. Then you might have issues with URL’s grabbing only one category. I’m not entirely sure smile

  19. Great writeup! Let’s assume on first landing page with the categories I also wanted to show a random product, almost like a dynamic featured product. Getting it to show up isn’t a big deal, but how would one go about linking to its product page 2 segments away?

    It seems like this shouldn’t be a big deal, but I can’t wrap my head around it. Even if the product had multiple categories (which in my case, it doesn’t), the call to find it’s category could return the top/default category.

    So basically I want a product living at /products/ to link to its product page at /products/category/url-title/—not already being nested in it’s category segment, though. Possible?

  20. Figured out my aforementioned question. The EE thread lives here: http://expressionengine.com/forums/viewthread/170356/

  21. @Chris glad you figured it out. I think others have had the same question as well..at least I think I remember putting up code like that smile Good luck, sir!

  22. Thanks for this post. It’s a great work-around to something that I think should be automatic in EE. I’m running into trouble using the switch function in the second category statement. I’m guessing it has something to do with the SQL statement but I really have no clue.

    Here’s the code:


    {exp:query sql=“SELECT cat_id, cat_name FROM exp_categories WHERE cat_url_title = ‘{segment_2}’”}

    {cat_name}

    {exp:weblog:entries weblog=“museum” category=”{cat_id}” orderby=“title” sort=“asc” dynamic_parameters=“orderby”}

    {switch=“one|two|three|four|five”}

    {museum_feature}

    {/exp:weblog:entries}
    {/exp:query}

    I’ve simplified this a bit so it makes sense, but I can’t seem to get the switch to work here. Is there an easy workaround that you can think of?

  23. @Andy I had to use Switchplus; hopefully that helps!

  24. This is great and all, but destroyed when making an article span over multiple pages, but also parameter view_count_x will not work either. Such a drag.

    It would be nice to force dynamic=“on” when pulling a single entry by the url_title parameter.

  25. @Bransin, yes this is a very specific use case. Things like next/prev, pagination all stop working unfortunately.

  26. More Comments:    < 1 2 3 4 > 

Leave Your Thoughts Behind

Remember my personal information