Completed
Pull Request — development (#1000)
by
unknown
07:02
created

Block_Container::set_script()   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 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Carbon_Fields\Container;
4
5
use Carbon_Fields\Datastore\Datastore;
6
use Carbon_Fields\Helper\Helper;
7
use Carbon_Fields\Exception\Incorrect_Syntax_Exception;
8
9
class Block_Container extends Container {
10
	/**
11
	 * {@inheritDoc}
12
	 */
13
	public $settings = array(
14
		'mode' => 'edit',
15
		'preview' => true,
16
		'parent' => null,
17
		'icon' => 'block-default',
18
		'inner_blocks' => array(
19
			'enabled' => false,
20
			'position' => 'above',
21
			'template' => null,
22
			'template_lock' => null,
23
			'allowed_blocks' => null,
24
		),
25
		'category' => array(
26
			'slug' => 'common',
27
		),
28
	);
29
30
	/**
31
	 * Mode map for settings
32
	 *
33
	 * @see set_mode()
34
	 * @var array
35
	 */
36
	protected $mode_map = array(
37
		'both' => array(
38
			'mode' => 'edit',
39
			'preview' => true,
40
		),
41
		'edit' => array(
42
			'mode' => 'edit',
43
			'preview' => false,
44
		),
45
		'preview' => array(
46
			'mode' => 'preview',
47
			'preview' => false,
48
		),
49
	);
50
51
	/***
52
	 * Block type render callback.
53
	 *
54
	 * @var callable
55
	 */
56
	protected $render_callback;
57
58
	/**
59
	 * {@inheritDoc}
60
	 */
61 View Code Duplication
	public function __construct( $id, $title, $type, $condition_collection, $condition_translator ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
62
		parent::__construct( $id, $title, $type, $condition_collection, $condition_translator );
63
64
		if ( ! $this->get_datastore() ) {
65
			$this->set_datastore( Datastore::make( 'empty' ), $this->has_default_datastore() );
66
		}
67
	}
68
69
	/**
70
	 * {@inheritDoc}
71
	 */
72
	public function init() {
73
		add_action( 'init', array( $this, '_attach' ) );
74
	}
75
76
	/**
77
	 * {@inheritDoc}
78
	 */
79
	public function is_valid_save() {
80
		// Return false because Gutenberg
81
		// will handle saving.
82
		return false;
83
	}
84
85
	/**
86
	 * {@inheritDoc}
87
	 */
88
	public function save( $data = null ) {
89
		// Nothing to do here because
90
		// the data is saved by Gutenberg.
91
	}
92
93
	/**
94
	 * {@inheritDoc}
95
	 */
96
	protected function get_environment_for_request() {
97
		return array();
98
	}
99
100
	/**
101
	 * {@inheritDoc}
102
	 */
103
	public function is_valid_attach_for_request() {
104
		return function_exists( 'register_block_type' );
105
	}
106
107
	/**
108
	 * {@inheritDoc}
109
	 */
110
	protected function get_environment_for_object( $object_id ) {
111
		return array();
112
	}
113
114
	/**
115
	 * {@inheritDoc}
116
	 */
117
	public function is_valid_attach_for_object( $object_id = null ) {
118
		return function_exists( 'register_block_type' );
119
	}
120
121
	/**
122
	 * {@inheritDoc}
123
	 */
124
	public function attach() {
125
		add_filter( 'block_categories', array( $this, 'attach_block_category' ), 10, 2 );
126
127
		$this->register_block();
128
	}
129
130
	/**
131
	 * Attach the category of the block type.
132
	 *
133
	 * @param  array $categories
134
	 * @return array
135
	 */
136
	public function attach_block_category( $categories ) {
137
		foreach ( $categories as $category ) {
138
			if ( $category[ 'slug' ] === $this->settings[ 'category' ][ 'slug' ] ) {
139
				return $categories;
140
			}
141
		}
142
143
		return array_merge( $categories, array( $this->settings[ 'category' ] ) );
144
	}
145
146
	/**
147
	 * Set the description of the block type.
148
	 *
149
	 * @see https://wordpress.org/gutenberg/handbook/designers-developers/developers/block-api/block-registration/#description-optional
150
	 *
151
	 * @param  string $description
152
	 * @return Block_Container
153
	 */
154
	public function set_description( $description ) {
155
		$this->settings[ 'description' ] = $description;
156
157
		return $this;
158
	}
159
160
	/**
161
	 * Set the category of the block type.
162
	 *
163
	 * @see https://wordpress.org/gutenberg/handbook/designers-developers/developers/block-api/block-registration/#category
164
	 *
165
	 * @param  string $slug
166
	 * @param  string $title
167
	 * @param  string $icon
168
	 * @return Block_Container
169
	 */
170
	public function set_category( $slug, $title = null, $icon = null ) {
171
		$this->settings[ 'category' ][ 'slug' ] = $slug;
172
		$this->settings[ 'category' ][ 'icon' ] = $icon;
173
		$this->settings[ 'category' ][ 'title' ] = $title ?: Helper::normalize_label( $slug );
174
175
		return $this;
176
	}
177
178
	/**
179
	 * Set the icon of the block type.
180
	 *
181
	 * @see https://developer.wordpress.org/resource/dashicons
182
	 * @see https://wordpress.org/gutenberg/handbook/designers-developers/developers/block-api/block-registration/#icon-optional
183
	 *
184
	 * @param  string $icon
185
	 * @return Block_Container
186
	 */
187
	public function set_icon( $icon ) {
188
		$this->settings[ 'icon' ] = $icon;
189
190
		return $this;
191
	}
192
193
	/**
194
	 * Set the keywords of the block type.
195
	 *
196
	 * @see https://wordpress.org/gutenberg/handbook/designers-developers/developers/block-api/block-registration/#keywords-optional
197
	 *
198
	 * @param  array $keywords
199
	 * @return Block_Container
200
	 */
201
	public function set_keywords( $keywords = array() ) {
202
		$this->settings[ 'keywords' ] = array_slice( $keywords, 0, 3 );
203
204
		return $this;
205
	}
206
207
	/**
208
	 * Set a style handle.
209
	 *
210
	 * @param  string $key
211
	 * @param  string $handle
212
	 * @return Block_Container
213
	 */
214
	protected function set_style_handle( $key, $handle ) {
215
		if ( ! wp_style_is( $handle ) ) {
216
			throw new \Exception( __( "Style '$handle' is not enqueued.", 'crb' ) );
217
		}
218
219
		$this->settings[ $key ] = $handle;
220
221
		return $this;
222
	}
223
224
	/**
225
	 * Set the style of the block type.
226
	 *
227
	 * @param  string $handle
228
	 * @return Block_Container
229
	 */
230
	public function set_style( $handle ) {
231
		return $this->set_style_handle( 'style', $handle );
232
	}
233
234
	/**
235
	 * Set the editor style of the block type.
236
	 *
237
	 * @param  string $handle
238
	 * @return Block_Container
239
	 */
240
	public function set_editor_style( $handle ) {
241
		return $this->set_style_handle( 'editor_style', $handle );
242
	}
243
244
	/**
245
	 * Set a script handle.
246
	 *
247
	 * @param  string $key
248
	 * @param  string $handle
249
	 * @return Block_Container
250
	 */
251
	protected function set_script_handle( $key, $handle ) {
252
		if ( ! wp_script_is( $handle, "enqueued" ) && ! wp_script_is( $handle, "registered" ) ) {
253
			throw new \Exception( __( "script '$handle' is not enqueued or registered.", 'crb' ) );
254
		}
255
256
		$this->settings[ $key ] = $handle;
257
258
		return $this;
259
	}
260
261
	/**
262
	 * Set the script of the block type.
263
	 *
264
	 * @param  string $handle
265
	 * @return Block_Container
266
	 */
267
	public function set_script( $handle ) {
268
		return $this->set_script_handle( 'script', $handle );
269
	}
270
271
	/**
272
	 * Set the editor script of the block type.
273
	 *
274
	 * @param  string $handle
275
	 * @return Block_Container
276
	 */
277
	public function set_editor_script( $handle ) {
278
		return $this->set_script_handle( 'editor_script', $handle );
279
	}
280
281
	/**
282
	 * Set whether the preview mode is available for the block type.
283
	 *
284
	 * @param  boolean $preview
285
	 * @return Block_Container
286
	 */
287
	public function set_preview_mode( $preview = true ) {
288
		_deprecated_function( __FUNCTION__, '3.0', 'set_mode()' );
289
290
		$mode = $preview ? 'both' : 'edit';
291
		$this->set_mode( $mode );
292
293
		return $this;
294
	}
295
296
	/**
297
	 * Set the mode for the block type.
298
	 *
299
	 * @param  string $mode
300
	 * @return Block_Container
301
	 */
302
	public function set_mode( $mode ) {
303
		$modes = array_keys( $this->mode_map );
304
		if ( ! in_array( $mode, $modes ) ) {
305
			Incorrect_Syntax_Exception::raise( 'The mode must be one of the following: ' . implode( ', ', $modes ) );
306
		}
307
308
		$this->settings[ 'mode' ] = $this->mode_map[ $mode ][ 'mode' ];
309
		$this->settings[ 'preview' ] = $this->mode_map[ $mode ][ 'preview' ];
310
311
		return $this;
312
	}
313
314
	/**
315
	 * Set the parent block(s) in which the block type can be inserted.
316
	 *
317
	 * @see https://wordpress.org/gutenberg/handbook/designers-developers/developers/block-api/block-registration/#parent-optional
318
	 *
319
	 * @param  string|string[]|null $parent
320
	 * @return Block_Container
321
	 */
322
	public function set_parent( $parent = null ) {
323 View Code Duplication
		if ( ! is_array( $parent ) && ! is_string( $parent ) && ! is_null( $parent ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
324
			throw new \Exception( __( "The parent must be 'array', 'string' or 'null'.", 'crb' ) );
325
		}
326
327
		$this->settings[ 'parent' ] = is_string( $parent ) ? array( $parent ) : $parent;
328
329
		return $this;
330
	}
331
332
	/**
333
	 * Set whether the inner blocks are available for the block type.
334
	 *
335
	 * @param  boolean $inner_blocks
336
	 * @return Block_Container
337
	 */
338
	public function set_inner_blocks( $inner_blocks = true ) {
339
		$this->settings[ 'inner_blocks' ][ 'enabled' ] = $inner_blocks;
340
341
		return $this;
342
	}
343
344
	/**
345
	 * Set the position of the inner blocks to be rendered
346
	 * above or below the fields.
347
	 *
348
	 * @param  string $position
349
	 * @return Block_Container
350
	 */
351 View Code Duplication
	public function set_inner_blocks_position( $position = 'above' ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
352
		if ( ! in_array( $position, [ 'above', 'below' ] ) ) {
353
			throw new \Exception( __( "The position of inner blocks must be 'above' or 'below'.", 'crb' ) );
354
		}
355
356
		$this->settings[ 'inner_blocks' ][ 'position' ] = $position;
357
358
		return $this;
359
	}
360
361
	/**
362
	 * Set the default template that should be rendered in inner blocks.
363
	 *
364
	 * @see https://github.com/WordPress/gutenberg/tree/master/packages/editor/src/components/inner-blocks#template
365
	 *
366
	 * @param  array[]|null $template
367
	 * @return Block_Container
368
	 */
369
	public function set_inner_blocks_template( $template = null ) {
370 View Code Duplication
		if ( ! is_array( $template ) && ! is_null( $template ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
371
			throw new \Exception( __( "The template must be an 'array' or 'null'.", 'crb' ) );
372
		}
373
374
		$this->settings[ 'inner_blocks' ][ 'template' ] = $template;
375
376
		return $this;
377
	}
378
379
	/**
380
	 * Set the lock mode used by template of inner blocks.
381
	 *
382
	 * @see https://github.com/WordPress/gutenberg/tree/master/packages/editor/src/components/inner-blocks#templatelock
383
	 *
384
	 * @param  string|boolean|null $lock
385
	 * @return Block_Container
386
	 */
387 View Code Duplication
	public function set_inner_blocks_template_lock( $lock = null ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
388
		if ( is_string( $lock ) && ! in_array( $lock, [ 'all', 'insert' ] ) ) {
389
			throw new \Exception( __( "The template lock must be 'all', 'insert', 'false' or 'null'.", 'crb' ) );
390
		}
391
392
		$this->settings[ 'inner_blocks' ][ 'template_lock' ] = $lock;
393
394
		return $this;
395
	}
396
397
	/**
398
	 * Set the list of allowed blocks that can be inserted.
399
	 *
400
	 * @see https://github.com/WordPress/gutenberg/tree/master/packages/editor/src/components/inner-blocks#allowedblocks
401
	 *
402
	 * @param  string[]|null $blocks
403
	 * @return Block_Container
404
	 */
405
	public function set_allowed_inner_blocks( $blocks = null ) {
406 View Code Duplication
		if ( ! is_array( $blocks ) && ! is_null( $blocks ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
407
			throw new \Exception( __( "The allowed blocks must be an 'array' or 'null'.", 'crb' ) );
408
		}
409
410
		if ( is_array( $blocks ) ) {
411
			$this->settings[ 'inner_blocks' ][ 'allowed_blocks' ] = array_map( function ( $block ) {
412
				if ( $block instanceof self ) {
413
					return $block->get_block_type_name();
414
				}
415
416
				return $block;
417
			}, $blocks );
418
		} else {
419
			$this->settings[ 'inner_blocks' ][ 'allowed_blocks' ] = $blocks;
420
		}
421
422
		return $this;
423
	}
424
425
	/**
426
	 * Set the render callback of the block type.
427
	 *
428
	 * @see https://wordpress.org/gutenberg/handbook/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks/
429
	 *
430
	 * @param  callable $render_callback
431
	 * @return Block_Container
432
	 */
433
	public function set_render_callback( $render_callback ) {
434
		$this->render_callback = $render_callback;
435
436
		return $this;
437
	}
438
439
	/**
440
	 * Render the block type.
441
	 *
442
	 * @param  array  $attributes
443
	 * @param  string $content
444
	 * @return string
445
	 */
446
	public function render_block( $attributes, $content ) {
447
		$fields = $attributes['data'];
448
449
		// Unset the "data" property because we
450
		// pass it as separate argument to the callback.
451
		unset($attributes['data']);
452
453
		ob_start();
454
455
		call_user_func( $this->render_callback , $fields, $attributes, $content );
456
457
		return ob_get_clean();
458
	}
459
460
	/**
461
	 * Returns the block type name, e.g. "carbon-fields/testimonial"
462
	 */
463
	private function get_block_type_name() {
464
		return str_replace( 'carbon-fields-container-', 'carbon-fields/', str_replace( '_', '-', $this->id ) );
465
	}
466
467
	/**
468
	 * Register the block type.
469
	 *
470
	 * @return void
471
	 */
472
	protected function register_block() {
473
		if ( is_null( $this->render_callback ) ) {
474
			throw new \Exception( __( "'render_callback' is required for the blocks.", 'crb' ) );
475
		}
476
477
		if ( ! is_callable( $this->render_callback ) ) {
478
			throw new \Exception( __( "'render_callback' must be a callable.", 'crb' ) );
479
		}
480
481
		$style = isset( $this->settings[ 'style' ] ) ? $this->settings[ 'style' ] : null;
482
		$editor_style = isset( $this->settings[ 'editor_style' ] ) ? $this->settings[ 'editor_style' ] : null;
483
		$script = isset( $this->settings[ 'script' ] ) ? $this->settings[ 'script' ] : null;
484
		$editor_script = isset( $this->settings[ 'editor_script' ] ) ? $this->settings[ 'editor_script' ] : null;
485
		$attributes = array_reduce( $this->get_fields(), function( $attributes, $field ) {
486
			$attributes[ 'data' ][ 'default' ][ $field->get_base_name() ] = $field->get_default_value();
487
488
			return $attributes;
489
		}, array(
490
			'data' => array(
491
				'type' => 'object',
492
				'default' => array(),
493
			),
494
		) );
495
496
		register_block_type( $this->get_block_type_name(), array(
497
			'style' => $style,
498
			'editor_style' => $editor_style,
499
			'script' => $script,
500
			'editor_script' => $editor_script,
501
			'attributes' => $attributes,
502
			'render_callback' => array( $this, 'render_block' ),
503
		) );
504
	}
505
}
506