1.4 Plugins Revisited – Part 1

Creative Commons Licence

Plugins Evolved

A while ago when I wrote the original article on Prestashop plugins I promised a follow-up to allow it to be used with smarty 3. Unfortunately work has kept me from a proper write-up so I’m only now getting around to publishing the next version. I had intended adding the ability to easily extend the functionality on a per-theme basis, but since the demand for some usable code right now has been so great I’ve decided to publish this in two parts. I will try to ensure that Part 2 doesn’t take as long to appear as this article has!

The new Plugin class

When I originally started work on this I had in mind that it may be useful for people to be able to override the plugin class using the same method Prestashop uses for its own core classes. While implementing it in a real-world Prestashop site however, I decided that this wasn’t such a good idea and the Plugin class is now implemented as a simple additional class. In Part 2 I’ll detail the mechanism I’ve decided to implement in preference to the override system to allow others to extend the functionality of this.

Note: If you implemented the original PluginCore class from the previous article, then you should delete the old Plugin.php class definition from the /classes drectory in your Prestashop installation.

The new version of Plugin.php should now be placed in the /overrides/classes folder on your server:

class Plugin
{
  public static $initialized = false;
  protected static $smarty;
  protected static $cookie;
  protected static $link;
  protected static $cart;
  function init()
  {
    global $smarty, $cookie, $link, $cart;
    if (self::$initialized)
      return;
    self::$initialized = true;
    self::$cookie = $cookie;
    self::$cart = $cart;
    self::$smarty = $smarty;
    self::$link = $link;
    if (!Configuration::get('PS_FORCE_SMARTY_2'))
    {
      self::$smarty->registerPlugin('function', 'plugin', array('Plugin', 'ecs_smartyplugin'));
      self::$smarty->registerPlugin('function', 'cmspage', array('Plugin', 'ecs_smartycmspage'));
      self::$smarty->registerPlugin('function', 'psconfig', array('Plugin', 'ecs_smartypsconfig'));
    } else {
      self::$smarty->register_function('plugin', array('Plugin', 'ecs_smartyplugin'));
      self::$smarty->register_function('cmspage', array('Plugin', 'ecs_smartycmspage'));
      self::$smarty->register_function('psconfig', array('Plugin', 'ecs_smartypsconfig'));
    }
  }
  public static function moduleoutput($module, $hook, $hookArgs = array())
  {
    $output = '';
    if (!isset($hookArgs['cookie']) OR !$hookArgs['cookie'])
      $hookArgs['cookie'] = self::$cookie;
    if (!isset($hookArgs['cart']) OR !$hookArgs['cart'])
      $hookArgs['cart'] = self::$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;
  }
  public static function cmspage($id_cms = 1)
  {
    $output = '';
    $cms = new CMS($id_cms, intval(self::$cookie->id_lang));
    if (Validate::isLoadedObject($cms))
      $output = $cms->content;
    return $output;
  }
  static function ecs_smartyplugin($params, &$smarty)
  {
    return Plugin::moduleoutput($params['module'], $params['hook'], isset($params['args']) ? $params['args'] : array());
  }
  static function ecs_smartycmspage($params, &$smarty)
  {
    return Plugin::cmspage($params['id']);
  }
  static function ecs_smartypsconfig($params, &$smarty)
  {
    return Configuration::get($params['item']);
  }
}

The main architectural difference apart from no longer declaring the class as a “Core” one is that all of the required code, including callbacks, is now contained within the class. This allows us to eliminate the global functions from within the FrontController class override. You will also notice that I have added another two basic elements to the class and now supports the following theme extensions by default:

  1. The original “plugin” code to insert module output from a specific hook.
    {plugin module='homefeatured' hook='home'}
    
  2. A “cms” code which allows the output of a specific Prestashop CMS “page”. This allows you to create “user-editable” areas in the theme that can be modified via the admin panel simply by changing the corresponding CMS document. By setting the documents to “disabled” they will also never show on the site other than where you need them to (if required).
    {cmspage id='1'}
    
  3. A “psconfig” code to output the value of a Prestashop config variable. This is extremely handy when creating areas such as footers where you may wish to place information like the store address, telephone number etc. By using this mechanism the theme will always track the values set from the admin screens.
    {psconfig item='PS_SHOP_PHONE'}
    

The FrontController override

Since we have moved the bulk of the code to the Plugin class now, we can simply use the following in /overrides/classes/FrontController.php:

class FrontController extends FrontControllerCore
{
  protected static $plugin;
  function __construct()
  {
    parent::__construct();
    self::$plugin = new Plugin();
  }
  function init()
  {
    parent::init();
    self::$plugin->init();
  }
}

Download the required files

Once again, 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 v1.1.0

Continue to Part 2

Sharing is caring!

Posted on June 8, 2011 | Related Categories: Development Resources, Prestashop, Tips and Tricks | 11 comments

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

11 Responses to 1.4 Plugins Revisited – Part 1

  1. McRoa says:

    A good day to all,

    A little research learned that the Smarty {capture} command is not needed in order for the search block to operate in a footer. Two things should be noted in this context:

    1.) The searchblock needs to be hooked to the header in the admin panel. This is also true for several other modules. It’s quite odd, but failing to do so will result in stylesheets not being loaded.

    2.) The css-file for the searchblock assumes that all of the block elements are contained in a parent element with id ‘header_right’. When placing the searchblock in a footer this is of course not true. The css should be modified to correct this.

    After addressing both issues {plugin module='blocksearch' hook='Top'} in footer.tpl works just as it is meant to be.

    By the way: thanks a lot for this nice piece of work!

    Regards,
    McRoa

  2. Piotr says:

    Hi,
    your solution has one serious problem. Let us suppose we want to put blocksearch module in footer. Somewhere in footer.tpl file we should insert this code: {plugin module=’blocksearch’ hook=’leftColumn’}. When footer is rendered, hookLeftColumn function from blocksearch.php file is executed. This function executes Tools::addCss function seomewhere inside. In spite of adding css file to $css_files global array, css file won’t be placed in html head section, because header.tpl file is already rendered. In other words using Your solution causes incorrect working of Tools::addCss function (it applies to Tools::addJS function either).
    Regards
    Piotr

    • Hi Piotr,

      I would argue that the blocksearch module is at fault, not my code ;)

      In almost every case, apart from that module, Tools:addCSS() and Tools::addJS() calls are placed in hookHeader(). I have no idea why that one particular module is different….

      The problem isn’t insurmountable, even in the event that a module author depends on a trick such as this to get their module working. All you need to do is add the following at the start of header.tpl:

      {capture name='cache_search_block' assign='search_block'}{plugin module='blocksearch' hook='leftColumn'}{/capture}

      In the footer.tpl file you can then use:

      {$search_block}

      I haven’t come across any other modules that try and place Tools::addCSS() and Tools::addJS() calls in the left and right column hook functions but there may be some… It only works because those hooks happen to be executed before hookHeader, but it’s not good practice….

      • Piotr says:

        Hi Paul,
        after rethink I agree with you. It’s rather blocksearch module design problem. But still it exists. General problem is I wuold like to do something like this
        class MyBlockSearch extends BlockSearch
        {
        public function hookMyOwnHook($params)
        {
        // code
        }

        }
        Unfortunately it is impossible.

        Anyway, because blocksearch is not very complex, I decided to create my own search module using blocksearch as a base. Your solution with smarty capture function didn’t work for me, bat I did not investigate why. Maybe I did something wrong.

        Regards
        Piotr

  3. Hi !
    You said in your last post that this plugin didn’t work with Smarty V3 but only with v2. Is this version working with v3 ?
    Good job, it seems to be a great addon for prestashop !
    Thanks ;)

  4. Rassy says:

    Hi Paul,

    do you think that using “plugins” will affect prestashops CACHING mechanism in any way? Will prestashop still be fast? ??? :-)

    I really really love this. Will give it a try now. :-)

    • The Module template files still obey all the compilation and caching rules as normal, so there shouldn’t be a huge effect, if any. In fact since you don;t have to run through the database lookups for the hooks for modules called this way it could be faster….

  5. John says:

    I think the cms addition will be highly useful espcially for the likes of the contact-form and being able to add text there, which currently isnt possible unless you edit the file directly (not good for non-techy types).

  6. Lars Petter Gjelsten Bøe says:

    Without a doubt the most anticipated update of any kind to PrestaShop on my radar. I’m leaving for meeting a client shortly and will give my feedback and thoughts later tonight. Thank you again so much for you dedication and great work.

  7. Uddhava says:

    Heeeeee Paul,
    Great work of course. And i will try it out soon. So you decided to create a new class then even can be overrided later by other devs. Thats great. I hope the PS team will look into this also and try to incorporate it into the core (with your permission)

    ys