Completed
Push — add/limited-blocks ( 1d7f2f )
by
unknown
08:45 queued 01:32
created

Jetpack_Gutenberg::is_gutenberg_available()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 3
rs 10
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
11
/**
12
 * Wrapper function to safely register a gutenberg block type
13
 *
14
 * @param string $slug Slug of the block.
15
 * @param array  $args Arguments that are passed into register_block_type.
16
 *
17
 * @see register_block_type
18
 *
19
 * @since 6.7.0
20
 *
21
 * @return WP_Block_Type|false The registered block type on success, or false on failure.
22
 */
23
function jetpack_register_block( $slug, $args = array() ) {
24
	if ( 0 !== strpos( $slug, 'jetpack/' ) && ! strpos( $slug, '/' ) ) {
25
		_doing_it_wrong( 'jetpack_register_block', 'Prefix the block with jetpack/ ', '7.1.0' );
26
		$slug = 'jetpack/' . $slug;
27
	}
28
29
	// Checking whether block is registered to ensure it isn't registered twice.
30
	if ( Jetpack_Gutenberg::is_registered( $slug ) ) {
31
		return false;
32
	}
33
34
	return register_block_type( $slug, $args );
35
}
36
37
/**
38
 * Helper function to register a Jetpack Gutenberg plugin
39
 *
40
 * @deprecated 7.1.0 Use Jetpack_Gutenberg::set_extension_available() instead
41
 *
42
 * @param string $slug Slug of the plugin.
43
 *
44
 * @since 6.9.0
45
 *
46
 * @return void
47
 */
48
function jetpack_register_plugin( $slug ) {
49
	_deprecated_function( __FUNCTION__, '7.1', 'Jetpack_Gutenberg::set_extension_available' );
50
51
	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...
52
}
53
54
/**
55
 * Set the reason why an extension (block or plugin) is unavailable
56
 *
57
 * @deprecated 7.1.0 Use Jetpack_Gutenberg::set_extension_unavailable() instead
58
 *
59
 * @param string $slug Slug of the block.
60
 * @param string $reason A string representation of why the extension is unavailable.
61
 *
62
 * @since 7.0.0
63
 *
64
 * @return void
65
 */
66
function jetpack_set_extension_unavailability_reason( $slug, $reason ) {
67
	_deprecated_function( __FUNCTION__, '7.1', 'Jetpack_Gutenberg::set_extension_unavailable' );
68
69
	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...
70
}
71
72
/**
73
 * General Gutenberg editor specific functionality
74
 */
75
class Jetpack_Gutenberg {
76
77
	/**
78
	 * Only these extensions can be registered. Used to control availability of beta blocks.
79
	 *
80
	 * @var array Extensions whitelist
81
	 */
82
	private static $extensions = array();
83
84
	/**
85
	 * Keeps track of the reasons why a given extension is unavailable.
86
	 *
87
	 * @var array Extensions availability information
88
	 */
89
	private static $availability = array();
90
91
	/**
92
	 * Prepend the 'jetpack/' prefix to a block name
93
	 *
94
	 * @param string $block_name The block name.
95
	 *
96
	 * @return string The prefixed block name.
97
	 */
98
	private static function prepend_block_prefix( $block_name ) {
99
		return 'jetpack/' . $block_name;
100
	}
101
102
	/**
103
	 * Remove the 'jetpack/' or jetpack-' prefix from an extension name
104
	 *
105
	 * @param string $extension_name The extension name.
106
	 *
107
	 * @return string The unprefixed extension name.
108
	 */
109
	private static function remove_extension_prefix( $extension_name ) {
110
		if ( wp_startswith( $extension_name, 'jetpack/' ) || wp_startswith( $extension_name, 'jetpack-' ) ) {
111
			return substr( $extension_name, strlen( 'jetpack/' ) );
112
		}
113
		return $extension_name;
114
	}
115
116
	/**
117
	 * Whether two arrays share at least one item
118
	 *
119
	 * @param array $a An array.
120
	 * @param array $b Another array.
121
	 *
122
	 * @return boolean True if $a and $b share at least one item
123
	 */
124
	protected static function share_items( $a, $b ) {
125
		return count( array_intersect( $a, $b ) ) > 0;
126
	}
127
128
	/**
129
	 * Register a block
130
	 *
131
	 * @deprecated 7.1.0 Use jetpack_register_block() instead
132
	 *
133
	 * @param string $slug Slug of the block.
134
	 * @param array  $args Arguments that are passed into register_block_type().
135
	 */
136
	public static function register_block( $slug, $args ) {
137
		_deprecated_function( __METHOD__, '7.1', 'jetpack_register_block' );
138
139
		jetpack_register_block( 'jetpack/' . $slug, $args );
140
	}
141
142
	/**
143
	 * Register a plugin
144
	 *
145
	 * @deprecated 7.1.0 Use Jetpack_Gutenberg::set_extension_available() instead
146
	 *
147
	 * @param string $slug Slug of the plugin.
148
	 */
149
	public static function register_plugin( $slug ) {
150
		_deprecated_function( __METHOD__, '7.1', 'Jetpack_Gutenberg::set_extension_available' );
151
152
		self::set_extension_available( $slug );
153
	}
154
155
	/**
156
	 * Register a block
157
	 *
158
	 * @deprecated 7.0.0 Use jetpack_register_block() instead
159
	 *
160
	 * @param string $slug Slug of the block.
161
	 * @param array  $args Arguments that are passed into the register_block_type.
162
	 * @param array  $availability array containing if a block is available and the reason when it is not.
163
	 */
164
	public static function register( $slug, $args, $availability ) {
165
		_deprecated_function( __METHOD__, '7.0', 'jetpack_register_block' );
166
167
		if ( isset( $availability['available'] ) && ! $availability['available'] ) {
168
			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...
169
		} else {
170
			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...
171
		}
172
	}
173
174
	/**
175
	 * Set a (non-block) extension as available
176
	 *
177
	 * @param string $slug Slug of the extension.
178
	 */
179
	public static function set_extension_available( $slug ) {
180
		self::$availability[ self::remove_extension_prefix( $slug ) ] = true;
181
	}
182
183
	/**
184
	 * Set the reason why an extension (block or plugin) is unavailable
185
	 *
186
	 * @param string $slug Slug of the extension.
187
	 * @param string $reason A string representation of why the extension is unavailable.
188
	 * @param array  $details A free-form array containing more information on why the extension is unavailable.
189
	 */
190
	public static function set_extension_unavailable( $slug, $reason, $details = array() ) {
191
		if (
192
			// Extensions that require a plan may be eligible for upgrades.
193
			'missing_plan' === $reason
194
			&& (
195
				/**
196
				 * Filter 'jetpack_block_editor_enable_upgrade_nudge' with `true` to enable or `false`
197
				 * to disable paid feature upgrade nudges in the block editor.
198
				 *
199
				 * When this is changed to default to `true`, you should also update `modules/memberships/class-jetpack-memberships.php`
200
				 * See https://github.com/Automattic/jetpack/pull/13394#pullrequestreview-293063378
201
				 *
202
				 * @since 7.7.0
203
				 *
204
				 * @param boolean
205
				 */
206
				! apply_filters( 'jetpack_block_editor_enable_upgrade_nudge', false )
207
				/** This filter is documented in _inc/lib/admin-pages/class.jetpack-react-page.php */
208
				|| ! apply_filters( 'jetpack_show_promotions', true )
209
			)
210
		) {
211
			// The block editor may apply an upgrade nudge if `missing_plan` is the reason.
212
			// Add a descriptive suffix to disable behavior but provide informative reason.
213
			$reason .= '__nudge_disabled';
214
		}
215
216
		self::$availability[ self::remove_extension_prefix( $slug ) ] = array(
217
			'reason'  => $reason,
218
			'details' => $details,
219
		);
220
	}
221
222
	/**
223
	 * Set the reason why an extension (block or plugin) is unavailable
224
	 *
225
	 * @deprecated 7.1.0 Use set_extension_unavailable() instead
226
	 *
227
	 * @param string $slug Slug of the extension.
228
	 * @param string $reason A string representation of why the extension is unavailable.
229
	 */
230
	public static function set_extension_unavailability_reason( $slug, $reason ) {
231
		_deprecated_function( __METHOD__, '7.1', 'Jetpack_Gutenberg::set_extension_unavailable' );
232
233
		self::set_extension_unavailable( $slug, $reason );
234
	}
235
236
	/**
237
	 * Set up a whitelist of allowed block editor extensions
238
	 *
239
	 * @return void
240
	 */
241
	public static function init() {
242
		if ( ! self::should_load() ) {
243
			return;
244
		}
245
246
		/**
247
		 * Alternative to `JETPACK_BETA_BLOCKS`, set to `true` to load Beta Blocks.
248
		 *
249
		 * @since 6.9.0
250
		 *
251
		 * @param boolean
252
		 */
253
		if ( apply_filters( 'jetpack_load_beta_blocks', false ) ) {
254
			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...
255
		}
256
257
		/**
258
		 * Filter the whitelist of block editor extensions that are available through Jetpack.
259
		 *
260
		 * @since 7.0.0
261
		 *
262
		 * @param array
263
		 */
264
		self::$extensions = apply_filters( 'jetpack_set_available_extensions', self::get_available_extensions() );
265
266
		/**
267
		 * Filter the whitelist of block editor plugins that are available through Jetpack.
268
		 *
269
		 * @deprecated 7.0.0 Use jetpack_set_available_extensions instead
270
		 *
271
		 * @since 6.8.0
272
		 *
273
		 * @param array
274
		 */
275
		self::$extensions = apply_filters( 'jetpack_set_available_blocks', self::$extensions );
276
277
		/**
278
		 * Filter the whitelist of block editor plugins that are available through Jetpack.
279
		 *
280
		 * @deprecated 7.0.0 Use jetpack_set_available_extensions instead
281
		 *
282
		 * @since 6.9.0
283
		 *
284
		 * @param array
285
		 */
286
		self::$extensions = apply_filters( 'jetpack_set_available_plugins', self::$extensions );
287
	}
288
289
	/**
290
	 * Resets the class to its original state
291
	 *
292
	 * Used in unit tests
293
	 *
294
	 * @return void
295
	 */
296
	public static function reset() {
297
		self::$extensions   = array();
298
		self::$availability = array();
299
	}
300
301
	/**
302
	 * Return the Gutenberg extensions (blocks and plugins) directory
303
	 *
304
	 * @return string The Gutenberg extensions directory
305
	 */
306
	public static function get_blocks_directory() {
307
		/**
308
		 * Filter to select Gutenberg blocks directory
309
		 *
310
		 * @since 6.9.0
311
		 *
312
		 * @param string default: '_inc/blocks/'
313
		 */
314
		return apply_filters( 'jetpack_blocks_directory', '_inc/blocks/' );
315
	}
316
317
	/**
318
	 * Checks for a given .json file in the blocks folder.
319
	 *
320
	 * @param string $preset The name of the .json file to look for.
321
	 *
322
	 * @return bool True if the file is found.
323
	 */
324
	public static function preset_exists( $preset ) {
325
		return file_exists( JETPACK__PLUGIN_DIR . self::get_blocks_directory() . $preset . '.json' );
326
	}
327
328
	/**
329
	 * Decodes JSON loaded from a preset file in the blocks folder
330
	 *
331
	 * @param string $preset The name of the .json file to load.
332
	 *
333
	 * @return mixed Returns an object if the file is present, or false if a valid .json file is not present.
334
	 */
335
	public static function get_preset( $preset ) {
336
		return json_decode(
337
			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
338
			file_get_contents( JETPACK__PLUGIN_DIR . self::get_blocks_directory() . $preset . '.json' )
339
		);
340
	}
341
342
	/**
343
	 * Returns a whitelist of Jetpack Gutenberg extensions (blocks and plugins), based on index.json
344
	 *
345
	 * @return array A list of blocks: eg [ 'publicize', 'markdown' ]
346
	 */
347
	public static function get_jetpack_gutenberg_extensions_whitelist() {
348
		$preset_extensions_manifest = self::preset_exists( 'index' ) ? self::get_preset( 'index' ) : (object) array();
349
350
		$preset_extensions = isset( $preset_extensions_manifest->production ) ? (array) $preset_extensions_manifest->production : array();
351
352
		if ( Constants::is_true( 'JETPACK_BETA_BLOCKS' ) ) {
353
			$beta_extensions = isset( $preset_extensions_manifest->beta ) ? (array) $preset_extensions_manifest->beta : array();
354
			return array_unique( array_merge( $preset_extensions, $beta_extensions ) );
355
		}
356
357
		return $preset_extensions;
358
	}
359
360
	/**
361
	 * Returns a diff from a combined list of whitelisted extensions and extensions determined to be excluded
362
	 *
363
	 * @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...
364
	 *
365
	 * @return array A list of blocks: eg array( 'publicize', 'markdown' )
366
	 */
367
	public static function get_available_extensions( $whitelisted_extensions = null ) {
368
		$exclusions             = get_option( 'jetpack_excluded_extensions', array() );
369
		$whitelisted_extensions = is_null( $whitelisted_extensions ) ? self::get_jetpack_gutenberg_extensions_whitelist() : $whitelisted_extensions;
370
371
		return array_diff( $whitelisted_extensions, $exclusions );
372
	}
373
374
	/**
375
	 * Get availability of each block / plugin.
376
	 *
377
	 * @return array A list of block and plugins and their availablity status
378
	 */
379
	public static function get_availability() {
380
		/**
381
		 * Fires before Gutenberg extensions availability is computed.
382
		 *
383
		 * In the function call you supply, use `jetpack_register_block()` to set a block as available.
384
		 * Alternatively, use `Jetpack_Gutenberg::set_extension_available()` (for a non-block plugin), and
385
		 * `Jetpack_Gutenberg::set_extension_unavailable()` (if the block or plugin should not be registered
386
		 * but marked as unavailable).
387
		 *
388
		 * @since 7.0.0
389
		 */
390
		do_action( 'jetpack_register_gutenberg_extensions' );
391
392
		$available_extensions = array();
393
394
		foreach ( self::$extensions as $extension ) {
395
			$is_available = self::is_registered( 'jetpack/' . $extension ) ||
396
			( isset( self::$availability[ $extension ] ) && true === self::$availability[ $extension ] );
397
398
			$available_extensions[ $extension ] = array(
399
				'available' => $is_available,
400
			);
401
402
			$attributes = self::get_attributes( 'jetpack/' . $extension );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $attributes is correct as self::get_attributes('jetpack/' . $extension) (which targets Jetpack_Gutenberg::get_attributes()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
403
			if ( isset( $attributes ) && isset( $attributes['limited'] ) ) {
404
				$available_extensions[ $extension ]['limited'] = $attributes['limited'];
405
			}
406
407
			if ( ! $is_available ) {
408
				$reason  = isset( self::$availability[ $extension ] ) ? self::$availability[ $extension ]['reason'] : 'missing_module';
409
				$details = isset( self::$availability[ $extension ] ) ? self::$availability[ $extension ]['details'] : array();
410
				$available_extensions[ $extension ]['unavailable_reason'] = $reason;
411
				$available_extensions[ $extension ]['details']            = $details;
412
			}
413
		}
414
415
		return $available_extensions;
416
	}
417
418
	/**
419
	 * Gets the attributes for a registered block
420
	 *
421
	 * @since ?
422
	 *
423
	 * @param string $slug Name of extension/block to check.
424
	 *
425
	 * @return null | array
426
	 */
427
	public static function get_attributes( $slug ) {
428
		$registered_block_type = WP_Block_Type_Registry::get_instance()->get_registered( $slug );
429
		if ( isset( $registered_block_type ) ) {
430
			return $registered_block_type->get_attributes();
431
		}
432
	}
433
434
	/**
435
	 * Check if an extension/block is already registered
436
	 *
437
	 * @since 7.2
438
	 *
439
	 * @param string $slug Name of extension/block to check.
440
	 *
441
	 * @return bool
442
	 */
443
	public static function is_registered( $slug ) {
444
		return WP_Block_Type_Registry::get_instance()->is_registered( $slug );
445
	}
446
447
	/**
448
	 * Check if Gutenberg editor is available
449
	 *
450
	 * @since 6.7.0
451
	 *
452
	 * @return bool
453
	 */
454
	public static function is_gutenberg_available() {
455
		return true;
456
	}
457
458
	/**
459
	 * Check whether conditions indicate Gutenberg Extensions (blocks and plugins) should be loaded
460
	 *
461
	 * Loading blocks and plugins is enabled by default and may be disabled via filter:
462
	 *   add_filter( 'jetpack_gutenberg', '__return_false' );
463
	 *
464
	 * @since 6.9.0
465
	 *
466
	 * @return bool
467
	 */
468
	public static function should_load() {
469
		if ( ! Jetpack::is_active() && ! Jetpack::is_development_mode() ) {
470
			return false;
471
		}
472
473
		/**
474
		 * Filter to disable Gutenberg blocks
475
		 *
476
		 * @since 6.5.0
477
		 *
478
		 * @param bool true Whether to load Gutenberg blocks
479
		 */
480
		return (bool) apply_filters( 'jetpack_gutenberg', true );
481
	}
482
483
	/**
484
	 * Only enqueue block assets when needed.
485
	 *
486
	 * @param string $type Slug of the block.
487
	 * @param array  $script_dependencies Script dependencies. Will be merged with automatically
488
	 *                                    detected script dependencies from the webpack build.
489
	 *
490
	 * @return void
491
	 */
492
	public static function load_assets_as_required( $type, $script_dependencies = array() ) {
493
		if ( is_admin() ) {
494
			// A block's view assets will not be required in wp-admin.
495
			return;
496
		}
497
498
		$type = sanitize_title_with_dashes( $type );
499
		self::load_styles_as_required( $type );
500
		self::load_scripts_as_required( $type, $script_dependencies );
501
	}
502
503
	/**
504
	 * Only enqueue block sytles when needed.
505
	 *
506
	 * @param string $type Slug of the block.
507
	 *
508
	 * @since 7.2.0
509
	 *
510
	 * @return void
511
	 */
512
	public static function load_styles_as_required( $type ) {
513
		if ( is_admin() ) {
514
			// A block's view assets will not be required in wp-admin.
515
			return;
516
		}
517
518
		// Enqueue styles.
519
		$style_relative_path = self::get_blocks_directory() . $type . '/view' . ( is_rtl() ? '.rtl' : '' ) . '.css';
520 View Code Duplication
		if ( self::block_has_asset( $style_relative_path ) ) {
521
			$style_version = self::get_asset_version( $style_relative_path );
522
			$view_style    = plugins_url( $style_relative_path, JETPACK__PLUGIN_FILE );
523
			wp_enqueue_style( 'jetpack-block-' . $type, $view_style, array(), $style_version );
524
		}
525
526
	}
527
528
	/**
529
	 * Only enqueue block scripts when needed.
530
	 *
531
	 * @param string $type Slug of the block.
532
	 * @param array  $dependencies Script dependencies. Will be merged with automatically
533
	 *                             detected script dependencies from the webpack build.
534
	 *
535
	 * @since 7.2.0
536
	 *
537
	 * @return void
538
	 */
539
	public static function load_scripts_as_required( $type, $dependencies = array() ) {
540
		if ( is_admin() ) {
541
			// A block's view assets will not be required in wp-admin.
542
			return;
543
		}
544
545
		// Enqueue script.
546
		$script_relative_path = self::get_blocks_directory() . $type . '/view.js';
547
		$script_deps_path     = JETPACK__PLUGIN_DIR . self::get_blocks_directory() . $type . '/view.deps.json';
548
549
		$script_dependencies = file_exists( $script_deps_path )
550
			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
551
			? json_decode( file_get_contents( $script_deps_path ) )
552
			: array();
553
		$script_dependencies = array_merge( $script_dependencies, $dependencies, array( 'wp-polyfill' ) );
554
555
		if ( ( ! class_exists( 'Jetpack_AMP_Support' ) || ! Jetpack_AMP_Support::is_amp_request() ) && self::block_has_asset( $script_relative_path ) ) {
556
			$script_version = self::get_asset_version( $script_relative_path );
557
			$view_script    = plugins_url( $script_relative_path, JETPACK__PLUGIN_FILE );
558
			wp_enqueue_script( 'jetpack-block-' . $type, $view_script, $script_dependencies, $script_version, false );
559
		}
560
561
		wp_localize_script(
562
			'jetpack-block-' . $type,
563
			'Jetpack_Block_Assets_Base_Url',
564
			plugins_url( self::get_blocks_directory(), JETPACK__PLUGIN_FILE )
565
		);
566
	}
567
568
	/**
569
	 * Check if an asset exists for a block.
570
	 *
571
	 * @param string $file Path of the file we are looking for.
572
	 *
573
	 * @return bool $block_has_asset Does the file exist.
574
	 */
575
	public static function block_has_asset( $file ) {
576
		return file_exists( JETPACK__PLUGIN_DIR . $file );
577
	}
578
579
	/**
580
	 * Get the version number to use when loading the file. Allows us to bypass cache when developing.
581
	 *
582
	 * @param string $file Path of the file we are looking for.
583
	 *
584
	 * @return string $script_version Version number.
585
	 */
586
	public static function get_asset_version( $file ) {
587
		return Jetpack::is_development_version() && self::block_has_asset( $file )
588
			? filemtime( JETPACK__PLUGIN_DIR . $file )
589
			: JETPACK__VERSION;
590
	}
591
592
	/**
593
	 * Load Gutenberg editor assets
594
	 *
595
	 * @since 6.7.0
596
	 *
597
	 * @return void
598
	 */
599
	public static function enqueue_block_editor_assets() {
600
		if ( ! self::should_load() ) {
601
			return;
602
		}
603
604
		// Required for Analytics. See _inc/lib/admin-pages/class.jetpack-admin-page.php.
605 View Code Duplication
		if ( ! Jetpack::is_development_mode() && Jetpack::is_active() ) {
606
			wp_enqueue_script( 'jp-tracks', '//stats.wp.com/w.js', array(), gmdate( 'YW' ), true );
607
		}
608
609
		$rtl        = is_rtl() ? '.rtl' : '';
610
		$beta       = Constants::is_true( 'JETPACK_BETA_BLOCKS' ) ? '-beta' : '';
611
		$blocks_dir = self::get_blocks_directory();
612
613
		$editor_script = plugins_url( "{$blocks_dir}editor{$beta}.js", JETPACK__PLUGIN_FILE );
614
		$editor_style  = plugins_url( "{$blocks_dir}editor{$beta}{$rtl}.css", JETPACK__PLUGIN_FILE );
615
616
		$editor_deps_path = JETPACK__PLUGIN_DIR . $blocks_dir . "editor{$beta}.deps.json";
617
		$editor_deps      = file_exists( $editor_deps_path )
618
			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
619
			? json_decode( file_get_contents( $editor_deps_path ) )
620
			: array();
621
		$editor_deps[] = 'wp-polyfill';
622
623
		$version = Jetpack::is_development_version() && file_exists( JETPACK__PLUGIN_DIR . $blocks_dir . 'editor.js' )
624
			? filemtime( JETPACK__PLUGIN_DIR . $blocks_dir . 'editor.js' )
625
			: JETPACK__VERSION;
626
627
		if ( method_exists( 'Jetpack', 'build_raw_urls' ) ) {
628
			$site_fragment = Jetpack::build_raw_urls( home_url() );
629
		} elseif ( class_exists( 'WPCOM_Masterbar' ) && method_exists( 'WPCOM_Masterbar', 'get_calypso_site_slug' ) ) {
630
			$site_fragment = WPCOM_Masterbar::get_calypso_site_slug( get_current_blog_id() );
631
		} else {
632
			$site_fragment = '';
633
		}
634
635
		wp_enqueue_script(
636
			'jetpack-blocks-editor',
637
			$editor_script,
638
			$editor_deps,
639
			$version,
640
			false
641
		);
642
643
		wp_localize_script(
644
			'jetpack-blocks-editor',
645
			'Jetpack_Block_Assets_Base_Url',
646
			plugins_url( $blocks_dir . '/', JETPACK__PLUGIN_FILE )
647
		);
648
649
		if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
650
			$user      = wp_get_current_user();
651
			$user_data = array(
652
				'userid'   => $user->ID,
653
				'username' => $user->user_login,
654
			);
655
			$blog_id   = get_current_blog_id();
656
		} else {
657
			$user_data = Jetpack_Tracks_Client::get_connected_user_tracks_identity();
658
			$blog_id   = Jetpack_Options::get_option( 'id', 0 );
659
		}
660
661
		wp_localize_script(
662
			'jetpack-blocks-editor',
663
			'Jetpack_Editor_Initial_State',
664
			array(
665
				'available_blocks' => self::get_availability(),
666
				'jetpack'          => array( 'is_active' => Jetpack::is_active() ),
667
				'siteFragment'     => $site_fragment,
668
				'tracksUserData'   => $user_data,
669
				'wpcomBlogId'      => $blog_id,
670
			)
671
		);
672
673
		wp_set_script_translations( 'jetpack-blocks-editor', 'jetpack' );
674
675
		wp_enqueue_style( 'jetpack-blocks-editor', $editor_style, array(), $version );
676
	}
677
678
	/**
679
	 * Some blocks do not depend on a specific module,
680
	 * and can consequently be loaded outside of the usual modules.
681
	 * We will look for such modules in the extensions/ directory.
682
	 *
683
	 * @since 7.1.0
684
	 */
685
	public static function load_independent_blocks() {
686
		if ( self::should_load() ) {
687
			/**
688
			 * Look for files that match our list of available Jetpack Gutenberg extensions (blocks and plugins).
689
			 * If available, load them.
690
			 */
691
			foreach ( self::$extensions as $extension ) {
692
				$extension_file_glob = glob( JETPACK__PLUGIN_DIR . 'extensions/*/' . $extension . '/' . $extension . '.php' );
693
				if ( ! empty( $extension_file_glob ) ) {
694
					include_once $extension_file_glob[0];
695
				}
696
			}
697
		}
698
	}
699
700
	/**
701
	 * Get CSS classes for a block.
702
	 *
703
	 * @since 7.7.0
704
	 *
705
	 * @param string $slug  Block slug.
706
	 * @param array  $attr  Block attributes.
707
	 * @param array  $extra Potential extra classes you may want to provide.
708
	 *
709
	 * @return string $classes List of CSS classes for a block.
710
	 */
711
	public static function block_classes( $slug = '', $attr, $extra = array() ) {
712
		if ( empty( $slug ) ) {
713
			return '';
714
		}
715
716
		// Basic block name class.
717
		$classes = array(
718
			'wp-block-jetpack-' . $slug,
719
		);
720
721
		// Add alignment if provided.
722
		if (
723
			! empty( $attr['align'] )
724
			&& in_array( $attr['align'], array( 'left', 'center', 'right', 'wide', 'full' ), true )
725
		) {
726
			array_push( $classes, 'align' . $attr['align'] );
727
		}
728
729
		// Add custom classes if provided in the block editor.
730
		if ( ! empty( $attr['className'] ) ) {
731
			array_push( $classes, $attr['className'] );
732
		}
733
734
		// Add any extra classes.
735
		if ( is_array( $extra ) && ! empty( $extra ) ) {
736
			$classes = array_merge( $classes, $extra );
737
		}
738
739
		return implode( ' ', $classes );
740
	}
741
}
742