Personalized checkout and custom promotions with Shopify Scripts
Hi, really need your guys help.
I'm trying to create a tiered fixed price offer.
Order 3 - for $X
Order 5 for $Y
Order 8 for $Z
However I can't find example in Shopify supplied guide. I was able to create only for 1 offer not tiered like example below. Could anyone help me how can I create similar script as below, BUT tiered?
# ================================ Customizable Settings ================================ # ================================================================ # Buy X of Product Y for $Z # # Buy a certain number of matching items for a specific price. # For example: # # "Buy 2 t-shirts for $20" # # - 'product_selector_match_type' determines whether we look for # products that do or don't match the entered selectors. Can # be: # - ':include' to check if the product does match # - ':exclude' to make sure the product doesn't match # - 'product_selector_type' determines how eligible products # will be identified. Can be either: # - ':tag' to find products by tag # - ':type' to find products by type # - ':vendor' to find products by vendor # - ':product_id' to find products by ID # - ':variant_id' to find products by variant ID # - ':subscription' to find subscription products # - ':all' for all products # - 'product_selectors' is a list of identifiers (from above) # for qualifying products. Product/Variant ID lists should # only contain numbers (ie. no quotes). If ':all' is used, # this can also be 'nil'. # - 'quantity_to_buy' is the number of products needed to # qualify # - 'final_price` is the amount to charge for all products that # are part of the offer # - 'discount_message' is the message to show when a discount # is applied # ================================================================ BUY_X_GET_Y_FOR_Z = [ { product_selector_match_type: :include, product_selector_type: :tag, product_selectors: ["your_tag"], quantity_to_buy: 2, final_price: 100, discount_message: 'Buy 2 for $20', }, ] # ================================ Script Code (do not edit) ================================ # ================================================================ # ProductSelector # # Finds matching products by the entered criteria. # ================================================================ class ProductSelector def initialize(match_type, selector_type, selectors) @match_type = match_type @comparator = match_type == :include ? 'any?' : 'none?' @selector_type = selector_type @selectors = selectors end def match?(line_item) if self.respond_to?(@selector_type) self.send(@selector_type, line_item) else raise RuntimeError.new('Invalid product selector type') end end def tag(line_item) product_tags = line_item.variant.product.tags.map { |tag| tag.downcase.strip } @selectors = @selectors.map { |selector| selector.downcase.strip } (@selectors & product_tags).send(@comparator) end def type(line_item) @selectors = @selectors.map { |selector| selector.downcase.strip } (@match_type == :include) == @selectors.include?(line_item.variant.product.product_type.downcase.strip) end def vendor(line_item) @selectors = @selectors.map { |selector| selector.downcase.strip } (@match_type == :include) == @selectors.include?(line_item.variant.product.vendor.downcase.strip) end def product_id(line_item) (@match_type == :include) == @selectors.include?(line_item.variant.product.id) end def variant_id(line_item) (@match_type == :include) == @selectors.include?(line_item.variant.id) end def subscription(line_item) !line_item.selling_plan_id.nil? end def all(line_item) true end end # ================================================================ # DollarDiscountApplicator # # Applies the entered discount to the supplied line item. # ================================================================ class DollarDiscountApplicator def initialize(discount_message) @discount_message = discount_message end def apply(line_item, discount_amount) new_line_price = line_item.line_price - discount_amount line_item.change_line_price(new_line_price, message: @discount_message) end end # ================================================================ # BuyXOfYForZCampaign # # Buy a certain number of matching items for a specific price. # ================================================================ class BuyXOfYForZCampaign def initialize(campaigns) @campaigns = campaigns end def run(cart) @campaigns.each do |campaign| product_selector = ProductSelector.new( campaign[:product_selector_match_type], campaign[:product_selector_type], campaign[:product_selectors], ) eligible_items = cart.line_items.select { |line_item| product_selector.match?(line_item) } next if eligible_items.nil? eligible_item_count = eligible_items.map(&:quantity).reduce(0, :+) quantity_to_buy = campaign[:quantity_to_buy] number_of_offers = (eligible_item_count / quantity_to_buy).floor next unless number_of_offers > 0 number_of_discountable_items = number_of_offers * quantity_to_buy total_offer_price = Money.new(cents: 100) * (number_of_offers * campaign[:final_price]) discount_applicator = DollarDiscountApplicator.new(campaign[:discount_message]) self.loop_items(cart, eligible_items, number_of_discountable_items, total_offer_price, discount_applicator) end end def loop_items(cart, line_items, num_to_discount, total_price, discount_applicator) current_price = Money.zero avg_price = total_price * (1 / num_to_discount) line_items = line_items.sort_by { |line_item| line_item.variant.price } line_items.each do |line_item| break if num_to_discount <= 0 if line_item.quantity > num_to_discount split_line_item = line_item.split(take: num_to_discount) discount_amount = split_line_item.line_price - (total_price - current_price) discount_applicator.apply(split_line_item, discount_amount) position = cart.line_items.find_index(line_item) cart.line_items.insert(position + 1, split_line_item) break elsif line_item.quantity == num_to_discount discount_amount = line_item.line_price - (total_price - current_price) discount_applicator.apply(line_item, discount_amount) break else if line_item.variant.price <= avg_price current_price += line_item.line_price else discount_amount = (line_item.variant.price - avg_price) * line_item.quantity current_price += (line_item.line_price - discount_amount) discount_applicator.apply(line_item, discount_amount) end num_to_discount -= line_item.quantity end end end end CAMPAIGNS = [ BuyXOfYForZCampaign.new(BUY_X_GET_Y_FOR_Z), ] CAMPAIGNS.each do |campaign| campaign.run(Input.cart) end Output.cart = Input.cart
@dmitry_z Try the following script repo:
https://github.com/Shopify/shopify-scripts
Plus Merchants that need direct support to either customize business logic , debug , or integrate checkout scripts can contact me at paull.newton+shopifyforums@gmail.com with this topic url, store url, and use case details for pricing.
New Feature: Automatic free shipping discounts
Confused? Busy? Get the solution you need paull.newton+shopifyforum@gmail.com
Problem Solved? ✔Accept and Like solutions to help future merchants
Answers powered by coffee Buy Paul a ☕ Coffee for more answers or donate to eff.org
Defeat problems ,Learn To Ask Questions The Smart Way
Thanks for the links, unfortunately I didn't find the correct one.
I need something similar to this but tiered, buy 3, 5, 8:
BUY_X_GET_Y_FOR_Z = [ { product_selector_match_type: :include, product_selector_type: :tag, product_selectors: ["your_tag"], quantity_to_buy: 3, final_price: 100, discount_message: 'Buy 3 for $20',
I tried to merging this script + script with tiered data. It was unsuccessful 😞
You'd still have to update the logic in your script to match how it's using that configuration.
Or go the other way and update the tier script to incorporate your scripts logic.
Where PRICE_TIERS becomes BUY_X_GET_Y_FOR_Z if need be
PRICE_TIERS = [ # Pricing tiers for Shoes { product_types: ['Shoes'], group_by: :product, # :product or :variant tiers: [ { quantity: 10, discount_percentage: 10, discount_message: '10% off for 10+' }, { quantity: 50, discount_percentage: 15, discount_message: '15% off for 50+' } ] } ]
New Feature: Automatic free shipping discounts
Confused? Busy? Get the solution you need paull.newton+shopifyforum@gmail.com
Problem Solved? ✔Accept and Like solutions to help future merchants
Answers powered by coffee Buy Paul a ☕ Coffee for more answers or donate to eff.org
Defeat problems ,Learn To Ask Questions The Smart Way
This blog post is a recap of the webinar Getting Ready For BFCM: How To Run A Flash Sal...
By Jacqui Oct 3, 2023Explore the 30-30-30 rule, a dynamic social media strategy for new businesses. Learn how t...
By Trevor Sep 20, 2023Discover how to leverage the often overlooked footer of your ecommerce site to gain custom...
By Skye Sep 15, 2023