How to Override Module Templates and Classes in Prestashop 1.7 | Alexander Molochko

Overriding modules is a really powerful feature of the Prestsahop CMS. It makes possible to change behavior and appearance of modules without altering original source code. However, due to latest changes in Prestashop 1.7 a lot of changes were made and some features are gone forever. Therefore this article is intended to explain the most widely used cases and understand how does the Override system work in Prestashop and what overriding techniques are still available.

Prestashop 1.7 changes

One important note is that starting from Prestashop 1.7 overriding is considered a bad practice. According to this article, overrides still be available, even so a lot overriding features are already missed in 1.7.X versions. For instance you cannot override core classes anymore by putting your classes in prestashop-root/override/classes/module/Module.php like that.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<?php
class Module extends ModuleCore
{
    protected function getCacheId($name = null)
    {
    }
    public function display($file, $template, $cache_id = null, $compile_id = null)
    {
    }
}
?>

Only classes for translation can be overridden this way. Have a look at the getFileToParseByTypeTranslation method in AdminTranslationsController file

Prerequisites

Before starting any modification and creation of source files enable Debug Mode from your Admin Panel. Advanced Parameters -> Performance -> Set Debub Mode to true . Also you may need to enable recompilation of template files in case you are going to change layout. Alternatively, you can delete the cache/class_index.php file

Debug Mode Prestashop

Throughout this article I will be working with a default module Main menu. Of course you can apply all these techniques for other modules.

Documentation vs GREPping source code

When you are trying to find how to implement something using a CMS, usually you refer to the official documentation. But, based on my personal experience it may take much more time trying to find an explanation of some part of an engine by googling or reading the official documentation. For that reason I prefer grepping source code. The most valuable benefit you get by using this method is understanding how everything works under the hood, what architecture is used, how some feature is implemented. After exploring several software products, you will get an idea how something could be implemented, what are pros and cons, as a result you can use acquired knowledge while building your own software products.

Override system

In order not to break most of available modules, Prestashop 1.7 still supports overriding for modules. As far as we are interested in overriding modules behavior, I encourage you to have a look at the Module class that is located at prestashop-root/classes/module/Module.php.

Override Template Files

At first let’s find out how to override a module’s view appearance. Find the _isTemplateOverloadedStatic method

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
  protected static function _isTemplateOverloadedStatic($module_name, $template)
    {
        if (Tools::file_exists_cache(_PS_THEME_DIR_.'modules/'.$module_name.'/'.$template)) {
            return _PS_THEME_DIR_.'modules/'.$module_name.'/'.$template;
        } elseif (Tools::file_exists_cache(_PS_THEME_DIR_.'modules/'.$module_name.'/views/templates/hook/'.$template)) {
            return _PS_THEME_DIR_.'modules/'.$module_name.'/views/templates/hook/'.$template;
        } elseif (Tools::file_exists_cache(_PS_THEME_DIR_.'modules/'.$module_name.'/views/templates/front/'.$template)) {
            return _PS_THEME_DIR_ . 'modules/' . $module_name . '/views/templates/front/' . $template;
        } elseif (Tools::file_exists_cache(_PS_PARENT_THEME_DIR_.'modules/'.$module_name.'/'.$template)) {
            return _PS_PARENT_THEME_DIR_.'modules/'.$module_name.'/'.$template;
        } elseif (Tools::file_exists_cache(_PS_PARENT_THEME_DIR_.'modules/'.$module_name.'/views/templates/hook/'.$template)) {
            return _PS_PARENT_THEME_DIR_.'modules/'.$module_name.'/views/templates/hook/'.$template;
        } elseif (Tools::file_exists_cache(_PS_PARENT_THEME_DIR_.'modules/'.$module_name.'/views/templates/front/'.$template)) {
            return _PS_PARENT_THEME_DIR_.'modules/'.$module_name.'/views/templates/front/'.$template;
        } elseif (Tools::file_exists_cache(_PS_MODULE_DIR_.$module_name.'/views/templates/hook/'.$template)) {
            return false;
        } elseif (Tools::file_exists_cache(_PS_MODULE_DIR_.$module_name.'/views/templates/front/'.$template)) {
            return false;
        } elseif (Tools::file_exists_cache(_PS_MODULE_DIR_.$module_name.'/'.$template)) {
            return false;
        }
        return null;
    }
 ?>

As you can see from the code above there are different possible patterns that can be used to override a module’s template files. In my case I have created a file at the following path prestashop-root/themes/my-theme/modules/ps_mainmenu/ps_mainmenu.tpl.

Override Module Classes

To modify behavior of a module’s class you have to put your modified class at prestashop-root/override/modules/NAME_OF_MODULE/class_to_override.php. And your class should have name defined according to this pattern {NameOfOriginalModuleClass}Override. For example override/modules/ps_mainmenu/ps_mainmenu.php and the class name should be Ps_MainMenuOverride. To understand how does the CMS process module classes overrides, find the coreLoadModule method.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
  protected static function coreLoadModule($module_name)
    {
        include_once(_PS_MODULE_DIR_.$module_name.'/'.$module_name.'.php');

        $r = false;
        if (Tools::file_exists_no_cache(_PS_OVERRIDE_DIR_.'modules/'.$module_name.'/'.$module_name.'.php')) {
            include_once(_PS_OVERRIDE_DIR_.'modules/'.$module_name.'/'.$module_name.'.php');
            $override = $module_name.'Override';

            if (class_exists($override, false)) {
                $r = self::$_INSTANCE[$module_name] = ServiceLocator::get($override);
            }
        }

        if (!$r && class_exists($module_name, false)) {
            $r = self::$_INSTANCE[$module_name] = ServiceLocator::get($module_name);
        }

        return $r;
    }
 ?>

As you could see the implementation is quite straightforward. And according to these rules our class might look as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php
class Ps_MainMenuOverride extends Ps_MainMenu
{
    public function getMenuItems()
    {
        return "HELLO";
    }

    public function renderForm()
    {
        return "Hello World";
    }
}
?>
Implementation

From the code above you may notice that these functions are defined as static. PHP has a feature called Late Static Bindings, but anyway I don’t think it should be used. Furthermore, the Module class file has more than 3000 lines of code. Most of functions are static making it more like an utility class rather than an OOP entity. This class is some kind of the God object anti-pattern. A possible solution could be implemented by separating functions like loadModule, loadTemplate into a separate class called ModuleLoader/ModuleManager. Surely there might be a reason for such decision.

Conclusion

All in all Prestashop 1.7 has breaking changes for a developers who leveraged the overriding feature extensively. According to the prestashop blog posts it seems that the team want to improve an architecture of the system, this is definetly commendable, but any major changes should be added step by step leaving backward compatible options for developers.

If you are still trying to find a way to override the CMS core classes without direct modification of source code, you could probably find a workaround, for instance:

  • Use advanced PHP features like runkit/classkit.
  • Explore the request flow of the Prestashop. And add your own logic for loading classes (for example modify autoload.php). But every time you update the CMS core, you will need to add/review your custom implementation. Here you can find a detailed image of a request processing in Prestashop.
  • Explore source code of the CMS in order to find other ways like runtime inejction/modification via include statements, etc.

I hope this article will be helpful for understanding how override features works under the hood, if you have any questions please feel free to leave comments below.