Completed
Push — update/wpcom-premium-block-reg... ( ceb48a )
by Jeremy
07:15
created

Jetpack_Gutenberg::set_extension_unavailable()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 2
nop 3
dl 0
loc 31
rs 9.424
c 0
b 0
f 0
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
use Automattic\Jetpack\Constants;
10
use Automattic\Jetpack\Status;
11
12
/**
13
 * Wrapper function to safely register a gutenberg block type
14
 *
15
 * @param string $slug          Slug of the block.
16
 * @param array  $args          Arguments that are passed into register_block_type.
17
 * @param array  $required_plan {
18
 *    Optional. Does the block require a plan.
19
 *
20
 *    @type string wpcom   Slug of the plan required to use feature on WordPress.com simple sites.
21
 *    @type string jetpack Slug of the plan required to use feature on Jetpack sites.
22
 * }
23
 *
24
 * @see register_block_type
25
 *
26
 * @since 6.7.0
27
 * @since 8.2.0 Added required_plan parameter.
28
 *
29
 * @return WP_Block_Type|false The registered block type on success, or false on failure.
30
 */
31
function jetpack_register_block( $slug, $args = array(), $required_plan = array() ) {
32
	if ( 0 !== strpos( $slug, 'jetpack/' ) && ! strpos( $slug, '/' ) ) {
33
		_doing_it_wrong( 'jetpack_register_block', 'Prefix the block with jetpack/ ', '7.1.0' );
34
		$slug = 'jetpack/' . $slug;
35
	}
36
37
	// Checking whether block is registered to ensure it isn't registered twice.
38
	if ( Jetpack_Gutenberg::is_registered( $slug ) ) {
39
		return false;
40
	}
41
42
	$env = ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ? 'wpcom' : 'jetpack';
43
44
	// If the block requires a plan and your site does not have said plan, stop.
45
	if (
46
		! empty( $required_plan )
47
		&& ! empty( $required_plan[ $env ] )
48
		&& ! Jetpack_Gutenberg::is_supported_by_plan( $slug, $env )
49
	) {
50
		Jetpack_Gutenberg::set_extension_unavailable(
51
			$slug,
52
			'missing_plan',
53
			array(
54
				'required_feature' => $slug,
55
				'required_plan'    => $required_plan[ $env ],
56
			)
57
		);
58
		return false;
59
	}
60
61
	return register_block_type( $slug, $args );
62
}
63
64
/**
65
 * Helper function to register a Jetpack Gutenberg plugin
66
 *
67
 * @deprecated 7.1.0 Use Jetpack_Gutenberg::set_extension_available() instead
68
 *
69
 * @param string $slug Slug of the plugin.
70
 *
71
 * @since 6.9.0
72
 *
73
 * @return void
74
 */
75
function jetpack_register_plugin( $slug ) {
76
	_deprecated_function( __FUNCTION__, '7.1', 'Jetpack_Gutenberg::set_extension_available' );
77
78
	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...
79
}
80
81
/**
82
 * Set the reason why an extension (block or plugin) is unavailable
83
 *
84
 * @deprecated 7.1.0 Use Jetpack_Gutenberg::set_extension_unavailable() instead
85
 *
86
 * @param string $slug Slug of the block.
87
 * @param string $reason A string representation of why the extension is unavailable.
88
 *
89
 * @since 7.0.0
90
 *
91
 * @return void
92
 */
93
function jetpack_set_extension_unavailability_reason( $slug, $reason ) {
94
	_deprecated_function( __FUNCTION__, '7.1', 'Jetpack_Gutenberg::set_extension_unavailable' );
95
96
	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...
97
}
98
99
/**
100
 * General Gutenberg editor specific functionality
101
 */
102
class Jetpack_Gutenberg {
103
104
	/**
105
	 * Only these extensions can be registered. Used to control availability of beta blocks.
106
	 *
107
	 * @var array Extensions whitelist
108
	 */
109
	private static $extensions = array();
110
111
	/**
112
	 * Keeps track of the reasons why a given extension is unavailable.
113
	 *
114
	 * @var array Extensions availability information
115
	 */
116
	private static $availability = array();
117
118
	/**
119
	 * Prepend the 'jetpack/' prefix to a block name
120
	 *
121
	 * @param string $block_name The block name.
122
	 *
123
	 * @return string The prefixed block name.
124
	 */
125
	private static function prepend_block_prefix( $block_name ) {
126
		return 'jetpack/' . $block_name;
127
	}
128
129
	/**
130
	 * Remove the 'jetpack/' or jetpack-' prefix from an extension name
131
	 *
132
	 * @param string $extension_name The extension name.
133
	 *
134
	 * @return string The unprefixed extension name.
135
	 */
136
	private static function remove_extension_prefix( $extension_name ) {
137
		if ( wp_startswith( $extension_name, 'jetpack/' ) || wp_startswith( $extension_name, 'jetpack-' ) ) {
138
			return substr( $extension_name, strlen( 'jetpack/' ) );
139
		}
140
		return $extension_name;
141
	}
142
143
	/**
144
	 * Whether two arrays share at least one item
145
	 *
146
	 * @param array $a An array.
147
	 * @param array $b Another array.
148
	 *
149
	 * @return boolean True if $a and $b share at least one item
150
	 */
151
	protected static function share_items( $a, $b ) {
152
		return count( array_intersect( $a, $b ) ) > 0;
153
	}
154
155
	/**
156
	 * Register a block
157
	 *
158
	 * @deprecated 7.1.0 Use jetpack_register_block() instead
159
	 *
160
	 * @param string $slug Slug of the block.
161
	 * @param array  $args Arguments that are passed into register_block_type().
162
	 */
163
	public static function register_block( $slug, $args ) {
164
		_deprecated_function( __METHOD__, '7.1', 'jetpack_register_block' );
165
166
		jetpack_register_block( 'jetpack/' . $slug, $args );
167
	}
168
169
	/**
170
	 * Register a plugin
171
	 *
172
	 * @deprecated 7.1.0 Use Jetpack_Gutenberg::set_extension_available() instead
173
	 *
174
	 * @param string $slug Slug of the plugin.
175
	 */
176
	public static function register_plugin( $slug ) {
177
		_deprecated_function( __METHOD__, '7.1', 'Jetpack_Gutenberg::set_extension_available' );
178
179
		self::set_extension_available( $slug );
180
	}
181
182
	/**
183
	 * Register a block
184
	 *
185
	 * @deprecated 7.0.0 Use jetpack_register_block() instead
186
	 *
187
	 * @param string $slug Slug of the block.
188
	 * @param array  $args Arguments that are passed into the register_block_type.
189
	 * @param array  $availability array containing if a block is available and the reason when it is not.
190
	 */
191
	public static function register( $slug, $args, $availability ) {
192
		_deprecated_function( __METHOD__, '7.0', 'jetpack_register_block' );
193
194
		if ( isset( $availability['available'] ) && ! $availability['available'] ) {
195
			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...
196
		} else {
197
			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...
198
		}
199
	}
200
201
	/**
202
	 * Set a (non-block) extension as available
203
	 *
204
	 * @param string $slug Slug of the extension.
205
	 */
206
	public static function set_extension_available( $slug ) {
207
		self::$availability[ self::remove_extension_prefix( $slug ) ] = true;
208
	}
209
210
	/**
211
	 * Set the reason why an extension (block or plugin) is unavailable
212
	 *
213
	 * @param string $slug Slug of the extension.
214
	 * @param string $reason A string representation of why the extension is unavailable.
215
	 * @param array  $details A free-form array containing more information on why the extension is unavailable.
216
	 */
217
	public static function set_extension_unavailable( $slug, $reason, $details = array() ) {
218
		if (
219
			// Extensions that require a plan may be eligible for upgrades.
220
			'missing_plan' === $reason
221
			&& (
222
				/**
223
				 * Filter 'jetpack_block_editor_enable_upgrade_nudge' with `true` to enable or `false`
224
				 * to disable paid feature upgrade nudges in the block editor.
225
				 *
226
				 * When this is changed to default to `true`, you should also update `modules/memberships/class-jetpack-memberships.php`
227
				 * See https://github.com/Automattic/jetpack/pull/13394#pullrequestreview-293063378
228
				 *
229
				 * @since 7.7.0
230
				 *
231
				 * @param boolean
232
				 */
233
				! apply_filters( 'jetpack_block_editor_enable_upgrade_nudge', false )
234
				/** This filter is documented in _inc/lib/admin-pages/class.jetpack-react-page.php */
235
				|| ! apply_filters( 'jetpack_show_promotions', true )
236
			)
237
		) {
238
			// The block editor may apply an upgrade nudge if `missing_plan` is the reason.
239
			// Add a descriptive suffix to disable behavior but provide informative reason.
240
			$reason .= '__nudge_disabled';
241
		}
242
243
		self::$availability[ self::remove_extension_prefix( $slug ) ] = array(
244
			'reason'  => $reason,
245
			'details' => $details,
246
		);
247
	}
248
249
	/**
250
	 * Set the reason why an extension (block or plugin) is unavailable
251
	 *
252
	 * @deprecated 7.1.0 Use set_extension_unavailable() instead
253
	 *
254
	 * @param string $slug Slug of the extension.
255
	 * @param string $reason A string representation of why the extension is unavailable.
256
	 */
257
	public static function set_extension_unavailability_reason( $slug, $reason ) {
258
		_deprecated_function( __METHOD__, '7.1', 'Jetpack_Gutenberg::set_extension_unavailable' );
259
260
		self::set_extension_unavailable( $slug, $reason );
261
	}
262
263
	/**
264
	 * Set up a whitelist of allowed block editor extensions
265
	 *
266
	 * @return void
267
	 */
268
	public static function init() {
269
		if ( ! self::should_load() ) {
270
			return;
271
		}
272
273
		/**
274
		 * Alternative to `JETPACK_BETA_BLOCKS`, set to `true` to load Beta Blocks.
275
		 *
276
		 * @since 6.9.0
277
		 *
278
		 * @param boolean
279
		 */
280
		if ( apply_filters( 'jetpack_load_beta_blocks', false ) ) {
281
			Constants::set_constant( 'JETPACK_BETA_BLOCKS', true );
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
282
		}
283
284
		/**
285
		 * Filter the whitelist of block editor extensions that are available through Jetpack.
286
		 *
287
		 * @since 7.0.0
288
		 *
289
		 * @param array
290
		 */
291
		self::$extensions = apply_filters( 'jetpack_set_available_extensions', self::get_available_extensions() );
292
293
		/**
294
		 * Filter the whitelist of block editor plugins that are available through Jetpack.
295
		 *
296
		 * @deprecated 7.0.0 Use jetpack_set_available_extensions instead
297
		 *
298
		 * @since 6.8.0
299
		 *
300
		 * @param array
301
		 */
302
		self::$extensions = apply_filters( 'jetpack_set_available_blocks', self::$extensions );
303
304
		/**
305
		 * Filter the whitelist of block editor plugins that are available through Jetpack.
306
		 *
307
		 * @deprecated 7.0.0 Use jetpack_set_available_extensions instead
308
		 *
309
		 * @since 6.9.0
310
		 *
311
		 * @param array
312
		 */
313
		self::$extensions = apply_filters( 'jetpack_set_available_plugins', self::$extensions );
314
	}
315
316
	/**
317
	 * Resets the class to its original state
318
	 *
319
	 * Used in unit tests
320
	 *
321
	 * @return void
322
	 */
323
	public static function reset() {
324
		self::$extensions   = array();
325
		self::$availability = array();
326
	}
327
328
	/**
329
	 * Return the Gutenberg extensions (blocks and plugins) directory
330
	 *
331
	 * @return string The Gutenberg extensions directory
332
	 */
333
	public static function get_blocks_directory() {
334
		/**
335
		 * Filter to select Gutenberg blocks directory
336
		 *
337
		 * @since 6.9.0
338
		 *
339
		 * @param string default: '_inc/blocks/'
340
		 */
341
		return apply_filters( 'jetpack_blocks_directory', '_inc/blocks/' );
342
	}
343
344
	/**
345
	 * Checks for a given .json file in the blocks folder.
346
	 *
347
	 * @param string $preset The name of the .json file to look for.
348
	 *
349
	 * @return bool True if the file is found.
350
	 */
351
	public static function preset_exists( $preset ) {
352
		return file_exists( JETPACK__PLUGIN_DIR . self::get_blocks_directory() . $preset . '.json' );
353
	}
354
355
	/**
356
	 * Decodes JSON loaded from a preset file in the blocks folder
357
	 *
358
	 * @param string $preset The name of the .json file to load.
359
	 *
360
	 * @return mixed Returns an object if the file is present, or false if a valid .json file is not present.
361
	 */
362
	public static function get_preset( $preset ) {
363
		return json_decode(
364
			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
365
			file_get_contents( JETPACK__PLUGIN_DIR . self::get_blocks_directory() . $preset . '.json' )
366
		);
367
	}
368
369
	/**
370
	 * Returns a whitelist of Jetpack Gutenberg extensions (blocks and plugins), based on index.json
371
	 *
372
	 * @return array A list of blocks: eg [ 'publicize', 'markdown' ]
373
	 */
374
	public static function get_jetpack_gutenberg_extensions_whitelist() {
375
		$preset_extensions_manifest = self::preset_exists( 'index' )
376
			? self::get_preset( 'index' )
377
			: (object) array();
378
		$blocks_variation           = self::blocks_variation();
379
380
		return self::get_extensions_preset_for_variation( $preset_extensions_manifest, $blocks_variation );
381
	}
382
383
	/**
384
	 * Returns a diff from a combined list of whitelisted extensions and extensions determined to be excluded
385
	 *
386
	 * @param  array $whitelisted_extensions An array of whitelisted extensions.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $whitelisted_extensions not be array|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
387
	 *
388
	 * @return array A list of blocks: eg array( 'publicize', 'markdown' )
389
	 */
390
	public static function get_available_extensions( $whitelisted_extensions = null ) {
391
		$exclusions             = get_option( 'jetpack_excluded_extensions', array() );
392
		$whitelisted_extensions = is_null( $whitelisted_extensions ) ? self::get_jetpack_gutenberg_extensions_whitelist() : $whitelisted_extensions;
393
394
		return array_diff( $whitelisted_extensions, $exclusions );
395
	}
396
397
	/**
398
	 * Get availability of each block / plugin.
399
	 *
400
	 * @return array A list of block and plugins and their availablity status
401
	 */
402
	public static function get_availability() {
403
		/**
404
		 * Fires before Gutenberg extensions availability is computed.
405
		 *
406
		 * In the function call you supply, use `jetpack_register_block()` to set a block as available.
407
		 * Alternatively, use `Jetpack_Gutenberg::set_extension_available()` (for a non-block plugin), and
408
		 * `Jetpack_Gutenberg::set_extension_unavailable()` (if the block or plugin should not be registered
409
		 * but marked as unavailable).
410
		 *
411
		 * @since 7.0.0
412
		 */
413
		do_action( 'jetpack_register_gutenberg_extensions' );
414
415
		$available_extensions = array();
416
417
		foreach ( self::$extensions as $extension ) {
418
			$is_available = self::is_registered( 'jetpack/' . $extension ) ||
419
			( isset( self::$availability[ $extension ] ) && true === self::$availability[ $extension ] );
420
421
			$available_extensions[ $extension ] = array(
422
				'available' => $is_available,
423
			);
424
425
			if ( ! $is_available ) {
426
				$reason  = isset( self::$availability[ $extension ] ) ? self::$availability[ $extension ]['reason'] : 'missing_module';
427
				$details = isset( self::$availability[ $extension ] ) ? self::$availability[ $extension ]['details'] : array();
428
				$available_extensions[ $extension ]['unavailable_reason'] = $reason;
429
				$available_extensions[ $extension ]['details']            = $details;
430
			}
431
		}
432
433
		return $available_extensions;
434
	}
435
436
	/**
437
	 * Check if an extension/block is already registered
438
	 *
439
	 * @since 7.2
440
	 *
441
	 * @param string $slug Name of extension/block to check.
442
	 *
443
	 * @return bool
444
	 */
445
	public static function is_registered( $slug ) {
446
		return WP_Block_Type_Registry::get_instance()->is_registered( $slug );
447
	}
448
449
	/**
450
	 * Check if Gutenberg editor is available
451
	 *
452
	 * @since 6.7.0
453
	 *
454
	 * @return bool
455
	 */
456
	public static function is_gutenberg_available() {
457
		return true;
458
	}
459
460
	/**
461
	 * Check whether conditions indicate Gutenberg Extensions (blocks and plugins) should be loaded
462
	 *
463
	 * Loading blocks and plugins is enabled by default and may be disabled via filter:
464
	 *   add_filter( 'jetpack_gutenberg', '__return_false' );
465
	 *
466
	 * @since 6.9.0
467
	 *
468
	 * @return bool
469
	 */
470
	public static function should_load() {
471
		if ( ! Jetpack::is_active() && ! ( new Status() )->is_development_mode() ) {
472
			return false;
473
		}
474
475
		/**
476
		 * Filter to disable Gutenberg blocks
477
		 *
478
		 * @since 6.5.0
479
		 *
480
		 * @param bool true Whether to load Gutenberg blocks
481
		 */
482
		return (bool) apply_filters( 'jetpack_gutenberg', true );
483
	}
484
485
	/**
486
	 * Only enqueue block assets when needed.
487
	 *
488
	 * @param string $type Slug of the block.
489
	 * @param array  $script_dependencies Script dependencies. Will be merged with automatically
490
	 *                                    detected script dependencies from the webpack build.
491
	 *
492
	 * @return void
493
	 */
494
	public static function load_assets_as_required( $type, $script_dependencies = array() ) {
495
		if ( is_admin() ) {
496
			// A block's view assets will not be required in wp-admin.
497
			return;
498
		}
499
500
		$type = sanitize_title_with_dashes( $type );
501
		self::load_styles_as_required( $type );
502
		self::load_scripts_as_required( $type, $script_dependencies );
503
	}
504
505
	/**
506
	 * Only enqueue block sytles when needed.
507
	 *
508
	 * @param string $type Slug of the block.
509
	 *
510
	 * @since 7.2.0
511
	 *
512
	 * @return void
513
	 */
514
	public static function load_styles_as_required( $type ) {
515
		if ( is_admin() ) {
516
			// A block's view assets will not be required in wp-admin.
517
			return;
518
		}
519
520
		// Enqueue styles.
521
		$style_relative_path = self::get_blocks_directory() . $type . '/view' . ( is_rtl() ? '.rtl' : '' ) . '.css';
522 View Code Duplication
		if ( self::block_has_asset( $style_relative_path ) ) {
523
			$style_version = self::get_asset_version( $style_relative_path );
524
			$view_style    = plugins_url( $style_relative_path, JETPACK__PLUGIN_FILE );
525
			wp_enqueue_style( 'jetpack-block-' . $type, $view_style, array(), $style_version );
526
		}
527
528
	}
529
530
	/**
531
	 * Only enqueue block scripts when needed.
532
	 *
533
	 * @param string $type Slug of the block.
534
	 * @param array  $dependencies Script dependencies. Will be merged with automatically
535
	 *                             detected script dependencies from the webpack build.
536
	 *
537
	 * @since 7.2.0
538
	 *
539
	 * @return void
540
	 */
541
	public static function load_scripts_as_required( $type, $dependencies = array() ) {
542
		if ( is_admin() ) {
543
			// A block's view assets will not be required in wp-admin.
544
			return;
545
		}
546
547
		// Enqueue script.
548
		$script_relative_path = self::get_blocks_directory() . $type . '/view.js';
549
		$script_deps_path     = JETPACK__PLUGIN_DIR . self::get_blocks_directory() . $type . '/view.asset.php';
550
		$script_dependencies  = array( 'wp-polyfill' );
551
		if ( file_exists( $script_deps_path ) ) {
552
			$asset_manifest      = include $script_deps_path;
553
			$script_dependencies = $asset_manifest['dependencies'];
554
		}
555
556
		if ( ( ! class_exists( 'Jetpack_AMP_Support' ) || ! Jetpack_AMP_Support::is_amp_request() ) && self::block_has_asset( $script_relative_path ) ) {
557
			$script_version = self::get_asset_version( $script_relative_path );
558
			$view_script    = plugins_url( $script_relative_path, JETPACK__PLUGIN_FILE );
559
			wp_enqueue_script( 'jetpack-block-' . $type, $view_script, $script_dependencies, $script_version, false );
560
		}
561
562
		wp_localize_script(
563
			'jetpack-block-' . $type,
564
			'Jetpack_Block_Assets_Base_Url',
565
			plugins_url( self::get_blocks_directory(), JETPACK__PLUGIN_FILE )
566
		);
567
	}
568
569
	/**
570
	 * Check if an asset exists for a block.
571
	 *
572
	 * @param string $file Path of the file we are looking for.
573
	 *
574
	 * @return bool $block_has_asset Does the file exist.
575
	 */
576
	public static function block_has_asset( $file ) {
577
		return file_exists( JETPACK__PLUGIN_DIR . $file );
578
	}
579
580
	/**
581
	 * Get the version number to use when loading the file. Allows us to bypass cache when developing.
582
	 *
583
	 * @param string $file Path of the file we are looking for.
584
	 *
585
	 * @return string $script_version Version number.
586
	 */
587
	public static function get_asset_version( $file ) {
588
		return Jetpack::is_development_version() && self::block_has_asset( $file )
589
			? filemtime( JETPACK__PLUGIN_DIR . $file )
590
			: JETPACK__VERSION;
591
	}
592
593
	/**
594
	 * Load Gutenberg editor assets
595
	 *
596
	 * @since 6.7.0
597
	 *
598
	 * @return void
599
	 */
600
	public static function enqueue_block_editor_assets() {
601
		if ( ! self::should_load() ) {
602
			return;
603
		}
604
605
		// Required for Analytics. See _inc/lib/admin-pages/class.jetpack-admin-page.php.
606
		if ( ! ( new Status() )->is_development_mode() && Jetpack::is_active() ) {
607
			wp_enqueue_script( 'jp-tracks', '//stats.wp.com/w.js', array(), gmdate( 'YW' ), true );
608
		}
609
610
		$rtl              = is_rtl() ? '.rtl' : '';
611
		$blocks_dir       = self::get_blocks_directory();
612
		$blocks_variation = self::blocks_variation();
613
614
		if ( 'production' !== $blocks_variation ) {
615
			$blocks_env = '-' . esc_attr( $blocks_variation );
616
		} else {
617
			$blocks_env = '';
618
		}
619
620
		$editor_script = plugins_url( "{$blocks_dir}editor{$blocks_env}.js", JETPACK__PLUGIN_FILE );
621
		$editor_style  = plugins_url( "{$blocks_dir}editor{$blocks_env}{$rtl}.css", JETPACK__PLUGIN_FILE );
622
623
		$editor_deps_path = JETPACK__PLUGIN_DIR . $blocks_dir . "editor{$blocks_env}.asset.php";
624
		$editor_deps      = array( 'wp-polyfill' );
625
		if ( file_exists( $editor_deps_path ) ) {
626
			$asset_manifest = include $editor_deps_path;
627
			$editor_deps    = $asset_manifest['dependencies'];
628
		}
629
630
		$version = Jetpack::is_development_version() && file_exists( JETPACK__PLUGIN_DIR . $blocks_dir . 'editor.js' )
631
			? filemtime( JETPACK__PLUGIN_DIR . $blocks_dir . 'editor.js' )
632
			: JETPACK__VERSION;
633
634
		if ( method_exists( 'Jetpack', 'build_raw_urls' ) ) {
635
			$site_fragment = Jetpack::build_raw_urls( home_url() );
636
		} elseif ( class_exists( 'WPCOM_Masterbar' ) && method_exists( 'WPCOM_Masterbar', 'get_calypso_site_slug' ) ) {
637
			$site_fragment = WPCOM_Masterbar::get_calypso_site_slug( get_current_blog_id() );
638
		} else {
639
			$site_fragment = '';
640
		}
641
642
		wp_enqueue_script(
643
			'jetpack-blocks-editor',
644
			$editor_script,
645
			$editor_deps,
646
			$version,
647
			false
648
		);
649
650
		wp_localize_script(
651
			'jetpack-blocks-editor',
652
			'Jetpack_Block_Assets_Base_Url',
653
			plugins_url( $blocks_dir . '/', JETPACK__PLUGIN_FILE )
654
		);
655
656
		if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
657
			$user      = wp_get_current_user();
658
			$user_data = array(
659
				'userid'   => $user->ID,
660
				'username' => $user->user_login,
661
			);
662
			$blog_id   = get_current_blog_id();
663
		} else {
664
			$user_data = Jetpack_Tracks_Client::get_connected_user_tracks_identity();
665
			$blog_id   = Jetpack_Options::get_option( 'id', 0 );
666
		}
667
668
		wp_localize_script(
669
			'jetpack-blocks-editor',
670
			'Jetpack_Editor_Initial_State',
671
			array(
672
				'available_blocks' => self::get_availability(),
673
				'jetpack'          => array( 'is_active' => Jetpack::is_active() ),
674
				'siteFragment'     => $site_fragment,
675
				'tracksUserData'   => $user_data,
676
				'wpcomBlogId'      => $blog_id,
677
			)
678
		);
679
680
		wp_set_script_translations( 'jetpack-blocks-editor', 'jetpack' );
681
682
		wp_enqueue_style( 'jetpack-blocks-editor', $editor_style, array(), $version );
683
	}
684
685
	/**
686
	 * Some blocks do not depend on a specific module,
687
	 * and can consequently be loaded outside of the usual modules.
688
	 * We will look for such modules in the extensions/ directory.
689
	 *
690
	 * @since 7.1.0
691
	 */
692
	public static function load_independent_blocks() {
693
		if ( self::should_load() ) {
694
			/**
695
			 * Look for files that match our list of available Jetpack Gutenberg extensions (blocks and plugins).
696
			 * If available, load them.
697
			 */
698
			foreach ( self::$extensions as $extension ) {
699
				$extension_file_glob = glob( JETPACK__PLUGIN_DIR . 'extensions/*/' . $extension . '/' . $extension . '.php' );
700
				if ( ! empty( $extension_file_glob ) ) {
701
					include_once $extension_file_glob[0];
702
				}
703
			}
704
		}
705
	}
706
707
	/**
708
	 * Get CSS classes for a block.
709
	 *
710
	 * @since 7.7.0
711
	 *
712
	 * @param string $slug  Block slug.
713
	 * @param array  $attr  Block attributes.
714
	 * @param array  $extra Potential extra classes you may want to provide.
715
	 *
716
	 * @return string $classes List of CSS classes for a block.
717
	 */
718
	public static function block_classes( $slug = '', $attr, $extra = array() ) {
719
		if ( empty( $slug ) ) {
720
			return '';
721
		}
722
723
		// Basic block name class.
724
		$classes = array(
725
			'wp-block-jetpack-' . $slug,
726
		);
727
728
		// Add alignment if provided.
729
		if (
730
			! empty( $attr['align'] )
731
			&& in_array( $attr['align'], array( 'left', 'center', 'right', 'wide', 'full' ), true )
732
		) {
733
			array_push( $classes, 'align' . $attr['align'] );
734
		}
735
736
		// Add custom classes if provided in the block editor.
737
		if ( ! empty( $attr['className'] ) ) {
738
			array_push( $classes, $attr['className'] );
739
		}
740
741
		// Add any extra classes.
742
		if ( is_array( $extra ) && ! empty( $extra ) ) {
743
			$classes = array_merge( $classes, $extra );
744
		}
745
746
		return implode( ' ', $classes );
747
	}
748
749
	/**
750
	 * Determine whether a site should use the default set of blocks, or a custom set.
751
	 * Possible variations are currently beta, experimental, and production.
752
	 *
753
	 * @since 8.1.0
754
	 *
755
	 * @return string $block_varation production|beta|experimental
756
	 */
757
	public static function blocks_variation() {
758
		// Default to production blocks.
759
		$block_varation = 'production';
760
761
		if ( Constants::is_true( 'JETPACK_BETA_BLOCKS' ) ) {
762
			$block_varation = 'beta';
763
		}
764
765
		/*
766
		 * Switch to experimental blocks if you use the JETPACK_EXPERIMENTAL_BLOCKS constant.
767
		 */
768
		if ( Constants::is_true( 'JETPACK_EXPERIMENTAL_BLOCKS' ) ) {
769
			$block_varation = 'experimental';
770
		}
771
772
		/**
773
		 * Allow customizing the variation of blocks in use on a site.
774
		 *
775
		 * @since 8.1.0
776
		 *
777
		 * @param string $block_variation Can be beta, experimental, and production. Defaults to production.
778
		 */
779
		return apply_filters( 'jetpack_blocks_variation', $block_varation );
780
	}
781
782
	/**
783
	 * Get a list of extensions available for the variation you chose.
784
	 *
785
	 * @since 8.1.0
786
	 *
787
	 * @param obj    $preset_extensions_manifest List of extensions available in Jetpack.
788
	 * @param string $blocks_variation           Subset of blocks. production|beta|experimental.
789
	 *
790
	 * @return array $preset_extensions Array of extensions for that variation
791
	 */
792
	public static function get_extensions_preset_for_variation( $preset_extensions_manifest, $blocks_variation ) {
793
		$preset_extensions = isset( $preset_extensions_manifest->{ $blocks_variation } )
794
				? (array) $preset_extensions_manifest->{ $blocks_variation }
795
				: array();
796
797
		/*
798
		 * Experimental and Beta blocks need the production blocks as well.
799
		 */
800 View Code Duplication
		if (
801
			'experimental' === $blocks_variation
802
			|| 'beta' === $blocks_variation
803
		) {
804
			$production_extensions = isset( $preset_extensions_manifest->production )
805
				? (array) $preset_extensions_manifest->production
806
				: array();
807
808
			$preset_extensions = array_unique( array_merge( $preset_extensions, $production_extensions ) );
809
		}
810
811
		/*
812
		 * Beta blocks need the experimental blocks as well.
813
		 *
814
		 * If you've chosen to see Beta blocks,
815
		 * we want to make all blocks available to you:
816
		 * - Production
817
		 * - Experimental
818
		 * - Beta
819
		 */
820 View Code Duplication
		if ( 'beta' === $blocks_variation ) {
821
			$production_extensions = isset( $preset_extensions_manifest->experimental )
822
				? (array) $preset_extensions_manifest->experimental
823
				: array();
824
825
			$preset_extensions = array_unique( array_merge( $preset_extensions, $production_extensions ) );
826
		}
827
828
		return $preset_extensions;
829
	}
830
831
	/**
832
	 * Check if a block is supported by your plan,
833
	 * whether it's a Jetpack plan or a WordPress.com plan.
834
	 *
835
	 * This can be used to decide a block should be registered or not.
836
	 *
837
	 * @since 8.2.0
838
	 *
839
	 * @param string $slug Block slug.
840
	 * @param string $env  Current environment. Can be wpcom (wpcom simple sites) or jetpack.
841
	 *
842
	 * @return bool
843
	 */
844
	public static function is_supported_by_plan( $slug, $env ) {
845
		$slug = self::remove_extension_prefix( $slug );
846
847
		if ( 'wpcom' === $env ) {
848
			return Wpcom_Plan::supports( $slug );
849
		} elseif ( 'jetpack' === $env ) {
850
			return Jetpack::is_active() && Jetpack_Plan::supports( $slug );
851
		}
852
853
		return false;
854
	}
855
}
856