Blog
Articles, musings, rants, and news...

Avoiding Duplicate Title Issues in ExpressionEngine

We've been ramping up our own SEO efforts here at 420 Creative and recently ran into a duplicate title/content issue regarding paginated sections/pages. Since our site uses the awesome ExpressionEngine CMS,  I thought I'd share the problem and how we solved it.

Duplicate Titles? Don't you mean duplicate content?

From an SEO standpoint, duplicate content can have a very negative effect on your site's rankings, whether it's getting stuck in a low ranking spot, not getting ranked at all, or getting dropped from search engines altogether (rare but it happens once in a while). Most people will address a page's content when discussing duplicate content. That is, the text on each page should be unique and not a duplicate anywhere else on the web. One thing that gets overlooked, however, is the title tag. This guy:

<title>Your page title here</title>

That powerful little tag is critical to any SEO efforts and having duplicates can potentially hurt your rankings. If you don't have duplicate titles on your site, good on ya. Carry on and skip this article. :)  We, on the other hand, found dozens of duplicate title tags on our site.

 

Finding Duplicate Titles

I'm a Pro member over at SEOmoz and using their tools I found the offending pages. You don't have to be an SEOmoz member though. Most SEO tools will have a way to find any duplicate titles within your site. If in doubt, use Google Webmaster Tools.

In any case, I found most of our duplicate titles were in two sections on our site: our design portfolio and the design blog.

In the case of the portfolio, it wasn't too bad. There were only a small handful of portfolio entries that had duplicate titles. This was a result of using the client name as the title only rather than being a bit more descriptive (which is good SEO anyway) and unique in the title tag. Since we use (and love) NSM Better Meta, this was an easy fix. After identifying which portfolio entries contained duplicate titles, I headed into each one and tweaked them in the NSM Better Meta tab.

The blog was a little bit more involved. The entries/posts themselves weren't the issue. The issue was in the pagination of each category. For instance, the URL to the "Around the Web" category looks like this: http://420creative.com/blog/category/web_development. We have several posts in that category, so depending on the page you're on within that category listing, you'll see "Next" and "Previous" links (i.e., pagination). So the issue came up with the subsequent pages within the category listings. On page two, for instance, the URL looks like this: http://420creative.com/blog/category/web_development/P6  (You may think that it should have "P2" at the end there but EE is a little odd in how it handles pagination in the URL.)

In both cases (and subsequent pages within the category), the title tag read like this:

Web Development Blog - 420 Creative

Both were the same. And that's a problem.

I determined that to make each one unique it would be best to add "Page n of y" (where n is the current page number and y is the total number of pages) so that we ended up with something like this:

Page 2 of 53 - Web Development Blog - 420 Creative

In ExpressionEngine, the only way to really get that text to show up is to use the Channel Entries tag. In the template that renders the category listing pages, we use an embed to call in everything from the opening <html> tag to the closing head tag. The embed, at its simplest, looks like this:

{embed="_global/_head"}

In that embedded template lies the NSM Better Meta tag and code.

I should note that we use one template to handle the main blog page and the category pages. We do this with conditionals:

{if segment_2 == ""}
  {embed="_global/_head" title="[our main blog page title]" description="[meta description here]"}
{/if}

{if segment_2 == "category" && segment_4 == ""}{embed="_global/_head" title="{segment_3_category_name} Blog"}{/if}


{if segment_2 == "category" && segment_4 != ""}{embed="_global/_head" title="
  {exp:channel:entries site="420" channel="blog" disable="member_data" limit="6" paginate="bottom"}
  {paginate}Page {current_page} of {total_pages} - {/paginate}
  {/exp:channel:entries}
  {segment_3_category_name} Blog"}
{/if}

Admittedly it's not the prettiest or most sophisticated solution, but it works well. I'm not a huge fan of using a ton of conditionals if it can be avoided due to their overhead. But our pages are still pretty speedy so this works fine for this site. We may end up changing this to use either Switchee or Ifelse – both really great add-ons by Mark Croxton – to improve performance a bit.

The second and third conditional you see in the code above is where the duplicate title issue is resolved:

{if segment_2 == "category" && segment_4 == ""}{embed="_global/_head" title="{segment_3_category_name} Blog"}{/if}

That conditional tells EE that if the URL is the main category page (i.e., there's no pagination number/ID in segment 4 of the URL), grab the code from the embedded template (_head in this case) and apply the category name – which is in segment 3 – for the title followed by "blog". (We use Low Seg2Cat to grab the category name from the segment.) Easy enough.

(The title variable in the embed is used in conjunction with NSM Better Meta.)

Next, we tell EE that if the URL is not the main category page (because there is a pagination number/ID in segment 4 of the URL), grab the code from the embedded template and modify the title:

{if segment_2 == "category" && segment_4 != ""}{embed="_global/_head" title="
  {exp:channel:entries site="420" channel="blog" disable="member_data" limit="6" paginate="bottom"}
    {paginate}Page {current_page} of {total_pages} - {/paginate}
  {/exp:channel:entries}
  {segment_3_category_name} Blog"}
{/if}

Within the title variable you can see I added a condensed version of the code that displays the entries and pagination on each category page. Here it is by itself:

{exp:channel:entries site="420" channel="blog" disable="member_data" limit="6" paginate="bottom"}
{paginate}Page {current_page} of {total_pages} - {/paginate}
{/exp:channel:entries}

Since the paginate tags are dynamic, each category page then automatically adds the correct current page number out of the total number of pages. I made sure that the parameters in the Channel Entries tag are identical as the ones where this code shows up later in the template. The reason for this is so that the pagination output (the numbering) is identical to the page itself, otherwise it may end up spitting out incorrect numbering.

Again, this isn't the most elegant solution since we've essentially added to the overhead of the page by adding yet another query by using the channel entries EE tag. It works, but it may not be a good solution for sites that are more complex or heavily trafficked.

 

Unique Titles FTW!

So what does this all work do in the end? Well, in terms of SEO efforts, it's mostly just being a perfectionist. In terms of search engine ranking, there is an impact. How much, I can't really say. But it is a basic premise of good SEO, so there's no reason to be lazy about it really.

In any case, I hope I've helped any EE devs out there with a penchant for good SEO with this post. Got any other ideas or solutions to this? Post them in the comments!