Home > Blockchain >  Shopify get meta field value of product using JS/jQuery
Shopify get meta field value of product using JS/jQuery

Time:03-03

I've been exploring and testing for hours how to retrieve the metafield values from a specific product handle.

I've tested using AJAX calls and using getJSON neither of which have had any success with all seem to throw the same error.

I'm aware that you most definitely can't access the product metafields directly as they're somewhat protected and therefore are excluded from the usual handle.js file I'm currently successfully able to get.

I am seeking someones help to essentially point me in the direction of how to accomplish what I'm looking for.

product-view.js file

$(document).ready(function () {
    $.getScript("//cdnjs.cloudflare.com/ajax/libs/fancybox/2.1.5/jquery.fancybox.min.js").done(function() {
        createProductData();
    });
});

function createProductData() {
    $(".product-view").click(function () {
        if ($('#product-view').length == 0){
            $("body").append('<div id="product-view"></div>');
        }

        var product_handle = $(this).data('handle');

        $('#product-view').addClass(product_handle);

        //Default Product Fields
        jQuery.getJSON('/products/'   product_handle   '.js', function (product) {
            var images = product.images;
            var title = product.title;
            var price = product.price;
            var desc = product.description;
        });

        //Product Meta Fields
        jQuery.getJSON('/products/'   product_handle   '?view=metafields.json', function (product) {
            var dish_type = product.metafields.arena.dish;
            console.log(dish_type);
            //error: Cannot read properties of undefined (reading 'arena')
        });
    });
}

product.metafields.liquid file

{% layout none %}
{{ product.metafields.arena | json }}

CodePudding user response:

So I managed to find a website finally that used what they described as a 'hack' because they don't believe this is the way that {% capture %} however, it did achieve the require outcome that I needed and hopefully is useful for others in future:

theme.liquid file

{% capture 'dishMetaFields' %}
    {
        {% for product in collections["all-dishes"].products %}

            "{{ product.handle }}" : {
                product_chinese_title : "{{product.metafields.arena.chinese_title}}",
                product_feeds : "{{product.metafields.arena.feeds}}",
                product_spice_level : "{{product.metafields.arena.spice}}",
                product_dish : "{{product.metafields.arena.dish}}",
                product_proteins : "{{product.metafields.arena._proteins}}",
                product_diet : "{{product.metafields.arena._diet}}",
                product_cooking_time : "{{product.metafields.arena._diet}}",
                product_cooking_video : "{{product.metafields.arena._method_video}}",
                product_cooking_text : "{{product.metafields.arena._method}}",
                product_nutrients : "{{product.metafields.arena._nutrition}}",
                product_allergies : "{{product.metafields.arena._allergies}}",
                {% unless product.metafields.arena._bundle_dishes == blank %}
                    {%- assign dishCounter = 1 -%}
                    product_bundle_dish : {
                        {% for value in product.metafields.arena._bundle_dishes %}
                            "dish-{{ dishCounter }}" : "{{ value }}",
                            {%- assign dishCounter = dishCounter | plus:1 -%}
                        {% endfor %}
                    }
                {% endunless %}
            },
        
        {% endfor %}
    }
{% endcapture %}

<script type = "text/javascript">
  let dishMetaFields = {{ dishMetaFields }}
</script>

You can then access the dishMetaFields from the javascript file you're using to access the product object to get the defined metafields should the handles match.

product-view.js

$(document).ready(function () {
    $.getScript("//cdnjs.cloudflare.com/ajax/libs/fancybox/2.1.5/jquery.fancybox.min.js").done(function() {
        createProductData();
    });
});

function createProductData() {
    $(".product-view").click(function () {
        if ($('#product-view').length == 0){
            $("body").append('<div id="product-view"></div>');
        }

        var product_handle = $(this).data('handle');

        $('#product-view').addClass(product_handle);

        jQuery.getJSON('/products/'   product_handle   '.js', function (product) {
            //Default Product Fields
            var images = product.images;
            var title = product.title;
            var price = product.price;
            var desc = product.description;

            //Product Meta Fields
            var metafields = dishMetaFields[product_handle];
            var dish_type = metafields.product_dish;
        });
    });
}

CodePudding user response:

You can also do it like this following your initial approach. In this scenario, you don't need to iterate over all metafields of a collection but only for the required product. This should be better comparatively in terms of performance. The idea is same, that you generate the JSON object in Liquid snippet and then parse the JSON in JavaScript.

{% layout none %}
{
    "product_chinese_title" : "{{product.metafields.arena.chinese_title}}",
    "product_feeds" : "{{product.metafields.arena.feeds}}",
    "product_spice_level" : "{{product.metafields.arena.spice}}",
    "product_dish" : "{{product.metafields.arena.dish}}",
    "product_proteins" : "{{product.metafields.arena._proteins}}",
    "product_diet" : "{{product.metafields.arena._diet}}",
    "product_cooking_time" : "{{product.metafields.arena._diet}}",
    "product_cooking_video" : "{{product.metafields.arena._method_video}}",
    "product_cooking_text" : "{{product.metafields.arena._method}}",
    "product_nutrients" : "{{product.metafields.arena._nutrition}}",
    "product_allergies" : "{{product.metafields.arena._allergies}}"
    {% unless product.metafields.arena._bundle_dishes == blank %}
        ,
        {%- assign dishCounter = 1 -%}
        "product_bundle_dish" : {
            {% for value in product.metafields.arena._bundle_dishes %}
                "dish-{{ dishCounter }}" : "{{ value }}"
                 {% if forloop.last == false %}
                    ,
                 {% endif %}
                 {%- assign dishCounter = dishCounter | plus:1 -%}
            {% endfor %}
                    }
    {% endunless %}
}

And for JavaScript part, use simple GET and then parse the response.

jQuery.get('/products/'   product_handle   '?view=metafield', function (product) {
  console.log(product)
  console.log(JSON.parse(product))         
});
  • Related