How to create a blog view of a page listing

by Marilen Corciovei last modified Dec 30, 2008 03:03 PM
Modifying a CMFContentPanels viewlet to add a blog-style view to a Plone site

Purpose

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 (original text) describes a small customization of this product in order to also add more text to the recent news list.

Prerequisities

It applies to Plone 2.5.3 and CMFContentPanels 2.4 and requires some basic Python and template (pt) skills.

Step by step

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

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"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##parameters=text
##title=get rss result
##

from zLOG import LOG, INFO
from re import sub

maxStart = 250
cleanText = sub('<[^>]*>','', text)
if len(cleanText) > maxStart:
    i = cleanText.find(' ', maxStart)
    summary = cleanText[:i]
else:
    summary = cleanText

return summary

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
allow_module("feedparser")
allow_module('Products.CMFContentPanels.browser.subnavtree')
#start modif len
allow_module('re')
#end modif len

def initialize(context):
That was what it took to get the desired effect which you can check here.