Page Templates

In this part you will:

  • Learn to write page templates

Topics covered:

  • TAL y TALES

  • METAL
  • Chameleon

Page Templates are HTML files with some additional information, written in TAL, METAL and TALES.

Las plantillas de página debe ser XML válido.

Las tres lenguas son:

  • TAL: “Template Attribute Language”
    • Templating XML/HTML using special attributes
    • Using TAL we include expressions within html
  • TALES: “TAL Expression Syntax”
    • define la sintaxis y la semántica de estas expresiones

  • METAL: “Macro Expansion for TAL”
    • esto nos permite combinar, la reutilización y las plantillas anidadas juntos

TAL and METAL are written like html attribues (href, src, title). TALES are written like the values of html attributes. A typical TAL attribute looks like this:

<title tal:content="context/title">
    The Title of the content
</title>

Se utiliza para modificar la salida:

<p tal:content="string:I love red">I love blue</p>

resultado en:

<p>I love red</p>

Let’s try it. Open the file training.pt and add:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      lang="en"
      i18n:domain="ploneconf.site">
<body>

    <p>red</p>

</body>
</html>

TAL y TALES

Vamos a añadir un poco de magia y modificar la etiqueta <p>:

<p tal:content="string:blue">red</p>

Esto resultará en:

<p>blue</p>

Without restarting Plone open http://localhost:8080/Plone/@@training.

Lo mismo ocurre con los atributos. Vuelva a colocar la línea <p> con:

<a href="http://www.mssharepointconference.com"
   tal:define="a_fine_url string:http://www.ploneconf.org"
   tal:attributes="href a_fine_url"
   tal:content="string:An even better conference">
    A sharepoint conference
</a>

resultado en:

<a href="http://www.ploneconf.org">
    An even better conference
</a>

Nosotros hemos utilizado los tres atributos TAL aquí. Esta es la lista completa de los atributos TAL:

tal:define
define variables. We definded the variable a_fine_url to the string “http://www.ploneconf.org
tal:content
replace the content of an element. We replaced the default content above with “An even better conference”
tal:attributes
dynamically change element attributes. We set the html attribute href to the value of the variable a_fine_url
tal:condition
tests whether the expression is true or false.
tal:repeat

repite un elemento iterable, en nuestro caso, la lista de Charlas.

tal:replace
replace the content of an element, like tal:content does, but removes the element only leaving the content.
tal:omit-tag

eliminar un elemento, dejando el contenido del elemento.

tal:on-error

controlar los errores.

python expressions

So far we only used one TALES expression (the string: bit). Let’s use a different TALES expression now. With python: we can use python code. A simple example:

<p tal:define="title context/title"
   tal:content="python:title.upper()">
   A big title
</p>

Y otro:

<p tal:define="talks python:['Dexterity for the win!',
                             'Deco is the future',
                             'A keynote on some weird topic',
                             'The talk that I did not submit']"
   tal:content="python:talks[0]">
    A talk
</p>

With python expressions

  • sólo se puede escribir declaraciones individuales

  • usted podría importar cosas pero no debe (ejemplo: tal:define="something modules/Products.PythonScripts/something;).

tal:condition

tal:condition
tests whether the expression is true or false.
  • Si es cierto, entonces la etiqueta se representa.

  • Si es false, entonces la etiqueta y todos sus hijos se retiran y ya no se evalúa.

  • Podemos invertir la lógica anteponiendo un not: a la expresión.

Let’s add another TAL Attribute to our above example:

tal:condition="talks"

También pudimos probar que el número de charlas:

tal:condition="python:len(talks) >= 1"

o si una cierta charla está en la lista de charlas:

tal:condition="python:'Deco is the future' in talks"

tal:repeat

Let’s try another attribute:

<p tal:define="talks python:['Dexterity for the win!',
                             'Deco is the future',
                             'A keynote on some weird topic',
                             'The talk that I did not submit']"
   tal:repeat="talk talks"
   tal:content="talk">
   A talk
</p>
tal:repeat

repite un elemento iterable, en nuestro caso, la lista de Charlas.

Cambiamos el formato un poco para construir una lista en la que hay una lista <li> para cada charla:

<ul tal:define="talks python:['Dexterity for the win!',
                              'Deco is the future',
                              'A keynote on some weird topic',
                              'The talk that I did not submit']">
    <li tal:repeat="talk talks"
        tal:content="talk">
          A talk
    </li>
    <li tal:condition="not:talks">
          Sorry, no talks yet.
    </li>
</ul>

path expressions

Regarding TALES so far we used string: or python: or only variables. The next and most common expression are path expressions. Optionally you can start a path expression with path:

Cada expresión de ruta comienza con un nombre de variable. Puede ser tanto un objeto como context, view, template o una variable definida anteriormente como charla.

Después de la variable se añade una barra / y el nombre de un sub-objeto, atributo o método llamable. El ‘/’ se utiliza para terminar el nombre de un objeto y el inicio del nombre de la propiedad. Mismas propiedades pueden ser objetos que a su vez tienen propiedades.

<p tal:content="context/title"></p>

Nos puede encadenar varios de los elementos para obtener la información que queremos.

<p tal:content="context/REQUEST/form"></p>

This would return the value of the form dictionary of the HTTPRequest object. Useful for form handling.

El | (“o”) se utiliza para encontrar un valor alternativo a un camino si la primera ruta se evalúe como nothing o no existe.

<p tal:content="context/title | context/id"></p>

Esto devuelve el id del contexto si no tiene título.

<p tal:replace="talk/average_rating | nothing"></p>

Esto devuelve nada si no hay ‘average_rating’ para una charla. Lo que no funciona es tal:content="python:talk['average_rating'] or ''". ¿Quién sabe lo que esto produciría?

Conseguiremos KeyError: 'average_rating'. Es muy mala práctica, use | con demasiada frecuencia, ya que se tragará errores como un error tipográfico en tal:content="talk/averange_ratting | nothing" y es posible que se preguntan por qué no existen calificaciones más tarde...

You can’t and should not use it to prevent errors like a try/except block.

Hay varias variables incorporado que se pueden utilizar en caminos:

El más utilizado uno es nothing que es el equivalente a None

<p tal:replace="nothing">
    this comment will not be rendered
</p>

A dict of all the available variables is econtext

<dl tal:define="path_variables_dict econtext">
  <tal:vars tal:repeat="variable path_variables_dict">
    <dt>${variable}</dt>
    <dd>${python:path_variables_dict[variable]}</dd>
  </tal:vars>
</dl>

Nota

In Plone 4 that used to be CONTEXTS

<dl tal:define="path_variables_dict CONTEXTS">
  <tal:vars tal:repeat="variable path_variables_dict">
    <dt tal:content="variable"></dt>
    <dd tal:content="python:path_variables_dict[variable]"></dd>
  </tal:vars>
</dl>

Muy útil para depuración :-)

Pure TAL blocks

We can use TAL attributes without HTML Tags. This is useful when we don’t need to add any tags to the markup

Sintaxis:

<tal:block attribute="expression">some content</tal:block>

Ejemplos:

<tal:block define="id template/id">
...
  <b tal:content="id">The id of the template</b>
...
</tal:block>

<tal:news condition="python:context.content_type == 'News Item'">
    This text is only visible if the context is a News Item
</tal:news>

manejo de datos complejos en plantillas

Let’s move on to a little more complex data. And to another TAL attribute:

tal:replace

reemplazar el contenido de un elemento y elimina el elemento dejando sólo el contenido.

Ejemplo:

<p>
    <img tal:define="tag string:<img src='https://plone.org/logo.png'>"
         tal:replace="tag">
</p>

este resulta en:

<p>
    &lt;img src='https://plone.org/logo.png'&gt;
</p>

tal:replace drops its own base tag in favor of the result of the TALES expression. Thus the original <img... > is replaced. But the result is escaped by default.

Para prevenir que se escapen utilizamos structure

<p>
    <img tal:define="tag string:<img src='https://plone.org/logo.png'>"
         tal:replace="structure tag">
</p>

Ahora vamos a emular una estructura típica Plone mediante la creación de un diccionario.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
  <table tal:define="talks python:[{'title':'Dexterity for the win!',
                                    'subjects':('content-types', 'dexterity')},
                                   {'title':'Deco is the future',
                                    'subjects':('layout', 'deco')},
                                   {'title':'The State of Plone',
                                    'subjects':('keynote',) },
                                   {'title':'Diazo designs dont suck!',
                                    'subjects':('design', 'diazo', 'xslt')}
                                  ]">
      <tr>
          <th>Title</th>
          <th>Topics</th>
      </tr>
      <tr tal:repeat="talk talks">
          <td tal:content="talk/title">A talk</td>
          <td tal:define="subjects talk/subjects">
              <span tal:repeat="subject subjects"
                    tal:replace="subject">
              </span>
          </td>
      </tr>
  </table>

We emulate a list of talks and display information about them in a table. We’ll get back to the list of talks later when we use the real talk objects that we created with dexterity.

To complete the list here are the TAL attributes we have not yet used:

tal:omit-tag
Omit the element tag, leaving only the inner content.
tal:on-error

controlar los errores.

When an element has multiple TAL attributes, they are executed in this order:

  1. define
  2. condition
  3. repeat
  4. content o replace

  5. attributes
  6. omit-tag

Plone 5

Plone 5 uses a new rendering engine called Chameleon. Using the integration layer five.pt it is fully compatible with the normal TAL syntax but offers some additional features:

You can use ${...} as short-hand for text insertion in pure html effectively making tal:content and tal:attributes obsolete. Here are some examples:

Plone 4 and Plone 5:

1
2
3
4
5
<a tal:attributes="href string:${context/absolute_url}?ajax_load=1;
                   class python:context.portal_type().lower().replace(' ', '')"
   tal:content="context/title">
   The Title of the current object
</a>

Plone 5 (and Plone 4 with five.pt) :

1
2
3
4
<a href="${context/absolute_url}?ajax_load=1"
   class="${python:context.portal_type().lower().replace(' ', '')}">
   ${python:context.title}
</a>

You can also add pure python into the templates:

1
2
3
4
5
6
7
8
<div>
  <?python
  someoptions = dict(
      id=context.id,
      title=context.title)
  ?>
  This object has the id "${python:someoptions['id']}"" and the title "${python:someoptions['title']}".
</div>

Exercise 1

Modify the following template and one by one solve the following problems: :

<table tal:define="talks python:[{'title': 'Dexterity is the new default!',
                                  'subjects': ('content-types', 'dexterity')},
                                 {'title': 'Mosaic will be the next big thing.',
                                  'subjects': ('layout', 'deco', 'views'),
                                  'url': 'https://www.youtube.com/watch?v=QSNufxaYb1M'},
                                 {'title': 'The State of Plone',
                                  'subjects': ('keynote',) },
                                 {'title': 'Diazo is a powerful tool for theming!',
                                  'subjects': ('design', 'diazo', 'xslt')},
                                 {'title': 'Magic templates in Plone 5',
                                  'subjects': ('templates', 'TAL'),
                                  'url': 'http://www.starzel.de/blog/magic-templates-in-plone-5'}
                                ]">
    <tr>
        <th>Title</th>
        <th>Topics</th>
    </tr>
    <tr tal:repeat="talk talks">
        <td tal:content="talk/title">A talk</td>
        <td tal:define="subjects talk/subjects">
            <span tal:repeat="subject subjects"
                  tal:replace="subject">
            </span>
        </td>
    </tr>
</table>
  1. Display the subjects as comma-separated.

Solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<table tal:define="talks python:[{'title': 'Dexterity is the new default!',
                                  'subjects': ('content-types', 'dexterity')},
                                 {'title': 'Mosaic will be the next big thing.',
                                  'subjects': ('layout', 'deco', 'views'),
                                  'url': 'https://www.youtube.com/watch?v=QSNufxaYb1M'},
                                 {'title': 'The State of Plone',
                                  'subjects': ('keynote',) },
                                 {'title': 'Diazo is a powerful tool for theming!',
                                  'subjects': ('design', 'diazo', 'xslt')},
                                 {'title': 'Magic templates in Plone 5',
                                  'subjects': ('templates', 'TAL'),
                                  'url': 'http://www.starzel.de/blog/magic-templates-in-plone-5'}
                                ]">
    <tr>
        <th>Title</th>
        <th>Topics</th>
    </tr>
    <tr tal:repeat="talk talks">
        <td tal:content="talk/title">A talk</td>
        <td tal:define="subjects talk/subjects">
            <span tal:replace="python:', '.join(subjects)">
            </span>
        </td>
    </tr>
</table>
  1. Turn the title in a link to the url of the talk if there is one.

Solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<table tal:define="talks python:[{'title': 'Dexterity is the new default!',
                                  'subjects': ('content-types', 'dexterity')},
                                 {'title': 'Mosaic will be the next big thing.',
                                  'subjects': ('layout', 'deco', 'views'),
                                  'url': 'https://www.youtube.com/watch?v=QSNufxaYb1M'},
                                 {'title': 'The State of Plone',
                                  'subjects': ('keynote',) },
                                 {'title': 'Diazo is a powerful tool for theming!',
                                  'subjects': ('design', 'diazo', 'xslt')},
                                 {'title': 'Magic templates in Plone 5',
                                  'subjects': ('templates', 'TAL'),
                                  'url': 'http://www.starzel.de/blog/magic-templates-in-plone-5'}
                                ]">
    <tr>
        <th>Title</th>
        <th>Topics</th>
    </tr>
    <tr tal:repeat="talk talks">
        <td>
            <a tal:attributes="href talk/url | nothing"
               tal:content="talk/title">
               A talk
            </a>
        </td>
        <td tal:define="subjects talk/subjects">
            <span tal:replace="python:', '.join(subjects)">
            </span>
        </td>
    </tr>
</table>
  1. If there is no url turn it into a link to a google search for that talk’s title

Solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<table tal:define="talks python:[{'title': 'Dexterity is the new default!',
                                  'subjects': ('content-types', 'dexterity')},
                                 {'title': 'Mosaic will be the next big thing.',
                                  'subjects': ('layout', 'deco', 'views'),
                                  'url': 'https://www.youtube.com/watch?v=QSNufxaYb1M'},
                                 {'title': 'The State of Plone',
                                  'subjects': ('keynote',) },
                                 {'title': 'Diazo is a powerful tool for theming!',
                                  'subjects': ('design', 'diazo', 'xslt')},
                                 {'title': 'Magic templates in Plone 5',
                                  'subjects': ('templates', 'TAL'),
                                  'url': 'http://www.starzel.de/blog/magic-templates-in-plone-5'}
                                ]">
    <tr>
        <th>Title</th>
        <th>Topics</th>
    </tr>
    <tr tal:repeat="talk talks">
        <td>
            <a tal:define="google_url string:https://www.google.com/search?q=${talk/title}"
               tal:attributes="href talk/url | google_url"
               tal:content="talk/title">
               A talk
            </a>
        </td>
        <td tal:define="subjects talk/subjects">
            <span tal:replace="python:', '.join(subjects)">
            </span>
        </td>
    </tr>
</table>
  1. Add alternating the css classes ‘odd’ and ‘even’ to the <tr>. (repeat.<name of item in loop>.odd is True if the ordinal index of the current iteration is an odd number)

    Use some css to prove your solution:

    <style type="text/css">
      tr.odd {background-color: #ddd;}
    </style>
    

Solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<table tal:define="talks python:[{'title': 'Dexterity is the new default!',
                                  'subjects': ('content-types', 'dexterity')},
                                 {'title': 'Mosaic will be the next big thing.',
                                  'subjects': ('layout', 'deco', 'views'),
                                  'url': 'https://www.youtube.com/watch?v=QSNufxaYb1M'},
                                 {'title': 'The State of Plone',
                                  'subjects': ('keynote',) },
                                 {'title': 'Diazo is a powerful tool for theming!',
                                  'subjects': ('design', 'diazo', 'xslt')},
                                 {'title': 'Magic templates in Plone 5',
                                  'subjects': ('templates', 'TAL'),
                                  'url': 'http://www.starzel.de/blog/magic-templates-in-plone-5'}
                                ]">
    <tr>
        <th>Title</th>
        <th>Topics</th>
    </tr>
    <tr tal:repeat="talk talks"
        tal:attributes="class python: 'odd' if repeat.talk.odd else 'even'">
        <td>
            <a tal:define="google_url string:https://www.google.com/search?q=${talk/title};
                           "
               tal:attributes="href talk/url | google_url;
                               "
               tal:content="talk/title">
               A talk
            </a>
        </td>
        <td tal:define="subjects talk/subjects">
            <span tal:replace="python:', '.join(subjects)">
            </span>
        </td>
    </tr>
</table>
  1. Only use python expressions.

Solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<table tal:define="talks python:[{'title': 'Dexterity is the new default!',
                                  'subjects': ('content-types', 'dexterity')},
                                 {'title': 'Mosaic will be the next big thing.',
                                  'subjects': ('layout', 'deco', 'views'),
                                  'url': 'https://www.youtube.com/watch?v=QSNufxaYb1M'},
                                 {'title': 'The State of Plone',
                                  'subjects': ('keynote',) },
                                 {'title': 'Diazo is a powerful tool for theming!',
                                  'subjects': ('design', 'diazo', 'xslt')},
                                 {'title': 'Magic templates in Plone 5',
                                  'subjects': ('templates', 'TAL'),
                                  'url': 'http://www.starzel.de/blog/magic-templates-in-plone-5'}
                                ]">
    <tr>
        <th>Title</th>
        <th>Topics</th>
    </tr>
    <tr tal:repeat="talk python:talks"
        tal:attributes="class python: 'odd' if repeat.talk.odd else 'even'">
        <td>
            <a tal:attributes="href python:talk.get('url', 'https://www.google.com/search?q=%s' % talk['title'])"
               tal:content="python:talk['title']">
               A talk
            </a>
        </td>
        <td tal:content="python:', '.join(talk['subjects'])">
        </td>
    </tr>
</table>
  1. Use the new syntax of Plone 5

Solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<table tal:define="talks python:[{'title': 'Dexterity is the new default!',
                                  'subjects': ('content-types', 'dexterity')},
                                 {'title': 'Mosaic will be the next big thing.',
                                  'subjects': ('layout', 'deco', 'views'),
                                  'url': 'https://www.youtube.com/watch?v=QSNufxaYb1M'},
                                 {'title': 'The State of Plone',
                                  'subjects': ('keynote',) },
                                 {'title': 'Diazo is a powerful tool for theming!',
                                  'subjects': ('design', 'diazo', 'xslt')},
                                 {'title': 'Magic templates in Plone 5',
                                  'subjects': ('templates', 'TAL'),
                                  'url': 'http://www.starzel.de/blog/magic-templates-in-plone-5'}
                                ]">
    <tr>
        <th>Title</th>
        <th>Topics</th>
    </tr>

    <tr tal:repeat="talk python:talks"
        class="${python: 'odd' if repeat.talk.odd else 'even'}">
        <td>
            <a href="${python:talk.get('url', 'https://www.google.com/search?q=%s' % talk['title'])}">
                ${talk_title}
            </a>
        </td>
        <td>
            ${python:', '.join(talk['subjects'])}
        </td>
    </tr>
</table>
  1. Sort the talks alphabetically by title

Solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<table tal:define="talks python:[{'title': 'Dexterity is the new default!',
                                  'subjects': ('content-types', 'dexterity')},
                                 {'title': 'Mosaic will be the next big thing.',
                                  'subjects': ('layout', 'deco', 'views'),
                                  'url': 'https://www.youtube.com/watch?v=QSNufxaYb1M'},
                                 {'title': 'The State of Plone',
                                  'subjects': ('keynote',) },
                                 {'title': 'Diazo is a powerful tool for theming!',
                                  'subjects': ('design', 'diazo', 'xslt')},
                                 {'title': 'Magic templates in Plone 5',
                                  'subjects': ('templates', 'TAL'),
                                  'url': 'http://www.starzel.de/blog/magic-templates-in-plone-5'}
                                ]">
    <tr>
        <th>Title</th>
        <th>Topics</th>
    </tr>

<?python from operator import itemgetter ?>

    <tr tal:repeat="talk python:sorted(talks, key=itemgetter('title'))"
        class="${python: 'odd' if repeat.talk.odd else 'even'}">
        <td>
            <a href="${python:talk.get('url', 'https://www.google.com/search?q=%s' % talk['title'])}">
                ${talk_title}
            </a>
        </td>
        <td>
            ${python:', '.join(talk['subjects'])}
        </td>
    </tr>
</table>

METAL y macros

¿Por qué nuestra vista es tan feo?, ¿Cómo conseguimos nuestro HTML para representar en la interfaz de usuario de Plone?

Utilizamos METAL (extensión macro para TAL) para definir ranuras que podemos llenar y macros que podemos reutilizar.

We add to the <html> tag:

metal:use-macro="context/main_template/macros/master"

And then wrap the code we want to put in the content area of Plone in:

<metal:content-core fill-slot="content-core">
    ...
</metal:content-core>

Esto pondrá a nuestro código de una sección definida en el main_template llamado “content-core”.

La plantilla de ahora debería tener este aspecto:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      lang="en"
      metal:use-macro="context/main_template/macros/master"
      i18n:domain="ploneconf.site">
<body>

<metal:content-core fill-slot="content-core">

<table tal:define="talks python:[{'title':'Dexterity for the win!',
                                  'subjects':('content-types', 'dexterity')},
                                 {'title':'Deco is the future',
                                  'subjects':('layout', 'deco')},
                                 {'title':'The State of Plone',
                                  'subjects':('keynote',) },
                                 {'title':'Diazo designs are great',
                                  'subjects':('design', 'diazo', 'xslt')}
                                ]">
    <tr>
        <th>Title</th>
        <th>Topics</th>
    </tr>
    <tr tal:repeat="talk talks">
        <td tal:content="talk/title">A talk</td>
        <td tal:define="subjects talk/subjects">
            <span tal:repeat="subject subjects"
                  tal:replace="subject">
            </span>
        </td>
    </tr>
</table>

</metal:content-core>

</body>
</html>

Nota

Since the training only used content from the template, not from the context that it is called on it makes little sense to have the edit bar. We hide it by setting the respective variable on the current request with python to 1: request.set('disable_border', 1).

The easiest way to do this is to define a dummy variable. Dummy because it is never used except to allow us to execute some code.

<metal:block fill-slot="top_slot"
    tal:define="dummy python:request.set('disable_border', 1)" />

macros in browser views

Define un macro en un nuevo archivo macros.pt

<div metal:define-macro="my_macro">
    <p>I can be reused</p>
</div>

Register it as a simple BrowserView in zcml:

<browser:page
  for="*"
  name="abunchofmacros"
  template="templates/macros.pt"
  permission="zope2.View"
  />

Reuse the macro in the template training.pt:

<div metal:use-macro="context/@@abunchofmacros/my_macro">
    Instead of this the content of the macro will appear...
</div>

Which is the same as:

<div metal:use-macro="python:context.restrictedTraverse('abunchofmacros')['my_macro']">
    Instead of this the content of the macro will appear...
</div>

Accediendo a Plonde desde la plantilla

In our template we have access to the context object on which the view is called on, the browser view itself (i.e. all python methods we’ll put in the view later on), the request and response objects and with these we can get almost anything.

In templates we can also access other browser views. Some of those exist to provide easy access to methods we often need:

tal:define="context_state context/@@plone_context_state;
            portal_state context/@@plone_portal_state;
            plone_tools context/@@plone_tools;
            plone_view context/@@plone;"
@@plone_context_state

El BrowserView plone.app.layout.globals.context.ContextState tiene métodos útiles que tienen que ver con el objeto de contexto actual como is_default_page

@@plone_portal_state

El BrowserView plone.app.layout.globals.portal.PortalState tiene métodos para el portal como portal_url

@@plone_tools

El BrowserView plone.app.layout.globals.tools.Tools da acceso a las herramientas mas importante como plone_tools/catalog

Estos son muy utilizados y hay muchos más.

Lo que echamos de menos

Hay algunas cosas que no nos cubrimos hasta el momento:

tal:condition="exists:expression"

comprueba si existe un objeto o un atributo (rara vez utilizada)

tal:condition="nocall:context"

que explícitamente no llamar a un metodo llamable.

Si nos referimos a objetos de contenido sin usar el modificador nocall: estos objetos son innecesariamente representados en la memoria como la expresión se evaluada.

i18n:translate y i18n:domain

las cadenas que ponemos en las plantillas se pueden traducir de forma automática.

Hay mucho más acerca de TAL, TALES y METAL que no hemos cubierto. Usted solamente aprenderá si sigues leyendo, escribiendo y personalización de plantillas.

Chameleon

Chameleon is the successor of Zope Page Templates, is used in Plone 5 and can be used in Plone 4 as an add-on.

In Plone 4 uses the default ZPT where some features are missing.