Viewlet registration in Plone 3.0
How viewlets are registered in a default Plone installation.
As mentioned in the above introduction, Plone 3 main template looks up viewlet managers only, it does not call viewlets directly. This also applies to any Plone 3 template that generates HTML code from Zope 3 components.
The advantage of this approach is that we can now organize the different regions of a Plone page without having to modify the code in main_template.pt itself.
The viewlet managers of main_template.pt and their registered viewlets are defined in the plone.app.layout package, in the module called viewlets. That package can be found in any Plone installation on the filesystem, in $INSTANCE_HOME/lib/python/plone/app/layout/.
In the configure.zcml file of the viewlets module (read: in $INSTANCE_HOME/lib/python/plone/app/layout/viewlets/configure.zcml), we can find viewlet manager definitions, followed by the registration of their viewlets.
We see for instance that the plone.portaltop viewlet manager provides the interface IPortalTop:
<browser:viewletManager
name="plone.portaltop"
provides=".interfaces.IPortalTop"
permission="zope2.View"
class="plone.app.viewletmanager.manager.OrderedViewletManager"
/>
IPortalTop is a marker interface for the component that manages the plone.header, the plone.personal_bar and the plone.path_bar viewlets.
It is in the browser:viewlet declarations that we find the management association between the viewlets and the viewlet manager, for instance:
<!-- The portal header -->
<browser:viewlet
name="plone.header"
manager=".interfaces.IPortalTop"
template="portal_header.pt"
permission="zope2.View"
/>
...
<!-- The personal bar -->
<browser:viewlet
name="plone.personal_bar"
manager=".interfaces.IPortalTop"
class=".common.PersonalBarViewlet"
permission="zope2.View"
/>
<!-- The breadcrumbs -->
<browser:viewlet
name="plone.path_bar"
manager=".interfaces.IPortalTop"
class=".common.PathBarViewlet"
permission="zope2.View"
/>
We notice from its ZCML definition that the plone.header viewlet looks up a template directly (portal_header.pt), where the other viewlets managed by IPortalTop are associated with a class.
In that template, all there is is the call of another viewlet manager, which name is plone.portalheader:
<div id="portal-header">
<div tal:replace="structure provider:plone.portalheader" />
</div>
Again from configure.zcml we see that plone.portalheader, which implements the IPortalHeader interface, manages the plone.skip_links, the plone.site_actions, the plone.searchbox, the plone.logo, and the plone.global_sections viewlets.
All these viewlets, with the aforementioned two ones registered for plone.portaltop, are associated with python classes defined in plone/app/layout/viewlets/common.py. Those classes are Zope 3 browser views that implement zope.viewlet.interfaces.IViewlet, which means that they have a render() method that yields the HTML snippet that will be injected in the page.
We can also see in configure.zcml that all viewlet managers are instances of OrderedViewletManager (see manager.py in plone.app.viewletmanager). It means that viewlets will be looked up in a specific order.
The order of the viewlets is defined in a utility that implements IViewletSettingsStorage.
That utility stores the order of the viewlets in a viewlet manager for a specific skin. Its setup comes from a Generic Setup profile called viewlets.xml.
For the PloneDefault skin, ordering of viewlets is described in Products/CMFPlone/profiles/default/viewlets.xml:
<?xml version="1.0"?>
<object>
<order manager="plone.portaltop" skinname="Plone Default">
<viewlet name="plone.header" />
<viewlet name="plone.personal_bar" />
<viewlet name="plone.app.i18n.locales.languageselector" />
<viewlet name="plone.path_bar" />
</order>
<order manager="plone.portalheader" skinname="Plone Default">
<viewlet name="plone.skip_links" />
<viewlet name="plone.site_actions" />
<viewlet name="plone.searchbox" />
<viewlet name="plone.logo" />
<viewlet name="plone.global_sections" />
</order>
</object>
Now that we know how Plone 3.0 sets up the defaults for viewlet managers and their viewlets in the PloneDefault skin, let's see how we can customize those values from a Python product on the file system, either for the default skin or for a skin that we would be developing.
In the following paragraphs, I will refer to a product called MyTheme. Simply replace MyTheme with the name of the Python product you are developing on the file system.
- Note
- For quickly generating a theme (skin) product for Plone 3.0 (a Python product that has to be placed in the Products folder of a Zope instance), you can use the generator script of DIYPloneStyle (svn trunk until version 3.0 is out). If you want to quickly generate a python egg or a package that must be installed in $INSTANCE_HOME/lib/python/ or somewhere in the Python path, you can use the plone3_theme template of ZopeSkel (from svn trunk).
alternate Plone installation path
$INSTANCE_HOME\Python\Lib\site-packages\plone.app.layout-1.0.5-py2.4.egg\plone\app\layout
rather than
$INSTANCE_HOME/lib/python/plone/app/layout/ as described in the article.