Skip to main content
Zones define geographic regions for your store. Each zone groups countries together and associates them with a currency, carriers, payment methods, and tax rules. When a customer checks out, Shopper resolves their zone from the shipping address and uses it to determine available shipping options, payment methods, and tax rates.

Model

The model used is Shopper\Core\Models\Zone. It uses the HasSlug trait for automatic slug generation. The model is not configurable via config/shopper/models.php.

Database Schema

ColumnTypeNullableDefaultDescription
idbigintnoautoPrimary key
namestringno-Zone name (unique)
slugstringyesautoURL-friendly identifier (unique)
codestringyesnullShort code identifier (unique)
is_enabledbooleannofalseZone visibility
currency_idbigintyesnullFK to currencies table
metadatajsonbyesnullAdditional custom data
created_attimestampyesnullCreation timestamp
updated_attimestampyesnullLast update timestamp

Pivot Table

The zone_has_relations pivot table connects zones to countries, carriers, payment methods, and collections through a polymorphic relationship.
ColumnTypeDescription
zone_idbigintFK to zone
zonable_typestringMorph type (Country, Carrier, PaymentMethod, Collection)
zonable_idbigintFK to the related model

Relationships

Currency

Each zone is associated with one currency. This determines which currency is used for pricing and checkout in that zone.
$zone->currency;       // Currency model
$zone->currency_code;  // "EUR" (computed accessor)

Countries

Zones group multiple countries together. When a customer enters a shipping address, Shopper resolves the zone by matching the country.
$zone->countries;

$zone->countries()->attach([$franceId, $germanyId, $belgiumId]);

Carriers

Carriers (shipping providers) are scoped to zones. A carrier available in Europe may not be available in North America.
$zone->carriers;

$zone->carriers()->attach([$colissimoId, $dhlId]);

Payment Methods

Payment methods are scoped to zones. For example, iDEAL is only available in the Netherlands zone.
$zone->paymentMethods;

$zone->paymentMethods()->attach([$stripeId, $idealId]);

Shipping Options

Each zone has shipping options (carrier options with rates) available at checkout:
$zone->shippingOptions;

Collections

Collections can be scoped to specific zones for region-specific merchandising:
$zone->collections;

Query Scopes

The enabled scope filters zones that are active:
use Shopper\Core\Models\Zone;

Zone::query()->enabled()->get();

Computed Attributes

The Zone model provides computed attributes that return comma-separated names for related entities:
$zone->countries_name;  // "France, Germany, Belgium"
$zone->carriers_name;   // "Colissimo, DHL"
$zone->payments_name;   // "Stripe, iDEAL"
$zone->currency_code;   // "EUR"

HasZones Trait

Models that can be scoped to zones use the HasZones trait. This is already applied to PaymentMethod, Carrier, and Collection models.
use Shopper\Core\Models\Traits\HasZones;

$model->zones;
$model->zones()->attach([$zoneId1, $zoneId2]);

Creating Zones

To create a zone for the European market:
use Shopper\Core\Models\Zone;
use Shopper\Core\Models\Country;

$zone = Zone::query()->create([
    'name' => 'Europe',
    'code' => 'EU',
    'is_enabled' => true,
    'currency_id' => $eurCurrency->id,
]);

$countries = Country::query()
    ->whereIn('cca2', ['FR', 'DE', 'BE', 'NL', 'ES', 'IT'])
    ->pluck('id');

$zone->countries()->attach($countries);
$zone->carriers()->attach([$colissimoId, $dhlId]);
$zone->paymentMethods()->attach([$stripeId]);

Retrieving Zones

To find the zone for a customer’s shipping address:
$zone = Zone::query()
    ->enabled()
    ->whereHas('countries', fn ($q) => $q->where('id', $countryId))
    ->first();
To get all enabled zones with their currencies:
$zones = Zone::query()
    ->enabled()
    ->with('currency')
    ->get();

Components

The zone management components are part of the settings configuration. To customize:
php artisan shopper:component:publish setting
Zone-related components in config/shopper/components/setting.php:
use Shopper\Livewire;

return [
    'pages' => [
        'zones' => Livewire\Pages\Settings\Zones::class,
    ],
    'components' => [
        'settings.zones.detail' => Livewire\Components\Settings\Zones\Detail::class,
        'settings.zones.shipping-options' => Livewire\Components\Settings\Zones\ZoneShippingOptions::class,
    ],
];