PluginProbe
Content Blocks Builder – Create blocks, repeater blocks with carousel, grid, popup layouts / trunk
Content Blocks Builder – Create blocks, repeater blocks with carousel, grid, popup layouts vtrunk
2.8.14 2.8.13 2.8.12 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.10 2.8.11 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 trunk 1.0.1 1.0.2 1.1.0 1.1.1 All 147 releases
content-blocks-builder / includes / patterns.php

patterns.php in Content Blocks Builder – Create blocks, repeater blocks with carousel, grid, popup layouts trunk, at includes/patterns.php

634 lines 16.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Register custom patterns
4 *
5 * @package BoldBlocks
6 * @author Phi Phan <mrphipv@gmail.com>
7 * @copyright Copyright (c) 2022, Phi Phan
8 */
9
10 namespace BoldBlocks;
11
12 // Exit if accessed directly.
13 defined( 'ABSPATH' ) || exit;
14
15 if ( ! class_exists( Patterns::class ) ) :
16 /**
17 * Manage custom patterns.
18 */
19 class Patterns extends CoreComponent {
20 /**
21 * Post type
22 *
23 * @var string
24 */
25 protected $post_type = 'boldblocks_pattern';
26
27 /**
28 * Post type helper instance
29 *
30 * @var PostType
31 */
32 protected $post_type_helper;
33
34 /**
35 * Store all custom patterns
36 *
37 * @var array
38 */
39 protected $all_custom_patterns = [];
40
41 /**
42 * Max items that can query
43 *
44 * @var integer
45 */
46 protected $max_items = 200;
47
48 /**
49 * Constructor
50 */
51 public function __construct( $the_plugin_instance ) {
52 parent::__construct( $the_plugin_instance );
53
54 $this->post_type_helper = PostType::get_instance();
55 }
56
57 /**
58 * Run main hooks
59 *
60 * @return void
61 */
62 public function run() {
63 // Register custom post type.
64 add_action( 'init', [ $this, 'register_custom_post_type' ], 5 );
65
66 // Load data for js.
67 add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_block_editor_assets' ] );
68
69 // Register patterns.
70 add_action( 'init', [ $this, 'register_patterns' ] );
71
72 // Custom pattern columns.
73 add_filter( 'manage_edit-' . $this->post_type . '_columns', [ $this, 'add_pattern_custom_columns' ] );
74 add_action( 'manage_' . $this->post_type . '_posts_custom_column', [ $this, 'manage_pattern_columns' ], 10, 2 );
75
76 // Add rest api endpoint to query all pattern categories.
77 add_action( 'rest_api_init', [ $this, 'register_get_pattern_categories_endpoint' ] );
78
79 // Register rest fields.
80 add_action( 'rest_api_init', [ $this, 'register_rest_fields' ] );
81
82 // Add meta fields to meta revisioning.
83 add_filter( 'boldblocks_post_revision_meta_keys', [ $this, 'add_fields_to_revision_meta_keys' ] );
84
85 // Change the placeholder text.
86 add_filter( 'enter_title_here', [ $this, 'enter_title_here' ] );
87
88 // Handle save post.
89 add_action( 'save_post_' . $this->post_type, [ $this, 'save_post' ], 10, 2 );
90
91 // Clear the transient cache on upgraded.
92 add_action( 'cbb/version_upgraded', [ $this, 'clear_transient_cache' ] );
93
94 // Force to remove custom fields.
95 add_action( 'add_meta_boxes', [ $this, 'remove_meta_boxes' ] );
96 }
97
98 /**
99 * Register custom post type
100 *
101 * @return void
102 */
103 public function register_custom_post_type() {
104 // Register pattern type.
105 $this->post_type_helper->register_post_type(
106 $this->post_type,
107 [
108 'rest_base' => 'boldblocks-patterns',
109 'show_in_menu' => 'edit.php?post_type=boldblocks_block',
110 'capabilities' => [
111 'read_post' => 'manage_options',
112 'edit_post' => 'manage_options',
113 'delete_post' => 'manage_options',
114 'edit_posts' => 'manage_options',
115 'delete_posts' => 'manage_options',
116 ],
117 ],
118 [
119 'name' => _x( 'Patterns', 'post type general name', 'content-blocks-builder' ),
120 'singular_name' => _x( 'Pattern', 'post type singular name', 'content-blocks-builder' ),
121 'name_admin_bar' => _x( 'Pattern', 'add new on admin bar', 'content-blocks-builder' ),
122 'all_items' => __( 'All Patterns', 'content-blocks-builder' ),
123 'add_new' => __( 'Add New Pattern', 'content-blocks-builder' ),
124 ]
125 );
126
127 // Pattern keywords.
128 $this->post_type_helper->register_taxonomy(
129 'boldblocks_pattern_keywords',
130 $this->post_type,
131 [],
132 [
133 'name' => _x( 'Keywords', 'Taxonomy General Name', 'content-blocks-builder' ),
134 'singular_name' => _x( 'Keyword', 'Taxonomy Singular Name', 'content-blocks-builder' ),
135 ]
136 );
137
138 // Meta fields.
139 $this->register_meta(
140 'boldblocks_pattern_categories',
141 [
142 'type' => 'array',
143 'show_in_rest' => array(
144 'schema' => array(
145 'items' => array(
146 'type' => 'object',
147 'properties' => array(
148 'name' => array(
149 'type' => 'string',
150 ),
151 'label' => array(
152 'type' => 'string',
153 ),
154 ),
155 ),
156 ),
157 ),
158 'default' => [],
159 ]
160 );
161
162 $this->register_meta( 'boldblocks_pattern_description' );
163
164 $this->register_meta(
165 'boldblocks_pattern_dependencies',
166 [
167 'type' => 'array',
168 'show_in_rest' => array(
169 'schema' => array(
170 'items' => array(
171 'type' => 'object',
172 'properties' => array(
173 'slug' => array(
174 'type' => 'string',
175 ),
176 'name' => array(
177 'type' => 'string',
178 ),
179 ),
180 ),
181 ),
182 ),
183 'default' => [],
184 ]
185 );
186
187 $this->register_meta(
188 'boldblocks_pattern_dependent_blocks',
189 [
190 'show_in_rest' => array(
191 'schema' => array(
192 'items' => array(
193 'type' => 'string',
194 ),
195 ),
196 ),
197 'type' => 'array',
198 'default' => [],
199 ]
200 );
201
202 $this->register_meta(
203 'boldblocks_pattern_block_types',
204 [
205 'type' => 'array',
206 'show_in_rest' => array(
207 'schema' => array(
208 'type' => 'array',
209 'items' => array(
210 'type' => 'string',
211 ),
212 ),
213 ),
214 'default' => [],
215 ]
216 );
217
218 $this->register_meta(
219 'boldblocks_pattern_disabled_inserter',
220 [
221 'type' => 'boolean',
222 'sanitize_callback' => 'rest_sanitize_boolean',
223 'default' => false,
224 ]
225 );
226
227 // Setting fields.
228 // phpcs:disable PluginCheck.CodeAnalysis.SettingSanitization.register_settingDynamic
229 register_setting(
230 'cbb',
231 'cbb_pattern_categories',
232 [
233 'type' => 'array',
234 'show_in_rest' => array(
235 'schema' => array(
236 'items' => array(
237 'type' => 'object',
238 'properties' => array(
239 'name' => array(
240 'type' => 'string',
241 ),
242 'label' => array(
243 'type' => 'string',
244 ),
245 ),
246 ),
247 ),
248 ),
249 'sanitize_callback' => function( $value ) {
250 if ( ! is_array( $value ) ) {
251 return [];
252 }
253
254 $categories = [];
255 foreach ( $value as $category ) {
256 if ( ! is_array( $category ) ) {
257 continue;
258 }
259
260 $categories[] = [
261 'name' => sanitize_text_field( $category['name'] ?? '' ),
262 'label' => sanitize_text_field( $category['label'] ?? '' ),
263 ];
264 }
265
266 return $categories;
267 },
268 'default' => [],
269 ]
270 );
271
272 register_setting(
273 'cbb',
274 'cbb_pattern_categories_all_label',
275 [
276 'type' => 'string',
277 'show_in_rest' => true,
278 'default' => __( 'All patterns by CBB', 'content-blocks-builder' ),
279 ]
280 );
281 // phpcs:enable PluginCheck.CodeAnalysis.SettingSanitization.register_settingDynamic
282 }
283
284 /**
285 * Register meta field
286 *
287 * @param string $meta_key
288 * @param array $args
289 * @return void
290 */
291 private function register_meta( $meta_key, $args = [] ) {
292 $this->post_type_helper->register_meta( $this->post_type, $meta_key, $args );
293 }
294
295 /**
296 * Remove custom meta boxes
297 *
298 * @param string $post_type
299 * @return void
300 */
301 public function remove_meta_boxes( $post_type ) {
302 if ( $post_type === $this->post_type ) {
303 remove_meta_box( 'postcustom', false, 'normal' );
304 }
305 }
306
307 /**
308 * Enqueue editor assets
309 *
310 * @return void
311 */
312 public function enqueue_block_editor_assets() {
313 // Custom blocks access file.
314 $patterns_asset = $this->the_plugin_instance->include_file( 'build/patterns.asset.php' );
315
316 // Scripts.
317 wp_enqueue_script(
318 'boldblocks-patterns',
319 $this->the_plugin_instance->get_file_uri( '/build/patterns.js' ),
320 $patterns_asset['dependencies'] ?? [],
321 $this->the_plugin_instance->get_script_version( $patterns_asset ),
322 [ 'in_footer' => true ]
323 );
324
325 // Add translation.
326 wp_set_script_translations( 'boldblocks-patterns', 'content-blocks-builder' );
327 }
328
329 /**
330 * Register all custom patterns
331 *
332 * @return void
333 */
334 public function register_patterns() {
335 // Register custom categories.
336 $pattern_categories = get_option( 'cbb_pattern_categories', [] );
337 if ( is_array( $pattern_categories ) ) {
338 foreach ( $pattern_categories as $category ) {
339 if ( ! empty( $category['name'] ) && ! empty( $category['label'] ) ) {
340 if ( ! \WP_Block_Pattern_Categories_Registry::get_instance()->is_registered( $category['name'] ) ) {
341 register_block_pattern_category( $category['name'], [ 'label' => $category['label'] ] );
342 }
343 }
344 }
345 }
346
347 // Register a custom category for patterns made by CBB.
348 register_block_pattern_category( 'cbb', [ 'label' => get_option( 'cbb_pattern_categories_all_label', _x( 'All patterns by CBB', 'CBB block pattern category', 'content-blocks-builder' ) ) ] );
349
350 if ( apply_filters( 'boldblocks_load_patterns', true ) ) {
351 // Query all patterns.
352 $pattern_posts = $this->get_all_custom_patterns();
353
354 foreach ( $pattern_posts as $pattern_name => $pattern_settings ) {
355 register_block_pattern(
356 sprintf( 'boldblocks/%s', $pattern_name ),
357 $pattern_settings
358 );
359 }
360 }
361 }
362
363 /**
364 * Get all custom patterns.
365 *
366 * @return array
367 */
368 public function get_all_custom_patterns() {
369 if ( ! $this->all_custom_patterns ) {
370 $this->all_custom_patterns = $this->get_posts( $this->the_plugin_instance->is_debug_mode() );
371 }
372
373 return $this->all_custom_patterns;
374 }
375
376 /**
377 * Query posts and cache the results.
378 *
379 * @param bool $force_refresh Optional. Whether to force the cache to be refreshed. Default false.
380 * @return array Array of WP_Post objects.
381 */
382 public function get_posts( $force_refresh = false ) {
383 if ( $force_refresh ) {
384 return $this->query_posts();
385 }
386
387 $cache_key = 'bb_pattern_posts';
388 $posts = get_transient( $cache_key );
389
390 // If nothing is found, build the object.
391 if ( false === $posts ) {
392 // Query posts.
393 $posts = $this->query_posts();
394
395 if ( ! is_wp_error( $posts ) && count( $posts ) > 0 ) {
396 set_transient( $cache_key, $posts, HOUR_IN_SECONDS );
397 }
398 }
399
400 return $posts;
401 }
402
403 /**
404 * Query and parse patterns
405 *
406 * @return array
407 */
408 public function query_posts() {
409 // Query all patterns.
410 $raw_posts = get_posts(
411 [
412 'post_type' => $this->post_type,
413 'posts_per_page' => $this->get_max_items(),
414 'orderby' => [
415 'menu_order' => 'DESC',
416 'date' => 'DESC',
417 ],
418 ]
419 );
420
421 $pattern_posts = [];
422
423 foreach ( $raw_posts as $pattern_post ) {
424 $blocks = parse_blocks( $pattern_post->post_content );
425 if ( count( $blocks ) === 0 ) {
426 continue;
427 }
428
429 $categories = get_post_meta( $pattern_post->ID, 'boldblocks_pattern_categories', true );
430 if ( ! is_array( $categories ) ) {
431 $categories = [];
432 } else {
433 $categories = array_map(
434 function( $item ) {
435 return $item['name'] ?? '';
436 },
437 $categories
438 );
439 }
440 $categories[] = 'cbb';
441
442 $pattern_settings = [
443 'title' => wp_strip_all_tags( $pattern_post->post_title ),
444 'content' => $pattern_post->post_content,
445 'categories' => $categories,
446 'description' => get_post_meta( $pattern_post->ID, 'boldblocks_pattern_description', true ) ?? '',
447 'inserter' => ! ( get_post_meta( $pattern_post->ID, 'boldblocks_pattern_disabled_inserter', true ) ?? false ),
448 ];
449
450 $keywords = get_the_terms( $pattern_post, 'boldblocks_pattern_keywords' );
451 if ( $keywords && ! is_wp_error( $keywords ) ) {
452 $keywords = wp_list_pluck( $keywords, 'name' );
453 } else {
454 $keywords = false;
455 }
456
457 if ( $keywords ) {
458 $pattern_settings['keywords'] = $keywords;
459 }
460
461 // Add blockTypes.
462 $pattern_settings['blockTypes'] = [];
463 if ( in_array( 'header', $categories, true ) ) {
464 $pattern_settings['blockTypes'][] = 'core/template-part/header';
465 }
466
467 if ( in_array( 'footer', $categories, true ) ) {
468 $pattern_settings['blockTypes'][] = 'core/template-part/footer';
469 }
470
471 if ( in_array( 'query', $categories, true ) ) {
472 $pattern_settings['blockTypes'][] = 'core/query';
473 }
474
475 $pattern_posts[ sanitize_key( $pattern_post->post_name ) ] = $pattern_settings;
476
477 }
478
479 return $pattern_posts;
480 }
481
482 /**
483 * Handle save post
484 *
485 * @param int $post_id
486 * @param WP_Post $post
487 * @return void
488 */
489 public function save_post( $post_id, $post ) {
490 // Ignore auto-draft status.
491 if ( 'auto-draft' === $post->post_status ) {
492 return;
493 }
494
495 // Ignore autosave.
496 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
497 return;
498 }
499
500 $this->clear_transient_cache();
501 }
502
503 /**
504 * Clear transient cache
505 *
506 * @return void
507 */
508 public function clear_transient_cache() {
509 delete_transient( 'bb_pattern_posts' );
510 }
511
512 /**
513 * Add custom columns to custom post type
514 *
515 * @param array $columns The array of columns.
516 * @return array
517 */
518 public function add_pattern_custom_columns( $columns ) {
519 $custom_columns = array(
520 'pattern_name' => esc_html__( 'Pattern name', 'content-blocks-builder' ),
521 );
522
523 // Add after title column.
524 $return = array_slice( $columns, 0, 2, true ) + $custom_columns + array_slice( $columns, 2, count( $columns ) - 2, true );
525
526 return $return;
527 }
528
529 /**
530 * Manage custom columns.
531 *
532 * @param string $column the column name.
533 * @param int $post_id the post id.
534 */
535 public function manage_pattern_columns( $column, $post_id ) {
536 switch ( $column ) {
537 case 'pattern_name':
538 echo esc_html( 'boldblocks/' . sanitize_key( get_post_field( 'post_name', $post_id ) ) );
539 break;
540
541 // Just break out of the switch statement for everything else.
542 default:
543 break;
544 }
545 }
546
547 /**
548 * Register an endpoint to query pattern categories.
549 *
550 * @return array
551 */
552 public function register_get_pattern_categories_endpoint() {
553 register_rest_route(
554 'boldblocks/v1',
555 '/getPatternCategories/',
556 array(
557 'methods' => 'GET',
558 'callback' => [ $this, 'get_pattern_categories' ],
559 'permission_callback' => '__return_true',
560 )
561 );
562 }
563
564 /**
565 * Build pattern categories.
566 *
567 * @param WP_Rest_Request $request
568 * @return WP_Rest_Response
569 */
570 public function get_pattern_categories( $request ) {
571 $categories = \WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered();
572
573 return $categories;
574 }
575
576 /**
577 * Add custom block's meta fields to meta revisioning.
578 *
579 * @param array $fields
580 * @return array
581 */
582 public function add_fields_to_revision_meta_keys( $fields ) {
583 return array_merge( $fields, [ 'boldblocks_pattern_categories' ] );
584 }
585
586 /**
587 * Register custom rest fields for easier getting, updating data.
588 *
589 * @return void
590 */
591 public function register_rest_fields() {
592 register_rest_field(
593 $this->post_type,
594 'keywords',
595 array(
596 'get_callback' => function( $params ) {
597 $keywords = wp_list_pluck( wp_get_object_terms( $params['id'], 'boldblocks_pattern_keywords' ), 'name' );
598
599 return \implode( ',', $keywords );
600 },
601 'update_callback' => function( $value, $post ) {
602 wp_set_post_terms( $post->ID, $value, 'boldblocks_pattern_keywords' );
603 },
604 'schema' => array(
605 'type' => 'string',
606 ),
607 )
608 );
609 }
610
611 /**
612 * Placeholder text. Default 'Add title'.
613 *
614 * @param string $text
615 * @return string
616 */
617 public function enter_title_here( $text ) {
618 $post_type = get_post_type();
619 if ( $this->post_type === $post_type ) {
620 $text = __( 'Add pattern title', 'content-blocks-builder' );
621 }
622
623 return $text;
624 }
625
626 /**
627 * Get max items
628 */
629 public function get_max_items() {
630 return apply_filters( 'cbb_get_max_items', $this->max_items, $this->post_type );
631 }
632 }
633 endif;
634