Description
How to create and subclass portlets in Plone. How to look-up and modify portlets on the site programmatically.
Please read Portlets developer manual.
You can subclass a portlet to create a new portlet type with your enhanced functionality.
Use <plone:portletRenderer> directive. Specify 1) layer, 2) template and/or 3) class 4) portlet interface.
You need <include package=""> directive for the package whose portlet you are going to override.
<configure
xmlns:plone="http://namespaces.plone.org/plone"
>
<include package="plone.app.portlets" />
<plone:portletRenderer
portlet="plone.app.portlets.portlets.news.INewsPortlet"
template="mytheme_news.pt"
layer=".interfaces.IThemeSpecific"
/>
</configure>
More information
These methods should honour zope.contentprovider.interfaces.IContentProvider call contract.
The portlet renderer can define available property to hint the portlet manager when the portlet should be rendered.
Example
class Renderer(base.Renderer):
@property
def available(self):
# Show this portlet for logged in users only
return not self.anonymous
Below is an simple example how to print all portlets which have been assigned to the portal root:
def check_root_portlets(self):
""" Print all portlet assignments in the portal root """
from zope.component import getUtility, getMultiAdapter
from plone.portlets.interfaces import IPortletManager
from plone.portlets.interfaces import IPortletAssignment
from plone.portlets.interfaces import IPortletAssignmentMapping
content = self.portal
for manager_name in [ "plone.leftcolumn", "plone.rightcolumn" ]:
print "Checking portlet column:" + manager_name
manager = getUtility(IPortletManager, name=manager_name, context=content)
mapping = getMultiAdapter((content, manager), IPortletAssignmentMapping)
# id is portlet assignment id
# and automatically generated
for id, assignment in mapping.items():
print "Found portlet assignment:" + id + " " + str(assignment)
The following code iterates through all portlets assigned directly to content items. This excludes dashboard, group and content type based portlets. Then it prints some info about them and renders them.
Example code:
from Products.Five.browser import BrowserView
from zope.component import getUtility, getMultiAdapter
from zope.app.component.hooks import setHooks, setSite, getSite
from plone.portlets.interfaces import IPortletType
from plone.portlets.interfaces import IPortletManager
from plone.portlets.interfaces import IPortletAssignment
from plone.portlets.interfaces import IPortletDataProvider
from plone.portlets.interfaces import IPortletRenderer
from plone.portlets.interfaces import IPortletAssignmentMapping
from plone.portlets.interfaces import ILocalPortletAssignable
from Products.CMFCore.interfaces import IContentish
class FixPortlets(BrowserView):
""" Magical portlet debugging view """
def __call__(self):
"""
"""
request = self.request
portal = getSite()
# Not sure why this is needed...
view = portal.restrictedTraverse('@@plone')
# Query all content items on the site which can get portlets assigned
# Note that this should excule special, hidden, items like tools which otherwise
# might appearn in portal_catalog queries
all_content = portal.portal_catalog(show_inactive=True, language="ALL", object_provides=ILocalPortletAssignable.__identifier__)
# Load the real object instead of index stub
all_content = [ content.getObject() for content in all_content ]
# portal itself does not show up in the query above,
# though it might contain portlet assignments
all_content = list(all_content) + [portal]
for content in all_content:
for manager_name in [ "plone.leftcolumn", "plone.rightcolumn" ]:
manager = getUtility(IPortletManager, name=manager_name, context=content)
mapping = getMultiAdapter((content, manager), IPortletAssignmentMapping)
# id is portlet assignment id
# and automatically generated
for id, assignment in mapping.items():
print "Found portlet assignment:" + id + " " + str(assignment)
renderer = getMultiAdapter((content, request, view, manager, assignment), IPortletRenderer)
# Renderer acquisition chain must be set-up so that templates
# et. al. can resolve permission inheritance
renderer = renderer.__of__(content)
# Seee http://svn.zope.org/zope.contentprovider/trunk/src/zope/contentprovider/interfaces.py?rev=98212&view=auto
renderer.update()
html = renderer.render()
print "Got HTML output:" + html
return "OK"
For more information about portlet assignments and managers, see
Example:
import Acquisition
from zope.component import getUtility, getMultiAdapter
from plone.portlets.interfaces import IPortletRetriever, IPortletManager
for column in ["plone.leftcolumn", "plone.rightcolumn"]:
manager = getUtility(IPortletManager, name=column)
retriever = getMultiAdapter((self.context, manager), IPortletRetriever)
portlets = retriever.getPortlets()
for portlet in portlets:
# portlet is {'category': 'context', 'assignment': <FacebookLikeBoxAssignment at facebook-like-box>, 'name': u'facebook-like-box', 'key': '/isleofback/sisalto/huvit-ja-harrasteet
# Identify portlet by interface provided by assignment
if IFacebookLikeBoxData.providedBy(portlet["assignment"]):
return True
return False
If you need additional portlet slots at the site.