Dev:Creating A Theme

From Habari Project

Jump to: navigation, search

Habari supports a powerful and flexible way to create custom themes, and this article describes in detail how to create one.

A good way to get started is to use the default K2 theme or one of the other available themes as a reference. Create a new directory in /user/themes/ for your new theme, and put all of your theme files in this directory. The minimum requirement for a theme is an XML file that describes the theme, and some template files, with a minimum of the home.php template. Themes may also optionally—and almost always will—include a file called theme.php, which is used to customise theme behaviour. Themes may also include a screen shot to be shown on the Admin | Themes page. The screen shot should be in png, jpg, or gif format, and be 150px high by 200px wide for optimal display (or some 3:4 ratio, as the image will be resized to those dimensions). The screen shot should be named screenshot.file_type, i.e., screenshot.png.

There is a glossary which defines common terms you'll encounter when working with Habari themes.



The first step in creating a custom theme is to define it's basic properties in theme.xml within the theme's base directory. These properties will be used to identify the theme to users, give you credit, and appropriately version the theme through its life. The following table the elements that should be included in your theme's XML.

name The name of the theme.
author Author's name or whomever is being credited with the design.
url Location at which the theme can be found.
version Current version of the template
description A description of the template
template_engine The template engine that the theme uses.

Example theme.xml

<?xml version="1.0" encoding="UTF-8" ?>
<pluggable type="theme">
        <author>K2 Team</author>
        <description>A port of the popular design K2 and first Habari "theme"</description>

<class>node is optional, which is only needed when you override core Theme class.

You can now visit your Admin -> Themes page and activate your new theme, however, if you visit your site you will be presented with a blank page. This is because as yet there are no templates, so Habari does not know how to display anything.


This optional file can be part of your theme. By including it, you can provide additional functionality to your theme. If you do not include it, the core theme functions will be used.

The theme.php file should contain a class that extends Habari's own Theme class. This class can be used to override Habari's default behaviour and to define functions that your theme can call. For example, you might define a function to format tags in a particular way. See Customizing Theme Behavior for more information.

The instance of your custom theme class — or the default theme if you have not defined your own — is available in your theme as the $theme variable. Thus, functions you define in your theme class can be called as $theme->my_function().

A custom theme class has all of the same abilities as a plugin. If you add functions in the theme class that use the plugin prefixes (filter_, action_, etc.), Habari will treat them as though they were in an active plugin. Only the current theme's theme class will have functions like this enabled.

Template Files

Habari has flexible template support, allowing you to customise any aspect of a how a blog is displayed. The way that the templates are processed is dependent on the template engine being used. More information can be found at Template Engines.

Templates using the RawPHPEngine are simply HTML files with embedded PHP. While you can use any code you like in your templates, you should try to keep the templates as simple as possible. Ideally, complex code should be located in theme.php and the output included in variables, which you simply echo in your template.

Most themes will include a number of different templates, each being called in different circumstances. This section will describe some of the most common template files. Note that this is far from an exhaustive list of templates recognized by Habari. In fact, Habari will use templates as specific as for a particular post id or date. See Template File Hierarchy for information on how Habari decides what template to use when displaying particular content.

Remember to add: <?php if ( !defined( 'HABARI_PATH' ) ) { die('No direct access'); } ?> on the first line of every file.


This template is used to display the front page of the blog. Usually, this template will display the most recent blog entries.


This template is used to display a single post, no matter what it's content type. A theme developer may choose not to use this template but instead have specific templates for a content type, such as entry.single.php.


Similar to single.php, this template is used when multiple posts are to be displayed, no matter what the content type. This means that this template might be displaying entries and pages on the same page. Again, a theme developer may choose not to include this template but to use specific templates, such as entry.multiple.php.


The tag.php template is used for displaying queries for a specific tag. By default, using the $post->tags_out variable, tags are linked to display such a query.


The search.php template is used when displaying the results of a search. As with multiple.php, posts may be any content type, so this template will display a mixture of entries and pages on the same page.


The 404.php template is used as a fall back when attempting to serve a post or page that the site can not find. The template can contain any type of information, including calling a search form, a list of tags, or simply a message notifying the visitor that they've reached a bad URL.


The login.php template is an option for themers to add if they want to customize the login screen for registered users to match the active theme. Depending on the theme design, this template can either call an internal template loginform.php or contain the code directly, depending if the designer wants the login in multiple locations. If no login.php template is provided, Habari uses a default login screen.

Internal Templates

Themes can also include internal templates for common code that are never called directly by Habari. For example, if your theme has a sidebar that should be displayed on every page, you could have a template called sidebar.php. You can simply call include sidebar.php in the appropriate place in each template to display the sidebar, however, the ideal way to include these ancillary templates would be to use $theme->display ('sidebar'); or what ever template it is you are looking to include. This allows for plugins to do things with the template that a regular include would not. Other examples templates that your theme might include are templates for the header and footer. Other common internal templates would be searchform.php, commentform.php and the aforementioned loginform.php.

The "assets" Directory

Themes may provide a sub-directory named "assets". Within this directory, theme authors can place css and js files, which will be automatically added (in alphabetical order) to the appropriate stacks for output. Only files with the extensions ".css" and ".js" will be added this way, but it is possible to register more file extensions to the same and other stacks.

To add other file extensions to other stacks, the code similar to the following should be added to the theme class or a plugin:

	public function action_template_header_10()
		$assets = $this->load_assets();
		foreach($assets['less'] as $less) {
			Stack::add('template_stylesheet', array($less , 'screen,projection,print', array('rel' => 'stylesheet/less')));

The above code adds files with the extension ".less" to the template_stylesheet stack, outputting them with the appropriate rel value for use with a LESS javascript processor. In the code, $assets is assigned a multi-dimensional array. Each array within the array is a list of files from the assets directory with an extension of the top-level array key. For example, $assets['less'] contains an array of files with ".less" extensions, whereas $assets['foo'] contains an array of files with ".foo" extensions, etc.

Note that the priority of this action is set to 10, which prevents it from interfering with some internal processes that automatically register the .css and .js files from the assets directory.

Plugin Output

It's likely that you'll want your theme to display output from plugins, if those plugins are active. Habari provides a number of ways of doing this.

Areas and Blocks

Themes can include "areas" in their templates that user-defined "blocks" of output will be displayed. A Block can be provided by a theme or plugin via code and can be placed into any area that the theme provides on the themes page in the Habari admin. Blocks are very configurable, and can be templated in many ways to produce ideal output in your theme.

For a more complete description of the implementation, see the Areas and Blocks pages.

Theme Functions

The best way to output specific direct values from plugins is to use theme functions. These are special functions that let theme developers safely insert content returned by plugins. If the theme function is called from a template, and a plugin that supplies that function is not active, nothing will output and the theme will ignore the function; no error will be generated, and there is no need to check if a specific plugin exists or the function intended to produce that output is present. More detail can be found under Dev:Theme Functions.

Using theme functions for direct output of data is strongly advised because:

  • Calling a theme function from a theme will not generate an error if the function is not defined by a plugin.
  • Other plugins can modify the output of a theme function before it is rendered -- for example, to apply additional styles/markup to the output.
  • Multiple plugins can provide different implementations of the same function -- for example, two different plugins could provide the $theme->tag_cloud() function, but the output would be different.


It is strongly advised that plugins not output content directly. Doing this makes it nearly impossible to override or modify the content that is output, and produces a non-standard way of interacting with the Habari code.

It is strongly advised that themes not check for loaded plugins on which to offer specific functionality. By checking for specific plugins, themes eliminate the possibility of using other plugins to provide similar features that might be more desirable to the site administrator than the plugin the theme requires. Using theme functions or areas/blocks offers a better way to implement dynamic features based on what plugins are available to the site.

For example, if a theme checks for a plugin named "Moxy's Tag Cloud", then only the plugin named "Moxy's Tag Cloud" will be supported. Any other tag cloud plugin could be suitable, but compatibility with them is stifled because the theme only checks for that one plugin. If the "Moxy's Tag Cloud" plugin goes out of date, or has security issues, that makes it more necessary to use something else, and would perhaps require the site administrator to enable a different theme.

If all else fails, it is possible to check if the plugin is loaded and call its functions from your templates. Checking that a particular plugin is loaded is illustrated here by looking for an active plugin named "pingback". (A more complete example demonstrating the active condtion). The is_loaded() function can also take a second parameter that specifies a particular version of the plugin.

<?php Plugins::is_loaded('pingback'); ?>

If you find yourself doing the above, you should perhaps instead ask questions via the mailing list or IRC how you might use one of the other methods described here to produce output.

Variables Available to Custom Themes

In addition to the $theme variable that holds a reference to the theme, other variables available to theme developers are described in the table below.

Variable Description
$template The name of the template Habari has chosen for display.
$template_file The full path to the template Habari is using for display.
$matched_rule An object representing the rewrite rule that was matched to transform the requested URL.
$request An object representing the original request.
$posts An object that holds the posts that are available for display. Individual post objects can be accessed through this variable.
$page The current number being displayed. For example, if multiple posts have been returned in response to a request, these may be spread across several pages.

Content Output

There are two methods of outputting posts within themes. The first method is to directly call the $post or $posts object. However, this does not allow plugins to provide new content types. The alternate method simply involves calling the $theme->content($post, $context) method, which will output the appropriate template.

<?php foreach($posts as $post): ?>
	<?php echo $theme->content($post, 'multiple'); ?>
<?php endforeach; ?>

This will select the most accurate template (which can be provided by the theme or a plugin) and output it. At the very least, you should include a post.php template. The hierarchy of selecting the appropriate template is as follows:

  1. {context}.{type}
  2. {context}.{class}
  3. {context}.content
  4. {type}
  5. {class}
  6. content
  7. {context}

Where {type} is the type of post (eg. "entry" or "page"), {class} is the actual class used for storage (usually "post"), and {context} is the provided context in the call to ->content().

Plugin and theme developers should be careful not to use context names that are the same as names Habari uses internally, since this can lead to unexpected behaviors.

Returned Items

By default, Habari will return 5 items per page. This can be changed within the Admin | Options page.

This setting affects all blocks of returned items, be it on the homepage, search results, or tag results.

The number of items included in the feed also defaults to 5 items per page. This can be changed on the Admin | Options page.

Customizing forms

Habari includes a form engine that separates a form's required arguments from its "view". It functions by configuring a FormUI object, and relying on PHP templates to output the HTML code. Default templates can be found in the system/admin/formcontrols folder, and are prefixed by formcontrol_.

The big advantage of using FormUI is that it neatly separates the arguments that a form requires from the HTML code generation. This makes forms easy to extend with plugins.

Since version 0.7, comment forms in themes must use FormUI. See Adding a Comment Form for how to work with the comment form.

Here are some things that you can do with it:

Replacing the form template used for comments:

  • Create a new php file, or use the formcontrol_form.php default template as a basis and copy it, in the theme folder.
  • Register the template with your theme - theme.php file, action_init() method:
$this->add_template( 'html5_form', dirname(__FILE__) . '/formcontrol_form.php' );
  • Set the comments form to use the template you just specified - theme.php file, action_form_comment( $form ) method:

Adding a field with personalized parameters:

  • Determine which template file you are going to use - and take note of the parameter names you're going to use. (Let's say you're going to use $parameter1 in the php template)
  • If the template is one of the default ones, then it is already registered - just note its name. ('formcontrol_thing')
  • If the template is not default, then put the php file in the theme folder and register it - theme.php file, add_template_vars method:
$this->add_template( 'formcontrol_thing', dirname(__FILE__) . '/your_template_filename.php' );
  • Add the following code in the theme.php file, action_form_comment( $form ) method:
$form->append( // That line adds the new parameter to the form - if the parameter already exists, you may want to skip it.
'text', // A type of input - it can at least take the values of 'text' or 'textarea' or 'hidden'
'yourfield' // The name of the  - will be used afterwards when you'll modify it later
'null:null', // I'd guess it is the default value
'Your Field', // The caption for the parameter
'formcontrol_thing' // The template that will be to generate the field.
// You can modify the above parameters later.
$form->yourfield->template = 'formcontrol_thing';
$form->yourfield->caption = 'Your awesome field';
// You can add new parameters that will be available when the template is executed.
$form->yourfield->parameter1 = 'whateveryouwant';
Personal tools