How to write a PrestaShop module tutorial - making of Kinky Slider part 1

Tutorials

Kinky Slider - Free PrestaShop module

Author:

Front-end developer i freelancer, fan Star Wars i Terence'a McKenny

Hello and welcome to the first part of the PrestaShop tutorial that will cover creating a slider module from the scratch. You should have some general knowledge of PHP and object-oriented programming, JavaScript (jQuery) and Smarty. All new elements will be discussed as they appear so don't worry if  you haven't touched on some of the topics yet. If something is unclear or you find an inaccuracy in the text please use the comments to share your thoughts, I'm sure we'll all benefit from that.

We'll start off by looking at the PHP side of our project and the basics of the PrestaShop modules structure. By expanding our simple examples we will be able to depart from a "Hello world" app and arrive at a complete, working PrestaShop slider.

[NOTE: New, fixed version of the 0.1 release - links & paths problems should be no more]

Those of you interested in downloading an already built, full version of Bazinga's Kinky Slider pleaseuse one of the following links: Kinky Slider v0.1-fixed (zip) / Kinky Slider v0.1-fixed (tar.gz) 

This is the end result that we will be working on. The video is a bit choppy because my computer turned out to be a bit too slow to capture but here you go:


Setting our aim

  1. A PrestaShop slider with automatic image shrinking/enlargement during upload

  2. Nice and configurable looks, engaging animations, images preloaded, no Flash and no HTML5 Canvas

  3. The slider has to work with Internet Explorer 8

  4. Ability to add/edit text headers and price tags to the images and links to specific pages inside andoutside your shop.

Some tools we'll use

Apart from the PrestaShop engine, we will use two jQuery libraries that will make our work easier and more efficient:

jQuery 2d Transform plugin 0.9.3 (github.com/heygrady/transform/wiki) -  a jQuery library for 2d transforms and animations. All up-to-date web browsers (Google Chrome, FireFox, Opera, Safari, Internet Explorer 9) will be given a kick by the native use of CSS3. Older browsers (IE8 and IE7) will receive some special treatment and we'll try to make them behave as best as we can. 

jQuery Timers plugin (http://jquery.offput.ca/every/) -  a sweet WTFPL licensed library making the vents timing a piece of cake. We will use it to write our own images preloader and to code some other time-dependent things like cyclic image changes.

On the course of making the slider we will also help ourserlves with some ready to use PHP functions . We'll cover them later in the next parts of this tutorial.

The basics

If you are new to the concept of MVC programming (Model, View, Controller) you will get a chance to dive into it a bit while writing your PrestaShop module. Although PrestaShop might not strictly follow all the guides of a MVC application, we can still safely say that it consists of 3 interweaving layers:

  • Model: represents the data structure of the application and deals with all the Create, Read, Update, Delete (CRUD) functionality. The models in PrestaShop sit in the /classes folder. We will use the base class named Module as a basis for our module. 

  • View: responsible for the presentation of the data - each model can have unlimited number of views, thank to what you can show the same data in a number of ways. The views are held in the  /themes directory and are written using the Smarty templating language (we will look closer on that soon). Each module can have its own views, we just put them in the module directory and give them a .tpl extension

  • Controller: Deals with all the business logic of the application. It receives the requests from the user, interprets them and sends appropriate data to the View. Since PrestaShop 1.4 all controllersreside in the /controllers folder

We attach the modules in specific places on the page using PrestaShop hooks system. They are fairly easy to use and we will discuss them later on. Hooks let you easily change the position of your module if you want to. You can also add your own, non-standard hooks.

Building our first test module

Its job will be to appear in the Modules tab. We will stick to a convention during creating our own module directories and filenames: lowercase names for both files and directories. Just remember to put all your newly created PrestaShop modules in the /modules folder. 

  1. Create /modules/testone folder

  2. Create /modules/testone/testone.php file

  3. Copy the following content to the newly created testone.php:

class TestOne extends Module
{
  function __construct()
  {
    $this->name = 'testone';
    $this->tab = 'other';
    $this->version = '0.1.0';
    $this->author = 'You';
    parent::__construct();
    $this->displayName = $this->l('Our first module');
    $this->description = $this->l('This module does nothing yet.');
  }
} // End of: testone.php

The module should be now available from your admin panel. You can check it by browsing to modules -> Others tab.

Thanks to the fact that our little module extends from the core class Module, it inherits the methods and properties of its parent. That is why we could access here properties like name, tab and version without defining them beforehand. Just to be clear:  in the world of object driven programming the functions are usually called methods while the variables are called properties.

Treat your module as a child of the Module class. Your parent gives you a set of methods and properties to start with but you can change the way they work (override them)

The Test One module sets the following properties:

  1. name - internal name of the module, don't use spaces or any special signs here; stick to letters

  2. tab- name of one of the predefined categories of modules that your own module will appear in;Note: in versions prior to 1.4.x you could set the name here to anything you wanted; from 1.4 onwards you have to stick to the list of tabs - you can find this list at the end of the tutorial

  3. author- module's author

  4. version- module's version

  5. displayName - the name that the module will appear with on the modules list

  6. description- the description of the module in the admin panel

Accessing the properties and methods inside your own class

In order to set or change a given property inside the class use the $this variable. The same rule applies to the methods:

$getTheValue = $this->propertyName;
$result = $this->methodName($parameter);

Constructors, parents and translations

function __construct()  and parent::__construct()

First, imagine that the PrestaShop module in a form of PHP class that we are writting is not a ready to use object yet but a form that is used to make the objects. In order to gain access to the object, PrestaShop has to first create the object based on the code that we provide inside our class.

The __construct() function is a special kind of function. It is run right after the creation of a new object.  It sets various start-up things, think of it as if it was car starter.

What we did was in fact here was to override the already written __construct() function that is present inside the parent class Module . After we set some specific things here we have to give a hint to our parent class that it now can execute the rest of its original code. We give this hint by writting parent::__construct() inside our child-module.

$this->l('Your text here') :

By using the l()method instead of writing your text strings directly you allow for further translations ofall the messages inside the module. Just wrap all your messages in this function and you will make life easier for other people.

Module Test Two

Let's create a bit more sophisticated module now. It will display a message in the PrestaShop front office using the data that we enter in the admin panel. We will learn one of the ways to store data in database here. 

  1. Create /modules/testtwo folder

  2. Create /modules/testtwo/testtwo.php file

  3. Create /modules/testtwo/testtwo.tpl file

  4. Paste the following content into testtwo.php:

class TestTwo extends Module {
                                                                            
private $_html= '';
                                                                            
function __construct() {
    $this->name = 'testtwo';
    $this->tab = 'other';
    $this->version = '0.2.0';
    $this->author = 'You';
    parent::__construct();
    $this->displayName = $this->l('Our second module');
    $this->description = $this->l('This module is a real hello world!.');
}
                                                                            
public function install() {
    parent::install();
    if(!$this->registerHook('leftColumn')) return false;
    return true;
}
                                                                            
public function getContent() {
                                                                            
    if(Tools::isSubmit('submit_text')) {
                                                                            
      Configuration::updateValue(
              $this->name.'_text_to_show',
              Tools::getValue('the_text')
              );
                                                                            
    }
                                                                            
    $this->_generateForm();
    return $this->_html;
}
                                                                            
private function _generateForm() {
                                                                            
    $textToShow=Configuration::get($this->name.'_text_to_show');
                                                                            
    $this->_html .= '<form action="'.$_SERVER['REQUEST_URI'].'" method="post">';
    $this->_html .= '<label>'.$this->l('Enter your text: ').'</label>';
    $this->_html .= '<div class="margin-form">';
    $this->_html .= '<input type="text" name="the_text" value="'.$textToShow.'" >';
    $this->_html .= '<input type="submit" name="submit_text" ';
    $this->_html .= 'value="'.$this->l('Update the text').'" class="button" />';
    $this->_html .= '</div>';
    $this->_html .= '</form>';
}
                                                                            
public function hookLeftColumn() {
                                                                            
    global $smarty;
    $smarty->assign('our_text',Configuration::get($this->name.'_text_to_show'));
    return $this->display(__FILE__, 'testtwo.tpl');
                                                                            
}
                                                                            
} // End of: testtwo.php

Then paste this content into testtwo.tpl:

<br />
And our message is: {$our_text}
<br />

After you have installed the new module you will see that the Configure option is now enabled. Click it and you should see now a HTML form.  Fill it in with any message you like and click "Update the text". Check the front-office now: on the bottom of the left column you should be able to spot  "And our message is: " followed by the text you entered in the admin panel.

Three times P

As far as the structure of the second test module goes, some new methods appeared here as well as a new property: $_html. We'll use this property to store and output the html form (the one you just used in the admin panel to enter your message).  Let's stop for a moment and focus on the three keywords that appear throughout our module: privatepublic and protected:

private $_html= '';

By using one of these keywords you can set the appriopiate acceess to the methods and properties inside your class:

  • private: properties and methods will be accessible only from inside the class; Classes inherited from this class will have no access to these properties and methods

  • protected: similiar to private, but protected methods and properties can be accessed from the classes that inherit from the given class

  • public: public properties and methods are accessible both from the outside of the class and from the inside of the class; Any inheriting class inherits the public methods and properties.

The getContent() method

The getContent() method is responsible for displaying all the configuration options for our module in the admin panel and dealing with your input there.

In the current state of development, getContent() checks if the admin submitted the form using the "submit_text" button and if so - it updates the database key with the entered value. The name of the key in the database will be as follows:

$this->name.'_text_to_show' // == testtwo_text_to_show

When using the database to store our data we will stick to a convention: all keys will be preceded by the name of our module that is set in $this->name variable. Thanks to that we'll keep our records clean and we won't do to much mess.

4 important functions used in this test example

Tools::isSubmit('nameOfTheButton')

Used to check if  a form was submitted using the specified button name.

Tools::getValue('nameOfTheField')

Receives the $_POST value corresponding to the given field name from the submitted form.

Configuration::updateValue('nameOfTheKey', 'value');

Thanks to this function we can easily create and update our own configuration rows in the database. The first parameter specifies the key under which we'll save our value while the second one is the value itself. All configuration rows we create land inside the ps_configuration table in the database. Note that ps_ is a standard PrestaShop prefix for database tables and you might have chosen a different one during the installation of PrestaShop on your server.

Configuration::get('nameOfTheKey');

This function receives the data stored in the database. It requires only one parameter, that is the name of the key that you used during inserting the data into the database.

Let's get back to getContent()

At the very on of the getContent() method we return the content of the $this->_html variable that holds the ordinary html code to display the form in our little configuration panel. Due to the fact that getContent() will be growing in our examples we'll put the code that generates this configuration form in a separate function called _generateForm() and call it from withing the getContent() method:

private function _generateForm() {
                                                                              
    $textToShow=Configuration::get($this->name.'_text_to_show');
                                                                              
    $this->_html .= '<form action="'.$_SERVER['REQUEST_URI'].'" method="post">';
    $this->_html .= '<label>'.$this->l('Enter your text: ').'</label>';
    $this->_html .= '<div class="margin-form">';
    $this->_html .= '<input type="text" name="the_text" value="'.$textToShow.'" >';
    $this->_html .= '<input type="submit" name="submit_text" ';
    $this->_html .= 'value="'.$this->l('Update the text').'" class="button" />';
    $this->_html .= '</div>';
    $this->_html .= '</form>';
}

In the above example we used the already mentioned method Configuration::get() to insert the value from the database into our form so that after successful update we could se the entered message in our admin panel.

The last step, point a : hooks

One of the last things we have to do in order to complete our module is to place it at the right place on the page. That's where the hooks come into play. We hook the modules inside the install() method. As we want our module to appear in the left column, we shall write:

public function install() {
    parent::install();
    if(!$this->registerHook('leftColumn')) return false;
    return true;
}

By passing a parameter to the registerHook method, we will choose the place for our module to appear. We can choose various different hooks, but here are the most commonly used:

  • rightColumn - the right column

  • leftColumn - the left column

  • home - the center of the main page

  • header

  • top - the very top of the page

  • footer

The last step, point b : hookLeftColumn()

There is one more function left to write in order to hook the module where we wanted. We have to name it using the convention: hook+name of the hook. In our example it will be named: hookLeftColumn() :

public function hookLeftColumn() {
                                                                              
    global $smarty;
    $smarty->assign('our_text',Configuration::get($this->name.'_text_to_show'));
    return $this->display(__FILE__, 'testtwo.tpl');
                                                                              
}

Here's the explenation of what just happened. In the foreword we mentioned the use of Smarty in the building process of the modules. Smarty is a templating language that helps to maintain the code between the front-end developer and the back-end developer. The minus is that we have to learn a new thing. The plus is that we can learn a new thing :) Smarty syntax is easy to learn and you can grasp it in a matter of minutes. PrestaShop uses Smarty in the View files so at the very end of the production chain we will not be using PHP direcly. All the data that comes out of our module will be assigned to Smarty variables . Here's how you do it: 

$smarty->assign('nameOfTheVariable','value');

We just assigned our message that we want to display to a Smarty variable named our_text . It's time now to show PrestaShop which View file it should use to render our content. One more thing, from this moment on all Smarty variables will be in green.

The View files are those with the .tpl extension. If you went step by step with this tutorial's instructions you should already have created the /modules/testtwo/testtwo.tpl file:

<br/>
And our message is: {$our_text}
<br/>

As you can see, we use regular HTML inside .tpl files. You can put here JavaScript code too. The difference is, that inside .tpl files you can also access the previously defined Smarty variables. Here you have an example of the most basic use of Smarty: opening bracket, dolar sign, Smarty variable name and a closing bracket. Just enough to show your message on the screen.

Thank you for reading! I hope this humble tutorial inspired you to go deeper in the subject of writing your own modules using the PrestaShop engine. We'll try to upload the second part of the Kinky Slider tutorial as soon as we can; we want to introduce some faster ways of accessing the database, getting and storing data from multiple form fields, more Smarty and - if the size of the content will be still beyond the attention span length radar - uploading files with PrestaShop.

We prepared a small list of links that you might find useful while learning to develop your own PrestaShop based modules:

  1. The source of everything: www.google.com

  2. PrestaShop Development Guide - all you need to know: http://www.nethercottconstructions.com/en/content/32-prestashop-development-guide

  3. Classes, object-driven programming: http://php.net/manual/en/language.oop5.visibility.php

  4. A very good PrestaShop modules tutorial: http://www.ecartservice.net/17072009/writing-your-own-prestashop-module-part-1/

  5. Article about PrestaShop hooks: http://www.prestashop.com/blog/article/better_understand_and_use_hooks_by_julien_breux

  6. A list of PrestaShop hooks: http://www.techietips.net/prestashop-list-of-hooks-version-131.html