Ciudades como desplegables en PrestaShop

En este tutorial veremos paso a paso como añadir el campo ciudad como menú desplegable al crear o modificar una dirección.

El primer paso es crear una tabla con las ciudades. La tabla la llamaremos city, y tendrá esta estructura

ta1.jpg.fa7ee2dd0d5574e61aca404fa694739d.jpg

Los id_state deben ser los da cada estado que tenga su tienda prestashop. La tabla se vería así:

ta2.jpg.cce791a4fe9698d920f31b2ffbce29dd.jpg

El siguiente paso es modificar la tabla ps_address añadiendo un campo id_city

ta3.thumb.jpg.9f94ea418efdd9cafc68e16e7a753b26.jpg

Por último, modificaremos la tabla address_format definiendo para que países usaremos el formato de droptown en la ciudad.

 

Solo basta con editar el campo format,  que generalmente cuando contiene estados luce asi:

ta4.jpg.232413cd0c762c14f22e94d564329f93.jpg

Y le cambiaremos el campo city asi  city:name. Name añadiría el dropdown:

ta5.jpg.3c583a2c27ae481edf102fbf1d8fbb13.jpg

A esta altura la tienda nos dará errores ya que faltaran clases, asi que ahora debemos modificar los archivos para que todo esto funcione.

Primero crearemos un archivo City.php en la carpeta clases que permitirá trabajar con las ciudades.El archivo contendrá:
 

<?php
class CityCore extends ObjectModel {    public $id_city;    public $id_state;    public $name;                    protected           $fieldsRequired = array('id_city', 'name');                 protected           $fieldsSize = array('name' => 128, 'id_state' => 10);                 protected           $fieldsValidate = array('name' => 'isGenericName', 'id_state' => 'isUnsignedId', );                 protected           $table = 'city';                 protected           $identifier = 'id_city';                    private static $_cache_get_cities = array();                       public function getFields()                 {                                parent::validateFields();                                $fields['id_city'] = (int)($this->id_city);                                $fields['name'] = pSQL($this->name);                                $fields['id_state'] = pSQL($this->id_state);                                     return $fields;                 }                    public function delete()                 {                                $id = $this->id;                                parent::delete();                 }                         public static function getCities($id_state)                 {                                                $id_city = Db::getInstance()->ExecuteS('                                                SELECT * FROM `'._DB_PREFIX_.'city`                                                WHERE `id_state` = '.(int)$id_state.'          ORDER BY `name`;'                                                );                                                               return $id_city;                 }          public static function getCityName($id_city)    {                                return Db::getInstance()->getValue('                                SELECT `name` FROM `'._DB_PREFIX_.'city`                                WHERE `id_city` = '.(int)$id_city                                );     } }

 

El siguiente archivo es el clases/form/CustomerAddressFormatter.php

 

Buscaremos esta línea de estados

elseif ($entity === 'State') {

                    if ($this->country->contains_states) {

                        $states = State::getStatesByIdCountry($this->country->id, true);

                        foreach ($states as $state) {

                            $formField->addAvailableValue(

                                $state['id_state'],

                                $state[$entityField]

                            );

                        }

                        $formField->setRequired(true);

                    }

                }

 

y añadiremos al final

elseif ($entity === 'city') {

                    $formField->setType('select');

                    $formField->setName('id_' . strtolower($entity));

                        $cities =  State::getCities(315);

                        foreach ($cities as $city) {

                            $formField->addAvailableValue(

                                $city['id_city'],

                                $city[$entityField]

                            );

                        }

                        $formField->setRequired(false);

                   

                }

 

Luego añadiremos esta función a el archivo clases/State.php


               

 public static function getCities($id_state)

                {



                                               $id_city = Db::getInstance()->ExecuteS('

                                               SELECT * FROM `'._DB_PREFIX_.'city`

                                               WHERE `id_state` = '.(int)$id_state.'

         ORDER BY `name`;'

                                               );

                              



                               return $id_city;

                }

Para estos archivos ya creados siempre podemos usar un override para evitar perder cambios al actualizar PrestaShop

EL siguiente archivo es el clases/Address.php

 

Añadiremos al inicio las variables publicas:   

 public  $id_city;

 public  $cityName;

 

En la fucion  public static $definition = array(

 

Añadiremos al final el campo creado id_city para la tabla address

'id_city' => 'isUnsignedId',

 

Y añadiremos esta nueva función

public function getFields()

    {

        if (isset($this->id))

        $sql = 'select * from '. _DB_PREFIX_ . 'city

        WHERE  id_city= ' . $this->id_city;

        $sql2 = Db::getInstance()->getRow($sql);

        $fields['id_address'] = (int)($this->id);

        $fields['id_customer']     = is_null($this->id_customer) ? 0 : (int)($this->id_customer);

        $fields['id_manufacturer'] = is_null($this->id_manufacturer) ? 0 : (int)($this->id_manufacturer);

        $fields['id_supplier']     = is_null($this->id_supplier) ? 0 : (int)($this->id_supplier);

        $fields['id_country']      = (int)($this->id_country);

        $fields['id_state']        = (int)($this->id_state);

        $fields['alias']           = pSQL($this->alias);

        $fields['company']         = pSQL($this->company);

        $fields['lastname']        = pSQL($this->lastname);

        $fields['firstname']       = pSQL($this->firstname);

        $fields['address1']        = pSQL($this->address1);

        $fields['address2']        = pSQL($this->address2);

        $fields['postcode']        = pSQL($this->postcode);

        $fields['city']            = pSQL($sql2['name']);

        $fields['other']           = pSQL($this->other);

        $fields['phone']           = pSQL($this->phone);

        $fields['phone_mobile']    = pSQL($this->phone_mobile);

        $fields['vat_number']      = pSQL($this->vat_number);

        $fields['dni']             = pSQL($this->dni);

        $fields['deleted']         = (int)($this->deleted);

        $fields['date_add']        = pSQL($this->date_add);

        $fields['date_upd']        = pSQL($this->date_upd);

       

        $fields['id_city']   = is_null($this->id_city) ? 0 : (int)($this->id_city);

        return $fields;

    }

 

Y al final modificaremos esta función

public static function initialize($id_address = null, $with_geoloc = false) 

 

donde este elseif debe añadir el campo city    

        } elseif ($with_geoloc && isset($context->customer->geoloc_id_country)) {

                $address = new Address();

                $address->id_country = (int) $context->customer->geoloc_id_country;

                $address->id_state = (int) $context->customer->id_state;

                $address->id_city = (int) $context->customer->id_city;

                $address->postcode = $context->customer->postcode;

            }

 

Luego el classes/form/customeraddressform.php reemplazaremos esta función

    public function submit()

    {

        if (!$this->validate()) {

            return false;

        }



        $address = new Address(

            $this->getValue('id_address'),

            $this->language->id

        );



        

        

        foreach ($this->formFields as $formField) {

        if ($formField->getName() == 'id_city'){

                        $id_city = Db::getInstance()->getRow('

                                   SELECT * FROM `'._DB_PREFIX_.'city`

                                   WHERE `id_city` = '.$formField->getValue().';');

            $address->city = $id_city['name'];

            $address->{$formField->getName()} = $formField->getValue();

        } else {

            $address->{$formField->getName()} = $formField->getValue();



        }

      

        }



        if (!isset($this->formFields['id_state'])) {

            $address->id_state = 0;

        }



        if (empty($address->alias)) {

            $address->alias = $this->translator->trans('My Address', [], 'Shop.Theme.Checkout');

        }





                                 

        Hook::exec('actionSubmitCustomerAddressForm', array('address' => &$address));

        $this->setAddress($address);

        $this->getPersister()->save(

            $address,

            $this->getValue('token'));

        Db::getInstance()->Execute('UPDATE `'._DB_PREFIX_.'address` SET `city` = ''.$address->city.'' WHERE id_address = '.$address->id);

        return true;

    }

El siguiente paso es añadir el código javascript para que tome las ciudades al cambiar de estado:

Para esto modificaremos el archivo themes/nuestrotheme/templates/_partials/javascript.tpl de nuestro theme y le añadiremos  este código al final:

<!-- direcciones -->





{literal}

<script>

(function(){"use strict";var c=[],f={},a,e,d,b;if(!window.jQuery){a=function(g){c.push(g)};f.ready=function(g){a(g)};e=window.jQuery=window.$=function(g){if(typeof g=="function"){a(g)}return f};window.checkJQ=function(){if(!d()){b=setTimeout(checkJQ,100)}};b=setTimeout(checkJQ,100);d=function(){if(window.jQuery!==e){clearTimeout(b);var g=c.shift();while(g){jQuery(g);g=c.shift()}b=f=a=e=d=window.checkJQ=null;return true}return false}}})();

</script>

{/literal}







{if $page.page_name == "address" or $page.page_name == "order" or  $page.page_name == "checkout"}

                <script type="text/javascript">

$(document).ready(function(){

$(".form-control-select .js-city").last().val();









                                                               var mi_ajaxurl                  = '{$urls.base_url}modules/';

                                                               var aux_id_state             = {if isset($smarty.post.id_state) and $smarty.post.id_state <> null}{$smarty.post.id_state}{else}{if isset($customer.addresses[$smarty.get.id_address].id_state)}{$customer.addresses[$smarty.get.id_address].id_state}{else}0{/if}{/if};

                                                               var aux_id_city = {if isset($smarty.post.id_city) and $smarty.post.id_city <> null}{$smarty.post.id_city}{else}{if isset($customer.addresses[$smarty.get.id_address].id_city)}{$customer.addresses[$smarty.get.id_address].id_city}{else}0{/if}{/if};

                                                               var aux_city       = '{if isset($smarty.post.city) and $smarty.post.city <> null}{$smarty.post.city}{else}{if isset($customer.addresses[$smarty.get.id_address].city)}{$customer.addresses[$smarty.get.id_address].city}{else}0{/if}{/if}';





                                                               {literal}

                                                                                              $(document).ready(function(){



              $.urlParam = function(name){

    var results = new RegExp('[?&]' + name + '=([^&#]*)').exec(window.location.href);

    if (results==null) {

       return null;

    }

    return decodeURI(results[1]) || 0;

}



                                                                                                              ajaxCity();



                                                                                                              $("[name='id_state']").change(function() {

                                                                                                              ajaxCity();

                                                                                                              });

                                                                                                             

                                                                                                              $("[name='id_city']").change(function() {



                                                                                                              });

                                                                                                             



                                                                                                              function ajaxCity(valueaaa){

                                                                                                                             $.ajax({

                                                                                                                                             type: "GET",

                                                                                                                                             url: mi_ajaxurl+"ajax_addresses/ajax.php?ajaxCity=1&id_state="+$("[name='id_state']").val()+"&aux_id_state="+aux_id_state+"&aux_city="+aux_city,

                                                                                                                                             success: function(r){

                                                                                                                                                             if( r == 'false' ){

                                                                                                                                                                             $("[name='id_city']").fadeOut();

                                                                                                                                                                            $("[name='id_city'] option[value=0]").attr("selected", "selected");

                                                                                                                                                             }else{

                                                                                                                                                                            $("[name='id_city']").html(r);

                                                                                                                                                                            $("[name='id_city']").fadeIn();

                                                                                                                                                                            //$('#id_city option[value=0]').attr("selected", "selected");                                                                                                                                            

                                                                                                                                                                            $("[name='id_city'] option[value='+aux_id_city+']").attr("selected", "selected");

                                                                                                                                                             }

                                                                                                                                                             $("[name='id_city']").trigger('click');

                                                                                                                                                             //$("#id_street").trigger('click');

                                                                                                                                                             /*/***ajaxStreet();*/

                                                                                                                                             }

                                                                                                                             });

                                                                                                              };

                                                                                                                                                                                                                                          



                                                                                                             

                                                                                              });



                                                               {/literal}

                                                               </script>

{/if}


Por ultimo, crearemos un pseudo modulo para las funciones Ajax. Esto se puede hacer de otras formas, esta es solo una sencilla.En la carpeta modules, creamos una carpeta llamada ajax_addresses  y dentro de la misma un archivo llamado ajax.php  con este contenido:
 

<?php
include(dirname(__FILE__). '/../../config/config.inc.php');
include(dirname(__FILE__). '/../../init.php');




// obtengo city
if (isset($_GET['ajaxCity']) AND isset($_GET['id_state']))
{

$idTemp = ( (int)(Tools::getValue('id_state')) == 0 ? (int)(Tools::getValue('aux_id_state')) : (int)(Tools::getValue('id_state')) );
$idcitym = Tools::getValue('aux_city');
$states = Db::getInstance()->ExecuteS('
SELECT C.id_city, C.name
FROM '._DB_PREFIX_.'city C
WHERE C.id_state = '.$idTemp.'
ORDER BY C.`name` ASC');
$states2 = Db::getInstance()->getRow('
SELECT C.id_city, C.name
FROM '._DB_PREFIX_.'city C
WHERE C.name = ''.$idcity.''
ORDER BY C.`name` ASC');

if (is_array($states) AND !empty($states))
{
$list = '';
if (Tools::getValue('aux_id_state') != true){
if($idcitym != null){
$list .= '<option value="'.$states2['name'].'" class="showme" >'.($idcitym == 0 ? "---" : $idcitym) .'</option>'."n";
}

}

foreach ($states AS $state)
if($idcitym != null or $idcitym != 0) {
$list .= '<option value="'.(int)($state['id_city']).'"'.((isset($idcitym) AND $idcitym == $state['name']) ? ' selected="selected"' : '').'>'.$state['name'].'</option>'."n";
} else{
$list .= '<option value="'.(int)($state['id_city']).'"'.((isset($_GET['id_city']) AND $_GET['id_city'] == $state['id_city']) ? ' selected="selected"' : '').'>'.$state['name'].'</option>'."n";

}
}
else
$list = 'false';

die($list);
}

 

Luego solo debemos limpiar cache y ya deberíamos ver las ciudades como dropdown.


Carro 0 Carrito de compras

sin productos

¡Envío gratis! Envío
$0.00 Total

Revisa