Remove the default portlet assignments using GenericSetup

I'd like for my add-on to remove all existing portlet assignments from the Plone site. Can I do that using portlets.xml or do I need to remove them using a custom import step code?

You can do it with xml:

2 Likes

It is possible to do it with XML as Davi pointed out, but that is only going to work if you know which portlets are in the site and where they are assigned. You would be better off writing an upgrade steps that runs through the site to remove all portlets.

1 Like

I'm late on the party, but do you have any code pointer to do such removal? I want a portlets free website :slight_smile:

UPDATE: with the following no portlet manager, portlet, assignment or blacklist is registered. Add it to your portlets.xml:

<?xml version="1.0"?>
<portlets purge="True">
</portlets>

While this works fine on a local (empty) instance, I'm not sure what would be the impact on a production site with potentially, thousands of portlets, thus a code pointer would still be nice :slight_smile:

2 Likes

Here is an upgrade step from one of our projects for removing a specific portlet. Removing the condition on the id and just doing del mapping[id] should remove portlets set anywhere other than the site root.

def remove_mostviewed_portlet_assignments(context):
    """ We are no longer using these and the code has been removed
    """
    portal = getSite()
    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():
                if id.startswith('most-viewed'):
                    # set fixing_up to True to let zope.container.contained
                    # know that our object doesn't have __name__ and __parent__
                    fixing_up = contained.fixing_up
                    contained.fixing_up = True
                    del mapping[id]
                    contained.fixing_up = fixing_up
                    logger.info(
                        "Removed `most-viewed` assignment from: {0}".format(
                            '/'.join(content.getPhysicalPath()))
                    )
3 Likes

this code just remove portlets bound to objects in the catalog; do you know how to remove Dashbord, Group and Content type portlets?

are we missing other contexts?

There was another upgrade step after that one for removing from the content types:

def remove_mostviewed_portlet_assignments2(context):
    """Remove the default assignments by type"""

    manager = 'plone.rightcolumn'
    category = 'content_type'
    types_with_mv = ('News', 'Homepage')
    mv_portlets = (u'most-viewed-1', u'most-viewed-2')

    mapping = getUtility(IPortletManager, manager)[category]

    for mv_type in types_with_mv:
        tmap = mapping[mv_type]
        for portlet in mv_portlets:
            if portlet in tmap:
                fixing_up = contained.fixing_up
                contained.fixing_up = True
                del tmap[portlet]
                contained.fixing_up = fixing_up
                logger.info(
                    "Removed `most-viewed` assignment from type: " + mv_type
                )

    transaction.savepoint()
3 Likes

awesome! that gives a clue on how to find the others.

CC @idgserpro

1 Like

A dream would be to have a method like this but in portlet code, like remove_portlet_assignment. :cry:

Anyways, nice snippet.

what about adding the portlets namespace to plone.api? :wink:

2 Likes

We're not sure about it's goals:

(plone.api) The intention is to cover 20% of the tasks any Plone developer does 80% of the time,

But somehow in the future having functions like this to help with general uninstalling (for example We need to stop using an add-on that registered a browserlayer. Which is the best way to do it and avoid pickling errors between upgradeSteps?) would be really nice.

Somewhat related to the portlet discussion on removing all portlets from a certin type on the site, but I didn't get any feedback on my own post, so I'll try to plug it here. :innocent: Is there any interest in the community to limit the contents of the portlet dropdownmenu based on roles without resorting to genericsetup portlets.xml ?

This statement is kind of outdated, it was common sens that we will increase the possibilities of the plone.api, so that we can use it for more things. That is allowing us later to change and cleanup things under it without breaking others code.
Maybe we should update the statement;)

1 Like