Portal#

Get portal object#

Getting the Plone portal object is easy with api.portal.get().

from plone import api
portal = api.portal.get()

Get navigation root#

In multilingual or multi-site Plone installations, you probably want to get the language-specific navigation root object, not the top portal object.

You do this with api.portal.get_navigation_root().

Assuming there is a document english_page in a folder en, which is the navigation root:

from plone import api
nav_root = api.portal.get_navigation_root(english_page)

Returns the folder en. If the folder en is not a navigation root, it would return the portal.

Get portal url#

Since we now have the portal object, it's easy to get the portal URL.

from plone import api
url = api.portal.get().absolute_url()

Get tool#

To get a portal tool easily, use api.portal.get_tool() and pass in the name of the tool you need.

from plone import api
catalog = api.portal.get_tool(name='portal_catalog')

Get localized time#

To display the date/time in a user-friendly way, localized to the user's preferred language, use api.portal.get_localized_time().

from plone import api
from DateTime import DateTime
today = DateTime()
localized = api.portal.get_localized_time(datetime=today)

Get default language#

To get the default language, use api.portal.get_default_language().

from plone import api
lang = api.portal.get_default_language()

Get current language#

To get the currently negotiated language, use api.portal.get_current_language().

from plone import api
lang = api.portal.get_current_language()

Translate#

To translate a message in a given language, use api.portal.translate().

from plone import api
msg = api.portal.translate('Edited', lang='es')

Send E-Mail#

To send an e-mail use api.portal.send_email():

from plone import api
api.portal.send_email(
    recipient="bob@plone.org",
    sender="noreply@plone.org",
    subject="Trappist",
    body="One for you Bob!",
)

If you need to add other fields not supported on send_email signature, Python's standard email module can also be used:

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

message = MIMEMultipart()
message.attach(MIMEText("One for you Bar!"))

part = MIMEText('<xml></xml>', 'xml')
part.add_header(
    'Content-Disposition',
    'attachment; filename="report.xml"'
)
message.attach(part)

message['Reply-To'] = "community@plone.org"

api.portal.send_email(
    recipient="bob@plone.org",
    sender="noreply@plone.org",
    subject="Trappist",
    body=message,
)

The following code is a more complex example that constructs an email with a file attachment, HTML, plain text, and mail headers to control the mail response.

from email.encoders import encode_base64
from email.header import Header
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from plone import api

# we need a message part to bundle the HTML and Plain Text
textmsgpart = MIMEMultipart("alternative")

# create plain text part of email
plaintextpart = MIMEText("Fill out your plain text", "plain", "utf-8")

# create html text of email
html = "<html><body><p>fill out your text in HTML</p></body></html>"
htmlpart = MIMEText(html, "html", "utf-8")

# bundle the parts
textmsgpart.attach(plaintextpart)
textmsgpart.attach(htmlpart)

# handle the file attachment

# Create a dummy PDF as NamedBlobFile
from plone.namedfile.file import NamedBlobFile

# Minimal PDF content (a valid but nearly empty PDF)
pdf_content = b"""%PDF-1.4
1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj
2 0 obj<</Type/Pages/Count 1/Kids[3 0 R]>>endobj
3 0 obj<</Type/Page/Parent 2 0 R/MediaBox[0 0 612 792]/Contents 4 0 R>>endobj
4 0 obj<</Length 44>>stream
BT /F1 12 Tf 100 700 Td (Hello World) Tj ET
endstream endobj
xref
0 5
0000000000 65535 f
0000000009 00000 n
0000000056 00000 n
0000000115 00000 n
0000000214 00000 n
trailer<</Size 5/Root 1 0 R>>
startxref
315
%%EOF"""

attachment = NamedBlobFile(
    data=pdf_content,
    contentType='application/pdf',
    filename='document.pdf'
)

filepart = MIMEBase("application", "pdf")
filepart.set_payload(attachment.data)
encode_base64(filepart)
filepart.add_header(
    "Content-Disposition",
    "attachment",
    filename=(Header(attachment.filename, "utf-8").encode()),
)

# we need a mixed Multipart Message to bundle the text bundle and the attachment
msg = MIMEMultipart("mixed")
msg["From"] = "sender@abc"
msg["To"] = "recipient@zzz"
msg["Subject"] = "The Mail Subject"
msg["Reply-To"] = "community@plone.org"
msg["Return-Path"] = "error@xxx"

# add the text message bundle
msg.attach(textmsgpart)

# add the file attachment
msg.attach(filepart)

# send with plone.api
api.portal.send_email(
    sender=msg["From"],
    recipient=msg["To"],
    subject=msg["Subject"],
    body=msg.as_string()
)

Show notification message#

With api.portal.show_message() you can show a notification message to the user.

from plone import api
api.portal.show_message(message='Blueberries!', request=request)

Since version 2.0.0, the request argument can be omitted. In that case, the global request will be used.

api.portal.show_message(message='Cranberries!')

Get plone.app.registry record#

Plone comes with a package plone.app.registry that provides a common way to store configuration and settings. api.portal.get_registry_record() provides an easy way to access these.

from plone import api
api.portal.get_registry_record('my.package.someoption')

One common pattern when using registry records is to define an interface with all the settings. api.portal.get_registry_record() also allows you to use this pattern.

from plone import api
api.portal.get_registry_record('field_one', interface=IMyRegistrySettings)

It is possible to provide a default value that will be returned by api.portal.get_registry_record(), if the queried record is not found.

from plone import api
api.portal.get_registry_record('foo', interface=IMyRegistrySettings, default='bar')
api.portal.get_registry_record('foo', default='baz')

Set plone.app.registry record#

api.portal.set_registry_record() provides an easy way to change plone.app.registry configuration and settings.

from plone import api
api.portal.set_registry_record('my.package.someoption', False)

api.portal.set_registry_record() allows you to define an interface with all the settings.

from plone import api
api.portal.set_registry_record('field_one', 'new value', interface=IMyRegistrySettings)

Get vocabulary#

To get a vocabulary by name, use api.portal.get_vocabulary().

from plone import api

# Get vocabulary using default portal context
vocabulary = api.portal.get_vocabulary(name='plone.app.vocabularies.PortalTypes')

# Get vocabulary with specific context
context = api.portal.get()
states_vocabulary = api.portal.get_vocabulary(
    name='plone.app.vocabularies.WorkflowStates',
    context=context
)

Get all vocabulary names#

To get a list of all available vocabulary names in your Plone site, use api.portal.get_vocabulary_names().

from plone import api

# Get all vocabulary names
vocabulary_names = api.portal.get_vocabulary_names()

# Common vocabularies that should be available
common_vocabularies = [
    'plone.app.vocabularies.PortalTypes',
    'plone.app.vocabularies.WorkflowStates',
    'plone.app.vocabularies.WorkflowTransitions'
]

for vocabulary_name in common_vocabularies:
    assert vocabulary_name in vocabulary_names

Further reading#

For more information on possible flags and usage options please see the full plone.api.portal specification.