Using the Resource Registries to control CSS and Javascript
Plone has two neat tools for managing Cascading Stylesheets and Javascript in a handy way. This tutorial explains some whys and hows and even has a minimal practical example of how it works.
Why do we even have these registries?
Why were the Resource Registries written, what do they do, and why are they useful?
The ResourceRegistries spring out of ( as most features in Plone ) frustrations with the state of the world before their existence: If you wanted to add a CSS style sheet or a Javascript library to your Plone site, beyond using the ploneCustom.css-file, you would have to override the header templates. This was painful from a maintenance point of view, and it also didn't allow it happening more than once. There was no way of Products supplying their own css files without massive conflicts if more than one Product attempted the same. Having several style sheets and Javascript files to make things more manageable on the filesystem was painful too.
With the existence of ResourceRegistries we were also able to split up Plone's CSS and Javascript into more manageable parts that can be turned on or off at the click of a button. We couldn't do this in earlier versions of Plone as splitting the style sheets would increase the number of separate http-requests needed to display a page incredibly.
The resource registries should:
- Make it easier to work with and supply your own Cascading Style Sheets and Javascripts in Plone
- Make it possible/easier to add conditions to your Cascading Style Sheets and Javascripts so they only apply when you want them to
- Make it easy for Product authors to supply Cascading Style Sheets and Javascripts for their products without getting conflicts with other products
- Reduce the number of http-requests needed to display a Plone page in a browser
- Pack Cascading Style Sheets and Javascripts to reduce the download sizes of files to users, and the bandwidth usage from serving a Plone site
- Make it easy to change priorities amongst Cascading Style Sheets and Javascripts
- Make it easy to disable all or parts of Plone's default Cascading Style Sheets and Javascripts
What are the registries?
The Resource Registries currently consist of two Plone tools living in the ZMI in the root of your Plone site. They have been part of the Plone bundle/installers since Plone 2.1.
They can be used with Plone 2.0.x as well. There is a special readme-file in the product for installation instructions for Plone 2.0.x
How do the registries work?
Each registry has an ordered list of resources, CSS or Javascript files, each with its own set of attributes. Entries in the registries will be linked automatically in Plone pages in the standard templates when the browser requests a page. The registries have been configured to have very sensible defaults — so for almost all use-cases (probably 90%+) it is merely the matter of adding the id of a resource you want to use.
NOTE: For experimentation, for example when reading this document, make sure to check the "debug/development mode" checkbox on the top of the configuration panel. ( read more about why in part 4 )
Overview and example walkthrough
Basic operations of the CSS-and Javascript-registries – and a truly minimal example of how to use them in real life
The registries are two tool that live only in the ZMI. They have no interface in the Plone portal UI itself.
they are called portal_css and portal_javascript. You can easily find them when browsing the ZMI of your Plone site.

Once selected, the css-registry ( the one we use for this example. The javascript one is almost exactly the same) will present an interface displaying all the registered resources ( in the case of the CSS-registry, the resources are CSS-files)
Each entry in the registries has an id that references a resource that can be found in the current Plone acquisition context. This normally means that the corresponding object should live in portal_skins like custom templates and most customisation-stuff do in Plone. Whether it exists somewhere like portal_skins/custom or in your own filesystem product makes no difference. Technically it could be a tool or a utility or anything that has a name and is avaialable, but most commonly it will be a File object ( for static CSS and JS) or a DTML Method (for dynamic variable replacement). The Resource Registries makes no difference as to what the object is, as long as it can be found and called, rendered or printed as a string.
So to use one of the registries, you have to
- Have a resource (for example a File) in the current context ( for example portal_skins/custom) with some CSS or Javascript in it
- Make an entry in the corresponding registry (for example portal_css) with the id of the resource.
Example walkthrough of adding a CSS resource
As a simple example of how the most basic functionality, we'll add and register a minimal stylesheet that adds to the background of your Plone a terrible red color.- in your ZMI, navigate to portal_skins/custom
- from the add-item menu, select File
- Give the new File an id of 'css-demo.css'
- paste the following content into the file:
body{ background-color : red }…and save it
Now you have your resource. Now we just have to link it from the Plone site to make the style apply:
in your ZMI, navigate to the CSS-Registries: portal_cssscroll to the bottom of the form, where there is a form for adding a stylesheet
in the id field, enter 'css-demo.css' (Leave the other values as they are by default for now)
Voila! – view your Plone site and you'll easily notice its (admittedly quite horrifying) shiny red background color!
Conditions, merging, caching and debugging
some more details on how the ResourceRegistries function
Conditions
When a user agent (i.e a Browser) makes a page request, all the resources registered in the registry are evaluated against their condition field. If the condition is true, the resource is served to the browser. If the condition evaluates to false, the resource is not served.
This gives you the ability to conditionally serve different style sheets or scripts based on logic like whether the user is logged in, whether you are in the "Human Resources"-section of your intranet of if the content-type is a news-item.
Read more in my small and general how-to on CMF Expressions
Merging
Whenever you click the save-button in a registry, a new set of css or javascript files are created. The registry will try to assemble the different resources into bigger lumps/files to server to the browser. This is to reduce the number of http-requests necessary and can improve performance considerably.
The rules for merging resources
- The registry will only try to merge resources that are adjacent in the list. Otherwise you would risk that the order of operations in the browser would be affected (order of code in javascript and the order of the cascade in CSS. This would possibly affect rendering or execution in the browser in a negative way, and is therefore not available ).
- Two adjacent resources are only merged if their condition is exactly the same (more about conditions in the next chapter)
- Two adjacent resources are not merged if they don't have the 'allow merging' checkbox checked
The magically assembled 'Files' are assigned a new random number as their name. So you'll find entries like <link rel="stylesheet" href="plone2341.css" /> in your html source.
You can inspect how the resources will be merged if you click the second tab in the registry; "composition". It will present you with a list of 'magic' files, like 'plone2341.css', and nested within them the component resources they are constructed from. You can click each entry to inspect what it will look like when served.
The CSS-composition UI

The comment stuff usually looks like the following.
/* ----- base.css ----- */
@media screen {
/* http://yourhost/plone/portal_css/base.css?original=1 */
/* */
Caching and HTTP
The merged resources are automatically served with HTTP-headers optimized for being cached a long time. Since the auto-generated number is being changed every time you save the registry settings, the browser will request the new 'files' and not use its old cached values anyway. The scheme is actually rather clever.
Debug and development mode
To enable the debug and development mode, check the corresponding checkbox in the registry configuration page and click "save".Enabling the debug and development mode
- Disables merging of resources (great for finding bugs and specific declarations with the inspectors and development tools like Firebug)
- Sets HTTP-headers for not caching so that you get a fresh copy every time
- Disables compression
These settings affect performance in an adverse way, so make sure to disable the debug mode when your Plone goes live.
Resource parameters
The parameters for a registry entry in the CSS (and Javascript) registry.
When working with CSS in the CSS Registry, each stylesheet has some parameters that can be tweaked.
- id
- The Zope id of the stylesheet to be used.
- expression
- A CMF expression to be evaluated to check if the stylesheet should be included in output or not.
- media
- The media for which the stylesheet should apply, normally empty or 'all'. other possible values are 'screen', 'print' etc. Read more about the media settings of CSS at w3.org
- rel
- Link relation. defaults to 'stylesheet', and should almost always stay that way. For designating alternative stylesheets. This is used for the toggle between large, medium and small fonts in default Plone. Don't change this one unless you know what you are doing.
- title
- the title of an alternate stylesheet.
- rendering
- How the stylesheet is linked from the html page. This is an advanced setting. Leave it set to the default 'import' unless you know the effects of different ways of rendering and linking stylesheets
- import
- the default. normal css import
- link
- works better for old browsers and is needed for alternate stylesheets
- inline
- render the stylesheet inline instead of linking it externally. Shouldn't be used at all! It isn't possible to create sites which validate if you do.
For more information see: http://developer.mozilla.org/en/docs/Properly_Using_CSS_and_JavaScript_in_XHTML_Documents
- compression
- Whether and how much the resource should be compressed
- none
- the original content will not be changed
- safe
- the content will be compressed in a way which should be safe for any workarounds for browser bugs. Conditional code for Internet Explorer is preserved since ResourceRegistries 1.2.3 and 1.3.1.
- full
- the content will be compressed with some additional rules.For css all comments and most newlines are removed, this may break special browser hacks, so use with care. For javascript this encodes variables with special prefixes according to the rules described here (Special Characters):
http://dean.edwards.name/packer/usage/ The source code needs to be written according to those rules, otherwise it's more than likely that it will break. - safe-encode
- - only available for javascript
- 'full-encode' - only available for javascript. Additionally encodes keywords. This heavily compresses the javascript, but it needs to be decoded on the fly in the browser on each load. Depending on the size of the scripts this could lead to timeouts in Firefox. Use with special care!
Using Resource Registries programmatically
Instructions for controlling the CSS and Javascript registries programmatically instead of through the user-interface. This is especially relevant for product authors or for crating file-system-based site-configuration products.
The by far most common need for using the ResourceRegistries programmatically is to register resources with the installation of products.
A very common use-case is 'site-configuration'-products and 'themes' that usually supply at least one CSS-file. (The equivalent of what we used ploneCustom.css for back in 2004). Other common uses are supplying custom javascript files, either with site-configurations or as client-side supplemements to custom products.
There are currently two main approaches to supplying registry configuration through filesystem code
- Python API calls, typically called from a product's Install.py module. Very flexible, but somewhat cumbersome and opaque to non-programmers. The old-style way of doing it. Has access to more (rarely needed) functionality than (2)
- GenericSetup XML configuration ( the new shiny way of supplying Plone configuration settings )
Configuring the ResourceRegistries from the Python APIs
ResourceRegistries/Interfaces/registires.py has the authorative list, but here are some examples. These examples are for the CSS-registry (chosen because it is more commonly used, and also more often used by non-programmers)To work with the tool, you must first get your hands on the tool itself…
from Products.CMFCore.utils import getToolByNameTo register a new resource ( the same as using the add-form in the UI ) , you can simply do
CSSRegistry = getToolByName(self, 'portal_css')
CSSRegistry.registerStylesheet(self, id)…and stick with the defaults. They are usually just what you need anyway.
if you feel you need more detailed control, there are many options you can supply if you need
CSSRegistry.registerStylesheet(self, id, expression='', media='', rel='stylesheet',title='',Using python calls for installation stuff is, however, rapidly becoming obsolete. GenericSetup is the new way, and luckily the ResourceRegistries also supports this scheme.
rendering='import', enabled=1,
cookable=True, compression='safe', cacheable=True)
Configuring the ResourceRegistries with GenericSetup XML
Note that this approach is instead of the Python API approach listed above. You don't need both.If you have not worked with GenericSetup yet, there is a nice tutorial from Rob Miller right here on plone.org. If you do know the basic of it, all you have to do is add a file called cssregistry.xml to your profile and let it contain something like this
<?xml version="1.0"?>As you can see, the parameters are the same as through Python or through the user-interface-forms.
<object name="portal_css" meta_type="Stylesheets Registry">
<stylesheet title="" cacheable="True" compression="safe" cookable="True"
enabled="1" expression="" id="css-test.css" media="screen"
rel="stylesheet" rendering="import"/>
</object>
