|
11 | 11 | * Manages the registered Content Models.
|
12 | 12 | */
|
13 | 13 | final class Content_Model {
|
| 14 | + public const FALLBACK_VALUE_PLACEHOLDER = '__CREATE_CONTENT_MODEL__FALLBACK_VALUE__'; |
| 15 | + |
14 | 16 | /**
|
15 | 17 | * The slug of the content model.
|
16 | 18 | *
|
@@ -39,6 +41,13 @@ final class Content_Model {
|
39 | 41 | */
|
40 | 42 | public $blocks = array();
|
41 | 43 |
|
| 44 | + /** |
| 45 | + * A reverse map of meta keys, with the values being |
| 46 | + * the bound block and which attribute the meta key is bound to. |
| 47 | + * |
| 48 | + * @var array |
| 49 | + */ |
| 50 | + private $bound_meta_keys = array(); |
42 | 51 |
|
43 | 52 | /**
|
44 | 53 | * Holds the fields of the content model.
|
@@ -75,9 +84,13 @@ public function __construct( WP_Post $content_model_post ) {
|
75 | 84 | $this->maybe_enqueue_the_fields_ui();
|
76 | 85 | $this->maybe_enqueue_bound_group_extractor();
|
77 | 86 | $this->maybe_enqueue_content_locking();
|
| 87 | + $this->maybe_enqueue_fallback_value_clearer(); |
78 | 88 |
|
79 | 89 | add_filter( 'block_categories_all', array( $this, 'register_block_category' ) );
|
80 | 90 |
|
| 91 | + add_filter( 'rest_request_before_callbacks', array( $this, 'remove_default_meta_keys_on_save' ), 10, 3 ); |
| 92 | + add_filter( 'rest_post_dispatch', array( $this, 'fill_empty_meta_keys_with_default_values' ), 10, 3 ); |
| 93 | + |
81 | 94 | add_action( 'rest_after_insert_' . $this->slug, array( $this, 'extract_post_content_from_blocks' ), 99, 1 );
|
82 | 95 |
|
83 | 96 | /**
|
@@ -204,15 +217,27 @@ private function register_meta_fields() {
|
204 | 217 | continue;
|
205 | 218 | }
|
206 | 219 |
|
| 220 | + $this->bound_meta_keys[ $field ] = (object) array( |
| 221 | + 'block' => $block, |
| 222 | + 'attribute_name' => $attribute_name, |
| 223 | + ); |
| 224 | + |
| 225 | + $args = array( |
| 226 | + 'show_in_rest' => true, |
| 227 | + 'single' => true, |
| 228 | + 'type' => $block->get_attribute_type( $attribute_name ), |
| 229 | + ); |
| 230 | + |
| 231 | + $default_value = $block->get_default_value_for_attribute( $attribute_name ); |
| 232 | + |
| 233 | + if ( ! empty( $default_value ) ) { |
| 234 | + $args['default'] = $default_value; |
| 235 | + } |
| 236 | + |
207 | 237 | register_post_meta(
|
208 | 238 | $this->slug,
|
209 | 239 | $field,
|
210 |
| - array( |
211 |
| - 'show_in_rest' => true, |
212 |
| - 'single' => true, |
213 |
| - 'type' => $block->get_attribute_type( $attribute_name ), |
214 |
| - 'default' => $block->get_default_value_for_attribute( $attribute_name ), |
215 |
| - ) |
| 240 | + $args |
216 | 241 | );
|
217 | 242 | }
|
218 | 243 | }
|
@@ -307,6 +332,70 @@ public function extract_post_content_from_blocks( $post ) {
|
307 | 332 | );
|
308 | 333 | }
|
309 | 334 |
|
| 335 | + /** |
| 336 | + * Intercepts the saving request and removes the meta keys with default values. |
| 337 | + * |
| 338 | + * TODO Remove when Gutneberg 19.2 gets released. |
| 339 | + * |
| 340 | + * @param WP_HTTP_Response|null $response The response. |
| 341 | + * @param WP_REST_Server $server Route handler used for the request. |
| 342 | + * @param WP_REST_Request $request The request. |
| 343 | + * |
| 344 | + * @return WP_REST_Response The response. |
| 345 | + */ |
| 346 | + public function remove_default_meta_keys_on_save( $response, $server, $request ) { |
| 347 | + $is_upserting = in_array( $request->get_method(), array( 'POST', 'PUT' ), true ); |
| 348 | + $is_touching_post_type = str_starts_with( $request->get_route(), '/wp/v2/' . $this->slug ); |
| 349 | + |
| 350 | + if ( $is_upserting && $is_touching_post_type ) { |
| 351 | + $meta = $request->get_param( 'meta' ) ?? array(); |
| 352 | + |
| 353 | + foreach ( $meta as $key => $value ) { |
| 354 | + if ( '' === $value ) { |
| 355 | + unset( $meta[ $key ] ); |
| 356 | + delete_post_meta( $request->get_param( 'id' ), $key ); |
| 357 | + } |
| 358 | + } |
| 359 | + |
| 360 | + $request->set_param( 'meta', $meta ); |
| 361 | + } |
| 362 | + |
| 363 | + return $response; |
| 364 | + } |
| 365 | + |
| 366 | + /** |
| 367 | + * Intercepts the response and fills the empty meta keys with default values. |
| 368 | + * |
| 369 | + * TODO Remove when Gutneberg 19.2 gets released. |
| 370 | + * |
| 371 | + * @param WP_HTTP_Response $result The response. |
| 372 | + * @param WP_REST_Server $server The server. |
| 373 | + * @param WP_REST_Request $request The request. |
| 374 | + * |
| 375 | + * @return WP_REST_Response The response. |
| 376 | + */ |
| 377 | + public function fill_empty_meta_keys_with_default_values( $result, $server, $request ) { |
| 378 | + $is_allowed_method = in_array( $request->get_method(), array( 'GET', 'POST', 'PUT' ), true ); |
| 379 | + $is_touching_post_type = str_starts_with( $request->get_route(), '/wp/v2/' . $this->slug ); |
| 380 | + |
| 381 | + if ( $is_allowed_method && $is_touching_post_type ) { |
| 382 | + $data = $result->get_data(); |
| 383 | + |
| 384 | + $data['meta'] ??= array(); |
| 385 | + |
| 386 | + foreach ( $data['meta'] as $key => $value ) { |
| 387 | + $bound_meta_key = $this->bound_meta_keys[ $key ] ?? null; |
| 388 | + |
| 389 | + if ( empty( $value ) && $bound_meta_key ) { |
| 390 | + $data['meta'][ $key ] = self::FALLBACK_VALUE_PLACEHOLDER; |
| 391 | + } |
| 392 | + } |
| 393 | + |
| 394 | + $result->set_data( $data ); |
| 395 | + } |
| 396 | + |
| 397 | + return $result; |
| 398 | + } |
310 | 399 | /**
|
311 | 400 | * Extracts the post content from the blocks.
|
312 | 401 | *
|
@@ -495,4 +584,45 @@ function () {
|
495 | 584 | }
|
496 | 585 | );
|
497 | 586 | }
|
| 587 | + |
| 588 | + /** |
| 589 | + * Conditionally enqueues the fallback value clearer, allowing the block to become editable. |
| 590 | + * |
| 591 | + * Checks if the current post is of the correct type before enqueueing the script. |
| 592 | + * |
| 593 | + * @return void |
| 594 | + */ |
| 595 | + private function maybe_enqueue_fallback_value_clearer() { |
| 596 | + add_action( |
| 597 | + 'enqueue_block_editor_assets', |
| 598 | + function () { |
| 599 | + global $post; |
| 600 | + |
| 601 | + if ( ! $post || $this->slug !== $post->post_type ) { |
| 602 | + return; |
| 603 | + } |
| 604 | + |
| 605 | + $asset_file = include CONTENT_MODEL_PLUGIN_PATH . 'includes/runtime/dist/fallback-value-clearer.asset.php'; |
| 606 | + |
| 607 | + wp_register_script( |
| 608 | + 'data-types/fallback-value-clearer', |
| 609 | + CONTENT_MODEL_PLUGIN_URL . '/includes/runtime/dist/fallback-value-clearer.js', |
| 610 | + $asset_file['dependencies'], |
| 611 | + $asset_file['version'], |
| 612 | + true |
| 613 | + ); |
| 614 | + |
| 615 | + wp_localize_script( |
| 616 | + 'data-types/fallback-value-clearer', |
| 617 | + 'contentModelFields', |
| 618 | + array( |
| 619 | + 'postType' => $this->slug, |
| 620 | + 'FALLBACK_VALUE_PLACEHOLDER' => self::FALLBACK_VALUE_PLACEHOLDER, |
| 621 | + ) |
| 622 | + ); |
| 623 | + |
| 624 | + wp_enqueue_script( 'data-types/fallback-value-clearer' ); |
| 625 | + } |
| 626 | + ); |
| 627 | + } |
498 | 628 | }
|
0 commit comments