Viewlet registration in Plone 3.0
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 Plone Default 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 Plone Default 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).
$INSTANCE_HOME/lib/python/plone/app/layout/ does not exist for me
installed, but not configured
If you just want to play around, set PYTHON_PATH environment variable containing the FQPN of your Zope python libs and add the Zope bin directory to your PATH. Export those settings, create a folder somewhere to hold your toy Plone site, and run mkzopeinstance.py to create a Zope server. Check the Products under the target folder for CMFPlone, and if it's not there, download a Plone tarball and copy/link its Products into your Products and libs into your new Zope instance's libs. Start up your Zope, point your browser to the ZMI, and add a "Plone Instance". If you decide you want to go ahead and run a Plone site, find the howto docs for "buildout" so you can manage separate sandbox and live site instances.
FreeBSD's www/plone3 port layout
Let ZOPE_INSTALL be /usr/local/www/Zope210, and INSTANCE_HOME be /var/db/zope2/zinstance.
The www/plone3 port adds all Plone3 packages to $ZOPE_INSTALL, e.g. to $ZOPE_INSTALL/Products and $ZOPE_INSTALL/lib/python. Those packages are visible to all your Zope instances, as if they had been installed in, e.g., $INSTANCE_HOME/lib/python and $INSTANCE_HOME/Products.
As a rule of thumb: if the documentation here mentions instance-specific stuff (MyTheme), it will be in $INSTANCE_HOME/Products/MyTheme and below; and if it mentions classes or packages that are part of Plone3 (lib/python/plone/app/layout) it will be in $ZOPE_INSTALL/...
Re: FreeBSD's www/plone3 port layout
Having said that, it is not so difficult to understand after reading your comment. :) Just one thing: HOW are those packages visible to all my instances?
Anyway, this is somewhat irrelevant now. I've switched to Drupal. I was able to grok Drupal in *full* in a matter of a week. I'm even already writing my own modules. I believe Plone is one of the best CMS's and further more I think it's THE best for users. As for the admin/dev side, it has an unjustifiable, again IMO, learning curve; I don't see the payoff for its extreme complexity, especially when compared to the likes of Drupal and others. This is coming from someone who has a CS degree, has programmed in numerous languages and is no stranger to Unix/Linux admin. I've had both a lot of fun and frustration working with Plone, but Drupal fits my organization's needs better and is much easier to comprehend.
I will continue to dabble with Plone occasionally and monitor its evolution; I have a few instances at work and one on my iMac here at home. Maybe I'll reconsider Plone in the future? Thanks for you comment.
- Gavin
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.