Creating a theme package with ZopeSkel

(Read more interesting articles on Plone here.)

Download code from here

Creating a theme package with ZopeSkel

Now that we have examined someone else's theme, let us try creating our own.

Remember, we will not cover theme creation in depth; this is only a sample for site administrators (who may or may not be required to develop themes, in addition to managing their site).

For more information about creating themes, Visit:

To create a theme, we will use the ZopeSkel tool ( to generate some of the boilerplate code. ZopeSkel uses PasteScript ( to facilitate package generation using a set of templates.

Other options include:

  • Write everything by hand from memory
  • Copy the contents of another theme package
  • Use another tool such as ArchGenXML to generate boilerplate code (

Adding ZopeSkel to a buildout

Now let's add ZopeSkel to our buildout.

In 03-appearance-zopeskel.cfg, we have this:

extends = 03-appearance-zopepy.cfg
parts +=

recipe = zc.recipe.egg
dependent-scripts = true

We extend the previous working configuration file, and add a new section called zopeskel.

This section uses the zc.recipe.egg recipe ( to download ZopeSkel from the Python Package Index (zc.recipe.egg will search the Python Package Index for packages that match the section name zopeskel).

We set dependent-scripts to true, to tell Buildout to generate Python scripts for ZopeSkel's dependencies such as PasteScript, which includes the paster script.

Now stop Plone (with Ctrl + C or Ctrl + Z/Enter) and run Buildout:

$ bin/buildout -c 03-appearance-zopeskel.cfg

You should see:

$ bin/buildout -c 03-appearance-zopeskel.cfg

Uninstalling plonesite.

Updating zope2.

Updating fake eggs

Updating instance.

Installing plonesite.

Updating zopepy.

Installing zopeskel.

Getting distribution for 'zopeskel'.

Got ZopeSkel 2.16.

Getting distribution for 'Cheetah>1.0,<=2.2.1'.

Got Cheetah 2.2.1.

Getting distribution for 'PasteScript'.

Got PasteScript 1.7.3.

Getting distribution for 'PasteDeploy'.

Got PasteDeploy 1.3.3.

Getting distribution for 'Paste>=1.3'.

Got Paste

Generated script '/Users/aclark/Developer/plone-site-admin/
Generated script '/Users/aclark/Developer/plone-site-admin/
Generated script '/Users/aclark/Developer/plone-site-admin/
Generated script '/Users/aclark/Developer/plone-site-admin/

You will notice that in addition to bin/zopeskel, Buildout also installed the "dependent scripts" bin/paster and bin/easy_install (the latter of which we do not really need in this case).

Running ZopeSkel

Now try running ZopeSkel with the command:

$ bin/zopeskel

You should see:


zopeskel <template> <output-name> [var1=value] ... [varN=value]

zopeskel --help Full help

zopeskel --list List template verbosely, with details

zopeskel --make-config-file Output .zopeskel prefs file


This tells us we need to pick a template and output-name.

ZopeSkel goes on to list the available templates. They are:


A Plone project that uses Archetypes content types


A project for a KSS plugin


A project for Plone products


A theme for Plone 2.1


A Plone 3 portlet


A project for Plone products with a nested namespace


A project for a Plone PAS plugin


A theme for Plone 2.5


A theme for Plone 3


A buildout for Plone 2.5 projects


A buildout for Plone 3 installation


Plone hosting:

buildout with ZEO and Plone



A recipe project for zc.buildout


A buildout for Silva projects


A basic Python project with a namespace package


A basic Python project with a nested


A Zope project

(Read more interesting articles on Plone here.)

In our case, we will choose plone3_theme.

The output-name is the name of the package we want to create for example, my.theme.

Since we are creating a new package, let us change directories to the src directory and run ZopeSkel from there, like this:

$ cd src

$ ../bin/zopeskel plone3_theme my.theme

You should see:

$ ../bin/zopeskel plone3_theme my.theme

plone3_theme: A theme for Plone 3

This creates a project for a theme for Plone 3.

This will be followed by a series of questions, which you can answer based on these suggestions:

  • Mode: Easy: This mode asks the least number of questions it needs to do its job.
  • Skin name: My Theme: This name will show up in various places, including Site Setup Add/Remove Products|.
  • Empty styles: False: This means we want our theme to look like the Plone Default theme. If you answer True, you will get an unstyled theme instead.
  • Include documentation: True: This means our code will be generated with helpful comments included inline.
  • Version: 1.0: This means our theme is ready for production use! Feel free to adjust this value if you like.
  • Description: An installable theme for Plone 3: You can change this to whatever you like.

Running Paster

Next, when ZopeSkel completes, it tells us about the additional commands we can run to generate more boilerplate code.

We do not need to do it now, but if you are curious, try this:

$ cd my.theme

$ ../../bin/paster addcontent --list-all

You should see the following templates available (to generate more boilerplate code):

anonymous_user_factory_plugin: Plugin


A Plone PAS AnonymousUserFactory



A handy AT schema builder


A Plone PAS Authentication Plugin


A Plone PAS Challenge Plugin


A content type skeleton


A Plone PAS CredentialsReset Plugin


A Plone PAS Extraction Plugin


A form skeleton


Schema field for a form


A Plone PAS GroupEnumeration Plugin


A Plone PAS Groups Plugin


An i18n locale directory structure


A Plone 3 portlet


A Plone PAS Properties Plugin


A Plone PAS RoleAssigner Plugin


A Plone PAS RoleEnumeration Plugin


A Plone PAS Roles Plugin


A Plone PAS Update Plugin


A Plone PAS UserAdder Plugin


A Plone PAS UserEnumeration Plugin


A Plone PAS UserFactory Plugin


A Plone PAS Validation Plugin


A browser view skeleton


      A ZCML meta directive skeleton

Some of these which apply to themes are:

  • i18nlocale
  • portlet
  • view

To add a portlet (little boxes on the left and right side of your site) to your theme,try this:

$ ../../bin/paster addcontent portlet

We could go on, but let's come back to basics now.

We now have a new theme package, but we do not have a new theme package in our buildout or in Plone. Let us now add our package to the buildout and to Plone.

The easiest way to do this is to tell Buildout we are developing a new package, by setting the value of the develop parameter in the buildout section to our package name (and relative filesystem path, in this case src/my.theme).

In addition to making Plone aware of this package, we must list it in the eggs parameter of the instance section.

In 03-appearance-develop.cfg, we have:


extends = 03-appearance-zopeskel.cfg
develop = src/my.theme

eggs += my.theme

Now stop Plone (with Ctrl + C or Ctrl + Z/Enter) and run Buildout:

$ bin/buildout -c 03-appearance-develop.cfg

You should see:

$ bin/buildout -c 03-appearance-develop.cfg
Develop: '/Users/aclark/Developer/plone-site-admin/buildout/src/my.theme'
Uninstalling plonesite.
Updating zope2.
Updating fake eggs
Updating instance.
Installing plonesite.

The first line indicates that Buildout has recognized our new package. You may encounter an error during the Buildout run, when the collective.recipe.plonesite recipe tries to start Plone and add a Plone site. Ignore that for now. In fact when Buildout finishes and you restart Zope, you may see an (obnoxiously long) error like this:

$ bin/instance fg

runzope -X debug-mode=on

2010-05-02 11:38:08 INFO ZServer HTTP server started at Sun May 2
11:38:08 2010

OSError: [Errno 2] No such file or directory: '/Users/aclark/

But this error is good; it means we have succeeded in adding our package to Buildout and Plone.

To fix this error (if you get it), create a locales directory where Plone says one isneeded (ZopeSkel forgot to do this for us; a future release that is a release newer than ZopeSkel 2.16 should address the problem.):

$ mkdir src/my.theme/my/theme/locales

Now start Plone and you should see:

$ bin/instance fg

runzope -X debug-mode=on

2010-05-02 11:44:28 INFO ZServer HTTP server started at Sun May 2
11:44:28 2010

Port: 8080

2010-05-02 11:44:40 INFO Application New disk product detected,
determining if we need to fix up any ZClasses.

2010-05-02 11:44:40 INFO Zope Ready to handle requests

The second to last line indicates that Zope 2 has found our package!

Next, browse to http://localhost:8080/Plone. Now, click on Site Setup Add/Remove Products |and look for our package in the Quick Installer:

Check the box next to My Theme 1.0 and click Install.

You will notice the beyondskins.ploneday.site2010 theme has disappeared, and the Plone Default theme has returned (because My Theme 1.0 is based on Plone Default).

Now that our theme is installed, we can try to make a simple customization, like changing the logo.

To do that, we are going to copy a file with the same name as the default logo to our custom images directory: src/my/theme/skins/my_theme_custom_images.

But how do we know the logo image filename? One easy way to find it is to use the Firefox web browser with the Firebug add-on installed (

The next step is to add a file of the same name to the custom images folder in our theme package.

You can use any image, but we will use plone-logo-128-white-bg.png from the Plone logo pack on (

For adding the file just mentioned:

$ cp ~/Desktop/plone-logo-128-white-bg.png my.theme/my/theme/skins/my_

Now without restarting Plone (assuming you are running it in the foreground with bin/instance fg), reload the front page and you should see:

This is a simple example of customizing Plone with a filesystem theme package. We can customize many aspects of Plone's appearance using this technique.

Why did this work?

You may wonder why we copied plone-logo-128-white-bg.png to logo.jpg. The short answer is because it works, and the file extension does not matter.

The medium length answer is that we have registered a new filesystem directory view and it is higher in the skin resolution order than Plone's filesystem directory view. Both contain an object called logo.jpg, but ours is discovered first.

The long answer is that there is a feature in Zope 2 called Acquisition that makes this customization possible ( In addition to the (core) Acquisition feature, there is a powerful add-on called the Content Management Framework (CMF) that Plone uses extensively. Plone registers a filesystem directory view and adds resources to it; then we customize a resource by ensuring it is acquired before Plone's resource is acquired.


In this article we have learned how to create a theme using the ZopeSkel tool to generate some of the boilerplate code.

If you have read this article you may be interested to view:

You've been reading an excerpt of:

Plone 3.3 Site Administration

Explore Title