Child pages
  • Creating a PrestaShop module

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

A module is made of a lot of files, all stored in a folder that bears the same name as the module, that folder being in turn stored in the /modules folder at the root of the main PrestaShop folder: /modules/name_of_the_module/.

/views/templates/cssSub-folder for CSS files used.If the module needs to work with PrestaShop 1.4, the CSS files should be placed in a /css folder at the root of the module's folder.
/views/templates/jsSub-folder for JavaScript files.If the module needs to work with PrestaShop 1.4, the JavaScript files should be placed in a /js folder at the root of the module's folder.
/views/templates/imgSub-folder for image files.If the module needs to work with PrestaShop 1.4, the image files should be placed in a /img folder at the root of the module's folder.

Default files and folders for a PrestaShop 1.5 module:

  • Main file: name_of_the_module.php. This PHP file should have the same name as its root folder.
  • Cache configuration file (generated by PrestaShop): config.xml.
  • View files: JavaScript, images, CSS files, template files, etc. They can be placed in folders within the module's main folder:
    • /views/templates/css folder  folder for CSS files. If the module needs to work with PrestaShop 1.4, the CSS files should be placed in a /css folder at the root of the module's folder.
    • /views/templates/img folder  folder for image files. If the module needs to work with PrestaShop 1.4, the CSS files should be placed in an /img folder at the root of the module's folder.
    • /views/templates/js folder  folder for JavaScript files. If the module needs to work with PrestaShop 1.4, the CSS files should be placed in a /js folder at the root of the module's folder.
    • /views/templates/admin sub-folder for files used by the module's admin controller.
    • /views/templates/front sub-folder for files used by the module's front controller.
    • /views/templates/hook sub-folder for files used by the module's hooks.
  • Module-specific controllers, all in the /controllers sub-folder.
  • Class-overriding code, all in the /override sub-folder (automatic install/uninstall using copy or merge).
  • Two icon files representing this module in the back-office.
    • One file for PrestaShop 1.4: logo.gif or logo.jpg, 16*16 pixels.
    • One file for PrestaShop 1.5: logo.png, 32*32 pixels.
  • Translation files: fr.php, en.php, es.php, etc. From v1.5 onward, all these files can be placed in the /translations sub-folder.
  • Optional: in a /themes/[theme name]/modules folder, a folder with the same name as the module, containing .tpl and language files if necessary. This last folder is essential during modifications of existing module, so that you can adapt it without having to touch its original files. Notably, it enables you to handle the module's display in various ways, according to the current theme.

...

That class must bear the same name as the module and its folder, in CamelCase (see http://en.wikipedia.org/wiki/CamelCase): MyModule.
Furthermore, that class must extend the Module class, and thus inherits all methods and attributes. It can just as well extend any class derived from Module, for specific needs: PaymentModule, ModuleGridEngine, ModuleGraph...

Code Block
borderStylesolid
titlemymodule.php
borderStylesolid
<?php
if (!defined('_PS_VERSION_'))
  exit;

class MyModule extends Module
{
}
?>

...

Now, let's fill the class' code block with the essential bootstrap lines:

Code Block
borderStylesolid
titlemymodule.php
borderStylesolid
<?php
if (!defined('_PS_VERSION_'))
  exit;

class MyModule extends Module
{
  public function __construct()
  {
    $this->name = 'mymodule';
    $this->tab = 'front_office_features';
    $this->version = '1.0';
    $this->author = 'Firstname Lastname';
    $this->need_instance = 0;
    $this->ps_versions_compliancy = array('min' => '1.5', 'max' => '1.5');	
    $this->dependencies = array('blockcart');

    parent::__construct();

    $this->displayName = $this->l('My module');
    $this->description = $this->l('Description of my module.');

    $this->confirmUninstall = $this->l('Are you sure you want to uninstall?');

    if (!Configuration::get('MYMODULE_NAME'))		
      $this->warning = $this->l('No name provided');
  }
}
?>

...

Here is our template file, located at /views/templates/hook/mymodule.tpl:

Code Block
borderStylesolid
titlemymodule.tpl
borderStylesolid
<!-- Block mymodule -->
<div id="mymodule_block_left" class="block">
  <h4>Welcome!</h4>
  <div class="block_content">
    <p>Hello, 
       {if isset($my_module_name) && $my_module_name}
           {$my_module_name}
       {else}
           World
       {/if}
       !        
    </p>    
    <ul>
      <li><a href="{$my_module_link}" title="Click this link">Click me!</a></li>
    </ul>
  </div>
</div>
<!-- /Block mymodule -->

...

Here are our two files:

Code Block
borderStylesolid
titledisplay.php
borderStylesolid
<?php
class mymoduledisplayModuleFrontController extends ModuleFrontController
{
  public function initContent()
  {
    parent::initContent();
    $this->setTemplate('display.tpl');
  }
}
Code Block
borderStylesolid
titledisplay.tpl
borderStylesolid
Welcome to my shop!

Let's explore display.php, our first PrestaShop front-end controller, stored in the /controllers/front folder of the module's main folder:

...

Note

Until PrestaShop 1.4, developers who wanted to embed a template file into the site's theme had to use PHP's include() calls to include each portion of the page. Here is the equivalent code for display.php:

Code Block
borderStylesolid
titledisplay.php
borderStylesolid
<?php
// This file must be placed at the root of the module's folder.
global $smarty;
include('../../config/config.inc.php');
include('../../header.php');

$smarty->display(dirname(__FILE__).'/display.tpl');

include('../../footer.php');
?>

As you can see, this is not necessary anymore since PrestaShop 1.5: you can and should use a front-end controller, and both the controller (Controller) and its template (View) should share the same name: display.php is tied to display.tpl.

...

For instance, we can create the $my_module_message variable in PHP right in the hookDisplayLeftColumn() method, and have it displayed by our template file:

Code Block
borderStylesolid
titlemymodule.php
borderStylesolid
public function hookDisplayLeftColumn($params)
{
    $this->context->smarty->assign(
        array(
            'my_module_name' => Configuration::get('MYMODULE_NAME'),
            'my_module_link' => $this->context->link->getModuleLink('mymodule', 'display'),
            'my_module_message' => $this->l('This is a simple text message') // Do not forget to enclose your strings in the l() translation method
        )
    );
    
    return $this->display(__FILE__, 'mymodule.tpl');
}

From there on, we can ask Smarty to display the content of this variable in our TPL file.

Code Block
borderStylesolid
titlemymodule.tpl
borderStylesolid
{$my_module_message}

PrestaShop adds its own set of variables. For instance, {$hook_left_column} will be replaced with the content for the left column, meaning the content from all the modules that have been attached to the left column's hook.

...

Strings in PHP files will need to be displayed through the l() method, which comes from the Module abstract class, and thus is available in all modules.

Code Block
borderStylesolid
titlemymodule.php (partial)
borderStylesolid
...
$this->displayName = $this->l('My module');
$this->description = $this->l('Description of my module.');
...

Strings in TPL files will need to be turned into dynamic content, which Smarty will replace by the translation for the chosen language. In our sample module, the mymodule.tpl file...

Code Block
borderStylesolid
titlemymodule.tpl (partial)
borderStylesolid
<li>
  <a href="{$base_dir}modules/mymodule/mymodule_page.php" title="Click this link">Click me!</a>
</li>
<!-- Block mymodule -->
<div id="mymodule_block_left" class="block">
  <h4>{l s='Welcome!' mod='mymodule'}</h4>
  <div class="block_content">
    <p>Hello, 
       {if isset($my_module_name) && $my_module_name}
           {$my_module_name}
       {else}
           World
       {/if}
       !        
    </p>    
    <ul>
      <li><a href="{$my_module_link}" title="Click this link">Click me!</a></li>
    </ul>
  </div>
</div>
<!-- /Block mymodule -->	 

...becomes:

Code Block
borderStylesolid
titlemymodule.tpl (partial)
borderStylesolid
<li>
  <a href="{$base_dir}modules/mymodule/mymodule_page.php" title="{l s='Click this link' mod='mymodule'}">{l s='Click me!' mod='mymodule'}</a>
</li>
<!-- Block mymodule -->
<div id="mymodule_block_left" class="block">
  <h4>{l s='Welcome!' mod='mymodule'}</h4>
  <div class="block_content">
    <p>
      {if !isset($my_module_name) || !$my_module_name}
        {capture name='my_module_tempvar'}{l s='World' mod='mymodule'}{/capture}
        {assign var='my_module_name' value=$smarty.capture.my_module_tempvar}
      {/if}
      {l s='Hello %1$s!' sprintf=$my_module_name mod='mymodule'}    
    </p>    
    <ul>
      <li><a href="{$my_module_link}"  title="{l s='Click this link' mod='mymodule'}">{l s='Click me!' mod='mymodule'}</a></li>
    </ul>
  </div>
</div>
<!-- /Block mymodule -->

...

Code Block
titledisplay.tpl
Welcome to this page!

...becomes:

Code Block
borderStylesolid
titledisplay.tpl
borderStylesolid
{l s='Welcome to this page!' mod='mymodule'}

...

PrestaShop then saves the translations in a new file, named using the languageCode.php format (for instance, /mymodule/fr.php). The translation file looks like so:

Code Block
borderStylesolid
titlefr.php
borderStylesolid
<?php
global $_MODULE;
$_MODULE = array();
$_MODULE['<{mymodule}prestashop>mymodule_2ddddc2a736e4128ce1cdfd22b041e7f'] = 'Mon module';
$_MODULE['<{mymodule}prestashop>mymodule_d6968577f69f08c93c209bd8b6b3d4d5'] = 'Description du module.';
$_MODULE['<{mymodule}prestashop>mymodule_533937acf0e84c92e787614bbb16a7a0'] = 'Êtes-vous certain de vouloir désinstaller ce module ? Vous perdrez tous vos réglages !';
$_MODULE['<{mymodule}prestashop>mymodule_0f40e8817b005044250943f57a21c5e7'] = 'Aucun nom fourni';
$_MODULE['<{mymodule}prestashop>mymodule_fe5d926454b6a8144efce13a44d019ba'] = 'Valeur de configuration non valide.';
$_MODULE['<{mymodule}prestashop>mymodule_c888438d14855d7d96a2724ee9c306bd'] = 'Réglages mis à jour';
$_MODULE['<{mymodule}prestashop>mymodule_f4f70727dc34561dfde1a3c529b6205c'] = 'Réglages';
$_MODULE['<{mymodule}prestashop>mymodule_2f6e771db304264c8104cb7534bb80cd'] = 'Valeur de configuration';
$_MODULE['<{mymodule}prestashop>mymodule_c9cc8cce247e49bae79f15173ce97354'] = 'Enregistrer';
$_MODULE['<{mymodule}prestashop>mymodule_630f6dc397fe74e52d5189e2c80f282b'] = 'Retour à la liste';
$_MODULE['<{mymodule}prestashop>display_86e88cbccafa83831b4c6685501c6e58'] = 'Bienvenue sur cette page !';
$_MODULE['<{mymodule}prestashop>mymodule_9a843f20677a52ca79af903123147af0'] = 'Bienvenue !';
$_MODULE['<{mymodule}prestashop>mymodule_f5a7924e621e84c9280a9a27e1bcb7f6'] = 'Monde';
$_MODULE['<{mymodule}prestashop>mymodule_3af204e311ba60e6556822eac1437208'] = 'Bonjour %s !';
$_MODULE['<{mymodule}prestashop>mymodule_c66b10fbf9cb6526d0f7d7a602a09b75'] = 'Cliquez sur ce lien';
$_MODULE['<{mymodule}prestashop>mymodule_f42c5e677c97b2167e7e6b1e0028ec6d'] = 'Cliquez-moi !';

...