Skip to content

Instantly share code, notes, and snippets.

@stewartknapman
Created November 28, 2021 23:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stewartknapman/b1efb34c837a8d1135178d80648fcf40 to your computer and use it in GitHub Desktop.
Save stewartknapman/b1efb34c837a8d1135178d80648fcf40 to your computer and use it in GitHub Desktop.
Shopify script to show shipping rates if products have certain tags
# ================================ Customizable Settings ================================
# ================================================================
# Show Rate(s) for Product Tag
#
# If we have a product with matching tag, the entered rate(s) will be
# shown, and all others will be hidden. Otherwise, the entered
# rate(s) will be hidden.
#
# - 'product_tag_match_type' determines whether we look for the
# product to be tagged with any of the entered tags or not.
# Can be:
# - ':include' to check if the product is tagged
# - ':exclude' to make sure the product isn't tagged
# - 'product_tags' is a list of product tags to trigger the
# campaign
# - 'rate_match_type' determines whether the below strings
# should be an exact or partial match. Can be:
# - ':exact' for an exact match
# - ':partial' for a partial match
# - 'rate_names' is a list of strings to identify rates
# ================================================================
SHOW_RATES_FOR_PRODUCT_TAG = [
{
product_tag_match_type: :include,
product_tags: ["free_shipping"],
rate_match_type: :exact,
rate_names: ["Free Shipping"],
},
]
# ================================ Script Code (do not edit) ================================
# ================================================================
# ProductTagSelector
#
# Finds whether the supplied product has any of the entered tags.
# ================================================================
class ProductTagSelector
def initialize(match_type, tags)
@comparator = match_type == :include ? 'any?' : 'none?'
@tags = tags.map { |tag| tag.downcase.strip }
end
def match?(product_tags)
product_tags_cleaned = product_tags.map { |tag| tag.downcase.strip }
(@tags & product_tags_cleaned).send(@comparator)
end
end
# ================================================================
# RateNameSelector
#
# Finds whether the supplied rate name matches any of the entered
# names.
# ================================================================
class RateNameSelector
def initialize(match_type, rate_names)
@comparator = match_type == :exact ? '==' : 'include?'
@rate_names = rate_names.map { |rate_name| rate_name.downcase.strip }
end
def match?(shipping_rate)
@rate_names.any? { |name| shipping_rate.name.downcase.send(@comparator, name) }
end
end
# ================================================================
# ShowRateForProductTagCampaign
#
# If we have a product with matching tags, the entered rate(s) will be
# shown, and all others will be hidden. Otherwise, the entered
# rate(s) will be hidden.
# ================================================================
class ShowRateForProductsTagCampaign
def initialize(campaigns)
@campaigns = campaigns
end
def run(cart, shipping_rates)
@campaigns.each do |campaign|
product_tag_selector = ProductTagSelector.new(
campaign[:product_tag_match_type],
campaign[:product_tags]
)
# Get all the product tags from the line items
product_tags = []
cart.line_items.map{|item| product_tags.concat(item.variant.product.tags) }
product_tags.uniq!
product_match = product_tag_selector.match?(product_tags)
rate_name_selector = RateNameSelector.new(
campaign[:rate_match_type],
campaign[:rate_names]
)
shipping_rates.delete_if do |shipping_rate|
rate_name_selector.match?(shipping_rate) != product_match
end
end
end
end
CAMPAIGNS = [
ShowRateForProductsTagCampaign.new(SHOW_RATES_FOR_PRODUCT_TAG),
]
CAMPAIGNS.each do |campaign|
campaign.run(Input.cart, Input.shipping_rates)
end
Output.shipping_rates = Input.shipping_rates
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment