--- title: Create a custom Liquid block for nested cart lines description: >- Learn how to create nested cart lines for extended warranties using the Cart AJAX API and metafields source_url: html: >- https://shopify.dev/docs/apps/build/product-merchandising/nested-cart-lines/tutorial md: >- https://shopify.dev/docs/apps/build/product-merchandising/nested-cart-lines/tutorial.md --- ExpandOn this page * [1.​Create variant metafield definition for extended warranties](https://shopify.dev/docs/apps/build/product-merchandising/nested-cart-lines/tutorial.md#1-create-variant-metafield-definition-for-extended-warranties) * [2.​Custom Liquid block for creating nested cart line](https://shopify.dev/docs/apps/build/product-merchandising/nested-cart-lines/tutorial.md#2-custom-liquid-block-for-creating-nested-cart-line) * [3.​Defining nesting rules](https://shopify.dev/docs/apps/build/product-merchandising/nested-cart-lines/tutorial.md#3-defining-nesting-rules) # Create a custom Liquid block for nested cart lines This tutorial covers how to create nested cart lines for extended warranties using the Cart AJAX API and metafields with a custom Liquid block. *** ## 1.​Create variant metafield definition for extended warranties First, you'll need to create a metafield definition that maps a product to their available extended warranty options. Create a metafield definition named `extended_warranty` on the product object and set the metafield type to a list of product variants. ![Metafield definition for extended warranty](https://shopify.dev/assets/assets/images/merchandising/nested-cart-lines-metafield-definition-CCI1pqrR.png) This metafield will store references to warranty product variants that can be offered for each product variant. This can be configured in the Shopify admin product details page. ![Metafield definition for extended warranty](https://shopify.dev/assets/assets/images/merchandising/nested-cart-lines-metafield-use-paE8tQON.png) *** ## 2.​Custom Liquid block for creating nested cart line Next, you'll create custom Liquid block that reads the extended warranty metafield and displays the available warranty options to customers. On your theme editor, add a custom Liquid block on the product details page. ![How to create a custom Liquid block](https://shopify.dev/assets/assets/images/merchandising/nested-cart-lines-custom-liquid-block-juxHlPMW.png) Paste the following snippet: ## Custom Liquid block ```liquid {% assign current_variant = product.selected_or_first_available_variant %} {% assign warranties = product.metafields.custom.extended_warranty.value %}

Protect Your Purchase

{% for warranty in warranties %} {% else %}

No warranty options available

{% endfor %}
``` Once saved, the block will be rendered on the product details page and the "Add to Cart" button will enable multiple product variants to be added to the cart, with selected variants containing a reference to the parent cart line. ![Snippet rendering product variant options for warranties.](https://shopify.dev/assets/assets/images/merchandising/nested-cart-lines-block-DiyqmRiL.png) When added to the cart, nested cart lines will have distinct representation on Checkout. ![Checkout with a nested cart line. The leash has a warranty as its nested item](https://shopify.dev/assets/assets/images/merchandising/nested-cart-lines-checkout-BGRZdfIy.png) Note If you want to build validation to ensure that only eligible products were nested, the [Cart and Checkout Validation Function](https://shopify.dev/docs/api/functions/latest/cart-and-checkout-validation) can be leveraged. *** ## 3.​Defining nesting rules You can use custom data like custom data like [product reference lists](https://help.shopify.com/en/manual/custom-data/metafields/metafield-definitions/metafield-lists) to define nesting rules. Depending on the use case, you can either: * List all the products (or variants) a specific product (or variant) can be nested under. * List all the products (or variants) that can be nested under a specific product (or variant). This data can be read by: * Themes in order to display the right products. * Cart validation functions in order to validate the data before nesting the product under another one in the cart. Note It is important to validate the cart using functions in order to ensure someone trying to manipulate the storefront using the cart API directly can't bypass the rules defined by the merchant through the app. Same goes for quantity and line splitting rules. In this example, checkout and cart validation function has been deployed with an app for checking allowed nested cart lines. A metafield, `nestable_products` contains a list of allowed products that can be nested. ## Example Cart Validation function ## run.graphql ```graphql query RunInput { cart { lines { id quantity lineRelationship { parent { id quantity merchandise { ...MerchandiseFields } } } merchandise { ...MerchandiseFields } } } } fragment MerchandiseFields on Merchandise { ... on ProductVariant { id metafield(key: "nestable_variants") { value type jsonValue } title product { id title metafield(key: "nestable_products", namespace: "custom") { value type jsonValue } } } } ``` ## run.ts ```typescript import type { RunInput, CartValidationsGenerateRunResult, ValidationError, MerchandiseFields, } from "../generated/api"; type ExtractMerchandise = T extends { id: string } ? T : never; type Merchandise = ExtractMerchandise; function performValidationChecks(lineMerch: Merchandise, parentMerch: Merchandise): boolean { const childProductId = lineMerch.product?.id; // This is a metafield that contains an array of product ids that are compatible with the parent product const compatibleChildProducts = parentMerch.product?.metafield?.jsonValue; // Check if the child product is in the list of compatible child products return compatibleChildProducts?.includes(childProductId) ?? false; } export function cartValidationsGenerateRun(input: RunInput): CartValidationsGenerateRunResult { const errors: ValidationError[] = []; for (const line of input.cart.lines) { const parent = line.lineRelationship?.parent; if (!parent) continue; const lineMerch = line.merchandise; const parentMerch = parent.merchandise; const isValid = performValidationChecks(lineMerch, parentMerch); if (!isValid) { errors.push({ message: `Parent ${parentMerch.title} is not compatible with child ${lineMerch.title}`, target: "$.cart", }); } } const operations = [ { validationAdd: { errors, }, }, ]; return { operations }; }; ``` *** * [1.​Create variant metafield definition for extended warranties](https://shopify.dev/docs/apps/build/product-merchandising/nested-cart-lines/tutorial.md#1-create-variant-metafield-definition-for-extended-warranties) * [2.​Custom Liquid block for creating nested cart line](https://shopify.dev/docs/apps/build/product-merchandising/nested-cart-lines/tutorial.md#2-custom-liquid-block-for-creating-nested-cart-line) * [3.​Defining nesting rules](https://shopify.dev/docs/apps/build/product-merchandising/nested-cart-lines/tutorial.md#3-defining-nesting-rules)