.. _portlethowto: How to create a Portlet? ======================== **Portlets** are pluggable user interface software components that are managed and displayed in a web portal, for example an enterprise portal or a web CMS. A portlet can aggregate (integrate) and personalize content from different sources within a web page. A portlet responds to requests from a web client and generates dynamic content (*reference:* `Wiki portlet`_). .. _`wiki portlet`: https://en.wikipedia.org/wiki/Portlet **PyAMS Portal** provides the portal engine but only a very small set of predefined portlets that can be used to compose and organize the structure of a web page; additional portlets are provided by other packages, like :ref:`pyams_content`. Create Portlet --------------- The Portlet component is a utility, which implements the :py:class:`pyams_portal.interfaces.IPortlet` interface and is registered by the :py:func:`pyams_portal.portlet.portlet_config` decorator; .. code-block:: python @portlet_config(permission=VIEW_PERMISSION) class ImagePortlet(Portlet): """Image portlet""" name = NEW_PORTLET_NAME label = _("New portlet") toolbar_image = None toolbar_css_class = 'fa fa-fw fa-2x fa-picture-o' Where: - **permission**: permission required to display this portlet content - **name**: internal name given to this portlet. This name must be unique between all portlets, so using your own namespace into this name is generally a good option! - **label**: user label given to this portlet - **toolbar_image**: URL of an image used to display portlet button into ZMI toolbar, if any - **toolbar_css_class**: CSS class used to display portlet button into ZMI toolbar, if any NB: the argument **settings_class** could be set to add a portlet settings (see below). Portlet settings ---------------- Portlet settings interface are defined in ``interfaces.py``, you can use :py:class:`pyams_portal.interfaces.IPortletSettings` or extend the interface by adding additional properties for example: 1) create portlet settings ^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: python from zope.schema import Text NEW_PORTLET_NAME = 'new.portlet' class INewPortletSettings(IPortletSettings): comment = Text(title=_("Comment"), required=True) A :py:class:`pyams_portal.portlet.PortletSettings` persistent subclass then implements what IPortletSettings describes: .. code-block:: python @implementer(INewPortletSettings) class NewPortletSettings(PortletSettings): """Portlet settings""" comment = FieldProperty(INewPortletSettings['comment']) 2. declare the settings portlet ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Add the settings portlet class inside the portlet .. code-block:: python @portlet_config(permission=VIEW_PERMISSION) class ImagePortlet(Portlet): """Image portlet""" name = NEW_PORTLET_NAME label = _("New portlet") toolbar_image = None toolbar_css_class = 'fa fa-fw fa-2x fa-picture-o' settings_class = NewPortletSettings 3. portlet settings edit form ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Portlet settings have to be updated through management interface (ZMI) via a :py:class:`pyams_portal.zmi.portlet.PortletSettingsEditor` subform: .. code-block:: python @pagelet_config(name='properties.html', context=INewPortletSettings, layer=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION) class NewPortletSettingsEditor(PortletSettingsEditor): """New portlet settings editor""" settings = INewPortletSettings @adapter_config(name='properties.json', context=(INewPortletSettings, IPyAMSLayer), provides=IPagelet) class NewPortletSettingsAJAXEditor(AJAXEditForm, NewPortletSettingsEditor): """New portlet settings editor, JSON renderer""" Previewing portlet content -------------------------- A *previewer* is used into ZMI to display portlet content into portal template definition page: .. code-block:: python @adapter_config(context=(Interface, IPyAMSLayer, Interface, INewPortletSettings), provides=IPortletPreviewer) @template_config(template='my-portlet-preview.pt', layer=IPyAMSLayer) class NewPortletPreviewer(PortletPreviewer): """New portlet previewer""" The previewer template is a Chameleon template: .. code-block:: genshi
Comment
Here we check if portlet is visible or not to display a small icon when hidden; otherwise we display entered comment. Rendering portlet content ------------------------- A *renderer* is used to display portlet content into rendered page content: .. code-block:: python @adapter_config(context=(IPortalContext, IPyAMSLayer, Interface, INewPortletSettings), provides=IPortletRenderer) @template_config(template='my-portlet-render.pt', layer=IPyAMSLayer) class NewPortletRenderer(PortletRenderer): """New portlet renderer""" label = _("Default comment renderer") Each renderer template is also a Chameleon template: .. code-block:: genshi
Comment
This is the configuration of a *default* renderer defined for this portlet; you can provide several renderers for a given portlet by given distinct names to the adapters: .. code-block:: python @adapter_config(name='another-renderer', context=(IPortalContext, IPyAMSLayer, Interface, INewPortletSettings), provides=IPortletRenderer) @template_config(template='my-portlet-render-2.pt', layer=IPyAMSLayer) class AnotherNewPortletRenderer(PortletRenderer): """Another new portlet renderer""" label = _("Another comment renderer") .. tip:: You can use an other template without create a new renderer component, with :py:func:`pyams_utils` to override the default template with you own. .. note:: Select the new portlet in ZMI to make it available in the website template editor .. image:: ../_static/select_portlet.png