buy-button-js icon indicating copy to clipboard operation
buy-button-js copied to clipboard

Adding customAttributes to cart and lineItems

Open mahlingam opened this issue 4 years ago • 13 comments

see issue #598

  • Add custom attributes to cart via options
ui.createComponent('cart', {
    options: { 
        cart: {
            customAttributes: [
                { key: 'key1', value: 'value1' },
                { key: 'key2', value: 'value2' }
            ],
        }
  • Add custom attributes to line item via template
<div  data-lineitem-attributes='[ { "key": "_someHiddenKey", "value": "someHiddenValue"}, { "key": "someKey", "value": "someValue"} ]' data-product-id="@productGId" data-variant-id="@variantId" >
   ....
</div>
ui.createComponent('product', {
    id: $(this).data('productId'),
    variantId: $(this).data('variantId'),
    node: this,
    customAttributes: $(this).data('lineitemAttributes'), 
...

mahlingam avatar Dec 12 '20 15:12 mahlingam

@mahlingam would you be able to compile the js file with this change and make it public somewhere? I'm very interested, unfortunately this repo doesn't seem to compile under macOS 11.

gmalette avatar Apr 28 '21 20:04 gmalette

I managed to compile it by shedding some dependencies and using -std=c++17 🙂

gmalette avatar May 03 '21 18:05 gmalette

@gmalette hey, long time :) any chance you have a fork with a compilable version?

jnormore avatar May 17 '21 14:05 jnormore

@jnormore JASON! LONG TIME! Sorry I hadn't seen your message, wasn't checking notifications. I do have one, and though I imagine it's some months too late, here it is https://github.com/gmalette/buy-button-js/tree/line-item-properties

gmalette avatar Jul 26 '21 00:07 gmalette

any idea why it hasn't been merged yet?

AleksMeshkov avatar Oct 20 '21 20:10 AleksMeshkov

Can we get this merged please?

lopugit avatar May 01 '22 23:05 lopugit

Sorry to ask but where does $(this).data('lineitemAttributes') come from?

lopugit avatar May 02 '22 00:05 lopugit

Sorry to ask but where does $(this).data('lineitemAttributes') come from?

same as productId and variantId, it is the value of the data-line-item-attributes attribute, the name is mangled according to https://html.spec.whatwg.org/multipage/dom.html#dom-dataset and https://api.jquery.com/data/

mahlingam avatar Jul 11 '22 07:07 mahlingam

Could I possible have some help with this? I'm assuming this still isn't possible with the master version?

I've currently added "customAttributes: [ { "key": "_someHiddenKey", "value": "someHiddenValue"}, { "key": "someKey", "value": "someValue"} ]" directly to ui.createComponent('product' just to get some custom attributes coming through on the order. Nothing yet, though.

Also, after building with yarn, I wrapped the script in the ShopifyBuy function, so it works in the same way as the original Shopify buy button, rather than as a module. Is there any reason to not do this? It seems to work fine (other than the custom attributes).

Any help on configuring this correctly would be much appreciated :)

Tom

tomathyg avatar Oct 01 '22 19:10 tomathyg

I started afresh and this is now working fine with some dummy data added directly to customAttributes in ui.createComponent.

My only question now is how to pass a custom attribute from an input, either on the product or product modal, to the line item when added to cart? Would you mind pointing me in the right direction, here?

tomathyg avatar Oct 02 '22 14:10 tomathyg

I started afresh and this is now working fine with some dummy data added directly to customAttributes in ui.createComponent.

My only question now is how to pass a custom attribute from an input, either on the product or product modal, to the line item when added to cart? Would you mind pointing me in the right direction, here?

Glad you got it working. I use the buy button integrated into a custom frontend: Buy Button of the product template:

<div  class="buy-button__action" data-product-id="@productGroup.shopifyId" data-variant-id="@product.shopifyId" 
        data-lineitem-attributes='[ { "key": "_someHiddenKey", "value": "someHiddenValue"}, { "key": "someKey", "value": "someValue"} ]'
</div>

and a script fragment embeded in the product template:

(function (global, $) {
    'use strict';

    function ShopifyBuyInit() {
        var client = global.ShopifyBuy.buildClient({
            domain: global.settings.shopify.domain,
            storefrontAccessToken: global.settings.shopify.storefrontAccessToken
        });
        var ui = global.ShopifyBuy.UI.init(client);
        var shopifyOptions = {
           ....
        };
        if ($('.buy-button__action').length === 0) {
            ui.createComponent('cart', {
                options: shopifyOptions,
                moneyFormat: '%E2%82%AC%7B%7Bamount_with_comma_separator%7D%7D',
                debug: false
            });
        }
        $.each($('.buy-button__action'), function() {
                shopifyOptions.product.text = { 'button' : $(this).data('buttonText') };
                ui.createComponent('product', {
                    id: $(this).data('productId'),
                    variantId: $(this).data('variantId'),
                    node: this,
                    customAttributes: $(this).data('lineitemAttributes'),
                    moneyFormat: '%E2%82%AC%7B%7Bamount_with_comma_separator%7D%7D',
                    options: shopifyOptions,
                    debug: false
                });
            }
        );
    }
    
    function loadScript() {
        var script = document.createElement('script');
        script.async = true;
        script.src = scriptURL;
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(script);
        script.onload = ShopifyBuyInit;
    }

    if (global.settings.shopify.enabled) {
        var scriptURL = global.settings.assets.url + 'js/libs/buybutton-2.1.7.min.js';
        if (global.ShopifyBuy) {
            if (global.ShopifyBuy.UI) {
                new ShopifyBuyInit();
            } else {
                loadScript();
            }
        } else {
            loadScript();
        }
    }
})(window, window.jQuery);

mahlingam avatar Nov 26 '22 13:11 mahlingam

events: { afterInit: (cart) => { cart.onCheckout = () => { // we dynamically change the checkout function. const firstName = storefront?.account?.name?.split(" ")?.[0] ?? ""; const lastName = storefront?.account?.name?.split(" ")?.[1] ?? ""; const prefill = checkout[shipping_address][first_name]=${firstName}&checkout[shipping_address][last_name]=${lastName}&checkout[email]=${storefront.email}&checkout[shipping_address][address1]=${storefront.account?.address1}&checkout[shipping_address][city]=${storefront.account?.city}&checkout[shipping_address][zip]=${storefront.account?.postcode}&checkout[shipping_address][country]=${storefront.account?.country}&checkout[shipping_address][province]=${storefront.account?.province_code}; const params = attributes[username]=${storefront.username}&attributes[platform]=viaGlamour&attributes[plan]=${features.plan};

        const variables = cart.model.lineItems
          .map((el) => {
            if (el?.variant?.id) {
              return `${el?.variant?.id?.replace(/\D/g, "")}:${el.quantity}`;
            }
          })
          .join(",");

        const url = `https://viaglamourca.myshopify.com/cart/${variables}?channel=buy_button&${params}&${prefill}`;

        cart.checkout.open(url);
        identify(storefront.email, storefront);
        track("InitiateCheckout", { event_id: url, attributes: prefill });
      };
    },
  }

keiraarts avatar Jul 31 '23 20:07 keiraarts

thank you @mahlingam I was looking to do the same thing, and your PR was very helpful. For others looking for this, I have forked and compiled a library with support for custom attributes so others can learn how to do this. https://github.com/Innovation-Magic-LLC/buy-button-js-customattributes

TaylorTheDeveloper avatar May 04 '24 16:05 TaylorTheDeveloper