In this tutorial we will see step by step how to add the city field as a drop-down menu when creating or modifying an address.

The first step is to create a table with the cities. We will call the table city, and it will have this structure

ta1.jpg.647f9d6d4ba1e60e4ef4c44457d02dac.jpg

The id_states must be given by each state that has your prestashop store. The table would look like this:

ta2.jpg.2156faee70522bad1a8fba9291eb3c10.jpg

The next step is to modify the ps_address table by adding an id_city field.

ta3.thumb.jpg.c7b808f1601c55e6b813479c33731879.jpg

Finally, we will modify the address_format table defining for which countries we will use the droptown format in the city.

 

Just edit the format field, which generally when it contains states looks like this:

ta4.jpg.eac9a8a73023df6822cf98edf19ff310.jpg

And we will change the field city to city: name. Name would add the dropdown:

ta5.jpg.095f9408af2899655b329bc4ba8e1612.jpg

At this point the store will give us errors since classes are missing, so now we must modify the files so that all this works.

First we will create a City.php file in the classes folder that will allow us to work with cities. The file will contain:


<?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

                               ); 

   }

 

}

Then we replace this function in  classes/form/customeraddressform.php :

    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;

    }

The following file is the classes / form / CustomerAddressFormatter.php

We will look for this line of states

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);

                    }

                }

 

and we add this to the end of these lines

 

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);

                   

                }

 

And we add this function to the clases/State.php file

 

                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;

                }

For these already created files we can always use an override to avoid losing changes when updating PrestaShop

The next file is the classes / Address.php

We will add public variables at the beginning:

 

    public  $id_city;

    public  $cityName;

 

in the function  public static $definition = array(

 

We will add at the end the created field id_city for the address table

'id_city' => 'isUnsignedId',

 

And we add this new function

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;

    }

 

And change this function at the end

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

 

where this elseif we add the city field

 

            } 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;

            }

 

 

The next step is to add the javascript code so that it takes the cities when changing state:

For this we will modify the file themes / ourtheme / templates / _partials / javascript.tpl of our theme and we will add this code at the end:

<!-- 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}

 

Finally, we will create a pseudo module for Ajax functions. This can be done in other ways, this is just a simple one: In the modules folder, we create a folder called ajax_addresses and within it a file called ajax.php with this content:
 

<?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);
}

 

 

ACter that, just clear cache and you are done

ta6.jpg.48e48500d93444a5a66e2b8e06730b56.jpg

Link to files

https://github.com/shacker2/citiesasdropdownprestashop

Product added to wishlist
Product added to compare.

Nous utilisons nos propres cookies et ceux de tiers pour mesurer et obtenir des données statistiques sur la navigation des utilisateurs. À leur tour, nous utilisons des cookies d'analyse et de personnalisation pour, par exemple, mémoriser la connexion au compte de l'utilisateur ou enregistrer les préférences de l'utilisateur. Vous pouvez configurer et accepter l'utilisation de cookies à l'aide des boutons ci-dessous, et modifier vos options de consentement à tout moment en consultant notre politique de cookies. De même, vous pouvez obtenir plus d'informations dans « Configurer les cookies ».