Oxfam America

Topics

A Topic is a special content type that allows you to create a sort of "canned search" - a list of items created by a given set of criteria - and display it on the website.


Examples

Topics can be displayed on a page by themselves, or, through special sidebars and templates, as a short list on other pages. One example of a topic can be found on the MTF News page. This page (at the time of writing) shows a list of articles with the following criteria: items of specific content types (News Update, Press Release, and Feature Story) associated with a specific campaign (Make Trade Fair) in their metadata [XXX: link]. The same Topic is shown in a sidebar on the main MTF page, where only the first four items are visible.

Creating a Topic

In order to create a Topic, this content type must be enabled in the folder you're adding to [XXX: link]. As with all other content, you can use the Add New Item button to add a new Topic [XXX: link].

The Edit Topic screen has the same basic parts as most other content: Short Name, Title, and Description. These work exactly the same as with other content; Title will show up on the page and in navigation, Description will show up on the page below the title and in searches, etc.

Below the Description are several fields which you can generally ignore: Inherit Criteria, Limit Number of Items, and Number of Items. At the bottom of the page is the meat of the Topic: the Search Script. There are other ways of specifying criteria, but the fastest and most flexible is to use a script - a very short program specifying your search. It might seem a little unfamiliar if you've never done any programming, but it's pretty straightforward and easy to learn.

Writing a Search Script

A search script needs to have the following elements:

  • A query that defines the criteria you're looking for
  • A function call that asks the system for the results of your query
  • A return statement that displays the results.

In some scripts, you may also have a few lines in the beginning to help define your query. As in any code, punctuation matters - so make sure that all quotation marks, parentheses, and curly braces are "closed" - i.e. every time you have an open parenthesis ( you also have a close parenthesis ). It will be easier to write the script in Notepad (or a code editor if you have one) than to try to write it in the textbox in your browser. Don't write it in Word - it'll screw up your punctuation.

The Query

There are several ways to write these scripts, but I find it simplest to define the query ahead of time. You define the query in a statement like this:

query={'portal_type':'News Updates',
'sort_on':'start',
'sort_order':'descending',
'path':'/Plone/public_website/en',
}

What you're actually doing here is defining a variable call "query" which you will use later. Everything within the curly braces {} is called a dictionary - it allows you to define a number of different criteria. Each criterion name, such as "portal_type", must be enclosed in quotes (either single ' or double ") and followed with a colon : ; the criterion value, such as 'News Updates', also enclosed in quotes; and a comma , .

There are a number of different criterion types possible:

  • portal_type - this is the name of a content type, such as 'Press Release', 'Feature Story', or 'Briefing Paper'.
  • path - this is the path of the folder you want the system to look in. As you can see above, the path must begin with the root of the public website, '/Plone/public_website/en'. If you wanted to search in a particular regional section, for example, the path might be '/Plone/public_website/en/whatwedo/where_we_work/camexca'.
  • sort_on - this defines how the list should be ordered, along with sort_order. The criterion value 'start' means "by start date", so 'sort_on':'start' and 'sort_order':'descending' will order the items by date, latest first. This is the most common way we order lists on the site, and almost all Topic scripts will include those values.
  • sort_order - see above; in conjunction with the sort_on criterion, this defines how the list is ordered. Possible values are 'ascending' and 'descending' - in a chronological list, these translate to "oldest first" and "latest first" respectively.
  • getRegions - this is a region or country found in the metadata. Regions and countries are defined as a path, like so: '/ALL/South America' or '/ALL/CAMEXCA/El Salvador'. Case matters.

The Function Call and the Return Statement

Once you've defined the query, you can get it from the system through a function call, like this:

results = context.portal_catalog(**query)

and return the results for display with a return statement, like this:

return results

or you can combine the two statements in one line (now would be a good time to get your cutting-and-pasting skills ready):

return context.portal_catalog(**query)

If you don't include this line, no results will appear, so you may want to start off your script by pasting this at the bottom.

Final Script

So, in this example, your final script looks like this:

query={'portal_type':'News Updates',
'sort_on':'start',
'sort_order':'descending',
'path':'/Plone/public_website/en',
}
return context.portal_catalog(**query)

This will display a list of all the News Updates on the website, in descending chronological order.

Campaigns, Emergencies, and Issues

There's a slightly more complicated set of criteria for specifying articles associated with Campaigns, Emergencies, and Issues. First, you identify the actual Campaign or Emergency item by its path, e.g. 'public_website/en/whatwedo/emergencies/iraq/index_html' (note the index_html on the end - the Emergency is the actual default page, not the folder it's in). Then you cut and paste some code to get a special id for the item, and then you refer to this id in your query. For example (key lines in bold):

path='public_website/en/whatwedo/emergencies/iraq/index_html'
portal = context.portal_url.getPortalObject()
obj = portal.restrictedTraverse(path)
targetUUID = obj.UID()

query={'portal_type':'News Updates',
'sort_on':'start',
'sort_order':'descending',
'path':'/Plone/public_website/en',
getEmergencyUUIDs=targetUUID,
}
return context.portal_catalog(**query)

Don't worry about the three lines after the path definition - just cut and paste them into your script. Note that you don't need an extra line break between the first 4 lines and the query, but it makes the script a little more legible.

Campaigns and Issues are exactly the same, except instead of the line:

getEmergencyUUIDs=targetUUID,

you use the line:

getCampaignUUIDs=targetUUID,

or:

getIssueUUIDs=targetUUID,

Multiple Options in One Criterion

Suppose you want to have more than one option in, for example, the portal_type criterion - you want to show more than just one content type, you want to show two or three. To do this, you use a special format to specify the criterion:

'portal_type':['Feature Story', 'News Update', 'Press Release'],

This will display any item that is any of these content types. You can use the same syntax for other criteria, such as getRegions:

'getRegions':['/ALL/CAMEXCA/', '/ALL/United States'],

would display items in either CAMEXCA or the US.

Putting It All Together

Imagine you're making a new campaign folder for the One Campaign, located at /whatwedo/campaigns/one. You want a Latest News Topic that will show all the latest News Updates and Press Releases associated with the new campaign. Your script might look something like this:

path='public_website/en/whatwedo/campaigns/one/index_html'
portal = context.portal_url.getPortalObject()
obj = portal.restrictedTraverse(path)
targetUUID = obj.UID()

query={'portal_type':['News Updates','Press Releases'],
'sort_on':'start',
'sort_order':'descending',
'path':'/Plone/public_website/en',
getCampaignUUIDs=targetUUID,
}
return context.portal_catalog(**query)

The first four lines indicate the new Campaign object and get its special id. The query uses the list format to specify both News Updates and Press Releases should be shown; it specifies that they should be displayed in chronological order, latest first; it says to show all items in the public website (we could have said all items in the One Campaign folder, but most News Updates and Press Releases will live in the News & Publications section, and we want to inlude them); and it refers to the special id of the campaign, specifying that only items associated with this campaign should be shown. The last line gets the data from the system and returns it for display.

Easy, huh?

More Information

The easiest way to get more examples is to look at Topics already in the system. Cut and paste the scripts into new Topics in a Private Sandbox and you'll be able to make changes and see the results.

The Topic scripts are just standard Plone searches. For more information, including other criteria and ways to narrow the search, see Andy McKay's Definitive Guide to Plone - there's a copy in the Boston office.