class-wp-block.php (6765B)
1 <?php 2 /** 3 * Blocks API: WP_Block class 4 * 5 * @package WordPress 6 * @since 5.5.0 7 */ 8 9 /** 10 * Class representing a parsed instance of a block. 11 * 12 * @since 5.5.0 13 * @property array $attributes 14 */ 15 class WP_Block { 16 17 /** 18 * Original parsed array representation of block. 19 * 20 * @since 5.5.0 21 * @var array 22 */ 23 public $parsed_block; 24 25 /** 26 * Name of block. 27 * 28 * @example "core/paragraph" 29 * 30 * @since 5.5.0 31 * @var string 32 */ 33 public $name; 34 35 /** 36 * Block type associated with the instance. 37 * 38 * @since 5.5.0 39 * @var WP_Block_Type 40 */ 41 public $block_type; 42 43 /** 44 * Block context values. 45 * 46 * @since 5.5.0 47 * @var array 48 */ 49 public $context = array(); 50 51 /** 52 * All available context of the current hierarchy. 53 * 54 * @since 5.5.0 55 * @var array 56 * @access protected 57 */ 58 protected $available_context; 59 60 /** 61 * List of inner blocks (of this same class) 62 * 63 * @since 5.5.0 64 * @var WP_Block[] 65 */ 66 public $inner_blocks = array(); 67 68 /** 69 * Resultant HTML from inside block comment delimiters after removing inner 70 * blocks. 71 * 72 * @example "...Just <!-- wp:test /--> testing..." -> "Just testing..." 73 * 74 * @since 5.5.0 75 * @var string 76 */ 77 public $inner_html = ''; 78 79 /** 80 * List of string fragments and null markers where inner blocks were found 81 * 82 * @example array( 83 * 'inner_html' => 'BeforeInnerAfter', 84 * 'inner_blocks' => array( block, block ), 85 * 'inner_content' => array( 'Before', null, 'Inner', null, 'After' ), 86 * ) 87 * 88 * @since 5.5.0 89 * @var array 90 */ 91 public $inner_content = array(); 92 93 /** 94 * Constructor. 95 * 96 * Populates object properties from the provided block instance argument. 97 * 98 * The given array of context values will not necessarily be available on 99 * the instance itself, but is treated as the full set of values provided by 100 * the block's ancestry. This is assigned to the private `available_context` 101 * property. Only values which are configured to consumed by the block via 102 * its registered type will be assigned to the block's `context` property. 103 * 104 * @since 5.5.0 105 * 106 * @param array $block Array of parsed block properties. 107 * @param array $available_context Optional array of ancestry context values. 108 * @param WP_Block_Type_Registry $registry Optional block type registry. 109 */ 110 public function __construct( $block, $available_context = array(), $registry = null ) { 111 $this->parsed_block = $block; 112 $this->name = $block['blockName']; 113 114 if ( is_null( $registry ) ) { 115 $registry = WP_Block_Type_Registry::get_instance(); 116 } 117 118 $this->block_type = $registry->get_registered( $this->name ); 119 120 $this->available_context = $available_context; 121 122 if ( ! empty( $this->block_type->uses_context ) ) { 123 foreach ( $this->block_type->uses_context as $context_name ) { 124 if ( array_key_exists( $context_name, $this->available_context ) ) { 125 $this->context[ $context_name ] = $this->available_context[ $context_name ]; 126 } 127 } 128 } 129 130 if ( ! empty( $block['innerBlocks'] ) ) { 131 $child_context = $this->available_context; 132 133 if ( ! empty( $this->block_type->provides_context ) ) { 134 foreach ( $this->block_type->provides_context as $context_name => $attribute_name ) { 135 if ( array_key_exists( $attribute_name, $this->attributes ) ) { 136 $child_context[ $context_name ] = $this->attributes[ $attribute_name ]; 137 } 138 } 139 } 140 141 $this->inner_blocks = new WP_Block_List( $block['innerBlocks'], $child_context, $registry ); 142 } 143 144 if ( ! empty( $block['innerHTML'] ) ) { 145 $this->inner_html = $block['innerHTML']; 146 } 147 148 if ( ! empty( $block['innerContent'] ) ) { 149 $this->inner_content = $block['innerContent']; 150 } 151 } 152 153 /** 154 * Returns a value from an inaccessible property. 155 * 156 * This is used to lazily initialize the `attributes` property of a block, 157 * such that it is only prepared with default attributes at the time that 158 * the property is accessed. For all other inaccessible properties, a `null` 159 * value is returned. 160 * 161 * @since 5.5.0 162 * 163 * @param string $name Property name. 164 * @return array|null Prepared attributes, or null. 165 */ 166 public function __get( $name ) { 167 if ( 'attributes' === $name ) { 168 $this->attributes = isset( $this->parsed_block['attrs'] ) ? 169 $this->parsed_block['attrs'] : 170 array(); 171 172 if ( ! is_null( $this->block_type ) ) { 173 $this->attributes = $this->block_type->prepare_attributes_for_render( $this->attributes ); 174 } 175 176 return $this->attributes; 177 } 178 179 return null; 180 } 181 182 /** 183 * Generates the render output for the block. 184 * 185 * @since 5.5.0 186 * 187 * @param array $options { 188 * Optional options object. 189 * 190 * @type bool $dynamic Defaults to 'true'. Optionally set to false to avoid using the block's render_callback. 191 * } 192 * @return string Rendered block output. 193 */ 194 public function render( $options = array() ) { 195 global $post; 196 $options = wp_parse_args( 197 $options, 198 array( 199 'dynamic' => true, 200 ) 201 ); 202 203 $is_dynamic = $options['dynamic'] && $this->name && null !== $this->block_type && $this->block_type->is_dynamic(); 204 $block_content = ''; 205 206 if ( ! $options['dynamic'] || empty( $this->block_type->skip_inner_blocks ) ) { 207 $index = 0; 208 foreach ( $this->inner_content as $chunk ) { 209 $block_content .= is_string( $chunk ) ? 210 $chunk : 211 $this->inner_blocks[ $index++ ]->render(); 212 } 213 } 214 215 if ( $is_dynamic ) { 216 $global_post = $post; 217 $parent = WP_Block_Supports::$block_to_render; 218 219 WP_Block_Supports::$block_to_render = $this->parsed_block; 220 221 $block_content = (string) call_user_func( $this->block_type->render_callback, $this->attributes, $block_content, $this ); 222 223 WP_Block_Supports::$block_to_render = $parent; 224 225 $post = $global_post; 226 } 227 228 if ( ! empty( $this->block_type->script ) ) { 229 wp_enqueue_script( $this->block_type->script ); 230 } 231 232 if ( ! empty( $this->block_type->style ) ) { 233 wp_enqueue_style( $this->block_type->style ); 234 } 235 236 /** 237 * Filters the content of a single block. 238 * 239 * @since 5.0.0 240 * 241 * @param string $block_content The block content about to be appended. 242 * @param array $block The full block, including name and attributes. 243 */ 244 $block_content = apply_filters( 'render_block', $block_content, $this->parsed_block ); 245 246 /** 247 * Filters the content of a single block. 248 * 249 * The dynamic portion of the hook name, `$name`, refers to 250 * the block name, e.g. "core/paragraph". 251 * 252 * @since 5.7.0 253 * 254 * @param string $block_content The block content about to be appended. 255 * @param array $block The full block, including name and attributes. 256 */ 257 $block_content = apply_filters( "render_block_{$this->name}", $block_content, $this->parsed_block ); 258 259 return $block_content; 260 } 261 262 }