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

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