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 );
|
||||
$events_client = new WP_Community_Events( $user_id, $saved_location );
|
||||
$events = $events_client->get_events( $search, $timezone );
|
||||
$ip_changed = false;
|
||||
|
||||
if ( is_wp_error( $events ) ) {
|
||||
wp_send_json_error( array(
|
||||
'error' => $events->get_error_message(),
|
||||
) );
|
||||
} else {
|
||||
if ( isset( $events['location'] ) ) {
|
||||
// Store the location network-wide, so the user doesn't have to set it on each site.
|
||||
if ( empty( $saved_location['ip'] ) && ! empty( $events['location']['ip'] ) ) {
|
||||
$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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -94,12 +94,13 @@ class WP_Community_Events {
|
|||
return $cached_events;
|
||||
}
|
||||
|
||||
$request_url = $this->get_request_url( $location_search, $timezone );
|
||||
$response = wp_remote_get( $request_url );
|
||||
$api_url = 'https://api.wordpress.org/events/1.0/';
|
||||
$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_body = json_decode( wp_remote_retrieve_body( $response ), true );
|
||||
$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 ) ) {
|
||||
$response_error = $response;
|
||||
|
@ -128,6 +129,31 @@ class WP_Community_Events {
|
|||
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 );
|
||||
|
||||
$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
|
||||
* @since 4.8.0
|
||||
*
|
||||
* @param string $search Optional. City search 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 = '' ) {
|
||||
$api_url = 'https://api.wordpress.org/events/1.0/';
|
||||
$args = array(
|
||||
protected function get_request_args( $search = '', $timezone = '' ) {
|
||||
$args = array(
|
||||
'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.
|
||||
*/
|
||||
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
|
||||
* or false on failure.
|
||||
*/
|
||||
protected function get_client_ip() {
|
||||
public static function get_unsafe_client_ip() {
|
||||
$client_ip = false;
|
||||
|
||||
// In order of preference, with the best ones for this purpose first.
|
||||
|
@ -249,6 +277,24 @@ class WP_Community_Events {
|
|||
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.
|
||||
*
|
||||
|
@ -266,7 +312,9 @@ class WP_Community_Events {
|
|||
protected function get_events_transient_key( $location ) {
|
||||
$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'] );
|
||||
}
|
||||
|
||||
|
|
|
@ -1234,15 +1234,23 @@ function wp_print_community_events_templates() {
|
|||
|
||||
<script id="tmpl-community-events-no-upcoming-events" type="text/template">
|
||||
<li class="event-none">
|
||||
<?php printf(
|
||||
/* 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>?' ),
|
||||
'{{ data.location.description }}',
|
||||
__( 'https://make.wordpress.org/community/handbook/meetup-organizer/welcome/' )
|
||||
); ?>
|
||||
<# if ( data.location.description ) { #>
|
||||
<?php printf(
|
||||
/* 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>?' ),
|
||||
'{{ data.location.description }}',
|
||||
__( '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>
|
||||
</script>
|
||||
|
||||
<?php
|
||||
}
|
||||
|
||||
|
|
|
@ -385,7 +385,26 @@ jQuery( function( $ ) {
|
|||
* Determine which templates should be rendered and which elements
|
||||
* 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' );
|
||||
$locationMessage.html( template( templateParams ) );
|
||||
|
||||
|
@ -435,7 +454,7 @@ jQuery( function( $ ) {
|
|||
|
||||
$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.
|
||||
app.toggleLocationForm( 'hide' );
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1012,9 +1012,24 @@ function wp_localize_community_events() {
|
|||
|
||||
require_once( ABSPATH . 'wp-admin/includes/class-wp-community-events.php' );
|
||||
|
||||
$user_id = get_current_user_id();
|
||||
$user_location = get_user_option( 'community-events-location', $user_id );
|
||||
$events_client = new WP_Community_Events( $user_id, $user_location );
|
||||
$user_id = get_current_user_id();
|
||||
$saved_location = get_user_option( 'community-events-location', $user_id );
|
||||
$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(
|
||||
'nonce' => wp_create_nonce( 'community_events' ),
|
||||
|
@ -1023,6 +1038,7 @@ function wp_localize_community_events() {
|
|||
'l10n' => array(
|
||||
'enter_closest_city' => __( 'Enter your closest city to find nearby events.' ),
|
||||
'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
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* @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.
|
||||
|
|
Loading…
Reference in New Issue