Components

« Return to page index

Plone Theme Reference

1. Component Wiring and ZCML

About components and how they are wired together

diagram of a componentComponents are powerful and flexible tools in Plone 3, but a little more abstract than page templates or Python scripts. As the diagram on the right attempts to show, they are normally combinations of Python classes and page templates wired together in Zope Configuration Language (ZCML) and given a name.

There are two important things to remember about components

Components are compounds of classes, templates, interfaces, permissions etc.
To track components down you need to look in .zcml files first, locate their names, and that will lead you to the classes and templates that contribute to them.
Components come into existence when your Zope Instance is started up
Provided Zope has read the .zcml file, a component will be available to use. You can't overwrite existing components, better to create your own, reusing some of the parts.

Parts of a Component

A component comes into being via a ZCML "directive" (there's an example of one of these below). The directive will have a series of "attributes" which will point to the various parts that go into its creation. These parts have four main functions.

  1. To identify the component (in the case of a viewlet this will usually be done with a "name" attribute).
  2. To compute the information the component is supposed to display (this is usually done with a Python class, and pointed to with a "class" attribute). For example, in the case of the navigation tree, this would be working out which part of the tree should be displayed for each page.
  3. To display the information the component's class has computed (this is usually done with a page template).
  4. To restrict the display of the component. In the case of a viewlet, this could be restricting it to display only to certain logged-in users (by using the "permission" attribute) or restricting it to display only with specific content types (by using the "for" attribute).

There's more about this in the component parts section.

Zope Configuration Language (ZCML)

The Five Tutorial on WorldCookery.com will walk you through ZCML, and there are plenty of examples in tutorials on the plone documentation site.

Here's a sample ZCML directive conjuring up the presentation viewlet (which simply provides a link to a presentation version of a page):

<configure    xmlns="http://namespaces.zope.org/zope"
    xmlns:browser="http://namespaces.zope.org/browser">  
    <browser:viewlet      
         name="plone.presentation"      
         for="Products.ATContentTypes.interface.IATDocument"      
         manager="plone.app.layout.viewlets.interfaces.IAboveContentBody"      
         class=".presentation.PresentationViewlet"      
         permission="zope2.View"      
    />
</configure>

There are three things to note:

  • Like any kind of XML, ZCML uses namespaces - watch out for these if you're writing your own ZCML file. For theme components, you'll mostly use the browser namespace.
  • ZCML attributes often refer to interfaces rather than actual content types, classes or components (see the for and manager attributes in the example above). You'll find more about interfaces in a later section.
  • Look at the class attribute and you'll see it begins with a leading dot. This means you can find it in the same directory as the ZCML file itself. If it isn't within the same directory you'll need to give the full name.

You can get detailed information about ZCML directives in the ZCML Reference section of the Zope 3 API - http://apidoc.zope.org/++apidoc++/. If you want to be very disciplined and tidy, consult the ZCMLStyleGuide http://wiki.zope.org/zope3/ZCMLStyleGuide.

 

2. Viewlets, Portlets and Other Components

Types of component.

Viewlet

This is a new feature in Plone 3 and is used to provide aspects of the page furniture - those elements of the page which generally don't change throughout the site. These are organized by another type of component - a Viewlet Manager.

For more information you can look at

Portlet

Portlets in Plone are boxes of information, usually in the right or left column of a page, containing aggregated content or additional information, which may or may not be directly relevant to the content item being displayed. Behind the scenes these used to be constructed from ordinary page templates, but now, in Plone 3, they are wired together as components and are managed by another component - a Portlet Manager.

For more information take a look at:

View (Browser View)

We gave one definition of the term "view" above in the skin section. However, behind the scenes, in the context of components, View has a more technical meaning. It refers to a component which is usually made up of a Python class or a template or both and, put simply, processes the data from a content item before it reaches the page. There's a technical explanation in the Plone Developer Manual.

You'll sometimes see it referred to as BrowserView or <browser:page> and in templates you'll see a browser view's name prefaced by @@. We look at browser views again in the section on putting a page together.

Note that the term browser and the browser namespace are used to demarcate presentational components – that is, those bits of code which go to make up elements which will find their way to a web browser at some point.

Resource (Browser Resource) & ResourceDirectory

Although we've indicated that the skin and layers are the usual home of page templates, images and style sheets, it is also possible to turn them into components by registering them in ZCML. In this case you'll see them referred to like this ++resource++[resource name]. The same can be done for a directory containing templates and style sheets.

“Oh great”, I can hear you saying, “so which should I use, components or skins?” Go to the section Skin or Components? for a discussion of the pros and cons. At the time of writing we suggest the simpler option is to keep your templates, images and style sheets in your skin. We're just mentioning browser resources so that you know what they are if you encounter them.

3. Customizing or Creating New

You can customize through the web, but on the file system, the way to customize or create components for your theme is to wire up new ones.

Through the Web

Just as for Skins and Layers, it is possible to customize the templates used by components through the Zope Management Interface.

  • Site Setup > Zope Management Interface > portal_view_customizations

You will need to know the name of your component (plone.presentation for instance). The Elements section of this manual will help if the name isn't obvious. You can only rewrite the template, which might be limiting.

On the File System

You can achieve much more if you are building your own theme product on the file system, and in this case the approach is slightly different.

Rather than overwrite a component (as you could for skins), it is far easier to create your own version. This involves some rewiring or new wiring in your own .zcml file, but is actually simpler than it sounds.

Here's an example of the presentation viewlet - as it is used by Plone:

<browser:viewlet
      name="plone.presentation"
      for="Products.ATContentTypes.interface.IATDocument"
      manager="plone.app.layout.viewlets.interfaces.IAboveContentBody"
      class=".presentation.PresentationViewlet"
      permission="zope2.View"
      />

Imagine, for your purposes, you need to use a new class to get this viewlet as you want. In your own configure.zcml file, give it a new name and wire in your own class.

<browser:viewlet
      name="[your namespace].[your presentation viewlet]"
      for="Products.ATContentTypes.interface.IATDocument"
      manager="plone.app.layout.viewlets.interfaces.IAboveContentBody"
      class=".[your viewlet module].[your viewlet class]"
      permission="zope2.View"
      />
  • Remember that the dot in front of your class namespace indicates that it can be found in the same directory as this configure.zcml file.
  • If you're not sure where your configure.zcml file lives, consult the Where to Find What you Need page of this section.

4. Component Parts

Further information on some of the parts that go to make up components.

4.1. Interfaces and why they matter

Interfaces are a bit techie and something a non-developer would probably rather not think about. However, they are an important part of component wiring, so it is as well to know a bit about what they are and do.

Interfaces as Markers

ZCML attributes often refer to interfaces rather than actual classes - for instance the example below wires up the presentation viewlet for content types that have the IATDocument interface.

<browser:viewlet
      name="plone.presentation"
      for="Products.ATContentTypes.interface.IATDocument"
      manager="plone.app.layout.viewlets.interfaces.IAboveContentBody"
      class=".presentation.PresentationViewlet"
      permission="zope2.View"
      />

In effect this is saying that the presentation viewlet is available for any content type which is ATDocument-like or behaves like an ATDocument. So, in this case, the interface is a marker.

The convenience of this is that a content type can have one (or more) interfaces, and several content types can share the same one. If you develop a new content type and mark it with the IATDocument interface, you can use this presentation viewlet with it - no extra wiring required.

Components and Interfaces

Components themselves can be marked with an interface - the technical term is "provides". Note that in the presentation viewlet example, the viewlet manager is referred to by its interface, not its name:

 manager="plone.app.layout.viewlets.interfaces.IAboveContentBody"

To track down the actual component, look in the configure.zcml file in the same directory as the interfaces. For instance, in plone/app/layout/viewlets/configure.zcml you'll see the interface has been wired up with a Python class to create a viewlet manager component:

      <browser:viewletManager
        name="plone.abovecontentbody"
        provides=".interfaces.IAboveContentBody"
        permission="zope2.View"
        class="plone.app.viewletmanager.manager.OrderedViewletManager"
        />

How to spot an interface

It is usually fairly easy to spot a reference to an interface. By convention, their names will be prefixed with an "I", and they will live in an interface or interfaces namespace. If you investigate interfaces.py or interface.py in any egg or product, you won't find very much code, but you'll often find useful information – effectively it is documentation about what a component providing (i.e. marked by) that interface should do. For example:

class IAboveContentBody(IViewletManager):
    """A viewlet manager that sits above the content body in view templates    """

If you've used the plone3_theme paster template, you'll find you have a ready-made interfaces.py file to which you can add your own interfaces if you need to create them.

4.2. Python Classes

You'll have noticed that Python classes are often part of the wiring of Components, and you will find that you can't really avoid understanding a little bit about them, particularly if you want to make your own viewlets.

Having to deal with something as advanced as Python classes can be daunting for the non-developer. The good news is that using Python classes will be more a case of copying and changing little bits of code than writing anything from scratch.

What's a Class?

It's best to think of a class as a discrete piece of code containing a collection of methods ('actions' of some sort) and attributes ('variables' which can hold a value).

In the case of components, the main purpose of a class is to compute the pieces of information a component needs to display. The class for the logo viewlet is a good example. You can find it in:

  • [your egg location]/plone/app/layout/viewlets/common.py - look for LogoViewlet

After a bit of preparatory work, the LogoViewlet class first finds out the name of the image that is to be used for the logo (and is defined in the base_properties property sheet):

logoName = portal.restrictedTraverse('base_properties').logoName

Then it works out the logo's vital statistics, size, alt text etc and turns this into an HTML anchor tag:

self.logo_tag = portal.restrictedTraverse(logoName).tag()

Finally, just in case you might need it, it looks up the title of the site:

self.portal_title = self.portal_state.portal_title()

In the page template associated with this viewlet you can get hold of this information (self.logo_tag, self.portal_title) using the variable "view":

<img src="logo.jpg" alt=""
         tal:replace="structure view/logo_tag" />

Do I have to use Classes?

Viewlets tend to be wired up with a Python class which points to a template. So, even though you might only want to create a new template, you'll find that you have to write a class to point to your new template. The Elements section of this manual should help you by giving you a snippet of code for each element to copy and paste into your own product.

Here's an example. The standard logo template doesn't actually make use of view/portal_title. So if you wanted to incorporate this into your logo in some way, then you would need to write your own template and then also your own class:

from plone.app.layout.viewlets.common import LogoViewlet
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile

class [your class name](LogoViewlet):
    render = ViewPageTemplateFile('[your template name]')
  • First, pull in ("import") all the bits and pieces with which to build your class using from ….. import …… .

  • Next, define your class. The important thing here is to base it on a pre-existing class so that you don't have to start from scratch. Put the name of the pre-existing class in brackets after your class name (make sure that you've imported it first). Don't forget the colon!
  • Finally, rewrite any of the methods or attributes you need. Here, we've just rewritten the render method to display our own template.

Note: indenting is very important in Python code, the convention is to use four spaces (rather than a tab). If you are having problems, double check the indentation first.

If you're feeling brave or want to know more, a straightforward introduction is here:


4.3. Permission

The permission attribute can be used to restrict visibility of a component.

When a user logs in to a site, they will be given a role ('manager' or 'editor' for instance). This role is, effectively, a set of permissions, giving them particular rights over particular aspects of the site.

To find out more about permissions consult the Understanding Permissions and Security Tutorial:

In the case of components, the permission attribute allows the site to decide whether a user has a right to see, or interact with a component. Most viewlets have the permission Zope2.View or Zope2.Public, which are permissions assigned to everyone, even anonymous visitors. However, look at the Lock Info viewlet:

<browser:viewlet
        name="plone.lockinfo"
        manager=".interfaces.IAboveContent"
        class="plone.locking.browser.info.LockInfoViewlet"
        permission="cmf.ModifyPortalContent"
        for="plone.locking.interfaces.ITTWLockable"
        />

By using cmf.ModifyPortalContent, this viewlet is restricted only to those who have the right to edit content (those who don't wouldn't be interested in whether an item was locked or not).

The list of available permissions is buried rather deeply in the Five product which comes with your installation of Zope - look in permissions.zcml for the most up-to-date list.

 

zope2.Public

Public, everyone can access

zope2.Private

Private, only accessible from trusted code

zope2.AccessContentsInformation

Access contents information

zope2.ChangeImagesFiles

Change Images and Files

zope2.ChangeConfig

Change configuration

zope2.ChangePermissions

Change permissions

zope2.CopyOrMove

Copy or Move

zope2.DefinePermissions

Define permissions

zope2.DeleteObjects

Delete objects

zope2.FTPAccess

FTP access

zope2.ImportExport

Import/Export objects

zope2.ManageProperties

Manage properties

zope2.ManageUsers

Manage users

zope2.Undo

Undo changes

zope2.View

View

zope2.ViewHistory

View History

zope2.ViewManagementScreens

View management screens

zope2.WebDAVLock

WebDAV Lock items

zope2.WebDAVUnlock

WebDAV Unlock items

zope2.WebDAVAccess

WebDAV access

cmf.ListFolderContents

List folder contents

cmf.ListUndoableChanges

List undoable changes

cmf.AccessInactivePortalContent

Access inactive portal content

cmf.ManagePortal

Manage portal

cmf.ModifyPortalContent

Modify portal content

cmf.ManageProperties

Manage properties

cmf.ListPortalMembers

List portal members

cmf.AddPortalFolders

Add portal folders

cmf.AddPortalContent

Add portal content

cmf.AddPortalMember

Add portal member

cmf.SetOwnPassword

Set own password

cmf.SetOwnProperties

Set own properties

cmf.MailForgottonPassword

Mail forgotten password

cmf.RequestReview

Request review

cmf.ReviewPortalContent

Review portal content

cmf.AccessFuturePortalContent

Access future portal content

 

5. Making Components Theme Specific

You may want to make components only available for your particular theme. To do this you will need an interface.

As components come into being as soon as Zope starts up and reads the .zcml files, they are available for every Plone site you have in a Zope instance. You might not want this to happen.

A Theme Interface

You can specify that your components are available only for your theme with a marker interface and a layer attribute in ZCML. Here's a rewired version of the presentation viewlet:

<browser:viewlet
      name="[your namespace].[your presentation viewlet]"
      for="Products.ATContentTypes.interface.IATDocument"
      manager="plone.app.layout.viewlets.interfaces.IAboveContentBody"
      class=".[your viewlet module].[your viewlet class]"
      layer=".interfaces.IThemeSpecific"
      permission="zope2.View"
      />

Note: Don't confuse the layer attribute with a skin layer. Here, layer refers to the whole theme rather than just one slice of it.

There are two methods for creating a theme interface:

Using plone.theme

In Plone 3.0, plone.theme is used:

  • A marker interface is defined in [your theme package]/browser/interfaces.py:
from plone.theme.interfaces import IDefaultPloneLayer

class IThemeSpecific(IDefaultPloneLayer):
    """Marker interface that defines a Zope 3 browser layer.    """
  • and this is registered in ZCML in [your theme package]/browser/configure.zcml
<interface
        interface=".interfaces.IThemeSpecific"
        type="zope.publisher.interfaces.browser.IBrowserSkinType"
        name="[your skin name]"
        />

Note: [your skin name] crops up here; refer back to the skins section if you are wondering what this is.

Using plone.browserlayer

In Plone 3.1, plone.browserlayer is available to you.

  • Create your interface (e.g. in [your theme package]/browser/interfaces.py)
from zope.interface import Interface
    class IThemeSpecific(Interface):
        """A layer specific to my product        """
  • Register this in the configuration (in [your theme package]/profiles/default/browserlayer.xml):
<layers>
 <layer name="[your skin name]"
   interface="[your namespace].[your theme name].browser.interfaces.IThemeSpecific"
 />
</layers>

If you generate your file system product or egg using the plone3_theme paster template, then the basics will be done for you (using the plone.theme method), you will simply need to track down the interface to find its name. Look in

  • [your theme package]/browser/interfaces.py or configure.zcml

and you should find it with the name IThemeSpecific. When you refer to it, use its path

layer=".interfaces.IThemeSpecific"

6. Skin or Components?

You’ll have noticed that you can turn any template or css file, or any directory containing these into a component. So why bother with the Skin building block?

The product created by the plone3_theme paster template does the following:

  • overrides and rewrites of the standard Plone Default templates and CSS files go in the Skin section – the skins directory.
  • new style sheets and images go in the Components section – the browser directory.

This manual suggests putting all your templates, style sheets and images in the Skin section - leaving just the viewlet and portlet templates in the components. There are a few reasons for this

  • it is simpler to do this when you're just starting out
  • it follows the way in which Plone Default is constructed
  • it makes it quick and easy to adjust your theme on-the-fly after it's installed. At that point, you can make further customizations of the Skin through the Zope Management Interface.

At the time of writing there's a big discussion going on about this very question.

 

If you want to strip the browser resources out of the product created by the plone3_theme paster template

  • remove the images and stylesheets directories in the [your theme package]/browser
  • remove the <browser:resourceDirectory /> entries in [your theme package]/browser/configure.zcml
  • remove the register stylesheet entry for main.css in [your theme package]/profiles/default/cssregistry.xml
  • if you have already installed your product you may need to check the CSS registry in the Zope Management Interface (portal_css) and delete the main.css entry there too

 

7. Where to find what you need

Where to put components in your own product and how to track them down in the Zope Management Interface and on the file system.

Through the Web

The templates for most components can be customized through the web:

  • Site Setup > Zope Management Interface > portal_view_customizations

The Elements section can help you identify the component you need.

Plone Default Components on the File system

If you're planning to wire up your own components, you may need to track down the relevant files of existing components to copy. This can be tricky. They are packaged up into a number of different eggs, so you need first to locate where your eggs are stored, and then work out which of these contains the component elements you need.

  • To work out where your eggs are stored, look at the Where is What section of this manual?
  • The Elements section of this manual will help you track down the egg containing the component you need.

In your own Theme Product

The browser folder in your theme product/browser/viewlet.py | viewlet.pt
An example viewlet component
/browser/interfaces.py
This is used to create your theme interface
/profiles/default/viewlets.xml
Use this file to order your viewlets within viewlet managers
/browser/configure..zcml
Use this file to wire up your components
/browser/templates | styles
These directories can be used for templates, styles, and images. You will need to register these as directories as resources in configure.zcml