I’m also using plone for my personal web site to which I add various articles and thoughts rather often. For this reason I wanted to be able to have a list of changes and interesting links on the home page. The CMFContentPanels product has been of great help in this matter as it allowed me to create a more complex content in the pages notably the home page. This article describes a small customization of this product in order to also add more text to the recent news list. It applies to Plone 2.5.3 and CMFContentPanels 2.4.

The viewlets

It took only little research to find that all I had to change was the viewlet responsible for the folder_recent content.

Viewlet template

The template for this can be found in: CMFContentPanels/skins/cp_viewlets/viewlets_folder_recent.pt. Here is the changed code for displaying the results:

<tal:items tal:repeat="obj results"><br></br>    <dd class="portletItem"<br></br>        tal:attributes="class python:test(repeat['obj'].odd(),<br></br>                                         'portletItem even',<br></br>                                         'portletItem odd')"<br></br>	><br></br>        <a class="tile" <br></br>           tal:attributes="href string:${obj/getURL}/view"><br></br>           <img src="#"<br></br>               tal:attributes="src string:$portal_url/${obj/getIcon}" /><br></br>           <tal:title tal:content="obj/pretty_title_or_id">title</tal:title><br></br>	</a><br></br>           <span tal:define="ro python:obj.getObject()" tal:condition="python:ro.getPortalTypeName()=='Document'"><br></br>	   <span tal:replace="structure python:context.pageSummary(ro.getText())"/>&nbsp;&nbsp;<br></br>	   <a tal:attributes="href string:${obj/getURL}/view">...read the rest.</a></span><br></br>        <a class="tile" <br></br>           tal:attributes="href string:${obj/getURL}/view">	<br></br>	  <span class="portletItemDetails"<br></br>                 tal:define="modificationDate obj/Date;<br></br>                             creator obj/Creator;<br></br>                             author python:mtool.getMemberInfo(creator);<br></br>                             authorName python:author and author['fullname'] or creator;<br></br>                             modificationDate python:here.toLocalizedTime(modificationDate)"<br></br>                 tal:content="string:(${authorName}) $modificationDate"><br></br>                      creator   08/19/2001 03:01 AM<br></br>           </span><br></br>        </a><br></br>    </dd><br></br>    </tal:items><br></br>

Here are some pointers to understand it:

  • results are returned by portal_catalog.searchResults. The results list does not contain actual site objects but something called brains which are shorter versions of the objects. You have to call the getObject() method on a brain in order to get the actual object.
  • once you have the site object a very good way to know what methods to call is to use the DocFinderTab product which adds a doc tab to all site objects. Just navigate in the zope management interface to the desired object and use the doc tab to find it’s methods and, very important, the security issues related to these methods
  • in my case I check if the object is of type Document (which corresponds to a page) and then I return a summary of the page content as returned by the getText() method
  • in order to have the summary of the page I wrote a python script which removes all the tags and returns the text up to the first white space after 250 characters.

Summary script

Here is the script pageSummary.py located in the same path as the viewlet template file:

## Script (Python) "pageSummary"<br></br>##bind container=container<br></br>##bind context=context<br></br>##bind namespace=<br></br>##bind script=script<br></br>##bind subpath=traverse_subpath<br></br>##parameters=text<br></br>##title=get rss result<br></br>##<br></br><br></br>from zLOG import LOG, INFO<br></br>from re import sub<br></br><br></br>maxStart = 250<br></br>cleanText = sub('<[^>]*>','', text)<br></br>if len(cleanText) > maxStart:<br></br>    i = cleanText.find(' ', maxStart)<br></br>    summary = cleanText[:i]<br></br>else:<br></br>    summary = cleanText<br></br><br></br>return summary<br></br>

Granted the method could be improved and it would require more error handling but it responds to my initial needs. One very important aspect is the use of the “restricted” module “re”. In order to be able to use this module I had to modify the product __init__.py script and reinstall the product:

from Products.PythonScripts.Utility import allow_module<br></br>allow_module("feedparser")<br></br>allow_module('Products.CMFContentPanels.browser.subnavtree')<br></br>#start modif len<br></br>allow_module('re')<br></br>#end modif len<br></br><br></br>def initialize(context):

That was what it took to get the desired effect which you can check here.

Screenshots

Before: before * 958 x 674 * (137KB) and after: after * 955 x 739 * (198KB)

Comments:

Len -

This does not sound right: item_body.find('

', item_bodysum_max) will return an occurence of

AFTER item_bodysum_max. Here is a simple example:

>» item_body='

basdasdas asda adsad adas dasdad da da

'
>» item_bodysum_max=10
>» a = item_body[:item_body.find('

', item_bodysum_max)]
>» print a

basdasdas asda adsad adas dasdad da da \>>> print item\_body.find('

', item\_bodysum\_max) 41 \>>> ___ #### peter -

I change your script i my template for articles, i can html code:
item_body = python:ro.getText();
-–

-–