Shopify脚本学习笔记

Shopify 与 Shopify 脚本、 Script Editor 应用

  • Shopify:Shopify Inc.是加拿大的一家跨国电子商务公司,总部位于安大略省渥太华,Shopify也是该公司所有的电子商务平台的名称。[3]Shopify为在线零售商提供一整套服务“包括支付、市场营销、运输和客户契合工具,以简化小型商户开设在线商店的过程”
  • Shopify 脚本和 Script Editor 应用:Shopify 脚本是一小段代码,使您能够为客户创建个性化购物车体验和结账体验。

    • 仅支持 plus 商家(氪金)
    • Shopify 脚本 API

      • 脚本示例:当客户订购非礼品卡的产品时,产品价格会降低 9 美元。此外还会显示该客户在对您的在线商店的所有访问中花费的总金额

          customer = Input.cart.customer
          Input.cart.line_items.each do |line_item|
              product = line_item.variant.product
              next if product.gift_card?
              line_item.change_line_price(line_item.line_price - Money.new(cents: 900), message: customer.total_spent)
          end
        
          Output.cart = Input.cart
        
      • 补充知识:

Shopify 脚本

脚本种类

  • 订单商品脚本。
  • 发货脚本。
  • 付款脚本。

脚本要求和限制

  • 可以选择运行在在线商店,或者在线商店、服务器、移动端 sdk。
  • 生成结账的自定义应用。
  • Tapcart 和 Plobal Apps 移动应用生成器。(暂不清楚 Tapcart 和 Plobal Apps 是什么)
  • 每种脚本类型一次只能发布一个脚本。
  • 最多可以创建 200 个 Shopify 脚本。
  • 订单项目脚本、发货脚本和付款脚本不适用于草稿订单或草稿订单结账。
  • 不能访问元字段。(不能直接访问接口字段)
  • Shopify 脚本无法访问(页面中的) Shopify Liquid 购物车属性。(不能操作前端页面中的属性)
  • 脚本可以访问是否应用了折扣码、折扣金额和折扣类型(固定金额、百分比或运费),但他们无法访问其应用方式(特定购物车或订单项目)。因此,脚本无法访问折扣后的总金额,也无法访问自动折扣。
  • 脚本无法向购物车添加商品,也无法提高商品的价格。(即脚本具有滞后性)
  • 脚本无法提高运费价格。
  • 不支持正则。
  • 对模版有要求。(没看懂要求了啥)
  • 有资源追踪和监控。
  • Shopify 脚本无法进行输入/输出(相对封闭)。但是可以用 puts 输入到 Script Editor 应用中的控制台(调试)。
  • 脚本不能包含随机计算或基于时间的计算。
  • 限制 24,576 个字符以内。
  • 订阅产品有限制(什么限制没看懂)。具体参考订阅和脚本
  • 快捷结账会忽略脚本影响,但是实际支付时会按脚本折扣进行。
  • 不适用于 Shopify POS (实体店销售)。

更新用于脚本的 Liquid 模板此章应该非常重要

模板与脚本的关系

  • 模板是界面层,脚本是逻辑层。模板应该显示脚本运行前后的效果。
  • 添加脚本后,可能需要更新模板文件。
  • 是否有测试环境?

Liquid 对象属性

Liquid:Liquid 是一门开源的模板语言,由 Shopify 创造并用 Ruby 实现。它是 Shopify 主题的骨骼,并且被用于加载店铺系统的动态内容。 草,又一个搞前端轮子的。

  • 购物车对象及其属性。
  • 订单项目及其属性。
  • 脚本对象

模板与脚本示例

<table>
    <thead>
        <tr>
            <th>Month</th>
            <th>Savings</th>
        </tr>
    </thead>
    <tbody class="line-items">
        {% for item in cart.items %}
        <tr>
            <td>{{ item.product.title }}</td>
            <td>{{ item.quantity }}</td>
            <td>
            {{ item.line_price }}
            {% if item.total_discount > 0 %}
                <s>{{ item.original_line_price }}</s>
                ( {{ item.message }} )
            {% endif %}
            </td>
        </tr>
        {% endfor %}
    </tbody>
    <tfoot class="summary">
        <tr>
            <td colspan="2">Subtotal</td>
            <td>{{ cart.original_total_price | money }}</td>
        </tr>
        <tr>
            <td colspan="2">Discount Savings</td>
            <td>{{ cart.total_discount | money }}</td>
        </tr>
        <tr>
            <td colspan="2">Total</td>
            <td>{{ cart.total_price | money }}</td>
        </tr>
    </tfoot>
</table>

脚本示例

使用 & 阅读脚本前知识储备

脚本基本类型

  • 折扣产品带有特定的标签以提供百分比 (%) 折扣、固定金额(美元)折扣或者这两种折扣的组合。
  • 投放逻辑简单或复杂的促销活动(买一送一 (BOGO));买两件打九折、买四件打八折)。
  • 根据基于数量的价格区间提供动态价格。
  • 修改、隐藏发货选项和价格或将其重新排序。
  • 修改、隐藏或重新排列支付网关方法。

示例脚本

热门脚本
  1. 按消费金额提供购物车分级折扣
# ================================ Customizable Settings ================================
# ================================================================
# Tiered Cart Discounts by Spend Threshold
#
# If the cart total is greater than (or equal to) an entered
# threshold, the associated discount is applied to the cart. The
# discount will be spread, as evenly as possible, across all items.
#
# - 'threshold' is the spend amount needed to qualify
# - 'discount_amount' is the dollar discount to apply to the
# cart
# - 'discount_message' is the message to show when a discount
# is applied
# ================================================================
SPENDING_THRESHOLDS = [
  {
    threshold: 150,
    discount_amount: 25,
    discount_message: 'Spend $150 and get $25 off!',
  },
  {
    threshold: 300,
    discount_amount: 50,
    discount_message: 'Spend $300 and get $50 off!',
  },
  {
    threshold: 400,
    discount_amount: 75,
    discount_message: 'Spend $400 and get $75 off!',
  },
]

# ================================ Script Code (do not edit) ================================
# ================================================================
# 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

# ================================================================
# TieredCartDiscountBySpendCampaign
#
# If the cart total is greater than (or equal to) an entered
# threshold, the associated discount is applied to the cart. The
# discount will be spread, as evenly as possible, across all items.
# ================================================================
class TieredCartDiscountBySpendCampaign
  def initialize(tiers)
    @tiers = tiers.sort_by { |tier| tier[:threshold] }.reverse
  end

  def run(cart)
    # 1. 通过 subtotal_price 判断此时购物车金额是否大于等于折扣价格
    # 2. subtotal_price 的计量单位为美分。
    applicable_tier = @tiers.find { |tier| cart.subtotal_price >= (Money.new(cents: 100) * tier[:threshold]) }
    # 如果找不到,则不对 cart 做改变
    return if applicable_tier.nil?
    # 如果找到折扣,记录此时的提示 message
    discount_applicator = DollarDiscountApplicator.new(applicable_tier[:discount_message])
    # 记录折扣额度
    discount_amount = applicable_tier[:discount_amount]
    # 根据价格排序商品
    items = cart.line_items.sort_by { |line_item| line_item.variant.price }
    # 对购物车进行改变
    self.loop_items(cart, items, discount_amount, discount_applicator)
  end

  def loop_items(cart, line_items, discount_amount, discount_applicator)
    # 根据货物数量计算每个货物应该获得的折扣
    avg_discount = (discount_amount.to_f * (1 / line_items.map(&:quantity).reduce(0, :+))).round(2)
    # 对平均折扣转换为美分
    avg_discount = Money.new(cents: 100) * avg_discount
    # 折扣转换成美分
    discount_amount = Money.new(cents: 100) * discount_amount

    line_items.each_with_index do |line_item, index|
      # 如果折扣用完了,则不再进行折扣
      break if discount_amount <= Money.zero
      # 计算每种商品的折扣,每种商品的折扣 = 平均折扣 * 商品数量
      line_discount = avg_discount * line_item.quantity
      # 如果是最后一位商品,或者总体折扣价格少于该商品予折扣价格(意思是剩余折扣已经不能 cover 计算出的折扣)
      if discount_amount < line_discount || index == (line_items.size - 1)
        # 如果剩余折扣比原本购买金额多,则使用原本金额做折扣(不能倒贴钱);如果剩余折扣少于原本金额,则使用剩余折扣。
        discount_update = line_item.line_price > discount_amount ? discount_amount : line_item.line_price
      else
        # 使用购物金额和折扣金额最低的那个做折扣(比如折扣是 10 美元,但是该商品总共就值 1 美元,不能倒贴 9 美元)
        discount_update = line_item.line_price > line_discount ? line_discount : line_item.line_price
      end
      # 计算剩余折扣金额
      discount_amount -= discount_update
      # 根据金额显示提示
      discount_applicator.apply(line_item, discount_update)
    end
  end
end

CAMPAIGNS = [
  # 折扣规则,可以多条
  TieredCartDiscountBySpendCampaign.new(SPENDING_THRESHOLDS),
]

# 每条折扣规则都要对商品进行计算
CAMPAIGNS.each do |campaign|
  campaign.run(Input.cart)
end

# 输出
Output.cart = Input.cart
  1. 按消费金额提供分级折扣
# ================================ Customizable Settings ================================
# ================================================================
# Tiered Discounts by Spend Threshold
#
# If the cart total is greater than (or equal to) an entered
# threshold, the associated discount is applied to each item.
#
# - 'threshold' is the spend amount needed to qualify
# - 'discount_type' is the type of discount to provide. Can be
# either:
# - ':percent'
# - ':dollar'
# - 'discount_amount' is the percentage/dollar discount to
# apply (per item)
# - 'discount_message' is the message to show when a discount
# is applied
# ================================================================
SPENDING_THRESHOLDS = [
  {
    threshold: 30,
    discount_type: :percent,
    discount_amount: 10,
    discount_message: 'Spend $30 and get 10% off!',
  },
  {
    threshold: 50,
    discount_type: :percent,
    discount_amount: 15,
    discount_message: 'Spend $50 and get 15% off!',
  },
  {
    threshold: 100,
    discount_type: :percent,
    discount_amount: 20,
    discount_message: 'Spend $100 and get 20% off!',
  },
]

# ================================ Script Code (do not edit) ================================
# ================================================================
# DiscountApplicator
#
# Applies the entered discount to the supplied line item.
# ================================================================
class DiscountApplicator
  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 apply(line_item)
    new_line_price = if @discount_type == :percent
      line_item.line_price * @discount_amount
    else
      [line_item.line_price - (@discount_amount * line_item.quantity), Money.zero].max
    end

    line_item.change_line_price(new_line_price, message: @discount_message)
  end
end

# ================================================================
# TieredDiscountBySpendCampaign
#
# If the cart total is greater than (or equal to) an entered
# threshold, the associated discount is applied to each item.
# ================================================================
class TieredDiscountBySpendCampaign
  def initialize(tiers)
    @tiers = tiers.sort_by { |tier| tier[:threshold] }.reverse
  end

  def run(cart)
    applicable_tier = @tiers.find { |tier| cart.subtotal_price >= (Money.new(cents: 100) * tier[:threshold]) }
    return if applicable_tier.nil?

    discount_applicator = DiscountApplicator.new(
      applicable_tier[:discount_type],
      applicable_tier[:discount_amount],
      applicable_tier[:discount_message]
    )

    cart.line_items.each do |line_item|
      next if line_item.variant.product.gift_card?
      discount_applicator.apply(line_item)
    end
  end
end

CAMPAIGNS = [
  TieredDiscountBySpendCampaign.new(SPENDING_THRESHOLDS),
]

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

Output.cart = Input.cart

测试和调试 Shopify 脚本

results matching ""

    No results matching ""