ProductImageGallery', 'ProductMeta', 'ProductNew', 'ProductOnSale', 'ProductPrice', 'ProductTemplate', 'ProductQuery', 'ProductAverageRating', 'ProductRating', 'ProductRatingCounter', 'ProductRatingStars', 'ProductResultsCount', 'ProductSaleBadge', 'ProductSearch', 'ProductSKU', 'ProductStockIndicator', 'ProductSummary', 'ProductTag', 'ProductTitle', 'ProductTopRated', 'ProductsByAttribute', 'RatingFilter', 'ReviewsByCategory', 'ReviewsByProduct', 'RelatedProducts', 'SingleProduct', 'StockFilter', 'PageContentWrapper', 'OrderConfirmation\Status', 'OrderConfirmation\Summary', 'OrderConfirmation\Totals', 'OrderConfirmation\TotalsWrapper', 'OrderConfirmation\Downloads', 'OrderConfirmation\DownloadsWrapper', 'OrderConfirmation\BillingAddress', 'OrderConfirmation\ShippingAddress', 'OrderConfirmation\BillingWrapper', 'OrderConfirmation\ShippingWrapper', 'OrderConfirmation\AdditionalInformation', 'OrderConfirmation\AdditionalFieldsWrapper', 'OrderConfirmation\AdditionalFields', 'OrderConfirmation\CreateAccount', 'ProductDetails', 'ProductDescription', 'ProductSpecifications', // Generic blocks that will be pushed upstream. 'Accordion\AccordionGroup', 'Accordion\AccordionItem', 'Accordion\AccordionPanel', 'Accordion\AccordionHeader', // End: generic blocks that will be pushed upstream. 'Reviews\ProductReviews', 'Reviews\ProductReviewRating', 'Reviews\ProductReviewsTitle', 'Reviews\ProductReviewForm', 'Reviews\ProductReviewDate', 'Reviews\ProductReviewContent', 'Reviews\ProductReviewAuthorName', 'Reviews\ProductReviewsPagination', 'Reviews\ProductReviewsPaginationNext', 'Reviews\ProductReviewsPaginationPrevious', 'Reviews\ProductReviewsPaginationNumbers', 'Reviews\ProductReviewTemplate', ); $block_types = array_merge( $block_types, Cart::get_cart_block_types(), Checkout::get_checkout_block_types(), MiniCartContents::get_mini_cart_block_types() ); if ( wp_is_block_theme() ) { $block_types[] = 'AddToCartWithOptions\AddToCartWithOptions'; $block_types[] = 'AddToCartWithOptions\QuantitySelector'; $block_types[] = 'AddToCartWithOptions\VariationDescription'; $block_types[] = 'AddToCartWithOptions\VariationSelector'; $block_types[] = 'AddToCartWithOptions\VariationSelectorAttribute'; $block_types[] = 'AddToCartWithOptions\VariationSelectorAttributeName'; $block_types[] = 'AddToCartWithOptions\VariationSelectorAttributeOptions'; $block_types[] = 'AddToCartWithOptions\GroupedProductSelector'; $block_types[] = 'AddToCartWithOptions\GroupedProductItem'; $block_types[] = 'AddToCartWithOptions\GroupedProductItemSelector'; $block_types[] = 'AddToCartWithOptions\GroupedProductItemLabel'; } /** * This enables specific blocks in Widget Areas using an opt-in approach. */ if ( in_array( $pagenow, array( 'widgets.php', 'themes.php', 'customize.php' ), true ) && ( empty( $_GET['page'] ) || 'gutenberg-edit-site' !== $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification $block_types = array_intersect( $block_types, $this->get_widget_area_block_types() ); } /** * This disables specific blocks in Post and Page editor by not registering them. */ if ( in_array( $pagenow, array( 'post.php', 'post-new.php' ), true ) ) { $block_types = array_diff( $block_types, array( 'Breadcrumbs', 'CatalogSorting', 'ClassicTemplate', 'ProductResultsCount', 'ProductReviews', 'OrderConfirmation\Status', 'OrderConfirmation\Summary', 'OrderConfirmation\Totals', 'OrderConfirmation\TotalsWrapper', 'OrderConfirmation\Downloads', 'OrderConfirmation\DownloadsWrapper', 'OrderConfirmation\BillingAddress', 'OrderConfirmation\ShippingAddress', 'OrderConfirmation\BillingWrapper', 'OrderConfirmation\ShippingWrapper', 'OrderConfirmation\AdditionalInformation', 'OrderConfirmation\AdditionalFieldsWrapper', 'OrderConfirmation\AdditionalFields', ) ); } /** * Filters the list of allowed block types. * * @since 9.0.0 * * @param array $block_types List of block types. */ return apply_filters( 'woocommerce_get_block_types', $block_types ); } /** * By default, when the classic theme is used, block style is always * enqueued even if the block is not used on the page. We want WooCommerce * store to always performant so we have to manually enqueue the block style * on-demand for classic themes. * * @internal * * @param array $args Block metadata. * @param string $block_name Block name. * * @return array Block metadata. */ public function enqueue_block_style_for_classic_themes( $args, $block_name ) { // Repeatedly checking the theme is expensive. So statically cache this logic result and remove the filter if not needed. static $should_enqueue_block_style_for_classic_themes = null; if ( null === $should_enqueue_block_style_for_classic_themes ) { $should_enqueue_block_style_for_classic_themes = ! ( is_admin() || wp_is_block_theme() || ( function_exists( 'wp_should_load_block_assets_on_demand' ) && wp_should_load_block_assets_on_demand() ) || wp_should_load_separate_core_block_assets() ); } if ( ! $should_enqueue_block_style_for_classic_themes ) { remove_filter( 'register_block_type_args', array( $this, 'enqueue_block_style_for_classic_themes' ), 10 ); return $args; } if ( false === strpos( $block_name, 'woocommerce/' ) || ( empty( $args['style_handles'] ) && empty( $args['style'] ) ) ) { return $args; } $style_handlers = $args['style_handles'] ?? $args['style']; add_filter( 'render_block_' . $block_name, static function ( $html ) use ( $style_handlers ) { array_map( 'wp_enqueue_style', $style_handlers ); return $html; }, 10 ); $args['style_handles'] = array(); $args['style'] = array(); return $args; } /** * Set the preferred taxonomy and term for the breadcrumbs block on the product post type. * * This method mimics the behavior of WC_Breadcrumb::add_crumbs_single() to ensure * consistent breadcrumb term selection between WooCommerce's legacy breadcrumbs * and the Core breadcrumbs block. * * @param array $settings The settings for the breadcrumbs block. * @param string $post_type The post type. * @param int $post_id The current post ID. * @return array The settings for the breadcrumbs block. * * @internal */ public function set_product_breadcrumbs_preferred_taxonomy( $settings, $post_type, $post_id = 0 ) { if ( ! is_array( $settings ) || 'product' !== $post_type ) { return $settings; } $settings['taxonomy'] = 'product_cat'; // If we have a post ID, determine the specific term using WooCommerce's logic. if ( ! empty( $post_id ) ) { $terms = wc_get_product_terms( $post_id, 'product_cat', /** * Filters the arguments used to fetch product terms for breadcrumbs. * * @since 9.5.0 * * @param array $args Array of arguments for `wc_get_product_terms()`. */ apply_filters( 'woocommerce_breadcrumb_product_terms_args', array( 'orderby' => 'parent', 'order' => 'DESC', ) ) ); if ( ! empty( $terms ) && ! is_wp_error( $terms ) ) { /** * Filters the main term used in product breadcrumbs. * * @since 9.5.0 * * @param \WP_Term $main_term The main term to be used in breadcrumbs. * @param \WP_Term[] $terms Array of all product category terms. */ $main_term = apply_filters( 'woocommerce_breadcrumb_main_term', $terms[0], $terms ); if ( $main_term instanceof \WP_Term ) { $settings['term'] = $main_term->slug; } } } return $settings; } /** * Apply WooCommerce breadcrumb filters to Core breadcrumbs block items. * * This bridges the Core breadcrumbs block with WooCommerce's legacy breadcrumb filters, * ensuring backward compatibility for sites that have customized breadcrumbs using * the `woocommerce_get_breadcrumb` filter. * * @param array $items Array of breadcrumb items from Core. * @return array Modified breadcrumb items. * * @internal */ public function apply_woocommerce_breadcrumb_filters( $items ) { // Convert Core format to WooCommerce format. // Core: array( 'url' => '...', 'label' => '...' ) // Woo: array( 'label', 'url' ). $wc_crumbs = array_map( function ( $item ) { return array( $item['label'] ?? '', $item['url'] ?? '', ); }, $items ); /** * Filters the breadcrumb trail array. * * @since 2.3.0 * * @param array $crumbs The breadcrumb trail. * @param \WC_Breadcrumb|null $breadcrumb The breadcrumb object (null when called from Core block). */ $wc_crumbs = apply_filters( 'woocommerce_get_breadcrumb', $wc_crumbs, null ); // Convert back to Core format. return array_map( function ( $crumb ) { return array( 'label' => $crumb[0] ?? '', 'url' => $crumb[1] ?? '', ); }, $wc_crumbs ); } }