1 | diff --git src/wp-admin/admin-ajax.php src/wp-admin/admin-ajax.php |
---|
2 | index 3213d55028..e0f4464d94 100644 |
---|
3 | --- src/wp-admin/admin-ajax.php |
---|
4 | +++ src/wp-admin/admin-ajax.php |
---|
5 | @@ -64,7 +64,7 @@ $core_actions_post = array( |
---|
6 | 'parse-media-shortcode', 'destroy-sessions', 'install-plugin', 'update-plugin', 'press-this-save-post', |
---|
7 | 'press-this-add-category', 'crop-image', 'generate-password', 'save-wporg-username', 'delete-plugin', |
---|
8 | 'search-plugins', 'search-install-plugins', 'activate-plugin', 'update-theme', 'delete-theme', |
---|
9 | - 'install-theme', 'get-post-thumbnail-html', 'get-community-events', |
---|
10 | + 'install-theme', 'get-post-thumbnail-html', |
---|
11 | ); |
---|
12 | |
---|
13 | // Deprecated |
---|
14 | diff --git src/wp-admin/includes/ajax-actions.php src/wp-admin/includes/ajax-actions.php |
---|
15 | index 029e20e62b..3342cad375 100644 |
---|
16 | --- src/wp-admin/includes/ajax-actions.php |
---|
17 | +++ src/wp-admin/includes/ajax-actions.php |
---|
18 | @@ -297,40 +297,6 @@ function wp_ajax_autocomplete_user() { |
---|
19 | } |
---|
20 | |
---|
21 | /** |
---|
22 | - * Handles AJAX requests for community events |
---|
23 | - * |
---|
24 | - * @since 4.8.0 |
---|
25 | - */ |
---|
26 | -function wp_ajax_get_community_events() { |
---|
27 | - require_once( ABSPATH . 'wp-admin/includes/class-wp-community-events.php' ); |
---|
28 | - |
---|
29 | - check_ajax_referer( 'community_events' ); |
---|
30 | - |
---|
31 | - $search = isset( $_POST['location'] ) ? wp_unslash( $_POST['location'] ) : ''; |
---|
32 | - $timezone = isset( $_POST['timezone'] ) ? wp_unslash( $_POST['timezone'] ) : ''; |
---|
33 | - $user_id = get_current_user_id(); |
---|
34 | - $saved_location = get_user_option( 'community-events-location', $user_id ); |
---|
35 | - $events_client = new WP_Community_Events( $user_id, $saved_location ); |
---|
36 | - $events = $events_client->get_events( $search, $timezone ); |
---|
37 | - |
---|
38 | - if ( is_wp_error( $events ) ) { |
---|
39 | - wp_send_json_error( array( |
---|
40 | - 'error' => $events->get_error_message(), |
---|
41 | - ) ); |
---|
42 | - } else { |
---|
43 | - if ( isset( $events['location'] ) ) { |
---|
44 | - // Send only the data that the client will use. |
---|
45 | - $events['location'] = $events['location']['description']; |
---|
46 | - |
---|
47 | - // Store the location network-wide, so the user doesn't have to set it on each site. |
---|
48 | - update_user_option( $user_id, 'community-events-location', $events['location'], true ); |
---|
49 | - } |
---|
50 | - |
---|
51 | - wp_send_json_success( $events ); |
---|
52 | - } |
---|
53 | -} |
---|
54 | - |
---|
55 | -/** |
---|
56 | * Ajax handler for dashboard widgets. |
---|
57 | * |
---|
58 | * @since 3.4.0 |
---|
59 | diff --git src/wp-admin/includes/dashboard.php src/wp-admin/includes/dashboard.php |
---|
60 | index b25426e753..514ff58af4 100644 |
---|
61 | --- src/wp-admin/includes/dashboard.php |
---|
62 | +++ src/wp-admin/includes/dashboard.php |
---|
63 | @@ -144,7 +144,8 @@ function wp_get_community_events_script_data() { |
---|
64 | $events_client = new WP_Community_Events( $user_id, $user_location ); |
---|
65 | |
---|
66 | $script_data = array( |
---|
67 | - 'nonce' => wp_create_nonce( 'community_events' ), |
---|
68 | + 'rest_url' => rest_url( '/' ), |
---|
69 | + 'rest_nonce' => wp_create_nonce( 'wp_rest' ), |
---|
70 | 'cache' => $events_client->get_cached_events(), |
---|
71 | |
---|
72 | 'l10n' => array( |
---|
73 | @@ -1243,7 +1244,7 @@ function wp_print_community_events_templates() { |
---|
74 | <?php printf( |
---|
75 | /* translators: %s is a placeholder for the name of a city. */ |
---|
76 | __( 'Attend an upcoming event near %s.' ), |
---|
77 | - '<strong>{{ data.location }}</strong>' |
---|
78 | + '<strong>{{ data.location.description }}</strong>' |
---|
79 | ); ?> |
---|
80 | </script> |
---|
81 | |
---|
82 | @@ -1265,12 +1266,14 @@ function wp_print_community_events_templates() { |
---|
83 | </div> |
---|
84 | </div> |
---|
85 | |
---|
86 | - <div class="event-date-time"> |
---|
87 | - <span class="event-date">{{ event.formatted_date }}</span> |
---|
88 | - <# if ( 'meetup' === event.type ) { #> |
---|
89 | - <span class="event-time">{{ event.formatted_time }}</span> |
---|
90 | - <# } #> |
---|
91 | - </div> |
---|
92 | + <# if ( event.date && event.date.formatted ) { #> |
---|
93 | + <div class="event-date-time"> |
---|
94 | + <span class="event-date">{{ event.date.formatted.date }}</span> |
---|
95 | + <# if ( 'meetup' === event.type ) { #> |
---|
96 | + <span class="event-time">{{ event.date.formatted.time }}</span> |
---|
97 | + <# } #> |
---|
98 | + </div> |
---|
99 | + <# } #> |
---|
100 | </li> |
---|
101 | <# } ) #> |
---|
102 | </script> |
---|
103 | @@ -1280,7 +1283,7 @@ function wp_print_community_events_templates() { |
---|
104 | <?php printf( |
---|
105 | /* translators: 1: the city the user searched for, 2: meetup organization documentation URL */ |
---|
106 | __( 'There aren’t any events scheduled near %1$s at the moment. Would you like to <a href="%2$s">organize one</a>?' ), |
---|
107 | - '{{data.location}}', |
---|
108 | + '{{data.location.description}}', |
---|
109 | __( 'https://make.wordpress.org/community/handbook/meetup-organizer/welcome/' ) |
---|
110 | ); ?> |
---|
111 | </li> |
---|
112 | diff --git src/wp-admin/js/dashboard.js src/wp-admin/js/dashboard.js |
---|
113 | index 6a9b5033d4..d3d2bcc644 100644 |
---|
114 | --- src/wp-admin/js/dashboard.js |
---|
115 | +++ src/wp-admin/js/dashboard.js |
---|
116 | @@ -191,7 +191,7 @@ jQuery(document).ready( function($) { |
---|
117 | |
---|
118 | jQuery( function( $ ) { |
---|
119 | 'use strict'; |
---|
120 | - |
---|
121 | + |
---|
122 | var communityEventsData = window.communityEventsData || {}; |
---|
123 | |
---|
124 | var app = window.wp.communityEvents = { |
---|
125 | @@ -288,45 +288,71 @@ jQuery( function( $ ) { |
---|
126 | getEvents: function( requestParams ) { |
---|
127 | var initiatedBy, |
---|
128 | app = this, |
---|
129 | - $spinner = $( '.community-events-form' ).children( '.spinner' ); |
---|
130 | + $spinner = $( '.community-events-form' ).children( '.spinner' ), |
---|
131 | + dashboardLoadPromise = wp.api.init( { 'versionString': 'wp/dashboard/v1/' } ); |
---|
132 | +; |
---|
133 | |
---|
134 | requestParams = requestParams || {}; |
---|
135 | - requestParams._wpnonce = communityEventsData.nonce; |
---|
136 | requestParams.timezone = window.Intl ? window.Intl.DateTimeFormat().resolvedOptions().timeZone : ''; |
---|
137 | + requestParams._embed = 1; |
---|
138 | |
---|
139 | initiatedBy = requestParams.location ? 'user' : 'app'; |
---|
140 | |
---|
141 | $spinner.addClass( 'is-active' ); |
---|
142 | |
---|
143 | - wp.ajax.post( 'get-community-events', requestParams ) |
---|
144 | - .always( function() { |
---|
145 | - $spinner.removeClass( 'is-active' ); |
---|
146 | - }) |
---|
147 | - |
---|
148 | - .done( function( response ) { |
---|
149 | - if ( 'no_location_available' === response.error ) { |
---|
150 | - if ( requestParams.location ) { |
---|
151 | - response.unknownCity = requestParams.location; |
---|
152 | - } else { |
---|
153 | - /* |
---|
154 | - * No location was passed, which means that this was an automatic query |
---|
155 | - * based on IP, locale, and timezone. Since the user didn't initiate it, |
---|
156 | - * it should fail silently. Otherwise, the error could confuse and/or |
---|
157 | - * annoy them. |
---|
158 | - */ |
---|
159 | - |
---|
160 | - delete response.error; |
---|
161 | + dashboardLoadPromise.done( function( endpoint ) { |
---|
162 | + if ( ! app.model ) { |
---|
163 | + app.model = new wp.api.collections.CommunityEventsMyLocation(); |
---|
164 | + } |
---|
165 | + requestParams = requestParams || {}; |
---|
166 | + requestParams.timezone = window.Intl ? window.Intl.DateTimeFormat().resolvedOptions().timeZone : ''; |
---|
167 | + requestParams._embed = 1; |
---|
168 | + initiatedBy = requestParams.location ? 'user' : 'app'; |
---|
169 | + |
---|
170 | + $spinner.addClass( 'is-active' ); |
---|
171 | + |
---|
172 | + |
---|
173 | + var meModel = app.model.fetch( { |
---|
174 | + 'data': requestParams, |
---|
175 | + 'success': function( model, response ) { |
---|
176 | + var events = response._embedded && response._embedded.events ? response._embedded.events[0] : []; |
---|
177 | + var location = response; |
---|
178 | + |
---|
179 | + delete response._embedded; |
---|
180 | + delete response._links; |
---|
181 | + |
---|
182 | + app.renderEventsTemplate({ |
---|
183 | + location: location, |
---|
184 | + events: events |
---|
185 | + }, initiatedBy ); |
---|
186 | + |
---|
187 | + }, |
---|
188 | + 'error': function( model, response ) { |
---|
189 | + |
---|
190 | + if ( 'rest_cannot_retrieve_user_location' === response.code && requestParams.location ) { |
---|
191 | + app.renderEventsTemplate({ |
---|
192 | + unknownCity: requestParams.location, |
---|
193 | + location: false, |
---|
194 | + events: [] |
---|
195 | + }, initiatedBy ); |
---|
196 | + |
---|
197 | + return; |
---|
198 | } |
---|
199 | + |
---|
200 | + app.renderEventsTemplate( { |
---|
201 | + 'location' : false, |
---|
202 | + 'error' : true |
---|
203 | + }, initiatedBy ); |
---|
204 | } |
---|
205 | - app.renderEventsTemplate( response, initiatedBy ); |
---|
206 | - }) |
---|
207 | - |
---|
208 | - .fail( function() { |
---|
209 | - app.renderEventsTemplate( { |
---|
210 | - 'location' : false, |
---|
211 | - 'error' : true |
---|
212 | - }, initiatedBy ); |
---|
213 | - }); |
---|
214 | + } ); |
---|
215 | + |
---|
216 | + meModel |
---|
217 | + .always( function() { |
---|
218 | + $spinner.removeClass( 'is-active' ); |
---|
219 | + }); |
---|
220 | + }); |
---|
221 | }, |
---|
222 | |
---|
223 | /** |
---|
224 | diff --git src/wp-includes/js/wp-api.js src/wp-includes/js/wp-api.js |
---|
225 | index 3f950a47f5..bf3257b80b 100644 |
---|
226 | --- src/wp-includes/js/wp-api.js |
---|
227 | +++ src/wp-includes/js/wp-api.js |
---|
228 | @@ -1282,14 +1282,20 @@ |
---|
229 | |
---|
230 | // Function that returns a constructed url passed on the parent. |
---|
231 | url: function() { |
---|
232 | + var hasParent = ! _.isEmpty( this.parent ); |
---|
233 | return routeModel.get( 'apiRoot' ) + routeModel.get( 'versionString' ) + |
---|
234 | - parentName + '/' + this.parent + '/' + |
---|
235 | + parentName + '/' + |
---|
236 | + ( hasParent ? ( this.parent + '/' ) : '' ) + |
---|
237 | routeName; |
---|
238 | }, |
---|
239 | |
---|
240 | // Specify the model that this collection contains. |
---|
241 | model: function( attrs, options ) { |
---|
242 | - return new loadingObjects.models[ modelClassName ]( attrs, options ); |
---|
243 | + if ( loadingObjects.models[ modelClassName ] ) { |
---|
244 | + return new loadingObjects.models[ modelClassName ]( attrs, options ); |
---|
245 | + } else { |
---|
246 | + return new Backbone.Model(); |
---|
247 | + } |
---|
248 | }, |
---|
249 | |
---|
250 | // Include a reference to the original class name. |
---|
251 | diff --git src/wp-includes/rest-api.php src/wp-includes/rest-api.php |
---|
252 | index ec7c50d27b..891be7ceb6 100644 |
---|
253 | --- src/wp-includes/rest-api.php |
---|
254 | +++ src/wp-includes/rest-api.php |
---|
255 | @@ -237,6 +237,14 @@ function create_initial_rest_routes() { |
---|
256 | // Settings. |
---|
257 | $controller = new WP_REST_Settings_Controller; |
---|
258 | $controller->register_routes(); |
---|
259 | + |
---|
260 | + // Community events. |
---|
261 | + $controller = new WP_REST_Community_Events_Events_Controller; |
---|
262 | + $controller->register_routes(); |
---|
263 | + |
---|
264 | + // Community events location. |
---|
265 | + $controller = new WP_REST_Community_Events_Location_Controller; |
---|
266 | + $controller->register_routes(); |
---|
267 | } |
---|
268 | |
---|
269 | /** |
---|
270 | diff --git src/wp-includes/rest-api/endpoints/dashboard/class-wp-rest-community-events-events-controller.php src/wp-includes/rest-api/endpoints/dashboard/class-wp-rest-community-events-events-controller.php |
---|
271 | new file mode 100644 |
---|
272 | index 0000000000..570abd2adc |
---|
273 | --- /dev/null |
---|
274 | +++ src/wp-includes/rest-api/endpoints/dashboard/class-wp-rest-community-events-events-controller.php |
---|
275 | @@ -0,0 +1,281 @@ |
---|
276 | +<?php |
---|
277 | +/** |
---|
278 | + * REST API: WP_REST_Community_Events_Events_Controller class |
---|
279 | + * |
---|
280 | + * @package WordPress |
---|
281 | + * @subpackage REST_API |
---|
282 | + * @since 4.8.0 |
---|
283 | + */ |
---|
284 | + |
---|
285 | +/** |
---|
286 | + * Core class to access community events via the REST API. |
---|
287 | + * |
---|
288 | + * @since 4.8.0 |
---|
289 | + * |
---|
290 | + * @see WP_REST_Controller |
---|
291 | + */ |
---|
292 | +class WP_REST_Community_Events_Events_Controller extends WP_REST_Controller { |
---|
293 | + |
---|
294 | + /** |
---|
295 | + * Constructor. |
---|
296 | + * |
---|
297 | + * @since 4.8.0 |
---|
298 | + * @access public |
---|
299 | + */ |
---|
300 | + public function __construct() { |
---|
301 | + $this->namespace = 'wp/dashboard/v1'; |
---|
302 | + $this->rest_base = 'community-events/events'; |
---|
303 | + } |
---|
304 | + |
---|
305 | + /** |
---|
306 | + * Registers the routes for the objects of the controller. |
---|
307 | + * |
---|
308 | + * @since 4.8.0 |
---|
309 | + * @access public |
---|
310 | + * |
---|
311 | + * @see register_rest_route() |
---|
312 | + */ |
---|
313 | + public function register_routes() { |
---|
314 | + |
---|
315 | + register_rest_route( $this->namespace, '/' . $this->rest_base . '/me', array( |
---|
316 | + array( |
---|
317 | + 'methods' => WP_REST_Server::READABLE, |
---|
318 | + 'callback' => array( $this, 'get_current_items' ), |
---|
319 | + 'permission_callback' => array( $this, 'get_current_items_permissions_check' ), |
---|
320 | + 'args' => $this->get_collection_params(), |
---|
321 | + ), |
---|
322 | + 'schema' => array( $this, 'get_public_item_schema' ), |
---|
323 | + ) ); |
---|
324 | + } |
---|
325 | + |
---|
326 | + /** |
---|
327 | + * Checks whether a given request has permission to read community events. |
---|
328 | + * |
---|
329 | + * @since 4.8.0 |
---|
330 | + * @access public |
---|
331 | + * |
---|
332 | + * @param WP_REST_Request $request Full details about the request. |
---|
333 | + * @return WP_Error|true True if the request has read access, WP_Error object otherwise. |
---|
334 | + */ |
---|
335 | + public function get_current_items_permissions_check( $request ) { |
---|
336 | + if ( ! is_user_logged_in() ) { |
---|
337 | + return new WP_Error( 'rest_not_logged_in', __( 'You are not currently logged in.' ), array( 'status' => 401 ) ); |
---|
338 | + } |
---|
339 | + |
---|
340 | + return true; |
---|
341 | + } |
---|
342 | + |
---|
343 | + /** |
---|
344 | + * Retrieves community events. |
---|
345 | + * |
---|
346 | + * @since 4.8.0 |
---|
347 | + * @access public |
---|
348 | + * |
---|
349 | + * @param WP_REST_Request $request Full details about the request. |
---|
350 | + * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure. |
---|
351 | + */ |
---|
352 | + public function get_current_items( $request ) { |
---|
353 | + require_once( ABSPATH . 'wp-admin/includes/class-wp-community-events.php' ); |
---|
354 | + |
---|
355 | + $user_id = get_current_user_id(); |
---|
356 | + |
---|
357 | + $location = $request->get_param( 'location' ); |
---|
358 | + $timezone = $request->get_param( 'timezone' ); |
---|
359 | + |
---|
360 | + $saved_location = get_user_option( 'community-events-location', $user_id ); |
---|
361 | + $events_client = new WP_Community_Events( $user_id, $saved_location ); |
---|
362 | + $events = $events_client->get_events( $location, $timezone ); |
---|
363 | + |
---|
364 | + $data = array(); |
---|
365 | + |
---|
366 | + // Store the location network-wide, so the user doesn't have to set it on each site. |
---|
367 | + if ( ! is_wp_error( $events ) ) { |
---|
368 | + if ( isset( $events['location'] ) ) { |
---|
369 | + update_user_option( $user_id, 'community-events-location', $events['location'], true ); |
---|
370 | + } |
---|
371 | + |
---|
372 | + if ( isset( $events['events'] ) ) { |
---|
373 | + foreach ( $events['events'] as $event ) { |
---|
374 | + $data[] = $this->prepare_item_for_response( $event, $request ); |
---|
375 | + } |
---|
376 | + } |
---|
377 | + } |
---|
378 | + |
---|
379 | + return rest_ensure_response( $data ); |
---|
380 | + } |
---|
381 | + |
---|
382 | + /** |
---|
383 | + * Prepares a single event output for response. |
---|
384 | + * |
---|
385 | + * @since 4.8.0 |
---|
386 | + * @access public |
---|
387 | + * |
---|
388 | + * @param array $event Event data array from the API. |
---|
389 | + * @param WP_REST_Request $request Request object. |
---|
390 | + * @return array Item prepared for response. |
---|
391 | + */ |
---|
392 | + public function prepare_item_for_response( $event, $request ) { |
---|
393 | + $data = array(); |
---|
394 | + |
---|
395 | + $keys_to_copy = array( 'type', 'title', 'url', 'meetup', 'meetup_url' ); |
---|
396 | + foreach ( $keys_to_copy as $key ) { |
---|
397 | + if ( isset( $event[ $key ] ) ) { |
---|
398 | + $data[ $key ] = $event[ $key ]; |
---|
399 | + } else { |
---|
400 | + $data[ $key ] = null; |
---|
401 | + } |
---|
402 | + } |
---|
403 | + |
---|
404 | + $data['date'] = array( |
---|
405 | + 'raw' => isset( $event['date'] ) ? $event['date'] : null, |
---|
406 | + 'formatted' => array( |
---|
407 | + 'date' => isset( $event['formatted_date'] ) ? $event['formatted_date'] : null, |
---|
408 | + 'time' => isset( $event['formatted_time'] ) ? $event['formatted_time'] : null, |
---|
409 | + ), |
---|
410 | + ); |
---|
411 | + |
---|
412 | + $data['location'] = isset( $event['location'] ) ? $event['location'] : null; |
---|
413 | + |
---|
414 | + return $data; |
---|
415 | + } |
---|
416 | + |
---|
417 | + /** |
---|
418 | + * Retrieves a community event's schema, conforming to JSON Schema. |
---|
419 | + * |
---|
420 | + * @since 4.8.0 |
---|
421 | + * @access public |
---|
422 | + * |
---|
423 | + * @return array Item schema data. |
---|
424 | + */ |
---|
425 | + public function get_item_schema() { |
---|
426 | + return array( |
---|
427 | + '$schema' => 'http://json-schema.org/schema#', |
---|
428 | + 'title' => 'community_event', |
---|
429 | + 'type' => 'object', |
---|
430 | + 'properties' => array( |
---|
431 | + 'type' => array( |
---|
432 | + 'description' => __( 'Type for the event.' ), |
---|
433 | + 'type' => 'string', |
---|
434 | + 'enum' => array( 'meetup', 'wordcamp' ), |
---|
435 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
436 | + 'readonly' => true, |
---|
437 | + ), |
---|
438 | + 'title' => array( |
---|
439 | + 'description' => __( 'Title for the event.' ), |
---|
440 | + 'type' => 'string', |
---|
441 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
442 | + 'readonly' => true, |
---|
443 | + ), |
---|
444 | + 'url' => array( |
---|
445 | + 'description' => __( 'Website URL for the event.' ), |
---|
446 | + 'type' => 'string', |
---|
447 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
448 | + 'readonly' => true, |
---|
449 | + ), |
---|
450 | + 'meetup' => array( |
---|
451 | + 'description' => __( 'Name of the meetup, if the event is a meetup.' ), |
---|
452 | + 'type' => 'string', |
---|
453 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
454 | + 'readonly' => true, |
---|
455 | + ), |
---|
456 | + 'meetup_url' => array( |
---|
457 | + 'description' => __( 'URL for the meetup on meetup.com, if the event is a meetup.' ), |
---|
458 | + 'type' => 'string', |
---|
459 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
460 | + 'readonly' => true, |
---|
461 | + ), |
---|
462 | + 'date' => array( |
---|
463 | + 'description' => __( 'Date and time information for the event.' ), |
---|
464 | + 'type' => 'object', |
---|
465 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
466 | + 'readonly' => true, |
---|
467 | + 'properties' => array( |
---|
468 | + 'raw' => array( |
---|
469 | + 'description' => __( 'Unformatted date and time string.' ), |
---|
470 | + 'type' => 'string', |
---|
471 | + 'format' => 'date-time', |
---|
472 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
473 | + 'readonly' => true, |
---|
474 | + ), |
---|
475 | + 'formatted' => array( |
---|
476 | + 'description' => __( 'Formatted date and time information for the event.' ), |
---|
477 | + 'type' => 'object', |
---|
478 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
479 | + 'readonly' => true, |
---|
480 | + 'properties' => array( |
---|
481 | + 'date' => array( |
---|
482 | + 'description' => __( 'Formatted event date.' ), |
---|
483 | + 'type' => 'string', |
---|
484 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
485 | + 'readonly' => true, |
---|
486 | + ), |
---|
487 | + 'time' => array( |
---|
488 | + 'description' => __( 'Formatted event time.' ), |
---|
489 | + 'type' => 'string', |
---|
490 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
491 | + 'readonly' => true, |
---|
492 | + ), |
---|
493 | + ), |
---|
494 | + ), |
---|
495 | + ), |
---|
496 | + ), |
---|
497 | + 'location' => array( |
---|
498 | + 'description' => __( 'Location information for the event.' ), |
---|
499 | + 'type' => 'object', |
---|
500 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
501 | + 'readonly' => true, |
---|
502 | + 'properties' => array( |
---|
503 | + 'location' => array( |
---|
504 | + 'description' => __( 'Location name for the event.' ), |
---|
505 | + 'type' => 'string', |
---|
506 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
507 | + 'readonly' => true, |
---|
508 | + ), |
---|
509 | + 'country' => array( |
---|
510 | + 'description' => __( 'Two-letter country code for the event.' ), |
---|
511 | + 'type' => 'string', |
---|
512 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
513 | + 'readonly' => true, |
---|
514 | + ), |
---|
515 | + 'latitude' => array( |
---|
516 | + 'description' => __( 'Latitude for the event.' ), |
---|
517 | + 'type' => 'number', |
---|
518 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
519 | + 'readonly' => true, |
---|
520 | + ), |
---|
521 | + 'longitude' => array( |
---|
522 | + 'description' => __( 'Longitude for the event.' ), |
---|
523 | + 'type' => 'number', |
---|
524 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
525 | + 'readonly' => true, |
---|
526 | + ), |
---|
527 | + ), |
---|
528 | + ), |
---|
529 | + ), |
---|
530 | + ); |
---|
531 | + } |
---|
532 | + |
---|
533 | + /** |
---|
534 | + * Retrieves the query params for collections. |
---|
535 | + * |
---|
536 | + * @since 4.8.0 |
---|
537 | + * @access public |
---|
538 | + * |
---|
539 | + * @return array Collection parameters. |
---|
540 | + */ |
---|
541 | + public function get_collection_params() { |
---|
542 | + return array( |
---|
543 | + 'context' => $this->get_context_param( array( 'default' => 'view' ) ), |
---|
544 | + 'location' => array( |
---|
545 | + 'description' => __( 'Optional city name to help determine the location for the events.' ), |
---|
546 | + 'type' => 'string', |
---|
547 | + 'default' => '', |
---|
548 | + ), |
---|
549 | + 'timezone' => array( |
---|
550 | + 'description' => __( 'Optional timezone to help determine the location for the events.' ), |
---|
551 | + 'type' => 'string', |
---|
552 | + 'default' => '', |
---|
553 | + ), |
---|
554 | + ); |
---|
555 | + } |
---|
556 | +} |
---|
557 | diff --git src/wp-includes/rest-api/endpoints/dashboard/class-wp-rest-community-events-location-controller.php src/wp-includes/rest-api/endpoints/dashboard/class-wp-rest-community-events-location-controller.php |
---|
558 | new file mode 100644 |
---|
559 | index 0000000000..3763885731 |
---|
560 | --- /dev/null |
---|
561 | +++ src/wp-includes/rest-api/endpoints/dashboard/class-wp-rest-community-events-location-controller.php |
---|
562 | @@ -0,0 +1,217 @@ |
---|
563 | +<?php |
---|
564 | +/** |
---|
565 | + * REST API: WP_REST_Community_Events_Location_Controller class |
---|
566 | + * |
---|
567 | + * @package WordPress |
---|
568 | + * @subpackage REST_API |
---|
569 | + * @since 4.8.0 |
---|
570 | + */ |
---|
571 | + |
---|
572 | +/** |
---|
573 | + * Core class to access community events user locations via the REST API. |
---|
574 | + * |
---|
575 | + * @since 4.8.0 |
---|
576 | + * |
---|
577 | + * @see WP_REST_Controller |
---|
578 | + */ |
---|
579 | +class WP_REST_Community_Events_Location_Controller extends WP_REST_Controller { |
---|
580 | + |
---|
581 | + /** |
---|
582 | + * Constructor. |
---|
583 | + * |
---|
584 | + * @since 4.8.0 |
---|
585 | + * @access public |
---|
586 | + */ |
---|
587 | + public function __construct() { |
---|
588 | + $this->namespace = 'wp/dashboard/v1'; |
---|
589 | + $this->rest_base = 'community-events'; |
---|
590 | + } |
---|
591 | + |
---|
592 | + /** |
---|
593 | + * Registers the routes for the objects of the controller. |
---|
594 | + * |
---|
595 | + * @since 4.8.0 |
---|
596 | + * @access public |
---|
597 | + * |
---|
598 | + * @see register_rest_route() |
---|
599 | + */ |
---|
600 | + public function register_routes() { |
---|
601 | + |
---|
602 | + register_rest_route( $this->namespace, '/' . $this->rest_base . '/my-location', array( |
---|
603 | + array( |
---|
604 | + 'methods' => WP_REST_Server::READABLE, |
---|
605 | + 'callback' => array( $this, 'get_current_item' ), |
---|
606 | + 'permission_callback' => array( $this, 'get_current_item_permissions_check' ), |
---|
607 | + 'args' => $this->get_item_params(), |
---|
608 | + ), |
---|
609 | + 'schema' => array( $this, 'get_public_item_schema' ), |
---|
610 | + ) ); |
---|
611 | + } |
---|
612 | + |
---|
613 | + /** |
---|
614 | + * Checks whether a given request has permission to read the current user's community events location. |
---|
615 | + * |
---|
616 | + * @since 4.8.0 |
---|
617 | + * @access public |
---|
618 | + * |
---|
619 | + * @param WP_REST_Request $request Full details about the request. |
---|
620 | + * @return WP_Error|true True if the request has read access, WP_Error object otherwise. |
---|
621 | + */ |
---|
622 | + public function get_current_item_permissions_check( $request ) { |
---|
623 | + if ( ! is_user_logged_in() ) { |
---|
624 | + return new WP_Error( 'rest_not_logged_in', __( 'You are not currently logged in.' ), array( 'status' => 401 ) ); |
---|
625 | + } |
---|
626 | + |
---|
627 | + return true; |
---|
628 | + } |
---|
629 | + |
---|
630 | + /** |
---|
631 | + * Retrieves the community events location for the current user. |
---|
632 | + * |
---|
633 | + * @since 4.8.0 |
---|
634 | + * @access public |
---|
635 | + * |
---|
636 | + * @param WP_REST_Request $request Full details about the request. |
---|
637 | + * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure. |
---|
638 | + */ |
---|
639 | + public function get_current_item( $request ) { |
---|
640 | + require_once( ABSPATH . 'wp-admin/includes/class-wp-community-events.php' ); |
---|
641 | + |
---|
642 | + $user_id = get_current_user_id(); |
---|
643 | + |
---|
644 | + $location = $request->get_param( 'location' ); |
---|
645 | + $timezone = $request->get_param( 'timezone' ); |
---|
646 | + |
---|
647 | + $saved_location = get_user_option( 'community-events-location', $user_id ); |
---|
648 | + $events_client = new WP_Community_Events( $user_id, $saved_location ); |
---|
649 | + $events = $events_client->get_events( $location, $timezone ); |
---|
650 | + |
---|
651 | + // Store the location network-wide, so the user doesn't have to set it on each site. |
---|
652 | + if ( ! is_wp_error( $events ) ) { |
---|
653 | + if ( isset( $events['error'] ) && 'no_location_available' === $events['error'] ) { |
---|
654 | + return new WP_Error( 'rest_cannot_retrieve_user_location', __( 'The user location could not be retrieved.' ) ); |
---|
655 | + } |
---|
656 | + |
---|
657 | + if ( isset( $events['location'] ) ) { |
---|
658 | + update_user_option( $user_id, 'community-events-location', $events['location'], true ); |
---|
659 | + |
---|
660 | + $data = $this->prepare_item_for_response( $events['location'], $request ); |
---|
661 | + |
---|
662 | + return rest_ensure_response( $data ); |
---|
663 | + } |
---|
664 | + } |
---|
665 | + |
---|
666 | + return $events; |
---|
667 | + } |
---|
668 | + |
---|
669 | + /** |
---|
670 | + * Prepares a single location output for response. |
---|
671 | + * |
---|
672 | + * @since 4.8.0 |
---|
673 | + * @access public |
---|
674 | + * |
---|
675 | + * @param array $location Location data array from the API. |
---|
676 | + * @param WP_REST_Request $request Request object. |
---|
677 | + * @return WP_REST_Response Response object. |
---|
678 | + */ |
---|
679 | + public function prepare_item_for_response( $location, $request ) { |
---|
680 | + $data = array( |
---|
681 | + 'description' => isset( $location['description'] ) ? $location['description'] : null, |
---|
682 | + 'country' => isset( $location['country'] ) ? $location['country'] : null, |
---|
683 | + 'latitude' => isset( $location['latitude'] ) ? (float) $location['latitude'] : null, |
---|
684 | + 'longitude' => isset( $location['longitude'] ) ? (float) $location['longitude'] : null, |
---|
685 | + ); |
---|
686 | + |
---|
687 | + $response = rest_ensure_response( $data ); |
---|
688 | + |
---|
689 | + $url = rest_url( 'wp/dashboard/v1/community-events/events/me' ); |
---|
690 | + |
---|
691 | + $url_args = array(); |
---|
692 | + |
---|
693 | + if ( ! empty( $request['location'] ) ) { |
---|
694 | + $url_args['location'] = $request['location']; |
---|
695 | + } |
---|
696 | + if ( ! empty( $request['timezone'] ) ) { |
---|
697 | + $url_args['timezone'] = $request['timezone']; |
---|
698 | + } |
---|
699 | + |
---|
700 | + if ( ! empty( $url_args ) ) { |
---|
701 | + $url = add_query_arg( $url_args, $url ); |
---|
702 | + } |
---|
703 | + |
---|
704 | + $response->add_links( array( |
---|
705 | + 'events' => array( |
---|
706 | + 'href' => $url, |
---|
707 | + 'embeddable' => true, |
---|
708 | + ), |
---|
709 | + ) ); |
---|
710 | + |
---|
711 | + return $response; |
---|
712 | + } |
---|
713 | + |
---|
714 | + /** |
---|
715 | + * Retrieves a community events location schema, conforming to JSON Schema. |
---|
716 | + * |
---|
717 | + * @since 4.8.0 |
---|
718 | + * @access public |
---|
719 | + * |
---|
720 | + * @return array Item schema data. |
---|
721 | + */ |
---|
722 | + public function get_item_schema() { |
---|
723 | + return array( |
---|
724 | + '$schema' => 'http://json-schema.org/schema#', |
---|
725 | + 'title' => 'community_events_location', |
---|
726 | + 'type' => 'object', |
---|
727 | + 'properties' => array( |
---|
728 | + 'description' => array( |
---|
729 | + 'description' => __( 'Location description.' ), |
---|
730 | + 'type' => 'string', |
---|
731 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
732 | + 'readonly' => true, |
---|
733 | + ), |
---|
734 | + 'country' => array( |
---|
735 | + 'description' => __( 'Two-letter country code.' ), |
---|
736 | + 'type' => 'string', |
---|
737 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
738 | + 'readonly' => true, |
---|
739 | + ), |
---|
740 | + 'latitude' => array( |
---|
741 | + 'description' => __( 'Latitude.' ), |
---|
742 | + 'type' => 'number', |
---|
743 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
744 | + 'readonly' => true, |
---|
745 | + ), |
---|
746 | + 'longitude' => array( |
---|
747 | + 'description' => __( 'Longitude.' ), |
---|
748 | + 'type' => 'number', |
---|
749 | + 'context' => array( 'view', 'edit', 'embed' ), |
---|
750 | + 'readonly' => true, |
---|
751 | + ), |
---|
752 | + ), |
---|
753 | + ); |
---|
754 | + } |
---|
755 | + |
---|
756 | + /** |
---|
757 | + * Retrieves the params for a single item. |
---|
758 | + * |
---|
759 | + * @since 4.8.0 |
---|
760 | + * @access public |
---|
761 | + * |
---|
762 | + * @return array Item parameters. |
---|
763 | + */ |
---|
764 | + public function get_item_params() { |
---|
765 | + return array( |
---|
766 | + 'context' => $this->get_context_param( array( 'default' => 'view' ) ), |
---|
767 | + 'location' => array( |
---|
768 | + 'description' => __( 'Optional city name to help determine the location.' ), |
---|
769 | + 'type' => 'string', |
---|
770 | + 'default' => '', |
---|
771 | + ), |
---|
772 | + 'timezone' => array( |
---|
773 | + 'description' => __( 'Optional timezone to help determine the location.' ), |
---|
774 | + 'type' => 'string', |
---|
775 | + 'default' => '', |
---|
776 | + ), |
---|
777 | + ); |
---|
778 | + } |
---|
779 | +} |
---|
780 | diff --git src/wp-includes/script-loader.php src/wp-includes/script-loader.php |
---|
781 | index f1eda9ee38..c02fe73588 100644 |
---|
782 | --- src/wp-includes/script-loader.php |
---|
783 | +++ src/wp-includes/script-loader.php |
---|
784 | @@ -732,7 +732,7 @@ function wp_default_scripts( &$scripts ) { |
---|
785 | 'current' => __( 'Current Color' ), |
---|
786 | ) ); |
---|
787 | |
---|
788 | - $scripts->add( 'dashboard', "/wp-admin/js/dashboard$suffix.js", array( 'jquery', 'admin-comments', 'postbox', 'wp-util', 'wp-a11y' ), false, 1 ); |
---|
789 | + $scripts->add( 'dashboard', "/wp-admin/js/dashboard$suffix.js", array( 'jquery', 'admin-comments', 'postbox', 'wp-util', 'wp-a11y', 'wp-api' ), false, 1 ); |
---|
790 | |
---|
791 | $scripts->add( 'list-revisions', "/wp-includes/js/wp-list-revisions$suffix.js" ); |
---|
792 | |
---|
793 | diff --git src/wp-settings.php src/wp-settings.php |
---|
794 | index d1505c502d..060ab4c782 100644 |
---|
795 | --- src/wp-settings.php |
---|
796 | +++ src/wp-settings.php |
---|
797 | @@ -234,6 +234,8 @@ require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-terms-controller.p |
---|
798 | require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-users-controller.php' ); |
---|
799 | require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-comments-controller.php' ); |
---|
800 | require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-settings-controller.php' ); |
---|
801 | +require( ABSPATH . WPINC . '/rest-api/endpoints/dashboard/class-wp-rest-community-events-events-controller.php' ); |
---|
802 | +require( ABSPATH . WPINC . '/rest-api/endpoints/dashboard/class-wp-rest-community-events-location-controller.php' ); |
---|
803 | require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-meta-fields.php' ); |
---|
804 | require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-comment-meta-fields.php' ); |
---|
805 | require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-post-meta-fields.php' ); |
---|