This repository was archived by the owner on Feb 1, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathsavvyinterface.php
More file actions
499 lines (434 loc) · 13.8 KB
/
savvyinterface.php
File metadata and controls
499 lines (434 loc) · 13.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
<?php
/*
Copyright (C) 2016 Cimbura.com
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @class The list of functions that a class must implement
* to be used as an interface
*/
abstract class SavvyInterface {
/**
* @var The SavvyMapper instance.
*/
var $savvy;
/**
* @var This interface's name.
*/
var $name = 'Default Savvy Interface';
/**
* @var This instance's config
*/
var $config;
/**
* @var A place for the instance to cache things
*
* Instances shouldn't use this directly but should use
*
* get_cache($key) and set_cache($key,$value) instead
*/
var $cache;
/**
* Init self and load self into SavvyMapper
*
* @param array $config
*/
function __construct( $config = array() ) {
$this->savvy = SavvyMapper::get_instance();
$this->setup_actions();
$this->set_config( $config );
}
/**
* Ajax autocomplete. Return the JSON features that match the query
*
* Matching should ideally be done as a case-insensitive match, matching the first part of the string
*
* @param mappingconfig $mapping The current mapping for the connection.
* @param string $term The term we're autocompleting with
*
* @note This should really only return some practical number of items. Probably 15ish, and they should be sorted alphabetically
*
* @return An array of matched values
*/
abstract function autocomplete( $mapping, $term );
/**
* Make the metabox for this interface
*
* @param WP_Post $post The post this metabox is for.
* @param Array $mapping The current connection mapping.
* @param array $current_settings The current settings for the given post.
*
* Prints the metabox html
*/
abstract function extra_metabox_fields( $post, $mapping, $current_settings = array() );
/**
* Get the part of the form for the connection interface
*
* @return Any HTML form elements needed to set up a new connection on the
* options page, as a string, or an empty string if no config is needed.
*
* Input elements should have a data-name property with the name of the field
*
* For existing connections, input elements should populate the inputs with the values in $this->config
*/
abstract function options_div();
/**
* Get the part of the form for setting up the mapping
*
* @param array $mapping The current mapping config
*
* Create the html needed to set up a new mapping in the current connection
*
* Input elements should have a data-name property with the name of the field
*
* For existing mappings, input elements should populate the inputs with the values in the passed-in $mapping parameter
*/
abstract function mapping_div( $mapping );
/**
* Get a list of all the available attributes
*
* @param array $mapping The current mapping config
*
* @return An array of attribute/property names
*/
abstract function get_attribute_names( $mapping );
/**
* App postmeta is actually stored in savvymapper_post_meta, but SavvyMapper
* only knows about the default mapping options.
*
* This save_meta function looks for interface-specific values in $_POST
* and returns an array with any additional keys that SavvyMapper should
* merge in for this post's meta.
*
* @param string/int $post_id The post that meta is being saved for.
* @param integer $index The mapping instance index
*/
abstract function save_meta( $post_id, $index );
/**
* Map initialization is all done in JavaScript.
*
* This function allows an interface to supply additional settings which the JavaScript can access.
*
* @param array $attrs The shortcode $attrs.
* @param string $contents The contents between the shortcode tags.
* @param array $mapping The current mapping config.
* @param array $current_settings The settings for this specific post.
*
* @note Values returned here should be handled in the js file corresponding to the interface.
*
* @return An Array of additional properties for the map to be aware of.
*/
abstract function get_map_shortcode_properties( $attrs, $contents, $mapping, $current_settings );
/**
* Get a GeoJSON object for the current post
*
* @param array $mapping The current mapping config.
* @param array $current_settings The settings for this specific post.
*
* @return A GeoJSON-compatible array.
*/
abstract function get_geojson_for_post( $mapping, $current_settings );
/**
* This is the actual class called when we need json for a post
* It calls the interface's get_geojson_for_post and then calls
* make_popups with that geojson
*
* @param array $mapping The current mapping config.
* @param array $current_settings The settings for this specific post.
*
* @return A GeoJSON-compatible array.
*/
function _get_geojson_for_post( $mapping, $current_settings ) {
$json = $this->get_geojson_for_post( $mapping, $current_settings );
if ( ! isset( $json['features'] ) ) {
$json['features'] = array();
}
if ( ! isset( $json['type'] ) ) {
$json['type'] = 'FeatureCollection';
}
$show_popups = ( isset( $current_settings['show_popups'] ) ? $current_settings['show_popups'] : $mapping['show_popups'] );
if ( $show_popups ) {
$json = $this->make_popups( $mapping, $json );
}
return $json;
}
/**
* Setup the actions to get things started
*
* Enqueue js/css needed for this interface
*
* This is run for all instances of the interface, even empty ones
*/
abstract function setup_actions();
/**
* Fetch the GeoJSON feature(s) for the current post so we can print their attributes
* for the attribute shortcode.
*
* Returned features should have at least the property specified in $attrs['attr'].
*
* @note This is separate from get_geojson_for_post because some optimizations
* can be made by selecting only the columsn needed in this call, while
* get_geojson_for_post probably needs to return all columns For now we're just
* going to fetch the geojson the same way for both calls. We'll see if it's an
* issue later
*
* @param array $attrs The shortcode $attrs.
* @param string $contents The contents between the shortcode tags.
* @param array $mapping The current mapping config.
* @param array $current_settings The settings for this specific post.
*
* @return GeoJSON with each feature having the property specified $attrs['attr']
*/
function get_attribute_shortcode_geojson( $attrs, $contents, $mapping, $current_settings ) {
return $this->get_geojson_for_post( $mapping, $current_settings );
}
/**
* Setup actions for a specific connection
*
* This is run only when we have a connection configured
*/
function connection_setup_actions() { }
/**
* @param array $config This instance's config
*/
function set_config( $config = array() ) {
$this->config = $config;
if ( ! empty( $config ) ) {
$this->connection_setup_actions();
}
}
/**
* Wrapper for wp_remote_post with caching
*
* @param string $url The url to post to.
* @param array $args The args for the post.
* @param bool $cache Should cache be enabled for this request.
*
* return The post body.
*/
function remote_post( $url, $args = array(), $cache = true ) {
if ( $cache ) {
$queryString = http_build_query( $args );
$cache_string = $url . $queryString;
$cache_hash = sha1( $cache_string );
$cached = $this->savvy->get_from_cache( $cache_hash );
if ( $cached ) {
return $cached;
}
}
$result = wp_remote_post( $url, $args );
if ( $cache && strpos( $result['response']['code'], '2' ) === 0 ) {
$this->savvy->write_to_cache( $cache_hash, $result['body'] );
}
return $result['body'];
}
/**
* Wrapper for wp_remote_post with caching
*
* @param string $url The url to post to.
* @param array $args The args for the post.
* @param bool $cache Should cache be enabled for this request.
*
* return The post body.
*/
function remote_get( $url, $args = array(), $cache = true ) {
if ( $cache ) {
$queryString = http_build_query( $args );
$cache_string = $url . $queryString;
$cache_hash = sha1( $cache_string );
$cached = $this->savvy->get_from_cache( $cache_hash );
if ( $cached ) {
return $cached;
}
}
$result = wp_remote_get( $url, $args );
if ( $cache && strpos( $result['response']['code'], '2' ) === 0 ) {
$this->savvy->write_to_cache( $cache_hash, $result['body'] );
}
return $result['body'];
}
/**
* Get the ID for this instance
*
* @return The ID, or the curren time if this interface isn't set up yet.
*/
function get_id() {
if ( ! empty( $this->config['_id'] ) ) {
return $this->config['_id'];
}
return time();
}
/**
* Get the connection_name for this instance
*
* @return The connection name, or empty string if this interface isn't set up yet.
*/
function get_connection_name() {
if ( ! empty( $this->config['connection_name'] ) ) {
return $this->config['connection_name'];
}
return '';
}
/**
* Get something from cache
*/
function get_cache( $cache_key ) {
if ( isset( $this->cache[ $cache_key ] ) ) {
return $this->cache[ $cache_key ];
}
return false;
}
/**
* Set the cache
*/
function set_cache( $cache_key, $cache_value ) {
$this->cache[ $cache_key ] = $cache_value;
}
/**
* Interfaces should use these form_make functions so that css and layout is consistant.
*
* @param string $label The label to display.
* @param string $param_name The input parameter
* @param array $values An arry of values for the options
* @param array $labels the labels to use, if the values shouldn't also be used for the labels.
* @param bool/string $selected The value to pre-select
*
* @return An html string.
*/
function form_make_select( $label, $param_name, $values, $labels = array(), $selected = false ) {
if ( $label == '' ) {
$html = '';
} else {
$html = '<label>' . $label . '</label>';
}
$html .= '<select data-name="' . $param_name . '">';
$html .= '<option value="">--</option>';
foreach ( $values as $k => $value ) {
$html .= '<option value="' . $value . '"';
if ( $selected == $value ) {
$html .= ' selected="selected"';
}
$html .= '>';
if ( ! empty( $labels ) ) {
$label = $labels[ $k ];
} else {
$label = $value;
}
$html .= $label . '</option>';
}
$html .= '</select>';
return $html;
}
/**
* Make a textarea
*
* @param string $label The label to display.
* @param string $param_name The input parameter
* @param string $value the value to include in the textarea
*
* @return An html string.
*/
function form_make_textarea( $label, $param_name, $value = '' ) {
$html = '<label>' . $label . '</label>';
if ( is_array( $value ) ) {
$value = implode( "\n",$value );
}
$html .= '<textarea data-name="' . $param_name . '">' . $value . '</textarea>';
return $html;
}
/**
* Make a checkbox
*
* @param string $label The label to display.
* @param string $param_name The input parameter.
* @param bool $checked Should the checkbox be checked.
*
* @return An html string.
*/
function form_make_checkbox( $label, $param_name, $checked ) {
$html = '<label>' . $label . '</label>';
$html .= '<input data-name="' . $param_name . '" type="checkbox" value="1"';
if ( $checked ) {
$html .= ' checked="checked"';
}
$html .= '>';
return $html;
}
/**
* Make a text input
*
* @param string $label The label to display.
* @param string $param_name The input parameter.
* @param bool $value The pre-populated input of the text input
*
* @return An html string
*/
function form_make_text( $label, $param_name, $value ) {
$html = '<label>' . $label . '</label>';
$html .= '<input type="text" data-name="' . $param_name . '" value="' . $value . '">';
return $html;
}
/**
* Get the name of this plugin
*/
function get_name() {
return $this->name;
}
/**
* The type should be an html-attribute friendly name
*/
function get_type() {
$typename = sanitize_title( $this->name );
$typename = str_replace( '-', '_', $typename );
return $typename;
}
/**
* Make the popups for the geojson
*
* @param array $mapping The current mapping we're working with.
* @param geojson $json A GeoJSON FeatureCollection.
*
* @return The modified GeoJSON.
*/
function make_popups( $mapping, $json ) {
if ( empty( $json['features'] ) ) {
return $json;
}
foreach ( $json['features'] as &$feature ) {
$popup_properties = apply_filters( 'savvymapper_popup_fields', $feature['properties'] , $feature, $mapping );
$html = '';
if ( ! empty( $popup_properties ) ) {
$html .= '<div class="savvymapper_popup_wrapper"><table class="savvymapper_popup">';
foreach ( $popup_properties as $k => $v ) {
$empty_row = '';
if ( empty( $v ) ) {
$empty_row = ' class="empty_row"';
}
$html .= '<tr' . $empty_row . '><th>' . $k . '</th><td>' . $v . '</td></tr>';
}
$html .= '</table></div>';
}
$popuphtml = apply_filters( 'savvymapper_popup_html', $html, $feature, $mapping );
if ( ! empty( $popuphtml ) ) {
$feature['_popup_contents'] = $popuphtml;
}
}
return $json;
}
/**
* Handle any unsupported methods here
*/
function __call( $method, $args ) {
error_log( 'The method ' . $method . ' is not supported by this class.' );
}
}