Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection

HandlerRegistry::register_core_collections()publicWC 1.0

Register core collection handlers.

Method of the class: HandlerRegistry{}

No Hooks.

Return

null. Nothing (null).

Usage

$HandlerRegistry = new HandlerRegistry();
$HandlerRegistry->register_core_collections();

HandlerRegistry::register_core_collections() code WC 9.6.0

public function register_core_collections() {
	$this->register_collection_handlers(
		'woocommerce/product-collection/hand-picked',
		function ( $collection_args, $common_query_values, $query ) {
			// For Hand-Picked collection, if no products are selected, we should return an empty result set.
			// This ensures that the collection doesn't display any products until the user explicitly chooses them.
			if ( empty( $query['handpicked_products'] ) ) {
				return array(
					'post__in' => array( -1 ),
				);
			}
		}
	);

	$this->register_collection_handlers(
		'woocommerce/product-collection/related',
		function ( $collection_args ) {
			// No products should be shown if no related product reference is set.
			if ( empty( $collection_args['relatedProductReference'] ) ) {
				return array(
					'post__in' => array( -1 ),
				);
			}

			$category_callback = function () use ( $collection_args ) {
				return $collection_args['relatedBy']['categories'];
			};

			$tag_callback = function () use ( $collection_args ) {
				return $collection_args['relatedBy']['tags'];
			};

			add_filter( 'woocommerce_product_related_posts_relate_by_category', $category_callback, PHP_INT_MAX );
			add_filter( 'woocommerce_product_related_posts_relate_by_tag', $tag_callback, PHP_INT_MAX );

			$related_products = wc_get_related_products(
				$collection_args['relatedProductReference'],
				// Use a higher limit so that the result set contains enough products for the collection to subsequently filter.
				100
			);

			remove_filter( 'woocommerce_product_related_posts_relate_by_category', $category_callback, PHP_INT_MAX );
			remove_filter( 'woocommerce_product_related_posts_relate_by_tag', $tag_callback, PHP_INT_MAX );

			if ( empty( $related_products ) ) {
				return array(
					'post__in' => array( -1 ),
				);
			}

			// Have it filter the results to products related to the one provided.
			return array(
				'post__in' => $related_products,
			);
		},
		function ( $collection_args, $query ) {
			$product_reference = $query['productReference'] ?? null;
			// Infer the product reference from the location if an explicit product is not set.
			if ( empty( $product_reference ) ) {
				$location = $collection_args['productCollectionLocation'];
				if ( isset( $location['type'] ) && 'product' === $location['type'] ) {
					$product_reference = $location['sourceData']['productId'];
				}
			}

			$collection_args['relatedProductReference'] = $product_reference;
			$collection_args['relatedBy']               = array(
				'categories' => isset( $query['relatedBy']['categories'] ) && true === $query['relatedBy']['categories'],
				'tags'       => isset( $query['relatedBy']['tags'] ) && true === $query['relatedBy']['tags'],
			);

			return $collection_args;
		},
		function ( $collection_args, $query, $request ) {
			$product_reference = $request->get_param( 'productReference' );
			// In some cases the editor will send along block location context that we can infer the product reference from.
			if ( empty( $product_reference ) ) {
				$location = $collection_args['productCollectionLocation'];
				if ( isset( $location['type'] ) && 'product' === $location['type'] ) {
					$product_reference = $location['sourceData']['productId'];
				}
			}

			$collection_args['relatedProductReference'] = $product_reference;

			$collection_args['relatedBy'] = array(
				'categories' => rest_sanitize_boolean( $request->get_param( 'relatedBy' )['categories'] ?? false ),
				'tags'       => rest_sanitize_boolean( $request->get_param( 'relatedBy' )['tags'] ?? false ),
			);

			return $collection_args;
		}
	);

	$this->register_collection_handlers(
		'woocommerce/product-collection/upsells',
		function ( $collection_args ) {
			$product_reference = $collection_args['upsellsProductReferences'] ?? null;
			// No products should be shown if no upsells product reference is set.
			if ( empty( $product_reference ) ) {
				return array(
					'post__in' => array( -1 ),
				);
			}

			$products = array_map( 'wc_get_product', $product_reference );

			if ( empty( $products ) ) {
				return array(
					'post__in' => array( -1 ),
				);
			}

			$all_upsells = array_reduce(
				$products,
				function ( $acc, $product ) {
					return array_merge(
						$acc,
						$product->get_upsell_ids()
					);
				},
				array()
			);

			// Remove duplicates and product references. We don't want to display
			// what's already in cart.
			$unique_upsells = array_unique( $all_upsells );
			$upsells        = array_diff( $unique_upsells, $product_reference );

			return array(
				'post__in' => empty( $upsells ) ? array( -1 ) : $upsells,
			);
		},
		function ( $collection_args, $query ) {
			$product_references = isset( $query['productReference'] ) ? array( $query['productReference'] ) : null;
			// Infer the product reference from the location if an explicit product is not set.
			if ( empty( $product_references ) ) {
				$location = $collection_args['productCollectionLocation'];
				if ( isset( $location['type'] ) && 'product' === $location['type'] ) {
					$product_references = array( $location['sourceData']['productId'] );
				}

				if ( isset( $location['type'] ) && 'cart' === $location['type'] ) {
					$product_references = $location['sourceData']['productIds'];
				}

				if ( isset( $location['type'] ) && 'order' === $location['type'] ) {
					$product_references = $this->get_product_ids_from_order( $location['sourceData']['orderId'] ?? 0 );
				}
			}

			$collection_args['upsellsProductReferences'] = $product_references;
			return $collection_args;
		},
		function ( $collection_args, $query, $request ) {
			$product_reference = $request->get_param( 'productReference' );
			// In some cases the editor will send along block location context that we can infer the product reference from.
			if ( empty( $product_reference ) ) {
				$location = $collection_args['productCollectionLocation'];
				if ( isset( $location['type'] ) && 'product' === $location['type'] ) {
					$product_reference = $location['sourceData']['productId'];
				}
			}

			$collection_args['upsellsProductReferences'] = array( $product_reference );
			return $collection_args;
		}
	);

	$this->register_collection_handlers(
		'woocommerce/product-collection/cross-sells',
		function ( $collection_args ) {
			$product_reference = $collection_args['crossSellsProductReferences'] ?? null;
			// No products should be shown if no cross-sells product reference is set.
			if ( empty( $product_reference ) ) {
				return array(
					'post__in' => array( -1 ),
				);
			}

			$products = array_filter( array_map( 'wc_get_product', $product_reference ) );

			if ( empty( $products ) ) {
				return array(
					'post__in' => array( -1 ),
				);
			}

			$product_ids = array_map(
				function ( $product ) {
					return $product->get_id();
				},
				$products
			);

			$all_cross_sells = array_reduce(
				$products,
				function ( $acc, $product ) {
					return array_merge(
						$acc,
						$product->get_cross_sell_ids()
					);
				},
				array()
			);

			// Remove duplicates and product references. We don't want to display
			// what's already in cart.
			$unique_cross_sells = array_unique( $all_cross_sells );
			$cross_sells        = array_diff( $unique_cross_sells, $product_ids );

			return array(
				'post__in' => empty( $cross_sells ) ? array( -1 ) : $cross_sells,
			);
		},
		function ( $collection_args, $query ) {
			$product_references = isset( $query['productReference'] ) ? array( $query['productReference'] ) : null;
			// Infer the product reference from the location if an explicit product is not set.
			if ( empty( $product_references ) ) {
				$location = $collection_args['productCollectionLocation'];
				if ( isset( $location['type'] ) && 'product' === $location['type'] ) {
					$product_references = array( $location['sourceData']['productId'] );
				}

				if ( isset( $location['type'] ) && 'cart' === $location['type'] ) {
					$product_references = $location['sourceData']['productIds'];
				}

				if ( isset( $location['type'] ) && 'order' === $location['type'] ) {
					$product_references = $this->get_product_ids_from_order( $location['sourceData']['orderId'] ?? 0 );
				}
			}

			$collection_args['crossSellsProductReferences'] = $product_references;
			return $collection_args;
		},
		function ( $collection_args, $query, $request ) {
			$product_reference = $request->get_param( 'productReference' );
			// In some cases the editor will send along block location context that we can infer the product reference from.
			if ( empty( $product_reference ) ) {
				$location = $collection_args['productCollectionLocation'];
				if ( isset( $location['type'] ) && 'product' === $location['type'] ) {
					$product_reference = $location['sourceData']['productId'];
				}
			}

			$collection_args['crossSellsProductReferences'] = array( $product_reference );
			return $collection_args;
		}
	);
	return $this->collection_handler_store;
}