block-editor.php (16999B)
1 <?php 2 /** 3 * Block Editor API. 4 * 5 * @package WordPress 6 * @subpackage Editor 7 * @since 5.8.0 8 */ 9 10 /** 11 * Returns the list of default categories for block types. 12 * 13 * @since 5.8.0 14 * 15 * @return array[] Array of categories for block types. 16 */ 17 function get_default_block_categories() { 18 return array( 19 array( 20 'slug' => 'text', 21 'title' => _x( 'Text', 'block category' ), 22 'icon' => null, 23 ), 24 array( 25 'slug' => 'media', 26 'title' => _x( 'Media', 'block category' ), 27 'icon' => null, 28 ), 29 array( 30 'slug' => 'design', 31 'title' => _x( 'Design', 'block category' ), 32 'icon' => null, 33 ), 34 array( 35 'slug' => 'widgets', 36 'title' => _x( 'Widgets', 'block category' ), 37 'icon' => null, 38 ), 39 array( 40 'slug' => 'theme', 41 'title' => _x( 'Theme', 'block category' ), 42 'icon' => null, 43 ), 44 array( 45 'slug' => 'embed', 46 'title' => _x( 'Embeds', 'block category' ), 47 'icon' => null, 48 ), 49 array( 50 'slug' => 'reusable', 51 'title' => _x( 'Reusable Blocks', 'block category' ), 52 'icon' => null, 53 ), 54 ); 55 } 56 57 /** 58 * Returns all the categories for block types that will be shown in the block editor. 59 * 60 * @since 5.0.0 61 * @since 5.8.0 It is possible to pass the block editor context as param. 62 * 63 * @param WP_Post|WP_Block_Editor_Context $post_or_block_editor_context The current post object or 64 * the block editor context. 65 * 66 * @return array[] Array of categories for block types. 67 */ 68 function get_block_categories( $post_or_block_editor_context ) { 69 $block_categories = get_default_block_categories(); 70 $block_editor_context = $post_or_block_editor_context instanceof WP_Post ? 71 new WP_Block_Editor_Context( 72 array( 73 'post' => $post_or_block_editor_context, 74 ) 75 ) : $post_or_block_editor_context; 76 77 /** 78 * Filters the default array of categories for block types. 79 * 80 * @since 5.8.0 81 * 82 * @param array[] $block_categories Array of categories for block types. 83 * @param WP_Block_Editor_Context $block_editor_context The current block editor context. 84 */ 85 $block_categories = apply_filters( 'block_categories_all', $block_categories, $block_editor_context ); 86 if ( ! empty( $block_editor_context->post ) ) { 87 $post = $block_editor_context->post; 88 89 /** 90 * Filters the default array of categories for block types. 91 * 92 * @since 5.0.0 93 * @deprecated 5.8.0 Use the {@see 'block_categories_all'} filter instead. 94 * 95 * @param array[] $block_categories Array of categories for block types. 96 * @param WP_Post $post Post being loaded. 97 */ 98 $block_categories = apply_filters_deprecated( 'block_categories', array( $block_categories, $post ), '5.8.0', 'block_categories_all' ); 99 } 100 101 return $block_categories; 102 } 103 104 /** 105 * Gets the list of allowed block types to use in the block editor. 106 * 107 * @since 5.8.0 108 * 109 * @param WP_Block_Editor_Context $block_editor_context The current block editor context. 110 * 111 * @return bool|array Array of block type slugs, or boolean to enable/disable all. 112 */ 113 function get_allowed_block_types( $block_editor_context ) { 114 $allowed_block_types = true; 115 116 /** 117 * Filters the allowed block types for all editor types. 118 * 119 * @since 5.8.0 120 * 121 * @param bool|array $allowed_block_types Array of block type slugs, or boolean to enable/disable all. 122 * Default true (all registered block types supported). 123 * @param WP_Block_Editor_Context $block_editor_context The current block editor context. 124 */ 125 $allowed_block_types = apply_filters( 'allowed_block_types_all', $allowed_block_types, $block_editor_context ); 126 if ( ! empty( $block_editor_context->post ) ) { 127 $post = $block_editor_context->post; 128 129 /** 130 * Filters the allowed block types for the editor. 131 * 132 * @since 5.0.0 133 * @deprecated 5.8.0 Use the {@see 'allowed_block_types_all'} filter instead. 134 * 135 * @param bool|array $allowed_block_types Array of block type slugs, or boolean to enable/disable all. 136 * Default true (all registered block types supported) 137 * @param WP_Post $post The post resource data. 138 */ 139 $allowed_block_types = apply_filters_deprecated( 'allowed_block_types', array( $allowed_block_types, $post ), '5.8.0', 'allowed_block_types_all' ); 140 } 141 142 return $allowed_block_types; 143 } 144 145 /** 146 * Returns the default block editor settings. 147 * 148 * @since 5.8.0 149 * 150 * @return array The default block editor settings. 151 */ 152 function get_default_block_editor_settings() { 153 // Media settings. 154 $max_upload_size = wp_max_upload_size(); 155 if ( ! $max_upload_size ) { 156 $max_upload_size = 0; 157 } 158 159 /** This filter is documented in wp-admin/includes/media.php */ 160 $image_size_names = apply_filters( 161 'image_size_names_choose', 162 array( 163 'thumbnail' => __( 'Thumbnail' ), 164 'medium' => __( 'Medium' ), 165 'large' => __( 'Large' ), 166 'full' => __( 'Full Size' ), 167 ) 168 ); 169 170 $available_image_sizes = array(); 171 foreach ( $image_size_names as $image_size_slug => $image_size_name ) { 172 $available_image_sizes[] = array( 173 'slug' => $image_size_slug, 174 'name' => $image_size_name, 175 ); 176 } 177 178 $default_size = get_option( 'image_default_size', 'large' ); 179 $image_default_size = in_array( $default_size, array_keys( $image_size_names ), true ) ? $default_size : 'large'; 180 181 $image_dimensions = array(); 182 $all_sizes = wp_get_registered_image_subsizes(); 183 foreach ( $available_image_sizes as $size ) { 184 $key = $size['slug']; 185 if ( isset( $all_sizes[ $key ] ) ) { 186 $image_dimensions[ $key ] = $all_sizes[ $key ]; 187 } 188 } 189 190 $editor_settings = array( 191 'alignWide' => get_theme_support( 'align-wide' ), 192 'allowedBlockTypes' => true, 193 'allowedMimeTypes' => get_allowed_mime_types(), 194 'blockCategories' => get_default_block_categories(), 195 'disableCustomColors' => get_theme_support( 'disable-custom-colors' ), 196 'disableCustomFontSizes' => get_theme_support( 'disable-custom-font-sizes' ), 197 'disableCustomGradients' => get_theme_support( 'disable-custom-gradients' ), 198 'enableCustomLineHeight' => get_theme_support( 'custom-line-height' ), 199 'enableCustomSpacing' => get_theme_support( 'custom-spacing' ), 200 'enableCustomUnits' => get_theme_support( 'custom-units' ), 201 'isRTL' => is_rtl(), 202 'imageDefaultSize' => $image_default_size, 203 'imageDimensions' => $image_dimensions, 204 'imageEditing' => true, 205 'imageSizes' => $available_image_sizes, 206 'maxUploadFileSize' => $max_upload_size, 207 ); 208 209 // Theme settings. 210 $color_palette = current( (array) get_theme_support( 'editor-color-palette' ) ); 211 if ( false !== $color_palette ) { 212 $editor_settings['colors'] = $color_palette; 213 } 214 215 $font_sizes = current( (array) get_theme_support( 'editor-font-sizes' ) ); 216 if ( false !== $font_sizes ) { 217 $editor_settings['fontSizes'] = $font_sizes; 218 } 219 220 $gradient_presets = current( (array) get_theme_support( 'editor-gradient-presets' ) ); 221 if ( false !== $gradient_presets ) { 222 $editor_settings['gradients'] = $gradient_presets; 223 } 224 225 return $editor_settings; 226 } 227 228 /** 229 * Returns the block editor settings needed to use the Legacy Widget block which 230 * is not registered by default. 231 * 232 * @since 5.8.0 233 * 234 * @return array Settings to be used with get_block_editor_settings(). 235 */ 236 function get_legacy_widget_block_editor_settings() { 237 $editor_settings = array(); 238 239 /** 240 * Filters the list of widget-type IDs that should **not** be offered by the 241 * Legacy Widget block. 242 * 243 * Returning an empty array will make all widgets available. 244 * 245 * @since 5.8.0 246 * 247 * @param array $widgets An array of excluded widget-type IDs. 248 */ 249 $editor_settings['widgetTypesToHideFromLegacyWidgetBlock'] = apply_filters( 250 'widget_types_to_hide_from_legacy_widget_block', 251 array( 252 'pages', 253 'calendar', 254 'archives', 255 'media_audio', 256 'media_image', 257 'media_gallery', 258 'media_video', 259 'search', 260 'text', 261 'categories', 262 'recent-posts', 263 'recent-comments', 264 'rss', 265 'tag_cloud', 266 'custom_html', 267 'block', 268 ) 269 ); 270 271 return $editor_settings; 272 } 273 274 /** 275 * Returns the contextualized block editor settings for a selected editor context. 276 * 277 * @since 5.8.0 278 * 279 * @param array $custom_settings Custom settings to use with the given editor type. 280 * @param WP_Block_Editor_Context $block_editor_context The current block editor context. 281 * 282 * @return array The contextualized block editor settings. 283 */ 284 function get_block_editor_settings( array $custom_settings, $block_editor_context ) { 285 $editor_settings = array_merge( 286 get_default_block_editor_settings(), 287 array( 288 'allowedBlockTypes' => get_allowed_block_types( $block_editor_context ), 289 'blockCategories' => get_block_categories( $block_editor_context ), 290 ), 291 $custom_settings 292 ); 293 294 $theme_json = WP_Theme_JSON_Resolver::get_merged_data( $editor_settings ); 295 296 if ( WP_Theme_JSON_Resolver::theme_has_support() ) { 297 $editor_settings['styles'][] = array( 298 'css' => $theme_json->get_stylesheet( 'block_styles' ), 299 '__unstableType' => 'globalStyles', 300 ); 301 $editor_settings['styles'][] = array( 302 'css' => $theme_json->get_stylesheet( 'css_variables' ), 303 '__experimentalNoWrapper' => true, 304 '__unstableType' => 'globalStyles', 305 ); 306 } 307 308 $editor_settings['__experimentalFeatures'] = $theme_json->get_settings(); 309 // These settings may need to be updated based on data coming from theme.json sources. 310 if ( isset( $editor_settings['__experimentalFeatures']['color']['palette'] ) ) { 311 $colors_by_origin = $editor_settings['__experimentalFeatures']['color']['palette']; 312 $editor_settings['colors'] = isset( $colors_by_origin['user'] ) ? 313 $colors_by_origin['user'] : ( 314 isset( $colors_by_origin['theme'] ) ? 315 $colors_by_origin['theme'] : 316 $colors_by_origin['core'] 317 ); 318 } 319 if ( isset( $editor_settings['__experimentalFeatures']['color']['gradients'] ) ) { 320 $gradients_by_origin = $editor_settings['__experimentalFeatures']['color']['gradients']; 321 $editor_settings['gradients'] = isset( $gradients_by_origin['user'] ) ? 322 $gradients_by_origin['user'] : ( 323 isset( $gradients_by_origin['theme'] ) ? 324 $gradients_by_origin['theme'] : 325 $gradients_by_origin['core'] 326 ); 327 } 328 if ( isset( $editor_settings['__experimentalFeatures']['typography']['fontSizes'] ) ) { 329 $font_sizes_by_origin = $editor_settings['__experimentalFeatures']['typography']['fontSizes']; 330 $editor_settings['fontSizes'] = isset( $font_sizes_by_origin['user'] ) ? 331 $font_sizes_by_origin['user'] : ( 332 isset( $font_sizes_by_origin['theme'] ) ? 333 $font_sizes_by_origin['theme'] : 334 $font_sizes_by_origin['core'] 335 ); 336 } 337 if ( isset( $editor_settings['__experimentalFeatures']['color']['custom'] ) ) { 338 $editor_settings['disableCustomColors'] = ! $editor_settings['__experimentalFeatures']['color']['custom']; 339 unset( $editor_settings['__experimentalFeatures']['color']['custom'] ); 340 } 341 if ( isset( $editor_settings['__experimentalFeatures']['color']['customGradient'] ) ) { 342 $editor_settings['disableCustomGradients'] = ! $editor_settings['__experimentalFeatures']['color']['customGradient']; 343 unset( $editor_settings['__experimentalFeatures']['color']['customGradient'] ); 344 } 345 if ( isset( $editor_settings['__experimentalFeatures']['typography']['customFontSize'] ) ) { 346 $editor_settings['disableCustomFontSizes'] = ! $editor_settings['__experimentalFeatures']['typography']['customFontSize']; 347 unset( $editor_settings['__experimentalFeatures']['typography']['customFontSize'] ); 348 } 349 if ( isset( $editor_settings['__experimentalFeatures']['typography']['customLineHeight'] ) ) { 350 $editor_settings['enableCustomLineHeight'] = $editor_settings['__experimentalFeatures']['typography']['customLineHeight']; 351 unset( $editor_settings['__experimentalFeatures']['typography']['customLineHeight'] ); 352 } 353 if ( isset( $editor_settings['__experimentalFeatures']['spacing']['units'] ) ) { 354 $editor_settings['enableCustomUnits'] = $editor_settings['__experimentalFeatures']['spacing']['units']; 355 unset( $editor_settings['__experimentalFeatures']['spacing']['units'] ); 356 } 357 if ( isset( $editor_settings['__experimentalFeatures']['spacing']['customPadding'] ) ) { 358 $editor_settings['enableCustomSpacing'] = $editor_settings['__experimentalFeatures']['spacing']['customPadding']; 359 unset( $editor_settings['__experimentalFeatures']['spacing']['customPadding'] ); 360 } 361 362 /** 363 * Filters the settings to pass to the block editor for all editor type. 364 * 365 * @since 5.8.0 366 * 367 * @param array $editor_settings Default editor settings. 368 * @param WP_Block_Editor_Context $block_editor_context The current block editor context. 369 */ 370 $editor_settings = apply_filters( 'block_editor_settings_all', $editor_settings, $block_editor_context ); 371 if ( ! empty( $block_editor_context->post ) ) { 372 $post = $block_editor_context->post; 373 374 /** 375 * Filters the settings to pass to the block editor. 376 * 377 * @since 5.0.0 378 * @deprecated 5.8.0 Use the {@see 'block_editor_settings_all'} filter instead. 379 * 380 * @param array $editor_settings Default editor settings. 381 * @param WP_Post $post Post being edited. 382 */ 383 $editor_settings = apply_filters_deprecated( 'block_editor_settings', array( $editor_settings, $post ), '5.8.0', 'block_editor_settings_all' ); 384 } 385 386 return $editor_settings; 387 } 388 389 /** 390 * Preloads common data used with the block editor by specifying an array of 391 * REST API paths that will be preloaded for a given block editor context. 392 * 393 * @since 5.8.0 394 * 395 * @global WP_Post $post Global post object. 396 * 397 * @param array $preload_paths List of paths to preload. 398 * @param WP_Block_Editor_Context $block_editor_context The current block editor context. 399 * 400 * @return void 401 */ 402 function block_editor_rest_api_preload( array $preload_paths, $block_editor_context ) { 403 global $post; 404 405 /** 406 * Filters the array of REST API paths that will be used to preloaded common data for the block editor. 407 * 408 * @since 5.8.0 409 * 410 * @param string[] $preload_paths Array of paths to preload. 411 */ 412 $preload_paths = apply_filters( 'block_editor_rest_api_preload_paths', $preload_paths, $block_editor_context ); 413 if ( ! empty( $block_editor_context->post ) ) { 414 $selected_post = $block_editor_context->post; 415 416 /** 417 * Filters the array of paths that will be preloaded. 418 * 419 * Preload common data by specifying an array of REST API paths that will be preloaded. 420 * 421 * @since 5.0.0 422 * @deprecated 5.8.0 Use the {@see 'block_editor_rest_api_preload_paths'} filter instead. 423 * 424 * @param string[] $preload_paths Array of paths to preload. 425 * @param WP_Post $selected_post Post being edited. 426 */ 427 $preload_paths = apply_filters_deprecated( 'block_editor_preload_paths', array( $preload_paths, $selected_post ), '5.8.0', 'block_editor_rest_api_preload_paths' ); 428 } 429 430 if ( empty( $preload_paths ) ) { 431 return; 432 } 433 434 /* 435 * Ensure the global $post remains the same after API data is preloaded. 436 * Because API preloading can call the_content and other filters, plugins 437 * can unexpectedly modify $post. 438 */ 439 $backup_global_post = ! empty( $post ) ? clone $post : $post; 440 441 $preload_data = array_reduce( 442 $preload_paths, 443 'rest_preload_api_request', 444 array() 445 ); 446 447 // Restore the global $post as it was before API preloading. 448 $post = $backup_global_post; 449 450 wp_add_inline_script( 451 'wp-api-fetch', 452 sprintf( 453 'wp.apiFetch.use( wp.apiFetch.createPreloadingMiddleware( %s ) );', 454 wp_json_encode( $preload_data ) 455 ), 456 'after' 457 ); 458 } 459 460 /** 461 * Creates an array of theme styles to load into the block editor. 462 * 463 * @since 5.8.0 464 * 465 * @global array $editor_styles 466 * 467 * @return array An array of theme styles for the block editor. Includes default font family 468 * style and theme stylesheets. 469 */ 470 function get_block_editor_theme_styles() { 471 global $editor_styles; 472 473 if ( ! WP_Theme_JSON_Resolver::theme_has_support() ) { 474 $styles = array( 475 array( 476 'css' => 'body { font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif }', 477 '__unstableType' => 'core', 478 ), 479 ); 480 } else { 481 $styles = array(); 482 } 483 484 if ( $editor_styles && current_theme_supports( 'editor-styles' ) ) { 485 foreach ( $editor_styles as $style ) { 486 if ( preg_match( '~^(https?:)?//~', $style ) ) { 487 $response = wp_remote_get( $style ); 488 if ( ! is_wp_error( $response ) ) { 489 $styles[] = array( 490 'css' => wp_remote_retrieve_body( $response ), 491 '__unstableType' => 'theme', 492 ); 493 } 494 } else { 495 $file = get_theme_file_path( $style ); 496 if ( is_file( $file ) ) { 497 $styles[] = array( 498 'css' => file_get_contents( $file ), 499 'baseURL' => get_theme_file_uri( $style ), 500 '__unstableType' => 'theme', 501 ); 502 } 503 } 504 } 505 } 506 507 return $styles; 508 }