29.2.2024

Rozszerz możliwości swojego sklepu i twórz zaawansowane kampanie sprzedażowe w Shopify

‍Jeśli korzystasz z platformy Shopify, możesz w prosty sposób tworzyć promocje w swoim sklepie internetowym przy użyciu dostępnych narzędzi. Jeśli jednak chcesz postawić na bardziej zaawansowane kampanie sprzedażowe, z pomocą przyjdzie edytor skryptów. Jak wykorzystać jego potencjał? Sprawdźmy!

Domyślnie Shopify daje administratorom relatywnie proste narzędzia do tworzenia promocji. Możesz skonfigurować kupon rabatowy (discount code) lub automatyczną promocję, która obniża cenę o jakiś procent lub stałą kwotę, dać możliwość skorzystania z innej opcji dostawy (np. darmowej) czy stworzyć promocję Buy X Get Y. Jeżeli kupon rabatowy to za mało na Twoją następną promocję, możesz spróbować wykorzystać potencjał edytora skryptów w planie Shopify Plus.

Przykładowa promocja oparta o discount code

Jakie możliwości oferuje Script Editor Shopify?

Opcje nie są nieograniczone, ale otwierają drzwi na wiele perspektyw. Przykłady:

Promocje

  • Łącz zniżki z promocyjnymi opcjami dostawy (10% zniżki + darmowa dostawa)
  • Przydziel X% zniżki na produkty objęte subskrypcją
  • Twórz różne poziomy zniżek (10% od kwoty X oraz 20% od kwoty Y)
  • Konfiguruj zestawy produktów - jeżeli w koszyku są dwie sztuki produktu X, jedna Y oraz Z, to obniż cenę do 50.00 zamiast 84.32, przydzielając zniżkę proporcjonalnie między produktami w zestawie
  • Dla kodu rabatowego PROMO10 przydziel 10% zniżki ale tylko na pierwsze 5 sztuk
  • ... i wiele innych! Tworząc bardziej zaawansowaną logikę możesz planować całe programy jak program premium dla grupy klientów spełniającej specjalne kryteria.

Zabezpieczenie sklepu

  • Jeżeli waga produktów w koszyku przekracza 10kg, wyłącz standardowe opcje dostawy
  • Jeżeli kwota do zapłaty wynosi 0.00 to usuń wszystkie przedmioty w koszyku, aby przeciwdziałać darmowym zamówieniom
  • Ogranicz ilość sztuk danego produktu w zamówieniu, aby zabezpieczyć przed wykupieniem całego asortymentu przez jedną osobę
  • Wyłącz bramkę płatności dla produktu Y
  • Zmień nazwę shippingów

Rozszerzenie UI

  • Wyświetl banner jeżeli w koszyku znajduje się produkt X oraz Y
  • Wyświetlaj dodatkowe informacje na temat promocji w koszyku jeżeli warunki promocji zostały spełnione
  • Ogranicz możliwość wybrania produktu w ilości większej niż X
Promocja oparta o Shopify Scripts API 

Co będzie potrzebne?

Mniej radosną informacją jest konieczność znajomości Script Editor API oraz znajomość języka Ruby, który jest w skryptach wykorzystywany. Edytor też nie jest dostępny dla planów innych niż Plus.

Jak ograniczyć ilość produktów za pomocą Shopify Scripts? 

Analiza rozwiązania

Przystępując do pisania kodu musimy przyjąć sobie kryteria akceptacyjne i nakreślić dlaczego to robimy. Kryteria akceptacyjne wskażą nam oczekiwany efekt końcowy, natomiast opis potrzeby potwierdzi nam, że kryteria są kompletne. Przykład:

Chcielibyśmy utworzyć kampanię, która będzie powodowała, że automatycznie dodany produkt po stronie użytkownika będzie miał limit równy 1. Ten produkt będzie free giftem dołączonym do jakiegokolwiek zakupionego produktu. Jako właściciele sklepu nie chcemy, aby użytkownik przypadkiem miał w koszyku więcej niż 1 free gift na wskutek błędu skryptu dodającego upominek.

Podsumowując:

  • jeżeli w koszyku znajduje się produkt otagowany w panelu administracyjnym jako freegift, to limit ilości dla danego zamówienia powinien być równy 1

Znając kontekst kampanii, możemy dodać jeszcze jedną regułę:

  • jeżeli suma cen wszystkich produktów w koszyku wynosi 0zł, a w koszyku znajduje się produkt z tagiem freegift, to jego liczba również powinna wynosić 0

To zabezpieczy nas przed sytuacją, w któ®rejużytkownik jest w stanie złożyć zamówienie na sam upominek. Pamiętajmy, że błędy przy pracy z edytorem skryptów mogą być kosztowne.

Piszemy kod!

W tym artykule napiszemy maksymalnie prosty kod, którym będziemy mogli zarządzać w łatwy sposób później. Stworzymy absolutne minimum - bardziej skalowalne rozwiązania wymagałyby więcej czasu.

Słowniczek:

line item - pojedyncza pozycja w koszyku - nie produkt. Różnica polega na tym, że w koszyku może być kilka pozycji z tym samym produktem, ale różnymi właściwościami np. cena

kampania - funkcja spełniająca ustalone kryteria. Promocja może składać się z wielu kampanii

Zacznijmy od deklaracji obiektu Hash, opisującego kampanie uruchamiane przez skrypt:


QUANTITY_LIMIT = {  
  campaigns: [    
    {      
      enable?: true,      
      product_selector_match_type: :includes,      
      product_tags: ["freegift", "freepromo"],      
      quantity_limit: 1    
    } 
  ]
}

Hash QUANTITY_LIMIT kategoryzuje nam kampanie na te związane z ograniczeniem ilości. Później mamy deklarację poszczególnych kampanii. Na ich właściwości składa się:

  • enable?: czy w danym momencie chcemy, aby kampania była uruchomiona (true/false)
  • product_selector_match_type: tutaj definiujemy rodzaj warunku: jeżeli jest :includes, to produkt musi posiadać jeden z niżej wymienionych tagów, jeżeli inny, to nie może posiadać żadnego z wymienionych
  • product_tags: tablica dopuszczalnych (lub nie) tagów
  • quantity_limit: maksymalna liczebność produktów spełniających powyższe kryteria

Następnie potrzebujemy selektora - jest to klasa, która będzie wskazywała programowi, na które line item-y będzie miał wpływ. Selektor zwraca line itemy z koszyka spełniające jego kryteria:


class ProductSelector
  def initialize(match_type, selectors)
    @match_type = match_type
    @comparator = match_type == :includes ? 'any?' : 'none?'
    @selectors = selectors
  end

  def match?(line_item)
    self.send(:tag, line_item)
  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

end

Klasa obsługująca kampanię:


class QuantityLimitCampaign 
  def initialize(enable, campaign)    
    @enable = enable    
    @campaign = campaign  
  end
  
  def run(cart)    
    return unless @enable   
    product_selector = ProductSelector.new(
      @campaign[:product_selector_match_type],
      @campaign[:product_tags]
    )
    
    # applicable_items jest tablicą zawierającą line itemy spełniające warunek tagów oraz rodzaju selektora
    applicable_items = cart.line_items.select { |line_item| product_selector.match?(line_item) }
    
    # zakończ działanie skryptu, jeżeli nie znaleziono żadnego produktu spełniającego kryteria
    return if applicable_items.nil?
    total_quantity = applicable_items.map(&:quantity).reduce(0, :+)
    
    # jeżeli ograniczenie jest większe niż suma liczebności
    # wszystkich produktów spełniających kryterium, to
    # kończymy działanie skryptu
    return unless total_quantity > @campaign[:quantity_limit]  
    
    # w innym przypadku ustalamy ile sztuk jest do usunięcia
    num_to_remove = total_quantity - @campaign[:quantity_limit]
    
    # usuwamy produkty z koszyka
    self.loop_items(cart, applicable_items, num_to_remove)
  end 
  
  def loop_items(cart, line_items, num_to_remove)    
    line_items.each do |line_item| 
      if line_item.quantity > num_to_remove
        # .split({ take: Integer }) dzieli pozycję pojedynczą na dwie pozycje.
        # take określa jaką ilość należy usunąć z oryginalnej pozycji pojedynczej
        # aby utworzyć nową pozycję. Ostatecznie zwracamy nową pozycję.
        split_line_item = line_item.split(take: num_to_remove)
        break 
      else
        # Usuwamy line_item całkowicie jeżeli limit jest większy
        index = cart.line_items.find_index(line_item)
        cart.line_items.delete_at(index)
        num_to_remove -= line_item.quantity
      end
      
      break if num_to_remove <= 0
    end
  end
end

Wykorzystanie:


# Definiujemy pustą tablicę kampanii
CAMPAIGNS = []

# Iterując po hashu QUANTITY_LIMIT dynamicznie tworzymy kampanie
QUANTITY_LIMIT[:campaigns].each do |limit|
  CAMPAIGNS[CAMPAIGNS.size] = QuantityLimitCampaign.new(limit[:enable?], limit)
end

# Uruchamiamy kampanie modyfikując początkowy stan koszyka
CAMPAIGNS.each do |campaign|
  campaign.run(Input.cart)
end

# Przypisanie nowego stanu do wyjścia
Output.cart = Input.cart

Powyższy kod zaspokoi pierwsze kryterium. Musimy jeszcze zabezpieczyć się przed zamawianiem samych upominków. Potrzebne będą dodatkowe modyfikacje. Zacznijmy od klasy sprawdzającej finalną cenę w koszyku:


class CartTotalPriceCondition
  def initialize(match_type, amount)
    @match_type = match_type
    @amount = Money.new(cents: amount * 100)
  end

  def match?(cart)
    compare_to = cart.subtotal_price
    compare(@match_type, @amount, compare_to)
  end

  def compare(type, val1, val2)
    case type
      when :greater_than
        return val1 > val2
      when :greater_than_or_equal
        return val1 >= val2
      when :less_than
        return val1 < val2
      when :less_than_or_equal
        return val1 <= val2
      when :equal_to
        return val1 == val2
      else
        raise "Invalid comparison type"
    end
  end
end

Dodajmy CartTotalPriceCondition do klasy obsługującej naszą kampanię w metodzie run() między linijkami istniejącego już kodu:


...
  def run(cart)
    return unless @enable

    if @campaign.key?(:cart_subtotal)
      cart_condition = CartTotalPriceCondition.new(:equal_to, @campaign[:cart_subtotal])
      return unless cart_condition.match?(cart)
    end‍
    
    product_selector = ProductSelector.new(
      @campaign[:product_selector_match_type],
      @campaign[:product_tags]
    )
...

Testujemy rozwiązanie 🎉

Script Editor umożliwia nam szybką weryfikację bez wchodzenia na front sklepu. Po lewej możesz zobaczyć jak wyglądał koszyk, który użytkownik próbował utworzyć, a po prawej koszyk, który otrzymaliśmy po tym, jak skrypt się wykonał:

W przypadku, w którym użytkownik znalazł sposób, jak dodać sam upominek do koszyka, koszyk się wyzerował, co stanowi doskonałe zabezpieczenie naszej promocji:

Ograniczenia oraz na co należy uważać

To rozwiązanie ma sporo zalet, jednak powiedzenie "Z wielką mocą wiąże się wielka odpowiedzialność!" znajduje tu jak najbardziej miejsce. Funkcjonalność ta jest dość skomplikowana i asysta doświadczonego dewelopera może być nieunikniona.

Aplikacja nie ma w swoim interfejsie wizualnej reprezentacji logiki kampanii. Do dyspozycji mamy tak naprawdę tylko edytor kodu. To oznacza, że jest to miejsce jak najbardziej podatne na bugi. Szczególnie przy pracy z ceną produktu należy uważać - może się zdarzyć, że o naszym błędzie dowiemy się z mediów społecznościowych, a kolejne dni będziemy tłumaczyli się przed klientami z odrzuconych zamówień.

Możliwości też nie są nieograniczone:

  • nie mamy dostępu do obiektu Time, który pozwalałby nam tworzyć kampanie oparte na czasie*
  • Shopify nie ma dobrych rozwiązań do przeciwdziałania zjawisku multi kont i nie inaczej jest w przypadku SE
  • ilość zasobów (CPU i pamięć) na dany skrypt jest ograniczona
  • nie możemy zwiększać ceny produktów oraz dodawać produkty do koszyka z poziomu edytora
  • wiele innych - lista może być w tym miejscu długa, jeżeli wejdziemy w szczegóły

* - podobne ograniczenia można próbować obejść integrując się z customowymi usługami backendowymi. Nie jest to jednak kierunek bez wad - dodatkowe koszty utrzymania, ryzyko awarii, wydajność promocji itd.

Podsumowanie

Script Editor jest bardzo ciekawym, dającym dużo możliwości rozwiązaniem jednak nie jest on przeznaczony dla wszystkich. Z naszego doświadczenia wynika, że sklepom udaje się przyciągnąć duże grupy klientów, wspomagając się promocjami opartymi o edytora skryptów. Z drugiej strony jest to też funkcja skierowana do osób, które rozumieją jej wady i ograniczenia. Projekty oparte o wykorzystanie edytora wymagają więcej analizy oraz testowania, a zatem czasu. Zachęcam do poznania tego narzędzia - jest ono szansą na uzyskanie przewagi nad konkurencją oraz przykucia uwagi klientów.

Więcej interesujących treści o podobnej tematyce znajdziecie na: https://wiktorwisniewski.dev

Wiktor Wiśniewski

Senior Headless Developer w WeCanFly

Zacznijmy od rozmowy

Idealnym pierwszym krokiem będzie krótka rozmowa, w trakcie której opowiesz nam przed jakim wyzwaniem stoisz.

WYŚLIJ ZAPYTANIE

Być może zainteresuje Cię również

Jeśli chcesz dostosować Shopify do swoich potrzeb, dodając kolejne funkcjonalności lub personalizując szablon, to nie obejdzie się bez pracy nad Shopify Developmentem. Jaki jest zakres prac Shopify Developera i jak pracują agencje Shopify? Zapraszamy do czytania.

Sklepy internetowe prześcigają się we wprowadzeniu rozwiązań, które nie tylko wpłyną na komfort zakupów dla użytkownika, ale także wpłyną pozytywnie na sprzedaż. Jednym z nich są spersonalizowane rekomendacje produktów. Zaprosiliśmy Recostream do napisania artykułu o swoim produkcie - systemie rekomendacji produktów. Zobaczmy, jak prawidłowo wdrożyć takie narzędzie.