Creating, Customizing, and Assigning Portlets Automatically for Plone 3.3

(For more resources on Plone, see here.)


One of the major changes from Plone 2.5 to Plone 3.0 was the complete refactoring of its portlets engine. In Plone 2.5, left and right side portlets were managed from Zope Management Interface (ZMI) by setting two special properties: left_slots and right_slots.

This was not so hard but was cumbersome. Any TALES path expression—ZPT macros typically—could be manually inserted in the above two properties and would be displayed as a bit of HTML to the final user.

The major drawback for site managers with the old-style approach was not just the uncomfortable way of setting which portlets to display, but the lack of any configuration options for them. For example, if we wanted to present the latest published news items, we wouldn't have any means of telling how many of them to show, unless the portlet itself were intelligent enough to get that value from some other contextual property. But again, we were still stuck in the ZMI.

Fortunately, this has changed enormously in Plone 3.x:

  • Portlets can now be configured and their settings are mantained in ZODB.
  • Portlets are now managed via a user-friendly, Plone-like interface. Just click on the Manage portlets link below each of the portlets columns (see the following screenshot).

In the above screen, if we click on the News portlet link, we are presented with a special configuration form to choose the Number of items to display and the Workflow state(s) we want to consider when showing news items.

If you have read previous chapters, you might be correctly guessing that Zope 3 components (zope.formlib mainly) are behind the portlets configuration forms.

In the next sections, we'll look again at the customer's requirements:

  • Advertisement banners will be located in several areas of every page
  • Advertisement banners may vary according to the section of the website

Creating a portlet package

Once again, paster comes to the rescue. As in Creating a product package structure and Creating an Archetypes product with paster, we will use the paster command here to create all the necessary boilerplate (and even more) to get a fully working portlet.

Getting ready

As we are still at the development stage, we should run the following commands in our buildout's src folder:

cd ./src

How to do it...

  1. Run the paster command: We are going to create a new egg called pox.portlet.banner. The pox prefix is from PloneOpenX (the website we are working on) and it will be the namespace of our product.

    Portlets eggs usually have a nested portlet namespace as in plone.portlet.collection or plone.portlet.static. We have chosen the pox main namespace as in the previous eggs we have created, and the banner suffix corresponds to the portlet name. For more information about eggs and packages names read
    If you want to add portlets to an existing package instead of creating a new one, the steps covered in this chapter should tell you all you need to know (the use of paster addcontent portlet local command will be of great help).

    In your src folder, run the following command:

    paster create -t plone3_portlet

    This paster command creates a product using the plone3_portlet template. When run, it will output some informative text, and then a short wizard will be started to select options for the package:



    Enter project name


    Expert Mode?





    Portlet to show banners

    Portlet Name

    Banner portlet

    Portlet Type


    After selecting the last option, you'll get an output like this (a little longer actually):

    Creating directory ./pox.portlet.banner
    Recursing into +namespace_package+
    Recursing into +namespace_package2+
    Recursing into +package+
    Recursing into profiles
    Creating ./pox.portlet.banner/pox/portlet/banner/profiles/
    Recursing into default
    Creating ./pox.portlet.banner/pox/portlet/banner/profiles/default/
    Copying metadata.xml_tmpl to ./pox.portlet.banner/pox/portlet/banner/profiles/default/metadata.xml
    Copying portlets.xml_tmpl to ./pox.portlet.banner/pox/portlet/banner/profiles/default/portlets.xml

    This tells us that even the GenericSetup extension profile has also been created by paster. This means that we can install the new Banner portlet product (as entered in the portlet_name option above).

  2. Install the product: To tell our Zope instance about the new product, we must update the buildout.cfg file as follows:

    eggs =
    develop =

    We can automatically install the product during buildout. Add a pox.portlet.banner line inside the products parameter of the [plonesite] part:

    recipe = collective.recipe.plonesite
    products =

  3. Build your instance and, if you want to, launch it to see the new empty Banner portlet:

    ./bin/instance fg

  4. Check the new portlet: After implementing the changes above, if you click on the Manage portlets link in the site's home page (or anywhere in the Plone site), you will see a new Banner portlet option in the drop-down menu. A new box in the portlet column will then be shown.

The Header/Body text/Footer box shown above matches the template definition in the file the way paster created it.

(For more resources on Plone, see here.)

How it works...

Let's have a look at the different folders and files paster has just created:

Portlet component configuration file

In the pox.portlet.banner main folder, open configure.zcml. It contains the <genericsetup:registerProfile /> directive for this product to be listed in the portal_quickinstaller tool and in the Add-on Products configlet in Plone Control Panel.

Most important is the <plone:portlet /> directive used to register the generated portlet and to let it available to be used everywhere we can add portlets (left and right columns or user’s dashboard, for instance):

<!-- If the portlet has no configurable parameters, you
can remove the EditForm declaration in
and delete the 'editview' attribute from this statement.

Portlet registration has several properties which are explained in this table:




The name of the portlet. Think of it as the name of a browser (Zope 3) view.


The actual class-used for this portlet display logic-will be the one implementing this interface.

IBannerPortlet in our example.


The implementing class.


Zope 3-like permissions to guard the viewing and editing of the portlet.


A class with a special render method to tell what to show in the user interface (generally a ZPT file).

Other helper methods can be created and they will all be available via the view variable inside the template.


An add form class, pretty much like previous add form examples we already saw.


Same as above. If the portlet had no configuration options, we could just skip this property.

Portlet module

In the automatically created source files, open the file to find:



The interface (IBannerPortlet in our case)

It's empty for the time being, which means that no configuration settings can be applied to the portlet.

An Assignment class

The interface implementation class with a @property decorated title method to tell how to call this portlet within the management screen.

An AddForm class with a special create method

If our portlet had no settings, AddForm could inherit from base.NullAddForm instead.

An EditForm class

A class to handle edition of the portlet configuration options. If the portlet had no settings, we could skip this class.

GenericSetup import step

As we said before, there's also a profiles/default folder with this portlets.xml file to tell GenericSetup to register the portlet:

<?xml version="1.0"?>

<!-- Portlet type registrations -->

title="Banner portlet"
description="Portlet to show banners"

Note that the addview property matches the addview in the configure.zcml file described earlier.

See also

  • Creating an Archetypes product with paster
  • Creating a product package structure
  • Creating the user interface for Zope 3 content types
  • Creating a policy product
  • Protecting operations with permissions
  • Customizing a new portlet according to our requirements

    In the previous recipe, we covered how to create a new portlet package and then we examined some of its most remarkable pieces of code.

    In this task, we will modify some of the previously explained classes and modules to achieve the desired results: to display several Banners inside a single portlet.

    How to do it...

    1. Add a schema to the portlet interface: In the bannerportlet module, change the IBannerPortlet interface definition for the following block of code:

      from pox.banner.interfaces import ISection
      from import \

      class IBannerPortlet(IPortletDataProvider):
      section = schema.Choice(
      description=_(u"Base section where banners will be
      fetched from."),
      {'object_provides': ISection.__identifier__,}))

      initial = schema.Int(
      title=_(u"Initial Banner"),
      description=_(u"First banner to show from the above

      final = schema.Int(
      title=_(u"Final Banner"),
      description=_(u"Last banner to show. Leave it empty to
      show all banners."),

    2. Initialize data in the Assignment class: In the same file, change the Assignment class with the following lines:

      class Assignment(base.Assignment):

      section = u""
      initial = 1
      final = 0

      def __init__(self, section=u"", initial = 1, final = 0):
      self.section = section
      self.initial = initial = final

      def title(self):
      return "Banner portlet"

    3. Tweak forms by changing widgets: Modify the AddForm and EditForm classes to change the default widget used by a Choice field with this folder-navigation oriented one:

      from import \
      class AddForm(base.AddForm):
      form_fields = form.Fields(IBannerPortlet)
      form_fields['section'].custom_widget = UberSelectionWidget

      def create(self, data):
      return Assignment(**data)

      class EditForm(base.EditForm):
      form_fields = form.Fields(IBannerPortlet)
      form_fields['section'].custom_widget = UberSelectionWidget

    4. State what and when to show in the portlet: In the same bannerportlet module, add these lines:

      from Acquisition import aq_inner
      from pox.banner.interfaces import IBanner
      from plone.memoize import ram
      from time import time

      def _banners_cachekey(method, self):
      Returns key used by @ram.cache.
      the_key = [,,]
      the_key.append(time() // RAM_CACHE_SECONDS)
      return tuple(the_key)

      class Renderer(base.Renderer):
      render = ViewPageTemplateFile('')

      def available(self):
      return len(self.banners())
      def banners(self):
      """ Returns banner HTML from selected section
      context = aq_inner(self.context)
      # Get the catalog
      catalog = getToolByName(context, 'portal_catalog')
      # Is it a min:max or just min: query?
      if not
      position_range = "min:"
      range = ( - 1, )
      elif ==
      position_range = ""
      range = - 1
      position_range = "min:max"
      range = ( - 1, - 1)

      # From the selected section
      # get all the banners
      # in range
      banners = catalog(
      path =
      {"query": '/'.join(portal.getPhysicalPath()) + \,
      "depth": 1},
      object_provides = IBanner.__identifier__,
      getObjPositionInParent =
      {"query": range,
      "range": position_range})
      banners = [banner.body for banner in banners]
      return banners

    5. Modify the ZPT file to display the portlet: Change with this short TAL-improved XHTML:

      <dl class="portlet portletBannerPortlet"

      <dt class="portletHeader">
      <span class="portletTopLeft"></span>
      <tal:title i18n:translate="">Advertisement</tal:title>
      <span class="portletTopRight"></span>

      <dd class="portletItem">
      <tal:banners repeat="banner view/banners">
      <div tal:content="structure banner">
      Banner HTML

    6. There's one remaining task that is not related to portlet creation, but to this particular portlet. Banner objects store their HTML code in a body field, which is not included by default as metadata (catalog columns) in Plone portal_catalog. To correct this, we have created a catalog.xml file in profiles/default of the pox.banner package to tell us which new metadata columns we need in the catalog:

      <?xml version="1.0"?>
      <object name="portal_catalog" meta_type="Plone Catalog Tool">
      <column value="body"/>

    Although this field's name is body, which might be reminiscent of long-formatted text, the contents stored in it are limited: merely the HTML code to render the banner. That's why we included it as metadata in the catalog. Note that it's bad practice to put big fields in catalog.

    Once GenericSetup has created this new column, we must re-index all existing Banners to update their catalog information. To do this, we have also created a custom import step in pox.banner that runs the new reindexBanner method in the setuphandlers module (available in the accompanying source code).

    How it works...

    The code in Step 1 is just another schema definition with three fields. For section, we are using a schema.Choice field, which expects a source argument with the vocabulary to be used. In this case, we are using the very useful SearchableTextSourceBinder method that returns a vocabulary with all objects found in portal_catalog with the passed query. Once we select a Section object, its full path will be stored in the field. You can see how we use it in the banners method in Step 4.

    The changes to the Assignment class in Step 2 provide sensible default values for the three fields in the portlet schema: the highlighted lines show the default values when displaying the add form. The __init__ method is called from the create method in AddForm class (when submitting the portlet configuration data for the first time) and sets the values for every field.

    In Step 4, inside the Renderer class, we created a @property decorated available method that returns True if the portlet should be displayed (that is, has contents to show, is appropriate for the current user, and so on) or False if not.

    The render method is used to tell what to show to the final user, in this case, a ZPT file.

    The banners decorated method is used to get all the Banners to display. Inside the template file, this method will be available via a special view variable: view/banners will return the tuple of found banners.

    In the template in Step 5, the repeat tag uses the banners method from the Renderer class referenced by the view variable.

    See also

  • Creating a folderish content type
  • Creating content types with Dexterity
  • Improving performance by tweaking expensive code
  • Adding configuration options in Plone control panel
  • (For more resources on Plone, see here.)

    Testing portlets

    When working with portlets, we can test two things:

    • Whether the portlet is correctly installed and ready to be used
    • Whether the portlet shows what we wanted under the expected conditions

    Fortunately, paster creates a test suite with these two test cases. Given that it can't know what we want to show in any portlet (paster magic doesn't cover Divination, a rather fuzzy discipline), there's a part that we must complete: the test_render method in the test_portlet module.

    If we have a look at test_portlet in the pox.portlet.banner.tests package, we'll find something that we haven't seen so far: a PyUnit test.

    We have already talked about our favorite testing approach (doctest), so we won't give more details here. Nevertheless, paster has done a very good job so we don't need to reinvent the wheel. Let's see our render test

    How to do it...

    1. Update the afterSetup method: Open the file in tests sub-package and modify the afterSetup method in the TestRenderer class with the following:

      from zope.publisher.browser import TestRequest
      from zope.annotation.interfaces import IAttributeAnnotatable
      from zope.interface import classImplements

      class TestRenderer(TestCase):
      def afterSetUp(self):
      #log in as manager to install pox.banner product
      self.setRoles(('Manager', ))

      # create a pox-root Section
      self.portal.invokeFactory('Section', 'pox-root')

      # Then, 2 Sections with 2 Banners each are created.
      folder = getattr(self.portal, 'pox-root')
      folder.invokeFactory('Section', 'mars')
      folder.invokeFactory('Section', 'earth')
      folder.mars.invokeFactory('Banner', 'banner1')
      folder.mars.banner1.body = "<span>Good bye</span>"
      folder.mars.invokeFactory('Banner', 'banner2')
      folder.mars.banner2.body = "<span>Mars</span>"
      folder.mars.banner2.reindexObject()'Banner', 'banner1') = "<span>Hello</span>"'Banner', 'banner2', ) = "<span>World!</span>"

    2. In the same module and class, update the test_render method:

      def test_render(self):
      classImplements(TestRequest, IAttributeAnnotatable)
      # new portlet with "mars" as the configurable section
      r = self.renderer(
      context = self.portal,
      assignment = bannerportlet.Assignment(section=
      r = r.__of__(self.folder)
      # render the portlet and start the tests
      output = r.render()
      self.failUnless('<span>Good bye</span>' in output)
      self.failUnless('<span>Mars</span>' in output)
      self.failIf('<span>Hello</span>' in output)
      self.failIf('<span>World!</span>' in output)
      # new portlet with "earth" as the configurable section
      r = self.renderer(
      context = self.portal,
      assignment = bannerportlet.Assignment(section=
      r = r.__of__(self.folder)
      # render the portlet and start the opposite tests
      output = r.render()
      self.failUnless('<span>Hello</span>' in output)
      self.failUnless('<span>World!</span>' in output)
      self.failIf('<span>Good bye</span>' in output)
      self.failIf('<span>Mars</span>' in output)

    3. Test the portlet: Run this command in your buildout folder:

      ./bin/instance test -s pox.portlet.banner

    How it works...

    The code in Step 1 of the How to do it... section creates the correct environment for our test to take place:

    • We make sure that pox.banner is installed in Plone. The afterSetUp method is run before any test method is executed. In this way we can do everything we need for the following tests such as creating Sections and Banners.
    • Then we create a pox-root Section in the root of the site. Bear in mind that the pox.controlpanel product has not been installed for this test run, so we don't have any pox-root section that is already created.

    Step 2 shows the code of the test itself:

    • We have slightly changed the original paster Assignment call to pass the section argument our portlet Assignment class expects.
    • The output variable contains the HTML snippet rendered from the portlet associated ZPT file ( in our case).
    • Then the actual tests begin: for a /pox-root/mars Section portlet there should be two banners—Good bye and Mars—and nothing else (neither Hello nor World!).
    • After that, a new configuration is set to our portlet—associated to another Section—and we make the opposed test: for a /pox-root/earth Section portlet, Hello and World! banners are shown, unlike Good bye and Mars that are not displayed.

    Note the use of a special TestRequest method to create new requests every time we call to renderer. This is necessary because the portlet's main method (banners) is decorated with @ram.cache which keeps a cache of the returned value as long as the _banners_cachekey method returns the same value.

    See also

    • Working with paster generated test suites
    • Adding configuration options in Plone control panel

    Assigning portlets automatically

    As we said in the introduction to the article, one of the main advantages of Plone 3.x portlets is the great improvement with regards to the portlets management user interface. Portlets can now be assigned very easily in a friendly and typical Plone administration area.

    However, as Plone developers, we always want to automate things, and if there's a customer requirement that states there must be a certain portlet under certain conditions, then it is not just a wish but a need.

    There are four categories we can use for portlets assignment:

    1. Context: Portlets created in folders via the Manage portlets link.
    2. Group: Portlets associated to a group will be displayed just for those users belonging to it. These portlets can be created or managed when visiting the Group details page in Site Setup
    3. Content type: Portlets related to all objects of an explicit content type. They can be managed in the Types configlet in Plone Control Panel by choosing the selected content type and then clicking on Manage portlets assigned to this content type.
    4. User: Portlets inserted into a member's dashboard. You can view and manage your personal dashboard at http://localhost:8080/plone/dashboard.

    In this task, we will automatically associate a new portlet to a specific content type. Nevertheless, the code presented here can be easily changed to work with other portlet categories.

    Getting ready

    For this task to be more useful, we have created a new portlet inside the package. This portlet displays a Flash player (FlowPlayer actually) with every Video included as a related item in any object.

    Since we haven't explained this portlet anywhere before, first download the source code. Here is a summarized list of the steps taken to produce the portlet in the package:

    1. A new file was added in the portlets sub-package.
    2. The matching file was also created with the required markup.
    3. The new inlinevideoportlet portlet was registered in the configure.zcml file.
    4. Some JavaScript (jQuery actually) was added to the video.js source file inside the browser/flowplayer folder.
    5. The new portlet was included in the portlets.xml file in the profiles/default folder as a new import step for GenericSetup.

    We encourage you to have a look at this new portlet, especially the Python module and the component configuration (ZCML) file.

    Since the configuration we are going to set involves XNewsItem and Video content types (they are separate products) and it is very specific to this particular project, we have chosen to add a new installation routine (a GenericSetup import step) in the pox.policy package. Get an updated copy of it from here.

    How to do it...

    The following changes will be made in the pox.policy package:

    1. Create this portlets.xml import step in the profiles/default folder:

      <?xml version="1.0"?>

    2. Create or update metadata.xml in profiles/default to install dependency products:

      <?xml version="1.0"?>

    3. Relaunch and reinstall the pox.policy product for these changes to take effect. After creating and publishing Video and XNewsItem objects and linking them properly (Video as a related item of XNewsItem) you should get a result like this:

    How it works...

    The new portlet assignment in the XML file in Step 1 has five properties:

    • Depending on the portlet group we want to deal with, we should use different combinations for category and key:




      Context, for portlets in a specific path of the site


      The path of the object we want

      to assign portlets to.

      Group, for portlets to be displayed to users in a certain group


      The group ID.

      Content type, for portlets associated to every object of a content type


      The content meta type.

      User, for portlets in user's dashboard


      The user ID. It works just for Dashboard portlet managers.

    • Once we are clear which group of portlets we want to update, we can choose the portlet manager that will render the portlet: typically plone.leftcolumn and plone.rightcolumn (for left and right portlet columns).
    • Plone has a special container for portlets for every combination of category, key, and manager. The name property is actually the portlet ID to be uniquely identified in that container.
    • The type property matches the name of the <portlet /> directive in its configuration file. In our case, this is configure.zcml in the package:


    There's more...

    Assigning portlets programmatically

    Martin Aspeli's Professional Plone Development shows an example of adding context portlets automatically after content creation. You can find it in its accompanying source code at

    Portlet managers

    We won't cover in this article how to create portlet managers, as there's already a great add-on product that can be used to add them in several places in the final web page: ContentWellPortlets.

    If you need to place even more portlet managers, you can check ContentWellPortlets code and documentation to achieve similar results; consider starting from the browser/configure.zcml file.

    These online tutorials can be also of great help:

    See also

    • Modifying the view of a content type with jQuery
    • Creating a policy product
    • Adding user groups


    In this article, we covered:

  • Creating a portlet package
  • Customizing a new portlet according to our requirements
  • Testing portlets
  • Assigning portlets automatically

  • Further resources on this subject:





    You've been reading an excerpt of:

    Plone 3 Products Development Cookbook

    Explore Title