Content types

Description

Plone's content type subsystems and creating new content types programmatically.

Introduction

Plone has two kind of content types subsystems

Flexible architecture allows other kinds of content type subsystems as well.

Type information registry

Plone maintains available content types in portal_types tool.

portal_types is a folderish content where type information are child objects, keyed by portal_type metadata.

portal_factory is a tool responsible for creating the persistent object representing the content.

TypesTool source code.

Listing available content types

Below is an example Zope 3 vocabulary factory which will return all the available content types to be used with multi-selection field.

Define vocabulary in ZCML:

<utility
    provides="zope.schema.interfaces.IVocabularyFactory"
    component=".vocabularies.content_types_vocabulary"
    name="mfabrik.like.content_types"
    />

Then have the factory code for it in vocabularies.py:

"""

    Zope 3 schema vocabulary factory for making multiple choices between installed content types of Plone site.

    http://mfabrik.com

"""

__license__ = "GPL 2"
__copyright__ = "2010 mFabrik Research Oy"
__author__ = "Mikko Ohtamaa <mikko@mfabrik.com>"
__docformat__ = "epytext"

from Acquisition import aq_inner
from zope.app.component.hooks import getSite
from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
from Products.CMFCore.utils import getToolByName

def make_terms(items):
    """ Create zope.schema terms for vocab from tuples,

    @return: Generator of SimpleTerm objects
    """
    terms = [ SimpleTerm(value=pair[0], token=pair[0], title=pair[1]) for pair in items ]
    return terms

def friendly_types(site):
    """ List user selectable content types.

    Note that there exist a method in IPortalState utility view for this, but we cannot
    use it, because vocabulary factory must be available in contexts where there is
    no HTTP request (e.g. installing add-on product).

    This code is copy-pasted from https://svn.plone.org/svn/plone/plone.app.layout/trunk/plone/app/layout/globals/portal.py

    @return: Generator for (id, type_info title) tuples
    """
    context = aq_inner(site)
    site_properties = getToolByName(context, "portal_properties").site_properties
    not_searched = site_properties.getProperty('types_not_searched', [])

    portal_types = getToolByName(context, "portal_types")
    types = portal_types.listContentTypes()

    # Get list of content type ids which are not filtered out
    prepared_types = [t for t in types if t not in not_searched]

    # Return (id, title) pairs
    return [ (id, portal_types[id].title) for id in prepared_types ]

def content_types_vocabulary(context):
    """
    A vocabulary factory for making a choice of a portal type.

    @param context: Assume Plone site.

    @return: SimpleVocabulary containing (portal type id, portal type title) pairs.
    """

    # This special case must be handled by plone.app.registry quick installing registry.xml
    # which refers to zope.schema refering to this vocabulary
    # site information is *not* available

    try:
        import plone.registry.record
        import plone.registry.recordsproxy
        if isinstance(context, plone.registry.record.Record) or isinstance(context, plone.registry.recordsproxy.RecordsProxy):
            context = getSite()
    except ImportError:
        pass

    items = friendly_types(context)

    return SimpleVocabulary(make_terms(items))

Creating a new content type

This instructions apply for Archetypes subsystem based content types

  • You need to have an add-on product code skeleton created using paster's archetypes template
  • Use paster addcontent content command new types.

Related how tos

Note

Creating types by hand is not worth of the problems. Please use a code generator to create the skeleton for your new content type.

Warning

Content type name must not contain spaces. Content type name or description must not contain non-ASCII letters. If you need to change these please create a translation catalog which will translate the text to one with spaces or international letters.

Debugging new content type problems

Creating types by hand is not worth of the problems.

Creating new content types through-the-web

There exist solutions for non-programmes and Plone novices to create their content types more easily.

Dexterity

Plomino (Archetypes-based add-on)

Implictly allowed

Implictly allowed is flag whether the content is globally addable or must be specifically enabled for certain folders.

The following example allows creation of Large Plone Folder anywhere at the site (it is disabled by default). For available properties, see TypesTool._advanced_properties.

Example:

portal_types = self.context.portal_types
lpf = portal_types["Large Plone Folder"]
lpf.global_allow = True # This is "Globally allowed" property

Constraining the addable types per type instance

For the instances of some content types, the user may manually restrict which kinds of objects may be added inside. This is done by clicking the Add new... link on the green edit bar and then choosing Restrictions....

This can also be done programmatically on an instance of a content type that supports it.

First, we need to know whether the instance supports this:

Example:

from Products.Archetypes.utils import shasattr # To avoid acquisition
if shasattr(context, 'canSetConstrainTypes'):
    # constrain the types
    context.setConstrainTypesMode(1)
    context.setLocallyAllowedTypes(('News Item',))

If setConstrainTypesMode is 1, then only the types enabled by using setLocallyAllowedTypes will be allowed.

The types specified by setLocallyAllowedTypes must be a subset of the allowable types specified in the content-type's FTI (Factory Type Information) in the portal_types tool.

If you want the types to appear in the "Add new.." dropdown menu, then you must also set the immediately addable types. Otherwise, they will appear under the "more" submenu of "Add new..".

Example:

context.setImmediatelyAddableTypes(('News Item',))

The immediately addable types must be a subset of the locally allowed types.

To retrieve information on the constrained types, you can just use the accessor equivalents of the above methods.

Example:

context.getConstrainTypesMode()
context.getLocallyAllowedTypes()
context.getImmediatelyAddableTypes()
context.getDefaultAddableTypes()
context.allowedContentTypes()

Be careful of Acquisition. You might be aquiring these methods from the current instance's parent. It would be wise to first check whether the current object has this attibute. Either by using shasattr or by using hasattr on the object's base (via aq_base).

The default addable types, are the types that would be addable, if constrainTypesMode is 0 (i.e not enabled).

For more information, see Products/CMFPlone/interfaces/constraints.py




Edit this document

The source code of this file is hosted on GitHub. Everyone can update and fix errors in this document with few clicks - no downloads needed.

  1. Go to Content types on GitHub.
  2. Press Fork and edit this file button.
  3. Edit file contents using GitHub's text editor in your web browserm
  4. Fill in the Commit message text box at the end of the page telling why you did the changes. Press Propose file change button next to it when done.
  5. On Send a pull request page you don't need to fill in text anymore. Just press Send pull request button.
  6. Your changes are now queued for review under project's Pull requests tab on Github.

For basic information about updating this manual and Sphinx format please see Writing and updating the manual guide.