> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sitestorepro.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Building Shipping Rate Plugins for Site Store Pro

> Build custom shipping rate plugins using ShippingPlugin, return structured rate arrays from calculateRates(), and register as built-in or drop-in.

Shipping plugins allow you to connect any carrier API — or implement any custom rate logic — and surface the results as selectable shipping options during checkout. Each plugin receives a `ShippingContext` containing the full order details and returns a structured array of labelled rate options. The registration flow is identical to display plugins, so if you've already built one of those, building a shipping plugin will feel immediately familiar.

## The ShippingPlugin Interface

Every shipping plugin must implement the following contract:

```php theme={null}
namespace App\Plugins\Contracts;

use App\Models\Plugin;
use App\Plugins\Support\ShippingContext;

interface ShippingPlugin
{
    public function slug(): string;
    public function name(): string;
    public function calculateRates(ShippingContext $context, Plugin $plugin): array;
}
```

| Method             | Description                                                                 |
| ------------------ | --------------------------------------------------------------------------- |
| `slug()`           | Unique identifier for the plugin, used internally and in the admin panel    |
| `name()`           | Human-readable label shown during checkout and in plugin settings           |
| `calculateRates()` | Returns an array of rate options given the current order's shipping context |

## The ShippingContext Object

The `ShippingContext` passed to `calculateRates()` carries everything you need to compute a rate:

| Property      | Description                                |
| ------------- | ------------------------------------------ |
| `weight`      | Total order weight                         |
| `dimensions`  | Package dimensions (length, width, height) |
| `origin`      | Warehouse or fulfilment address            |
| `destination` | Customer's shipping address                |

Access these properties inside your plugin to call a carrier API or apply your own rate table logic.

## Expected Return Format

`calculateRates()` must return a flat array of associative rate options. Each option requires a `label` and a numeric `rate`:

```php theme={null}
return [
    [
        'label' => 'Standard Ground (3-5 Days)',
        'rate'  => 9.99,
    ],
    [
        'label' => 'Express (1-2 Days)',
        'rate'  => 19.99,
    ],
];
```

Site Store Pro renders each entry as a selectable shipping method at checkout. The customer sees the `label`, and the `rate` is added to the order total.

<Note>
  Return an empty array `[]` when no rates are available for the given context — for example, when the destination country is outside your coverage area. Site Store Pro will suppress the plugin's options at checkout rather than showing a zero-rate entry.
</Note>

## Complete Example: Flat-Rate Shipping Plugin

Here is a minimal but fully functional shipping plugin that demonstrates reading a plugin setting and returning tiered flat rates:

```php theme={null}
<?php

class FlatRateShippingPlugin implements \App\Plugins\Contracts\ShippingPlugin
{
    public function slug(): string
    {
        return 'flat-rate-shipping';
    }

    public function name(): string
    {
        return 'Flat Rate Shipping';
    }

    public function calculateRates(
        \App\Plugins\Support\ShippingContext $context,
        \App\Models\Plugin $plugin
    ): array {
        // Read a base rate configured in the admin panel
        $baseRate = (float) $plugin->getSetting('base_rate', '5.99');

        // Apply weight-based surcharge
        $weight      = $context->weight ?? 0;
        $surcharge   = $weight > 5 ? 4.00 : 0.00;
        $expressRate = $baseRate + $surcharge + 10.00;

        return [
            [
                'label' => 'Standard Shipping (5-7 Days)',
                'rate'  => round($baseRate + $surcharge, 2),
            ],
            [
                'label' => 'Express Shipping (1-2 Days)',
                'rate'  => round($expressRate, 2),
            ],
        ];
    }
}
```

## Registering a Shipping Plugin

You can register a shipping plugin as a built-in class or as a drop-in directory — the process mirrors display plugins exactly.

<Tabs>
  <Tab title="Built-in (PluginServiceProvider)">
    Place your class in `app/Plugins/Shipping/` and register it in `app/Providers/PluginServiceProvider.php`:

    ```php theme={null}
    $manager->register(\App\Plugins\Shipping\FlatRateShippingPlugin::class);
    ```

    Then add the database record and any option fields via the `PluginSeeder` and reseed:

    ```bash theme={null}
    php artisan db:seed --class=PluginSeeder
    ```
  </Tab>

  <Tab title="Drop-in (/plugins/ directory)">
    Create a directory under `/plugins/` with a `plugin.json` manifest and your PHP class file:

    ```text theme={null}
    plugins/
      flat-rate-shipping/
        plugin.json
        FlatRateShippingPlugin.php
    ```

    Set `"type": "shipping"` in your manifest:

    ```json theme={null}
    {
      "class": "FlatRateShippingPlugin",
      "name": "Flat Rate Shipping",
      "version": "1.0",
      "type": "shipping",
      "shortcode": "flat-rate-shipping",
      "description": "Configurable flat-rate shipping with optional weight surcharge",
      "author": "Store Dev",
      "options": [
        {
          "field_name": "base_rate",
          "field_label": "Base Shipping Rate ($)",
          "field_type": "input",
          "field_required": "yes",
          "sort_order": 10,
          "field_default_value": "5.99"
        }
      ]
    }
    ```

    The `PluginManager` detects the new directory on the next boot and automatically syncs the option fields to the database.
  </Tab>
</Tabs>

<Tip>
  After registering your shipping plugin, navigate to **Admin → Shipping → Methods** to activate it and configure its settings. Inactive shipping plugins are never called during checkout rate calculation.
</Tip>

## Plugin Model Helpers

The `Plugin` model passed to `calculateRates()` provides the same three convenience methods available to display plugins. Their formal signatures are:

```php theme={null}
// Retrieve a single setting with a fallback default
Plugin::getSetting(string $key, mixed $default): mixed

// Retrieve all settings as a key => value array
Plugin::getSettings(): array

// Persist one or more settings at once
Plugin::saveSettings(array $settings): void
```

**Usage examples:**

```php theme={null}
// Read a single setting with a fallback
$baseRate = $plugin->getSetting('base_rate', '5.99');

// Read all settings at once
$settings = $plugin->getSettings();

// Persist updated settings
$plugin->saveSettings(['base_rate' => '7.99']);

// Query all active shipping plugins
$shippingPlugins = Plugin::scopeActive()->scopeOfType('shipping')->get();
```
