PluginProbe
Gutenberg / 8.7.1
Gutenberg v8.7.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 / rest-api.php

rest-api.php in Gutenberg 8.7.1, at lib/rest-api.php

331 lines 10.5 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 changes related to REST API.
5 *
6 * @package gutenberg
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 die( 'Silence is golden.' );
11 }
12
13 /**
14 * Handle a failing oEmbed proxy request to try embedding as a shortcode.
15 *
16 * @see https://core.trac.wordpress.org/ticket/45447
17 *
18 * @since 2.3.0
19 *
20 * @param WP_HTTP_Response|WP_Error $response The REST Request response.
21 * @param WP_REST_Server $handler ResponseHandler instance (usually WP_REST_Server).
22 * @param WP_REST_Request $request Request used to generate the response.
23 * @return WP_HTTP_Response|object|WP_Error The REST Request response.
24 */
25 function gutenberg_filter_oembed_result( $response, $handler, $request ) {
26 if ( ! is_wp_error( $response ) || 'oembed_invalid_url' !== $response->get_error_code() ||
27 '/oembed/1.0/proxy' !== $request->get_route() ) {
28 return $response;
29 }
30
31 // Try using a classic embed instead.
32 global $wp_embed;
33 $html = $wp_embed->shortcode( array(), $_GET['url'] );
34 if ( ! $html ) {
35 return $response;
36 }
37
38 global $wp_scripts;
39
40 // Check if any scripts were enqueued by the shortcode, and include them in
41 // the response.
42 $enqueued_scripts = array();
43 foreach ( $wp_scripts->queue as $script ) {
44 $enqueued_scripts[] = $wp_scripts->registered[ $script ]->src;
45 }
46
47 return array(
48 'provider_name' => __( 'Embed Handler', 'gutenberg' ),
49 'html' => $html,
50 'scripts' => $enqueued_scripts,
51 );
52 }
53 add_filter( 'rest_request_after_callbacks', 'gutenberg_filter_oembed_result', 10, 3 );
54
55 /**
56 * Add fields required for site editing to the /themes endpoint.
57 *
58 * @todo Remove once Gutenberg's minimum required WordPress version is v5.5.
59 * @see https://core.trac.wordpress.org/ticket/49906
60 * @see https://core.trac.wordpress.org/changeset/47921
61 *
62 * @param WP_REST_Response $response The response object.
63 * @param WP_Theme $theme Theme object used to create response.
64 * @param WP_REST_Request $request Request object.
65 */
66 function gutenberg_filter_rest_prepare_theme( $response, $theme, $request ) {
67 $data = $response->get_data();
68 $fields = array_keys( $data );
69
70 /**
71 * The following is basically copied from Core's WP_REST_Themes_Controller::prepare_item_for_response()
72 * (as of WP v5.5), with `rest_is_field_included()` replaced by `! in_array()`.
73 * This makes sure that we add all the fields that are missing from Core.
74 *
75 * @see https://github.com/WordPress/WordPress/blob/019bc2d244c4d536338d2c634419583e928143df/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php#L118-L167
76 */
77 if ( ! in_array( 'stylesheet', $fields, true ) ) {
78 $data['stylesheet'] = $theme->get_stylesheet();
79 }
80
81 if ( ! in_array( 'template', $fields, true ) ) {
82 /**
83 * Use the get_template() method, not the 'Template' header, for finding the template.
84 * The 'Template' header is only good for what was written in the style.css, while
85 * get_template() takes into account where WordPress actually located the theme and
86 * whether it is actually valid.
87 */
88 $data['template'] = $theme->get_template();
89 }
90
91 $plain_field_mappings = array(
92 'requires_php' => 'RequiresPHP',
93 'requires_wp' => 'RequiresWP',
94 'textdomain' => 'TextDomain',
95 'version' => 'Version',
96 );
97
98 foreach ( $plain_field_mappings as $field => $header ) {
99 if ( ! in_array( $field, $fields, true ) ) {
100 $data[ $field ] = $theme->get( $header );
101 }
102 }
103
104 if ( ! in_array( 'screenshot', $fields, true ) ) {
105 // Using $theme->get_screenshot() with no args to get absolute URL.
106 $data['screenshot'] = $theme->get_screenshot() ? $theme->get_screenshot() : '';
107 }
108
109 $rich_field_mappings = array(
110 'author' => 'Author',
111 'author_uri' => 'AuthorURI',
112 'description' => 'Description',
113 'name' => 'Name',
114 'tags' => 'Tags',
115 'theme_uri' => 'ThemeURI',
116 );
117
118 foreach ( $rich_field_mappings as $field => $header ) {
119 if ( ! in_array( $field, $fields, true ) ) {
120 $data[ $field ]['raw'] = $theme->display( $header, false, true );
121 $data[ $field ]['rendered'] = $theme->display( $header );
122 }
123 }
124
125 $response->set_data( $data );
126 return $response;
127 }
128 add_filter( 'rest_prepare_theme', 'gutenberg_filter_rest_prepare_theme', 10, 3 );
129
130 /**
131 * Start: Include for phase 2
132 */
133 /**
134 * Registers the REST API routes needed by the legacy widget block.
135 *
136 * @since 5.0.0
137 */
138 function gutenberg_register_rest_widget_updater_routes() {
139 $widget_forms = new WP_REST_Widget_Forms();
140 $widget_forms->register_routes();
141 }
142 add_action( 'rest_api_init', 'gutenberg_register_rest_widget_updater_routes' );
143
144 /**
145 * Registers the widget area REST API routes.
146 *
147 * @since 5.7.0
148 */
149 function gutenberg_register_rest_widget_areas() {
150 $widget_areas_controller = new WP_REST_Widget_Areas_Controller();
151 $widget_areas_controller->register_routes();
152 }
153 add_action( 'rest_api_init', 'gutenberg_register_rest_widget_areas' );
154
155 /**
156 * Registers the block directory.
157 *
158 * @since 6.5.0
159 */
160 function gutenberg_register_rest_block_directory() {
161 $block_directory_controller = new WP_REST_Block_Directory_Controller();
162 $block_directory_controller->register_routes();
163 }
164 add_filter( 'rest_api_init', 'gutenberg_register_rest_block_directory' );
165
166 /**
167 * Registers the Block types REST API routes.
168 */
169 function gutenberg_register_block_type() {
170 $block_types = new WP_REST_Block_Types_Controller();
171 $block_types->register_routes();
172 }
173 add_action( 'rest_api_init', 'gutenberg_register_block_type' );
174 /**
175 * Registers the menu locations area REST API routes.
176 */
177 function gutenberg_register_rest_menu_location() {
178 $nav_menu_location = new WP_REST_Menu_Locations_Controller();
179 $nav_menu_location->register_routes();
180 }
181 add_action( 'rest_api_init', 'gutenberg_register_rest_menu_location' );
182
183 /**
184 * Registers the menu locations area REST API routes.
185 */
186 function gutenberg_register_rest_customizer_nonces() {
187 $nav_menu_location = new WP_Rest_Customizer_Nonces();
188 $nav_menu_location->register_routes();
189 }
190 add_action( 'rest_api_init', 'gutenberg_register_rest_customizer_nonces' );
191
192
193 /**
194 * Registers the Plugins REST API routes.
195 */
196 function gutenberg_register_plugins_endpoint() {
197 $plugins = new WP_REST_Plugins_Controller();
198 $plugins->register_routes();
199 }
200 add_action( 'rest_api_init', 'gutenberg_register_plugins_endpoint' );
201
202 /**
203 * Hook in to the nav menu item post type and enable a post type rest endpoint.
204 *
205 * @param array $args Current registered post type args.
206 * @param string $post_type Name of post type.
207 *
208 * @return array
209 */
210 function wp_api_nav_menus_post_type_args( $args, $post_type ) {
211 if ( 'nav_menu_item' === $post_type ) {
212 $args['show_in_rest'] = true;
213 $args['rest_base'] = 'menu-items';
214 $args['rest_controller_class'] = 'WP_REST_Menu_Items_Controller';
215 }
216
217 return $args;
218 }
219 add_filter( 'register_post_type_args', 'wp_api_nav_menus_post_type_args', 10, 2 );
220
221 /**
222 * Hook in to the nav_menu taxonomy and enable a taxonomy rest endpoint.
223 *
224 * @param array $args Current registered taxonomy args.
225 * @param string $taxonomy Name of taxonomy.
226 *
227 * @return array
228 */
229 function wp_api_nav_menus_taxonomy_args( $args, $taxonomy ) {
230 if ( 'nav_menu' === $taxonomy ) {
231 $args['show_in_rest'] = true;
232 $args['rest_base'] = 'menus';
233 $args['rest_controller_class'] = 'WP_REST_Menus_Controller';
234 }
235
236 return $args;
237 }
238 add_filter( 'register_taxonomy_args', 'wp_api_nav_menus_taxonomy_args', 10, 2 );
239
240 /**
241 * Shim for get_sample_permalink() to add support for auto-draft status.
242 *
243 * This function filters the return from get_sample_permalink() and essentially
244 * re-runs the same logic minus the filters, but pretends a status of auto-save
245 * is actually publish in order to return the future permalink format.
246 *
247 * This is a temporary fix until we can patch get_sample_permalink()
248 *
249 * @see https://core.trac.wordpress.org/ticket/46266
250 *
251 * @param array $permalink Array containing the sample permalink with placeholder for the post name, and the post name.
252 * @param int $id ID of the post.
253 * @param string $title Title of the post.
254 * @param string $name Slug of the post.
255 * @param object $post WP_Post object.
256 *
257 * @return array Array containing the sample permalink with placeholder for the post name, and the post name.
258 */
259 function gutenberg_auto_draft_get_sample_permalink( $permalink, $id, $title, $name, $post ) {
260 if ( 'auto-draft' !== $post->post_status ) {
261 return $permalink;
262 }
263 $ptype = get_post_type_object( $post->post_type );
264
265 $original_status = $post->post_status;
266 $original_date = $post->post_date;
267 $original_name = $post->post_name;
268
269 // Hack: get_permalink() would return ugly permalink for drafts, so we will fake that our post is published.
270 $post->post_status = 'publish';
271 $post->post_name = sanitize_title( $post->post_name ? $post->post_name : $post->post_title, $post->ID );
272
273 // If the user wants to set a new name -- override the current one.
274 // Note: if empty name is supplied -- use the title instead, see #6072.
275 if ( ! is_null( $name ) ) {
276 $post->post_name = sanitize_title( $name ? $name : $title, $post->ID );
277 }
278
279 $post->post_name = wp_unique_post_slug( $post->post_name, $post->ID, $post->post_status, $post->post_type, $post->post_parent );
280
281 $post->filter = 'sample';
282
283 $permalink = get_permalink( $post, true );
284
285 // Replace custom post_type Token with generic pagename token for ease of use.
286 $permalink = str_replace( "%$post->post_type%", '%pagename%', $permalink );
287
288 // Handle page hierarchy.
289 if ( $ptype->hierarchical ) {
290 $uri = get_page_uri( $post );
291 if ( $uri ) {
292 $uri = untrailingslashit( $uri );
293 $uri = strrev( stristr( strrev( $uri ), '/' ) );
294 $uri = untrailingslashit( $uri );
295 }
296
297 if ( ! empty( $uri ) ) {
298 $uri .= '/';
299 }
300 $permalink = str_replace( '%pagename%', "{$uri}%pagename%", $permalink );
301 }
302
303 $permalink = array( $permalink, $post->post_name );
304 $post->post_status = $original_status;
305 $post->post_date = $original_date;
306 $post->post_name = $original_name;
307 unset( $post->filter );
308
309 return $permalink;
310 }
311 add_filter( 'get_sample_permalink', 'gutenberg_auto_draft_get_sample_permalink', 10, 5 );
312
313 /**
314 * Registers the image editor.
315 *
316 * @since 7.x.0
317 */
318 function gutenberg_register_image_editor() {
319 global $wp_version;
320
321 // Strip '-src' from the version string. Messes up version_compare().
322 $version = str_replace( '-src', '', $wp_version );
323
324 // Only register routes for versions older than WP 5.5.
325 if ( version_compare( $version, '5.5-beta', '<' ) ) {
326 $image_editor = new WP_REST_Image_Editor_Controller();
327 $image_editor->register_routes();
328 }
329 }
330 add_filter( 'rest_api_init', 'gutenberg_register_image_editor' );
331