Archive for the 'Plone' Category


New product: collective.weightedportlets

Ever been frustrated with not being able to control exactly what order your portlets show up in, if you’ve got inherited portlets, content type portlets, and group portlets? I just released collective.weightedportlets, which allows you to specify an integer weight for each portlet assignment, which will be taken into account in the final ordering. See the Plone.org product page for details.



A buildout for Plone 2.0.5

At ONE/Northwest we’re always looking for ways to improve and streamline our system administration tasks. Recently, we’ve been working on converting all our old Zope instances to be buildout-based (to make it easier to recreate the environment for local testing of changes or in case the instance needs to move to another server). Here are some tips based on things we’ve learned in the process of putting together our buildout for Plone 2.0.5 …

Use the right Python

Plone 2.0.5 is based on Zope 2.7, which requires Python 2.3 rather than Python 2.4 like modern versions of Zope. (We tested using Python 2.4 and it seems to work okay; however Zope 2.7’s RestrictedPython has not been audited in Python 2.4 and there’s no guarantee that users with the rights to edit scripts won’t be able to do something nasty.)

I installed Python 2.3 using macports, then made sure to bootstrap and run my buildout using Python 2.3. Buildout initially complained about the ’subprocess’ module being missing, but I was able to work around this by copying subprocess.py from my Python 2.4 libs (/opt/local/lib/python2.4/subprocess.py in my case) into the Python 2.3 libs.

Update: Recent versions of plone.recipe.zope2install use some Python generators which aren’t compatible with Python 2.3, so I had to pin this egg to version 3.2.

Fry up some products

In a classic Zope installation you keep all your products in one Products directory. In buildout they are typically spread between several different product directories. In the case of Zope 2.7, we were seeing an issue where it only found products located in a Products directory at the root of the buildout, even if we listed additional directories. To work around this, I used collective.recipe.omelette to symlink the various buildout-generated products dirs into the main Products dir that Zope finds. Always nice to find a new use for a tool I designed for a completely different problem!

We do our development on OS X which uses a case insensitive filesystem, so I started using /svnproducts as a replacement for the /products dir that is often found in buildouts, since this would otherwise conflict with the auto-generated /Products.

Your configuration is no good here

Unfortunately the zope.conf that the plone.recipe.zope2instance recipe generates contains a couple bits of configuration (verbose-security and default-zpublisher-encoding) that cause Zope 2.7 to barf, since they were not added until later versions of Zope. To work around this, we used sed (via the plone.recipe.command recipe) to remove the offending bits.

The buildout

I ripped out the bits specific to our own systems and ended up with the following, which incorporates the above learnings. If I didn’t mess up while abridging it, it even works!

[buildout]
parts =
    plone
    zope2
    productdistros
    omelette
    instance
    fixer
versions = versions

[versions]
plone.recipe.zope2install = 3.2

[plone]
recipe = plone.recipe.distros
urls = http://heanet.dl.sourceforge.net/sourceforge/plone/Plone-2.0.5.tar.gz
nested-packages = Plone-2.0.5.tar.gz
version-suffix-packages = Plone-2.0.5.tar.gz

[zope2]
recipe = plone.recipe.zope2install
url = http://www.zope.org/Products/Zope/2.7.7/Zope-2.7.7-final.tgz
fake-zope-eggs = false

# Archetypes and kupu are not strictly required, but here's how to get them if you need them.
[productdistros]
recipe = plone.recipe.distros
urls =
    http://voxel.dl.sourceforge.net/sourceforge/archetypes/Archetypes-1.3.2-final-Bundle.tar.gz
    http://plone.org/products/kupu/releases/1.3.9/kupu.tgz
nested-packages =
    Archetypes-1.3.2-final-Bundle.tar.gz
version-suffix-packages =

[omelette]
recipe = collective.recipe.omelette
eggs =
packages =
    ${buildout:directory}/svnproducts .
    ${buildout:directory}/parts/productdistros .
    ${buildout:directory}/parts/plone .
location = ${buildout:directory}/Products

[instance]
recipe = plone.recipe.zope2instance
zope2-location = ${zope2:location}
user = admin:admin
http-address = 8080
debug-mode = on
verbose-security = on
products =
    ${buildout:directory}/Products

[fixer]
recipe = plone.recipe.command
command =
    sed -i '' 's/verbose-security/#verbose-security/' ${buildout:directory}/parts/instance/etc/zope.conf
    sed -i '' 's/default-zpublisher-encoding/#default-zpublisher-encoding/' ${buildout:directory}/parts/instance/etc/zope.conf
update-command = ${fixer:command}

Many thanks to my colleague Jon Baldivieso who did some of the initial work on this buildout.

Update 5/1/2009: Added fake-zope-eggs = false to avoid trying to build fake eggs from a directory that doesn’t exist in Zope 2.7.

Update 8/21/2009: Pinned plone.recipe.zope2install to version 3.2, as newer versions use Python generators that aren’t compatible with Python 2.3.



Image captions and the PortalTransforms cache

Plone 3 contains a cool feature whereby images inserted in kupu can automatically be captioned with the description stored on the image itself. However, if you’ve tried to use this you may have noticed that after you edit the description, and then try to view a page that includes that image with a caption, the caption sometimes does not update for up to an hour.

The reason has to do with the way in which the captions are added, via the html-to-captioned transform (which should be applied to anything with the text/x-html-safe output mimetype, thanks to a special transform policy that is configured for that mimetype). It turns out that PortalTransforms caches the result of a transform for an hour. It stores this result in a volatile (that means non-persistent) attribute of the value that is being transformed, so in normal cases when you are editing and replacing that value entirely, we don’t have to worry about cache invalidation–that is, if I save new body text for a page, the cached transform value will be wiped out and we’ll see the new text the next time we view the page. However, in the case of editing the caption of an image, I’m saving a completely different value, on a different object, than the one where the transform result is cached. So even if I reload the page I’ll see the old caption.

Workaround 1: Change cache lifetime setting

Option 1: Go to /portal_transforms/manage_cacheForm in the ZMI and lower the cache lifetime. But remember that this will have a negative effect on performance (particularly for pages that are viewed frequently but not served out of a reverse proxy), as the transform will have to be applied more often.

Workaround 2: Manually invalidate the cache when the image is edited

Option 2: When the image caption is edited, invalidate the transform cache on the field referencing the image. I took a first stab at doing this for a project currently underway. For this project I have a custom subclass of ATImage and images are always contained within a (folderish) article, so I modified the caption mutator as follows:

    def setCaption(self, value, **kw):
        self.getField('caption').set(self, value, **kw)

        # The result of transforms is cached for up to one hour.
        # Our caption is inserted into article text via a transform,
        # so if we're located within an article, invalidate the
        # (volatile) cache of the article's text.
        parent = aq_parent(aq_inner(self))
        if IArticle.providedBy(parent):
            value = parent.getField('text').getBaseUnit(parent)
            if hasattr(value, '_v_transform_cache'):
                delattr(value, '_v_transform_cache')

(Note: I first investigated using the Cache class from Products.PortalTransforms.cache so that I could simply do Cache(value).purgeCache() …however, in the current PortalTransforms release the purgeCache method uses a method which was not imported, so I just recreated what that method does. I checked in a fix to the PortalTransforms bug which should make it into the next release of that package.)

For a more generic implementation of this cache invalidation, you would want to do the cache invalidation in a handler for the IObjectEdited event on ATImages, and use whatever the linkintegrity code does to determine what items contain references to the image which was edited–and are therefore candidates for cache invalidation. (The cache invalidation is only needed if the referencing field has already been rendered and is still in memory in the ZODB cache, so of course it would be good to make sure that the cache invalidation doesn’t cause extra objects to be woken up.)

I don’t have the need, time, or interest to work on this more generic solution myself, but it would be cool if someone tackled it. :) Perhaps some of you also have ideas for other options for how to deal with this…



heads-up: watch out for dependencies on “Plone”

Watch out if you’re installing an add-on product to a Plone 3.1.x site that declares a dependency on “Plone” in its setup.py. Plone wasn’t packaged as an egg until Plone 3.2.x, so this will result in buildout trying to pull in the latest Plone on top of the one you’ve already got via the plone.recipe.plone recipe, and you’ll see a VersionConflictError.

I just helped someone on #plone who ran into this with the collective.flowplayer product. If you’re sure the product is actually compatible with Plone 3.1.x, you can work around this by adding “Plone” to the additional-fake-eggs option of the plone.recipe.zope2install buildout section.



report from the Berlinale sprint: how we can fix the Plone skin situation

Well! I am back from two wonderful weeks of traveling in Germany, Belgium, and Spain, and it’s high time that I write something about what I got done at the Berlinale sprint which was a highlight of the trip and is already almost two weeks past!

I headed into the sprint with the goal of figuring out how to make Plone 4 not have two different ways of registering templates and resources, like we have in Plone 3. By the end of the week I had written only a little bit of code toward this end, but I was able to spend a lot of time talking to Hanno Schlichting, Laurence Rowe, and Andi Zeidler and figuring out how we’d like things to work. I feel quite good about the progress we were able to make toward a clearer vision of “what good looks like” in this area, and have a better idea now about what further code needs to be written to make that vision a reality.

To summarize our overall conclusion… I’ve heard a number of people say “skin layers should die.” But this is a bit shortsighted, and probably reflects more the fact that people are tired of having two different ways to do this stuff, and that Zope 3 views and resources are a newer technology, rather than any clear superiority in functionality of the Zope 3 approaches over the alternative. So instead of ditching portal_skins, we should try to modernize it and make it compatible with the Zope 3 approaches.

But, this is a complicated thing to get right, and I would like to have feedback on whether we are on the right track and considering all the important use cases, so let me go into some detail on our current challenge and some concrete steps we can take to improve the situation.

The status quo

Currently in Plone 3 we have two different ways to register a resource that will be accessible via a URL in Zope. There are Content Management Framework (CMF) skin layers, which let you create a directory with a bunch of files (such as templates, images, Python scripts, CMF Form Controller objects, etc.) and associate it with a particular “theme” which may be enabled in your Plone site. These files are then magically available via Python attribute access on the portal root, thanks to a magic __getattr__ method in CMF’s Skinnable class, which the portal root class extends.

There are also browser views and browser resources, concepts borrowed from Zope 3. These are generally registered via declarations in the XML-based Zope Configuration Markup Language (ZCML) which result in these resources getting registered as multi-adapters of a context and a request in the global registry (a.k.a. global site manager) of the Zope Component Architecture (ZCA). These adapters are then looked up as one of the steps in the traversal process of the Zope publisher.

Of course, it’s confusing to have two different ways of solving the same problem that are both used in different places. (Just try to explain to a Plone newbie what the difference between portal_skins and portal_view_customizations is and when each should be used. There are answers, but they depend mostly on the technical details of the implementation and the history of Plone’s development, and are not much use to someone actually trying to use these systems to solve the practical question of how to override component X.) We’d really like to have one system for registering resources. But the problem is that neither of the existing approaches is an obvious winner. Each one has benefits and tradeoffs.

Comparison of CMF skin layers vs. Zope 3 views and resources

A. CMF skin layers / portal_skins
Pros Cons
  • Very easy both to add a new resource and to override an existing one
  • The concept of overriding a resource through the web by copying it to a ‘custom’ layer is fairly intuitive
  • Supports TTW customization for many different types of resources (templates, images, CSS, JS, KSS, etc.)
  • Includes a diff feature for comparing customized items to the filesystem version.
  • Includes a Find feature for determining which version of an item is active.
  • Tools exist to aid with exporting TTW customizations back to the filesystem.
  • Supports the concept of multiple themes which may be activated at different times
  • Resources are available globally and can collide with content ids
  • The way resources are traversed is a bit magical and may slow attribute access for anything acquired from the portal
  • A bit cumbersome to register a new layer (requires ZCML and Generic Setup)
B. Zope 3 views & resources / portal_view_customizations
Pros Cons
  • Views and resources can be registered more selectively for a particular interface only, so that two resources of the same name can be used in different contexts.
  • Built on infrastructure that is more “core” to Zope (and thus probably better maintained and optimized)
  • Resources can be namespaced by using resource directories, and thereby separated from content.
  • The portal_view_customizations UI is rather poor and doesn’t support some of the nice features of portal_skins.
  • Adding a new view or overriding an existing one requires a new ZCML registration.
  • There’s no way to override just one item from a resource directory.
  • Through-the-web overrides are only supported for templates.
  • There’s no good way to export through-the-web customizations back to the filesystem.
  • No simple way to handle subsite theming…a number of people have been struggling with this lately.

So what do we do?

So how can we continue our modernization toward Zope 3 approaches, without losing all the good things about CMF skin layers?

Based on the conversations I had at the Berlinale sprint, I think the answer involves three parts…

1. Register skin layer items as Zope 3 views and resources

The big coding task I tackled at the sprint was creating a package called ‘plone.resource’. This is intended to be a reimplementation of the DirectoryInformation class from CMF (the class which handles exposing filesystem items as objects within Zope) but with different behavior behind the scenes, such that each item in the directory gets registered as a browser view.

Some more details:

  • It will be possible to register new resources (including template-based browser views) just by creating a file in the right directory. If Zope is running in debug mode, we can detect new and removed files without needing a restart.
  • All the items in a particular resource directory will be registered for a particular, configurable Zope 3 browser layer.
  • For templates, additional parameters to the view registration (such as “for” and “name”) can be specified either in .metadata files or in <meta> tags in the <head> of the template’s HTML. (Of course, ZCML registrations for browser views not located in a plone.resource-managed directory will continue to work.)
  • It will be possible to configure the resources associated with a directory to show up in the global namespace a la portal_skins (for cases where you really do want a resource accessible anywhere), in a ++resource++ namespace directory a la Zope 3 resources (mostly for backwards compatibility), or in a named path like ‘images/’ (for cases where you want resources separated from content, but want a prettier URL than ++resource++).
  • Because everything gets registered as a browser view in the end, it will be easier for us to create a single UI which can handle customizing all kinds of resources.
  • It should be possible to override existing resources from another package in a fashion similar to z3c.jbot, by creating a file whose name is the full dotted path to the resource being overridden.
  • For now I am reusing the resource classes from CMF; though, as Hanno pointed out, it may be possible to replace these with something more lightweight at some point. Supporting DTML, CMFFormController, and Python scripts in the long term are not priorities for me, although I hope to make plone.resource pluggable enough that support for them and other types of resources could be provided by add-on products.

A lot of this still needs to be built, but the foundation is already in place.

2. Improve our mechanisms for managing how browser layers get activated

Since more things will depend on Zope 3 browser layers, we will need better support in plone.browserlayer for:

  • Making sure that items on a “theme” layer take precedence over items on an “add-on product” layer. (That is, controlling the order in which layer interfaces are applied to the request).
  • Enabling a theme layer only for certain sections of the site (as well as disabling any other theme layer within that section).

I haven’t done much thinking yet about the details of either the UI or the implementation for these enhancements. Suggestions welcome.

3. Revamp the UI for customization

portal_view_customizations is functional, but it needs a new user interface…possibly one that is based in the Plone control panel rather than the ZMI. I envision a listing of views and resources driven by a form that lets you filter by name of resource, type of resource, layer it’s registered on, interface that a view is “for”, etc. (Ideally we could even support a full text search of template contents.) For each resource shown in the results listing, all of the layers providing that resource need to be made evident, along with an indication of which is currently taking precedence. And it should be possible to see a diff of changes for items that have been customized through the web, as well as to export all such items for use in filesystem resource directories.

Alternatively, or in addition, an approach more like gloworm (which operates by the “poke-that-thing-on-the-page-and-tell-me-more-about-it-style” interface) could be taken. As long as plone.resource (or whatever else registers views) takes advantage of zope.configuration’s support for annotating the view registration with info about where the registration originated, and as long as we have some way to expose this when a view’s template is rendered, this shouldn’t be too hard to achieve.

Aside from the new things that need to be built, the main implications this has for the existing plone.app.customerize implementation are:

  • We need to support other types of resources besides templates, both in terms of finding them and storing persistent copies of them. (I need to investigate further whether it’s possible to adapterize the function of getting file contents somehow, so that we don’t need to have separate persistent and non-persistent versions of each resource class.)
  • When an item gets customized through the web and plone.app.customerize makes a local copy of the view registration, we need to change the layer to something like ITTWCustomized so that it doesn’t mask the global registration for the purposes of introspection.

A few last words

Okay, I think that’s probably enough to keep me busy for a little while. :) Please don’t hesitate to ask questions; this plan incorporates a lot of small improvements and there are no doubt places where I should have been clearer about what something means or why something is a good idea. Constructive criticism and suggestions on how to make this even better are also welcome.

You’ll no doubt notice that I haven’t said much (if anything) about viewlets and portlets. Don’t worry, we know that understanding the distinction between these and learning how to create and register them is one of the common pain points in learning Plone theming today, and we hope to make things easier in Plone 4. But this problem is mostly orthogonal to the question of how resources get registered and customized, and is being dealt with elsewhere, so I’m not going to spend time on it here. For now, suffice it to say that as long as the approach used in Plone 4 for generating a section of a page is based on a Zope 3 browser view, it should be compatible with the improvements discussed here.



A tale of a resurrected bug

This is the story of a Friday night spent tracking down a particularly pesky bug in my Plone site. In gory detail.

Crap, it’s not working…

I had just finished moving one of our larger Plone deployments to a new host. Everything had gone, with one or two minor exceptions, exceedingly smoothly, and I was looking forward to setting aside the laptop for the rest of the evening. (Yes, that does happen occasionally ;) …But then I got an IM…

[our client]: 22:06:50
i am getting:

Bad gateway
The proxy server received an invalid response from an upstream server

Well, shit. That’s weird… Normally I might have expected this 502 error from squid when Zope is restarting, but in this case Zope is directly behind apache, and is running fine. And the error’s only occurring on one particular page…what the heck? Also… why is this a problem now when it definitely wasn’t happening on the old server? My entire software stack is installed from a buildout with pinned versions, and I copied the apache configuration, so what variables could be left?

I could probably have already known at this point that the evening was shot. But what to do?

Time for some inspection…

Okay, well obviously Apache doesn’t like something it’s getting from Zope. Maybe a Zope bug of some sort? Let’s check the apache error log and see what it tells us:

[Fri Jan 23 22:12:05 2009] [warn] proxy: bad HTTP/1.1 header returned by /@@sub_trial (POST)

Gee, thanks for all the detail, apache. Well, at least this confirms my suspicions that some header from Zope is wrong. But what could it be? Time to hit Zope directly and see what we can see in the headers. Open up the port in the firewall, enter the Virtual Host Monster URL to the problem page, view the headers in Firebug…what have we got?

Date: Mon, 26 Jan 2009 08:35:33 GMT
Server: Zope/(Zope 2.10.5-final, python 2.4.4, linux2) ZServer/1.1 Plone/3.0.3
Content-Type: text/html; charset=utf-8
Location: https://www.xxxxx.org/thankyou_trial
Set-Cookie: statusmessages="A+RXZWxjb21lISBZb3UgYXJlIG5vdyBsb2dnZWQgaW4uaW5mbwTEWW91ciBUcmlhbCBTdWJzY3JpcHRpb24gSXMgTm93IEFjdGl2ZS5pbmZv"; Path=/
Via: 1.1 xxxxx.org
Vary: Accept-Encoding,User-Agent
Content-Encoding: gzip
Content-Length: 20
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive

Well, the page loads fine when I hit the site directly in Zope, and those headers look pretty innocuous. At this point my only guess was that the gzipping was screwing things up somehow, and thus followed a half-hour-long digression of confirming the gzip settings in CacheFu, confirming the mod_deflate settings in apache, and finally disabling gzipping entirely in Firefox. All of which served only to tell me in the end that the problem had nothing to do with gzipping.

Pull out the big guns: Google

At this point I did what any self-respecting software professional would do: I typed the error message into Google. This is where things really start to get interesting…

A query of zope "bad HTTP/1.1 header" netted me a few irrelevant-looking results. But aha, also an old e-mail thread that describes a similar error, and that has a link to a Plone trac ticket that…well, “Plone Hotfix 20071106 breaks long status messages” doesn’t exactly sound relevant, but look, there’s a comment that mentions the bug results in a 502 gateway error when running behind apache — which matches my experience — and it even says the bug is still present in Plone 3.0.3, the version I’m using on this particular site. And the description of the issue — a problem with the statusmessage cookie header — sounds reasonably close to the diagnosis I was guessing at. Hey, maybe we’re on to something!

But something is still not right. The comments on the ticket also say that a newer version of the hotfix that introduced the bug, PloneHotfix20071106, was released to fix the issue all the way back in November 2007. And my buildout already includes this updated version — it’s right there as:

http://plone.org/products/plone-hotfix/releases/20071106-2/PloneHotfix20071106.tar.gz

(Note the “-2″). Hmm, now that I think about it, maybe I have a vague recollection of encountering this same issue sometime in the distant past, and updating that hotfix in the buildout. But, obviously the fix is not working now. So what’s going on?

The epiphany

And then it hit me.

David Glick: 23:14:50 holy crap, I think the real problem here is related to the recent plone.org upgrade
David Glick: 23:14:56 no shit :)

Let me explain. During the recent plone.org upgrade, all the product tarball files stored in PloneSoftwareCenter were migrated from being stored in the ZODB to being stored in a big directory on the filesystem using FileSystemStorage and collective.psc.externalstorage. (This is part of the efforts to make PSC function as a pypi-style repository, a cool ability which I hope Alex Clark and Tarek Ziad?? will publicize before too long.) Now, the thing I noticed that made me think “aha!” is that the filename listed for the hotfix tarball in my buildout has no version suffix. And it didn’t take me much longer to check the older release of that hotfix and see that it has the exact same tarball filename. And then, knowing what I did about the plone.org upgrade, it didn’t take much imagination to think that the two releases must now be accessing the same file on the filesystem, and the “-2″ release was getting the wrong data. And this was quickly confirmed by inspection of the actual Hotfix code that had been fetched into my buildout.

To express my feelings at this point, echoing the immortal words of our Zope Pope:

“WAAAA!”

Case closed? You betcha. I stopped using the broken tarball and checked out the correct version of the hotfix from the svn tag instead. After restarting Zope, no more 502 error when I hit the form. And I followed up soon thereafter by replacing the hotfix tarball with the most recent release so that others shouldn’t run into this same issue.

Note, however, that there’s no guarantee at this point that other packages aren’t experiencing a similar issue, so keep your wits about you when installing old-style product tarballs from plone.org. However, I have filed a report and trust that Alex or Tarek will be able to work on it before too long.

Of course, it goes without saying that I was rather lucky to have the familiarity with the plone.org upgrade needed to correctly diagnose the cause of this issue. But otherwise, just another day in the life of a Plone hacker…



PloneFormGen gets a little shinier

Over the past couple days Steve McMahon has been with us at the ONE/Northwest Seattle office, and we’ve been working on a number of improvements to PloneFormGen. With the involvement of several other Seattle-based Plone developers who often join us for open source work on Friday afternoons anyway, we had a small army working on PFG.

Faced with a long list of good ideas, we decided to focus on the relatively easy changes. We’ll try to get these through beta to a final release fairly quickly so that we can move on to more interesting challenges like a revamped form editing UI, multi-page forms, and no longer storing fields as Archetypes objects.

Sprint accomplishments:

  • Andrew Burkhalter finished converting the installation over to GenericSetup (work begun by Jesse Snyder at the sprint in DC)
  • I merged a branch I’ve been working on which adds support for rendering PFG forms from another template, viewlet, or portlet.
  • Steve McMahon cleaned out some compatibility code for Plone 2.1 (which will no longer be supported except in the 1.2.x maintenance series)
  • I created a proof-of-concept of a recaptcha integration which we plan to ship with PFG. This needs more work though.
  • Steve added an option to the mailer to select which fields will be included in the e-mail, as well as an option to exclude empty fields.
  • Steve removed the restriction on which fields can be used as the mailer recipient.
  • Jon Baldivieso added a link spam validator to ensure that a field doesn’t contain links.
  • Steve switched the default view of form fields to the edit view, to save a few clicks when building forms.
  • Steve added CSS ids to the rich label field.
  • I fixed up the test infrastructure to work with roadrunner, and added some basic integration tests.
  • Andrew made progress on his branch which will add a form import/export feature.
  • Paul Bugni added an e-mail validator that support multiple e-mail addresses.
  • Alex Tokar and Fulvio Casali almost finished implementing an option to make a field “server side” only, which is like a hidden field that doesn’t actually render for the client (to avoid the chance of hacking hidden fields).
  • Steve added a BCC field override setting.
  • Jesse Snyder fixed a bug where copied-and-pasted action adapters were not automatically activated.
  • Michael Dunlap removed the isUrl validator from the form action override, so that it’s possible to use relative URLs.
  • Elliot Cohen joined the fun even though he’s new to Plone, and reviewed PFG documentation.
  • I added a ‘force SSL’ option for form folders which will redirect to an https:// version of the form.

Thanks to everyone who participated, including those who responded to my previous request for voting on features!



call for PloneFormGen feature requests

ONE/Northwest is gearing up for building various “civic engagement features”–things like online fundraising, online advocacy, and event RSVP–on top of Plone and Salesforce.com. (You’ll be hearing more about this.) PloneFormGen will play a significant role in implementing several of these features, so we’ve invited its creator, the illustrious Steve McMahon, to come up to Seattle for a little PloneFormGen mini-sprint at the beginning of December.

As part of planning for this sprint and the future of PloneFormGen development, we’d like to get a sense of which outstanding feature requests are most desired by the community. So if you use PloneFormGen, please take a minute to go to http://ploneformgen.uservoice.com and vote for the improvements that would most ease your life when working with PloneFormGen. (The list is as of this writing heavily influenced by my own sense of what’s important — please feel free to add new items as well.)

Of course, our primary interest during the mini-sprint will be in scratching our own itches, but this may help us choose which of a number of minor itches to scratch if we have time, and I imagine the rating of priorities will come in handy in the future. (This is also a bit of a case study to see how well +/- voting works for prioritizing feature requests, to see if it’s something we should also consider doing for Plone itself.)



Forcing TAL to render mismatched tags

Today I installed Google website optimizer for a Plone site. This tool requires the use of a </noscript> tag in order to designate the end of a block that may be used in experiments. Unfortunately, if you try to insert this in a Zope page template you’ll see something like this:

Compilation failed
zope.tal.htmltalparser.NestingError: No tags are open to match </noscript>, at line 2, column 1

You can work around this using the following idiom:

<tal:block tal:content="structure string:&lt;/noscript&gt;"/>

This bypasses TAL compilation by parsing the </noscript> as a string, then inserts it into the template as HTML structure. The angle brackets are written as HTML entities so that the template has a chance of passing XML validation.

Credit to Darryl Dixon via #plone on IRC, and my colleague Jon Baldivieso for the HTML entities suggestion. Thanks!



on the Plone community

Some of you already know that during the past year, I have become quite involved with an open-source software product called Plone. Plone is a content management system–a tool for organizing, presenting, and sharing information on the web. We use it extensively for the websites we build at ONE/Northwest. But more than just a piece of software, Plone is an international community, the people who create the software and build websites with it and support it and promote it.

This Friday has been declared World Plone Day, and in honor of it I want to name some of the traits that I so much appreciate about this worldwide group of people that is Plone:

  1. We welcome and empower newcomers. As a complex and powerful system, Plone can seem inscrutable to the newcomer. But there are patient and friendly folks waiting in the Plone forums and IRC channel. I am amazed at the patience and generosity of experienced Plonistas in sharing their hard-earned wisdom. You may not be given all the answers, but if you ask politely you will at least be given the right questions and pointed in the right direction.
  2. I’ll say again what’s been said before: Plone is a do-ocracy. We honor competence, not celebrity. Many open-source projects have a “benevolent dictator for life” or a small cadre of experienced developers who have commit rights. Plone has neither–in fact, the Plone code repository has had 277 direct contributors. And yet somehow, in an ongoing tension between chaos and order, good things keep happening. An important part of this is the care that those in the (nebulous) “inner circle” of Plone take to encourage those on the outskirts who have shown prime talent to step up and take a more active role.
  3. We respect each other. This is an unusual thing in an online community, which can tend to be volatile and prone to flame wars. But I have a very keen sense that Plone people value each other as first as people with common interests, before we pay attention to ideology of software design, politics, or other matters. No doubt it helps that we are a relatively small community and have been able to nurture relationships in person at sprints and conferences. But the dividends are great, because respecting those with whom we differ strengthens us via an ongoing interchange of ideas, and we should try to hold this intact even as we grow.
  4. We share. Of course we do — it’s hard to quantify our own benefit from the community’s past efforts on this software, and we try to give back. Individual developers tidy up code from one-off projects for use by the broader community. Some organizations using Plone have devoted 10 percent of their time to work on the system. Zope’s component architecture and the recent push to release packages as Python eggs have put Plone developers in a favorable position by making it easier to release reusable add-on products that don’t require invasive changes to the framework, as in so many other platforms.
  5. We recognize our limits. Plone is not the right tool for every project. To put it more positively, we focus on a subset of the opportunities that are out there in the world of web development, and try to handle them well. I’ve been impressed with the candor at which we acknowledge our weaknesses and try to make sure that people are using the correct approach.
  6. We don’t shy away from hard problems. While we have limitations, we’re not afraid of (controlled) experimentation and change to try to remove them. The community benefits both from many years of hard-earned experience and from the enthusiastic contributions of new arrivals. Several versions ago Plone did not use Archetypes or the Zope component architecture, elements which are integral these days. Today, the very orderly progression of minor Plone 3 releases expertly managed by Wichert Akkerman belies a lot of exciting work being done on projects like dexterity, deliverance, contentmirror, repoze.bfg, and a vastly more flexible layout model, whose concepts if not code will likely play some part in what we do in Plone 4. The challenge — make Plone easier to use for end users, administrators, integrators, deployers, and developers while also making its code leaner and faster — is not a small one, but (throwing naivet?? to the wind here) if there’s any open source project with the community to pull this off, it is Plone.

To the Plonistas: It has been an honor and a privilege to join your ranks and give back in some small ways. Here’s to many more thriving years ahead!