How to manage product variants with GraphQL API when productCreate mutation create default variant

How to manage product variants with GraphQL API when productCreate mutation create default variant

skorp
Shopify Partner
3 0 3

I am developing a system using the latest shopify version 2024-04 to automate product and variant creation using Shopify's GraphQL API. My workflow involves using the productCreate mutation followed by productVariantsBulkCreate. However, I'm encountering challenges with handling the default variant created by productCreate.

 

Workflow Details:

Product Creation: I use the productCreate mutation which takes productOptions and automatically creates a default variant with these options (e.g., color:green). This default variant lacks other critical details like SKU, price, and inventory quantities. Adding More Variants: When I try to use productVariantsBulkCreate to add more variants, I encounter an error because the default variant with the first option already exists. Updating the Default Variant: I attempted to update this default variant using productVariantUpdate to add SKU and price successfully. However, adding images (using mediaSrc) and updating inventory quantities isn't supported by this mutation.

 

Problems Encountered:

Updating Images and Quantities: productVariantUpdate doesn’t support adding images or specifying inventory quantities, as these are only supported in the productVariantCreate mutation.

Deleting the Default Variant: Attempting to delete the default variant with productVariantDelete seems to remove the associated options too, leading to errors when trying to recreate variants.

 

Questions:

How can I efficiently manage the default variant created by productCreate to include all necessary details like images, inventory quantities, etc.? Is there a recommended approach to modify or delete the default variant without affecting the ability to add new variants with the same options?

Thank you

Replies 9 (9)

FrancoTampieri
Shopify Partner
9 0 1

That's interesting, Coming from the old REST API I used this query founded in this post and it works, I think u can put images adding the "images" connection taking as example as the user used to add that.

 

For the inventory, with the REST API I wasn't able to add the quantity in one query, because you have to use the InventoryLevel entity.

For the optimization side, it depends on many factor, like:

  • The shopify profile (business, plus, enterprise) because u need to look at the rate limits
  • Using the batch GraphQL I don't know if is executed immediately or deferred
  • How much u quick u need that synchronization will be quick executed?

Kind regards

 

Franco

hocinehamdi
Shopify Partner
3 0 3

I have the same problem, still didn't find any solution on how optimize this, please any one from shopify can help here?

adeolamorren
Shopify Partner
3 0 4

Hi @skorp @hocinehamdi  I ran into the same problem and ultimately this is the solution:

1 You need to start of by utilizing the productSet mutation https://shopify.dev/docs/api/admin-graphql/2024-04/mutations/productSet

Here you can add all the product options and all the variants (without images)

 

2. Make sure to return the product Variant ID's, I currently use the product query itself do this but Im sure you can return it from the original mutation (I'm not a GraphQL expert so I'm sure there are more efficient ways)

 

3. Then you can use the productVariantsBulkUpdate mutation to upload images to the variant

 

That mutation has the media input as a input parameter, where you will supply the image urls.

 

Then it also has the variants input parameter, which has the mediaSrc parameter for every variant. You have to make sure you supply the image url, that you also have inside of the media input array. The API will then match the media, and you should be good to go.

 

If you are importing products from an external shopify account and if you are wondering how you can make sure to attach the correct image to the correct variant as you clone the products, I would recommend creating a map that keeps track for each product set of variants, the variant position, and the variant image that belongs to the variant with that position.

This way you can also supply that same position in the productSet mutation. Then make sure to return the position as well of the newly created variants.

Now you have the position as the thing that can be a link between the newly created variants and the ones which you were using as the source.

Then inside of the variantBulkUpdate mutation you can use that information to attach the correct mediaSrc link.

 

 

I didn't address the inventory aspect, but you can include that in the productVariantsBulkUpdate mutation where you are setting the images

 

I hope this helps!

FrancoTampieri
Shopify Partner
9 0 1

Hi do u have some example using productSet? because I face off with that problem when I try the example on the admin doc:
message': "Field 'productSet' doesn't exist on type 'Mutation'"

and this is with all the samples that I find in the admin doc for productSet mutation.

 

Thanks

adeolamorren
Shopify Partner
3 0 4

Yep here it is:

 

import Shopify from "shopify-api-node";

const shopify = new Shopify({
  shopName: "",
  accessToken: "",
  apiVersion: "2024-04",
});
try {
  const query = `mutation createProductAsynchronous($productSet: ProductSetInput!, $synchronous: Boolean!) {
  productSet(synchronous: $synchronous, input: $productSet) {
    product {
      id
    }
    productSetOperation {
      id
      status
      userErrors {
        code
        field
        message
      }
    }
    userErrors {
      code
      field
      message
    }
  }
}`;

  const input = {
    synchronous: true,
    productSet: {
      title: "",
      descriptionHtml: "",
      handle: "",
      vendor: "",
      collections: [""],
      productOptions: product.options.map((option) => {
        return {
          name: option.name,
          position: option.position,
          values: option.values.map((value) => {
            return {
              name: value,
            };
          }),
        };
      }),
      variants: product.variants.map((variant) => ({
        barcode: variant.barcode,
        compareAtPrice: variant.compare_at_price,
        optionValues: [
          {
            name: value,
            optionName: productOption?.name,
          },
        ],
        position: variant.position,
        price: variant.price,
        sku: variant.sku,

        taxable: variant.taxable,
      })),
      status: "ACTIVE",
      tags: product.tags,
    },
  };

  const response = await shopify.graphql(query, input);

  if (!response.productSet || response.productSet.userErrors.length > 0) {
    throw new Error(
      "Error creating product: " + response.productSet.userErrors.toString()
    );
  }

  return { id: response.productSet.product.id };
} catch (err) {
  console.error("Error creating product: ");
  console.error(err);
  throw new Error("Error creating product: " + err.toString());
}

 

FrancoTampieri
Shopify Partner
9 0 1

Great! damn in the official documentation there are a ProductPreferencesInput that generate everytime a Typo error... 

 

But your mutation WORKS!!! That's great 🙂

hocinehamdi
Shopify Partner
3 0 3

Check below what I tried and it works but I think your solution is more elegant.

 

mutation createProduct($input: ProductInput!, $media: [CreateMediaInput!]){
  productCreate(input: $input, media: $media) {
    product {
      id
      hasOnlyDefaultVariant
      options {
        name
      }
      variants {
        edges {
          node {
            id
          }
        }
      }
    }
    userErrors {
      field
      message
    }
  }
}

 

1) Create the product and return the default variant id

mutation createProduct($input: ProductInput!, $media: [CreateMediaInput!]){
  productCreate(input: $input, media: $media) {
    product {
      id
      hasOnlyDefaultVariant
      options {
        name
      }
      variants(first: 10) {
        edges {
          node {
            id
            title
            sku
            inventoryQuantity
          }
        }
      }
    }
    userErrors {
      field
      message
    }
  }
}

 

2) Create the wanted variants

mutation productVariantCreate($input: ProductVariantInput!) {
  productVariantCreate(input: $input) {
    product {
      id
      variants {
        edges {
          node {
            id
          }
        }
      }
    }
    productVariant {
      id
    }
    userErrors {
      field
      message
    }
  }
}

 

3) Delete the default variant

mutation productVariantDelete($id: ID!) {
  productVariantDelete(id: $id) {
    deletedProductVariantId
    product {
      id
      title
    }
    userErrors {
      field
      message
    }
  }
}

 

When I try to delete right after creating the product then create the wanted variants it was not behaving correctly, the first variant data was not set correctly!

 

I will give a try with your method.

 

Thanks a lot.

hocinehamdi
Shopify Partner
3 0 3

I tried your method @adeolamorren but it was too complex for my use case, so I get back to my initial solution (shared above), thanks again.

WebdevSam
Shopify Partner
1 0 0

hi @skorp  I also ran into a same problem. However I managed some sort of solution.

I first created a product using productCreate mutation with my required productOptions just adding 's' at my option value so that I can delete that at last

Created a variant now with my required optionvalues  with productVariantBulkCreate . Added inventory using inventoryAdjustQuantities

mutation and after all things done , Deleted the defaultVariant using productVariantDelete Mutation. Looks good now.