Plone

vsCore, vsPloneLibrary, vsPloneSongs projects listed on ohloh.net

Our vsCore, vsPloneLibrary and vsPloneSongs, have been listed on http://www.ohloh.net.

vsPloneSongs

  • Home: This project doesn’t have a home page.
  • Download: Download page is missing
Project: http://www.ohloh.net/projects/6718
Commits: http://www.ohloh.net/projects/6718/commits
Individual commits: http://www.ohloh.net/projects/6718/contributors

It even rates two of them as "Extremely well-commented source code" ๐Ÿ˜€

Displaying body text of a news item in sdotnews

http://www.srichinmoycentre.org/gallery/d/205411-2/P1030839.JPG

Who says a technical site can’t have pictures? (Photo:Kedar Misani )

Sdotnews by default displays the description of a news item. However, sometimes you will want to link to another page direct from the front sdotnews page, so it might be better to display the body text instead of the description, and in the body text of the news item you can then insert your links.

In order to implement this change we have to change the sdotnews_view template; specifically, replacing the bit that says

<p tal:content="result/Description">

At first I tried to call the text of the page body using

<p tal:content="result/getText">

or

<p tal: content="python: result.CookedBody()">

But this doesn’t work, because once sdot has batched the news articles in groups so they can be displayed on different pages, the page results can access the metadata listed in the catalog, (so result/Description or result/Title is ok, but result/getText isn’t).

Now, to get around this, you can include the page body in the catalog metadata (which would defeat the whole purpose of having a catalog in the first place), or else you can use the getObject method to access the obkjct and all of its attributes, rather than just the ones specified in the catalog.

tal:define="resultObject result/getObject;
            resultText python:resultObject.CookedBody(stx_level=2);

 <p tal:replace="structure resultText">

Note that sdot news already has defined resultObject, which it needed to access the news item image. Also note the structure command, this converts the HTML or ReStructured text. If you just put in

<p tal:content="resultText">

you will just get all the HTML tags.

Tips for faster speed in Plone

Plone, like any content management system, has slower page load speeds than static pages. Ensuring a fast enough page load speed so users won’t get turned off is therefore a big concern of Plone site maintainers. Here are some tips:

1. Avoid missing page components

If a part of a page (most commonly an image) returns a 404 or 301, it can slow down the page to more than half the speed. No matter what one does on system level you cannot make up for that kind of speed loss.

301 errors are particularly tricky since it is basically a bad link, but some code (most probably RedirectionTool) finds the requested object somewhere else and redirects the original request to the correct url. The url is served correctly, but that 301 makes the page load slow.

Actually the standard use of RedirectionTool (aliases) has the same effect, so it should be used just temporarily.

The Tamper Data extension (https://addons.mozilla.org/firefox/966/) to Firefox is a great tool because it allows you to quickly inspect headers of all the page components, not only the page itself. After installation, you will be requested to close the browser completely and start it again. Now Open Tamper Data from Tools menu in Firefox, and open a page you want to check out in Firefox. You can now see that Tamper Data window is being populated. Each line is one individual component of the requested page that has to be loaded in order to render the page. The most important column for us
is "Status". We are looking for 404 and 301 errors. 200 means you accessed site content without error and 304 means your local content is the same as in the squid, which is even better.

2. Page content – sometimes less is more

A page with twice as much content will most probably load two times slowly. Understandably that we want put as much possible into every page, but quite often less is more. Things that have to be generated by Zope (smart folders ect) will obviously take longer to load than static content

3. Caching

Most speed improvement on a system level involves caching – storing site content in easily accessible areas. Most large sites run a proxy cache like squid to serve up static content and keep Zope from doing the work. Other static content is cached in the browser itself. The most import thing is to make sure all pages and their components have correct caching headers; this is done by the CacheFu product, which now ships with Plone.

The whole plone caching business is described in http://plone.org/events/regional/nola06/collateral/make-plone-go-fast.pdf and CacheFu product documentation.

Obviously, any caching issue we fix has a double effect. The page is served from cache much faster and it does not create any load on zope server. Then the pages that have to be served by zope (cache refresh, editors) are much faster.

Another crucial point is to evaluate any new feature or product we are going to use from the caching and performance perspectives. Then we should document what adjustments have to be done when a product or a feature is deployed on a particular site. For instance if EasyBlog is installed on a site, the CacheFu will have to be set; if sdot is installed, the CacheFu will have to be set and icon image will have to be created, etc.

(Thanks to Atmasamarpan for all his help with this article)

Archetypes and ATContentTypes, part 2: Templates and customization slots

We will now look at how these schemas are called by the edit templates, and point out slots and hooks which Archetypes have left for customization.

Let us return to our Image type: selecting this type in portal_types and looking at properties will show that atct_edit is the default editing form, as it is for all ATContent Types. There is only one line in atct_edit, calling the master macro in the base_edit template. The main function of this macro is to call other macros for different parts of the page: most of these macros are located in the edit_macros file"

  • the top slot gets filled by edit_macros/topslot
  • javascript is looked after by archetypes_custom_js/macros/javascript_head
  • css: edit_macros/css
  • header,description, body,footer all in edit_macros.

So, let’s take a closer look at some of the macros in edit_macros:

Macros in edit_macros

  • header generates document actions like print, rss ect via the document actions macro and generates a title for the edit form with the name ‘Edit (Content Type)’
  • byline generates the byline, via the document_byline macro
  • archetypes_schemata_links: not sure what this bit does yet ๐Ÿ™‚
  • typedescription returns the description of the content type, which will appear at the top of the page under the title. It can be edited in portal_types without customizing, but the resulting edit will only appear in the ‘add item’ listng and not the edit form where you want it.
  • body: This is where the main action happens: for us, the interesting part of this macro is:
<metal:block define-slot="extra_top" />

        <metal:block define-slot="widgets">
          <tal:fields repeat="field fields">
            <metal:fieldMacro use-macro="python:here.widget(field.getName(), mode='edit')" />
          </tal:fields>
        </metal:block>

        <metal:block define-slot="extra_bottom" />

If we look at the above piece of code, it is essentially asking us to go through each field of the image schema and get its widget (For more on schemas and widgets, see part 1). Note the two slots ‘extra-top’ and ‘extra-bottom’ if you want to put something above or below the image widgets without changing the template.

The body macro also contains a good bit to do with sending the form, and the buttons. It contains a block defining Previous, Next (these automatically appear if there is more than one page in the edit form) Save and Cancel buttons. There is also a slot called ‘extra-buttons’ if you need to make any more buttons for your form, so you can make them in another template.

Whilst Archetypes does have a range of customization slots, one cannot make any easily reversible customizations to the schema as one might with a page template, as the files containing the schema are not stored on the zodb.

One is then left with the prospect of defining a new Archetype derived from your old one, either in a new product or as part of an existing one. Then in Extension/Install.py the portal_types tool can be manipulated to use the new type, or alternatively you can set that the old type can be just not globally allowed while the new type would be. Before you run into that course of action, there might be extra hooks for customization I havent found: for example, Villiam pointed out a post_validate hook for validators.

I am very grateful to Villiam Segeda, our resident Archetypes expert, for teaching me what little I know.

How do they do the navigation on the plone.org site?

When you visit the plone site (http://plone.org) you see that the side navigation bar (viewable at any page besides homepage) contains only the root folders, the item and its immediate ancestors. A very nice behaviour, and one I spent a while fiddling with navigation properties trying to make happen.

But actually the solution is much simpler. Every version of Plone since 2.1 comes packaged with two identical states ‘public draft’ and ‘published’ – items in either of these two states are available to the general public. Why two identical states? Well, it does enable the user to choose which items he wants public but not available in navigation by putting the items he wants available in navigation ‘published’ and the ones he doesn’t ‘public draft’, say. Then he can go to navigation properties in preferences, check filter workflow states, and put in published into the box below.

That’s what Plone have done on their site: in addition, only the folders at site root are published, and all other content is visible, so that it will only appear in navigation if the actual page is selected.

Archetypes and ATContentTypes, part 1: The Archetype Schema

All the default types in Plone – file, image, folder – are part of the ATContentTypes product, and are examples of archetypes. Archetypes were integrated into Plone 2.1, and allow you to create content types easily by providing a range of readymade tools so you can generate edit forms without using any HTML.

An example will perhaps best explain how Archetypes works – lets look at the familiar ‘image’ type. The edit form of an Archetype is generated using a schema, and the schema for image can be found in Products/ATContentTypes/content/image.py: here we’ve taken out some of the code to focus on the essentials:

ATImageSchema = ATContentTypeSchema.copy() + Schema((
  ImageField('image',
        required=True,
                ....(lots of other stuff here, to do with image sizing and such).....
        validators = (('isNonEmptyFile', V_REQUIRED),
                      ('checkImageMaxSize', V_REQUIRED)),
        widget = ImageWidget(
                   #description = "Select the image to be added by
                                   clicking the 'Browse' button.",
                   #description_msgid = "help_image",
                   description = "",
                   label= "Image",
                   label_msgid = "label_image",
                   i18n_domain = "plone",
                   show_content_type = False,)),

  ), marshall=PrimaryFieldMarshaller()
  )

That’s all a bit of a mouthful, so we’ll break it up and isolate the essential parts:

ATImageSchema = ATContentTypeSchema.copy() + Schema((
     ImageField(

Every schema contains a collection of fields; in the edit form the short name is one field , the Title is another and so on… The reason we don’t see the title, id, or description in the above schema is they are already defined in ATContentSchema (they are common to all types); the first line of the code joins ATContentTypeSchema to the schema we are creating above.

For an image, there is only one extra field, the ImageField. Lets say we want another field to specify the camera the image was taken with; our schema will then look like:

ATImageSchema = ATContentTypeSchema.copy() + Schema((
      ImageField(   # all the stuff above
           ),

       StringField('camera',
                  required=1,
                  widget=TextAreaWidget(),),

   ), marshall=PrimaryFieldMarshaller()
       )

Archetypes provides many different kinds of field you can include – TextField, BooleanField (for yes/no values) ect. In plone.org there is a list of available Archetypes fields….

OK, lets look at the arguments of ImageField:

ImageField('image',
       required=True,
               ....(lots of other stuff here).....
       validators = (('isNonEmptyFile', V_REQUIRED),
                     ('checkImageMaxSize', V_REQUIRED)),
       widget = ImageWidget(
                                # whatever goes here we'll explain
                                # when we talk about widgets
        )),

 )

The first argument ‘image’ is the title of the field, the required=True puts the little red ‘required’ dot beside the title. Now, the next two are important:

  • validators: these are classes which check that whatever we’ve entered into the field satisfies a set of conditions, and it won’t accept it if it doesn’t. For example, ImageField calls instances of two validator classes: one of them makes sure the uploaded file isn’t empty, and the other rejects the uploaded file if it is too large. There is some readymade validators at Products/validation/validators, although quite often people have the need to add extra ones of their own.
  • widget: the widget is the graphical layout that the field will take; it defines how to render the field into HTML/XML. For example a StringWidget will set out a one-line box; a TextAreaWidget will set out a bigger box, like what is used for the Description. On plone.org you can see pictures of all the available Archetypes widgets ; it is very unlikely you will need to make your own. In many cases, the field type suggests what widget type to use: an ImageField will use an ImageWidget, for example.

The arguments of ImageWidget are quite straightforward:

widget = ImageWidget(
       #description = "Select the image to be added by clicking the 'Browse' button.",
       #description_msgid = "help_image",
       description = "",
       label= "Image",
       label_msgid = "label_image",
       i18n_domain = "plone",
       show_content_type = False,)),

The _msgid label is used by the internationalization (i18n) mechanism to generate translations in other languages.

Ok, one final thing to deal with, the marshaller, this makes Archetype fields understandable to clients such as WebDAV. As you can see above, the schema took two arguments, the field and the marshaller.

Schema (    (ImageField( all the stuff we discussed ),),
                                    marshall=PrimaryFieldMarshaller()
     )

PrimaryFieldMarshaller is the most common marshaller used, apparently.

Ok, so that’s the first part of my ATContentTypes exploration; the second part will deal with the question I first asked when I saw a type schema: how does all this called by a template and end up on our screens?

Selecting content item as default view of a folder (including the /Members folder!)

I always wondered why the ‘Display’ tab containing the ‘select content item as default view’ was sometimes clickable and sometimes not. Well the answer is simple (it always is after you’ve found it): if you have an item in your folder called index_html, Plone will automatically recognise that as the default view item, and you have to rename it before you can access the ‘Display’ tab….

This also goes for the Members folder. By default, index_html will bring up a ‘search for members’ template, which I never found very useful, and always wanted to replace with a nice smart folder. First go into /Members in the zmi, select index_html (it’s in there somewhere amongst all the members), and rename it to something like index_html.old. Now, somewhere outside of Members, create the item you want to have as default view, and paste it into Members with title (guess) index_html.

This is a rather contrived way of going about things, I admit: Atmasamarpan tells me there is an index_home python script which calls index_html as the default view for the Members Large Plone Folder (which I have yet to find). Rename this script and you can access the display tab as normal. (Note: if you dont rename the script and there is no index_html item, you will get a site error when you try to acess the Members folder in Plone),.

Inserting content of Plone document into Zope template

As explained in an recent article titled ‘Edit ZPT content through Plone ‘ on plone.org, we can insert the content of a document called my-document, say, by inserting the following into your template:

<tal:block tal:condition="exists:here/footer-content/my_document"
             tal:replace="structure here/footer-content/my_document/getText">
              Document content here</tal:block>

Perhaps one of these days Plone can use this method so that we can edit footers and colophons directly through Plone; ive submitted a ticket to Plone here…

Perhaps we could even extend it to things like bylines, although that’s a harder kettle of fish as we’re dealing with variables like creator and modification date. Any ideas, anyone?

Negotiating the Plone security maze

If, like me, you have been trying to resolve permission problems by checking and unchecking boxes in the ZMI Security tab in a trial-and-error fashion, there is in fact an easier way (I never doubted Plone for an instant ๐Ÿ™‚ )

  • Before going to the Security tab, you should first find the Actions tab for the process you want to control permissions for. By default, things like the top navigation tabs and the buttons at the bottom of the folder listing are controlled in the Actions tab of portal_actions.
  • Things like the edit, properties and sharing tabs are defined seperately for each item type in portal_types: i.e to access the actions for an image, one would go to portal_types->image and click on the Actions tab. (The Content tab is defined globally in portal_actions).
  • Scroll down to see the action you want to change the permissions for, and you will see the permission you need to change (there are cases where you might want to change this permission: for example, to stop object owners from accessing the properties tab, you would have to change the permission from ‘modify portal content’ to something like ‘manage properties’ and restrict that permission).