Canonical way to disable/remove portlets

Continuing the discussion from Removing a portlet from an add-on:

I'm working to clean up an add-on that has a portlet and I need to remove it.

Basically, what I did was the following:

  • disable the portlet by replacing the code on schema, assignment, add form and edit form with empty classes
  • add a DeprecationWarning on the renderer code telling the portlet will be gone in next major version
  • remove the portlets.xml file on the installation profile
  • add an upgrade step to purge the portlet registration (portlets.xml with purge option)

the portlet code looks like this:

# -*- coding: utf-8 -*-
# BBB: this module will be removed in version 3.0
from plone.app.portlets.portlets import base
from plone.portlets.interfaces import IPortletDataProvider
from zope.interface import implementer

import logging
import warnings


logging.captureWarnings(True)


class IFooPortlet(IPortletDataProvider):
    pass


@implementer(IFooPortlet)
class Assignment(base.Assignment):
    pass


class Renderer(base.Renderer):

    def render(self):
        msg = (
            'Use of portlet "Foo" is deprecated; '
            'remove assignment manually from {0}'.format(self.context))
        warnings.warn(msg, DeprecationWarning)


class AddForm(base.AddForm):
    pass


class EditForm(base.EditForm):
    pass

the portlet removal is done like this:

<?xml version="1.0"?>
<portlets>
  <portlet purge="true" addview="my.package.foo" />
</portlets>

(the whole thing can be seen in this pull request.)

do I miss something? how do you handle this kind of use case in your projects?

Note that the GenericSetup documentation says that purge is designed for containers: it will empty the container (not delete it). Use remove="true" to remove a configuration item (it will not always work; some handlers sadly do not support all GenericSetup update facilities -- but I think, it works for portlets (with the speciality that the portlet is identified by the addview rather than the id attribute)).

I think you're not reading the part that does the portlets purge:

but now I'm confused with this: I don't know if it will get rid of all portlets or just the one I'm marking to purge.

You are right :slight_smile: I usually do not look at details but stay on the "overview stage".

"purge" is an attribute designed for container (configuring) elements; it is placed on those container elements and it has the effect to clear the container. The container element can have child elements which will be applied after the purge.

The code you cited indicates that it implements the "purge" attribute on the top level portlets element: it clears all (well almost all) portlet related objects: portlet managers, portlet types, and portlets assigned at the portal root (but not portlets assigned elsewhare).

To remove individual portlet related objects, use the remove attribute on the respective XML element (I hope that this is supported, but I am not sure).

thanks! I replaced purge="true" with remove="true" as suggested.

I merged a couple of pull requests following this pattern.