Building our own Plone 3 Theme Add-on Product

(For more resources on Plone, see here.)

We can build our own theme add-on product from scratch. It can be done easily with PasteScript. Just type this on our command line from the root of our buildout:

$ cd src
$ paster create -t plone3_theme plonetheme.myintranet

Answer all the questions with the default option except for:

  • Skin Name: A human facing name for the theme, added to portal_skins, for example, MyIntranetTheme.
  • Skin Base: Name of the theme from which this is copied. By default, it is Plone Default. Answer the default option here.
  • Empty Styles?: If true, it will override default public stylesheets with empty ones. Answer False.
  • Include documentation?: If true, the generated theme will include auto- explanatory documentation, desirable for beginners.

The resultant theme add-on product will be generated in the src buildout folder. This add-on is completely usable right now, but it's innocuous. Once installed, it will replace the original Plone default theme with the one in this package.

Installing the product

Just proceed as any other add-on product. However, since we are developing the product, we should specify it in our buildout by filling the develop directive in the buildout section and the eggs directive in the instance section in our buildout.cfg file:

develop = src/plonetheme.myintranet
eggs = plonetheme.myintranet

Go to the package folder, src/plonetheme.myintranet/plonetheme/myintranet, and edit the configure.zcml file. As we don't want to define an i18n folder, delete the following line if it exists:

<i18n:registerTranslations directory="locales" />

And then, rerun buildout.cfg:

$ ./bin/buildout
$ ./bin/instance fg

Now, go to the Add-on Products control panel configlet and install it.

If we browse our site, we will notice that nothing has changed, because we've chosen to inherit the default theme in our new one. But, now the theme defined in our theme add-on product is in use in our site. Check it out in portal_skins:

Building our own Plone 3 Theme Add-on Product

Notice three things in the previous screenshot: the Default skin is our recently created skin and three additional Plone skin layers have been added to the top of the layer's precedence order list. These three layers will contain the resources we may need for our new theme. These layers represent three folders inside our package structure; to be more precise, those inside skins folder:

Name of the layer/folder



It will contain our theme images.


It will contain our theme custom templates.


It will contain our theme styles.

In fact, this layer organization is merely for convenience, as all the layers can contain any type of resources.

Customizing Plone skin layer resources

As our theme product is positioning the new layers on the top of the precedence order, the elements we place in these folders will override those in layers with less precedence. Just place our custom resource in any of the layers defined by our product and name it as the original one. Our custom resource will override the default one. We can also place other resources we may use, such as our custom templates, images, and styles as well.

Enabling CSS debug mode

By default, the changes made to our product will not be available until we restart our instance. For the changes to take effect immediately, we should enable CSS debug mode in CSS resource registry. We will find this setting at the top of the portal_css ZMI view.

In debug/development mode, stylesheets are not merged to composites, and caching and compression of CSS is disabled. The registry also sends HTTP headers to prevent browsers from caching the stylesheets. It's recommended to enable this mode during CSS-related development. Remember to turn it off again when we finish CSS modifications, as debug mode affects site performance.

Customizing the site logo

Plone renders the site logo combining two kinds of resources—the viewlet plone. logo provides the HTML structure needed and a Plone skin layer image. Let's say we want to change the site logo and add an additional logo of our company containing a link to the corporate web besides it. We need to customize the original logo with the logo of our intranet and add the required HTML structure to add the new company logo besides the original one. We will need to customize the original logo and the plone.logo viewlet. Later, we will need to add our company logo as a new Plone skin layer image.

Customizing the logo image and adding a new one

We should override the original logo image with our customized one. In order to accomplish this, we should rename the image we've chosen to use as our site logo with the same name as the original one. The original logo image is called logo.jpg and it is located in the plone_images skin layer. We override it by simply placing our customized image inside skins/plonetheme_myintranet_custom_images and naming it exactly the same as the original one. Place the image for the second logo here too, and name it as company-logo.png.

Customizing the plone.logo viewlet

Customizing a viewlet is a little trickier than overriding skin layer resources. We will need to tell Zope that we want to override the original viewlet declaration by creating an overrides.zcml file in the plonetheme/myintranet folder of our custom add-on product, and add the attribute that tells Zope where to find the new template associated to this viewlet:

<!-- The new logo viewlet declaration -->
permission="zope2.View" />

Then place this Zope page template called in the browser folder of our add-on product:

<a id="portal-logo-company"
tal:attributes="href string:">
<img src="company-logo.png"
alt=" logo"
title=" logo"/></a>
<a metal:define-macro="portal_logo"
tal:attributes="href view/navigation_root_url"
<img src="logo.jpg" alt=""
tal:replace="structure view/logo_tag" /></a>

We leave the original logo template at the end of the file and add a new link tag with the structure for the new logo and the reference to the new Plone skin layer image (company-logo.png).

Restart our instance to see the changes applied. This is needed because we have overridden a viewlet defining an additional ZCML file.

(For more resources on Plone, see here.)

Customizing Plone CSS

If you followed the previous example, you've probably noticed that the recently added new logo is somehow displaced. If we want to adjust its position, we will need to customize some CSS files. In this case, we need to define a style for the new ID (portal-logo-company) introduced by the structure of the company logo. We can do it in an empty CSS file provided by the PasteScript template, already available in our theme product. It's called main.css and it's located in the plonetheme/myintranet/browser/stylesheets/ folder.

Open it and add these lines:

#portal-logo-company img {
border:0 none;
margin:1em 0 1em 2em;

We can also adjust some other CSS declarations by adding them to this file. As main.css is located at the bottom of the CSS chain, the definitions in it will be the last being applied. For this reason, we can override any previous CSS definitions by redefining them in this file.

For example, let's adjust the space between both logos by reducing the margin defined by the portal-logo ID. Add these lines to main.css file:

#portal-logo img {
margin:1em 0 1em 1em;

If you want to know more about Plone CSS and the resources involved in Plone styling, you should check the CSS files located in the plone_styles layer. They are organized by importance, styled elements, or purpose. The following table gives a little summary about them:

Name of the CSS resource



Plone member specific CSS, such as styling for the colors

assigned to workflow states in the state drop-down box.


Plone basic elements CSS, such as styling for basic tag

elements (a, body, and so on)


Plone public facing elements CSS, such as style for the

content headers (h1, h2, and so on).


Plone table-based layout CSS.


Plone authoring/editing environment CSS.


Plone portlets CSS.


Plone control panel CSS.


Plone print CSS applied when printing some site element.


Deprecated Plone CSS elements that will disappear in

the next version.


Plone navigation tree CSS.


Plone invisible elements and accessibility elements CSS.


Plone forms CSS.


Plone right-to-left CSS (for Arabic and Hebrew).


Blank CSS file ready for quick style customization.

Since Plone 4 no longer uses DTML files to define CSS, if we want to customize them , we should just remove the .dtml extension from the previous Files.

Resetting Plone CSS

If we want to reset the CSS defined by Plone completely, we should include these empty files in our product skin layer folder plonetheme/myintranet/skins/ plonetheme_myintranet_styles:

  • base.css.dtml
  • public.css.dtml
  • portlets.css.dtml

How to customize CSS effectively
It's recommended to use some kind of helper application when dealing with CSS, for example, Firebug ( This tool will help us to identify the correct CSS file used by any element of the site and preview the results of any change to the CSS on the fly. Don't forget to enable debug/development mode in your portal_css resource registry!

More about customizing viewlets

All the default viewlets are defined in a Plone egg called We can find it by browsing the eggs folder inside our buildout.cfg folder. We can override any of them following these steps:

  • Use the manage-viewlets view to identify the viewlet we want to customize.
  • Search the viewlet declaration in the configure.zcml file inside the plone. app.layout-1.2.5-py2.4.egg/plone/app/layout/viewlets folder. For example, if we want to customize the portal breadcrumbs located in the plone.path_bar viewlet, find the snippet of code referring to this viewlet. It should look like this:

    <!-- The breadcrumbs -->
    permission="zope2.View" />

  • Copy these lines to the overrides.zcml file and modify them to look like:

    <!-- The new site breadcrumbs declaration -->
    permission="zope2.View" />

  • As we are overriding a viewlet located in another egg product, we should complete the prefix in the manager attribute with the full path to the plone. app.layout egg. Do the same for the class attribute.
  • Add a line with a template attribute defining where the new template for this viewlet is located. Its location is relative to our product folder. In the example, we are defining a new template for the viewlet called newpathbar. pt located in the browser folder. It's recommended that we copy the default template defined by and customize it. We will find it in the folder; it's called

Using Generic Setup to customize a theme

Once more, Generic Setup (GS) has some configuration files that help us to customize some theming aspects of our site. We can add the following GS definition files to the default profile of our product:

Generic Setup file



It configures the CSS resource registry (portal_css). We can add more CSS resources and configure them. By default, Paster defines the main.css file and places it at the bottom of the CSS chain.


It defines the JavaScript resource registry (portal_javascript).


It configures the position and the visibility of the site viewlets. Basically we can perform all the tasks provided by manage-viewlets view.


This file holds the setup configuration for the portal_skins tool. We can enable new layers and position and order them in the layer precedence list.

Theming—best practices

Whilst theming for an intranet, it is important to keep one thing in mind: try to keep it as clean and simple as possible for one thing only—performance. Most of the time, our intranet will be used by authenticated members. This means that all the security calculations, template generating, and the JavaScript needed in the edit mode will be at work.

Try to minimize their effects by not bloating our intranet theme. It will be always well-received by our users and their subjective sense about how our site performs. Think that an intranet usually doesn't have to sell anything, as a public site would do. Probably the only thing we have to sell to our intranet users is value, productivity, elegance, efficiency, and a corporate look and feel. So, try to deliver all of these to them!

This doesn't mean that our intranet has to be austere, ugly, or boring. On the contrary, it's just a matter of finding the correct balance and applying it.


In this article we covered the building of our own theme add-on product. We also covered the best practices on theming an intranet.

Further resources on this subject:

You've been reading an excerpt of:

Plone 3 Intranets

Explore Title