(For more resources on Plone, see here.)
Plone's stock configuration delivers a great deal of concrete functionality: workflow, security, tagging, and more. However, the people whom you need to win over—like your boss and the public—often form their first impressions of your site based solely on visual design. Replacing the out-of-the-box look of Plone with one tailored to your organization is thus a very important task.
Changing the overall look of a Plone site requires more than just the web designer's usual toolkit of HTML and CSS. In this article, we provide an introduction to the additional Zope- and Plone-specific techniques you need. We give an overview of Plone's somewhat complicated theming situation, show how to theme a site in a portable, reusable way, and demonstrate practices that strike a balance among ease, speed, and compatibility with future versions of Plone. Theming is a complex topic, and there are entire books on that topic alone, so we also give plenty of outside references in case your needs extend beyond the basic.
An overview of Plone theming
Plone themes, also known as skins, are visual designs that can be applied to a site, independent of its content. There are two main ways to create a theme: through the web and via the filesystem.
Through-the-web versus filesystem
One of the great advantages of Zope (and thus Plone) has historically been the customization power available through its web-based interface. Though there are some holes in this functionality with Plone 3 and 4, you can, for the most part, still point and click your way to a working theme. The advantages of this approach are:
- Immediate feedback. Iterations are simple. As a result, you're encouraged to test often, bugs turn up early, and bugs caught early are bugs solved easily.
- Explorability. Though the Zope Management Interface, where most theme work takes place, isn't the best-organized or friendliest environment in the world, it at least offers some semblance of navigable structure. You can find a piece of HTML or CSS you want to customize, click a button, and begin editing. There's less need to think abstractly.
- Accessibility. Through-the-web theming requires no access to the server's filesystem, so it is usable by people without, for example, Unix command-line experience or the ability to restart Zope.
The alternative is theming by developing add-on products, which live on the server's filesystem. The advantages of this are:
- Better tools. Expressing a theme as files and folders lets you use the entire ecosystem of filesystem-based development tools: proper text editors and version control systems, for example.
- Ease of re-use. Encapsulating a theme as a product means you can easily make use of it on more than one site, copy it from machine to machine, or share it with the world.
- Completeness. Some customizations can't yet be done through the Web: for example, moving the search box from the top of the page to the bottom by moving its viewlet into a different viewlet manager.
In practice, a filesystem product is usually better, with through-the-web styling used to test changes and to make emergency in-production tweaks between Zope restarts.
A load of languages
Theming involves several special-purpose languages. Here's the rundown:
Use in Theming
The old standby, Hypertext Markup Language defines the semantic
structure of every page. Plone's markup sticks admirably to specifying
meaning and avoids visual design. For example, its navigation bars are
<ul>s, and its portlets (those omnipresent titled sidebars) are actually
definition lists (<dl>s) with the title as the term and the content as the
definition. Visual styling is applied almost wholly by CSS.
Cascading Stylesheets, another standard tool in the web designer's kit,
apply a layer of visual design atop HTML. Because Plone's HTML so
assiduously avoids visual design, we can change the look of a Plone site
substantially without tampering with markup.
Most theming can be done with just CSS, but sometimes, like when
adding new element to a page, only HTML changes will do. All HTML
in Plone is produced by Template Attribute Language (TAL), a simple
XML-based language so named because it nestles entirely within the
attributes of XML tags. Like other templating languages, TAL is a more
readable alternative to littering program code with bits of hard-coded
markup. It is good for inserting content into a page skeleton, repeating
portions of a page, and doing other simple presentation logic. More
complicated logic is best done in Python modules, where you aren't
limited to cramped one-liners.
A good introduction to TAL is http://docs.zope.org/zope2/zope2book/ZPT.html.
The Macro Expansion for TAL (METAL) language helps combine
bits of TAL from different templates to create a single page.
is a good introduction.
The general-purpose language Zope and Plone are written in.
We will write almost no Python in this article, but it often does
make an appearance in page templates. It has a much more prominent
role in Zope 3-style theming than in Zope 2.
Some parts of theming use the Zope 3 component architecture, a scheme
for tying plugins and customizations into a large system like Plone. The
Zope Component Markup Language (ZCML) is an XML-based language
that specifies where to plug these in. For example, we will use ZCML to
tie our theme product to a third-party package that drastically simplifies
overriding some templates.
A variety of XML mini-languages, which show up in your product's
profiles folder. These are run by GenericSetup, Plone's installation
framework, when your theme product is installed or uninstalled.
Don't let theming hold you up
Theming is complicated and can be time-consuming the first time through. Don't make the common mistake of letting it hold up work on the rest of your site. Indeed, most information-oriented work—audience analysis, the creation and input of content, information architecture decisions, and development of custom content types—can go on without much thought toward the coat of paint that will eventually go over it. (Likewise, you can change the look of your site later without having to redo all your navigation and content.)
The few elements to decide on ahead of time are…
- Navigation. What is your navigation strategy? Should the theme provide space for main or contextual navigation or for a search field? It can help to have your graphic designer join you for the last few minutes of each information architecture discussion to synchronize expectations. Drawing wireframes is another fast way to get everybody on the same page. For an excellent primer on strategies for organizing your site's content, see Peter Morville's Information Architecture for the World Wide Web.
- CSS styles. The style menu in Plone's built-in editor is commonly customized to suit the semantic needs of the site at hand. Decide early in the design process what styles will be needed: for example, body text, warning messages, sidebars containing supplementary material, and various levels of headings. It's not necessary to settle on a look for these styles—just to enumerate them and establish their CSS class names. After that, theme and content work can progress in parallel.
Prepare your development environment
Before we get down the business of creating a theme, make sure you have all the tools and settings in place:
- Run Zope in foreground mode. When developing, always launch Zope using bin/instance fg rather than bin/instance start. At the cost of a little processor power, this greatly speeds development by…
- Printing error messages, usually hidden in the event.log file, to the terminal. Plone typically makes a lot of noise when it starts up; that can be ignored. But watch for errors, hidden among the innocuous INFO and DEBUG messages, when you exercise the functionality of your product.
- Turn on CSS debug mode. With Plone 3.3 or above, you can skip this step, as it's implicitly done when you run Zope in foreground mode. In older versions of Plone, go into the ZMI, then to your Plone site, and finally to portal_css. There, turn on Debug/development mode. This will keep Plone from doing its clever caching, merging, and compression of stylesheets while you're developing them, helping ensure that you always see the latest version of your work. Without CSS debug mode, your CSS changes will take effect only when Zope is restarted.
- Get Firefox, Firebug, and the Web Developer add-on. Firefox is a nice browser, but what really makes it shine is its third-party plugins. Get the latest version, available from http://www.getfirefox.com/, then grab two vital plugins, Firebug (http://getfirebug.com/) and Web Developer (https://addons.mozilla.org/firefox/addon/60).
- Turn off caching. In Firefox, show the Web Developer Toolbar (View ? Toolbars ? Web Developer Toolbar), then pull down its Disable menu and select Disable Cache. Together with enabling CSS debug mode, this will ensure that you always see your latest CSS changes. Nothing is more frustrating than spending hours chasing a problem, only to track it down to a stale cache. If you use Firefox for casual browsing, you may not wish to disable caching globally and slow down your surfing. In that case, be sure to use Shift+Command+R (on the Mac) or Shift+Ctrl+R (on other platforms) to force your stylesheets to reload when doing theme work.
Begin your theme
On-disk theme products can be quite verbose, so we employ a program to generate the skeleton of ours. We'll then make a few clean-ups before moving on to making a visual impact.
Install paster and ZopeSkel
To generate the empty shell of a theme, we'll use a code generation tool called paster. A set of Zope- and Plone-specific code snippets, called ZopeSkel, extends paster to provide a sort of "madlibs for Plone", churning out skeletal products whose blanks we can fill in. Here's how to get a copy of paster up and running:
- Some installations of Plone come with paster and ZopeSkel; check the bin folder in your buildout. If paster is in there, you're done; skip to the next section. If not, read on.
- Install easy_install, a simple Python installer, which we can use to install paster and ZopeSkel. Follow the platform-specific instructions on the easy_install download page: http://pypi.python.org/ pypi/setuptools.
- Use easy_install to install ZopeSkel, which also automatically installs paster. For example:
(For more resources on Plone, see here.)
Generate an empty theme
Once paster is installed, we can use it to generate an empty theme product. paster can generate all sorts of things, supported by various templates. (To see them all, type paster create --list-templates.) The template we're interested in is plone3_theme.
- Go into the src folder of your buildout folder, where products under development live:
- Start the process of generating a blank Plone 3 theme:
paster create -t plone3_theme
- paster needs some information to create the blank product. Answer the questions as follows:
Selected and implied templates:
ZopeSkel#basic_namespace A project with a namespace package
ZopeSkel#plone A Plone project
ZopeSkel#plone3_theme A Theme for Plone 3.0
Enter project name: Products.PracticeTheme
Enter namespace_package (Namespace package (like plonetheme))
Enter package (The package contained namespace package (like
example)) ['example']: PracticeTheme
The first three questions are about the name of the product. Most product names consist of two parts: a namespace package and the package within it. In the above example, the namespace package is Products, and the inner package name is PracticeTheme, making the product's full name Products.PracticeTheme.
Choosing a namespace package With one exception, the choice of namespace package has no functional impact. Some people use their company name, some use collective to invite community contribution, and others use the default plonetheme to drive home the fact that this is a theme. We use the one special namespace, Products, because it gives us more flexibility for deployment: we can copy the inner package (PracticeTheme, in our case) straight into a Plone installation's products folder, bypassing the buildout.cfg configuration changes and re-running of buildout that would otherwise be necessary. The egg metadata, found in setup.py in the root of the generated package, is also arguably a better place than the package name for company identifiers and other semantic tags. After all, packages have been known to change ownership, and changing a package name breaks any code—and any Plone site—which uses it.
The questions continue…
Enter skinname (The skin selection to be added to 'portal_skins'
(like 'My Theme')) ['']: Practice Theme
paster asks for a plain-English name for our theme, which will show up in the ZMI but never be exposed to end users. Feel free to use spaces and be as wordy as you like.
Enter skinname (The skin selection to be added to 'portal_skins'
(like 'My Theme')) ['']: Practice Theme
Choosing the default here (which you can do just by pressing Return) is always a good move. Bits of Plone's default look will then be used as fallbacks for what our skin doesn't override.
Enter empty_styles (Override default public stylesheets with empty
ones?) [True]: False
We almost always choose not to nullify Plone's out-of-the-box CSS. A typical Plone page can use upwards of 70 CSS classes, so starting from absolute scratch is a hefty commitment. Also, Plone's stylesheets are well structured and easy to build upon; they hardly ever get in the way of customizing by simple addition.
Enter include_doc (Include in-line documentation in generated
code?) [False]: True
Some commented-out documentation doesn't hurt, especially for your first few themes.
Enter zope2product (Are you creating a Zope 2 Product?) [True]:
This is always True for Plone, which runs on Zope 2, even though it uses some pieces from Zope 3 as well.
Enter version (Version) ['1.0']:
Choose whatever you like for a version number. Dotted sequences of numbers are typical.
Enter description (One-line description of the package) ['An
installable theme for Plone 3.0']:
My first Plone theme, made for practice
Enter long_description (Multi-line description (in reST)) ['']:
Enter author (Author name) ['Plone Collective']: Erik Rose
Enter author_email (Author email) ['product-developers@lists.
Descriptions and attributions become important should you decide to distribute your theme to a large audience.
Enter keywords (Space-separated keywords/tags) ['web zope plone
These keywords become part of your product's metadata, stored in setup. py. At the moment, they aren't used for much, but they might someday inform the browsing interface at the Python Package Index (http://pypi. python.org/). The defaults here are good and can be left alone.
Enter url (URL of homepage) ['http://svn.plone.org/svn/
If you are checking your theme into a version control system like Subversion— highly recommended—provide its URL here. If you distribute your theme more widely and actually create a marketing page for it, that page's URL is an even better choice.
Enter license_name (License name) ['GPL']:
Enter zip_safe (True/False: if the package can be distributed as a
.zip file) [False]:
These last two should almost always be left as they are. Plone themes must be GPL-licensed because they import from modules that are. And they must be marked as non-zip-safe because Plone doesn't use the zip-aware pkg_resources module to get to themes' stylesheets, templates, and images.
After you answer the last question, a large swath of text will scroll by, and you'll find a folder called Products.PracticeTheme deposited in your buildout's src folder. This, despite the fact that it comprises almost 60 files and folders, is your "blank" theme product.
- If you are using a version control system (like Subversion), this is an excellent time to check in your theme. Its current state is, if not working exactly perfectly, at least a well-known starting point. Committing your code early will let you use your version control system to highlight any mistakes you make from this point forward. Plus, if you use descriptive commit messages and commit frequently, you'll build your own compact theming tutorial as you work.
Clean up after paster
paster does a fine job getting us started, but no great work of literature was ever generated from a madlibs book. We need to clean up a few messy spots of code before we get down to theming proper.
Remove redundant package registration
Because we're using the special Products namespace, we need to delete one line from the file Products.PracticeTheme ? Products ? PracticeTheme ? configure.zcml. As generated, the file looks like this:
<five:registerPackage package="." initialize=".initialize" />
<include package=".browser" />
<include file="skins.zcml" />
<include file="profiles.zcml" />
Because using the Products namespace gives us some registration functionality for free, we must delete the <five:registerPackage package="." initialize=". initialize" /> line, or our product will show up twice in the Add-on Products control panel. It's important to do this before installing your product for the first time, or you'll have to delve into the ZMI's Products control panel to manually remove the errant registration.
Directly inside Products.PracticeTheme lives a file called MANIFEST.in, which specifies which files to include when building your egg. When using a version control system like Subversion that integrates with setuptools, Python's egg-packaging toolkit, it's best to delete this file. setuptools will then draw its knowledge about what to include directly from the versioning system's list of managed files and folders.
Even though Products.PracticeTheme is in your buildout's src folder, Plone won't see it until you re-run buildout:
- Edit buildout.cfg to enable eggtractor, a utility that lets buildout automatically see whatever is in src:
extensions = buildout.eggtractor
- Re-run buildout.
- Install Practice Theme using Plone's Add-on Products control panel. It should install without errors, though we haven't yet implemented any cosmetic changes.
In this article we have…
- Seen how Plone mixes Zope 2 and Zope 3 approaches and become familiar with the basics of each
- Built the skeleton of a theme product
- Plone 3 Multimedia [book]
- Plone 3 Theming [book]
- Practical Plone 3: A Beginner's Guide to Building Powerful Websites [book]
- Blogs and Forums using Plone 3 [article]
- Add-on Tools and Theming Tips for Plone 3 [article]