Completed
Push — update/map-block-frontend-get-... ( 868a6e )
by
unknown
19:10 queued 11:46
created

Jetpack_Gutenberg   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 334
Duplicated Lines 2.99 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
dl 10
loc 334
rs 8.72
c 0
b 0
f 0
wmc 46
lcom 1
cbo 2

13 Methods

Rating   Name   Duplication   Size   Complexity  
A add_block() 0 3 1
B load_blocks() 0 31 8
A get_blocks_directory() 0 10 1
A preset_exists() 0 3 1
A get_preset() 0 3 1
A jetpack_set_available_blocks() 0 12 5
B get_block_availability() 0 34 9
A is_gutenberg_available() 0 3 1
A should_load_blocks() 0 14 3
B load_assets_as_required() 10 37 6
A block_has_asset() 0 3 1
A get_asset_version() 0 5 3
B enqueue_block_editor_assets() 0 65 6

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Jetpack_Gutenberg often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Jetpack_Gutenberg, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Handles server-side registration and use of all blocks available in Jetpack for the block editor, aka Gutenberg.
4
 * Works in tandem with client-side block registration via `block-manifest.json`
5
 *
6
 * @package Jetpack
7
 */
8
9
/**
10
 * Helper function to register a Jetpack Gutenberg block
11
 *
12
 * @param string $type Slug of the block. Will be prefixed with jetpack/.
13
 * @param array  $args Arguments that are passed into the register_block_type.
14
 * @param array  $avalibility Arguments that tells us what kind of avalibility the block has
0 ignored issues
show
Bug introduced by
There is no parameter named $avalibility. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
15
 *
16
 * @see register_block_type
17
 *
18
 * @since 6.7.0
19
 *
20
 * @return void
21
 */
22
function jetpack_register_block( $type, $args = array(), $availability = array( 'available' => true ) ) {
23
	$type = sanitize_title_with_dashes( $type );
24
	Jetpack_Gutenberg::add_block( $type, $args, $availability );
25
}
26
27
/**
28
 * General Gutenberg editor specific functionality
29
 */
30
class Jetpack_Gutenberg {
31
32
	/**
33
	 * Array of blocks we will be registering.
34
	 *
35
	 * @var array $blocks Array of blocks we will be registering.
36
	 */
37
	private static $jetpack_blocks = array();
38
	private static $blocks_index = array();
39
	/**
40
	 * Add a block to the list of blocks to be registered.
41
	 *
42
	 * @param string $type Slug of the block.
43
	 * @param array  $args Arguments that are passed into the register_block_type.
44
	 */
45
	public static function add_block( $type, $args, $availability ) {
46
		self::$jetpack_blocks[ $type ] = array( 'args' => $args, 'availability' => $availability );
47
	}
48
49
	/**
50
	 * Register all Jetpack blocks available.
51
	 *
52
	 * @return void|WP_Block_Type|false The registered block type on success, or false on failure.
53
	 */
54
	public static function load_blocks() {
55
		if ( ! self::is_gutenberg_available() ) {
56
			return;
57
		}
58
59
		if ( ! self::should_load_blocks() ) {
60
			return;
61
		}
62
63
		/**
64
		 * Filter the list of blocks that are available through jetpack.
65
		 *
66
		 * This filter is populated by Jetpack_Gutenberg::jetpack_set_available_blocks
67
		 *
68
		 * @since 6.8.0
69
		 *
70
		 * @param array
71
		 */
72
		self::$blocks_index = apply_filters( 'jetpack_set_available_blocks', array() );
73
74
		foreach ( self::$jetpack_blocks as $type => $args ) {
75
			if ( 'publicize' === $type ) {
76
				// publicize is not actually a block, it's a gutenberg plugin.
77
				// We will handle it's registration on the client-side.
78
				continue;
79
			}
80
			if ( isset( $args['availability']['available'] ) && $args['availability']['available'] && in_array( $type, self::$blocks_index ) ) {
81
				register_block_type( 'jetpack/' . $type, $args['args'] );
82
			}
83
		}
84
	}
85
86
	/**
87
	 * Return the Gutenberg extensions (blocks and plugins) directory
88
	 *
89
	 * @return string The Gutenberg extensions directory
90
	 */
91
	public static function get_blocks_directory() {
92
		/**
93
		 * Filter to select Gutenberg blocks directory
94
		 *
95
		 * @since 6.9
96
		 *
97
		 * @param string default: '_inc/blocks/'
98
		 */
99
		return apply_filters( 'jetpack_blocks_directory', '_inc/blocks/' );
100
	}
101
102
	/**
103
	 * Checks for a given .json file in the blocks folder.
104
	 *
105
	 * @param $preset The name of the .json file to look for.
106
	 *
107
	 * @return bool True if the file is found.
108
	 */
109
	public static function preset_exists( $preset ) {
110
		return file_exists( JETPACK__PLUGIN_DIR . self::get_blocks_directory() . $preset . '.json' );
111
	}
112
113
	/**
114
	 * Decodes JSON loaded from a preset file in the blocks folder
115
	 *
116
	 * @param $preset The name of the .json file to load.
117
	 *
118
	 * @return mixed Returns an object if the file is present, or false if a valid .json file is not present.
119
	 */
120
	public static function get_preset( $preset ) {
121
		return json_decode( file_get_contents(  JETPACK__PLUGIN_DIR .self::get_blocks_directory() . $preset . '.json' ) );
122
	}
123
124
	/**
125
	 * Filters the results of `apply_filter( 'jetpack_set_available_blocks', array() )`
126
	 * using the merged contents of `blocks-manifest.json` ( $preset_blocks )
127
	 * and self::$jetpack_blocks ( $internal_blocks )
128
	 *
129
	 * @param $blocks The default list.
130
	 *
131
	 * @return array A list of blocks: eg [ 'publicize', 'markdown' ]
132
	 */
133
	public static function jetpack_set_available_blocks( $blocks ) {
134
		$preset_blocks_manifest =  self::preset_exists( 'block-manifest' ) ? self::get_preset( 'block-manifest' ) : (object) array( 'blocks' => $blocks );
135
		$preset_blocks = isset( $preset_blocks_manifest->blocks ) ? (array) $preset_blocks_manifest->blocks : array() ;
136
		$internal_blocks = array_keys( self::$jetpack_blocks );
137
138
		if ( Jetpack_Constants::is_true( 'JETPACK_BETA_BLOCKS' ) ) {
139
			$beta_blocks = isset( $preset_blocks_manifest->betaBlocks ) ? (array) $preset_blocks_manifest->betaBlocks : array();
140
			return array_unique( array_merge( $preset_blocks, $beta_blocks, $internal_blocks ) );
141
		}
142
143
		return array_unique( array_merge( $preset_blocks, $internal_blocks ) );
144
	}
145
146
	/**
147
	 * @return array A list of block-availability information, eg: [ "publicize" => ["available" => true ], "markdown" => [ "available" => false, "unavailable_reason" => 'missing_module' ] ]
148
	 */
149
	public static function get_block_availability() {
150
151
		if ( ! self::should_load_blocks() ) {
152
			return array();
153
		}
154
155
		$blocks_availability = array(); // default
156
157
		foreach ( self::$jetpack_blocks as $type => $args ) {
158
			if ( ! in_array( $type,  self::$blocks_index ) ) {
159
				// Jetpack shouldn't expose blocks that are not in the manifest.
160
				continue;
161
			}
162
			$availability = $args['availability'];
163
			$available = array(
164
				'available' => ( isset( $availability['available'] ) ? (bool) $availability['available'] : true ),
165
			);
166
			$unavailability_reason = array();
167
			if ( ! $available['available'] ) {
168
				$unavailability_reason = array(
169
					'unavailable_reason' => ( isset( $availability['unavailable_reason'] ) ? $availability['unavailable_reason'] : 'unknown' )
170
				);
171
			}
172
			$blocks_availability[ $type ] = array_merge( $available, $unavailability_reason );
173
		}
174
175
		foreach ( self::$blocks_index as $block ) {
176
			if ( ! isset( $blocks_availability[ $block ] ) ) {
177
				$blocks_availability[ $block ] = array( 'available' => false, 'unavailable_reason' => 'missing_module' );
178
			}
179
		}
180
181
		return $blocks_availability;
182
	}
183
184
	/**
185
	 * Check if Gutenberg editor is available
186
	 *
187
	 * @since 6.7.0
188
	 *
189
	 * @return bool
190
	 */
191
	public static function is_gutenberg_available() {
192
		return function_exists( 'register_block_type' );
193
	}
194
195
	/**
196
	 * Check whether conditions indicate Gutenberg blocks should be loaded
197
	 *
198
	 * Loading blocks is enabled by default and may be disabled via filter:
199
	 *   add_filter( 'jetpack_gutenberg', '__return_false' );
200
	 *
201
	 * @since 6.7.0
202
	 *
203
	 * @return bool
204
	 */
205
	public static function should_load_blocks() {
206
		if ( ! Jetpack::is_active() && ! Jetpack::is_development_mode() ) {
207
			return false;
208
		}
209
210
		/**
211
		 * Filter to disable Gutenberg blocks
212
		 *
213
		 * @since 6.5.0
214
		 *
215
		 * @param bool true Whether to load Gutenberg blocks
216
		 */
217
		return (bool) apply_filters( 'jetpack_gutenberg', true );
218
	}
219
220
	/**
221
	 * Only enqueue block assets when needed.
222
	 *
223
	 * @param string $type slug of the block.
224
	 * @param array $script_dependencies An array of view-side Javascript dependencies to be enqueued.
225
	 * @param array $localize_data An array of view-side Javascript object accessible though the window object
226
	 *
227
	 * @return void
228
	 */
229
	public static function load_assets_as_required( $type, $script_dependencies = array(), $localize_data = array() ) {
230
		if ( is_admin() ) {
231
			// A block's view assets will not be required in wp-admin.
232
			return;
233
		}
234
235
		$type = sanitize_title_with_dashes( $type );
236
		// Enqueue styles.
237
		$style_relative_path = self::get_blocks_directory() . $type . '/view' . ( is_rtl() ? '.rtl' : '' ) . '.css';
238 View Code Duplication
		if ( self::block_has_asset( $style_relative_path ) ) {
239
			$style_version = self::get_asset_version( $style_relative_path );
240
			$view_style    = plugins_url( $style_relative_path, JETPACK__PLUGIN_FILE );
241
			wp_enqueue_style( 'jetpack-block-' . $type, $view_style, array(), $style_version );
242
		}
243
244
		// Enqueue script.
245
		$script_relative_path = self::get_blocks_directory() . $type . '/view.js';
246 View Code Duplication
		if ( self::block_has_asset( $script_relative_path ) ) {
247
			$script_version = self::get_asset_version( $script_relative_path );
248
			$view_script    = plugins_url( $script_relative_path, JETPACK__PLUGIN_FILE );
249
			wp_enqueue_script( 'jetpack-block-' . $type, $view_script, $script_dependencies, $script_version, false );
250
		}
251
252
		wp_localize_script(
253
			'jetpack-block-' . $type,
254
			'Jetpack_Block_Assets_Base_Url',
255
			plugins_url( self::get_blocks_directory(), JETPACK__PLUGIN_FILE )
256
		);
257
		if ( ! empty( $localize_data ) ) {
258
			wp_localize_script(
259
				'jetpack-block-' . $type,
260
				'Jetpack_Block_' . $type . '_data',
261
				$localize_data
262
			);
263
		}
264
265
	}
266
267
	/**
268
	 * Check if an asset exists for a block.
269
	 *
270
	 * @param string $file Path of the file we are looking for.
271
	 *
272
	 * @return bool $block_has_asset Does the file exist.
273
	 */
274
	public static function block_has_asset( $file ) {
275
		return file_exists( JETPACK__PLUGIN_DIR . $file );
276
	}
277
278
	/**
279
	 * Get the version number to use when loading the file. Allows us to bypass cache when developing.
280
	 *
281
	 * @param string $file Path of the file we are looking for.
282
	 *
283
	 * @return string $script_version Version number.
284
	 */
285
	public static function get_asset_version( $file ) {
286
		return Jetpack::is_development_version() && self::block_has_asset( $file )
287
			? filemtime( JETPACK__PLUGIN_DIR . $file )
288
			: JETPACK__VERSION;
289
	}
290
291
	/**
292
	 * Load Gutenberg editor assets
293
	 *
294
	 * @since 6.7.0
295
	 *
296
	 * @return void
297
	 */
298
	public static function enqueue_block_editor_assets() {
299
		if ( ! self::should_load_blocks() ) {
300
			return;
301
		}
302
303
		$rtl = is_rtl() ? '.rtl' : '';
304
		$beta = Jetpack_Constants::is_true('JETPACK_BETA_BLOCKS' ) ? '-beta' : '';
305
		$blocks_dir = self::get_blocks_directory();
306
307
		$editor_script = plugins_url( "{$blocks_dir}editor{$beta}.js", JETPACK__PLUGIN_FILE );
308
		$editor_style  = plugins_url( "{$blocks_dir}editor{$beta}{$rtl}.css", JETPACK__PLUGIN_FILE );
309
310
		$version       = Jetpack::is_development_version() && file_exists( JETPACK__PLUGIN_DIR . $blocks_dir . 'editor.js' )
311
			? filemtime( JETPACK__PLUGIN_DIR . $blocks_dir . 'editor.js' )
312
			: JETPACK__VERSION;
313
314
		wp_enqueue_script(
315
			'jetpack-blocks-editor',
316
			$editor_script,
317
			array(
318
				'lodash',
319
				'wp-api-fetch',
320
				'wp-blocks',
321
				'wp-components',
322
				'wp-compose',
323
				'wp-data',
324
				'wp-date',
325
				'wp-edit-post',
326
				'wp-editor',
327
				'wp-element',
328
				'wp-hooks',
329
				'wp-i18n',
330
				'wp-keycodes',
331
				'wp-plugins',
332
				'wp-rich-text',
333
				'wp-token-list',
334
				'wp-url',
335
			),
336
			$version,
337
			false
338
		);
339
340
		wp_localize_script(
341
			'jetpack-blocks-editor',
342
			'Jetpack_Block_Assets_Base_Url',
343
			plugins_url( $blocks_dir . '/', JETPACK__PLUGIN_FILE )
344
		);
345
346
		wp_localize_script(
347
			'jetpack-blocks-editor',
348
			'Jetpack_Editor_Initial_State',
349
			array(
350
				'available_blocks' => self::get_block_availability(),
351
				'jetpack' => array( 'is_active' => Jetpack::is_active() ),
352
			)
353
		);
354
355
		Jetpack::setup_wp_i18n_locale_data();
356
357
		wp_enqueue_style( 'jetpack-blocks-editor', $editor_style, array(), $version );
358
359
		// The social-logos styles are used for Publicize service icons
360
		// TODO: Remove when we ship the icons with the Gutenberg blocks build
361
		wp_enqueue_style( 'social-logos' );
362
	}
363
}
364