contact-info.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. <?php
  2. if ( ! class_exists( 'Jetpack_Contact_Info_Widget' ) ) {
  3. //register Contact_Info_Widget widget
  4. function jetpack_contact_info_widget_init() {
  5. register_widget( 'Jetpack_Contact_Info_Widget' );
  6. }
  7. add_action( 'widgets_init', 'jetpack_contact_info_widget_init' );
  8. /**
  9. * Makes a custom Widget for displaying Restaurant Location/Map, Hours, and Contact Info available.
  10. *
  11. * @package WordPress
  12. */
  13. class Jetpack_Contact_Info_Widget extends WP_Widget {
  14. /**
  15. * Constructor
  16. */
  17. function __construct() {
  18. $widget_ops = array(
  19. 'classname' => 'widget_contact_info',
  20. 'description' => __( 'Display a map with your location, hours, and contact information.', 'jetpack' ),
  21. 'customize_selective_refresh' => true,
  22. );
  23. parent::__construct(
  24. 'widget_contact_info',
  25. /** This filter is documented in modules/widgets/facebook-likebox.php */
  26. apply_filters( 'jetpack_widget_name', __( 'Contact Info & Map', 'jetpack' ) ),
  27. $widget_ops
  28. );
  29. $this->alt_option_name = 'widget_contact_info';
  30. if ( is_customize_preview() ) {
  31. add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
  32. }
  33. }
  34. /**
  35. * Enqueue scripts and styles.
  36. */
  37. public function enqueue_scripts() {
  38. wp_enqueue_style( 'contact-info-map-css', plugins_url( 'contact-info/contact-info-map.css', __FILE__ ), null, 20160623 );
  39. }
  40. /**
  41. * Return an associative array of default values
  42. *
  43. * These values are used in new widgets.
  44. *
  45. * @return array Array of default values for the Widget's options
  46. */
  47. public function defaults() {
  48. return array(
  49. 'title' => __( 'Hours & Info', 'jetpack' ),
  50. 'address' => __( "3999 Mission Boulevard,\nSan Diego CA 92109", 'jetpack' ),
  51. 'phone' => _x( '1-202-555-1212', 'Example of a phone number', 'jetpack' ),
  52. 'hours' => __( "Lunch: 11am - 2pm \nDinner: M-Th 5pm - 11pm, Fri-Sat:5pm - 1am", 'jetpack' ),
  53. 'email' => null,
  54. 'showmap' => 0,
  55. 'apikey' => null,
  56. 'lat' => null,
  57. 'lon' => null
  58. );
  59. }
  60. /**
  61. * Outputs the HTML for this widget.
  62. *
  63. * @param array $args An array of standard parameters for widgets in this theme
  64. * @param array $instance An array of settings for this widget instance
  65. *
  66. * @return void Echoes it's output
  67. **/
  68. function widget( $args, $instance ) {
  69. $instance = wp_parse_args( $instance, $this->defaults() );
  70. echo $args['before_widget'];
  71. if ( '' != $instance['title'] ) {
  72. echo $args['before_title'] . $instance['title'] . $args['after_title'];
  73. }
  74. /**
  75. * Fires at the beginning of the Contact Info widget, after the title.
  76. *
  77. * @module widgets
  78. *
  79. * @since 3.9.2
  80. */
  81. do_action( 'jetpack_contact_info_widget_start' );
  82. echo '<div itemscope itemtype="http://schema.org/LocalBusiness">';
  83. if ( '' != $instance['address'] ) {
  84. $showmap = $instance['showmap'];
  85. /** This action is documented in modules/widgets/contact-info.php */
  86. if ( $showmap && $this->has_good_map( $instance ) ) {
  87. /**
  88. * Set a Google Maps API Key.
  89. *
  90. * @since 4.1.0
  91. *
  92. * @param string $api_key Google Maps API Key
  93. */
  94. $api_key = apply_filters( 'jetpack_google_maps_api_key', $instance['apikey'] );
  95. echo $this->build_map( $instance['address'], $api_key );
  96. }
  97. $map_link = $this->build_map_link( $instance['address'] );
  98. echo '<div class="confit-address" itemscope itemtype="http://schema.org/PostalAddress" itemprop="address"><a href="' . esc_url( $map_link ) . '" target="_blank">' . str_replace( "\n", "<br/>", esc_html( $instance['address'] ) ) . "</a></div>";
  99. }
  100. if ( '' != $instance['phone'] ) {
  101. if ( wp_is_mobile() ) {
  102. echo '<div class="confit-phone"><span itemprop="telephone"><a href="' . esc_url( 'tel:' . $instance['phone'] ) . '">' . esc_html( $instance['phone'] ) . "</a></span></div>";
  103. }
  104. else {
  105. echo '<div class="confit-phone"><span itemprop="telephone">' . esc_html( $instance['phone'] ) . '</span></div>';
  106. }
  107. }
  108. if ( is_email( trim( $instance['email'] ) ) ) {
  109. printf(
  110. '<div class="confit-email"><a href="mailto:%1$s">%1$s</a></div>',
  111. esc_html( $instance['email'] )
  112. );
  113. }
  114. if ( '' != $instance['hours'] ) {
  115. echo '<div class="confit-hours" itemprop="openingHours">' . str_replace( "\n", "<br/>", esc_html( $instance['hours'] ) ) . "</div>";
  116. }
  117. echo '</div>';
  118. /**
  119. * Fires at the end of Contact Info widget.
  120. *
  121. * @module widgets
  122. *
  123. * @since 3.9.2
  124. */
  125. do_action( 'jetpack_contact_info_widget_end' );
  126. echo $args['after_widget'];
  127. /** This action is documented in modules/widgets/gravatar-profile.php */
  128. do_action( 'jetpack_stats_extra', 'widget_view', 'contact_info' );
  129. }
  130. /**
  131. * Deals with the settings when they are saved by the admin. Here is
  132. * where any validation should be dealt with.
  133. *
  134. * @param array $new_instance New configuration values
  135. * @param array $old_instance Old configuration values
  136. *
  137. * @return array
  138. */
  139. function update( $new_instance, $old_instance ) {
  140. $update_lat_lon = false;
  141. if (
  142. ! isset( $old_instance['address'] ) ||
  143. $this->urlencode_address( $old_instance['address'] ) != $this->urlencode_address( $new_instance['address'] )
  144. ) {
  145. $update_lat_lon = true;
  146. }
  147. $instance = array();
  148. $instance['title'] = wp_kses( $new_instance['title'], array() );
  149. $instance['address'] = wp_kses( $new_instance['address'], array() );
  150. $instance['phone'] = wp_kses( $new_instance['phone'], array() );
  151. $instance['email'] = wp_kses( $new_instance['email'], array() );
  152. $instance['hours'] = wp_kses( $new_instance['hours'], array() );
  153. $instance['apikey'] = wp_kses( isset( $new_instance['apikey'] ) ? $new_instance['apikey'] : $old_instance['apikey'], array() );
  154. $instance['lat'] = isset( $old_instance['lat'] ) ? floatval( $old_instance['lat'] ) : 0;
  155. $instance['lon'] = isset( $old_instance['lon'] ) ? floatval( $old_instance['lon'] ) : 0;
  156. if ( ! $instance['lat'] || ! $instance['lon'] ) {
  157. $update_lat_lon = true;
  158. }
  159. if ( $instance['address'] && $update_lat_lon ) {
  160. // Get the lat/lon of the user specified address.
  161. $address = $this->urlencode_address( $instance['address'] );
  162. $path = "https://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=" . $address;
  163. /** This action is documented in modules/widgets/contact-info.php */
  164. $key = apply_filters( 'jetpack_google_maps_api_key', $instance['apikey'] );
  165. if ( ! empty( $key ) ) {
  166. $path = add_query_arg( 'key', $key, $path );
  167. }
  168. $json = wp_remote_retrieve_body( wp_remote_get( esc_url( $path, null, null ) ) );
  169. if ( ! $json ) {
  170. // The read failed :(
  171. 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' );
  172. die();
  173. }
  174. $json_obj = json_decode( $json );
  175. if ( "ZERO_RESULTS" == $json_obj->status ) {
  176. // The address supplied does not have a matching lat / lon.
  177. // No map is available.
  178. $instance['lat'] = "0";
  179. $instance['lon'] = "0";
  180. }
  181. else {
  182. $loc = $json_obj->results[0]->geometry->location;
  183. $lat = floatval( $loc->lat );
  184. $lon = floatval( $loc->lng );
  185. $instance['lat'] = "$lat";
  186. $instance['lon'] = "$lon";
  187. }
  188. }
  189. if ( ! isset( $new_instance['showmap'] ) ) {
  190. $instance['showmap'] = 0;
  191. }
  192. else {
  193. $instance['showmap'] = intval( $new_instance['showmap'] );
  194. }
  195. return $instance;
  196. }
  197. /**
  198. * Displays the form for this widget on the Widgets page of the WP Admin area.
  199. *
  200. * @param array $instance Instance configuration.
  201. *
  202. * @return void
  203. */
  204. function form( $instance ) {
  205. $instance = wp_parse_args( $instance, $this->defaults() );
  206. wp_enqueue_script(
  207. 'contact-info-admin',
  208. Jetpack::get_file_url_for_environment(
  209. '_inc/build/widgets/contact-info/contact-info-admin.min.js',
  210. 'modules/widgets/contact-info/contact-info-admin.js'
  211. ),
  212. array( 'jquery' ),
  213. 20160727
  214. );
  215. ?>
  216. <p>
  217. <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php esc_html_e( 'Title:', 'jetpack' ); ?></label>
  218. <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $instance['title'] ); ?>" />
  219. </p>
  220. <p>
  221. <label for="<?php echo esc_attr( $this->get_field_id( 'address' ) ); ?>"><?php esc_html_e( 'Address:', 'jetpack' ); ?></label>
  222. <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>
  223. <?php
  224. if ( $this->has_good_map( $instance ) ) {
  225. ?>
  226. <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 ); ?> />
  227. <label for="<?php echo esc_attr( $this->get_field_id( 'showmap' ) ); ?>"><?php esc_html_e( 'Show map', 'jetpack' ); ?></label>
  228. <?php
  229. }
  230. else {
  231. ?>
  232. <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>
  233. <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" />
  234. <?php
  235. }
  236. ?>
  237. </p>
  238. <p class="jp-contact-info-apikey" style="<?php echo $instance['showmap'] ? '' : 'display: none;'; ?>">
  239. <label for="<?php echo esc_attr( $this->get_field_id( 'apikey' ) ); ?>">
  240. <?php _e( 'Google Maps API Key', 'jetpack' ); ?>
  241. <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'] ); ?>" />
  242. <br />
  243. <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>
  244. </label>
  245. </p>
  246. <p>
  247. <label for="<?php echo esc_attr( $this->get_field_id( 'phone' ) ); ?>"><?php esc_html_e( 'Phone:', 'jetpack' ); ?></label>
  248. <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'] ); ?>" />
  249. </p>
  250. <p>
  251. <label for="<?php echo esc_attr( $this->get_field_id( 'email' ) ); ?>"><?php esc_html_e( 'Email Address:', 'jetpack' ); ?></label>
  252. <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'email' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'email' ) ); ?>" type="text" value="<?php echo esc_attr( $instance['email'] ); ?>" />
  253. </p>
  254. <p>
  255. <label for="<?php echo esc_attr( $this->get_field_id( 'hours' ) ); ?>"><?php esc_html_e( 'Hours:', 'jetpack' ); ?></label>
  256. <textarea class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'hours' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'hours' ) ); ?>"><?php echo esc_textarea( $instance['hours'] ); ?></textarea>
  257. </p>
  258. <?php
  259. }
  260. /**
  261. * Generate a Google Maps link for the supplied address.
  262. *
  263. * @param string $address Address to link to.
  264. *
  265. * @return string
  266. */
  267. function build_map_link( $address ) {
  268. // Google map urls have lots of available params but zoom (z) and query (q) are enough.
  269. return "https://maps.google.com/maps?z=16&q=" . $this->urlencode_address( $address );
  270. }
  271. /**
  272. * Builds map display HTML code from the supplied latitude and longitude.
  273. *
  274. * @param float $lat Map Latitude
  275. * @param float $lon Map Longitude
  276. *
  277. * @return string HTML of the map
  278. */
  279. function build_map( $address, $api_key = null ) {
  280. $this->enqueue_scripts();
  281. $src = add_query_arg( 'q', urlencode( $address ), 'https://www.google.com/maps/embed/v1/place' );
  282. if ( ! empty( $api_key ) ) {
  283. $src = add_query_arg( 'key', $api_key, $src );
  284. }
  285. return '<iframe width="600" height="216" frameborder="0" src="' . esc_url( $src ) . '" class="contact-map"></iframe>';
  286. }
  287. /**
  288. * Encode an URL
  289. *
  290. * @param string $address The URL to encode
  291. *
  292. * @return string The encoded URL
  293. */
  294. function urlencode_address( $address ) {
  295. $address = strtolower( $address );
  296. $address = preg_replace( "/\s+/", " ", trim( $address ) ); // Get rid of any unwanted whitespace
  297. $address = str_ireplace( " ", "+", $address ); // Use + not %20
  298. urlencode( $address );
  299. return $address;
  300. }
  301. /**
  302. * Check if the instance has a valid Map location.
  303. *
  304. * @param array $instance Widget instance configuration.
  305. *
  306. * @return bool Whether or not there is a valid map.
  307. */
  308. function has_good_map( $instance ) {
  309. // The lat and lon of an address that could not be plotted will have values of 0 and 0.
  310. return ! ( "0" == $instance['lat'] && "0" == $instance['lon'] );
  311. }
  312. }
  313. }