Subscribe to this feed June 7, 2007

Typo3 CMS SEO (Part 2): Page URLs

Part two of a ten part series: Typo3 SEO

Another widely-held SEO best-practice involves the task of including targeted keywords in the webpage URL to make sure that each URL accurately describes your page. The goal here is simply to make each URL as easy-to-read as possible, so that search engine spiders (and humans) have an easier time understanding your site structure. Again, not so hard with smaller sites with only a few static pages. However, with larger, dynamically-generated CMS sites, the results can be undesirable.

For instance, the following URL (and complicated query-string parameters) communicates to users no information regarding the subject matter of the page, or it’s relative hierarchy in the site structure:

www.dawsoninteractive.com/index.php?id=270&type=0&L=1

However, notice how much can be communicated by simply re-writing the above URL in the following format:

www.dawsoninteractive.com/services/web-design

Now, by the URL alone, we’ve told the user (and search engines in particular) about our subject matter and how to categorize this information relative to the rest of the site. Not bad!

So, with Typo3, how do you arrive at clean URLs with no question marks, query strings, special characters, and dashes? Good question! Here’s how:

Typo3 and the RealURL Extension

In order to achieve these so-called “speaking URLs”, you’ll simply need to install the RealURL (realurl) extension. This beautifully written application provides a way to translate between page-IDs and (virtual) URLs that are easy to read and remember. The extension uses the Apache module “mod_rewrite” to rewrite the virtual URLs of the site to the TYPO3 frontend engine.

Here are just a few of the cool features available with the RealURL extension:

  • Supports programmatic or user-defined schemes for coding the page path
  • Page titles can contain spaces and characters like /.,&@ etc, the URL with no problem
  • URLs are generated as nice-looking lowercase paths
  • If a page is renamed, the old URL can still be used, so if the page was indexed by e.g. Google, it can still be found.
  • Offers advanced translation of almost any set of GET parameters to/from virtual URL
  • URLs are cached, so translating between URLs and IDs is very fast.
  • URLs are multilingual: if you're browsing in Dutch, you'll see Dutch URLs
  • Once configured the systems works fully automatic, creating new and updating existing URLs
  • You can easily see where shortcuts are pointing to, as the 'target' URL is generated, instead of the URL to the shortcut itself.


The RealURL installation only takes a few minutes to set up. (I’ve included my default configuration below). Once you get it configured, your URL translation will begin on the next page load.

In addition to any installation of the RealURL extension, I would also recommend adding the RealURL Management and RealURL Configurator backend modules.

RealURL Management

RealURL Management is a backend module that allows you to to delete and change the URLs created by RealURL. It is useful after site-renaming, if RealURL create a URL that you don’t like or if you are done with testing and you want to insert real data. RealURL Management is also very useful for managing aliases, error pages, and page redirects – such as the ability to create 301 permanent redirects in the event that URLs need to be moved:



One of the coolest things about RealURL Management is its ability to change your URLs to whatever you want them to be. So, for example, suppose your keyword analysis told you that “SEM” is a better keyword than “search engine marketing”, and you decided to rename the URL for the Search Engine Marketing page. Simply select the RealURL Management module, and click the pencil icon to edit the page path:

Now, www.dawsoninteractive.com/services/search-engine-marketing has just become www.dawsoninteractive.com/services/sem. Too simple!

RealURL Configurator Backend Module

RealURL Configurator is a tool that allows you to easily edit your RealURL configuration, with syntax check, help, and a few other useful tools:

Dawson Interactive RealURL Configuration

Typoscript template setup:

# RealURL Setup
config.simulateStaticDocuments = 0
config.baseURL = www.dawsoninteractive.com
config.tx_realurl_enable = 1
config.uniqueLinkVars = 1
config.linkVars = L
config.defaultToHTMLsuffixOnPrev = 1

.htaccess setup:

RewriteEngine On
RewriteRule ^typo3$ - [L]
RewriteRule ^typo3/.*$ - [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule .* index.php

RealURL configuration:

$TYPO3_CONF_VARS['EXTCONF']['realurl'] = array(
    '_DEFAULT' => array(
        'init' => array(
            'enableCHashCache' => 1,
            'appendMissingSlash' => 'ifNotFile',
            'enableUrlDecodeCache' => 1,
            'enableUrlEncodeCache' => 1,
        ),
        'redirects' => array(),
        'preVars' => array(
            array(
                'GETvar' => 'no_cache',
                'valueMap' => array(
                    'nc' => 1,
                ),
                'noMatch' => 'bypass',
            ),
            array(
                'GETvar' => 'L',
                'valueMap' => array(
                    'dk' => '2',
                    'de' => '1',
                ),
                'noMatch' => 'bypass',
            ),
        ),
        'pagePath' => array(
            'type' => 'user',
            'userFunc' =>
'EXT:realurl/class.tx_realurl_advanced.php:&tx_realurl_advanced->main',
            'spaceCharacter' => '-',
            'languageGetVar' => 'L',
            'expireDays' => 7,
###### include your rootpage id here
            'rootpage_id' => 1,
        ),
        'fixedPostVars' => array(),
        'postVarSets' => array(
            '_DEFAULT' => array(
                // news archive parameters
                'archive' => array(
                    array(
                        'GETvar' => 'tx_ttnews[year]' ,
                        ),
                    array(
                        'GETvar' => 'tx_ttnews[month]' ,
                        'valueMap' => array(
                            'january' => '01',
                            'february' => '02',
                            'march' => '03',
                            'april' => '04',
                            'may' => '05',
                            'june' => '06',
                            'july' => '07',
                            'august' => '08',
                            'september' => '09',
                            'october' => '10',
                            'november' => '11',
                            'december' => '12',
                            )
                        ),
                    ),
                // news pagebrowser
                'browse' => array(
                    array(
                        'GETvar' => 'tx_ttnews[pointer]',
                        ),
                    ),
                // news categories
                'select_category' => array (
                    array(
                        'GETvar' => 'tx_ttnews[cat]',
                        ),
                    ),
                // news articles and searchwords
                'article' => array(
                    array(
                        'GETvar' => 'tx_ttnews[tt_news]',
                        'lookUpTable' => array(
                            'table' => 'tt_news',
                            'id_field' => 'uid',
                            'alias_field' => 'title',
                            'addWhereClause' => ' AND NOT deleted',
                            'useUniqueCache' => 1,
                            'useUniqueCache_conf' => array(
                                'strtolower' => 1,
                                'spaceCharacter' => '-',
                                ),
                            ),
                        ),
                    array(
                        'GETvar' => 'tx_ttnews[swords]',
                        ),
                    ),
                ),
            ),
        // configure filenames for different pagetypes
        'fileName' => array(
            'index' => array(
                'rss.xml' => array(
                    'keyValues' => array(
                        'type' => 100,
                    ),
                ),
                'rss091.xml' => array(
                    'keyValues' => array(
                        'type' => 101,
                    ),
                ),
                'rdf.xml' => array(
                    'keyValues' => array(
                        'type' => 102,
                    ),
                ),
                'atom.xml' => array(
                    'keyValues' => array(
                        'type' => 103,
                    ),
                ),
            ),
        ),
    ),
);

Next article in this series:

Meta Tags: Creating keyword targeted meta tags with Typo3

write a comment