Ten lesser-known improvements in Plone 4
As you've probably heard by now, Plone 4.0 final was released this week! (The cynical among you are probably muttering that we couldn't even beat Perl 6, but hey, it's here now :) ). Working on Plone 4 has been a huge part of my life for the past year, but I did far from all of the work. Thanks to every one of you who contributed; I couldn't be prouder of what we've created together!
See the link above for info on major features in the release, but there are a lot more little things included too. Without further ado, here are ten of my favorite Plone 4 improvements that nobody's talking about...
General / site admin features
1. New editor features. Check the control panel for TinyMCE (our new WYSIWYG editor) to find some useful buttons that aren't enabled by default:
- Paste as Plain Text (preserves newlines)
- Paste from Word (strips junk markup)
- Insert/edit Media
2. Better date/time handling. The display of event times in listings is now smarter. If the event begins and ends on different days, the time is not shown. If the start and end times are the same, it is not shown twice.
In addition, dates and times are now stored with a timezone, with proper consideration of daylight savings time.
3. Inline error tracebacks. If you're logged in as a Manager and encounter an error, the traceback is shown immediately, rather than requiring you to click through to the error_log in the ZMI.
4. Permission auditing. Thanks to a new feature in Zope 2.12, it's now easy to double-check what permissions a particular user will have in a particular context, via this button on the Security tab in the ZMI:
5. Better control over portlet columns. In Plone 3, it was possible to make a template prevent rendering of the portlet columns by filling METAL slots. In Plone 4, this can be done by setting the disable_plone.leftcolumn and disable_plone.rightcolumn flags on the request before calling main_template. For example:
<tal:block tal:define="foo python:request.set('disable_plone.leftcolumn', 1)"/> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal" xmlns:metal="http://xml.zope.org/namespaces/metal" xmlns:i18n="http://xml.zope.org/namespaces/i18n" lang="en" metal:use-macro="context/main_template/macros/master" i18n:domain="plone"> (snip) </html>
(This might also be done in Python in the __init__ method of a browser view.) Handily, it's actually a 3-way flag: set it to True to force hiding the colum, False to force displaying it even if there are no portlets assigned, and None to use the default logic based on whether there are portlets assigned.
6. "All content" listing view and content-core macro. There is a new folder listing display option called "All content", which renders the full content of each item. (See it in action on the homepage of this website.)
This listing takes advantage of the new content-core slot which is defined in main_template following the title and description and between the various above/below viewlet managers, and filled by each content type's default view. This gives each content type control over how it renders in the "all content" listing. (The "all content" listing also takes advantage of some new slots/macros in the folder_listing template to reuse its logic for batching and fetching item properties; this may be a useful model for other custom folder listings.)
It also makes it simpler to write a view template for a content type, since one no longer needs to include the title, description, and common viewlet managers as boilerplate. The simplest view template is now (this is a copy of Plone 4's document_view):
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal" xmlns:metal="http://xml.zope.org/namespaces/metal" xmlns:i18n="http://xml.zope.org/namespaces/i18n" lang="en" metal:use-macro="context/main_template/macros/master" i18n:domain="plone"> <body> <metal:content-core fill-slot="content-core"> <metal:content-core define-macro="content-core"> <metal:field use-macro="python:context.widget('text', mode='view')"> Body text </metal:field> </metal:content-core> </metal:content-core> </body> </html>
For backwards compatibility, templates may still continue to fill the main slot instead of content-core, and provide their own title, description, and viewlet managers.
7. Flexible image scaling. There is now an Image Handling control panel which allows configuring the standard image scale sizes used by Plone.
In addition, since image scales are now generated on demand, it's quite easy for a template to request an image scale of a non-standard size, using this idiom:
<img tal:define="scale context/@@images" tal:replace="structure python: scale.scale('image', width=42, height=42).tag()" />
Including a standard image scale is simpler too:
<img tal:replace="structure context/@@images/image/mini" />
See plone.app.imaging for additional options.
8. Automatic registering of Zope 2 permissions. In Zope 2.10, registering a new permission took two steps (using the <permission/> ZCML directive to register a Zope 3 permission utility, and registering it as a Zope 2 permission, usually by calling Products.CMFCore.permissions.setDefaultRoles during product initialization).
In Zope 2.12, only the first step is required. The equivalent of setDefaultRoles is automatically called after processing the permission directive, and sets the default roles to ('Manager',).
If you want different default roles, you must still call setDefaultRoles yourself, prior to loading of ZCML (e.g., at import time). This will improve in Plone 4.1 / Zope 2.13, where the permission directive gets an optional role subdirective to specify the desired default roles in ZCML.
9. Fixed ordering of CMF/Archetypes interaction during object creation. In Plone 3, when you created a new content item, CMF called the factory method of an Archetypes content type, then called its ObjectCreated event, then updated the item's portal_type attribute. This had the unfortunate effect that if you were trying to create a schema extender that used the portal_type to determine whether the extender should be applied (perhaps based on some configurable property), and your site used content types that shared the class of other content types, you were out of luck.
This is now fixed so that ObjectCreated is not fired until the portal_type is set. I think we also managed to avoid calling some event twice during object creation that was causing duplicate catalog indexing, but I could be misremembering that.
10. Folder ordering adapters. The order of items in a folder is now looked up via a named adapter of the folder to plone.folder.interfaces.IOrdering—and it is looked up dynamically when ordering catalog results by getObjPositionInParent, rather than consulting an index. This means that it should now be simpler to customize how a particular folder is ordered (e.g. to automatically sort alphabetically or by date), by writing a new adapter that provides IOrdering and setting a folder to use it. To set the name of the IOrdering adapter that is used for a particular folder, use its setOrdering method.
Out of the box, most folders use the DefaultOrdering adapter, which allows user-configurable order. This should be appropriate in many cases. Folders that were migrated from Plone 3's Large Plone Folders use the "unordered" ordering (but this shouldn't be needed for new folders that will store many items, as the default ordering is reasonably performant). plone.folder also has a "partial" ordering which allows specifying the order for some but not all subitems, but this is not directly used or supported in the Plone UI at this time.
On to 4.1 and beyond!