Setting up dynamic themes on Kohana


It’s been a little over six months since I first began to use Kohana framework for all PHP development, and I thoroughly love the system. The only issue I’ve had with Kohana is the lack of built in, intuitive support for dynamic themes. I was unable to find an easy method to set up a theme that automatically wraps itself around all pages, while remaining dynamic enough to change certain elements on a page to page basis.

Over the past few days, I have been exploring methods to do this, with the following requirements:

  • Keep all theme files separate from the application
  • Require no changes to existing controllers and views to implement or change a theme
  • Allow multiple applications on the same Kohana build to use the same theme
  • Provide support for cascading themes

After a few failed attempts, I have found a solution that covers all four requirements and is pretty easy to implement. Of course, it is easier to implement this from the start, but if you have an existing Kohana site, it shouldn’t be too difficult to integrate this theming setup into the site. The concept of the theme is simple: create a theme as a module and then use hooks to implement the theme elements as appropriate.

Step 1 – Enable hooks

Without hooks, this theming set up won’t be able to execute at the proper time, and timing is essential. In order to enable hooks, open up application/config/config.php and change $config['enable_hooks'] to TRUE. With hooks enabled, all files within a hooks directory are included. This will be the starting point for inserting the theme content around the template.

Step 2 – Create a theme folder

One of my stated goals for the theme was to keep all theme files inside a single folder. This encapsulation allows for very easy modification, copying and replacing of themes. Make a folder called themes, and a subfolder named after the theme. This theme folder will operate just like a module folder, containing config, controllers, hooks, views, etc. My directory tree now looks like this:

/httpdocs
    /application
    /modules
    /system
    /themes
        /visual77
            /config
            /controllers
            /css
            /hooks
            /images
            /views
    /index.php

Step 3 – Add the theme folder to the list of enabled modules

In order to use the theme folder just as a module folder, you need to register the folder in the list of modules being used by your application. Open up application/config/config.php and add the theme folder to your list of modules at the end. This lets Kohana make full use of the directory.

$config['modules'] = array
(
    DOCROOT.'themes/visual77',
);

Step 4 – Create a hook for adding theme content

The most important step is creating a hook to add your theme content around your template content. You want to let your template proceed as normal, and after completion, add your theme data.

To create hooks in Kohana, just create a file inside your hooks directory. All files in that directory will be loaded automatically. For instance, make a file called theme.php inside themes/<theme-name>/hooks.

In order to do the theming, the ideal hook to use is system.post_controller. The previous hook, system.post_controller_constructor, is before the controller has executed; the following hook, system.send_headers, is after system.execute, and therefore can’t manipulate the controller.

The goal is then to create a hook on system.post_controller and manipulate the controller to take the template data and move it within the overall theme. To access the controller, call Kohana::$instance and begin manipulating. My hook file looks like this:

<?php defined('SYSPATH') or die('No direct access allowed');

// set my hook up to execute at the appropriate time
event::add('system.post_controller', 'visual77_theme');

function visual77_theme() {
    // grab the controller
    $controller = Kohana::$instance;

    // pull the original template aside
    $temp = $controller->template;
    // replace the template with my theme template
    $controller->template = new View('visual77/index');
    // put the original template into the content section of my theme
    $controller->template->content = $temp;
    // free up some memory by unsetting the temp variable
    unset($temp);
}

Step 5 – Begin building the theme

Now that the hook is in place, the only thing left to do is build your theme. In my example, create an index.php file in themes/<theme-name>/views/<theme-name>. This index file will contain the wrapper HTML for your theme, leaving the original template to drop neatly inside the content section that you define. When you begin adding css and images, you can keep it inside the theme directory. The usual .htaccess restriction on modules only applies to the module directory, which is why I put the themes outside of the module folder.

While building, remember to keep all theme related content, such as views and controllers, inside the theme directory. This makes the theme ultra portable and easily removed. To change themes, just change the name of the theme from Step 3 to the new theme directory.

In a system like this, you can even cascade themes. One great example of cascading themes is including barebones files like CSS resets and jQuery files. On a current project, I have to build an internal client administration and an external company website. Both use certain shared libraries and both need a CSS reset and jQuery files. Using cascading themes and module sharing, I can blend these two sites very neatly. The file structure for this project looks like this:

/httpdocs
    /internal_application
    /external_application
    /modules
        /shared_libraries
    /system
    /themes
        /internal_theme
        /external_theme
        /default
    /index.php

Both internal and external applications include modules/shared_libraries and themes/default. However, internal_application also includes themes/internal_theme and external_application includes themes/external_theme. A switch statement in index.php dynamically switches the application based on the hostname. In the end, I  have two sites running smoothly in parallel on a single Kohana build.

Final Thoughts

Kohana is a fantastic system, but really needs better support for dynamic theming. In my build process for this theming pattern, I tried to emulate the wordpress theme convention, where all theme files are kept clustered and are easily swapped out for a new theme.

To see a full theme example, you can download my Sample Kohana Theme and then modify it to fit your needs. Just remember to enable hooks and include this theme as a module!

, ,

  1. #1 by Millie Mosqueda on October 3, 2010 - 8:35 pm

    What a excellent design you have. your site articles are pretty informative too! Thanks ;)

  2. #2 by visual77 on September 28, 2010 - 8:45 am

    nickr,

    This tutorial was written for Kohana 2.3, although it can work for 2.4 as well, but it won’t apply to 3.0. I really don’t like Kohana 3.0 and have stuck to 2.3.4 for all of my work, because of the removal of critical features like the entire Events class.

    The closest approximation to what I did here would involve work in application/Bootstrap.php. This file essentially launches everything. You’ll have to find where the controller has been executed (which will approximate system.post_controller), and grab the controller immediately afterwards and then do what is done in my hook file.

  3. #3 by nickr on September 28, 2010 - 4:31 am

    Hi Stephen, I’m new to Kohana so I thought I’d start with a theme… and I found this post. In Kohana 3.0.8, there isn’t a config file in application/config which makes your instructions kind of hard to follow. Has Kohana changed or should I be creating my own file?

    Many thanks,
    Nick.

  4. #4 by Joaquim Homrighausen on August 17, 2010 - 2:02 pm

    Nice tutorial!

(will not be published)