With old style theming in a package you could base your themes on Sunburst or classic. Creating themes based on frameworks got me to do the theming on the content side and then move the complete body over to the theme side. After several variations of one type of framework the constant duplication of resources, made me realize I needed some form of inheritance for this type of diazo theme. Check out diazotheme.frameworks and diazotheme.bootswatch for the result.
Why theme on the content side?
Diazo is a great tool when you want to change similar html structures across a lot of templates. With only a few lines of code in the rules file you can change al the submit inputs into buttons. If you would want to do that in an oldstyle theme you would have to change dozens of templates. There was a question on the Plone UI Team mailing list about making it easier to plug Plone into some popular frameworks. This made me think that diazo would be the tool to do it. You don’t want to redo a complete template set in order for the html to fit with another framework. By switching out Plone’s reusable structures with the framework ones on the content side, you keep the templates intact but turn the html into what Plone would look like in another framework.
I figured I’d try and start with the most popular kid on the block and theme me some Bootstrap. Not looking around whether or not anyone had done it already. Starting off I was just moving Plone content into the example templates they have in their documentation. But then I got to the grid system. Since Bootstrap already has div.row and only uses a different syntax for the columns within, the best way was to swap out the div.cell with the Bootstap divs.
One thing led to another and I was starting to see swappable structures all over the place. Several iterations and themes later (I was also working on some easy starter themes, which of course also had to have a Bootstrap one, not having seen the example theme…), I was duplicating the same framework files all over the place. Not only that, but also huge chunks of rule file. Being human, in all that copying some sloppiness will occur and I noticed that there is no problem using resources from other themes. I also ran into diazotheme.bootstrap (which was also the name I was working under) which uses XIncludes to move some recurring rules to a separate file. These two “discoveries” are the basis for diazo theme inheritance or using a parent themes resources and rules.
The premise for framework themes
I ran into Bootswatch, which gives you a load of new stylesheets that work with Bootstrap, different themes if you will. Every Bootswatch theme needs 80% of the Bootstrap theme’s resources and 99% of its rules. What did I want from a framework theme:
No adaptation of the framework files itself, so you can copy over a new version whenever one is available.
Reuse the resources of the framework theme for other themes based on that framework.
Reuse the template of the framework theme for other themes based on that framework.
Reuse the rules that mold the content.
Edit the rules files only in one place
A childtheme should only need it’s unique resources and the files to define the theme (manifest.cfg, preview.png, rules.xml)
Create a package (I tend to use paster create -t Plone diazotheme.*) and copy in the framework files. Some frameworks come with an html example, for others you need to find it online, also copy that in and then do not touch them anymore. I tend to want to change directory names and structures to my preference, I DO NOT DO THIS FOR FRAMEWORK FILES. If you feel you need other resources outside of the framework resources, keep them separate from the framework resources and out of the framework directories. Do think twice before adding any extra resources, wouldn’t they fit better in a child theme?
Then setup the diazo theme, by adding rules.xml, preview.png and manifest.cfg. Do the theming until you think the rules are done. Chop the rules up into sensible blocks with XIncludes and move them into separate files. Think of likely candidates for being done differently in a child theme while keeping the rest of the rules intact. One block you will at least want is the framework stylesheets, because most likely a theme will override them. The easiest is to have your rules file only have rules you are certain will never be needed in a child theme. And even then have as little rules in there as possible, the rest of the rules in XIncludes. I tend to copy the complete rules file into a child theme and then remove and change what I need. Removing XInclude one liners is easier then code blocks.
Create a package (I tend to use paster create -t Plone diazotheme.*), add the unique resources (or start creating them later on) and setup the diazo theme. Add a preview.png and manifest.cfg. Copy over the rules.xml and start tweaking them.
Remember to add the framework theme as a dependency to the child theme.
So everything you needed to do for xdv to get it to go HTML5 is now no longer necessary. I thought I’d have to use a registry.xml to be able to have a HTML5 doctype, which wouldn’t help much with the zip deployment of themes. But yesterday I saw it set in a manifest.cfg on the ploneconf (2011).
An example HTML5 manifest.cfg file:
title = My Theme
description = Description of your theme
rules = /++theme++my.theme/directory/rules.xml
prefix = /++theme++my.theme/directory
doctype = <!DOCTYPE html>
Another nifty little trick I’ve seen yesterday was the use of xsl:apply-templates and css:select. For instance if you want to do something silly with your breadcrumb.
This tests if the “breadcrumb-1” id is available (when you have more than just home)
Select the div with the breadcrumb id
xsl:for-each Loops through all the children of spans, directly under portal-breadcrumbs, that do not have the “breadcrumbs-you-are-here” id.
For when you have multiple scenarios. In this case sort of if else, but you could have lots of different cases.
First scenario, in this case selecting the breadcrumb separator and changing it.
Yes, you can add html structure like this.
If none of the above scenario’s match, then do this.
Put the content you select into the theme side. In case of a for-each the selection is relative to the for each select.
The xsl:apply-templates bit I used to do by useing xsl:copy-of, which put the content there, but takes it out of the xdv loop. The xsl:apply-templates way leaves it in.
Other fun tricks
You can use an href to draw in content from outside of the content page. In plone you can use it for browser view for instance. The following example gets in the html in the @@login-form browser view:
<append css:theme=”” css:content=”form” href=”@@login_form” />
To select comments, for instance one that has the word ‘base’ somewhere in there use //comment()[contains(., 'base')]. The following example moves the base tag from the content to the comments in the theme that contain the word base:
<replace theme=”//comment()[contains(., ‘base’)]” css:content=”base”/>
The greatest thing to me about XDV is that you can leave Plone as it is and alter nearly everything about it. Mostly xdv will suffice, but when necessary you can even grab for xsl. You’re not even doctype bound. I’ve been working on an XDV theme based on HTML5 boilerplate.
Compared to my previous post on moving from xhtml 1.0 transitional to strict, this was a bit less of a picknick. More like a night in the wild having to catch and collect your own food. I ran into some major hurdles. Here is how I crossed them.
First off, get HTML5 Boilerplate and create a basic theme. Then start with the rules file, starting off with changing the doctype according to Denys his method.
<!-- Set output to HTML5 -->
<xsl:output doctype-public="html" doctype-system="" />
Mostly I start with filling the head, working my way down through the HTML. Now after the doctype is where the trouble started. Wanting to use most of the plone metatags, but have the html5 charset and the boilerplate IE edge statement proved more of a problem than I anticipated. Though mostly because I needed to refresh my xpath expressions. I went through a few XSL attempts after realizing i could just do it with regular XDV.
<!-- Pull in Plone Meta -->
<!-- Exclude HTML5 specific meta defined in Boilerplate -->
@content='text/html; charset=utf-8')]" />
All the issues seemed to be solved, so I started filling content until I was ready to run it through a validator again. Once again I ran into self closed tags that were not allowed to be closed. This time it was span’s and div’s from the content side. Looking through posts and forums I ran into the problem, but not really a feasible solution. After a lot of part solutions and even a post from Laurence Row, I ended up with the following XSL. It seems to work, but it has not been greatly tested yet.
Update: Found a way to shorten the code. copy-of can strip the whole for-each blocks and the xsl:comment gets stripped, but leaves the closing tag in place. This removes the need for special casing the script element.
Let me know if you use it. Any changes I’ll post here.
Update 2: For Diazo all this is no longer necessary
With Plone’s new theming mechanism it is a breeze to conform to a strict doctype necessary for the Dutch Web-guidelines (Webrichtlijnen Overheid). This post is actually long overdue since I’ve done this at least half a year ago, but still, better late then never.
I’ll start of giving the rules.xml used to do it and then I’ll explain the parts of it.
<?xml version="1.0" encoding="UTF-8"?>
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- Strict will need rules to fix plone Transitional differences -->
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
<!-- Remove whitespace because of line ends breaking validation. -->
<xsl:strip-space elements="ul ol dl" /> <!-- Remove name attribute from forms -->
<xdv:drop content="//form/attribute::name" />
As you can see, I start of namespacing the different dialects in the rule file. A lot of the online tutorials don’t show it this way. They generally have the xdv namespace as the default. I started of like that but it caused validation errors because the default namespace got the namespace added to some of the tags. Namespacing everything explicitly solved this.
The next step is to change the output doctype. I’ve focussed on getting the code to comply to xhtml 1.0 strict, but in theory it is also possible to turn it into html4.01 stict. For plone it’s easier to go for xhtml since it’ s already xhtml 1.0 transitional.
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
method="xhtml" /> <!-- For html 4.01 you would use this code, the other rules on this page won't work to help validate that though, you'd have to find out for yourself what works. -->
doctype-public="-//W3C//DTD HTML 4.01//EN"
Now our doctype for the XDV themed part of the site is shtml 1.0 strict. The content source is still transitional though. For the content to be valid we also need to make some changes to it. First off, the xsl transform caused whitespace characters to show up in places they were not allowed to show up. The issue was with character &13;.
I’ve solved this by selectively stripping whitespace. For now it is just stripped between list items. This is however a growing list. So far I haven’t run in to the problem anymore, but if I will I’ll update the items that need their whitespace stripped. Another option would be to strip all whitespace, but with this you would be risking stripping significant whitespace. <!-- Remove whitespace because of line ends breaking validation.
This rule will only remove whitespace between li, dt and dd elements.
<xsl:strip-space elements="ul ol dl" />
The rules below will remove them all, which could cause trouble if
there is significant whitespace without text between two elements.
<xsl:strip-space elements="*" />
<xsl:preserve-space elements="pre" /> -->
<xsl:strip-space elements="ul ol dl" />
Another validation error was caused by the name attribute on forms. This was an easy strip. Most Plone forms already have an id. If you’re in a situation this is not the case you could decide, instead of dropping it, to set from name to id.
<!-- Remove name attribute from forms -->
<xdv:drop content="//form/attribute::name" /></xdv:rules>
The installation of python2.4 on Ubuntu 10.04 had me pulling the hair from my head. I needed to deploy a Plone project using Fabric and buildout-source-release and python2.4, but the latter has been dropped for Ubuntu 10.04. Through dirty hacks it was possible to release, but now I’ve got the propper solution.
For a customer I needed to have an old school custom Plone template not to be cashed. The site was put behind varnish and just adding “no-cache” headers did not work.
The solution was creating an extra rule in the “Cache Configuration Tool” (http://yourplonecms.com/portal_cache_settings/with-caching-proxy/rules), which allows for quite a lot of customization.
To the top of the existing rule set, add a copy of the plone-templates. In the rule under “Templates” add your template id and for the “Header Set for …” set both dropdowns to “Do not cache”. This should do the trick, at least it did for me.
This book has proven to be a great read. It is: easily written, focussed on web designers, has great regard for web standard and builds up nicely by showing all the steps and then sticking them together in a fictional case.
While updating a plone 3.1.7 instance to 3.2.1 I all of the sudden had the following import error:
ImportError: No module named ImplPython
Searching the net I only found irrelevant solutions to my situation. I had an other plone 3.2.1 instance that used to work, so I checked if it would still run and it did. Creating a test instance of that buildout, once again didn’t work. Running a div between the two instance files showed 3 differences.
zope.component-3.5.1 was now zope.component-3.6.0
and two missing packages
(both dependencies of zope.component-3.5.1)
Version pinning zope.component-3.5.1 in the buildout solved the import error.
For a generic plone 3 portlet with a template portlet.pt and a module named portlet.py, this is what you need to do to subclass it. I tend to create a portlets folder in my porducts, which you have to register in the same way as the browser folder from your theme is registered. Don’t forget the __init__.py and a configure.zcml!
Copy portlet.pt template from the source egg into your theme’s portlets/ directory. Don’t copy portlet.py, but instead create your own portlet.py. It needs only the following measly five lines of code:
from source.egg.portlet import Renderer
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
render = ViewPageTemplateFile('portlet.pt')
In portlets/configure.zcml put the following lines:
If, like in this example, the template in the renderer is called render (so render = ViewPageTemplateFile(‘portlet.pt’)) and not index or _template or something the like, you just use the template instead of creating a class for it in a special portlet.py. The subclassing also works with multiple templates or differently named ones.