Dashboard: Improve the handling of locations determined by geolocating the IP address and by entering a city name. Fix couple of edge cases, and some names.
Props iandunn coreymckrill. Fixes #40702. Built from https://develop.svn.wordpress.org/trunk@40790 git-svn-id: http://core.svn.wordpress.org/trunk@40648 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
daab579a88
commit
7a9ce6d03f
|
@ -312,14 +312,33 @@ function wp_ajax_get_community_events() {
|
||||||
$saved_location = get_user_option( 'community-events-location', $user_id );
|
$saved_location = get_user_option( 'community-events-location', $user_id );
|
||||||
$events_client = new WP_Community_Events( $user_id, $saved_location );
|
$events_client = new WP_Community_Events( $user_id, $saved_location );
|
||||||
$events = $events_client->get_events( $search, $timezone );
|
$events = $events_client->get_events( $search, $timezone );
|
||||||
|
$ip_changed = false;
|
||||||
|
|
||||||
if ( is_wp_error( $events ) ) {
|
if ( is_wp_error( $events ) ) {
|
||||||
wp_send_json_error( array(
|
wp_send_json_error( array(
|
||||||
'error' => $events->get_error_message(),
|
'error' => $events->get_error_message(),
|
||||||
) );
|
) );
|
||||||
} else {
|
} else {
|
||||||
if ( isset( $events['location'] ) ) {
|
if ( empty( $saved_location['ip'] ) && ! empty( $events['location']['ip'] ) ) {
|
||||||
// Store the location network-wide, so the user doesn't have to set it on each site.
|
$ip_changed = true;
|
||||||
|
} elseif ( isset( $saved_location['ip'] ) && ! empty( $events['location']['ip'] ) && $saved_location['ip'] !== $events['location']['ip'] ) {
|
||||||
|
$ip_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The location should only be updated when it changes. The API doesn't always return
|
||||||
|
* a full location; sometimes it's missing the description or country. The location
|
||||||
|
* that was saved during the initial request is known to be good and complete, though.
|
||||||
|
* It should be left in tact until the user explicitly changes it (either by manually
|
||||||
|
* searching for a new location, or by changing their IP address).
|
||||||
|
*
|
||||||
|
* If the location were updated with an incomplete response from the API, then it could
|
||||||
|
* break assumptions that the UI makes (e.g., that there will always be a description
|
||||||
|
* that corresponds to a latitude/longitude location).
|
||||||
|
*
|
||||||
|
* The location is stored network-wide, so that the user doesn't have to set it on each site.
|
||||||
|
*/
|
||||||
|
if ( $ip_changed || $search ) {
|
||||||
update_user_option( $user_id, 'community-events-location', $events['location'], true );
|
update_user_option( $user_id, 'community-events-location', $events['location'], true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,12 +94,13 @@ class WP_Community_Events {
|
||||||
return $cached_events;
|
return $cached_events;
|
||||||
}
|
}
|
||||||
|
|
||||||
$request_url = $this->get_request_url( $location_search, $timezone );
|
$api_url = 'https://api.wordpress.org/events/1.0/';
|
||||||
$response = wp_remote_get( $request_url );
|
$request_args = $this->get_request_args( $location_search, $timezone );
|
||||||
|
$response = wp_remote_get( $api_url, $request_args );
|
||||||
$response_code = wp_remote_retrieve_response_code( $response );
|
$response_code = wp_remote_retrieve_response_code( $response );
|
||||||
$response_body = json_decode( wp_remote_retrieve_body( $response ), true );
|
$response_body = json_decode( wp_remote_retrieve_body( $response ), true );
|
||||||
$response_error = null;
|
$response_error = null;
|
||||||
$debugging_info = compact( 'request_url', 'response_code', 'response_body' );
|
$debugging_info = compact( 'api_url', 'request_args', 'response_code', 'response_body' );
|
||||||
|
|
||||||
if ( is_wp_error( $response ) ) {
|
if ( is_wp_error( $response ) ) {
|
||||||
$response_error = $response;
|
$response_error = $response;
|
||||||
|
@ -128,6 +129,31 @@ class WP_Community_Events {
|
||||||
unset( $response_body['ttl'] );
|
unset( $response_body['ttl'] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The IP in the response is usually the same as the one that was sent
|
||||||
|
* in the request, but in some cases it is different. In those cases,
|
||||||
|
* it's important to reset it back to the IP from the request.
|
||||||
|
*
|
||||||
|
* For example, if the IP sent in the request is private (e.g., 192.168.1.100),
|
||||||
|
* then the API will ignore that and use the corresponding public IP instead,
|
||||||
|
* and the public IP will get returned. If the public IP were saved, though,
|
||||||
|
* then get_cached_events() would always return `false`, because the transient
|
||||||
|
* would be generated based on the public IP when saving the cache, but generated
|
||||||
|
* based on the private IP when retrieving the cache.
|
||||||
|
*/
|
||||||
|
if ( ! empty( $response_body['location']['ip'] ) ) {
|
||||||
|
$response_body['location']['ip'] = $request_args['body']['ip'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The API doesn't return a description for latitude/longitude requests,
|
||||||
|
* but the description is already saved in the user location, so that
|
||||||
|
* one can be used instead.
|
||||||
|
*/
|
||||||
|
if ( $this->coordinates_match( $request_args['body'], $response_body['location'] ) && empty( $response_body['location']['description'] ) ) {
|
||||||
|
$response_body['location']['description'] = $this->user_location['description'];
|
||||||
|
}
|
||||||
|
|
||||||
$this->cache_events( $response_body, $expiration );
|
$this->cache_events( $response_body, $expiration );
|
||||||
|
|
||||||
$response_body = $this->trim_events( $response_body );
|
$response_body = $this->trim_events( $response_body );
|
||||||
|
@ -143,24 +169,23 @@ class WP_Community_Events {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a URL for requests to the w.org Events API.
|
* Builds an array of args to use in an HTTP request to the w.org Events API.
|
||||||
*
|
*
|
||||||
* @access protected
|
* @access protected
|
||||||
* @since 4.8.0
|
* @since 4.8.0
|
||||||
*
|
*
|
||||||
* @param string $search Optional. City search string. Default empty string.
|
* @param string $search Optional. City search string. Default empty string.
|
||||||
* @param string $timezone Optional. Timezone string. Default empty string.
|
* @param string $timezone Optional. Timezone string. Default empty string.
|
||||||
* @return string The request URL.
|
* @return @return array The request args.
|
||||||
*/
|
*/
|
||||||
protected function get_request_url( $search = '', $timezone = '' ) {
|
protected function get_request_args( $search = '', $timezone = '' ) {
|
||||||
$api_url = 'https://api.wordpress.org/events/1.0/';
|
|
||||||
$args = array(
|
$args = array(
|
||||||
'number' => 5, // Get more than three in case some get trimmed out.
|
'number' => 5, // Get more than three in case some get trimmed out.
|
||||||
'ip' => $this->get_client_ip(),
|
'ip' => self::get_unsafe_client_ip(),
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send the minimal set of necessary arguments, in order to increase the
|
* Include the minimal set of necessary arguments, in order to increase the
|
||||||
* chances of a cache-hit on the API side.
|
* chances of a cache-hit on the API side.
|
||||||
*/
|
*/
|
||||||
if ( empty( $search ) && isset( $this->user_location['latitude'], $this->user_location['longitude'] ) ) {
|
if ( empty( $search ) && isset( $this->user_location['latitude'], $this->user_location['longitude'] ) ) {
|
||||||
|
@ -178,7 +203,10 @@ class WP_Community_Events {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return add_query_arg( $args, $api_url );
|
// Wrap the args in an array compatible with the second parameter of `wp_remote_get()`.
|
||||||
|
return array(
|
||||||
|
'body' => $args
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -207,7 +235,7 @@ class WP_Community_Events {
|
||||||
* @return false|string The anonymized address on success; the given address
|
* @return false|string The anonymized address on success; the given address
|
||||||
* or false on failure.
|
* or false on failure.
|
||||||
*/
|
*/
|
||||||
protected function get_client_ip() {
|
public static function get_unsafe_client_ip() {
|
||||||
$client_ip = false;
|
$client_ip = false;
|
||||||
|
|
||||||
// In order of preference, with the best ones for this purpose first.
|
// In order of preference, with the best ones for this purpose first.
|
||||||
|
@ -249,6 +277,24 @@ class WP_Community_Events {
|
||||||
return $client_ip;
|
return $client_ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if two pairs of latitude/longitude coordinates match each other.
|
||||||
|
*
|
||||||
|
* @since 4.8.0
|
||||||
|
* @access protected
|
||||||
|
*
|
||||||
|
* @param array $a The first pair, with indexes 'latitude' and 'longitude'.
|
||||||
|
* @param array $b The second pair, with indexes 'latitude' and 'longitude'.
|
||||||
|
* @return bool True if they match, false if they don't.
|
||||||
|
*/
|
||||||
|
protected function coordinates_match( $a, $b ) {
|
||||||
|
if ( ! isset( $a['latitude'], $a['longitude'], $b['latitude'], $b['longitude'] ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $a['latitude'] === $b['latitude'] && $a['longitude'] === $b['longitude'];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a transient key based on user location.
|
* Generates a transient key based on user location.
|
||||||
*
|
*
|
||||||
|
@ -266,7 +312,9 @@ class WP_Community_Events {
|
||||||
protected function get_events_transient_key( $location ) {
|
protected function get_events_transient_key( $location ) {
|
||||||
$key = false;
|
$key = false;
|
||||||
|
|
||||||
if ( isset( $location['latitude'], $location['longitude'] ) ) {
|
if ( isset( $location['ip'] ) ) {
|
||||||
|
$key = 'community-events-' . md5( $location['ip'] );
|
||||||
|
} else if ( isset( $location['latitude'], $location['longitude'] ) ) {
|
||||||
$key = 'community-events-' . md5( $location['latitude'] . $location['longitude'] );
|
$key = 'community-events-' . md5( $location['latitude'] . $location['longitude'] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1234,15 +1234,23 @@ function wp_print_community_events_templates() {
|
||||||
|
|
||||||
<script id="tmpl-community-events-no-upcoming-events" type="text/template">
|
<script id="tmpl-community-events-no-upcoming-events" type="text/template">
|
||||||
<li class="event-none">
|
<li class="event-none">
|
||||||
|
<# if ( data.location.description ) { #>
|
||||||
<?php printf(
|
<?php printf(
|
||||||
/* translators: 1: the city the user searched for, 2: meetup organization documentation URL */
|
/* translators: 1: the city the user searched for, 2: meetup organization documentation URL */
|
||||||
__( 'There aren’t any events scheduled near %1$s at the moment. Would you like to <a href="%2$s">organize one</a>?' ),
|
__( 'There aren’t any events scheduled near %1$s at the moment. Would you like to <a href="%2$s">organize one</a>?' ),
|
||||||
'{{ data.location.description }}',
|
'{{ data.location.description }}',
|
||||||
__( 'https://make.wordpress.org/community/handbook/meetup-organizer/welcome/' )
|
__( 'https://make.wordpress.org/community/handbook/meetup-organizer/welcome/' )
|
||||||
); ?>
|
); ?>
|
||||||
|
|
||||||
|
<# } else { #>
|
||||||
|
<?php printf(
|
||||||
|
/* translators: meetup organization documentation URL. */
|
||||||
|
__( 'There aren’t any events scheduled near you at the moment. Would you like to <a href="%s">organize one</a>?' ),
|
||||||
|
__( 'https://make.wordpress.org/community/handbook/meetup-organizer/welcome/' )
|
||||||
|
); ?>
|
||||||
|
<# } #>
|
||||||
</li>
|
</li>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -385,7 +385,26 @@ jQuery( function( $ ) {
|
||||||
* Determine which templates should be rendered and which elements
|
* Determine which templates should be rendered and which elements
|
||||||
* should be displayed.
|
* should be displayed.
|
||||||
*/
|
*/
|
||||||
if ( templateParams.location ) {
|
if ( templateParams.location.ip ) {
|
||||||
|
/*
|
||||||
|
* If the API determined the location by geolocating an IP, it will
|
||||||
|
* provide events, but not a specific location.
|
||||||
|
*/
|
||||||
|
$locationMessage.text( communityEventsData.l10n.attend_event_near_generic );
|
||||||
|
|
||||||
|
if ( templateParams.events.length ) {
|
||||||
|
template = wp.template( 'community-events-event-list' );
|
||||||
|
$results.html( template( templateParams ) );
|
||||||
|
} else {
|
||||||
|
template = wp.template( 'community-events-no-upcoming-events' );
|
||||||
|
$results.html( template( templateParams ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
elementVisibility['#community-events-location-message'] = true;
|
||||||
|
elementVisibility['.community-events-toggle-location'] = true;
|
||||||
|
elementVisibility['.community-events-results'] = true;
|
||||||
|
|
||||||
|
} else if ( templateParams.location.description ) {
|
||||||
template = wp.template( 'community-events-attend-event-near' );
|
template = wp.template( 'community-events-attend-event-near' );
|
||||||
$locationMessage.html( template( templateParams ) );
|
$locationMessage.html( template( templateParams ) );
|
||||||
|
|
||||||
|
@ -435,7 +454,7 @@ jQuery( function( $ ) {
|
||||||
|
|
||||||
$toggleButton.attr( 'aria-expanded', elementVisibility['.community-events-toggle-location'] );
|
$toggleButton.attr( 'aria-expanded', elementVisibility['.community-events-toggle-location'] );
|
||||||
|
|
||||||
if ( templateParams.location ) {
|
if ( templateParams.location && ( templateParams.location.ip || templateParams.location.latitude ) ) {
|
||||||
// Hide the form when there's a valid location.
|
// Hide the form when there's a valid location.
|
||||||
app.toggleLocationForm( 'hide' );
|
app.toggleLocationForm( 'hide' );
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1013,8 +1013,23 @@ function wp_localize_community_events() {
|
||||||
require_once( ABSPATH . 'wp-admin/includes/class-wp-community-events.php' );
|
require_once( ABSPATH . 'wp-admin/includes/class-wp-community-events.php' );
|
||||||
|
|
||||||
$user_id = get_current_user_id();
|
$user_id = get_current_user_id();
|
||||||
$user_location = get_user_option( 'community-events-location', $user_id );
|
$saved_location = get_user_option( 'community-events-location', $user_id );
|
||||||
$events_client = new WP_Community_Events( $user_id, $user_location );
|
$saved_ip_address = isset( $saved_location['ip'] ) ? $saved_location['ip'] : false;
|
||||||
|
$current_ip_address = WP_Community_Events::get_unsafe_client_ip();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the user's location is based on their IP address, then update their
|
||||||
|
* location when their IP address changes. This allows them to see events
|
||||||
|
* in their current city when travelling. Otherwise, they would always be
|
||||||
|
* shown events in the city where they were when they first loaded the
|
||||||
|
* Dashboard, which could have been months or years ago.
|
||||||
|
*/
|
||||||
|
if ( $saved_ip_address && $current_ip_address && $current_ip_address !== $saved_ip_address ) {
|
||||||
|
$saved_location['ip'] = $current_ip_address;
|
||||||
|
update_user_option( $user_id, 'community-events-location', $saved_location, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
$events_client = new WP_Community_Events( $user_id, $saved_location );
|
||||||
|
|
||||||
wp_localize_script( 'dashboard', 'communityEventsData', array(
|
wp_localize_script( 'dashboard', 'communityEventsData', array(
|
||||||
'nonce' => wp_create_nonce( 'community_events' ),
|
'nonce' => wp_create_nonce( 'community_events' ),
|
||||||
|
@ -1023,6 +1038,7 @@ function wp_localize_community_events() {
|
||||||
'l10n' => array(
|
'l10n' => array(
|
||||||
'enter_closest_city' => __( 'Enter your closest city to find nearby events.' ),
|
'enter_closest_city' => __( 'Enter your closest city to find nearby events.' ),
|
||||||
'error_occurred_please_try_again' => __( 'An error occurred. Please try again.' ),
|
'error_occurred_please_try_again' => __( 'An error occurred. Please try again.' ),
|
||||||
|
'attend_event_near_generic' => __( 'Attend an upcoming event near you.' ),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These specific examples were chosen to highlight the fact that a
|
* These specific examples were chosen to highlight the fact that a
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*
|
*
|
||||||
* @global string $wp_version
|
* @global string $wp_version
|
||||||
*/
|
*/
|
||||||
$wp_version = '4.8-beta1-40789';
|
$wp_version = '4.8-beta1-40790';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||||
|
|
Loading…
Reference in New Issue