Keine Beschreibung

block-editor.php 17KB

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