Tired of hooks? Try a Plugin (Prestashop 1.4)

Update: This article has been revised in: 1.4 Plugins Revisited

Please note that this version only works currently for Smarty v2, enabling smarty v3 will cause an error. I'll post an update that resolves this issue shortly.

In a previous article Display Module Output Anywhere I touched on the subject of subverting Prestashop's internal Module architecture to our own ends. In this article we'll be looking at creating a new mechanism for injecting module output into themes that doesn't rely on tedious code changes, and should be able to be employed by (almost) anyone regardless of programming ability.

How about being able to display the home featured products anywhere in your template files just by adding a single line (as below)?

php{plugin module='homefeatured' hook='home'}

If this looks like something you would find useful, then read on....

Hooks - A sledgehammer to crack a nut

I was recently faced with a design "problem" which I'm sure many of us working with Prestashop have faced. In this case there was a requirement to add featured products at the bottom of every cms page. It sounds really simple, but it's actually a lot more complicated than it needs to be.

Modules are great for packaging up custom output for display. With modules you can create your own slideshows, tag clouds etc. and distribute them for use by non-programmers easily with just a click of a button. The major stumbling block to them being the ultimate "drop-in" component however is that modules are limited to rendering their output at very specific points within a theme, defined in Prestashop as "hooks". The only control a theme designer has is to move an entire "hook point", and these are pretty much hard-coded into the Prestashop core. Worse still - each module needs to be written to specifically support each hook point you may want to hook it to, and in reality many modules only support a limited selection of the available hooks.

The above limitations are only made worse by the fact that the ability to move the pre-defined hook points is limited almost to being within a single template file. In reality you can move a hook outside it's "default" template file, but only to another template file which is rendered after its default one. For example you can move the header hook into the footer template, but not vice versa. This is due to the fact that the smarty variables used to hold the hook output are only in scope from the point in the page rendering process at which they're defined.

In partial mitigation of this, as of version 1.4, it is now possible to override the core points at which Prestashop sets the scope of these hook variables. With proper care you can override the necessary controllers and redefine the order in which the hook points are rendered. You can also create your own hook points and populate them with appropriate content should you wish, although this may well be outwith the comfort zone of most end-users and theme designers, and in many cases will require modifications to modules which may cause issues when upgrading them later.

My Solution: "Plugins"

As stated at the beginning of this article; wouldn't it be nice to just be able to add a single line of uncomplicated code in any template file, exactly where you want the output of a pre-existing module's hook function to display? For example:

php{plugin module='homefeatured' hook='home'}

Here's how.....

The Plugin Core Class

For this to work we simply need to extend Prestashop a little by adding a new core class. For those who have been following articles on this site for some time you will recognise that this is based on my previous article on displaying module output.

// File: classes/Plugin.php
class PluginCore
  public function moduleoutput($module, $hook, $hookArgs = array())
    global $cart, $cookie;
    $output = '';
    if (!isset($hookArgs['cookie']) OR !$hookArgs['cookie'])
      $hookArgs['cookie'] = $cookie;
    if (!isset($hookArgs['cart']) OR !$hookArgs['cart'])
      $hookArgs['cart'] = $cart;
    $hookArgs['altern'] = 1;
    $instance = Module::getInstanceByName($module);
    if (is_callable(array($instance, 'hook'.$hook)))
      $output = call_user_func(array($instance,'hook'.$hook), $hookArgs);
    echo $output;

You may also have noticed that in addition to the two parameters we passed in the initial smarty template code example above ('module' and 'hook'), this function takes a third parameter '$hookArgs'. This is to allow for the rare case where a module hook function expects additional arguments. It is unlikely that this will ever be used in practice in a theme. Surprisingly, the above is the bulk of the changes required to get this technique to work, in fact just by adding the above file we could insert module output into our theme's template files, although we would have to use the {php} tags in smarty to call our class. To make this even more end-user friendly however, we're next going to add an override to the FrontController class so that we can integrate this into Smarty via a 'plugin' template function.

// File: override/classes/FrontController.php
function smartyEcartPlugin($params, &$smarty)
  return Plugin::moduleoutput($params['module'], $params['hook'], isset($params['args']) ? $params['args'] : array());
class FrontController extends FrontControllerCore
  function __construct()
  function init()
    global $smarty;
    $this->smarty = $smarty; // Not really sure why, but necessary.
    if (!Configuration::get('PS_FORCE_SMARTY_2'))
      $this->smarty->registerPlugin('function', 'plugin', 'smartyEcartPlugin');
    } else {
      $this->smarty->register_function('plugin', 'smartyEcartPlugin');

With the addition of just these two files you can now call module hook functions from anywhere within your theme's template files using the syntax used in the example at the start of this article e.g.

php{plugin module='homefeatured' hook='home'}


php{plugin module='blocksearch' hook='top'}

Note: Modules still have to be installed so that you can use them in your theme. If you do not wish the module to display output in it's default location then you should install the module and then remove unwanted hooks via the positions admin menu. There will also be cases where certain modules cannot display their output, and also cases where a particular module's hook support function would not make sense in the context of a particular theme file.

I have kept the code to an absolute minimum and will likely extend some of the functions to perform some form of validation and perhaps even caching, but in essence the above is all you need to do to implement this handy theme shortcut. One of the reasons for implementing the code as a core class rather than just implementing all the code within the FrontController override is so that the Plugin class itself can be extended with an override. Have fun.

Download the required files

Please regard these files as experimental. They are not guaranteed in any way and could cause your store to function incorrectly.

Download Prestashop 1.4 Theme Plugin Extension