Bez popisu

class-wp-block.php 8.0KB

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