Choosing a CMS with Search Engines in Mind – Part One

By Aidan Moore | 12 Jun 2013

Choosing a CMS with search engines in mind can be challenging, as both CMS’s and search engines are developing new functionality every day, writes Aidan Moore.

With over ten years spent working in search engine optimisation, one question seems to be asked again and again.

“Which content management system (CMS) will help my site’s ability to rank well in search?”

Choosing a CMS with search engines in mind can be very challenging, because both CMS’s and search engines are developing new features and functionality every day.

If you are considering which CMS to choose for your business, the following is a list of aspects to keep in mind. Most off-the-shelf CMSs will have example installations that you can test out to see if the below are covered. If you are developing a custom CMS, your specifications should also keep these essentials in mind.

Primary Considerations: 

SEO-Friendly URLs

This is one of the most important aspects of a CMS, and is where a lot of CMS’s used to go wrong (and some still do).

A good URL is one that is self-explanatory, unique (e.g. a product page can only be found at one location) and minimises non text elements (e.g. ‘?’ and ‘=’)

A non-SEO-Friendly URL would be:

Whereas a SEO-Friendly URL would be something like:

Some CMS’s do not handle SEO Friendly URLs out of the box, but have plugins that can be installed.  If it is not obvious, check with their help support.

Title/Meta Tag Control

While there are differing opinions on the future value of optimising Meta Data, we still find that the Title tag plays a big part in onsite optimisation and the meta description content often powers the description Google uses for its snippets – potentially aiding Click Through Rate.

Google snippet

Meta data will be used in various places by Google.

Your CMS should allow you to set the page Title & Meta Description for each page of your site.

We recommend that all your key product and category pages have unique optimised Titles and Meta Descriptions, but if you are selling thousands of products this can be very time consuming.  For scalability, it is beneficial to be able to set rules for the generation of this data, taking information from areas of the database if no optimised content is present.

For example:

Page Title: <Brand> <Product Name> | The Biggest Range of <Category> in Australia

Page Description:  Buy <Brand> <Product Name> online from <Shop Name>.  We have the biggest range of <Category> in Australia.


The ability of a CMS to handle page redirects is very important, whether this will be your first site or if you are moving from an old CMS.  If you are moving from an old CMS to a new one, you should create redirects from your old pages to the relevant pages on the new site.  This is for both search engine optimisation and usability. Redirects will help  to pass historic SEO value on to your new pages and users who may have bookmarked internal pages of your site will still be able to find them in the new structure.

If this will be your first site, considering redirects is still important because in the future you may discontinue some products and you will want to redirect that old traffic to your new relevant product pages.

The key thing with redirects is that they should be the 301 (permanent) type.  It can be hard to tell what type of redirect is being used, but there are plenty of testing tools that can be found on Google through a search for “Header Checker”.

Canonical Tags

Google describes a canonical page as “the preferred version of a set of pages with highly similar content”.  A common use of canonical tags within e-commerce sites is for category pages where sorting or filtering is being used.

So if your site will have the functionality of sorting by name, price or popularity, and the content is very similar to the main page, the CMS should make use of canonical tags.

You can test this by going to a test installation of the CMS, finding a category page (make note of the URL) and then choose a sorting option.  View the source code of the page and look for the following code:

<link rel=”canonical” href=”<This is where the category URL goes>” />

If the CMS does not handle canonical tags it can result in Google indexing many variations of the one page and having difficulty assigning value to the main category page.

Handling Broken Pages

A templated 404 error page should be shown when a page that does not exist is requested.  This allows for search engines (and users) to continue browsing the site if they have clicked on a malformed link.

Bad 404 example

An example of a bad handling of a broken URL.

The Iconic's 404

An example of a custom 404 error page.

Also be sure to double check whether the CMS returns a 404 page not found error for broken links by doing a search on Google for ‘Header Checker’ and using a tool to test out a URL that does not exist.


Schema is the next evolution of meta data, where specific html tags are placed around different types of data on a page (eg price, product image, availability, reviews etc.) that allow search engines to better understand the content  within the tags.  There are a variety of schema’s relevant to e-commerce sites, you can find the complete list at the Schema website

Check that the CMS automatically handles Schema out of the box as it can be quite difficult (but probably not impossible) to manually add to your templates.

Below is how schema is used by Google to show extra details in the search results:

Google search results

An example of Google’s search results.

Automatic Sitemap Generation

The way search engines work is that they create copies of your site’s pages into their database, and they find new pages through following the links on the pages they already have. This system can sometimes mean that what they have indexed in their database does not match what you actually have on your site. This is where an XML sitemap can help. An XML sitemap is a list of all the examples of a type of content available in your site, and gives the search engine something to compare against.

Keeping an XML sitemap up to date is a laborious task, so a CMS that can auto generate a new sitemap as new pages / products are created will save you time.

There are two main sitemap types that your CMS should generate:

  • Page – this is the most important to be auto-generated and is a list of all the pages on your site, with a priority associated.
  • Image – Google search results often include image search – an image sitemap can help your images to appear there.

You can submit your sitemaps to Google via Webmaster Tools.

Test Speed

Google (and other search engines) are placing more influence on user experience and therefore site speed is becoming more important. We recommend using a speed test tool to check how the CMS performs for existing installations.

In Part Two of this article, we’ll discuss further considerations for search value when choosing a CMS.


0 Comment

Leave a Reply

Your email address will not be published. Required fields are marked *

[gravityform id="11" title="false" description="false" ajax="true"]
<div class='gf_browser_unknown gform_wrapper fix-om-styling_wrapper' id='gform_wrapper_11' ><div id='gf_11' class='gform_anchor' tabindex='-1'></div><form method='post' enctype='multipart/form-data' target='gform_ajax_frame_11' id='gform_11' class='fix-om-styling' action='/editorial-2/choosing-cms-with-search-engines-in-mind-part-one/#gf_11'> <div class='gform_body'><ul id='gform_fields_11' class='gform_fields top_label form_sublabel_below description_below'><li id='field_11_2' class='gfield gfield_contains_required field_sublabel_below field_description_below hidden_label gfield_visibility_visible' ><label class='gfield_label' for='input_11_2' >Email Address<span class='gfield_required'>*</span></label><div class='ginput_container ginput_container_email'> <input name='input_2' id='input_11_2' type='text' value='' class='large' placeholder='Email' aria-required="true" aria-invalid="false" /> </div></li><li id='field_11_3' class='gfield gfield_contains_required field_sublabel_hidden_label field_description_below hidden_label gfield_visibility_visible' ><label class='gfield_label gfield_label_before_complex' >Name<span class='gfield_required'>*</span></label><div class='ginput_complex ginput_container no_prefix has_first_name no_middle_name has_last_name no_suffix gf_name_has_2 ginput_container_name' id='input_11_3'> <span id='input_11_3_3_container' class='name_first' > <input type='text' name='input_3.3' id='input_11_3_3' value='' aria-label='First name' aria-required="true" aria-invalid="false" placeholder='First Name'/> <label for='input_11_3_3' class='hidden_sub_label screen-reader-text'>First</label> </span> <span id='input_11_3_6_container' class='name_last' > <input type='text' name='input_3.6' id='input_11_3_6' value='' aria-label='Last name' aria-required="true" aria-invalid="false" placeholder='Last Name'/> <label for='input_11_3_6' class='hidden_sub_label screen-reader-text'>Last</label> </span> </div></li><li id='field_11_5' class='gfield gfield_contains_required field_sublabel_below field_description_below hidden_label gfield_visibility_visible' ><label class='gfield_label' for='input_11_5' >Company / Organisation<span class='gfield_required'>*</span></label><div class='ginput_container ginput_container_text'><input name='input_5' id='input_11_5' type='text' value='' class='large' placeholder='Company' aria-required="true" aria-invalid="false" /></div></li><li id='field_11_6' class='gfield gform_hidden field_sublabel_below field_description_below gfield_visibility_visible' ><input name='input_6' id='input_11_6' type='hidden' class='gform_hidden' aria-invalid="false" value='NOT PROVIDED' /></li><li id='field_11_7' class='gfield gform_hidden field_sublabel_below field_description_below gfield_visibility_visible' ><input name='input_7' id='input_11_7' type='hidden' class='gform_hidden' aria-invalid="false" value='NOT PROVIDED' /></li><li id='field_11_8' class='gfield gform_hidden field_sublabel_below field_description_below gfield_visibility_visible' ><input name='input_8' id='input_11_8' type='hidden' class='gform_hidden' aria-invalid="false" value='NOT PROVIDED' /></li><li id='field_11_9' class='gfield gform_validation_container field_sublabel_below field_description_below gfield_visibility_visible' ><label class='gfield_label' for='input_11_9' >Name</label><div class='ginput_container'><input name='input_9' id='input_11_9' type='text' value='' /></div><div class='gfield_description' id='gfield_description__9'>This field is for validation purposes and should be left unchanged.</div></li> </ul></div> <div class='gform_footer top_label'> <button type="submit" class="button-3" id="gform_submit_button_11">SUBSCRIBE</button> <input type='hidden' name='gform_ajax' value='form_id=11&amp;title=&amp;description=&amp;tabindex=0' /> <input type='hidden' class='gform_hidden' name='is_submit_11' value='1' /> <input type='hidden' class='gform_hidden' name='gform_submit' value='11' /> <input type='hidden' class='gform_hidden' name='gform_unique_id' value='' /> <input type='hidden' class='gform_hidden' name='state_11' value='WyJbXSIsIjRjNDYzMzMwNzM3OTFjM2ZlOGZhNjY2ZDA4ZDVlMDcyIl0=' /> <input type='hidden' class='gform_hidden' name='gform_target_page_number_11' id='gform_target_page_number_11' value='0' /> <input type='hidden' class='gform_hidden' name='gform_source_page_number_11' id='gform_source_page_number_11' value='1' /> <input type='hidden' name='gform_field_values' value='' /> </div> </form> </div> <iframe style='display:none;width:0px;height:0px;' src='about:blank' name='gform_ajax_frame_11' id='gform_ajax_frame_11' title='This iframe contains the logic required to handle Ajax powered Gravity Forms.'></iframe> <script type='text/javascript'>jQuery(document).ready(function($){gformInitSpinner( 11, '' );jQuery('#gform_ajax_frame_11').on('load',function(){var contents = jQuery(this).contents().find('*').html();var is_postback = contents.indexOf('GF_AJAX_POSTBACK') >= 0;if(!is_postback){return;}var form_content = jQuery(this).contents().find('#gform_wrapper_11');var is_confirmation = jQuery(this).contents().find('#gform_confirmation_wrapper_11').length > 0;var is_redirect = contents.indexOf('gformRedirect(){') >= 0;var is_form = form_content.length > 0 && ! is_redirect && ! is_confirmation;var mt = parseInt(jQuery('html').css('margin-top'), 10) + parseInt(jQuery('body').css('margin-top'), 10) + 100;if(is_form){jQuery('#gform_wrapper_11').html(form_content.html());if(form_content.hasClass('gform_validation_error')){jQuery('#gform_wrapper_11').addClass('gform_validation_error');} else {jQuery('#gform_wrapper_11').removeClass('gform_validation_error');}setTimeout( function() { /* delay the scroll by 50 milliseconds to fix a bug in chrome */ jQuery(document).scrollTop(jQuery('#gform_wrapper_11').offset().top - mt); }, 50 );if(window['gformInitDatepicker']) {gformInitDatepicker();}if(window['gformInitPriceFields']) {gformInitPriceFields();}var current_page = jQuery('#gform_source_page_number_11').val();gformInitSpinner( 11, '' );jQuery(document).trigger('gform_page_loaded', [11, current_page]);window['gf_submitting_11'] = false;}else if(!is_redirect){var confirmation_content = jQuery(this).contents().find('.GF_AJAX_POSTBACK').html();if(!confirmation_content){confirmation_content = contents;}setTimeout(function(){jQuery('#gform_wrapper_11').replaceWith(confirmation_content);jQuery(document).scrollTop(jQuery('#gf_11').offset().top - mt);jQuery(document).trigger('gform_confirmation_loaded', [11]);window['gf_submitting_11'] = false;}, 50);}else{jQuery('#gform_11').append(contents);if(window['gformRedirect']) {gformRedirect();}}jQuery(document).trigger('gform_post_render', [11, current_page]);} );} );</script><script type='text/javascript'> jQuery(document).bind('gform_post_render', function(event, formId, currentPage){if(formId == 11) {if(typeof Placeholders != 'undefined'){ Placeholders.enable(); }} } );jQuery(document).bind('gform_post_conditional_logic', function(event, formId, fields, isInit){} );</script><script type='text/javascript'> jQuery(document).ready(function(){jQuery(document).trigger('gform_post_render', [11, 1]) } ); </script>