PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 9.8.6
WooCommerce v9.8.6
10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / src / Blocks / BlockTypesController.php
woocommerce / src / Blocks Last commit date
AI 1 year ago AIContent 1 year ago Assets 1 year ago BlockTypes 1 year ago Domain 1 year ago Images 2 years ago Integrations 2 years ago Interactivity 1 year ago Patterns 1 year ago Payments 1 year ago Registry 2 years ago Shipping 1 year ago Templates 1 year ago Utils 1 year ago Assets.php 2 years ago AssetsController.php 1 year ago BlockPatterns.php 1 year ago BlockTemplatesController.php 1 year ago BlockTemplatesRegistry.php 1 year ago BlockTypesController.php 1 year ago InboxNotifications.php 2 years ago Installer.php 1 year ago Library.php 2 years ago Migration.php 2 years ago Options.php 2 years ago Package.php 1 year ago QueryFilters.php 1 year ago TemplateOptions.php 1 year ago
BlockTypesController.php
581 lines
1 <?php
2 declare(strict_types=1);
3
4 namespace Automattic\WooCommerce\Blocks;
5
6 use Automattic\WooCommerce\Admin\Features\Features;
7 use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;
8 use Automattic\WooCommerce\Blocks\Assets\Api as AssetApi;
9 use Automattic\WooCommerce\Blocks\Integrations\IntegrationRegistry;
10 use Automattic\WooCommerce\Blocks\BlockTypes\Cart;
11 use Automattic\WooCommerce\Blocks\BlockTypes\Checkout;
12 use Automattic\WooCommerce\Blocks\BlockTypes\MiniCartContents;
13
14 /**
15 * BlockTypesController class.
16 *
17 * @since 5.0.0
18 * @internal
19 */
20 final class BlockTypesController {
21
22 /**
23 * Instance of the asset API.
24 *
25 * @var AssetApi
26 */
27 protected $asset_api;
28
29 /**
30 * Instance of the asset data registry.
31 *
32 * @var AssetDataRegistry
33 */
34 protected $asset_data_registry;
35
36 /**
37 * Holds the registered blocks that have WooCommerce blocks as their parents.
38 *
39 * @var array List of registered blocks.
40 */
41 private $registered_blocks_with_woocommerce_parents;
42
43 /**
44 * Constructor.
45 *
46 * @param AssetApi $asset_api Instance of the asset API.
47 * @param AssetDataRegistry $asset_data_registry Instance of the asset data registry.
48 */
49 public function __construct( AssetApi $asset_api, AssetDataRegistry $asset_data_registry ) {
50 $this->asset_api = $asset_api;
51 $this->asset_data_registry = $asset_data_registry;
52 $this->init();
53 }
54
55 /**
56 * Initialize class features.
57 */
58 protected function init() { // phpcs:ignore WooCommerce.Functions.InternalInjectionMethod.MissingPublic
59 add_action( 'init', array( $this, 'register_blocks' ) );
60 add_action( 'wp_loaded', array( $this, 'register_block_patterns' ) );
61 add_filter( 'block_categories_all', array( $this, 'register_block_categories' ), 10, 2 );
62 add_filter( 'render_block', array( $this, 'add_data_attributes' ), 10, 2 );
63 add_action( 'woocommerce_login_form_end', array( $this, 'redirect_to_field' ) );
64 add_filter( 'widget_types_to_hide_from_legacy_widget_block', array( $this, 'hide_legacy_widgets_with_block_equivalent' ) );
65 add_action( 'woocommerce_delete_product_transients', array( $this, 'delete_product_transients' ) );
66 }
67
68 /**
69 * Get registered blocks that have WooCommerce blocks as their parents. Adds the value to the
70 * `registered_blocks_with_woocommerce_parents` cache if `init` has been fired.
71 *
72 * @return array Registered blocks with WooCommerce blocks as parents.
73 */
74 public function get_registered_blocks_with_woocommerce_parent() {
75 // If init has run and the cache is already set, return it.
76 if ( did_action( 'init' ) && ! empty( $this->registered_blocks_with_woocommerce_parents ) ) {
77 return $this->registered_blocks_with_woocommerce_parents;
78 }
79
80 $registered_blocks = \WP_Block_Type_Registry::get_instance()->get_all_registered();
81
82 if ( ! is_array( $registered_blocks ) ) {
83 return array();
84 }
85
86 $this->registered_blocks_with_woocommerce_parents = array_filter(
87 $registered_blocks,
88 function ( $block ) {
89 if ( empty( $block->parent ) ) {
90 return false;
91 }
92 if ( ! is_array( $block->parent ) ) {
93 $block->parent = array( $block->parent );
94 }
95 $woocommerce_blocks = array_filter(
96 $block->parent,
97 function ( $parent_block_name ) {
98 return 'woocommerce' === strtok( $parent_block_name, '/' );
99 }
100 );
101 return ! empty( $woocommerce_blocks );
102 }
103 );
104 return $this->registered_blocks_with_woocommerce_parents;
105 }
106
107 /**
108 * Register blocks, hooking up assets and render functions as needed.
109 */
110 public function register_blocks() {
111 $this->register_block_metadata();
112 $block_types = $this->get_block_types();
113
114 foreach ( $block_types as $block_type ) {
115 $block_type_class = __NAMESPACE__ . '\\BlockTypes\\' . $block_type;
116
117 new $block_type_class( $this->asset_api, $this->asset_data_registry, new IntegrationRegistry() );
118 }
119 }
120
121 /**
122 * Register block metadata collections for WooCommerce blocks.
123 *
124 * This method handles the registration of block metadata by using WordPress's block metadata
125 * collection registration system. It includes a temporary workaround for WordPress 6.7's
126 * strict path validation that might fail for sites using symlinked plugins.
127 *
128 * If the registration fails due to path validation, blocks will fall back to regular
129 * registration without affecting functionality.
130 */
131 public function register_block_metadata() {
132 $meta_file_path = WC_ABSPATH . 'assets/client/blocks/blocks-json.php';
133 if ( function_exists( 'wp_register_block_metadata_collection' ) && file_exists( $meta_file_path ) ) {
134 add_filter( 'doing_it_wrong_trigger_error', array( __CLASS__, 'bypass_block_metadata_doing_it_wrong' ), 10, 4 );
135 wp_register_block_metadata_collection(
136 WC_ABSPATH . 'assets/client/blocks/',
137 $meta_file_path
138 );
139 remove_filter( 'doing_it_wrong_trigger_error', array( __CLASS__, 'bypass_block_metadata_doing_it_wrong' ), 10 );
140 }
141 }
142
143 /**
144 * Temporarily bypasses _doing_it_wrong() notices for block metadata collection registration.
145 *
146 * WordPress 6.7 introduced block metadata collections (with strict path validation).
147 * Any sites using symlinks for plugins will fail the validation which causes the metadata
148 * collection to not be registered. However, the blocks will still fall back to the regular
149 * registration and no functionality is affected.
150 * While this validation is being discussed in WordPress Core (#62140),
151 * this method allows registration to proceed by temporarily disabling
152 * the relevant notice.
153 *
154 * @param bool $trigger Whether to trigger the error.
155 * @param string $function The function that was called.
156 * @param string $message A message explaining what was done incorrectly.
157 * @param string $version The version of WordPress where the message was added.
158 * @return bool Whether to trigger the error.
159 */
160 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
161 if ( 'WP_Block_Metadata_Registry::register_collection' === $function ) {
162 return false;
163 }
164 return $trigger;
165 }
166
167 /**
168 * Register block patterns
169 */
170 public function register_block_patterns() {
171 register_block_pattern(
172 'woocommerce/order-confirmation-totals-heading',
173 array(
174 'title' => '',
175 'inserter' => false,
176 'content' => '<!-- wp:heading {"level":2,"style":{"typography":{"fontSize":"24px"}}} --><h2 class="wp-block-heading" style="font-size:24px">' . esc_html__( 'Order details', 'woocommerce' ) . '</h2><!-- /wp:heading -->',
177 )
178 );
179 register_block_pattern(
180 'woocommerce/order-confirmation-downloads-heading',
181 array(
182 'title' => '',
183 'inserter' => false,
184 'content' => '<!-- wp:heading {"level":2,"style":{"typography":{"fontSize":"24px"}}} --><h2 class="wp-block-heading" style="font-size:24px">' . esc_html__( 'Downloads', 'woocommerce' ) . '</h2><!-- /wp:heading -->',
185 )
186 );
187 register_block_pattern(
188 'woocommerce/order-confirmation-shipping-heading',
189 array(
190 'title' => '',
191 'inserter' => false,
192 'content' => '<!-- wp:heading {"level":2,"style":{"typography":{"fontSize":"24px"}}} --><h2 class="wp-block-heading" style="font-size:24px">' . esc_html__( 'Shipping address', 'woocommerce' ) . '</h2><!-- /wp:heading -->',
193 )
194 );
195 register_block_pattern(
196 'woocommerce/order-confirmation-billing-heading',
197 array(
198 'title' => '',
199 'inserter' => false,
200 'content' => '<!-- wp:heading {"level":2,"style":{"typography":{"fontSize":"24px"}}} --><h2 class="wp-block-heading" style="font-size:24px">' . esc_html__( 'Billing address', 'woocommerce' ) . '</h2><!-- /wp:heading -->',
201 )
202 );
203 register_block_pattern(
204 'woocommerce/order-confirmation-additional-fields-heading',
205 array(
206 'title' => '',
207 'inserter' => false,
208 'content' => '<!-- wp:heading {"level":2,"style":{"typography":{"fontSize":"24px"}}} --><h2 class="wp-block-heading" style="font-size:24px">' . esc_html__( 'Additional information', 'woocommerce' ) . '</h2><!-- /wp:heading -->',
209 )
210 );
211 }
212
213 /**
214 * Register block categories
215 *
216 * Used in combination with the `block_categories_all` filter, to append
217 * WooCommerce Blocks related categories to the Gutenberg editor.
218 *
219 * @param array $categories The array of already registered categories.
220 */
221 public function register_block_categories( $categories ) {
222 $woocommerce_block_categories = array(
223 array(
224 'slug' => 'woocommerce',
225 'title' => __( 'WooCommerce', 'woocommerce' ),
226 ),
227 array(
228 'slug' => 'woocommerce-product-elements',
229 'title' => __( 'WooCommerce Product Elements', 'woocommerce' ),
230 ),
231 );
232
233 return array_merge( $categories, $woocommerce_block_categories );
234 }
235
236 /**
237 * Check if a block should have data attributes appended on render. If it's in an allowed namespace, or the block
238 * has explicitly been added to the allowed block list, or if one of the block's parents is in the WooCommerce
239 * namespace it can have data attributes.
240 *
241 * @param string $block_name Name of the block to check.
242 *
243 * @return boolean
244 */
245 public function block_should_have_data_attributes( $block_name ) {
246 $block_namespace = strtok( $block_name ?? '', '/' );
247
248 /**
249 * Filters the list of allowed block namespaces.
250 *
251 * This hook defines which block namespaces should have block name and attribute `data-` attributes appended on render.
252 *
253 * @since 5.9.0
254 *
255 * @param array $allowed_namespaces List of namespaces.
256 */
257 $allowed_namespaces = array_merge( array( 'woocommerce', 'woocommerce-checkout' ), (array) apply_filters( '__experimental_woocommerce_blocks_add_data_attributes_to_namespace', array() ) );
258
259 /**
260 * Filters the list of allowed Block Names
261 *
262 * This hook defines which block names should have block name and attribute data- attributes appended on render.
263 *
264 * @since 5.9.0
265 *
266 * @param array $allowed_namespaces List of namespaces.
267 */
268 $allowed_blocks = (array) apply_filters( '__experimental_woocommerce_blocks_add_data_attributes_to_block', array() );
269
270 $blocks_with_woo_parents = $this->get_registered_blocks_with_woocommerce_parent();
271 $block_has_woo_parent = in_array( $block_name, array_keys( $blocks_with_woo_parents ), true );
272 $in_allowed_namespace_list = in_array( $block_namespace, $allowed_namespaces, true );
273 $in_allowed_block_list = in_array( $block_name, $allowed_blocks, true );
274
275 return $block_has_woo_parent || $in_allowed_block_list || $in_allowed_namespace_list;
276 }
277
278 /**
279 * Add data- attributes to blocks when rendered if the block is under the woocommerce/ namespace.
280 *
281 * @param string $content Block content.
282 * @param array $block Parsed block data.
283 * @return string
284 */
285 public function add_data_attributes( $content, $block ) {
286
287 $content = trim( $content );
288
289 if ( ! $this->block_should_have_data_attributes( $block['blockName'] ) ) {
290 return $content;
291 }
292
293 $attributes = (array) $block['attrs'];
294 $exclude_attributes = array( 'className', 'align' );
295
296 $processor = new \WP_HTML_Tag_Processor( $content );
297
298 if (
299 false === $processor->next_token() ||
300 'DIV' !== $processor->get_token_name() ||
301 $processor->is_tag_closer()
302 ) {
303 return $content;
304 }
305
306 foreach ( $attributes as $key => $value ) {
307 if ( ! is_string( $key ) || in_array( $key, $exclude_attributes, true ) ) {
308 continue;
309 }
310 if ( is_bool( $value ) ) {
311 $value = $value ? 'true' : 'false';
312 }
313 if ( ! is_scalar( $value ) ) {
314 $value = wp_json_encode( $value );
315 }
316
317 // For output consistency, we convert camelCase to kebab-case and output in lowercase.
318 $key = strtolower( preg_replace( '/(?<!^|\ )[A-Z]/', '-$0', $key ) );
319
320 $processor->set_attribute( "data-{$key}", $value );
321 }
322
323 // Set this last to prevent user-input from overriding it.
324 $processor->set_attribute( 'data-block-name', $block['blockName'] );
325 return $processor->get_updated_html();
326 }
327
328 /**
329 * Adds a redirect field to the login form so blocks can redirect users after login.
330 */
331 public function redirect_to_field() {
332 // phpcs:ignore WordPress.Security.NonceVerification
333 if ( empty( $_GET['redirect_to'] ) ) {
334 return;
335 }
336 echo '<input type="hidden" name="redirect" value="' . esc_attr( esc_url_raw( wp_unslash( $_GET['redirect_to'] ) ) ) . '" />'; // phpcs:ignore WordPress.Security.NonceVerification
337 }
338
339 /**
340 * Hide legacy widgets with a feature complete block equivalent in the inserter
341 * and prevent them from showing as an option in the Legacy Widget block.
342 *
343 * @param array $widget_types An array of widgets hidden in core.
344 * @return array $widget_types An array including the WooCommerce widgets to hide.
345 */
346 public function hide_legacy_widgets_with_block_equivalent( $widget_types ) {
347 array_push(
348 $widget_types,
349 'woocommerce_product_search',
350 'woocommerce_product_categories',
351 'woocommerce_recent_reviews',
352 'woocommerce_product_tag_cloud',
353 'woocommerce_price_filter',
354 'woocommerce_layered_nav',
355 'woocommerce_layered_nav_filters',
356 'woocommerce_rating_filter'
357 );
358
359 return $widget_types;
360 }
361
362 /**
363 * Delete product transients when a product is deleted.
364 */
365 public function delete_product_transients() {
366 delete_transient( 'wc_blocks_has_downloadable_product' );
367 }
368
369 /**
370 * Get list of block types allowed in Widget Areas. New blocks won't be
371 * exposed in the Widget Area unless specifically added here.
372 *
373 * @return array Array of block types.
374 */
375 protected function get_widget_area_block_types() {
376 return array(
377 'ActiveFilters',
378 'AllReviews',
379 'AttributeFilter',
380 'Breadcrumbs',
381 'CartLink',
382 'CatalogSorting',
383 'ClassicShortcode',
384 'CustomerAccount',
385 'FeaturedCategory',
386 'FeaturedProduct',
387 'FilterWrapper',
388 'MiniCart',
389 'PriceFilter',
390 'ProductCategories',
391 'ProductResultsCount',
392 'ProductSearch',
393 'RatingFilter',
394 'ReviewsByCategory',
395 'ReviewsByProduct',
396 'StockFilter',
397 // Below product grids are hidden from inserter however they could have been used in widgets.
398 // Keep them for backward compatibility.
399 'HandpickedProducts',
400 'ProductBestSellers',
401 'ProductNew',
402 'ProductOnSale',
403 'ProductTopRated',
404 'ProductsByAttribute',
405 'ProductCategory',
406 'ProductTag',
407 );
408 }
409
410 /**
411 * Get list of block types.
412 *
413 * @return array
414 */
415 protected function get_block_types() {
416 global $pagenow;
417
418 $block_types = array(
419 'ActiveFilters',
420 'AddToCartForm',
421 'AllProducts',
422 'AllReviews',
423 'AttributeFilter',
424 'Breadcrumbs',
425 'CartLink',
426 'CatalogSorting',
427 'ClassicTemplate',
428 'ClassicShortcode',
429 'ComingSoon',
430 'CustomerAccount',
431 'FeaturedCategory',
432 'FeaturedProduct',
433 'FilterWrapper',
434 'HandpickedProducts',
435 'MiniCart',
436 'StoreNotices',
437 'PriceFilter',
438 'ProductBestSellers',
439 'ProductButton',
440 'ProductCategories',
441 'ProductCategory',
442 'ProductCollection\Controller',
443 'ProductCollection\NoResults',
444 'ProductGallery',
445 'ProductGalleryLargeImage',
446 'ProductGalleryLargeImageNextPrevious',
447 'ProductGalleryPager',
448 'ProductGalleryThumbnails',
449 'ProductImage',
450 'ProductImageGallery',
451 'ProductMeta',
452 'ProductNew',
453 'ProductOnSale',
454 'ProductPrice',
455 'ProductTemplate',
456 'ProductQuery',
457 'ProductAverageRating',
458 'ProductRating',
459 'ProductRatingCounter',
460 'ProductRatingStars',
461 'ProductResultsCount',
462 'ProductReviews',
463 'ProductSaleBadge',
464 'ProductSearch',
465 'ProductSKU',
466 'ProductStockIndicator',
467 'ProductSummary',
468 'ProductTag',
469 'ProductTitle',
470 'ProductTopRated',
471 'ProductsByAttribute',
472 'RatingFilter',
473 'ReviewsByCategory',
474 'ReviewsByProduct',
475 'RelatedProducts',
476 'ProductDetails',
477 'SingleProduct',
478 'StockFilter',
479 'PageContentWrapper',
480 'OrderConfirmation\Status',
481 'OrderConfirmation\Summary',
482 'OrderConfirmation\Totals',
483 'OrderConfirmation\TotalsWrapper',
484 'OrderConfirmation\Downloads',
485 'OrderConfirmation\DownloadsWrapper',
486 'OrderConfirmation\BillingAddress',
487 'OrderConfirmation\ShippingAddress',
488 'OrderConfirmation\BillingWrapper',
489 'OrderConfirmation\ShippingWrapper',
490 'OrderConfirmation\AdditionalInformation',
491 'OrderConfirmation\AdditionalFieldsWrapper',
492 'OrderConfirmation\AdditionalFields',
493 'OrderConfirmation\CreateAccount',
494 );
495
496 $block_types = array_merge(
497 $block_types,
498 Cart::get_cart_block_types(),
499 Checkout::get_checkout_block_types(),
500 MiniCartContents::get_mini_cart_block_types()
501 );
502
503 // Update plugins/woocommerce-blocks/docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md
504 // when modifying this list.
505 if ( Features::is_enabled( 'experimental-blocks' ) ) {
506 $block_types[] = 'ProductFilters';
507 $block_types[] = 'ProductFilterStatus';
508 $block_types[] = 'ProductFilterPrice';
509 $block_types[] = 'ProductFilterPriceSlider';
510 $block_types[] = 'ProductFilterAttribute';
511 $block_types[] = 'ProductFilterRating';
512 $block_types[] = 'ProductFilterActive';
513 $block_types[] = 'ProductFilterRemovableChips';
514 $block_types[] = 'ProductFilterClearButton';
515 $block_types[] = 'ProductFilterCheckboxList';
516 $block_types[] = 'ProductFilterChips';
517 if ( Features::is_enabled( 'blockified-add-to-cart' ) && wc_current_theme_is_fse_theme() ) {
518 $block_types[] = 'AddToCartWithOptions';
519 $block_types[] = 'AddToCartWithOptionsQuantitySelector';
520 $block_types[] = 'AddToCartWithOptionsVariationSelector';
521 $block_types[] = 'AddToCartWithOptionsGroupedProductSelector';
522 $block_types[] = 'AddToCartWithOptionsGroupedProductSelectorItemTemplate';
523 }
524 // Generic blocks that will be pushed upstream.
525 $block_types[] = 'Accordion\AccordionGroup';
526 $block_types[] = 'Accordion\AccordionItem';
527 $block_types[] = 'Accordion\AccordionPanel';
528 $block_types[] = 'Accordion\AccordionHeader';
529 $block_types[] = 'BlockifiedProductDetails';
530 }
531
532 /**
533 * This enables specific blocks in Widget Areas using an opt-in approach.
534 */
535 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
536 $block_types = array_intersect(
537 $block_types,
538 $this->get_widget_area_block_types()
539 );
540 }
541
542 /**
543 * This disables specific blocks in Post and Page editor by not registering them.
544 */
545 if ( in_array( $pagenow, array( 'post.php', 'post-new.php' ), true ) ) {
546 $block_types = array_diff(
547 $block_types,
548 array(
549 'Breadcrumbs',
550 'CatalogSorting',
551 'ClassicTemplate',
552 'ProductResultsCount',
553 'ProductDetails',
554 'OrderConfirmation\Status',
555 'OrderConfirmation\Summary',
556 'OrderConfirmation\Totals',
557 'OrderConfirmation\TotalsWrapper',
558 'OrderConfirmation\Downloads',
559 'OrderConfirmation\DownloadsWrapper',
560 'OrderConfirmation\BillingAddress',
561 'OrderConfirmation\ShippingAddress',
562 'OrderConfirmation\BillingWrapper',
563 'OrderConfirmation\ShippingWrapper',
564 'OrderConfirmation\AdditionalInformation',
565 'OrderConfirmation\AdditionalFieldsWrapper',
566 'OrderConfirmation\AdditionalFields',
567 )
568 );
569 }
570
571 /**
572 * Filters the list of allowed block types.
573 *
574 * @since 9.0.0
575 *
576 * @param array $block_types List of block types.
577 */
578 return apply_filters( 'woocommerce_get_block_types', $block_types );
579 }
580 }
581