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

gutenberg.php in Gutenberg 4.0.0, at gutenberg.php

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