PluginProbe
Content Blocks Builder – Create blocks, repeater blocks with carousel, grid, popup layouts / 2.7.8
Content Blocks Builder – Create blocks, repeater blocks with carousel, grid, popup layouts v2.7.8
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 2.7.8, at includes/patterns.php

612 lines 15.6 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 'default' => false,
223 ]
224 );
225
226 // Setting fields.
227 register_setting(
228 'boldblocks',
229 'boldblocks_pattern_categories',
230 [
231 'type' => 'array',
232 'show_in_rest' => array(
233 'schema' => array(
234 'items' => array(
235 'type' => 'object',
236 'properties' => array(
237 'name' => array(
238 'type' => 'string',
239 ),
240 'label' => array(
241 'type' => 'string',
242 ),
243 ),
244 ),
245 ),
246 ),
247 'default' => [],
248 ]
249 );
250
251 register_setting(
252 'boldblocks',
253 'boldblocks_pattern_categories_all_label',
254 [
255 'type' => 'string',
256 'show_in_rest' => true,
257 'default' => __( 'All patterns by CBB', 'content-blocks-builder' ),
258 ]
259 );
260 }
261
262 /**
263 * Register meta field
264 *
265 * @param string $meta_key
266 * @param array $args
267 * @return void
268 */
269 private function register_meta( $meta_key, $args = [] ) {
270 $this->post_type_helper->register_meta( $this->post_type, $meta_key, $args );
271 }
272
273 /**
274 * Remove custom meta boxes
275 *
276 * @param string $post_type
277 * @return void
278 */
279 public function remove_meta_boxes( $post_type ) {
280 if ( $post_type === $this->post_type ) {
281 remove_meta_box( 'postcustom', false, 'normal' );
282 }
283 }
284
285 /**
286 * Enqueue editor assets
287 *
288 * @return void
289 */
290 public function enqueue_block_editor_assets() {
291 // Custom blocks access file.
292 $patterns_asset = $this->the_plugin_instance->include_file( 'build/patterns.asset.php' );
293
294 // Scripts.
295 wp_enqueue_script(
296 'boldblocks-patterns',
297 $this->the_plugin_instance->get_file_uri( '/build/patterns.js' ),
298 $patterns_asset['dependencies'] ?? [],
299 $this->the_plugin_instance->get_script_version( $patterns_asset ),
300 [ 'in_footer' => true ]
301 );
302
303 // Add translation.
304 wp_set_script_translations( 'boldblocks-patterns', 'content-blocks-builder' );
305 }
306
307 /**
308 * Register all custom patterns
309 *
310 * @return void
311 */
312 public function register_patterns() {
313 // Register custom categories.
314 $pattern_categories = get_option( 'boldblocks_pattern_categories', [] );
315 if ( is_array( $pattern_categories ) ) {
316 foreach ( $pattern_categories as $category ) {
317 if ( ! empty( $category['name'] ) && ! empty( $category['label'] ) ) {
318 if ( ! \WP_Block_Pattern_Categories_Registry::get_instance()->is_registered( $category['name'] ) ) {
319 register_block_pattern_category( $category['name'], [ 'label' => $category['label'] ] );
320 }
321 }
322 }
323 }
324
325 // Register a custom category for patterns made by BoldBlocks.
326 register_block_pattern_category( 'boldblocks', [ 'label' => get_option( 'boldblocks_pattern_categories_all_label', _x( 'All patterns by CBB', 'Block pattern category', 'content-blocks-builder' ) ) ] );
327
328 if ( apply_filters( 'boldblocks_load_patterns', true ) ) {
329 // Query all patterns.
330 $pattern_posts = $this->get_all_custom_patterns();
331
332 foreach ( $pattern_posts as $pattern_name => $pattern_settings ) {
333 register_block_pattern(
334 sprintf( 'boldblocks/%s', $pattern_name ),
335 $pattern_settings
336 );
337 }
338 }
339 }
340
341 /**
342 * Get all custom patterns.
343 *
344 * @return array
345 */
346 public function get_all_custom_patterns() {
347 if ( ! $this->all_custom_patterns ) {
348 $this->all_custom_patterns = $this->get_posts( $this->the_plugin_instance->is_debug_mode() );
349 }
350
351 return $this->all_custom_patterns;
352 }
353
354 /**
355 * Query posts and cache the results.
356 *
357 * @param bool $force_refresh Optional. Whether to force the cache to be refreshed. Default false.
358 * @return array Array of WP_Post objects.
359 */
360 public function get_posts( $force_refresh = false ) {
361 if ( $force_refresh ) {
362 return $this->query_posts();
363 }
364
365 $cache_key = 'bb_pattern_posts';
366 $posts = get_transient( $cache_key );
367
368 // If nothing is found, build the object.
369 if ( false === $posts ) {
370 // Query posts.
371 $posts = $this->query_posts();
372
373 if ( ! is_wp_error( $posts ) && count( $posts ) > 0 ) {
374 set_transient( $cache_key, $posts, HOUR_IN_SECONDS );
375 }
376 }
377
378 return $posts;
379 }
380
381 /**
382 * Query and parse patterns
383 *
384 * @return array
385 */
386 public function query_posts() {
387 // Query all patterns.
388 $raw_posts = get_posts(
389 [
390 'post_type' => $this->post_type,
391 'posts_per_page' => $this->get_max_items(),
392 'orderby' => [
393 'menu_order' => 'DESC',
394 'date' => 'DESC',
395 ],
396 ]
397 );
398
399 $pattern_posts = [];
400
401 foreach ( $raw_posts as $pattern_post ) {
402 $blocks = parse_blocks( $pattern_post->post_content );
403 if ( count( $blocks ) === 0 ) {
404 continue;
405 }
406
407 $categories = get_post_meta( $pattern_post->ID, 'boldblocks_pattern_categories', true );
408 if ( ! is_array( $categories ) ) {
409 $categories = [];
410 } else {
411 $categories = array_map(
412 function( $item ) {
413 return $item['name'] ?? '';
414 },
415 $categories
416 );
417 }
418 $categories[] = 'boldblocks';
419
420 $pattern_settings = [
421 'title' => wp_strip_all_tags( $pattern_post->post_title ),
422 'content' => $pattern_post->post_content,
423 'categories' => $categories,
424 'description' => get_post_meta( $pattern_post->ID, 'boldblocks_pattern_description', true ) ?? '',
425 'inserter' => ! ( get_post_meta( $pattern_post->ID, 'boldblocks_pattern_disabled_inserter', true ) ?? false ),
426 ];
427
428 $keywords = get_the_terms( $pattern_post, 'boldblocks_pattern_keywords' );
429 if ( $keywords && ! is_wp_error( $keywords ) ) {
430 $keywords = wp_list_pluck( $keywords, 'name' );
431 } else {
432 $keywords = false;
433 }
434
435 if ( $keywords ) {
436 $pattern_settings['keywords'] = $keywords;
437 }
438
439 // Add blockTypes.
440 $pattern_settings['blockTypes'] = [];
441 if ( in_array( 'header', $categories, true ) ) {
442 $pattern_settings['blockTypes'][] = 'core/template-part/header';
443 }
444
445 if ( in_array( 'footer', $categories, true ) ) {
446 $pattern_settings['blockTypes'][] = 'core/template-part/footer';
447 }
448
449 if ( in_array( 'query', $categories, true ) ) {
450 $pattern_settings['blockTypes'][] = 'core/query';
451 }
452
453 $pattern_posts[ sanitize_key( $pattern_post->post_name ) ] = $pattern_settings;
454
455 }
456
457 return $pattern_posts;
458 }
459
460 /**
461 * Handle save post
462 *
463 * @param int $post_id
464 * @param WP_Post $post
465 * @return void
466 */
467 public function save_post( $post_id, $post ) {
468 // Ignore auto-draft status.
469 if ( 'auto-draft' === $post->post_status ) {
470 return;
471 }
472
473 // Ignore autosave.
474 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
475 return;
476 }
477
478 $this->clear_transient_cache();
479 }
480
481 /**
482 * Clear transient cache
483 *
484 * @return void
485 */
486 public function clear_transient_cache() {
487 delete_transient( 'bb_pattern_posts' );
488 }
489
490 /**
491 * Add custom columns to custom post type
492 *
493 * @param array $columns The array of columns.
494 * @return array
495 */
496 public function add_pattern_custom_columns( $columns ) {
497 $custom_columns = array(
498 'pattern_name' => esc_html__( 'Pattern name', 'content-blocks-builder' ),
499 );
500
501 // Add after title column.
502 $return = array_slice( $columns, 0, 2, true ) + $custom_columns + array_slice( $columns, 2, count( $columns ) - 2, true );
503
504 return $return;
505 }
506
507 /**
508 * Manage custom columns.
509 *
510 * @param string $column the column name.
511 * @param int $post_id the post id.
512 */
513 public function manage_pattern_columns( $column, $post_id ) {
514 switch ( $column ) {
515 case 'pattern_name':
516 echo esc_html( 'boldblocks/' . sanitize_key( get_post_field( 'post_name', $post_id ) ) );
517 break;
518
519 // Just break out of the switch statement for everything else.
520 default:
521 break;
522 }
523 }
524
525 /**
526 * Register an endpoint to query pattern categories.
527 *
528 * @return array
529 */
530 public function register_get_pattern_categories_endpoint() {
531 register_rest_route(
532 'boldblocks/v1',
533 '/getPatternCategories/',
534 array(
535 'methods' => 'GET',
536 'callback' => [ $this, 'get_pattern_categories' ],
537 'permission_callback' => '__return_true',
538 )
539 );
540 }
541
542 /**
543 * Build pattern categories.
544 *
545 * @param WP_Rest_Request $request
546 * @return WP_Rest_Response
547 */
548 public function get_pattern_categories( $request ) {
549 $categories = \WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered();
550
551 return $categories;
552 }
553
554 /**
555 * Add custom block's meta fields to meta revisioning.
556 *
557 * @param array $fields
558 * @return array
559 */
560 public function add_fields_to_revision_meta_keys( $fields ) {
561 return array_merge( $fields, [ 'boldblocks_pattern_categories' ] );
562 }
563
564 /**
565 * Register custom rest fields for easier getting, updating data.
566 *
567 * @return void
568 */
569 public function register_rest_fields() {
570 register_rest_field(
571 $this->post_type,
572 'keywords',
573 array(
574 'get_callback' => function( $params ) {
575 $keywords = wp_list_pluck( wp_get_object_terms( $params['id'], 'boldblocks_pattern_keywords' ), 'name' );
576
577 return \implode( ',', $keywords );
578 },
579 'update_callback' => function( $value, $post ) {
580 wp_set_post_terms( $post->ID, $value, 'boldblocks_pattern_keywords' );
581 },
582 'schema' => array(
583 'type' => 'string',
584 ),
585 )
586 );
587 }
588
589 /**
590 * Placeholder text. Default 'Add title'.
591 *
592 * @param string $text
593 * @return string
594 */
595 public function enter_title_here( $text ) {
596 $post_type = get_post_type();
597 if ( $this->post_type === $post_type ) {
598 $text = __( 'Add pattern title', 'content-blocks-builder' );
599 }
600
601 return $text;
602 }
603
604 /**
605 * Get max items
606 */
607 public function get_max_items() {
608 return apply_filters( 'cbb_get_max_items', $this->max_items, $this->post_type );
609 }
610 }
611 endif;
612