Mini-Tutorial: Modify Cart Data on the Fly with Shopify Scripts

We heard thrilling news last March at Shopify Unite: Shopify announced they would be rolling out Shopify Scripts – a brand new way to run custom code directly on Shopify servers when a customer adds items to their cart.

Available to Shopify Plus clients, Scripts allow developers to write Ruby code that makes server-side updates to the cart. Changes are then reflected in the browser on the cart page in Liquid. Not only is this an elegant way to extend the capabilities of the self-hosted platform without the extra costs related to provisioning servers, it’s yet another powerful tool in Demac Media’s arsenal to drive more growth for our merchants!

In true Shopify fashion, they’ve helped get us started by providing developers with both superb documentation and example scripts as well as the Scripts API.

A Shopify Scripts Case Study

ecommerce, website design, demac media, shopify plus, shopify partners, shopify developers, shopify tags
A merchant came to us with an idea – could we build them a feature that let them offer rush order upgrades to products on the cart page? The idea being that when the customer views the items in their cart, they would be presented with the option to put a rush on their order. The cost of the rush would depend on the cart subtotal.

Of course, our answer was yes!

With the power of Scripts, we could implement this functionality by checking the cart subtotal and updating the rush order price accordingly – all server-side. We would then display the correct rush order price on the cart page and follow it through to checkout. No need for an app or a separate server to run the code.

Changing a Line Item Price with Shopify Scripts

In order to write Scripts, you must install the Script Editor App. The app is available to Shopify Plus Merchants and Shopify Development Stores.

It’s worth noting that with the Script Editor App, you can only run one script at a time, but you are welcome to run multiple campaigns within that script. The app gives you the ability to run the script within the editor to test for errors, as well as a link to preview it on your store before publishing. You cannot make changes to the script unless you “Unpublish” it. Once you’re done making changes, you’ll have to hit the “Save and Publish” button again.

A Little Ruby Goes a Long Way

It’s fairly simple to write a basic, one-off implementation of this feature using the Scripts API. Imagine the customer has added the rush order product to the cart. The code would then loop through each item in the cart, stop when it gets to the rush order product, check the cart subtotal, and adjust the price accordingly.

Input.cart.line_items.each do |line_item|
  product = line_item.variant.product

  next unless product.id == 1234567890

  subtotal_without_item = Input.cart.subtotal_price_was - line_item.line_price

  if subtotal_without_item < Money.new(cents: 100_00)
    line_item.change_line_price(Money.new(cents: 20_00), message: "Rush Order is $20")
  end
end

Output.cart = Input.cart

Implementing a Campaign

Since the merchant might want to add more campaigns in the future, rather than use the one-time script above, we might choose to implement this as a campaign so we can keep our code clean.

To start, we’ll include some of the handy classes Shopify has come up with for us: ItemCampaign, AndSelector and ProductsSelector. Then, we will create own own custom class for handling the line item price update.

ItemCampaign kicks it all off by looping through the items in the cart, taking the selector we pass into it, and applying the update. It takes two arguments: the selector and the update that will be applied.

class ItemCampaign
  def initialize(selector, update)
    @selector = selector
    @update = update
  end

  def run(cart)
    cart.line_items.each do |line_item|
      next unless @selector.match?(line_item)

      @update.apply(line_item)
    end
  end
end

Then, AndSelector takes the line item that matches the selector we pass into it. You can pass in any number of selectors, but in our case we’ll only need one.

class AndSelector
  def initialize(*selectors)
    @selectors = selectors
  end

  def match?(line_item)
    @selectors.all? { |selector| selector.match?(line_item) }
  end
end

ProductsSelector selects our line item by product ID. You can pass in multiple product ids by comma separating the values.

class ProductsSelector
  def initialize(product_ids)
    @product_ids = Array(product_ids)
  end
  
  def match?(line_item)
    @product_ids.include?(line_item.variant.product.id)
  end
end

And finally, UpdatePrice is our own custom class for handling the price update. We pass in two arguments: the amount and the corresponding message that we can display on the cart page if we choose.

class UpdatePrice
  def initialize(cents, message)
    @amount = Money.new(cents: cents)
    @message = message
  end
  
  def apply(line_item)
    subtotal_without_item = Input.cart.subtotal_price_was - line_item.line_price
    money_divider = Money.new(cents: 100_00)
    
    if subtotal_without_item <= money_divider
      line_item.change_line_price(@amount, message: @message)
    end
  end
end

Then we set up our campaigns, loop through each campaign, and output the script!

CAMPAIGNS = [
  ItemCampaign.new(
    AndSelector.new(
      ProductsSelector.new(1234567890)
    ),
    UpdatePrice.new(20_00, "Rush Order is $50")
  )
]

CAMPAIGNS.each do |campaign|
  campaign.run(Input.cart)
end

Output.cart = Input.cart

And there you have it! Once you’re done, you can use Shopify’s Liquid Object for Scripts to reflect any extra information created as a result of Scripts on the cart page.

This just scratches the surface of what we can do with Scripts – and we can’t wait to see what more we can accomplish!

Check out our guide to building your on Shopify app by clicking here