Create a simple blog site using eZ Publish

We'll create a Simple Blog Site from scratch using the eZ Publish CMS.

If you didn't come across eZ Publish yet it would be useful to familiarize yourself with both installation of eZ Publish and with first steps after an installation (post includes basics of creating a extension).

In this post I'll start with a "Plain Site" eZ Publish installation, because it's easier to explain some concepts that way, but if you already have another installation it really doesn't matter because we'll make our own design, templates and classes.

Preparing for work

Open your favorite PHP editor (I use Eclipse with PDT plugin) and create a new Project. In Eclipse you can select the option "Create project at existing location (from existing source)" and then choose the folder where you extracted eZ Publish.

Let's disable ViewCaching and TemplateCache.

Open the /settings/override/site.ini.append.php file and at the end of file add these lines:

[TemplateSettings]
TemplateCache=disabled
TemplateCompile=disabled 
 
[ContentSettings]
ViewCaching=disabled
StaticCache=disabled

Let's also disable design location cache in the same file:

[DesignSettings]
DesignLocationCache=disabled

OK, now we're ready to get started.

Creating a custom extension

Inside extension folder create a new folder named simpleblog. You can use Eclipse to do this. Simply right-click on extensions folder and choose New -> Folder.

Make a structure like this:

simpleblog
    - design
        - simpleblog
            - images
            - javascript
            - stylesheets
            - templates
    - settings

Just follow the illustration and you won't get lost. Now inside settings folder create two new files: design.ini.append.php and site.ini.append.php.

Open design.ini.append.php and modify it to contain:

<?php /* #?ini charset="utf-8"?
 
[ExtensionSettings]
DesignExtensions[]=simpleblog
 
*/ ?>

site.ini.append.php:

<?php  /* #?ini charset="utf-8"?
 
[TemplateSettings]
ExtensionAutoloadPath[]=simpleblog
 
[RegionalSettings]
TranslationExtensions[]=simpleblog
 
[FileSettings]
VarDir=var/simpleblog
 
*/ ?>

After this, inside the templates folder create a new file called pagelayout.tpl. In order to avoid changing the main template of eZ Publish, we've created a new main template, just for our design.

Edit the pagelayout.tpl template like this:

<!DOCTYPE html>
 
<html lang="{$site.http_equiv.Content-language|wash}">
    <head>
        <title>Simple Blog Site</title>
    </head>
    <body>
        {$module_result.content}
    </body>
</html>

Activate our design extension. Open the /settings/override/site.ini.append.php and add the new extension to the list of active extensions:

[ExtensionSettings]
ActiveExtensions[]
ActiveExtensions[]=ezjscore
ActiveExtensions[]=ezie
ActiveExtensions[]=ezoe
ActiveExtensions[]=ezodf
ActiveExtensions[]=simpleblog

Open the /settings/<siteaccess>/site.ini.append.php where is a name of your siteaccess and change the Site Design like this:

[DesignSettings]
SiteDesign=simpleblog
AdditionalSiteDesignList[]=base

Delete cache via admin interface or manually delete the cache folder located inside the /var folder and refresh the site. You should get something like this:

Basic styling

Let's just improve our main template. Change it to this:

<!DOCTYPE html>
 
<html lang="{$site.http_equiv.Content-language|wash}">
    <head>
        {section name=css loop=ezini( 'CssSettings', 'CssList', 'design.ini' ) }
            <link href={concat( 'stylesheets/', $:item )|ezdesign} rel="stylesheet" type="text/css" media="all" />
        {/section}
        <!--[if IE]>
            <link rel="stylesheet" type="text/css" href={"stylesheets/ie.css"|ezdesign} media="all" />
        <![endif]-->
 
        {section name=JavaScript loop=ezini( 'JavaScriptSettings', 'JavaScriptList', 'design.ini' ) }
            <script type="text/javascript" src={concat( 'javascript/', $:item )|ezdesign}></script>
        {/section}
         
        {include uri='design:page_head.tpl'}
    </head>
    <body>
         
        <div id="outer">
             
            <div id="wrap">
                 
                {include uri='design:parts/header.tpl'}
                 
                <div class="container">
                     
                    <section id="sidebar">
                        {include uri='design:parts/leftmenu.tpl'}
                        {include uri='design:parts/aside.tpl'}
                    </section>
                     
                    <section id="main">
                        {$module_result.content}
                    </section>
                    <div class="clear"> </div>
                     
                </div>                
            </div>
             
            {include uri='design:parts/footer.tpl'}
             
        </div>
         
    <!--DEBUG_REPORT-->
    </body>
</html>

This is the final design of our main template. We'll use external files to store header, left menu, side box and footer code, same if we were using PHP includes. Simple.

Time for styling! And to style something we need CSS files, right?

In the main template we said: read the CSS & JavaScript file list from a design.ini.append.php file. The sections are named JavaScriptSettings and CssSettings, and the arrays are JavaScriptList and CssList.

One thing to note are template operators, such as ezdesign. This operator "Returns the input string prepended with the current design directory.", which means we don't need to hardcode the path to our design files.

Let's add that file to our design extension. You can copy it from the /settings/<siteaccess>/ folder to our /extension/simpleblog/settings/ folder. Then edit the file to look like this:

<?php /* #?ini charset="utf-8"?
 
[ExtensionSettings]
DesignExtensions[]=simpleblog
 
[JavaScriptSettings]
JavaScriptList[]=jquery-1.7.min.js
 
[CssSettings]
CssList[]=main.css
CssList[]=style.css
 
*/ ?>

You might wonder why use settings file for a single javascript file and two CSS files. It's simple. First, it's not a very good practice to hardcode anything into template you don't have to, and secondly we want to learn how to do something, don't we? While we're on it, we won't even use jQuery but we added it as an example. :)

Remember: after you change the CSS files you should delete the cache.

Create the CSS files needed, named main.css and style.css inside the stylesheets folder. You know, the /extension/simpleblog/design/simpleblog/stylesheets.

OK, main.css will contain basic styling of elements. This is the main.css:

@CHARSET "UTF-8";
 
/********************************************************
    CSS Reset & Global
*********************************************************/
  
body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p, blockquote,th,td {
    margin:0;
    padding:0;
}
fieldset,img {
    border:0;
}
address,caption,cite,code,dfn,em,strong,th,var {
    font-style:normal;
    font-weight:normal;
}
ol,ul {
    list-style:none;
}
h1,h2,h3,h4,h5,h6 {
    font-size:100%;
    font-weight:normal;
}
  
/* HTML 5 Elements */
  
header, section, aside, footer, article {
    display: block;
}
 
/*********************************************************
    Styling the layout
 *********************************************************/
  
html {
    height: 100%;
}
  
body {
    height: 100%;
    font-family: Arial, Helvetica, sans-serif;
}
 
strong {
    font-weight: bold;
}
 
#outer {
    min-height: 100%;
    position: relative;
    font-size: 14px;
    line-height: 18px;
}
  
#wrap {
    padding-bottom: 200px;
}
 
header {
    height: 160px;
    border-bottom: 1px #000000 solid;
    background-color: #1E4C6D;
}
  
.container {
    width: 960px;
    margin: 0 auto;
}
  
section#main {
    float: left;
    width: 660px;
    padding: 30px 0;
}
  
section#sidebar {
    float: left;
    width: 270px;
    padding: 30px 30px 0 0;
}
 
section#sidebar aside {
    margin-top: 30px;
}
 
.clear {
    clear:both;
}
 
/*********************************************************
    Footer
 *********************************************************/
 
footer {
    border-top: 1px #000000 solid;
    background-color: #A65419;
    position: absolute;
    bottom: 0;
    width: 100%;
    height: 125px;
    color: white;
    font-size: 1em;
}
 
footer .container {
    padding-top: 30px;
}
 
footer .copyright {
    float: right;
}
 
footer h2 {
    font-size: 22px;
    color: #FFF5C9;
}
 
footer p {
    font-size: 14px;
    line-height: 20px;
}

Let's do style.css to add some colors to our site:

@CHARSET "UTF-8";
 
/*********************************************************
    Menu
 *********************************************************/
  
nav ul li a {
    background-color: #1e6190;
    border-bottom: 1px solid #1E4C6D;
    display: block;
    color: white;
    padding: 12px 15px;
    text-decoration: none;
 }
  
nav ul li.current a {
    background-color: #a65419;
}
  
 nav ul li a:hover {
    background-color: #7e2376;
 }
  
 /*********************************************************
    Layout sizes & colors
 *********************************************************/
  
header h1 {
    font: 35px Arial, Helvetica, sans-serif;
    padding-left: 50px;
    padding-top: 35px;
    color: #FFF5C9;
}
 
header h2 {
    font: 16px Arial, Helvetica, sans-serif;
    color: #FFFFFF;
    padding-left: 50px;
}
  
h1 {
    font: 25px Arial, Helvetica, sans-serif;
    color: #7e2376;
    margin-bottom: 10px;
}
  
h2 {
    font: 20px Arial, Helvetica, sans-serif;
    color: #414141;
    margin-bottom: 10px;
}
 
section#main p {
    margin-bottom: 15px;
}
 
section#main a {
    color: #1e6190;
    text-decoration: none;
}
  
section#main a:hover {
    color: #7e2376;
}
  
section#sidebar aside h1 a {
    color: #d36111;
    text-decoration: none;
}
  
section#sidebar aside h1 a:hover {
    color: #2469d1;
}
 
 /*********************************************************
    Blog posts & Images
 *********************************************************/
 
.right {
    float: right;
    margin-left: 25px;
}
 
.blog {
    margin-top: 31px;
    line-height: 18px;
}
 
.post {
    font-size: 14px;
    float: left;
    width: 384px;
}
 
.post {
    font-style: italic;
    color: #414141;
    margin-bottom: 25px;
}
 
.post a {
    font-weight: bold;
    color: #993300;
    text-decoration: none;
}
 
.post a:hover {
    color: #d36111;
}
 
a.post-photo {
    float: left;
    border: 1px #1E4C6D solid;
    background-color: #1e6190;
    padding: 2px;
    margin-right: 32px;
}
 
a.post-photo:hover {
    background-color: #7e2376;
    border: 1px solid #000000;
}
 
a.post-photo img {
    display: block;
    border: 1px #d36111 solid;
}

That's it. Basic styling is complete! Hit F5 and see what we got:

Adding the folder template

eZ Publish uses something called Automatic fallback system.

That basically means that eZ Publish will first look in the main design for a specific file and if it doesn't find it, it will look into other „designs”. So, like we created new pagelayout.tpl inside our extension for eZ Publish to use, we can do the same with other files.

Inside the /extension/simplebog/ folder create a new folder named override. Inside that folder create a new folder named templates and inside that folder create another named full. Inside the full folder create a new file named folder.tpl.

Just follow the illustration:

-   design
-       simpleblog
-           images
-           javascript
-           override
-               templates
-                   full
-           stylesheets
-           templates
-               parts
-   settings

The contents of the new file folder.tpl are pretty simple:

<h1>{attribute_view_gui attribute=$node.data_map.name}</h1>
 
{if $node.object.data_map.description.has_content}
    {attribute_view_gui attribute=$node.data_map.description}
{/if}

Why did we do that? Because it's more clean than altering original eZ Publish files and because for our simple example we don't really need a complex template. Now, let's continue and create some content for our website.

NOTE: We can access all the attributes the object has via data_map method. We use the attribute_view_gui function to display the formatted output of a attribute.

Creating About & Blog „folders”

Login to the eZ Publish admin interface and switch to Content Structure tab.

There click the "Create new" button and choose Folder. A editor will open. Name the folder "About Me" and enter some text. When you're done click "Send for publishing".

In the same manner create the "Blog folder" and add some content.

Adding other template files

It's time to continue with our little design.

Go to templates folder and create a parts subfolder. Inside the parts subfolder create four .tpl files:

  • header.tpl
  • leftmenu.tpl
  • aside.tpl
  • footer.tpl

We'll do them one by one. First, the header.

Header

Our header file (header.tpl) is pretty simple. It's just static HTML. It goes like this:

<header>
    <h1>Simple Website</h1>
    <h2>powered by eZ Publish</h2>
</header>

Footer

Once again, just static HTML:

<footer>
    <div class="container">
        <div class="copyright">
            <h2>Copyrights & Links</h2>
            <p>Nothing is © Everything is FREE</p>            
        </div>
         
        <h2>My web site</h2>
        <p>No rights reserved.</p>
    </div>
</footer>

Aside

This one is my favorite:

<p>This is not so important ...</p>

Left Menu

Finally, let's code something. We'll use eZ Publish template fetch functions. Here's our menu:

{def $home = fetch( 'content', 'node', hash( 'node_id', 2 ) )}
{def $menu_items = fetch( 'content', 'list', hash(  'parent_node_id', 2,
                                                    'class_filter_type', 'include',
                                                    'class_filter_array', ezini( 'MenuSettings', 'LeftMenu', 'menu.ini' ) ) )}
<nav>
    <ul>
        <li{if eq($home.node_id, $module_result.node_id)} class="current"{/if}>
            <a href={$home.url_alias|ezurl}>{$home.name|wash}</a>
        </li>
        {foreach $menu_items as $key => $item}
            <li{if eq($item.node_id, $module_result.node_id)} class="current"{/if}>
                <a href={$item.url_alias|ezurl}>{$item.name|wash}</a>
            </li>
        {/foreach}
    </ul>
</nav>

Here we used template fetch function to fetch a node (eZ Publish root folder node) and a list of nodes that are children of our root node. We then used those nodes to create our menu.

It's not that hard. For home page we created a new link and used another of our template operators, this time to create the link to the home page.

We compared the node_id of our fetced node with the node_id of currently viewed node. If they're the same we add class "current" to the list-item that contains the link to home page.

Same thing we did with the children, only here we used a foreach loop to build the list items and links.

If you refresh the page now, you'll see there's only our home page (named eZ Publish) in the menu. Why?

Because if you look at the code you'll notice there's one thing missing.

Adding the menu.ini.append.php file

As you can see, we used template operator ezini to return the array of classes that can be used inside our menu.

So, let's create that file. Open the /extension/settings/ folder and inside it create a file named menu.ini.append.php with these contents:

<?php  /* #?ini charset="utf-8"?
 
[MenuSettings]
LeftMenu[]=folder
 
*/ ?>

So, when you save the file and delete the cache, refresh the page too see what we got.

If you try to browse the content you'll see that the links work and the site shows the content we entered via admin interface.

Creating the blog class

OK, it's time to make our Blog functional. To do that we'll need to have a list of blog posts which includes a short introduction and a link to a full article.

First step is to create our own content class for blog posts so we can then create them via admin interface as simple as we create "folders" now. So, let's get started. Open eZ Publish site admin.

Once you're in admin go to: Setup (tab) -> Classes -> Content. There click on a New class button.

The class editor will open. Name the new class Blog Post and in the "Identifier" field enter blogpost.

For description enter anything you want, or if you want, you can leave it empty. Leave empty the Object name pattern and URL alias name pattern.

Leave the Container and Default object availability unchecked.

From the drop down menu select Text line and click the "Add attribute" button. Another part of the form will show where you can enter the class attribute. Add the following attributes to our class:

  1. Title [Text line], Identifier: title, required, Searchable
  2. Published [Date and time], Identifier: published, Required, Searchable, Default value: Current datetime
  3. Introduction [Text block], Identifier: introduction, Required, Searchable
  4. Article [XML block], Identifier: article, Required, Searchable
  5. Image [Image], Identifier: image, Required
  6. Image show [Checkbox], Identifier: imageshow, Not required, Not Searchable

After you add all the attributes click OK to save the class.

Adding the Blog posts

We can simply add new "Blog Posts", same as we added folders before. In the site admin switch to the Content structure. Now go to the Blog folder and inside the + Create new you'll find "Blog Post".

To create a new blog post simply fill out all the required fields and click "Send for publishing". Of course, editing the blog post is also an easy task with eZ Publish:

Add few blog posts so we have some content to display.

Template override for Blog Posts listing

Let's make a page to display the list of available blog posts.

To do that we'll make a template override. As the documentation states, "template overrides are typically useful for displaying different types of nodes in different ways." We'll do just that. We'll make an override for a blog folder, meaning when a user visits the blog link our template override will be used instead of standard folder.tpl we created at the beginning.

First, we need to find out the Node ID of the Blog folder. We'll do that via the admin interface. Simply go to Content structure and click on the Blog folder. Right beneath the Folder name Node ID will be specified. The text goes something like this:

Last modified: 11/16/2011 08:52 pm, Administrator User (Node ID: 60, Object ID: 58)

So, now we know Node ID. Of course, you have to use yours and not 60 like me. Open the /settings/siteaccess/<siteaccess_name>/override.ini.append.php file and add the following on top of the file:

[blog_list]
Source=node/view/full.tpl
MatchFile=blog.tpl
Subdir=templates
Match[node]=60

This override rule states: If the source is full.tpl and Node ID is 60, then use blog.tpl template. After we save the file we need to delete the cache.

Listing the Blog Posts

Open /extension/simpleblog/override/templates/ folder and inside it create a file named blog.tpl.

This is the code for blog.tpl:

<h1>{attribute_view_gui attribute=$node.data_map.name}</h1>
 
{if $node.object.data_map.short_description.has_content}
    <div class="attribute-long">
        {attribute_view_gui attribute=$node.data_map.short_description}
    </div>
{/if}
 
{def $per_page = 2}
{def $count=fetch( 'content', 'list_count', hash(   'parent_node_id', $node.node_id,
                                                    'class_filter_type', 'include',
                                                    'class_filter_array', array('blogpost') ) )}
 
{def $posts=fetch( 'content', 'list', hash( 'parent_node_id', $node.node_id,
                                            'class_filter_type', 'include',
                                            'class_filter_array', array('blogpost'),
                                            'sort_by', array( 'attribute', false(), 'blogpost/published' ),
                                            'offset', $view_parameters.offset,
                                            'limit', $per_page  ) )}
 
{foreach $posts as $p}
     
    <div class="blog">
        <a class="post-photo" href={$p.url_alias|ezurl}>{attribute_view_gui image_class="medium" attribute=$p.data_map.image}</a>
        <h1><a href={$p.url_alias|ezurl}>{$p.name|wash}</a></h1>
        <div class="post">
            <p>{attribute_view_gui attribute=$p.data_map.introduction}</p>
            <p><a href={$p.url_alias|ezurl}>Continue reading</a></p>
        </div>
    </div>
    <div class="clear"> </div>
     
{/foreach}
 
{include name=navigator
         uri='design:navigator/google.tpl'
         page_uri=$node.url_alias
         item_count=$count
         view_parameters=$view_parameters
         item_limit=$per_page}

The code may look complicated, but it isn't really. First part is the same as normal folder.tpl template, just show the title of the folder and if folder has a short description also show that.

Then we define the variable per_page which we'll use later.

After that we'll count the total number of posts using the list_count fetch function.

We need the limit of posts per page and total number of blog posts to include the eZ Publish pagination to our blog template and to have the pagination of our blog posts list.

We used template fetch list function to get a list of Blog Posts. Note that we used offset and limit parameters to control how many nodes we want and at which offset the fetch should start.We used the class_filter_type and class_filter_array to limit our fetch to only Blog Posts.

After that, (similar to stuff we did in the menu) we used foreach loop to write out the list of blog posts and to create the links to their details.

Lastly, we included eZ Publish template for pagination. The beauty of including pagination template is that we get the correct pagination links for our Blog Posts list if we provide the right parameters (which we did, with $count for total number of posts and $per_page for number of items per page).

Refresh the Blog page to see what we got:

Blog post details

OK, we need to make a template that will show the details of our blog post when users click on it.

To do that we'll once again use template override.

Open our well-known /settings/siteaccess/<siteaccess_name>/override.ini.append.php file and add the following at the top:

[blog_details]
Source=node/view/full.tpl
MatchFile=blog_details.tpl
Subdir=templates
Match[class_identifier]=blogpost

This override rule basically tells eZ Publish to use the blog_details.tpl template whenever user accesses the blogpost class. In short, whenever a user clicks on a blog link, blogpost class is used and then blog_details.tpl will be shown.

So, let's create that file at the same place where we created the blog.tpl file -> /extension/simpleblog/override/templates/.

The content of our blog_details.tpl file:

<h1>{attribute_view_gui attribute=$node.data_map.title}</h1>
<p>
    Published on: 
    <strong>{$node.data_map.published.content.timestamp|datetime('custom', '%F %d, %Y.')}</strong>
</p>
 
{if eq(1, $node.data_map.imageshow)}
    {attribute_view_gui attribute=$node.data_map.image css_class="right"}
{/if}
 
{attribute_view_gui attribute=$node.data_map.article}

As you can see, it's basicall pretty simple. There's an <h1> containing our title, and after that there's the date formatted with the datetime operator.

NOTE: we didn't use the attribute_view_gui function to display the "published" attribute, but instead we went "all the way down" to raw timestamp and used that to format our output.

Delete the cache and then click on a Blog Post link to see it's details:

Summary

eZ Publish CMS enables us to build our own content classes and gives us a great deal of control over the display of our content.

The extension and template system gives us the opportunity to add our own content views and application logic without the need for editing it's core files.

In this post we created a simple blog site from scratch, proving that it's not very difficult to get started with eZ Publish. In some future post we'll dig even deeper and use PHP together with eZ Publish template language to do stuff with our content.

Thanks for visiting this site and until next time I wish you all the best!

Comments are closed