Discuss all the new features introduced with the new product model in GraphQL.
Good day,
Seems I'm having the issue of when I create products via the Admin API with GraphQL that once we get to the creating the variants part - it works but I always have a default title with 0 price which then causes the product to show it has 0 price on the site and also that being an option.
This is how the product data looks like I want to add to the shop:
KMQ: [
{
"title": "Founder Backpack",
"bodyHtml": "The Founder Backpack is manufactured using 210 Denier and Polyester material. The bag is very lightweight, making it the perfect companion for a quick outdoor trip. It has a front pocket as well as a main zippered compartment with a small, internal zippered pocket. The bag has a stretchy mesh pocket on each side, as well as adjustable shoulder straps.",
"vendor": "KMQ",
"productType": "Backpacks",
"images": [
{
"src": "https://www.kmq.co.za/content/webimages/LowRes/CxwhC9o4sVD_BAG2269-R.jpg",
"altText": "Founder Backpack image"
},
{
"src": "https://www.kmq.co.za/content/webimages/LowRes/DGcWeR3qtD0_BAG2269-RBU.jpg",
"altText": "Founder Backpack image"
}
],
"options": [
{
"name": "Color",
"values": [
"Red",
"Royal Blue"
]
}
],
"variants": [
{
"price": "116.12",
"sku": "BAG2269/R",
"inventoryQuantity": 1378,
"options": [
"Red"
]
},
{
"price": "116.12",
"sku": "BAG2269/RBU",
"inventoryQuantity": 896,
"options": [
"Royal Blue"
]
}
]
}
]
I have these functions setup to create, the product, then create the variants, adjust the inventory and finally publishing it:
Creating:
const createProduct = async (product) => {
const productCreateMutation = `
mutation CreateProductWithOptions($input: ProductInput!, $media: [CreateMediaInput!]) {
productCreate(input: $input, media: $media) {
product {
id
media(first: 10) {
nodes {
alt
mediaContentType
preview {
status
}
}
}
options {
id
name
position
values
optionValues {
id
name
hasVariants
}
}
variants(first: 20) {
nodes {
id
title
selectedOptions {
name
value
}
}
}
}
userErrors {
field
message
}
}
}
`;
const encodeURL = (url) => {
return encodeURI(url);
};
const mediaInput = product.images.map((image) => ({
originalSource: encodeURL(image.src),
alt: image.altText || "",
mediaContentType: "IMAGE",
}));
const productOptions = product.options.map((option) => ({
name: option.name,
values: option.values.map((value) => ({ name: value })),
}));
try {
const productResponse = await shopifyAPI.post(
"",
JSON.stringify({
query: productCreateMutation,
variables: {
input: {
title: product.title,
bodyHtml: product.bodyHtml,
vendor: product.vendor,
productType: product.productType,
// productOptions: productOptions,
metafields: [
{
namespace: "custom",
key: "sync_from_api",
type: "boolean",
value: "true",
},
],
},
media: mediaInput,
},
})
);
if (
productResponse.data.errors ||
productResponse.data.data.productCreate.userErrors.length > 0
) {
console.error(
"Error creating product:",
productResponse.data.errors ||
productResponse.data.data.productCreate.userErrors
);
return null;
}
return productResponse.data.data.productCreate.product.id;
} catch (error) {
console.error("Network or Server Error:", error);
return null;
}
};
Variants:
const createVariants = async (productId, variants) => {
const variantCreateMutation = `
mutation CreateVariant($input: ProductVariantInput!) {
productVariantCreate(input: $input) {
productVariant {
id
inventoryItem {
id
}
}
userErrors {
field
message
}
}
}
`;
const createdVariants = [];
for (const variant of variants) {
try {
const variantResponse = await shopifyAPI.post(
"",
JSON.stringify({
query: variantCreateMutation,
variables: {
input: {
productId,
price: variant.price,
sku: variant.sku,
options: variant.options,
},
},
})
);
if (
variantResponse.data.errors ||
variantResponse.data.data.productVariantCreate.userErrors.length > 0
) {
console.error(
"Error creating variant:",
variantResponse.data.errors ||
variantResponse.data.data.productVariantCreate.userErrors
);
} else {
console.log(`Variant created: ${variant.sku}`);
const inventoryItemId =
variantResponse.data.data.productVariantCreate.productVariant.inventoryItem.id
.split("/")
.pop();
createdVariants.push({
inventoryItemId,
inventoryQuantity: variant.inventoryQuantity,
});
}
} catch (error) {
console.error("Network or Server Error:", error);
}
}
return createdVariants;
};
Inventory:
const adjustInventory = async (inventoryItemId, inventoryQuantity) => {
const restAPI = axios.create({
baseURL: `https://${process.env.SHOPIFY_SHOP}/admin/api/2024-04`,
headers: {
"Content-Type": "application/json",
"X-Shopify-Access-Token": process.env.SHOPIFY_ACCESS_TOKEN,
},
});
const locationId = process.env.SHOPIFY_LOCATION_ID;
try {
await restAPI.post(`/inventory_levels/adjust.json`, {
location_id: locationId,
inventory_item_id: inventoryItemId, // Ensure inventoryItemId is correct
available_adjustment: inventoryQuantity,
});
console.log(`Inventory adjusted for item: ${inventoryItemId}`);
} catch (error) {
console.error("Error adjusting inventory:", error.response.data);
}
};
Finally Publising:
const publishProduct = async (
productId,
publicationId = "gid://shopify/Publication/126377492736"
) => {
const publishMutation = `
mutation PublishProduct($id: ID!, $input: [PublicationInput!]!) {
publishablePublish(id: $id, input: $input) {
publishable {
availablePublicationsCount {
count
}
resourcePublicationsCount {
count
}
}
shop {
publicationCount
}
userErrors {
field
message
}
}
}
`;
try {
const response = await shopifyAPI.post(
"",
JSON.stringify({
query: publishMutation,
variables: {
id: productId,
input: [
{
publicationId: publicationId,
},
],
},
})
);
if (
response.data.errors ||
response.data.data.publishablePublish.userErrors.length > 0
) {
console.error(
"Error publishing product:",
response.data.errors || response.data.data.publishablePublish.userErrors
);
return false;
}
console.log(`Product published successfully: ${productId}`);
return true;
} catch (error) {
console.error("Error publishing product:", error);
return false;
}
};
You'll see in the createProduct I have productOptions commented out - if I use that it works correctly but I dont get all the options and variants. So not sure where my issue/mistake is
Does anyone have some insight into this? Help would be appreciated as I'm still new to this way of adding products and using Shopify.
Hi, have you been able to resolve this?