Skip to main content

Delivery Methods

Delivery widgets provide a flexible way to customize the checkout form fields for different delivery methods in sCommerce. Each delivery method can have its own Blade template that renders the necessary form fields.

Overview

Starting from version 1.x, sCommerce supports customizable delivery widgets through Blade templates. This allows you to:

  • Customize checkout forms for each delivery method
  • Create project-specific delivery implementations
  • Integrate third-party delivery service widgets (Nova Poshta, UPS, etc.)
  • Maintain consistent styling across delivery methods

Template Resolution

Templates are resolved in the following priority order:

  1. Project views (highest priority)

    views/delivery/{delivery-name}.blade.php
  2. Vendor default (lowest priority)

    core/vendor/seiger/scommerce/views/delivery/{delivery-name}.blade.php

This allows you to override any delivery template by simply copying it to your project's views directory.

Available Variables

All delivery widget templates receive the following variables:

$delivery

Array containing delivery method information:

  • $delivery['name'] - Unique delivery identifier (e.g., 'courier', 'pickup')
  • $delivery['title'] - Localized delivery method title
  • $delivery['description'] - Localized delivery method description

$checkout

Array with current checkout data:

  • $checkout['user'] - User information
  • $checkout['user']['address'] - Address data (city, street, building, room, etc.)
  • $checkout['cart'] - Shopping cart data
  • Other checkout-related information

$settings

Array with delivery method settings configured in admin panel:

  • Custom settings vary by delivery method
  • Example for courier: $settings['cities'], $settings['info']
  • Example for pickup: $settings['locations']

Creating Custom Delivery Widget

Step 1: Create Delivery Class

Create a new delivery method class that extends BaseDeliveryMethod:

<?php namespace App\Delivery;

use Seiger\sCommerce\Delivery\BaseDeliveryMethod;

class CustomDelivery extends BaseDeliveryMethod
{
public function getName(): string
{
return 'custom';
}

public function getType(): string
{
return "<b>Custom Delivery</b> (custom)";
}

public function getValidationRules(): array
{
return [
'delivery.custom.address' => 'required|string|max:255',
'delivery.custom.phone' => 'required|string',
];
}

public function calculateCost(array $order): float
{
return 50.00; // Fixed cost or custom calculation
}

public function defineFields(): array
{
return [
// Admin panel settings fields
];
}

public function prepareSettings(array $data): string
{
return json_encode($data, JSON_UNESCAPED_UNICODE);
}
}

Step 2: Create Widget Template

Create a Blade template for your delivery widget:

File: views/delivery/custom.blade.php

{{--
Custom Delivery Widget

Available variables: $delivery, $checkout, $settings
--}}

<label class="form-label">
<input
type="text"
name="delivery[{{$delivery['name']}}][address]"
value="{{old('delivery.'.$delivery['name'].'.address', '')}}"
placeholder="Enter delivery address"
required
/>
<span>Delivery Address</span>
</label>

<label class="form-label">
<input
type="tel"
name="delivery[{{$delivery['name']}}][phone]"
placeholder="Phone number"
required
/>
<span>Contact Phone</span>
</label>

Step 3: Register Delivery Method

The delivery method will be automatically registered when added to the database with the correct class name.

Examples

Courier Delivery

Default template location: core/vendor/seiger/scommerce/views/delivery/courier.blade.php

Features:

  • City input with quick city selection
  • Street, building, apartment fields
  • Receiver selection (self or other person)

To customize, copy to: views/delivery/courier.blade.php

Pickup Delivery

Default template location: core/vendor/seiger/scommerce/views/delivery/pickup.blade.php

Features:

  • Radio buttons for pickup location selection
  • Displays all configured pickup addresses

To customize, copy to: views/delivery/pickup.blade.php

Field Naming Convention

Always use the following naming pattern for input fields:

name="delivery[{{$delivery['name']}}][field_name]"

This ensures proper data structure for:

  • Validation processing
  • Order data storage
  • Multi-delivery support

Using Widgets in Checkout

In your checkout view, simply output the widget:

@foreach($deliveries as $delivery)
<div data-delivery="{{$delivery['name']}}">

{{-- Info message from settings --}}
@if(isset($delivery['info']) && trim($delivery['info']))
<div class="message-info">
{!! nl2br(e($delivery['info'])) !!}
</div>
@endif

{{-- Delivery widget --}}
{!! $delivery['widget'] !!}

</div>
@endforeach

The $delivery['widget'] contains the pre-rendered HTML from the delivery method's template.

Advanced Usage

Adding JavaScript

Use @push('scripts') directive to add JavaScript for your widget:

<div id="delivery-{{$delivery['name']}}">
{{-- Your form fields --}}
</div>

@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
// Your JavaScript code
console.log('Delivery widget initialized');
});
</script>
@endpush

Conditional Fields with Alpine.js

<div x-data="{ showAdvanced: false }">
<label>
<input type="checkbox" x-model="showAdvanced">
Show advanced options
</label>

<div x-show="showAdvanced" x-transition>
{{-- Additional fields --}}
</div>
</div>

API Integration

For third-party delivery services:

<div id="delivery-api-widget-{{$delivery['name']}}"></div>

@push('scripts')
<script src="https://api.delivery-service.com/widget.js"></script>
<script>
DeliveryServiceWidget.init({
container: '#delivery-api-widget-{{$delivery['name']}}',
apiKey: '{{$settings['api_key'] ?? ''}}',
onSelect: function(data) {
// Handle delivery selection
}
});
</script>
@endpush

Best Practices

  1. Always validate input - Define validation rules in getValidationRules()
  2. Use translation keys - Make widgets multilingual with __('key')
  3. Preserve user data - Use old() helper for form repopulation
  4. Handle errors gracefully - Check if settings exist before using them
  5. Keep widgets focused - One widget = one delivery method
  6. Document your code - Add comments explaining complex logic
  7. Test across browsers - Ensure compatibility with target browsers

Troubleshooting

Widget not displaying

  1. Check if template file exists in one of the search paths
  2. Verify delivery method class implements DeliveryMethodInterface
  3. Check Laravel logs for rendering errors: storage/logs/scommerce.log

Validation errors

  1. Ensure field names match validation rules
  2. Check getValidationRules() method in delivery class
  3. Verify all required fields are present in the widget

Styling issues

  1. Check if your project's CSS classes match the widget's HTML
  2. Consider creating a custom template in views/delivery/
  3. Use browser developer tools to inspect applied styles

Migration from Hardcoded Forms

If you have existing hardcoded delivery forms in checkout.blade.php:

  1. Create widget template: views/delivery/{name}.blade.php
  2. Copy form HTML from checkout to the widget template
  3. Replace hardcoded values with template variables
  4. Update input names to use delivery[{{$delivery['name']}}][field] format
  5. Test checkout process thoroughly
  6. Remove old hardcoded form from checkout.blade.php

See Also