Merging Two Shopify Script Examples for Customer and Product Tag Discounts

Need Help Combining Customer Tag and Product Tag Discount Scripts

I’m trying to merge two different discount scripts from Shopify’s documentation. The goal is to create a combined script that only gives discounts to specific products (tagged with something like “sale-item”) when the customer has a certain tag (like “premium-member”).

I’ve been struggling with this for a while and my attempts keep failing. Here’s what I tried so far:

# ================================ Configuration Settings ================================
# ================================================================
# Customer Tag Based Discounts
#
# Apply discounts to specific products only for tagged customers
# ================================================================
CUSTOMER_PRODUCT_DISCOUNTS = [
  {
    customer_tag_match_type: :include,
    customer_tags: ["premium-member"],
    item_selector_match_type: :include,
    item_selector_type: :tag,
    item_selectors: ["sale-eligible"],
    discount_type: :percent,
    discount_amount: 15,
    discount_message: "Premium member exclusive discount!",
  },
]

# ================================================================
# CustomerValidator
# ================================================================
class CustomerValidator
  def initialize(match_type, tags)
    @matcher = match_type == :include ? 'any?' : 'none?'
    @tags = tags.map { |tag| tag.downcase.strip }
  end

  def valid?(customer)
    customer_tags = customer.tags.map { |tag| tag.downcase.strip }
    (@tags & customer_tags).send(@matcher)
  end
end

# ================================================================
# ItemSelector
# ================================================================
class ItemSelector
  def initialize(match_type, selector_type, selectors)
    @match_type = match_type
    @matcher = match_type == :include ? 'any?' : 'none?'
    @selector_type = selector_type
    @selectors = selectors
  end

  def eligible?(cart_item)
    if self.respond_to?(@selector_type)
      self.send(@selector_type, cart_item)
    else
      raise RuntimeError.new('Unknown item selector type')
    end
  end

  def tag(cart_item)
    item_tags = cart_item.variant.product.tags.map { |tag| tag.downcase.strip }
    @selectors = @selectors.map { |selector| selector.downcase.strip }
    (@selectors & item_tags).send(@matcher)
  end
end

# ================================================================
# PriceModifier
# ================================================================
class PriceModifier
  def initialize(discount_type, discount_amount, discount_message)
    @discount_type = discount_type
    @discount_message = discount_message

    @discount_amount = if discount_type == :percent
      1 - (discount_amount * 0.01)
    else
      Money.new(cents: 100) * discount_amount
    end
  end

  def modify(cart_item)
    updated_price = if @discount_type == :percent
      cart_item.line_price * @discount_amount
    else
      [cart_item.line_price - (@discount_amount * cart_item.quantity), Money.zero].max
    end

    cart_item.change_line_price(updated_price, message: @discount_message)
  end
end

The script runs but doesn’t apply the discount properly. I think there’s an issue with how I’m connecting the customer validation with the product selection logic. Can someone help me figure out what’s wrong?

Your CustomerValidator class has a bug. The problem is (@tags & customer_tags).send(@matcher) - when you call any? or none? on an array without a block, they don’t work right.

I hit this exact issue building customer segmentation logic. Just check if the intersection has elements:

class CustomerValidator
  def initialize(match_type, tags)
    @match_type = match_type
    @tags = tags.map { |tag| tag.downcase.strip }
  end

  def valid?(customer)
    return false unless customer
    customer_tags = customer.tags.map { |tag| tag.downcase.strip }
    matches = (@tags & customer_tags).any?
    @match_type == :include ? matches : !matches
  end
end

Don’t forget the execution loop AdventurousHiker17 mentioned. Your logic’s fine - that method call was just silently breaking validation.

Yeah, I see what’s wrong with your Ruby script - you’ve got the classes defined but there’s no execution logic actually calling them.

Honestly though, Shopify Scripts are a nightmare. They’re deprecated now and even the new Shopify Functions have tons of limitations.

I ran into the same discount headaches at work and just moved everything to external automation. Way more flexible and handles edge cases that Shopify can’t touch.

What you want is a workflow that watches customer tags and product tags, then auto-applies discount codes or tweaks pricing through the Admin API. Full control without getting stuck in Shopify’s scripting mess.

I built one that checks customer segments, validates collections, and does tiered discounts based on purchase history. Takes 10 minutes to set up vs hours debugging Ruby.

Bonus: you can add email notifications when discounts hit, track analytics, or make discount amounts change based on inventory.

Check out Latenode for this stuff: https://latenode.com

you’re missing the execution part at the end. you defined all those classes but never actually used them. after your class definitions, you need to loop through the cart items and apply the logic:

Input.cart.line_items.each do |line_item|
  CUSTOMER_PRODUCT_DISCOUNTS.each do |discount|
    if CustomerValidator.new(discount[:customer_tag_match_type], discount[:customer_tags]).valid?(Input.cart.customer)
      if ItemSelector.new(discount[:item_selector_match_type], discount[:item_selector_type], discount[:item_selectors]).eligible?(line_item)
        PriceModifier.new(discount[:discount_type], discount[:discount_amount], discount[:discount_message]).modify(line_item)
      end
    end
  end
end

Output.cart = Input.cart

you built all the tools but forgot to use them.

Your code defines all the classes but doesn’t actually run them. You’re missing the main execution logic that processes cart items and applies discounts.

I hit this same issue building store scripts. The classes look right, but there’s no code that loops through CUSTOMER_PRODUCT_DISCOUNTS and applies it to Input.cart.line_items.

You need to instantiate CustomerValidator and ItemSelector for each discount config, then loop through cart items checking if the customer AND product both qualify before calling PriceModifier. Right now the script just sits there - it defines classes but never runs the discount logic.

Also verify your customer has the right tag and products have correct tags in your test environment. Sometimes it’s not the code, it’s bad test data.