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
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
}
`;
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
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>
);
}
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
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},
);
}
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.