Generating Apache redirects from sitemap.xml for WordPress using Python

Sitemap.xml (Sitemaps) is a protocol exposing website pages for the search engines. Beyond hinting crawler bots you can find some creative uses for it.

I was migrating blog posts from one WordPress site to another. I wanted to have the old site still run the front page and few other static pages and I wanted to move the blog posts only. A best practice for content migrations is set HTTP 301 Moved Permantently redirects on the orignal web server so that users and search engines following old links will automatically find the new content.

WordPress sites were and are hosted on Apache web server. Since writing Apache .htaccess redirects by hand is something no living soul wants to do, I wrote a little Python script using Requests (a.k.a. urllib done right) and lxml libraries.

This script will

  • Read sitemap.xml.gz file
  • Extract page URLs out of it
  • (add optional filtering step here)
  • Output Apache .htaccess redirect rules so that old links will point to the new site

The beauty of scraping the information from sitemap.xml: Even though this script was written for WordPress it is valid for any CMS supporting Sitemaps protocol. (hint: Plone, Drupal, Joomla!, you name it.. they all support it)

In theory one could run this script in cron so that all new WordPress content gets automatically redirected continuously.

In additional for setting up .htaccess WordPress provides easy export and import tool for blog posts through its admin interface.

And the script:

# Python stdlib
from StringIO import StringIO
import urlparse

# 3rd party
import requests
from lxml import etree

# Sitemap of the source site
SITEMAP_URL = "http://mobilizejs.com/wp-content/plugins/simple-google-sitemap-xml/sitemap.xml"

# Where posts will be moved
NEW_DOMAIN="http://opensourcehacker.com"

# Apache .htaccess line template
# http://httpd.apache.org/docs/2.0/mod/mod_alias.html#redirectmatch
REDIRECT_TEMPLATE="RedirectMatch permanent %(path)s$ %(new_domain)s%(path)s"

response = requests.get(SITEMAP_URL)

def create_apache_redirect_to_other_domain(url, new_domain):
    """
    Creates .htaccess redirect entry.

    Create HTTP 301 Permanent Redirect.

    Output is something along lines::

        RedirectMatch permanent /tag/cache-control/$ http://opensourcehacker.com/tag/cache-control/

    """
    parts = urlparse.urlparse(url)

    vars = {
        "new_domain" : new_domain,
        "path" : parts.path          
    }    

    # Simple Python string template substituion
    return REDIRECT_TEMPLATE % vars

# Parse sitemap
tree = etree.parse(StringIO(response.content))
root = tree.getroot()

locs = root.xpath("//*[name()='loc']")

# Iterate through each sitemap <loc> entry and creating corresponding redirect
for loc in locs:
    url = loc.text
    redirect_line = create_apache_redirect_to_other_domain(url, NEW_DOMAIN)
    print redirect_line

 

\"\" Subscribe to RSS feed Image Follow me on Twitter Image Follow me on Facebook Image Follow me Google+

Making an offline file system copy of a Plone site using WebDAV

You might want to create an offline copy of a Plone site because

  • You are traveling and you want to have all files on the site (PDFs for reading)
  • You are taking a site down and making the final back-up
  • You just want to feel how cool Plone is

Plone supports WebDAV.

Creating a file system viewable offline copy of a Plone site is a task of

  • Enabling WebDAV
  • Login to site via WebDAV. On OSX use Cyberduck, Finder (the file browser of OSX itself) may have issues, though works. You might need Zope admin priviledges for certain operations.
  • Drag and drop Plone site to your hard disk

WebDAV copy process works smoothly

  • Folder and page structure is intact
  • Files are copied as is (think PDFs, Docs)
  • Images are copied as is
  • Pages (HTML) are converted to special files, which are still readable in plain-text editor

Note that some special folders (acl_users, reference_catalog, etc.) might be exposed through WebDAV, but they are not really copyable. Just ignore these during the copy process.

You can also use WebDAV to mass upload files and images for your image bank instead of manually uploading them through web interface.

\"\" Subscribe to RSS feed Image Follow me on Twitter Image Follow me on Facebook Image Follow me Google+

Importing and exporting Plone folders using quintagroup.transmogrify

0. Exporting single folder only

Here is explained how to export and import Plone CMS folders between different Plonen versions, or different CMS systems, using XML based content marshalling and quintagroup.transmogrifier.

This overcomes some problems with Zope management based export/import which uses Python pickles and thus needs identical codebase on the source and target site. Exporting and importing between Plone 3 and Plone 4 is possible.

You can limit export to cover source content to with arbitary portal_catalog conditions. If you limit source content by path you can effectively export single folder only.

The recipe described here assumes the exported and imported site have the same path for the folder. Manually rename or move the folder on source or target to change its location.

Note: The instructions here requires quintagroup.transmogrify version 0.4 or later … or trunk version during the writing of this blog post.

1) Source site

Execute these actions on the source Plone site.

Install quintagroup.transmogrifier via buildout and Plone add-on control panel.

Go to Site setup > Content migration.

Edit export settings. Remove unnecessary pipeline entries by looking the example below. Add a new catalogsource blueprin. The exclude-contained option makes sure we do not export unnecessary items from the parent folderst:

.

[transmogrifier]
pipeline =
    catalogsource
    fileexporter
    marshaller
    datacorrector
    writer
    EXPORTING

[catalogsource]
blueprint = quintagroup.transmogrifier.catalogsource
path = query= /isleofback/ohjeet
exclude-contained = true

Also we need to include some field-level exluding bits for the folders, because the target site does not necessary have the same content types available as the source site and this may prevent setting up folderish content settings:

[marshaller]
blueprint = quintagroup.transmogrifier.marshaller
exclude =
  immediatelyAddableTypes
  locallyAllowedTypes

You might want to remove other, unneeded blueprints from the export pipeline. For example, portletexporter may cause problems if the source and target site do not have the same portlet code.

Go to Zope Management Interface > portal_setup > Export tab. Check Content (transmogrifier) step. Press Export Selected Steps at the bottom of the page. Now a .tar.gz file will be downloaded.

During the export process instance.log file is updated with status info. You might want to follow it in real-time from UNIX command line

tail -f var/log/instance.log

In log you should see entries running like:

2010-12-27 12:05:30 INFO EXPORTING _path=sisalto/ohjeet/yritys/yritysten-tuotetiedot/tuotekortti
2010-12-27 12:05:30 INFO EXPORTING
Pipeline processing time: 00:00:02
          94 items were generated in source sections
          94 went through full pipeline
           0 were discarded in some section

2) Target site

Execute these actions on the target Plone site.

Install quintagroup.transmogrifier via buildout and Plone add-on control panel.

Open target site instance.log file for monitoring the import process

tail -f var/log/instance.log

Go to Zope Management Interface > portal_setup > Import tab.

Choose downloaded setup_toolxxx.tar.gz file at the bottom of the page, for Import uploaded tarball input.

Run import and monitoring log file for possible errors. Note that the import completes even if the target site would not able to process incoming content. If there is a serious problem the import seems to complete succesfully, but no content is created.

Note: Currently export/import is not perfect. For example, ZMI content type icons are currently lost in the process. It is recommended to do a test run on a staging server before doing this process on a production server. Also, the item order in the folder is being lost.

\"\" Subscribe to RSS feed Image Follow me on Twitter Image Follow me on Facebook Image Follow me Google+