DIYPloneStyle: Creating a Custom Style for Plone 2.1 and 2.5

« Return to page index

This tutorial will teach you how DIYPloneStyle can be used as a base for creating a custom style product for Plone 2.1 or Plone 2.5 that adds to a portal a new skin selection and makes use of the new stylesheet and javascript registries.

Introduction

Introducing DIYPloneStyle and the purpose of this tutorial.

Since version 2.1 Plone ships with ResourceRegistries, a component that provides tools for managing stylesheet and javascript files linked to plone pages (templates). These tools - portal_css and portal_javascripts - let you register CSS and JS files in a way close to how actions are registered with portal_actions (for instance you can put a condition on them). Thanks to ResourceRegistries, we can now customize Plone look in a much cleaner and more powerful way.

One of the common ways to customize components of a Plone site is to do it TTW (from the ZMI), making use of the custom layer in the Skins Tool. Although it works, this approach only suits small customer side changes, made by people who don't have access to the filesystem. If this is all you need to do, you'd probably be happy enough with reading the chapter 7 of the Plone 2.0 book. But if you think of building a full graphical environment for Plone, the best practice is to write a python code product on the filesystem.

In this tutorial, we will use DIYPloneStyle - a simple example/skeleton of a skin product for Plone 2.1 - as a base for discovering how the stylesheet and javascript registries work, and start building a new product that installs a custom style in any Plone portal.

DIYPloneStyle is based on two complementary products:

  • Martin Aspeli's MySkin, a skeleton product for Plone that installs a skin selection with its own layers, but does not make use of the Resource Registries.
  • SimplePloneStyle (which I wrote), another skeleton product that makes use of the Resource Registries but does not create a new skin selection.

Those two products are not dead though. For instance, you may want to use SimplePloneStyle for starting a new project which has to register some stylesheets for all Plone skin selections. You also may want to base on MySkin a new product that mustn't do more than adding to Plone a skin selection with a few layers.

This tutorial covers the use of the current version of DIYPloneStyle, which is version 2.1.1.

Installation and basic example

Quick learning from the basic example included in DIYPloneStyle.

Installing the product

First, download the last version of DIYPloneStyle (this tutorial covers version 2.1.x), expand it, and follow the installation instructions that are in the README.txt (it is a classic installation procedure for a Plone product).

Your portal should now look like this:

DIY Plone Style 2.1

Basic Example

The code of the example resides in the files contained in the folders which name starts with diystyle_example in the DIYPloneStyle/skins/ directory (on the filesystem).

We can see that there aren't many files in those folders:

  • Some images

    They are kept in the folder diystyle_example_images.
    You can add to this folder the images that will override the ones shipped with Plone (mainly action and content type icons).

    It is better to keep them in a separate folder for having tidy folder listings in the portal_skins tool.

  • A custom base_properties.props file

    From this file, you can learn how to replace the portal logo by another one, and how to simply change portal style properties.
    This file is not used by the example, but is provided by the skeleton theme created by the generator script for your convenience.

    note
    Customizing base_properties.props is the easiest way to modify the style attributes of Plone UI elements, but it has its caveat as you will see further in this tutorial.
  • A custom stylesheet (diystylesheet.css.dtml)

    The most interesting thing about that stylesheet is probably that its name is not (and must not be) ploneCustom.css.dtml.

    You will learn in a further chapter of this tutorial how to register stylesheets with the new portal_css tool introduced in Plone 2.1 instead of using the old ploneCustom.css implementation.

    Stylesheets and base_properties.props are stored in the DIYPloneStyle/skins/diystyle_example_styles folder.

  • A set of empty stylesheets

    Their names are public.css.dtml, base.css.dtml, generated.css.dtml, and portlets.css.dtml.

    They are used to disable equivalent Plone stylesheets by overriding them with empty CSS files (see chapter about skin layers).

  • Some templates

    As Alexander Limi states, it is ok to customize Plone templates as long as it is only for small structural changes. The templates that are customized in the example are kept in DIYPloneStyle/skins/diystyle_example_templates.

Getting Started - The Manual Way

Preparing DIYPloneStyle for making it the skeleton of a new visual theme for Plone.

  1. Uninstall the product (with the Portal Quick Installer) before modifying anything.
  2. Rename the product to something other than DIYPloneStyle(1). This must be done on the filesystem, not in the ZMI (don't laugh, it happened).
  3. Renameskins/diystyle_base_styles/diystylesheet.css.dtml to something that suits better your product name.
    This file is where you will add your own CSS rules.
  4. Rename all the folders which name starts with diystyle_base in the skins/ directory to something that suits better your product name (2).
  5. In config.py, change the name of your skin selection by modifying the name value of the first entry in SKINSELECTIONS(3). If your product won't provide more than one skin selection, you can remove the layers key from that entry (make sure SKINSELECTIONS match folder names in your skins directory).
    Change DEFAULTSKIN to make it use the name of your skin selection.
    In the STYLESHEETS declaration, replace diystylesheet.css by the name you chose for that template, omitting the .dtml suffix.
  6. In Extensions/Install.py, edit the relevant lines in the import declarations (see # CHANGE comments).
  7. In tests/testStyleInstallation.py, replace all occurences of DIYPloneStyle by the name of your product (see # CHANGE comment).
  8. Edit README.txt, give it another description, remove the usage and credits paragraphs, and replace author names and email addresses.
    If you plan to distribute your work, please leave a note stating that it is based on DIYPloneStyle.
  9. Clear HISTORY.txt from its DIYPloneStyle related content.
  10. Remove the basic example
    • Remove all the files which name starts with diystyle_example in the skins/ directory.
    • In config.py, in the SKINSELECTIONS declaration, remove the lines declaring the DIY Style Example skin.
  11. Remove the bin/ folder as the script it contains only works on a clean, left unmolested version of DIYPloneStyle.

That's it!
Now you can test the initial state of your visual theme by restarting the Zope server and installing it from the Site Setup > Add/Remove Products page (as manager, in the Plone interface).

Your Plone Site should now look like this:

Now have fun with your new project!

Troubleshooting
This part of the tutorial is likely to be the one that will put you into some trouble.
See the Troubleshooting section of this tutorial if you feel that you are in a desperate situation.

(1) It is safer to work with a copy of the product so that it's easy to compare with the original version if you feel like in trouble. back

(2) Unless you configured it otherwise in the config.py module, any folder located in the skins/ directory of your product will be registered as an FSDirectoryView with the portal skins tool. Because FSDirectoryViews must have a unique name/id in the skins tool, good practice is to include your product name into folder names to ensure these don't clash - particularly when using a name that might be commonly used. back

(3) In versions prior to 1.0.3, the name of the skin selection is setup using the SKINNAME variable. back

Getting Started - The Automated Way

Using the built-in generator script for quick skeleton creation.

You learned from the first part of this chapter how to manually setup DIYPloneStyle for making it a ready to go skin skeleton product.

There is a much faster way to get a clean product that can become a new style for Plone, by making use of the included generator script.

In the DIYPloneStyle product folder on the filesystem, there is a bin/ directory where you will find a python script called generator.py. This script can be used for applying all the manual modifications that are listed in the previous part of this chapter.

Download and Expand DIYPloneStyle

  • Place the expanded DIYPloneStyle product folder in the Products/ directory of your Zope instance.
  • Uninstall DIYPloneStyle if you already installed it (in Plone, as manager, go to Site Setup > Add/Remove Products).

Run the script

On Unix/Linux/OSX

From a bash shell (from the Terminal), use a command which should look like this one:

   /path_to_zope_instance_home_folder/Products/DIYPloneStyle/bin/generator.py --productname MyOwnPloneSkin

On Windows

  • Choose run from the Windows Start menu and type cmd. Press OK
  • Run the script with a command which should look like this one:
       python c:\instance_home_folder\Products\DIYPloneStyle\bin\generator.py --productname MyOwnPloneSkin
    

On Unix like systems, you can call the script from any directory.
On Windows you can't: your current working directory must be outside the product.

I've heard about permission problems on Windows when using the script from a subversion checkout of DIYPloneStyle.
If you need to work with the latest svn trunk version of the product under Windows, take the time to remove all its .svn folders before running the script.

Start Building

You now have a fresh Plone skin product in the Products/ directory of your Zope instance.
All you have to do when you want it to be installable in Plone is to restart the Zope server.

Note
If you want to learn more about the possible script arguments, you can either see the script output when called without args (or with the --help option) or read its fairly easy to understand code.

Organizing the skins layers

A bit of theory on the portal_skins tool mechanism.

To better understand how the Skins Tool and its layers traversal work, I invite you to read the paragraphs about Using Layers Within a Skin and Managing Skins with the portal_skins Tool in the chapter 7 of the official Plone Book by Andy McKay. The links are unofficials but they are the only public ones I know that deliver a rendered HTML version of the book, and they are up-to-date. These paragraphs cover TTW Plone customization. Although it is a good way for learning the Skins Tool layers traversal mechanism, we know that working in the ZMI is not the best approach when it comes to building a full graphical environment for Plone.

When building a skin product on the filesystem, concepts are the same:
The install function first creates a skin selection containing the layers of the skin it is based on, then adds the product specific layers to it. On the filesystem, the product specific layers are the folders that are located in the product skins/ directory (*).

In practice, if your product is built for customizing a Plone site by adding a few stylesheets and replacing graphical UI elements (images like the logo and some icons), you won't need to have much more than one layer to add to your skin selection (**).

But there are situations where it might be useful to have several layers, mainly for organizing skin elements into categories (images, customizations, stylesheets, etc).

(*) Any folder located in the skins/ directory of your product will be registered as an FSDirectoryView with the portal Skins Tool, and then be added to your skin selection layers. Exceptions are folders which name starts with . or equals CVS or {arch} (This is hardcoded in Products.DIYPloneStyle.Extensions.utils.getSkinsFolderNames()).

(**) If DIYPloneStyle provides more than one skin layer (if its skins/ folder contains more than one folder), it's only for making easier the example removal part of the Get Started process.

Working with Base Properties

Editing base_properties.props for quick customization.

Customizing base_properties.props is the easiest way to modify the style attributes of Plone UI elements. But it has its caveat: due to the way the skins tool works, you must have all default Plone base properties in the file, even if you plan to customize only a small set of them. If you remove some of the properties from the file, Plone won't be able to access them anymore.

All this doesn't make the base_properties.props approach ideal for maintenance, upgrades and customization. That's one of the reasons why it will be gradually phased out in Plone (also for avoiding the use of DTML in CSS files).
I am not yet aware of how and when this will be implemented, so check for further updates of this paragraph.

You can find more information about the Plone pre-defined properties in the file CMFPlone/skins/plone_styles/ploneCustom.css.

You may need to use your own properties in addition to the ones that are pre-defined in Plone. Instead of adding new properties to base_properties.props, it is probably better practice to create a new .props file in your skin layer and to register a stylesheet that uses it (instead of the base_properties one - see in the original DIYPloneStyle/skins/diystyle/renameThisFile.css.dtmlDTML code).

Registering and customizing stylesheets

Best use of the Resource Registries.

Registering new stylesheets

Before the ResourceRegistries was included in Plone, the only way to override the Plone default CSS rules was to customize the files base_properties.props and ploneCustom.css. Because of that, choosing what rules should override the plone ones had to be done by playing with the layers traversal in the Skins Tool, or by setting unelegant Zope Access Rules.
As we saw in the previous chapter, we still have to use base_properties.props for defining our basic graphical chart. But now that we can register stylesheets with the CSS tool, ploneCustom.css is kept for backward compatibility only.

Another limit of Plone without the ResourceRegistries was that there was no possibility to put a condition on whether a stylesheet should be loaded or not.

Stylesheet registration in DIYPloneStyle is set up in config.py, in the STYLESHEETS declaration. STYLESHEETS is a tuple of python dictionaries, one dictionary for each stylesheet to register with the portal_css tool.

If you need to put a condition on a stylesheet, you have too add to its dictionary an expression key. It's value is a TAL expression that works the same way as for actions in the portal_actions tool.

You can learn more about the stylesheet attributes (dictionary keys) from the STYLESHEETS inline comments.

Customizing existing stylesheets

DIYPloneStyle can be useful not only for registering new stylesheets: you can also define in the config.py how you want to customize resources that are already registered in the registries.

In the STYLESHEETS declaration, simply add a dictionary with the same id than the one of the resource that you want to customize, and add a key to the dictionary for each resource property that you want to modify.

It can be handy for instance for disabling some Plone default resources in order to start a project from absolute no-style scratch or to put specific conditions on them to define different styles for public and registered modes.

Note: All customizations will be automatically reverted when uninstalling the product.

Practical example

A very common use case is to define a skin for public anonymous access, and keep a basic plone style for members access.

One easy way to do so is to put a condition on the product specific stylesheet(s), and disable basic plone resources under the same condition.

In the config.py file of your product, declare your stylesheets like these ones (in STYLESHEETS):

   STYLESHEETS = (
     {'id': 'diystylesheet.css', 'media': 'screen', 'rendering': 'import',
      'expression': 'python: member is None'},
     {'id': 'base.css', 'expression': 'python: member is not None'},
     {'id': 'public.css', 'expression': 'python: member is not None'},
     {'id': 'portlets.css', 'expression': 'python: member is not None'},
     {'id': 'generated.css', 'expression': 'python: member is not None'},
     )

Troubleshooting

Some solutions in case you encounter problems.

Use and development of your product

Use valid name for your product
A products which name starts with a digit won't be installable in Plone, even if you see it registered as a Zope product in the ZMI in Control_Panel > Products.
Empty all caches (!!)
If the changes you applied to the product don't show out the way you planned, or if some skin elements persist after you uninstalled the product, make sure that either the browser and the front-end proxy caches (apache, squid) are emptied, and reload the current page.
In Firefox, press shift while clicking the reload button. In IE, use the key combination <Ctrl-F5>.
Do not underestimate this possible issue, it covers at least 60% of the problems that you may encounter with a skin product (based on DIYPloneStyle or not).
Beware of any TTW customization
Some of your product skin elements might have been customized from within the ZMI, and be overridden by their equivalent in the custom skin layer. This one also covers a lot of the possible problems you might experience.
Uninstall your product before renaming its elements
If you forgot to do so before renaming stylesheets or javascripts, you can resolve conflicts from the portal_css and portal_javascripts tools in the ZMI.
If you didn't uninstall the product before renaming it or the skin selection, revert your changes on the filesystem, uninstall the product and rename the elements again.
Check that the product is loaded in Zope
From the ZMI, go to /Control_Panel/Products/manage_main and check that the product is listed and not marked as broken.
If it's not listed you should double check the product installation on the filesystem, making sure that the user who launches the Zope server has at least read access on it.
If it is marked as broken, you should check your error log and make sure that your business python code is valid (this should only happen if you added a broken Python class definition to your initial skeleton Plone style product).
Make sure that the product is installable in Plone
If your product is not listed or is marked as removed in Site Setup > Add/Remove Products or in the Quick Installer (portal_quickinstaller in the ZMI), it probably means that you have to debug the module Extensions/Install.py.
Use the provided testing framework
DIYPloneStyle comes with basic unit tests.
Follow the links from the Resources chapter of this tutorial if you care about learning the Plone Unit Testing Framework.

Use of the generator script

Check that the script uses the right python interpreter
Thank you Casper R. Nielsen for suggesting me to add this point.
With unix like systems, you can run the script by calling it directly, omitting the python command. If you get the error bad interpreter: No such file or directory by calling the script that way, it's because the first line of the script refers to a file that does not exist.
To make it run without error, you can either:
  • prefix the shell command by the python command
    $ python generator.py --productname CustomSkin
    or by the full path of the python interpreter. For instance:
    $ /usr/local/bin/python generator.py --productname CustomSkin
  • edit the first line of the script to make it point to your python interpreter.
Check that the script is executable
If you get the error Permission denied by calling the script directly (under Linux/Unix), there are big chances that the executable bit was removed from the script file permissions. You can either run the script by prefixing the command by a python call (see previous paragraph) or use chmod to restore file permissions:
      $ chmod 0755 generator.py
Check that you have the needed write permissions
If you get a traceback that looks like this one,

Traceback (most recent call last):
  File "DIYPloneStyle/bin/generator.py", line 226, in ?
    generateDirectoryCopy( path, path.replace(DIYPloneStyle, productname) )
  File "DIYPloneStyle/bin/generator.py", line 182, in generateDirectoryCopy
    os.mkdir(dstDirectory)
OSError: [Errno 13] Permission denied: /Users/david/plone-instance/Products/CustomStyle/
it is probably because you don't have write permissions on the folder where DIYPloneStyle resides and where the new product will be created.

Get Further support

From the Plone community
Before adding a comment to the manual, please post your question/issue on the plone-users mailing list or try to get some support on the IRC#plone channel.
From the DIYPloneStyle product authors
Feel free to contact DIYPloneStyle authors by sending them an email (email addresses appear in the product README.txt file).

Resources

Related documentation, Zope/Plone products and CSS oriented developer tools.

Download the latest release of DIYPloneStyle from here.

Essential References

The following links will certainly answer most of the questions that could remain unanswered after reading this tutorial.

ResourceRegistries
The Project Description or the product README.txt give a good overview of its functionalities.
To learn more about the registries' API, you can install DocFinderTab. This product is recommended anyway as soon as you start learning the Zope/Plone API.
Customizing Plone - the Plone 2.0 approach by Alex Limi
An overview of Plone 2.0 layout structure and philosophy, and of what you can do with CSS.
(This document can be used as a good demo of the full-screen mode in Opera that uses the projectionCSS media ,which displays Plone page sections as projection slides).

TTW Customization

These links can be useful for a better understanding of the Skins Tool machinery and how things are organized with regard to Plone User Interface elements.

The Plone Book by Andy McKay
Chapter 7, about Customizing the Look and Feel of Plone is a must-read for People who need to understand better the Skins Tool machinery.
Where is what? by Jet Wilda and John DeStefano
A reference on what templates and CSS control the UI elements and where to find them in the ZMI (updated for Plone 3.0).
Plone Skin Dump
A Plone product developped by Quinta Group, which "allows to create Plone product based on some ZMI located skin folder (eg "custom") from portal_skins. So you can easy create Plone product with skin based on folder with customized styles and page templates". Plone Skin Dump supports stylesheets registration since version 0.3.0.

Filesystem Development

The How-to section of plone.org
There are many good resources from the section User Interface: Styles and styling, CSS.
In particular the one about Creating a Custom Skin by Ben Calder.
Best Practices for Plone development by Joel Burton
It will give you good advice if you plan to develop filesystem python code based products.

The following references may seem off topic as they are mainly about developing content types, but they are valuable for learning how to build Python products for Plone.

MySite by Raphael Ritz
This tutorial/product for Plone newbies (and less newbies) covers many aspects of the product development on the filesystem.
RichDocument by Martin Aspeli
Although this tutorial/product is more about creating a new type of content for Plone, It has a short section covering the use of the ResourceRegistries
The Plone Book by Andy McKay
There is also a chapter about Writing a Product in Python.

DIYPloneStyle ships Unit Tests Included.
Even if most of the following references describe the Zope and Plone Unit Testing Framework, it's really easy to adapt them to any product for Plone.

PloneTestCase
PloneTestCase is a thin layer on top of the ZopeTestCase package. It has been developed to simplify testing of Plone-based applications and products.
How to write unit tests for Plone
This document shows how easy it is to write unit tests and describes how to set up your environment to invoke them.
the ZopeTestCase Wiki
A comprehensive documentation about the Zope Unit Tesing Framework.

Other Plone Skins Products

Most of the graphical designs for Plone that can be found are not yet making use of the Resource Registries, but adapting the code should be easy now that you read this tutorial ;-)

The Products section of plone.org
Is a central repository for Plone Add-ons. It has a section dedicated to visual themes that can be used as a source of useful examples on how to apply new designs to a Plone site.
ploneskins.org
Is another repository for Plone skins.

CSS Design

official W3C CSS documentation
The official Cascading Style Sheets documentation delivered by the Word Wide Web Consortium.
CSS Zen Garden: The Beauty in CSS Design
A demonstration of what can be accomplished visually through CSS-based design.
A List Apart
A web magazine that "explores the design, development, and meaning of web content, with a special focus on techniques and benefits of designing with web standards".
Famous book author web sites
Some authors of books about CSS design like Eric Meyer, Jeffrey Zeldman, Dan Cederholm and Owen Briggs have their own web site that are good places for finding documentation, examples and recipes.

Mozilla/Firefox Tools and Extensions

The following tools are your best friends when you need to inspect the CSS attributes of Plone page elements or find out what id or class you want to override in your stylesheets.

DOM Inspector
This Mozilla tool can be used to inspect and edit the live DOM of any web document.
Web Developer
Adds a menu and a toolbar with various web developer tools.
Aardvark
This extension displays on a Web page the attributes (like ID or class name) of a selected element.
EditCSS
Stylesheet modifier in the Sidebar.
ColorZilla
Advanced Eyedropper, ColorPicker, Page Zoomer and other colorful goodies. It assists web developers and graphic designers with color related tasks - both basic and advanced.
View formatted source (format source extension)
Displays formatted and color-coded source and optional CSS information for each element. You can see exactly which CSS rules match for an element. The rules are displayed including file name and line number. The topmost element is that with the highest priority. You can fold/unfold/hilite block elements (table, tr, td, div, span,...). Really cool feature: select a block level element of interest directly in the page and view it's source! To help you to quickly analyze the source code you can view images directly from the source and add comments to folded block elements. The code view is based on the rendered document, so you will also see dynamically (by Javascript) created and modified html elements! Works also with frames and selected text.
View Rendered Source Chart
Creates a Colorful Chart of a Webpage's Rendered Source Code.
Displays Dynamically Generated HTML and Static HTML Together.
Removes JavaScript Code, Displays JavaScript Output.
Excellent as a Visual Aid in Learning Environments.

Translations

This tutorial in your language (?).

Chinese
Chinese translation
Japanese
Japanese translation
German
German translation