PluginProbe
Gutenberg / 4.7.0
Gutenberg v4.7.0
24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 All 403 releases
← All changes | gutenberg.php +516 -20 24.0.04.7.0 View file →
@@ -1,23 +1,153 @@
1 1 <?php
2 2 /**
3 3 * Plugin Name: Gutenberg
4 4 * Plugin URI: https://github.com/WordPress/gutenberg
5 - * Description: Printing since 1440. This is the development plugin for the block editor, site editor, and other future WordPress core functionality.
6 - * Requires at least: 6.9
7 - * Requires PHP: 7.4
8 - * Version: 24.0.0
5 + * Description: Printing since 1440. This is the development plugin for the new block editor in core.
6 + * Version: 4.7.0
9 7 * Author: Gutenberg Team
10 - * Text Domain: gutenberg
11 8 *
12 9 * @package gutenberg
13 10 */
14 11
15 -defined( 'GUTENBERG_MINIMUM_WP_VERSION' ) or define( 'GUTENBERG_MINIMUM_WP_VERSION', '6.9' );
12 +### BEGIN AUTO-GENERATED DEFINES
13 +define( 'GUTENBERG_VERSION', '4.7.0' );
14 +define( 'GUTENBERG_GIT_COMMIT', '185fa5877db2c27fb466ac8799f66be022c55adf' );
15 +### END AUTO-GENERATED DEFINES
16 16
17 17 gutenberg_pre_init();
18 18
19 19 /**
20 + * Project.
21 + *
22 + * The main entry point for the Gutenberg editor. Renders the editor on the
23 + * wp-admin page for the plugin.
24 + *
25 + * The gutenberg and gutenberg__editor classNames are left for backward compatibility.
26 + *
27 + * @since 0.1.0
28 + */
29 +function the_gutenberg_project() {
30 + global $post_type_object;
31 + ?>
32 + <noscript>
33 + <div class="error" style="position:absolute;top:32px;z-index:40"><p>
34 + <?php
35 + // Using Gutenberg as Plugin.
36 + if ( is_plugin_active( 'gutenberg/gutenberg.php' ) ) {
37 + $current_url = esc_url( add_query_arg( 'classic-editor', true, $_SERVER['REQUEST_URI'] ) );
38 + printf(
39 + // Translators: link is to current page specify classic editor.
40 + __( 'The Block Editor requires JavaScript. You can use the <a href="%s">Classic Editor</a>.', 'gutenberg' ),
41 + $current_url
42 + );
43 + } else { // Using Gutenberg in Core.
44 + printf(
45 + /* translators: %s: https://wordpress.org/plugins/classic-editor/ */
46 + __( 'The Block Editor requires JavaScript. Please try the <a href="%s">Classic Editor plugin</a>.', 'gutenberg' ),
47 + __( 'https://wordpress.org/plugins/classic-editor/', 'gutenberg' )
48 + );
49 + }
50 + ?>
51 + </p></div>
52 + </noscript>
53 + <div class="block-editor gutenberg">
54 + <h1 class="screen-reader-text"><?php echo esc_html( $post_type_object->labels->edit_item ); ?></h1>
55 + <div id="editor" class="block-editor__container gutenberg__editor"></div>
56 + <div id="metaboxes" style="display: none;">
57 + <?php the_gutenberg_metaboxes(); ?>
58 + </div>
59 + </div>
60 + <?php
61 +}
62 +
63 +/**
64 + * Gutenberg's Menu.
65 + *
66 + * Adds a new wp-admin menu page for the Gutenberg editor.
67 + *
68 + * @since 0.1.0
69 + */
70 +function gutenberg_menu() {
71 + global $submenu;
72 +
73 + add_menu_page(
74 + 'Gutenberg',
75 + 'Gutenberg',
76 + 'edit_posts',
77 + 'gutenberg',
78 + 'the_gutenberg_project',
79 + 'dashicons-edit'
80 + );
81 +
82 + add_submenu_page(
83 + 'gutenberg',
84 + __( 'Demo', 'gutenberg' ),
85 + __( 'Demo', 'gutenberg' ),
86 + 'edit_posts',
87 + 'gutenberg'
88 + );
89 +
90 + if ( current_user_can( 'edit_posts' ) ) {
91 + $submenu['gutenberg'][] = array(
92 + __( 'Support', 'gutenberg' ),
93 + 'edit_posts',
94 + __( 'https://wordpress.org/support/plugin/gutenberg', 'gutenberg' ),
95 + );
96 +
97 + $submenu['gutenberg'][] = array(
98 + __( 'Feedback', 'gutenberg' ),
99 + 'edit_posts',
100 + 'http://wordpressdotorg.polldaddy.com/s/gutenberg-support',
101 + );
102 +
103 + $submenu['gutenberg'][] = array(
104 + __( 'Documentation', 'gutenberg' ),
105 + 'edit_posts',
106 + 'https://wordpress.org/gutenberg/handbook/',
107 + );
108 + }
109 +}
110 +add_action( 'admin_menu', 'gutenberg_menu' );
111 +
112 +/**
113 + * Checks whether we're currently loading a Gutenberg page
114 + *
115 + * @return boolean Whether Gutenberg is being loaded.
116 + *
117 + * @since 3.1.0
118 + */
119 +function is_gutenberg_page() {
120 + global $post;
121 +
122 + if ( ! is_admin() ) {
123 + return false;
124 + }
125 +
126 + /*
127 + * There have been reports of specialized loading scenarios where `get_current_screen`
128 + * does not exist. In these cases, it is safe to say we are not loading Gutenberg.
129 + */
130 + if ( ! function_exists( 'get_current_screen' ) ) {
131 + return false;
132 + }
133 +
134 + if ( get_current_screen()->base !== 'post' ) {
135 + return false;
136 + }
137 +
138 + if ( isset( $_GET['classic-editor'] ) ) {
139 + return false;
140 + }
141 +
142 + if ( ! gutenberg_can_edit_post( $post ) ) {
143 + return false;
144 + }
145 +
146 + return true;
147 +}
148 +
149 +/**
20 150 * Display a version notice and deactivate the Gutenberg plugin.
21 151 *
22 152 * @since 0.1.0
23 153 */
@@ -22,13 +152,12 @@
22 152 * @since 0.1.0
23 153 */
24 154 function gutenberg_wordpress_version_notice() {
25 155 echo '<div class="error"><p>';
26 - /* translators: %s: Minimum required version */
27 - printf( __( 'Gutenberg requires WordPress %s or later to function properly. Please upgrade WordPress before activating Gutenberg.', 'gutenberg' ), GUTENBERG_MINIMUM_WP_VERSION );
156 + _e( 'Gutenberg requires WordPress 4.9.8 or later to function properly. Please upgrade WordPress before activating Gutenberg.', 'gutenberg' );
28 157 echo '</p></div>';
29 158
30 - deactivate_plugins( array( plugin_basename( __FILE__ ) ) );
159 + deactivate_plugins( array( 'gutenberg/gutenberg.php' ) );
31 160 }
32 161
33 162 /**
34 163 * Display a build notice.
@@ -36,9 +165,9 @@
36 165 * @since 0.1.0
37 166 */
38 167 function gutenberg_build_files_notice() {
39 168 echo '<div class="error"><p>';
40 - _e( 'Gutenberg development mode requires files to be built. Run <code>npm install</code> to install dependencies, <code>npm run build</code> to build the files or <code>npm run dev</code> to build the files and watch for changes. Read the <a href="https://github.com/WordPress/gutenberg/blob/HEAD/docs/contributors/code/getting-started-with-code-contribution.md">contributing</a> file for more information.', 'gutenberg' );
169 + _e( 'Gutenberg development mode requires files to be built. Run <code>npm install</code> to install dependencies, <code>npm run build</code> to build the files or <code>npm run dev</code> to build the files and watch for changes. Read the <a href="https://github.com/WordPress/gutenberg/blob/master/CONTRIBUTING.md">contributing</a> file for more information.', 'gutenberg' );
41 170 echo '</p></div>';
42 171 }
43 172
44 173 /**
@@ -44,15 +173,11 @@
44 173 /**
45 174 * Verify that we can initialize the Gutenberg editor , then load it.
46 175 *
47 176 * @since 1.5.0
48 - *
49 - * @global string $wp_version The WordPress version string.
50 - *
51 177 */
52 178 function gutenberg_pre_init() {
53 - global $wp_version;
54 - if ( ! file_exists( __DIR__ . '/build/scripts/blocks' ) ) {
179 + if ( defined( 'GUTENBERG_DEVELOPMENT_MODE' ) && GUTENBERG_DEVELOPMENT_MODE && ! file_exists( dirname( __FILE__ ) . '/build/blocks' ) ) {
55 180 add_action( 'admin_notices', 'gutenberg_build_files_notice' );
56 181 return;
57 182 }
58 183
@@ -61,14 +186,385 @@
61 186
62 187 // Strip '-src' from the version string. Messes up version_compare().
63 188 $version = str_replace( '-src', '', $wp_version );
64 189
65 - // Compare against major release versions (X.Y) rather than minor (X.Y.Z)
66 - // unless a minor release is the actual minimum requirement. WordPress reports
67 - // X.Y for its major releases.
68 - if ( version_compare( $version, GUTENBERG_MINIMUM_WP_VERSION, '<' ) ) {
190 + if ( version_compare( $version, '4.9.8', '<' ) ) {
69 191 add_action( 'admin_notices', 'gutenberg_wordpress_version_notice' );
70 192 return;
71 193 }
72 194
73 - require_once __DIR__ . '/lib/load.php';
195 + require_once dirname( __FILE__ ) . '/lib/load.php';
196 +
197 + if ( function_exists( 'gutenberg_silence_rest_errors' ) ) {
198 + gutenberg_silence_rest_errors();
199 + }
200 +
201 + add_filter( 'replace_editor', 'gutenberg_init', 10, 2 );
74 202 }
203 +
204 +/**
205 + * Initialize Gutenberg.
206 + *
207 + * Load API functions, register scripts and actions, etc.
208 + *
209 + * @param bool $return Whether to replace the editor. Used in the `replace_editor` filter.
210 + * @param object $post The post to edit or an auto-draft.
211 + * @return bool Whether Gutenberg was initialized.
212 + */
213 +function gutenberg_init( $return, $post ) {
214 + global $title, $post_type;
215 +
216 + if ( true === $return && current_filter() === 'replace_editor' ) {
217 + return $return;
218 + }
219 +
220 + if ( ! is_gutenberg_page() ) {
221 + return false;
222 + }
223 +
224 + add_action( 'admin_enqueue_scripts', 'gutenberg_editor_scripts_and_styles' );
225 + add_filter( 'screen_options_show_screen', '__return_false' );
226 + add_filter( 'admin_body_class', 'gutenberg_add_admin_body_class' );
227 +
228 + $post_type_object = get_post_type_object( $post_type );
229 +
230 + /*
231 + * Always force <title> to 'Edit Post' (or equivalent)
232 + * because it needs to be in a generic state for both
233 + * post-new.php and post.php?post=<id>.
234 + */
235 + if ( ! empty( $post_type_object ) ) {
236 + $title = $post_type_object->labels->edit_item;
237 + }
238 +
239 + /*
240 + * Remove the emoji script as it is incompatible with both React and any
241 + * contenteditable fields.
242 + */
243 + remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
244 +
245 + /*
246 + * Ensure meta box functions are available to third-party code;
247 + * includes/meta-boxes is typically loaded from edit-form-advanced.php.
248 + */
249 + require_once ABSPATH . 'wp-admin/includes/meta-boxes.php';
250 + gutenberg_collect_meta_box_data();
251 +
252 + require_once ABSPATH . 'wp-admin/admin-header.php';
253 + the_gutenberg_project();
254 +
255 + return true;
256 +}
257 +
258 +/**
259 + * Redirects the demo page to edit a new post.
260 + */
261 +function gutenberg_redirect_demo() {
262 + global $pagenow;
263 +
264 + if ( 'admin.php' === $pagenow && isset( $_GET['page'] ) && 'gutenberg' === $_GET['page'] ) {
265 + wp_safe_redirect( admin_url( 'post-new.php?gutenberg-demo' ) );
266 + exit;
267 + }
268 +}
269 +add_action( 'admin_init', 'gutenberg_redirect_demo' );
270 +
271 +/**
272 + * Adds the filters to register additional links for the Gutenberg editor in
273 + * the post/page screens.
274 + *
275 + * @since 1.5.0
276 + */
277 +function gutenberg_add_edit_link_filters() {
278 + // For hierarchical post types.
279 + add_filter( 'page_row_actions', 'gutenberg_add_edit_link', 10, 2 );
280 + // For non-hierarchical post types.
281 + add_filter( 'post_row_actions', 'gutenberg_add_edit_link', 10, 2 );
282 +}
283 +add_action( 'admin_init', 'gutenberg_add_edit_link_filters' );
284 +
285 +/**
286 + * Registers an additional link in the post/page screens to edit any post/page in
287 + * the Classic editor.
288 + *
289 + * @since 1.5.0
290 + *
291 + * @param array $actions Post actions.
292 + * @param WP_Post $post Edited post.
293 + *
294 + * @return array Updated post actions.
295 + */
296 +function gutenberg_add_edit_link( $actions, $post ) {
297 + // Build the classic edit action. See also: WP_Posts_List_Table::handle_row_actions().
298 + $title = _draft_or_post_title( $post->ID );
299 +
300 + if ( 'wp_block' === $post->post_type ) {
301 + unset( $actions['inline hide-if-no-js'] );
302 +
303 + // Export uses block raw content, which is only returned from the post
304 + // REST endpoint via `context=edit`, requiring edit capability.
305 + $post_type = get_post_type_object( $post->post_type );
306 + if ( ! current_user_can( $post_type->cap->edit_post, $post->ID ) ) {
307 + return $actions;
308 + }
309 +
310 + $actions['export'] = sprintf(
311 + '<button type="button" class="wp-list-reusable-blocks__export button-link" data-id="%s" aria-label="%s">%s</button>',
312 + $post->ID,
313 + esc_attr(
314 + sprintf(
315 + /* translators: %s: post title */
316 + __( 'Export &#8220;%s&#8221; as JSON', 'gutenberg' ),
317 + $title
318 + )
319 + ),
320 + __( 'Export as JSON', 'gutenberg' )
321 + );
322 + return $actions;
323 + }
324 +
325 + if ( ! gutenberg_can_edit_post( $post ) ) {
326 + return $actions;
327 + }
328 +
329 + $edit_url = get_edit_post_link( $post->ID, 'raw' );
330 + $edit_url = add_query_arg( 'classic-editor', '', $edit_url );
331 +
332 + $edit_action = array(
333 + 'classic' => sprintf(
334 + '<a href="%s" aria-label="%s">%s</a>',
335 + esc_url( $edit_url ),
336 + esc_attr(
337 + sprintf(
338 + /* translators: %s: post title */
339 + __( 'Edit &#8220;%s&#8221; in the classic editor', 'gutenberg' ),
340 + $title
341 + )
342 + ),
343 + __( 'Classic Editor', 'gutenberg' )
344 + ),
345 + );
346 +
347 + // Insert the Classic Edit action after the Edit action.
348 + $edit_offset = array_search( 'edit', array_keys( $actions ), true );
349 + $actions = array_merge(
350 + array_slice( $actions, 0, $edit_offset + 1 ),
351 + $edit_action,
352 + array_slice( $actions, $edit_offset + 1 )
353 + );
354 +
355 + return $actions;
356 +}
357 +
358 +/**
359 + * Removes the Edit action from the reusable block list's Bulk Actions dropdown.
360 + *
361 + * @since 3.8.0
362 + *
363 + * @param array $actions Bulk actions.
364 + *
365 + * @return array Updated bulk actions.
366 + */
367 +function gutenberg_block_bulk_actions( $actions ) {
368 + unset( $actions['edit'] );
369 + return $actions;
370 +}
371 +add_filter( 'bulk_actions-edit-wp_block', 'gutenberg_block_bulk_actions' );
372 +
373 +/**
374 + * Prints the JavaScript to replace the default "Add New" button.$_COOKIE
375 + *
376 + * @since 1.5.0
377 + */
378 +function gutenberg_replace_default_add_new_button() {
379 + global $typenow;
380 +
381 + if ( 'wp_block' === $typenow ) {
382 + ?>
383 + <style type="text/css">
384 + .page-title-action {
385 + display: none;
386 + }
387 + </style>
388 + <?php
389 + }
390 +
391 + if ( ! gutenberg_can_edit_post_type( $typenow ) ) {
392 + return;
393 + }
394 +
395 + ?>
396 + <style type="text/css">
397 + .split-page-title-action {
398 + display: inline-block;
399 + }
400 +
401 + .split-page-title-action a,
402 + .split-page-title-action a:active,
403 + .split-page-title-action .expander:after {
404 + padding: 6px 10px;
405 + position: relative;
406 + top: -3px;
407 + text-decoration: none;
408 + border: 1px solid #ccc;
409 + border-radius: 2px;
410 + background: #f7f7f7;
411 + text-shadow: none;
412 + font-weight: 600;
413 + font-size: 13px;
414 + line-height: normal; /* IE8-IE11 need this for buttons */
415 + color: #0073aa; /* some of these controls are button elements and don't inherit from links */
416 + cursor: pointer;
417 + outline: 0;
418 + }
419 +
420 + .split-page-title-action a:hover,
421 + .split-page-title-action .expander:hover:after {
422 + border-color: #008EC2;
423 + background: #00a0d2;
424 + color: #fff;
425 + }
426 +
427 + .split-page-title-action a:focus,
428 + .split-page-title-action .expander:focus:after {
429 + border-color: #5b9dd9;
430 + box-shadow: 0 0 2px rgba( 30, 140, 190, 0.8 );
431 + }
432 +
433 + .split-page-title-action .expander:after {
434 + content: "\f140";
435 + font: 400 20px/.5 dashicons;
436 + speak: none;
437 + top: 1px;
438 + <?php if ( is_rtl() ) : ?>
439 + right: -1px;
440 + <?php else : ?>
441 + left: -1px;
442 + <?php endif; ?>
443 + position: relative;
444 + vertical-align: top;
445 + text-decoration: none !important;
446 + padding: 4px 5px 4px 3px;
447 + }
448 +
449 + .split-page-title-action .dropdown {
450 + display: none;
451 + }
452 +
453 + .split-page-title-action .dropdown.visible {
454 + display: block;
455 + position: absolute;
456 + margin-top: 3px;
457 + z-index: 1;
458 + }
459 +
460 + .split-page-title-action .dropdown.visible a {
461 + display: block;
462 + top: 0;
463 + margin: -1px 0;
464 + <?php if ( is_rtl() ) : ?>
465 + padding-left: 9px;
466 + <?php else : ?>
467 + padding-right: 9px;
468 + <?php endif; ?>
469 + }
470 +
471 + .split-page-title-action .expander {
472 + outline: none;
473 + }
474 +
475 + </style>
476 + <script type="text/javascript">
477 + document.addEventListener( 'DOMContentLoaded', function() {
478 + var buttons = document.getElementsByClassName( 'page-title-action' ),
479 + button = buttons.item( 0 );
480 +
481 + if ( ! button ) {
482 + return;
483 + }
484 +
485 + var url = button.href;
486 + var urlHasParams = ( -1 !== url.indexOf( '?' ) );
487 + var classicUrl = url + ( urlHasParams ? '&' : '?' ) + 'classic-editor';
488 +
489 + var newbutton = '<span id="split-page-title-action" class="split-page-title-action">';
490 + newbutton += '<a href="' + url + '">' + button.innerText + '</a>';
491 + newbutton += '<span class="expander" tabindex="0" role="button" aria-haspopup="true" aria-label="<?php echo esc_js( __( 'Toggle editor selection menu', 'gutenberg' ) ); ?>"></span>';
492 + newbutton += '<span class="dropdown"><a href="' + url + '">Gutenberg</a>';
493 + newbutton += '<a href="' + classicUrl + '"><?php echo esc_js( __( 'Classic Editor', 'gutenberg' ) ); ?></a></span></span><span class="page-title-action" style="display:none;"></span>';
494 +
495 + button.insertAdjacentHTML( 'afterend', newbutton );
496 + button.parentNode.removeChild( button );
497 +
498 + var expander = document.getElementById( 'split-page-title-action' ).getElementsByClassName( 'expander' ).item( 0 );
499 + var dropdown = expander.parentNode.querySelector( '.dropdown' );
500 + function toggleDropdown() {
501 + dropdown.classList.toggle( 'visible' );
502 + }
503 + expander.addEventListener( 'click', function( e ) {
504 + e.preventDefault();
505 + toggleDropdown();
506 + } );
507 + expander.addEventListener( 'keydown', function( e ) {
508 + if ( 13 === e.which || 32 === e.which ) {
509 + e.preventDefault();
510 + toggleDropdown();
511 + }
512 + } );
513 + } );
514 + </script>
515 + <?php
516 +}
517 +add_action( 'admin_print_scripts-edit.php', 'gutenberg_replace_default_add_new_button' );
518 +
519 +/**
520 + * Adds the block-editor-page class to the body tag on the Gutenberg page.
521 + *
522 + * @since 1.5.0
523 + *
524 + * @param string $classes Space separated string of classes being added to the body tag.
525 + * @return string The $classes string, with block-editor-page appended.
526 + */
527 +function gutenberg_add_admin_body_class( $classes ) {
528 + // gutenberg-editor-page is left for backward compatibility.
529 + if ( current_theme_supports( 'editor-styles' ) && current_theme_supports( 'dark-editor-style' ) ) {
530 + return "$classes block-editor-page gutenberg-editor-page is-fullscreen-mode wp-embed-responsive is-dark-theme";
531 + } else {
532 + // Default to is-fullscreen-mode to avoid jumps in the UI.
533 + return "$classes block-editor-page gutenberg-editor-page is-fullscreen-mode wp-embed-responsive";
534 + }
535 +}
536 +
537 +/**
538 + * Adds attributes to kses allowed tags that aren't in the default list
539 + * and that Gutenberg needs to save blocks such as the Gallery block.
540 + *
541 + * @param array $tags Allowed HTML.
542 + * @return array (Maybe) modified allowed HTML.
543 + */
544 +function gutenberg_kses_allowedtags( $tags ) {
545 + if ( isset( $tags['img'] ) ) {
546 + $tags['img']['data-link'] = true;
547 + $tags['img']['data-id'] = true;
548 + }
549 + return $tags;
550 +}
551 +
552 +add_filter( 'wp_kses_allowed_html', 'gutenberg_kses_allowedtags', 10, 2 );
553 +
554 +/**
555 + * Adds the wp-embed-responsive class to the body tag if the theme has opted in to
556 + * Gutenberg responsive embeds.
557 + *
558 + * @since 4.1.0
559 + *
560 + * @param Array $classes Array of classes being added to the body tag.
561 + * @return Array The $classes array, with wp-embed-responsive appended.
562 + */
563 +function gutenberg_add_responsive_body_class( $classes ) {
564 + if ( current_theme_supports( 'responsive-embeds' ) ) {
565 + $classes[] = 'wp-embed-responsive';
566 + }
567 + return $classes;
568 +}
569 +
570 +add_filter( 'body_class', 'gutenberg_add_responsive_body_class' );