You are here: Home / Documentation / How To's / How to create redirects, or, Have your own URL shortener!

How to create redirects, or, Have your own URL shortener!

by nguyen — published Aug 16, 2016 10:50 AM, last modified Aug 16, 2016 10:50 AM
We use this method on our site

What / Why

A while ago we saw the need for our own URL shortener service, and so we created the Plone site.  

For example, you can visit

and it'll redirect you to


Each redirect is a DTML Document created through the ZMI.  For the above example, we created a DTML Method and gave it the ID "associate", and its body is:

<dtml-var standard_html_header>
<h2><dtml-var title_or_id></h2>
<dtml-let target="''">
<dtml-call expr="RESPONSE.redirect(target)">
<dtml-var standard_html_footer>

Making it easier to use

To make it easy to create such a redirect, we have a Controller Page Template called ".addAlias" with this body:

    <title tal:content="template/title">The title</title>
  <body tal:define="errors options/state/getErrors">
        <span tal:condition="template/title"
              tal:replace="template/title">optional template id</span></h2>

    <p>This lets you add an alias that redirects to another URL.</p>

This is useful if you have a web page located at a URL that is hard to remember and you'd like to provide a shorter or more memorable URL.

<p>For example, if you want to redirect "" to "", the alias is "shortname". 

<p>Once you are done, you can tell people to browse to "".

    <p>There are initially no validators assiciated with this page template, 
       so the state will always be 'success' after you submit the form.  You
       will need to define an action for the 'success' state or you will get an 
       error when you submit the form.</p>

    <form method="POST" tal:attributes="action string:${here/absolute_url}/${template/id};">
      <p class="error_message" tal:define="err errors/alias|nothing" tal:condition="err"><b tal:content="err" /></p>
      <p class="error_message" tal:define="err errors/destinationURL|nothing" tal:condition="err"><b tal:content="err" /></p>

      <p>The alias you want to create:<input tal:attributes="value request/alias|nothing" name="alias" type="text" value=""></p>

      <p>The full destination URL of the alias you want to create: <input tal:attributes="value request/destinationURL|string:http://" name="destinationURL" type="text" value="http://"></p>

      <p><input type="submit" name="form.button.submit" value="Submit" /></p>

      <input type="hidden" name="form.submitted" value="1" />


The Controller Validator ".checkAlias" contains:

# validate your variables here
alias = context.REQUEST.get('alias', None)
if not alias:
   state.setError('alias', 'Please enter a value for the alias')
if getattr(container, alias, None):
   state.setError('alias', 'That alias exists already.  Please enter another value for the alias')

destinationURL = context.REQUEST.get('destinationURL', None)
if not destinationURL:
   state.setError('destinationURL', 'Please enter a value for the destination URL')
if not destinationURL.startswith('http://') and not destinationURL.startswith('https://'):
   state.setError('destinationURL', 'The destination URL is not correctly formed.  Please enter a full "http://" or "https://" URL for the destination URL.')

if state.getErrors():
   # An error has occurred.  Set the status to 'failure' 
   # (the default initial status is 'success')

# No errors.  Always make sure to return the ControllerState object
return state

The Controller Python Script called ".createAlias" and its body is:

# Get a value from the REQUEST
alias = context.REQUEST.get('alias')
destinationURL = context.REQUEST.get('destinationURL')

# do something with the value here
dtmlMethod = getattr(container, alias, None)
if dtmlMethod:
<dtml-let target="'%s'">
<dtml-call expr="RESPONSE.redirect(target)">
   """ % destinationURL, '')
   # (Optional) set the default next action (this can be overridden
   # in the script's actions tab in the ZMI).
   state.setNextAction('redirect_to:string:%s/manage_main' % dtmlMethod.absolute_url())
   state.setError('alias', 'Unable to create the alias for some unknown, unfathomable reason.')
# Always make sure to return the ControllerState object
return state