This blog post is a part of recent Plone developer manual update (the free to edit version). It tries to explain how to create viewlet managers in Plone. A viewlet manager is core part of Plone page rendering mechanism.
Sadly, viewlet managers lacked enough documented how they should be used or what kind of features they actual have. Also, I think this is an examplatory case of one of the worse parts of Plone process: some code gets pushed into the mainstream without proper documentation and then people need to spend three years to figure out how it works. I hope I think I finally got it how it works after reading the code. My hope is that in the future we could get less packages like this and if there is something frameworkish then please think your fellow developers and all the wasted work hours put into to the attempt trying to figure out how they work as it could have been solved with few lines of proper examples written in five minutes. I know you can do it.
Not to mention than viewlet manager mechanism is one of the spoiled parts of Plone architecture as you need to change and override and edit excessive amount of stuff just to change a bit of HTML. So I hope this helps you to get it done.
Viewlet managers contains viewlets. Viewlet manager itself is a Zope 3 interface which contains an OrdereredViewletManager implementation. OrderedViewletManager handles saving the order of the viewlets in the site database and provides the fancy /@@manage-viewlets output.
Viewlet manage can be rendered in a page template code using the following expression:
<div tal:replace="structrure provider:viewletmanagerid" />
Each viewlet manager allows you to shuffle viewlets inside a viewlet manager. This is done by using /@@manage-viewlets view. These settings are stored in the site database, so a good practice is to export viewlets.xml using portal_setup and then include the necessary bits of this viewlets.xml with your add-on installer so that when your add-on is installed, the viewletconfiguration is changed accordingly.
Note: You cannot move viewlets between viewlet managers. I know it sucks, but life is hard and Plone is harder. Hide viewlets in one manager using /@@manage-viewlets and viewlets.xml export, then re-register the same viewlet to a new manager.
Viewlet managers are based on zope.viewlet.manager.ViewletManager and plone.app.viewletmanager.manager.OrderedViewletManager.
Creating a viewlet manager: Grok way
Recommended if you want to keep the number of files and lines of XML and Python minimum.
An example here for related Python code:
Creating a viewlet manager: ZCML way
For those who want to write XML.
Usually viewlet managers are dummy interfaces and the actual implementation comes from plone.app.viewletmanager.manager.OrderedViewletManager.
In this example we put two viewlets in a new viewlet manager so that we can properly CSS float then and close this float.
Note: This example uses extensive Python module nesting: plonetheme.yourtheme.browser.viewlets is just too deep. You really don’t need to do some many levels, but the orignal plone3_theme paster templates do it in bad way. One of Python golden rules is that flat is better than nested. You can just dump everything to the root of your plonetheme.yourtheme package.
In your browser/viewlets/manager.py or similar file add:
<browser:viewletManager name="plonetheme.yourtheme.headerbottommanager" provides="plonetheme.yourtheme.browser.viewlets.manager.IHeaderBottomViewletManager" class="plone.app.viewletmanager.manager.OrderedViewletManager" layer="plonetheme.yourtheme.browser.interfaces.IThemeSpecific" permission="zope2.View" template="headerbottomviewletmanager.pt" />
Then in browser/viewlets/configure.zcml:
<browser:viewletManager name="plonetheme.yourock.browser.viewlets.MyViewletManager" provides=".viewlets.MyViewletManager" class="plone.app.viewletmanager.manager.OrderedViewletManager" layer="plonetheme.yourock.interfaces.IThemeLayer" permission="zope2.View" />
Optionally you can include a template which renders some wrapping HTML around viewlets. browser/viewlets/headerbottomviewletmanager.pt:
<div id="header-bottom"> <tal:comment replace="nothing"> <!-- Rendeder all viewlets inside this manager. Pull viewlets out of the manager and render then one-by-one --> </tal:comment> <tal:viewlets repeat="viewlet view/viewlets"> <tal:viewlet replace="structure python:viewlet.render()" /> </tal:viewlets> <div style="clear:both"><!-- --></div> </div>
And then re-register some stock viewlets against your new viewlet manager in browser/viewlets/configure.zcml:
<!-- Re-register two stock viewlets to the new manager --> <browser:viewlet name="plone.path_bar" for="*" manager="plonetheme.yourtheme.browser.viewlets.manager.IHeaderBottomViewletManager" layer="plonetheme.yourtheme.browser.interfaces.IThemeSpecific" class="plone.app.layout.viewlets.common.PathBarViewlet" permission="zope2.View" /> <!-- This is a customization for rendering the a bit different language selector --> <browser:viewlet name="plone.app.i18n.locales.languageselector" for="*" manager="plonetheme.yourtheme.browser.viewlets.manager.IHeaderBottomViewletManager" layer="plonetheme.yourtheme.browser.interfaces.IThemeSpecific" class=".selector.LanguageSelector" permission="zope2.View" />
Now, we need to render our viewlet manager somehow. One place to do it is in a main_template.pt, but because we need to add this HTML output to a header section which is produced by another viewlet manager, we need to create a new viewlet just for rendering our viewlet manager. Yo dawg – we put viewlets in your viewlets so you can render viewlets!
<tal:comment replace="nothing"> <!-- Render our precious viewlet manager --> </tal:comment> <tal:render-manager replace="structure provider:plonetheme.yourtheme.headerbottommanager" />
Only six files needed to change a bit of HTML code – welcome to the land of productivity! On the top of this you also need to create a new viewlets.xml export for your theme.
After all this ZCML typing you probably should just look the grok example above.