Creating New Types of Plone Portlets

A beginner’s practical guide to building Plone websites through graphical interface

(For more resources on Plone, see here.)

Plone makes it easy to create new types of portlets that include custom programming logic for your site. There are several ways to create custom portlets, but the simplest way to get started is to use the add-on product collective.portlet.tal which provides a new type of portlet, called a TAL Portlet. This portlet allows you to write simple bits of code using Zope's TAL templating language.

Let's walk through a quick example of building a custom TAL portlet, which will show a randomly-selected news item from your site.

Installing collective.portlet.tal

Before you can add a TAL portlet, you must download the product from and install the add-on product collective.portlet.tal on your site. The best way to do this is to modify your buildout.cfg file.

Add collective.portlet.tal to the eggs and zcml sections of your buildout. Here's a code snippet with the changes made to it:

eggs =
recipe = plone.recipe.zope2instance
zcml =

Once you've made these changes, re-run buildout by issuing the following command:

$ ./bin/buildout

Once you've added the product to your buildout, visit Site Setup and choose Add/Remove Products, to install collective.portlet.tal in your site.

Finally, add a few news items to your site so that we have something for our new TAL portlet to find.

Adding a simple TAL portlet

With the collective.portlet.tal product in place, the following can happen:

  1. Navigate to your Plone site.
  2. Choose Manage Portlets in the right column.
  3. From the Add portlet... drop-down list, choose TAL Portlet.

  4. You'll see an empty text box in which you can enter a title. We will specify Featured News Item as our title. We'll soon see the code needed to feature a random one of our site's published news items.
  5. In addition to the Title text box, you'll also see an HTML text area titled TAL code. Conveniently, this comes pre-populated with some boilerplate HTML and TAL code. Skim this, so that you get a feel for how this looks and what the common HTML structure is like, for a portlet in Plone.

As an immediate experiment, we will find the following snippet of code:

<dd class="portletItem odd">
Body text

We will modify this, slightly, to:

<dd class="portletItem odd">
Is this thing on?

Click on Save and navigate through the site, and you should see your first TAL portlet in action. Of course, there's nothing in this example that couldn't be accomplished with a static text portlet. So let's navigate back to the Featured News Item portlet and make it a bit more interesting and dynamic.

Update the code in your TAL Portlet to include the following:

<dl class="portlet portlet${portlet_type_name}"
tal:define="newsitems python:context.portal_catalog
(portal_type='News Item', review_state='published');"
<dt class="portletHeader">
<span class="portletTopLeft"></span>
Featured News Item
<span class="portletTopRight"></span>
<dd class="portletItem odd"
tal:define="random_newsitem python:random.choice(newsitems)">
<a tal:content="random_newsitem/Title"
href="[replaced by random news item link]"
title="[replaced by random news item title]"
tal:attributes="href random_newsitem/getURL;
title random_newsitem/Title">[replaced by random news
item title]</a>
<dd class="portletFooter">
<span class="portletBotomLeft"></span>
<a href="">More news...</a>
<span class="portletBottomRight"></span>

Now, let's go into more detail on a few of these sections, so that you understand what's happening. If at any point you need more context, try reading the excellent ZPT reference manual at

(For more resources on Plone, see here.)

Variable declaration

TAL provides a mechanism for declaring variables. This is designated by the tal:define attribute, which can be added to an HTML tag. Within any given  tal:define statement, any number of variables can be defined. The variable name is separated by a space from the code statement that will be executed to determine what value is assigned to the variable. Each variable line is terminated with a semicolon to signify that a new variable is to be defined in the next line.

Below, we add a new variable, newsitems, which consists of a search of the Plone site for all published pieces of content of type News Item.

<dl class="portlet portlet${portlet_type_name}"
tal:define="newsitems python:context.portal_catalog
(portal_type='News Item', review_state='published');"

The python: bit signifies that the ensuing statement should be interpreted as Python code, rather than basic TAL. This is required, so that we can pass several requirements (called "parameters") to Plone's catalog, which will determine the types of items that will be assigned to the newsitems variable. In our case, we request only the items of type News Item that are in the published state. We can now use the value of newsitems within the <dl /> tag and within any HTML tag that is nested below the <dl /> tag in the ensuing HTML (that is, child tags). This is referred to as the scope of this variable.


Another attribute, tal:condition, can be used to determine if everything below the given tag should be displayed. The following is used to make sure that we have found a newsitem before we move on with the rest of the code:


This is an attribute of the same <dl /> tag.

Choosing a random item

As explained above, we'll want to declare another variable that can be used to represent our randomly-chosen item. We will give this the appropriate name of random_newsitem, and the Python code is really quite simple. Python has a helper library called random, and if we pass a list of items to the choice function of Python's random library, we're assured of one randomly-selected result in return.

<dd class="portletItem odd"
tal:define="random_newsitem python:random.choice(newsitems)">

Now, anywhere within our <dd /> tag, we can refer to the random_newsitem variable.

Filling in the value of an HTML tag

The tal:content attribute on an HTML tag has the effect of filling in the HTML tag with a given value. The catalog query from our initial newsitems variable returns what Zope calls "catalog brains". The details aren't important, but remember the fact that it's a high-level overview of the full piece of content, and various items are "indexed" for quick retrieval. One of these items is the Title, and our following statement asks us to fill the <a /> tag with the title of our randomly-chosen news item.

<a tal:content="random_newsitem/Title"

Attributes on an HTML tag

If you're comfortable with HTML, you'll know that many tags have attributes. For example, the <a /> tag has an attribute href, which is used for listing the destination of a hyperlink when the link is clicked on in a web browser. An <img /> tag has a src attribute that specifies the location of the image to be displayed. In TAL, these attributes can be dynamically filled by using the tal:attributes attribute. Inside the quotes, the syntax looks similar to a tal:define attribute, but rather than setting up several variables for use, we're determining which attributes of a given tag will be valued with what. In our case, we fill the title attribute with the same value that will appear within the body of our <a /> tag, and we fill the href attribute with another item that our catalog brain returns which is the absolute url of the randomly-chosen news item. This can be studied within the following snippet:

<a href="[replaced by random news item link]"
title="[replaced by random news item title]"
tal:attributes="href random_newsitem/getURL;
title random_newsitem/Title">[replaced by random news
item title]</a>

The author prefers to include square brackets and a comment about what will happen within the various HTML elements as a reminder of how the code works, so that it looks more familiar to people who know HTML, but do not yet know TAL. However, these comments could be omitted entirely.

When this all is put together, the actual HTML will look something like this:

<a href="
title="Practical Plone Released!">Practical Plone Released!</a>

If at any point during this process you notice a message similar to the following:

<!-- Page Template Diagnostics
Compilation failed
zope.tal.taldefs.TALError: *something went wrong*, at line 1, column 1

it simply means that your HTML has a typo, and that you'll need to find the line in question and fix any issues. Common problems can include:

  • Missing HTML tags (for example, a forgotten </a> closing tag)
  • A mistyped TAL attribute (the author's favorite typo is tal:defines, rather than tal:define)
  • A missing semicolon needed to separate a new variable or HTML attribute declarations

You can now click on Save and navigate through the site. If you have more than one published news item within your site, clicking through the site should display all of your news items, eventually.

More information

A TAL portlet is a very simple way of creating custom portlets. More complex portlets can be created using filesystem-based development practices, but that's beyond the scope of this article.

There is considerable in-depth information on creating new portlets in the documentation section of and in Martin Aspeli's book, Professional Plone Development.


In this article, we looked at several ways to create custom portlets. We walked through a simple example using an add-on product collective.portlet.tal which allowed us to write simple bits of code using Zope's TAL templating language.

Further resources on this subject:


Books to Consider

Practical Plone 3: A Beginner's Guide to Building Powerful Websites
$ 19.50
Professional Plone 4 Development
$ 35.99
Building Websites with Plone
$ 0.00
comments powered by Disqus