Pages not linking to themselves: Categories, Stash and ExpressionEngine

BBC pages linking to themselves

Does anyone see the problem with this BBC web page? It's something that the BBC should know better of – that page links to itself. Why would someone click that link only for the page to refresh? It's bad user experience and decreases the users confidence for anyone clicking that link, and as it's so prominent - many will do. This template pattern happens right throughout the BBC website, as the BBC is sometimes seen as a go to for coding and web best practices, they are letting the web community down.

I have came across the same problem on a recent project and wondered how to prevent this happening in our CMS of choice – ExpressionEngine.

Example 1:


{exp:channel:entries channel="channel_name" url_title="not {segment_2}" dynamic="no" limit="5"  disable="custom_fields|member_data|pagination"}
    <h3><a href="/category-url-title/{url_title}">{title}</a></<h3>
{/exp:channel:entries}

The above is a very straight forward channel entries loop using the url_title parameter and inverting it with not, we are comparing it to the segment – thats the second url parameter. So pseudocode reads if not equal to the second segment then display.

The dynamic= no means that nothing is taken in from the segments altering how the segments work.

For anyone not aware of how segments work, its very simple when you see the following example

www.domain.com/articles/article-name

It works by using the structure: www.domain.com/{segment_1}/{segment_2}

It makes for an incredibly powerful and flexible url system, the possibilities are endless for displaying content.

Example 2: With Categories

The above example works for basic sites but on site with more content it's likely that you are going to have some categories or tags that break up the articles (or single entry pages as they are technically known in ExpressionEngine) into sections or identifiers.

In this example we will use the built in ExpressionEngine categories which are commonly used and work well in a number of circumstances for dividing content up.

We cannot do this natively and we need to install a completely free yet hugely powerful add-on - Stash. You can build websites in an entirely different way using Stash and a partials approach, it's a complex add-on and I won't go into too much detail here but if you are interested in its super powers please check out this fantastic guide from James Smith , looking forward to part 3 James!

So why can't we do this natively? Unfortunately due to the way ExpressionEngine works you cannot store some data and then reuse it throughout your templates and certainly not within a channel entries loop which we would want to, this is due to the dreaded and sometimes mind boggling parse order. I will only touch on parse order , it laymen’s terms its the way that code is read and it can cause big issues and headaches in a number of situations.

Anyway onto the code which will complete this small journey.


{exp:channel:entries channel="channel_name" disable="custom_fields|member_data|pagination"}
        {exp:stash:set_value name="the_id" value="{categories backspace="1"}{category_id}|{/categories}" }
{/exp:channel:entries}
{embed=template-group/template-name}

Since we are on an article page (single entry) this code will read in the parameter is segment 2 which is the url title of the page. This is known as a dynamic page in ExpressionEngine. Remember we can turn that off in any channel entries loop by setting dynamic=”no”, we don't want to do that in this instance however. In doing so we can grab the category(s) using the categories tag pair within the channel entries loop). Note this is different from the Channel Categories tag pair.

The backspace may need some explaining, but it works perfectly for what we are doing here.

When you are looping out content you sometimes want to omit the last few characters. If we didn't use it here then we would be outputting something like 1|4|5| or some 7|8|. That's not what we want because there is a trailing pipe. The different is subtle but important.

By using the backspace=1 we can remove that last pipe from our outputted categories. So categories will now we 1|4|5 and 7|8 from our above example.

Using Stash, we are setting a stash variable named “the_id” to that value of the categories.

To keep things simple we are using an embed (to help with parse order). That's another topic - embeds. To keep things short – don't use dozens of embeds – they can hurt your sites performance.

Within that embed we have:


{exp:channel:entries channel="channel_name" url_title="not {segment_2}" category="{exp:stash:get name='the_id'}" dynamic="no" limit="5" parse="inward" disable="custom_fields|member_data|pagination"}
    <h3><a href="/category-url-title/{url_title}">{title}</a></<h3>
{/exp:channel:entries}

A few notes: We are using the url_title =”not {segment_1}” as the exact same reason in the first example and the point of this article – we don't want articles to link to themselves.

Then we get onto the Stash stuff. We are getting that variable we set earlier, that will contain the categories by ID's.

We also need to set parse= inward so module and add on tags will be read before parsing the channel entries loop itself.

That completes our little task of making pages not link to themselves and with the added bonus of using categories which will be much more like a real example on a production site.

If you have any questions or comments please don't hesitate.