Adventures In Theming: The Final Chapter

This is the seventh post in a short series about the ideas, trials and tribulations of my first theme product. I’ll be posting the whole story in one place when the series is complete.

I’m Not Done Yet

Now that the theme is finished, there are a few more steps before I can consider it truly complete.

  1. Does it work in IE? Or FireFox, or Safari, or Konqurer or Your Cellphone or a screen reader…. It’s important to test your theme across a few browsers. Chances are if you follow the Plone WayTM, you won’t have too much trouble, but it’s always a good idea. This goes beyond the usual web designer’s perogative. You’ve opted to use a CMS that prides itself in graceful fallbacks, cross-browser compatibility and accessability. Make sure you’re not stomping all over those ends just so you can have a "rad" theme.

  2. Is anything missing? Much like how I missed the footer in my theme, there are other bits and pieces of Plone that your theme may not have taken into account. A good example of this is the calendar portlet. There are some very specific CSS rules that you may have to override to get your theme to take affect.

    It’s a good idea to add all the stock portlets, and install any third-party products you plan to use with your site into your theme product’s development buildout. Poke around the site, and make sure you didn’t miss anything. It may be the product or portlet developer’s fault, but it’s up to you as the theme creator to cover all the bases.

  3. Can you change themes? There is a theme control panel configlet (http://localhost:8080/plone/@@skins-controlpanel) that has a dropdown list allowing you to select the current theme. You should be able to select the "Default Plone" theme without any lingering effects.

    You will however, notice some immediate effects :). Reload the page, restart the server and poke around again like you did earlier just to be sure.

    If you find reminates, they can probably be attributed to forgetting to associate a stylesheet or viewlet customization specifically with your theme.

  4. Does it uninstall? If you do more than add theme-specific viewlets, make sure that nothing breaks when you uninstall your theme. This is especially important if you ever want to distribute your theme to other people, but even if it’s for internal use only, it will make you happier in the long run.

Walking through these steps myself, here’s what I discovered.

It looks funny in IE

A preliminary glance in IE 6 (installed on my Ubuntu Hardy system via IEs4Linux) showed some messy bits under my theme relating to portlets, but the same issues come up with the default Plone theme, so I’m counting this one passable.

I’m in the process of getting a new windows VM up and running so I can test "real" IE6 and IE7 (and probably IE8-beta just for kicks)

I need to dig a bit and see if IE6 compatibility is a priority for Plone, and see if there are any bugs relating to this issue (I’m sure there are, but I should verify)

Odd Portal Rows

I hadn’t noticed it before, but there are special odd/even classes for portlet content like there are for listing tables (e.g. folder contents). I added a bunch of portlets to my layout, and added some events and recent changes. I tried to cover as many bases as I could for the sake of throughness.

After adding all the content, I noticed that the portal footers and headers looked nice, but the content seemed a bit messy, as each item in the events and recent changes portlets would run together. I investigated a bit and found that there was class="portletItem even" and class="portletItem odd" attributes specified in the portlet content.

To account for this, I added the following to my CSS


.portletItem.even {
    background-color: #ecf0f5;


In testing the theme, I found out that the theme itself isn’t "deleted" when the product is uninstalled, inspite of the fact that all of it’s required resources and viewlets are no longer available.

And worse, the theme is still set as the default theme. This leaves the site in a more-or-less broken state to the end user, who may not realize they need to change the default theme to a theme that’s actually available still. And the theme stays in the dropdown list.

To fix this requires setting up an uninstall profile. This is documented on, but I’ll show you what I did in my case.

First, I created a new directory called uninstall in my profiles directory.

$ cd ~/my.theme/src/my/theme/profiles
$ mkdir uninstall

Then I added the XML files that made up the profile. It’s basically what I did in the default profile, but with remove="True" added to the bits I wanted to remove, and the default theme changed back to a sane default.


<?xml version="1.0"?>
<object name="portal_skins" 
   default_skin="Plone Default">

 <object name="my_theme_custom_images" remove="True"/>
 <object name="my_theme_custom_templates" remove="True"/>
 <object name="my_theme_styles" remove="True"/>

 <skin-path name="My Theme" based-on="Plone Default" remove="True">
  <layer name="my_theme_custom_images"
     insert-after="custom" remove="True"/>
  <layer name="my_theme_custom_templates"
     insert-after="my_theme_custom_images" remove="True"/>
  <layer name="my_theme_styles"
     insert-after="my_theme_custom_templates" remove="True"/>


You need just enough information to let GenericSetup find the configuration bits that need to be removed, so you may notice that I removed some of the extra attributes from this skins.xml.

Then, I had to wire up the profile. This is a multi-part process, that starts with registering the profile with ZCML


      title="My Theme - Uninstall"
      description='"My Theme" Plone theme. - UNINSTALL'

This is esentially the same as the other <genericsetup:registerProfile> tag that ZopeSkel already put into profiles.zcml for you, modified slightly to reflect the location and name of the new profile.

Now I’ve got a brand new GenericSetup profile, but no way to invoke it using the add/remove products interface that my users will be acustomed to. This means I’ll have to apply the uninstall profile with python code.

This is accomplished by bringing back an old-school, but still effective, method of controlling what happens when Plone installs or uninstalls a product: Extensions/

The Extensions directory is not created for us by ZopeSkel, so we need to create it ourselves.

$ cd ~/my.theme/src/my/theme/
$ mkdir Extensions

Then we need to create the file. This file can contain 3 functions: install(), uninstall(), and upgrade(). Each function will only be called if it’s present, and can basically do whatever you want. This is a very straight-forward way to add in some "magic" activity upon install, do some migration upon upgrade, or as in our case, tidy up when the product is being removed. It’s definately the go-to proceedure when GenericSetup doesn’t do what you want, or time prevents you from implementing a GenericSetup-based solution effectively.


from Products.CMFCore.utils import getToolByName

def uninstall(portal):
    setup_tool = getToolByName(portal, 'portal_setup')
    return "Ran all uninstall steps."

You can find out more about the setup_tool‘s API by inspecting it with DocFinderTab or looking at the source code (in parts/plone/CMFQuickInstallerTool)

This entry was posted in Uncategorized and tagged . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s