Adjusters
Adjuster classes return models that modify pricing when an order is recalculated.
Prior to version 4.5, custom adjusters were only honored in Commerce Pro.
# Writing an Adjuster
Each class implements the Adjuster Interface (opens new window) with an adjust()
method for evaluating the order and returning zero or more OrderAdjustment (opens new window) models. Each of those models may be applied to the order or one of its line items.
Do you need your own adjuster?
The built-in adjusters each include integration points that could reduce the amount of custom code you need to write. Look at the existing Discount (opens new window), Shipping (opens new window), and Tax (opens new window) adjusters before you write your own from scratch.
An adjustment model must have a type
of shipping
, discount
, or tax
to ensure the adjustment is properly represented to the payment gateway. (Adjustments are applied in that order under the hood.)
The rest of this page covers discount and shipping adjusters even though there is also a tax
adjuster type. Only one tax adjuster is allowed, but tax adjustments are deeply customizable via tax engines.
# Registering a New Adjuster
You can register your adjuster class by including it in the types
array attribute of the registerOrderAdjusters
or registerDiscountAdjusters
event model.
use craft\commerce\services\OrderAdjustments;
use yii\base\Event;
use MyAdjuster;
Event::on(
OrderAdjustments::class,
OrderAdjustments::EVENT_REGISTER_ORDER_ADJUSTERS,
function(RegisterComponentTypesEvent $event) {
$event->types[] = MyAdjuster::class;
}
);
The order of the adjustments within the types
array is important because adjusters will be called in exactly that sequence when an order is calculated.
Even if you don’t add or replace an adjuster you might still use either event solely to change the order in which existing adjustments are applied.
# Replacing an Adjuster
Because the adjusters are exposed in an array, you could also swap your own custom adjuster for one that’s included. Here, we’re swapping a custom MyShippingAdjuster
in place of the included Shipping (opens new window) class:
use craft\commerce\services\OrderAdjustments;
use yii\base\Event;
use craft\commerce\adjusters\Shipping;
use MyShippingAdjuster;
Event::on(
OrderAdjustments::class,
OrderAdjustments::EVENT_REGISTER_ORDER_ADJUSTERS,
function(RegisterComponentTypesEvent $event) {
$adjusters = $event->types;
foreach ($adjusters as $key => $adjuster) {
if ($adjuster == Shipping::class) {
$adjusters[$key] = MyShippingAdjuster::class;
}
}
$event->types = $adjusters;
}
);
# Creating Adjustments
The adjuster interface consists of a single method: adjust(Order $order)
.
Each OrderAdjustment (opens new window) model returned by that adjust
method—if it returns any at all—will have adjustment details and should include contextual information that explains why the adjuster returned it:
- $type should be
shipping
,discount
, ortax
to reflect the kind of adjustment. - $amount is the value (positive or negative) used to modify the order or line item. (Negative amounts reduce the price of the order.)
- $orderId is the ID of the applicable order, which should be set via the
setOrder()
method. - $sourceSnapshot is a required array or JSON string that should illuminate the rationale behind the adjustment. The included shipping adjuster, for example, includes whatever matching shipping rules were used to calculate the shipping cost.
- $lineItemId refers to the ID of an applicable line item on the order, which should optionally be set via the
setLineItem()
method. - $included is
false
by default, and whentrue
prevents the adjustment from changing the order’s total in order to clarify that it was already included in the price of the order. (The only included adjustment Commerce ships with is used for taxes.) - $name is an optional short, human-friendly label for the adjustment.
- $description is an optional longer, human-friendly description of the adjustment.
# Designating an Order and Line Item
An adjustment model always belongs to an order, but can optionally belong to a line item.
To specify the adjustment’s order, use the setOrder()
method when creating the adjustment:
$adjustment->setOrder($order);
To the adjustment’s line item, use the setLineItem()
method when creating the adjustment model:
$adjustment->setLineItem($lineItem);
Using these methods ensures the correct order and line item will be referenced even if either one is new and doesn’t yet have an ID.
# Example
Below is an example adjuster class that puts a $2 discount on each line item:
<?php
use craft\base\Component;
use craft\commerce\base\AdjusterInterface;
use craft\commerce\elements\Order;
use craft\commerce\models\OrderAdjustment;
class MyAdjuster extends Component implements AdjusterInterface
{
public function adjust(Order $order): array
{
$adjustments = [];
foreach ($order->getLineItems() as $item) {
$adjustment = new OrderAdjustment;
$adjustment->type = 'discount';
$adjustment->name = '$2 off';
$adjustment->description = '$2 off everything in the store';
// `sourceSnapshot` can contain information to explain the adjustment
$adjustment->sourceSnapshot = [ 'data' => 'value' ];
$adjustment->amount = -2;
$adjustment->setOrder($order);
$adjustment->setLineItem($item);
$adjustments[] = $adjustment;
}
return $adjustments;
}
}