Child pages
  • Creating a PrestaShop module

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

Table of contents

Table of Contents
maxLevel2

...

Creating a PrestaShop module

...

The mymodule.php file must start with the following test:

Code Block

if (!defined('_PS_VERSION_'))
  exit;

...

That class must bear the same name as the module and its folder, in 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 Block
borderStylesolid
titlemymodule.php
borderStylesolid

<?php
if (!defined('_PS_VERSION_'))
  exit;

class MyModule extends Module
  {
  public function __construct()
    {
    $this->name = 'mymodule';
    $this->tab = 'Test';
    $this->version = 1.0;
    $this->author = 'Firstname Lastname';
    $this->need_instance = 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;
    }
  }
?>

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

Code Block

public function __construct()

Defines the class' constructor.

Code Block

$this->name = 'mymodule';
$this->tab = 'Test';
$this->version = 1.0;
$this->author = 'PrestaShop';

...

  • A 'name' attribute. This is an internal identifier, so make it unique, without special characters or spaces, and keep it lower-case.
  • A 'tab' attribute. 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.
  • Version number for the module, displayed in the modules list.
  • An 'author' attribute. This is displayed in the PrestaShop modules list.
Code Block

$this->need_instance = 0;

The need_instance flag indicates whether to load the module's class when displaying the "Modules" page in the back-office. If set at 0, the module will not be loaded, and therefore will spend less resources to generate the page module. If your modules needs to display a warning message in the "Modules" page, then you must set this attribute to 1.

Code Block

parent::__construct();

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

Code Block

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

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 Block

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

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

Code Block

public function install()
  {
  return (parent::install());
  }

...

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

Code Block

public function uninstall()
  {
  if (!parent::uninstall())
    Db::getInstance()->Execute('DELETE FROM `'._DB_PREFIX_.'mymodule`');
  parent::uninstall();
  }

...

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

Code Block
borderStylesolid
titlemymodule.php (partial)
borderStylesolid

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);
  }

Let's explore these new or changed lines.

Code Block

if (parent::install() == false OR !$this->registerHook('leftColumn'))
  return false;
return true;

...

Therefore, this line now reads this way: if installation or hooking fail, we inform PrestaShop.

Code Block

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

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 Block

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

...

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

Code Block
borderStylesolid
titlemymodule.tpl
borderStylesolid

<!-- 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 -->

...

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.

Code Block
borderStylesolid
titlemymodule_page.tpl
borderStylesolid

Welcome to my shop!
Code Block
borderStylesolid
titlemymodule_page.php
borderStylesolid

<?php
global $smarty;
include('../../config/config.inc.php');
include('../../header.php');

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

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

...

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

Code Block
borderStylesolid
titlemymodule_page.php
borderStylesolid

<?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' );
?>

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

Code Block
borderStylesolid
titlemymodule_page.tpl
borderStylesolid

{$messageSmarty}

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.

...

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

Code Block

{debug}

Comments are based on asterisk:

Code Block

{* This string is commented out *}

{*
This string is too!
*}

...

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

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

Code Block
xml
xml
borderStylesolid
titlemymodule.tpl (partial)
borderStylesolid

<li>
  <a href="{$base_dir}modules/mymodule/mymodule_page.php" title="Click this link">Click me!</a>
</li>

...becomes:

Code Block
xml
xml
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>

...

Code Block
xml
xml
titlemymodule_page.tpl

<h4>Welcome!</h4>
...
Click me!

...becomes:

Code Block
xml
xml
borderStylesolid
titlemymodule.tpl
borderStylesolid

<h4>{l s='Welcome!' mod='mymodule'}</h4>
...
{l s='Click me!' mod='mymodule'}

...

The translations are saved in a new file, fr.php (or languageCode.php, which is generated by PrestaShop and looks like this:

Code Block
borderStylesolid
titlemymodule.tpl
borderStylesolid

<?php

global $_MODULE;
$_MODULE = array();
$_MODULE['<{mymodule}prestashop>mymodule_2ddddc2a736e4128ce1cdfd22b041e7f'] = 'Mon module';
$_MODULE['<{mymodule}prestashop>mymodule_d6968577f69f08c93c209bd8b6b3d4d5'] = 'Description de mon module';
$_MODULE['<{mymodule}prestashop>mymodule_c66b10fbf9cb6526d0f7d7a602a09b75'] = 'Cliquez sur ce lien';
$_MODULE['<{mymodule}prestashop>mymodule_f42c5e677c97b2167e7e6b1e0028ec6d'] = 'Cliquez-moi \!';
$_MODULE['<{mymodule}prestashop>mymodule_page_c0d7cffa0105851272f83d5c1fe63a1c'] = 'Bienvenue dans ma boutique \!';

...

  1. Add a new table to your PrestaShop database, named ps_test. Give it two fields:
    • id_test (INT 11)
    • test (VARCHAR 32)
  2. Create a blank file named Test.php in PrestaShop's /classes folder.
  3. Add the following lines to that file:
Code Block
borderStylesolid
titleTest.php
borderStylesolid

<?php
class Test extends ObjectModel 
  {
  /** @var string Name */
  public $test;

  protected $fieldsRequired = array('test');
  protected $fieldsSize = array('test' => 64);
  protected $fieldsValidate = array('test' => 'isGenericName');
  protected $table = 'test';
  protected $identifier = 'id_test';

  public function getFields() 
    {
    parent::validateFields();
    $fields['test'] = pSQL($this->test);
    return $fields;
    }
  }
?>
  1. Create a blank file named AdminTest.php in PrestaShop's /admin/tabs.
  2. Add the following lines to that file:
Code Block
borderStylesolid
titleAdminTest.php
borderStylesolid

<?php
include_once( PS_ADMIN_DIR.'/../classes/AdminTab.php');

class AdminTest extends AdminTab
  {
  public function __construct()
    {
    $this->table = 'test';
    $this->className = 'Test';
    $this->lang = false;
    $this->edit = true;
    $this->delete = true;
    $this->fieldsDisplay = array(
      'id_test' => array(
        'title' => $this->l('ID'),
        'align' => 'center',
        'width' => 25),
      'test' => array(
        'title' => $this->l('Name'),
        'width' => 200)
    );

    $this->identifier = 'id_test';

    parent::__construct();
    }

  public function displayForm()
    {
    global $currentIndex;

    $defaultLanguage = intval(Configuration::get('PS_LANG_DEFAULT'));
    $languages = Language::getLanguages();
    $obj = $this->loadObject(true);

    echo '
      <script type="text/javascript">
        id_language = Number('.$defaultLanguage.');
      </script>';

    echo '
      <form action="' . $currentIndex . '&submitAdd' .  $this->table . '=1&token=' . $this->token . '" method="post" class="width3">
        ' . ($obj->id ? '<input type="hidden" name="id_' . $this->table . '" value="' . $obj->id . '" />' : '').'
        <fieldset><legend><img src="../img/admin/profiles.png" />' . $this->l( 'Profiles' ) . '</legend>
          <label>'.$this->l( 'Name:' ).' </label>
          <div class="margin-form">';
    foreach ( $languages as $language )
      echo '
          <div id="name_' . $language['id_lang'|'id_lang'] . '" style="display: ' . ($language['id_lang'|'id_lang'] == $defaultLanguage ? 'block' : 'none') . '; float: left;">
            <input size="33" type="text" name="name_' . $language['id_lang'|'id_lang'] . '" value="' . htmlentities( $this->getFieldValue( $obj, 'name', intval( $language['id_lang'|'id_lang'] ) ), ENT_COMPAT, 'UTF-8' ) . '" /><sup>*</sup>
          </div>';
    $this->displayFlags( $languages, $defaultLanguage, 'name', 'name' );
    echo '
          <div class="clear"></div>
        </div>
        <div class="margin-form">
          <input type="submit" value="'.$this->l('Save').'" name="submitAdd'.$this->table.'" class="button" />
        </div>
        <div class="small"><sup>*</sup> '.$this->l('Required field').'</div>
      </fieldset>
    </form> ';
    }
  }
?>

...