{toc:maxLevel=2|style=disc|printable=false}

h1. Creating a PrestaShop module

h2. Modules' operating principles

Modules are the ideal way to let your talent and imagination as a developer express themselves, as the creative possibilities are many.

They can display a variety of content (blocks, text, etc.), perform many tasks (batch update, import, export, etc.), interface with other tools...

Modules can be made as configurable as necessary; the more configurable it is, the easier it will be to use, and thus will be able to address the need of a wider range of users.

One of the main interest of a module is to add functionalities to PrestaShop without having to edit its core files, this making it easier to perform an update without having the transpose all core changes.

That is way you should always strive to stay away from core files when building a module, even though this can prove hard to do in some situations...


h2. Module file tree

All PrestaShop modules are found in the {{/modules}} folder, which is at the root of the PrestaShop main folder. This is true for both default modules (provided with PrestaShop) and 3rd-party modules that are subsequently installed.

Each modules has its own sub-folder inside the {{/modules}} folder: {{/bankwire}}, {{/birthdaypresent}}, etc.


h2. Basic structure of a module

All modules use the same basic structure, which makes it easier to learn by observing existing modules' source code.

Let's create a simple first module; this will enable us to better describe its structure. We'll call it "My module".


Let's first create the module folder. It should have the same name as the module, with no space, only alphanumerical characters, the hyphen and the underscore, all in lowercase: {{/mymodule}}.

This folder must contain a PHP file of the same name, which will handle most of the processing: {{mymodule.php}}.

That is enough for a very basic module, but obviously more files and folders can complement it.

The front-office part of the module is defined in a {{.tpl}} file placed at the root of the module's folder. TPL files can have just about any name. It there's only one such file, it is good practice to give it the same name as the folder and main file: {{mymodule.tpl}}.

The {{mymodule.php}} must contain the module's class. PrestaShop is Object-Oriented Programming, and so does its modules.
That class must bear the same name as the module and its folder, in [CamelCase|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}}: {{PaymentModule}}, {{ModuleGridEngine}}, {{ModuleGraph}}...

{code:title=mymodule.php|borderStyle=solid}
<?php
class MyModule extends Module
  {
  public function __construct()
    {
    $this->name = 'mymodule';
    $this->tab = 'Test';
    $this->version = 1.0;

    parent::__construct();

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

  public function install()
    {
    if ( parent::install() == false )
      return false;
    return true;
    }
  }
?>
{code}

Let's examine each line from our {{MyModule}} object...

{code}
public function __construct()
{code}
Defines the class' constructor.

{code}
$this->name = 'mymodule';
{code}

Assigns a 'name' attribute to our class' instance.

{code}
$this->tab = 'Test';
{code}

Assigns a 'tab' attribute to our class' instance. This is the title for the table that shall contain this module in PrestaShop's back-office modules list. You may use an existing name, such as {{Products}}, {{Blocks}} or {{Stats}}, or a custom, as we did here. In this last case, a new table will be created with your title.

{code}
$this->version = 1.0;
{code}

Version number for the module, displayed in the modules list.

{code}
parent::__construct();
{code}

Calling the parent's constructor. This must be done before any use of the {{$this->l()}}, and after the creation of {{$this->name}}.

{code}
$this->displayName = $this->l( 'My module' );
{code}

Assigning a public name for the module, which will be displayed in the back-office's modules list.
The {{l()}} method is part of PrestaShop translation's tools, and is explained further below.

{code}
$this->description = $this->l('Description of my module.');
{code}

Assigning a public description for the module, which will be displayed in the back-office's modules list.

{code}
public function install()
  {
  if ( parent::install() == false )
    return false;
  return true;
  }
{code}

As it is, this method is useless, since all it does is check the value returned by the {{Module}} class' {{install()}} method. Moreover, if we hadn't created that method, the superclass' method would have been called instead anyway, making the end result identical.
Nevertheless, we must mention this method, because it will be very useful once we have to perform checks and actions during the module's installation process: creating SQL tables, copying files, creation configuration variables, etc.

Likewise, should contain an {{uninstall()}} method, so as to have a custom uninstallation process. This method could look as such:

{code}
public function uninstall()
  {
  Db::getInstance()->Execute( 'DELETE FROM `' . _DB_PREFIX_ . 'block_cms` WHERE `id_block` = ' . intval( $this->id ) );
  parent::uninstall();
  }
{code}

To put the finishing touch to this basic module, we can add an icon, which will be displayed next to the module's name in the back-office modules list.
The icon file must respect these requirements:
* 16*16 image.
* named {{logo.gif}}.
* place on the module's main folder.

You can find an excellent free set of icons to pick from on [the FamFamFam website|http://www.famfamfam.com/lab/icons/silk/].

Now that all basics are in place, put the module's folder in the {{/modules}} folder of your PrestaShop test install, open PrestaShop, and in the "Modules" tab, under "Other Modules", you should find your module. Install it in order to be able to manager it for the rest of this guide.

!_Images^devModule002-inModulesList.png|border=1!

PrestaShop automatically creates a small {{config.xml}} file in the module's folder, which stores a few configuration information.



h2. Hooking a module

Displaying data, starting a process at a specific time: in order for a module to be "attached" to a location on the front-office or the back-office, you need to give it access to one of the above cited hooks.

To that effect, we are going to change your module's code, and add these lines:

{code:title=mymodule.php (partial)|borderStyle=solid}
public function install()
  {
  if ( parent::install() == false OR !$this->registerHook( 'leftColumn' ) )
    return false;
  return true;
  }

...

public function hookLeftColumn( $params )
  {
  global $smarty;
  return $this->display( __FILE__, 'mymodule.tpl' );
  }

public function hookRightColumn( $params )
  {
  return $this->hookLeftColumn( $params );
  }
{code}

Let's explore these new or changed lines.

{code}
if ( parent::install() == false OR !$this->registerHook('leftColumn') )
{code}

We changed the original line to add a second test. Now this line reads this way: if installation or hooking fail, we inform PrestaShop.

{code}
public function hookLeftColumn($params)
  {
  global $smarty;
  return $this->display(__FILE__, 'mymodule.tpl');
  }
{code}

The {{hookLeftColumn()}} method makes it possible for the module to hook into the theme's left column.
{{$smarty}} is the global variable for the Smarty template system, which PrestaShop uses, and which we need to access.
The {{display()}} method returns the content of the {{mymodule.tpl}} template file, if it exists.

{code}
public function hookRightColumn($params)
  {
  return $this->hookLeftColumn($params);
  }
{code}

Likewise, {{hookRightColumn()}} gives access to the theme's right column. In this example, we simply call the {{hookLeftColumn()}} method, in order to have the very same display, whatever the column.

Save your file, and already you can hook it into the theme, move it around and transplant it: go to the "Positions" sub-tab for the "Modules" tab in the back-office, then click on the "Transplant a module" link.

In the transplantation form, find "My module" in the modules drop-down menu, then choose "Left column blocks" in the "Hook into" drop-down menu.

!_Images^devModule003-transplantModule.png|border=1!

{warning}It is useless to try to attach a module to a hook for which it has no implemented method.{warning}

Save. The "Positions" page should reload, with the following message: "Module transplanted successfully to hook". Congratulations\! Scroll down, and you should indeed see your module among the other modules from the "Left column blocks" list. Move it to the top of the list.

!_Images^devModule004-leftColumnList.png|border=1!


h2. Displaying content

Now that we have access to the left column, we should display something there.

As said earlier, the content to be displayed in the theme should be stored in {{.tpl}} files. We will create the {{mymodule.tpl}} file, which was passed as a parameter of the {{display()}} method in our module's code.

So, let's create the {{mymodule.tpl}} file, and add some lines of code to it.


{code:title=mymodule.tpl|borderStyle=solid}
<!-- Block mymodule -->
<div id="mymodule_block_left" class="block">
  <h4>Welcome!</h4>
  <div class="block_content">
    <ul>
      <li><a href="{$base_dir}modules/mymodule/mymodule_page.php" title="Click this link">Click me!</a></li>
    </ul>
  </div>
</div>
<!-- /Block mymodule -->
{code}

Save the file in the module's root folder, reload your shop's homepage: it should appear on top of the left column, right below the shop's logo.

!_Images^devModule005-topLeftColumnFO.png|border=1!

The displayed link doesn't lead anywhere for now. If you need to test it, add the needed {{mymodule_page.php}} file in the module's folder, with a minimal content, such as "Welcome to my shop\!" The resulting page will be very raw, so let's see if we can use the theme's style instead.

As you would expect, we have to create a TPL file in order to use the theme's style. Let's create the {{mymodule_page.tpl}} file, which will contain the basic line, and call that file from {{mymodule_page.php}}, which will add the theme's header, footer, etc.

{tip}
You should strive to use explicit and recognizable names for your TPL files, so that you can find them quickly in the back-office -- which is a must when using the translation tool.
{tip}

{code:title=mymodule_page.tpl|borderStyle=solid}
Welcome to my shop!
{code}

{code:title=mymodule_page.php|borderStyle=solid}
<?php
global $smarty;
include( '../../config/config.inc.php' );
include( '../../header.php' );

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

include( '../../footer.php' );
?>
{code}

We first load the current Smarty instance. This must be done before any call to the {{display()}} method.

The various {{include()}} calls in the file enable us to load:
* The current PrestaShop configuration.
* The theme's header file (through {{header.php}}, which acts as a load file).
* the theme's footer file (through {{footer.php}}, which acts as a load file).

In the middle of these, we place your custom template file, whose single action will be to display the "Welcome to my shop\!" line.

Save all files and reload your shop's homepage: with just a few lines, the end result is so much better, with our "Welcome" line neatly placed between header, footer and columns\!

!_Images^devModule006-welcomeFO.png|border=1!

{tip}
If you make multiple changes and reloads to your homepage, it may seem said changes do not apply. This is because Smarty caches a compiled version of the homepage. In order to force Smarty to recompile templates on every invocation, you must go to "Preferences" tab, its "Performance" sub-tab, and choose "Yes" for the "Force recompile" option.

!_Images^devModule007-forceRecompile.png|border=1!

*Do not force recompilation on production sites*, as it severely slows everything down\!
{tip}


h2. Using Smarty

Smarty is a PHP template engine, and is used by PrestaShop's theming system.



It parses TPL files, look for dynamic elements to replace by their data equivalents, then displays the generated result. Those dynamic elements are indicated with curly brackets: { ... }. The coder may create new variables and use them in TPL files.

For instance, in our {{mymodule_page.php}}, we can create such a a variable:


{code:title=mymodule_page.php|borderStyle=solid}
<?php
global $smarty;

include( '../../config/config.inc.php' );
include( '../../header.php' );

$mymodule = new MyModule();
$message = $mymodule->l( 'Welcome to my shop!' );
$smarty->assign( 'messageSmarty', $message ); // creation of our variable
$smarty->display( dirname(__FILE__) . '/mymodule_page.tpl' );

include( '../../footer.php' );
?>
{code}

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

{code:title=mymodule_page.tpl|borderStyle=solid}
{$messageSmarty}
{code}

PrestaShop includes a number 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.

All Smarty variables are global. You should therefore pay attention not to name your own variable with the name of an existing Smarty variable, in order to avoid overwriting it. It is good practice to avoid overly simple names, such as {{products}}.

Here is a list of Smarty variables that are common to all pages:

|| File / folder || Description ||
| img_ps_dir | URL for the PrestaShop image folder. |
| img_cat_dir | URL for the categories images folder. |
| img_lang_dir | URL for the languages images folder. |
| img_prod_dir | URL for the products images folder. |
| img_manu_dir | URL for the manufacturers images folder. |
| img_sup_dir | URL for the suppliers images folder. |
| img_ship_dir | URL for the carriers (shipping) images folder. |
| img_dir | URL for the theme's images folder. |
| css_dir | URL for the theme's CSS folder. |
| js_dir | URL for the theme's JavaScript folder. |
| tpl_dir | URL for the current theme's folder. |
| modules_dir | URL the modules folder. |
| mail_dir | URL for the mail templates folder. |
| pic_dir | URL for the pictures upload folder. |
| lang_iso | ISO code for the current language. |
| come_from | URL for the visitor's origin. |
| shop_name | Shop name. |
| cart_qties | Number of products in the cart. |
| cart | The cart. |
| currencies | The various available currencies. |
| id_currency_cookie | ID of the current currency. |
| currency | Currency object (currently used currency). |
| cookie | User cookie. |
| languages | The various available languages. |
| logged | Indicates whether the visitor is logged to a customer account. |
| page_name | Page name. |
| customerName | Client name (if logged in). |
| priceDisplay | Price display method (with or without taxes...). |
| roundMode | Rounding method in use. |
| use_taxes | Indicates whether taxes are enabled or not. |


If you need to have all of the current page's Smarty variables displayed, add the following function:

{code}
{debug}
{code}


Comments are based on asterisk:
{code}
{* This string is commented out *}
{code}

Unlike with a HTML comment, commented-out Smarty code is not present in the final output file.


h2. Module translation

Our module's text strings are written in English, but we might want French shop owners to use our module too. We therefore have to translate those strings into French, both front-office and back-offices ones. This could be a tedious task, but Smarty and PrestaShop's own translation make it far easier.

Strings in PHP files will need to be displayed through the {{l()}} method, from the {{Module.php}} abstract class.

{code:title=mymodule.php (partial)|borderStyle=solid}
...
$this->displayName = $this->l( 'My module' );
$this->description = $this->l( 'Description of my module.' );
...
{code}


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, this file:

{code:title=mymodule.tpl (partial)|borderStyle=solid}
<li>
  <a href="{$base_dir}modules/mymodule/mymodule_page.php" title="Click this link">Click me!</a>
</li>
{code}

...becomes:

{code:title=mymodule.tpl (partial)|borderStyle=solid}
<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>
{code}

...and this one:

{code:title=mymodule_page.tpl}
<h4>Welcome!</h4>
...
Click me!
{code}

...becomes:

{code:title=mymodule.tpl|borderStyle=solid}
<h4>{l s='Welcome!' mod='mymodule'}</h4>
...
{l s='Click me!' mod='mymodule'}
{code}


The translation tool needs the {{mod}} parameter in order to match the string to translate with its translation.
Strings are delimited with single quotes. If a string contains single quotes, they should be escaped using a backslash ().

This way, strings can be directly translated inside PrestaShop: go to the "Tools" tab, its "Translations" sub-tab, and in the "Modify translations" drop-down menu, choose "Module translations", then click the French flag in order to translate modules into French.

The next page displays all the strings for all the currently-installed modules. Modules that have all their strings already translated have their fieldset closed, whereas if at least one string is missing in a module's translation, its fieldset is expanded.
In order to translate your module's strings (the ones that were "marked" using the {{l()}} method), simply find your module in the list (use the browser's in-page search), and fill the empty fields.

!_Images^devModule008-translation.png|border=1!

Once all strings for your module are correctly translated, click on the "Update translation" button, either at the top or the bottom of the page.