Centre For Design, eZ Publish Case Study - Development

Development
The development phase started at the same time as the HTML prototype. We were able to
do the initial setup and configuration while the prototype was being built.
Install eZ publish
For this project, the first release of eZ publish 3.0 (3.0-1) was used initially, and later
upgraded to a bug fix release 3.0-2. Since then, there have been another two major
releases that have introduced a much-improved configuration process.
Installation of the eZ publish system is a relatively simple process. We incorporated the
setup of an eZ publish site into our existing development environment setup.
While the eZ publish initial configuration process has improved remarkably
in subsequent releases, the installation process remains largely similar to
the first version.
As a matter of policy, we use a regular site for the web server and a secure site for the
admin section. For example:
http://projectname.devserver/ Regular site
https://admin.projectname.devserver/ Admin site
The main steps in the installation of eZ publish are:
1. Set up virtual servers (regular and secure) as normal.
2. Create a MySQL database and database user.
3. Uncompress the eZ publish distribution in the site DOCROOT.
4. Change permissions and ownership on the var and settings directories to
allow the web server to write to these.
5. Visit the site URL and process through the eZ publish configuration screens.
6. Manually modify the eZ publish configuration files to match our setup. (This
involves changing the default way the regular site is distinguished from the
admin site. By default, eZ publish uses the "URL" method, but we used port
numbers. This part of the process is now included in the setup process via
web pages).
7. Setup and configure design directories for the admin and regular sites.
The CMS is now ready for configuration.
Define Content Classes and Sections
Because of the time spent in getting the information architecture correct, the setup of the
content type was a simple process. We used the existing content types Folder and Article,
with the Article type requiring the addition of a number of attributes. The other content
types were added using the Admin pages.
Configure Roles and Permissions
Due to the workflow requirements being left for a future production stage, the roles
required for this project were limited to three—the default Administrator and Anonymous
roles, and the additional Editor role for data entry.
The Administrator role has access to all functionality, including the creation,
modification, and removal of content, and the ability to modify configuration of the CMS
itself. We did not need to modify this role in any way.
The Editor role has access to create content where it is appropriate (this is based on the
Content model outlined earlier), and to modify and delete this content. Items in the misc
folder may only be edited, as these are statically linked in the templates and would break
links if removed. Similarly, adding content to this folder would be of no advantage.
Access to the configuration aspects of the CMS is not permitted by this role.
The Anonymous role, like that of the Administrator, is an existing role. The only
modification required to this role is to grant read access to the newly created content
objects.
It is a common mistake not to give the Anonymous role read access to newly
created content types. If you cannot view data in the site, check to see if the
Anonymous role has read permission for that particular content type.
Each role was assigned to a corresponding user group, and a number of Editor users were
created for the client for the content population staff.
Apply Display Logic and Templates
All page types (home, primary, secondary, tertiary), content types (article, folder, etc.),
and sectional summary pages are defined in the Information Architecture document and
created in a HTML prototype. This allows for the associated templates to be created
directly from the HTML prototype. Also, this process becomes a simple copying of the
core HTML and replacement of the sample data with the appropriate eZ publish template
code.
Templates in the eZ publish system are divided into two main types: page layout and
content templates. We will now see how these templates were created, along with the
templates for navigation and summaries of content.
Specifically, we will look at how the templates were created for:
• Page layout
• Navigation
• Summarized content
• Content
Create Page Layout Templates
The first step in applying the templates is to create the page layout template. This
template determines the layout of the page. This site has different page layouts for the
home page and all secondary pages and this process is performed for both.
All external files (images, stylesheets, and JavaScript) are copied to the design directory
on the eZ publish server. The HTML prototype is copied to pagelayout.tpl and all
references to external files (images, stylesheets, and JavaScript) are converted to use the
ezdesign and ezimage functions.
For example, the following HTML to include a JavaScript file:

 
<script language="JavaScript"
src="script/common.js"
type="text/JavaScript">
</script>
becomes:
<script language="JavaScript"
src={"script/common.js" |ezdesign}
type="text/JavaScript">
</script>
The following HTML to include a stylesheet:
<link rel="stylesheet" href="stylesheets/style.css"
type="text/css">
becomes:
<link rel="stylesheet" href={"stylesheets/style.css"|ezdesign}
type="text/css">
The following HTML to include an image:
<img src="images/nv_0202_montage.jpg" width="675" height="96"
alt="Welcome to the Centre for Design">
becomes:
<img src={"nv_0202_montage.jpg"|ezimage}
width="675" height="96"
alt="Welcome to the Centre for Design">

This tells the template system where to find the external files.
The main content area is then replaced with {module-result.content}. This is
substituted by the template system with the content for a specific page.
Navigation
The next stage is for the navigation to be programmed. This process requires the CMS to
be populated with sample content. It is always good to use real content if possible for this
process as this gives a real sense of how the system will eventually work.
Primary Navigation on Home Page
Primary Navigation on Secondary & Content Pages
The CFD site has the following top-level content areas
• Research and Consulting
• Training and Professional Development
• Publications
• Sustainable Products and Product Systems
• Sustainable Buildings
• Life Cycle Assessment
• Links
• News
These sections are created via the admin interface under the root node using the Section
Overview content type.
With most websites, there is usually content associated with the site that describes the site
or the content. A folder is created and called misc (short for Miscellaneous) and the
following articles are created in this folder:
• More about the Centre
• Copyright
• Disclaimer
• Sitemap
• Site credits
• Register for newsletter
(The "Register for newsletter" item is a different content type used to collect e-mail
addresses for the mailing list)
This provides us with a skeletal site into which the navigation can be programmed.
Footer on Home Page
Footer on All Other Pages
Setting Up
As the navigation differs for various sections of the site, the first step is to detect which
section the current node belongs to and to set some variables. This is done by including
an initialization (design/cfs/templates/common/initialization.tpl) file in the
page layout template.
The initialization file detects which section of the site the user is currently in and stores
the following items in variables:
• section_top_node_id: The node ID of the top node of this section
• section_img: The section banner image
• section_alt: The alt attribute for the banner image
• sec_nav: The secondary navigation for this section
The first step of the initialization is the setup of arrays that hold the information for each
section. The first array holds the banner image and all text for items in the misc folder.
These objects have individual banner images that we directly relate to their node ID;
hence the key to the array is the node ID of each object in this folder.
This code creates and initializes variables that are used in this file:

{let section_hash=false()
misc_node_hash=false()
section_top_node=false()
}
The misc items information array is as follows:
{set misc_node_hash=hash(
31,hash('image','images/hdr_moreabout.gif',
'image_alt','more about the centre',
),
32,hash('image','images/hdr_copyright.gif',
'image_alt','copyright',
),
33,hash('image','images/hdr_disclaimer.gif',
'image_alt','disclaimer',
),
59,hash('image','images/hdr_sitecredits.gif',
'image_alt','site credits',
),
65,hash('image','images/hdr_sitemap.gif',
'image_alt','sitemap',
),
81,hash('image','images/hdr_register.gif',
'image_alt','register for newsletter',
),
)
}

The following array stores the section information. In addition to the banner information,
the name of the file used for generating the secondary navigation for the section is added.
The key for this array is the section top node ID.

{set section_hash=hash(
16,hash('section_img','images/hdr_susproducts.gif',
'section_alt','Sustainable Products &amp; Product Systems',
'sec_nav','program_navigation.tpl',
),
17,hash('section_img','images/hdr_susbuildings.gif',
'section_alt','Sustainable Buildings',
'sec_nav','program_navigation.tpl',
),
18,hash('section_img','images/hdr_lifecycle.gif',
'section_alt','Life Cycle Assessment',
'sec_nav','program_navigation.tpl',
),
21,hash('section_img','images/hdr_publications.gif',
'section_alt','Publications',
'sec_nav','publication_navigation.tpl',
),
20,hash('section_img','images/hdr_research.gif',
'section_alt','Research &amp; Consulting',
'sec_nav','research_navigation.tpl',
),
19,hash('section_img','images/hdr_training.gif',
'section_alt','Training &amp; Professional Development',
'sec_nav','training_navigation.tpl',
),
22,hash('section_img','images/hdr_links.gif',
'section_alt','Links',
'sec_nav','link_navigation.tpl',
),
23,hash('section_img','images/hdr_news.gif',
'section_alt','News',
'sec_nav',false(),
),
'Search',hash('section_img','images/hdr_search_results.gif',
'section_alt','Search results',
'sec_nav',false(),
),
24,hash('section_img',$misc_node_hash[$module_result.node_id]['image'],
'section_alt',$misc_node_hash[$module_result.node_id]['image_alt'],
'sec_nav',false(),
),
)

Of note in this array are the elements with the keys Search and 24. The Search entry is
for search results pages. The element with key 24 is for items in the misc folder. The
banner information is set using the misc_node_hash array and the current node ID.
The code to determine the top node ID of the current section follows:

{section show=eq($module_result.path[0].text,'Search')}
{set section_top_node='Search'}
{section-else}
{section show=$DesignKeys:used.depth|gt(2)}
{set section_top_node=$module_result.path[1].node_id}
{section-else}
{set section_top_node=$module_result.node_id}
{/section}
{/section}

We check if the current page is a search results page. If this is not the case, the depth of
the current node is tested to see if we are not currently on one of the section top nodes
(depth less than or equal to 2). If this is the case, we retrieve the section top node ID from
the node path; otherwise we use the current node ID. The last step in this process is to
assign values to the variables so they can be used in the pagelayout.tpl file.

{set-block variable=section_top_node_id}
{$section_top_node}
{/set-block}
{set-block variable=section_img}
{$section_hash[$section_top_node]['section_img']}
{/set-block}
{set-block variable=section_alt}
{$section_hash[$section_top_node]['section_alt']}
{/set-block}

These lines set the banner information and the section top node ID (used in primary
navigation—see below):

{set-block variable=sec_nav}
{section show=$section_hash[$section_top_node]['sec_nav']}
{section show=array('publication','extended')|
contains($DesignKeys:used.viewmode)}
{set-block variable=section_top_node_id}21{/set-block}
{include uri="design:common/publication_navigation.tpl"}
{section-else}
{section show=ne($module_result.node_id,21)}
{include uri=concat(
"design:common/",$section_hash[$section_top_node]['sec_nav'])
section_top_node_id=$section_top_node}
{/section}
{/section}
{/section}
{/set-block}
{/let}

This code block sets the sec_nav variable. For some sections there is no secondary
navigation and this variable is empty. Apart from the publication section, this process is
simply a matter of including the correct file to generate the navigation.
The following code from the pagepayout.tpl file displays the section banner:

<img src={$section_img|ezdesign} alt="{$section_alt}"
width="370" height="26" border="0"><br>

The secondary navigation is simply added in the correct place in the template. The use of
the section_top_node_id variable is detailed in the next section.
Primary Navigation: Navigation Highlighted by Border
All of the primary navigation items are hard-coded in to the page layout template using
their unique node IDs. We initially used the URL alias feature but found that when a
content editor changed the title of an object the URL alias also changed, breaking the
hard-coded link.
The new URL Translator feature allows you to bypass this issue and will be
implemented in Stage 2.
The node IDs of the items in the misc folder are recorded and the links in the
pagelayout.tpl are configured using the ezurl template function.
Each primary navigation link has 'on', 'off', and 'active' states. The on and off states are
controlled by JavaScript using the onmouseover and onmouseout link attributes. The
active and non-active states are controlled by the template logic.
The following code fragment shows how this is implemented for the More About the
Centre link (node ID 31):

<a href={"content/view/full/31"|ezurl}
onMouseOver="imgOn('nv_moreabout')">
{section show=eq($module_result.node_id,31)}
onMouseOut="imgActive('nv_moreabout')">
<img src={"nv_moreabout_active.gif"|ezimage}
{section-else}
onMouseOut="imgOff('nv_moreabout')">
<img src={"nv_moreabout_off.gif"|ezimage}
{/section}
width="175" height="20" border="0"
alt="more about the centre"
name="nv_moreabout">
</a>

This code fragment is repeated for all the miscellaneous primary navigation items.
The logic for displaying the navigation for the main primary navigation items is slightly
different as these parts of the site have depth and it is not enough to check to see if the
current node ID matches. In these cases we need to check if the current node is either the
given node or is an ancestor of the given node.
The following code fragment shows how this is implemented for the Sustainable
Products and Product Systems link (node ID 16):

<a href={"content/view/full/16"|ezurl}
onMouseOver="imgOn('nv_susproducts')">
{section show=eq($section_top_node_id,16)}
"onMouseOut="imgActive('nv_susproducts')">
<img src={"nv_susproducts_active.gif"|ezimage}
{section-else}
"onMouseOut="imgOff('nv_susproducts')">
<img src={"nv_susproducts_off.gif"|ezimage}
{/section}
width="175" height="33" border="0"
alt="sustainable products &amp; product systems"
name="nv_susproducts"></a>

The variable $section_top_node_id is set in initialization.tpl.
Secondary Navigation for Life Cycle Assessment (Highlighted by Border)
The secondary navigation varies for the different sections of the site. First we'll examine
the secondary navigation for the Programs (Sustainable Products & Product Systems,
Sustainable Buildings, and Life Cycle Assessment) and Training & Professional
Development.
Each program is created in the system as a folder and may contain objects of type Project,
Publication, Training, Client, Articles, and Links. The secondary navigation displays all
items grouped by their type.
The following code is used to produce the secondary navigation for each program's
sections:

{let program_subsections=hash('Projects', 7,
'Publications',9,
'Training',8,
'Clients',11,
'Articles',2,
'Links',10,
)
}
<!-- 2nd navigation -->
<td valign="top">
<div class="sec_nav_column">
{section loop=$program_subsections}
{$:key}
{let item_list=fetch(content,list,
hash(parent_node_id,$section_top_node_id,
class_filter_type,include,
class_filter_array,array($:item)))
}
<ul>
{section show=$item_list}
{section loop=$item_list}
<li><a href={$:item.object.main_node.url_alias|ezurl}>
{$:item.name}</a></li>
{/section}
{section-else}
<li>No Items</li>
{/section}
</ul>
{/let}
{/section}
</div></td>
<!-- end 2nd navigation -->
{/let}

First we define an array of headings and their corresponding class IDs. This array is then
looped and for each class type:
• The heading is outputted.
• All objects of that type that belong to the current program area
($section_top_node_id) are retrieved.
• Links to the objects are outputted.
If no objects of a particular type exist, the text No Items is outputted.
The content model allows for training objects to be optionally associated with one of the
Programs. Additional training objects as well as any articles about training are placed in
the Training folder. The secondary navigation for the training section displays the
training objects grouped by their program plus any additional training objects and
training articles.
Secondary Navigation for Training (Highlighted with a Border)
The following code is used to produce the secondary navigation for the Training section:

{
let programs=hash(
'Sustainable Products & Product Systems', 16,
'Sustainable Buildings',17,
'Life Cycle Assessment',18,
'Other',19
)
}
<!-- 2nd navigation -->
<td valign="top">
<div class="sec_nav_column">
{* list training *}
{section loop=$programs}
{$:key}
{
let item_list=fetch(content,list,
hash(parent_node_id,$:item,
class_filter_type,include,
class_filter_array,array(8)))
}
<ul>
{section loop=$item_list show=$item_list}
<li><a href={$:item.object.main_node.url_alias|ezurl}>
{$:item.name}</a>
</li>
{section-else} {* no matching content *}
<li>No Items</li>
{/section}
</ul>
{/let}
{/section}
{* list articles *}
{
let articles=fetch(content,list,
hash(parent_node_id,$section_top_node_id,
class_filter_type,include,
class_filter_array,array(2)))
}
Articles
<ul>
{section show=$articles}
{section loop=$articles}
<li><a href={$:item.object.main_node.url_alias|ezurl}>{$:item.name}</a></li>
{/section}
{section-else}
<li>No Items</li>
{/section}
</ul>
{/let}
</div></td>
<!-- end 2nd navigation -->
{/let}

Similar to the Programs navigation, the first thing we do is define an array of items we
want to display. In this case, the array contains program names and the associated
node_id, as well as the Training node_id. This array is looped, and for each element of
the array all Training objects (class_id = 8) are retrieved. Links to these are then
displayed. If no training objects exist for a program then No Items is displayed.
The second part of the code retrieves and displays any articles that exist under the
training folder. Again, if no objects exists then No items is displayed.
Summary Pages
Secondary pages usually provide a summary of information from a particular section or
an alternative view of data from other parts of the site. These pages are programmed
based on the Information Architecture document, which defines the source, type, order,
and number of items displayed on the page.
The Publications page provides a summary of the publications associated with each
program. Summaries of the three most recent publications from each program are
displayed. Links to the full listing of all publications for each program and an
alphabetical listing of all publications are also displayed.
As Publication content types are located under each of the program folders, this page
template must retrieve the three most recent publications from each of the program
folders.
A publications folder is created at the top level to provide a point at which the user can
access this information. The node ID of the publications folder is 21.
The template override system is used to call the publications template
(publications.tpl).
The following entry in /settings/siteaccess/cfd/override.ini indicates that the
publications.tpl template should be used instead of the default full.tpl template for
node ID 21:

[publications]
Source=node/view/full.tpl
MatchFile=publications.tpl
Subdir=templates
Match[node]=21
The following code (/design/cfd/override/templates/publications.tpl) provides
the required functionality:
{* Publication Main Template *}
{let programs=hash('Sustainable Products', 16,
'Sustainable Buildings',17,
'Life Cycle Assessment',18,
)
publication_limit=3
}

We begin by creating an array of the program types and their node IDs along with a
publication_limit variable. The publication_limit variable allows us to easily
change the number of publications displayed.
Next, the programs array is looped through. For each program, we retrieve the three most
recent (sort_by,array(published,false())) publication objects (class_filter_type,
include, class_filter_array,array(9)) that are children of the current program
(parent_node_id,$:item).

<div style="width: 100%;">
<table border="0" cellpadding="0" cellspacing="0" align="left" width="100%">
<tr>
{section loop=$programs}
<td valign="top" width="33%">
<div class="heading_2">{$:key}</div>
{* Display 3 most recent items *}
{let publications=fetch(content,list,
hash(parent_node_id,$:item,
class_filter_type,include,
class_filter_array,array(9),
sort_by,array(published,false()),
limit,$publication_limit
)
)
}

A summary of each of the retrieved publications is displayed using the node_view_gui
function with the line view mode. (The use of alternative view modes will be examined
in detail in the next section.)

{section name=Publication loop=$publications}
{node_view_gui view=line content_node=$Publication:item}
{/section}
{/let}
{delimiter}
</td>
<td><img src={"images/spacer.gif"|ezdesign} alt="" width="30"
height="1" border="0"></td>
{/delimiter}
{/section} {* programs *}
</tr>
<tr>
<td colspan="5">&nbsp;</td>
</tr>
<tr>

This process is repeated for all programs defined in the programs array. The
{delimiter} option of the section loop is used to close table data tags and place a spacer
cell between the program columns.
The programs array is then looped again to produce the links to the full listing of
publications for each program:

{section loop=$programs}
<td colspan="2">
<a href={concat('content/view/publication/',$:item)|ezurl}>
<b>Full Listing</b></a></td>
{/section}
</tr>
<tr>
<td colspan="5">&nbsp;</td>
</tr>
<tr>
<td colspan="5"><a href={concat("content/view/allpublications
/",$node.node_id)|ezurl}><b>See all publications listed
alphabetically</b></a></td>
</tr>
</table>
{/let}
</div>

Alternative View Modes
This page uses three additional view modes, one for the summary (line) view of the
publications, one for showing all publications for a specific program (publications),
and one for the full alphabetical view of all publications (allpublications).
As with the Publications page, the template used for each of these cases needs to be
overridden.
In the case of the publication summary (line) view, a combination of the view mode and
the content class ID (9 for publications) is used to determine the template for displaying
the information:

[publication_line]
Source=node/view/line.tpl
MatchFile=publication_line.tpl
Subdir=templates
Match[class]=9

This results in the file design/cfd/override/templates/publication_line.tpl
being used when publications are displayed with the line view mode.
The link that displays a full listing of publications for a specific program will look like
/content/view/publication/16. The system interprets this to display node ID 16 using
the publication view mode.
There is no need to create an override.ini setting for this view mode. It is simply a
matter of creating the design/cfd/templates/node/view/publications.tpl file. The
same applies to the template to display all publications
(design/cfd/templates/node/view/allpublications.tpl).
Content Templates
Finally, the content templates are programmed. These templates determine how each
content type is displayed. They are based on the prototype and are usually a simple
cut-and-paste of the HTML for the mock-up, where the content is replaced with the
appropriate content type attribute variable.
Let's look at the process of creating the template for the Publication content type.
The publication object attributes are defined in the Information Architecture document
and required attributes are marked with an asterisk (*). Refer to the table discussing the
Publication content type, earlier in this chapter.
Admin View of the Publication Content Class
The override system is used to specify the particular template to use when displaying
publication content objects. The following entry tells the system to use the template file
design/cfd/override/templates/publication.tpl when displaying publication
content objects (class_id = 9):

[publication]
Source=node/view/full.tpl
MatchFile=publication.tpl
Subdir=templates
Match[class]=9

The first step is to take the HTML from the prototype and replace the static content with
the appropriate template variables. The HTML from the prototype follows:

<div class="heading_2">Design + Environment: A global guide to designing
greener goods</div>
<div class="heading_3">by Helen Lewis & John Gertsakis with Tim Grant, Nicola
Morelli & Andrew Sweatman</div>
<div class="heading_3">Greenleaf Publishing Limited, Sheffield UK</div>
<div class="heading_3">May 2003</div>
<div class="heading_3">$A50.00</div>
<div class="heading_3"><a href="#">Download order form as PDF file</a></div>
<p><img src="images/sample_publication.gif" alt="" width="175" height="215"
border="0" align="left" hspace="5"></p>
<p>There is a scarcity of good, practical resources for those interested in
minimising the environmental impacts of products. A new book called, Design +
Environment from Greenleaf Publishing, has been specifically written to
address this paucity. The authors - Helen Lewis and John Gertsakis with Tim
Grant, Nicola Morelli and Andrew Sweatman - have all been involved in
EcoReDesign(TM), the innovative program developed by the Centre for Design at
RMIT. The aim of EcoReDesign(TM) is to collaborate with Australian companies
to improve the environmental performance of their products by following design
for environment (DfE) principles. </p>
<p>This clear and informative work will prove to be invaluable to practising
designers, to course directors and their students in need of a core teaching
and reference text and to all those interested in learning about the tools and
trends influencing green product design. The book first provides background
information to assists the reader understand how and why DfE has become so
critical to design. Then, a step-by-step guide is presented on how to design a
product that meets requirements for quality, cost, manufacturability and
consumer appeal, while at the same time minimising environmental impacts.
Environmental assessment tools and strategies are also discussed in detail as
are some of the links between the major environmental problems and the
everyday products we consume. </p>
<p>Four further chapters provide detailed strategies and case studies for
packaging, textiles, furniture, and electrical and electronic products.
Finally, Design + Environment takes a look at some of the emerging trends in
DfE that offer opportunities to significantly reduce environmental impacts.
</p>
<p>Design + Environment is available from the Centre for Design at RMIT.</p>
After replacing the sample content with the appropriate template variables, we end up
with the following code in /design/cfd/override/templates/publication.tpl:
{default content_object=$node.object
content_version=$node.contentobject_version_object}
<div class="heading_2">
{attribute_view_gui attribute=$content_version.data_map.title}
</div>
<div class="heading_3">by
{attribute_view_gui attribute=$content_version.data_map.author}
</div>
<div class="heading_3">
{attribute_view_gui attribute=$content_version.data_map.publisher}
</div>
<div class="heading_3">
{attribute_view_gui attribute=$content_version.data_map.cost}
</div>
<div
class="heading_3">{$content_version.data_map.date.data_int|datetime(custom,"F
%Y")}</div>
<div class="heading_3">
<a href={concat("content/download/",
$content_version.data_map.order_form.contentobject_id,
"/",
$content_version.data_map.order_form.id,
"/file/",
$content_version.data_map.order_form.content.original_filename)|ezurl}>
Download order form as PDF file</a></div>
<p>{attribute_view_gui attribute=$content_object.data_map.image alignment=left
hspace=5 vspace=0 image_class=medium}</p>
{attribute_view_gui attribute=$content_version.data_map.description}
{/default}

The next step is to add some code so that any non-mandatory attributes (and associated
static information such as a label) are not displayed. Mandatory attributes are indicated
with an * in the content type table (refer back to the Content Types section). In this case
only the title, author, and description of content attributes are mandatory. The final code
follows:

{default content_object=$node.object
content_version=$node.contentobject_version_object}
<div class="heading_2">{attribute_view_gui
attribute=$content_version.data_map.title}</div>
<div class="heading_3">by {attribute_view_gui
attribute=$content_version.data_map.author}</div>
{section show=$content_version.data_map.publisher.content}
<div class="heading_3">{attribute_view_gui
attribute=$content_version.data_map.publisher}</div>{/section}
{section show=$content_version.data_map.cost.content}
<div class="heading_3">{attribute_view_gui
attribute=$content_version.data_map.cost}</div>{/section}
<div
class="heading_3">{$content_version.data_map.date.data_int|datetime(custom,"F
%Y")}</div>
{section show=$content_version.data_map.order_form.content}
<div class="heading_3"><a
href={concat("content/download/",$content_version.data_map.order_form.contento
bject_id,"/",$content_version.data_map.order_form.id,"/file/",$content_version
.data_map.order_form.content.original_filename)|ezurl}>
{section
show=$content_version.data_map.order_form_description.content}{attribute_view_
gui attribute=$content_version.data_map.order_form_description}
{section-else}
Download order form as PDF file
{/section}
</a></div>
{/section}
{section show=$content_object.data_map.image.content}<p>{attribute_view_gui
attribute=$content_object.data_map.image alignment=left hspace=5 vspace=0
image_class=medium}</p>{/section}
{attribute_view_gui attribute=$content_version.data_map.description}
{/default}

The order form is a binary file datatype. This code checks whether an order form has
been uploaded as part of the object by checking if there is data in
$content_version.data_map.order_form_description.content. If yes, the
appropriate link is generated. If a description of the binary file is present then the link is
displayed, otherwise the text Download order form as PDF file is displayed:

{section
show=$content_version.data_map.order_form_description.content}{attribute_view_
gui attribute=$content_version.data_map.order_form_description}
{section-else}
Download order form as PDF file
{/section}

Testing whether an attribute is empty is relatively straightforward (and is much easier
now with the introduction of the is_empty function in the current version of eZ publish).
For most attributes, if there is no associated content, the value content (such as
$content_object.data_map.publication.content) is set to false.