External Methods in Plone

Using external methods in Plone, capturing user input and returning data to a page template.

Prerequisite

If it doesn't exist already, you'll need to create a folder to house your external methods and reference that directory in buildout.cfg.

Depending on your Plone installation type, put this either under your [instance] or [client#] headings:

zope-conf-additional = extensions ${buildout:directory}/DIRECTORY_NAME

Don't forget to make sure your extensions directory exists.

Stop your Plone instances, and run buildout:

sudo -u plone_buildout bin/buildout

Once your Plone instances are started, External Methods you create will reside in this new folder.

External Method

Create a new Python script in your new DIRECTORY_NAME directory that you created earlier, this example will return the output of the dig command.

import subprocess

def dig(self, domain):
# If you send the form data directly to this method, you can access the request object with:
# self.REQUEST.get('YOUR_ATTRIBUTE')
return subprocess.check_output(['dig', domain])

In your Zope Management Interface create a new External Method and give it a name, then fill in the necessary fields so it can read your previous Python (in this example, each can contain: dig).

Script (Optional)

This step is optional as it depends on how you want to call your External Method, you can just send any form data directly to the External Method but I send it to a script usually for validation etc.

Create a new Script (Python) item in the Zope Management Interface and give it a name, this script will call your External Method, to call it you use context.externalmethod_id:

request = container.REQUEST # contains the form input fields

if not request.domain: # Check if the domain field exists in the request send to the script
  context.plone_utils.addPortalMessage("You must enter a domain.", "error") # add a message to appear in portal messages
  context.REQUEST.RESPONSE.redirect(context.absolute_url()) # redirect so the above message appears straight away

return context.dig_em(request.domain) # dig_em being the id of the External Method

Page Template

For our form form, create a new Page Template, we can reference the output of the script using structure context/script_id:

<html metal:use-macro="context/main_template/macros/master">
  <body metal:fill-slot="main">
    <h1>Page Title</h1>

    <form action="" method="post">
      <input type="text" placeholder="example.com" id="domain" name="domain" tal:attributes="value python:context.REQUEST.get('domain', None)" />
      <input type="submit" value="Dig" />
    </form>

    <pre tal:condition="exists:python:context.REQUEST.domain" tal:content="context/search">result</pre>
  </body>
</html>