diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 3c3629e..0000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git a/assets/images/dot_pinlet.png b/assets/images/dot_pinlet.png new file mode 100644 index 0000000..6b214b8 Binary files /dev/null and b/assets/images/dot_pinlet.png differ diff --git a/assets/images/dot_pinlet_spider.png b/assets/images/dot_pinlet_spider.png new file mode 100644 index 0000000..4bc0b1f Binary files /dev/null and b/assets/images/dot_pinlet_spider.png differ diff --git a/assets/images/pegman.png b/assets/images/pegman.png new file mode 100644 index 0000000..6bba735 Binary files /dev/null and b/assets/images/pegman.png differ diff --git a/assets/images/spotlight_pin.png b/assets/images/spotlight_pin.png new file mode 100644 index 0000000..e8ab6b3 Binary files /dev/null and b/assets/images/spotlight_pin.png differ diff --git a/assets/js/admin/build/main.js b/assets/js/admin/main.js similarity index 100% rename from assets/js/admin/build/main.js rename to assets/js/admin/main.js diff --git a/assets/js/admin/src/main.js b/assets/js/admin/src/main.js deleted file mode 100644 index 42d2c94..0000000 --- a/assets/js/admin/src/main.js +++ /dev/null @@ -1,14 +0,0 @@ -import GoogleMapsLoader from 'google-maps'; - -GoogleMapsLoader.KEY = data.api_key; -GoogleMapsLoader.LIBRARIES = ['places']; -var autocomplete; - -GoogleMapsLoader.load((google) => { - var autocomplete; - - autocomplete = new google.maps.places.Autocomplete( - (document.getElementById('autocomplete')), - {types: ['address']}); - -}); diff --git a/assets/js/build/main.js b/assets/js/build/main.js deleted file mode 100644 index c28a3f7..0000000 --- a/assets/js/build/main.js +++ /dev/null @@ -1,417 +0,0 @@ -(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o

' + location.post_title + '

' + '

' + '' + streetNumber + ' ' + streetName + '
' + cityName + ', ' + stateName + ' ' + countryName + ' ' + zip + '

' + '

' - }); - - marker.addListener('click', function () { - infoWindow.open(map, marker); - }); - } - }); - - google.maps.event.addListenerOnce(map, 'idle', function(){ - fitMapBounds( options.center ); - }); - } - - //Ensure map has all markers in view within 100 miles - function fitMapBounds( center ) { - var markerBoundsRange = 160934, - markersInBoundsRange = []; //100 Miles - - locations.forEach(function (location) { - var lat = location.lat; - var lng = location.lng; - - if (lat && lng) { - var numLat = parseFloat(lat); - var numLng = parseFloat(lng); - - var markerLatLng = new google.maps.LatLng({ lat: numLat, lng: numLng }), - toCenterDistance = google.maps.geometry.spherical.computeDistanceBetween( center, markerLatLng ); - console.log(toCenterDistance); - - if ( markerBoundsRange >= toCenterDistance) { - markersInBoundsRange.push( markerLatLng ); - } - } - }); - - var mapBounds = map.getBounds(); - markersInBoundsRange.forEach( function(markerLatLng) { - mapBounds.extend( markerLatLng ); - }); - map.fitBounds( mapBounds, 20 ); - } - - - /* - * Get lat and long from browsers geolocation API - */ - if (window.location.protocol === 'https:' && "geolocation" in navigator) { - navigator.geolocation.getCurrentPosition( function (position) { - //Success - options.center = new google.maps.LatLng(position.coords.latitude, position.coords.longitude); - loadMap(); - - // add user marker on center of map - var marker = new google.maps.Marker({ - map: map, - position: { lat: options.center.lat(), lng: options.center.lng() }, - icon: userIcon - }); - userMarkers.push(marker); - }, function() { - //Error - loadMap(); - }); - } else { - //Geolocation API not available - loadMap(); - } -}); - -},{"google-maps":2}],2:[function(require,module,exports){ -(function(root, factory) { - - if (root === null) { - throw new Error('Google-maps package can be used only in browser'); - } - - if (typeof define === 'function' && define.amd) { - define(factory); - } else if (typeof exports === 'object') { - module.exports = factory(); - } else { - root.GoogleMapsLoader = factory(); - } - -})(typeof window !== 'undefined' ? window : null, function() { - - - 'use strict'; - - - var googleVersion = '3.18'; - - var script = null; - - var google = null; - - var loading = false; - - var callbacks = []; - - var onLoadEvents = []; - - var originalCreateLoaderMethod = null; - - - var GoogleMapsLoader = {}; - - - GoogleMapsLoader.URL = 'https://maps.googleapis.com/maps/api/js'; - - GoogleMapsLoader.KEY = null; - - GoogleMapsLoader.LIBRARIES = []; - - GoogleMapsLoader.CLIENT = null; - - GoogleMapsLoader.CHANNEL = null; - - GoogleMapsLoader.LANGUAGE = null; - - GoogleMapsLoader.REGION = null; - - GoogleMapsLoader.VERSION = googleVersion; - - GoogleMapsLoader.WINDOW_CALLBACK_NAME = '__google_maps_api_provider_initializator__'; - - - GoogleMapsLoader._googleMockApiObject = {}; - - - GoogleMapsLoader.load = function(fn) { - if (google === null) { - if (loading === true) { - if (fn) { - callbacks.push(fn); - } - } else { - loading = true; - - window[GoogleMapsLoader.WINDOW_CALLBACK_NAME] = function() { - ready(fn); - }; - - GoogleMapsLoader.createLoader(); - } - } else if (fn) { - fn(google); - } - }; - - - GoogleMapsLoader.createLoader = function() { - script = document.createElement('script'); - script.type = 'text/javascript'; - script.src = GoogleMapsLoader.createUrl(); - - document.body.appendChild(script); - }; - - - GoogleMapsLoader.isLoaded = function() { - return google !== null; - }; - - - GoogleMapsLoader.createUrl = function() { - var url = GoogleMapsLoader.URL; - - url += '?callback=' + GoogleMapsLoader.WINDOW_CALLBACK_NAME; - - if (GoogleMapsLoader.KEY) { - url += '&key=' + GoogleMapsLoader.KEY; - } - - if (GoogleMapsLoader.LIBRARIES.length > 0) { - url += '&libraries=' + GoogleMapsLoader.LIBRARIES.join(','); - } - - if (GoogleMapsLoader.CLIENT) { - url += '&client=' + GoogleMapsLoader.CLIENT + '&v=' + GoogleMapsLoader.VERSION; - } - - if (GoogleMapsLoader.CHANNEL) { - url += '&channel=' + GoogleMapsLoader.CHANNEL; - } - - if (GoogleMapsLoader.LANGUAGE) { - url += '&language=' + GoogleMapsLoader.LANGUAGE; - } - - if (GoogleMapsLoader.REGION) { - url += '®ion=' + GoogleMapsLoader.REGION; - } - - return url; - }; - - - GoogleMapsLoader.release = function(fn) { - var release = function() { - GoogleMapsLoader.KEY = null; - GoogleMapsLoader.LIBRARIES = []; - GoogleMapsLoader.CLIENT = null; - GoogleMapsLoader.CHANNEL = null; - GoogleMapsLoader.LANGUAGE = null; - GoogleMapsLoader.REGION = null; - GoogleMapsLoader.VERSION = googleVersion; - - google = null; - loading = false; - callbacks = []; - onLoadEvents = []; - - if (typeof window.google !== 'undefined') { - delete window.google; - } - - if (typeof window[GoogleMapsLoader.WINDOW_CALLBACK_NAME] !== 'undefined') { - delete window[GoogleMapsLoader.WINDOW_CALLBACK_NAME]; - } - - if (originalCreateLoaderMethod !== null) { - GoogleMapsLoader.createLoader = originalCreateLoaderMethod; - originalCreateLoaderMethod = null; - } - - if (script !== null) { - script.parentElement.removeChild(script); - script = null; - } - - if (fn) { - fn(); - } - }; - - if (loading) { - GoogleMapsLoader.load(function() { - release(); - }); - } else { - release(); - } - }; - - - GoogleMapsLoader.onLoad = function(fn) { - onLoadEvents.push(fn); - }; - - - GoogleMapsLoader.makeMock = function() { - originalCreateLoaderMethod = GoogleMapsLoader.createLoader; - - GoogleMapsLoader.createLoader = function() { - window.google = GoogleMapsLoader._googleMockApiObject; - window[GoogleMapsLoader.WINDOW_CALLBACK_NAME](); - }; - }; - - - var ready = function(fn) { - var i; - - loading = false; - - if (google === null) { - google = window.google; - } - - for (i = 0; i < onLoadEvents.length; i++) { - onLoadEvents[i](google); - } - - if (fn) { - fn(google); - } - - for (i = 0; i < callbacks.length; i++) { - callbacks[i](google); - } - - callbacks = []; - }; - - - return GoogleMapsLoader; - -}); - -},{}]},{},[1]); diff --git a/assets/js/public/main.js b/assets/js/public/main.js new file mode 100644 index 0000000..af50a65 --- /dev/null +++ b/assets/js/public/main.js @@ -0,0 +1,450 @@ +jQuery(document).ready(function($) { + (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= toCenterDistance) { + markersInBoundsRange.push( markerLatLng ); + } + } + }); + + var mapBounds = map.getBounds(); + markersInBoundsRange.forEach( function(markerLatLng) { + mapBounds.extend( markerLatLng ); + }); + map.fitBounds( mapBounds, 20 ); + } + + + /* + * Get lat and long from browsers geolocation API + */ + if (window.location.protocol === 'https:' && "geolocation" in navigator) { + navigator.geolocation.getCurrentPosition( function (position) { + //Success + options.center = new google.maps.LatLng(position.coords.latitude, position.coords.longitude); + loadMap(); + + // add user marker on center of map + var marker = new google.maps.Marker({ + map: map, + position: { lat: options.center.lat(), lng: options.center.lng() }, + icon: userIcon + }); + userMarkers.push(marker); + }, function() { + //Error + loadMap(); + }); + } else { + //Geolocation API not available + loadMap(); + } + }); + + },{"google-maps":2}],2:[function(require,module,exports){ + (function(root, factory) { + + if (root === null) { + throw new Error('Google-maps package can be used only in browser'); + } + + if (typeof define === 'function' && define.amd) { + define(factory); + } else if (typeof exports === 'object') { + module.exports = factory(); + } else { + root.GoogleMapsLoader = factory(); + } + + })(typeof window !== 'undefined' ? window : null, function() { + + + 'use strict'; + + + var googleVersion = '3.18'; + + var script = null; + + var google = null; + + var loading = false; + + var callbacks = []; + + var onLoadEvents = []; + + var originalCreateLoaderMethod = null; + + + var GoogleMapsLoader = {}; + + + GoogleMapsLoader.URL = 'https://maps.googleapis.com/maps/api/js'; + + GoogleMapsLoader.KEY = null; + + GoogleMapsLoader.LIBRARIES = []; + + GoogleMapsLoader.CLIENT = null; + + GoogleMapsLoader.CHANNEL = null; + + GoogleMapsLoader.LANGUAGE = null; + + GoogleMapsLoader.REGION = null; + + GoogleMapsLoader.VERSION = googleVersion; + + GoogleMapsLoader.WINDOW_CALLBACK_NAME = '__google_maps_api_provider_initializator__'; + + + GoogleMapsLoader._googleMockApiObject = {}; + + + GoogleMapsLoader.load = function(fn) { + if (google === null) { + if (loading === true) { + if (fn) { + callbacks.push(fn); + } + } else { + loading = true; + + window[GoogleMapsLoader.WINDOW_CALLBACK_NAME] = function() { + ready(fn); + }; + + GoogleMapsLoader.createLoader(); + } + } else if (fn) { + fn(google); + } + }; + + + GoogleMapsLoader.createLoader = function() { + script = document.createElement('script'); + script.type = 'text/javascript'; + script.src = GoogleMapsLoader.createUrl(); + + document.body.appendChild(script); + }; + + + GoogleMapsLoader.isLoaded = function() { + return google !== null; + }; + + + GoogleMapsLoader.createUrl = function() { + var url = GoogleMapsLoader.URL; + + url += '?callback=' + GoogleMapsLoader.WINDOW_CALLBACK_NAME; + + if (GoogleMapsLoader.KEY) { + url += '&key=' + GoogleMapsLoader.KEY; + } + + if (GoogleMapsLoader.LIBRARIES.length > 0) { + url += '&libraries=' + GoogleMapsLoader.LIBRARIES.join(','); + } + + if (GoogleMapsLoader.CLIENT) { + url += '&client=' + GoogleMapsLoader.CLIENT + '&v=' + GoogleMapsLoader.VERSION; + } + + if (GoogleMapsLoader.CHANNEL) { + url += '&channel=' + GoogleMapsLoader.CHANNEL; + } + + if (GoogleMapsLoader.LANGUAGE) { + url += '&language=' + GoogleMapsLoader.LANGUAGE; + } + + if (GoogleMapsLoader.REGION) { + url += '®ion=' + GoogleMapsLoader.REGION; + } + + return url; + }; + + + GoogleMapsLoader.release = function(fn) { + var release = function() { + GoogleMapsLoader.KEY = null; + GoogleMapsLoader.LIBRARIES = []; + GoogleMapsLoader.CLIENT = null; + GoogleMapsLoader.CHANNEL = null; + GoogleMapsLoader.LANGUAGE = null; + GoogleMapsLoader.REGION = null; + GoogleMapsLoader.VERSION = googleVersion; + + google = null; + loading = false; + callbacks = []; + onLoadEvents = []; + + if (typeof window.google !== 'undefined') { + delete window.google; + } + + if (typeof window[GoogleMapsLoader.WINDOW_CALLBACK_NAME] !== 'undefined') { + delete window[GoogleMapsLoader.WINDOW_CALLBACK_NAME]; + } + + if (originalCreateLoaderMethod !== null) { + GoogleMapsLoader.createLoader = originalCreateLoaderMethod; + originalCreateLoaderMethod = null; + } + + if (script !== null) { + script.parentElement.removeChild(script); + script = null; + } + + if (fn) { + fn(); + } + }; + + if (loading) { + GoogleMapsLoader.load(function() { + release(); + }); + } else { + release(); + } + }; + + + GoogleMapsLoader.onLoad = function(fn) { + onLoadEvents.push(fn); + }; + + + GoogleMapsLoader.makeMock = function() { + originalCreateLoaderMethod = GoogleMapsLoader.createLoader; + + GoogleMapsLoader.createLoader = function() { + window.google = GoogleMapsLoader._googleMockApiObject; + window[GoogleMapsLoader.WINDOW_CALLBACK_NAME](); + }; + }; + + + var ready = function(fn) { + var i; + + loading = false; + + if (google === null) { + google = window.google; + } + + for (i = 0; i < onLoadEvents.length; i++) { + onLoadEvents[i](google); + } + + if (fn) { + fn(google); + } + + for (i = 0; i < callbacks.length; i++) { + callbacks[i](google); + } + + callbacks = []; + }; + + + return GoogleMapsLoader; + + }); + + },{}]},{},[1]); +}); \ No newline at end of file diff --git a/assets/js/public/oms.min.js b/assets/js/public/oms.min.js new file mode 100644 index 0000000..fb0d348 --- /dev/null +++ b/assets/js/public/oms.min.js @@ -0,0 +1,29 @@ +/* + OverlappingMarkerSpiderfier +https://github.com/jawj/OverlappingMarkerSpiderfier +Copyright (c) 2011 - 2017 George MacKerron +Released under the MIT licence: http://opensource.org/licenses/mit-license +Note: The Google Maps API v3 must be included *before* this code +*/ +(function(){var m,t,w,y,u,z={}.hasOwnProperty,A=[].slice;this.OverlappingMarkerSpiderfier=function(){function r(a,d){var b,f,e;this.map=a;null==d&&(d={});null==this.constructor.N&&(this.constructor.N=!0,h=google.maps,l=h.event,p=h.MapTypeId,c.keepSpiderfied=!1,c.ignoreMapClick=!1,c.markersWontHide=!1,c.markersWontMove=!1,c.basicFormatEvents=!1,c.nearbyDistance=20,c.circleSpiralSwitchover=9,c.circleFootSeparation=23,c.circleStartAngle=x/12,c.spiralFootSeparation=26,c.spiralLengthStart=11,c.spiralLengthFactor= +4,c.spiderfiedZIndex=h.Marker.MAX_ZINDEX+2E4,c.highlightedLegZIndex=h.Marker.MAX_ZINDEX+1E4,c.usualLegZIndex=h.Marker.MAX_ZINDEX+1,c.legWeight=1.5,c.legColors={usual:{},highlighted:{}},e=c.legColors.usual,f=c.legColors.highlighted,e[p.HYBRID]=e[p.SATELLITE]="#fff",f[p.HYBRID]=f[p.SATELLITE]="#f00",e[p.TERRAIN]=e[p.ROADMAP]="#444",f[p.TERRAIN]=f[p.ROADMAP]="#f00",this.constructor.j=function(a){return this.setMap(a)},this.constructor.j.prototype=new h.OverlayView,this.constructor.j.prototype.draw=function(){}); +for(b in d)z.call(d,b)&&(f=d[b],this[b]=f);this.g=new this.constructor.j(this.map);this.C();this.c={};this.B=this.l=null;this.addListener("click",function(a,b){return l.trigger(a,"spider_click",b)});this.addListener("format",function(a,b){return l.trigger(a,"spider_format",b)});this.ignoreMapClick||l.addListener(this.map,"click",function(a){return function(){return a.unspiderfy()}}(this));l.addListener(this.map,"maptypeid_changed",function(a){return function(){return a.unspiderfy()}}(this));l.addListener(this.map, +"zoom_changed",function(a){return function(){a.unspiderfy();if(!a.basicFormatEvents)return a.h()}}(this))}var l,h,m,v,p,c,t,x,u;c=r.prototype;t=[r,c];m=0;for(v=t.length;md)return this;g=this.s.splice(d,1)[0];b=0;for(f=g.length;bb||this.c[a].splice(b,1);return this};c.clearListeners=function(a){this.c[a]=[];return this};c.trigger=function(){var a,d,b,f,e,g;d=arguments[0];a=2<=arguments.length?A.call(arguments,1):[];d=null!=(b=this.c[d])?b:[];g=[];f=0;for(e=d.length;fa;b=0<=a?++e:--e)b= +this.circleStartAngle+b*f,c.push(new h.Point(d.x+g*Math.cos(b),d.y+g*Math.sin(b)));return c};c.M=function(a,d){var b,f,e,c,k;c=this.spiralLengthStart;b=0;k=[];for(f=e=0;0<=a?ea;f=0<=a?++e:--e)b+=this.spiralFootSeparation/c+5E-4*f,f=new h.Point(d.x+c*Math.cos(b),d.y+c*Math.sin(b)),c+=x*this.spiralLengthFactor/b,k.push(f);return k};c.V=function(a,d){var b,f,e,c,k,q,n,l,h;(q=null!=a._omsData)&&this.keepSpiderfied||this.unspiderfy();if(q||this.map.getStreetView().getVisible()||"GoogleEarthAPI"=== +this.map.getMapTypeId())return this.trigger("click",a,d);q=[];n=[];b=this.nearbyDistance;l=b*b;k=this.f(a.position);h=this.a;b=0;for(f=h.length;b=this.circleSpiralSwitchover?this.M(r,b).reverse():this.L(r,b);b=function(){var b,d,f;f=[];b=0;for(d=g.length;b

' + location.post_title + '

' + - '

' + '' + streetNumber + ' ' + streetName + '
' + cityName + ', ' + stateName + ' ' + countryName + ' ' + zip + '

' + - '

' - }); - - marker.addListener('click', function() { - infoWindow.open(map, marker); - }); - - } - }); - } - }); - }); diff --git a/includes/class-obj-admin.php b/includes/class-obj-admin.php index 7dbaaee..00d9322 100644 --- a/includes/class-obj-admin.php +++ b/includes/class-obj-admin.php @@ -1,9 +1,6 @@ file = $file; + $this->file = $file; $this->dir = dirname( $file ); + $this->uibuilder = new Obj_Gmaps_UIBuilder( 'obj_location' ); + $this->datavalidator = new Obj_Gmaps_DataValidator(); + $this->maps_api_key = get_option( 'obj_maps_api_key' ); + $this->geocode_api_key = get_option( 'obj_geocode_api_key' ); - // Activation and Deactivation Hooks - register_activation_hook( $file, array( $this, 'activate_plugin' ) ); + // Activation and Deactivation Hooks + register_activation_hook( $file, array( $this, 'activate_plugin' ) ); register_deactivation_hook( $file, array( $this, 'deactivate_plugin' ) ); if ( is_admin() ) { add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_js' ) ); add_action( 'admin_init', array( $this, 'metaboxes_setup' ) ); - add_action( 'save_post', array( $this, 'save_location_lat_long' ), 10, 3 ); } + } - } - - /** - * Activation callback - */ - public function activate_plugin() { - flush_rewrite_rules(); - } + /** + * Activation callback + */ + public function activate_plugin() { + flush_rewrite_rules(); + } - /** - * Deactivation Callback - */ - public function deactivate_plugin() { - flush_rewrite_rules(); - } + /** + * Deactivation Callback + */ + public function deactivate_plugin() { + flush_rewrite_rules(); + } /** - * Enqueue JS - * - * @since 1.0 - */ - public function enqueue_js( $hook ) { + * Enqueue JS + * + * @since 1.0 + */ + public function enqueue_js( $hook ) { $screen = get_current_screen(); $selected_post_type = get_option( 'obj_post_type' ); - $data_array = array( - 'api_key' => get_option( 'obj_api_key' ) - ); - if ( $hook == 'settings_page_obj_google_map_settings' || $screen->post_type == $selected_post_type ) { - wp_enqueue_script( 'obj-google-maps-admin', plugins_url( '/assets/js/admin/build/main.js', $this->file ), array(), $this->version, true ); - wp_localize_script( 'obj-google-maps-admin', 'data', $data_array ); + wp_localize_script( 'obj-google-maps-admin', 'objGoogleMapData', array( 'api_key' => $this->api_key ) ); + wp_enqueue_script( 'obj-google-maps-admin', plugins_url( '/assets/js/admin/main.js', $this->file ), false, $this->version, true ); } - - } + } /** * Register address metabox @@ -73,8 +68,12 @@ public function enqueue_js( $hook ) { */ public function metaboxes_setup () { $selected_post_type = get_option( 'obj_post_type' ); - add_action( 'add_meta_boxes_' . $selected_post_type, array( $this, 'create_metabox' ), 10, 1 ); - add_action( 'save_post', array( $this, 'save_metabox' ), 10, 2 ); + if( !empty($selected_post_type) ) { + add_action( 'add_meta_boxes_'.$selected_post_type, array( $this, 'create_metabox' ), 10, 1 ); + add_action( 'save_post_'.$selected_post_type, array( $this, 'save_post_validate' ), 9, 2 ); + add_action( 'save_post_'.$selected_post_type, array( $this, 'verify_wp_nonces' ), 10, 2 ); + add_action( 'save_post_'.$selected_post_type, array( $this, 'save_metabox' ), 11, 1 ); + } } /** @@ -99,44 +98,128 @@ public function create_metabox( $post ) { * @since 1.0 */ public function metabox_content( $object ) { - wp_nonce_field( plugin_basename( $this->dir ), 'obj_google_address_nonce' ); - $data = array(); + wp_nonce_field( 'obj_google_save', 'obj_google_save_nonce_'.$object->ID ); + + $lat = get_post_meta( $object->ID, 'obj_location_lat', true ); + if( empty($lat) ) + $lat = 'Not set. Marker will not appear on map. Save the post to try geocoding the address again.'; + $lng = get_post_meta( $object->ID, 'obj_location_lng', true ); + if( empty($lng) ) + $lng = 'Not set. Marker will not appear on map. Save the post to try geocoding the address again.'; ?> -

- -
- -

+ + + + + + + + + + + + + + + $field_array ) { + if( empty($field_array['type']) || empty($field_array['label']) + || !is_callable( array($this->uibuilder, $field_array['type']) ) ) + continue; + + $meta_value = get_post_meta( $object->ID, $this->uibuilder->get_name_id($meta_key), true ); + ?> + + + + + + +
+ + + +
+ + + +
+ + + +
+ + + uibuilder->{$field_array['type']}( $meta_key, $meta_value, 'widefat' ); ?> +
is_valid_post_save($post) ) { + //Remove post saving actions + $post_type = $post->post_type; + remove_action( 'save_post_'.$post_type, array( $this, 'verify_wp_nonces' ), 10 ); + remove_action( 'save_post_'.$post_type, array( $this, 'save_metabox' ), 11 ); + } } - function save_location_lat_long( $post_id, $post, $update ) { + private function is_valid_post_save($post) { + //Check for auto saves, creating a new post, no post array, and unhandled post types + if( is_array($post) ) + $post = (object) $post; + if( empty($_POST) + || 'auto-draft' == $post->post_status + || 'trash' == $post->post_status + || (defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE) ) + return false; + return true; + } - $post_type = get_post_type($post_id); + public function verify_wp_nonces( $post_id, $post ) { + if( !$this->is_valid_post_save($post) ) + return; //Do nothing + + if( !isset( $_POST['obj_google_save_nonce_'.$post_id] ) ) + $this->display_error('verify_nonce', 'Unable to verify security nonce.'); + + check_admin_referer( 'obj_google_save', 'obj_google_save_nonce_'.$post_id ); + } - // If this isn't a 'book' post, don't update it. - if ( get_option( 'obj_post_type' ) != $post_type ) return; + public function save_location_lat_long( $post_id, $address ) { + // - Update the post's metadata. + if ( !empty($address) ) { + $string = str_replace (" ", "+", urlencode( $address ) ); + $url = "https://maps.googleapis.com/maps/api/geocode/json?address=".$string; + if( !empty( $this->geocode_api_key) ) + $url .= '&key='.urlencode($this->geocode_api_key); - // - Update the post's metadata. - if ( isset( $_POST['obj-google-address'] ) ) { - $address = $_POST['obj-google-address']; - $string = str_replace (" ", "+", urlencode( $address ) ); - $url = "http://maps.googleapis.com/maps/api/geocode/json?address=".$string."&sensor=false"; + $response = wp_remote_get( $url ); + $data = wp_remote_retrieve_body( $response ); + $output = json_decode( $data ); - $response = wp_remote_get( $url ); - $data = wp_remote_retrieve_body( $response ); - $output = json_decode( $data ); - if (!empty($output) && $output->status == 'OK') { + if ( !empty($output) && $output->status == 'OK' ) { $address_components = $output->results[0]->address_components; - $geometry = $output->results[0]->geometry; - $longitude = $geometry->location->lng; - $latitude = $geometry->location->lat; + $geometry = $output->results[0]->geometry; + $latitude = $geometry->location->lat; + $longitude = $geometry->location->lng; update_post_meta( $post_id, 'obj_location_address_components', $address_components ); - update_post_meta( $post_id, 'obj_location_lat', $latitude ); - update_post_meta( $post_id, 'obj_location_lng', $longitude ); - } - } + update_post_meta( $post_id, 'obj_location_lat', $latitude ); + update_post_meta( $post_id, 'obj_location_lng', $longitude ); + return true; + } + } + + delete_post_meta( $post_id, 'obj_location_address_components' ); + delete_post_meta( $post_id, 'obj_location_lat' ); + delete_post_meta( $post_id, 'obj_location_lng' ); + return false; } /** @@ -144,15 +227,75 @@ function save_location_lat_long( $post_id, $post, $update ) { * * @since 1.0 */ - public function save_metabox( $post_id, $post ) { + public function save_metabox( $post_id ) { + //Save location address + $new_address = ''; + $address = get_post_meta( $post_id, 'obj_google_address', true ); + $address_components = get_post_meta( $post_id, 'obj_location_address_components', true ); + $latitude = get_post_meta( $post_id, 'obj_location_lat', true ); + $longitude = get_post_meta( $post_id, 'obj_location_lng', true ); + if( isset( $_POST['obj-google-address'] ) ) + $new_address = sanitize_text_field( $_POST['obj-google-address'] ); + //Prevent resaves from regeocoding address if lat and lng already exist + if( $new_address != $address || empty( $address_components ) || empty( $latitude ) || empty( $longitude ) ) { + update_post_meta( $post_id, 'obj_google_address', $new_address ); + $this->save_location_lat_long( $post_id, $new_address ); + } - $selected_post_type = get_option( 'obj_post_type' ); + //Save location post meta + $custom_post_meta = array(); + $custom_post_meta = apply_filters( 'obj_location_post_meta', $custom_post_meta ); + // Supported field types: date, time, textbox, url, email, hidden, tel, textarea + // TODO: Add support for checkbox, number, and selectbox field types. UI functions exist but the saving logic below will not work for them. + $errors = array(); + foreach( $custom_post_meta as $meta_key => $field_array ) { + $meta_value = ''; + if( isset( $_POST[$this->uibuilder->get_name_id($meta_key)] ) ) { + $meta_value = trim( $_POST[$this->uibuilder->get_name_id($meta_key)] ); + if( !empty( $meta_value ) ) { + switch( $field_array['type'] ) { + case 'textbox': + case 'hidden': + case 'tel': + $meta_value = sanitize_text_field( $meta_value ); + break; + case 'date': + if( !$this->datavalidator->validate_date( $meta_value ) ) { + $meta_value = ''; + $errors[] = $field_array['label'] . ': Please enter a valid date in YYYY-MM-DD format.'; + } + break; + case 'time': + if( !$this->datavalidator->validate_time( $meta_value ) ) { + $meta_value = ''; + $errors[] = $field_array['label'] . ': Please enter a valid time in HH:MM format.'; + } + break; + case 'url': + $meta_value = $this->datavalidator->sanitize_url( $meta_value, array( 'http', 'https' ) ); + break; + case 'email': + if( !$this->datavalidator->validate_email( $meta_value ) ) { + $meta_value = ''; + $errors[] = $field_array['label'] . ': Please enter a valid email address.'; + } + break; + case 'textarea': + $meta_value = wp_filter_kses( $meta_value ); + break; + } + } + } + update_post_meta( $post_id, $this->uibuilder->get_name_id($meta_key), $meta_value ); + } - $new_meta_value = ( isset( $_POST['obj-google-address'] ) ? sanitize_text_field( $_POST['obj-google-address'] ) : '' ); - $new_place_id_value = ( isset( $_POST['obj-google-address-place-id'] ) ? sanitize_text_field( $_POST['obj-google-address-place-id'] ) : '' ); - $meta_key = 'obj_google_address'; - $meta_value = get_post_meta( $post_id, $meta_key, true ); - update_post_meta( $post_id, $meta_key, $new_meta_value ); + if( !empty( $errors ) ) { + $errors = "
\n" . implode( "
\n", $errors ); + $this->display_error('location_meta', $errors); + } } + private function display_error($code, $message) { + wp_die( new WP_Error('obj_google_'.$code, 'Objectiv Google Maps: '.$message) ); + } } diff --git a/includes/class-obj-data-validator.php b/includes/class-obj-data-validator.php new file mode 100644 index 0000000..9843fef --- /dev/null +++ b/includes/class-obj-data-validator.php @@ -0,0 +1,137 @@ +filter_exists('url') ) { + $url = filter_var($url, FILTER_SANITIZE_URL); + } else { + $url = preg_replace( '|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i', '', $url ); + $url = $this->deep_replace( array('%0d', '%0a', '%0D', '%0A'), $url ); + } + if( empty($url) ) + return false; + + //Fix common mistakes + $url = str_replace(';//', '://', $url); + + //Append http:// if protocol is missing and http is allowed + if( false === strpos($url, ':') ) { + if( in_array('http', $protocols) ) + return 'http://' . $url; + return false; + } + + //Verify protocol is valid + foreach( $protocols as $protocol ) { + if( 0 == strcasecmp( $protocol, substr($url, 0, strlen($protocol)) ) ) + return $url; + } + + return false; + } + + public function validate_email ($email_string) { + if( $this->filter_exists('validate_email') ) + return filter_var($email_string, FILTER_VALIDATE_EMAIL); + + //Emails must be at least 3 characters and @ must appear somewhere after the first character + if( 3 > strlen($email_string) + || false === strpos( $email_string, '@', 1 ) ) + return false; + + list( $local, $domain ) = explode( '@', $email_string, 2 ); + + //Check for invalid characters in local + if( !preg_match( '/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$/', $local ) ) + return false; + + //Check for valid domain period syntax + if( preg_match( '/\.{2,}/', $domain ) + || $domain != trim( $domain, " \t\n\r\0\x0B." ) ) + return false; + + $namespaces = explode( '.', $domain ); + + //Domain must have at least 2 namespaces + if( 2 > count( $namespaces ) ) + return false; + + foreach( $namespaces as $namespace ) { + //Check for invalid characters in namespace + if( $namespace !== trim( $namespace, " \t\n\r\0\x0B-" ) + || !preg_match('/^[a-z0-9-]+$/i', $namespace) ) + return false; + } + + return true; + } + + private function deep_replace ($search, $subject) { + $subject = (string) $subject; + + $count = 1; + while ( $count ) { + $subject = str_replace( $search, '', $subject, $count ); + } + + return $subject; + } +} + \ No newline at end of file diff --git a/includes/class-obj-public.php b/includes/class-obj-public.php index 2aa3449..a1713f9 100644 --- a/includes/class-obj-public.php +++ b/includes/class-obj-public.php @@ -1,9 +1,6 @@ file = $file; - $this->version = $version; + public function __construct( $file, $version ) { + $this->file = $file; + $this->version = $version; - add_action( 'init', array( $this, 'add_map_shortcode' ) ); - add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_js' ) ); - - } + add_action( 'init', array( $this, 'add_map_shortcode' ) ); + add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_js' ) ); + } /** - * Enqueue JS - * - * @since 1.0 - */ - public function enqueue_js() { - - if ( obj_has_shortcode( 'objectiv_google_maps' ) ) { - wp_enqueue_script( 'obj-google-maps', plugins_url( '/assets/js/build/main.js', $this->file ), array(), $this->version, true ); + * Enqueue JS + * + * @since 1.0 + */ + public function enqueue_js() { + if ( obj_has_shortcode( 'objectiv_google_maps' ) ) { + wp_enqueue_script( 'obj-google-maps-oms', plugins_url( '/assets/js/public/oms.min.js', $this->file ), false, $this->version ); + wp_enqueue_script( 'obj-google-maps', plugins_url( '/assets/js/public/main.js', $this->file ), array('jquery', 'obj-google-maps-oms'), $this->version, true ); wp_enqueue_style( 'obj-google-maps-style', plugins_url( '/assets/css/public/public.css', $this->file ), array(), $this->version ); - } - - } - - /** - * Add map shortcode - * - * @since 1.0 - */ - public function add_map_shortcode() { - - add_shortcode( 'objectiv_google_maps', array( $this, 'map_shortcode_markup' ) ); + } + } - } + /** + * Add map shortcode + * + * @since 1.0 + */ + public function add_map_shortcode() { + add_shortcode( 'objectiv_google_maps', array( $this, 'map_shortcode_markup' ) ); + } - /** - * Create Map Shortcode Markup - * - * @since 1.0 - */ - public function map_shortcode_markup() { + /** + * Create Map Shortcode Markup + * + * @since 1.0 + */ + public function map_shortcode_markup() { $selected_post_type = get_option( 'obj_post_type' ); $height = get_option( 'obj_map_height' ); $search_by = get_option( 'obj_map_search_by' ); @@ -63,7 +55,18 @@ public function map_shortcode_markup() { $posts_arg = array( 'post_type' => $selected_post_type, - 'posts_per_page' => -1 + 'posts_per_page' => -1, + 'meta_query' => array( + 'relation' => 'AND', + array( + 'key' => 'obj_location_lat', + 'compare' => 'EXISTS' + ), + array( + 'key' => 'obj_location_lng', + 'compare' => 'EXISTS' + ) + ) ); $post_type_object = get_post_type_object( $selected_post_type ); @@ -71,31 +74,67 @@ public function map_shortcode_markup() { $posts = get_posts( $posts_arg ); + $location_pin_content_template = dirname( __FILE__ ) . '/../templates/obj-map-location-pin-content.php'; + if( $overridden_template = locate_template( 'obj-map-location-pin-content.php' ) ) + $location_pin_content_template = $overridden_template; + + $post_meta_to_load = array(); + $post_meta_to_load = array_keys( apply_filters( 'obj_location_post_meta', $post_meta_to_load ) ); + + $locations = array(); foreach( $posts as $key => $post ) { $lat = get_post_meta( $post->ID, 'obj_location_lat', true ); + $lat = filter_var( $lat, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION ); $lng = get_post_meta( $post->ID, 'obj_location_lng', true ); + $lng = filter_var( $lng, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION ); if ( $lat && $lng ) { - $posts[$key]->lat = $lat; - $posts[$key]->lng = $lng; - $posts[$key]->permalink = get_the_permalink( $post->ID ); - $posts[$key]->post_type_label = $post_type_object_labels->singular_name; - $posts[$key]->address = get_post_meta( $post->ID, 'obj_google_address', true ); - $posts[$key]->address_components = get_post_meta( $post->ID, 'obj_location_address_components', true ); + $address_components = get_post_meta( $post->ID, 'obj_location_address_components', true ); + $template_variables = $this->rekey_address_components_array( $address_components ); + $template_variables['lat'] = $lat; + $template_variables['lng'] = $lng; + $template_variables['post_id'] = $post->ID; + $template_variables['post_title'] = trim( $post->post_title ); + $template_variables['post_excerpt'] = trim( $post->post_excerpt ); + $template_variables['post_content'] = trim( $post->post_content ); + $template_variables['post_type_label'] = $post_type_object_labels->singular_name; + $template_variables['permalink'] = get_the_permalink( $post->ID ); + + foreach( $post_meta_to_load as $post_meta_key ) + $template_variables[$post_meta_key] = get_post_meta( $post->ID, 'obj_location_'.$post_meta_key, true ); + + extract( $template_variables, EXTR_OVERWRITE|EXTR_PREFIX_ALL, 'obj_location' ); + ob_start(); + include "$location_pin_content_template"; + $location_pin_content = ob_get_clean(); + foreach( array_keys($template_variables) as $key ) { + $key = 'obj_location_' . $key; + unset($$key); + } + + $location = new StdClass; + $location->lat = $lat; + $location->lng = $lng; + $location->title = htmlspecialchars( trim( $post->post_title ) ); + $location->content = $location_pin_content; + + $locations[] = $location; } } $data_array = array( - 'apiKey' => get_option( 'obj_api_key' ), + 'apiKey' => get_option( 'obj_maps_api_key' ), 'mapType' => get_option( 'obj_map_type' ), - 'mapCenter' => get_option( 'obj_map_center' ), - 'mapCenterAddressCompnents' => wp_cache_get( 'obj_map_center_address_components' ), - 'mapCenterLat' => wp_cache_get( 'obj_map_center_lat' ), - 'mapCenterLng' => wp_cache_get( 'obj_map_center_lng' ), + 'mapCenter' => get_option( 'obj_map_center' ), + 'mapCenterLat' => filter_var( wp_cache_get( 'obj_map_center_lat' ), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION ), + 'mapCenterLng' => filter_var( wp_cache_get( 'obj_map_center_lng' ), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION ), 'mapZoom' => get_option( 'obj_map_zoom' ), 'mapSearch' => get_option( 'obj_map_search_by' ), - 'mapLocationIcon' => get_option( 'obj_map_location_icon' ), - 'locations' => $posts + 'userIcon' => plugins_url( '/assets/images/pegman.png', $this->file ), + 'locationIcon' => plugins_url( '/assets/images/dot_pinlet.png', $this->file ), + 'spiderLocationIcon' => plugins_url( '/assets/images/dot_pinlet_spider.png', $this->file ), + 'activeLocationIcon' => plugins_url( '/assets/images/spotlight_pin.png', $this->file ), + 'locations' => $locations ); if( !empty( $data_array['mapCenter'] ) @@ -104,7 +143,7 @@ public function map_shortcode_markup() { } if ( obj_has_shortcode( 'objectiv_google_maps' ) ) { - wp_localize_script( 'obj-google-maps', 'data', $data_array ); + wp_localize_script( 'obj-google-maps', 'objGoogleMapData', $data_array ); } if ( $search_by == 'geocode' ) { @@ -120,16 +159,15 @@ public function map_shortcode_markup() { } - ob_start(); + ob_start(); echo '
'; - echo ''; - echo '
'; + echo ''; + echo '
'; echo '
'; - return ob_get_clean(); - - } + return ob_get_clean(); + } private function update_center_lat_long_cache( &$data_array ) { $string = str_replace (" ", "+", urlencode( $data_array['mapCenter'] ) ); @@ -143,12 +181,24 @@ private function update_center_lat_long_cache( &$data_array ) { $geometry = $output->results[0]->geometry; $longitude = $geometry->location->lng; $latitude = $geometry->location->lat; - wp_cache_set( 'obj_map_center_address_components', $address_components ); wp_cache_set( 'obj_map_center_lat', $latitude ); wp_cache_set( 'obj_map_center_lng', $longitude ); - $data_array['mapCenterAddressCompnents'] = $address_components; $data_array['mapCenterLat'] = $latitude; $data_array['mapCenterLng'] = $longitude; } } + + private function rekey_address_components_array( $raw_address_components ) { + $address_components = array(); + foreach( $raw_address_components as $component ) { + $key = $component->types[0]; + $value = $component->long_name; + if( !empty( $component->short_name ) ) + $value = $component->short_name; + + $address_components[$key] = $value; + } + + return $address_components; + } } diff --git a/includes/class-obj-settings.php b/includes/class-obj-settings.php index 31b4bb1..8eaaa7a 100644 --- a/includes/class-obj-settings.php +++ b/includes/class-obj-settings.php @@ -1,9 +1,6 @@ id == 'settings_page_obj_google_map_settings' ) { - wp_enqueue_style( 'obj-google-maps-admin-css', plugins_url( '/assets/css/admin/admin.css', $this->file ), array(), $this->version ); + wp_enqueue_style( 'obj-google-maps-admin-css', plugins_url( '/assets/css/admin/admin.css', $this->file ), false, $this->version ); } } @@ -186,18 +183,22 @@ private function settings_fields() { 'default' => 'address' ), array( - 'id' => 'map_location_icon', - 'label' => __( 'Location Icon', 'obj-google-maps' ), - 'description' => __( 'Display an icon on the location that was searched for.' ), - 'type' => 'checkbox' + 'id' => 'maps_api_key', + 'label' => __( 'Google Maps Javascript API Key', 'obj-google-maps' ), + 'description' => __( 'Enter the Google Maps Javascript API Key to use this plugin.', 'obj-google-maps' ), + 'type' => 'text', + 'default' => '', + 'placeholder' => __( 'Google Maps Javascript API Key', 'obj-google-maps' ), + 'class' => 'regular-text', + 'callback' => 'wp_strip_all_tags' ), array( - 'id' => 'api_key', - 'label' => __( 'Google API Key', 'obj-google-maps' ), - 'description' => __( 'Enter the Google API key to use this plugin.', 'obj-google-maps' ), + 'id' => 'geocode_api_key', + 'label' => __( 'Google Maps Geocode API Key', 'obj-google-maps' ), + 'description' => __( 'Enter the Google Maps Geocode API Key to use this plugin.', 'obj-google-maps' ), 'type' => 'text', 'default' => '', - 'placeholder' => __( 'Google API Key', 'obj-google-maps' ), + 'placeholder' => __( 'Google Maps Geocode API Key', 'obj-google-maps' ), 'class' => 'regular-text', 'callback' => 'wp_strip_all_tags' ) diff --git a/includes/class-obj-uibuilder.php b/includes/class-obj-uibuilder.php new file mode 100644 index 0000000..0ba563b --- /dev/null +++ b/includes/class-obj-uibuilder.php @@ -0,0 +1,378 @@ +name_id_prefix = $name_id_prefix; + } + + public function get_name_id( $field_name ) { + return $this->name_id_prefix.'_'.$field_name; + } + + /* + * Function name: selectbox + * Purpose: Builds and echos html for a selectbox. + * Agruements: + * -$field_name: Value of name attribute for form submission. + * Doubles as the field's id. + * -$options: An array of options to populate the selectbox with. + * Formatted as value => text. + * -$selected: Value of option to be selected by default.' + * If multiple is true, this can be an array of values. + * -$default_option: Text to be displayed in the default option. + * Blank or false for no default option. + * -$multiple: Boolean value indicates that multiple options can be selected. + */ + public function selectbox( $field_name, $options, $class=false, $selected='', + $default_option='Select an option', + $use_prefix=true, $multiple=false, $disabled=false ) { + + $field_name_id = $field_name; + if( $use_prefix ) + $field_name_id = $this->get_name_id($field_name); + $field_name = $field_name_id; + $field_id = $field_name_id; + if( $multiple ) + $field_name .= '[]'; + + $attrs = ''; + if( $multiple ) + $attrs[] .= 'multiple="multiple"'; + if( $disabled ) + $attrs[] .= 'disabled="disabled"'; + if( $class ) + $attrs[] .= 'class="'.$class.'"'; + $attrs = implode(' ', $attrs); + + if( !is_array($selected) ) + $selected = array($selected); + + $output = ''."\n"; + + echo $output; + } + + /* + * Function name: selectbox_posts + * Purpose: Builds and echos html for a selectbox to select a post id. + * Agruements: + * -$field_name: Value of name attribute for form submission. + * Doubles as the field's id. + * -$posts: An array of WP Post objects to populate selectbox options. + * -$selected: Value of option to be selected by default. + * -$default_option: Text to be displayed in the default option. + * Blank or false for no default option. + */ + public function selectbox_posts( $field_name, $posts, $class='', $selected='', + $default_option='Select an option', + $use_prefix=true, $multiple=false ) { + //Do nothing if no posts were provided + if( empty($posts) || !is_array($posts) ) + return; + + //Format post array into select options + $options = array(); + foreach( $posts as $post_obj ) { + $options[$post_obj->ID] = $post_obj->post_title; + } + + //Output selectbox + $this->selectbox( $field_name, $options, $selected, + $default_option, $use_prefix, $multiple, $class); + } + + /* + * Function name: selectbox_terms + * Purpose: Builds and echos html for a selectbox to select a term id + * Agruements: + * -$field_name: Value of name attribute for form submission. + * Doubles as the field's id. + * -$terms: An array of WP Term objects to populate selectbox options. + * -$selected: Value of option to be selected by default. + * -$default_option: Text to be displayed in the default option. + * Blank or false for no default option. + */ + public function selectbox_terms( $field_name, $terms, $class='', $selected='', + $default_option='Select an option', + $use_prefix=true, $multiple=false ) { + //Do nothing if no posts were provided + if( empty($terms) || !is_array($terms) ) + return; + + //Format post array into select options + $options = array(); + foreach( $terms as $term_obj ) { + $options[$term_obj->term_id] = $term_obj->name; + } + + //Output selectbox + $this->selectbox( $field_name, $options, $selected, + $default_option, $use_prefix, $multiple, $class); + } + + /* + * Function name: date + * Purpose: Builds and echos html for a date selector. + * Arguements: + * -$field_name: Value of name attribute for form submission. + * -$value: Initial value of the date field. + */ + public function date($field_name, $value='', $class='' ) { + $field_name_id = $this->get_name_id($field_name); + + $output = ''; + + echo $output; + } + + /* + * Function name: time + * Purpose: Builds and echos html for a time selector. + * Arguements: + * -$field_name: Value of name attribute for form submission. + * -$value: Initial value of the date field. + */ + public function time($field_name, $value='', $class='' ) { + $field_name_id = $this->get_name_id($field_name); + + $output = ''; + + echo $output; + } + + /* + * Function name: textbox + * Purpose: Builds and echos html for a textbox. + * Arguements: + * -$field_name: Value of name attribute for form submission. + * -$value: Initial value of the text field. + */ + public function textbox($field_name, $value='', $class='' ) { + $field_name_id = $this->get_name_id($field_name); + + $output = ''; + + echo $output; + } + + /* + * Function name: url + * Purpose: Builds and echos html for a url field. + * Arguements: + * -$field_name: Value of name attribute for form submission. + * -$value: Initial value of the url field. + */ + public function url($field_name, $value='', $class='' ) { + $field_name_id = $this->get_name_id($field_name); + + $output = ''; + + echo $output; + } + + /* + * Function name: email + * Purpose: Builds and echos html for an email field. + * Arguements: + * -$field_name: Value of name attribute for form submission. + * -$value: Initial value of the email field. + */ + public function email($field_name, $value='', $class='' ) { + $field_name_id = $this->get_name_id($field_name); + + $output = ''; + + echo $output; + } + + /* + * Function name: tel + * Purpose: Builds and echos html for a tel field. + * Arguements: + * -$field_name: Value of name attribute for form submission. + * -$value: Initial value of the tel field. + */ + public function tel($field_name, $value='', $class='', $attrs = '' ) { + $field_name_id = $this->get_name_id($field_name); + + $output = ''; + + echo $output; + } + + /* + * Function name: hidden + * Purpose: Builds and echos html for a hidden field. + * Arguements: + * -$field_name: Value of name attribute for form submission. + * -$value: Initial value of the hidden field. + */ + public function hidden($field_name, $value='', $class='' ) { + $field_name_id = $this->get_name_id($field_name); + + $output = ''; + + echo $output; + } + + /* + * Function name: checkbox + * Purpose: Builds and echos html for a checkbox. + * Arguements: + * -$field_name: Value of name attribute for form submission. + * -$value: Value of the checkbox. + * -$checked: Whether the checkbox is checked by default. + */ + public function checkbox($field_name, $value='', $class='', $checked=false ) { + $field_name_id = $this->get_name_id($field_name); + + if( $checked ) $checked = ' checked="checked"'; + else $checked = ''; + + $output = ''; + + echo $output; + } + + /* + * Function name: number + * Purpose: Builds and echos html for a number field. + * Arguements: + * -$field_name: Value of name attribute for form submission. + * Doubles as the field's id. + * -$value: Initial value of the number field. + * Must be a $step value inside the $min to $max range. + * -$step: Number to increment by starting with $min. + * -$min: Minimum allowed numeric value, inclusive. + * -$max: Maximum allowed numeric value, inclusive. + */ + public function number($field_name, $value=0, $class='', $step=1, $min='', $max='') { + //Validate and correct arguements + if(empty($value)) + $value = 0; + if(empty($step)) + $step = 1; + + //Ensure numbers were passed into the arguements + if(!empty($value)) + $value = (float) $value; + if(!empty($step)) + $step = (float) $step; + if(!empty($min)) + $min = (float) $min; + if(!empty($max)) + $max = (float) $max; + + //Correct initial value of field + if(!empty($min) && $value < $min) + $value = $min; + elseif(!empty($max) && $value > $max) + $value = $max; + elseif(!empty($min) && ($value - $min) % $step != 0) { + //Round down to nearest step + $num_steps = floor(($value - $min) / $step); + $value = $min + ($step * $num_steps); + } + + $field_name_id = $this->get_name_id($field_name); + + $output = ''; + + echo $output; + } + + /* + * Function name: file + * Purpose: Builds and echos html for a file field. + * Arguements: + * -$field_name: Value of name attribute for form submission. + * -$accept: Comma separated string or array of valid file extensions or mime types + * -$max-size: Maximum file size in bytes. For JS form validation. + * -$class: Value of class attribute. + * -$ajax_url: URL to be used by AJAX scripts for uploading the file. + */ + public function file($field_name, $accept='', $max_size='', $class='', $ajax_url='') { + $field_name_id = $this->get_name_id($field_name); + + $output = ''; + + echo $output; + } + + /* + * Function name: textarea + * Purpose: Builds and echos html for a textarea. + * Arguements: + * -$field_name: Value of name attribute for form submission. + * -$value: Initial value of the textarea. + */ + public function textarea($field_name, $value='', $class='') { + $field_name_id = $this->get_name_id($field_name); + + $output = ''; + + echo $output; + } + + /* + * Function name: submit + * Purpose: Builds and echos html for a submit button. + * Arguements: + * -$field_name: Value of name attribute for form submission. + * -$value: Value of the submit button. + */ + public function submit($field_name, $value='Submit', $class='') { + $field_name_id = $this->get_name_id($field_name); + + $output = ''; + + echo $output; + } + + /* + * Function name: tinymce_box + * Purpose: Builds and echos html for a TinyMCE WYSIWYG editor. + * Arguements: + * -$field_name: Value of name attribute for form submission. + * Doubles as the field's id. + * -$value: String containing html to rendered by TinyMCE. + */ + public function tinymce_editor($field_name, $value='', $tinymce_settings=array()) { + wp_editor($value, $this->get_name_id($field_name), $tinymce_settings); + } +} \ No newline at end of file diff --git a/includes/obj-functions.php b/includes/obj-functions.php index 169ebd7..0f6b35b 100644 --- a/includes/obj-functions.php +++ b/includes/obj-functions.php @@ -1,4 +1,6 @@ ID ); $found = false; @@ -20,5 +21,4 @@ function obj_has_shortcode( $shortcode = '' ) { $found = true; return $found; - } diff --git a/obj-google-maps.php b/obj-google-maps.php index f3e921c..bfcedf4 100644 --- a/obj-google-maps.php +++ b/obj-google-maps.php @@ -3,7 +3,7 @@ Plugin Name: Objectiv Google Maps Plugin URI: http://objectiv.co Description: Create searchable Google maps -Version: 1.2 +Version: 2.0 Author: Objectiv, Matthew Sigley Author URI: http://objectiv.co License: GPL2 @@ -24,18 +24,23 @@ along with Objectiv Google Maps. If not, see https://www.gnu.org/licenses/gpl-2.0.html. */ -if ( ! defined( 'ABSPATH' ) ) { - exit; -} +// Prevent direct access +defined( 'WPINC' ) || header( 'HTTP/1.1 403' ) & exit; + +class Obj_Gmaps { -$version = 1.1; + function __construct () { + require_once 'includes/class-obj-admin.php'; + require_once 'includes/class-obj-settings.php'; + require_once 'includes/class-obj-public.php'; + require_once 'includes/obj-functions.php'; + + $this->version = 2.0; + $this->obj_admin = new Obj_Gmaps_Admin( __FILE__ ); + $this->obj_settings = new Obj_Gmaps_Settings( __FILE__, $version ); + $this->obj_public = new Obj_Gmaps_Public( __FILE__, $version ); + } +} -require_once( 'includes/class-obj-admin.php' ); -require_once( 'includes/class-obj-settings.php' ); -require_once( 'includes/class-obj-public.php' ); -require_once( 'includes/obj-functions.php' ); +$Obj_Gmaps = new Obj_Gmaps(); -global $obj_admin, $obj_settings, $obj_public; -$obj_admin = new Obj_Gmaps_Admin( __FILE__ ); -$obj_settings = new Obj_Gmaps_Settings( __FILE__, $version ); -$obj_public = new Obj_Gmaps_Public( __FILE__, $version ); diff --git a/package.json b/package.json deleted file mode 100644 index e17f652..0000000 --- a/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "objectiv-google-maps", - "description": "Create searchable Google Maps for specific post types.", - "version": "1.0.0", - "dependencies": {}, - "devDependencies": { - "babel-preset-es2015": "^6.18.0", - "babelify": "^7.3.0", - "gulp": "^3.9.1", - "gulp-cheerio": "^0.6.2", - "gulp-clean-css": "^2.0.2", - "gulp-concat": "^2.6.0", - "gulp-minify": "0.0.14", - "gulp-rename": "^1.2.2", - "gulp-sass": "^2.3.2", - "gulp-sourcemaps": "^1.6.0", - "gulp-svgmin": "^1.2.2", - "gulp-svgstore": "^6.0.0", - "gulp-uglify": "^2.0.0" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "build": "browserify -t [ babelify --presets [ es2015 ] ] assets/js/src/main.js -o assets/js/build/main.js", - "watch": "watchify -t [ babelify --presets [ es2015 ] ] assets/js/src/main.js -o assets/js/build/main.js", - "build-admin": "browserify -t [ babelify --presets [ es2015 ] ] assets/js/admin/src/main.js -o assets/js/admin/build/main.js", - "watch-admin": "watchify -t [ babelify --presets [ es2015 ] ] assets/js/admin/src/main.js -o assets/js/admin/build/main.js" - } -} diff --git a/templates/obj-map-location-pin-content.php b/templates/obj-map-location-pin-content.php new file mode 100644 index 0000000..9a4447e --- /dev/null +++ b/templates/obj-map-location-pin-content.php @@ -0,0 +1,15 @@ +
+
+ + +
+

+

+
+ , +

+

+
\ No newline at end of file