Have your say in Community Polls: What was/is your greatest motivation to start your own business?

Re: Reference Metaobject in a Metafield using Shopify API

Reference Metaobject in a Metafield using Shopify API

angellam278
Tourist
3 0 2

Hi, 

 

I'm fairly new to Shopify and I am trying to create a python script that adds products onto the page. The products will have a custom metafield with metaobjects as values. Below is the code I have right now: 

 

 

product_payload = {
            'product': {
                'title': row['Title'],
                'body_html': row['Description'],
                'product_type': 'painting',
                'variants': [{
                    'price': row['Price'],
                }],
                'metafield': {
                    'key': 'Artist',
                    'value': "test-artist",
                    'value_type': 'string',
                    'namespace': 'custom'
                }
            }
        }

        # Make the API request to create the product
        response = requests.post(admin,
                                 headers=headers,
                                 json=product_payload)

 

It says the product is successfully created, but the custom metafield value remains blank.

Any guidance will be greatly appreciated. 

Replies 4 (4)

DiogoTeix
Shopify Partner
2 0 0

I suppose you have you found a solution to your problem in the last 5 months ! I'm trying to do the same with no success so far. I tried (in Python) directly using requests as well as using ShopifyAPI but so far without success... Could you share the solution you found, please ?
Thanks a lot !

Ryan_Mc
Explorer
46 0 17

Did you figure this out? 

DiogoTeix
Shopify Partner
2 0 0

I managed to insert / update product metafields referencing a list of metaobjects using the Shopify REST Api with Python. Using the REST Api you need to separate the product creation/update with the product metafield creation/update since the endpoints are different.
The endpoint for posting a product metafield will be :
https://{shop_url}/admin/api/{api_version}/products/{product_id_shopify}/metafields.json"  
The JSON posted will be something like (I placed my variable between []):
{"metafield": {"namespace": [metafield_namespace], "key": [metafield_key], "value": [metafield_value], "type": [metafield_type] }
In my case, I have a product metafield called custom.product_stickers that contains a list of metaobjects. To insert this metafield, I will have to POST a JSON with the following JSON content :
{"metafield": {"namespace": "custom", "key": "product_stickers", "value": "["gid://shopify/Metaobject/47445606731","gid://shopify/Metaobject/47446262091","gid://shopify/Metaobject/47447540043"]", "type": "list.metaobject_reference"  }

Here is my "post to shopify" function :
the "headers" variable (is global for me) will contain your access token, something like :

headers = {"Accept": "application/json", "Content-Type": "application/json", "X-Shopify-Access-Token": access_token}
def post_shopify_json(endpoint, json_function, json_content=None):
# call the json_function from shopify
try:
time.sleep(0.5)
response_data = {}
response_data['endpoint'] = f"https://{shop_url}/admin/api/{api_version}/{endpoint}.json"
response_data['json_content'] = json.dumps(json_content)

#req = requests.Request('POST', endpoint, data=json_content, headers=headers)
#prepared = req.prepare()

response = requests.post(response_data['endpoint'], headers=headers, data=response_data['json_content'])
response_data['status_code'] = response.status_code
if response_data['status_code'] < 300:
if int(response.headers['http_x_shopify_shop_api_call_limit'].split("/")[0]) > 30:
time.sleep(2)
content_decode = response.content.decode("utf-8")
content_list = json.loads(content_decode)[json_function]
response_data['content'] = content_list
else:
response_data['error'] = f"post_shopify_json - Error : endpoint: {endpoint}; json_content: {json_content}; response status code = {response.status_code} ; " \
f"response.content : {str(response.content.decode('utf-8'))}"
write_log_txt(response_data['error'])

return response_data

except Exception as e:
response_data['status_code'] = 500
response_data['error'] = f"post_shopify_json - Error : endpoint: {endpoint}; json_content: {json_content}; response status code = {response.status_code} ; " + str(type(e)) + " - " + str(e) + " - " + str(traceback.format_exc())
return response_data
blazSirpauls
Shopify Partner
2 0 0

I recently created python script for adding metafield definitions from json file. It would be basically same for products, just change json file accordingly or hardcode it inside python script. If you need any help, let me know.

import json
import requests
import time

# Load JSON data from file
def load_json_file(file_path):
    with open(file_path, 'r') as file:
        return json.load(file)

# Function to create metafield definition
def create_metafield_definition(shopify_store, access_token, definition, retries=3, delay=2):
    url = f"https://{shopify_store}/admin/api/2024-01/graphql.json"
    headers = {
        "X-Shopify-Access-Token": access_token,
        "Content-Type": "application/json"
    }
    mutation = """
    mutation CreateMetafieldDefinition($definition: MetafieldDefinitionInput!) {
        metafieldDefinitionCreate(definition: $definition) {
            createdDefinition {
                id
                name
            }
            userErrors {
                field
                message
                code
            }
        }
    }
    """

    for attempt in range(retries):
        response = requests.post(url, headers=headers, json={'query': mutation, 'variables': {'definition': definition}})
        if response.status_code == 200:
            return response.json()
        else:
            print(f"Attempt {attempt + 1} failed, retrying in {delay} seconds...")
            time.sleep(delay)

    return None  # Or raise an exception, depending on your error handling strategy

# Main function
def main():
    shopify_store = "your-shop-url.myshopify.com"
    access_token = "private_token"
    json_data = load_json_file("collection_metafields.json")
    ownerType = "COLLECTION"

    for edge in json_data['data']['metafieldDefinitions']['edges']:
        node = edge['node']
        definition = {
            "name": node["name"],
            "namespace": node["namespace"],
            "key": node["key"],
            "description": "Your description here",  # Add appropriate description
            "type": node['type']['name'],
            "ownerType": ownerType            
        }
        response = create_metafield_definition(shopify_store, access_token, definition)
        if response:
            print(response)
        else:
            print(f"Failed to create metafield definition for namespace: {namespace}, key: {key}")

if __name__ == "__main__":
    main()