Zope 3 browser views

Customising browser views and pages

Browser views are analogous to page templates (.pt files) in skin layers. However, they are registered in ZCML for a particular type of context. Here is an example, from plone.app.content.browser:

    <browser:page
        for="*"
        class=".reviewlist.FullReviewListView"
        name="full_review_list"
        template="full_review_list.pt"
        permission="cmf.ReviewPortalContent" />

This tells us that the view is called @@full_review_list (the @@ disambiguator is not strictly necessary, but it makes it clear that this is a view and not, say, a content item). It is available to users that currently have the Review portal content permission, and it is available for any context (for="*"). The implementation is held in a class called FullReviewListView in reviewlist.py in the current directory, which is implicitly rendered by a template called full_review_list.pt.

One way to customise this is to provide an override for a more specific (or different) context. The "*" context is the most general (under the hood, this means zope.interface.Interface). If we had our own implementation for a standard Page (as identified by the Products.ATContentTypes.interface.document.IATDocument interface), we could do so with the following declaration in our own package's ZCML:

    <browser:page
        for="Products.ATContentTypes.interface.document.IATDocument"
        class="plone.app.content.browser.reviewlist.FullReviewListView"
        name="full_review_list"
        template="document_full_review_list.pt"
        permission="cmf.ReviewPortalContent" />

Here, we have chosen to use the default layer (that is, we haven't specified a layer), but a new context type (the for attribute, which points to the interface of the context type in question). We could have provided a new class (or none at all), but here we use the default view class from plone.app.content. Note that we converted it from a relative module path to an absolute one, since we are now in a different package! We do change the template, which again is relative to the directory where the ZCML file is found. We could have chosen to use a class only, or a template only, if that made more sense.

Alternatively, we could customise by layer (and thus ensure that the customisation only takes effect when the product is installed). Here is another example, this time replacing the default view with a new one, using the old class with a new template.

    <browser:page
        for="*"
        class="plone.app.content.browser.reviewlist.FullReviewListView"
        name="full_review_list"
        template="standard_full_review_list.pt"
        layer=".interfaces.IExampleCustomization"
        permission="cmf.ReviewPortalContent" />

Note that these two declarations can co-exist. In this case, the default will use standard_full_review_list.pt, but the view on a Page will use document_full_review_list.pt, since that is more specific. Of course, we could do both - use a context override and a layer. The result would be that the context override only took effect when the layer is installed.

Finding views

Since views are spread out across packages, it can sometimes be difficult to identify where they come from. Often, doing a file search in your egg cache is a quick-and-dirty solution. However, you can also do either of the following:

  • Go to portal_view_customizations in the ZMI, where you will find views, viewlets and portlet renderers, grouped together by their context type. Hover your mouse over the view title, and you should see a package name and a template name in a tool tip.
  • Append /@@zptviews.html to the end of a particular URL, e.g. http://localhost:8080/plone/@@zptviews.html. This shows views with templates (but not viewlets or portlet renderers), along with their template, context type interface and source ZCML file.