---
myst:
html_meta:
"description": ""
"property=og:description": ""
"property=og:title": ""
"keywords": ""
---
(plone5-zpt2-label)=
# Customizing Existing Templates
````{sidebar} Get the code!
Code for the beginning of this chapter:
```shell
git checkout zpt
```
Code for the end of this chapter:
```shell
git checkout zpt_2
```
{doc}`code`
````
In this part you will:
- Customize existing templates
Topics covered:
- packages (omelette)
- z3c.jbot
- date formatting and the moment pattern
- listings
- skins
To dive deeper into real Plone data we now look at some existing templates and customize them.
(plone5-zpt2-news-label)=
## The view for News Items
We want to show the date a News Item is published.
This way people can see at a glance if they are looking at current or old news.
To do this you will first customize the template that is used to render News Items.
We use {py:mod}`z3c.jbot` for overriding templates.
The package already has the necessary configuration in {file}`browser/configure.zcml`.
Find the file {file}`newsitem.pt` in {file}`packages/plone/app/contenttypes/browser/templates/`
(in vagrant this directory is in {file}`/home/vagrant/packages`, otherwise it is in your buildout directory).
The file looks like this:
```html
```
```{note}
- Like almost all Plone templates, it uses `metal:use-macro="context/main_template/macros/master"` to use the main_template
- This template fills the same slot `content-core` as the template you created in the last chapter. This means the heading and description are displayed by the `main_template`.
- The image and image caption that is provided by the behavior is not part of the template. Instead a Viewlet is used to display it.
```
Copy that file into the folder {file}`browser/overrides/` of your package. If you use vagrant you'd have to use
```shell
cp /home/vagrant/packages/plone/app/contenttypes/browser/templates/newsitem.pt /vagrant/buildout/src/ploneconf.site/src/ploneconf/site/browser/overrides/
```
- Rename the new file from {file}`newsitem.pt` to {file}`plone.app.contenttypes.browser.templates.newsitem.pt`. {py:mod}`z3c.jbot` allows you to override templates by putting a file inside a special directory with a *canonical name* (i.e. the path of the file separated by `.` plus the original filename).
- Restart Plone
Now Plone will use the new file to override the original one.
Edit the new file {file}`plone.app.contenttypes.browser.templates.newsitem.pt` and insert the following before the `
The current Date
```
Since we use Plone 5 and Chameleon we could also write:
```html
${python: context.Date()}
```
- Open an existing news item in the browser
This will show something like: `2015-02-21T12:01:31+01:00`.
Not very user friendly.
Let's extend the code and use one of many helpers Plone offers.
```html
```
This will render `Feb 21, 2015`.
- `plone_view` is the BrowserView {py:class}`Products.CMFPlone.browser.ploneview.Plone` and it is defined in the `main_template` ({file}`Products/CMFPlone/browser/templates/main_template.pt`) of Plone 5 like this `plone_view context/@@plone;` and thus always available.
- The method {py:meth}`toLocalizedTime` runs a date object through Plone's `translation_service` and returns the Date in the current locales format, thus transforming `2015-02-21T12:01:31+01:00` to `Feb 21, 2015`.
The same in a slightly different style:
```html
The current Date in its local short format
```
Here we first get the Plone view and then the method {py:meth}`toLocalizedTime`
and we use `nocall` to prevent the method {py:meth}`toLocalizedTime` from being called, since we want to make it available for later use.
We could also leave the formatting to the frontend.
Plone 5 comes with the [moment pattern](https://plone.github.io/mockup/dev/#pattern/moment)
that uses the library [moment.js](https://plone.github.io/mockup/dev/#pattern/moment) to format dates in the browser with JavaScript.
Try the relative calendar format:
```html
${python: context.Date()}
```
Now we should see the date in a user friendly format like `Today at 12:01 PM`.
Experiment with other formats such as `calendar` and `LT`.
(plone5-zpt2-summary-label)=
## The Summary View
We use the view "Summary View" to list news releases.
They should also have the date.
The template associated with that view is {file}`listing_summary.pt`.
Let's look for the template:
```
plone/app/contenttypes/browser/templates/listing_summary.pt
```
The file looks like this:
```html
```
Note the following:
- Unlike {file}`newsitem.pt` the file does not display data from a context but obviously pre-defined variables like `item`, `item_link`, `item_type` or `item_description`.
- It reuses multiple macros of a view `context/@@listing_view`.
- The variables are most likely defined in the macro `entries` of that view.
Copy it to {file}`browser/overrides/` and rename it to {file}`plone.app.contenttypes.browser.templates.listing_summary.pt`.
Add the following after line 28:
```html
${python:plone_view.toLocalizedTime(item.Date())}
```
After you restart the instance and look at the new folder again you'll see the dates. {py:mod}`z3c.jbot` needs a restart to pick up the new file.
When you only change a existing override you don't have to restart.
The addition renders the date of the respective objects that the template iterates over
(hence `item` instead of `context` since `context` would be either a collection aggregating the news items or a folder containing a news item).
The date is only displayed if the variable `item_type` is `News Item`.
Let's take a closer look at that template. How does it know that `item_type` is the name of the content type?
The first step to uncovering that secret is line 14 of {file}`listing_summary.pt`:
```html
```
`use-macro` tells Plone to reuse the macro `entries` from the view `listing_view`.
That view is defined in {file}`packages/plone/app/contenttypes/browser/configure.zcml`.
It uses the template {file}`plone/app/contenttypes/browser/templates/listing.pt`.
That makes overriding that much easier.
That template {file}`listing.pt` defines the slot `entries` like this:
```xml
...
```
Here the `item_type` is defined as `item_type item/PortalType`.
Let's dig a little deeper and find out what `item` and `PortalType` are.
`tal:repeat="item batch"` tells the template to iterate over an iterable `batch` which is defined as `batch view/batch`.
`view` is always the BrowserView for which the template is registered.
In our case this is either {py:class}`plone.app.contenttypes.browser.collection.CollectionView` if you called that view on a collection,
or {py:class}`plone.app.contenttypes.browser.folder.FolderView` for folders.
You might remember that both are defined in {file}`configure.zcml`
Luckily the first is a class that inherits from the second:
```python
class CollectionView(FolderView):
```
{py:meth}`batch` is a method in {py:class}`FolderView` that turns {py:obj}`results` into batches. {py:obj}`results` exists in both classes.
This means, in case the item we are looking at is a collection, the method {py:meth}`results` of {py:class}`CollectionView`,
will be used; and in case it's a folder, the one in {py:class}`FolderView`.
`batch` is a list of items.
The way it is created is actually pretty complicated and makes use of a couple of packages to create
a filtered (through {py:mod}`plone.app.querystring`) list of optimized representations (through {py:mod}`plone.app.contentlisting`) of items.
For now it is enough to know that `item` represents one of the items in the list of News Items.
The template {file}`listing_summary.pt` is extraordinary in its heavy use of nested macros.
Most of the templates you will write are much simpler and easier to read.
It can be hard to understand templates as complicated as these, but there is help to be found if you know Python: use {py:mod}`pdb` to debug templates line by line.
Add the following to line 29 just before our additions:
```
```
When you reload the page and look at the terminal you see you have the pdb console and
can inspect the template at its current state by looking at the variable `econtext`.
You can now simply look up what `` item ` and `PortalType `` are:
```python
(pdb) pp econtext
[...]
'context': ,
'context_state': ,
'default':