diff --git src/wp-admin/admin-ajax.php src/wp-admin/admin-ajax.php
index 3213d55028..e0f4464d94 100644
--- src/wp-admin/admin-ajax.php
+++ src/wp-admin/admin-ajax.php
@@ -64,7 +64,7 @@ $core_actions_post = array(
'parse-media-shortcode', 'destroy-sessions', 'install-plugin', 'update-plugin', 'press-this-save-post',
'press-this-add-category', 'crop-image', 'generate-password', 'save-wporg-username', 'delete-plugin',
'search-plugins', 'search-install-plugins', 'activate-plugin', 'update-theme', 'delete-theme',
- 'install-theme', 'get-post-thumbnail-html', 'get-community-events',
+ 'install-theme', 'get-post-thumbnail-html',
);
// Deprecated
diff --git src/wp-admin/includes/ajax-actions.php src/wp-admin/includes/ajax-actions.php
index 029e20e62b..3342cad375 100644
--- src/wp-admin/includes/ajax-actions.php
+++ src/wp-admin/includes/ajax-actions.php
@@ -297,40 +297,6 @@ function wp_ajax_autocomplete_user() {
}
/**
- * Handles AJAX requests for community events
- *
- * @since 4.8.0
- */
-function wp_ajax_get_community_events() {
- require_once( ABSPATH . 'wp-admin/includes/class-wp-community-events.php' );
-
- check_ajax_referer( 'community_events' );
-
- $search = isset( $_POST['location'] ) ? wp_unslash( $_POST['location'] ) : '';
- $timezone = isset( $_POST['timezone'] ) ? wp_unslash( $_POST['timezone'] ) : '';
- $user_id = get_current_user_id();
- $saved_location = get_user_option( 'community-events-location', $user_id );
- $events_client = new WP_Community_Events( $user_id, $saved_location );
- $events = $events_client->get_events( $search, $timezone );
-
- if ( is_wp_error( $events ) ) {
- wp_send_json_error( array(
- 'error' => $events->get_error_message(),
- ) );
- } else {
- if ( isset( $events['location'] ) ) {
- // Send only the data that the client will use.
- $events['location'] = $events['location']['description'];
-
- // Store the location network-wide, so the user doesn't have to set it on each site.
- update_user_option( $user_id, 'community-events-location', $events['location'], true );
- }
-
- wp_send_json_success( $events );
- }
-}
-
-/**
* Ajax handler for dashboard widgets.
*
* @since 3.4.0
diff --git src/wp-admin/includes/dashboard.php src/wp-admin/includes/dashboard.php
index b25426e753..2e49ce54c5 100644
--- src/wp-admin/includes/dashboard.php
+++ src/wp-admin/includes/dashboard.php
@@ -144,7 +144,6 @@ function wp_get_community_events_script_data() {
$events_client = new WP_Community_Events( $user_id, $user_location );
$script_data = array(
- 'nonce' => wp_create_nonce( 'community_events' ),
'cache' => $events_client->get_cached_events(),
'l10n' => array(
@@ -1243,7 +1242,7 @@ function wp_print_community_events_templates() {
{{ data.location }}'
+ '{{ data.location.description }}'
); ?>
@@ -1265,12 +1264,14 @@ function wp_print_community_events_templates() {
-
- {{ event.formatted_date }}
- <# if ( 'meetup' === event.type ) { #>
- {{ event.formatted_time }}
- <# } #>
-
+ <# if ( event.date && event.date.formatted ) { #>
+
+ {{ event.date.formatted.date }}
+ <# if ( 'meetup' === event.type ) { #>
+ {{ event.date.formatted.time }}
+ <# } #>
+
+ <# } #>
<# } ) #>
@@ -1280,7 +1281,7 @@ function wp_print_community_events_templates() {
organize one?' ),
- '{{data.location}}',
+ '{{data.location.description}}',
__( 'https://make.wordpress.org/community/handbook/meetup-organizer/welcome/' )
); ?>
diff --git src/wp-admin/js/dashboard.js src/wp-admin/js/dashboard.js
index 6a9b5033d4..570eecadac 100644
--- src/wp-admin/js/dashboard.js
+++ src/wp-admin/js/dashboard.js
@@ -191,7 +191,7 @@ jQuery(document).ready( function($) {
jQuery( function( $ ) {
'use strict';
-
+
var communityEventsData = window.communityEventsData || {};
var app = window.wp.communityEvents = {
@@ -288,45 +288,70 @@ jQuery( function( $ ) {
getEvents: function( requestParams ) {
var initiatedBy,
app = this,
- $spinner = $( '.community-events-form' ).children( '.spinner' );
+ $spinner = $( '.community-events-form' ).children( '.spinner' ),
+ dashboardLoadPromise = wp.api.init( { 'versionString': 'wp/dashboard/v1/' } );
requestParams = requestParams || {};
- requestParams._wpnonce = communityEventsData.nonce;
requestParams.timezone = window.Intl ? window.Intl.DateTimeFormat().resolvedOptions().timeZone : '';
+ requestParams._embed = 1;
initiatedBy = requestParams.location ? 'user' : 'app';
$spinner.addClass( 'is-active' );
- wp.ajax.post( 'get-community-events', requestParams )
- .always( function() {
- $spinner.removeClass( 'is-active' );
- })
-
- .done( function( response ) {
- if ( 'no_location_available' === response.error ) {
- if ( requestParams.location ) {
- response.unknownCity = requestParams.location;
- } else {
- /*
- * No location was passed, which means that this was an automatic query
- * based on IP, locale, and timezone. Since the user didn't initiate it,
- * it should fail silently. Otherwise, the error could confuse and/or
- * annoy them.
- */
-
- delete response.error;
+ dashboardLoadPromise.done( function( endpoint ) {
+ if ( ! app.model ) {
+ app.model = new wp.api.collections.CommunityEventsMine();
+ }
+ requestParams = requestParams || {};
+ requestParams.timezone = window.Intl ? window.Intl.DateTimeFormat().resolvedOptions().timeZone : '';
+ requestParams._embed = 1;
+ initiatedBy = requestParams.location ? 'user' : 'app';
+
+ $spinner.addClass( 'is-active' );
+
+
+ var meModel = app.model.fetch( {
+ 'data': requestParams,
+ 'success': function( model, response ) {
+ window.console.log( 'success', response );
+ var events = response._embedded && response._embedded.events ? response._embedded.events[0] : [];
+ var location = response;
+
+ delete response._embedded;
+ delete response._links;
+
+ app.renderEventsTemplate({
+ location: location,
+ events: events
+ }, initiatedBy );
+
+ },
+ 'error': function( model, response ) {
+
+ if ( 'rest_cannot_retrieve_user_location' === response.code && requestParams.location ) {
+ app.renderEventsTemplate({
+ unknownCity: requestParams.location,
+ location: false,
+ events: []
+ }, initiatedBy );
+
+ return;
}
+
+ app.renderEventsTemplate( {
+ 'location' : false,
+ 'error' : true
+ }, initiatedBy );
}
- app.renderEventsTemplate( response, initiatedBy );
- })
-
- .fail( function() {
- app.renderEventsTemplate( {
- 'location' : false,
- 'error' : true
- }, initiatedBy );
- });
+ } );
+
+ meModel
+ .always( function() {
+ $spinner.removeClass( 'is-active' );
+ });
+ });
+
},
/**
diff --git src/wp-includes/js/wp-api.js src/wp-includes/js/wp-api.js
index 3f950a47f5..040a9af834 100644
--- src/wp-includes/js/wp-api.js
+++ src/wp-includes/js/wp-api.js
@@ -1270,7 +1270,11 @@
// Extract the name and any parent from the route.
var collectionClassName, modelClassName,
routeName = collectionRoute.index.slice( collectionRoute.index.lastIndexOf( '/' ) + 1 ),
- parentName = wp.api.utils.extractRoutePart( collectionRoute.index, 1, routeModel.get( 'versionString' ), false );
+ parentName = wp.api.utils.extractRoutePart( collectionRoute.index, 1, routeModel.get( 'versionString' ), false ),
+ remainder = collectionRoute.index
+ .replace( routeModel.get( 'versionString' ), '' )
+ .replace( routeName, '' )
+ .slice( 1 );
// If the collection has a parent in its route, add that to its class name.
if ( '' !== parentName && parentName !== routeName && routeModel.get( 'versionString' ) !== parentName ) {
@@ -1282,14 +1286,22 @@
// Function that returns a constructed url passed on the parent.
url: function() {
- return routeModel.get( 'apiRoot' ) + routeModel.get( 'versionString' ) +
- parentName + '/' + this.parent + '/' +
- routeName;
+ var hasParent = ! _.isEmpty( this.parent );
+
+ return routeModel.get( 'apiRoot' ) +
+ routeModel.get( 'versionString' ) +
+ ( hasParent ? ( parentName + '/' ) : remainder ) +
+ ( hasParent ? ( this.parent + '/' ) : '' ) +
+ routeName;
},
// Specify the model that this collection contains.
model: function( attrs, options ) {
- return new loadingObjects.models[ modelClassName ]( attrs, options );
+ if ( loadingObjects.models[ modelClassName ] ) {
+ return new loadingObjects.models[ modelClassName ]( attrs, options );
+ } else {
+ return new Backbone.Model();
+ }
},
// Include a reference to the original class name.
diff --git src/wp-includes/rest-api.php src/wp-includes/rest-api.php
index ec7c50d27b..891be7ceb6 100644
--- src/wp-includes/rest-api.php
+++ src/wp-includes/rest-api.php
@@ -237,6 +237,14 @@ function create_initial_rest_routes() {
// Settings.
$controller = new WP_REST_Settings_Controller;
$controller->register_routes();
+
+ // Community events.
+ $controller = new WP_REST_Community_Events_Events_Controller;
+ $controller->register_routes();
+
+ // Community events location.
+ $controller = new WP_REST_Community_Events_Location_Controller;
+ $controller->register_routes();
}
/**
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
new file mode 100644
index 0000000000..570abd2adc
--- /dev/null
+++ src/wp-includes/rest-api/endpoints/dashboard/class-wp-rest-community-events-events-controller.php
@@ -0,0 +1,281 @@
+namespace = 'wp/dashboard/v1';
+ $this->rest_base = 'community-events/events';
+ }
+
+ /**
+ * Registers the routes for the objects of the controller.
+ *
+ * @since 4.8.0
+ * @access public
+ *
+ * @see register_rest_route()
+ */
+ public function register_routes() {
+
+ register_rest_route( $this->namespace, '/' . $this->rest_base . '/me', array(
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'get_current_items' ),
+ 'permission_callback' => array( $this, 'get_current_items_permissions_check' ),
+ 'args' => $this->get_collection_params(),
+ ),
+ 'schema' => array( $this, 'get_public_item_schema' ),
+ ) );
+ }
+
+ /**
+ * Checks whether a given request has permission to read community events.
+ *
+ * @since 4.8.0
+ * @access public
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return WP_Error|true True if the request has read access, WP_Error object otherwise.
+ */
+ public function get_current_items_permissions_check( $request ) {
+ if ( ! is_user_logged_in() ) {
+ return new WP_Error( 'rest_not_logged_in', __( 'You are not currently logged in.' ), array( 'status' => 401 ) );
+ }
+
+ return true;
+ }
+
+ /**
+ * Retrieves community events.
+ *
+ * @since 4.8.0
+ * @access public
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
+ */
+ public function get_current_items( $request ) {
+ require_once( ABSPATH . 'wp-admin/includes/class-wp-community-events.php' );
+
+ $user_id = get_current_user_id();
+
+ $location = $request->get_param( 'location' );
+ $timezone = $request->get_param( 'timezone' );
+
+ $saved_location = get_user_option( 'community-events-location', $user_id );
+ $events_client = new WP_Community_Events( $user_id, $saved_location );
+ $events = $events_client->get_events( $location, $timezone );
+
+ $data = array();
+
+ // Store the location network-wide, so the user doesn't have to set it on each site.
+ if ( ! is_wp_error( $events ) ) {
+ if ( isset( $events['location'] ) ) {
+ update_user_option( $user_id, 'community-events-location', $events['location'], true );
+ }
+
+ if ( isset( $events['events'] ) ) {
+ foreach ( $events['events'] as $event ) {
+ $data[] = $this->prepare_item_for_response( $event, $request );
+ }
+ }
+ }
+
+ return rest_ensure_response( $data );
+ }
+
+ /**
+ * Prepares a single event output for response.
+ *
+ * @since 4.8.0
+ * @access public
+ *
+ * @param array $event Event data array from the API.
+ * @param WP_REST_Request $request Request object.
+ * @return array Item prepared for response.
+ */
+ public function prepare_item_for_response( $event, $request ) {
+ $data = array();
+
+ $keys_to_copy = array( 'type', 'title', 'url', 'meetup', 'meetup_url' );
+ foreach ( $keys_to_copy as $key ) {
+ if ( isset( $event[ $key ] ) ) {
+ $data[ $key ] = $event[ $key ];
+ } else {
+ $data[ $key ] = null;
+ }
+ }
+
+ $data['date'] = array(
+ 'raw' => isset( $event['date'] ) ? $event['date'] : null,
+ 'formatted' => array(
+ 'date' => isset( $event['formatted_date'] ) ? $event['formatted_date'] : null,
+ 'time' => isset( $event['formatted_time'] ) ? $event['formatted_time'] : null,
+ ),
+ );
+
+ $data['location'] = isset( $event['location'] ) ? $event['location'] : null;
+
+ return $data;
+ }
+
+ /**
+ * Retrieves a community event's schema, conforming to JSON Schema.
+ *
+ * @since 4.8.0
+ * @access public
+ *
+ * @return array Item schema data.
+ */
+ public function get_item_schema() {
+ return array(
+ '$schema' => 'http://json-schema.org/schema#',
+ 'title' => 'community_event',
+ 'type' => 'object',
+ 'properties' => array(
+ 'type' => array(
+ 'description' => __( 'Type for the event.' ),
+ 'type' => 'string',
+ 'enum' => array( 'meetup', 'wordcamp' ),
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ 'title' => array(
+ 'description' => __( 'Title for the event.' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ 'url' => array(
+ 'description' => __( 'Website URL for the event.' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ 'meetup' => array(
+ 'description' => __( 'Name of the meetup, if the event is a meetup.' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ 'meetup_url' => array(
+ 'description' => __( 'URL for the meetup on meetup.com, if the event is a meetup.' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ 'date' => array(
+ 'description' => __( 'Date and time information for the event.' ),
+ 'type' => 'object',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ 'properties' => array(
+ 'raw' => array(
+ 'description' => __( 'Unformatted date and time string.' ),
+ 'type' => 'string',
+ 'format' => 'date-time',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ 'formatted' => array(
+ 'description' => __( 'Formatted date and time information for the event.' ),
+ 'type' => 'object',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ 'properties' => array(
+ 'date' => array(
+ 'description' => __( 'Formatted event date.' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ 'time' => array(
+ 'description' => __( 'Formatted event time.' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ ),
+ ),
+ ),
+ ),
+ 'location' => array(
+ 'description' => __( 'Location information for the event.' ),
+ 'type' => 'object',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ 'properties' => array(
+ 'location' => array(
+ 'description' => __( 'Location name for the event.' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ 'country' => array(
+ 'description' => __( 'Two-letter country code for the event.' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ 'latitude' => array(
+ 'description' => __( 'Latitude for the event.' ),
+ 'type' => 'number',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ 'longitude' => array(
+ 'description' => __( 'Longitude for the event.' ),
+ 'type' => 'number',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * Retrieves the query params for collections.
+ *
+ * @since 4.8.0
+ * @access public
+ *
+ * @return array Collection parameters.
+ */
+ public function get_collection_params() {
+ return array(
+ 'context' => $this->get_context_param( array( 'default' => 'view' ) ),
+ 'location' => array(
+ 'description' => __( 'Optional city name to help determine the location for the events.' ),
+ 'type' => 'string',
+ 'default' => '',
+ ),
+ 'timezone' => array(
+ 'description' => __( 'Optional timezone to help determine the location for the events.' ),
+ 'type' => 'string',
+ 'default' => '',
+ ),
+ );
+ }
+}
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
new file mode 100644
index 0000000000..7b5f360d9e
--- /dev/null
+++ src/wp-includes/rest-api/endpoints/dashboard/class-wp-rest-community-events-location-controller.php
@@ -0,0 +1,217 @@
+namespace = 'wp/dashboard/v1';
+ $this->rest_base = 'community-events/location';
+ }
+
+ /**
+ * Registers the routes for the objects of the controller.
+ *
+ * @since 4.8.0
+ * @access public
+ *
+ * @see register_rest_route()
+ */
+ public function register_routes() {
+
+ register_rest_route( $this->namespace, '/' . $this->rest_base . '/mine', array(
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'get_current_item' ),
+ 'permission_callback' => array( $this, 'get_current_item_permissions_check' ),
+ 'args' => $this->get_item_params(),
+ ),
+ 'schema' => array( $this, 'get_public_item_schema' ),
+ ) );
+ }
+
+ /**
+ * Checks whether a given request has permission to read the current user's community events location.
+ *
+ * @since 4.8.0
+ * @access public
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return WP_Error|true True if the request has read access, WP_Error object otherwise.
+ */
+ public function get_current_item_permissions_check( $request ) {
+ if ( ! is_user_logged_in() ) {
+ return new WP_Error( 'rest_not_logged_in', __( 'You are not currently logged in.' ), array( 'status' => 401 ) );
+ }
+
+ return true;
+ }
+
+ /**
+ * Retrieves the community events location for the current user.
+ *
+ * @since 4.8.0
+ * @access public
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
+ */
+ public function get_current_item( $request ) {
+ require_once( ABSPATH . 'wp-admin/includes/class-wp-community-events.php' );
+
+ $user_id = get_current_user_id();
+
+ $location = $request->get_param( 'location' );
+ $timezone = $request->get_param( 'timezone' );
+
+ $saved_location = get_user_option( 'community-events-location', $user_id );
+ $events_client = new WP_Community_Events( $user_id, $saved_location );
+ $events = $events_client->get_events( $location, $timezone );
+
+ // Store the location network-wide, so the user doesn't have to set it on each site.
+ if ( ! is_wp_error( $events ) ) {
+ if ( isset( $events['error'] ) && 'no_location_available' === $events['error'] ) {
+ return new WP_Error( 'rest_cannot_retrieve_user_location', __( 'The user location could not be retrieved.' ), array( 'status' => 503 ) );
+ }
+
+ if ( isset( $events['location'] ) ) {
+ update_user_option( $user_id, 'community-events-location', $events['location'], true );
+
+ $data = $this->prepare_item_for_response( $events['location'], $request );
+
+ return rest_ensure_response( $data );
+ }
+ }
+
+ return new WP_Error( 'rest_cannot_retrieve_user_location', __( 'The user location could not be retrieved.' ), array( 'status' => 503 ) );
+ }
+
+ /**
+ * Prepares a single location output for response.
+ *
+ * @since 4.8.0
+ * @access public
+ *
+ * @param array $location Location data array from the API.
+ * @param WP_REST_Request $request Request object.
+ * @return WP_REST_Response Response object.
+ */
+ public function prepare_item_for_response( $location, $request ) {
+ $data = array(
+ 'description' => isset( $location['description'] ) ? $location['description'] : null,
+ 'country' => isset( $location['country'] ) ? $location['country'] : null,
+ 'latitude' => isset( $location['latitude'] ) ? (float) $location['latitude'] : null,
+ 'longitude' => isset( $location['longitude'] ) ? (float) $location['longitude'] : null,
+ );
+
+ $response = rest_ensure_response( $data );
+
+ $url = rest_url( 'wp/dashboard/v1/community-events/events/me' );
+
+ $url_args = array();
+
+ if ( ! empty( $request['location'] ) ) {
+ $url_args['location'] = $request['location'];
+ }
+ if ( ! empty( $request['timezone'] ) ) {
+ $url_args['timezone'] = $request['timezone'];
+ }
+
+ if ( ! empty( $url_args ) ) {
+ $url = add_query_arg( $url_args, $url );
+ }
+
+ $response->add_links( array(
+ 'events' => array(
+ 'href' => $url,
+ 'embeddable' => true,
+ ),
+ ) );
+
+ return $response;
+ }
+
+ /**
+ * Retrieves a community events location schema, conforming to JSON Schema.
+ *
+ * @since 4.8.0
+ * @access public
+ *
+ * @return array Item schema data.
+ */
+ public function get_item_schema() {
+ return array(
+ '$schema' => 'http://json-schema.org/schema#',
+ 'title' => 'community_events_location',
+ 'type' => 'object',
+ 'properties' => array(
+ 'description' => array(
+ 'description' => __( 'Location description.' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ 'country' => array(
+ 'description' => __( 'Two-letter country code.' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ 'latitude' => array(
+ 'description' => __( 'Latitude.' ),
+ 'type' => 'number',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ 'longitude' => array(
+ 'description' => __( 'Longitude.' ),
+ 'type' => 'number',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ ),
+ );
+ }
+
+ /**
+ * Retrieves the params for a single item.
+ *
+ * @since 4.8.0
+ * @access public
+ *
+ * @return array Item parameters.
+ */
+ public function get_item_params() {
+ return array(
+ 'context' => $this->get_context_param( array( 'default' => 'view' ) ),
+ 'location' => array(
+ 'description' => __( 'Optional city name to help determine the location.' ),
+ 'type' => 'string',
+ 'default' => '',
+ ),
+ 'timezone' => array(
+ 'description' => __( 'Optional timezone to help determine the location.' ),
+ 'type' => 'string',
+ 'default' => '',
+ ),
+ );
+ }
+}
diff --git src/wp-includes/script-loader.php src/wp-includes/script-loader.php
index f1eda9ee38..c02fe73588 100644
--- src/wp-includes/script-loader.php
+++ src/wp-includes/script-loader.php
@@ -732,7 +732,7 @@ function wp_default_scripts( &$scripts ) {
'current' => __( 'Current Color' ),
) );
- $scripts->add( 'dashboard', "/wp-admin/js/dashboard$suffix.js", array( 'jquery', 'admin-comments', 'postbox', 'wp-util', 'wp-a11y' ), false, 1 );
+ $scripts->add( 'dashboard', "/wp-admin/js/dashboard$suffix.js", array( 'jquery', 'admin-comments', 'postbox', 'wp-util', 'wp-a11y', 'wp-api' ), false, 1 );
$scripts->add( 'list-revisions', "/wp-includes/js/wp-list-revisions$suffix.js" );
diff --git src/wp-settings.php src/wp-settings.php
index d1505c502d..060ab4c782 100644
--- src/wp-settings.php
+++ src/wp-settings.php
@@ -234,6 +234,8 @@ require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-terms-controller.p
require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-users-controller.php' );
require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-comments-controller.php' );
require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-settings-controller.php' );
+require( ABSPATH . WPINC . '/rest-api/endpoints/dashboard/class-wp-rest-community-events-events-controller.php' );
+require( ABSPATH . WPINC . '/rest-api/endpoints/dashboard/class-wp-rest-community-events-location-controller.php' );
require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-meta-fields.php' );
require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-comment-meta-fields.php' );
require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-post-meta-fields.php' );