Content Management
In this section, we start adding and publishing content, and looking at easy ways to customise Plone, adding a Press Release type that extends the default News Item. While doing this, the use of Topics and the Catalog is discussed.
In any workspace they have access to, a member may add content. Plone offers some pretty useful generic content types that may be used to build many different kinds of site, namely Document, Event, File, Folder, Image, Link and News Item. [1] Another remarkable, and very useful, type is Topic. It is a Product (CMFTopic) in its own right that is being distributed with Plone.
You might not see Topic in your Add dropdown list as a Member. You will, however, see it as Manager. Let's find out why. We'll use this as a chance to get our feet wet with Mozilla's DOM Inspector. Launch it from the Tools menu:
Paste in the URL of the page you wish to investigate, and use the Find a node ... button to select the add dropdown above the folder contents listing.
This will position you in the right area of the DOM treeview in the top left pane. Now we're looking for something that will positively identify our context here. Nose around for a moment and you'll find the Add Item pulldown comment text. That should do. Flip back to the browser and enter the ZMI (via the Plone Control Panel or by entering a .../manage_mainURL directly). We can start in the Plone site object, but since all UI is provided by the portal_skins tool, we might as well start there. Go to the ZMI Find tab and look for the string you found. Perform the search, and you should have one hit:
Open it in the external editor by clicking on the pencil icon, or follow the link to plone_templates/folder_contents in the browser. Search for the Add Item pulldown text again, and look for the first following TAL repeat statement (since that will be the one iterating through the types available for adding). Here it is:
<metal:block tal:repeat="ctype types">
<option value="Document"
tal:define="Id ctype/getId"
tal:attributes="value ctype/getId"
tal:content="ctype/Title"
i18n:translate="">Document</option>
</metal:block>
Backtrack to find where types is defined (just before the Add Item pulldown):
<div tal:condition="standalone|nothing"
tal:define="types contentTypes">
Backtrack again, looking for 'contentTypes':
contentTypes python: here.getAllowedTypes();
Hmm, from this we can deduce that the difference in the lists seen by Member and Manager is due to the fact that Member is not allowed to add Topic instances. (If you like, you can follow the white rabbit to getAllowedTypes, but we'll follow up our hunch for now.) We know that, in Zope, access is governed by permissions assigned to roles, so let's go and see whether this is the problem. Visit the Plone site's Security tab and look for anything to do with "topic". Sure enough, while Owner has the Add portal folders permission, it doesn't have Add portal topics. Add that, and you should be set.
The default content types may also be used with very little effort as the basis of custom content types if you need something slightly different to what they offer. After adding some instances of the basic types, we'll change them to better suit our purposes.
Content management is central to Plone, and touches on most of its aspects, so let's take a couple of interesting types through their paces.
Select News Item from the dropdown, and press add new item. You're presented with a blank form for the new item. Take note of the current state of the breadcrumbs trail:
You'll see a crumb for the new item with an unwieldy id; something like news_item.2004-07-14.6828752427. This is because default Plone creates a blank instance of your item immediately, and then starts you off editing it. When you submit the complete form with a new id, the document is renamed.
This is a suboptimal solution. If you start adding something and change your mind, you'll find the blank item lying around in your workspace later on. The portal_factory tool was created to fix this issue, but since it doesn't work transparently (types must be updated to work with it), it isn't turned on by default. To start using it, visit it in the ZMI, study its Documentation tab, and enable for compatible types on the Factory Types tab.
The long id is the one returned by the .../portal_skins/plone_scripts/generateUniqueId script, and if you turn off the Allow Editing of Short Names preference for a member, this is what the ids of items they create will look like, unless you customize that script.
Complete the form for adding the news item:
I used a press release from CA's site as an example. The last field of the form is Format. Here, choose Structured Text and follow the Structured Text conventions when typing (you can see the use of indentation in the figure). This is a lot easier if you use a capable external editor, rather than using the form's textareas:
After saving the new item, you'll see the structured text rendered to tidy HTML. In default Plone, it starts out as a "visible draft", as you can see at the top right (the name of this workflow state has caused quite a bit of confusion). This means that anyone will be able to view the item if you send them the URL, but it won't feature in the site navigation. The item will also show up in site searches for everyone with permission to view it (i.e. everyone), unless we change the default workflow (we'll do that later).
For the news item to do its stuff, it needs to be published. This isn't something a member can do on their own. What they can do, is to submit the item for publication, so do that:
This puts the item into the pending state, from where the available transitions are retract and make private. In this state, the Edit and Properties tabs aren't available, as it wouldn't do for the item to be edited while the reviewer is busy looking at it. If you spot an error after submitting, retract and edit before submitting again.:
We now need to hand over to the reviewer. In another browser tab, log in as the reviewer user, and take note of the new review list portlet that will have appeared:
The reviewer can publish or reject an item, and can revise it, but cannot share it (note the absence of the Sharing tab) --- only the author can delegate that ability. In case the reviewer spots an error, she'll reject it, in which case the author will find it back in the visible state, and will need to submit it for publication again, potentially after reviewing any comments by the reviewer (on the advanced state page). If necessary, they can add comments of their own as well:
After publication, a news portlet will appear showing the published item, and the item will feature on the global news tab:
Plone will now take care of this news item throughout its lifespan (taking care of its effective date and expiration), listing the five most recent items in the portlet, generating RSS for them if this is enabled in the portal_syndication tool, removing it from view after its expiry date has passed, and so on.
Press releases are a special category of news, and there is usually an area on a site set aside for them. Using only default Plone, let's explore some ways of managing this.
Only Manager users may edit the published news item, so either retract our published item and edit it as the author, or simply edit it as a member of the Administrator group. Visit the Properties tab of the item. Here you find some of the Dublin Core metadata fields [2] of the item. Feel free to update them, but do add Press Release as a new keyword. When adding more press releases, remember to assign them the Press Release keyword.
That done, we have a hook for distinguishing press releases. The first visible consequence of the assignment of keywords is that a Related portlet shows up when browsing any press release, listing other press releases:
We need a better way to make press releases available to the site as a whole, though.
We can use the Topic content type for this. Since we want the releases to be part of the toplevel navigation, where only managers have editing rights, this is a job for a manager user. Go to the root, and add a topic (id: news, title: "News and Press"). Once you save the topic, you get to add criteria:
Here, some Zope guts comes spilling out. That's a very motley dropdown list, not in keeping with the otherwise polished Plone UI, and can't be expected to make sense to anyone but a Zope developer. In reality, it surfaces a very powerful mechanism (the Zope Catalog) in a very straightforward manner. For now, pick portal_type as the Field name, and fill in "News Item" as the value. When you visit the View tab of the topic, you'll see all the news items in the site, wherever they reside (in different members' workspaces). To get the same date-based ordering as the News tab, add a Sort Criterion on effective, and sort in descending order.
To give press releases the attention they deserve, visit the Subtopics tag and add one called press. On the Edit tab, note that it inherits criteria: the View tab shows the same listing as the parent news topic. Visit the Criteria tab and add an additional constraint, limiting Subject to "Press Release" (the criterion is Subject because Plone hides the Dublin Core "Subject" field under the name "Keywords" for some reason, as you'll see when you correlate the contents of the portal_metadata tool's Elements tab with the contents of the Keywords field in new instances, specifically once you've added a few Event instances ...). Now we have a "News and Press / Press Releases" virtual folder hierarchy, drawing together News Items from all over the site, and differentiating among them by the type of news:
Where does the contents of the dropdown list in the topic's Criteria tab come from? This list corresponds to all the indexes defined in the Zope Catalog provided by the portal_catalog tool.
The ZODB does not provide a query language such as SQL. For cases where objects cannot easily be found via their position in the ZODB containment hierarchy, Zope provides the Catalog. The Catalog provides a rich assortment of index types, from fulltext searching with stemming and ranking, through date ranges and precalculated searches.
When Zope is asked to catalog an object, it looks for each of the indexes as names on the object. If the name is found, it is examined to see whether it is callable. If it is, the value returned after calling is indexed; otherwise the attribute value is indexed. To illustrate this in its most basic way, lets slip in underneath Plone on the Python level, and examine the Creator and portal_type indexes:
jean@klippie plone203 $ ./bin/zopectl debug Starting debugger (the name "app" is bound to the top-level Zope object) >>> app.plone.Members.johndoe # The member's folder <PloneFolder instance at 41a91920> >>> app.plone.Members.johndoe.objectIds() ['index_html', '.personal', 'pr-q3-23', 'pr-q2-24', 't1', 'kittens', 'birthday'] >>> app.plone.Members.johndoe['pr-q3-23'].Creator # A method <bound method NewsItem.Creator of <NewsItem at /plone/Members/johndoe/pr-q3-23>> >>> app.plone.Members.johndoe['pr-q3-23'].Creator() 'johndoe' >>> app.plone.Members.johndoe['pr-q3-23'].portal_type # A string 'News Item'
Furthermore, if an index is not present on the object being cataloged, it may be acquired via the normal rules of acquisition. For example, if there was a portal_url index, every object in the Plone site would be indexed under it. Here the press release is shown acquiring it:
>>> app.plone.Members.johndoe['pr-q3-23'].portal_url <URLTool at /plone/portal_url used for /plone/Members/johndoe/pr-q3-23> >>> app.plone.Members.johndoe['pr-q3-23'].portal_url() 'plone'
You'll appreciate that indexes need to be chosen with care in order to avoid bloating the catalog with spurious index entries for every object in the site.
When a catalog is queried, it returns record objects (called brains, ironically, I guess). The records can tell you the ids and paths of the objects they represent, and if the catalog has metadata defined for attributes or methods present on the object (see the Metadata tab), it has their values handy. If you need the object itself, the record can give you that as well, but it's cheaper if you can get away with only the record:
jean@klippie plone203 $ ./bin/zopectl debug Starting debugger (the name "app" is bound to the top-level Zope object) >>> results = app.plone.portal_catalog(id='pr-q3-23') >>> results # A catalog query returns a list [<mybrains instance at 41a79120>] >>> result = results[0] >>> result.getId() # *Method* was indexed but *value* stored Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: 'str' object is not callable >>> result.getId # There we go .. 'pr-q3-23' >>> result.Creator 'johndoe' >>> result.getObject() <NewsItem at /plone/Members/johndoe/pr-q3-23> >>> newsitem = result.getObject() >>> newsitem.aq_parent # The object itself, in context <PloneFolder instance at 41a91920> >>> newsitem.aq_parent.getId() 'johndoe'
If the object has attributes that aren't present in the catalog metadata, the records won't know about them:
>>> link = app.plone.Members.johndoe.jibjab >>> link # I added a link object TTW .. <Link at /plone/Members/johndoe/jibjab> >>> link.remote_url # This is where it points 'http://jibjab.com' >>> results = app.plone.portal_catalog(Description="Everyone's talking") >>> results # Looked up via a TextIndex this time [<mybrains instance at 41a790a0>] >>> result = results[0] >>> result.remote_url # No metadata for 'remote_url' Traceback (most recent call last): File "<stdin>", line 1, in ? AttributeError: remote_url
From these examples we can see that Topic criteria expose the portal_catalog for use in creating alternative navigation structures in Plone sites. It's quite a simple idea, with wide-ranging applications.
Note
if you catalog every object in the site, storing metadata for all attributes, you're effectively storing everything twice, doubling the size of the database. When configuring a catalog, it's important to carefully consider the tradeoffs between size and speed.
[1] That said, there is an element of legacy code about these. They come from the Zope Content Management Framework's CMFDefault product, and are slated to be replaced by Archetypes-based content types.
[2] The "Dublin Core" is a set of metadata formulated by an open forum including members from the archive and library communities, governments, publishing houses, and others. http://dublincore.org/






















