diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index ad92582..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "editor.formatOnSave": true -} diff --git a/class.geocoder.php b/class.geocoder.php index 6bfebc3..a5cd525 100644 --- a/class.geocoder.php +++ b/class.geocoder.php @@ -2,7 +2,7 @@ /** * Geocoder * -* calls the specific geocoder function (chosen in admin or default: google_geocode) +* calls the specific geocoder function (chosen in admin or default: osm) * */ @@ -11,7 +11,7 @@ class Leaflet_Geocoder { * Geocoder should return this on error/not found * @var array $not_found */ - private $not_found = array('lat' => 0, 'lng' => 0); + private static $not_found = array('lat' => 0, 'lng' => 0); /** * Latitude * @var float $lat @@ -23,6 +23,9 @@ class Leaflet_Geocoder { */ public $lng = 0; + /** key for all locations */ + public static $locations_key = 'leaflet_geocoded_locations'; + /** * new Geocoder from address * @@ -42,7 +45,7 @@ public function __construct ($address) { $cached_address = 'leaflet_' . $geocoder . '_' . $address; /* retrieve cached geocoded location */ - $found_cache = get_option( $cached_address ); + $found_cache = $this->get_cache( $cached_address, $address ); if ( $found_cache ) { $location = $found_cache; @@ -53,16 +56,17 @@ public function __construct ($address) { try { $location = (Object) $this->$geocoding_method( $address ); - /* add location */ - add_option($cached_address, $location); + /* update location data in db/cache */ + $this->set_cache( $cached_address, $location ); - /* add option key to locations for clean up purposes */ - $locations = get_option('leaflet_geocoded_locations', array()); - array_push($locations, $cached_address); - update_option('leaflet_geocoded_locations', $locations); + /* add cache to cached list for cleanup */ + $this->update_caches( $cached_address ); } catch (Exception $e) { - // failed - $location = $this->not_found; + /** + * @since 3.4.0 + * use 'leaflet_geocoder_not_found' filter to return your own not_found response + */ + $location = apply_filters( 'leaflet_geocoder_not_found', self::$not_found ); } } @@ -72,17 +76,6 @@ public function __construct ($address) { } } - /** - * Removes location caches - */ - public static function remove_caches () { - $addresses = get_option('leaflet_geocoded_locations', array()); - foreach ($addresses as $address) { - delete_option($address); - } - delete_option('leaflet_geocoded_locations'); - } - /** * Used by geocoders to make requests via curl or file_get_contents * @@ -95,13 +88,12 @@ private function get_url( $url ) { $referer = get_site_url(); if (in_array('curl', get_loaded_extensions())) { - /* try curl */ $ch = curl_init(); curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE); curl_setopt($ch, CURLOPT_HEADER, 0); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_REFERER, $referer); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_REFERER, $referer); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); @@ -110,14 +102,12 @@ private function get_url( $url ) { return $data; } else if (ini_get('allow_url_fopen')) { - /* try file get contents */ - - $opts = array( - 'http' => array( - 'header' => array("Referer: $referer\r\n") - ) - ); - $context = stream_context_create($opts); + $opts = array( + 'http' => array( + 'header' => array("Referer: $referer\r\n") + ) + ); + $context = stream_context_create($opts); return file_get_contents($url, false, $context); } @@ -132,7 +122,6 @@ private function get_url( $url ) { * @param string $address the urlencoded address to look up * @return varies object from API or null (failed) */ - private function google_geocode ( $address ) { // Leaflet_Map_Plugin_Settings $settings = Leaflet_Map_Plugin_Settings::init(); @@ -146,7 +135,6 @@ private function google_geocode ( $address ) { /* found location */ if ($json->status == 'OK') { - $location = $json->results[0]->geometry->location; return (Object) $location; @@ -161,7 +149,6 @@ private function google_geocode ( $address ) { * @param string $address the urlencoded address to look up * @return varies object from API or null (failed) */ - private function osm_geocode ( $address ) { $geocode_url = 'https://nominatim.openstreetmap.org/?format=json&limit=1&q='; $geocode_url .= $address; @@ -198,4 +185,89 @@ private function dawa_geocode ( $address ) { 'lng' => $json[0]->adgangsadresse->adgangspunkt->koordinater[0] ); } + + /** + * gets a single location's coordinates from the cached locations + */ + public function get_cache($address_key, $plain_address) { + /** + * @since 3.4.0 + * using 'leaflet_geocoder_get_cache', + * you can return any value that is not identical to the address_key to avoid using get_transient + */ + $filtered = apply_filters( 'leaflet_geocoder_get_cache', $address_key, $plain_address ); + + if ($filtered === $address_key) { + return get_transient( $address_key ); + } + + return $filtered; + } + + /** + * gets the array of saved locations and updates an individual location + */ + public function set_cache($key, $value) { + /** + * @since 3.4.0 + * using 'leaflet_geocoder_set_cache', + * you can return any falsy value to omit the set_transient + */ + if (apply_filters('leaflet_geocoder_set_cache', $key, $value)) { + // get user-defined expiry (maybe this should be an admin option?) + $expiry = apply_filters('leaflet_geocoder_expiry', null); + + if ($expiry === null) { + // stagger caches between 200-400 days to prevent all caches expiring on the same day + $stagger = random_int(200, 400); + $expiry = DAY_IN_SECONDS * $stagger; + } + + set_transient( $key, $value, $expiry ); + } + } + + /** + * Appends an address to a list of addresses in the db, for cleanup + */ + public function update_caches( $address ) { + /** + * @since 3.4.0 + * using 'leaflet_geocoder_update_caches', + * you can return any falsy value to omit the set_transient + */ + if (apply_filters('leaflet_geocoder_update_caches', $address)) { + $locations = get_transient( self::$locations_key ); + + if (!$locations) { + $locations = array(); + } + + array_push( $locations, $address ); + + // set to 25 year expiry since we never really want it to expire + // but omitting expiry causes it to autoload + set_transient( self::$locations_key, $locations, YEAR_IN_SECONDS * 25 ); + } + } + + /** + * Removes all location caches + */ + public static function remove_caches() { + /** @since 3.4.0 */ + do_action('leaflet_geocoder_remove_caches'); + + $addresses = get_transient( self::$locations_key ); + + if ( !$addresses ) { + return; + } + + foreach ($addresses as $address) { + delete_transient( $address ); + } + + delete_transient( self::$locations_key ); + } } \ No newline at end of file diff --git a/class.leaflet-map.php b/class.leaflet-map.php index 5c36ac5..55b5d9f 100644 --- a/class.leaflet-map.php +++ b/class.leaflet-map.php @@ -104,6 +104,7 @@ public static function init() { * Leaflet_Map Constructor */ private function __construct() { + $this->run_migrations(); $this->init_hooks(); $this->add_shortcodes(); @@ -111,6 +112,26 @@ private function __construct() { do_action('leaflet_map_loaded'); } + /** + * Check for version discrepancy and run migrations if necessary + * @since 3.4.0 + */ + private function run_migrations() { + // assume 3.3.0 if it doesn't exist + $db_version = get_option(LEAFLET_MAP__DB_VERSION_KEY, '3.3.0'); + + if ($db_version === LEAFLET_MAP__PLUGIN_VERSION) { + return; + } + + include_once LEAFLET_MAP__PLUGIN_DIR . 'class.migrations.php'; + + Leaflet_Map_Migrations::run_once($db_version); + + // set db version to current plugin version + update_option(LEAFLET_MAP__DB_VERSION_KEY, LEAFLET_MAP__PLUGIN_VERSION); + } + /** * Add actions and filters */ @@ -187,8 +208,8 @@ public static function enqueue_and_register() $js_url = $settings->get('js_url'); $css_url = $settings->get('css_url'); - wp_register_style('leaflet_stylesheet', $css_url, Array(), null, false); - wp_register_script('leaflet_js', $js_url, Array(), null, true); + wp_register_style('leaflet_stylesheet', $css_url, Array(), LEAFLET_MAP__PLUGIN_VERSION, false); + wp_register_script('leaflet_js', $js_url, Array(), LEAFLET_MAP__PLUGIN_VERSION, true); // new required MapQuest javascript file $tiling_service = $settings->get('default_tiling_service'); @@ -204,7 +225,8 @@ public static function enqueue_and_register() // optional ajax geojson plugin wp_register_script('tmcw_togeojson', $settings->get('togeojson_url'), Array('jquery'), LEAFLET_MAP__PLUGIN_VERSION, false); - if (defined('WP_DEBUG') && WP_DEBUG) { + // @since 3.4.0 + if (defined('LEAFLET_MAP__DEBUG') && LEAFLET_MAP__DEBUG) { $minified = ''; } else { $minified = '.min'; diff --git a/class.migrations.php b/class.migrations.php new file mode 100644 index 0000000..3c244fb --- /dev/null +++ b/class.migrations.php @@ -0,0 +1,40 @@ +=6" + } + }, + "node_modules/mem": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/mem/-/mem-8.1.1.tgz", + "integrity": "sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==", + "dev": true, + "dependencies": { + "map-age-cleaner": "^0.1.3", + "mimic-fn": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/mem?sponsor=1" + } + }, + "node_modules/mem/node_modules/mimic-fn": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", + "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -3150,6 +3208,15 @@ "node": ">= 0.8.0" } }, + "node_modules/p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -3243,6 +3310,12 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/php-parser": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/php-parser/-/php-parser-3.1.4.tgz", + "integrity": "sha512-WUEfH4FWsVItqgOknM67msDdcUAfgPJsHhPNl6EPXzWtX+PfdY282m4i8YIJ9ALUEhf+qGDajdmW+VYqSd7Deg==", + "dev": true + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -3292,15 +3365,18 @@ } }, "node_modules/prettier": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", - "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, "bin": { "prettier": "bin-prettier.js" }, "engines": { "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/pretty-format": { @@ -4694,6 +4770,17 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "@prettier/plugin-php": { + "version": "0.19.4", + "resolved": "https://registry.npmjs.org/@prettier/plugin-php/-/plugin-php-0.19.4.tgz", + "integrity": "sha512-FiSnSfP+Vo0/HVRXg7ZnEYJEM1eWS+MmsozYtzEdIf8Vg9v/+fwvyXMNayI5SgZ1Y9F5LGhl/EOMWIPzr9c2Xg==", + "dev": true, + "requires": { + "linguist-languages": "^7.21.0", + "mem": "^8.0.0", + "php-parser": "^3.1.3" + } + }, "@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -6288,6 +6375,12 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "linguist-languages": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/linguist-languages/-/linguist-languages-7.21.0.tgz", + "integrity": "sha512-KrWJJbFOvlDhjlt5OhUipVlXg+plUfRurICAyij1ZVxQcqPt/zeReb9KiUVdGUwwhS/2KS9h3TbyfYLA5MDlxQ==", + "dev": true + }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -6330,6 +6423,33 @@ "tmpl": "1.0.5" } }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "mem": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/mem/-/mem-8.1.1.tgz", + "integrity": "sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.3", + "mimic-fn": "^3.1.0" + }, + "dependencies": { + "mimic-fn": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", + "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==", + "dev": true + } + } + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -6453,6 +6573,12 @@ "word-wrap": "~1.2.3" } }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", + "dev": true + }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -6519,6 +6645,12 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "php-parser": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/php-parser/-/php-parser-3.1.4.tgz", + "integrity": "sha512-WUEfH4FWsVItqgOknM67msDdcUAfgPJsHhPNl6EPXzWtX+PfdY282m4i8YIJ9ALUEhf+qGDajdmW+VYqSd7Deg==", + "dev": true + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -6553,9 +6685,9 @@ "dev": true }, "prettier": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", - "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true }, "pretty-format": { diff --git a/package.json b/package.json index b1c8754..a54b6ba 100644 --- a/package.json +++ b/package.json @@ -26,13 +26,22 @@ "prettier": { "tabWidth": 2, "semi": true, - "singleQuote": true + "singleQuote": true, + "overrides": [ + { + "files": ["*.php"], + "options": { + "tabWidth": 4 + } + } + ] }, "jest": { "testEnvironment": "jsdom" }, "devDependencies": { + "@prettier/plugin-php": "^0.19.4", "jest": "^27.0.5", - "prettier": "^2.3.2" + "prettier": "^2.8.8" } } diff --git a/shortcodes/class.map-shortcode.php b/shortcodes/class.map-shortcode.php index 0a1ee60..d8add94 100644 --- a/shortcodes/class.map-shortcode.php +++ b/shortcodes/class.map-shortcode.php @@ -231,6 +231,7 @@ protected function getAtts($atts='') */ protected function getDiv($height, $width) { // div does not get wrapped in script tags + // TODO: should height and width be escaped with esc_attr? ob_start(); ?>