PluginProbe
Gutenberg / 4.6.1
Gutenberg v4.6.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 / lib / compat.php

compat.php in Gutenberg 4.6.1, at lib/compat.php

308 lines 9.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * PHP and WordPress configuration compatibility functions for the Gutenberg
4 * editor plugin.
5 *
6 * @package gutenberg
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 die( 'Silence is golden.' );
11 }
12
13 /**
14 * Splits a UTF-8 string into an array of UTF-8-encoded codepoints.
15 *
16 * @since 0.5.0
17 *
18 * Based on WordPress' _mb_substr() compat function.
19 *
20 * @param string $str The string to split.
21 * @return array
22 */
23 function _gutenberg_utf8_split( $str ) {
24 if ( _wp_can_use_pcre_u() ) {
25 // Use the regex unicode support to separate the UTF-8 characters into
26 // an array.
27 preg_match_all( '/./us', $str, $match );
28 return $match[0];
29 }
30
31 $regex = '/(
32 [\x00-\x7F] # single-byte sequences 0xxxxxxx
33 | [\xC2-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
34 | \xE0[\xA0-\xBF][\x80-\xBF] # triple-byte sequences 1110xxxx 10xxxxxx * 2
35 | [\xE1-\xEC][\x80-\xBF]{2}
36 | \xED[\x80-\x9F][\x80-\xBF]
37 | [\xEE-\xEF][\x80-\xBF]{2}
38 | \xF0[\x90-\xBF][\x80-\xBF]{2} # four-byte sequences 11110xxx 10xxxxxx * 3
39 | [\xF1-\xF3][\x80-\xBF]{3}
40 | \xF4[\x80-\x8F][\x80-\xBF]{2}
41 )/x';
42
43 // Start with 1 element instead of 0 since the first thing we do is pop.
44 $chars = array( '' );
45 do {
46 // We had some string left over from the last round, but we counted it
47 // in that last round.
48 array_pop( $chars );
49
50 // Split by UTF-8 character, limit to 1000 characters (last array
51 // element will contain the rest of the string).
52 $pieces = preg_split(
53 $regex,
54 $str,
55 1000,
56 PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
57 );
58
59 $chars = array_merge( $chars, $pieces );
60
61 // If there's anything left over, repeat the loop.
62 if ( count( $pieces ) > 1 ) {
63 $str = array_pop( $pieces );
64 } else {
65 break;
66 }
67 } while ( $str );
68
69 return $chars;
70 }
71
72 /**
73 * Disables wpautop behavior in classic editor when post contains blocks, to
74 * prevent removep from invalidating paragraph blocks.
75 *
76 * @param array $settings Original editor settings.
77 * @param string $editor_id ID for the editor instance.
78 * @return array Filtered settings.
79 */
80 function gutenberg_disable_editor_settings_wpautop( $settings, $editor_id ) {
81 $post = get_post();
82 if ( 'content' === $editor_id && is_object( $post ) && has_blocks( $post ) ) {
83 $settings['wpautop'] = false;
84 }
85
86 return $settings;
87 }
88 add_filter( 'wp_editor_settings', 'gutenberg_disable_editor_settings_wpautop', 10, 2 );
89
90 /**
91 * Add rest nonce to the heartbeat response.
92 *
93 * @param array $response Original heartbeat response.
94 * @return array New heartbeat response.
95 */
96 function gutenberg_add_rest_nonce_to_heartbeat_response_headers( $response ) {
97 $response['rest-nonce'] = wp_create_nonce( 'wp_rest' );
98 return $response;
99 }
100 add_filter( 'wp_refresh_nonces', 'gutenberg_add_rest_nonce_to_heartbeat_response_headers' );
101
102 /**
103 * Check if we need to load the block warning in the Classic Editor.
104 *
105 * @since 3.4.0
106 */
107 function gutenberg_check_if_classic_needs_warning_about_blocks() {
108 global $pagenow;
109
110 if ( ! in_array( $pagenow, array( 'post.php', 'post-new.php' ), true ) || ! isset( $_REQUEST['classic-editor'] ) ) {
111 return;
112 }
113
114 $post = get_post();
115 if ( ! $post ) {
116 return;
117 }
118
119 if ( ! has_blocks( $post ) ) {
120 return;
121 }
122
123 // Enqueue the JS we're going to need in the dialog.
124 wp_enqueue_script( 'wp-a11y' );
125 wp_enqueue_script( 'wp-sanitize' );
126
127 add_action( 'admin_footer', 'gutenberg_warn_classic_about_blocks' );
128 }
129 add_action( 'admin_enqueue_scripts', 'gutenberg_check_if_classic_needs_warning_about_blocks' );
130
131 /**
132 * Adds a warning to the Classic Editor when trying to edit a post containing blocks.
133 *
134 * @since 3.4.0
135 */
136 function gutenberg_warn_classic_about_blocks() {
137 $post = get_post();
138
139 $gutenberg_edit_link = get_edit_post_link( $post->ID, 'raw' );
140
141 $classic_edit_link = $gutenberg_edit_link;
142 $classic_edit_link = add_query_arg(
143 array(
144 'classic-editor' => '',
145 'hide-block-warning' => '',
146 ),
147 $classic_edit_link
148 );
149
150 $revisions_link = '';
151 if ( wp_revisions_enabled( $post ) ) {
152 $revisions = wp_get_post_revisions( $post );
153
154 // If there's only one revision, that won't help.
155 if ( count( $revisions ) > 1 ) {
156 reset( $revisions ); // Reset pointer for key().
157 $revisions_link = get_edit_post_link( key( $revisions ) );
158 }
159 }
160 ?>
161 <style type="text/css">
162 #blocks-in-post-dialog .notification-dialog {
163 position: fixed;
164 top: 50%;
165 left: 50%;
166 width: 500px;
167 box-sizing: border-box;
168 transform: translate(-50%, -50%);
169 margin: 0;
170 padding: 25px;
171 max-height: 90%;
172 background: #fff;
173 box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3);
174 line-height: 1.5;
175 z-index: 1000005;
176 overflow-y: auto;
177 }
178
179 @media only screen and (max-height: 480px), screen and (max-width: 450px) {
180 #blocks-in-post-dialog .notification-dialog {
181 top: 0;
182 left: 0;
183 width: 100%;
184 height: 100%;
185 transform: none;
186 max-height: 100%;
187 }
188 }
189 </style>
190
191 <div id="blocks-in-post-dialog" class="notification-dialog-wrap">
192 <div class="notification-dialog-background"></div>
193 <div class="notification-dialog">
194 <div class="blocks-in-post-message">
195 <p><?php _e( 'This post was previously edited in Gutenberg. You can continue in the Classic Editor, but you may lose data and formatting.', 'gutenberg' ); ?></p>
196 <?php
197 if ( $revisions_link ) {
198 ?>
199 <p>
200 <?php
201 /* translators: link to the post revisions page */
202 printf( __( 'You can also <a href="%s">browse previous revisions</a> and restore a version of the post before it was edited in Gutenberg.', 'gutenberg' ), esc_url( $revisions_link ) );
203 ?>
204 </p>
205 <?php
206 } else {
207 ?>
208 <p><strong><?php _e( 'Because this post does not have revisions, you will not be able to revert any changes you make in the Classic Editor.', 'gutenberg' ); ?></strong></p>
209 <?php
210 }
211 ?>
212 </div>
213 <p>
214 <a class="button button-primary blocks-in-post-gutenberg-button" href="<?php echo esc_url( $gutenberg_edit_link ); ?>"><?php _e( 'Edit in Gutenberg', 'gutenberg' ); ?></a>
215 <button type="button" class="button blocks-in-post-classic-button"><?php _e( 'Continue to Classic Editor', 'gutenberg' ); ?></button>
216 </p>
217 </div>
218 </div>
219
220 <script type="text/javascript">
221 /* <![CDATA[ */
222 ( function( $ ) {
223 var dialog = {};
224
225 dialog.init = function() {
226 // The modal
227 dialog.warning = $( '#blocks-in-post-dialog' );
228 // Get the links and buttons within the modal.
229 dialog.warningTabbables = dialog.warning.find( 'a, button' );
230
231 // Get the text within the modal.
232 dialog.rawMessage = dialog.warning.find( '.blocks-in-post-message' ).text();
233
234 // Hide all the #wpwrap content from assistive technologies.
235 $( '#wpwrap' ).attr( 'aria-hidden', 'true' );
236
237 // Detach the warning modal from its position and append it to the body.
238 $( document.body )
239 .addClass( 'modal-open' )
240 .append( dialog.warning.detach() );
241
242 // Reveal the modal and set focus on the Gutenberg button.
243 dialog.warning
244 .removeClass( 'hidden' )
245 .find( '.blocks-in-post-gutenberg-button' ).focus();
246
247 // Attach event handlers.
248 dialog.warningTabbables.on( 'keydown', dialog.constrainTabbing );
249 dialog.warning.on( 'click', '.blocks-in-post-classic-button', dialog.dismissWarning );
250
251 // Make screen readers announce the warning message after a short delay (necessary for some screen readers).
252 setTimeout( function() {
253 wp.a11y.speak( wp.sanitize.stripTags( dialog.rawMessage.replace( /\s+/g, ' ' ) ), 'assertive' );
254 }, 1000 );
255 };
256
257 dialog.constrainTabbing = function( event ) {
258 var firstTabbable, lastTabbable;
259
260 if ( 9 !== event.which ) {
261 return;
262 }
263
264 firstTabbable = dialog.warningTabbables.first()[0];
265 lastTabbable = dialog.warningTabbables.last()[0];
266
267 if ( lastTabbable === event.target && ! event.shiftKey ) {
268 firstTabbable.focus();
269 event.preventDefault();
270 } else if ( firstTabbable === event.target && event.shiftKey ) {
271 lastTabbable.focus();
272 event.preventDefault();
273 }
274 };
275
276 dialog.dismissWarning = function() {
277 // Hide modal.
278 dialog.warning.remove();
279 $( '#wpwrap' ).removeAttr( 'aria-hidden' );
280 $( 'body' ).removeClass( 'modal-open' );
281 };
282
283 $( document ).ready( dialog.init );
284 } )( jQuery );
285 /* ]]> */
286 </script>
287 <?php
288 }
289
290 /**
291 * Display the privacy policy help notice.
292 *
293 * In Gutenberg, the `edit_form_after_title` hook is not supported. Because
294 * WordPress Core uses this hook to display this notice, it never displays.
295 * Outputting the notice on the `admin_notices` hook allows Gutenberg to
296 * consume the notice and display it with the Notices API.
297 *
298 * @since 4.5.0
299 */
300 function gutenberg_show_privacy_policy_help_text() {
301 if ( is_gutenberg_page() && has_action( 'edit_form_after_title', array( 'WP_Privacy_Policy_Content', 'notice' ) ) ) {
302 remove_action( 'edit_form_after_title', array( 'WP_Privacy_Policy_Content', 'notice' ) );
303
304 WP_Privacy_Policy_Content::notice( get_post() );
305 }
306 }
307 add_action( 'admin_notices', 'gutenberg_show_privacy_policy_help_text' );
308