Writing your own Prestashop Module – Part 5

The finishing touches

Introduction

In this part of our basic module writing tutorial series we'll look at the final steps to transform our Tutorialthird module class into a base template that we can use to kick start the writing of new modules. Rather than republish the same old code again we'll only discuss the changes, but I've added a download link at the end of this part so you can grab the final code and use it as the basis for your own projects. We're going to call this module "Skeleton" - a name that we'll replace with our own when it comes to producing new modules based on it.

Updated for Prestashop version 1.4 onwards.

Styling the configuration form

The first changes we're going to make are purely cosmetic, however this is an important element since we want to provide a consistent interface for our users. Our form code looked like:

private function _displayForm()
{
  $this->_html .= '
    <form action="'.$_SERVER['REQUEST_URI'].'" method="post">
      <label>'.$this->l('Message to the world').'</label>
      <div class="margin-form">
        <input type="text" name="our_message" />
      </div>
      <input type="submit" name="submit" value="'.$this->l('Update').'" class="button" />
    </form>';
}

The convention for these configuration screens is to wrap the settings in a fieldset, and we'll also need to add a nice friendly (translatable) legend complete with icon. Our code will now look like:

private function _displayForm()
{
  $this->_html .= '
    <form action="'.$_SERVER['REQUEST_URI'].'" method="post">
      <fieldset>
        <legend><img src="../img/admin/cog.gif" alt="" class="middle" />'.$this->l('Settings').'</legend>
        <label>'.$this->l('Message to the world').'</label>
        <div class="margin-form">
          <input type="text" name="our_message" />
        </div>
        <input type="submit" name="submit" value="'.$this->l('Update').'" class="button" />
      </fieldset>
    </form>';
}

Our final cosmetic change is to add a heading at the top of our settings screen just in case the user has forgotten where they are! We do this by adding the following line at the start of the getContent() function:

$this->_html .= '<h2> '.$this->displayName.'</h2>';

Pre-populating configuration form fields

Another missing element from our original tutorial design was the display of the current settings in the module configuration form, and even when the form returns from updating the values the fields are blank, so we need to fix this glitch too. There are two possibilities that we need to handle:

  1. Initial display of the form should display the current configuration (if any)
  2. After a form update we should display the data entered by the user

We can use the Configuration::get() function to retrieve the current settings from the database, and Tools::getValue() to get the field contents. The Tools::getValue() function takes a second parameter which is useful in this context, as this specifies a "default" to use should the field be empty. We can now set the "value" attribute of our input tag appropriately using these two functions, so our final form input code will be:

<input type="text" name="our_message" value="'.Tools::getValue('our_message', Configuration::get($this->name.'_message')).'"/>;

Another useful change to make when dealing with several fields in a configuration for is to move the database update code to it's own private function. For this we will replace the line:

if (!sizeof($this->_postErrors))
{
  Configuration::updateValue($this->name.'_message', Tools::getValue('our_message'), true);
  $this->_html .= '<div class="conf confirm">'.$this->l('Settings updated').'</div>';
}

with the following:

if (!sizeof($this->_postErrors))
  $this->_postProcess();

And we add the new private member function to our class to handle the actual updates in a single, easily identified location:

private function _postProcess()
{
  Configuration::updateValue($this->name.'_message', Tools::getValue('our_message'), true);
  $this->_html .= '<div class="conf confirm">'.$this->l('Settings updated').'</div>';
}

Handling other field types

In the final download of the skeleton module I've also added examples of other types of fields that will act as useful shortcuts to creating your module configuration form. This covers checkboxes, radio buttons, textarea and drop-down lists. All you need to do is add/rename the fields, add any validation required to the _postValidation() function and modify the update code in the _postProcess() function appropriately.

For mandatory settings you should also test for their presence in the install function and take appropriate action to prevent your module causing errors in the Front Office e.g. by setting appropriate defaults using the Configuration::updateValue() function. Alternatively this can be performed in the module constructor, although it is more correct to perform this within install().

Adding multiple display location hooks

Our Tutorialthird module could only display our content in the left column since this was the only hook we implemented. Luckily it's very easy to implement the "Transplant a module" BackOffice functionality in our code. In the simplest form we will just use the same output in all locations, but if required all of these additional hooks can produce different results.

To produce the same output in all the popular locations, we merely need to implement the additional hook functions in our module and call the original hook code to generate the output. Note that we only actually call registerHook() for the default one in the install() member function, and let the Back Office handle the registration of the others.

function hookRightColumn($params)
{
  return $this->hookLeftColumn($params);
}
function hookTop($params)
{
  return $this->hookLeftColumn($params);
}
function hookHome($params)
{
  return $this->hookLeftColumn($params);
}
function hookFooter($params)
{
  return $this->hookLeftColumn($params);
}

Summary

Over this series of articles you should have learned how the basic module system works in Prestashop and be able to code modules that deliver output to the different presentation areas in the Front Office. You'll also have a good code framework to base your own modules on. You may have noticed that at no time have we actually used smarty or its template files in the creation of our module -- this is deliberate as they can be seen as a separate entity from the module design itself.

Smarty is highly flexible, but the choice to use it is based on many factors, and for performance reasons it is best to avoid its use if at all possible. Later articles will explore how and when to use smarty to enhance your modules functionality though, as it is a fundamental part of the Prestashop architecture.

You can download the complete skeleton module code using the link below:

Skeleton v0.2.1 17th September 2011