Personalized checkout and custom promotions with Shopify Scripts
I want to use a script to exclude any coupon from being used on specific product variants(not collections or full products)
Context
We have many coupon codes with affiliates as well as 1 time use codes that go out for email subscribers and SMS etc. So we have hundreds of coupon codes out there. We have always excluded preset bundles from coupon codes using the collection method. We have since added multi-pack variants to each of our individdual products that have a hard discount. The price of the 3pack is already discounted so we don't want customers double-dipping with coupon codes.
There are two scripts on this link. One titled "Disable discount codes" this disables all codes from being used. You typically use this when running a store-wide sale so nobody can double dip. The other script is "Disable discount codes for product" this one allows you to input specific discount codes for specific products or product variants.
I'm trying to merge the two. I would like to have ALL coupon codes disabled for specific product variants all the time so that I don't have to input every unique coupon code that could be used into the script. I would also have to update it with additional codes constantly. I know that I will have to enter the unique SKU of each variant I want it to apply to.
Any help would be appreciated. Thank you in advance.
Hey there, I've generated this script for you. It blocks all discount codes for the listed variant IDs and displays a message to the customer. You can further customize it toward the bottom. I'll also attach it as a .txt file just in case.
########################################################################
## Create Shopify scripts without writing code at playwrightapp.com ##
########################################################################
class Campaign
def initialize(condition, *qualifiers)
@condition = (condition.to_s + '?').to_sym
@qualifiers = PostCartAmountQualifier ? [] : [] rescue qualifiers.compact
_item_selector = qualifiers.last unless _item_selector
qualifiers.compact.each do |qualifier|
is_multi_select = qualifier.instance_variable_get(:@conditions).is_a?(Array)
if is_multi_select
qualifier.instance_variable_get(:@conditions).each do |nested_q|
@post_amount_qualifier = nested_q if nested_q.is_a?(PostCartAmountQualifier)
@qualifiers << qualifier
end
else
@post_amount_qualifier = qualifier if qualifier.is_a?(PostCartAmountQualifier)
@qualifiers << qualifier
end
end if @qualifiers.empty?
end
def qualifies?(cart)
return true if @qualifiers.empty?
@unmodified_line_items = cart.line_items.map do |item|
new_item = item.dup
new_item.instance_variables.each do |var|
val = item.instance_variable_get(var)
new_item.instance_variable_set(var, val.dup) if val.respond_to?(:dup)
end
new_item
end if @post_amount_qualifier
@qualifiers.send(@condition) do |qualifier|
is_selector = false
if qualifier.is_a?(Selector) || qualifier.instance_variable_get(:@conditions).any? { |q| q.is_a?(Selector) }
is_selector = true
end rescue nil
if is_selector
raise "Missing line item match type" if _match_type.nil?
cart.line_items.send(@li_match_type) { |item| qualifier.match?(item) }
else
qualifier.match?(cart, _item_selector)
end
end
end
def run_with_hooks(cart)
before_run(cart) if respond_to?(:before_run)
run(cart)
after_run(cart)
end
def after_run(cart)
@discount.apply_final_discount if @discount && @discount.respond_to?(:apply_final_discount)
revert_changes(cart) unless @post_amount_qualifier.nil? || @post_amount_qualifier.match?(cart)
end
def revert_changes(cart)
cart.instance_variable_set(:@line_items, @unmodified_line_items)
end
end
class ConditionalDiscountCodeRejection < Campaign
def initialize(condition, customer_qualifier, cart_qualifier, li_match_type, line_item_qualifier, message)
super(condition, customer_qualifier, cart_qualifier, line_item_qualifier)
_match_type = (li_match_type.to_s + '?').to_sym
@message = message == "" ? "This discount code cannot be used at this time" : message
end
def run(cart)
return unless cart.discount_code
cart.discount_code.reject({message: @message}) if qualifies?(cart)
end
end
class Selector
def partial_match(match_type, item_info, possible_matches)
match_type = (match_type.to_s + '?').to_sym
if item_info.kind_of?(Array)
possible_matches.any? do |possibility|
item_info.any? do |search|
search.send(match_type, possibility)
end
end
else
possible_matches.any? do |possibility|
item_info.send(match_type, possibility)
end
end
end
end
class VariantIdSelector < Selector
def initialize(match_type, variant_ids)
@invert = match_type == :not_one
@variant_ids = variant_ids.map { |id| id.to_i }
end
def match?(line_item)
@invert ^ @variant_ids.include?(line_item.variant.id)
end
end
CAMPAIGNS = [
ConditionalDiscountCodeRejection.new(
:all,
nil,
nil,
:any,
VariantIdSelector.new(
:is_one,
["0123456789", "9876543210"]
),
"Sorry, cannot use discount codes with this purchase"
)
].freeze
CAMPAIGNS.each do |campaign|
campaign.run_with_hooks(Input.cart)
end
Output.cart = Input.cart
Feel free to test it out and let me know if you need any changes!
Best,
Matthew
Thank you so much. I will give it a go. Will this allow discounts to be applied to the other products? If we exclude 3 packs from any discount code and someone buys a 3 pack and a single would the discount codes still apply to the singles that are in the cart with the 3 pack?
@rockjuice2, no. This script will simply reject any and all discount codes when those products are in the cart.
If you find you need to switch strategies, let me know!
@playwright-mike We will have people buying packs as well as individual items. Is there a way to write the script where it would allow the discount to be used on the individual items and just not the 3 packs?
Hypothetically the cart would have:
3 pack $20
Single $10
Single $10
Subtotal $40
20% off Coupon code xxx
3pack would stay at $20
Single 1 drops to $8
Single 2 drops t0 $8
New Subtotal $36
Hi Playwright-Matt:
I have a very similar issue. We want to disable all discount codes on specific product items or variants, but we want all other products to accept the discount codes.
We have a lot of affiliate marketers that sign up to be an affiliate automatically, and so we have dozens of dynamic discount codes.
It is easier to take a product and just say "make this product unavailable for discount", but allow any other product in the cart to be able to use the code.
I have been using Playwright Script Generator to try to do this, but I can only see a way to disable all discount codes if one of those specific products is in the cart.
Is there a way to do this?
Hey Matthew! I can't figure out which part of your script I should edit to have it exclude my variants "solid gold" which have the tag "solid gold" and also in the SKU have text 14k-solid-yellow-gold or 14k-solid-white-gold (but all are tagged the same as solid gold). Thank you!
Hey @busyronin, responded to you in a private message.
Hi there,
I am trying to block ALL active discount codes that exist from affiliate's and automatic codes from newsletters on a certain SKU. We lowered the price of a product because it's out of stock. We are offering the lower price to pre order. We don't want customers to be able to apply additional discounts to that product. If they do have an discount code it can work on other SKUS just want to exclude a specific product.
I reached out to the app mentioned above "Automatic discount." waiting to hear back. If anyone has any advice on how to do this, please let me know. Thank you!
This works great for my needs of excluding discount codes from applying to certain variants. Thank you!
Where would this script be utilized?
Discover how to increase customer engagement on your store with articles from Shopify A...
By Jacqui Apr 23, 2025Hey Community 👋 Did you know that March 15th is National Everything You Think Is W...
By JasonH Apr 1, 2025Discover how to increase the efficiency of commerce operations with Shopify Academy's l...
By Jacqui Mar 26, 2025