diff --git a/assets/js/atomic/blocks/product-elements/button/block.js b/assets/js/atomic/blocks/product-elements/button/block.js
index 4283ae68c7d..579424b2f1b 100644
--- a/assets/js/atomic/blocks/product-elements/button/block.js
+++ b/assets/js/atomic/blocks/product-elements/button/block.js
@@ -35,7 +35,7 @@ import './style.scss';
* @param {string} [props.className] CSS Class name for the component.
* @return {*} The component.
*/
-const Block = ( props ) => {
+export const Block = ( props ) => {
const { className } = props;
const { parentClassName } = useInnerBlockLayoutContext();
diff --git a/assets/js/atomic/blocks/product-elements/image/block.js b/assets/js/atomic/blocks/product-elements/image/block.js
index e55f875c133..bc3e1cafab5 100644
--- a/assets/js/atomic/blocks/product-elements/image/block.js
+++ b/assets/js/atomic/blocks/product-elements/image/block.js
@@ -27,13 +27,13 @@ import './style.scss';
/**
* Product Image Block Component.
*
- * @param {Object} props Incoming props.
- * @param {string} [props.className] CSS Class name for the component.
- * @param {string} [props.imageSizing] Size of image to use.
- * @param {boolean} [props.showProductLink] Whether or not to display a link to the product page.
- * @param {boolean} [props.showSaleBadge] Whether or not to display the on sale badge.
- * @param {string} [props.saleBadgeAlign] How should the sale badge be aligned if displayed.
- * @param {boolean} [props.isDescendentOfQueryLoop] Whether or not be a children of Query Loop Block.
+ * @param {Object} props Incoming props.
+ * @param {string} [props.className] CSS Class name for the component.
+ * @param {string|undefined} [props.imageSizing] Size of image to use.
+ * @param {boolean|undefined} [props.showProductLink] Whether or not to display a link to the product page.
+ * @param {boolean} [props.showSaleBadge] Whether or not to display the on sale badge.
+ * @param {string|undefined} [props.saleBadgeAlign] How should the sale badge be aligned if displayed.
+ * @param {boolean} [props.isDescendentOfQueryLoop] Whether or not be a children of Query Loop Block.
* @return {*} The component.
*/
export const Block = ( props ) => {
diff --git a/assets/js/atomic/blocks/product-elements/price/block.js b/assets/js/atomic/blocks/product-elements/price/block.js
index b57fc475dc9..d6872ccf635 100644
--- a/assets/js/atomic/blocks/product-elements/price/block.js
+++ b/assets/js/atomic/blocks/product-elements/price/block.js
@@ -25,7 +25,7 @@ import { withProductDataContext } from '@woocommerce/shared-hocs';
* context will be used if this is not provided.
* @return {*} The component.
*/
-const Block = ( props ) => {
+export const Block = ( props ) => {
const { className, textAlign } = props;
const { parentClassName } = useInnerBlockLayoutContext();
const { product } = useProductDataContext();
diff --git a/assets/js/atomic/blocks/product-elements/rating/block.js b/assets/js/atomic/blocks/product-elements/rating/block.js
index a42c78f1a02..c1dacb14abd 100644
--- a/assets/js/atomic/blocks/product-elements/rating/block.js
+++ b/assets/js/atomic/blocks/product-elements/rating/block.js
@@ -27,7 +27,7 @@ import './style.scss';
* @param {string} [props.className] CSS Class name for the component.
* @return {*} The component.
*/
-const Block = ( props ) => {
+export const Block = ( props ) => {
const { parentClassName } = useInnerBlockLayoutContext();
const { product } = useProductDataContext();
const rating = getAverageRating( product );
diff --git a/assets/js/atomic/blocks/product-elements/sale-badge/block.js b/assets/js/atomic/blocks/product-elements/sale-badge/block.js
index d44cab0a773..bfd05e7171b 100644
--- a/assets/js/atomic/blocks/product-elements/sale-badge/block.js
+++ b/assets/js/atomic/blocks/product-elements/sale-badge/block.js
@@ -30,7 +30,7 @@ import './style.scss';
* @param {string} [props.align] Alignment of the badge.
* @return {*} The component.
*/
-const Block = ( props ) => {
+export const Block = ( props ) => {
const { className, align } = props;
const { parentClassName } = useInnerBlockLayoutContext();
const { product } = useProductDataContext();
diff --git a/assets/js/atomic/blocks/product-elements/title/types.ts b/assets/js/atomic/blocks/product-elements/title/types.ts
index 890ba7fecc5..68e77d0db39 100644
--- a/assets/js/atomic/blocks/product-elements/title/types.ts
+++ b/assets/js/atomic/blocks/product-elements/title/types.ts
@@ -2,7 +2,6 @@ export interface Attributes {
headingLevel: number;
showProductLink: boolean;
linkTarget?: string;
- productId: number;
align: string;
}
diff --git a/assets/js/base/context/hooks/cart/test/use-store-cart.js b/assets/js/base/context/hooks/cart/test/use-store-cart.js
index ffd5d7e1666..c92712b8d10 100644
--- a/assets/js/base/context/hooks/cart/test/use-store-cart.js
+++ b/assets/js/base/context/hooks/cart/test/use-store-cart.js
@@ -30,6 +30,7 @@ describe( 'useStoreCart', () => {
const previewCartData = {
cartCoupons: previewCart.coupons,
cartItems: previewCart.items,
+ crossSellsProducts: previewCart.cross_sells,
cartFees: previewCart.fees,
cartItemsCount: previewCart.items_count,
cartItemsWeight: previewCart.items_weight,
diff --git a/assets/js/base/context/hooks/cart/use-store-cart.ts b/assets/js/base/context/hooks/cart/use-store-cart.ts
index ff130605775..611d40371b8 100644
--- a/assets/js/base/context/hooks/cart/use-store-cart.ts
+++ b/assets/js/base/context/hooks/cart/use-store-cart.ts
@@ -9,6 +9,7 @@ import {
CART_STORE_KEY as storeKey,
EMPTY_CART_COUPONS,
EMPTY_CART_ITEMS,
+ EMPTY_CART_CROSS_SELLS,
EMPTY_CART_FEES,
EMPTY_CART_ITEM_ERRORS,
EMPTY_CART_ERRORS,
@@ -99,6 +100,7 @@ export const defaultCartData: StoreCart = {
cartFees: EMPTY_CART_FEES,
cartItemsCount: 0,
cartItemsWeight: 0,
+ crossSellsProducts: EMPTY_CART_CROSS_SELLS,
cartNeedsPayment: true,
cartNeedsShipping: true,
cartItemErrors: EMPTY_CART_ITEM_ERRORS,
@@ -150,6 +152,7 @@ export const useStoreCart = (
return {
cartCoupons: previewCart.coupons,
cartItems: previewCart.items,
+ crossSellsProducts: previewCart.cross_sells,
cartFees: previewCart.fees,
cartItemsCount: previewCart.items_count,
cartItemsWeight: previewCart.items_weight,
@@ -211,6 +214,7 @@ export const useStoreCart = (
return {
cartCoupons,
cartItems: cartData.items,
+ crossSellsProducts: cartData.crossSells,
cartFees,
cartItemsCount: cartData.itemsCount,
cartItemsWeight: cartData.itemsWeight,
diff --git a/assets/js/blocks/cart/cart-cross-sells-product-list/cart-cross-sells-product.tsx b/assets/js/blocks/cart/cart-cross-sells-product-list/cart-cross-sells-product.tsx
new file mode 100644
index 00000000000..067844d2116
--- /dev/null
+++ b/assets/js/blocks/cart/cart-cross-sells-product-list/cart-cross-sells-product.tsx
@@ -0,0 +1,65 @@
+/**
+ * External dependencies
+ */
+import {
+ InnerBlockLayoutContextProvider,
+ ProductDataContextProvider,
+} from '@woocommerce/shared-context';
+import { ProductResponseItem } from '@woocommerce/type-defs/product-response';
+
+/**
+ * Internal dependencies
+ */
+import { Block as ProductImage } from '../../../atomic/blocks/product-elements/image/block';
+import { Block as ProductName } from '../../../atomic/blocks/product-elements/title/block';
+import { Block as ProductRating } from '../../../atomic/blocks/product-elements/rating/block';
+import { Block as ProductSaleBadge } from '../../../atomic/blocks/product-elements/sale-badge/block';
+import { Block as ProductPrice } from '../../../atomic/blocks/product-elements/price/block';
+import { Block as ProductButton } from '../../../atomic/blocks/product-elements/button/block';
+import AddToCartButton from '../../../atomic/blocks/product-elements/add-to-cart/block';
+
+interface CrossSellsProductProps {
+ product: ProductResponseItem;
+ isLoading: boolean;
+}
+
+const CartCrossSellsProduct = ( {
+ product,
+}: CrossSellsProductProps ): JSX.Element => {
+ return (
+
+
+
+
+ { product.is_in_stock ? (
+
+ ) : (
+
+ ) }
+
+
+
+ );
+};
+
+export default CartCrossSellsProduct;
diff --git a/assets/js/blocks/cart/cart-cross-sells-product-list/index.tsx b/assets/js/blocks/cart/cart-cross-sells-product-list/index.tsx
new file mode 100644
index 00000000000..142d91030ce
--- /dev/null
+++ b/assets/js/blocks/cart/cart-cross-sells-product-list/index.tsx
@@ -0,0 +1,37 @@
+/**
+ * External dependencies
+ */
+import { ProductResponseItem } from '@woocommerce/type-defs/product-response';
+
+/**
+ * Internal dependencies
+ */
+import CartCrossSellsProduct from './cart-cross-sells-product';
+
+interface CrossSellsProductListProps {
+ products: ProductResponseItem[];
+ className?: string | undefined;
+ columns: number;
+}
+
+const CartCrossSellsProductList = ( {
+ products,
+ columns,
+}: CrossSellsProductListProps ): JSX.Element => {
+ const crossSellsProducts = products.map( ( product, i ) => {
+ if ( i >= columns ) return null;
+
+ return (
+
+ );
+ } );
+
+ return { crossSellsProducts }
;
+};
+
+export default CartCrossSellsProductList;
diff --git a/assets/js/blocks/cart/inner-blocks/cart-cross-sells-block/block.json b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-block/block.json
new file mode 100644
index 00000000000..5c8c562ff1f
--- /dev/null
+++ b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-block/block.json
@@ -0,0 +1,25 @@
+{
+ "name": "woocommerce/cart-cross-sells-block",
+ "version": "1.0.0",
+ "title": "Cart Cross-Sells block",
+ "description": "Shows the Cross-Sells block.",
+ "category": "woocommerce",
+ "supports": {
+ "align": false,
+ "html": false,
+ "multiple": false,
+ "reusable": false,
+ "inserter": true
+ },
+ "attributes": {
+ "lock": {
+ "type": "object",
+ "default": {
+ "move": true
+ }
+ }
+ },
+ "parent": [ "woocommerce/cart-items-block" ],
+ "textdomain": "woo-gutenberg-products-block",
+ "apiVersion": 2
+}
diff --git a/assets/js/blocks/cart/inner-blocks/cart-cross-sells-block/edit.tsx b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-block/edit.tsx
new file mode 100644
index 00000000000..25d8a8a9b20
--- /dev/null
+++ b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-block/edit.tsx
@@ -0,0 +1,41 @@
+/**
+ * External dependencies
+ */
+import type { TemplateArray } from '@wordpress/blocks';
+import { __ } from '@wordpress/i18n';
+import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
+
+export const Edit = (): JSX.Element => {
+ const blockProps = useBlockProps( {
+ className: 'wc-block-cart__cross-sells',
+ } );
+ const defaultTemplate = [
+ [
+ 'core/heading',
+ {
+ content: __(
+ 'You may be interested in…',
+ 'woo-gutenberg-products-block'
+ ),
+ level: 3,
+ },
+ ,
+ [],
+ ],
+ [ 'woocommerce/cart-cross-sells-products-block', {}, [] ],
+ ] as TemplateArray;
+
+ return (
+
+
+
+ );
+};
+
+export const Save = (): JSX.Element => {
+ return (
+
+
+
+ );
+};
diff --git a/assets/js/blocks/cart/inner-blocks/cart-cross-sells-block/frontend.tsx b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-block/frontend.tsx
new file mode 100644
index 00000000000..bdf825767a2
--- /dev/null
+++ b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-block/frontend.tsx
@@ -0,0 +1,24 @@
+/**
+ * External dependencies
+ */
+import { useStoreCart } from '@woocommerce/base-context/hooks';
+
+interface Props {
+ children?: JSX.Element | JSX.Element[];
+ className?: string;
+}
+
+const FrontendBlock = ( {
+ children,
+ className = '',
+}: Props ): JSX.Element | null => {
+ const { crossSellsProducts, cartIsLoading } = useStoreCart();
+
+ if ( cartIsLoading || crossSellsProducts.length < 1 ) {
+ return null;
+ }
+
+ return { children }
;
+};
+
+export default FrontendBlock;
diff --git a/assets/js/blocks/cart/inner-blocks/cart-cross-sells-block/index.tsx b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-block/index.tsx
new file mode 100644
index 00000000000..857f713e16f
--- /dev/null
+++ b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-block/index.tsx
@@ -0,0 +1,24 @@
+/**
+ * External dependencies
+ */
+import { Icon, column } from '@wordpress/icons';
+import { registerExperimentalBlockType } from '@woocommerce/block-settings';
+
+/**
+ * Internal dependencies
+ */
+import { Edit, Save } from './edit';
+import metadata from './block.json';
+
+registerExperimentalBlockType( metadata, {
+ icon: {
+ src: (
+
+ ),
+ },
+ edit: Edit,
+ save: Save,
+} );
diff --git a/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/block.json b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/block.json
new file mode 100644
index 00000000000..c867f2ca2ad
--- /dev/null
+++ b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/block.json
@@ -0,0 +1,31 @@
+{
+ "name": "woocommerce/cart-cross-sells-products-block",
+ "version": "1.0.0",
+ "title": "Cart Cross-Sells products",
+ "description": "Shows the Cross-Sells products.",
+ "category": "woocommerce",
+ "supports": {
+ "align": false,
+ "html": false,
+ "multiple": false,
+ "reusable": false,
+ "inserter": false,
+ "lock": false
+ },
+ "attributes": {
+ "columns": {
+ "type": "number",
+ "default": 3
+ },
+ "lock": {
+ "type": "object",
+ "default": {
+ "remove": true,
+ "move": true
+ }
+ }
+ },
+ "parent": [ "woocommerce/cart-cross-sells-block" ],
+ "textdomain": "woo-gutenberg-products-block",
+ "apiVersion": 2
+}
diff --git a/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/block.tsx b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/block.tsx
new file mode 100644
index 00000000000..645f8499b25
--- /dev/null
+++ b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/block.tsx
@@ -0,0 +1,33 @@
+/**
+ * External dependencies
+ */
+import { useStoreCart } from '@woocommerce/base-context/hooks';
+
+/**
+ * Internal dependencies
+ */
+import CartCrossSellsProductList from '../../cart-cross-sells-product-list';
+import metadata from './block.json';
+
+interface BlockProps {
+ className?: string | undefined;
+ columns: number;
+}
+
+const Block = ( { className, columns }: BlockProps ): JSX.Element => {
+ const { crossSellsProducts } = useStoreCart();
+
+ if ( typeof columns === 'undefined' ) {
+ columns = metadata.attributes.columns.default;
+ }
+
+ return (
+
+ );
+};
+
+export default Block;
diff --git a/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/edit.tsx b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/edit.tsx
new file mode 100644
index 00000000000..3c0dedcb7a2
--- /dev/null
+++ b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/edit.tsx
@@ -0,0 +1,59 @@
+/**
+ * External dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import { PanelBody, RangeControl } from '@wordpress/components';
+import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
+import { getSetting } from '@woocommerce/settings';
+import Noninteractive from '@woocommerce/base-components/noninteractive';
+
+/**
+ * Internal dependencies
+ */
+import Block from './block';
+import './editor.scss';
+
+interface Attributes {
+ className?: string;
+ columns: number;
+}
+
+interface Props {
+ attributes: Attributes;
+ setAttributes: ( attributes: Record< string, unknown > ) => void;
+}
+
+export const Edit = ( { attributes, setAttributes }: Props ): JSX.Element => {
+ const { className, columns } = attributes;
+ const blockProps = useBlockProps();
+
+ return (
+
+
+
+
+ setAttributes( { columns: value } )
+ }
+ min={ getSetting( 'min_columns', 1 ) }
+ max={ getSetting( 'max_columns', 6 ) }
+ />
+
+
+
+
+
+
+ );
+};
+
+export const Save = (): JSX.Element => {
+ return ;
+};
diff --git a/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/editor.scss b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/editor.scss
new file mode 100644
index 00000000000..77083516b47
--- /dev/null
+++ b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/editor.scss
@@ -0,0 +1,38 @@
+.wp-block-woocommerce-cart-cross-sells-products-block {
+
+ .cross-sells-product {
+ display: inline-block;
+ margin-bottom: 2em;
+ padding-right: 5%;
+ text-align: center;
+ vertical-align: top;
+ width: 30%;
+
+ &:nth-child(3n + 3) {
+ padding-right: 0;
+ }
+
+ div {
+ .wc-block-components-product-name {
+ font-weight: 400;
+ }
+
+ .wc-block-components-product-price {
+ display: block;
+ }
+ }
+
+ .wc-block-components-product-add-to-cart-button:not(.is-link) {
+ background-color: #eee;
+ color: #333;
+ margin-top: 1em;
+
+ &:focus,
+ &:hover {
+ background-color: #d5d5d5;
+ border-color: #d5d5d5;
+ color: #333;
+ }
+ }
+ }
+}
diff --git a/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/frontend.tsx b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/frontend.tsx
new file mode 100644
index 00000000000..4fc9ad2897a
--- /dev/null
+++ b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/frontend.tsx
@@ -0,0 +1,6 @@
+/**
+ * Internal dependencies
+ */
+import Block from './block';
+
+export default Block;
diff --git a/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/index.tsx b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/index.tsx
new file mode 100644
index 00000000000..857f713e16f
--- /dev/null
+++ b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/index.tsx
@@ -0,0 +1,24 @@
+/**
+ * External dependencies
+ */
+import { Icon, column } from '@wordpress/icons';
+import { registerExperimentalBlockType } from '@woocommerce/block-settings';
+
+/**
+ * Internal dependencies
+ */
+import { Edit, Save } from './edit';
+import metadata from './block.json';
+
+registerExperimentalBlockType( metadata, {
+ icon: {
+ src: (
+
+ ),
+ },
+ edit: Edit,
+ save: Save,
+} );
diff --git a/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/style.scss b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/style.scss
new file mode 100644
index 00000000000..4bf8332ddda
--- /dev/null
+++ b/assets/js/blocks/cart/inner-blocks/cart-cross-sells-products/style.scss
@@ -0,0 +1,72 @@
+.wp-block-woocommerce-cart {
+
+ &.is-loading .wp-block-woocommerce-cart-cross-sells-block {
+ @include placeholder();
+ margin-top: 2em;
+ min-height: 15em;
+
+ h3 {
+ display: none;
+ }
+ }
+
+ .wp-block-woocommerce-cart-cross-sells-block {
+
+ .cross-sells-product {
+ display: inline-block;
+ box-sizing: content-box;
+ margin-bottom: 2em;
+ padding-right: 5%;
+ text-align: center;
+ vertical-align: top;
+ width: 30%;
+
+ &:nth-child(3n + 3) {
+ padding-right: 0;
+ }
+
+ div {
+ .wc-block-components-product-name {
+ font-weight: 400;
+ }
+
+ .wc-block-components-product-price {
+ display: block;
+ }
+ }
+
+ .wc-block-components-product-button__button {
+ margin-top: 1em;
+ }
+
+ .wc-block-components-product-add-to-cart {
+ justify-content: center;
+
+ .wc-block-components-product-add-to-cart-button:not(.is-link) {
+ background-color: #eee;
+ color: #333;
+ font-weight: 600;
+ margin-top: 1em;
+
+ &:focus,
+ &:hover {
+ background-color: #d5d5d5;
+ border-color: #d5d5d5;
+ color: #333;
+ }
+ }
+ }
+ }
+ }
+}
+
+@include breakpoint("<480px") {
+ .wp-block-woocommerce-cart {
+ .wp-block-woocommerce-cart-cross-sells-block {
+ .cross-sells-product {
+ display: block;
+ width: 100%;
+ }
+ }
+ }
+}
diff --git a/assets/js/blocks/cart/inner-blocks/cart-items-block/edit.tsx b/assets/js/blocks/cart/inner-blocks/cart-items-block/edit.tsx
index 2ac1a66db44..bfad15f3dcc 100644
--- a/assets/js/blocks/cart/inner-blocks/cart-items-block/edit.tsx
+++ b/assets/js/blocks/cart/inner-blocks/cart-items-block/edit.tsx
@@ -4,6 +4,7 @@
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
import { Main } from '@woocommerce/base-components/sidebar-layout';
import { innerBlockAreas } from '@woocommerce/blocks-checkout';
+import { isExperimentalBuild } from '@woocommerce/block-settings';
import type { TemplateArray } from '@wordpress/blocks';
/**
* Internal dependencies
@@ -13,12 +14,19 @@ import {
getAllowedBlocks,
} from '../../../cart-checkout-shared';
-export const Edit = ( { clientId }: { clientId: string } ): JSX.Element => {
+interface Props {
+ clientId: string;
+}
+
+export const Edit = ( { clientId }: Props ): JSX.Element => {
const blockProps = useBlockProps( { className: 'wc-block-cart__main' } );
const allowedBlocks = getAllowedBlocks( innerBlockAreas.CART_ITEMS );
const defaultTemplate = [
[ 'woocommerce/cart-line-items-block', {}, [] ],
- ] as TemplateArray;
+ ...( isExperimentalBuild()
+ ? [ [ 'woocommerce/cart-cross-sells-block', {}, [] ] ]
+ : [] ),
+ ] as unknown as TemplateArray;
useForcedLayout( {
clientId,
diff --git a/assets/js/blocks/cart/inner-blocks/component-metadata.ts b/assets/js/blocks/cart/inner-blocks/component-metadata.ts
index cf979e31355..631d2bdcadb 100644
--- a/assets/js/blocks/cart/inner-blocks/component-metadata.ts
+++ b/assets/js/blocks/cart/inner-blocks/component-metadata.ts
@@ -6,6 +6,8 @@ import EMPTY_CART from './empty-cart-block/block.json';
import CART_ITEMS from './cart-items-block/block.json';
import CART_EXPRESS_PAYMENT from './cart-express-payment-block/block.json';
import CART_LINE_ITEMS from './cart-line-items-block/block.json';
+import CART_CROSS_SELLS from './cart-cross-sells-block/block.json';
+import CART_CROSS_SELLS_PRODUCTS from './cart-cross-sells-products/block.json';
import CART_TOTALS from './cart-totals-block/block.json';
import PROCEED_TO_CHECKOUT from './proceed-to-checkout-block/block.json';
import CART_ACCEPTED_PAYMENT_METHODS from './cart-accepted-payment-methods-block/block.json';
@@ -24,6 +26,8 @@ export default {
CART_ITEMS,
CART_EXPRESS_PAYMENT,
CART_LINE_ITEMS,
+ CART_CROSS_SELLS,
+ CART_CROSS_SELLS_PRODUCTS,
CART_TOTALS,
PROCEED_TO_CHECKOUT,
CART_ACCEPTED_PAYMENT_METHODS,
diff --git a/assets/js/blocks/cart/inner-blocks/index.tsx b/assets/js/blocks/cart/inner-blocks/index.tsx
index 003f6f54634..99df256e16c 100644
--- a/assets/js/blocks/cart/inner-blocks/index.tsx
+++ b/assets/js/blocks/cart/inner-blocks/index.tsx
@@ -4,6 +4,8 @@
import './filled-cart-block';
import './cart-items-block';
import './cart-line-items-block';
+import './cart-cross-sells-block';
+import './cart-cross-sells-products';
import './cart-totals-block';
import './cart-express-payment-block';
import './proceed-to-checkout-block';
diff --git a/assets/js/blocks/cart/inner-blocks/register-components.ts b/assets/js/blocks/cart/inner-blocks/register-components.ts
index bf4ac082f28..5aec48ea60b 100644
--- a/assets/js/blocks/cart/inner-blocks/register-components.ts
+++ b/assets/js/blocks/cart/inner-blocks/register-components.ts
@@ -2,7 +2,10 @@
* External dependencies
*/
import { lazy } from '@wordpress/element';
-import { WC_BLOCKS_BUILD_URL } from '@woocommerce/block-settings';
+import {
+ WC_BLOCKS_BUILD_URL,
+ isExperimentalBuild,
+} from '@woocommerce/block-settings';
import { registerCheckoutBlock } from '@woocommerce/blocks-checkout';
/**
@@ -58,6 +61,30 @@ registerCheckoutBlock( {
),
} );
+if ( isExperimentalBuild() ) {
+ registerCheckoutBlock( {
+ metadata: metadata.CART_CROSS_SELLS,
+ component: lazy(
+ () =>
+ import(
+ /* webpackChunkName: "cart-blocks/cart-cross-sells" */
+ './cart-cross-sells-block/frontend'
+ )
+ ),
+ } );
+
+ registerCheckoutBlock( {
+ metadata: metadata.CART_CROSS_SELLS_PRODUCTS,
+ component: lazy(
+ () =>
+ import(
+ /* webpackChunkName: "cart-blocks/cart-cross-sells-products" */
+ './cart-cross-sells-products/frontend'
+ )
+ ),
+ } );
+}
+
registerCheckoutBlock( {
metadata: metadata.CART_TOTALS,
component: lazy(
diff --git a/assets/js/blocks/cart/style.scss b/assets/js/blocks/cart/style.scss
index d3539cf4097..c495532e6cc 100644
--- a/assets/js/blocks/cart/style.scss
+++ b/assets/js/blocks/cart/style.scss
@@ -21,7 +21,7 @@ table.wc-block-cart-items td {
background: none !important;
// Remove borders on default themes.
border: 0;
- margin: 0;
+ margin: 0 0 2em;
}
.editor-styles-wrapper table.wc-block-cart-items,
diff --git a/assets/js/data/constants.ts b/assets/js/data/constants.ts
index 996dbbd8105..14a16efc68b 100644
--- a/assets/js/data/constants.ts
+++ b/assets/js/data/constants.ts
@@ -7,6 +7,7 @@ export const API_BLOCK_NAMESPACE = 'wc/blocks';
export const EMPTY_CART_COUPONS: [] = [];
export const EMPTY_CART_ITEMS: [] = [];
+export const EMPTY_CART_CROSS_SELLS: [] = [];
export const EMPTY_CART_FEES: [] = [];
export const EMPTY_CART_ITEM_ERRORS: [] = [];
export const EMPTY_CART_ERRORS: [] = [];
diff --git a/assets/js/data/default-states.ts b/assets/js/data/default-states.ts
index 8fe8ec2b698..a0345719078 100644
--- a/assets/js/data/default-states.ts
+++ b/assets/js/data/default-states.ts
@@ -9,6 +9,7 @@ import type { Cart, CartMeta } from '@woocommerce/types';
import {
EMPTY_CART_COUPONS,
EMPTY_CART_ITEMS,
+ EMPTY_CART_CROSS_SELLS,
EMPTY_CART_FEES,
EMPTY_CART_ITEM_ERRORS,
EMPTY_CART_ERRORS,
@@ -64,6 +65,7 @@ export const defaultCartState: CartState = {
items: EMPTY_CART_ITEMS,
itemsCount: 0,
itemsWeight: 0,
+ crossSells: EMPTY_CART_CROSS_SELLS,
needsShipping: true,
needsPayment: false,
hasCalculatedShipping: true,
diff --git a/assets/js/previews/cart.ts b/assets/js/previews/cart.ts
index 4a06a8a0e0b..6852a35ee9b 100644
--- a/assets/js/previews/cart.ts
+++ b/assets/js/previews/cart.ts
@@ -172,6 +172,228 @@ export const previewCart: CartResponse = {
extensions: {},
},
],
+ cross_sells: [
+ {
+ id: 1,
+ name: __( 'Polo', 'woo-gutenberg-products-block' ),
+ permalink: 'https://example.org',
+ prices: {
+ currency_code: 'USD',
+ currency_symbol: '$',
+ currency_minor_unit: 2,
+ currency_decimal_separator: '.',
+ currency_thousand_separator: ',',
+ currency_prefix: '$',
+ currency_suffix: '',
+ price: displayWithTax ? '24000' : '20000',
+ regular_price: displayWithTax ? '24000' : '20000',
+ sale_price: displayWithTax ? '12000' : '10000',
+ raw_prices: {
+ precision: 6,
+ price: displayWithTax ? '24000000' : '20000000',
+ regular_price: displayWithTax ? '24000000' : '20000000',
+ sale_price: displayWithTax ? '12000000' : '10000000',
+ },
+ },
+ images: [
+ {
+ id: 17,
+ src: WC_BLOCKS_IMAGE_URL + 'previews/polo.jpg',
+ thumbnail: WC_BLOCKS_IMAGE_URL + 'previews/polo.jpg',
+ srcset: '',
+ sizes: '',
+ name: '',
+ alt: '',
+ },
+ ],
+ average_rating: 4.5,
+ },
+ {
+ id: 2,
+ name: __( 'Long Sleeve Tee', 'woo-gutenberg-products-block' ),
+ permalink: 'https://example.org',
+ prices: {
+ currency_code: 'USD',
+ currency_symbol: '$',
+ currency_minor_unit: 2,
+ currency_decimal_separator: '.',
+ currency_thousand_separator: ',',
+ currency_prefix: '$',
+ currency_suffix: '',
+ price: displayWithTax ? '30000' : '25000',
+ regular_price: displayWithTax ? '30000' : '25000',
+ sale_price: displayWithTax ? '30000' : '25000',
+ raw_prices: {
+ precision: 6,
+ price: displayWithTax ? '30000000' : '25000000',
+ regular_price: displayWithTax ? '30000000' : '25000000',
+ sale_price: displayWithTax ? '30000000' : '25000000',
+ },
+ },
+ images: [
+ {
+ id: 17,
+ src: WC_BLOCKS_IMAGE_URL + 'previews/long-sleeve-tee.jpg',
+ thumbnail:
+ WC_BLOCKS_IMAGE_URL + 'previews/long-sleeve-tee.jpg',
+ srcset: '',
+ sizes: '',
+ name: '',
+ alt: '',
+ },
+ ],
+ average_rating: 4,
+ },
+ {
+ id: 3,
+ name: __( 'Hoodie with Zipper', 'woo-gutenberg-products-block' ),
+ permalink: 'https://example.org',
+ on_sale: true,
+ prices: {
+ currency_code: 'USD',
+ currency_symbol: '$',
+ currency_minor_unit: 2,
+ currency_decimal_separator: '.',
+ currency_thousand_separator: ',',
+ currency_prefix: '$',
+ currency_suffix: '',
+ price: displayWithTax ? '15000' : '12500',
+ regular_price: displayWithTax ? '30000' : '25000',
+ sale_price: displayWithTax ? '15000' : '12500',
+ raw_prices: {
+ precision: 6,
+ price: displayWithTax ? '15000000' : '12500000',
+ regular_price: displayWithTax ? '30000000' : '25000000',
+ sale_price: displayWithTax ? '15000000' : '12500000',
+ },
+ },
+ images: [
+ {
+ id: 17,
+ src:
+ WC_BLOCKS_IMAGE_URL + 'previews/hoodie-with-zipper.jpg',
+ thumbnail:
+ WC_BLOCKS_IMAGE_URL + 'previews/hoodie-with-zipper.jpg',
+ srcset: '',
+ sizes: '',
+ name: '',
+ alt: '',
+ },
+ ],
+ average_rating: 1,
+ },
+ {
+ id: 4,
+ name: __( 'Hoodie with Logo', 'woo-gutenberg-products-block' ),
+ permalink: 'https://example.org',
+ on_sale: false,
+ prices: {
+ currency_code: 'USD',
+ currency_symbol: '$',
+ currency_minor_unit: 2,
+ currency_decimal_separator: '.',
+ currency_thousand_separator: ',',
+ currency_prefix: '$',
+ currency_suffix: '',
+ price: displayWithTax ? '4500' : '4250',
+ regular_price: displayWithTax ? '4500' : '4250',
+ sale_price: displayWithTax ? '4500' : '4250',
+ raw_prices: {
+ precision: 6,
+ price: displayWithTax ? '45000000' : '42500000',
+ regular_price: displayWithTax ? '45000000' : '42500000',
+ sale_price: displayWithTax ? '45000000' : '42500000',
+ },
+ },
+ images: [
+ {
+ id: 17,
+ src: WC_BLOCKS_IMAGE_URL + 'previews/hoodie-with-logo.jpg',
+ thumbnail:
+ WC_BLOCKS_IMAGE_URL + 'previews/hoodie-with-logo.jpg',
+ srcset: '',
+ sizes: '',
+ name: '',
+ alt: '',
+ },
+ ],
+ average_rating: 5,
+ },
+ {
+ id: 5,
+ name: __( 'Hoodie with Pocket', 'woo-gutenberg-products-block' ),
+ permalink: 'https://example.org',
+ on_sale: true,
+ prices: {
+ currency_code: 'USD',
+ currency_symbol: '$',
+ currency_minor_unit: 2,
+ currency_decimal_separator: '.',
+ currency_thousand_separator: ',',
+ currency_prefix: '$',
+ currency_suffix: '',
+ price: displayWithTax ? '3500' : '3250',
+ regular_price: displayWithTax ? '4500' : '4250',
+ sale_price: displayWithTax ? '3500' : '3250',
+ raw_prices: {
+ precision: 6,
+ price: displayWithTax ? '35000000' : '32500000',
+ regular_price: displayWithTax ? '45000000' : '42500000',
+ sale_price: displayWithTax ? '35000000' : '32500000',
+ },
+ },
+ images: [
+ {
+ id: 17,
+ src:
+ WC_BLOCKS_IMAGE_URL + 'previews/hoodie-with-pocket.jpg',
+ thumbnail:
+ WC_BLOCKS_IMAGE_URL + 'previews/hoodie-with-pocket.jpg',
+ srcset: '',
+ sizes: '',
+ name: '',
+ alt: '',
+ },
+ ],
+ average_rating: 3.75,
+ },
+ {
+ id: 6,
+ name: __( 'T-Shirt', 'woo-gutenberg-products-block' ),
+ permalink: 'https://example.org',
+ on_sale: false,
+ prices: {
+ currency_code: 'USD',
+ currency_symbol: '$',
+ currency_minor_unit: 2,
+ currency_decimal_separator: '.',
+ currency_thousand_separator: ',',
+ currency_prefix: '$',
+ currency_suffix: '',
+ price: displayWithTax ? '1800' : '1500',
+ regular_price: displayWithTax ? '1800' : '1500',
+ sale_price: displayWithTax ? '1800' : '1500',
+ raw_prices: {
+ precision: 6,
+ price: displayWithTax ? '1800000' : '1500000',
+ regular_price: displayWithTax ? '1800000' : '1500000',
+ sale_price: displayWithTax ? '1800000' : '1500000',
+ },
+ },
+ images: [
+ {
+ id: 17,
+ src: WC_BLOCKS_IMAGE_URL + 'previews/tshirt.jpg',
+ thumbnail: WC_BLOCKS_IMAGE_URL + 'previews/tshirt.jpg',
+ srcset: '',
+ sizes: '',
+ name: '',
+ alt: '',
+ },
+ ],
+ average_rating: 3,
+ },
+ ],
fees: [
{
id: 'fee',
diff --git a/assets/js/shared/context/product-data-context.js b/assets/js/shared/context/product-data-context.js
index 3d91f5f5635..a81cc16e913 100644
--- a/assets/js/shared/context/product-data-context.js
+++ b/assets/js/shared/context/product-data-context.js
@@ -1,7 +1,6 @@
/**
* External dependencies
*/
-import PropTypes from 'prop-types';
import { createContext, useContext } from '@wordpress/element';
/**
@@ -68,6 +67,14 @@ const ProductDataContext = createContext( {
export const useProductDataContext = () => useContext( ProductDataContext );
+/**
+ * This context is used to pass product data down to all children blocks in a given tree.
+ *
+ * @param {Object} object A react context object
+ * @param {any|null} object.product The product data to be passed down
+ * @param {Object} object.children The product data to be passed down
+ * @param {boolean} object.isLoading The product data to be passed down
+ */
export const ProductDataContextProvider = ( {
product = null,
children,
@@ -89,8 +96,3 @@ export const ProductDataContextProvider = ( {
);
};
-
-ProductDataContextProvider.propTypes = {
- children: PropTypes.node,
- product: PropTypes.object,
-};
diff --git a/assets/js/types/type-defs/cart-response.ts b/assets/js/types/type-defs/cart-response.ts
index a28bf1b8391..13e6f583f31 100644
--- a/assets/js/types/type-defs/cart-response.ts
+++ b/assets/js/types/type-defs/cart-response.ts
@@ -3,6 +3,7 @@
*/
import { CurrencyResponse } from './currency';
import type { CartItem } from './cart';
+import type { ProductResponseItem } from './product-response';
export interface CartResponseTotalsItem extends CurrencyResponse {
total_discount: string;
@@ -170,6 +171,7 @@ export interface CartResponse {
items: Array< CartResponseItem >;
items_count: number;
items_weight: number;
+ cross_sells: Array< ProductResponseItem >;
needs_payment: boolean;
needs_shipping: boolean;
has_calculated_shipping: boolean;
diff --git a/assets/js/types/type-defs/cart.ts b/assets/js/types/type-defs/cart.ts
index 9d9aa98dfc9..f80a847835a 100644
--- a/assets/js/types/type-defs/cart.ts
+++ b/assets/js/types/type-defs/cart.ts
@@ -12,7 +12,10 @@ import {
ExtensionsData,
} from './cart-response';
-import { ProductResponseItemData } from './product-response';
+import {
+ ProductResponseItemData,
+ ProductResponseItem,
+} from './product-response';
export interface CurrencyInfo {
currency_code: CurrencyCode;
@@ -190,6 +193,7 @@ export interface Cart {
items: Array< CartItem >;
itemsCount: number;
itemsWeight: number;
+ crossSells: Array< ProductResponseItem >;
needsPayment: boolean;
needsShipping: boolean;
hasCalculatedShipping: boolean;
diff --git a/assets/js/types/type-defs/hooks.ts b/assets/js/types/type-defs/hooks.ts
index 716b8645079..09cead7e6c8 100644
--- a/assets/js/types/type-defs/hooks.ts
+++ b/assets/js/types/type-defs/hooks.ts
@@ -1,3 +1,8 @@
+/**
+ * External dependencies
+ */
+import { ProductResponseItem } from '@woocommerce/type-defs/product-response';
+
/**
* Internal dependencies
*/
@@ -34,6 +39,7 @@ export interface StoreCartCoupon {
export interface StoreCart {
cartCoupons: CartResponseCoupons;
cartItems: Array< CartResponseItem >;
+ crossSellsProducts: Array< ProductResponseItem >;
cartFees: Array< CartResponseFeeItem >;
cartItemsCount: number;
cartItemsWeight: number;
diff --git a/docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md b/docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md
index 29c2b43646d..c1c48bdb0ab 100644
--- a/docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md
+++ b/docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md
@@ -35,6 +35,16 @@ The majority of our feature flagging is blocks, this is a list of them:
### Experimental flag
+- Cart block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/index.js#L44) | [PHP flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/961c0c476d4228a218859c658c42f9b6eebfdec4/src/BlockTypesController.php#L182)).
+- Cart Express Checkout block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/inner-blocks/cart-express-payment-block/index.tsx#L13)).
+- Cart Items block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/inner-blocks/cart-items-block/index.tsx#L13)).
+- Cart Line Items block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/inner-blocks/cart-line-items-block/index.tsx#L13)).
+- Cart Order Summary block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/inner-blocks/cart-order-summary-block/index.tsx#L14)).
+- Cart Totals block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/inner-blocks/cart-totals-block/index.tsx#L13)).
+- Cross-Sells block ([JS flag](https://github.com/woocommerce/woocommerce-blocks/blob/84950e6188c451d522a7ce614f77272362575d37/assets/js/blocks/cart/inner-blocks/cart-cross-sells-block/index.tsx#L13) | [JS flag](https://github.com/woocommerce/woocommerce-blocks/blob/84950e6188c451d522a7ce614f77272362575d37/assets/js/blocks/cart/inner-blocks/cart-items-block/edit.tsx#L26-L28))
+- Empty Cart block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/inner-blocks/empty-cart-block/index.tsx#L13)).
+- Filled Cart block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/inner-blocks/filled-cart-block/index.tsx#L13)).
+- Cart Proceed to checkout block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8516e87bddee6c07a080c934f3d8cc0683adef06/assets/js/blocks/cart-checkout/cart-i2/inner-blocks/proceed-to-checkout-block/index.tsx#L14)).
- Single Product block ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/9b76ea7a1680e68cc20bfee01078e43ccfc996bd/assets/js/blocks/single-product/index.js#L43) | [PHP flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/4a1ee97eb97011458174e93e44a9b7ad2f10ca36/src/BlockTypesController.php#L181) | [webpack flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/341be1f56071fbd4b5ff975e8788d65a09512df2/bin/webpack-entries.js#L57-L59)).
- ⚛️ Add to cart ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b3a9753d8b7dae18b36025d09fbff835b8365de0/assets/js/atomic/blocks/product-elements/add-to-cart/index.js#L29-L32)).
- ⚛️ Product category list ([JS flag](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/b3a9753d8b7dae18b36025d09fbff835b8365de0/assets/js/atomic/blocks/product-elements/category-list/index.js#L29-L32)).
@@ -126,4 +136,3 @@ Current list of events:
🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce-blocks/issues/new?assignees=&labels=type%3A+documentation&template=--doc-feedback.md&title=Feedback%20on%20./docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md)
-
diff --git a/docs/third-party-developers/extensibility/rest-api/available-endpoints-to-extend.md b/docs/third-party-developers/extensibility/rest-api/available-endpoints-to-extend.md
index 87069fb56e4..597f8e2808d 100644
--- a/docs/third-party-developers/extensibility/rest-api/available-endpoints-to-extend.md
+++ b/docs/third-party-developers/extensibility/rest-api/available-endpoints-to-extend.md
@@ -2,18 +2,18 @@
## Table of Contents
-- [`wc/store/checkout`](#wcstorecheckout)
- - [Passed Parameters](#passed-parameters)
- - [Key](#key)
-- [`wc/store/cart`](#wcstorecart)
- - [Passed Parameters](#passed-parameters-1)
- - [Key](#key-1)
-- [`wc/store/cart/items`](#wcstorecartitems)
- - [Passed Parameters](#passed-parameters-2)
- - [Key](#key-2)
-- [`wc/store/products`](#wcstoreproducts)
- - [Passed Parameters](#passed-parameters-3)
- - [Key](#key-3)
+- [`wc/store/checkout`](#wcstorecheckout)
+ - [Passed Parameters](#passed-parameters)
+ - [Key](#key)
+- [`wc/store/cart`](#wcstorecart)
+ - [Passed Parameters](#passed-parameters-1)
+ - [Key](#key-1)
+- [`wc/store/cart/items`](#wcstorecartitems)
+ - [Passed Parameters](#passed-parameters-2)
+ - [Key](#key-2)
+- [`wc/store/products`](#wcstoreproducts)
+ - [Passed Parameters](#passed-parameters-3)
+ - [Key](#key-3)
To see how to add your data to Store API using ExtendSchema, [check this document](./extend-rest-api-add-data.md). This is a list of available endpoints that you can extend. If you want to add a new endpoint, [check this document](./extend-rest-api-new-endpoint.md).
@@ -78,4 +78,3 @@ The main products endpoint is extensible via ExtendSchema. The data is available
🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce-blocks/issues/new?assignees=&labels=type%3A+documentation&template=--doc-feedback.md&title=Feedback%20on%20./docs/third-party-developers/extensibility/rest-api/available-endpoints-to-extend.md)
-
diff --git a/images/previews/beanie.jpg b/images/previews/beanie.jpg
index 09fb0606639..b725e78afde 100644
Binary files a/images/previews/beanie.jpg and b/images/previews/beanie.jpg differ
diff --git a/images/previews/collection.jpg b/images/previews/collection.jpg
index 9b2051cf510..890f6c5e340 100644
Binary files a/images/previews/collection.jpg and b/images/previews/collection.jpg differ
diff --git a/images/previews/hoodie-with-logo.jpg b/images/previews/hoodie-with-logo.jpg
new file mode 100644
index 00000000000..9609e3bf856
Binary files /dev/null and b/images/previews/hoodie-with-logo.jpg differ
diff --git a/images/previews/hoodie-with-pocket.jpg b/images/previews/hoodie-with-pocket.jpg
new file mode 100644
index 00000000000..72c3272d0cb
Binary files /dev/null and b/images/previews/hoodie-with-pocket.jpg differ
diff --git a/images/previews/hoodie-with-zipper.jpg b/images/previews/hoodie-with-zipper.jpg
new file mode 100644
index 00000000000..f9b27c9fd35
Binary files /dev/null and b/images/previews/hoodie-with-zipper.jpg differ
diff --git a/images/previews/long-sleeve-tee.jpg b/images/previews/long-sleeve-tee.jpg
new file mode 100644
index 00000000000..64c7d9d9e69
Binary files /dev/null and b/images/previews/long-sleeve-tee.jpg differ
diff --git a/images/previews/pennant.jpg b/images/previews/pennant.jpg
index b2093423750..61f64b7cda8 100644
Binary files a/images/previews/pennant.jpg and b/images/previews/pennant.jpg differ
diff --git a/images/previews/polo.jpg b/images/previews/polo.jpg
new file mode 100644
index 00000000000..6766cc216c7
Binary files /dev/null and b/images/previews/polo.jpg differ
diff --git a/images/previews/tshirt.jpg b/images/previews/tshirt.jpg
new file mode 100644
index 00000000000..d775d53efd3
Binary files /dev/null and b/images/previews/tshirt.jpg differ
diff --git a/packages/checkout/blocks-registry/types.ts b/packages/checkout/blocks-registry/types.ts
index 7bbcbbdb7ee..f752f2910bc 100644
--- a/packages/checkout/blocks-registry/types.ts
+++ b/packages/checkout/blocks-registry/types.ts
@@ -18,6 +18,7 @@ export enum innerBlockAreas {
EMPTY_CART = 'woocommerce/empty-cart-block',
FILLED_CART = 'woocommerce/filled-cart-block',
CART_ITEMS = 'woocommerce/cart-items-block',
+ CART_CROSS_SELLS = 'woocommerce/cart-cross-sells-block',
CART_TOTALS = 'woocommerce/cart-totals-block',
MINI_CART = 'woocommerce/mini-cart-contents',
EMPTY_MINI_CART = 'woocommerce/empty-mini-cart-contents-block',
diff --git a/storybook/__mocks__/woocommerce-base-hooks.js b/storybook/__mocks__/woocommerce-base-hooks.js
index 52ddc9fdfce..54b0a037de9 100644
--- a/storybook/__mocks__/woocommerce-base-hooks.js
+++ b/storybook/__mocks__/woocommerce-base-hooks.js
@@ -19,6 +19,7 @@ export const useStoreCart = () => ( {
cartIsLoading: false,
cartErrors: [],
cartFees: [],
+ crossSellsProducts: previewCart.cross_sells,
billingAddress: {},
shippingAddress: {},
shippingRates: previewShippingRates,