Theme Package IV: Creating And Customizing Plone Templates

In the previous sections we created our custom theme and customized it using CSS. But sometimes CSS isn’t enough, sometimes we have to adjust the HTML markup.

If we don’t want to use Diazo rules and XSLT for it, there is another way: customizing templates.

In this section we will show you how you can customize existing templates and create new ones specific for your theme.

Overriding A Plone Template

A large part of the Plone UI is provided by BrowserView and Viewlet templates.

You can see all viewlets and their managers (sortable containers) when you view the URL ./@@manage-viewlets.

Note

To override them from the ZMI, you can go to ./portal_view_customizations. But this is very limited and does not work for all views.

To override them from your theme product, the best way is to use z3c.jbot (Just a Bunch of Templates).

Since jbot is already included in the bobtemplates.plone theme skeleton via plone.app.themingplugins, you can start using it immediately by adding all the templates you want to override in the src/ploneconf/theme/theme/template-overrides directory.

In order for jbot to match the override to the template which is being overridden, the name of the new template needs to include the complete path to the original template as a prefix (with every / replaced by a .).

For instance, to override the path_bar.pt template (the breadcrumbs) from plone.app.layout, knowing that this template is found in a sub folder named viewlets, you need to name the overriding template plone.app.layout.viewlets.path_bar.pt.

Hint

Clicking the template in ZMI > portal_view_customizations is a handy way to find the template path. You can also copy the original template’s code here.

When a new override has been added, the Plone instance needs to be restarted. After this, a page reload is enough to see any changes to the template.

Example: Overriding The Event Item Template

The path to the original template is plone/app/event/browser/event_view.pt, the full dotted name for our replacement template should be: plone.app.event.browser.event_view.pt.

Create a new file with this dotted name into the template-overrides folder.

Let’s say we want to move the full text of the event item to appear before the event details block. To do this, we copy over the original template code and change the order of the two blocks:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      xmlns:tal="http://xml.zope.org/namespaces/tal"
      xmlns:metal="http://xml.zope.org/namespaces/metal"
      xmlns:i18n="http://xml.zope.org/namespaces/i18n"
      lang="en"
      metal:use-macro="context/main_template/macros/master"
      i18n:domain="plone.app.event">
  <body>

    <metal:content-core fill-slot="content-core">
      <metal:block define-macro="content-core">
        <tal:def tal:define="data nocall:view/data">
          <div class="event clearfix" itemscope="itemscope" itemtype="http://data-vocabulary.org/Event">
            <ul class="hiddenStructure">
              <li><a itemprop="url" class="url" href="" tal:attributes="href data/url" tal:content="data/url">url</a></li>
              <li itemprop="summary" class="summary" tal:content="data/title">title</li>
              <li itemprop="startDate" class="dtstart" tal:content="data/start/isoformat">start</li>
              <li itemprop="endDate" class="dtend" tal:content="data/end/isoformat">end</li>
              <li itemprop="description" class="description" tal:content="data/description">description</li>
            </ul>

            <div id="parent-fieldname-text" tal:condition="data/text">
              <tal:text content="structure data/text" />
            </div>

            <tal:eventsummary replace="structure context/@@event_summary" />
          </div>
        </tal:def>
      </metal:block>
    </metal:content-core>
  </body>
</html>

You can now restart Plone and view an event to see the effect.

Hint

If your buildout is using omelette, you can find the original template in buildout/parts/omelette/plone/app/event/browser.

Creating A New Plone Template

Create Dynamic Slider Content In Plone

To render our dynamic content for the slider we need a custom view in Plone. There are various ways to create views.

For now, we will use a very simple template-only-view via jbot and themingplugins. The bobtemplates.plone skeleton includes already everything you need.

The only thing we need to do, is to add a template file in the theme/views folder. Here we create a template file named slider-images.pt.

And we already have this file as an example.

The only thing we need to do is to rename the file slider-images.pt.example to slider-images.pt.

tree src/ploneconf/theme/theme/views/
src/ploneconf/theme/theme/views/
└── slider-images.pt.example

0 directories, 1 file

The template code looks like this:

<div id="carousel-example-generic" class="carousel slide">
  <!-- Indicators -->
  <ol class="carousel-indicators hidden-xs">
    <li tal:repeat="item context/keys"
        data-target="#carousel-example-generic"
        data-slide-to="${python:repeat.item.index}"
        class="${python: repeat.item.start and 'active' or ''}"></li>
  </ol>

  <!-- Wrapper for slides -->
  <div class="carousel-inner">
    <div tal:repeat="item context/values"
         class="item ${python: repeat.item.start and 'active' or ''}">
      <img tal:define="scales item/@@images"
           tal:replace="structure python: scales.tag('image', scale='large', css_class='img-responsive img-full')" />
    </div>
  </div>

  <!-- Controls -->
  <a class="left carousel-control" href="#carousel-example-generic" data-slide="prev">
    <span class="icon-prev"></span>
  </a>
  <a class="right carousel-control" href="#carousel-example-generic" data-slide="next">
    <span class="icon-next"></span>
  </a>
</div>

This is all that’s required to create a very simple template-only view. You can test the view after restarting your Plone instance.

For the view to show up, it needs some images to display. To supply the images, we have to create a folder in Plone named slider-images and add some images there.

Note

We will show you later how to create initial content for the theme

Now we can browse to the View on this folder by visiting: http://localhost:8080/Plone/slider-images/@@slider-images. This will render the markup required to render the slider.

Use The Dynamic Slider Content From Plone

Now that we have our slider-images view which renders our HTML markup for the slider, we need to replace that with the static markup in our template.

For that we use Diazo’s ability to load the content from other URLs, using the href attribute in our rules.xml.

We also make use of the css:if-content attribute to make sure it is only on the front page:

<!-- Front Page Slider -->
<replace
    css:theme="#carousel-example-generic"
    css:content="#carousel-example-generic"
    href="/slider-images/@@slider-images"
    css:if-content=".section-front-page"
    />
<drop
    css:theme="#front-page-slider"
    css:if-not-content=".section-front-page"
    />