@php $isDone = in_array($this->jobStatus, ['completed', 'failed']); $pct = $this->totalRows > 0 ? min(100, (int) round(($this->processedRows / $this->totalRows) * 100)) : ($this->jobStatus === 'processing' ? 5 : 0); $isRunning = $this->jobId && !$isDone; @endphp {{-- Polling is managed by JS setInterval in the Alpine component below --}} {{-- Progress section --}} @if($this->jobId) @if($isDone) {{ $this->jobStatus === 'completed' ? 'Import Complete' : 'Import Failed' }} @else Importing Products… @endif @if($isDone) {{ $this->importedRows }} imported · {{ $this->skippedRows }} skipped · {{ $this->failedRows }} failed @else Processing in the background — you can leave this page and come back. @endif
@if($this->totalRows > 0) {{ $this->processedRows }} / {{ $this->totalRows }} rows @elseif($this->jobStatus === 'pending') Queued… @else Starting… @endif {{ $pct }}%
@if($this->totalRows > 0 || $isDone)
{{ $this->importedRows }}
Imported
{{ $this->skippedRows }}
Skipped
{{ $this->failedRows }}
Failed
@endif @if($this->firstError)
{{ $this->firstError }}
@endif @if($isDone) Import Another File @endif
@endif {{-- Known columns for mapping --}} @php $channels = \Webkul\Channel\Models\Channel::all(['id','name']); $channelPriceCols = $channels->map(fn($c) => strtolower(str_replace(' ', '_', $c->name)) . '_price')->values()->all(); $channelTaxCols = $channels->map(fn($c) => strtolower(str_replace(' ', '_', $c->name)) . '_tax_rate')->values()->all(); $knownColumns = array_merge( ['company','sku','name','sub_title','price','cost','tax_rate','barcode','vendor','reference','type','description','description_sale','description_purchase','enable_sales','enable_purchase','is_favorite','track_inventory','uom','weight','volume','length','width','height'], ['bullet_points','country_of_origin'], $channelPriceCols, $channelTaxCols ); @endphp
{{-- File Upload Section --}} @if(!$this->jobId) Import Products Upload an XLSX or CSV file to import products into your catalog.
{{ $this->form }} {{-- Parse error (shown below the form before Start Import) --}}
Start Import
@endif {{-- Preview Section --}} @if(!$this->jobId)
Import Preview Green = mapped column, grey = ignored. {{-- XLSX notice --}}
XLSX file detected — column preview is not available for Excel files. Your file will be validated when the import starts. Make sure row 1 contains column headers matching the Supported Columns list below.
{{-- Missing required columns warning --}}
Missing required columns
Missing: — import will be rejected until these are present.
Columns found in your file:
{{-- Column summary (shown when headers exist and no missing-required error) --}}
✓ columns detected — mapped, ignored
{{-- Scrollable table wrapper (hidden for XLSX) --}}
#

Showing preview rows — full file will be processed on import.

@endif {{-- Instructions Section --}} Import Instructions How to prepare and run your import file.
{{-- Left: spreadsheet column reference --}}

Each cell is one CSV column header — hover for description.

{{-- Product Columns --}}
Product Columns
@php $importCols = [ 'company' => ['required', 'Company name — must match exactly e.g. Somerset4x4'], 'sku' => ['required', 'Unique product identifier — used to match on update'], 'name' => ['create', 'Product display name'], 'price' => ['optional', 'Selling price'], 'cost' => ['optional', 'Cost / purchase price'], 'tax_rate' => ['optional', 'Default tax rate as % e.g. 20.00 for 20%'], 'barcode' => ['optional', 'UPC / EAN barcode'], 'reference' => ['optional', 'Internal reference code'], 'type' => ['optional', 'goods or service (default: goods)'], 'description' => ['optional', 'Internal product description'], 'description_sale' => ['optional', 'Description on sales documents'], 'description_purchase' => ['optional', 'Description on purchase documents'], 'enable_sales' => ['optional', '1 or 0 — allow on sales orders'], 'enable_purchase' => ['optional', '1 or 0 — allow on purchase orders'], 'is_favorite' => ['optional', '1 or 0 — mark as favourite'], 'sub_title' => ['optional', 'Short product tagline displayed below the title on the storefront'], 'track_inventory' => ['optional', '1 or 0 — enable inventory tracking'], 'uom' => ['optional', 'Unit of measure e.g. Units, kg, L, Hours (default: Units)'], 'weight' => ['optional', 'Weight in kg'], 'volume' => ['optional', 'Volume in m³'], 'length' => ['optional', 'Length in cm'], 'width' => ['optional', 'Width in cm'], 'height' => ['optional', 'Height in cm'], ]; @endphp @foreach($importCols as $col => [$status, $hint])
{{ $col }} @if($status === 'required') required @elseif($status === 'create') create only @else optional @endif
@endforeach
{{-- Custom Fields --}}
Custom Fields
@php $customImportCols = [ 'bullet_points' => ['optional', 'Key product features, e.g. for Amazon listings — separate multiple entries with a pipe (|), e.g. "Feature one|Feature two"'], 'country_of_origin' => ['optional', 'Country of origin, e.g. GB, CN, TH — used for Amazon/eBay/Shopify shipping data'], ]; @endphp @foreach($customImportCols as $col => [$status, $hint])
{{ $col }} optional
@endforeach
@if($channels->isNotEmpty())
{{-- Channel Prices --}}
Channel Prices
@foreach($channels as $channel)
{{ strtolower(str_replace(' ', '_', $channel->name)) }}_price optional
@endforeach
{{-- Channel Tax Rates --}}
Channel Tax Rates
@foreach($channels as $channel)
{{ strtolower(str_replace(' ', '_', $channel->name)) }}_tax_rate optional
@endforeach
@endif
{{-- Right: formats + modes + download --}}
{{-- Formats --}}
Supported Formats
CSV XLSX

Row 1 must be column headers. Names are case-insensitive. Omitted optional columns are left unchanged on update, or set to defaults on create.

{{-- Import modes --}}
Import Modes
Create New
Skips any SKU that already exists.
Update Existing
Skips any SKU that doesn't exist yet.
Create or Update
Creates new and updates existing by SKU.
{{-- Download --}} Download CSV Template