Dev:Creating a Content Type

From Habari Project

Jump to: navigation, search



One of the great flexibilities with Habari is that all content types are created equal. This means that if you have a logically distinct aspect of a site in terms of content, you can create a content type to deal with it. Habari ships with two default types; you can work with an Entry or a Page.

This page describes how to create a very basic content type of your own, which you can then use as a base for your own plugins.

Let's Go!

For this how-to, we will use the eventscontent plugin. We'll be using the version compatible with 0.6 of Habari. You can find it via:

For the main part, we'll be working with the eventscontent.plugin.php file.


To satisfy the requirements of a Habari plugin, we have to implement a few methods, and extend the Plugin class. See Creating A Plugin for more information. You'll see that we've implemented the info() method, as well as the optional help() method. That'll do for framework, on to the fun bits.

Creating the type

On plugin activation, we create the new content type. We've called it event. Labels for new content types are converted to lower case, so Event would be equivalent. We'll cover pretty display of the content type name later. We can also deactivate the type when we disable the plugin. By using the Post::add_new_type() method, we ensure Habari creates appropriate permissions for your new content type. We also by default allow anonymous users to view the content. Note that if you change the content type, you need to change it in the grant() call as well as the add_new_type() and deactivate_post_type() methods.

 * Register content type
public function action_plugin_activation( $plugin_file )
  // add the content type.
  Post::add_new_type( 'event' );
  // Give anonymous users access
  $group = UserGroup::get_by_name( _t( 'anonymous' ));
  $group->grant( 'post_event', 'read');
public function action_plugin_deactivation( $plugin_file )
  Post::deactivate_post_type( 'event' );

Viewing the type

There's no point making a type if nobody can use it. So let's register the template type (called on each Habari invocation, and used when choosing which template file to use), and also tell the system to check for that kind of type when collecting posts for the blog page in the first place.

public function action_init()
  // Create templates
  $this->add_template('event.single', dirname(__FILE__) . '/event.single.php');
public function filter_template_user_filters($filters) {
  if ( isset($filters['content_type']) ) {
    $filters['content_type'] = Utils::single_array( $filters['content_type'] );
    $filters['content_type'][] = Post::type('event');
  return $filters;

Making the type a bit special

There's no point making a type, if you're not going to do something with it. One of the first things you might like to do is add some extra fields to access when theming or editing data.

We're going to add an address field, because like all good events, we have an awesome venue to hold it at. You might want to add a field about the event date, or perhaps a contact person. Whatever you like.

 * Modify publish form. We're going to add the custom 'address' field, as we like
 * to hold our events at addresses.
public function action_form_publish($form, $post, $context)
  // only edit the form if it's an event
  if ($form->content_type->value == Post::type('event')) {
    // just want to add a text field
    $form->insert('tags', 'text', 'address', 'null:null', _t('Event Address'), 'admincontrol_textArea');
    $form->address->value = $post->info->address;
    $form->address->template = 'admincontrol_text';
 * Save our data to the database
public function action_publish_post( $post, $form )
  if ($post->content_type == Post::type('event')) {
    // Address exists because we made it in action_form_publish()
    $post->info->address = $form->address->value;

Some nice text things

Okay so now we've registered the type, and the template files. Let's do some tidying up. First we make the menus and other things show a nice capitalized display:

public function filter_post_type_display($type, $foruse) 
  $names = array( 
    'event' => array(
      'singular' => _t('Event'),
      'plural' => _t('Events'),
  return isset($names[$type][$foruse]) ? $names[$type][$foruse] : $type; 

Adding Additional Properties

Your content type will often have special properties (such as the address example used above). Though these can be accessed using the ->info property it is often better to provide a virtual property, which is safer for the future and abstracts the location. To do so, simply implement the post_* filter, where * is the property name.

public function filter_post_address($address, $post) {
	if($post->content_type == Post::type('event')) {
		return $post->info->address;
	else {
		return $address;

Once implemented the property can be called on any post like a normal property.

echo $post->address;
echo $post->info->address; //same as above

Other bits

Add in Beacon support so your users can be notified when you update your plugin. Remember to add your own guid. There are lots of online resources for this, or you can use JibbyBot on IRC.

public function action_update_check()
  Update::add( $this->info->name, '<insert your own guid here>', $this->info->version );

From here?

You might want to register some other hooks to do things when the page is rendered. Maybe you want to combine it with a media type (check out silos), or maybe you want to give specific permissions for other groups. Have fun exploring it.


This plugin is based on the linkblog plugin.

BigJibby saved my hair in IRC.

Personal tools