In this blogpost I'd like to shed some light on two concepts that
sound similar and can be quite ambiguous and confusing when first
When we register certain Zope Components (via ZCML or Grok), we can
specify a layer attribute for which we would provide an
Interface. This will restrict these components to be available
only when that Interface is provided by the Request object.
In ZCML it looks like this:
And with Five.Grok:
How would the Request provide an interface? Well, with the
Zope Component Architecture,
you can make any object provide any interface, by using
the alsoProvides method. In this way we can use interfaces as
markers, to mark or identify certain objects.
In Plone this is very handy, because it allows us to only enable or
disable certain functionality, by registering it against a specific
Interface and then marking the Request or not. This "marking"
of the request is done when your Plone add-on product is installed
or uninstalled in the configuration panel.
How this is done, depends on two different implementations, one
in plone.theme (called
BrowserSkins), and one
Both approaches do the same thing, they mark the Request with an
Interface, but they way they do it differs, and that can be
bewildering to the uninitiated.
plone.theme provides a way mark the request with an interface
when it's associated with a skin installed in the portal_skins
tool. Plone 4 comes with two skins, the Classic skin and the
newer Sunburst. In other frameworks or environments, a skin
could be called a theme.
Lets pretend we were creating a skin with a new egg
product called collective.kickasstheme. If you've ever generated a
Plone theme package with
ZopeSkel, then you've
now doubt seen the following.
In collective.kickasstheme.browser.interfaces.py we have this
from plone.theme.interfaces import IDefaultPloneLayer
"""Marker interface that defines a Zope 3 browser layer.
If you need to register a viewlet only for the
"Custom Theme" theme, this interface must be its layer
Registered with this ZCML:
And then with browser resources registered against it, for
The skin is installed with
so we need to inform it about it in
<-- Here comes a list of registered folders that are registered in portal_skins -->
plone.theme registers an event subscriber (also known as an
event listener) for the IBeforeTraverseEvent. In this
subscriber, it queries for the BrowserSkin that is installed with
the current Skin in portal_skins and then uses
directlyProvides, to mark the Request object with this
BrowserSkin. If our skin/theme product is installed, then the
IThemeSpecific interface declared in our egg
collective.kickasstheme will be the BrowserLayer and will mark
You can see the code for yourself in plone/theme/layer.py
This means that all components (such as BrowserViews,
ResourceDirectories, viewlets, etc.) registered against our
BrowserSkin will now appear. As soon as we uninstall our theme
egg, they will again disappear, because the BrowserSkin is again
BrowserSkins have two major drawbacks.
- You can only have one of them active at any time. If you need
more than one BrowserSkin (which is just an Interface) on the
request (i.e to render portlets registered against another one)
you will have to subclass that other BrowserSkin.
- You also need to create a theme product (with a skin
registered in portal_skins) every time you want to create your
So, what do we do if we for example want to create a new viewlet or
portlet in a non-theme product, but don't want it to render unless
the product is installed?
plone.browserlayer was developed to solve this problem.
So, now we can create any egg, it doesn't have to be a theme egg,
and the declare inside it our BrowserLayer.
We start off by creating the marker Interface that will be given
to the layer attribute:
from zope.interface import Interface
"""Browser layer for this particular product
Then add a browserlayer.xml file to the GenericSetup profile
directory, with the following:
When we now install our egg in Plone's control panel, our
BrowserLayer will also added to plone.browserlayer's persistent
registry of "installed" layers and applied to the Request object
All components and resources registered against this BrowserLayer
will be activated and visible. Once we uninstall our egg, they will
The benefits of using BrowserLayers are basically the inverse of
the drawbacks of using BrowserSkins.
- Any egg can have a dependency on plone.browserlayers and
create BrowserLayers, not just theme eggs.
- You can have multiple BrowserLayers currently on the
Both BrowserSkins and BrowserLayers allow you to mark and
unmark the Request object and thereby switch components on or
off. They also allow you to override existing components, by simply
registering your custom components against a specific layer.
Previously, you had to override them in overrides.zcml and this
could only be done once.
BrowserSkins had some drawbacks and BrowserLayers where
developed to address these. That said, both are still around and
both are still in use.
Lastly, please use them! It's bad practice to register components
for Plone sites that are not tied to a layer. If you do. they
will be active in the Plone site, regardless of the egg being
installed or not, potentially causing havoc when serving multiple