PluginProbe
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar / trunk
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar vtrunk
3.3.1 3.3.0 3.2.14 3.2.13 3.2.12 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 trunk 0.2.5.5 0.2.5.6 0.2.5.7 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.2.1 All 156 releases
notificationx / vendor / wpdeveloper / lib-settings / lib / class-settings.php

class-settings.php in NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar trunk, at vendor/wpdeveloper/lib-settings/lib/class-settings.php

709 lines 16.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Settings Library
4 *
5 * @namespace UsabilityDynamics
6 */
7 namespace UsabilityDynamics {
8
9 if( !class_exists( 'UsabilityDynamics\Settings' ) ) {
10
11 /**
12 * Class Settings
13 *
14 * @package UsabilityDynamics
15 */
16 class Settings {
17
18 /**
19 * Settings Class version.
20 *
21 * @public
22 * @static
23 * @property $version
24 * @type {Object}
25 */
26 static public $version = '0.3.0';
27
28 /**
29 * Prefix for option keys to unique
30 *
31 * @var string
32 */
33 private $prefix = '';
34
35 /**
36 * Whether or not to hash option keys before saving
37 *
38 * @var bool
39 */
40 private $hash_keys = false;
41
42 /**
43 * Data storage
44 *
45 * @var array
46 */
47 private $_data = array();
48
49 /**
50 * Settings Schema.
51 *
52 * @static
53 * @property $_schema
54 * @type {Object}
55 */
56 private $_schema = false;
57
58 /**
59 * Settings Namespace.
60 *
61 * @static
62 * @property $_namespace
63 * @type {String}
64 */
65 private $_namespace = false;
66
67 /**
68 * Storage Key.
69 *
70 * @static
71 * @property $_key
72 * @type {String}
73 */
74 private $_key = false;
75
76 /**
77 * Settings Format.
78 *
79 * Options are: 'json', 'object', 'array', 'hash-map'.
80 *
81 * @static
82 * @property $_format
83 * @type {String}
84 */
85 private $_format = null;
86
87 /**
88 * Storage Location
89 *
90 * @static
91 * @property $_store
92 * @type {String}
93 */
94 private $_store = false;
95
96 /**
97 * For transient storage.
98 *
99 * @static
100 * @property $_expiration
101 * @type {String}
102 */
103 private $_expiration = 60;
104
105 /**
106 * Toggle Debugger.
107 *
108 * @static
109 * @property $_debug
110 * @type {Boolean}
111 */
112 private $_debug = false;
113
114 /**
115 * Automatically Save.
116 *
117 * @static
118 * @property $_debug
119 * @type {Boolean}
120 */
121 private $auto_commit = false;
122
123 /**
124 * Instance Valid.
125 *
126 * @static
127 * @property $is_valid
128 * @type {Boolean}
129 */
130 public $is_valid = true;
131
132 /**
133 * Constructor
134 *
135 * @param bool $args
136 *
137 * @example
138 *
139 * $_settings = new Settings(array(
140 * "store" => "options"
141 * ));
142 *
143 * $_settings->set( 'my.key', 'my.value' );
144 *
145 * @internal param \UsabilityDynamics\type $defaults
146 * @internal param bool|\UsabilityDynamics\type $force_save
147 * @internal param string|\UsabilityDynamics\type $prefix
148 * @internal param bool|\UsabilityDynamics\type $hash_keys
149 */
150 public function __construct( $args = false ) {
151
152 $args = Utility::parse_args( $args, array(
153 'namespace' => '',
154 'key' => '',
155 'auto_commit' => false,
156 'debug' => false,
157 'store' => false,
158 'schema' => false,
159 'format' => false,
160 'data' => null
161 ));
162
163 // Load Schema.
164 if( isset( $args->schema ) && $args->schema ) {
165 $this->set_schema( $args->schema );
166 }
167
168 // Set Storage Location(s).
169 if( isset( $args->store ) && $args->store ) {
170 $this->_store = $args->store;
171 }
172
173 // Set Storage Key.
174 if( isset( $args->key ) && $args->key ) {
175 $this->_key = $args->key;
176 }
177
178 // Set transient vxpiration value.
179 if( isset( $args->expiration ) && $args->expiration ) {
180 $this->_expiration = $args->expiration;
181 }
182
183 // Set Format to enforce.
184 if( $args->format ) {
185 $this->_format = $args->format;
186 }
187 // Toggle Debugger.
188 if( $args->debug ) {
189 $this->_debug = $args->debug;
190 }
191
192 // Set Settings Namespace.
193 if( $args->namespace ) {
194 $this->_namespace = $args->namespace;
195 }
196
197 // Set Auto Commit.
198 if( $args->auto_commit ) {
199 $this->auto_commit = $args->auto_commit;
200 }
201
202 // Load Initial.
203 $this->_load();
204
205 // Set Initial Data.
206 if( $args->data ) {
207 $this->set( $args->data );
208 }
209
210 }
211
212 /**
213 * Getter for options
214 *
215 * @param bool|\UsabilityDynamics\type $key
216 *
217 * @param bool $default
218 *
219 * @return type
220 */
221 public function get( $key = false, $default = false ) {
222
223 // Return all data.
224 if( !$key ) {
225 return $this->_output( $this->_data );
226 }
227
228 // Resolve dot-notated key.
229 if( strpos( $key, '.' ) ) {
230 return $this->_resolve( $this->_data, $key, $default );
231 }
232
233 // Return value or default.
234 return isset( $this->_data[ $key ] ) ? $this->_data[ $key ] : $default;
235
236 }
237
238 /**
239 * Setter for options
240 *
241 * @param string|\UsabilityDynamics\type $key
242 * @param bool|\UsabilityDynamics\type $value
243 * @param bool $bypass_validation
244 *
245 * @internal param bool|\UsabilityDynamics\type $force_save
246 *
247 * @return \UsabilityDynamics\Settings
248 */
249 public function set( $key = '', $value = false, $bypass_validation = false ) {
250
251 if( !$this->_data ) {
252 $this->_data = array();
253 }
254
255 // First argument is an object/array.
256 if( Utility::get_type( $key ) === 'object' || Utility::get_type( $key ) === 'array' || Utility::get_type( $key ) === 'stdClass' ) {
257
258 // Conver to array so merge can be done
259 $this->_data = Utility::extend( (array) $this->_data, (array) $key );
260
261 }
262
263 // Standard key & value pair
264 if( Utility::get_type( $key ) === 'string' && ( Utility::get_type( $value ) === 'string' || Utility::get_type( $value ) ==='integer' || Utility::get_type($value) === 'float' || Utility::get_type( $value ) === 'boolean' ) ) {
265
266 if( strpos( $key, '.' ) ) {
267 self::set_val( $this->_data, $key, $value );
268 } else {
269 $this->_data[ $key ] = $value;
270 }
271
272 }
273
274 // Standard key with complex value.
275 if( Utility::get_type( $key ) === 'string' ) {
276
277
278 if( Utility::get_type( $value ) === 'object' || Utility::get_type( $value ) === 'stdClass' ) {
279
280 if( strpos( $key, '.' ) ) {
281 self::set_val( $this->_data, $key, $value );
282 } else {
283
284 if( isset( $this->_data[ $key ] ) && Utility::get_type( $this->_data[ $key ] ) === 'object' ) {
285 $this->_data[ $key ] = Utility::extend( $this->_data[ $key ], $value );
286 } else {
287 $this->_data[ $key ] = $value;
288 }
289
290 }
291
292 }
293
294 // Standard key with array value
295 if( Utility::get_type( $value ) === 'array' ) {
296
297 if( strpos( $key, '.' ) ) {
298 self::set_val( $this->_data, $key, $value );
299 } else {
300 $this->_data[ $key ] = array_unique( array_merge( isset( $this->_data[ $key ] ) ? (array) $this->_data[ $key ] : array(), $value ), SORT_REGULAR );
301 }
302
303 }
304
305 }
306
307 // Validate if we have a schema.
308 if( $this->_schema ) {
309 // $this->_validate();
310 }
311
312 // Commit to Storage if validation passed.
313 if( $this->is_valid && $this->auto_commit ) {
314 $this->commit();
315 }
316
317 return $this;
318
319 }
320
321 /**
322 * Handle File Transfer for downloading
323 *
324 * @param array $args
325 *
326 * @return bool
327 */
328 public function file_transfer( $args = array() ) {
329
330 $args = Utility::parse_args( $args, array(
331 "name" => "settings",
332 "format" => "json",
333 "cache" => 'public',
334 "filename" => null,
335 "charset" => 'utf8'
336 ) );
337
338 $args->filename = $args->filename ? $args->filename : $args->name . '-' . date( 'Y-m-d' ) . '.' . $args->format;
339
340 // Ensure headers have not been sent.
341 if( headers_sent() ) {
342 return false;
343 }
344
345 // Send headers.
346 header( "Cache-Control: {$args->cache}" );
347 header( "Content-Disposition: attachment; filename={$args->filename}" );
348 header( "Content-Type: text/plain; charset={$args->charset}" );
349 header( "Content-Description: File Transfer" );
350 header( "Content-Transfer-Encoding: binary" );
351
352 // Prepare in needed format.
353 $_data = $this->_output( $this->get(), $args->format );
354
355 // Write data.
356 die( $_data );
357
358 }
359
360 /**
361 * Set Schema from a string or objct.
362 *
363 * @param bool $schema
364 *
365 * @return array|bool|mixed|object
366 */
367 public function set_schema( $schema = false ) {
368
369 try {
370
371 // Take schema as given.
372 if( gettype( $schema ) === 'array' ) {
373 $this->_schema = (object) $schema;
374 }
375
376 // Take schema as given.
377 if( gettype( $schema ) === 'object' ) {
378 $this->_schema = $schema;
379 }
380
381 // Load schema from a file.
382 if( gettype( $schema ) === 'string' && is_file( $schema ) ) {
383 $this->_schema = json_decode( file_get_contents( $schema ) );
384 }
385
386 } catch( \Exception $error ) {
387 $this->_console( 'Caught exception: ' . $error->getMessage() );
388 }
389
390 return $this->_schema ? $this->_schema : false;
391
392 }
393
394 /**
395 * Commit Settings to Storage.
396 *
397 * * site_options - For WordPress, falls back to option if not in multisite.
398 * * options - For WordPress, stores in blog options.
399 *
400 * @author potanin@UD
401 * @method commit
402 */
403 public function commit() {
404
405 $_data = $this->_data;
406
407 // Exclude protected keys.
408 foreach( (array) $_data as $key => $value ) {
409
410 if( substr( $key, 0, 2 ) === '__' ) {
411 unset( $_data[ $key ] );
412 }
413
414 }
415
416 switch( $this->_store ) {
417
418 case 'transient':
419 $_value = json_encode( $_data, JSON_FORCE_OBJECT );
420
421 if( function_exists( 'set_transient' ) ) {
422 $_value = set_transient( $this->_key, $_value, $this->_expiration );
423 }
424
425 break;
426
427 case 'site_transient':
428
429 $_value = json_encode( $_data, JSON_FORCE_OBJECT );
430
431 if( function_exists( 'set_site_transient' ) ) {
432 $_value = set_site_transient( $this->_key, $_value, $this->_expiration );
433 }
434
435 break;
436
437 case 'site_options':
438
439
440 if( function_exists( 'update_site_option' ) ) {
441 $_value = update_site_option( $this->_key, $_data );
442 }
443
444 break;
445
446 case 'options':
447
448 if( function_exists( 'update_option' ) ) {
449 $_value = update_option( $this->_key, $_data );
450 }
451
452 break;
453
454 }
455
456 return $this;
457
458 }
459
460 /**
461 * Remove Stored Settings
462 *
463 * @example
464 *
465 * $settings->flush();
466 *
467 * @return $this
468 */
469 public function flush($db = true, $key = null) {
470
471 if($db == true){
472 switch( $this->_store ) {
473 case 'options':
474 if( function_exists( 'delete_option' ) ) {
475 delete_option( $this->_key );
476 }
477 case 'site_options':
478 if( function_exists( 'delete_site_option' ) ) {
479 delete_option( $this->_key );
480 }
481 break;
482
483 }
484 }
485
486 if($key){
487 if(isset($this->_data[$key])){
488 unset($this->_data[$key]);
489 }
490 }
491 else{
492 $this->_data = [];
493 }
494
495
496 return $this;
497
498 }
499 /**
500 * Validate Settings against Schema
501 *
502 */
503 public function _validate() {
504
505 if( !class_exists( 'JsonSchema\Validator' ) ) {
506 return;
507 }
508
509 $validator = new \JsonSchema\Validator();
510
511 // Process Validation.
512 $validator->check( $this->_data, $this->_schema );
513
514 if( $validator->isValid() ) {
515 $this->is_valid = true;
516 $this->_console( "The supplied JSON validates against the schema." );
517 } else {
518 $this->is_valid = false;
519
520 $this->_console( "JSON does not validate. Violations:" );
521
522 foreach( $validator->getErrors() as $error ) {
523 $this->_console( sprintf( "[%s] %s\n", $error[ 'property' ], $error[ 'message' ] ) );
524 }
525
526 }
527
528 }
529
530 /**
531 * Library Debugger
532 *
533 * @param $data
534 */
535 public function _console( $data ) {
536
537 if( $this->_debug ) {
538 echo sprintf( "lib-settings debug: [%s].", $data );
539 }
540
541 }
542
543 /**
544 * Load options from DB
545 *
546 * @return \UsabilityDynamics\Settings
547 */
548 public function _load() {
549
550 switch( $this->_store ) {
551
552 // WordPress Site Options.
553 case 'options':
554 case 'site_options':
555
556 // Load from options.
557 if( $this->_store == 'site_options' ) {
558 $_value = \get_site_option( $this->_key );
559 } else {
560 $_value = \get_option( $this->_key );
561 }
562
563 // If already an array it must have been serialized
564 if( gettype( $_value ) === 'array' ) {
565 return $this->_output( $this->_data = $_value );
566 }
567
568 try {
569
570 $_value = json_decode( $_value, true );
571
572 } catch( \Exception $error ) {
573 $this->_console( 'Caught exception: ' . $error->getMessage() );
574 }
575
576 $this->_data = $_value;
577
578 break;
579
580 default:
581
582 break;
583
584 }
585
586 return $this->_data;
587
588 }
589
590 /**
591 * Prepare Data for Output
592 *
593 * @param $data
594 *
595 * @param bool $format
596 *
597 * @return array|mixed|string|void
598 */
599 public function _output( $data, $format = false ) {
600
601 $format = $format ? $format : $this->_format;
602
603 // Stringify.
604 if( $format === 'json' ) {
605 return json_encode( $data );
606 }
607
608 // Deeep Object.
609 if( $format === 'object' ) {
610 return json_decode( json_encode( $data ) );
611 }
612
613 return $data;
614
615 }
616
617 /**
618 * @param array $arr
619 * @param $path
620 * @param $val
621 *
622 * @return mixed
623 */
624 public function set_val( array &$arr, $path, $val ) {
625 $loc = & $arr;
626
627 foreach( explode( '.', $path ) as $step ) {
628 $loc = & $loc[ $step ];
629 }
630
631 return $loc = $val;
632
633 }
634
635 /**
636 * Expand Array
637 * @source http://stackoverflow.com/questions/17365059/how-to-unflatten-array-in-php-using-dot-notation
638 *
639 * @param $array
640 * @param int $level
641 *
642 * @return array
643 */
644 public function _expand( $array, $level = 0 ) {
645 $result = array();
646 $next = $level + 1;
647
648 foreach( $array as $key => $value ) {
649 $tree = explode( '.', $key );
650
651 if( isset( $tree[ $level ] ) ) {
652 if( !isset( $tree[ $next ] ) ) {
653 $result[ $tree[ $level ] ][ 'id' ] = $key;
654 $result[ $tree[ $level ] ][ 'title' ] = $value;
655 if( !isset( $result[ $tree[ $level ] ][ 'children' ] ) ) {
656 $result[ $tree[ $level ] ][ 'children' ] = array();
657 }
658 } else {
659 if( isset( $result[ $tree[ $level ] ][ 'children' ] ) ) {
660 $result[ $tree[ $level ] ][ 'children' ] = array_merge_recursive( $result[ $tree[ $level ] ][ 'children' ], self::_expand( array( $key => $value ), $next ) );
661 } else {
662 $result[ $tree[ $level ] ][ 'children' ] = self::_expand( array( $key => $value ), $next );
663 }
664 }
665
666 }
667 }
668
669 return $result;
670
671 }
672
673 /**
674 * Resolve dot-notated key.
675 *
676 * @source http://stackoverflow.com/questions/14704984/best-way-for-dot-notation-access-to-multidimensional-array-in-php
677 *
678 * @param $a
679 * @param $path
680 * @param null $default
681 *
682 * @internal param array $a
683 * @return array|null
684 */
685 public function _resolve( $a, $path, $default = null ) {
686
687 $current = $a;
688 $p = strtok( $path, '.' );
689
690 while( $p !== false ) {
691
692 if( !isset( $current[ $p ] ) ) {
693 return $default;
694 }
695
696 $current = $current[ $p ];
697 $p = strtok( '.' );
698
699 }
700
701 return $current;
702
703 }
704
705 }
706
707 }
708
709 }