Description
Plone's content type subsystems and creating new content types programmatically.
Plone has two kind of content types subsystems
Flexible architecture allows other kinds of content type subsystems as well.
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.
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))
This instructions apply for Archetypes subsystem based content 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.
Creating types by hand is not worth of the problems.
There exist solutions for non-programmes and Plone novices to create their content types more easily.
Dexterity
Plomino (Archetypes-based add-on)
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
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
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.
For basic information about updating this manual and Sphinx format please see Writing and updating the manual guide.