WP Store Locator - Version 2.2.23

Version Description

Download this release

Release Info

Developer tijmensmit
Plugin Icon 128x128 WP Store Locator
Version 2.2.23
Comparing to
See all releases

Code changes from version 2.2.22 to 2.2.23

admin/EDD_SL_Plugin_Updater.php CHANGED
@@ -1,491 +1,585 @@
1
- <?php
2
-
3
- // Exit if accessed directly
4
- if ( ! defined( 'ABSPATH' ) ) exit;
5
-
6
- /**
7
- * Allows plugins to use their own update API.
8
- *
9
- * @author Easy Digital Downloads
10
- * @version 1.6.14
11
- */
12
- class EDD_SL_Plugin_Updater {
13
-
14
- private $api_url = '';
15
- private $api_data = array();
16
- private $name = '';
17
- private $slug = '';
18
- private $version = '';
19
- private $wp_override = false;
20
- private $cache_key = '';
21
-
22
- /**
23
- * Class constructor.
24
- *
25
- * @uses plugin_basename()
26
- * @uses hook()
27
- *
28
- * @param string $_api_url The URL pointing to the custom API endpoint.
29
- * @param string $_plugin_file Path to the plugin file.
30
- * @param array $_api_data Optional data to send with API calls.
31
- */
32
- public function __construct( $_api_url, $_plugin_file, $_api_data = null ) {
33
-
34
- global $edd_plugin_data;
35
-
36
- $this->api_url = trailingslashit( $_api_url );
37
- $this->api_data = $_api_data;
38
- $this->name = plugin_basename( $_plugin_file );
39
- $this->slug = basename( $_plugin_file, '.php' );
40
- $this->version = $_api_data['version'];
41
- $this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false;
42
- $this->beta = ! empty( $this->api_data['beta'] ) ? true : false;
43
- $this->cache_key = md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) );
44
-
45
- $edd_plugin_data[ $this->slug ] = $this->api_data;
46
-
47
- // Set up hooks.
48
- $this->init();
49
-
50
- }
51
-
52
- /**
53
- * Set up WordPress filters to hook into WP's update process.
54
- *
55
- * @uses add_filter()
56
- *
57
- * @return void
58
- */
59
- public function init() {
60
-
61
- add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
62
- add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
63
- remove_action( 'after_plugin_row_' . $this->name, 'wp_plugin_update_row', 10 );
64
- add_action( 'after_plugin_row_' . $this->name, array( $this, 'show_update_notification' ), 10, 2 );
65
- add_action( 'admin_init', array( $this, 'show_changelog' ) );
66
-
67
- }
68
-
69
- /**
70
- * Check for Updates at the defined API endpoint and modify the update array.
71
- *
72
- * This function dives into the update API just when WordPress creates its update array,
73
- * then adds a custom API call and injects the custom plugin data retrieved from the API.
74
- * It is reassembled from parts of the native WordPress plugin update code.
75
- * See wp-includes/update.php line 121 for the original wp_update_plugins() function.
76
- *
77
- * @uses api_request()
78
- *
79
- * @param array $_transient_data Update array build by WordPress.
80
- * @return array Modified update array with custom plugin data.
81
- */
82
- public function check_update( $_transient_data ) {
83
-
84
- global $pagenow;
85
-
86
- if ( ! is_object( $_transient_data ) ) {
87
- $_transient_data = new stdClass;
88
- }
89
-
90
- if ( 'plugins.php' == $pagenow && is_multisite() ) {
91
- return $_transient_data;
92
- }
93
-
94
- if ( ! empty( $_transient_data->response ) && ! empty( $_transient_data->response[ $this->name ] ) && false === $this->wp_override ) {
95
- return $_transient_data;
96
- }
97
-
98
- $version_info = $this->get_cached_version_info();
99
-
100
- if ( false === $version_info ) {
101
- $version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug, 'beta' => $this->beta ) );
102
-
103
- $this->set_version_info_cache( $version_info );
104
-
105
- }
106
-
107
- if ( false !== $version_info && is_object( $version_info ) && isset( $version_info->new_version ) ) {
108
-
109
- if ( version_compare( $this->version, $version_info->new_version, '<' ) ) {
110
-
111
- $_transient_data->response[ $this->name ] = $version_info;
112
-
113
- }
114
-
115
- $_transient_data->last_checked = current_time( 'timestamp' );
116
- $_transient_data->checked[ $this->name ] = $this->version;
117
-
118
- }
119
-
120
- return $_transient_data;
121
- }
122
-
123
- /**
124
- * show update nofication row -- needed for multisite subsites, because WP won't tell you otherwise!
125
- *
126
- * @param string $file
127
- * @param array $plugin
128
- */
129
- public function show_update_notification( $file, $plugin ) {
130
-
131
- if ( is_network_admin() ) {
132
- return;
133
- }
134
-
135
- if( ! current_user_can( 'update_plugins' ) ) {
136
- return;
137
- }
138
-
139
- if( ! is_multisite() ) {
140
- return;
141
- }
142
-
143
- if ( $this->name != $file ) {
144
- return;
145
- }
146
-
147
- // Remove our filter on the site transient
148
- remove_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ), 10 );
149
-
150
- $update_cache = get_site_transient( 'update_plugins' );
151
-
152
- $update_cache = is_object( $update_cache ) ? $update_cache : new stdClass();
153
-
154
- if ( empty( $update_cache->response ) || empty( $update_cache->response[ $this->name ] ) ) {
155
-
156
- $version_info = $this->get_cached_version_info();
157
-
158
- if ( false === $version_info ) {
159
- $version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug, 'beta' => $this->beta ) );
160
-
161
- $this->set_version_info_cache( $version_info );
162
- }
163
-
164
- if ( ! is_object( $version_info ) ) {
165
- return;
166
- }
167
-
168
- if ( version_compare( $this->version, $version_info->new_version, '<' ) ) {
169
-
170
- $update_cache->response[ $this->name ] = $version_info;
171
-
172
- }
173
-
174
- $update_cache->last_checked = current_time( 'timestamp' );
175
- $update_cache->checked[ $this->name ] = $this->version;
176
-
177
- set_site_transient( 'update_plugins', $update_cache );
178
-
179
- } else {
180
-
181
- $version_info = $update_cache->response[ $this->name ];
182
-
183
- }
184
-
185
- // Restore our filter
186
- add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
187
-
188
- if ( ! empty( $update_cache->response[ $this->name ] ) && version_compare( $this->version, $version_info->new_version, '<' ) ) {
189
-
190
- // build a plugin list row, with update notification
191
- $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
192
- # <tr class="plugin-update-tr"><td colspan="' . $wp_list_table->get_column_count() . '" class="plugin-update colspanchange">
193
- echo '<tr class="plugin-update-tr" id="' . $this->slug . '-update" data-slug="' . $this->slug . '" data-plugin="' . $this->slug . '/' . $file . '">';
194
- echo '<td colspan="3" class="plugin-update colspanchange">';
195
- echo '<div class="update-message notice inline notice-warning notice-alt">';
196
-
197
- $changelog_link = self_admin_url( 'index.php?edd_sl_action=view_plugin_changelog&plugin=' . $this->name . '&slug=' . $this->slug . '&TB_iframe=true&width=772&height=911' );
198
-
199
- if ( empty( $version_info->download_link ) ) {
200
- printf(
201
- __( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s.', 'easy-digital-downloads' ),
202
- esc_html( $version_info->name ),
203
- '<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">',
204
- esc_html( $version_info->new_version ),
205
- '</a>'
206
- );
207
- } else {
208
- printf(
209
- __( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s or %5$supdate now%6$s.', 'easy-digital-downloads' ),
210
- esc_html( $version_info->name ),
211
- '<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">',
212
- esc_html( $version_info->new_version ),
213
- '</a>',
214
- '<a href="' . esc_url( wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $this->name, 'upgrade-plugin_' . $this->name ) ) .'">',
215
- '</a>'
216
- );
217
- }
218
-
219
- do_action( "in_plugin_update_message-{$file}", $plugin, $version_info );
220
-
221
- echo '</div></td></tr>';
222
- }
223
- }
224
-
225
- /**
226
- * Updates information on the "View version x.x details" page with custom data.
227
- *
228
- * @uses api_request()
229
- *
230
- * @param mixed $_data
231
- * @param string $_action
232
- * @param object $_args
233
- * @return object $_data
234
- */
235
- public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
236
-
237
- if ( $_action != 'plugin_information' ) {
238
-
239
- return $_data;
240
-
241
- }
242
-
243
- if ( ! isset( $_args->slug ) || ( $_args->slug != $this->slug ) ) {
244
-
245
- return $_data;
246
-
247
- }
248
-
249
- $to_send = array(
250
- 'slug' => $this->slug,
251
- 'is_ssl' => is_ssl(),
252
- 'fields' => array(
253
- 'banners' => array(),
254
- 'reviews' => false
255
- )
256
- );
257
-
258
- $cache_key = 'edd_api_request_' . md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) );
259
-
260
- // Get the transient where we store the api request for this plugin for 24 hours
261
- $edd_api_request_transient = $this->get_cached_version_info( $cache_key );
262
-
263
- //If we have no transient-saved value, run the API, set a fresh transient with the API value, and return that value too right now.
264
- if ( empty( $edd_api_request_transient ) ) {
265
-
266
- $api_response = $this->api_request( 'plugin_information', $to_send );
267
-
268
- // Expires in 3 hours
269
- $this->set_version_info_cache( $api_response, $cache_key );
270
-
271
- if ( false !== $api_response ) {
272
- $_data = $api_response;
273
- }
274
-
275
- } else {
276
- $_data = $edd_api_request_transient;
277
- }
278
-
279
- // Convert sections into an associative array, since we're getting an object, but Core expects an array.
280
- if ( isset( $_data->sections ) && ! is_array( $_data->sections ) ) {
281
- $new_sections = array();
282
- foreach ( $_data->sections as $key => $value ) {
283
- $new_sections[ $key ] = $value;
284
- }
285
-
286
- $_data->sections = $new_sections;
287
- }
288
-
289
- // Convert banners into an associative array, since we're getting an object, but Core expects an array.
290
- if ( isset( $_data->banners ) && ! is_array( $_data->banners ) ) {
291
- $new_banners = array();
292
- foreach ( $_data->banners as $key => $value ) {
293
- $new_banners[ $key ] = $value;
294
- }
295
-
296
- $_data->banners = $new_banners;
297
- }
298
-
299
- return $_data;
300
- }
301
-
302
- /**
303
- * Disable SSL verification in order to prevent download update failures
304
- *
305
- * @param array $args
306
- * @param string $url
307
- * @return object $array
308
- */
309
- public function http_request_args( $args, $url ) {
310
-
311
- $verify_ssl = $this->verify_ssl();
312
- if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
313
- $args['sslverify'] = $verify_ssl;
314
- }
315
- return $args;
316
-
317
- }
318
-
319
- /**
320
- * Calls the API and, if successfull, returns the object delivered by the API.
321
- *
322
- * @uses get_bloginfo()
323
- * @uses wp_remote_post()
324
- * @uses is_wp_error()
325
- *
326
- * @param string $_action The requested action.
327
- * @param array $_data Parameters for the API action.
328
- * @return false|object
329
- */
330
- private function api_request( $_action, $_data ) {
331
-
332
- global $wp_version;
333
-
334
- $data = array_merge( $this->api_data, $_data );
335
-
336
- if ( $data['slug'] != $this->slug ) {
337
- return;
338
- }
339
-
340
- if( $this->api_url == trailingslashit (home_url() ) ) {
341
- return false; // Don't allow a plugin to ping itself
342
- }
343
-
344
- $api_params = array(
345
- 'edd_action' => 'get_version',
346
- 'license' => ! empty( $data['license'] ) ? $data['license'] : '',
347
- 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
348
- 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
349
- 'version' => isset( $data['version'] ) ? $data['version'] : false,
350
- 'slug' => $data['slug'],
351
- 'author' => $data['author'],
352
- 'url' => home_url(),
353
- 'beta' => ! empty( $data['beta'] ),
354
- );
355
-
356
- $verify_ssl = $this->verify_ssl();
357
- $request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => $verify_ssl, 'body' => $api_params ) );
358
-
359
- if ( ! is_wp_error( $request ) ) {
360
- $request = json_decode( wp_remote_retrieve_body( $request ) );
361
- }
362
-
363
- if ( $request && isset( $request->sections ) ) {
364
- $request->sections = maybe_unserialize( $request->sections );
365
- } else {
366
- $request = false;
367
- }
368
-
369
- if ( $request && isset( $request->banners ) ) {
370
- $request->banners = maybe_unserialize( $request->banners );
371
- }
372
-
373
- if( ! empty( $request->sections ) ) {
374
- foreach( $request->sections as $key => $section ) {
375
- $request->$key = (array) $section;
376
- }
377
- }
378
-
379
- return $request;
380
- }
381
-
382
- public function show_changelog() {
383
-
384
- global $edd_plugin_data;
385
-
386
- if( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' != $_REQUEST['edd_sl_action'] ) {
387
- return;
388
- }
389
-
390
- if( empty( $_REQUEST['plugin'] ) ) {
391
- return;
392
- }
393
-
394
- if( empty( $_REQUEST['slug'] ) ) {
395
- return;
396
- }
397
-
398
- if( ! current_user_can( 'update_plugins' ) ) {
399
- wp_die( __( 'You do not have permission to install plugin updates', 'easy-digital-downloads' ), __( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) );
400
- }
401
-
402
- $data = $edd_plugin_data[ $_REQUEST['slug'] ];
403
- $beta = ! empty( $data['beta'] ) ? true : false;
404
- $cache_key = md5( 'edd_plugin_' . sanitize_key( $_REQUEST['plugin'] ) . '_' . $beta . '_version_info' );
405
- $version_info = $this->get_cached_version_info( $cache_key );
406
-
407
- if( false === $version_info ) {
408
-
409
- $api_params = array(
410
- 'edd_action' => 'get_version',
411
- 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
412
- 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
413
- 'slug' => $_REQUEST['slug'],
414
- 'author' => $data['author'],
415
- 'url' => home_url(),
416
- 'beta' => ! empty( $data['beta'] )
417
- );
418
-
419
- $verify_ssl = $this->verify_ssl();
420
- $request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => $verify_ssl, 'body' => $api_params ) );
421
-
422
- if ( ! is_wp_error( $request ) ) {
423
- $version_info = json_decode( wp_remote_retrieve_body( $request ) );
424
- }
425
-
426
-
427
- if ( ! empty( $version_info ) && isset( $version_info->sections ) ) {
428
- $version_info->sections = maybe_unserialize( $version_info->sections );
429
- } else {
430
- $version_info = false;
431
- }
432
-
433
- if( ! empty( $version_info ) ) {
434
- foreach( $version_info->sections as $key => $section ) {
435
- $version_info->$key = (array) $section;
436
- }
437
- }
438
-
439
- $this->set_version_info_cache( $version_info, $cache_key );
440
-
441
- }
442
-
443
- if( ! empty( $version_info ) && isset( $version_info->sections['changelog'] ) ) {
444
- echo '<div style="background:#fff;padding:10px;">' . $version_info->sections['changelog'] . '</div>';
445
- }
446
-
447
- exit;
448
- }
449
-
450
- public function get_cached_version_info( $cache_key = '' ) {
451
-
452
- if( empty( $cache_key ) ) {
453
- $cache_key = $this->cache_key;
454
- }
455
-
456
- $cache = get_option( $cache_key );
457
-
458
- if( empty( $cache['timeout'] ) || current_time( 'timestamp' ) > $cache['timeout'] ) {
459
- return false; // Cache is expired
460
- }
461
-
462
- return json_decode( $cache['value'] );
463
-
464
- }
465
-
466
- public function set_version_info_cache( $value = '', $cache_key = '' ) {
467
-
468
- if( empty( $cache_key ) ) {
469
- $cache_key = $this->cache_key;
470
- }
471
-
472
- $data = array(
473
- 'timeout' => strtotime( '+3 hours', current_time( 'timestamp' ) ),
474
- 'value' => json_encode( $value )
475
- );
476
-
477
- update_option( $cache_key, $data, 'no' );
478
-
479
- }
480
-
481
- /**
482
- * Returns if the SSL of the store should be verified.
483
- *
484
- * @since 1.6.13
485
- * @return bool
486
- */
487
- private function verify_ssl() {
488
- return (bool) apply_filters( 'edd_sl_api_request_verify_ssl', true, $this );
489
- }
490
-
491
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Exit if accessed directly
4
+ if ( ! defined( 'ABSPATH' ) ) exit;
5
+
6
+ /**
7
+ * Allows plugins to use their own update API.
8
+ *
9
+ * @author Easy Digital Downloads
10
+ * @version 1.6.19
11
+ */
12
+ class EDD_SL_Plugin_Updater {
13
+
14
+ private $api_url = '';
15
+ private $api_data = array();
16
+ private $name = '';
17
+ private $slug = '';
18
+ private $version = '';
19
+ private $wp_override = false;
20
+ private $cache_key = '';
21
+
22
+ private $health_check_timeout = 5;
23
+
24
+ /**
25
+ * Class constructor.
26
+ *
27
+ * @uses plugin_basename()
28
+ * @uses hook()
29
+ *
30
+ * @param string $_api_url The URL pointing to the custom API endpoint.
31
+ * @param string $_plugin_file Path to the plugin file.
32
+ * @param array $_api_data Optional data to send with API calls.
33
+ */
34
+ public function __construct( $_api_url, $_plugin_file, $_api_data = null ) {
35
+
36
+ global $edd_plugin_data;
37
+
38
+ $this->api_url = trailingslashit( $_api_url );
39
+ $this->api_data = $_api_data;
40
+ $this->name = plugin_basename( $_plugin_file );
41
+ $this->slug = basename( $_plugin_file, '.php' );
42
+ $this->version = $_api_data['version'];
43
+ $this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false;
44
+ $this->beta = ! empty( $this->api_data['beta'] ) ? true : false;
45
+ $this->cache_key = 'edd_sl_' . md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) );
46
+
47
+ $edd_plugin_data[ $this->slug ] = $this->api_data;
48
+
49
+ /**
50
+ * Fires after the $edd_plugin_data is setup.
51
+ *
52
+ * @since x.x.x
53
+ *
54
+ * @param array $edd_plugin_data Array of EDD SL plugin data.
55
+ */
56
+ do_action( 'post_edd_sl_plugin_updater_setup', $edd_plugin_data );
57
+
58
+ // Set up hooks.
59
+ $this->init();
60
+
61
+ }
62
+
63
+ /**
64
+ * Set up WordPress filters to hook into WP's update process.
65
+ *
66
+ * @uses add_filter()
67
+ *
68
+ * @return void
69
+ */
70
+ public function init() {
71
+
72
+ add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
73
+ add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
74
+ remove_action( 'after_plugin_row_' . $this->name, 'wp_plugin_update_row', 10 );
75
+ add_action( 'after_plugin_row_' . $this->name, array( $this, 'show_update_notification' ), 10, 2 );
76
+ add_action( 'admin_init', array( $this, 'show_changelog' ) );
77
+
78
+ }
79
+
80
+ /**
81
+ * Check for Updates at the defined API endpoint and modify the update array.
82
+ *
83
+ * This function dives into the update API just when WordPress creates its update array,
84
+ * then adds a custom API call and injects the custom plugin data retrieved from the API.
85
+ * It is reassembled from parts of the native WordPress plugin update code.
86
+ * See wp-includes/update.php line 121 for the original wp_update_plugins() function.
87
+ *
88
+ * @uses api_request()
89
+ *
90
+ * @param array $_transient_data Update array build by WordPress.
91
+ * @return array Modified update array with custom plugin data.
92
+ */
93
+ public function check_update( $_transient_data ) {
94
+
95
+ global $pagenow;
96
+
97
+ if ( ! is_object( $_transient_data ) ) {
98
+ $_transient_data = new stdClass;
99
+ }
100
+
101
+ if ( 'plugins.php' == $pagenow && is_multisite() ) {
102
+ return $_transient_data;
103
+ }
104
+
105
+ if ( ! empty( $_transient_data->response ) && ! empty( $_transient_data->response[ $this->name ] ) && false === $this->wp_override ) {
106
+ return $_transient_data;
107
+ }
108
+
109
+ $version_info = $this->get_cached_version_info();
110
+
111
+ if ( false === $version_info ) {
112
+ $version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug, 'beta' => $this->beta ) );
113
+
114
+ $this->set_version_info_cache( $version_info );
115
+
116
+ }
117
+
118
+ if ( false !== $version_info && is_object( $version_info ) && isset( $version_info->new_version ) ) {
119
+
120
+ if ( version_compare( $this->version, $version_info->new_version, '<' ) ) {
121
+
122
+ $_transient_data->response[ $this->name ] = $version_info;
123
+
124
+ // Make sure the plugin property is set to the plugin's name/location. See issue 1463 on Software Licensing's GitHub repo.
125
+ $_transient_data->response[ $this->name ]->plugin = $this->name;
126
+
127
+ }
128
+
129
+ $_transient_data->last_checked = time();
130
+ $_transient_data->checked[ $this->name ] = $this->version;
131
+
132
+ }
133
+
134
+ return $_transient_data;
135
+ }
136
+
137
+ /**
138
+ * show update nofication row -- needed for multisite subsites, because WP won't tell you otherwise!
139
+ *
140
+ * @param string $file
141
+ * @param array $plugin
142
+ */
143
+ public function show_update_notification( $file, $plugin ) {
144
+
145
+ if ( is_network_admin() ) {
146
+ return;
147
+ }
148
+
149
+ if( ! current_user_can( 'update_plugins' ) ) {
150
+ return;
151
+ }
152
+
153
+ if( ! is_multisite() ) {
154
+ return;
155
+ }
156
+
157
+ if ( $this->name != $file ) {
158
+ return;
159
+ }
160
+
161
+ // Remove our filter on the site transient
162
+ remove_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ), 10 );
163
+
164
+ $update_cache = get_site_transient( 'update_plugins' );
165
+
166
+ $update_cache = is_object( $update_cache ) ? $update_cache : new stdClass();
167
+
168
+ if ( empty( $update_cache->response ) || empty( $update_cache->response[ $this->name ] ) ) {
169
+
170
+ $version_info = $this->get_cached_version_info();
171
+
172
+ if ( false === $version_info ) {
173
+ $version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug, 'beta' => $this->beta ) );
174
+
175
+ // Since we disabled our filter for the transient, we aren't running our object conversion on banners, sections, or icons. Do this now:
176
+ if ( isset( $version_info->banners ) && ! is_array( $version_info->banners ) ) {
177
+ $version_info->banners = $this->convert_object_to_array( $version_info->banners );
178
+ }
179
+
180
+ if ( isset( $version_info->sections ) && ! is_array( $version_info->sections ) ) {
181
+ $version_info->sections = $this->convert_object_to_array( $version_info->sections );
182
+ }
183
+
184
+ if ( isset( $version_info->icons ) && ! is_array( $version_info->icons ) ) {
185
+ $version_info->icons = $this->convert_object_to_array( $version_info->icons );
186
+ }
187
+
188
+ if ( isset( $version_info->icons ) && ! is_array( $version_info->icons ) ) {
189
+ $version_info->icons = $this->convert_object_to_array( $version_info->icons );
190
+ }
191
+
192
+ if ( isset( $version_info->contributors ) && ! is_array( $version_info->contributors ) ) {
193
+ $version_info->contributors = $this->convert_object_to_array( $version_info->contributors );
194
+ }
195
+
196
+ $this->set_version_info_cache( $version_info );
197
+ }
198
+
199
+ if ( ! is_object( $version_info ) ) {
200
+ return;
201
+ }
202
+
203
+ if ( version_compare( $this->version, $version_info->new_version, '<' ) ) {
204
+
205
+ $update_cache->response[ $this->name ] = $version_info;
206
+
207
+ }
208
+
209
+ $update_cache->last_checked = time();
210
+ $update_cache->checked[ $this->name ] = $this->version;
211
+
212
+ set_site_transient( 'update_plugins', $update_cache );
213
+
214
+ } else {
215
+
216
+ $version_info = $update_cache->response[ $this->name ];
217
+
218
+ }
219
+
220
+ // Restore our filter
221
+ add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
222
+
223
+ if ( ! empty( $update_cache->response[ $this->name ] ) && version_compare( $this->version, $version_info->new_version, '<' ) ) {
224
+
225
+ // build a plugin list row, with update notification
226
+ $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
227
+ # <tr class="plugin-update-tr"><td colspan="' . $wp_list_table->get_column_count() . '" class="plugin-update colspanchange">
228
+ echo '<tr class="plugin-update-tr" id="' . $this->slug . '-update" data-slug="' . $this->slug . '" data-plugin="' . $this->slug . '/' . $file . '">';
229
+ echo '<td colspan="3" class="plugin-update colspanchange">';
230
+ echo '<div class="update-message notice inline notice-warning notice-alt">';
231
+
232
+ $changelog_link = self_admin_url( 'index.php?edd_sl_action=view_plugin_changelog&plugin=' . $this->name . '&slug=' . $this->slug . '&TB_iframe=true&width=772&height=911' );
233
+
234
+ if ( empty( $version_info->download_link ) ) {
235
+ printf(
236
+ __( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s.', 'easy-digital-downloads' ),
237
+ esc_html( $version_info->name ),
238
+ '<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">',
239
+ esc_html( $version_info->new_version ),
240
+ '</a>'
241
+ );
242
+ } else {
243
+ printf(
244
+ __( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s or %5$supdate now%6$s.', 'easy-digital-downloads' ),
245
+ esc_html( $version_info->name ),
246
+ '<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">',
247
+ esc_html( $version_info->new_version ),
248
+ '</a>',
249
+ '<a href="' . esc_url( wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $this->name, 'upgrade-plugin_' . $this->name ) ) .'">',
250
+ '</a>'
251
+ );
252
+ }
253
+
254
+ do_action( "in_plugin_update_message-{$file}", $plugin, $version_info );
255
+
256
+ echo '</div></td></tr>';
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Updates information on the "View version x.x details" page with custom data.
262
+ *
263
+ * @uses api_request()
264
+ *
265
+ * @param mixed $_data
266
+ * @param string $_action
267
+ * @param object $_args
268
+ * @return object $_data
269
+ */
270
+ public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
271
+
272
+ if ( $_action != 'plugin_information' ) {
273
+
274
+ return $_data;
275
+
276
+ }
277
+
278
+ if ( ! isset( $_args->slug ) || ( $_args->slug != $this->slug ) ) {
279
+
280
+ return $_data;
281
+
282
+ }
283
+
284
+ $to_send = array(
285
+ 'slug' => $this->slug,
286
+ 'is_ssl' => is_ssl(),
287
+ 'fields' => array(
288
+ 'banners' => array(),
289
+ 'reviews' => false,
290
+ 'icons' => array(),
291
+ )
292
+ );
293
+
294
+ $cache_key = 'edd_api_request_' . md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) );
295
+
296
+ // Get the transient where we store the api request for this plugin for 24 hours
297
+ $edd_api_request_transient = $this->get_cached_version_info( $cache_key );
298
+
299
+ //If we have no transient-saved value, run the API, set a fresh transient with the API value, and return that value too right now.
300
+ if ( empty( $edd_api_request_transient ) ) {
301
+
302
+ $api_response = $this->api_request( 'plugin_information', $to_send );
303
+
304
+ // Expires in 3 hours
305
+ $this->set_version_info_cache( $api_response, $cache_key );
306
+
307
+ if ( false !== $api_response ) {
308
+ $_data = $api_response;
309
+ }
310
+
311
+ } else {
312
+ $_data = $edd_api_request_transient;
313
+ }
314
+
315
+ // Convert sections into an associative array, since we're getting an object, but Core expects an array.
316
+ if ( isset( $_data->sections ) && ! is_array( $_data->sections ) ) {
317
+ $_data->sections = $this->convert_object_to_array( $_data->sections );
318
+ }
319
+
320
+ // Convert banners into an associative array, since we're getting an object, but Core expects an array.
321
+ if ( isset( $_data->banners ) && ! is_array( $_data->banners ) ) {
322
+ $_data->banners = $this->convert_object_to_array( $_data->banners );
323
+ }
324
+
325
+ // Convert icons into an associative array, since we're getting an object, but Core expects an array.
326
+ if ( isset( $_data->icons ) && ! is_array( $_data->icons ) ) {
327
+ $_data->icons = $this->convert_object_to_array( $_data->icons );
328
+ }
329
+
330
+ // Convert contributors into an associative array, since we're getting an object, but Core expects an array.
331
+ if ( isset( $_data->contributors ) && ! is_array( $_data->contributors ) ) {
332
+ $_data->contributors = $this->convert_object_to_array( $_data->contributors );
333
+ }
334
+
335
+ if( ! isset( $_data->plugin ) ) {
336
+ $_data->plugin = $this->name;
337
+ }
338
+
339
+ return $_data;
340
+ }
341
+
342
+ /**
343
+ * Convert some objects to arrays when injecting data into the update API
344
+ *
345
+ * Some data like sections, banners, and icons are expected to be an associative array, however due to the JSON
346
+ * decoding, they are objects. This method allows us to pass in the object and return an associative array.
347
+ *
348
+ * @since 3.6.5
349
+ *
350
+ * @param stdClass $data
351
+ *
352
+ * @return array
353
+ */
354
+ private function convert_object_to_array( $data ) {
355
+ $new_data = array();
356
+ foreach ( $data as $key => $value ) {
357
+ $new_data[ $key ] = is_object( $value ) ? $this->convert_object_to_array( $value ) : $value;
358
+ }
359
+
360
+ return $new_data;
361
+ }
362
+
363
+ /**
364
+ * Disable SSL verification in order to prevent download update failures
365
+ *
366
+ * @param array $args
367
+ * @param string $url
368
+ * @return object $array
369
+ */
370
+ public function http_request_args( $args, $url ) {
371
+
372
+ $verify_ssl = $this->verify_ssl();
373
+ if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
374
+ $args['sslverify'] = $verify_ssl;
375
+ }
376
+ return $args;
377
+
378
+ }
379
+
380
+ /**
381
+ * Calls the API and, if successfull, returns the object delivered by the API.
382
+ *
383
+ * @uses get_bloginfo()
384
+ * @uses wp_remote_post()
385
+ * @uses is_wp_error()
386
+ *
387
+ * @param string $_action The requested action.
388
+ * @param array $_data Parameters for the API action.
389
+ * @return false|object
390
+ */
391
+ private function api_request( $_action, $_data ) {
392
+
393
+ global $wp_version, $edd_plugin_url_available;
394
+
395
+ $verify_ssl = $this->verify_ssl();
396
+
397
+ // Do a quick status check on this domain if we haven't already checked it.
398
+ $store_hash = md5( $this->api_url );
399
+ if ( ! is_array( $edd_plugin_url_available ) || ! isset( $edd_plugin_url_available[ $store_hash ] ) ) {
400
+ $test_url_parts = parse_url( $this->api_url );
401
+
402
+ $scheme = ! empty( $test_url_parts['scheme'] ) ? $test_url_parts['scheme'] : 'http';
403
+ $host = ! empty( $test_url_parts['host'] ) ? $test_url_parts['host'] : '';
404
+ $port = ! empty( $test_url_parts['port'] ) ? ':' . $test_url_parts['port'] : '';
405
+
406
+ if ( empty( $host ) ) {
407
+ $edd_plugin_url_available[ $store_hash ] = false;
408
+ } else {
409
+ $test_url = $scheme . '://' . $host . $port;
410
+ $response = wp_remote_get( $test_url, array( 'timeout' => $this->health_check_timeout, 'sslverify' => $verify_ssl ) );
411
+ $edd_plugin_url_available[ $store_hash ] = is_wp_error( $response ) ? false : true;
412
+ }
413
+ }
414
+
415
+ if ( false === $edd_plugin_url_available[ $store_hash ] ) {
416
+ return;
417
+ }
418
+
419
+ $data = array_merge( $this->api_data, $_data );
420
+
421
+ if ( $data['slug'] != $this->slug ) {
422
+ return;
423
+ }
424
+
425
+ if( $this->api_url == trailingslashit ( home_url() ) ) {
426
+ return false; // Don't allow a plugin to ping itself
427
+ }
428
+
429
+ $api_params = array(
430
+ 'edd_action' => 'get_version',
431
+ 'license' => ! empty( $data['license'] ) ? $data['license'] : '',
432
+ 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
433
+ 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
434
+ 'version' => isset( $data['version'] ) ? $data['version'] : false,
435
+ 'slug' => $data['slug'],
436
+ 'author' => $data['author'],
437
+ 'url' => home_url(),
438
+ 'beta' => ! empty( $data['beta'] ),
439
+ );
440
+
441
+ $request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => $verify_ssl, 'body' => $api_params ) );
442
+
443
+ if ( ! is_wp_error( $request ) ) {
444
+ $request = json_decode( wp_remote_retrieve_body( $request ) );
445
+ }
446
+
447
+ if ( $request && isset( $request->sections ) ) {
448
+ $request->sections = maybe_unserialize( $request->sections );
449
+ } else {
450
+ $request = false;
451
+ }
452
+
453
+ if ( $request && isset( $request->banners ) ) {
454
+ $request->banners = maybe_unserialize( $request->banners );
455
+ }
456
+
457
+ if ( $request && isset( $request->icons ) ) {
458
+ $request->icons = maybe_unserialize( $request->icons );
459
+ }
460
+
461
+ if( ! empty( $request->sections ) ) {
462
+ foreach( $request->sections as $key => $section ) {
463
+ $request->$key = (array) $section;
464
+ }
465
+ }
466
+
467
+ return $request;
468
+ }
469
+
470
+ public function show_changelog() {
471
+
472
+ global $edd_plugin_data;
473
+
474
+ if( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' != $_REQUEST['edd_sl_action'] ) {
475
+ return;
476
+ }
477
+
478
+ if( empty( $_REQUEST['plugin'] ) ) {
479
+ return;
480
+ }
481
+
482
+ if( empty( $_REQUEST['slug'] ) ) {
483
+ return;
484
+ }
485
+
486
+ if( ! current_user_can( 'update_plugins' ) ) {
487
+ wp_die( __( 'You do not have permission to install plugin updates', 'easy-digital-downloads' ), __( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) );
488
+ }
489
+
490
+ $data = $edd_plugin_data[ $_REQUEST['slug'] ];
491
+ $beta = ! empty( $data['beta'] ) ? true : false;
492
+ $cache_key = md5( 'edd_plugin_' . sanitize_key( $_REQUEST['plugin'] ) . '_' . $beta . '_version_info' );
493
+ $version_info = $this->get_cached_version_info( $cache_key );
494
+
495
+ if( false === $version_info ) {
496
+
497
+ $api_params = array(
498
+ 'edd_action' => 'get_version',
499
+ 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
500
+ 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
501
+ 'slug' => $_REQUEST['slug'],
502
+ 'author' => $data['author'],
503
+ 'url' => home_url(),
504
+ 'beta' => ! empty( $data['beta'] )
505
+ );
506
+
507
+ $verify_ssl = $this->verify_ssl();
508
+ $request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => $verify_ssl, 'body' => $api_params ) );
509
+
510
+ if ( ! is_wp_error( $request ) ) {
511
+ $version_info = json_decode( wp_remote_retrieve_body( $request ) );
512
+ }
513
+
514
+
515
+ if ( ! empty( $version_info ) && isset( $version_info->sections ) ) {
516
+ $version_info->sections = maybe_unserialize( $version_info->sections );
517
+ } else {
518
+ $version_info = false;
519
+ }
520
+
521
+ if( ! empty( $version_info ) ) {
522
+ foreach( $version_info->sections as $key => $section ) {
523
+ $version_info->$key = (array) $section;
524
+ }
525
+ }
526
+
527
+ $this->set_version_info_cache( $version_info, $cache_key );
528
+
529
+ }
530
+
531
+ if( ! empty( $version_info ) && isset( $version_info->sections['changelog'] ) ) {
532
+ echo '<div style="background:#fff;padding:10px;">' . $version_info->sections['changelog'] . '</div>';
533
+ }
534
+
535
+ exit;
536
+ }
537
+
538
+ public function get_cached_version_info( $cache_key = '' ) {
539
+
540
+ if( empty( $cache_key ) ) {
541
+ $cache_key = $this->cache_key;
542
+ }
543
+
544
+ $cache = get_option( $cache_key );
545
+
546
+ if( empty( $cache['timeout'] ) || time() > $cache['timeout'] ) {
547
+ return false; // Cache is expired
548
+ }
549
+
550
+ // We need to turn the icons into an array, thanks to WP Core forcing these into an object at some point.
551
+ $cache['value'] = json_decode( $cache['value'] );
552
+ if ( ! empty( $cache['value']->icons ) ) {
553
+ $cache['value']->icons = (array) $cache['value']->icons;
554
+ }
555
+
556
+ return $cache['value'];
557
+
558
+ }
559
+
560
+ public function set_version_info_cache( $value = '', $cache_key = '' ) {
561
+
562
+ if( empty( $cache_key ) ) {
563
+ $cache_key = $this->cache_key;
564
+ }
565
+
566
+ $data = array(
567
+ 'timeout' => strtotime( '+3 hours', time() ),
568
+ 'value' => json_encode( $value )
569
+ );
570
+
571
+ update_option( $cache_key, $data, 'no' );
572
+
573
+ }
574
+
575
+ /**
576
+ * Returns if the SSL of the store should be verified.
577
+ *
578
+ * @since 1.6.13
579
+ * @return bool
580
+ */
581
+ private function verify_ssl() {
582
+ return (bool) apply_filters( 'edd_sl_api_request_verify_ssl', true, $this );
583
+ }
584
+
585
+ }
admin/data-export.php CHANGED
@@ -13,6 +13,8 @@ add_action( 'admin_init', 'wpsl_single_location_export' );
13
  */
14
  function wpsl_single_location_export() {
15
 
 
 
16
  if ( isset( $_GET['wpsl_data_export'] ) && isset( $_GET['wpsl_export_nonce'] ) ) {
17
  $post_id = absint( $_GET['post'] );
18
 
@@ -25,9 +27,30 @@ function wpsl_single_location_export() {
25
  if ( !current_user_can( 'edit_post', $post_id ) )
26
  return;
27
 
28
- $meta_fields = wpsl_get_field_names( false );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  $meta_data = get_post_custom( $post_id );
30
- $post_meta = '';
31
 
32
  // Loop over the wpsl meta fields, and collect the meta data.
33
  foreach ( $meta_fields as $meta_field ) {
@@ -48,7 +71,7 @@ function wpsl_single_location_export() {
48
  if ( $post_meta ) {
49
  $file_name = 'wpsl-export-' . $post_id . '-' . date('Ymd' ) . '.csv';
50
 
51
- // Set the download headers for the CSV file.
52
  header( 'Content-Type: text/csv; charset=utf-8' );
53
  header( 'Content-Disposition: attachment; filename=' . $file_name . '' );
54
 
13
  */
14
  function wpsl_single_location_export() {
15
 
16
+ global $wpsl_admin; // From the WPSL plugin
17
+
18
  if ( isset( $_GET['wpsl_data_export'] ) && isset( $_GET['wpsl_export_nonce'] ) ) {
19
  $post_id = absint( $_GET['post'] );
20
 
27
  if ( !current_user_can( 'edit_post', $post_id ) )
28
  return;
29
 
30
+ $meta_fields = array();
31
+ $wp_field_map = array(
32
+ 'wpsl_id' => 'ID',
33
+ 'name' => 'post_title',
34
+ 'status' => 'post_status',
35
+ 'permalink' => 'post_name',
36
+ 'description' => 'post_content',
37
+ 'excerpt' => 'post_excerpt',
38
+ 'author' => 'post_author',
39
+ 'date' => 'post_date'
40
+ );
41
+
42
+ $meta_box_fields = $wpsl_admin->metaboxes->meta_box_fields();
43
+ $fields = array_keys( $wp_field_map );
44
+ array_push( $fields, 'image', 'category', 'tags' );
45
+
46
+ foreach ( $meta_box_fields as $k => $field_section ) {
47
+ foreach ( $field_section as $field_name => $field_value ) {
48
+ $meta_fields[] = $field_name;
49
+ }
50
+ }
51
+
52
  $meta_data = get_post_custom( $post_id );
53
+ $post_meta = array();
54
 
55
  // Loop over the wpsl meta fields, and collect the meta data.
56
  foreach ( $meta_fields as $meta_field ) {
71
  if ( $post_meta ) {
72
  $file_name = 'wpsl-export-' . $post_id . '-' . date('Ymd' ) . '.csv';
73
 
74
+ // Set the download headers for the CSV file.
75
  header( 'Content-Type: text/csv; charset=utf-8' );
76
  header( 'Content-Disposition: attachment; filename=' . $file_name . '' );
77
 
frontend/class-frontend.php CHANGED
@@ -607,11 +607,7 @@ if ( !class_exists( 'WPSL_Frontend' ) ) {
607
 
608
  global $wpsl_settings, $post;
609
 
610
- // Prevent duplicate output when the Twenty Nineteen theme is active.
611
- $skip_status = ( get_option( 'template' ) === 'twentynineteen' ) ? true : false;
612
- $skip_cpt_template = apply_filters( 'wpsl_skip_cpt_template', $skip_status );
613
-
614
- if ( isset( $post->post_type ) && $post->post_type == 'wpsl_stores' && is_single() && in_the_loop() && !$skip_cpt_template ) {
615
  array_push( $this->load_scripts, 'wpsl_base' );
616
 
617
  $content .= '[wpsl_map]';
607
 
608
  global $wpsl_settings, $post;
609
 
610
+ if ( isset( $post->post_type ) && $post->post_type == 'wpsl_stores' && is_single() && in_the_loop() ) {
 
 
 
 
611
  array_push( $this->load_scripts, 'wpsl_base' );
612
 
613
  $content .= '[wpsl_map]';
readme.txt CHANGED
@@ -4,8 +4,8 @@ Contributors: tijmensmit
4
  Donate link: https://www.paypal.me/tijmensmit
5
  Tags: google maps, store locator, business locations, geocoding, stores, geo, zipcode locator, dealer locater, geocode, gmaps, google map, google map plugin, location finder, map tools, shop locator, wp google map
6
  Requires at least: 3.7
7
- Tested up to: 5.1.1
8
- Stable tag: 2.2.22
9
  License: GPLv3
10
  License URI: http://www.gnu.org/licenses/gpl.html
11
 
@@ -127,6 +127,11 @@ If you find a plugin or theme that causes a conflict, please report it on the [s
127
 
128
  == Changelog ==
129
 
 
 
 
 
 
130
  = 2.2.22, March 24, 2019 =
131
  * Added: Support for the [Borlabs Cookie](https://borlabs.io/borlabs-cookie/) plugin. This allows you to [block the loading](https://wpstorelocator.co/document/the-general-data-protection-regulation/#borlabs) of Google Maps until the user agrees to it.
132
  * Added: A 'Validate API Keys' tool that will provided feedback for any issues with the used API keys.
4
  Donate link: https://www.paypal.me/tijmensmit
5
  Tags: google maps, store locator, business locations, geocoding, stores, geo, zipcode locator, dealer locater, geocode, gmaps, google map, google map plugin, location finder, map tools, shop locator, wp google map
6
  Requires at least: 3.7
7
+ Tested up to: 5.2
8
+ Stable tag: 2.2.23
9
  License: GPLv3
10
  License URI: http://www.gnu.org/licenses/gpl.html
11
 
127
 
128
  == Changelog ==
129
 
130
+ = 2.2.23, May 6, 2019 =
131
+ * Fixed: The export data function on the single location pages in the admin area not working.
132
+ * Fixed: The map and location data not showing up in the TwentyNineteen theme on individual location pages.
133
+ * Changed: Updated the included EDD_SL_Plugin_Updater class that handles updates / license key checks for add-ons.
134
+
135
  = 2.2.22, March 24, 2019 =
136
  * Added: Support for the [Borlabs Cookie](https://borlabs.io/borlabs-cookie/) plugin. This allows you to [block the loading](https://wpstorelocator.co/document/the-general-data-protection-regulation/#borlabs) of Google Maps until the user agrees to it.
137
  * Added: A 'Validate API Keys' tool that will provided feedback for any issues with the used API keys.
wp-store-locator.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: WP Store Locator
4
  Description: An easy to use location management system that enables users to search for nearby physical stores
5
  Author: Tijmen Smit
6
  Author URI: https://wpstorelocator.co/
7
- Version: 2.2.22
8
  Text Domain: wpsl
9
  Domain Path: /languages/
10
  License: GPL v3
@@ -61,7 +61,7 @@ if ( !class_exists( 'WP_Store_locator' ) ) {
61
  public function define_constants() {
62
 
63
  if ( !defined( 'WPSL_VERSION_NUM' ) )
64
- define( 'WPSL_VERSION_NUM', '2.2.22' );
65
 
66
  if ( !defined( 'WPSL_URL' ) )
67
  define( 'WPSL_URL', plugin_dir_url( __FILE__ ) );
4
  Description: An easy to use location management system that enables users to search for nearby physical stores
5
  Author: Tijmen Smit
6
  Author URI: https://wpstorelocator.co/
7
+ Version: 2.2.23
8
  Text Domain: wpsl
9
  Domain Path: /languages/
10
  License: GPL v3
61
  public function define_constants() {
62
 
63
  if ( !defined( 'WPSL_VERSION_NUM' ) )
64
+ define( 'WPSL_VERSION_NUM', '2.2.23' );
65
 
66
  if ( !defined( 'WPSL_URL' ) )
67
  define( 'WPSL_URL', plugin_dir_url( __FILE__ ) );