auf.suno
Connector, geek, tech evangelist, business enabler, business angel, globetrotter, sportsman, agnostic, cosmopolitan, funny finch ...

This is my (Markus Gattol aka Suno Ano) website. It is composed and driven exclusively by Open Source Software. This website is
seamlessly integrating into my daily working environment (GNU Emacs + DebianGNU/Linux) which therefore means it becomes
a fully fledged and automatized publishing and communication platform. It will be under construction until 2012.

Open Source / Free Software, because freedom is in everyone's language ...
Frihed Svoboda Libertà Vrijheid เสรีภาพ Liberté Freiheit Cê̤ṳ-iù Ελευθερία Свобода פריי Bebas Libertada 自由
auf.suno
Website Sections
Home
FAQs
About me
Contact
Plone Appearance
Status: I will not finish this page; see Update below.
Pagecode: T->1 A->SAml H->trsa[t,a,si,di]d[t,a,si,di] C->SA[cccej]
Last changed: Monday 2010-03-01 [12:22 UTC]
Abstract:

This page is not about the many things under Plone's hood but about the visual/audio appearance of Plone to the user. In other words, this page is going to talk about XHTML, CSS, theming, skinning and the like. The reason why that is important respectively folks are interested in some individual site design -- something different than what ships with a Plone default installation -- is for the simple fact that individuals have personal likings or the site simply has to look like in a special way in order to comply to some corporate design agenda.
Table of Contents
Creating a Theme
GenericSetup
Profiles
portal_setup tool
Miscellaneous
Changing Images and CSS
Changing the Skin
Changing the CSS Code
Plone Templating
Understanding the Underlying Templating Machinery
DTML and ZPT
Portlets
Navigation
KSS (Kinetic Style Sheets)

Update: I now (May 2009) stopped working with/on Plone in favor of Dolmen simply because working with Plone is no fun anymore. Plone has become way to fat and confusing to work with over the years — I need something that works with me, not against me.


There is a particular section on plone.org that is about visual design in general.

Creating a Theme

This assumes that we already have a Buildout in place i.e. we start here right after the Buildout step has been completed.

GenericSetup

What is GenericSetup? GenericSetup is a major step forward in managing Plone site configuration, and as of Plone 2.5 GenericSetup is a core part of how Plone handles its own site creation process.

Okay, that is all well and good. But what is it? Simply put, GenericSetup is a Zope-based toolkit for managing site configuration. Not much clearer? Maybe this would work better as a story:

Meet Guy Ablaze. Guy is a Plone site developer, who manages websites built with Plone, and even develops add-on products for Plone using Python. Guy never uses Plone just out of the box. Instead, he does a lot of customization for every site he deploys. All of his sites have custom skins, where the CSS and template modifications live. A lot of his sites use custom content types. Rarely does he find that the default site tabs are to his liking; he often replaces those with custom tabs. And there are a myriad of little tweaks and adjustments that he makes to each site, to get it working just so, to satisfy his demanding customer's diverse requirements.

Guy knows that it is a good idea to be able to recreate a customer's site without having to do a lot of twiddling in the ZMI, so he creates install methods for each of the sites that he manages. These install methods are written in Python. Each one is comprised of a bunch of steps. One step is to install custom skins, containing the site's look and feel. Another step might be to install some custom types, while a third customizes the site tabs. And of course there are a bunch of little steps that correspond to all of the miscellaneous tweaks that he's made.

Guy is reasonably happy with this arrangement, but, you know, there are some ways that it could be better. First, he finds that he has to write a lot of repetitive boilerplate code in his various install methods. Also, using Python instructions to describe how his site should be configured does not really fit his brain. He would much rather just be able to make a list of the types he wants and have them automatically get installed. Also, it would be great if he could not only import site configuration, but export site configuration. As in, he could make some changes to the site, maybe using the Plone interface, maybe using the ZMI, and then be able to spit that out to be loaded somewhere else. And, wow, the mind boggles... would it not be great to be able to compare site configurations? To be able to ask What has been manually changed in my site since I did the original installation? and get a meaningful answer? All of this and more is what we get when we use GenericSetup!

Profiles

A profile is a set of XML (Extensible Markup Language) files that describe the configuration of a particular Plone site. Note the fundamental difference between a profile and an install method e.g. a Buildout — install methods define a set of steps that must be run to get a result, while a profile actually describes the result itself. This makes a lot more sense, semantically. It also brings site configuration down from the lofty clouds of programmer-land, to a realm where the non-programmer-type site managers might even be able to look at the site configuration and understand its meaning.

What does a GenericSetup profile look like? Well, we can see a very simple demonstration profile that has been recently added to the GenericSetup software itself. If we want to see a much more complex profile, we can look at the default Plone profile. I am not going into detail, but I will rather point out a couple of things these profiles have in common.


What we first notice, is that they both contain import_steps.xml and export_steps.xml files. The import_steps.xml file defines all of the steps that need to be taken when this configuration is loaded into our site, while export_steps.xml describes the steps that should be taken when we want to generate a new configuration profile from the live site.

If we look a little bit more closely at the import_steps.xml file, we will see that it contains a number of <import-step> tags, each of which have an ID (Identifier), a version, a title, and a handler. Some of them also contain one or more nested <dependency> tags. These dependency tags allow us to specify that certain steps must be run before other ones. For instance, it does us no good to configure the actions tool (which is handled by the actions import step) before the actions tool is instantiated (which is handled by the toolset import step). Therefore, in the actions import step we will typically see the following nested tag: <dependency step=toolset" />.

Note
A tool is a singleton persistent object, found in the root of the Plone site. Most tools have names starting with portal_, such as portal_membership, portal_setup or portal_types. They variously expose shared functionality and act as containers for configuration state. Most tools can be configured from the ZMI (Zope Management Interface), and many of the Plone Site Setup control panels manage tool settings under the hood.

Next, thing we see is that there are a bunch of other files. Each of these other files deals with a specific aspect of our site's configuration, and is usually related to a single step that was included in the import and/or export steps. Common examples of these additional files include:

toolset.xml
Registers all of the tools available to the site. This must happen before the tools are configured.
skins.xml
A list of all of the skin paths that should be added to the skins tool when our site is configured.
skins(folder)
Contains all of the templates, images, and CSS (Cascading Style Sheets) files for our skins.
types.xml
A list of all the types that should be defined in the site's portal_types tool.
types (folder)
A folder containing other XML files, one for each type listed in types.xml. Each file contains detailed configuration information related to the specific custom content type for which it is named.
workflows.xml
Registers all of the workflows for the product (those in the workflows folder).
workflows (folder)
Contains the workflow definitions. Each subfolder contains one workflow. The workflows consist of a definition.xml file, and any supporting scripts necessary for the workflow operation.
And so on ...

There are many more already defined configuration files that GenericSetup understands. And it is even possible to define and create our own! An important point to note about profiles is — Not all profiles are created equal. In fact, there are two types of profiles that GenericSetup understands

  • Base Profiles and
  • Extension Profiles

Base Profile

The first type is called a base profile. Base profiles, as anyone would guess, provide the base level information that a site needs to be created. In Plone 2.5 and onwards, Plone's default setup is itself a GenericSetup base profile. Base profiles contain configuration information such as tools, workflows, types, register plug-ins for some packages. Most people building custom sites will never have to create a base profile — and we should not create or alter our base profile until we have some practice.

Extension Profile

Extension profiles are meant to be applied after base profiles. Any number of extension profiles can be applied to a site, whereas only a single base profile is ever applied. Extension profiles are meant to describe new content types, custom skins, custom workflows, custom tools, and add their configuration to what has already been set up in the base profile. All of these are additive actions, that is they do not make any changes to currently existing products. Changing configuration in existing tools, modifying content types to respond to different workflow, or any other modifications of the base profiles, are less safe actions, and only should be undertaken when we know what we are doing.

When a base profile has been activated, we can install additional extension profiles. An extension profile is configured in the same way as a base profile and uses the same handlers, but it will normally only contain a subset of the settings that make up the site, either as overrides for those from the base profile, or as new entries. Extension profiles are useful for add-on products that need to be installable independently of the rest of the configuration of the site, as well as where the configuration will not deviate extensively from the base profile.

To see an example of the profile that describes a current Plone site and illustrates these concepts, one might export a snapshot and take a look at what is done. The portal_setup tools section will now show a few things in detail.

portal_setup tool

At first, let us clarify what we are talking about — the note from above plus the image below should make it clear (also note, that we are within a Plone Instance i.e. we are dealing with a particular Plone Instance running on some Zope Instance. In case the reader is still a bit uncertain about all the terms, the Glossary might be worth a look).

The first thing to know about the setup tool is that it is stateful i.e. that at any given time, the setup tool is working in relation to an active profile. We can see which profile is currently active, as well as set the active profile from any of the available profiles, on the portal_setup properties tab in the ZMI (Zope Management Interface).

The Plone Site profile that is currently active is the default Plone base profile, the one that is used whenever we add a Plone site using the ZMI. Once we know what profile is active, we can for example click on the Import tab to see the import steps that are currently registered. We can also export a profile using the Export tab. Then there can be snapshots made which we might compare to each another etc.

All that comes in handy when we are in the course of developing a new site e.g. we start with Plones Site profile, export it and also take a snapshot. Then we start customizing ... after a while, we take another snapshot. Starting with two snapshots we can already start to compare particular profiles, undo changes by importing a former exported profile from its XML file or simply use the snapshot taken from an earlier stage etc. Also, if someone else wants to help with customizing, he would run a Builout first (given we provided him with our buildout.cfg) then we would use the Export tab to create a XML file and send it to him/her.

Miscellaneous

A section for different kinds of information about GenericSetup.

Gotcha

We might imagine that when we select a new profile to be the active profile, and then we browse back to the import tab, that we would ONLY see the import steps that were related to the active profile.

This is not the case! The import steps that a profile registers are additive i.e. that whenever we select a new profile as the active configuration, any new import steps are added to the set of already registered import steps. Therefore, whenever we select a new profile as the active profile, we will never see fewer import steps, we will only (possibly) see more.


Why did they have to make this behavior so unintuitive? Why did they not simply list the import steps for the currently active profile?


There is a method to this bahavior, however as we will see further down ...

How Profiles are Applied

Okay, so we know now that profile import steps are additive. Let us look at the implications of this. To do so, we will once again be following the adventures of our good friend Guy Ablaze, who has now drunk deeply of the GenericSetup kool-aid, having repented for and moved beyond his former Python-based install method ways.

Say Guy adds a Plone site. When he does, of course the Plone Site base profile is applied to his site, as it is for every Plone site. But then he wants to install the membrane product. membrane, it turns out, does not use the QuickInstaller / install method mechanism for installation, but instead provides an extension profile. So he goes to the portal_setup properties tab and selects membrane as the active site configuration. Then he returns to the import tab and clicks the Import all steps button.

GenericSetup will then iterate through every registered import step, which includes all of the steps of the base profile and the two additional steps defined by membrane's extension profile. For each step, it will examine the active profile to see it contains any applicable configuration. If config info for that import step exists, then the step will run and the configuration will be applied. If there is no config info for that step, then the step will be skipped and nothing will happen.


This is an important point, with some interesting consequences. Let us look at the membrane setup profile. You will notice that the import_steps.xml file defines some new import steps. But you will notice that it does NOT include a toolset import step, even though the membrane profile DOES include a toolset.xml file. It is unnecessary to add a toolset import step to the membrane profile, because this step is already registered with the base profile. When the Import all steps button is pressed, most of the registered steps will do nothing. But the toolset step will find the toolset.xml file and will apply the configuration there. Likewise, the additional import steps will find corresponding configuration info, and these steps will be run.


If Guy were to switch back to Plone Site as the active profile and then click on Import all steps, then it would (re)apply all of the base configuration settings, but it would not find any configuration info for the membrane-specific steps, and would therefore skip them.

The reader might realize, then, that it is a good idea to become familiar with all of the import steps in the default Plone base profile. These are all available to us when we create extension profiles, and they do not even need to be added to our import_steps.xml file. All we need to do to define new types is to include a types.xml file and a properly constructed types folder. Similar statements hold true for specifying actions, workflows, and for registering skin paths.

In fact, if we are creating an extension profile that introduces no custom import steps, then we do not even need an import_steps.xml file. That's right... if we create a profile that defines some new types, maybe a workflow or two, a couple of custom actions, all of those profile steps are already included in Plone's default set of import steps. We only need to add an import_steps.xml file to our profile when we are introducing steps that are not included in the base profile.

Now, we can go back to the last section and re-read the bit about the gotcha. If the reader has understood everything I have covered here, he will understand why the setup tool behaves in the manner described.

Exports, Snapshots, and Comparisons

The first thing we notice upon clicking on the Export tab of the portal_setup tool is how similar it is to the Import tab. It shows a list of available steps (these are the export steps from export_steps.xml, of course), as well as two buttons at the bottom. One of the buttons says Export selected steps while the other reads Export all steps.

These export steps are linked up to code that knows how to examine the actual site setup and, from this, generate the appropriate XML files for a GenericSetup profile that would replicate the current setup. If we click on the Export all steps button, the browser should pop-up a file download dialog window, asking where we want to save our setup_tool-<time_stamp>.tar.gz file. This file, when extracted, contains the XML files and directory structure for our GenericSetup profile.

It is important to note that the active site configuration, as specified on the properties tab of the setup tool, does NOT have an direct impact on the export process. Whenever an export is run, all of the specified steps are exported in full. In other words, if Guy Ablaze were to make the membrane profile active and then run an export, he would get (among other things) an export of ALL of the tools that exist in the site, even though the membrane profile only lists a single tool in the toolset.xml file.

In addition to file system exports, it is also possible to create a profile snapshot that lives entirely within the ZODB (Zope Object Database). Finally, there is the Create a Snapshot button. Clicking on this button will do an export, only instead of offering a tarball for download, it will create a new folder inside the snapshots folder in the setup tool. This new folder will contain a ZODB file and folder objects which contain all of the XML that defines the site configuration at the time the snapshot was taken (see image below).

Also useful in the setup tool is the Comparison tab — I already mentioned the comparison feature above. On this tab we are able to pick between any two profiles — including any snapshots — that we have created, and generate diffs between them to see what has changed. Here is an example of what this might look like.

In this example I have run a comparison between the NuPlone profile and a snapshot that I created just before the comparison. Even more useful is it to take snapshots during customizing a site — one can not just rollback if needed but also compare different snapshots and see what has changed in between them.

Under the Hood

How does it really work? What glues it all together? How would we create our own, completely custom, import steps, in order to configure this really cool thing that we will install in every Plone site we ever touch from this day forward?


The import process is initiated when we tell the setup tool to run some set of import steps. At this point, GenericSetup will iterate through each of the steps, extracting the handler attribute (specified in the step's XML tag in the import_steps.xml file from which it was loaded). This handler is a callable, usually a function, that accepts a single argument context, which is some flavor of what GenericSetup calls an import context (the basic set of import and export contexts can be found in the GenericSetup/context.py file).

By convention, this handler function, and all of the associated adapters and other related import and export code, should live in either a module or a package called exportimport in our Product's package. For example, all of the Plone-specific import/export code lives in the Products.CMFPlone.exportimport package.

So what is this import handler supposed to do? Well, it is supposed to know which XML files in the profile it cares about, and it should read these. Then it should query for a multiadapter. This multiadapter should adapt from some interface that marks the object that is being configured, and from GenericSetup's ISetupEnviron, which is implemented by the import context object. It should adapt to GenericSetup's IBody interface. For example, the ZCML (Zope Configuration Meta Language) that defines this adapter for the Plone properties tool (which can be found in CMFPlone/exportimport/configure.zcml) looks like this:

sa@pc1:~$ type gr
gr is aliased to `grep -rni --color'
sa@pc1:~$ gr -A2 -B3 IPropertiesTool /home/sa/work/git/plone_buildout/parts/plone/CMFPlone/exportimport/configure.zcml
14-  <adapter
15-     factory=".propertiestool.PlonePropertiesToolXMLAdapter"
16-     provides="Products.GenericSetup.interfaces.IBody"
17:     for="Products.CMFPlone.interfaces.IPropertiesTool
18-          Products.GenericSetup.interfaces.ISetupEnviron"
19-     />
sa@pc1:~$

The code that performs the adapter lookup in the importPloneProperties handler looks like this importer = queryMultiAdapter((ptool, context), IBody)

importer, then, will be an instance of the PlonePropertiesToolXMLAdapter class, which implements GenericSetup's IBody interface — I will leave it as an exercise to the reader to look up that interface, but I will tell you that it defines a Zope 3 schema which includes a body text field. This is implemented (in the XMLAdapterBase that the properties tool's adapter extends) as a property, such that when we set the importer.body to be the XML read in from the configuration file, this XML is parsed (using minidom) and the configuration is applied.


So, if we want to have some fancy new ourthing tool that we want our product to install, and we want to be able to manage the configuration of that tool using XML files in a GenericSetup profile, what would you do? Here are the steps:

  1. Add a toolset.xml to our extension profile that lists our tool's class, so it will be created during the toolset import step.
  2. Add a handler function in an appropriate place within our product's exportimport package. This function should accept a context argument, it should read in any XML file(s), and (in most cases) it should set the body attribute to be the content of the XML file.
  3. Create and register an adapter that adapts from an IOurThing interface and ISetupEnviron to IBody. If we are subclassing from XMLAdapterBase, all we need to do is implement an _importNode method that accepts the minidom node that is the root of the XML tree in the configuration file. This should iterate through the tree and perform all necessary configuration.
  4. Add our new import step to our extension profile's import_steps.xml file.
  5. Add our new ourthing.xml file to the extension profile.

Note that we have been looking at an XMLAdapterBase-based example. XMLAdapterBase is a good starting point for situations where we have a tool and a single XML file that contains the tool's configuration. Not all import steps are like this, though, and there are other utility classes that GenericSetup provides in its utils module. It is beyond the scope of this page to cover them all in detail, but I will list a couple that we should know about:

ObjectManagerHelpers
When we need to import (or export) folderish objects that contain other objects, we will probably find this useful.
PropertyManagerHelpers
This provides some assistance when the configuration we need to perform relates to Zope's PropertyManager API.

It is also important to say, while we have been focusing on the import process, the export process works very similarly. Usually the same adapter is used for exporting as for importing. In the XMLAdapterBase situation, we would define an export handler that looked up the adapter, read the body attribute (which would actually trigger introspection of the site state and creation of the DOM (Document Object Model) nodes and XML that represent that state), and then write this out to the appropriate filename.

Applying Policies at Site Creation Time

Those who have been doing Plone product development for a while are probably familiar with customization policies. Customization policies are site configuration bundles, defined in the older python-based semantics, that can be applied to a Plone site. One of the more handy features of customization policies is that they could be made to show up as an option when the Plone site was first created. If we did not select one, we would get a default Plone site, but if we did, our site would get a bunch of extra configuration applied.

Customization policies have not been supported in Plone 2.5 for a while. There has been some justified grumbling about this — they were not given a suitable deprecation period. The good news is that GenericSetup provides the same ability, and that it is quite easy to convert existing customization policies to GenericSetup profiles (although these profiles will consist of just a single handler that calls all of the pre-existing customization policy code). However, for Plone 3 doing customization via GenericSetup is the way to go anyways ...


First let us look at how GenericSetup profiles are defined. This is done using a profile_registry mechanism provided by GenericSetup, which can be imported into our product as so from Products.GenericSetup import profile_registry. Also defined are some constants for specifying the type of profile you are registering from Products.GenericSetup import BASE, EXTENSION.

Once we have done these imports, a simple call to the profile_registry will register our profile. Here is what this call looks like for the membrane product

    profile_registry.registerProfile('default',
                                     'membrane',
                                     'Extension profile for membrane',
                                     'profiles/default',
                                     'membrane',
                                     EXTENSION,
                                     for_=IPloneSiteRoot)

I am not going to go into a detailed description of all of the arguments (you can see the IProfileRegistry interface for that), but I will draw our attention to the final for_ argument. This allows us to specify an interface that denotes the type of portal that the profile is meant to be used with. If we use the IPloneSiteRoot interface, defined for this purpose, then when we add a new Plone site, our profile will automatically show up as available to be applied when the site is created.


In order to create an Extension Profile from a Customization Policy, we would perform the following steps:

  1. Register an extension profile with the GenericSetup profile registry (do not forget for_ = IPloneSiteRoot).
  2. Add a single import step in import_steps.xml, which calls a runPolicy handler.
  3. Write the runPolicy function, which should accept a context argument, but which simply calls the same code that the customization policy calls.

We should now have a working extension profile that is functionally equivalent to the customization policy. There will not be any export support, however — in order to get that, we will need to do considerably more work in translating our older customization policy into a true XML based configuration.

Changing Images and CSS

The look and feel of a Plone site is a big subject. A skin is a series of CSS (Cascading Style Sheets), images, templates, and scripts that come together to form the look and feel for a particular Plone website. The idea of a skin is that we can change the skin and hence change the look and feel of a site without having to change the content.

Changing the Skin

We can change the default skin for a Plone site using the portal skin form, which is accessible from the PCP (Plone Control Panel) i.e. we can represent a Plone site in a few different ways by applying different colors, style sheets, and templates to a site. The portal skin form provides the following three choices:

  • Default skin: This is the default skin to show to a user when they access the site. There is only one skin that is given by default, which is Plone's default skin — the one Plone ships with any default installation.
  • Skin flexibility: This sets whether we are going to allow users the choice of choosing their own skin. If this is enabled, users can go to their preferences and choose a new skin based on their personal likings — this is enabled by default.
  • Skin cookie persistence: If a user can select a skin, we can select this to have the cookie last indefinitely. This means that a user will always see a particular skin when logging into a Plone site. However, this is disabled by default.

Changing the CSS Code

CSS determines the majority of the look and feel of a Plone site, including the tabs, the images, the boxes, and the overall layout. The fact that Plone's CSS is totally customizable means that from a few style sheets users can completely customize many aspects of a site.

To quickly alter the CSS access the ZMI, one needs to click portal_skins, then plone_styles, and then ploneCustom.css. This opens the page for that object. This style sheet is actually straightforward — in fact, it is empty. Plone is using the cascading property of CSS. Because the HTML (Hypertext Markup Language) for Plone first imports plone.css and then ploneCustom.css, any changes to the latter overrides the standard style sheet. Why is this a good thing? It means we can make small incremental changes to ploneCustom.css without breaking or altering the core style sheet.

So, if we were to customize the ploneCustom.css object, we had to click portal_skins, followed by plone_styles, then ploneCustom.css and finally the click the Customize button. Again, this object has been customized, and instead of being at ../portal_skins/plone_styles/ploneCustom.css, one will notice he is now at ../portal_skins/custom/ploneCustom.css. Because file objects can now be edited through the Web, we can directly edit the style sheet through the Web.

As an example, to make the background have an image in the middle of it (this is not necessarily the best user interface, but it is a clear example of how to customize the CSS code). First, we need to upload an image to Plone — we click portal_skins, click custom followed by the scroll down menu at the right where we chose Image and the Add button to select an Image.


We can choose any image. We then make sure that the ID (Identifier) of the image is something meaningful like background.png for example. Then we go to ../portal_skins/custom/ploneCustom.css and change the text from /* DELETE THIS LINE AND PUT YOUR CUSTOM STUFF HERE */ to the following:

body {
background-image: url(background.png);
background-repeat: no-repeat;
background-position: center;
}

Then we click Save Changes to commit the changes to this file. After returning to our Plone site, we can see the new background image.

Plone Templating

Plone puts together three layers of technology to create a page. Python and page templates create some HTML (Hypertext Markup Language), which is sent to the browser. There, some CSS (Cascading Style Sheets) render the nice page with which we are now familiar.

To understand how to generate and then edit a Plone template, we have to first learn about some key underlying concepts. Some of these concepts are particularly unique to Plone, and although they provide great advantages, it does take some time to get used to them.

Understanding the Underlying Templating Machinery

Diving straight into how Plone templating works would likely leave the first time reader confused, so we start by going through the underlying templating machinery. In an ideal world, this is something one should not have to worry about, but in practice it is usually the first block people hit when trying to learn to use Plone.

Plone is rather unique in that everything in Plone is an object. Those unfamiliar with the concept of an object, there is not much to know — an object is just a thing that encapsulates some behavior.

Each object has methods that can called on the object. One example is a computer mouse. A computer mouse could have methods such as move, click, and right-click. In Plone, a document is an object of a particular type. All this means is that the document is not just a static bit of text — instead, it is something a little more complicated and far more useful. A document in Plone has a description method, for example, that will give us the description that the user added. When using the templating system, we will see in more detail that everything is an object. look first at some of the basic principles of object publishing.

DTML and ZPT

Zope provides several mechanisms for HTML templating:

  • DTML (Document Template Markup Language) and
  • ZPT (Zope Page Templates)

DTML is a tag-based language which allows implementation of simple scripting in the templates. DTML has provisions for variable inclusion, conditions, and loops. However, DTML has major drawbacks: DTML tags interspersed with HTML form non-valid HTML documents, and careless inclusion of logic into templates results in very unreadable code.

ZPT is a technology that fixes these shortcomings. ZPT templates can be either well-formed XML documents or HTML documents, in which all special markup is presented as attributes in the TAL (Template Attribute Language) namespace. ZPT offers just a very limited set of tools for conditional inclusion and repetition of XML elements, thus the templates are usually quite simple, with most logic implemented in Python code. One significant advantage of ZPT templates is that they can be edited in most graphical HTML editors. ZPT also offers direct support for internationalization.


As mentioned previously, Zope Page Templates are themselves XHTML (Extensible HyperText Markup Language) documents which means they can be viewed and edited using XHTML compliant tools (which is a big benefit compared to other template languages used for web applications). However, these page templates are not meant to be rendered as is. Instead they are marked up with additional elements and attributes in special XML namespaces (see below). This additional information is used to describe how the page template should ultimately be processed.


Here are some basic examples. To conditionally include a particular element, like a div element, simply add the tal:condition attribute to the element as follows:

<div tal:condition="...">
  ...
</div>

To control what appears inside an element, use the tal:content attribute like this:

<h1><span tal:content="..."/></h1>
...

Finally, to introduce or replace values of attributes use the tal:attributes attribute as follows: The power of python could also be utilised to dynamically alter the href at runtime.

<a href="" tal:attributes="python: 'href http://someurl.com'">...</a>

Because Zope Page Templates are themselves XHTML not only can they be edited using normal HTML editors but they can also be checked for XHTML compliance in template form. As a result, we can be fairly confident that these templates will be expanded into proper XHTML automatically. This a very cursory explanation of Zope Page Templates. The behavior of Zope Page Templates is almost completely described by a template language (see below), fixed on TAL, TALES, and METAL specifications.

TAL (Template Attribute Language)

The Template Attribute Language (TAL) is a templating language aimed to generate HTML and XML pages. Its main goal is to simplify the collaboration of programmers and designers by templates being proper HTML (or XML, respectively) which can be worked on using common design tools. TAL was created for Zope but can be used in any other Python-based projects as well. For more information go here and here.

TALES (Template Attribute Language Expression Syntax)

The Template Attribute Language Expression Syntax (TALES) is the recommended expression language used by TAL and METAL. For more information go here and here.

METAL (Macro Expansion Template Attribute Language)

The Macro Expansion Template Attribute Language complements TAL, providing macros which allow the reuse of code across template files. Both were created for Zope but are used in other Python projects as well. For more information go here and here.

Portlets

Navigation

KSS (Kinetic Style Sheets)

Is Plone 3's new AJAX (Asynchronous JavaScript and XML) framework, called KSS, to add dynamic, JavaScript-driven, user interface elements.

Creative Commons License
The content of this site is licensed under Creative Commons Attribution-Share Alike 3.0 License.