Completed
Push — update/import-sync-detection ( 0bf98c...8808a0 )
by
unknown
25:48 queued 17:49
created

Jetpack_Gutenberg::enqueue_block_editor_assets()   B

Complexity

Conditions 9
Paths 49

Size

Total Lines 72

Duplication

Lines 7
Ratio 9.72 %

Importance

Changes 0
Metric Value
cc 9
nc 49
nop 0
dl 7
loc 72
rs 7.0553
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
/**
3
 * Handles server-side registration and use of all blocks and plugins available in Jetpack for the block editor, aka Gutenberg.
4
 * Works in tandem with client-side block registration via `index.json`
5
 *
6
 * @package Jetpack
7
 */
8
9
/**
10
 * Wrapper function to safely register a gutenberg block type
11
 *
12
 * @param string $slug Slug of the block.
13
 * @param array  $args Arguments that are passed into register_block_type.
14
 *
15
 * @see register_block_type
16
 *
17
 * @since 6.7.0
18
 *
19
 * @return WP_Block_Type|false The registered block type on success, or false on failure.
20
 */
21
function jetpack_register_block( $slug, $args = array() ) {
22
	if ( 0 !== strpos( $slug, 'jetpack/' ) && ! strpos( $slug, '/' ) ) {
23
		_doing_it_wrong( 'jetpack_register_block', 'Prefix the block with jetpack/ ', '7.1.0' );
24
		$slug = 'jetpack/' . $slug;
25
	}
26
	return register_block_type( $slug, $args );
27
}
28
29
/**
30
 * Helper function to register a Jetpack Gutenberg plugin
31
 *
32
 * @deprecated 7.1.0 Use Jetpack_Gutenberg::set_extension_available() instead
33
 *
34
 * @param string $slug Slug of the plugin.
35
 *
36
 * @since 6.9.0
37
 *
38
 * @return void
39
 */
40
function jetpack_register_plugin( $slug ) {
41
	_deprecated_function( __FUNCTION__, '7.1', 'Jetpack_Gutenberg::set_extension_available' );
42
43
	Jetpack_Gutenberg::register_plugin( $slug );
0 ignored issues
show
Deprecated Code introduced by
The method Jetpack_Gutenberg::register_plugin() has been deprecated with message: 7.1.0 Use Jetpack_Gutenberg::set_extension_available() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
44
}
45
46
/**
47
 * Set the reason why an extension (block or plugin) is unavailable
48
 *
49
 * @deprecated 7.1.0 Use Jetpack_Gutenberg::set_extension_unavailable() instead
50
 *
51
 * @param string $slug Slug of the block.
52
 * @param string $reason A string representation of why the extension is unavailable.
53
 *
54
 * @since 7.0.0
55
 *
56
 * @return void
57
 */
58
function jetpack_set_extension_unavailability_reason( $slug, $reason ) {
59
	_deprecated_function( __FUNCTION__, '7.1', 'Jetpack_Gutenberg::set_extension_unavailable' );
60
61
	Jetpack_Gutenberg::set_extension_unavailability_reason( $slug, $reason );
0 ignored issues
show
Deprecated Code introduced by
The method Jetpack_Gutenberg::set_e...unavailability_reason() has been deprecated with message: 7.1.0 Use set_extension_unavailable() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
62
}
63
64
/**
65
 * General Gutenberg editor specific functionality
66
 */
67
class Jetpack_Gutenberg {
68
69
	/**
70
	 * Only these extensions can be registered. Used to control availability of beta blocks.
71
	 *
72
	 * @var array Extensions whitelist
73
	 */
74
	private static $extensions = array();
75
76
	/**
77
	 * Keeps track of the reasons why a given extension is unavailable.
78
	 *
79
	 * @var array Extensions availability information
80
	 */
81
	private static $availability = array();
82
83
	/**
84
	 * Prepend the 'jetpack/' prefix to a block name
85
	 *
86
	 * @param string $block_name The block name.
87
	 *
88
	 * @return string The prefixed block name.
89
	 */
90
	private static function prepend_block_prefix( $block_name ) {
91
		return 'jetpack/' . $block_name;
92
	}
93
94
	/**
95
	 * Remove the 'jetpack/' or jetpack-' prefix from an extension name
96
	 *
97
	 * @param string $extension_name The extension name.
98
	 *
99
	 * @return string The unprefixed extension name.
100
	 */
101
	private static function remove_extension_prefix( $extension_name ) {
102
		if ( wp_startswith( $extension_name, 'jetpack/' ) || wp_startswith( $extension_name, 'jetpack-' ) ) {
103
			return substr( $extension_name, strlen( 'jetpack/' ) );
104
		}
105
		return $extension_name;
106
	}
107
108
	/**
109
	 * Whether two arrays share at least one item
110
	 *
111
	 * @param array $a An array.
112
	 * @param array $b Another array.
113
	 *
114
	 * @return boolean True if $a and $b share at least one item
115
	 */
116
	protected static function share_items( $a, $b ) {
117
		return count( array_intersect( $a, $b ) ) > 0;
118
	}
119
120
	/**
121
	 * Register a block
122
	 *
123
	 * @deprecated 7.1.0 Use jetpack_register_block() instead
124
	 *
125
	 * @param string $slug Slug of the block.
126
	 * @param array  $args Arguments that are passed into register_block_type().
127
	 */
128
	public static function register_block( $slug, $args ) {
129
		_deprecated_function( __METHOD__, '7.1', 'jetpack_register_block' );
130
131
		jetpack_register_block( 'jetpack/' . $slug, $args );
132
	}
133
134
	/**
135
	 * Register a plugin
136
	 *
137
	 * @deprecated 7.1.0 Use Jetpack_Gutenberg::set_extension_available() instead
138
	 *
139
	 * @param string $slug Slug of the plugin.
140
	 */
141
	public static function register_plugin( $slug ) {
142
		_deprecated_function( __METHOD__, '7.1', 'Jetpack_Gutenberg::set_extension_available' );
143
144
		self::set_extension_available( $slug );
145
	}
146
147
	/**
148
	 * Register a block
149
	 *
150
	 * @deprecated 7.0.0 Use jetpack_register_block() instead
151
	 *
152
	 * @param string $slug Slug of the block.
153
	 * @param array  $args Arguments that are passed into the register_block_type.
154
	 * @param array  $availability array containing if a block is available and the reason when it is not.
155
	 */
156
	public static function register( $slug, $args, $availability ) {
157
		_deprecated_function( __METHOD__, '7.0', 'jetpack_register_block' );
158
159
		if ( isset( $availability['available'] ) && ! $availability['available'] ) {
160
			self::set_extension_unavailability_reason( $slug, $availability['unavailable_reason'] );
0 ignored issues
show
Deprecated Code introduced by
The method Jetpack_Gutenberg::set_e...unavailability_reason() has been deprecated with message: 7.1.0 Use set_extension_unavailable() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
161
		} else {
162
			self::register_block( $slug, $args );
0 ignored issues
show
Deprecated Code introduced by
The method Jetpack_Gutenberg::register_block() has been deprecated with message: 7.1.0 Use jetpack_register_block() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
163
		}
164
	}
165
166
	/**
167
	 * Set a (non-block) extension as available
168
	 *
169
	 * @param string $slug Slug of the extension.
170
	 */
171
	public static function set_extension_available( $slug ) {
172
		self::$availability[ self::remove_extension_prefix( $slug ) ] = true;
173
	}
174
175
	/**
176
	 * Set the reason why an extension (block or plugin) is unavailable
177
	 *
178
	 * @param string $slug Slug of the extension.
179
	 * @param string $reason A string representation of why the extension is unavailable.
180
	 */
181
	public static function set_extension_unavailable( $slug, $reason ) {
182
		self::$availability[ self::remove_extension_prefix( $slug ) ] = $reason;
183
	}
184
185
	/**
186
	 * Set the reason why an extension (block or plugin) is unavailable
187
	 *
188
	 * @deprecated 7.1.0 Use set_extension_unavailable() instead
189
	 *
190
	 * @param string $slug Slug of the extension.
191
	 * @param string $reason A string representation of why the extension is unavailable.
192
	 */
193
	public static function set_extension_unavailability_reason( $slug, $reason ) {
194
		_deprecated_function( __METHOD__, '7.1', 'Jetpack_Gutenberg::set_extension_unavailable' );
195
196
		self::set_extension_unavailable( $slug, $reason );
197
	}
198
199
	/**
200
	 * Set up a whitelist of allowed block editor extensions
201
	 *
202
	 * @return void
203
	 */
204
	public static function init() {
205
		if ( ! self::should_load() ) {
206
			return;
207
		}
208
209
		/**
210
		 * Alternative to `JETPACK_BETA_BLOCKS`, set to `true` to load Beta Blocks.
211
		 *
212
		 * @since 6.9.0
213
		 *
214
		 * @param boolean
215
		 */
216
		if ( apply_filters( 'jetpack_load_beta_blocks', false ) ) {
217
			Jetpack_Constants::set_constant( 'JETPACK_BETA_BLOCKS', true );
218
		}
219
220
		/**
221
		 * Filter the whitelist of block editor extensions that are available through Jetpack.
222
		 *
223
		 * @since 7.0.0
224
		 *
225
		 * @param array
226
		 */
227
		self::$extensions = apply_filters( 'jetpack_set_available_extensions', self::get_jetpack_gutenberg_extensions_whitelist() );
228
229
		/**
230
		 * Filter the whitelist of block editor plugins that are available through Jetpack.
231
		 *
232
		 * @deprecated 7.0.0 Use jetpack_set_available_extensions instead
233
		 *
234
		 * @since 6.8.0
235
		 *
236
		 * @param array
237
		 */
238
		self::$extensions = apply_filters( 'jetpack_set_available_blocks', self::$extensions );
239
240
		/**
241
		 * Filter the whitelist of block editor plugins that are available through Jetpack.
242
		 *
243
		 * @deprecated 7.0.0 Use jetpack_set_available_extensions instead
244
		 *
245
		 * @since 6.9.0
246
		 *
247
		 * @param array
248
		 */
249
		self::$extensions = apply_filters( 'jetpack_set_available_plugins', self::$extensions );
250
	}
251
252
	/**
253
	 * Resets the class to its original state
254
	 *
255
	 * Used in unit tests
256
	 *
257
	 * @return void
258
	 */
259
	public static function reset() {
260
		self::$extensions   = array();
261
		self::$availability = array();
262
	}
263
264
	/**
265
	 * Return the Gutenberg extensions (blocks and plugins) directory
266
	 *
267
	 * @return string The Gutenberg extensions directory
268
	 */
269
	public static function get_blocks_directory() {
270
		/**
271
		 * Filter to select Gutenberg blocks directory
272
		 *
273
		 * @since 6.9.0
274
		 *
275
		 * @param string default: '_inc/blocks/'
276
		 */
277
		return apply_filters( 'jetpack_blocks_directory', '_inc/blocks/' );
278
	}
279
280
	/**
281
	 * Checks for a given .json file in the blocks folder.
282
	 *
283
	 * @param string $preset The name of the .json file to look for.
284
	 *
285
	 * @return bool True if the file is found.
286
	 */
287
	public static function preset_exists( $preset ) {
288
		return file_exists( JETPACK__PLUGIN_DIR . self::get_blocks_directory() . $preset . '.json' );
289
	}
290
291
	/**
292
	 * Decodes JSON loaded from a preset file in the blocks folder
293
	 *
294
	 * @param string $preset The name of the .json file to load.
295
	 *
296
	 * @return mixed Returns an object if the file is present, or false if a valid .json file is not present.
297
	 */
298
	public static function get_preset( $preset ) {
299
		return json_decode(
300
			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
301
			file_get_contents( JETPACK__PLUGIN_DIR . self::get_blocks_directory() . $preset . '.json' )
302
		);
303
	}
304
305
	/**
306
	 * Returns a whitelist of Jetpack Gutenberg extensions (blocks and plugins), based on index.json
307
	 *
308
	 * @return array A list of blocks: eg [ 'publicize', 'markdown' ]
309
	 */
310
	public static function get_jetpack_gutenberg_extensions_whitelist() {
311
		$preset_extensions_manifest = self::preset_exists( 'index' ) ? self::get_preset( 'index' ) : (object) array();
312
313
		$preset_extensions = isset( $preset_extensions_manifest->production ) ? (array) $preset_extensions_manifest->production : array();
314
315
		if ( Jetpack_Constants::is_true( 'JETPACK_BETA_BLOCKS' ) ) {
316
			$beta_extensions = isset( $preset_extensions_manifest->beta ) ? (array) $preset_extensions_manifest->beta : array();
317
			return array_unique( array_merge( $preset_extensions, $beta_extensions ) );
318
		}
319
320
		return $preset_extensions;
321
	}
322
323
	/**
324
	 * Get availability of each block / plugin.
325
	 *
326
	 * @return array A list of block and plugins and their availablity status
327
	 */
328
	public static function get_availability() {
329
		/**
330
		 * Fires before Gutenberg extensions availability is computed.
331
		 *
332
		 * In the function call you supply, use `jetpack_register_block()` to set a block as available.
333
		 * Alternatively, use `Jetpack_Gutenberg::set_extension_available()` (for a non-block plugin), and
334
		 * `Jetpack_Gutenberg::set_extension_unavailable()` (if the block or plugin should not be registered
335
		 * but marked as unavailable).
336
		 *
337
		 * @since 7.0.0
338
		 */
339
		do_action( 'jetpack_register_gutenberg_extensions' );
340
341
		$available_extensions = array();
342
343
		foreach ( self::$extensions as $extension ) {
344
			$is_available = WP_Block_Type_Registry::get_instance()->is_registered( 'jetpack/' . $extension ) ||
345
			( isset( self::$availability[ $extension ] ) && true === self::$availability[ $extension ] );
346
347
			$available_extensions[ $extension ] = array(
348
				'available' => $is_available,
349
			);
350
351
			if ( ! $is_available ) {
352
				$reason = isset( self::$availability[ $extension ] ) ? self::$availability[ $extension ] : 'missing_module';
353
				$available_extensions[ $extension ]['unavailable_reason'] = $reason;
354
			}
355
		}
356
357
		$unwhitelisted_blocks  = array();
358
		$all_registered_blocks = WP_Block_Type_Registry::get_instance()->get_all_registered();
359
		foreach ( $all_registered_blocks as $block_name => $block_type ) {
360
			if ( ! wp_startswith( $block_name, 'jetpack/' ) || isset( $block_type->parent ) ) {
361
				continue;
362
			}
363
364
			$unprefixed_block_name = self::remove_extension_prefix( $block_name );
365
366
			if ( in_array( $unprefixed_block_name, self::$extensions, true ) ) {
367
				continue;
368
			}
369
370
			$unwhitelisted_blocks[ $unprefixed_block_name ] = array(
371
				'available'          => false,
372
				'unavailable_reason' => 'not_whitelisted',
373
			);
374
		}
375
376
		// Finally: Unwhitelisted non-block extensions. These are in $availability.
377
		$unwhitelisted_extensions = array_fill_keys(
378
			array_diff( array_keys( self::$availability ), self::$extensions ),
379
			array(
380
				'available'          => false,
381
				'unavailable_reason' => 'not_whitelisted',
382
			)
383
		);
384
		return array_merge( $available_extensions, $unwhitelisted_blocks, $unwhitelisted_extensions );
385
	}
386
387
	/**
388
	 * Check if Gutenberg editor is available
389
	 *
390
	 * @since 6.7.0
391
	 *
392
	 * @return bool
393
	 */
394
	public static function is_gutenberg_available() {
395
		return true;
396
	}
397
398
	/**
399
	 * Check whether conditions indicate Gutenberg Extensions (blocks and plugins) should be loaded
400
	 *
401
	 * Loading blocks and plugins is enabled by default and may be disabled via filter:
402
	 *   add_filter( 'jetpack_gutenberg', '__return_false' );
403
	 *
404
	 * @since 6.9.0
405
	 *
406
	 * @return bool
407
	 */
408
	public static function should_load() {
409
		if ( ! Jetpack::is_active() && ! Jetpack::is_development_mode() ) {
410
			return false;
411
		}
412
413
		/**
414
		 * Filter to disable Gutenberg blocks
415
		 *
416
		 * @since 6.5.0
417
		 *
418
		 * @param bool true Whether to load Gutenberg blocks
419
		 */
420
		return (bool) apply_filters( 'jetpack_gutenberg', true );
421
	}
422
423
	/**
424
	 * Only enqueue block assets when needed.
425
	 *
426
	 * @param string $type slug of the block.
427
	 * @param array  $script_dependencies An array of view-side Javascript dependencies to be enqueued.
428
	 *
429
	 * @return void
430
	 */
431
	public static function load_assets_as_required( $type, $script_dependencies = array() ) {
432
		if ( is_admin() ) {
433
			// A block's view assets will not be required in wp-admin.
434
			return;
435
		}
436
437
		$type = sanitize_title_with_dashes( $type );
438
		// Enqueue styles.
439
		$style_relative_path = self::get_blocks_directory() . $type . '/view' . ( is_rtl() ? '.rtl' : '' ) . '.css';
440 View Code Duplication
		if ( self::block_has_asset( $style_relative_path ) ) {
441
			$style_version = self::get_asset_version( $style_relative_path );
442
			$view_style    = plugins_url( $style_relative_path, JETPACK__PLUGIN_FILE );
443
			wp_enqueue_style( 'jetpack-block-' . $type, $view_style, array(), $style_version );
444
		}
445
446
		// Enqueue script.
447
		$script_relative_path = self::get_blocks_directory() . $type . '/view.js';
448 View Code Duplication
		if ( self::block_has_asset( $script_relative_path ) ) {
449
			$script_version = self::get_asset_version( $script_relative_path );
450
			$view_script    = plugins_url( $script_relative_path, JETPACK__PLUGIN_FILE );
451
			wp_enqueue_script( 'jetpack-block-' . $type, $view_script, $script_dependencies, $script_version, false );
452
		}
453
454
		wp_localize_script(
455
			'jetpack-block-' . $type,
456
			'Jetpack_Block_Assets_Base_Url',
457
			plugins_url( self::get_blocks_directory(), JETPACK__PLUGIN_FILE )
458
		);
459
	}
460
461
	/**
462
	 * Check if an asset exists for a block.
463
	 *
464
	 * @param string $file Path of the file we are looking for.
465
	 *
466
	 * @return bool $block_has_asset Does the file exist.
467
	 */
468
	public static function block_has_asset( $file ) {
469
		return file_exists( JETPACK__PLUGIN_DIR . $file );
470
	}
471
472
	/**
473
	 * Get the version number to use when loading the file. Allows us to bypass cache when developing.
474
	 *
475
	 * @param string $file Path of the file we are looking for.
476
	 *
477
	 * @return string $script_version Version number.
478
	 */
479
	public static function get_asset_version( $file ) {
480
		return Jetpack::is_development_version() && self::block_has_asset( $file )
481
			? filemtime( JETPACK__PLUGIN_DIR . $file )
482
			: JETPACK__VERSION;
483
	}
484
485
	/**
486
	 * Load Gutenberg editor assets
487
	 *
488
	 * @since 6.7.0
489
	 *
490
	 * @return void
491
	 */
492
	public static function enqueue_block_editor_assets() {
493
		if ( ! self::should_load() ) {
494
			return;
495
		}
496
497
		$rtl        = is_rtl() ? '.rtl' : '';
498
		$beta       = Jetpack_Constants::is_true( 'JETPACK_BETA_BLOCKS' ) ? '-beta' : '';
499
		$blocks_dir = self::get_blocks_directory();
500
501
		$editor_script = plugins_url( "{$blocks_dir}editor{$beta}.js", JETPACK__PLUGIN_FILE );
502
		$editor_style  = plugins_url( "{$blocks_dir}editor{$beta}{$rtl}.css", JETPACK__PLUGIN_FILE );
503
504
		$version = Jetpack::is_development_version() && file_exists( JETPACK__PLUGIN_DIR . $blocks_dir . 'editor.js' )
505
			? filemtime( JETPACK__PLUGIN_DIR . $blocks_dir . 'editor.js' )
506
			: JETPACK__VERSION;
507
508 View Code Duplication
		if ( method_exists( 'Jetpack', 'build_raw_urls' ) ) {
509
			$site_fragment = Jetpack::build_raw_urls( home_url() );
510
		} elseif ( class_exists( 'WPCOM_Masterbar' ) && method_exists( 'WPCOM_Masterbar', 'get_calypso_site_slug' ) ) {
511
			$site_fragment = WPCOM_Masterbar::get_calypso_site_slug( get_current_blog_id() );
512
		} else {
513
			$site_fragment = '';
514
		}
515
516
		wp_enqueue_script(
517
			'jetpack-blocks-editor',
518
			$editor_script,
519
			array(
520
				'lodash',
521
				'wp-api-fetch',
522
				'wp-blob',
523
				'wp-blocks',
524
				'wp-components',
525
				'wp-compose',
526
				'wp-data',
527
				'wp-date',
528
				'wp-edit-post',
529
				'wp-editor',
530
				'wp-element',
531
				'wp-hooks',
532
				'wp-i18n',
533
				'wp-keycodes',
534
				'wp-plugins',
535
				'wp-polyfill',
536
				'wp-rich-text',
537
				'wp-token-list',
538
				'wp-url',
539
			),
540
			$version,
541
			false
542
		);
543
544
		wp_localize_script(
545
			'jetpack-blocks-editor',
546
			'Jetpack_Block_Assets_Base_Url',
547
			plugins_url( $blocks_dir . '/', JETPACK__PLUGIN_FILE )
548
		);
549
550
		wp_localize_script(
551
			'jetpack-blocks-editor',
552
			'Jetpack_Editor_Initial_State',
553
			array(
554
				'available_blocks' => self::get_availability(),
555
				'jetpack'          => array( 'is_active' => Jetpack::is_active() ),
556
				'siteFragment'     => $site_fragment,
557
			)
558
		);
559
560
		Jetpack::setup_wp_i18n_locale_data();
561
562
		wp_enqueue_style( 'jetpack-blocks-editor', $editor_style, array(), $version );
563
	}
564
565
	/**
566
	 * Some blocks do not depend on a specific module,
567
	 * and can consequently be loaded outside of the usual modules.
568
	 * We will look for such modules in the extensions/ directory.
569
	 *
570
	 * @since 7.1.0
571
	 */
572
	public static function load_independent_blocks() {
573
		if ( self::should_load() ) {
574
			/**
575
			 * Look for files that match our list of available Jetpack Gutenberg extensions (blocks and plugins).
576
			 * If available, load them.
577
			 */
578
			foreach ( self::$extensions as $extension ) {
579
				$extension_file_glob = glob( JETPACK__PLUGIN_DIR . 'extensions/*/' . $extension . '/' . $extension . '.php' );
580
				if ( ! empty( $extension_file_glob ) ) {
581
					include_once $extension_file_glob[0];
582
				}
583
			}
584
		}
585
	}
586
}
587