Plone's content type subsystems and creating new content types programmatically.
- Type information registry
- Creating a new content type
- Creating new content types through-the-web
- Implicitly allowed
- Constraining the addable types per type instance
Plone has two kind of content types subsystems:
- Dexterity (covered in the Plone 4 documentation)
- See also Plomino (later in this document).
Flexible architecture allows other kinds of content type subsystems as well.
Plone maintains available content types in the
portal_types is a folderish object which stores type information as
keyed by the
portal_type property of the types.
portal_factory is a tool responsible for creating the persistent object representing the content.
Often you need to ask the user to choose specific Plone content types.
Plone offers two Zope 3 vocabularies for this purpose:
- a list of types installed in
- a list of those types that are likely to mean something to users.
If you need to build a vocabulary of user-selectable content types in Python instead, here's how:
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 friendly_types(site): """ List user-selectable content types. We cannot use the method provided by the IPortalState utility view, because the vocabulary factory must be available in contexts where there is no HTTP request (e.g. when installing add-on product). This code is copied from https://github.com/plone/plone.app.layout/blob/master/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 ]
These instructions apply to Archetypes-based content types.
Add ZopeSkel to your buildout.cfg and run buildout:
[buildout] ... parts = instance zopeskel ... [zopeskel] recipe = zc.recipe.egg eggs = PasteScript ZopeSkel
Run the following command and answer the questions e.g. for the project name use my.product:
./bin/paster create -t archetype
Adjust your buildout.cfg and run buildout again:
[buildout] develop = my.product ... parts = instance zopeskel ... [instance] eggs = my.product
You need to install your new product using buildout before you can add a new content type in the next step. Otherwise paster complains with the following message: "Command 'addcontent' not known".
Change into the directory of the new product and then use paster to add a new content type:
cd my.product ../bin/paster addcontent contenttype
Creating types by hand is not worth the trouble. Please use a code generator to create the skeleton for your new content type.
The content type name must not contain spaces. Neither the content type name or the description may 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 the trouble.
There exist solutions for non-programmers and Plone novices to create their content types more easily.
- Core feature
- Use Dexterity control panel in site setup
- With Plomino you can make an entire web application that can organize & manipulate data with very limited programming experience.
Implictly allowed is a flag specifying 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
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.
from Products.Archetypes.utils import shasattr # To avoid acquisition if shasattr(context, 'canSetConstrainTypes'): # constrain the types context.setConstrainTypesMode(1) context.setLocallyAllowedTypes(('News Item',))
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
If you want the types to appear in the :guilabel:
Add new.. dropdown menu, then you must
also set the immediately addable types. Otherwise, they will appear under the
more submenu of Add new...
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.
context.getConstrainTypesMode() context.getLocallyAllowedTypes() context.getImmediatelyAddableTypes() context.getDefaultAddableTypes() context.allowedContentTypes()
Be careful of Acquisition. You might be acquiring these methods from the
current instance's parent. It would be wise to first check whether the current
object has this attribute,
either by using
shasattr or by using
hasattr on the
object's base (access the base object using
The default addable types are the types that are addable when
0 (i.e not enabled).
For more information, see Products/CMFPlone/interfaces/constraints.py