Crear un Módulo - Parte 1

Crear un Módulo – Parte 1

5/5 (8)

Aprende a crear tu módulo para prestashop con este tutorial. Verás que es más sencillo de lo que parece si sigues estos pasos y consejos.

Antes de empezar

Muy recomendable tener bien estructurado lo que queremos mostrar y la forma cómo la mostraremos. Debemos pensar en:

  • ¿Dónde guardamos la información? Tabla configuración (poca información almacenada) o tablas propias.
  • ¿Dónde queremos que aparezca el módulo? Tener planificado el hook o hooks dónde va a aparecer o afectar el módulo.

Cuando tengamos estructurado esto vamos a empezar a programar.

Empezar el módulo

Vamos a crear una carpeta dentro del directorio modules dentro de nuestro Prestashop con un nombre único. Para que no haya errores de compatibilidad con otros módulos en un futuro.

En este caso el módulo lo vamos a llamar urimodulo. Así que éste va a ser el nombre del módulo: urimodulo.

Para este ejercicio vamos a crear un módulo que aparezca un texto en la página inicial. ¿Qué vamos a necesitar? La estructura completa – muy sencilla – va a ser esta:

 

Como veis tenemos 1 archivo .tpl para mostrar en el front office y un archivo .php con el mismo nombre que la carpeta (muy importante que el nombre sea idéntico) dónde vamos a definir todas las acciones del módulo. Empecemos.

Definición del módulo

El archivo urimodulo.php va a ser el que defina el módulo por completo (en módulos más complejos pueden haber archivos .php complementarios). En este archivo vamos a empezarlos definiendo que es un módulo:

Class UriModulo extends Module
{
    [...]
}

Importante

El módulo tiene que cumplir sí o sí estas condiciones. Sino no funcionará.

  • Carpeta del módulo tiene que tener el mismo nombre que el archivo que lo define.
  • El Class urimodulo extends Module tiene que llamarse como el archivo y la carpeta. Se recomienda ponerlo en FormatoCamel.

Funciones del módulo

En carácter general el módulo va a tener 4 funciones + la de los hooks. Vamos a explicarlas.

Funciones esenciales para el módulo de Prestashop que están marcadas por Prestashop. Importante no cambiarles el nombre.

  • public function __construct()
    • Esta función “construye” el módulo. Con la información descriptiva y tabs dónde está almacenado.
  • public function install()
    • Se ejecuta al instalar el módulo. Si, por ejemplo, tienes que crear tablas en la base de datos, lo pondrías aquí. También se registran aquí los hook donde se va a instalar el módulo.
  • public function uninstall()
    • Se ejecuta al desinstalar el módulo. Todo lo que se haya definido en install() se debe de ejecutar aquí pero a la inversa. Eliminar tablas, des-registrar los hooks…
  • public function getContent()
    • Esta función es opcional. Es la que coge la información para configurar el módulo. Si no hay que configurar nada no es necesaria esta función.

Función __construct()

    public function __construct()
    {
        $this->name = 'urimodulo';
        $this->version = '1.00.0';
        $this->author = 'urimarti.com';
        $this->displayName = $this->l('Uri Modulo');
        $this->description = $this->l('Uri Modulo Descripción');
        $this->controllers = array('default');
        $this->bootstrap = 1;
        parent::__construct();
    }

Como veis, definimos el nombre, versión, autor, descripción del módulo. Función Informativa pero Necesaria.

Función install()

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

Este sería el install más simple de todos. Sólo mira que el módulo esté instalado y le devuelve true. También lo que nos hace es registrar el módulo en el hook displayHome.

Función uninstall()

    public function uninstall()
    {
        if( !parent::uninstall() || !$this->unregisterHook('displayHome'))
            return false;
        return true;
    }

Este sería el uninstall más simple de todos. Sólo mira que el módulo esté desinstalado y le devuelve true. También elimina el registro del módulo en el hook displayHome.

Función getContent()

    public function getContent()
    {
        return $this->postProcess() . $this->getForm();
    }

Cada vez que entremos en el apartado de configurar el módulo vamos a acceder a esta función. En mi caso me gusta hacerlo limpio y le devuelvo 2 o 3 funciones. En este caso las funciones van a ser:

  • $this->postProcess()
  • $this->getForm()

Estas funciones las puedes llamar como quieras. Recomendable utilizar nombres en inglés por si en un futuro queremos compartir el módulo.

Función postProcess()

    public function postProcess()
    {
        if (Tools::isSubmit('urimodulo')) {
            $texto = Tools::getValue('texto');
            Configuration::updateValue('URI_MODULO_TEXTO_HOME', $texto);
            return $this->displayConfirmation($this->l('Updated Successfully'));
        }
    }

Esta función lo que hace es coger la información del formulario enviado – lo explicamos más abajo – y lo guarda en la tabla ps_configuration. Vamos a analizarla.

if (Tools::isSubmit(‘urimodulo’)) { … } Lo que nos mira es que si el formulario urimodulo está enviado (submit) haga lo siguiente:

$texto = Tools::getValue(‘texto’); Cogemos la variable del formulario que se llama texto

Configuration::updateValue(‘URI_MODULO_TEXTO_HOME’, $texto); Actualizamos la tabla ps_configuration y le asignamos a URI_MODULO_TEXTO_HOME la variable de $texto.

return $this->displayConfirmation($this->l(‘Updated Successfully’)); Si llega a este paso le devolveremos un mensaje de confirmación al usuario con el texto traducible Updated Successfully.

Función getForm()

    public function getForm()
    {
        $helper = new HelperForm();
        $helper->module = $this;
        $helper->name_controller = $this->name;
        $helper->identifier = $this->identifier;
        $helper->token = Tools::getAdminTokenLite('AdminModules');
        $helper->languages = $this->context->controller->getLanguages();
        $helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
        $helper->default_form_language = $this->context->controller->default_form_language;
        $helper->allow_employee_form_lang = $this->context->controller->allow_employee_form_lang;
        $helper->title = $this->displayName;

        $helper->submit_action = 'urimodulo';
        $helper->fields_value['texto'] = Configuration::get('URI_MODULO_TEXTO_HOME');
        
        $this->form[0] = array(
            'form' => array(
                'legend' => array(
                    'title' => $this->displayName
                 ),
                'input' => array(
                    array(
                        'type' => 'text',
                        'label' => $this->l('Texto'),
                        'desc' => $this->l('Qué texto quieres que aparezca en la página de inicio'),
                        'hint' => $this->l('Pista'),
                        'name' => 'texto',
                        'lang' => false,
                     ),
                 ),
                'submit' => array(
                    'title' => $this->l('Save')
                 )
             )
         );
        return $helper->generateForm($this->form);
    }

Esta función ya es un poco más compleja. Utilizamos la librería HelperForm de Prestashop (enlace de la información completa por Prestashop) para definir los campos del formulario que vamos a utilizar. De forma general lo único que se modifica de esta función es la array $this->form[] y, por supuesto, las variables que coge. Vamos a mirar qué hace:

        $helper = new HelperForm();
        $helper->module = $this;
        $helper->name_controller = $this->name;
        $helper->identifier = $this->identifier;
        $helper->token = Tools::getAdminTokenLite('AdminModules');
        $helper->languages = $this->context->controller->getLanguages();
        $helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
        $helper->default_form_language = $this->context->controller->default_form_language;
        $helper->allow_employee_form_lang = $this->context->controller->allow_employee_form_lang;
        $helper->title = $this->displayName;

Esto es muy genérico. Definimos el controlador del nombre, el módulo, idiomas… Y como todo es dinámico no es necesario editar nada para que funcione correctamente.

        $this->form[0] = array(
            'form' => array(
                'legend' => array(
                    'title' => $this->displayName
                 ),
                'input' => array(
                    array(
                        'type' => 'text',
                        'label' => $this->l('Texto'),
                        'desc' => $this->l('Qué texto quieres que aparezca en la página de inicio'),
                        'hint' => $this->l('Pista'),
                        'name' => 'texto',
                        'lang' => false,
                     ),
                 ),
                'submit' => array(
                    'title' => $this->l('Save')
                 )
             )
         );

Esta es la parte más importante. Tenemos un array que va a contener todos los elementos del formulario. Como veis tenemos 3 apartados grandes del array:

  • Legend. Es la leyenda del formulario. El título, icono, imagen, descripción de la cabecera del formulario.
  • Input. Contiene todos los inputs o entradas del formulario. Los textos, archivos, selects… Lo definimos todo dentro del array y nos lo va a mostrar automáticamente.
  • Submit. Definimos el botón de submit. Podemos darle clases, cambiar el nombre, añadir un botón de reset…

Nos vamos a centrar en el input. En este caso vamos a enviar sólo un input de tipo texto que tiene estos parámetros:

    ...
    array(
        'type' => 'text',
        'label' => $this->l('Texto'),
        'desc' => $this->l('Qué texto quieres que aparezca en la página de inicio'),
        'hint' => $this->l('Pista'),
        'name' => 'texto',
        'lang' => false,
     ),
    ...
  • type. Necesario. Definimos el tipo de input que es. Puede ser text, textarea, file, select, radio, switch, date…
  • label. Necesario. El la etiqueta o nombre que mostramos al usuario. El título que aparece a la izquierda para saber qué tenemos que poner.
  • desc. Opcional. Es la descripción del campo. Información complementaria que aparece debajo del campo para ayudar a saber qué poner en el campo.
  • hint. Opcional. Es una pista o ayuda. Esta información complementaria aparece en una caja cuando pasas el cursor por encima del label.
  • name. Necesario. ID del input. Tiene que ser un valor único. Es el que utilizamos para coger las variables y procesarlas.
  • lang. Opcional. Definimos si el input necesita o utiliza idiomas.

*Hay más campos para utilizar. Pero estos son los más genéricos. Tienes más información sobre qué elementos hay en la página de prestashop.

Y para terminar y mandar el formulario lo que hacemos es hacer un return del formulario pero ya formateado:

    return $helper->generateForm($this->form);

Hooks

Puedes leer mucho más sobre los hooks en esta página.

Tenemos registrado en el hook displayHome. ¿Como le pasamos la información? Para ello vamos a crear para cada uno de los hooks que queramos instalar una función que se llame hookNombreHook donde el NombreHook será el nombre del hook que estamos utilizando. En este caso utilizamos el hook displayHome. Así que la función será hookDisplayHome()

    public function hookDisplayHome()
    {
        $texto = Configuration::get('URI_MODULO_TEXTO_HOME');
        $this->context->smarty->assign(array(
            'texto_variable' => $texto,
        ));
        return $this->context->smarty->fetch($this->local_path.'views/templates/hook/home.tpl');
    }

Vamos a mirar uno a uno los diferentes elementos de la función del hook:

Cogemos la información almacenada dentro de la tabla ps_configuration que se llama URI_MODULO_TEXTO_HOME.

        $texto = Configuration::get('URI_MODULO_TEXTO_HOME');

Le asignamos las variables que utilizaremos dentro de la plantilla. Dónde el ‘texto_variable’ va a ser el nombre de la variable dentro de la plantilla y $texto es la variable que hemos definido arriba.

        $this->context->smarty->assign(array(
            'texto_variable' => $texto,
        ));

Para finalizar le haremos un return de la plantilla que utilizaremos.

        return $this->context->smarty->fetch($this->local_path.'views/templates/hook/home.tpl');

Plantilla .tpl

Para terminar sólo nos faltaría crear un archivo de plantilla .tpl para mostrar la información que queramos dentro del hook displayHome. Recordad que hemos definido arriba que la plantilla se encuentra en $this->local_path.’views/templates/hook/home.tpl’ así que tendremos que llamar el archivo home.tpl y alojarlo dentro de urimodulo/views/templates/hook/

<div id="uri_modulo">
    <h1>{l s='Texto Fijo Traducible' mod='urimodulo'}</h1>
    <p>{$texto_variable|escape:'html':'UTF-8'}</p>
</div>

Como veis le pasamos la variable definida en hookDisplayHome $texto_variable. Así que si lo hemos hecho todo correcto en el hook displayHome va a aparecer la plantilla que hemos creado con la variable que le pasemos definida en la configuración del módulo.

Para terminar os quiero dejar el archivo php escrito entero para no tener ninguna duda de como funcionar. Recordad mantener siempre la estructura para ahorraros problemas de compatibilidad.

<?php
/**
* NOTICE OF LICENSE
*
* This file is licenced under the Software License Agreement.
* With the purchase or the installation of the software in your application
* you accept the licence agreement.
*
* You must not modify, adapt or create derivative works of this source code
*
* @author urimarti.com
* @license LICENSE.txt
*/
Class UriModulo extends Module {
    public function __construct()
    {
        $this->name = 'urimodulo';
        $this->version = '1.00.0';
        $this->author = 'urimarti.com';
        $this->displayName = $this->l('Uri Modulo');
        $this->description = $this->l('Uri Modulo Descripción');
        $this->controllers = array('default');
        $this->bootstrap = 1;
        parent::__construct();
    }
    
    public function install()
    {
        if( !parent::install() || !$this->registerHook('displayHome'))
            return false;
        return true;
    }
    
    public function uninstall()
    {
        if( !parent::uninstall() || !$this->unregisterHook('displayHome'))
            return false;
        return true;
    }
    
    public function getContent()
    {
        return $this->postProcess() . $this->getForm();
    }
    
    public function getForm()
    {
        $helper = new HelperForm();
        $helper->module = $this;
        $helper->name_controller = $this->name;
        $helper->identifier = $this->identifier;
        $helper->token = Tools::getAdminTokenLite('AdminModules');
        $helper->languages = $this->context->controller->getLanguages();
        $helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
        $helper->default_form_language = $this->context->controller->default_form_language;
        $helper->allow_employee_form_lang = $this->context->controller->allow_employee_form_lang;
        $helper->title = $this->displayName;

        $helper->submit_action = 'urimodulo';
        $helper->fields_value['texto'][$id] = Configuration::get('URI_MODULO_TEXTO_HOME');
        
        $this->form[0] = array(
            'form' => array(
                'legend' => array(
                    'title' => $this->displayName
                 ),
                'input' => array(
                    array(
                        'type' => 'text',
                        'label' => $this->l('Texto'),
                        'desc' => $this->l('Qué texto quieres que aparezca en la página de inicio'),
                        'hint' => $this->l('Pista'),
                        'name' => 'texto',
                        'lang' => false,
                     ),
                 ),
                'submit' => array(
                    'title' => $this->l('Save')
                 )
             )
         );
        
        return $helper->generateForm($this->form);
         
    }
    
    public function postProcess()
    {
        if(Tools::isSubmit('urimodulo')) {
            $texto = Tools::getValue('texto');
            Configuration::updateValue('URI_MODULO_TEXTO_HOME', $texto);
            return $this->displayConfirmation($this->l('Updated Successfully'));
        }
    }
    
    public function hookDisplayHome()
    {
        $texto = Configuration::get('URI_MODULO_TEXTO_HOME');
        $this->context->smarty->assign(array(
            'texto_variable' => $texto,
        ));
        return $this->context->smarty->fetch($this->local_path.'views/templates/hook/home.tpl');
    }
 
}

[script]
var data_tree = [{
text: ‘modules’,
tags: [‘1’],
nodes: [{
text: ‘urimodulo’,
tags: [‘2’],
nodes: [{
text: ‘views’,
tags: [‘1’],
nodes: [{
text: ‘templates’,
tags: [‘1’],
nodes: [{
text: ‘hook’,
tags: [‘1’],
nodes: [{
text: ‘home.tpl’,
tags: [‘0’],
}],
}],

}],
},
{
text: ‘urimodulo.php’,
tags: [‘1’],
}],
}],
}];

jQuery(document).ready(function(){
jQuery(‘#treeview’).treeview({
levels:99,
data: data_tree
});
})
[/script]

Valoración de la Información

7 comentarios

  1. Amigo te felicito super tu pagina y la forma de explicar, en este momento estoy desarrollando un modulo donde se deben cargar unas subcategorias acorde una categoría seleccionada por el usuario, ya tengo cargando las categorías pero no se como mostrar las subcategorías dentro del mismo modulo, me podrías dar una luz por favor, mil gracias.

    1. Yo de tu lo que haría sería echar un vistazo a la classe de Category.php
      Lo primero que veo es que hay la función getSubcategories ($id_lang, $active = true) { … } y la función getChildren($id_parent, $id_lang, $active = true, $id_shop = false)

      No sé exactamente lo que devuelve cada función. Se debería de probar.

      En getSubcategories (…)
      Como vemos que no hay una variable de $id_category supongo que debe de cargarse la categoría en cuestión previamente.
      Entonces, lo que provaría yo es:
      1 – Crear la categoría como objeto. $category = new Category ($id_category);
      2- Buscar las subcategorías. $subcategories = $category->getSubCategories((int)$this->context->language->id);

      ¿Lo pruebas y me dices si funciona? Si no funcionara a la noche le doy un vistazo a ver cómo funciona exactamente la función o se puede utilizar otra que mejor se acerque a lo que necesitas.

  2. Hola. hice paso a paso, pero cuando doy clic en instalar me aparece “Necesita iniciar sesión en su cuenta de PrestaShop Addons para actualizar los (nombre modulo) módule. Haz clic aquí para iniciar sesión.” ¿Sabras a que se debe?

    1. Yo lo que haría sería activar el modo debug de tu prestashop. A lo mejor hay algún elemento que te está creando un error y no aparece; prestashop se confunde y te da un error que no es el correcto.

      Para habilitar el modo debug en Prestashop 1.6 debes abrir el ftp y dirigirte a la carpeta config/defines.inc.php y en la línea 28~30 debes encontrar un código dónde se le asigna el valor de ‘_PS_MODE_DEV_’ a false y cambiarlo a true. Es decir:
      pasar de esto:
      if (!defined(‘_PS_MODE_DEV_’)) {
      define(‘_PS_MODE_DEV_’, false);
      }

      a esto:
      if (!defined(‘_PS_MODE_DEV_’)) {
      define(‘_PS_MODE_DEV_’, true);
      }

      Cuando tengas el modo debug encendido intenta instalar otra vez el módulo a ver qué error te aparece.
      Yo recomiendo que siempre que se esté programando se utilice el modo debug para evitar errores que pasen desapercibidos.

      ¡Un saludo y gracias por el comentario!

  3. Buenas como andas? Muy buen sitio, pregunta si quisiera cargar datos en tablas creadas por mi como debería hacer. Gracias por su tiempo

  4. Hola, gracias por el detalle en la explicación.

    Como se hace si el formulario tiene más campos y es necesario crear tablas propias, de qué forma se almacena la información y se accede a ella ?

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *