1: <?php
2:
3: 4: 5:
6: class Papi_Core_Property {
7:
8: 9: 10: 11: 12:
13: protected $conditional;
14:
15: 16: 17: 18: 19:
20: public $convert_type = 'string';
21:
22: 23: 24: 25: 26:
27: private $default_import_settings = [
28: 'property_array_slugs' => false
29: ];
30:
31: 32: 33: 34: 35:
36: protected $default_options = [
37: 'after_class' => '',
38: 'after_html' => '',
39: 'before_class' => '',
40: 'before_html' => '',
41: 'capabilities' => [],
42: 'default' => '',
43: 'description' => '',
44: 'disabled' => false,
45: 'display' => true,
46: 'lang' => false,
47: 'overwrite' => false,
48: 'post_type' => '',
49: 'raw' => false,
50: 'required' => false,
51: 'rules' => [],
52: 'settings' => [],
53: 'sidebar' => true,
54: 'slug' => '',
55: 'sort_order' => -1,
56: 'title' => '',
57: 'type' => '',
58: 'value' => ''
59: ];
60:
61: 62: 63: 64: 65:
66: public $default_value;
67:
68: 69: 70: 71: 72:
73: protected $display = true;
74:
75: 76: 77: 78: 79:
80: private $options;
81:
82: 83: 84: 85: 86:
87: private $page;
88:
89: 90: 91: 92: 93:
94: private $post_id;
95:
96: 97: 98:
99: public function __construct() {
100: $this->setup_actions();
101: $this->setup_conditional();
102: $this->setup_default_options();
103: $this->setup_filters();
104: }
105:
106: 107: 108: 109: 110: 111: 112:
113: public function __get( $key ) {
114: return $this->get_option( $key );
115: }
116:
117: 118: 119: 120: 121: 122: 123:
124: public function __isset( $key ) {
125: return $this->get_option( $key ) !== null;
126: }
127:
128: 129: 130: 131: 132: 133:
134: public function __set( $key, $value ) {
135: $this->set_option( $key, $value );
136: }
137:
138: 139: 140: 141: 142: 143: 144:
145: public static function create( $options = [] ) {
146: $property = new static;
147: $property->set_options( $options );
148: return $property;
149: }
150:
151: 152: 153: 154: 155: 156: 157:
158: private function convert_settings( $settings ) {
159: foreach ( $settings as $key => $value ) {
160: if ( ! is_array( $value ) ) {
161: continue;
162: }
163:
164: $settings[$key] = $this->convert_items_array( $value );
165: }
166:
167: return $settings;
168: }
169:
170: 171: 172: 173: 174: 175: 176:
177: private function convert_items_array( $items ) {
178: foreach ( $items as $index => $item ) {
179: if ( is_array( $item ) && ! isset( $item['type'] ) ) {
180: foreach ( $item as $key => $value ) {
181: if ( is_array( $value ) ) {
182: $items[$index][$key] = $this->convert_items_array( $value );
183: $items[$index][$key] = array_filter( $items[$index][$key] );
184: $items[$index][$key] = array_values( $items[$index][$key] );
185: }
186: }
187:
188: continue;
189: }
190:
191: if ( papi_is_property( $item ) ) {
192: $child_items = $item->get_setting( 'items' );
193:
194: if ( is_array( $child_items ) ) {
195: $items[$index]->set_setting( 'items', $this->convert_items_array( $child_items ) );
196: }
197:
198: continue;
199: }
200:
201: if ( ( is_array( $item ) && isset( $item['type'] ) ) || ( is_object( $item ) && isset( $item->type ) ) ) {
202: $items[$index] = papi_get_property_type( $item );
203:
204: if ( is_null( $items[$index] ) ) {
205: unset( $items[$index] );
206: continue;
207: }
208:
209: if ( is_object( $items[$index] ) ) {
210: $child_items = $items[$index]->get_setting( 'items' );
211:
212: if ( is_array( $child_items ) ) {
213: $items[$index]->set_setting( 'items', $this->convert_items_array( $child_items ) );
214: }
215: }
216: }
217: }
218:
219: return $items;
220: }
221:
222: 223: 224: 225: 226: 227: 228: 229: 230:
231: public function delete_value( $slug, $post_id, $type ) {
232: if ( $type === Papi_Core_Page::TYPE_OPTION || $this->is_option_page() ) {
233: return delete_option( $slug );
234: }
235:
236: return delete_post_meta( $post_id, $slug );
237: }
238:
239: 240: 241: 242: 243:
244: public function disabled() {
245:
246:
247: if ( ! empty( $this->post_type ) && $this->post_type !== papi_get_post_type() ) {
248: return true;
249: }
250:
251: return $this->disabled;
252: }
253:
254: 255: 256: 257: 258:
259: public function display() {
260:
261:
262: return $this->display ? $this->options->display : false;
263: }
264:
265: 266: 267: 268: 269: 270: 271:
272: public static function factory( $type ) {
273: if ( is_array( $type ) ) {
274: $prop = self::create( $type );
275: $type = $prop->get_options();
276: }
277:
278: if ( ! is_string( $type ) && ! is_object( $type ) ) {
279: return;
280: }
281:
282: if ( is_subclass_of( $type, __CLASS__ ) ) {
283: return $type;
284: }
285:
286: $options = null;
287:
288: if ( is_object( $type ) ) {
289: if ( ! isset( $type->type ) || ! is_string( $type->type ) ) {
290: return;
291: }
292:
293: $options = $type;
294: $type = $type->type;
295: }
296:
297: $type = preg_replace( '/^Property/', '', $type );
298:
299: if ( empty( $type ) ) {
300: return;
301: }
302:
303: $class_name = papi_get_property_class_name( $type );
304:
305: if ( ! class_exists( $class_name ) || ! is_subclass_of( $class_name, __CLASS__ ) ) {
306: return;
307: }
308:
309: if ( ! papi()->exists( $class_name ) ) {
310: papi()->bind( $class_name, new $class_name() );
311: }
312:
313: $class = papi()->make( $class_name );
314:
315: if ( ! is_object( $class ) || $class instanceof Papi_Core_Property === false ) {
316: $class = new $class_name();
317: papi()->bind( $class_name, $class );
318: }
319:
320: $property = clone $class;
321:
322: if ( is_object( $options ) ) {
323: $property->set_options( $options );
324: }
325:
326: return $property;
327: }
328:
329: 330: 331: 332: 333: 334: 335: 336: 337: 338:
339: public function format_value( $value, $slug, $post_id ) {
340: return papi_maybe_json_decode(
341: maybe_unserialize( $value ),
342: $this->convert_type === 'array'
343: );
344: }
345:
346: 347: 348: 349: 350:
351: public function get_child_properties() {
352: return $this->get_setting( 'items', [] );
353: }
354:
355: 356: 357: 358: 359:
360: public function get_default_settings() {
361: return [];
362: }
363:
364: 365: 366: 367: 368:
369: public function get_import_settings() {
370: return [];
371: }
372:
373: 374: 375: 376: 377: 378: 379:
380: public function get_option( $key ) {
381: if ( isset( $this->options->$key ) ) {
382: return $this->options->$key;
383: }
384:
385: if ( isset( $this->default_options[$key] ) ) {
386: $option = $this->default_options[$key];
387:
388: if ( $key === 'settings' ) {
389: $option = (object) $option;
390: }
391:
392: return $option;
393: }
394: }
395:
396: 397: 398: 399: 400:
401: public function get_options() {
402: return $this->options;
403: }
404:
405: 406: 407: 408: 409:
410: public function get_page() {
411: if ( $this->page instanceof Papi_Core_Page ) {
412: return $this->page;
413: }
414:
415: return papi_get_page( $this->get_post_id() );
416: }
417:
418: 419: 420: 421: 422:
423: public function get_post_id() {
424: if ( ! papi_is_empty( $this->post_id ) ) {
425: return $this->post_id;
426: }
427:
428: if ( $this->page instanceof Papi_Core_Page ) {
429: return $this->page->id;
430: }
431:
432: return papi_get_post_id();
433: }
434:
435: 436: 437: 438: 439:
440: public function get_rules() {
441: return $this->get_option( 'rules' );
442: }
443:
444: 445: 446: 447: 448: 449: 450: 451:
452: public function get_setting( $key, $default = null ) {
453: if ( ! is_string( $key ) ) {
454: return $default;
455: }
456:
457: $settings = $this->get_settings();
458:
459: if ( isset( $settings->$key ) ) {
460: return $settings->$key;
461: }
462:
463: return $default;
464: }
465:
466: 467: 468: 469: 470:
471: public function get_settings() {
472: $settings = wp_parse_args(
473: $this->get_option( 'settings' ),
474: $this->get_default_settings()
475: );
476:
477: return (object) $this->convert_settings( $settings );
478: }
479:
480: 481: 482: 483: 484: 485: 486:
487: public function get_slug( $remove_prefix = false ) {
488: if ( $remove_prefix ) {
489: return papi_remove_papi( $this->get_option( 'slug' ) );
490: }
491:
492: return $this->get_option( 'slug' );
493: }
494:
495: 496: 497: 498: 499:
500: public function get_value() {
501: $value = $this->get_option( 'value' );
502:
503: if ( papi_is_empty( $value ) ) {
504: $slug = $this->get_slug( true );
505:
506: if ( $this->is_option_page() ) {
507: $value = papi_get_option( $slug );
508: } else {
509: $value = papi_get_field( $this->get_post_id(), $slug );
510: }
511:
512: $post_status = get_post_status( $this->get_post_id() );
513:
514: if ( papi_is_empty( $value ) && ( $post_status === false || $post_status === 'auto-draft' ) ) {
515: $value = $this->get_option( 'default' );
516: }
517: }
518:
519: return $this->prepare_value( $value );
520: }
521:
522: 523: 524: 525: 526: 527: 528: 529:
530: public function html_id( $suffix = '', $row = null ) {
531: if ( is_array( $suffix ) || is_object( $suffix ) ) {
532: return '_' . $this->html_name( $suffix, $row );
533: } else {
534: $suffix = empty( $suffix ) ||
535: ! is_string( $suffix ) ? '' : '_' . $suffix;
536: $suffix = papi_underscorify( papi_slugify( $suffix ) );
537: }
538:
539: $name = $this->html_name();
540:
541: if ( $name[strlen( $name ) - 1] === ']' ) {
542: return sprintf( '_%s%s]', substr( $name, 0, strlen( $name ) - 1 ), $suffix );
543: }
544:
545: return sprintf( '_%s%s', $this->html_name(), $suffix );
546: }
547:
548: 549: 550: 551: 552: 553: 554: 555:
556: public function html_name( $sub_property = null, $row = null ) {
557: $base_slug = $this->get_option( 'slug' );
558:
559: if ( is_null( $sub_property ) ) {
560: return $base_slug;
561: }
562:
563: if ( is_numeric( $row ) ) {
564: $base_slug = sprintf( '%s[%d]', $base_slug, intval( $row ) );
565: }
566:
567: if ( ! papi_is_property( $sub_property ) ) {
568: if ( is_array( $sub_property ) || is_object( $sub_property ) ) {
569: $sub_property = self::factory( $sub_property );
570: } else {
571: return $base_slug;
572: }
573: }
574:
575: return sprintf(
576: '%s[%s]',
577: $base_slug,
578: papi_remove_papi( $sub_property->get_slug() )
579: );
580: }
581:
582: 583: 584: 585: 586: 587: 588: 589:
590: public function import_setting( $key, $default = null ) {
591: if ( ! is_string( $key ) ) {
592: return $default;
593: }
594:
595: $settings = $this->import_settings();
596:
597: return isset( $settings->$key ) ? $settings->$key : $default;
598: }
599:
600: 601: 602: 603: 604:
605: public function import_settings() {
606: $settings = $this->get_import_settings();
607:
608: $settings = is_array( $settings ) || is_object( $settings ) ?
609: $settings : [];
610:
611: return (object) array_merge(
612: $this->default_import_settings,
613: (array) $settings
614: );
615: }
616:
617: 618: 619: 620: 621: 622: 623: 624: 625:
626: public function import_value( $value, $slug, $post_id ) {
627: return papi_maybe_json_decode(
628: maybe_unserialize( $value ),
629: $this->convert_type === 'array'
630: );
631: }
632:
633: 634: 635: 636: 637:
638: public function is_option_page() {
639: if ( $this->page === null ) {
640: return papi_is_option_page();
641: }
642:
643: return $this->page->is( Papi_Core_Page::TYPE_OPTION );
644: }
645:
646: 647: 648: 649: 650: 651: 652: 653: 654:
655: public function load_value( $value, $slug, $post_id ) {
656: return papi_maybe_json_decode(
657: maybe_unserialize( $value ),
658: $this->convert_type === 'array'
659: );
660: }
661:
662: 663: 664: 665: 666: 667: 668:
669: public function match_slug( $slug ) {
670: if ( ! is_string( $slug ) ) {
671: $slug = '';
672: }
673:
674: return $this->get_slug( ! preg_match( '/^papi\_/', $slug ) ) === $slug;
675: }
676:
677: 678: 679: 680: 681: 682: 683:
684: protected function prepare_value( $value ) {
685: if ( papi_is_empty( $value ) ) {
686: return $this->default_value;
687: }
688:
689: if ( $this->convert_type === 'string' ) {
690: $value = papi_convert_to_string( $value );
691: }
692:
693: return papi_santize_data( $value );
694: }
695:
696: 697: 698:
699: public function render_ajax_request() {
700: papi_render_property( $this );
701: }
702:
703: 704: 705: 706: 707: 708: 709: 710:
711: public function render_is_allowed_by_rules( array $rules = [] ) {
712: if ( empty( $rules ) ) {
713: $rules = $this->get_rules();
714: }
715:
716: return $this->conditional->display( $rules, $this );
717: }
718:
719: 720: 721: 722: 723:
724: public function set_page( Papi_Core_Page $page ) {
725: $this->page = $page;
726: }
727:
728: 729: 730: 731: 732:
733: public function set_post_id( $post_id ) {
734: if ( ! is_numeric( $post_id ) ) {
735: return;
736: }
737:
738: $this->post_id = (int) $post_id;
739: }
740:
741: 742: 743: 744: 745:
746: public function set_options( $options ) {
747: $this->options = $this->setup_options( $options );
748: }
749:
750: 751: 752: 753: 754: 755:
756: public function set_option( $key, $value ) {
757: if ( ! is_object( $this->options ) ) {
758: $this->options = (object) $this->default_options;
759: }
760:
761: if ( isset( $this->options->$key ) ) {
762: $this->options->$key = $value;
763: }
764: }
765:
766: 767: 768: 769: 770: 771:
772: public function set_setting( $key, $value ) {
773: if ( isset( $this->options->settings ) && isset( $this->options->settings->$key ) ) {
774: $this->options->settings->$key = $value;
775: }
776: }
777:
778: 779: 780:
781: protected function setup_actions() {
782: }
783:
784: 785: 786:
787: protected function setup_conditional() {
788: $this->conditional = new Papi_Core_Conditional();
789: }
790:
791: 792: 793: 794:
795: private function setup_default_options() {
796: if ( $this->default_options['sort_order'] === -1 ) {
797: $this->default_options['sort_order'] = papi_filter_settings_sort_order();
798: }
799:
800: if ( empty( $this->default_options['post_type'] ) ) {
801: $this->default_options['post_type'] = papi_get_post_type();
802: }
803:
804: if ( papi_is_empty( $this->default_options['default'] ) ) {
805: $this->default_options['default'] = $this->default_value;
806: }
807: }
808:
809: 810: 811:
812: protected function setup_filters() {
813: }
814:
815: 816: 817: 818: 819: 820: 821:
822: private function setup_options( $options ) {
823:
824: if ( is_object( $options ) ) {
825: return $options;
826: }
827:
828:
829: if ( ! is_array( $options ) ) {
830: $options = [];
831: }
832:
833:
834: $options = array_merge( $this->default_options, $options );
835: $options = (object) $options;
836:
837:
838: $options->capabilities = papi_to_array( $options->capabilities );
839:
840:
841: $options->slug = $this->setup_options_slug( $options );
842:
843:
844: $options->settings = $this->setup_options_settings( $options );
845:
846:
847: return papi_esc_html( $options, ['before_html', 'html', 'after_html'] );
848: }
849:
850: 851: 852: 853: 854: 855: 856:
857: private function setup_options_slug( $options ) {
858: $slug = $options->slug;
859:
860: if ( empty( $slug ) ) {
861: if ( empty( $options->title ) ) {
862: $slug = papi_slugify( $options->type );
863: } else {
864: $slug = papi_slugify( $options->title );
865: }
866: }
867:
868: return $slug === 'papi_' ? '' : papi_html_name( $slug );
869: }
870:
871: 872: 873: 874: 875: 876: 877:
878: private function setup_options_settings( $options ) {
879: $property_class = self::factory( $options->type );
880:
881: if ( papi_is_property( $property_class ) ) {
882: $options->settings = array_merge(
883: (array) $property_class->get_default_settings(),
884: (array) $options->settings
885: );
886: }
887:
888: return (object) $this->convert_settings( $options->settings );
889: }
890:
891: 892: 893: 894: 895: 896: 897: 898: 899:
900: public function update_value( $value, $slug, $post_id ) {
901: return papi_maybe_json_encode( $value );
902: }
903: }
904: