Cómo añadir nuevos campos a la dirección del cliente en Prestashop 1.6

30 noviembre, 2014 |

Si te gusta, compártelo ;)

En este tutorial vamos a ver cómo añadir nuevos campos a la dirección del cliente en Prestashop 1.6. También podemos hacerlo en Prestashop 1.5. Me refiero a esto:

La dirección del cliente en Prestashop

Como podéis ver en la imagen de arriba, hay un nuevo campo en el formulario de dirección del cliente.


Compatibilidad: Prestashop 1.6 y 1.5

Descargar los archivos del proyecto

Lo que vamos a hacer...

Con el fin de añadir un nuevo campo al formulario de inscripción del cliente, vamos a crear un par de overrides, también crearemos un nuevo campo en la base de datos, y por último, modificaremos el archivo address.tpl de nuestro tema.

La clase address y la base de datos

Queremos que el cliente pueda rellenar un campo que no existe, por lo tanto debemos crear un campo en nuestra base de datos. Así que, vayamos a nuestra herramienta para manejar nuestras bases de datos (en mi caso phpMyAdmin), y accedamos a la tabla ps_address para crear un campo nuevo:

Tabla address de Prestashop

Como vemos en la imagen, tenemos que agregar un campo de tipo VARCHAR y 64 de longitud.

Ahora tenemos que informar al objeto address (la clase) de que tiene un nuevo campo a tratar. Asi que, debemos crear un archivo dentro de prestashop/override/classes/ y lo llamaremos Address.php. Agreguemos el siguiente código (sin olvidar la etiqueta de apertura <?php) dentro del archivo:

class Address extends AddressCore
{

 public $mi_campo;

 public static $definition = array(
  'table' => 'address',
  'primary' => 'id_address',
  'fields' => array(
   'id_customer' =>   array('type' => self::TYPE_INT, 'validate' => 'isNullOrUnsignedId', 'copy_post' => false),
   'id_manufacturer' =>  array('type' => self::TYPE_INT, 'validate' => 'isNullOrUnsignedId', 'copy_post' => false),
   'id_supplier' =>   array('type' => self::TYPE_INT, 'validate' => 'isNullOrUnsignedId', 'copy_post' => false),
   'id_warehouse' =>   array('type' => self::TYPE_INT, 'validate' => 'isNullOrUnsignedId', 'copy_post' => false),
   'id_country' =>   array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
   'id_state' =>    array('type' => self::TYPE_INT, 'validate' => 'isNullOrUnsignedId'),
   'alias' =>     array('type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => true, 'size' => 32),
   'company' =>    array('type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'size' => 64),
   'lastname' =>    array('type' => self::TYPE_STRING, 'validate' => 'isName', 'required' => true, 'size' => 32),
   'firstname' =>    array('type' => self::TYPE_STRING, 'validate' => 'isName', 'required' => true, 'size' => 32),
   'vat_number' =>    array('type' => self::TYPE_STRING, 'validate' => 'isGenericName'),
   'address1' =>    array('type' => self::TYPE_STRING, 'validate' => 'isAddress', 'required' => true, 'size' => 128),
   'address2' =>    array('type' => self::TYPE_STRING, 'validate' => 'isAddress', 'size' => 128),
   'postcode' =>    array('type' => self::TYPE_STRING, 'validate' => 'isPostCode', 'size' => 12),
   'city' =>     array('type' => self::TYPE_STRING, 'validate' => 'isCityName', 'required' => true, 'size' => 64),
   'other' =>     array('type' => self::TYPE_STRING, 'validate' => 'isMessage', 'size' => 300),
   'phone' =>     array('type' => self::TYPE_STRING, 'validate' => 'isPhoneNumber', 'size' => 32),
   'phone_mobile' =>   array('type' => self::TYPE_STRING, 'validate' => 'isPhoneNumber', 'size' => 32),
   'dni' =>     array('type' => self::TYPE_STRING, 'validate' => 'isDniLite', 'size' => 16),
   'deleted' =>    array('type' => self::TYPE_BOOL, 'validate' => 'isBool', 'copy_post' => false),
   'date_add' =>    array('type' => self::TYPE_DATE, 'validate' => 'isDateFormat', 'copy_post' => false),
   'date_upd' =>    array('type' => self::TYPE_DATE, 'validate' => 'isDateFormat', 'copy_post' => false),
   'mi_campo' =>    array('type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'size' => 64),

  ),
 );
}
Analicemos el código anterior. Como podemos ver, no estamos asignando el nuevo campo sobre la creación de la instancia, estamos haciendo override sobre la definición (con definición nos referimos a $definition). La razón es sencilla: La definición de Address se denomina estática cuando se crea una nueva dirección en el Front-office, y si añadimos el nuevo campo en el método construct, nos hubiéramos perdido en la lista.

Esta definición proviene de Prestashop 1.6.0.5, y por lo tanto es recomendable modificar la clase Address original en caso de tener una versión de Prestashop anterior. La clase Address original se encuentra en prestashop/classes/Address.php

El controlador Address del Back-office

Ahora tenemos que hacer override sobre el controlador del Back-office, que es el responsable de mostrar el formulario para modificar la dirección de cada cliente.

Para ello debemos crear el archivo AdminAddressesController.php en prestashop/override/controllers/admin. Necesitamos extender el método renderForm(); por lo tanto debemos tomar el archivo original prestashop/controllers/admin/AdminAddressesController.php; localizaremos el método renderForm() y lo copiaremos.
A continuación, debemos agregar el siguiente código dentro de nuestro controlador en la carpeta del override...

class AdminAddressesController extends AdminAddressesControllerCore
{

}

... y ahora pegamos el método renderForm() dentro de la clase. Así es como queda el mío (en Prestashop 1.6.0.5):

class AdminAddressesController extends AdminAddressesControllerCore
{

public function renderForm()
 {
  $this->fields_form = array(
   'legend' => array(
    'title' => $this->l('Addresses'),
    'icon' => 'icon-envelope-alt'
   ),
   'input' => array(
    array(
     'type' => 'text_customer',
     'label' => $this->l('Customer'),
     'name' => 'id_customer',
     'required' => false,
    ),
    array(
     'type' => 'text',
     'label' => $this->l('Identification Number'),
     'name' => 'dni',
     'required' => false,
     'col' => '4',
     'hint' => $this->l('DNI / NIF / NIE')
    ),
    array(
     'type' => 'text',
     'label' => $this->l('Address alias'),
     'name' => 'alias',
     'required' => true,
     'col' => '4',
     'hint' => $this->l('Invalid characters:').' <>;=#{}'
    ),
    array(
     'type' => 'text',
     'label' => $this->l('Home phone'),
     'name' => 'phone',
     'required' => false,
     'col' => '4',
     'hint' => Configuration::get('PS_ONE_PHONE_AT_LEAST') ? sprintf($this->l('You must register at least one phone number.')) : ''
    ),
    array(
     'type' => 'text',
     'label' => $this->l('Mobile phone'),
     'name' => 'phone_mobile',
     'required' => false,
     'col' => '4',
     'hint' => Configuration::get('PS_ONE_PHONE_AT_LEAST') ? sprintf($this->l('You must register at least one phone number.')) : ''
    ),
    array(
     'type' => 'textarea',
     'label' => $this->l('Other'),
     'name' => 'other',
     'required' => false,
     'cols' => 15,
     'rows' => 3,
     'hint' => $this->l('Forbidden characters:').' <>;=#{}'
    ),
   ),
   'submit' => array(
    'title' => $this->l('Save'),
   )
  );
  $id_customer = (int)Tools::getValue('id_customer');
  if (!$id_customer && Validate::isLoadedObject($this->object))
   $id_customer = $this->object->id_customer;
  if ($id_customer)
  {
   $customer = new Customer((int)$id_customer);
   $token_customer = Tools::getAdminToken('AdminCustomers'.(int)(Tab::getIdFromClassName('AdminCustomers')).(int)$this->context->employee->id);
  }

  $this->tpl_form_vars = array(
   'customer' => isset($customer) ? $customer : null,
   'tokenCustomer' => isset ($token_customer) ? $token_customer : null
  );

  // Order address fields depending on country format
  $addresses_fields = $this->processAddressFormat();
  // we use  delivery address
  $addresses_fields = $addresses_fields['dlv_all_fields'];

  $temp_fields = array();

  foreach ($addresses_fields as $addr_field_item)
  {
   if ($addr_field_item == 'company')
   {
    $temp_fields[] = array(
     'type' => 'text',
     'label' => $this->l('Company'),
     'name' => 'company',
     'required' => false,
     'col' => '4',
     'hint' => $this->l('Invalid characters:').' <>;=#{}'
    );
    $temp_fields[] = array(
     'type' => 'text',
     'label' => $this->l('VAT number'),
     'col' => '2',
     'name' => 'vat_number'
    );
   }
   else if ($addr_field_item == 'lastname')
   {
    if (isset($customer) &&
     !Tools::isSubmit('submit'.strtoupper($this->table)) &&
     Validate::isLoadedObject($customer) &&
     !Validate::isLoadedObject($this->object))
     $default_value = $customer->lastname;
    else
     $default_value = '';

    $temp_fields[] = array(
     'type' => 'text',
     'label' => $this->l('Last Name'),
     'name' => 'lastname',
     'required' => true,
     'col' => '4',
     'hint' => $this->l('Invalid characters:').' 0-9!&lt;&gt;,;?=+()@#"�{}_$%:',
     'default_value' => $default_value,
    );
   }
   else if ($addr_field_item == 'firstname')
   {
    if (isset($customer) &&
     !Tools::isSubmit('submit'.strtoupper($this->table)) &&
     Validate::isLoadedObject($customer) &&
     !Validate::isLoadedObject($this->object))
     $default_value = $customer->firstname;
        else
         $default_value = '';

    $temp_fields[] = array(
     'type' => 'text',
     'label' => $this->l('First Name'),
     'name' => 'firstname',
     'required' => true,
     'col' => '4',
     'hint' => $this->l('Invalid characters:').' 0-9!&lt;&gt;,;?=+()@#"�{}_$%:',
     'default_value' => $default_value,
    );
   }
   else if ($addr_field_item == 'address1')
   {
    $temp_fields[] = array(
     'type' => 'text',
     'label' => $this->l('Address'),
     'name' => 'address1',
     'col' => '6',
     'required' => true,
    );
   }
   else if ($addr_field_item == 'address2')
   {
    $temp_fields[] = array(
     'type' => 'text',
     'label' => $this->l('Address').' (2)',
     'name' => 'address2',
     'col' => '6',
     'required' => false,
    );
   }
   elseif ($addr_field_item == 'postcode')
   {
    $temp_fields[] = array(
     'type' => 'text',
     'label' => $this->l('Zip/Postal Code'),
     'name' => 'postcode',
     'col' => '2',
     'required' => true,
    );
   }
   else if ($addr_field_item == 'city')
   {
    $temp_fields[] = array(
     'type' => 'text',
     'label' => $this->l('City'),
     'name' => 'city',
     'col' => '4',
     'required' => true,
    );
   }
   else if ($addr_field_item == 'country' || $addr_field_item == 'Country:name')
   {
    $temp_fields[] = array(
     'type' => 'select',
     'label' => $this->l('Country'),
     'name' => 'id_country',
     'required' => false,
     'col' => '4',
     'default_value' => (int)$this->context->country->id,
     'options' => array(
      'query' => Country::getCountries($this->context->language->id),
      'id' => 'id_country',
      'name' => 'name'
     )
    );
    $temp_fields[] = array(
     'type' => 'select',
     'label' => $this->l('State'),
     'name' => 'id_state',
     'required' => false,
     'col' => '4',
     'options' => array(
      'query' => array(),
      'id' => 'id_state',
      'name' => 'name'
     )
    );
   }
  }

  // merge address format with the rest of the form
  array_splice($this->fields_form['input'], 3, 0, $temp_fields);

  return parent::renderForm();
 }

}

Debemos añadir a la variable $this->fields_form el nuevo campo; justo después de este código...

array(
     'type' => 'text',
     'label' => $this->l('Identification Number'),
     'name' => 'dni',
     'required' => false,
     'col' => '4',
     'hint' => $this->l('DNI / NIF / NIE')
    ),

...añadir el siguiente...

array(
     'type' => 'text',
     'label' => $this->l('Mi campo personalizado'),
     'name' => 'mi_campo',
     'required' => false,
     'col' => '4',
     'hint' => $this->l('Mi campo personalizado!')
    ),

Por último, al final del método cambiar la línea...

return parent::renderForm();

Por...

return AdminController::renderForm();

Haciendo esto la nueva lista de campos no es sustituida por la original.

Debemos asegurarnos de que el nombre de nuestro campo coincida con el insertado en la base de datos y en los archivos que hemos visto hasta ahora.

Para que el override sea llevado a cabo debemos eliminar el archivo prestahop/cache/class_index.php. No hay peligro en borrar este achivo, vuelve a regenerarse.

La plantilla Address del Front-office

Como último paso, vamos a agregar nuestro campo personalizado a la plantilla del Front-office. Este campo es el que los clientes verán a la hora de registrarse. Abramos el archivo address.tpl, ubicado en la carpeta de nuestro tema. Buscar este código:

{if $field_name eq 'vat_number'}
 <div id="vat_area">
   <div id="vat_number">
   <div class="form-group">
    <label for="vat-number">{l s='VAT number'}</label>
    <input type="text" class="form-control validate" data-validate="{$address_validation.$field_name.validate}" id="vat-number" name="vat_number" value="{if isset($smarty.post.vat_number)}{$smarty.post.vat_number}{else}{if isset($address->vat_number)}{$address->vat_number|escape:'html':'UTF-8'}{/if}{/if}" />
   </div>
  </div>
 </div>
{/if}

Y justo después añadir:

{if $field_name eq 'mi_campo'}
 <div id="vat_area">
  <div id="mi_campo">
   <div class="form-group">
    <label for="mi_campo">{l s='Mi_campo'}</label>
    <input type="text" class="form-control validate" data-validate="{$address_validation.$field_name.validate}" id="mi_campo" name="mi_campo" value="{if isset($smarty.post.mi_campo)}{$smarty.post.mi_campo}{else}{if isset($address->mi_campo)}{$address->mi_campo|escape:'html':'UTF-8'}{/if}{/if}" />
   </div>
  </div>
 </div>
{/if}

Guardamos cambios y ya está.

Si no vemos ningún cambio en el Front-office, deberemos ir a nuestro Back-office y forzar la compilación desde Parámetros avanzados > Rendimiento. Si es necesario vaciar la caché también.

Añadiendo el nuevo campo para que por fín sea visible

Para que nuestro campo sea visible, debemos editar el formato de dirección del país pertinente. Para ello debemos ir al Back-office y acceder a Localización > Países > Nuestro país

Editar el formato de dirección de nuestro país

Como podemos ver en esta imagen, debemos clicar en el campo que acabamos de crear y será insertado en la lista de campos.

Opcional: Hacer que el nuevo campo sea obligatorio

Si necesitamos que nuestro campo sea obligatorio será necesario crear otro override. Debemos crear un archivo en prestashop/override/controllers/front, lo llamaremos AddressController.php.

Incluir (como siempre) la etiqueta de apertura PHP <?php y peguemos el siguiente código dentro del archivo:

class AddressController extends AddressControllerCore
{
 
}

Tenemos que sobreescribir el método processSubmitAddress(). Por lo tanto, si nuestra versión de Prestashop es anterior a la 1.6.0.5, tomaremos el método original de prestashop/controllers/front/AddressController.php y lo copiaremos en este override. De lo contrario podemos utilizar el siguiente código:

protected function processSubmitAddress()
{
    $address = new Address();
    $this->errors = $address->validateController();
    $address->id_customer = (int)$this->context->customer->id;
 
    // Check page token
    if ($this->context->customer->isLogged() && !$this->isTokenValid())
        $this->errors[] = Tools::displayError('Invalid token.');
 
    // Check phone
    if (Configuration::get('PS_ONE_PHONE_AT_LEAST') && !Tools::getValue('phone') && !Tools::getValue('phone_mobile'))
        $this->errors[] = Tools::displayError('You must register at least one phone number.');
    if ($address->id_country)
    {
        // Check country
        if (!($country = new Country($address->id_country)) || !Validate::isLoadedObject($country))
            throw new PrestaShopException('Country cannot be loaded with address->id_country');
 
        if ((int)$country->contains_states && !(int)$address->id_state)
            $this->errors[] = Tools::displayError('This country requires you to chose a State.');
 
        $postcode = Tools::getValue('postcode');        
        /* Check zip code format */
        if ($country->zip_code_format && !$country->checkZipCode($postcode))
            $this->errors[] = sprintf(Tools::displayError('The Zip/Postal code you\'ve entered is invalid. It must follow this format: %s'), str_replace('C', $country->iso_code, str_replace('N', '0', str_replace('L', 'A', $country->zip_code_format))));
        elseif(empty($postcode) && $country->need_zip_code)
            $this->errors[] = Tools::displayError('A Zip/Postal code is required.');
        elseif ($postcode && !Validate::isPostCode($postcode))
            $this->errors[] = Tools::displayError('The Zip/Postal code is invalid.');
 
        // Check country DNI
        if ($country->isNeedDni() && (!Tools::getValue('dni') || !Validate::isDniLite(Tools::getValue('dni'))))
            $this->errors[] = Tools::displayError('The identification number is incorrect or has already been used.');
        else if (!$country->isNeedDni())
            $address->dni = null;
    }
    // Check if the alias exists
    if (!$this->context->customer->is_guest && !empty($_POST['alias']) && (int)$this->context->customer->id > 0)
    {
        $id_address = Tools::getValue('id_address');
        if(Configuration::get('PS_ORDER_PROCESS_TYPE') && (int)Tools::getValue('opc_id_address_'.Tools::getValue('type')) > 0)
            $id_address = Tools::getValue('opc_id_address_'.Tools::getValue('type'));
 
        if (Db::getInstance()->getValue('
            SELECT count(*)
            FROM '._DB_PREFIX_.'address
            WHERE `alias` = \''.pSql($_POST['alias']).'\'
            AND id_address != '.(int)$id_address.'
            AND id_customer = '.(int)$this->context->customer->id.'
            AND deleted = 0') > 0)
            $this->errors[] = sprintf(Tools::displayError('The alias "%s" has already been used. Please select another one.'), Tools::safeOutput($_POST['alias']));
    }
 
    // Check the requires fields which are settings in the BO
    $this->errors = array_merge($this->errors, $address->validateFieldsRequiredDatabase());
 
    // Don't continue this process if we have errors !
    if ($this->errors && !$this->ajax)
        return;
 
    // If we edit this address, delete old address and create a new one
    if (Validate::isLoadedObject($this->_address))
    {
        if (Validate::isLoadedObject($country) && !$country->contains_states)
            $address->id_state = 0;
        $address_old = $this->_address;
        if (Customer::customerHasAddress($this->context->customer->id, (int)$address_old->id))
        {
            if ($address_old->isUsed())
                $address_old->delete();
            else
            {
                $address->id = (int)($address_old->id);
                $address->date_add = $address_old->date_add;
            }
        }
    }
     
    if ($this->ajax && Tools::getValue('type') == 'invoice' && Configuration::get('PS_ORDER_PROCESS_TYPE'))
    {
        $this->errors = array_unique(array_merge($this->errors, $address->validateController()));          
        if (count($this->errors))
        {
            $return = array(
                'hasError' => (bool)$this->errors,
                'errors' => $this->errors
            );
            die(Tools::jsonEncode($return));
        }
    }
     
    // Save address
    if ($result = $address->save())
    {           
        // Update id address of the current cart if necessary
        if (isset($address_old) && $address_old->isUsed())
            $this->context->cart->updateAddressId($address_old->id, $address->id);
        else // Update cart address
            $this->context->cart->autosetProductAddress();
 
        if ((bool)(Tools::getValue('select_address', false)) == true OR (Tools::getValue('type') == 'invoice' && Configuration::get('PS_ORDER_PROCESS_TYPE')))
            $this->context->cart->id_address_invoice = (int)$address->id;
        elseif (Configuration::get('PS_ORDER_PROCESS_TYPE'))
            $this->context->cart->id_address_invoice = (int)$this->context->cart->id_address_delivery;
        $this->context->cart->update();
 
        if ($this->ajax)
        {
            $return = array(
                'hasError' => (bool)$this->errors,
                'errors' => $this->errors,
                'id_address_delivery' => (int)$this->context->cart->id_address_delivery,
                'id_address_invoice' => (int)$this->context->cart->id_address_invoice
            );
            die(Tools::jsonEncode($return));
        }
 
        // Redirect to old page or current page
        if ($back = Tools::getValue('back'))
        {
            if ($back == Tools::secureReferrer(Tools::getValue('back')))
                Tools::redirect(html_entity_decode($back));
            $mod = Tools::getValue('mod');
            Tools::redirect('index.php?controller='.$back.($mod ? '&back='.$mod : ''));
        }
        else
            Tools::redirect('index.php?controller=addresses');
    }       
    $this->errors[] = Tools::displayError('An error occurred while updating your address.');
}

Una vez copiado el código anterior, buscar este código y...

// Check page token
  if ($this->context->customer->isLogged() && !$this->isTokenValid())
   $this->errors[] = Tools::displayError('Invalid token.');

... justo después, añadir el siguiente:

// Check mi campo
   if ( !Tools::getValue('mi_campo'))
    $this->errors[] = Tools::displayError('El campo "Color favorito" es obligatorio');

De esta forma si se deja el campo vacío se emitirá un mensaje de error.

Como siempre, y para que el override pueda tener lugar, borrar el archivo prestashop/cache/class_index.php.

Y con esto hemos terminado!!!

Consejo:

Si tenéis problemas con la parte del código, descargar los archivos del proyecto. Estos archivos contienen todo el código necesario, y una vez hayáis probado todo lo indicado en el tutorial, comprenderéis mejor toda la explicación.

8 comentarios:

  1. consulta, y como puedo hacer lo opuesto? quitar campos?
    Saludos

    ResponderEliminar
    Respuestas
    1. Desde Localización > Países > Nuestro país en el Back-office puedes eliminar los campos. Fíjate en la última imagen de esta entrada, verás un recuadro con los campos: company, dni, address1 etc...

      Pues borras, por ejemplo, "dni" del recuadro y ya no se verá más en el Front-office de Prestashop.

      Eliminar
  2. Hola, Francisco Javier.

    Llevo buscando durante varios días por google un tutorial para hacer exactamente lo que explicas aquí pero relativo a añadir un nuevo campo a lo que sería la clase "Customer", ya que quiero que el usuario lo rellene cuando se registre como nuevo usuario.

    Además, necesitaría que fuese obligatorio (cosa que también contemplas en este tutorial) y que el nuevo campo fuese un select con varias opciones, las cuales tomaría de una tabla que tengo creada en la base de datos. En la tabla tengo una columna con un id y otra columna con el nombre, el cual quiero que les aparezca como opciones al usuario. Sé que en un momento dado podría indicar las opciones manualmente en el código, pero pienso que así estaría más optimizado (aunque sé que complica la cosa).

    El problema es que no encuentro ningún tutorial específico para lo que quiero, aunque el tuyo se acerca bastante. He visto una web en inglés (http://nemops.com/new-customer-address-fields-prestashop/#.VX_FhlKz5UM) donde se explica tu mismo tutorial y que al final hacen referencia a que esto mismo se puede aplicar para lo que yo quiero, modificando la clase Customer y sus controladores, así como otros archivos como authentication.tpl, identity.tpl y order-opc-new-account.tpl.

    ¿Podrías echarme una mano?

    Muchas gracias.

    ResponderEliminar
    Respuestas
    1. Hola amigo,

      Precisamente me basé en este tutorial en inglés, lo he intentado pensando que lo conseguiría, pensaba que lo tenía controlado, pero no hay manera, no me ha funcionado, lo siento.

      Eliminar
  3. Es una pena.

    La verdad es que he avanzado bastante, pero no termino de conseguirlo.

    He hecho override de las clases "Customer", "AdminCustomersController" y "Tools" (ésta para añadir una función que obtiene los elementos de la base de datos a mostrar en el select).
    Luego he modificado los archivos "identity.tpl", "authentication.tpl" y "order-opc-new-account.tpl", pero no carga las opciones en el select del formulario de registro, las cuales debería leer de la base de datos (con el método de la clase Tools). Viendo los errores que muestra, la variable que se supone que trae los elementos de la base de datos no está inicializada, así que ahí estoy estancado.

    Para este procedimiento que he seguido, me fijé un poco en lo que hace prestashop con el select para construir la fecha de nacimiento, pero desconozco si debo hacer algo más aparte de lo que ya he hecho.

    Seguiré buscando a ver si puedo conseguirlo.

    Saludos.

    ResponderEliminar
  4. Hola,
    ¿Serías tan amable de enviarme por email los archivos que estás utilizando? Si es posible señala con comentarios los cambios que has hecho en los .tpl

    A ver si entre los dos conseguimos algo.

    ¿Qué versión de Prestashop estás usando?

    Un saludo.

    ResponderEliminar