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.