Ticket #40702: 40702.8.diff
File 40702.8.diff, 24.0 KB (added by , 7 years ago) |
---|
-
src/wp-admin/admin-ajax.php
64 64 'parse-media-shortcode', 'destroy-sessions', 'install-plugin', 'update-plugin', 'press-this-save-post', 65 65 'press-this-add-category', 'crop-image', 'generate-password', 'save-wporg-username', 'delete-plugin', 66 66 'search-plugins', 'search-install-plugins', 'activate-plugin', 'update-theme', 'delete-theme', 67 'install-theme', 'get-post-thumbnail-html', 'get-community-events',67 'install-theme', 'get-post-thumbnail-html', 68 68 ); 69 69 70 70 // Deprecated -
src/wp-admin/includes/ajax-actions.php
297 297 } 298 298 299 299 /** 300 * Handles AJAX requests for community events301 *302 * @since 4.8.0303 */304 function wp_ajax_get_community_events() {305 require_once( ABSPATH . 'wp-admin/includes/class-wp-community-events.php' );306 307 check_ajax_referer( 'community_events' );308 309 $search = isset( $_POST['location'] ) ? wp_unslash( $_POST['location'] ) : '';310 $timezone = isset( $_POST['timezone'] ) ? wp_unslash( $_POST['timezone'] ) : '';311 $user_id = get_current_user_id();312 $saved_location = get_user_option( 'community-events-location', $user_id );313 $events_client = new WP_Community_Events( $user_id, $saved_location );314 $events = $events_client->get_events( $search, $timezone );315 316 if ( is_wp_error( $events ) ) {317 wp_send_json_error( array(318 'error' => $events->get_error_message(),319 ) );320 } else {321 if ( isset( $events['location'] ) ) {322 // Send only the data that the client will use.323 $events['location'] = $events['location']['description'];324 325 // Store the location network-wide, so the user doesn't have to set it on each site.326 update_user_option( $user_id, 'community-events-location', $events['location'], true );327 }328 329 wp_send_json_success( $events );330 }331 }332 333 /**334 300 * Ajax handler for dashboard widgets. 335 301 * 336 302 * @since 3.4.0 -
src/wp-admin/includes/dashboard.php
144 144 $events_client = new WP_Community_Events( $user_id, $user_location ); 145 145 146 146 $script_data = array( 147 'nonce' => wp_create_nonce( 'community_events' ), 147 'rest_url' => rest_url( '/' ), 148 'rest_nonce' => wp_create_nonce( 'wp_rest' ), 148 149 'cache' => $events_client->get_cached_events(), 149 150 150 151 'l10n' => array( … … 1225 1226 <?php printf( 1226 1227 /* translators: %s is a placeholder for the name of a city. */ 1227 1228 __( 'Attend an upcoming event near %s.' ), 1228 '<strong>{{ data.location }}</strong>'1229 '<strong>{{ data.location.description }}</strong>' 1229 1230 ); ?> 1230 1231 </script> 1231 1232 … … 1247 1248 </div> 1248 1249 </div> 1249 1250 1250 <div class="event-date-time"> 1251 <span class="event-date">{{ event.formatted_date }}</span> 1252 <# if ( 'meetup' === event.type ) { #> 1253 <span class="event-time">{{ event.formatted_time }}</span> 1254 <# } #> 1255 </div> 1251 <# if ( event.date && event.date.formatted ) { #> 1252 <div class="event-date-time"> 1253 <span class="event-date">{{ event.date.formatted.date }}</span> 1254 <# if ( 'meetup' === event.type ) { #> 1255 <span class="event-time">{{ event.date.formatted.time }}</span> 1256 <# } #> 1257 </div> 1258 <# } #> 1256 1259 </li> 1257 1260 <# } ) #> 1258 1261 </script> … … 1262 1265 <?php printf( 1263 1266 /* translators: 1: the city the user searched for, 2: meetup organization documentation URL */ 1264 1267 __( 'There aren’t any events scheduled near %1$s at the moment. Would you like to <a href="%2$s">organize one</a>?' ), 1265 '{{data.location }}',1268 '{{data.location.description}}', 1266 1269 __( 'https://make.wordpress.org/community/handbook/meetup-organizer/welcome/' ) 1267 1270 ); ?> 1268 1271 </li> -
src/wp-admin/js/dashboard.js
191 191 192 192 jQuery( function( $ ) { 193 193 'use strict'; 194 194 195 195 var communityEventsData = window.communityEventsData || {}; 196 196 197 197 var app = window.wp.communityEvents = { … … 291 291 $spinner = $( '.community-events-form' ).children( '.spinner' ); 292 292 293 293 requestParams = requestParams || {}; 294 requestParams._wpnonce = communityEventsData.nonce;295 294 requestParams.timezone = window.Intl ? window.Intl.DateTimeFormat().resolvedOptions().timeZone : ''; 295 requestParams._embed = 1; 296 296 297 297 initiatedBy = requestParams.location ? 'user' : 'app'; 298 298 299 299 $spinner.addClass( 'is-active' ); 300 300 301 wp.ajax.post( 'get-community-events', requestParams ) 302 .always( function() { 303 $spinner.removeClass( 'is-active' ); 304 }) 305 306 .done( function( response ) { 307 if ( 'no_location_available' === response.error ) { 308 if ( requestParams.location ) { 309 response.unknownCity = requestParams.location; 310 } else { 311 /* 312 * No location was passed, which means that this was an automatic query 313 * based on IP, locale, and timezone. Since the user didn't initiate it, 314 * it should fail silently. Otherwise, the error could confuse and/or 315 * annoy them. 316 */ 301 $.ajax( communityEventsData.rest_url + 'wp/dashboard/v1/community-events/location/me', { 302 method: 'GET', 303 data: requestParams, 304 dataType: 'json', 305 headers: { 306 'X-WP-Nonce': communityEventsData.rest_nonce 307 }, 308 success: function( response ) { 309 var events = response._embedded && response._embedded.events ? response._embedded.events[0] : []; 310 var location = response; 311 312 delete location._embedded; 313 delete location._links; 314 315 app.renderEventsTemplate({ 316 location: location, 317 events: events 318 }, initiatedBy ); 319 }, 320 error: function( xhr ) { 321 if ( xhr.responseJSON && 'rest_cannot_retrieve_user_location' === xhr.responseJSON.code && requestParams.location ) { 322 app.renderEventsTemplate({ 323 unknownCity: requestParams.location, 324 location: false, 325 events: [] 326 }, initiatedBy ); 317 327 318 delete response.error; 319 } 328 return; 320 329 } 321 app.renderEventsTemplate( response, initiatedBy );322 })323 330 324 .fail( function() {325 331 app.renderEventsTemplate( { 326 332 'location' : false, 327 333 'error' : true 328 334 }, initiatedBy ); 329 }); 335 }, 336 complete: function() { 337 $spinner.removeClass( 'is-active' ); 338 } 339 }); 330 340 }, 331 341 332 342 /** -
src/wp-includes/rest-api/endpoints/dashboard/class-wp-rest-community-events-events-controller.php
1 <?php 2 /** 3 * REST API: WP_REST_Community_Events_Events_Controller class 4 * 5 * @package WordPress 6 * @subpackage REST_API 7 * @since 4.8.0 8 */ 9 10 /** 11 * Core class to access community events via the REST API. 12 * 13 * @since 4.8.0 14 * 15 * @see WP_REST_Controller 16 */ 17 class WP_REST_Community_Events_Events_Controller extends WP_REST_Controller { 18 19 /** 20 * Constructor. 21 * 22 * @since 4.8.0 23 * @access public 24 */ 25 public function __construct() { 26 $this->namespace = 'wp/dashboard/v1'; 27 $this->rest_base = 'community-events/events'; 28 } 29 30 /** 31 * Registers the routes for the objects of the controller. 32 * 33 * @since 4.8.0 34 * @access public 35 * 36 * @see register_rest_route() 37 */ 38 public function register_routes() { 39 40 register_rest_route( $this->namespace, '/' . $this->rest_base . '/me', array( 41 array( 42 'methods' => WP_REST_Server::READABLE, 43 'callback' => array( $this, 'get_current_items' ), 44 'permission_callback' => array( $this, 'get_current_items_permissions_check' ), 45 'args' => $this->get_collection_params(), 46 ), 47 'schema' => array( $this, 'get_public_item_schema' ), 48 ) ); 49 } 50 51 /** 52 * Checks whether a given request has permission to read community events. 53 * 54 * @since 4.8.0 55 * @access public 56 * 57 * @param WP_REST_Request $request Full details about the request. 58 * @return WP_Error|true True if the request has read access, WP_Error object otherwise. 59 */ 60 public function get_current_items_permissions_check( $request ) { 61 if ( ! is_user_logged_in() ) { 62 return new WP_Error( 'rest_not_logged_in', __( 'You are not currently logged in.' ), array( 'status' => 401 ) ); 63 } 64 65 return true; 66 } 67 68 /** 69 * Retrieves community events. 70 * 71 * @since 4.8.0 72 * @access public 73 * 74 * @param WP_REST_Request $request Full details about the request. 75 * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure. 76 */ 77 public function get_current_items( $request ) { 78 require_once( ABSPATH . 'wp-admin/includes/class-wp-community-events.php' ); 79 80 $user_id = get_current_user_id(); 81 82 $location = $request->get_param( 'location' ); 83 $timezone = $request->get_param( 'timezone' ); 84 85 $saved_location = get_user_option( 'community-events-location', $user_id ); 86 $events_client = new WP_Community_Events( $user_id, $saved_location ); 87 $events = $events_client->get_events( $location, $timezone ); 88 89 $data = array(); 90 91 // Store the location network-wide, so the user doesn't have to set it on each site. 92 if ( ! is_wp_error( $events ) ) { 93 if ( isset( $events['location'] ) ) { 94 update_user_option( $user_id, 'community-events-location', $events['location'], true ); 95 } 96 97 if ( isset( $events['events'] ) ) { 98 foreach ( $events['events'] as $event ) { 99 $data[] = $this->prepare_item_for_response( $event, $request ); 100 } 101 } 102 } 103 104 return rest_ensure_response( $data ); 105 } 106 107 /** 108 * Prepares a single event output for response. 109 * 110 * @since 4.8.0 111 * @access public 112 * 113 * @param array $event Event data array from the API. 114 * @param WP_REST_Request $request Request object. 115 * @return array Item prepared for response. 116 */ 117 public function prepare_item_for_response( $event, $request ) { 118 $data = array(); 119 120 $keys_to_copy = array( 'type', 'title', 'url', 'meetup', 'meetup_url' ); 121 foreach ( $keys_to_copy as $key ) { 122 if ( isset( $event[ $key ] ) ) { 123 $data[ $key ] = $event[ $key ]; 124 } else { 125 $data[ $key ] = null; 126 } 127 } 128 129 $data['date'] = array( 130 'raw' => isset( $event['date'] ) ? $event['date'] : null, 131 'formatted' => array( 132 'date' => isset( $event['formatted_date'] ) ? $event['formatted_date'] : null, 133 'time' => isset( $event['formatted_time'] ) ? $event['formatted_time'] : null, 134 ), 135 ); 136 137 $data['location'] = isset( $event['location'] ) ? $event['location'] : null; 138 139 return $data; 140 } 141 142 /** 143 * Retrieves a community event's schema, conforming to JSON Schema. 144 * 145 * @since 4.8.0 146 * @access public 147 * 148 * @return array Item schema data. 149 */ 150 public function get_item_schema() { 151 return array( 152 '$schema' => 'http://json-schema.org/schema#', 153 'title' => 'community_event', 154 'type' => 'object', 155 'properties' => array( 156 'type' => array( 157 'description' => __( 'Type for the event.' ), 158 'type' => 'string', 159 'enum' => array( 'meetup', 'wordcamp' ), 160 'context' => array( 'view', 'edit', 'embed' ), 161 'readonly' => true, 162 ), 163 'title' => array( 164 'description' => __( 'Title for the event.' ), 165 'type' => 'string', 166 'context' => array( 'view', 'edit', 'embed' ), 167 'readonly' => true, 168 ), 169 'url' => array( 170 'description' => __( 'Website URL for the event.' ), 171 'type' => 'string', 172 'context' => array( 'view', 'edit', 'embed' ), 173 'readonly' => true, 174 ), 175 'meetup' => array( 176 'description' => __( 'Name of the meetup, if the event is a meetup.' ), 177 'type' => 'string', 178 'context' => array( 'view', 'edit', 'embed' ), 179 'readonly' => true, 180 ), 181 'meetup_url' => array( 182 'description' => __( 'URL for the meetup on meetup.com, if the event is a meetup.' ), 183 'type' => 'string', 184 'context' => array( 'view', 'edit', 'embed' ), 185 'readonly' => true, 186 ), 187 'date' => array( 188 'description' => __( 'Date and time information for the event.' ), 189 'type' => 'object', 190 'context' => array( 'view', 'edit', 'embed' ), 191 'readonly' => true, 192 'properties' => array( 193 'raw' => array( 194 'description' => __( 'Unformatted date and time string.' ), 195 'type' => 'string', 196 'format' => 'date-time', 197 'context' => array( 'view', 'edit', 'embed' ), 198 'readonly' => true, 199 ), 200 'formatted' => array( 201 'description' => __( 'Formatted date and time information for the event.' ), 202 'type' => 'object', 203 'context' => array( 'view', 'edit', 'embed' ), 204 'readonly' => true, 205 'properties' => array( 206 'date' => array( 207 'description' => __( 'Formatted event date.' ), 208 'type' => 'string', 209 'context' => array( 'view', 'edit', 'embed' ), 210 'readonly' => true, 211 ), 212 'time' => array( 213 'description' => __( 'Formatted event time.' ), 214 'type' => 'string', 215 'context' => array( 'view', 'edit', 'embed' ), 216 'readonly' => true, 217 ), 218 ), 219 ), 220 ), 221 ), 222 'location' => array( 223 'description' => __( 'Location information for the event.' ), 224 'type' => 'object', 225 'context' => array( 'view', 'edit', 'embed' ), 226 'readonly' => true, 227 'properties' => array( 228 'location' => array( 229 'description' => __( 'Location name for the event.' ), 230 'type' => 'string', 231 'context' => array( 'view', 'edit', 'embed' ), 232 'readonly' => true, 233 ), 234 'country' => array( 235 'description' => __( 'Two-letter country code for the event.' ), 236 'type' => 'string', 237 'context' => array( 'view', 'edit', 'embed' ), 238 'readonly' => true, 239 ), 240 'latitude' => array( 241 'description' => __( 'Latitude for the event.' ), 242 'type' => 'number', 243 'context' => array( 'view', 'edit', 'embed' ), 244 'readonly' => true, 245 ), 246 'longitude' => array( 247 'description' => __( 'Longitude for the event.' ), 248 'type' => 'number', 249 'context' => array( 'view', 'edit', 'embed' ), 250 'readonly' => true, 251 ), 252 ), 253 ), 254 ), 255 ); 256 } 257 258 /** 259 * Retrieves the query params for collections. 260 * 261 * @since 4.8.0 262 * @access public 263 * 264 * @return array Collection parameters. 265 */ 266 public function get_collection_params() { 267 return array( 268 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 269 'location' => array( 270 'description' => __( 'Optional city name to help determine the location for the events.' ), 271 'type' => 'string', 272 'default' => '', 273 ), 274 'timezone' => array( 275 'description' => __( 'Optional timezone to help determine the location for the events.' ), 276 'type' => 'string', 277 'default' => '', 278 ), 279 ); 280 } 281 } -
src/wp-includes/rest-api/endpoints/dashboard/class-wp-rest-community-events-location-controller.php
1 <?php 2 /** 3 * REST API: WP_REST_Community_Events_Location_Controller class 4 * 5 * @package WordPress 6 * @subpackage REST_API 7 * @since 4.8.0 8 */ 9 10 /** 11 * Core class to access community events user locations via the REST API. 12 * 13 * @since 4.8.0 14 * 15 * @see WP_REST_Controller 16 */ 17 class WP_REST_Community_Events_Location_Controller extends WP_REST_Controller { 18 19 /** 20 * Constructor. 21 * 22 * @since 4.8.0 23 * @access public 24 */ 25 public function __construct() { 26 $this->namespace = 'wp/dashboard/v1'; 27 $this->rest_base = 'community-events/location'; 28 } 29 30 /** 31 * Registers the routes for the objects of the controller. 32 * 33 * @since 4.8.0 34 * @access public 35 * 36 * @see register_rest_route() 37 */ 38 public function register_routes() { 39 40 register_rest_route( $this->namespace, '/' . $this->rest_base . '/me', array( 41 array( 42 'methods' => WP_REST_Server::READABLE, 43 'callback' => array( $this, 'get_current_item' ), 44 'permission_callback' => array( $this, 'get_current_item_permissions_check' ), 45 'args' => $this->get_item_params(), 46 ), 47 'schema' => array( $this, 'get_public_item_schema' ), 48 ) ); 49 } 50 51 /** 52 * Checks whether a given request has permission to read the current user's community events location. 53 * 54 * @since 4.8.0 55 * @access public 56 * 57 * @param WP_REST_Request $request Full details about the request. 58 * @return WP_Error|true True if the request has read access, WP_Error object otherwise. 59 */ 60 public function get_current_item_permissions_check( $request ) { 61 if ( ! is_user_logged_in() ) { 62 return new WP_Error( 'rest_not_logged_in', __( 'You are not currently logged in.' ), array( 'status' => 401 ) ); 63 } 64 65 return true; 66 } 67 68 /** 69 * Retrieves the community events location for the current user. 70 * 71 * @since 4.8.0 72 * @access public 73 * 74 * @param WP_REST_Request $request Full details about the request. 75 * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure. 76 */ 77 public function get_current_item( $request ) { 78 require_once( ABSPATH . 'wp-admin/includes/class-wp-community-events.php' ); 79 80 $user_id = get_current_user_id(); 81 82 $location = $request->get_param( 'location' ); 83 $timezone = $request->get_param( 'timezone' ); 84 85 $saved_location = get_user_option( 'community-events-location', $user_id ); 86 $events_client = new WP_Community_Events( $user_id, $saved_location ); 87 $events = $events_client->get_events( $location, $timezone ); 88 89 // Store the location network-wide, so the user doesn't have to set it on each site. 90 if ( ! is_wp_error( $events ) ) { 91 if ( isset( $events['error'] ) && 'no_location_available' === $events['error'] ) { 92 return new WP_Error( 'rest_cannot_retrieve_user_location', __( 'The user location could not be retrieved.' ), array( 'status' => 503 ) ); 93 } 94 95 if ( isset( $events['location'] ) ) { 96 update_user_option( $user_id, 'community-events-location', $events['location'], true ); 97 98 $data = $this->prepare_item_for_response( $events['location'], $request ); 99 100 return rest_ensure_response( $data ); 101 } 102 } 103 104 return new WP_Error( 'rest_cannot_retrieve_user_location', __( 'The user location could not be retrieved.' ), array( 'status' => 503 ) ); 105 } 106 107 /** 108 * Prepares a single location output for response. 109 * 110 * @since 4.8.0 111 * @access public 112 * 113 * @param array $location Location data array from the API. 114 * @param WP_REST_Request $request Request object. 115 * @return WP_REST_Response Response object. 116 */ 117 public function prepare_item_for_response( $location, $request ) { 118 $data = array( 119 'description' => isset( $location['description'] ) ? $location['description'] : null, 120 'country' => isset( $location['country'] ) ? $location['country'] : null, 121 'latitude' => isset( $location['latitude'] ) ? (float) $location['latitude'] : null, 122 'longitude' => isset( $location['longitude'] ) ? (float) $location['longitude'] : null, 123 ); 124 125 $response = rest_ensure_response( $data ); 126 127 $url = rest_url( 'wp/dashboard/v1/community-events/events/me' ); 128 129 $url_args = array(); 130 131 if ( ! empty( $request['location'] ) ) { 132 $url_args['location'] = $request['location']; 133 } 134 if ( ! empty( $request['timezone'] ) ) { 135 $url_args['timezone'] = $request['timezone']; 136 } 137 138 if ( ! empty( $url_args ) ) { 139 $url = add_query_arg( $url_args, $url ); 140 } 141 142 $response->add_links( array( 143 'events' => array( 144 'href' => $url, 145 'embeddable' => true, 146 ), 147 ) ); 148 149 return $response; 150 } 151 152 /** 153 * Retrieves a community events location schema, conforming to JSON Schema. 154 * 155 * @since 4.8.0 156 * @access public 157 * 158 * @return array Item schema data. 159 */ 160 public function get_item_schema() { 161 return array( 162 '$schema' => 'http://json-schema.org/schema#', 163 'title' => 'community_events_location', 164 'type' => 'object', 165 'properties' => array( 166 'description' => array( 167 'description' => __( 'Location description.' ), 168 'type' => 'string', 169 'context' => array( 'view', 'edit', 'embed' ), 170 'readonly' => true, 171 ), 172 'country' => array( 173 'description' => __( 'Two-letter country code.' ), 174 'type' => 'string', 175 'context' => array( 'view', 'edit', 'embed' ), 176 'readonly' => true, 177 ), 178 'latitude' => array( 179 'description' => __( 'Latitude.' ), 180 'type' => 'number', 181 'context' => array( 'view', 'edit', 'embed' ), 182 'readonly' => true, 183 ), 184 'longitude' => array( 185 'description' => __( 'Longitude.' ), 186 'type' => 'number', 187 'context' => array( 'view', 'edit', 'embed' ), 188 'readonly' => true, 189 ), 190 ), 191 ); 192 } 193 194 /** 195 * Retrieves the params for a single item. 196 * 197 * @since 4.8.0 198 * @access public 199 * 200 * @return array Item parameters. 201 */ 202 public function get_item_params() { 203 return array( 204 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 205 'location' => array( 206 'description' => __( 'Optional city name to help determine the location.' ), 207 'type' => 'string', 208 'default' => '', 209 ), 210 'timezone' => array( 211 'description' => __( 'Optional timezone to help determine the location.' ), 212 'type' => 'string', 213 'default' => '', 214 ), 215 ); 216 } 217 } -
src/wp-includes/rest-api.php
237 237 // Settings. 238 238 $controller = new WP_REST_Settings_Controller; 239 239 $controller->register_routes(); 240 241 // Community events. 242 $controller = new WP_REST_Community_Events_Events_Controller; 243 $controller->register_routes(); 244 245 // Community events location. 246 $controller = new WP_REST_Community_Events_Location_Controller; 247 $controller->register_routes(); 240 248 } 241 249 242 250 /** -
src/wp-settings.php
234 234 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-users-controller.php' ); 235 235 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-comments-controller.php' ); 236 236 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-settings-controller.php' ); 237 require( ABSPATH . WPINC . '/rest-api/endpoints/dashboard/class-wp-rest-community-events-events-controller.php' ); 238 require( ABSPATH . WPINC . '/rest-api/endpoints/dashboard/class-wp-rest-community-events-location-controller.php' ); 237 239 require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-meta-fields.php' ); 238 240 require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-comment-meta-fields.php' ); 239 241 require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-post-meta-fields.php' );