Update cart metafields
This guide shows you how to use a cart handler to update cart metafields.
Anchor to RequirementsRequirements
- You've completed the quickstart guide.
- You've set up a cart handler.
Anchor to Step 1: Read cart metafieldsStep 1: Read cart metafields
Update the cart query fragment to return cart metafields. For more information, refer to the default CartApiQuery fragment.
The following example adds themetafield field:
File
server.js
JavaScript
const cart = createCartHandler({
storefront,
getCartId: cartGetIdDefault(request.headers),
setCartId: cartSetIdDefault(),
cartQueryFragment: CART_QUERY_FRAGMENT,
});
const CART_QUERY_FRAGMENT = `#graphql
fragment CartApiQuery on Cart {
metafield(namespace: "custom", key: "gift") {
value
}
id
checkoutUrl
totalQuantity
buyerIdentity {
countryCode
customer {
id
email
firstName
lastName
displayName
}
email
phone
}
lines(first: $numCartLines) {
edges {
node {
id
quantity
attributes {
key
value
}
cost {
totalAmount {
amount
currencyCode
}
amountPerQuantity {
amount
currencyCode
}
compareAtAmountPerQuantity {
amount
currencyCode
}
}
merchandise {
... on ProductVariant {
id
availableForSale
compareAtPrice {
...CartApiMoney
}
price {
...CartApiMoney
}
requiresShipping
title
image {
...CartApiImage
}
product {
handle
title
id
}
selectedOptions {
name
value
}
}
}
}
}
}
cost {
subtotalAmount {
...CartApiMoney
}
totalAmount {
...CartApiMoney
}
totalDutyAmount {
...CartApiMoney
}
totalTaxAmount {
...CartApiMoney
}
}
note
attributes {
key
value
}
discountCodes {
applicable
code
}
}
fragment CartApiMoney on MoneyV2 {
currencyCode
amount
}
fragment CartApiImage on Image {
id
url
altText
width
height
}
`;TypeScript
const cart = createCartHandler({
storefront,
getCartId: cartGetIdDefault(request.headers),
setCartId: cartSetIdDefault(),
cartQueryFragment: CART_QUERY_FRAGMENT,
});
const CART_QUERY_FRAGMENT = `#graphql
fragment CartApiQuery on Cart {
id
metafield(namespace: "custom", key: "gift") {
value
}
}
`;Anchor to Step 2: Create a metafield formStep 2: Create a metafield form
Use React Router's useFetcher hook to create a form that submits information that you want to store in a metafield. The hook submits a form request to the /cart route's action when users submit with this metafield form. You can use this component anywhere in the app.
When you use fetcher.submit, make sure there's a data key with the name CartForm.INPUT_NAME. The key value must be a JSON stringified object with action and inputs defined.
File
/app/components/ThisIsGift.jsx
JavaScript
import {useFetcher} from '@react-router';
import {CartForm} from '@shopify/hydrogen';
export function ThisIsGift({metafield}) {
const fetcher = useFetcher();
return (
<div>
<input
checked={metafield?.value === 'true'}
type="checkbox"
id="isGift"
onChange={(event) = /> {
fetcher.submit(
{
[CartForm.INPUT_NAME]: JSON.stringify({
action: CartForm.ACTIONS.MetafieldsSet,
inputs: {
metafields: [{
key: 'custom.gift',
type: 'boolean',
value: event.target.checked.toString(),
}],
},
}),
},
{method: 'POST', action: '/cart'}
)
}}
/>
<label htmlFor="isGift">This is a gift</label>
</div>
);
}TypeScript
import {useFetcher} from '@react-router';
import {CartForm} from '@shopify/hydrogen';
import type {Cart} from '@shopify/hydrogen/storefront-api-types';
export function ThisIsGift({
metafield,
}: {
metafield: Cart['metafield'];
}) {
const fetcher = useFetcher();
return (
<div>
<input
checked={metafield?.value === 'true'}
type="checkbox"
id="isGift"
onChange={(event) = /> {
fetcher.submit(
{
[CartForm.INPUT_NAME]: JSON.stringify({
action: CartForm.ACTIONS.MetafieldsSet,
inputs: {
metafields: [{
key: 'custom.gift',
type: 'boolean',
value: event.target.checked.toString(),
}],
},
}),
},
{method: 'POST', action: '/cart'}
)
}}
/>
<label htmlFor="isGift">This is a gift</label>
</div>
);
}Anchor to Step 3: Handle the update metafield form requestStep 3: Handle the update metafield form request
Handle the update metafield form request in an action. Use the cart, created from createCartHandler, to handle cart mutation requests to the Storefront API.
File
/app/routes/cart.jsx
JavaScript
import {CartForm} from '@shopify/hydrogen';
import invariant from 'tiny-invariant';
export async function action({request, context}) {
const {cart} = context;
const formData = await request.formData();
const {action, inputs} = CartForm.getFormInput(formData);
let result;
switch(action) {
case CartForm.ACTIONS.MetafieldsSet:
result = await cart.setMetafields(inputs.metafields);
break;
default:
invariant(false, `${action} cart action is not defined`);
}
// The Cart ID might change after each mutation, so update it each time.
const headers = cart.setCartId(result.cart.id);
return json(
result,
{status: 200, headers},
);
}TypeScript
import {
type CartQueryData,
CartForm,
} from '@shopify/hydrogen';
import invariant from 'tiny-invariant';
export async function action({request, context}: ActionArgs) {
const {cart} = context;
const formData = await request.formData();
const {action, inputs} = CartForm.getFormInput(formData);
let result: CartQueryData;
switch(action) {
case CartForm.ACTIONS.MetafieldsSet:
result = await cart.setMetafields(inputs.metafields);
break;
default:
invariant(false, `${action} cart action is not defined`);
}
// The Cart ID might change after each mutation, so update it each time.
const headers = cart.setCartId(result.cart.id);
return json(
result,
{status: 200, headers},
);
}Anchor to Next stepsNext steps
- Learn how to update buyer identity.