Personal tools
You are here: Home Documentation Tutorials Customization for developers Skin layer customisation
Support

Get Help

Join our chat rooms or support forums if you have more specific questions.

Plone Training
Learn how to design, build, and deploy a website in Plone through one of the numerous Plone training sessions around the world.
Find Plone training…
 
Document Actions

Skin layer customisation

The old-fashioned way

Martin Aspeli

This tutorial provides an overview of how to customise different aspects of Plone 3
Page 2 of 7.

Traditionally, customisation in Zope has been done through acquisition. For example, a developer might have placed a page template in the root of the site and acquire it to render an object in a subfolder /foo/bar. If the developer wanted a different rendering for objects in /foo/bar/baz only, he may place a template with the same name (id) in that folder, which would take precedence.

Since Plone (and the CMF) is all about letting site users create their own content hierarchies, placing templates and code inside the site structure would become messy. Therefore, the CMF developers invented the portal_skins tool.If you view this tool in the ZMI, you will find one or more skins on its Properties tab, notably Plone Default. A skin (which we tend to call themes to avoid confusion), is just an ordered list of skin layers. The skin layers listed on the Properties tab corresponds to folders inside the portal_skins tool. When Zope is looking for a resource (logo.jpg, say) it will search the current folder, and then parent folders up until the site root. If the resource can't be found, CMF will look for it in the skin layers for the current theme, starting at the top of the list and going down until it finds one.

Notice how custom is the first entry in the list. This is how through-the-web customisation works. Copy an item to this folder, and the new copy takes precedence over existing entries. Also notice how all the other folders read-only. That is because they are not folders in the ZODB at all - they are Filesystem Directory Views - folders that reflect the files inside a particular folder in the filesystem.

Thus, to create a product that overrides some resource in a skin layer that ships with Plone, we must:

  • Register a new filesystem directory view
  • Insert this in the list of skin layers for the current skin, normally just below the custom folder
  • Copy the relevant resource into the new skin layer directory, keeping the same name
  • Customise this copy

Note: Some resources will have an associated .metadata file. If so, you must copy the .metadata file along with the resource when customising the resource.

Traditionally, all Plone resources - images, style sheets, Javascript files, page templates and Python scripts such as form handlers, were kept in skin layers. However, as you may imagine this became a bit cumbersome as Plone grew, since the skin layer mechanism presupposes that every resource has a globally unique name (id). Still, most of the core views, images and style sheets that are part of Plone are kept in skin layers that have names prefixed with plone_, such as plone_images or plone_templates. On the filesystem, you will find these inside CMFPlone/skins. You can search the subfolders of this folder to find various resources.

In general, if a resource is mentioned in the Plone UI (e.g. from a url, an action in portal_actions or an alias in portal_types) and it is not prefixed with either @@ (as in @@view) or ++resource++ (as ++resource++stylesheet.css), then it is likely to be found in a skin layer.

Registering and installing a new filesystem-based skin layer

In the example.customization product, we have a skins/ subdirectory, with a single skin layer directory, example_customiation. For us to be able to register this a filesystem directory view, we must tell CMF about the top-level skins directory. We do so in the package's __init__.py file:

from Products.CMFCore.DirectoryView import registerDirectory

GLOBALS = globals()
registerDirectory('skins', GLOBALS)

def initialize(context):
    """Intializer called when used as a Zope 2 product."""

For this to work, we also need to ensure that this package is a Zope 2 product. If it is in the magical Products.* namespace (e.g. a traditional product placed in the Products directory if a Zope instance), this happens automatically. If we are using an egg-based product in a different namespace, we add this to the package's configure.zcml:

<configure
    xmlns="http://namespaces.zope.org/zope"
    xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
    xmlns:five="http://namespaces.zope.org/five"
    i18n_domain="example.customization">

   <five:registerPackage package="." initialize=".initialize" />

   ...

</configure>

We then need to create the directory view and install it for the current skin when the product is installed in a Plone site. We do this using GenericSetup. First, we must register a new extension profile so that the product is installable. This is done in configure.zcml, as follows:

   <genericsetup:registerProfile
      name="default"
      title="Example customizations"
      directory="profiles/default"
      description='Install various customizations from the example.customization package'
      provides="Products.GenericSetup.interfaces.EXTENSION"
      />

Then we use the skins.xml import handler to configure the portal_skins tool:

<?xml version="1.0"?>
<!-- This file holds the setup configuration for the portal_skins tool -->

<object name="portal_skins">

 <object name="example_customization"
    meta_type="Filesystem Directory View"
    directory="example.customization:skins/example_customization"/>

 <skin-path name="*">
  <layer name="example_customization"
     insert-after="custom"/>
 </skin-path>

</object>

If we wanted to, we could register as many directory views as we wanted here.

To test it all, we have placed an exciting new logo in skins/example_customizations/logo.jpg, overriding logo.jpg from CMFPlone/skins/plone_images. When the product is installed, you will see this logo instead of the default Plone one. You may need to do a hard-refresh in your browser.

 
by Martin Aspeli last modified January 15, 2008 - 09:59 All content is copyright Plone Foundation and the individual contributors.

How to remove a skin layer?

Posted by Stanislav Posonsky at February 2, 2008 - 10:45
Hi,
After example.customization deinstallation an example_customization layer in Plone Default theme is still there. How can I remove this?
Thanks.

For any issues with the web site functionality, please file a ticket.

Please consult the policy on plone.org content if you want your content published on this site.

Servers and hosting by