Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/geo-mashup/geo-mashup.php
+++ b/geo-mashup/geo-mashup.php
@@ -3,7 +3,7 @@
Plugin Name: Geo Mashup
Plugin URI: https://wordpress.org/plugins/geo-mashup/
Description: Save location for posts and pages, or even users and comments. Display these locations on Google, Leaflet, and OSM maps. Make WordPress into your GeoCMS.
-Version: 1.13.15
+Version: 1.13.16
Author: Dylan Kuhn
Text Domain: GeoMashup
Domain Path: /lang
@@ -256,7 +256,7 @@
define('GEO_MASHUP_DIRECTORY', dirname( GEO_MASHUP_PLUGIN_NAME ) );
define('GEO_MASHUP_URL_PATH', trim( plugin_dir_url( __FILE__ ), '/' ) );
define('GEO_MASHUP_MAX_ZOOM', 20);
- define('GEO_MASHUP_VERSION', '1.13.15');
+ define('GEO_MASHUP_VERSION', '1.13.16');
define('GEO_MASHUP_DB_VERSION', '1.3');
}
--- a/geo-mashup/trunk/default-templates/comment.php
+++ b/geo-mashup/trunk/default-templates/comment.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * This is the default template for the comment info window in Geo Mashup maps.
+ *
+ * Don't modify this file! It will be overwritten by upgrades.
+ *
+ * Instead, copy this file to "geo-mashup-comment.php" in your theme directory,
+ * or "comment.php" in the Geo Mashup Custom plugin directory, if you have that
+ * installed. Those files take precedence over this one.
+ *
+ * For styling of the info window, see map-style-default.css.
+ *
+ * @package GeoMashup
+ */
+?>
+<div class="locationinfo comment-location-info">
+<?php if ( GeoMashupQuery::have_comments() ) : ?>
+
+ <?php GeoMashupQuery::list_comments( 'callback=geo_mashup_comment_default' ); ?>
+
+<?php else : ?>
+
+ <h2 class="center">Not Found</h2>
+ <p class="center">Sorry, but you are looking for something that isn't here.</p>
+
+<?php endif; ?>
+
+</div>
+<?php
+/**
+ * Template callback for GeoMashupQuery::list_comments()
+ *
+ * Use the newer form of template, where the individual comment template goes in
+ * a function that matches the callback argument to list_comments
+ *
+ * @since 1.3
+ * @access public
+ * @package GeoMashup
+ *
+ * @param object $comment The comment to display
+ * @param array $args Arguments from wp_list_comments
+ * @param mixed $depth Nested depth
+ */
+function geo_mashup_comment_default( $comment, $args, $depth ) {
+ // Enable the WordPress comment functions
+ GeoMashupQuery::set_the_comment( $comment );
+ // From here to the closing curly brace should look like a familiar template
+?>
+ <div id="div-comment-<?php comment_ID() ?>" class="<?php comment_class(''); ?>">
+ <div class="comment-author vcard">
+ <?php printf(__('<cite class="fn">%s</cite> <span class="says">says:</span>'), get_comment_author_link()) ?>
+ </div>
+ <div class="comment-meta commentmetadata">
+ <a href="<?php echo esc_html( get_comment_link( $comment->comment_ID ) ) ?>"><?php printf(__('%1$s at %2$s'), get_comment_date(), get_comment_time()) ?></a>
+ </div>
+ <?php comment_text() ?>
+
+ </div>
+<?php } ?>
--- a/geo-mashup/trunk/default-templates/full-post.php
+++ b/geo-mashup/trunk/default-templates/full-post.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * This is the default template for full post display of a clicked marker
+ * in a Geo Mashup map.
+ *
+ * Don't modify this file! It will be overwritten by upgrades.
+ *
+ * Instead, copy this file to "full-post.php" in your geo-mashup-custom directory,
+ * or "geo-mashup-full-post.php" in your theme directory. Those files will
+ * take precedence over this one.
+ *
+ * @package GeoMashup
+ */
+?>
+<?php if (have_posts()) : ?>
+
+ <?php while (have_posts()) : the_post(); ?>
+
+ <h2><a href="<?php the_permalink() ?>" title="<?php the_title_attribute(); ?>"><?php the_title(); ?></a></h2>
+ <p class="meta"><span class="blogdate"><?php echo get_the_date(); ?></span> <?php the_category( ', ' ) ?></p>
+ <?php if ( function_exists( 'has_post_thumbnail') and has_post_thumbnail() ) : ?>
+ <?php the_post_thumbnail(); ?>
+ <?php endif; ?>
+
+ <div class="storycontent">
+ <?php the_content(); ?>
+ </div>
+
+ <?php endwhile; ?>
+
+<?php else : ?>
+
+ <h2 class="center">Not Found</h2>
+ <p class="center">Sorry, but you are looking for something that isn't here.</p>
+
+<?php endif; ?>
--- a/geo-mashup/trunk/default-templates/info-window-max.php
+++ b/geo-mashup/trunk/default-templates/info-window-max.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * This is the default template for the maximized info window display of a clicked marker
+ * in a Geo Mashup map.
+ *
+ * Don't modify this file! It will be overwritten by upgrades.
+ *
+ * Instead, copy this file to "info-window-max.php" in your geo-mashup-custom directory,
+ * or "geo-mashup-info-window-max.php" in your theme directory. Those files will
+ * take precedence over this one.
+ *
+ * @package GeoMashup
+ */
+
+// Avoid nested maps
+add_filter( 'the_content', array( 'GeoMashupQuery', 'strip_map_shortcodes' ), 1, 9 );
+?>
+<div class="info-window-max">
+<?php if (have_posts()) : ?>
+
+ <?php while (have_posts()) : the_post(); ?>
+
+ <h2><a href="<?php the_permalink() ?>" title="<?php the_title_attribute(); ?>"><?php the_title(); ?></a></h2>
+ <p class="meta"><span class="blogdate"><?php echo get_the_date(); ?></span> <?php the_category( ', ' ) ?></p>
+ <?php if ( function_exists( 'has_post_thumbnail') and has_post_thumbnail() ) : ?>
+ <?php the_post_thumbnail(); ?>
+ <?php endif; ?>
+
+ <div class="storycontent">
+ <?php the_content(); ?>
+ </div>
+
+ <?php endwhile; ?>
+
+<?php else : ?>
+
+ <h2 class="center">Not Found</h2>
+ <p class="center">Sorry, but you are looking for something that isn't here.</p>
+
+<?php endif; ?>
+</div>
--- a/geo-mashup/trunk/default-templates/info-window.php
+++ b/geo-mashup/trunk/default-templates/info-window.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * This is the default template for the info window in Geo Mashup maps.
+ *
+ * Don't modify this file! It will be overwritten by upgrades.
+ *
+ * Instead, copy this file to "geo-mashup-info-window.php" in your theme directory,
+ * or info-window.php in the Geo Mashup Custom plugin directory, if you have that
+ * installed. Those files take precedence over this one.
+ *
+ * For styling of the info window, see map-style-default.css.
+ *
+ * @package GeoMashup
+ */
+
+add_filter( 'post_thumbnail_size', [ 'GeoMashupQuery', 'post_thumbnail_size' ]);
+
+// A potentially heavy-handed way to remove shortcode-like content
+add_filter( 'the_excerpt', array( 'GeoMashupQuery', 'strip_brackets' ) );
+?>
+<div class="locationinfo post-location-info">
+<?php if (have_posts()) : ?>
+
+ <?php while (have_posts()) : the_post(); ?>
+
+ <h2><a href="<?php the_permalink() ?>" title="<?php the_title_attribute(); ?>"><?php the_title(); ?></a></h2>
+ <p class="meta"><span class="blogdate"><?php echo get_the_date(); ?></span> <?php the_category( ', ' ) ?></p>
+ <?php if ( function_exists( 'has_post_thumbnail') and has_post_thumbnail() ) : ?>
+ <?php the_post_thumbnail(); ?>
+ <?php endif; ?>
+
+ <?php if ($wp_query->post_count == 1) : ?>
+ <div class="storycontent">
+ <?php the_excerpt(); ?>
+ </div>
+ <?php endif; ?>
+
+ <?php endwhile; ?>
+
+<?php else : ?>
+
+ <h2 class="center">Not Found</h2>
+ <p class="center">Sorry, but you are looking for something that isn't here.</p>
+
+<?php endif; ?>
+
+</div>
--- a/geo-mashup/trunk/default-templates/map-frame.php
+++ b/geo-mashup/trunk/default-templates/map-frame.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * This is the default template for map frames.
+ *
+ * Don't modify this file! It will be overwritten by upgrades.
+ *
+ * Instead, copy this file to "geo-mashup-map-frame.php" in your theme directory,
+ * or map-frame.php in the Geo Mashup Custom plugin directory, if you have that
+ * installed. Those files take precedence over this one.
+ *
+ * For styling of map elements, see map-style-default.dev.css.
+ *
+ * Map properties include height, width, and name (see the style tag for example).
+ *
+ * Individual registered scripts can be added with code like
+ *
+ * <code>GeoMashupRenderMap::enqueue_script( 'colorbox' );</code>
+ *
+ * Or include all queued resources by replacing
+ *
+ * <code>GeoMashupRenderMap::head();</code>
+ *
+ * with
+ *
+ * <code>wp_head();</code>
+ *
+ * @package GeoMashup
+ */
+?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
+ <title>Geo Mashup Map</title>
+ <?php GeoMashupRenderMap::head(); ?>
+
+ <style type="text/css">
+ v:* { behavior:url(#default#VML); }
+ #geo-mashup {
+ width:100%;
+ height:100%;
+ <?php if ( GeoMashupRenderMap::map_property( 'background_color' ) ) : ?>
+ background-color: <?php echo esc_attr( GeoMashupRenderMap::map_property( 'background_color' ) ); ?>;
+ <?php endif; ?>
+ }
+ </style>
+ </head>
+ <body>
+ <div id="geo-mashup" class="<?php echo esc_attr( GeoMashupRenderMap::map_property( 'name' ) ); ?>">
+ <noscript>
+ <p><?php _e( 'This map requires JavaScript. You may have to enable it in your browser's settings.', 'GeoMashup' ); ?></p>
+ </noscript>
+ </div>
+ <?php echo GeoMashupRenderMap::map_script( 'geo-mashup' ); ?>
+ </body>
+</html>
--- a/geo-mashup/trunk/default-templates/nearby-list.php
+++ b/geo-mashup/trunk/default-templates/nearby-list.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * Default Geo Mashup Search nearby posts template.
+ *
+ * THIS FILE WILL BE OVERWRITTEN BY AUTOMATIC UPGRADES
+ * See the geo-mashup-search.php plugin file for license
+ *
+ * Copy this to a file named geo-mashup-nearby-list.php in your active theme folder
+ * to customize. For bonus points delete this message in the copy!
+ *
+ * Variables in scope:
+ * $geo_mashup_search object The managing search object
+ * $search_text string The search text entered in the form
+ * $radius int The search radius
+ * $units string 'mi' or 'km' or 'nm'
+ * $object_name string 'post' or 'user' or 'comment'
+ * $near_location array The location searched, including 'lat' and 'lng'
+ * $distance_factor float The multiplier to convert the radius to kilometers
+ * $approximate_zoom int A guess at a zoom level that will include all results
+ *
+ * Methods of $geo_mashup_search mimic WordPress Loop functions have_posts()
+ * and the_post() (see http://codex.wordpress.org/The_Loop). This makes post
+ * template functions like the_title() work as expected. For distance:
+ *
+ * $geo_mashup_search->the_distance();
+ *
+ * will echo the distance with units. Its output can be modified:
+ *
+ * $geo_mashup_search->the_distance( 'decimal_places=1&append_units=0&echo=0' );
+ */
+?>
+<?php if ( $geo_mashup_search->have_posts() ) : ?>
+
+ <aside>
+ <?php if ($object_name == 'post'): ?>
+ <h1><?php _e( 'Posts Nearby', 'GeoMashup' ); ?></h1>
+ <?php elseif ($object_name == 'user'):?>
+ <h1><?php _e( 'Users Nearby', 'GeoMashup' ); ?></h1>
+ <?php endif; ?>
+ <ul class="geo-mashup-nearby-posts">
+
+ <?php if ($object_name == 'post'):?>
+
+ <?php while ( $geo_mashup_search->have_posts() ) : $geo_mashup_search->the_post(); ?>
+ <li>
+ <a href="<?php the_permalink(); ?>" title=""><?php the_title(); ?></a>
+ <span class="distance"><?php $geo_mashup_search->the_distance(); ?></span>
+ </li>
+ <?php endwhile; ?>
+
+ <?php elseif ($object_name == 'user'):?>
+
+ <?php while ( $geo_mashup_search->have_posts() ) : $user=$geo_mashup_search->get_userdata(); ?>
+ <li>
+ <?php echo $user->first_name.' '.$user->last_name;?> aka <?php echo $user->user_nicename?>
+ <span class="distance"><?php $geo_mashup_search->the_distance(); ?></span>
+ </li>
+ <?php endwhile; ?>
+
+ <?php endif; ?>
+
+ </ul>
+ </aside>
+
+<?php endif; ?>
--- a/geo-mashup/trunk/default-templates/search-form.php
+++ b/geo-mashup/trunk/default-templates/search-form.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * Default Geo Mashup Search widget form template.
+ *
+ * THIS FILE WILL BE OVERWRITTEN BY AUTOMATIC UPGRADES
+ * See the geo-mashup-search.php plugin file for license
+ *
+ * Copy this to a file named geo-mashup-search-form.php in your active theme folder
+ * to customize. For bonus points delete this message in the copy!
+ *
+ * Variables in scope:
+ * $widget object The widget generating this form
+ * $widget_id string The unique widget identifier
+ * $instance array The widget instance data
+ * $action_url string The URL of the page chosen to display results
+ * $categories array Terms objects to include in the category menu, if any.
+ * $radii array Radius distances to include in the radius menu, if any.
+ */
+?>
+<form class="geo-mashup-search-form" method="post" action="<?php echo $action_url; ?>">
+ <input name="results_page_id" type="hidden" value="<?php echo esc_attr( $instance['results_page_id'] ); ?>" />
+ <input name="units" type="hidden" value="<?php echo esc_attr( $instance['units'] ); ?>" />
+ <div class="Location clear">
+ <label for="<?php echo $widget_id; ?>-input"><?php _e('Location','GeoMashup' ) ?>:</label>
+ <input id="<?php echo $widget_id; ?>-input" class="geo-mashup-search-input" name="location_text" type="search"
+ placeholder="<?php if ( !empty( $_POST['location_text'] ) ) { echo esc_attr( $_POST['location_text'] ); } else if ( !empty( $instance['default_search_text'] ) ) {echo esc_attr( $instance['default_search_text'] );} ?>"
+ value=""/>
+ </div>
+ <div class="object clear">
+ <?php
+ if($instance['object_name'] === 'user' || $instance['object_name'] === 'comment') : ?>
+ <input name="object_name" type="hidden" value="<?php echo esc_attr( $instance['object_name'] ); ?>" />
+ </div><!-- .object -->
+ <?php else : ?>
+ <input name="object_name" type="hidden" value="post" />
+ <input name="map_post_type" type="hidden" value="<?php echo esc_attr( $instance['object_name'] ); ?>" />
+ </div><!-- .object -->
+
+ <?php if ( !empty( $categories ) ) : ?>
+ <?php if ( $categories === 'all' ) : ?>
+ <div class="taxonomy clear">
+ <input name="taxonomy" type="hidden" value="<?php echo $widget->get_default_value($instance, 'taxonomy', 'category'); ?>" />
+ <input name="map_terms" type="hidden" value="<?php echo $categories; ?>" />
+ </div><!-- .taxonomy -->
+ <?php else: // $taxonomy_terms ?>
+ <div class="taxonomy clear">
+ <input name="taxonomy" type="hidden" value="<?php echo $widget->get_default_value($instance, 'taxonomy', 'category'); ?>" />
+ <label for="<?php echo $widget_id; ?>-categories"><?php _e( 'Category', 'GeoMashup' ); ?>:</label>
+ <select id="<?php echo $widget_id; ?>-categories" name="map_terms">
+ <?php foreach ( $categories as $term ) : ?>
+ <option value="<?php echo $term->term_id; ?>"<?php
+ if ( $widget->get_default_value( $_POST, 'map_terms' ) == $term->term_id ) echo ' selected="selected"'; ?>>
+ <?php echo $term->name; ?>
+ </option>
+ <?php endforeach; ?>
+ </select>
+ </div><!-- .taxonomy -->
+ <?php endif; ?>
+ <?php endif; // $taxonomy_terms ?>
+
+ <?php endif; ?>
+ <?php if ( !empty( $radii ) ) : ?>
+ <div class="radius clear">
+ <label for="<?php echo $widget_id; ?>-radius"><?php echo ucfirst(__( 'within', 'GeoMashup' )); ?>:</label>
+ <select id="<?php echo $widget_id; ?>-radius" name="radius">
+ <?php foreach ( $radii as $radius ) : ?>
+ <option value="<?php echo $radius; ?>"<?php
+ if ( $widget->get_default_value( $_POST, 'radius' ) == $radius )
+ echo ' selected="selected"';
+ ?>><?php echo $radius; ?> <?php echo esc_html( $instance['units'] ); ?></option>
+ <?php endforeach; ?>
+ </select>
+ </div>
+ <?php endif; // Radius ?>
+ <div class="submit">
+ <input id="<?php echo $widget_id; ?>-submit" name="geo_mashup_search_submit" type="submit" value="<?php _e( 'Search', 'GeoMashup' ); ?>" />
+ <?php if ( !empty( $instance['find_me_button'] ) ) : ?>
+ <input name="geolocation" type="hidden" value="" />
+ <button id="<?php echo $widget_id; ?>-find-me" class="geo-mashup-search-find-me" style="display:none;"><?php echo $instance['find_me_button']; ?></button>
+ <?php endif; ?>
+ </div>
+</form>
No newline at end of file
--- a/geo-mashup/trunk/default-templates/search-results.php
+++ b/geo-mashup/trunk/default-templates/search-results.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * Default Geo Mashup Search results template.
+ *
+ * THIS FILE WILL BE OVERWRITTEN BY AUTOMATIC UPGRADES
+ * See the geo-mashup-search.php plugin file for license
+ *
+ * Copy this to a file named geo-mashup-search-results.php in your active theme folder
+ * to customize. For bonus points delete this message in the copy!
+ *
+ * Variables in scope:
+ * @var $geo_mashup_search object The managing search object
+ * @var $result_count int The number of objects found
+ * @var $search_text string The search text entered in the form
+ * @var $radius int The search radius
+ * @var $units string 'mi' or 'km' or 'nm'
+ * @var $object_name string 'post' or 'user' or 'comment'
+ * @var $near_location array The location searched, including 'lat' and 'lng'
+ * @var $distance_factor float The multiplier to convert the radius to kilometers
+ * @var $approximate_zoom int A guess at a zoom level that will include all results
+ *
+ * Methods of $geo_mashup_search mimic WordPress Loop functions have_posts()
+ * and the_post() (see http://codex.wordpress.org/The_Loop). This makes post
+ * template functions like the_title() work as expected. For distance:
+ *
+ * $geo_mashup_search->the_distance();
+ *
+ * will echo the distance with units. Its output can be modified:
+ *
+ * $geo_mashup_search->the_distance( 'decimal_places=1&append_units=0&echo=0' );
+ */
+?>
+<div id="geo-mashup-search-results">
+
+ <h2><?php printf( __( 'Search results near "%s"', 'GeoMashup' ), esc_html( $search_text ) ); ?></h2>
+
+ <?php if ( $geo_mashup_search->have_posts() ) : ?>
+
+ <?php echo GeoMashup::map( array(
+ 'name' => 'search-results-map',
+ 'search_text' => $search_text,
+ 'object_ids' => $geo_mashup_search->get_the_ID_list(),
+ 'center_lat' => $near_location['lat'],
+ 'center_lng' => $near_location['lng'],
+ 'search_lat' => $near_location['lat'],
+ 'search_lng' => $near_location['lng'],
+ 'map_content' => 'global',
+ 'object_name'=> $object_name,
+ 'zoom' => $approximate_zoom + 1 // Adjust to taste
+ ) ); ?>
+
+ <?php if ($object_name == 'post'):?>
+
+ <?php while ( $geo_mashup_search->have_posts() ) : $geo_mashup_search->the_post(); ?>
+ <div class="search-result">
+ <h3><a href="<?php the_permalink(); ?>" title=""><?php the_title(); ?></a></h3>
+ <p><?php the_excerpt(); ?></p>
+ <p>
+ <?php _e( 'Distance', 'GeoMashup' ); ?>:
+ <?php $geo_mashup_search->the_distance(); ?>
+ </p>
+ </div>
+ <?php endwhile; ?>
+ <?php elseif ($object_name == 'user'):?>
+
+ <?php while ( $geo_mashup_search->have_posts() ) : $user=$geo_mashup_search->get_userdata(); ?>
+ <div class="search-result">
+ <h3><?php echo $user->first_name.' '.$user->last_name;?> aka <?php echo $user->user_nicename?></h3>
+ <p>
+ <?php _e( 'Distance', 'GeoMashup' ); ?>:
+ <?php $geo_mashup_search->the_distance(); ?>
+ </p>
+ </div>
+ <?php endwhile; ?>
+ <?php endif;?>
+ <?php else : ?>
+
+ <p><?php _e( 'No results found.', 'GeoMashup' ); ?></p>
+
+ <?php endif; ?>
+</div>
--- a/geo-mashup/trunk/default-templates/user.php
+++ b/geo-mashup/trunk/default-templates/user.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * This is the default template for the User info window in Geo Mashup maps.
+ *
+ * Don't modify this file! It will be overwritten by upgrades.
+ *
+ * Instead, copy this file to "geo-mashup-user.php" in your theme directory,
+ * or "user.php" in the Geo Mashup Custom plugin directory, if you have that
+ * installed. Those files take precedence over this one.
+ *
+ * For styling of the info window, see map-style-default.css.
+ *
+ * @package GeoMashup
+ */
+?>
+<div class="locationinfo user-location-info">
+<?php if ( GeoMashupQuery::have_users() ) : ?>
+
+<?php GeoMashupQuery::list_users( 'callback=geo_mashup_user_default_template' ); ?>
+
+<?php else : ?>
+
+ <h2 class="center">Not Found</h2>
+ <p class="center">Sorry, but you are looking for something that isn't here.</p>
+
+<?php endif; ?>
+</div>
+<?php
+/**
+ * Template callback for GeoMashupQuery::list_users()
+ *
+ * @since 1.3
+ * @package GeoMashup
+ * @param object $user The user to display.
+ */
+function geo_mashup_user_default_template( $user ) {
+ GeoMashupQuery::set_the_user( $user );
+?>
+<div id="div-user-<?php echo esc_attr( $user->ID ); ?>" class="vcard">
+ <div class="fn">
+ <span class="type"><?php _e( 'Display Name' ); ?></span>: <span class="value"><?php echo esc_attr( $user->display_name ); ?></span>
+ </div>
+ <?php echo GeoMashup::location_info( 'fields=locality_name,admin_code&format=<div class="adr"><span class="locality">%s</span>, <span class="region">%s</span></div>' ); ?>
+ <?php if ( isset( $user->user_url ) && strlen( $user->user_url ) > 7 ) : ?>
+ <div class="url">
+ <span class="type"><?php _e( 'Website' ); ?></span>: <a class="value" href="<?php echo esc_attr( $user->user_url ); ?>"><?php echo esc_attr( $user->user_url ); ?></a>
+ </div>
+ <?php endif; ?>
+</div>
+<?php } ?>
+
--- a/geo-mashup/trunk/edit-form.php
+++ b/geo-mashup/trunk/edit-form.php
@@ -0,0 +1,237 @@
+<?php
+/**
+ * A function wrapper for the location editor HTML.
+ *
+ * @package GeoMashup
+ */
+
+/**
+ * Print the Geo Mashup location editor HTML for an object.
+ *
+ * Goals for this interface are to make it usable for any kind of locatable
+ * object, to be usable without javascript, functional on the front end or admin,
+ * and eventually adaptable to editing multiple locations for an object.
+ *
+ * It's assumed this will go inside an existing form for editing the object,
+ * such as the WordPress admin post edit form.
+ *
+ * @since 1.2
+ * @see geo-mashup-ui-managers.php
+ * @see geo-mashup-location-editor.js
+ * @uses edit-form.css
+ * @access public
+ *
+ * @param string $object_name The type of object, e.g. 'post', 'user', etc.
+ * @param string $object_id The ID of the object being edited.
+ * @param string $ui_manager Optionally the name of UI Manager class to use for AJAX operations.
+ */
+function geo_mashup_edit_form( $object_name, $object_id, $ui_manager = '' ) {
+ global $geo_mashup_options;
+
+ $help_class = 'geo-mashup-js';
+ $add_input_style = 'style="display:none;"';
+ $update_input_style = $delete_input_style = '';
+ $coordinate_string = '';
+
+ // Load any existing location for the object
+ $location = GeoMashupDB::get_object_location( $object_name, $object_id );
+ if ( empty( $location ) ) {
+ $location = GeoMashupDB::blank_object_location();
+ $help_class = '';
+ $add_input_style = '';
+ $update_input_style = $delete_input_style = 'style="display:none;"';
+ } else {
+ $coordinate_string = $location->lat . ',' . $location->lng;
+ }
+
+ $post_location_name = $location->saved_name;
+ $kml_url = '';
+
+ // Set a Geo date default when needed & possible
+ $date_missing = ( empty( $location->geo_date ) || '0000-00-00 00:00:00' == $location->geo_date );
+ if ( 'post' == $object_name) {
+ if ( $date_missing ) {
+
+ // Geo date defaults to post date
+ $post = get_post( $object_id );
+ $location->geo_date = $post->post_date;
+ if ( !empty( $location->id ) ) {
+ GeoMashupDB::set_object_location( $object_name, $object_id, $location->id, false, $location->geo_date );
+ }
+
+ }
+
+ // For posts, look for a KML attachment
+ $kml_urls = GeoMashup::get_kml_attachment_urls( $object_id );
+ if (count($kml_urls)>0) {
+ $kml_url = array_pop($kml_urls);
+ }
+
+ } else if ( 'user' == $object_name && $date_missing ) {
+
+ // Geo date defaults to registration date
+ $user = get_userdata( $object_id );
+ $location->geo_date = $user->user_registered;
+ if ( !empty( $location->id ) ) {
+ GeoMashupDB::set_object_location( $object_name, $object_id, $location->id, false, $location->geo_date );
+ }
+
+ } else if ( 'comment' == $object_name && $date_missing ) {
+
+ // Geo date defaults to comment date
+ $comment = get_comment( $object_id );
+ $location->geo_date = $comment->comment_date;
+ if ( !empty( $location->id ) ) {
+ GeoMashupDB::set_object_location( $object_name, $object_id, $location->id, false, $location->geo_date );
+ }
+
+ }
+ if ( empty( $location->geo_date ) ) {
+ $location_datetime = mktime();
+ } else {
+ $location_datetime = strtotime( $location->geo_date );
+ }
+ $location_date = date( 'M j, Y', $location_datetime );
+ $location_hour = date( 'G', $location_datetime );
+ $location_minute = date( 'i', $location_datetime );
+
+ // Load saved locations
+ $saved_locations = GeoMashupDB::get_saved_locations( );
+ $saved_location_options = array();
+ if ( ! empty( $saved_locations ) ) {
+ foreach ( $saved_locations as $saved_location ) {
+ $escaped_name = str_replace( array( "rn", "r", "n" ), '', $saved_location->saved_name );
+ if ( $saved_location->id != $location->id )
+ $selected = '';
+ else
+ $selected = ' selected="selected"';
+ $saved_location_options[] = '<option value="' . esc_attr( $saved_location->id . '|' . $saved_location->lat . '|' .
+ $saved_location->lng . '|' . $saved_location->address ) . '"' . $selected . '>' . esc_html( $escaped_name ) . '</option>';
+ }
+ }
+ $saved_location_options = implode( '', $saved_location_options );
+
+ $nonce = wp_create_nonce('geo-mashup-edit');
+
+ $static_maps_base_url = 'http://maps.google.com/maps/api/staticmap?key=' .
+ $geo_mashup_options->get( 'overall', 'googlev3_key' );
+?>
+ <div id="geo_mashup_location_editor">
+ <div id="geo_mashup_ajax_message" class="geo-mashup-js ui-state-highlight"></div>
+ <input id="geo_mashup_nonce" name="geo_mashup_nonce" type="hidden" value="<?php echo $nonce; ?>" />
+ <input id="geo_mashup_changed" name="geo_mashup_changed" type="hidden" value="" />
+ <?php ob_start(); ?>
+ <table id="geo-mashup-location-table">
+ <thead class="ui-widget-header">
+ <tr>
+ <th><?php _e( 'Address', 'GeoMashup' ); ?></th>
+ <th><?php _e( 'Saved Name', 'GeoMashup' ); ?></th>
+ <th><?php _e( 'Geo Date', 'GeoMashup' ); ?></th>
+ </tr>
+ </thead>
+ <tbody class="ui-widget-content">
+ <tr id="geo_mashup_display" class="geo-mashup-display-row">
+ <td class="geo-mashup-info">
+ <div class="geo-mashup-address"><?php echo esc_html( $location->address ); ?></div>
+ <div class="geo-mashup-coordinates"><?php echo esc_attr( $coordinate_string ); ?></div>
+ </td>
+ <td id="geo_mashup_saved_name_ui">
+ <input id="geo_mashup_location_name" name="geo_mashup_location_name" size="50" type="text" value="<?php echo esc_attr( $post_location_name ); ?>" />
+ </td>
+ <td id="geo_mashup_date_ui">
+ <input id="geo_mashup_date" name="geo_mashup_date" type="text" size="20" value="<?php echo esc_attr( $location_date ); ?>" /><br />
+ @
+ <input id="geo_mashup_hour" name="geo_mashup_hour" type="text" size="2" maxlength="2" value="<?php echo esc_attr( $location_hour ); ?>" />
+ :
+ <input id="geo_mashup_minute" name="geo_mashup_minute" type="text" size="2" maxlength="2" value="<?php echo esc_attr( $location_minute ); ?>" />
+ </td>
+ <td id="geo_mashup_ajax_buttons">
+ </td>
+
+ </tr>
+ </tbody>
+ </table>
+ <?php $location_table_html = ob_get_clean(); ?>
+ <?php ob_start(); ?>
+ <div id="geo_mashup_map" class="geo-mashup-js">
+ <?php _e('Loading Google map. Check Geo Mashup options if the map fails to load.', 'GeoMashup'); ?>
+ </div>
+ <?php if ( ! empty( $location->id ) ) : ?>
+ <noscript>
+ <div id="geo_mashup_static_map">
+ <img src="<?php echo $static_maps_base_url; ?>&size=400x300&zoom=4&markers=size:small|color:green|<?php echo esc_attr( $location->lat . ',' . $location->lng ); ?>"
+ alt="<?php _e( 'Location Map Image', 'GeoMashup' ); ?>" />
+ </div>
+ </noscript>
+ <?php endif; ?>
+ <?php $map_html = ob_get_clean(); ?>
+ <?php ob_start(); ?>
+ <label for="geo_mashup_search"><?php _e('Find a new location:', 'GeoMashup'); ?>
+ <input id="geo_mashup_search" name="geo_mashup_search" type="text" size="35" />
+ </label>
+
+ <?php _e( 'or select from', 'GeoMashup' ); ?>
+ <select id="geo_mashup_select" name="geo_mashup_select">
+ <option value=""><?php _e('[Saved Locations]','GeoMashup'); ?></option>
+ <?php echo $saved_location_options; ?>
+ </select>
+ <?php $search_html = ob_get_clean(); ?>
+
+ <?php echo empty( $location->id ) ? $search_html . $map_html . $location_table_html : $location_table_html . $map_html . $search_html; ?>
+
+ <input id="geo_mashup_ui_manager" name="geo_mashup_ui_manager" type="hidden" value="<?php echo $ui_manager; ?>" />
+ <input id="geo_mashup_object_id" name="geo_mashup_object_id" type="hidden" value="<?php echo $object_id; ?>" />
+ <input id="geo_mashup_no_js" name="geo_mashup_no_js" type="hidden" value="true" />
+ <input id="geo_mashup_location_id" name="geo_mashup_location_id" type="hidden" value="<?php echo esc_attr( $location->id ); ?>" />
+ <input id="geo_mashup_location" name="geo_mashup_location" type="hidden" value="<?php echo esc_attr( $coordinate_string ); ?>" />
+ <input id="geo_mashup_geoname" name="geo_mashup_geoname" type="hidden" value="<?php echo esc_attr( $location->geoname ); ?>" />
+ <input id="geo_mashup_address" name="geo_mashup_address" type="hidden" value="<?php echo esc_attr( $location->address ); ?>" />
+ <input id="geo_mashup_postal_code" name="geo_mashup_postal_code" type="hidden" value="<?php echo esc_attr( $location->postal_code ); ?>" />
+ <input id="geo_mashup_country_code" name="geo_mashup_country_code" type="hidden" value="<?php echo esc_attr( $location->country_code ); ?>" />
+ <input id="geo_mashup_admin_code" name="geo_mashup_admin_code" type="hidden" value="<?php echo esc_attr( $location->admin_code ); ?>" />
+ <input id="geo_mashup_admin_name" name="geo_mashup_admin_name" type="hidden" value="" />
+ <input id="geo_mashup_kml_url" name="geo_mashup_kml_url" type="hidden" value="<?php echo $kml_url; ?>" />
+ <input id="geo_mashup_sub_admin_code" name="geo_mashup_sub_admin_code" type="hidden" value="<?php echo esc_attr( $location->sub_admin_code ); ?>" />
+ <input id="geo_mashup_sub_admin_name" name="geo_mashup_sub_admin_name" type="hidden" value="" />
+ <input id="geo_mashup_locality_name" name="geo_mashup_locality_name" type="hidden" value="<?php echo esc_attr( $location->locality_name ); ?>" />
+ <div id="geo_mashup_submit" class="submit">
+ <input id="geo_mashup_add_location" name="geo_mashup_add_location" type="submit" <?php echo $add_input_style; ?> value="<?php _e( 'Add Location', 'GeoMashup' ); ?>" />
+ <input id="geo_mashup_delete_location" name="geo_mashup_delete_location" type="submit" <?php echo $delete_input_style; ?> value="<?php _e( 'Delete', 'GeoMashup' ); ?>" />
+ <input id="geo_mashup_update_location" name="geo_mashup_update_location" type="submit" <?php echo $update_input_style; ?> value="<?php _e( 'Save', 'GeoMashup' ); ?>" />
+ </div>
+ <div id="geo-mashup-inline-help-link-wrap" class="geo-mashup-js">
+ <a href="#geo-mashup-inline-help" id="geo-mashup-inline-help-link"><?php _e('help', 'GeoMashup'); ?><span class="ui-icon ui-icon-triangle-1-s"></span></a>
+ </div>
+ <div id="geo-mashup-inline-help" class="<?php echo $help_class; ?> ui-widget-content">
+ <p><?php _e( '<em>Saved Name</em> is an optional name you may use to add entries to the Saved Locations menu.', 'GeoMashup' ); ?></p>
+ <p><?php _e( '<em>Geo Date</em> associates a date (most formats work) and time with a location. Leave the default value if uncertain.', 'GeoMashup' ); ?></p>
+ <div class="geo-mashup-js">
+ <p><?php _e('Put a green pin at a new location. There are many ways to do it:', 'GeoMashup'); ?></p>
+ <ul>
+ <li><?php _e('Search for a location name.', 'GeoMashup'); ?></li>
+ <li><?php _e('For multiple search results, mouse over pins to see location names, and click a result pin to select that location.', 'GeoMashup'); ?></li>
+ <li><?php _e('Search for a decimal latitude and longitude separated by a comma, like <em>40.123,-105.456</em>. Seven decimal places are stored. Negative latitude is used for the southern hemisphere, and negative longitude for the western hemisphere.', 'GeoMashup'); ?></li>
+ <li><?php _e('Search for a street address, like <em>123 main st, anytown, acity</em>.', 'GeoMashup'); ?></li>
+ <li><?php _e('Click on the location. Zoom in if necessary so you can refine the location by dragging it or clicking a new location.', 'GeoMashup'); ?></li>
+ </ul>
+ <p><?php _e('To execute a search, type search text into the Find Location box and hit the enter key. If you type a name next to "Save As", the location will be saved under that name and added to the Saved Locations dropdown list.', 'GeoMashup'); ?></p>
+ <p><?php _e('To remove the location (green pin), clear the search box and hit the enter key.', 'GeoMashup'); ?></p>
+ <p><?php _e('When you are satisfied with the location, save or update.', 'GeoMashup'); ?></p>
+ </div>
+ <noscript>
+ <div>
+ <p><?php _e( 'To add or update location choose a saved location, or find a new location using one of these formats:', 'GeoMashup' ); ?></p>
+ <ul>
+ <li><?php _e('A place name like <em>Yellowstone National Park</em>', 'GeoMashup'); ?></li>
+ <li><?php _e('A decimal latitude and longitude, like <em>40.123,-105.456</em>.', 'GeoMashup'); ?></li>
+ <li><?php _e('A full or partial street address, like <em>123 main st, anytown, acity 12345 USA</em>.', 'GeoMashup'); ?></li>
+ </ul>
+ <p><?php _e( 'When you save or update, the closest match available will be saved as the location.', 'GeoMashup' ); ?></p>
+ </div>
+ </noscript>
+
+ </div>
+ </div><!-- id="geo_mashup_location_editor" -->
+<?php
+}
+?>
--- a/geo-mashup/trunk/freemius.php
+++ b/geo-mashup/trunk/freemius.php
@@ -0,0 +1,133 @@
+<?php
+
+/**
+ * Freemius integration
+ * @since 1.9.1
+ * @since 1.10 Made instantiable.
+ */
+class GeoMashupFreemius {
+ /**
+ * @since 1.10.0
+ * @var string
+ */
+ protected static $init_data_option_name = 'geo_mashup_freemius_init';
+
+ /**
+ * @since 1.10.0
+ * @var array
+ */
+ protected $init_data;
+
+ /**
+ * @since 1.10.0
+ * @var Freemius
+ */
+ protected $freemius;
+
+
+ /**
+ * Instantiate a Freemius integration object.
+ * @since 1.10.0
+ */
+ public function __construct() {
+ }
+
+ /**
+ * @since 1.10.0
+ * @return bool
+ */
+ public function is_loaded() {
+ return isset( $this->freemius );
+ }
+
+ /**
+ * Load Freemius integrations.
+ * @since 1.9.1
+ */
+ public function load() {
+
+ if ( $this->is_loaded() ) {
+ return;
+ }
+
+ include_once( GEO_MASHUP_DIR_PATH . '/vendor/freemius/wordpress-sdk/start.php' );
+
+ $defaults = array(
+ 'id' => '472',
+ 'slug' => 'geo-mashup',
+ 'type' => 'plugin',
+ 'public_key' => 'pk_c28784eaec74e8b93e422064f2f99',
+ 'is_premium' => false,
+ 'has_premium_version' => false,
+ 'has_addons' => false,
+ 'has_paid_plans' => true,
+ 'navigation' => 'tabs',
+ 'menu' => array(
+ 'slug' => 'geo-mashup/geo-mashup.php',
+ 'contact' => false,
+ 'support' => false,
+ 'parent' => array(
+ 'slug' => 'options-general.php',
+ ),
+ ),
+ );
+
+ $this->init_data = defined( 'GEO_MASHUP_FREEMIUS_INIT' ) ? unserialize( GEO_MASHUP_FREEMIUS_INIT ) : array();
+
+ $this->init_data = array_replace_recursive( $defaults, $this->init_data );
+
+ $this->init_data = array_replace_recursive( $this->init_data, get_option( self::$init_data_option_name, array() ) );
+
+ $this->freemius = fs_dynamic_init( $this->init_data );
+
+ $this->freemius->add_action( 'after_license_change', array( $this, 'after_license_change' ) );
+
+ $this->freemius->add_action( 'after_account_delete', array( $this, 'after_account_delete' ) );
+
+ $this->freemius->add_action( 'after_uninstall', array( $this, 'uninstall' ) );
+ }
+
+ /**
+ * Track premium status when license changes.
+ *
+ * @since 1.10.0
+ * @param string $event The Freemius license event.
+ */
+ public function after_license_change( $event ) {
+ $is_paying = ! in_array( $event, array( 'cancelled', 'expired', 'trial_expired' ) );
+ $this->update_init_data( $is_paying );
+ }
+
+ /**
+ * Track premium status when account is deleted.
+ *
+ * @since 1.10.0
+ */
+ public function after_account_delete() {
+ $this->update_init_data( false );
+ }
+
+ /**
+ * @since 1.9.1
+ */
+ public function uninstall() {
+ delete_option( self::$init_data_option_name );
+ include_once( GEO_MASHUP_DIR_PATH . '/uninstaller.php' );
+ $uninstaller = new GeoMashupUninstaller();
+ $uninstaller->geo_mashup_uninstall_options();
+ }
+
+ /**
+ * @since 1.10.0
+ * @param bool $is_paying
+ */
+ public function update_init_data( $is_paying = false ) {
+ $init_data = array(
+ 'menu' => array(
+ 'contact' => $is_paying,
+ ),
+ );
+ update_option( self::$init_data_option_name, $init_data, false );
+ }
+
+}
--- a/geo-mashup/trunk/geo-mashup-db.php
+++ b/geo-mashup/trunk/geo-mashup-db.php
@@ -0,0 +1,2187 @@
+<?php
+/**
+ * Geo Mashup Data Access
+ *
+ * @package GeoMashup
+ */
+
+// Init at load time - just adds hooks
+GeoMashupDB::init();
+
+/**
+ * Static class to provide a namespace for Geo Mashup data functions.
+ *
+ * @since 1.2
+ * @package GeoMashup
+ */
+class GeoMashupDB {
+ /**
+ * Current installed database version.
+ *
+ * @since 1.4
+ * @var string
+ */
+ private static $installed_version = null;
+ /**
+ * Flag for objects that have geodata fields copied to.
+ * Key $meta_type-$object_id, value true.
+ *
+ * @since 1.4
+ * @var array
+ */
+ private static $copied_to_geodata = array();
+ /**
+ * Meta keys used to store geodata
+ *
+ * @since 1.4
+ * @var array
+ */
+ private static $geodata_keys = array( 'geo_latitude', 'geo_longitude', 'geo_address' );
+ /**
+ * The last geocode error, or empty if no error.
+ * @var WP_Error
+ */
+ public static $geocode_error = array();
+
+ /**
+ * WordPress action to set up data-related WordPress hooks.
+ *
+ * @since 1.4
+ */
+ public static function init() {
+ global $geo_mashup_options;
+
+ // Enable the geo_mashup_query var
+ add_filter( 'query_vars', array( 'GeoMashupDB', 'query_vars' ) );
+ add_filter( 'posts_fields', array( 'GeoMashupDB', 'posts_fields' ), 10, 2 );
+ add_filter( 'posts_join', array( 'GeoMashupDB', 'posts_join' ), 10, 2 );
+ add_filter( 'posts_where', array( 'GeoMashupDB', 'posts_where' ), 10, 2 );
+ add_action( 'parse_query', array( 'GeoMashupDB', 'parse_query' ) );
+
+ // Some caching plugins don't implement this
+ if ( function_exists( 'wp_cache_add_global_groups' ) )
+ wp_cache_add_global_groups( array( 'geo_mashup_object_locations', 'geo_mashup_locations' ) );
+
+ // Avoid orphans
+ add_action( 'delete_post', array( 'GeoMashupDB', 'delete_post' ) );
+ add_action( 'delete_comment', array( 'GeoMashupDB', 'delete_comment' ) );
+ add_action( 'delete_user', array( 'GeoMashupDB', 'delete_user' ) );
+
+ if ( 'true' == $geo_mashup_options->get( 'overall', 'copy_geodata' ) or '' != $geo_mashup_options->get( 'overall', 'import_custom_field' ) )
+ self::add_geodata_sync_hooks();
+ }
+
+ /**
+ * Add hooks to synchronize Geo Mashup ojbect locations with WordPress geodata.
+ *
+ * @since 1.4
+ */
+ public static function add_geodata_sync_hooks() {
+ add_filter( 'update_post_metadata', array( 'GeoMashupDB', 'filter_update_post_metadata' ), 10, 5 );
+ add_action( 'added_post_meta', array( 'GeoMashupDB', 'action_added_post_meta' ), 10, 4 );
+ add_action( 'updated_post_meta', array( 'GeoMashupDB', 'action_added_post_meta' ), 10, 4 );
+ add_filter( 'update_user_metadata', array( 'GeoMashupDB', 'filter_update_user_metadata' ), 10, 5 );
+ add_action( 'added_user_meta', array( 'GeoMashupDB', 'action_added_user_meta' ), 10, 4 );
+ add_action( 'updated_user_meta', array( 'GeoMashupDB', 'action_added_user_meta' ), 10, 4 );
+ add_filter( 'update_comment_metadata', array( 'GeoMashupDB', 'filter_update_comment_metadata' ), 10, 5 );
+ add_action( 'added_comment_meta', array( 'GeoMashupDB', 'action_added_comment_meta' ), 10, 4 );
+ add_action( 'updated_comment_meta', array( 'GeoMashupDB', 'action_added_comment_meta' ), 10, 4 );
+ // AJAX calls use a slightly different hook - triksy!
+ add_action( 'added_postmeta', array( 'GeoMashupDB', 'action_added_post_meta' ), 10, 4 );
+ add_action( 'updated_postmeta', array( 'GeoMashupDB', 'action_added_post_meta' ), 10, 4 );
+
+ add_action( 'geo_mashup_added_object_location', array( 'GeoMashupDB', 'copy_to_geodata' ), 10, 4 );
+ add_action( 'geo_mashup_updated_object_location', array( 'GeoMashupDB', 'copy_to_geodata' ), 10, 4 );
+ }
+
+ /**
+ * Remove hooks to synchronize Geo Mashup ojbect locations with WordPress geodata.
+ *
+ * @since 1.4
+ */
+ public static function remove_geodata_sync_hooks() {
+ remove_filter( 'update_post_metadata', array( 'GeoMashupDB', 'filter_update_post_metadata' ), 10, 5 );
+ remove_action( 'added_post_meta', array( 'GeoMashupDB', 'action_added_post_meta' ), 10, 4 );
+ remove_action( 'updated_post_meta', array( 'GeoMashupDB', 'action_added_post_meta' ), 10, 4 );
+ remove_filter( 'update_user_metadata', array( 'GeoMashupDB', 'filter_update_user_metadata' ), 10, 5 );
+ remove_action( 'added_user_meta', array( 'GeoMashupDB', 'action_added_user_meta' ), 10, 4 );
+ remove_action( 'updated_user_meta', array( 'GeoMashupDB', 'action_added_user_meta' ), 10, 4 );
+ remove_filter( 'update_comment_metadata', array( 'GeoMashupDB', 'filter_update_comment_metadata' ), 10, 5 );
+ remove_action( 'added_comment_meta', array( 'GeoMashupDB', 'action_added_comment_meta' ), 10, 4 );
+ remove_action( 'updated_comment_meta', array( 'GeoMashupDB', 'action_added_comment_meta' ), 10, 4 );
+ // AJAX calls use a slightly different hook - triksy!
+ remove_action( 'added_postmeta', array( 'GeoMashupDB', 'action_added_post_meta' ), 10, 4 );
+ remove_action( 'updated_postmeta', array( 'GeoMashupDB', 'action_added_post_meta' ), 10, 4 );
+
+ remove_action( 'geo_mashup_added_object_location', array( 'GeoMashupDB', 'copy_to_geodata' ), 10, 4 );
+ remove_action( 'geo_mashup_updated_object_location', array( 'GeoMashupDB', 'copy_to_geodata' ), 10, 4 );
+ }
+
+ /**
+ * WordPress action to update Geo Mashup post location when geodata custom fields are updated.
+ *
+ * @since 1.4
+ */
+ public static function action_added_post_meta( $meta_id, $post_id, $meta_key, $meta_value ) {
+ self::copy_from_geodata( 'post', $meta_id, $post_id, $meta_key, $meta_value );
+ }
+
+ /**
+ * WordPress action to update Geo Mashup user location when geodata custom fields are updated.
+ *
+ * @since 1.4
+ */
+ public static function action_added_user_meta( $meta_id, $user_id, $meta_key, $meta_value ) {
+ self::copy_from_geodata( 'user', $meta_id, $user_id, $meta_key, $meta_value );
+ }
+
+ /**
+ * WordPress action to update Geo Mashup comment location when geodata custom fields are updated.
+ *
+ * @since 1.4
+ */
+ public static function action_added_comment_meta( $meta_id, $comment_id, $meta_key, $meta_value ) {
+ self::copy_from_geodata( 'comment', $meta_id, $comment_id, $meta_key, $meta_value );
+ }
+
+ /**
+ * WordPress filter to prevent updates to geodata fields we've already updated.
+ *
+ * @since 1.4
+ */
+ public static function filter_update_post_metadata( $ok, $object_id, $meta_key, $meta_value, $prev_value ) {
+ if ( !in_array( $meta_key, self::$geodata_keys ) )
+ return $ok;
+ if ( isset( self::$copied_to_geodata['post-' . $object_id] ) )
+ return false;
+ else
+ return $ok;
+ }
+
+ /**
+ * WordPress filter to prevent updates to geodata fields we've already updated.
+ *
+ * @since 1.4
+ */
+ public static function filter_update_user_metadata( $ok, $object_id, $meta_key, $meta_value, $prev_value ) {
+ if ( !in_array( $meta_key, self::$geodata_keys ) )
+ return $ok;
+ if ( isset( self::$copied_to_geodata['user-' . $object_id] ) )
+ return false;
+ else
+ return $ok;
+ }
+
+ /**
+ * WordPress filter to prevent updates to geodata fields we've already updated.
+ *
+ * @since 1.4
+ */
+ public static function filter_update_comment_metadata( $ok, $object_id, $meta_key, $meta_value, $prev_value ) {
+ if ( !in_array( $meta_key, self::$geodata_keys ) )
+ return $ok;
+ if ( isset( self::$copied_to_geodata['comment-' . $object_id] ) )
+ return false;
+ else
+ return $ok;
+ }
+
+ /**
+ * Create a Geo Mashup object location from WordPress geodata.
+ *
+ * @since 1.4
+ * @see http://codex.wordpress.org/Geodata
+ */
+ private static function copy_from_geodata( $meta_type, $meta_id, $object_id, $meta_key, $meta_value ) {
+ global $geo_mashup_options, $wpdb;
+
+ // Do nothing if meta_key is not a known location field
+ $location_keys = array();
+ $is_copy_geodata_on = ( 'true' === $geo_mashup_options->get( 'overall', 'copy_geodata' ) );
+ $copy_imported_geodata = false;
+ if ( $is_copy_geodata_on ) {
+ $location_keys = array_merge( $location_keys, array( 'geo_latitude', 'geo_longitude', 'geo_lat_lng' ) );
+ }
+ $import_custom_keys = preg_split( '/s*,s*/', trim( $geo_mashup_options->get( 'overall', 'import_custom_field' ) ) );
+ $location_keys = array_merge( $location_keys, $import_custom_keys );
+ if ( ! in_array( $meta_key, $location_keys ) )
+ return;
+
+ $existing_location = self::get_object_location( $meta_type, $object_id );
+
+ $location = array();
+
+ // Do nothing unless both latitude and longitude exist for the object
+ if ( 'geo_lat_lng' == $meta_key ) {
+
+ $lat_lng = preg_split( '/s*[, ]s*/', trim( $meta_value ) );
+ if ( 2 != count( $lat_lng ) ) {
+ return;
+ }
+ $location['lat'] = $lat_lng[0];
+ $location['lng'] = $lat_lng[1];
+
+ } else if ( 'geo_latitude' == $meta_key ) {
+
+ $location['lat'] = $meta_value;
+ $lng = get_metadata( $meta_type, $object_id, 'geo_longitude', true );
+ if ( empty( $lng ) )
+ return;
+ $location['lng'] = $lng;
+
+ } else if ( 'geo_longitude' == $meta_key ) {
+
+ $location['lng'] = $meta_value;
+ $lat = get_metadata( $meta_type, $object_id, 'geo_latitude', true );
+ if ( empty( $lat ) )
+ return;
+ $location['lat'] = $lat;
+
+ } else if ( in_array( $meta_key, $import_custom_keys ) ) {
+
+ $lat_lng = preg_split( '/s*[, ]s*/', trim( $meta_value ) );
+ if ( count( $lat_lng ) == 2 and is_numeric( $lat_lng[0] ) and is_numeric( $lat_lng[1] ) ) {
+ $location['lat'] = $lat_lng[0];
+ $location['lng'] = $lat_lng[1];
+ } else if ( !empty( $meta_value ) ) {
+ $geocode_values = array();
+ foreach( $import_custom_keys as $import_custom_key ) {
+ if ( $meta_key == $import_custom_key ) {
+ $geocode_values[] = $meta_value;
+ } else {
+
+ // All keys must have a value - do nothing if not
+ if ( !metadata_exists( $meta_type, $object_id, $import_custom_key ) )
+ return;
+
+ $geocode_values[] = get_metadata( $meta_type, $object_id, $import_custom_key, true );
+
+ }
+ }
+ $location = self::blank_location( ARRAY_A );
+ self::geocode( implode( ',', $geocode_values ), $location );
+ if ( self::$geocode_error ) {
+ update_metadata( $meta_type, $object_id, 'geocoding_error', self::$geocode_error->get_error_message() );
+ return;
+ }
+ if ( $is_copy_geodata_on ) {
+ $copy_imported_geodata = true;
+ }
+ }
+ }
+
+ // Do nothing if the location already exists
+ if ( !empty( $existing_location ) ) {
+ $epsilon = 0.00001;
+ if ( abs( $location['lat'] - $existing_location->lat ) < $epsilon and abs( $location['lng'] - $existing_location->lng ) < $epsilon )
+ return;
+ }
+
+ // Save the location, attempt reverse geocoding
+ self::remove_geodata_sync_hooks();
+ // Use geo date if it exists
+ $geo_date = get_metadata( $meta_type, $object_id, 'geo_date', true );
+ $location_id = self::set_object_location( $meta_type, $object_id, $location, null, $geo_date );
+ if ( $copy_imported_geodata ) {
+ self::copy_to_geodata( $meta_type, $object_id, $geo_date, $location_id );
+ }
+ self::add_geodata_sync_hooks();
+ }
+
+ /**
+ * Update object geodata if needed.
+ *
+ * @since 1.4
+ *
+ * @param string $meta_type 'post','user','comment'
+ * @param int $object_id
+ * @param string $geo_date
+ * @param int $location_id The location to copy from.
+ */
+ public static function copy_to_geodata( $meta_type, $object_id, $geo_date, $location_id ) {
+
+ $geo_latitude = get_metadata( $meta_type, $object_id, 'geo_latitude', true );
+ $geo_longitude = get_metadata( $meta_type, $object_id, 'geo_longitude', true );
+ $existing_object_location = self::get_object_location( $meta_type, $object_id );
+
+ // Do nothing if the geodata already exists
+ if ( $geo_latitude and $geo_longitude ) {
+ $epsilon = 0.00001;
+ if ( abs( $geo_latitude - $existing_object_location->lat ) < $epsilon and abs( $geo_longitude - $existing_object_location->lng ) < $epsilon )
+ return;
+ }
+
+ self::remove_geodata_sync_hooks();
+ update_metadata( $meta_type, $object_id, 'geo_latitude', $existing_object_location->lat );
+ update_metadata( $meta_type, $object_id, 'geo_longitude', $existing_object_location->lng );
+ update_metadata( $meta_type, $object_id, 'geo_address', $existing_object_location->address );
+ update_metadata( $meta_type, $object_id, 'geo_date', $existing_object_location->geo_date );
+ self::$copied_to_geodata[$meta_type . '-' . $object_id] = true;
+ self::add_geodata_sync_hooks();
+ }
+
+ /**
+ * Set the installed database version.
+ *
+ * @since 1.4
+ *
+ * @param string $new_version
+ */
+ private static function set_installed_version( $new_version ) {
+ self::$installed_version = $new_version;
+ update_option( 'geo_mashup_db_version', $new_version );
+ }
+
+ /**
+ * Get the installed database version.
+ *
+ * @since 1.2
+ *
+ * @return string The installed database version.
+ */
+ public static function installed_version() {
+
+ if ( is_null( self::$installed_version ) ) {
+ self::$installed_version = get_option( 'geo_mashup_db_version' );
+ }
+ return self::$installed_version;
+ }
+
+ /**
+ * Get or set storage information for an object name.
+ *
+ * Potentially you could add storage information for a new kind of object:
+ * <code>
+ * GeoMashupDB::object_storage( 'foo', array(
+ * 'table' => $wpdb->prefix . 'foos',
+ * 'id_column' => 'foo_id',
+ * 'label_column' => 'foo_display_name',
+ * 'sort' => 'foo_order ASC' )
+ * );
+ * </code>
+ * Would add the necessary information for a custom table of foo objects. By convention the
+ * object name is the singular form of the table name without a prefix.
+ *
+ * @since 1.3
+ *
+ * @param string $object_name A type of object to be stored, default is 'post', 'user', and 'comment'.
+ * @param array $new_storage If provided, adds or replaces the storage information for the object name.
+ * @return array|bool The storage information array, or false if not found.
+ */
+ public static function object_storage( $object_name, $new_storage = null ) {
+ global $wpdb;
+ static $objects = null;
+
+ if ( is_null( $objects ) ) {
+ $objects = array(
+ 'post' => array(
+ 'table' => $wpdb->posts,
+ 'id_column' => 'ID',
+ 'label_column' => 'post_title',
+ 'date_column' => 'post_date',
+ 'sort' => 'post_status ASC, geo_date DESC' ),
+ 'user' => array(
+ 'table' => $wpdb->users,
+ 'id_column' => 'ID',
+ 'label_column' => 'display_name',
+ 'date_column' => 'user_registered',
+ 'sort' => 'display_name ASC' ),
+ 'comment' => array(
+ 'table' => $wpdb->comments,
+ 'id_column' => 'comment_ID',
+ 'label_column' => 'comment_author',
+ 'date_column' => 'comment_date',
+ 'sort' => 'comment_date DESC' )
+ );
+ }
+
+ if ( !empty( $new_storage ) ) {
+ $objects[$object_name] = $new_storage;
+ }
+ return ( isset( $objects[$object_name] ) ) ? $objects[$object_name] : false;
+ }
+
+ /**
+ * Return a conventional object name given a table name.
+ *
+ * @since 1.7
+ *
+ * @param string $table
+ * @return string
+ */
+ public static function table_to_object_name( $table ) {
+ global $wpdb;
+ $object_name = str_replace( $wpdb->prefix, '', $table );
+ if ( 's' === substr( $object_name, -1 ) ) {
+ $object_name = substr( $object_name, 0, strlen( $object_name ) - 1 );
+ }
+ return $object_name;
+ }
+
+ /**
+ * Toggle joining of WordPress queries with Geo Mashup tables.
+ *
+ * Use the public wrapper GeoMashup::join_post_queries()
+ *
+ * @since 1.3
+ * @deprecated Use the geo_mashup_query query var
+ *
+ * @param bool $new_value If provided, replaces the current active state.
+ * @return bool The current state.
+ */
+ public static function join_post_queries( $new_value = null) {
+ static $active = null;
+
+ if ( is_bool( $new_value ) ) {
+ _deprecated_function( __METHOD__, '1.7', 'the geo_mashup_query query var' );
+ $active = $new_value;
+ }
+
+ return $active;
+ }
+
+ /**
+ * WordPress filter to add Geo Mashup public query variables.
+ *
+ * query_vars {@link http://codex.wordpress.org/Plugin_API/Filter_Reference filter}
+ * called by Wordpress.
+ *
+ * @since 1.3
+ */
+ public static function query_vars( $public_query_vars ) {
+ if ( self::join_post_queries() ) {
+ $public_query_vars[] = 'geo_mashup_date';
+ $public_query_vars[] = 'geo_mashup_saved_name';
+ $public_query_vars[] = 'geo_mashup_country_code';
+ $public_query_vars[] = 'geo_mashup_postal_code';
+ $public_query_vars[] = 'geo_mashup_admin_code';
+ $public_query_vars[] = 'geo_mashup_locality';
+ }
+ return $public_query_vars;
+ }
+
+ /**
+ * Set or get custom data associated with a WP_Query object.
+ *
+ * @since 1.7
+ *
+ * @param WP_Query $query
+ * @param string $key Optional - return all data for the query if missing.
+ * @param mixed $value Optional - set or overwrite data for the key if present.
+ * @return mixed Extension data if present.
+ */
+ private static function query_extension( $query, $key = null, $value = null ) {
+ static $extensions = array();
+
+ $hash = spl_object_hash( $query );
+
+ if ( is_null( $key ) )
+ return $extensions;
+
+ if ( !isset( $extensions[$hash] ) )
+ $extensions[$hash] = array();
+
+ if ( !is_null( $value ) )
+ $extensions[$hash][$key] = $value;
+ else if ( !isset( $extensions[$hash][$key] ) )
+ return null;
+
+ return $extensions[$hash][$key];
+ }
+
+ /**
+ * WordPress action to capture custom orderby field before it is removed.
+ *
+ * parse_query {@link http://codex.wordpress.org/Plugin_API/Action_Reference action}
+ * called by WordPress.
+ *
+ * @since 1.3
+ * @access private
+ * @static
+ */
+ public static function parse_query( $query ) {
+ global $wpdb;
+
+ if ( !self::join_post_queries() )
+ return;
+
+ // Check for geo mashup fields in the orderby before they are removed as invalid
+ switch ( $query->query_vars['orderby'] ) {
+ case 'geo_mashup_date':
+ self::query_extension( $query, 'orderby', $wpdb->prefix . 'geo_mashup_location_relationships.geo_date' );
+ break;
+
+ case 'geo_mashup_locality':
+ self::query_extension( $query, 'orderby', $wpdb->prefix . 'geo_mashup_locations.locality_name' );
+ break;
+
+ case 'geo_mashup_saved_name':
+ self::query_extension( $query, 'orderby', $wpdb->prefix . 'geo_mashup_locations.saved_name' );
+ break;
+
+ case 'geo_mashup_country_code':
+ self::query_extension( $query, 'orderby', $wpdb->prefix . 'geo_mashup_locations.country_code' );
+ break;
+
+ case 'geo_mashup_admin_code':
+ self::query_extension( $query, 'orderby', $wpdb->prefix . 'geo_mashup_locations.admin_code' );
+ break;
+
+ case 'geo_mashup_postal_code':
+ self::query_extension( $query, 'orderby', $wpdb->prefix . 'geo_mashup_locations.postal_code' );
+ break;
+ }
+ }
+
+ /**
+ * WordPress filter to add Geo Mashup fields to WordPress post queries.
+ *
+ * posts_fields {@link http://codex.wordpress.org/Plugin_API/Filter_Reference filter}
+ * called by WordPress.
+ *
+ * @since 1.3
+ */
+ public static function posts_fields( $fields, $query ) {
+ global $wpdb;
+
+ if ( self::join_post_queries() ) {
+ $fields .= ',' . $wpdb->prefix . 'geo_mashup_location_relationships.geo_date' .
+ ',' . $wpdb->prefix . 'geo_mashup_locations.*';
+ }
+
+ return $fields;
+ }
+
+ /**
+ * WordPress filter to join Geo Mashup tables to WordPress post queries.
+ *
+ * posts_join {@link http://codex.wordpress.org/Plugin_API/Filter_Reference filter}
+ * called by WordPress.
+ *
+ * @since 1.3
+ */
+ public static function posts_join( $join, $query ) {
+ global $wpdb;
+
+ if ( self::join_post_queries() ) {
+ $gmlr = $wpdb->prefix . 'geo_mashup_location_relationships';
+ $gml = $wpdb->prefix . 'geo_mashup_locations';
+ $join .= " INNER JOIN $gmlr ON ($gmlr.object_name = 'post' AND $gmlr.object_id = $wpdb->posts.ID)" .
+ " INNER JOIN $gml ON ($gml.id = $gmlr.location_id) ";
+ }
+
+ return $join;
+ }
+
+ /**
+ * WordPress filter to incorporate geo mashup query vars in WordPress post queries.
+ *
+ * posts_where {@link http://codex.wordpress.org/Plugin_API/Filter_Reference filter}
+ * called by WordPress.
+ *
+ * @since 1.3
+ */
+ public static function posts_where( $where, $query ) {
+ global $wpdb;
+
+ if ( !self::join_post_queries() )
+ return $where;
+
+ $gmlr = $wpdb->prefix . 'geo_mashup_location_relationships';
+ $gml = $wpdb->prefix . 'geo_mashup_locations';
+ $geo_date = get_query_var( 'geo_mashup_date' );
+ if ( $geo_date ) {
+ $where .= $wpdb->prepare( " AND $gmlr.geo_date = %s ", $geo_date );
+ }
+ $saved_name = get_query_var( 'geo_mashup_saved_name' );
+ if ( $saved_name ) {
+ $where .= $wpdb->prepare( " AND $gml.saved_name = %s ", $saved_name );
+ }
+ $locality = get_query_var( 'geo_mashup_locality' );
+ if ( $locality ) {
+ $where .= $wpdb->prepare( " AND $gml.locality_name = %s ", $locality );
+ }
+ $country_code = get_query_var( 'geo_mashup_country_code' );
+ if ( $country_code ) {
+ $where .= $wpdb->prepare( " AND $gml.country_code = %s ", $country_code );
+ }
+ $admin_code = get_query_var( 'geo_mashup_admin_code' );
+ if ( $admin_code ) {
+ $where .= $wpdb->prepare( " AND $gml.admin_code = %s ", $admin_code );
+ }
+ $postal_code = get_query_var( 'geo_mashup_postal_code' );
+ if ( $postal_code ) {
+ $where .= $wpdb->prepare( " AND $gml.postal_code = %s ", $postal_code );
+ }
+
+ return $where;
+ }
+
+ /**
+ * Append to the activation log.
+ *
+ * Add a message and optionally write the activation log.
+ * Needs to be written before the end of the request or it will not be saved.
+ *
+ * @since 1.4
+ *
+ * @param string $message The message to append.
+ * @param boolean $write Whether to save the log.
+ * @return string The current log.
+ */
+ public static function activation_log( $message = null, $write = false ) {
+ static $log = null;
+
+ if ( is_null( $log ) ) {
+ $log = get_option( 'geo_mashup_activation_log' );
+ }
+ if ( ! is_null( $message ) ) {
+ $log .= "n" . $message;
+ }
+ if ( $write ) {
+ update_option( 'geo_mashup_activation_log', $log );
+ }
+ return $log;
+ }
+
+ /**
+ * Install or update Geo Mashup tables.
+ *
+ * @uses GeoMashupDB::activation_log()
+ * @since 1.2
+ */
+ public static function install() {
+ global $wpdb, $geo_mashup_options;
+
+ self::activation_log( date( 'r' ) . ' ' . __( 'Activating Geo Mashup', 'GeoMashup' ) );
+ $location_table_name = $wpdb->prefix . 'geo_mashup_locations';
+ $relationships_table_name = $wpdb->prefix . 'geo_mashup_location_relationships';
+ $administrative_names_table_name = $wpdb->prefix . 'geo_mashup_administrative_names';
+
+ $charset_collate = '';
+
+ if ( ! empty($wpdb-