Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 127 additions & 75 deletions modules/widgets/contact-info.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class Jetpack_Contact_Info_Widget extends WP_Widget {
* Constructor
*/
function __construct() {
global $pagenow;

$widget_ops = array(
'classname' => 'widget_contact_info',
'description' => __( 'Display a map with your location, hours, and contact information.', 'jetpack' ),
Expand All @@ -37,14 +39,23 @@ function __construct() {

if ( is_customize_preview() ) {
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
} elseif ( 'widgets.php' === $pagenow ) {
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
}

add_action( 'wp_ajax_customize-contact-info-api-key', array( $this, 'ajax_check_api_key' ) );
}

/**
* Enqueue scripts and styles.
*/
public function enqueue_scripts() {
wp_enqueue_style( 'contact-info-map-css', plugins_url( 'contact-info/contact-info-map.css', __FILE__ ), null, 20160623 );
wp_enqueue_style(
'contact-info-map-css',
plugins_url( 'contact-info/contact-info-map.css', __FILE__ ),
array(),
JETPACK__VERSION
);
}


Expand All @@ -64,8 +75,7 @@ public function defaults() {
'email' => null,
'showmap' => 0,
'apikey' => null,
'lat' => null,
'lon' => null,
'goodmap' => null,
);
}

Expand Down Expand Up @@ -100,9 +110,9 @@ function widget( $args, $instance ) {
if ( '' != $instance['address'] ) {

$showmap = $instance['showmap'];
$goodmap = isset( $instance['goodmap'] ) ? $instance['goodmap'] : $this->has_good_map( $instance );

/** This action is documented in modules/widgets/contact-info.php */
if ( $showmap && $this->has_good_map( $instance ) ) {
if ( $showmap && true === $goodmap ) {
/**
* Set a Google Maps API Key.
*
Expand All @@ -112,6 +122,11 @@ function widget( $args, $instance ) {
*/
$api_key = apply_filters( 'jetpack_google_maps_api_key', $instance['apikey'] );
echo $this->build_map( $instance['address'], $api_key );
} elseif ( $showmap && is_customize_preview() && true !== $goodmap ) {
printf(
'<span class="contact-map-api-error" style="display: block;">%s</span>',
esc_html( $instance['goodmap'] )
);
}

$map_link = $this->build_map_link( $instance['address'] );
Expand Down Expand Up @@ -166,13 +181,6 @@ function widget( $args, $instance ) {
* @return array
*/
function update( $new_instance, $old_instance ) {
$update_lat_lon = false;
if (
! isset( $old_instance['address'] ) ||
$this->urlencode_address( $old_instance['address'] ) != $this->urlencode_address( $new_instance['address'] )
) {
$update_lat_lon = true;
}

$instance = array();
$instance['title'] = wp_kses( $new_instance['title'], array() );
Expand All @@ -181,57 +189,15 @@ function update( $new_instance, $old_instance ) {
$instance['email'] = wp_kses( $new_instance['email'], array() );
$instance['hours'] = wp_kses( $new_instance['hours'], array() );
$instance['apikey'] = wp_kses( isset( $new_instance['apikey'] ) ? $new_instance['apikey'] : $old_instance['apikey'], array() );
$instance['lat'] = isset( $old_instance['lat'] ) ? floatval( $old_instance['lat'] ) : 0;
$instance['lon'] = isset( $old_instance['lon'] ) ? floatval( $old_instance['lon'] ) : 0;

if ( ! $instance['lat'] || ! $instance['lon'] ) {
$update_lat_lon = true;
}

if ( $instance['address'] && $update_lat_lon ) {

// Get the lat/lon of the user specified address.
$address = $this->urlencode_address( $instance['address'] );
$path = 'https://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=' . $address;
/** This action is documented in modules/widgets/contact-info.php */
$key = apply_filters( 'jetpack_google_maps_api_key', $instance['apikey'] );

if ( ! empty( $key ) ) {
$path = add_query_arg( 'key', $key, $path );
}
$json = wp_remote_retrieve_body( wp_remote_get( esc_url( $path, null, null ) ) );

if ( ! $json ) {
// The read failed :(
esc_html_e( 'There was a problem getting the data to display this address on a map. Please refresh your browser and try again.', 'jetpack' );
die();
}

$json_obj = json_decode( $json );

if ( 'ZERO_RESULTS' == $json_obj->status ) {
// The address supplied does not have a matching lat / lon.
// No map is available.
$instance['lat'] = '0';
$instance['lon'] = '0';
} else {

$loc = $json_obj->results[0]->geometry->location;

$lat = floatval( $loc->lat );
$lon = floatval( $loc->lng );

$instance['lat'] = "$lat";
$instance['lon'] = "$lon";
}
}

if ( ! isset( $new_instance['showmap'] ) ) {
$instance['showmap'] = 0;
} else {
$instance['showmap'] = intval( $new_instance['showmap'] );
}

$instance['goodmap'] = $this->update_goodmap( $old_instance, $instance );

return $instance;
}

Expand All @@ -245,6 +211,9 @@ function update( $new_instance, $old_instance ) {
*/
function form( $instance ) {
$instance = wp_parse_args( $instance, $this->defaults() );
/** This filter is documented in modules/widgets/contact-info.php */
$apikey = apply_filters( 'jetpack_google_maps_api_key', $instance['apikey'] );

wp_enqueue_script(
'contact-info-admin',
Assets::get_file_url_for_environment(
Expand All @@ -255,6 +224,15 @@ function form( $instance ) {
20160727
);

if ( is_customize_preview() ) {
$customize_contact_info_api_key_nonce = wp_create_nonce( 'customize_contact_info_api_key' );
wp_localize_script(
'contact-info-admin',
'contact_info_api_key_ajax_obj',
array( 'nonce' => $customize_contact_info_api_key_nonce )
);
}

?>
<p>
<label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php esc_html_e( 'Title:', 'jetpack' ); ?></label>
Expand All @@ -264,30 +242,33 @@ function form( $instance ) {
<p>
<label for="<?php echo esc_attr( $this->get_field_id( 'address' ) ); ?>"><?php esc_html_e( 'Address:', 'jetpack' ); ?></label>
<textarea class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'address' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'address' ) ); ?>"><?php echo esc_textarea( $instance['address'] ); ?></textarea>
<?php
if ( $this->has_good_map( $instance ) ) {
?>
<input class="jp-contact-info-showmap" id="<?php echo esc_attr( $this->get_field_id( 'showmap' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'showmap' ) ); ?>" value="1" type="checkbox" <?php checked( $instance['showmap'], 1 ); ?> />
<label for="<?php echo esc_attr( $this->get_field_id( 'showmap' ) ); ?>"><?php esc_html_e( 'Show map', 'jetpack' ); ?></label>
<?php
} else {
?>
<span class="error-message"><?php _e( 'Sorry. We can not plot this address. A map will not be displayed. Is the address formatted correctly?', 'jetpack' ); ?></span>
<input id="<?php echo esc_attr( $this->get_field_id( 'showmap' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'showmap' ) ); ?>" value="<?php echo( intval( $instance['showmap'] ) ); ?>" type="hidden" />
<?php
}
?>

<input class="jp-contact-info-showmap" id="<?php echo esc_attr( $this->get_field_id( 'showmap' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'showmap' ) ); ?>" value="1" type="checkbox" <?php checked( $instance['showmap'], 1 ); ?> />
<label for="<?php echo esc_attr( $this->get_field_id( 'showmap' ) ); ?>"><?php esc_html_e( 'Show map', 'jetpack' ); ?></label>
</p>

<p class="jp-contact-info-apikey" style="<?php echo $instance['showmap'] ? '' : 'display: none;'; ?>">
<p class="jp-contact-info-admin-map" style="<?php echo $instance['showmap'] ? '' : 'display: none;'; ?>">
<label for="<?php echo esc_attr( $this->get_field_id( 'apikey' ) ); ?>">
<?php _e( 'Google Maps API Key', 'jetpack' ); ?>
<input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'apikey' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'apikey' ) ); ?>" type="text" value="<?php echo esc_attr( $instance['apikey'] ); ?>" />
<input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'apikey' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'apikey' ) ); ?>" type="text" value="<?php echo esc_attr( $apikey ); ?>" />
<br />
<small><?php printf( wp_kses( __( 'Google now requires an API key to use their maps on your site. <a href="%s">See our documentation</a> for instructions on acquiring a key.', 'jetpack' ), array( 'a' => array( 'href' => true ) ) ), 'https://jetpack.com/support/extra-sidebar-widgets/contact-info-widget/' ); ?></small>
</label>
</p>

<p class="jp-contact-info-admin-map jp-contact-info-embed-map" style="<?php echo $instance['showmap'] ? '' : 'display: none;'; ?>">
<?php
if ( ! is_customize_preview() && true === $instance['goodmap'] ) {
echo $this->build_map( $instance['address'], $apikey ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
} elseif ( true !== $instance['goodmap'] && ! empty( $instance['goodmap'] ) ) {
printf(
'<span class="notice notice-warning" style="display: block;">%s</span>',
esc_html( $instance['goodmap'] )
);
}
?>
</p>

<p>
<label for="<?php echo esc_attr( $this->get_field_id( 'phone' ) ); ?>"><?php esc_html_e( 'Phone:', 'jetpack' ); ?></label>
<input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'phone' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'phone' ) ); ?>" type="text" value="<?php echo esc_attr( $instance['phone'] ); ?>" />
Expand Down Expand Up @@ -321,7 +302,7 @@ function build_map_link( $address ) {


/**
* Builds map display HTML code from the supplied latitude and longitude.
* Builds map display HTML code from the supplied address.
*
* @param string $address Address.
* @param string $api_key API Key.
Expand Down Expand Up @@ -379,16 +360,87 @@ function urlencode_address( $address ) {
return urlencode( $address );
}

/**
* Returns the instance's updated 'goodmap' value.
*
* @param array $old_instance Old configuration values.
* @param array $instance Current configuration values.
*
* @return bool|string The instance's updated 'goodmap' value. The value is true if
* $instance can display a good map. If not, returns an error message.
*/
function update_goodmap( $old_instance, $instance ) {
/*
* If we have no address or don't want to show a map,
* no need to check if the map is valid.
*/
if ( empty( $instance['address'] ) || 0 === $instance['showmap'] ) {
return false;
}

/*
* If there have been any changes that may impact the map in the widget
* (adding an address, address changes, new API key, API key change)
* then we want to check whether our map can be displayed again.
*/
if (
! isset( $instance['goodmap'] )
|| ! isset( $old_instance['address'] )
|| $this->urlencode_address( $old_instance['address'] ) !== $this->urlencode_address( $instance['address'] )
|| ! isset( $old_instance['apikey'] )
|| $old_instance['apikey'] !== $instance['apikey']
) {
return $this->has_good_map( $instance );
} else {
return $instance['goodmap'];
}
}

/**
* Check if the instance has a valid Map location.
*
* @param array $instance Widget instance configuration.
*
* @return bool Whether or not there is a valid map.
* @return bool|string Whether or not there is a valid map. If not, return an error message.
*/
function has_good_map( $instance ) {
// The lat and lon of an address that could not be plotted will have values of 0 and 0.
return ! ( '0' == $instance['lat'] && '0' == $instance['lon'] );
/** This filter is documented in modules/widgets/contact-info.php */
$api_key = apply_filters( 'jetpack_google_maps_api_key', $instance['apikey'] );
if ( ! empty( $api_key ) ) {
$path = add_query_arg(
array(
'q' => rawurlencode( $instance['address'] ),
'key' => $api_key,
),
'https://www.google.com/maps/embed/v1/place'
);
$response = wp_remote_get( esc_url_raw( $path ) );

if ( 200 === wp_remote_retrieve_response_code( $response ) ) {
return true;
} else {
return wp_remote_retrieve_body( $response );
}
}

return __( 'Please enter a valid Google API Key.', 'jetpack' );
}

/**
* Check the Google Maps API key after an Ajax call from the widget's admin form in
* the Customizer preview.
*/
function ajax_check_api_key() {
if ( isset( $_POST['apikey'] ) ) {
if ( check_ajax_referer( 'customize_contact_info_api_key' ) && current_user_can( 'customize' ) ) {
$apikey = wp_kses( $_POST['apikey'], array() );
$default_instance = $this->defaults();
$default_instance['apikey'] = $apikey;
wp_send_json( array( 'result' => esc_html( $this->has_good_map( $default_instance ) ) ) );
}
} else {
wp_die();
}
}

}
Expand Down
48 changes: 47 additions & 1 deletion modules/widgets/contact-info/contact-info-admin.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,57 @@
/* global ajaxurl, contact_info_api_key_ajax_obj */

( function( $ ) {
$( document ).on( 'change', '.jp-contact-info-showmap', function() {
var $checkbox = $( this ),
isChecked = $checkbox.is( ':checked' );

$checkbox
.closest( '.widget' )
.find( '.jp-contact-info-apikey' )
.find( '.jp-contact-info-admin-map' )
.toggle( isChecked );
} );

$( document ).on( 'widget-synced', function( event, widgetContainer ) {
// This event fires for all widgets, so restrict this to Contact Info widgets and the API key input.
if (
! widgetContainer.is( '[id*="widget_contact_info"]' ) ||
! $( document.activeElement ).is( 'input[id*="apikey"]' )
) {
return;
}

event.preventDefault();

var $apikey_input = widgetContainer.find( 'input[id*="apikey"]' );

$.post(
ajaxurl,
{
_ajax_nonce: contact_info_api_key_ajax_obj.nonce,
action: 'customize-contact-info-api-key',
apikey: $apikey_input.val(),
},
function( data ) {
var $map_element = $apikey_input
.closest( '.jp-contact-info-admin-map' )
.parent()
.find( '.jp-contact-info-embed-map' );
var $warning_span = $map_element.find( '[class*="notice"]' );

if ( '1' !== data.result ) {
if ( $warning_span.length === 0 ) {
$map_element.append(
'<span class="notice notice-warning" style="display: block;">' +
data.result +
'</span>'
);
} else if ( $warning_span.text() !== data.result ) {
$warning_span.text( data.result );
}
} else {
$map_element.empty();
}
}
);
} );
} )( window.jQuery );
9 changes: 9 additions & 0 deletions modules/widgets/contact-info/contact-info-map.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
.contact-map {
max-width: 100%;
border: 0;
}

.contact-map-api-error {
border-left-color: #ffb900;
border-left-style: solid;
border-left-width: 4px;
box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
margin: 5px 0 15px;
padding: 1px 12px;
}