PluginProbe
Gutenberg / 4.0.1
Gutenberg v4.0.1
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.0.1, at gutenberg.php

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