PluginProbe
Gutenberg / 4.3.0
Gutenberg v4.3.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 7.4.0 All 402 releases
gutenberg / gutenberg.php

gutenberg.php in Gutenberg 4.3.0, at gutenberg.php

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