GitHub-only

WARNING: If you are reading this on GitHub, DON'T! Read the documentation at docs.plone.org so you have working references and proper formatting.

Content

Create content

To add an object, you must first have a container in which to put it. Get the portal object, it will serve nicely:

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

Create your new content item using the api.content.create() method. The type argument will decide which content type will be created. Both Dexterity and Archetypes content types are supported.

from plone import api
obj = api.content.create(
    type='Document',
    title='My Content',
    container=portal)

The id of the new object is automatically and safely generated from its title.

assert obj.id == 'my-content'

Get content object

There are several approaches to getting your content object. Consider the following portal structure:

plone (portal root)
|-- blog
|-- about
|   |-- team
|   `-- contact
`-- events
    |-- training
    |-- conference
    `-- sprint

The following operations will get objects from the stucture above, including using api.content.get().

# let's first get the portal object
from plone import api
portal = api.portal.get()
assert portal.id == 'plone'

# content can be accessed directly with dict-like access
blog = portal['blog']

# another way is to use ``get()`` method and pass it a path
about = api.content.get(path='/about')

# more examples
conference = portal['events']['conference']
sprint = api.content.get(path='/events/sprint')

# moreover, you can access content by its UID
uid = about['team'].UID()
team = api.content.get(UID=uid)

# returns None if UID cannot be found in catalog
not_found = api.content.get(UID='notfound')

Find content objects

You can use the find function to search for content.

Finding all Documents:

from plone import api
documents = api.content.find(portal_type='Document')

Finding all Documents within a context:

from plone import api
documents = api.content.find(
    context=api.portal.get(), portal_type='Document')

Limit search depth:

from plone import api
documents = api.content.find(depth=1, portal_type='Document')

Limit search depth within a context:

from plone import api
documents = api.content.find(
    context=api.portal.get(), depth=1, portal_type='Document')

Search by interface:

from plone import api
from Products.CMFCore.interfaces import IContentish
documents = api.content.find(object_provides=IContentish)

Combining multiple arguments:

from plone import api
from Products.CMFCore.interfaces import IContentish
documents = api.content.find(
    context=api.portal.get(),
    depth=2,
    object_provides=IContentish,
    SearchableText='Team',
)

More information about how to use the catalog may be found in the Plone Documentation. Note that the catalog returns brains (metadata stored in indexes) and not objects. However, calling getObject() on brains does in fact give you the object.

document_brain = documents[0]
document_obj = document_brain.getObject()

Get content object UUID

A Universally Unique IDentifier (UUID) is a unique, non-human-readable identifier for a content object which stays on the object even if the object is moved.

Plone uses UUIDs for storing references between content and for linking by UIDs, enabling persistent links.

To get the UUID of any content object use api.content.get_uuid(). The following code gets the UUID of the contact document.

from plone import api
portal = api.portal.get()
contact = portal['about']['contact']

uuid = api.content.get_uuid(obj=contact)

Move content

To move content around the portal structure defined above use the api.content.move() method. The code below moves the contact item (with all it contains) out of the folder about and into the Plone portal root.

from plone import api
portal = api.portal.get()
contact = portal['about']['contact']

api.content.move(source=contact, target=portal)

Actually, move behaves like a filesystem move. If you pass it an id argument the object will have that new ID in it's new home. By default it will retain its original ID.

Rename content

To rename a content object (change its ID), use the api.content.rename() method.

from plone import api
portal = api.portal.get()
api.content.rename(obj=portal['blog'], new_id='old-blog')

Copy content

To copy a content object, use the api.content.copy() method.

from plone import api
portal = api.portal.get()
training = portal['events']['training']

api.content.copy(source=training, target=portal)

Note that the new object will have the same ID as the old object (unless otherwise stated). This is not a problem, since the new object is in a different container.

You can also set target to source's container and set safe_id=True. This will duplicate your content object in the same container and assign it a new, non-conflicting ID.

api.content.copy(source=portal['training'], target=portal, safe_id=True)
new_training = portal['copy_of_training']

Delete content

To delete a content object, pass the object to the api.content.delete() method:

from plone import api
portal = api.portal.get()
api.content.delete(obj=portal['copy_of_training'])

To delete multiple content objects, pass the objects to the api.content.delete() method:

from plone import api
portal = api.portal.get()
data = [portal['copy_of_training'], portal['events']['copy_of_training'], ]
api.content.delete(objects=data)

If deleting content would result in broken links you will get a LinkIntegrityNotificationException. To delete anyway, set the option check_linkintegrity to False:

from plone import api
portal = api.portal.get()
api.content.delete(obj=portal['copy_of_training'], check_linkintegrity=False)

Content manipulation with the safe_id option

When manipulating content with api.content.create(), api.content.move() or api.content.copy() the safe_id flag is disabled by default. This means the uniqueness of IDs will be enforced. If another object with the same ID is already present in the target container these API methods will raise an error.

However, if the safe_id option is enabled, a non-conflicting id will be generated.

api.content.create(container=portal, type='Document', id='document', safe_id=True)
document = portal['document-1']

Get workflow state

To find out the current workflow state of your content, use the api.content.get_state() method.

from plone import api
portal = api.portal.get()
state = api.content.get_state(obj=portal['about'])

The optional default argument is returned if no workflow is defined for the object.

from plone import api
portal = api.portal.get()
state = api.content.get_state(obj=portal['image'], default='Unknown')

Transition

To transition your content to a new workflow state, use the api.content.transition() method.

from plone import api
portal = api.portal.get()
api.content.transition(obj=portal['about'], transition='publish')

If your workflow accepts any additional arguments to the checkin method you may supply them via kwargs. These arguments can be saved to your transition using custom workflow variables inside of the ZMI using an expression, for example: "python:state_change.kwargs.get('comment', '')"

from plone import api
portal = api.portal.get()
api.content.transition(obj=portal['about'], transition='reject', comment='You had a typo on your page.')

Get view

To get a BrowserView for your content, use api.content.get_view().

from plone import api
portal = api.portal.get()
view = api.content.get_view(
    name='plone',
    context=portal['about'],
    request=request,
)

Further reading

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