Creating Search Engine Friendly URLs - Part 2

The first article in this series talked about how to leverage the out of the box functionality of FirstSpirit to optimize your URLs for search engines. Today we want to focus on two additional functions that come with your basic FirstSpirit installation and help to define individual URLs for given pages, namely SEO URLs and Short URLs.

Both functions are available from Global Settings > URL Settings in the SiteArchitect and allow to define special URLs for pages that either override the “automatic” creation of URLs or create additional URLs for one and the same page. To use these features you have to make sure to either use the Advanced URL generation technique or one with the SEO suffix as described in part one of the series.

SEO URLs

SEO URLs can be used to define individual URLs for menu levels and page references from the site structure. This offers the possibility to rename directories and files, even create a directory structure for the web server that differs completely from the website structure as defined in the Site Store. The feature also allows defining individual URLs for every language and template set making it very powerful.

Project administrators can define SEO URLs in Global Settings > URL Settings in the SiteArchitect (formerly known as JavaClient). Allowing each and every editor the right to define URLs for the pages they create is generally not a good idea because it makes it hard to ensure naming standards are met at all times. To grant a specific group of editors the right to edit URLs and/or provide similar functionality in the ContentCreator (aka WebClient), FirstSpirit provides an easy to understand and easy to use API forUrlProperties.

To give you a general idea of what can be achieved with the API, some examples are listed below. Many other uses are possible, most likely your prefered use-case as well.

  • Provide a "Set URL" option in the context menu of every element in the site structure to a given user or user group. Using this option a simple dialog is opened asking the editor for the desired URL.
  • Add an option to the actions menu of the ContentCreator allowing users to define individual URLs for the current site in all languages and all output formats (HTML, PDF, etc.).
  • Automate the creation of SEO URLs based on available data (for example the page title defined by an editor) using a script or module.

Let us have a look on how to implement a script to provide the functionality outlined in the first idea above. The example is designed to be independent of the amount of output channels and languages by creating the form and rules required on the fly, based on the specifics of your project, as it is tedious work to adjust the form for every project and/or every change in a project manually. This is achieved by implementing a script you can also find in the example project attached to this article and which can be used in your projects as well. If you just want the bare Beanshell script, without the project to directly test it, you can find it attached as well.

The Form

The form defines input components for every language and every output channel available in the project. These components are used by the editor to define the desired URL for the given page in the given output channel and language combination.

The form is created on the fly depending on the output channels and languages defined in your project. Below you can see an example of what would be created when two output channels (HTML, PDF) and two languages (EN, DE) are defined in both source and a screenshot.

<CMS_MODULE>
<CMS_GROUP>
<LANGINFOS>
<LANGINFO lang="*" label="HTML"/>
</LANGINFOS>
<CMS_INPUT_TEXT name="HTML_EN" hFill="yes" preset="copy" useLanguages="no">
<LANGINFOS>
<LANGINFO lang="*" label="EN"/>
</LANGINFOS>
</CMS_INPUT_TEXT>
<CMS_INPUT_TEXT name="HTML_DE" hFill="yes" preset="copy" useLanguages="no">
<LANGINFOS>
<LANGINFO lang="*" label="DE"/>
</LANGINFOS>
</CMS_INPUT_TEXT>
</CMS_GROUP>
<CMS_GROUP>
<LANGINFOS>
<LANGINFO lang="*" label="PDF"/>
</LANGINFOS>
<CMS_INPUT_TEXT name="PDF_EN" hFill="yes" preset="copy" useLanguages="no">
<LANGINFOS>
<LANGINFO lang="*" label="EN"/>
</LANGINFOS>
</CMS_INPUT_TEXT>
<CMS_INPUT_TEXT name="PDF_DE" hFill="yes" preset="copy" useLanguages="no">
<LANGINFOS>
<LANGINFO lang="*" label="DE"/>
</LANGINFOS>
</CMS_INPUT_TEXT>
</CMS_GROUP>
<CMS_LABEL>
<LANGINFOS>
<LANGINFO lang="*" label="The URL for empty fields is determined using the standard behavior upon generation."/>
<LANGINFO lang="DE" label="Die URL für leere Felder wird beim Generieren mit dem Standard-Verhalten erzeugt."/>
</LANGINFOS>
</CMS_LABEL>
</CMS_MODULE>

The Rules

Similar to the form described above, the rules required are also created on the fly. To provide the functionality required we need to implement two rules.

The first rule is created for each input component of the form. It checks if the URL entered by the editor is in a valid format using a regular expression and displays an error message if it is not. The form can, of course, only be saved when all URLs are valid. It basically looks like this:

<ON_SAVE>
<IF>
<NOT>
<PROPERTY source="HTML_EN" name="EMPTY"/>
</NOT>
</IF>
<WITH>
<MATCHES regex="^(/.*\.html)|(\s*)$"><PROPERTY source="HTML_EN" name="VALUE"/></MATCHES>
</WITH>
<DO>
<VALIDATION>
<PROPERTY source="HTML_EN" name="VALID"/>
<MESSAGE lang="*" text="Required format: /path/filename.html"/>
</VALIDATION>
</DO>
</ON_SAVE>

The second rule is dynamically injected once the form was submitted. This rule will only be created for entered URLs that are already used elsewhere in the project to avoid duplicates. If the URL entered by the editor is unique no errors will occur and the rule is simply not present. Please refer to the explanation of the script below to see how this works in detail. This rule looks like this when necessary:

<ON_SAVE>
<IF>
<NOT>
<PROPERTY source="HTML_EN" name="EMPTY"/>
</NOT>
</IF>
<WITH>
<MATCHES regex="^(/.*\.html)|(\s*)$"><PROPERTY source="HTML_EN" name="VALUE"/></MATCHES>
</WITH>
<DO>
<VALIDATION>
<PROPERTY source="HTML_EN" name="VALID"/>
<MESSAGE lang="*" text="Required format: /path/filename.html"/>
</VALIDATION>
</DO>
</ON_SAVE>

If you want to learn more about rules in general, please have a look at the FirstSpirit <RULES>! article published earlier on Inside FirstSpirit and covering the basics in part one. A second part covering the use of ValueServices will follow soon.

The Script

The most interesting part of the example is the script which does most of the work. The whole script is available in the project attached to this article. Below we want to step through the most important parts of it. Further information can be gatherd from the comments inside of the script and you are more than welcome to ask further questions below.

Starting at line 21 the script iterates all output channels (aka template sets) and languages available in the project to assemble the form and the first rule described above. This is done every time the script is called so it is able to adjust itself to all changes made to the project and even work out of the box in every project you add it to.


Line 76 and following then read all URLs already stored for the current page reference and adds these as default values to the form. This allows the editor to see what URLs are already set and allows him to delete or modify them.

After the form was shown to and submitted by the editor the URLs entered are validated starting in line 104. If everything is valid the URL is finally stored in FirstSpirit or, in case the editor wants to delete a URL previously defined, removed from the URL storage. In case the URL entered is already in use by another page reference the second rule mentioned above is injected and the dialog is opened again informing the editor about the problem.

Setting SEO URLs in the ContentCreator

Certainly, setting the URLs as demonstrated above also works in the ContentCreator. To make the functionality available to the user you simply define a FS_BUTTON in the form of your templates to call the script…

<FS_BUTTON
name="pt_setSeoUrls"
hFill="no"
hidden="yes"
icon="fs:action"
noBreak="no"
onClick="script:set_seo_urls"
style="button"
useLanguages="no">
<LANGINFOS>
<LANGINFO lang="*" label="Set SEO URLs"/>
<LANGINFO lang="DE" label="SEO URLs setzen"/>
</LANGINFOS>
</FS_BUTTON>

… and add it to the output channel:

$CMS_IF(#global.is("WEBEDIT"))$
<span$CMS_VALUE(fsbutton(editorName: "pt_setSeoUrls"))$></span>
$CMS_END_IF$

Short URLs

Similar to the SEO URLs explained above, Short URLs can be used to define URLs for menu levels and page references from the site structure. In contrast to the SEO URLs, there can be more than one URL for each item and the use case is slightly different. Consider Short URLs as alternative URLs for one and the same content which can for example be used to create landing pages. In general, these are brief, expressive URLs as you might have already guessed from the name. Short URLs are always generated in addition to the "normal" URL, allowing you to define constructs like the following, where each of the URLs lead to the same content:

Normal URL: http://www.example.com/products/tablets/ipad
1. Short URL: http://www.example.com/ipad
2. Short URL: http://www.example.com/ipad-summer-sale

You probably have seen a lot of examples of these URLs in real life already. They are for example used in campaigns advertised in TV and radio spots or on billboards to have a short URL the viewers/listeners can remember easily. Having different Short URLs for different channels of a multi channel marketing campaign also allows your marketing department to track them individually and thus find out which channel worked best.

When defining more than one URL for the same content it makes sense to inform search engines about this so they do not detect duplicate content. Please refer to the article Search Engine Optimization using Canonical Tags on Inside FirstSpirit to learn more about this topic.

Short URLs can be defined by project administrators in Global Settings > URL Settings in the SiteArchitect (aka JavaClient), just like you can with SEO URLs. Again, the UrlProperties provide a lot of API functionality to create custom functionality around this feature and you can read more in the API documentation for UrlProperties. Please refer to the example explained in the SEO URL chapter to get an idea of what can be done and how to approach the implementation of this feature.

More on SEO URLs and Short URLs can also be found in chapter 6.1.15 of the Release Notes for FirstSpirit 5.0.