Have your say in Community Polls: What was/is your greatest motivation to start your own business?
Our Partner & Developer boards on the community are moving to a brand new home: the .dev community forums! While you can still access past discussions here, for all your future app and storefront building questions, head over to the new forums.

Use theme buy button in my app block

Use theme buy button in my app block

Infalodon
Shopify Partner
5 0 0

Hi everyone,

I've developed a new app feature that allows customers to add multiple variants to their shopping cart with just one click.

This is quite simple to implement (see the code snippet below for a simplified example).

However, there's a problem with this code: some merchants have theme-specific callbacks on their submit buttons. Some redirects to the cart page, while others open a cart drawer.

In most themes, there are 'buy buttons' blocks included. I'm wondering if it's possible for merchants to use these blocks with my app feature without having to edit their theme code. Unfortunately, in the themes I've looked at, the section and product form ID information isn't passed to app blocks, so I haven't found a way to avoid having to create custom 'Add to Cart' buttons.

 

Is there any solution? Or the best I can do is allow user to add custom javascript?

 

 

<form action='/cart/add'>

   <input name="items[0]id" value="id123"/>

   <input name="items[0]quantity" value="2"/>

   <input name="items[1]id" value="id456"/>

   <input name="items[1]quantity" value="4"/>

   <button type="submit"/>

</form>

 

 

Replies 3 (3)

Liam
Community Manager
3108 344 894

Hi Infalodon,

 

This is a tricky issue as you found, there's no way to completely ensure that the buy button will trigger a cart drawer or redirect to cart/ checkout. Theme developers could use different techniques to control this, and merchants could change their theme settings that would affect what call-back function is used - so there's no "one-size-fits-all" approach possible here. What you could do is to create offer settings within your app's configuration to allow merchants to specify the IDs of their theme's form elements or any other relevant selectors. This way, your app could dynamically adjust to work with the merchant's specific theme setup? Is this an app that will be on the Shopify App Store?

Liam | Developer Advocate @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

Infalodon
Shopify Partner
5 0 0

Thank your for your answer

Indeed, ask to merchant for form id would be a good solution, hoping it's not a dynamic one. I would try it out!

 

This is a shopify app that's already available on the Shopify App Qtore yes!

Infalodon
Shopify Partner
5 0 0

Best solution I've found is the following one:
1. I allow merchants to configure a form selector. By default I use 

'form:has([name="id"]):has(button[type="submit"])'

2. Then, I disabled the `name='id'` input and inject variants into the product form

export interface ShopifyCartItem {
  id: string;
  quantity: number;
  properties?: { [key: string]: string };
}

  /**
   * Updates the product form with the given items.
   * @Anonymous items - An array of ShopifyCartItem objects representing the items to update the form with.
   */
  public updateProductForm(items: ShopifyCartItem[]) {
    // Remove all previously injected elements and add the new ones
    this.form.querySelectorAll(`input.planet-dataset`).forEach((el) => {
      this.form.removeChild(el);
    });
    const inputId = this.form.querySelector(
      `input[name=id]`
    ) as HTMLInputElement;
    if (inputId) {
      inputId.setAttribute("disabled", "true");
    }

    items.forEach(({ id, quantity }, index) => {
      const existingIdInput = this.form.querySelector(
        `input[name="items[${index}]id"]`
      );
      const idInput = existingIdInput || document.createElement("input");
      idInput.setAttribute("type", "hidden");
      idInput.setAttribute(`name`, `items[${index}]id`);
      idInput.setAttribute(`value`, id.toString());
      idInput.setAttribute("class", "planet-dataset");
      if (!existingIdInput) {
        this.form.appendChild(idInput);
      }

      const existingQtyInput = this.form.querySelector(
        `input[name="items[${index}]quantity"]`
      );
      const qtyInput = existingQtyInput || document.createElement("input");
      qtyInput.setAttribute("type", "hidden");
      qtyInput.setAttribute(`name`, `items[${index}]quantity`);
      qtyInput.setAttribute(`value`, quantity.toString());
      qtyInput.setAttribute("class", "planet-dataset");
      if (!existingQtyInput) {
        this.form.appendChild(qtyInput);
      }
    });
  }

 3.  Then, I manually click on the button using javascript.

Until now it has been working with a lot of themes with two known exceptions:

1. it doesn't work with the 'Pop up' cart of dawn themes because it expects a response from `/cart/add` with a payload of 'id' and quantity', not an array of items, so it breaks.

2. Some themes work by getting info of quantity and variant selector of the theme, no amtter what's in the form.

For now, the only workaround I've found is set a weird form selector so it's not found, and then I catch the 'FormNotFound' error and do as I was doing before: redirect to the cart after using the AJAX API.