├── BlocksLogo.png
├── README.md
├── acf-block-field.php
├── advanced-custom-blocks.php
└── assets
├── 44556941-25c55100-a70a-11e8-8ff5-b51c312be386.png
├── 44556962-49889700-a70a-11e8-89de-b8c6f9693cd8.png
├── 44556981-6755fc00-a70a-11e8-9a69-47a9aad03f3d.png
├── 44557063-d4699180-a70a-11e8-8f55-3b8528852361.png
└── BlocksLogo.png
/BlocksLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchipka/advanced-custom-blocks/c6b80345ea9ebcf10464480ce043ef662a9f8b0f/BlocksLogo.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Advanced Custom Blocks
2 |
3 | Create custom blocks for the new Wordpress [Gutenberg editor](https://github.com/WordPress/gutenberg) using [Advanced Custom Fields](https://github.com/elliotcondon/acf).
4 |
5 | 
6 |
7 |
8 |
9 |
10 |
11 |
12 | Key Features •
13 | Installation •
14 | How to make a block •
15 | How To Use The Block •
16 | Credits •
17 | Related •
18 | License
19 |
20 |
21 |
22 | ## Motivation
23 | Make an easy straightforward way for Wordpress developers to create custom Gutenberg blocks using a pipeline they are already familiar with.
24 |
25 | ## Installation
26 |
27 | Download the zipped folder from Github, and then [install manually to Wordpress via upload](https://themetry.com/docs/install-wordpress-plugin-zip-upload/) in the admin interface.
28 |
29 | ## How to make a block
30 | 1. First create a custom field group in ACF and set the location rules to target the block.
31 |
32 | 
33 |
34 | 2. Next, at the bottom of the field group page you can set the block name, and the icon that will appear in the Gutenberg block menu.
35 |
36 | 
37 |
38 | 3. Create `testimonial.php` inside of the `blocks/acf/` directory within your theme
39 |
40 | ```
41 |
42 |
43 |
the_field('author'); ?>
44 |
the_field('testimonial'); ?>
45 |
46 | ```
47 |
48 |
49 | ## How to use the block
50 |
51 | It's really simple! Just add the block when from the normal Gutenberg insert block menu when writing a post.
52 |
53 | 
54 |
55 | And you can add multiple blocks of the same kind, similar to the repeater field.
56 |
57 | 
58 |
59 |
60 | ## Rendering block content
61 |
62 | Here are the ways in which Advanced Custom Blocks will load block content:
63 |
64 | ```php
65 | # Prepend
66 | do_action("acf/before_render_block", $attributes);
67 | do_action("acf/before_render_block/name=$block_name", $attributes);
68 |
69 |
70 | # Block content actions
71 | do_action("acf/render_block", $attributes);
72 | do_action("acf/render_block/name=$block_name", $attributes);
73 |
74 |
75 | # Block content templates
76 | include(get_template_directory() . "/blocks/acf/$block_name.php");
77 | include(get_template_directory() . "/blocks/acf-$block_name.php");
78 |
79 |
80 | # Append
81 | do_action("acf/after_render_block", $attributes);
82 | do_action("acf/after_render_block/name=$block_name", $attributes);
83 | ```
84 |
85 |
86 | ## Contribute
87 |
88 | Please contribute! Just fork this repo and make a pull request.
89 |
90 |
91 | ## TODOs:
92 |
93 | * Create a "Block" field type so that we can have inner blocks as fields
94 | * Location rules for block placement and quantity restrictions
95 | * Sidebar positioning for block field groups
96 |
97 | ## Credits
98 |
99 | See [this thread](https://github.com/elliotcondon/acf/issues/622) for original project discussion.
100 |
101 | Project by [Robbie Chipka](https://github.com/rchipka)
102 |
103 | Logo by [David Aslan French](https://github.com/thedonquixotic) (forked from [Darius Dan](https://www.flaticon.com/authors/darius-dan) )
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/acf-block-field.php:
--------------------------------------------------------------------------------
1 | name = 'block';
36 |
37 |
38 | /*
39 | * label (string) Multiple words, can include spaces, visible when selecting a field type
40 | */
41 |
42 | $this->label = __('Block', 'TEXTDOMAIN');
43 |
44 |
45 | /*
46 | * category (string) basic | content | choice | relational | jquery | layout | CUSTOM GROUP NAME
47 | */
48 |
49 | $this->category = 'layout';
50 |
51 |
52 | /*
53 | * defaults (array) Array of default settings which are merged into the field object. These are used later in settings
54 | */
55 |
56 | $this->defaults = array(
57 | // 'font_size' => 14,
58 | );
59 |
60 |
61 | /*
62 | * l10n (array) Array of strings that are used in JavaScript. This allows JS strings to be translated in PHP and loaded via:
63 | * var message = acf._e('block', 'error');
64 | */
65 |
66 | $this->l10n = array(
67 | 'error' => __('Error! Please enter a higher value', 'TEXTDOMAIN'),
68 | );
69 |
70 |
71 | /*
72 | * settings (array) Store plugin settings (url, path, version) as a reference for later use with assets
73 | */
74 |
75 | $this->settings = $settings;
76 |
77 |
78 | // do not delete!
79 | parent::__construct();
80 |
81 | }
82 |
83 |
84 | /*
85 | * render_field_settings()
86 | *
87 | * Create extra settings for your field. These are visible when editing a field
88 | *
89 | * @type action
90 | * @since 3.6
91 | * @date 23/01/13
92 | *
93 | * @param $field (array) the $field being edited
94 | * @return n/a
95 | */
96 |
97 | function render_field_settings( $field ) {
98 |
99 | /*
100 | * acf_render_field_setting
101 | *
102 | * This function will create a setting for your field. Simply pass the $field parameter and an array of field settings.
103 | * The array of settings does not require a `value` or `prefix`; These settings are found from the $field array.
104 | *
105 | * More than one setting can be added by copy/paste the above code.
106 | * Please note that you must also have a matching $defaults value for the field name (font_size)
107 | */
108 |
109 | // acf_render_field_setting( $field, array(
110 | // 'label' => __('Font Size','TEXTDOMAIN'),
111 | // 'instructions' => __('Customise the input font size','TEXTDOMAIN'),
112 | // 'type' => 'number',
113 | // 'name' => 'font_size',
114 | // 'prepend' => 'px',
115 | // ));
116 |
117 | }
118 |
119 |
120 |
121 | /*
122 | * render_field()
123 | *
124 | * Create the HTML interface for your field
125 | *
126 | * @param $field (array) the $field being rendered
127 | *
128 | * @type action
129 | * @since 3.6
130 | * @date 23/01/13
131 | *
132 | * @param $field (array) the $field being edited
133 | * @return n/a
134 | */
135 |
136 | function render_field( $field ) {
137 |
138 |
139 | /*
140 | * Review the data of $field.
141 | * This will show what data is available
142 | */
143 |
144 | $block_id = acb_current_block('block_id');
145 | $parent_post_id = acb_current_block('post_id');
146 |
147 | if (!$block_id) {
148 | echo '';
149 | print_r( $field );
150 | echo ' ';
151 |
152 | return;
153 | }
154 |
155 | $field_id = $field['id'];
156 | $post_name = implode('-', ['acf-child-block', $parent_post_id, $block_id, $field_id]);
157 | echo '';
158 | print_r( $post_name );
159 | print_r( $field );
160 | echo ' ';
161 |
162 | if (!isset($field['value']) || !$field['value'] || !(get_post($field['value']))) {
163 | $field['value'] = intval(wp_insert_post([
164 | 'post_type' => 'acf-child-block',
165 | 'post_parent' => $parent_post_id,
166 | 'post_name' => $post_name,
167 | ]));
168 |
169 | update_post_meta($parent_post_id, $field_id, $field['value']);
170 | }
171 |
172 | $post = get_post($field['value']);
173 | $editor_settings = acb_get_editor_settings($post);
174 | $post_name .= '-' . rand(0, 99999);
175 | ?>
176 |
177 |
178 | content
179 | post_content); ?>
180 |
181 | settings['url'];
205 | $version = $this->settings['version'];
206 |
207 |
208 | // register & include JS
209 | wp_register_script('TEXTDOMAIN', "{$url}assets/js/input.js", array('acf-input'), $version);
210 | wp_enqueue_script('TEXTDOMAIN');
211 |
212 |
213 | // register & include CSS
214 | wp_register_style('TEXTDOMAIN', "{$url}assets/css/input.css", array('acf-input'), $version);
215 | wp_enqueue_style('TEXTDOMAIN');
216 |
217 | }
218 |
219 | */
220 |
221 |
222 | /*
223 | * input_admin_head()
224 | *
225 | * This action is called in the admin_head action on the edit screen where your field is created.
226 | * Use this action to add CSS and JavaScript to assist your render_field() action.
227 | *
228 | * @type action (admin_head)
229 | * @since 3.6
230 | * @date 23/01/13
231 | *
232 | * @param n/a
233 | * @return n/a
234 | */
235 |
236 | /*
237 |
238 | function input_admin_head() {
239 |
240 |
241 |
242 | }
243 |
244 | */
245 |
246 |
247 | /*
248 | * input_form_data()
249 | *
250 | * This function is called once on the 'input' page between the head and footer
251 | * There are 2 situations where ACF did not load during the 'acf/input_admin_enqueue_scripts' and
252 | * 'acf/input_admin_head' actions because ACF did not know it was going to be used. These situations are
253 | * seen on comments / user edit forms on the front end. This function will always be called, and includes
254 | * $args that related to the current screen such as $args['post_id']
255 | *
256 | * @type function
257 | * @date 6/03/2014
258 | * @since 5.0.0
259 | *
260 | * @param $args (array)
261 | * @return n/a
262 | */
263 |
264 | /*
265 |
266 | function input_form_data( $args ) {
267 |
268 |
269 |
270 | }
271 |
272 | */
273 |
274 |
275 | /*
276 | * input_admin_footer()
277 | *
278 | * This action is called in the admin_footer action on the edit screen where your field is created.
279 | * Use this action to add CSS and JavaScript to assist your render_field() action.
280 | *
281 | * @type action (admin_footer)
282 | * @since 3.6
283 | * @date 23/01/13
284 | *
285 | * @param n/a
286 | * @return n/a
287 | */
288 |
289 | /*
290 |
291 | function input_admin_footer() {
292 |
293 |
294 |
295 | }
296 |
297 | */
298 |
299 |
300 | /*
301 | * field_group_admin_enqueue_scripts()
302 | *
303 | * This action is called in the admin_enqueue_scripts action on the edit screen where your field is edited.
304 | * Use this action to add CSS + JavaScript to assist your render_field_options() action.
305 | *
306 | * @type action (admin_enqueue_scripts)
307 | * @since 3.6
308 | * @date 23/01/13
309 | *
310 | * @param n/a
311 | * @return n/a
312 | */
313 |
314 | /*
315 |
316 | function field_group_admin_enqueue_scripts() {
317 |
318 | }
319 |
320 | */
321 |
322 |
323 | /*
324 | * field_group_admin_head()
325 | *
326 | * This action is called in the admin_head action on the edit screen where your field is edited.
327 | * Use this action to add CSS and JavaScript to assist your render_field_options() action.
328 | *
329 | * @type action (admin_head)
330 | * @since 3.6
331 | * @date 23/01/13
332 | *
333 | * @param n/a
334 | * @return n/a
335 | */
336 |
337 | /*
338 |
339 | function field_group_admin_head() {
340 |
341 | }
342 |
343 | */
344 |
345 |
346 | /*
347 | * load_value()
348 | *
349 | * This filter is applied to the $value after it is loaded from the db
350 | *
351 | * @type filter
352 | * @since 3.6
353 | * @date 23/01/13
354 | *
355 | * @param $value (mixed) the value found in the database
356 | * @param $post_id (mixed) the $post_id from which the value was loaded
357 | * @param $field (array) the field array holding all the field options
358 | * @return $value
359 | */
360 |
361 | /*
362 |
363 | function load_value( $value, $post_id, $field ) {
364 |
365 | return $value;
366 |
367 | }
368 |
369 | */
370 |
371 |
372 | /*
373 | * update_value()
374 | *
375 | * This filter is applied to the $value before it is saved in the db
376 | *
377 | * @type filter
378 | * @since 3.6
379 | * @date 23/01/13
380 | *
381 | * @param $value (mixed) the value found in the database
382 | * @param $post_id (mixed) the $post_id from which the value was loaded
383 | * @param $field (array) the field array holding all the field options
384 | * @return $value
385 | */
386 |
387 | /*
388 |
389 | function update_value( $value, $post_id, $field ) {
390 |
391 | return $value;
392 |
393 | }
394 |
395 | */
396 |
397 |
398 | /*
399 | * format_value()
400 | *
401 | * This filter is appied to the $value after it is loaded from the db and before it is returned to the template
402 | *
403 | * @type filter
404 | * @since 3.6
405 | * @date 23/01/13
406 | *
407 | * @param $value (mixed) the value which was loaded from the database
408 | * @param $post_id (mixed) the $post_id from which the value was loaded
409 | * @param $field (array) the field array holding all the field options
410 | *
411 | * @return $value (mixed) the modified value
412 | */
413 |
414 | /*
415 |
416 | function format_value( $value, $post_id, $field ) {
417 |
418 | // bail early if no value
419 | if( empty($value) ) {
420 |
421 | return $value;
422 |
423 | }
424 |
425 |
426 | // apply setting
427 | if( $field['font_size'] > 12 ) {
428 |
429 | // format the value
430 | // $value = 'something';
431 |
432 | }
433 |
434 |
435 | // return
436 | return $value;
437 | }
438 |
439 | */
440 |
441 |
442 | /*
443 | * validate_value()
444 | *
445 | * This filter is used to perform validation on the value prior to saving.
446 | * All values are validated regardless of the field's required setting. This allows you to validate and return
447 | * messages to the user if the value is not correct
448 | *
449 | * @type filter
450 | * @date 11/02/2014
451 | * @since 5.0.0
452 | *
453 | * @param $valid (boolean) validation status based on the value and the field's required setting
454 | * @param $value (mixed) the $_POST value
455 | * @param $field (array) the field array holding all the field options
456 | * @param $input (string) the corresponding input name for $_POST value
457 | * @return $valid
458 | */
459 |
460 | /*
461 |
462 | function validate_value( $valid, $value, $field, $input ){
463 |
464 | // Basic usage
465 | if( $value < $field['custom_minimum_setting'] )
466 | {
467 | $valid = false;
468 | }
469 |
470 |
471 | // Advanced usage
472 | if( $value < $field['custom_minimum_setting'] )
473 | {
474 | $valid = __('The value is too little!','TEXTDOMAIN'),
475 | }
476 |
477 |
478 | // return
479 | return $valid;
480 |
481 | }
482 |
483 | */
484 |
485 |
486 | /*
487 | * delete_value()
488 | *
489 | * This action is fired after a value has been deleted from the db.
490 | * Please note that saving a blank value is treated as an update, not a delete
491 | *
492 | * @type action
493 | * @date 6/03/2014
494 | * @since 5.0.0
495 | *
496 | * @param $post_id (mixed) the $post_id from which the value was deleted
497 | * @param $key (string) the $meta_key which the value was deleted
498 | * @return n/a
499 | */
500 |
501 | /*
502 |
503 | function delete_value( $post_id, $key ) {
504 |
505 |
506 |
507 | }
508 |
509 | */
510 |
511 |
512 | /*
513 | * load_field()
514 | *
515 | * This filter is applied to the $field after it is loaded from the database
516 | *
517 | * @type filter
518 | * @date 23/01/2013
519 | * @since 3.6.0
520 | *
521 | * @param $field (array) the field array holding all the field options
522 | * @return $field
523 | */
524 |
525 | /*
526 |
527 | function load_field( $field ) {
528 |
529 | return $field;
530 |
531 | }
532 |
533 | */
534 |
535 |
536 | /*
537 | * update_field()
538 | *
539 | * This filter is applied to the $field before it is saved to the database
540 | *
541 | * @type filter
542 | * @date 23/01/2013
543 | * @since 3.6.0
544 | *
545 | * @param $field (array) the field array holding all the field options
546 | * @return $field
547 | */
548 |
549 | /*
550 |
551 | function update_field( $field ) {
552 |
553 | return $field;
554 |
555 | }
556 |
557 | */
558 |
559 |
560 | /*
561 | * delete_field()
562 | *
563 | * This action is fired after a field is deleted from the database
564 | *
565 | * @type action
566 | * @date 11/02/2014
567 | * @since 5.0.0
568 | *
569 | * @param $field (array) the field array holding all the field options
570 | * @return n/a
571 | */
572 |
573 | /*
574 |
575 | function delete_field( $field ) {
576 |
577 |
578 |
579 | }
580 |
581 | */
582 |
583 |
584 | }
585 |
586 | function acb_get_editor_settings($post) {
587 |
588 | $available_templates = wp_get_theme()->get_page_templates( get_post( $post->ID ) );
589 | $available_templates = ! empty( $available_templates ) ? array_merge(
590 | array(
591 | '' => apply_filters( 'default_page_template_title', __( 'Default template', 'gutenberg' ), 'rest-api' ),
592 | ),
593 | $available_templates
594 | ) : $available_templates;
595 |
596 | $gutenberg_theme_support = get_theme_support( 'gutenberg' );
597 | $align_wide = get_theme_support( 'align-wide' );
598 | $color_palette = current( (array) get_theme_support( 'editor-color-palette' ) );
599 | $font_sizes = current( (array) get_theme_support( 'editor-font-sizes' ) );
600 | $max_upload_size = wp_max_upload_size();
601 | if ( ! $max_upload_size ) {
602 | $max_upload_size = 0;
603 | }
604 | global $editor_styles;
605 | $styles = array(
606 | array(
607 | 'css' => file_get_contents(
608 | gutenberg_dir_path() . 'build/editor/editor-styles.css'
609 | ),
610 | ),
611 | );
612 | if ( $editor_styles && current_theme_supports( 'editor-styles' ) ) {
613 | foreach ( $editor_styles as $style ) {
614 | if ( filter_var( $style, FILTER_VALIDATE_URL ) ) {
615 | $styles[] = array(
616 | 'css' => file_get_contents( $style ),
617 | );
618 | } else {
619 | $file = get_theme_file_path( $style );
620 | $styles[] = array(
621 | 'css' => file_get_contents( get_theme_file_path( $style ) ),
622 | 'baseURL' => get_theme_file_uri( $style ),
623 | );
624 | }
625 | }
626 | }
627 |
628 | // Lock settings.
629 | $user_id = wp_check_post_lock( $post->ID );
630 | if ( $user_id ) {
631 | /**
632 | * Filters whether to show the post locked dialog.
633 | *
634 | * Returning a falsey value to the filter will short-circuit displaying the dialog.
635 | *
636 | * @since 3.6.0
637 | *
638 | * @param bool $display Whether to display the dialog. Default true.
639 | * @param WP_Post $post Post object.
640 | * @param WP_User|bool $user The user id currently editing the post.
641 | */
642 | if ( apply_filters( 'show_post_locked_dialog', true, $post, $user_id ) ) {
643 | $locked = true;
644 | }
645 |
646 | $user_details = null;
647 | if ( $locked ) {
648 | $user = get_userdata( $user_id );
649 | $user_details = array(
650 | 'name' => $user->display_name,
651 | );
652 | $avatar = get_avatar( $user_id, 64 );
653 | if ( $avatar ) {
654 | if ( preg_match( "|src='([^']+)'|", $avatar, $matches ) ) {
655 | $user_details['avatar'] = $matches[1];
656 | }
657 | }
658 | }
659 |
660 | $lock_details = array(
661 | 'isLocked' => $locked,
662 | 'user' => $user_details,
663 | );
664 | } else {
665 |
666 | // Lock the post.
667 | $active_post_lock = wp_set_post_lock( $post->ID );
668 | $lock_details = array(
669 | 'isLocked' => false,
670 | 'activePostLock' => esc_attr( implode( ':', $active_post_lock ) ),
671 | );
672 | }
673 |
674 | $editor_settings = array(
675 | 'alignWide' => $align_wide || ! empty( $gutenberg_theme_support[0]['wide-images'] ),
676 | 'availableTemplates' => $available_templates,
677 | 'allowedBlockTypes' => apply_filters( 'allowed_block_types', true, $post ),
678 | 'disableCustomColors' => get_theme_support( 'disable-custom-colors' ),
679 | 'disableCustomFontSizes' => get_theme_support( 'disable-custom-font-sizes' ),
680 | 'disablePostFormats' => ! current_theme_supports( 'post-formats' ),
681 | 'titlePlaceholder' => apply_filters( 'enter_title_here', __( 'Add title', 'gutenberg' ), $post ),
682 | 'bodyPlaceholder' => apply_filters( 'write_your_story', __( 'Write your story', 'gutenberg' ), $post ),
683 | 'isRTL' => is_rtl(),
684 | 'autosaveInterval' => 10,
685 | 'maxUploadFileSize' => $max_upload_size,
686 | 'allowedMimeTypes' => get_allowed_mime_types(),
687 | 'styles' => $styles,
688 | 'postLock' => $lock_details,
689 | 'postLockUtils' => array(
690 | 'nonce' => wp_create_nonce( 'lock-post_' . $post->ID ),
691 | 'unlockNonce' => wp_create_nonce( 'update-post_' . $post->ID ),
692 | 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
693 | ),
694 | );
695 |
696 | return $editor_settings;
697 | }
698 |
699 |
700 | // initialize
701 | new ACB_acf_field_block( [] );
702 |
703 |
704 | // class_exists check
705 | endif;
706 |
707 | ?>
708 |
--------------------------------------------------------------------------------
/advanced-custom-blocks.php:
--------------------------------------------------------------------------------
1 | ';
55 | }, 10, 2);
56 |
57 | add_filter('acf/location/rule_match/block_name', function ( $match, $rule, $options ) {
58 | if (empty($rule['value'])) {
59 | return true;
60 | }
61 |
62 | return ($rule['operator'] === '==') === (acb_current_block('name') == $rule['value']);
63 | }, 10, 3);
64 |
65 | add_filter('acf/location/screen', function ($screen, $field_group) {
66 | if (!isset($field_group['block_name']) || !$field_group['block_name']) {
67 | return $screen;
68 | }
69 |
70 | if (!isset($screen['post_id']) || !$screen['post_id']) {
71 | $screen['post_id'] = $_REQUEST['post'] ?: $_REQUEST['post_id'] ?: $_REQUEST['attributes']['post_id'];
72 | }
73 |
74 | return $screen;
75 | }, 1, 2);
76 |
77 | add_filter('get_post_metadata', function ($orig_value, $post_id, $meta_key, $single) {
78 | $block_meta = acb_current_block('block_meta');
79 |
80 | if (!$block_meta || !isset($block_meta[$meta_key])) {
81 | return $orig_value;
82 | }
83 |
84 | $meta_value = $block_meta[$meta_key];
85 |
86 | if ($single && is_array($meta_value)) {
87 | $meta_value = $meta_value[0];
88 | }
89 |
90 | if (!$single && !is_array($meta_value)) {
91 | $meta_value = [$meta_value];
92 | }
93 |
94 | // $type = 'single';
95 |
96 | // if (!$single) {
97 | // $type = 'array';
98 | // }
99 |
100 | // error_log('Block #' . acb_current_block('block_id') . ' - overriding ' . $type . ' value for ' . json_encode($meta_key) . ' from ' . json_encode($orig_value) . ' to ' . json_encode($meta_value));
101 |
102 | return $meta_value;
103 | }, 0, 4);
104 |
105 | add_action('acf/render_field_group_settings', function ($field_group) {
106 | acf_render_field_wrap(array(
107 | 'label' => 'Block Name',
108 | 'instructions' => '',
109 | 'type' => 'text',
110 | 'name' => 'block_name',
111 | 'prefix' => 'acf_field_group',
112 | 'value' => $field_group['block_name'],
113 | ));
114 |
115 | acf_render_field_wrap(array(
116 | 'label' => 'Block Icon',
117 | 'instructions' => '',
118 | 'type' => 'text',
119 | 'name' => 'block_icon',
120 | 'placeholder' => 'Dashicons class name',
121 | 'prefix' => 'acf_field_group',
122 | 'value' => $field_group['block_icon'],
123 | ));
124 |
125 | acf_render_field_wrap(array(
126 | 'label' => 'Block Category',
127 | 'instructions' => '',
128 | 'type' => 'text',
129 | 'name' => 'block_category',
130 | 'prefix' => 'acf_field_group',
131 | 'placeholder' => 'Widgets',
132 | 'value' => $field_group['block_category'],
133 | ));
134 | }, 10, 1);
135 |
136 | function my_plugin_block_categories( $categories, $post ) {
137 | if ( $post->post_type !== 'post' ) {
138 | return $categories;
139 | }
140 | return array_merge(
141 | $categories,
142 | array(
143 | array(
144 | 'slug' => 'my-category',
145 | 'title' => __( 'My category', 'my-plugin' ),
146 | ),
147 | )
148 | );
149 | }
150 |
151 | add_filter( 'block_categories', function ($block_categories, $post) {
152 | $block_category_slugs = wp_list_pluck($block_categories, 'slug');
153 |
154 | setup_postdata($post);
155 |
156 | foreach (wp_list_pluck(acf_gb_get_block_field_groups(), 'block_category') as $category) {
157 | $slug = sanitize_title($category);
158 |
159 | if (!in_array($slug, $block_category_slugs)) {
160 | $block_category_slugs[] = $slug;
161 | $block_categories[] = [
162 | 'slug' => $slug,
163 | 'title' => $category
164 | ];
165 | }
166 | }
167 |
168 | wp_reset_postdata();
169 |
170 | return $block_categories;
171 | }, 5, 2 );
172 |
173 |
174 | add_action( 'init', function () {
175 | register_post_type('acf-child-block', [
176 | 'label' => 'ACF Block',
177 | 'labels' => [],
178 | 'public' => true,
179 | 'show_in_menu' => false,
180 | 'capability_type' => 'page',
181 | 'supports' => array( 'title', 'editor', 'comments', 'thumbnail', 'custom-fields' ),
182 | ]);
183 |
184 | if (!function_exists('register_block_type')) {
185 | return;
186 | }
187 |
188 | foreach (acf_gb_get_block_field_groups() as $group) {
189 | register_block_type( 'acf/' . $group['block_name'], array(
190 | 'attributes' => array(
191 | 'post_id' => array(
192 | 'type' => 'number',
193 | 'default' => 0,
194 | ),
195 | 'block_id' => array(
196 | 'type' => 'string',
197 | 'default' => '',
198 | ),
199 | 'block_name' => array(
200 | 'type' => 'string',
201 | 'default' => $group['block_name'],
202 | ),
203 | 'acf_fields' => array(
204 | 'type' => 'object',
205 | 'default' => [],
206 | ),
207 | 'acf_field_group' => array(
208 | 'type' => 'number',
209 | 'default' => 0,
210 | ),
211 | ),
212 | 'render_callback' => function ($attributes) {
213 | global $post;
214 | global $acb_block;
215 |
216 | $output = '';
217 |
218 | if ($post instanceof WP_Post && $post->ID) {
219 | $post_id = $attributes['post_id'] = $post->ID;
220 | } else if ($attributes['post_id']) {
221 | $post_id = intval($attributes['post_id']);
222 | setup_postdata($post = get_post($post_id));
223 | }
224 |
225 | $cache_active = acf_is_cache_active();
226 |
227 | if ($cache_active) {
228 | acf_disable_cache();
229 | }
230 |
231 | $attributes['block_meta'] = get_post_meta($post_id, '__block_' . $attributes['block_id'], true);
232 |
233 | if (!is_array($attributes['block_meta'])) {
234 | $attributes['block_meta'] = [];
235 | }
236 |
237 | if (isset($_REQUEST['attributes']) && isset($_REQUEST['attributes']['acf_fields'])) {
238 | $post_id = $_REQUEST['attributes']['post_id'];
239 | $block_id = $_REQUEST['attributes']['block_id'];
240 | $acf_fields = $attributes['acf_fields'] = $_REQUEST['attributes']['acf_fields'];
241 |
242 | $fields = array_map(function ($field_key) {
243 | return get_field_object($field_key);
244 | }, array_keys($acf_fields));
245 |
246 | $filter_keys = [];
247 |
248 | foreach ($fields as $field) {
249 | if (!$field['name']) {
250 | continue;
251 | }
252 |
253 | $filter_keys[] = '_' . $field['name'];
254 | $filter_keys[] = $field['name'];
255 | }
256 |
257 | acf_save_post( $post_id, $acf_fields );
258 |
259 | if (sizeof($filter_keys) > 0) {
260 | $attributes['block_meta'] = [];
261 | $regex = '/^(' . implode($filter_keys, '|') . ')/';
262 |
263 | foreach (get_post_meta($post_id) as $meta_key => $meta_values) {
264 | if (!preg_match($regex, $meta_key)) {
265 | continue;
266 | }
267 |
268 | $attributes['block_meta'][$meta_key] = $meta_values[0];
269 | }
270 | }
271 |
272 | // foreach ($fields as $field) {
273 | // $meta_value = $attributes['block_meta'][$field_name];
274 | // add_post_meta($post_id, $field['name'], $meta_value, false);
275 | // }
276 |
277 | update_post_meta($post_id, '__block_' . $block_id, $attributes['block_meta']);
278 | }
279 |
280 | $acb_block = $attributes;
281 |
282 | if ($_GET['context'] === 'edit') {
283 | ob_start();
284 | $fields = acf_get_fields($attributes['acf_field_group']);
285 | acf_render_fields($fields, $attributes['post_id']);
286 | $output .= trim(ob_get_contents());
287 | ob_end_clean();
288 |
289 | if (!$output) {
290 | $output = '
';
291 | }
292 | } else {
293 | ob_start();
294 |
295 | do_action('acf/before_render_block', $attributes);
296 | do_action('acf/before_render_block/name=' . $attributes['block_name'], $attributes);
297 |
298 | do_action('acf/render_block', $attributes);
299 | do_action('acf/render_block/name=' . $attributes['block_name'], $attributes);
300 |
301 | $file_name = $attributes['block_name'] . '.php';
302 |
303 | foreach (['/blocks/acf/' . $file_name, '/blocks/acf-' . $file_name] as $path) {
304 | if (file_exists(get_stylesheet_directory() . $path)) {
305 | include(get_stylesheet_directory() . $path);
306 | }
307 | }
308 |
309 | do_action('acf/after_render_block', $attributes);
310 | do_action('acf/after_render_block/name=' . $attributes['block_name'], $attributes);
311 |
312 | $output .= ob_get_contents();
313 | ob_end_clean();
314 | }
315 |
316 | reset_rows();
317 | wp_reset_postdata();
318 | $acb_block = null;
319 |
320 | if ($cache_active) {
321 | acf_enable_cache();
322 | }
323 |
324 | return $output;
325 | },
326 | ) );
327 | }
328 | });
329 |
330 | function acf_gb_get_block_field_groups() {
331 | global $acb_block;
332 |
333 | $groups = [];
334 |
335 | if (isset($_REQUEST['post']) && $_REQUEST['post']) {
336 | setup_postdata($post = get_post($_REQUEST['post']));
337 | }
338 |
339 | foreach (acf_get_field_groups() as $group) {
340 | $acb_block = [
341 | 'block_name' => ($is_block = (isset($group['block_name']) ?: $group['block_name'])),
342 | ];
343 |
344 | if ($is_block) {
345 | if (!isset($group['block_category']) || !$group['block_category']) {
346 | $group['block_category'] = 'widgets';
347 | }
348 |
349 | if (isset($group['block_category'])) {
350 | $group['block_category_slug'] = sanitize_title($group['block_category']);
351 | }
352 |
353 | if (acf_get_field_group_visibility($group)) {
354 | $groups[] = $group;
355 | }
356 | }
357 |
358 | $acb_block = null;
359 | }
360 |
361 | if ($_REQUEST['post']) {
362 | wp_reset_postdata();
363 | }
364 |
365 | return $groups;
366 | }
367 |
368 | add_action('admin_notices', function () {
369 | ?>
370 |
567 |
589 |