Aspect Oriented Programming
Springboot embeded flowable

Prestashop 1.7 module

I’ve installed a Prestashop store because…​ It’s free and open source. I need some modules like EU cookie banner and I don’t want to pay 30+€ just for that.

I looked at the community solution but I didn’t find a solution that transcended me…​ And in fact, it’s a good "hello world" example for me to learn how to create modules for Prestashop.

The full implementation of the module can be found in this GitHub project.

Environment

For this tutorial, I use a fresh installed Prestashop 1.7.2.1 and PHP 7.1.1.

I use a symbolic link to add my git source folder to prestashopFolder/modules/z_cookiesalert

Initialization

For initializing the module files, you can follow the Prestashop documentation.

But it’s full of naming convention and specific folder organization. Your module folder must be lowercase (z_cookiesalert). The first php file name must be lowercase too (z_cookiesalert.php). The class name in this file must be camlCase (class Z_Cookiesalert extends Module). And don’t forget everytime you add a folder, you must add an index.php file.

The easiest way I found on community forum is to start from an existing module (get an official one from Prestashop’s GitHub) and modify the names.

Another tip is to target 1.7+ compatibility and forget 1.6 and 1.5. There are too many differences between well-organized modules for 1.7 and for preview versions.

The module

The z_cookiesalert.php content must start by

1
2
3
if (!defined('_PS_VERSION_')) {
    exit;
}
The sole purpose of this is to prevent malicious visitors to load this file directly.

After that, we need to create the main class with the module description. All information on the __construct method will be used by Prestashop to generate the config.xml file.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Z_Cookiesalert extends Module
{
    public function __construct()
    {
        $this->name = 'z_cookiesalert';
        $this->tab = 'front_office_features';
        $this->version = '0.1.0';
        $this->author = 'Zomzog';
        $this->need_instance = 0;
        $this->ps_versions_compliancy = array('min' => '1.7', 'max' => _PS_VERSION_);
        $this->bootstrap = true;

        parent::__construct();

        $this->displayName = $this->l('Cookies Alert');
        $this->description = $this->l('Cookies alert for users.');

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

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

The front office

For displaying the ribbon message, we will add a hook to the "displayFooter" hook. And we will add all css and js required on the "header" hook. At installation, we will also declare a default content message for the ribbon.

1
2
3
4
5
6
7
public function install()
{
    return parent::install() &&
        $this->registerHook('displayFooter') &&
        $this->registerHook('header') &&
        Configuration::updateValue('Z_COOKIES_ALERT_MESSAGE', 'En poursuivant votre navigation, vous acceptez l\'utilisation des cookies pour disposer de services et d\'offres adaptés à vos centres d\'intérêt.');
}

To get the hooked content, Prestashop will look at the method named hookNameOfTheHook. In our case, it will be hookDisplayFooter and hookDisplayHeader.

We will register the module’s stylesheet and the module’s javascript files on the header with :

1
2
3
4
5
public function hookDisplayHeader()
{
    $this->context->controller->registerStylesheet('modules-z_cookiesalert', 'modules/' . $this->name . '/views/css/z_cookiesalert.css', ['media' => 'all', 'priority' => 150]);
    $this->context->controller->registerJavascript('modules-z_cookiesalert', 'modules/' . $this->name . '/views/js/z_cookiesalert.js', ['position' => 'bottom', 'priority' => 150]);
}

For the footer, if the cookie usage has not been accepted yet ( check on the cookie =D ), we will add two parameters to smarty and display the cookiealert template.

The back office

The content of the ribbon must be customizable by the end user. For this, we must declare a new displayConfigForm method. For having a uniform render, Prestashop advice to use HelperForm.

For this, we will create a $fields_form with all required fields and use the helper to configure the render.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public function displayConfigForm()
{
    // Get default language
    $default_lang = (int)Configuration::get('PS_LANG_DEFAULT');

    // Init Fields form array
    $fields_form = array(
        'form' => array(
            'legend' => array(
                'title' => $this->l('Settings'),
            ),
            'input' => array(
                array(
                    'type' => 'text',
                    'label' => $this->l('Message'),
                    'name' => 'Z_COOKIES_ALERT_MESSAGE',
                    'size' => 128,
                    'required' => true
                )
            ),
            'submit' => array(
                'title' => $this->l('Save'),
                'class' => 'btn btn-default pull-right'
            )
        )
    );

    $helper = new HelperForm();

    // Module, token and currentIndex
    $helper->module = $this;
    $helper->name_controller = $this->name;
    $helper->token = Tools::getAdminTokenLite('AdminModules');
    $helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;

    // Language
    $helper->default_form_language = $default_lang;
    $helper->allow_employee_form_lang = $default_lang;

    // Title and toolbar
    $helper->title = $this->displayName;
    $helper->show_toolbar = true;        // false -> remove toolbar
    $helper->toolbar_scroll = true;      // yes - > Toolbar is always visible on the top of the screen.
    $helper->submit_action = 'submit' . $this->name;
    $helper->toolbar_btn = array(
        'save' =>
            array(
                'desc' => $this->l('Save'),
                'href' => AdminController::$currentIndex . '&configure=' . $this->name . '&save' . $this->name .
                    '&token=' . Tools::getAdminTokenLite('AdminModules'),
            ),
        'back' => array(
            'href' => AdminController::$currentIndex . '&token=' . Tools::getAdminTokenLite('AdminModules'),
            'desc' => $this->l('Back to list')
        )
    );

    // Load current value
    $helper->fields_value['Z_COOKIES_ALERT_MESSAGE'] = Configuration::get('Z_COOKIES_ALERT_MESSAGE');

    return $helper->generateForm(array($fields_form));
}

The ajax call

When the user closes the ribbon, we want to create an ajax call to update the cookie on the server side. For this, we must create a front controller. We will add a cookies.php file on z_cookiealert/controllers/front/. This file will declare a ModuleFrontController. The naming convention will force the name to Z_CookiesalertCookiesModuleFrontController class.

When the class will be called, it will set the cookiealert to accepted and response true.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
require_once _PS_MODULE_DIR_.'z_cookiesalert/z_cookiesalert.php';

class Z_CookiesalertCookiesModuleFrontController extends ModuleFrontController {

    public function initContent()
    {
        $module = new Z_Cookiesalert;

        if (Tools::isSubmit('action')) {
            $context = Context::getContext();
            $cookie = $context->cookie;

            $cookie->__set('zcookiealert', "accepted");

            $response = array('status' => true, "message" => $module->l('Done.'));
        }
       die(Tools::jsonEncode($response));
    }
}

For calling the controller, we must resolve the url to the controller. The easiest way to do that is to use url method on the template. For this, we will add a data-url attribute to cookie_alert div.

1
<div id="cookies_alert" data-url="{url entity='module' name='z_cookiesalert' controller='Cookies' params = [action => 'action_name']}"
This information will be resolve at display. And we will be able to add a javascript click handler with jquery like :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$(document).ready(function() {
    var cookieContent = $('.cookies_alert');

    $('.accept-cookie').click(function () {
        $.getJSON($('div.cookies_alert').data('url'), {}, function(data) {
            if(typeof data.status !== "undefined") {
                // Do something
            }
        });
        cookieContent.hide(500);
    });
});

Aspect Oriented Programming
Springboot embeded flowable

Share

comments powered by Disqus