Working with MetaObjects in ShipReady
What are MetaObjects in Shopify?
MetaObjects in Shopify are customizable data structures that allow you to create and manage complex, structured data that doesn't fit into Shopify's standard data models. They are particularly useful for:
- Creating custom content types (e.g., recipes, team members, FAQ entries)
- Organizing related pieces of information
- Building flexible, app-specific data structures
- Storing app data that needs to be accessed and managed by merchants
MetaObjects consist of a definition (which defines the structure) and instances (which contain the actual data).
Using the MetaObject Class in ShipReady
ShipReady provides a powerful MetaObject
class to simplify working with Shopify's metaobjects. Here's how to use each method:
Initializing the MetaObject Class
First, import and initialize the MetaObject
class:
import { MetaObject } from "../entities/metaobject.js";
const metaobject = new MetaObject(admin);
Defining a MetaObject
Use the define
method to create a new MetaObject definition. The method now includes error handling for cases where the definition already exists:
try {
const definition = await metaobject.define({
name: "Recipe",
type: "recipe",
access: {
admin: "MERCHANT_READ_WRITE",
storefront: "PUBLIC_READ"
},
fieldDefinitions: [
{ key: "title", name: "Title", type: "single_line_text_field" },
{ key: "ingredients", name: "Ingredients", type: "multi_line_text_field" },
{ key: "instructions", name: "Instructions", type: "multi_line_text_field" },
{ key: "prep_time", name: "Preparation Time", type: "number_integer" }
]
});
console.log(definition);
// Output: { metaobjectDefinition: { name: "Recipe", type: "recipe", fieldDefinitions: [...] }, userErrors: [] }
} catch (error) {
if (error.message.includes("Type has already been taken")) {
console.log("MetaObject definition already exists");
} else {
console.error("Error defining MetaObject:", error);
}
}
Getting a MetaObject Definition
Retrieve an existing MetaObject definition:
try {
const recipeDefinition = await metaobject.getDefinition({ type: "recipe" });
console.log(recipeDefinition);
// Output: { id: "gid://shopify/MetaobjectDefinition/1234", name: "Recipe", type: "recipe", fieldDefinitions: [...] }
} catch (error) {
console.error("Error getting MetaObject definition:", error);
}
Deleting a MetaObject Definition
Remove a MetaObject definition:
try {
const deletedDefinition = await metaobject.deleteDefinition({ type: "recipe" });
console.log(deletedDefinition);
// Output: { deletedId: "gid://shopify/MetaobjectDefinition/1234", userErrors: [] }
} catch (error) {
console.error("Error deleting MetaObject definition:", error);
}
Creating a MetaObject Instance
Create a new instance of a MetaObject:
try {
const recipeInstance = await metaobject.create(
{
type: "recipe",
fieldDefinitions: [
{ key: "title" },
{ key: "ingredients" },
{ key: "instructions" },
{ key: "prep_time" }
]
},
{
title: "Chocolate Chip Cookies",
ingredients: "Flour, Sugar, Butter, Chocolate Chips",
instructions: "Mix ingredients, bake at 350°F for 10 minutes",
prep_time: 15
}
);
console.log(recipeInstance);
// Output: { id: "gid://shopify/Metaobject/5678", handle: "chocolate-chip-cookies", type: "recipe" }
} catch (error) {
console.error("Error creating MetaObject instance:", error);
}
Finding a MetaObject Instance
Retrieve a specific MetaObject instance:
try {
const foundRecipe = await metaobject.find(
{
fieldDefinitions: [
{ key: "title" },
{ key: "ingredients" },
{ key: "instructions" },
{ key: "prep_time" }
]
},
"gid://shopify/Metaobject/5678"
);
console.log(foundRecipe);
// Output: { id: "gid://shopify/Metaobject/5678", handle: "chocolate-chip-cookies", type: "recipe", title: "Chocolate Chip Cookies", ... }
} catch (error) {
console.error("Error finding MetaObject instance:", error);
}
Updating a MetaObject Instance
Update an existing MetaObject instance:
try {
const updatedRecipe = await metaobject.update(
{
fieldDefinitions: [
{ key: "title" },
{ key: "ingredients" },
{ key: "instructions" },
{ key: "prep_time" }
]
},
"gid://shopify/Metaobject/5678",
{
prep_time: 20
}
);
console.log(updatedRecipe);
// Output: { id: "gid://shopify/Metaobject/5678", handle: "chocolate-chip-cookies", type: "recipe" }
} catch (error) {
console.error("Error updating MetaObject instance:", error);
}
Listing MetaObject Instances
Retrieve a list of MetaObject instances with pagination support:
async function listRecipes(limit = 10) {
let allRecipes = [];
let hasNextPage = true;
let cursor = null;
while (hasNextPage) {
try {
const result = await metaobject.list(
{
type: "recipe",
fieldDefinitions: [
{ key: "title" },
{ key: "ingredients" },
{ key: "instructions" },
{ key: "prep_time" }
]
},
limit,
cursor
);
allRecipes = allRecipes.concat(result.nodes);
hasNextPage = result.pageInfo.hasNextPage;
cursor = result.pageInfo.endCursor;
} catch (error) {
console.error("Error listing MetaObject instances:", error);
break;
}
}
console.log(allRecipes);
return allRecipes;
}
listRecipes();
Deleting a MetaObject Instance
Remove a MetaObject instance:
try {
const deletedId = await metaobject.delete("gid://shopify/Metaobject/5678");
console.log(deletedId);
// Output: "gid://shopify/Metaobject/5678"
} catch (error) {
console.error("Error deleting MetaObject instance:", error);
}
Best Practices
- Plan your MetaObject structure carefully before defining it.
- Use meaningful names and keys for your MetaObject fields.
- Consider access levels (admin and storefront) when defining MetaObjects.
- Implement proper error handling for all MetaObject operations.
- Use pagination when listing MetaObjects to handle large datasets efficiently.
- Cache MetaObject definitions when appropriate to reduce API calls.
- Use MetaObjects to organize related data that doesn't fit into Shopify's standard models.
For more information on MetaObjects in Shopify, refer to the official Shopify documentation (opens in a new tab).
If you encounter any issues or have questions about using MetaObjects in ShipReady, please check our Troubleshooting page or contact our support team.