Viewlets were introduced in Plone 2.5 and they are extensively utilized in Plone 3.0. Viewlets are controlling the snippets of web pages and you must understand them if you wish to add new Plone UI elements or create new Plone themes. This new technology promises to separate Python based logic from page templates, thus making HTML authoring a cleaner process. On the other hand, it introduces new elements to Plone technology soup, further bumping already steep Plone learning curve. Could we avoid this learning bump and keeping simple changes simple.
I present not-so-rare scenario where a newbie wants to add a new piece of HTML code to every Plone page. I use a custom language bar as an example: instead of using the normal language selector, provided by Plone or LinguaPlone extension, our newbie developr wants to style a language bar suitable to his/her site theme and have it in non-standard location on the page.
1. Old way
In Plone 2.5, much of the Plone HTML output were controlled by two things
- TAL templates
- Python scripts, standalone or inlined into templates
To add a new item to the portal header section, let’s call it a custom language bar, you had to do the following.
- Open a sample Plone page in the browser
- Use Firebug to identify related CSS ids in the page you are viewing
- Search through Plone page templates for these ids
- Identify the template which produces the piece you are going to modify. You might had to follow metal:define-macro and metal:define-slot chains a bit, but generally this all could be achieved with simple source tree searches. In our case, this template was global_languageselector.pt.
- Make a copy of this template.
- Insert your own template code to produce the customized language bar.
- Modify main_template.pt or similar file to add metal:use-macro entry which will place the new template no the page
- If there are any problems with the page template files, they are detected on-the-fly and you can fix errors by just reloading the page
Voila! 7 steps. One had to understand HTML, CSS, Firebug, TAL and little bit Python now and then. This is nothing too difficult for an average Joe.
2. Plone 3.0 way
Plone 3.0 has a system with containers and viewlets. All viewlets are bind to a certain container, in which they can shuffled and hide (even through-the-web!) .
- New products can register their own viewlets without messing up other site layout customizations: no conflicting main_template.pt overrides.
- Through-the-web layout editing is really limited. You cannot move item away from one container area to another. You still need to do CSS and page template editing to make more advanced customization i.e. anything more complex than moving the logo to the right side of the page.
- There is an additional technology layer in the HTML output system, making mastering this system difficult
- This viewlet stuff is generally quite developer oriented. It feels like top developers have been writing things for other top developers. Average Joe has been forgotten in the some point of evolution.
Below are steps what we need to create the imaginary custom language bar in Plone 3.0. This is not the exact recipe, but I guess you all get the point along the lines…
- Use @@manage-viewlets to see what containers exist in the page area you want to add your custom HTML piece
- Search through ZCML files to see how these containers are defined
- Create a new Python file: interfaces.py
- Create a new Python file: viewlets.py
- Create a new profile (GenericProfile) file: viewlets.xml
- Create a new container which will be placed between somewhere between the existing container
- Define the interface for your new container
- Register new interface in configure.zcml
- Position your container in viewlets.xml
- Create a new language bar
- Locate the Python class which the old language bar viewlet implementation uses. Copy-paste its code to your new MyLanguageBar viewlet class or try extend the base class and hope you don’t need to copy-paste that much of code.
- Create a new template my_languagebar.pt, copy-paste the content from global_languagebar.pt
- Place your viewlet in the new container in viewlets.xml
- Register your viewlet in configure.zcml
- Restart Zope.
- Fix ZCML typos.
- Restart Zope.
- Reinstall your product.
- Fix Python syntax errors.
- Restart Zope.
- Reinstall your product.
- Fix page template errors.
- … and so on
Phew. In this point we have at least 2 python modules, 1 page template file, 2 different XML dialects, 150 lines of Python code. You need to master following technologies: HTML, CSS, TAL, @@manage-viewlets, object-oriented Python, Zope Component Architecture, ZCML and GenericProfile XML. The five latter ones don’t actually have anything to do with the job, changing a bit of HTML code. Basically this means that anyone who wants to pimp his/her Plone must have PhD in software architectures.
Why would you need to be Enterprise Software Architecture to make a simple HTML change? I am afraid that the new Plone way of HTML authoring will drive people futher away from Plone, because they just can’t do it(tm) anymore. Plone is already enjoying bad ass learning curve. Making it even steeper and forcing people to learn things which are not really related to their jobs won’t make Plone more attractive. I am afraid that soon there might be only three people left in this world how actually have the skillset to create new Plone skins (Alexander Limi, David Convent and Denis Mishunov).
3. Could it be easier?
The bitter comments in viewlets tutorial indicate that not everyone loves the new way. Though we need a system like this to make Plone flexible, somewhere along the way architecture just got little too complex. Maybe we should be a bit more Grok‘ish and try to hide all this complexity from novices. These two principles help in designing a system:
- KISS (Keep It Simple Stupid): The infamous learning curve. Is it really necessary to create a new Python class and play around with ZCML to spit out value True instead of False in some point of rendering chain?
- DRY (Don’t repeat yourself): Don’t force the developer type anything twice. Why you need to have IMyLanguageBar, MyLangugeBar, mylanguagebar.py, <browser:viewlet name=”myLanguageBar”, my_language_bar.pt, tal:define-macro=”my_language_bar”, #my-language-bar and so on… when this all could be generated by the system with some intelligence in it? Too many files, the same stuff in different wrapping.
My dream is that to accomplish something you need as few lines and few files as possible. Preferably one file for one thing. No changes in other files needed.
It could be something like this (indent problems below!):
<plone:viewlet="my_languagebar" to-slot="portal-top" default-visibility="true"
<li>Choose English</li> </ul> </plone:viewlet>
</html> Explanation: Let’s add viewlet my_languagebar to portal_top container and by default it should be placed after logo viewlet. The HTML code is all there. We override context variable showCurrentLanguage with inline Python script.
- Only one file needed! Forget interfaces.py, viewlets.py, configure.zcml, Python classes and other extra XML sit-ups.
- You are doing the definition in good old TAL using custom Plone tags. Forget learning of ZCML or GenericProfile XML.
- This file is picked up automatically, you don’t need to mess with configuration files. When you are doing changes you need to do them in one place only. People love this kind of magic if the alternative is XML sit-ups.
- All viewlet context specific variables are clearly visible in TAL and you can override them without creating a new Python class, using TALES definitions or Python scripts. You don’t need to go for long subclassing path just to tweak one context variable or HTML template name.
- Ordering clearly states that it’s default ordering and the site administrator can resolve conflicts using @@manage-viewlets. We don’t need separate <order> and <hidden> sections as in viewlets.xml.
- Less typing, less technologies, less mess = more productivity = more fun = more fans = Plone prevails
Now, let’s unleash the debate dogs and let them bite this blog 🙂
Technorati tags: Plone