Skip to content
  1. Extras
  2. MiniShop3
  3. Frontend interface
  4. Customer account
  5. Shipping addresses

Delivery addresses

Page for managing customer delivery addresses. Lets customers create, edit, delete addresses, and set a default address.

Page structure

ComponentFilePurpose
Base layouttpl.msCustomer.baseCommon wrapper with sidebar
Sidebartpl.msCustomer.sidebarAccount navigation
Address listtpl.msCustomer.addressesList container
Address rowtpl.msCustomer.address.rowSingle address in the list
Address formtpl.msCustomer.address.formCreate/edit form

Snippet call

fenom
{'!msCustomer' | snippet : [
    'service' => 'addresses'
]}

Parameters

ParameterDefaultDescription
serviceService type (addresses)
tpltpl.msCustomer.addressesAddress list chunk
addressTpltpl.msCustomer.address.rowAddress row chunk
formTpltpl.msCustomer.address.formForm chunk
unauthorizedTpltpl.msCustomer.unauthorizedChunk for guests
returntplFormat: tpl or data

Operating modes

The page works in three modes via the GET parameter mode:

URLModeDescription
/cabinet/addresses/listAddress list
/cabinet/addresses/?mode=createcreateCreate address
/cabinet/addresses/?mode=edit&id=5editEdit address #5

Placeholders

In tpl.msCustomer.addresses (list)

PlaceholderTypeDescription
{$addresses}stringRendered address rows (HTML)
{$addresses_count}intNumber of addresses
{$customer}arrayCustomer data
{$success}stringSuccess message
{$error}stringError message

In tpl.msCustomer.address.row

PlaceholderTypeDescription
{$id}intAddress ID
{$name}stringAddress name
{$display_name}stringAuto-generated name
{$is_default}boolDefault address
{$index}stringPostal code
{$country}stringCountry
{$region}stringRegion
{$city}stringCity
{$street}stringStreet
{$building}stringBuilding
{$entrance}stringEntrance
{$floor}stringFloor
{$room}stringApartment
{$metro}stringMetro station
{$text_address}stringAddress comment

In tpl.msCustomer.address.form

PlaceholderTypeDescription
{$mode}stringMode: create or edit
{$address}arrayAddress data (when editing)
{$errors}arrayValidation errors
{$customer}arrayCustomer data

Address list chunk

fenom
{* tpl.msCustomer.addresses *}
{extends 'tpl.msCustomer.base'}

{block 'content'}
<div class="ms3-customer-addresses">
    <div class="card shadow-sm">
        <div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
            <h5 class="mb-0">{'ms3_customer_addresses_title' | lexicon}</h5>
            <a href="?mode=create" class="btn btn-sm btn-light">
                {'ms3_customer_address_add' | lexicon}
            </a>
        </div>
        <div class="card-body">
            {if $success?}
            <div class="alert alert-success" role="alert">
                {$success}
            </div>
            {/if}

            {if $error?}
            <div class="alert alert-danger" role="alert">
                {$error}
            </div>
            {/if}

            {if $addresses_count > 0}
            <div class="list-group list-group-flush">
                {$addresses}
            </div>
            {else}
            <div class="alert alert-info" role="alert">
                {'ms3_customer_addresses_empty' | lexicon}
            </div>
            {/if}
        </div>
    </div>
</div>
{/block}

JavaScript

Since version 1.6, a separate customer-addresses.js script is not required. Address management (set default, delete) is built into CustomerUI and initializes automatically via ms3.js.

Address row chunk

fenom
{* tpl.msCustomer.address.row *}
<div class="list-group-item"
     data-confirm-set-default="{'ms3_customer_address_set_default_confirm' | lexicon}"
     data-confirm-delete="{'ms3_customer_address_delete_confirm' | lexicon}"
     data-error-unknown="{'ms3_err_unknown' | lexicon}">
    <div class="d-flex w-100 justify-content-between align-items-start">
        <div class="flex-grow-1">
            <h6 class="mb-1">
                {if $name}
                    {$name}
                {else}
                    {$display_name}
                {/if}
                {if $is_default}
                <span class="badge bg-success ms-2">
                    {'ms3_customer_address_default' | lexicon}
                </span>
                {/if}
            </h6>
            <p class="mb-1 text-muted small">
                {if $index}{$index}, {/if}
                {$city}{if $region}, {$region}{/if}{if $country}, {$country}{/if}
            </p>
            <p class="mb-1 small">
                {$street}{if $building}, bld. {$building}{/if}
                {if $entrance}, ent. {$entrance}{/if}
                {if $floor}, fl. {$floor}{/if}
                {if $room}, apt. {$room}{/if}
            </p>
            {if $metro}
            <p class="mb-1 small text-muted">Metro {$metro}</p>
            {/if}
        </div>
        <div class="btn-group btn-group-sm ms-3" role="group">
            {if !$is_default}
            <button type="button"
                    class="btn btn-outline-secondary set-default-address"
                    data-address-id="{$id}"
                    title="{'ms3_customer_address_set_default' | lexicon}">

            </button>
            {/if}
            <a href="?mode=edit&id={$id}"
               class="btn btn-outline-primary"
               title="{'ms3_customer_address_edit' | lexicon}">

            </a>
            <button type="button"
                    class="btn btn-outline-danger delete-address"
                    data-address-id="{$id}"
                    title="{'ms3_customer_address_delete' | lexicon}">

            </button>
        </div>
    </div>
</div>

Address form chunk

fenom
{* tpl.msCustomer.address.form *}
<div class="ms3-customer-address-form">
    <div class="card shadow-sm">
        <div class="card-header bg-primary text-white">
            <h5 class="mb-0">
                {if $mode == 'edit'}
                    {'ms3_customer_address_edit' | lexicon}
                {else}
                    {'ms3_customer_address_add' | lexicon}
                {/if}
            </h5>
        </div>
        <div class="card-body">
            <form class="ms3_form ms3-address-form" method="post" action="">
                <input type="hidden" name="ms3_action"
                       value="customer/{if $mode == 'edit'}address-update{else}address-create{/if}">
                {if $mode == 'edit'}
                <input type="hidden" name="id" value="{$address.id}">
                {/if}

                {* Address name *}
                <div class="mb-3">
                    <label for="name" class="form-label">
                        {'ms3_customer_address_name' | lexicon}
                    </label>
                    <input type="text" class="form-control" id="name" name="name"
                           value="{$address.name}"
                           placeholder="{'ms3_customer_address_name_placeholder' | lexicon}">
                    <div class="form-text">
                        {'ms3_customer_address_name_help' | lexicon}
                    </div>
                </div>

                <div class="row">
                    {* Postal code *}
                    <div class="col-md-4 mb-3">
                        <label for="index" class="form-label">
                            {'ms3_customer_index' | lexicon}
                        </label>
                        <input type="text" class="form-control" id="index" name="index"
                               value="{$address.index}">
                    </div>

                    {* Country *}
                    <div class="col-md-8 mb-3">
                        <label for="country" class="form-label">
                            {'ms3_customer_country' | lexicon}
                        </label>
                        <input type="text" class="form-control" id="country" name="country"
                               value="{$address.country}">
                    </div>
                </div>

                <div class="row">
                    {* Region *}
                    <div class="col-md-6 mb-3">
                        <label for="region" class="form-label">
                            {'ms3_customer_region' | lexicon}
                        </label>
                        <input type="text" class="form-control" id="region" name="region"
                               value="{$address.region}">
                    </div>

                    {* City *}
                    <div class="col-md-6 mb-3">
                        <label for="city" class="form-label">
                            {'ms3_customer_city' | lexicon} <span class="text-danger">*</span>
                        </label>
                        <input type="text" class="form-control" id="city" name="city"
                               value="{$address.city}" required>
                    </div>
                </div>

                {* Street *}
                <div class="mb-3">
                    <label for="street" class="form-label">
                        {'ms3_customer_street' | lexicon} <span class="text-danger">*</span>
                    </label>
                    <input type="text" class="form-control" id="street" name="street"
                           value="{$address.street}" required>
                </div>

                <div class="row">
                    {* Building *}
                    <div class="col-md-3 mb-3">
                        <label for="building" class="form-label">
                            {'ms3_customer_building' | lexicon} <span class="text-danger">*</span>
                        </label>
                        <input type="text" class="form-control" id="building" name="building"
                               value="{$address.building}" required>
                    </div>

                    {* Entrance *}
                    <div class="col-md-3 mb-3">
                        <label for="entrance" class="form-label">
                            {'ms3_customer_entrance' | lexicon}
                        </label>
                        <input type="text" class="form-control" id="entrance" name="entrance"
                               value="{$address.entrance}">
                    </div>

                    {* Floor *}
                    <div class="col-md-3 mb-3">
                        <label for="floor" class="form-label">
                            {'ms3_customer_floor' | lexicon}
                        </label>
                        <input type="text" class="form-control" id="floor" name="floor"
                               value="{$address.floor}">
                    </div>

                    {* Apartment *}
                    <div class="col-md-3 mb-3">
                        <label for="room" class="form-label">
                            {'ms3_customer_room' | lexicon}
                        </label>
                        <input type="text" class="form-control" id="room" name="room"
                               value="{$address.room}">
                    </div>
                </div>

                {* Metro *}
                <div class="mb-3">
                    <label for="metro" class="form-label">
                        {'ms3_customer_metro' | lexicon}
                    </label>
                    <input type="text" class="form-control" id="metro" name="metro"
                           value="{$address.metro}">
                </div>

                {* Comment *}
                <div class="mb-3">
                    <label for="text_address" class="form-label">
                        {'ms3_customer_comment' | lexicon}
                    </label>
                    <textarea class="form-control" id="text_address" name="text_address"
                              rows="2">{$address.text_address}</textarea>
                </div>

                {* Buttons *}
                <div class="d-flex justify-content-between gap-2 mt-4">
                    <a href="?" class="btn btn-secondary">
                        {'ms3_customer_cancel' | lexicon}
                    </a>
                    <button type="submit" class="btn btn-primary ms3_link">
                        {if $mode == 'edit'}
                            {'ms3_customer_save' | lexicon}
                        {else}
                            {'ms3_customer_address_add' | lexicon}
                        {/if}
                    </button>
                </div>
            </form>
        </div>
    </div>
</div>

JavaScript API

Address management is built into CustomerUI and works automatically via ms3.js.

API endpoints

PUT    /api/v1/customer/addresses/{id}/set-default  // Set as default
DELETE /api/v1/customer/addresses/{id}               // Delete address

Action buttons

html
<!-- Set as default -->
<button class="set-default-address" data-address-id="5">★</button>

<!-- Delete -->
<button class="delete-address" data-address-id="5">✕</button>

On delete and set-default, a confirmation dialog is shown (ms3Confirm). Confirmation text comes from data attributes on the address row:

html
<div class="list-group-item"
     data-confirm-set-default="{'ms3_customer_address_set_default_confirm' | lexicon}"
     data-confirm-delete="{'ms3_customer_address_delete_confirm' | lexicon}">

Hooks

HookDescription
beforeSetDefaultAddressBefore setting default address
afterSetDefaultAddressAfter setting default address
beforeDeleteAddressBefore deleting address
afterDeleteAddressAfter deleting address

Form handling

Actionms3_actionDescription
Createcustomer/address-createCreate new address
Editcustomer/address-updateUpdate address

Address fields

FieldRequiredDescription
nameNoAddress name (Home, Office)
indexNoPostal code
countryNoCountry
regionNoRegion/state
cityYesCity
streetYesStreet
buildingYesBuilding
entranceNoEntrance
floorNoFloor
roomNoApartment/office
metroNoMetro station
text_addressNoAddress comment

System settings

SettingDescription
ms3_customer_addresses_page_idAddresses page ID

CSS classes

ClassElement
.ms3-customer-addressesList container
.ms3-customer-address-formForm container
.ms3-address-formAddress form
.set-default-address"Set default" button
.delete-addressDelete button