asset_api = $asset_api;
$this->asset_data_registry = $asset_data_registry;
$this->init();
}
/**
* Initialize class features.
*/
protected function init() { // phpcs:ignore WooCommerce.Functions.InternalInjectionMethod.MissingPublic
add_action( 'init', array( $this, 'register_blocks' ) );
add_action( 'wp_loaded', array( $this, 'register_block_patterns' ) );
add_filter( 'block_categories_all', array( $this, 'register_block_categories' ), 10, 2 );
add_filter( 'render_block', array( $this, 'add_data_attributes' ), 10, 2 );
add_action( 'woocommerce_login_form_end', array( $this, 'redirect_to_field' ) );
add_filter( 'widget_types_to_hide_from_legacy_widget_block', array( $this, 'hide_legacy_widgets_with_block_equivalent' ) );
add_action( 'woocommerce_delete_product_transients', array( $this, 'delete_product_transients' ) );
add_filter( 'register_block_type_args', array( $this, 'enqueue_block_style_for_classic_themes' ), 10, 2 );
add_filter( 'block_core_breadcrumbs_post_type_settings', array( $this, 'set_product_breadcrumbs_preferred_taxonomy' ), 10, 3 );
}
/**
* Get registered blocks that have WooCommerce blocks as their parents. Adds the value to the
* `registered_blocks_with_woocommerce_parents` cache if `init` has been fired.
*
* @return array Registered blocks with WooCommerce blocks as parents.
*/
public function get_registered_blocks_with_woocommerce_parent() {
// If init has run and the cache is already set, return it.
if ( did_action( 'init' ) && ! empty( $this->registered_blocks_with_woocommerce_parents ) ) {
return $this->registered_blocks_with_woocommerce_parents;
}
$registered_blocks = \WP_Block_Type_Registry::get_instance()->get_all_registered();
if ( ! is_array( $registered_blocks ) ) {
return array();
}
$this->registered_blocks_with_woocommerce_parents = array_filter(
$registered_blocks,
function ( $block ) {
if ( empty( $block->parent ) ) {
return false;
}
if ( ! is_array( $block->parent ) ) {
$block->parent = array( $block->parent );
}
$woocommerce_blocks = array_filter(
$block->parent,
function ( $parent_block_name ) {
return 'woocommerce' === strtok( $parent_block_name, '/' );
}
);
return ! empty( $woocommerce_blocks );
}
);
return $this->registered_blocks_with_woocommerce_parents;
}
/**
* Register blocks, hooking up assets and render functions as needed.
*/
public function register_blocks() {
$this->register_block_metadata();
$block_types = $this->get_block_types();
foreach ( $block_types as $block_type ) {
$block_type_class = __NAMESPACE__ . '\\BlockTypes\\' . $block_type;
new $block_type_class( $this->asset_api, $this->asset_data_registry, new IntegrationRegistry() );
}
}
/**
* Register block metadata collections for WooCommerce blocks.
*
* This method handles the registration of block metadata by using WordPress's block metadata
* collection registration system. It includes a temporary workaround for WordPress 6.7's
* strict path validation that might fail for sites using symlinked plugins.
*
* If the registration fails due to path validation, blocks will fall back to regular
* registration without affecting functionality.
*/
public function register_block_metadata() {
$meta_file_path = WC_ABSPATH . 'assets/client/blocks/blocks-json.php';
if ( function_exists( 'wp_register_block_metadata_collection' ) && file_exists( $meta_file_path ) ) {
add_filter( 'doing_it_wrong_trigger_error', array( __CLASS__, 'bypass_block_metadata_doing_it_wrong' ), 10, 4 );
wp_register_block_metadata_collection(
WC_ABSPATH . 'assets/client/blocks/',
$meta_file_path
);
remove_filter( 'doing_it_wrong_trigger_error', array( __CLASS__, 'bypass_block_metadata_doing_it_wrong' ), 10 );
}
}
/**
* Temporarily bypasses _doing_it_wrong() notices for block metadata collection registration.
*
* WordPress 6.7 introduced block metadata collections (with strict path validation).
* Any sites using symlinks for plugins will fail the validation which causes the metadata
* collection to not be registered. However, the blocks will still fall back to the regular
* registration and no functionality is affected.
* While this validation is being discussed in WordPress Core (#62140),
* this method allows registration to proceed by temporarily disabling
* the relevant notice.
*
* @param bool $trigger Whether to trigger the error.
* @param string $function The function that was called.
* @param string $message A message explaining what was done incorrectly.
* @param string $version The version of WordPress where the message was added.
* @return bool Whether to trigger the error.
*/
public static function bypass_block_metadata_doing_it_wrong( $trigger, $function, $message, $version ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable,Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed,Universal.NamingConventions.NoReservedKeywordParameterNames.functionFound
if ( 'WP_Block_Metadata_Registry::register_collection' === $function ) {
return false;
}
return $trigger;
}
/**
* Register block patterns
*/
public function register_block_patterns() {
register_block_pattern(
'woocommerce/order-confirmation-totals-heading',
array(
'title' => '',
'inserter' => false,
'content' => '