Actions

Description

Creating and using portal_actions mechanism

Introduction

Plone has concept of actions which refer the end user functionality associated with site or content objects:

  • View, edit, sharing etc. are actions
  • Sitemap is action
  • Contact form is action
  • Cut, copy, paste are actions
  • Logged in menu is populated by actions

Actions are managed by

  • portal_actions for generic actions
  • portal_types for view, edit etc. actions and object default action... all actions which are tied to a particular content type and may vary by type

Iterating through available actions

Here is a page template example

 <ul>
      <tal:actions repeat="action python:context.portal_actions.listFilteredActionsFor(context)['portal_tabs']">
        <li>
              <a tal:attributes="href action/url; title action/title;" tal:content="action/title">
                Action title
              </a>
        </li>
      </tal:actions>
</ul>

Creating actions through-the-web

Visit portal_actions in ZMI.

Exporting and importing all portal_actions

You can transfer action configuration from a Plone site to another using GenericSetup export/import XML. You can also do this to generate XML from which you can cut out snippets for creating actions.xml by hand.

  • Go to portal_setup
  • Choose Export
  • Choose actions
  • Choose "Export selected steps" button at the end of the page
  • ...and so on

Creating actions.xml by hand

Usually all actions are rewritten by site policy product using portal_actions import/export. Actions are in GenericSetup profile file default/profiles/actions.xml.

  1. actions.xml is exported from the development instance using portal_setup
  2. actions.xml is made part of the site policy product

Alternatively, if you are developing add-on product, you can add actions one-by-one by manually creating entries in actions.xml.

Example how to add an action to the document_actions (like rss and print):

<?xml version="1.0"?>
<object name="portal_actions" meta_type="Plone Actions Tool"
   xmlns:i18n="http://xml.zope.org/namespaces/i18n">
 <object name="document_actions" meta_type="CMF Action Category">
  <object name="sendto" meta_type="CMF Action" i18n:domain="plone">
   <property name="title" i18n:translate="">Send this</property>
   <property name="description" i18n:translate=""></property>
   <property name="url_expr">string:$object_url/sendto_form</property>
   <property name="icon_expr"></property>
   <property name="available_expr">object/@@shareable</property>
   <property name="permissions">
    <element value="Allow sendto"/>
   </property>
   <property name="visible">True</property>
  </object>
 </object>
</object>

Example how to add actions to user menu, which is visible in the top right corner for logged in users (Plone 4):

<?xml version="1.0"?>
<object name="portal_actions" meta_type="Plone Actions Tool"
   xmlns:i18n="http://xml.zope.org/namespaces/i18n">
 <object name="user" meta_type="CMF Action Category">
  <object name="ora_sync" meta_type="CMF Action" i18n:domain="plone">
   <property name="title" i18n:translate="">ORA</property>
   <property name="description" i18n:translate="">ORA site synchronization status</property>
   <property name="url_expr">string:${portal_url}/@@syncall</property>
   <property name="icon_expr"></property>
   <property name="available_expr"></property>
   <property name="permissions">
    <element value="Manage portal"/>
   </property>
   <property name="visible">True</property>
  </object>
 </object>
</object>

Reordering actions in actions.xml

Try using these attributes

  • insert-after
  • insert-before

They accept * and action name parameters.

Example:

<object name="sendto" meta_type="CMF Action" i18n:domain="plone" insert-before="*">

Action URLs

Actions are applied to objects by adding action name to url.

E.g.:

http://localhost:8080/site/page/view

for view action and:

http://localhost:8080/site/page/edit

for edit action.

Action can be also not related to document, like:

http://localhost:8080/site/sitemap

Default action

Default action is executed when the content URL is opened without any prefix.

Default action is defined in portal_types.

Default action can be dynamic - meaning that site editor may set it from Display menu. For more information see Dynamic Views.

Content-type specific actions

Content-type specific actions can be registered in portal_types. Actions are viewable and editable in Zope Management Interface under portal_types. After editing actions, content type XML can be exported and placed to your content type add-on product.

GenericSetup example file for content type "ProductCard" which has a new tab added next to view, edit, sharing, etc. File is located in profiles/default/types/ProductCard.xml.

<?xml version="1.0"?>
<object name="ProductCard"
   meta_type="Factory-based Type Information with dynamic views"
   i18n:domain="saariselka.app" xmlns:i18n="http://xml.zope.org/namespaces/i18n">
  <property name="title" i18n:translate="">Tuotekortti</property>
  ....
  <alias from="(Default)" to="(dynamic view)" />
  <alias from="edit" to="atct_edit" />
  <alias from="sharing" to="@@sharing" />
  <alias from="view" to="(selected layout)" />
  <action title="View" action_id="view" category="object" condition_expr=""
    url_expr="string:${object_url}/" visible="True">
    <permission value="View" />
  </action>
  <action title="Edit" action_id="edit" category="object" condition_expr=""
    url_expr="string:${object_url}/edit" visible="True">
    <permission value="Modify portal content" />
  </action>

  <!-- Custom action code goes here. We add a new tab with title "Data" and
         uri @@productdata_view which is a registered BrowserView for the content type.
    -->

 <action title="Data" action_id="productdata_view" category="object" condition_expr=""
    url_expr="string:${object_url}/@@productdata_view" visible="True">
    <permission value="Modify portal content" />
  </action>

</object>

The corresponding BrowserView is registered as any other view in browser/configure.zcml:

<browser:page
    for="*"
    name="productdata_view"
    class=".productdataview.ProductDataView"
    template="productdataview.pt"
    allowed_attributes="renderData"
    permission="zope2.View"
    />

Toggling action visibility programmatically

Warning

This applies only for Plone 2.5. You should use actions.xml instead.

Example:

def disable_actions(portal):
    """ Remove unneeded Plone actions

    @param portal Plone instance
    """

    # getActionObject takes parameter category/action id
    # For ids and categories please refer to portal_actins in ZMI
    actionInformation = portal.portal_actions.getActionObject("document_actions/rss")

    # See ActionInformation.py / ActionInformation for available edits
    actionInformation.edit(visible=False)

Visibility expressions

In portal_actions expression is used to determine whether an action is visible on a particular page.

Expression is "expression" field in actions.xml or "Expression" field in portal_actions.

Note

This check is just a visibility check. Users can still try to type the action by typing the URL manually. You need to do the permission level security check on the view providing the action.

For more information see expressions.

Using actions in views and viewlets

Example:

context_state = getMultiAdapter((self.context, self.request),
                            name=u'plone_context_state')

# First argument is action category,
# we have custom "mobile_actions"
self.actions = context_state.actions().get('mobile_actions', None)

Tabs (sections)

Tabs are special actions

  • Some of tabs are automatically generated from root level content items
  • Some of tabs are manually added to portal_actions.portal_tabs

By default, they are shown as the top vertical navigation of Plone site.

Example how to generate tabs list:

def getSections(self):
    """

    @return: tuple (selectedTabs, currentSelectedTab)
    """

    context_state = getMultiAdapter((self.context, self.request),
                                    name=u'plone_context_state')
    actions = context_state.actions()


    # Get CatalogNavigationTabs instance
    portal_tabs_view = getMultiAdapter((self.context, self.request),
                                       name='portal_tabs_view')

    # Action parameter is "portal_tabs" by default, but can be other
    portal_tabs = portal_tabs_view.topLevelTabs(actions=actions)

    selectedTabs = self.context.restrictedTraverse('selectedTabs')

    selected_tabs = selectedTabs('index_html',
                                      self.context,
                                      portal_tabs)

    selected_portal_tab = selected_tabs['portal']

    return (portal_tabs, selected_portal_tab)

Custom action listings

Example:

import Acquisition
from zope.component import getMultiAdapter

class Sections(base.Sections):
    """
    """

    def update(self):
        base.Sections.update(self)

        context = Acquisition.aq_inner(self.context)
        # IContextState view provides shortcut to get different action listings
        context_state = getMultiAdapter((context, self.request), name=u'plone_context_state')
        all_actions = context_state.keyed_actions() # id -> action mappings
        mobile_site_actions = all_actions["mobile_site_actions"].values()
        self.portal_tabs = mobile_site_actions

Different tabs per section/folder

You might want to have different actions for different site sections or folders.

Copy, cut and paste

These action are based on OFS Zope 2 package SimpleItem mechanisms. Plone specific event handlers are used to update Plone related stuff like portal_catalog on move.

Plone internal clipboard relies on the presence of Zope 2 session (different from authentication session). Paste action fails silenlty (is missing) if _ZopeId session cookie does not work correctly on your web server.