|
| 1 | +<?php |
| 2 | +/** |
| 3 | + * Custom CSS block support. |
| 4 | + * |
| 5 | + * @package WordPress |
| 6 | + */ |
| 7 | + |
| 8 | +/** |
| 9 | + * Render the custom CSS stylesheet and add class name to block as required. |
| 10 | + * |
| 11 | + * @since 7.0.0 |
| 12 | + * |
| 13 | + * @param array $parsed_block The parsed block. |
| 14 | + * @return array The same parsed block with custom CSS class name added if appropriate. |
| 15 | + */ |
| 16 | +function wp_render_custom_css_support_styles( $parsed_block ) { |
| 17 | + $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $parsed_block['blockName'] ); |
| 18 | + |
| 19 | + if ( ! block_has_support( $block_type, 'customCSS', true ) ) { |
| 20 | + return $parsed_block; |
| 21 | + } |
| 22 | + |
| 23 | + $custom_css = trim( $parsed_block['attrs']['style']['css'] ?? '' ); |
| 24 | + |
| 25 | + if ( empty( $custom_css ) ) { |
| 26 | + return $parsed_block; |
| 27 | + } |
| 28 | + |
| 29 | + // Validate CSS doesn't contain HTML markup (same validation as global styles REST API). |
| 30 | + if ( preg_match( '#</?\w+#', $custom_css ) ) { |
| 31 | + return $parsed_block; |
| 32 | + } |
| 33 | + |
| 34 | + // Generate a unique class name for this block instance. |
| 35 | + $class_name = wp_unique_id_from_values( $parsed_block, 'wp-custom-css-' ); |
| 36 | + $updated_class_name = isset( $parsed_block['attrs']['className'] ) |
| 37 | + ? $parsed_block['attrs']['className'] . " $class_name" |
| 38 | + : $class_name; |
| 39 | + |
| 40 | + _wp_array_set( $parsed_block, array( 'attrs', 'className' ), $updated_class_name ); |
| 41 | + |
| 42 | + // Process the custom CSS using the same method as global styles. |
| 43 | + $selector = '.' . $class_name; |
| 44 | + $processed_css = WP_Theme_JSON::process_blocks_custom_css( $custom_css, $selector ); |
| 45 | + |
| 46 | + if ( ! empty( $processed_css ) ) { |
| 47 | + /* |
| 48 | + * Register and add inline style for block custom CSS. |
| 49 | + * The style depends on global-styles to ensure custom CSS loads after |
| 50 | + * and can override global styles. |
| 51 | + */ |
| 52 | + wp_register_style( 'wp-block-custom-css', false, array( 'global-styles' ) ); |
| 53 | + wp_add_inline_style( 'wp-block-custom-css', $processed_css ); |
| 54 | + } |
| 55 | + |
| 56 | + return $parsed_block; |
| 57 | +} |
| 58 | + |
| 59 | +/** |
| 60 | + * Enqueues the block custom CSS styles. |
| 61 | + * |
| 62 | + * @since 7.0.0 |
| 63 | + */ |
| 64 | +function wp_enqueue_block_custom_css() { |
| 65 | + wp_enqueue_style( 'wp-block-custom-css' ); |
| 66 | +} |
| 67 | + |
| 68 | +/** |
| 69 | + * Applies the custom CSS class name to the block's rendered HTML. |
| 70 | + * |
| 71 | + * The class name is generated in `wp_render_custom_css_support_styles` |
| 72 | + * and stored in block attributes. This filter adds it to the actual markup. |
| 73 | + * |
| 74 | + * @since 7.0.0 |
| 75 | + * |
| 76 | + * @param string $block_content Rendered block content. |
| 77 | + * @param array $block Block object. |
| 78 | + * @return string Filtered block content. |
| 79 | + */ |
| 80 | +function wp_render_custom_css_class_name( $block_content, $block ) { |
| 81 | + $class_string = $block['attrs']['className'] ?? ''; |
| 82 | + preg_match( '/\bwp-custom-css-\S+\b/', $class_string, $matches ); |
| 83 | + |
| 84 | + if ( empty( $matches ) ) { |
| 85 | + return $block_content; |
| 86 | + } |
| 87 | + |
| 88 | + $tags = new WP_HTML_Tag_Processor( $block_content ); |
| 89 | + |
| 90 | + if ( $tags->next_tag() ) { |
| 91 | + $tags->add_class( 'has-custom-css' ); |
| 92 | + $tags->add_class( $matches[0] ); |
| 93 | + } |
| 94 | + |
| 95 | + return $tags->get_updated_html(); |
| 96 | +} |
| 97 | + |
| 98 | +add_filter( 'render_block', 'wp_render_custom_css_class_name', 10, 2 ); |
| 99 | +add_filter( 'render_block_data', 'wp_render_custom_css_support_styles', 10, 1 ); |
| 100 | +add_action( 'wp_enqueue_scripts', 'wp_enqueue_block_custom_css', 1 ); |
| 101 | + |
| 102 | +/** |
| 103 | + * Registers the style block attribute for block types that support it. |
| 104 | + * |
| 105 | + * @param WP_Block_Type $block_type Block Type. |
| 106 | + */ |
| 107 | +function wp_register_custom_css_support( $block_type ) { |
| 108 | + // Setup attributes and styles within that if needed. |
| 109 | + if ( ! $block_type->attributes ) { |
| 110 | + $block_type->attributes = array(); |
| 111 | + } |
| 112 | + |
| 113 | + // Check for existing style attribute definition e.g. from block.json. |
| 114 | + if ( array_key_exists( 'style', $block_type->attributes ) ) { |
| 115 | + return; |
| 116 | + } |
| 117 | + |
| 118 | + $has_custom_css_support = block_has_support( $block_type, array( 'customCSS' ), true ); |
| 119 | + |
| 120 | + if ( $has_custom_css_support ) { |
| 121 | + $block_type->attributes['style'] = array( |
| 122 | + 'type' => 'object', |
| 123 | + ); |
| 124 | + } |
| 125 | +} |
| 126 | + |
| 127 | +// Register the block support. |
| 128 | +WP_Block_Supports::get_instance()->register( |
| 129 | + 'custom-css', |
| 130 | + array( |
| 131 | + 'register_attribute' => 'wp_register_custom_css_support', |
| 132 | + ) |
| 133 | +); |
0 commit comments