Dynamically Customizing Line Item Prices

Craft Commerce provides Sales and Discounts for promotional price adjustment based on certain criteria, but there may be cases where you need to dynamically set the normal price for a line item.

Maybe you’d like something similar to a VIP group discount, except the change isn’t a promotion but a different normal price. Or perhaps your variant’s price is a starting point that needs to factor in fee tables managed by custom fields.

Commerce veterans may have reached for a custom adjuster, which should be avoided because they can create problems sending the correct values to payment gateways. Commerce 5 will no longer accept custom adjusters—only discount, shipping, and tax.

The simplest way to change a line item’s price is to modify its price and salePrice properties the moment it’s being prepared for the cart. We can do that by using a custom module to hook into the LineItems::EVENT_POPULATE_LINE_ITEM event:

use craft\commerce\events\LineItemEvent;
use craft\commerce\services\LineItems;
use craft\commerce\models\LineItem;
use yii\base\Event;

Event::on(
    LineItems::class,
    LineItems::EVENT_POPULATE_LINE_ITEM, 
    function(LineItemEvent $event) {
        /** @var LineItem **/
        $lineItem = $event->lineItem;

        $lineItem->salePrice = 123.45;
        $lineItem->price = 123.45;
    }
);

It’s important to remember salePrice here since it’s what actually gets added to the cart. price is more of a display price that could be used for something like MSRP.

This example makes every line item available for $123.45, which is surely not what you’d like to do. So let’s use that example of VIP pricing.

Example #

We’d like members in a “VIP” user group to automatically get a special price for a specific product variant. That price is $100.25, which is a sweet deal, and the variant ID is 123.

We can add some conditionals to that example above in order to accomplish this:

use craft\commerce\events\LineItemEvent;
use craft\commerce\services\LineItems;
use craft\commerce\models\LineItem;
use craft\commerce\base\Purchasable;
use yii\base\Event;

Event::on(
    LineItems::class,
    LineItems::EVENT_POPULATE_LINE_ITEM, 
    function(LineItemEvent $event) {
        /** @var LineItem $lineItem **/
        $lineItem = $event->lineItem;
        /** @var Purchasable $purchasable **/
        $purchasable = $lineItem->getPurchasable();

        if (
            $purchasable->id === 123 
            && Craft::$app->getUser()->isInGroup('vip')
        ) {
             $lineItem->salePrice = 100.25;
             $lineItem->price = 100.25;
        }
    }
);

When our variant, identified by its ID of 123, is populated into a line item for the cart, any user that’s a member of our user group, identified by its vip handle, will see the special $100.25 in their cart and be able to complete the purchase at that price.

Applies to Craft Commerce 4 and Craft Commerce 3.