PluginProbe
Widget Context / 1.2.0
Widget Context v1.2.0
1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.1.0 1.1.1 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 trunk 0.4.1 0.4.2 0.4.3 0.4.4 0.4.5 0.6 0.7 0.7.1 0.7.2 0.8 0.8.1 All 30 releases
widget-context / src / WidgetContext.php

WidgetContext.php in Widget Context 1.2.0, at src/WidgetContext.php

1,056 lines 28.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Widget Context plugin core.
5 */
6 class WidgetContext {
7
8 private $sidebars_widgets;
9 private $options_name = 'widget_logic_options'; // Context settings for widgets (visibility, etc)
10 private $settings_name = 'widget_context_settings'; // Widget Context global settings
11 private $sidebars_widgets_copy;
12
13 private $context_options = array(); // Store visibility settings
14 private $context_settings = array(); // Store admin settings
15 private $contexts = array();
16
17 /**
18 * Instance of the abstract plugin.
19 *
20 * @var Preseto\WidgetContext\Plugin
21 */
22 private $plugin;
23
24 /**
25 * Instance of the current class for legacy purposes.
26 *
27 * @var WidgetContext
28 */
29 protected static $instance;
30
31 /**
32 * Start the plugin.
33 *
34 * @param Preseto\WidgetContext\Plugin $path Instance of the abstract plugin.
35 */
36 public function __construct( $plugin ) {
37 $this->plugin = $plugin;
38
39 // Keep an instance for legacy purposes.
40 self::$instance = $this;
41 }
42
43 /**
44 * Legacy singleton instance getter.
45 *
46 * @return WidgetContext
47 */
48 public static function instance() {
49 return self::$instance;
50 }
51
52 /**
53 * Interface for registering modules.
54 *
55 * @param mixed $module Instance of the module.
56 *
57 * @return void
58 */
59 public function register_module( $module ) {
60 $module->init();
61 }
62
63 /**
64 * Hook into WP.
65 */
66 public function init() {
67 // Define available widget contexts
68 add_action( 'init', array( $this, 'define_widget_contexts' ), 5 );
69
70 // Load plugin settings and show/hide widgets by altering the
71 // $sidebars_widgets global variable
72 add_action( 'wp', array( $this, 'set_widget_contexts_frontend' ) );
73
74 // Append Widget Context settings to widget controls
75 add_action( 'in_widget_form', array( $this, 'widget_context_controls' ), 10, 3 );
76
77 // Add admin menu for config
78 add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts' ) );
79
80 // Save widget context settings, when in admin area
81 add_action( 'sidebar_admin_setup', array( $this, 'save_widget_context_settings' ) );
82
83 // Fix legacy context option naming
84 add_filter( 'widget_context_options', array( $this, 'fix_legacy_options' ) );
85
86 // Register admin settings menu
87 add_action( 'admin_menu', array( $this, 'widget_context_settings_menu' ) );
88
89 // Register admin settings
90 add_action( 'admin_init', array( $this, 'widget_context_settings_init' ) );
91 }
92
93
94 function define_widget_contexts() {
95 $this->context_options = apply_filters(
96 'widget_context_options',
97 (array) get_option( $this->options_name, array() )
98 );
99
100 $this->context_settings = wp_parse_args(
101 (array) get_option( $this->settings_name, array() ),
102 array(
103 'contexts' => array(),
104 )
105 );
106
107 // Default context
108 $default_contexts = array(
109 'incexc' => array(
110 'label' => __( 'Widget Context', 'widget-context' ),
111 'description' => __( 'Set the default logic to show or hide.', 'widget-context' ),
112 'weight' => -100,
113 'type' => 'core',
114 ),
115 'location' => array(
116 'label' => __( 'Global Sections', 'widget-context' ),
117 'description' => __( 'Based on standard WordPress template tags.', 'widget-context' ),
118 'weight' => 10,
119 ),
120 'url' => array(
121 'label' => __( 'Target by URL', 'widget-context' ),
122 'description' => __( 'Based on URL patterns.', 'widget-context' ),
123 'weight' => 20,
124 ),
125 'admin_notes' => array(
126 'label' => __( 'Notes (invisible to public)', 'widget-context' ),
127 'description' => __( 'Enables private notes on widget context settings.', 'widget-context' ),
128 'weight' => 90,
129 ),
130 );
131
132 // Add default context controls and checks
133 foreach ( $default_contexts as $context_name => $context_desc ) {
134 add_filter( 'widget_context_control-' . $context_name, array( $this, 'control_' . $context_name ), 10, 2 );
135 add_filter( 'widget_context_check-' . $context_name, array( $this, 'context_check_' . $context_name ), 10, 2 );
136 }
137
138 // Enable other plugins and themes to specify their own contexts
139 $this->contexts = apply_filters( 'widget_contexts', $default_contexts );
140
141 // Sort contexts by their weight
142 uasort( $this->contexts, array( $this, 'sort_context_by_weight' ) );
143 }
144
145
146 public function get_context_options( $widget_id = null ) {
147 if ( ! $widget_id ) {
148 return $this->context_options;
149 }
150
151 if ( isset( $this->context_options[ $widget_id ] ) ) {
152 return $this->context_options[ $widget_id ];
153 }
154
155 return null;
156 }
157
158
159 public function get_context_settings( $widget_id = null ) {
160 if ( ! $widget_id ) {
161 return $this->context_settings;
162 }
163
164 if ( isset( $this->context_settings[ $widget_id ] ) ) {
165 return $this->context_settings[ $widget_id ];
166 }
167
168 return null;
169 }
170
171
172 public function get_contexts() {
173 return $this->contexts;
174 }
175
176
177 function sort_context_by_weight( $a, $b ) {
178 if ( ! isset( $a['weight'] ) ) {
179 $a['weight'] = 10;
180 }
181
182 if ( ! isset( $b['weight'] ) ) {
183 $b['weight'] = 10;
184 }
185
186 return ( $a['weight'] < $b['weight'] ) ? -1 : 1;
187 }
188
189
190 function set_widget_contexts_frontend() {
191 // Hide/show widgets for is_active_sidebar() to work
192 add_filter( 'sidebars_widgets', array( $this, 'maybe_unset_widgets_by_context' ), 10 );
193 }
194
195
196 function admin_scripts( $page ) {
197 // Enqueue only on widgets and customizer view
198 if ( ! in_array( $page, array( 'widgets.php', 'settings_page_widget_context_settings' ), true ) ) {
199 return;
200 }
201
202 wp_enqueue_style(
203 'widget-context-css',
204 $this->plugin->asset_url( 'assets/css/admin.css' ),
205 null,
206 $this->plugin->asset_version()
207 );
208
209 wp_enqueue_script(
210 'widget-context-js',
211 $this->plugin->asset_url( 'assets/js/widget-context.js' ),
212 array( 'jquery' ),
213 $this->plugin->asset_version()
214 );
215 }
216
217
218 function widget_context_controls( $object, $return, $instance ) {
219 echo $this->display_widget_context( $object->id );
220 }
221
222
223 function save_widget_context_settings() {
224 if ( ! current_user_can( 'edit_theme_options' ) || empty( $_POST ) || ! isset( $_POST['wl'] ) ) {
225 return;
226 }
227
228 // Delete a widget
229 if ( isset( $_POST['delete_widget'] ) && isset( $_POST['the-widget-id'] ) ) {
230 unset( $this->context_options[ $_POST['the-widget-id'] ] );
231 }
232
233 // Add / Update
234 $this->context_options = array_merge( $this->context_options, $_POST['wl'] );
235
236 $sidebars_widgets = wp_get_sidebars_widgets();
237 $all_widget_ids = array();
238
239 // Get a lits of all widget IDs
240 foreach ( $sidebars_widgets as $widget_area => $widgets ) {
241 foreach ( $widgets as $widget_order => $widget_id ) {
242 $all_widget_ids[] = $widget_id;
243 }
244 }
245
246 // Remove non-existant widget contexts from the settings
247 foreach ( $this->context_options as $widget_id => $widget_context ) {
248 if ( ! in_array( $widget_id, $all_widget_ids, true ) ) {
249 unset( $this->context_options[ $widget_id ] );
250 }
251 }
252
253 update_option( $this->options_name, $this->context_options );
254 }
255
256
257 function maybe_unset_widgets_by_context( $sidebars_widgets ) {
258 // Don't run this at the backend or before
259 // post query has been run
260 if ( is_admin() ) {
261 return $sidebars_widgets;
262 }
263
264 // Return from cache if we have done the context checks already
265 if ( ! empty( $this->sidebars_widgets ) ) {
266 return $this->sidebars_widgets;
267 }
268
269 // Store a local copy of the original widget location
270 $this->sidebars_widgets_copy = $sidebars_widgets;
271
272 foreach ( $sidebars_widgets as $widget_area => $widget_list ) {
273
274 if ( 'wp_inactive_widgets' === $widget_area || empty( $widget_list ) ) {
275 continue;
276 }
277
278 foreach ( $widget_list as $pos => $widget_id ) {
279
280 if ( ! $this->check_widget_visibility( $widget_id ) ) {
281 unset( $sidebars_widgets[ $widget_area ][ $pos ] );
282 }
283 }
284 }
285
286 // Store in class cache
287 $this->sidebars_widgets = $sidebars_widgets;
288
289 return $sidebars_widgets;
290 }
291
292
293 function check_widget_visibility( $widget_id ) {
294 // Check if this widget even has context set
295 if ( ! isset( $this->context_options[ $widget_id ] ) ) {
296 return true;
297 }
298
299 $matches = array();
300
301 foreach ( $this->get_contexts() as $context_id => $context_settings ) {
302 // This context check has been disabled in the plugin settings
303 if ( isset( $this->context_settings['contexts'][ $context_id ] ) && ! $this->context_settings['contexts'][ $context_id ] ) {
304 continue;
305 }
306
307 // Make sure that context settings for this widget are defined
308 if ( ! isset( $this->context_options[ $widget_id ][ $context_id ] ) ) {
309 $widget_context_args = array();
310 } else {
311 $widget_context_args = $this->context_options[ $widget_id ][ $context_id ];
312 }
313
314 $matches[ $context_id ] = apply_filters(
315 'widget_context_check-' . $context_id,
316 null,
317 $widget_context_args
318 );
319 }
320
321 // Get the match rule for this widget (show/hide/selected/notselected)
322 $match_rule = $this->context_options[ $widget_id ]['incexc']['condition'];
323
324 // Force show or hide the widget!
325 if ( 'show' === $match_rule ) {
326 return true;
327 } elseif ( 'hide' === $match_rule ) {
328 return false;
329 }
330
331 $inc = false;
332
333 if ( 'selected' === $match_rule ) {
334 $inc = true;
335 }
336
337 if ( $inc && in_array( true, $matches, true ) ) {
338 return true;
339 } elseif ( ! $inc && ! in_array( true, $matches, true ) ) {
340 return true;
341 }
342
343 return false;
344 }
345
346
347 /**
348 * Default context checks
349 */
350
351 function context_check_incexc( $check, $settings ) {
352 return $check;
353 }
354
355
356 function context_check_location( $check, $settings ) {
357 $status = array(
358 'is_front_page' => is_front_page(),
359 'is_home' => is_home(),
360 'is_singular' => is_singular(),
361 'is_single' => is_singular( 'post' ),
362 'is_page' => ( is_page() && ! is_front_page() ),
363 'is_attachment' => is_attachment(),
364 'is_search' => is_search(),
365 'is_404' => is_404(),
366 'is_archive' => is_archive(),
367 'is_date' => is_date(),
368 'is_day' => is_day(),
369 'is_month' => is_month(),
370 'is_year' => is_year(),
371 'is_category' => is_category(),
372 'is_tag' => is_tag(),
373 'is_author' => is_author(),
374 );
375
376 $matched = array_intersect_assoc( $settings, $status );
377
378 if ( ! empty( $matched ) ) {
379 return true;
380 }
381
382 return $check;
383 }
384
385
386 /**
387 * Conditional logic for the URL check.
388 *
389 * @param bool $check Current visibility state.
390 * @param array $settings Visibility settings.
391 *
392 * @return bool
393 */
394 function context_check_url( $check, $settings ) {
395 static $path;
396
397 $settings = wp_parse_args(
398 $settings,
399 array(
400 'urls' => null,
401 )
402 );
403
404 $urls = trim( $settings['urls'] );
405
406 if ( empty( $urls ) ) {
407 return $check;
408 }
409
410 if ( ! isset( $path ) ) {
411 // Do the parsing only once.
412 $path = $this->get_request_path( $_SERVER['REQUEST_URI'] );
413 }
414
415 if ( $this->match_path( $path, $urls ) ) {
416 return true;
417 }
418
419 return $check;
420 }
421
422 /**
423 * Return the path relative to the root of the hostname. We always remove
424 * the leading and trailing slashes around the URI path.
425 *
426 * @param string $uri Current request URI.
427 *
428 * @return string
429 */
430 public function get_request_path( $uri ) {
431 $parts = wp_parse_args(
432 wp_parse_url( $uri ),
433 array(
434 'path' => '',
435 )
436 );
437
438 $path = trim( $parts['path'], '/' );
439
440 if ( ! empty( $parts['query'] ) ) {
441 $path .= '?' . $parts['query'];
442 }
443
444 return $path;
445 }
446
447 /**
448 * Check if the current request matches path rules.
449 *
450 * @param string $path Current request relative to the root of the hostname.
451 * @param string $rules A list of path patterns seperated by new line.
452 *
453 * @return bool
454 */
455 function match_path( $path, $rules ) {
456 $path_only = strtok( $path, '?' );
457 $patterns = explode( "\n", $rules );
458
459 foreach ( $patterns as &$pattern ) {
460 // Use the same logic for parsing the visibility rules.
461 $pattern = $this->get_request_path( trim( $pattern ) );
462 }
463
464 // Remove empty patterns.
465 $patterns = array_filter( $patterns );
466
467 // Match against the path with and without the query string.
468 if ( $this->path_matches_patterns( $path, $patterns ) || $this->path_matches_patterns( $path_only, $patterns ) ) {
469 return true;
470 }
471
472 return false;
473 }
474
475 /**
476 * Check if a URI path matches a set of regex patterns.
477 *
478 * @param string $path Request URI.
479 * @param array $patterns A list of patterns.
480 *
481 * @return bool
482 */
483 public function path_matches_patterns( $path, $patterns ) {
484 if ( empty( $patterns ) ) {
485 return false;
486 }
487
488 foreach ( $patterns as &$pattern ) {
489 // Escape regex chars since we only support wildcards.
490 $pattern = preg_quote( trim( $pattern ), '/' );
491
492 // Enable wildcard checks.
493 $pattern = str_replace( '\*', '.*', $pattern );
494 }
495
496 $regex = sprintf(
497 '/^(%s)$/i',
498 implode( '|', $patterns )
499 );
500
501 return (bool) preg_match( $regex, $path );
502 }
503
504
505 // Dummy function
506 function context_check_admin_notes( $check, $widget_id ) {}
507
508
509 // Dummy function
510 function context_check_general( $check, $widget_id ) {}
511
512
513 /*
514 Widget Controls
515 */
516
517 function display_widget_context( $widget_id = null ) {
518 $controls = array();
519 $controls_disabled = array();
520 $controls_core = array();
521
522 foreach ( $this->contexts as $context_name => $context_settings ) {
523
524 $context_classes = array(
525 'context-group',
526 sprintf( 'context-group-%s', esc_attr( $context_name ) ),
527 );
528
529 // Hide this context from the admin UX. We can't remove them
530 // because settings will get lost if this page is submitted.
531 if ( isset( $this->context_settings['contexts'][ $context_name ] ) && ! $this->context_settings['contexts'][ $context_name ] ) {
532 $context_classes[] = 'context-inactive';
533 $controls_disabled[] = $context_name;
534 }
535
536 // Store core controls
537 if ( isset( $context_settings['type'] ) && 'core' === $context_settings['type'] ) {
538 $controls_core[] = $context_name;
539 }
540
541 $control_args = array(
542 'name' => $context_name,
543 'input_prefix' => 'wl' . $this->get_field_name( array( $widget_id, $context_name ) ),
544 'settings' => $this->get_field_value( array( $widget_id, $context_name ) ),
545 'widget_id' => $widget_id,
546 );
547
548 $context_controls = apply_filters( 'widget_context_control-' . $context_name, $control_args );
549 $context_classes = apply_filters( 'widget_context_classes-' . $context_name, $context_classes, $control_args );
550
551 if ( ! empty( $context_controls ) && is_string( $context_controls ) ) {
552 $controls[ $context_name ] = sprintf(
553 '<div class="%s">
554 <h4 class="context-toggle">%s</h4>
555 <div class="context-group-wrap">
556 %s
557 </div>
558 </div>',
559 esc_attr( implode( ' ', $context_classes ) ),
560 esc_html( $context_settings['label'] ),
561 $context_controls
562 );
563 }
564 }
565
566 // Non-core controls that should be visible if enabled
567 $controls_not_core = array_diff( array_keys( $controls ), $controls_core );
568
569 // Check if any non-core context controls have been enabled
570 $has_controls = array_diff( $controls_not_core, $controls_disabled );
571
572 if ( empty( $controls ) || empty( $has_controls ) ) {
573
574 if ( current_user_can( 'edit_theme_options' ) ) {
575 $controls = array(
576 sprintf(
577 '<p class="error">%s</p>',
578 sprintf(
579 /* translators: %s is a URL to the settings page. */
580 __( 'No widget controls enabled. You can enable them in <a href="%s">Widget Context settings</a>.', 'widget-context' ),
581 admin_url( 'options-general.php?page=widget_context_settings' )
582 )
583 ),
584 );
585 } else {
586 $controls = array(
587 sprintf(
588 '<p class="error">%s</p>',
589 __( 'No widget controls enabled.', 'widget-context' )
590 ),
591 );
592 }
593 }
594
595 $settings_link = '';
596
597 if ( current_user_can( 'edit_theme_options' ) ) {
598 $settings_link = sprintf(
599 '<a href="%s" class="widget-context-settings-link" title="%s">%s</a>',
600 admin_url( 'options-general.php?page=widget_context_settings' ),
601 esc_attr__( 'Widget Context Settings', 'widget-context' ),
602 esc_html__( 'Settings', 'widget-context' )
603 );
604 }
605
606 return sprintf(
607 '<div class="widget-context">
608 <div class="widget-context-header">
609 <h3>%s</h3>
610 %s
611 </div>
612 <div class="widget-context-inside" id="widget-context-%s" data-widget-id="%s">
613 %s
614 </div>
615 </div>',
616 __( 'Widget Context', 'widget-context' ),
617 $settings_link,
618 // Inslide classes
619 esc_attr( $widget_id ),
620 esc_attr( $widget_id ),
621 // Controls
622 implode( '', $controls )
623 );
624
625 }
626
627
628 function control_incexc( $control_args ) {
629 $options = array(
630 'show' => __( 'Show widget everywhere', 'widget-context' ),
631 'selected' => __( 'Show widget on selected', 'widget-context' ),
632 'notselected' => __( 'Hide widget on selected', 'widget-context' ),
633 'hide' => __( 'Hide widget everywhere', 'widget-context' ),
634 );
635
636 return $this->make_simple_dropdown( $control_args, 'condition', $options );
637 }
638
639
640 function control_location( $control_args ) {
641 $options = array(
642 'is_front_page' => __( 'Front page', 'widget-context' ),
643 'is_home' => __( 'Blog page', 'widget-context' ),
644 'is_singular' => __( 'All posts, pages and custom post types', 'widget-context' ),
645 'is_single' => __( 'All posts', 'widget-context' ),
646 'is_page' => __( 'All pages', 'widget-context' ),
647 'is_attachment' => __( 'All attachments', 'widget-context' ),
648 'is_search' => __( 'Search results', 'widget-context' ),
649 'is_404' => __( '404 error page', 'widget-context' ),
650 'is_archive' => __( 'All archives', 'widget-context' ),
651 'is_date' => __( 'All date archives', 'widget-context' ),
652 'is_day' => __( 'Daily archives', 'widget-context' ),
653 'is_month' => __( 'Monthly archives', 'widget-context' ),
654 'is_year' => __( 'Yearly archives', 'widget-context' ),
655 'is_category' => __( 'All category archives', 'widget-context' ),
656 'is_tag' => __( 'All tag archives', 'widget-context' ),
657 'is_author' => __( 'All author archives', 'widget-context' ),
658 );
659
660 foreach ( $options as $option => $label ) {
661 $out[] = $this->make_simple_checkbox( $control_args, $option, $label );
662 }
663
664 return implode( '', $out );
665 }
666
667
668 function control_url( $control_args ) {
669 return sprintf(
670 '<div>%s</div>
671 <p class="help">%s</p>',
672 $this->make_simple_textarea( $control_args, 'urls' ),
673 __( 'Enter one location fragment per line. Use <strong>*</strong> character as a wildcard. Example: <code>category/peace/*</code> to target all posts in category <em>peace</em>.', 'widget-context' )
674 );
675 }
676
677
678 function control_admin_notes( $control_args ) {
679 return sprintf(
680 '<div>%s</div>',
681 $this->make_simple_textarea( $control_args, 'notes' )
682 );
683 }
684
685
686
687 /**
688 * Widget control helpers
689 */
690
691
692 function make_simple_checkbox( $control_args, $option, $label ) {
693 $value = false;
694
695 if ( isset( $control_args['settings'][ $option ] ) && $control_args['settings'][ $option ] ) {
696 $value = true;
697 }
698
699 return sprintf(
700 '<label class="wc-field-checkbox-%s" data-widget-id="%s">
701 <input type="hidden" value="0" name="%s[%s]" />
702 <input type="checkbox" value="1" name="%s[%s]" %s />&nbsp;%s
703 </label>',
704 $this->get_field_classname( $option ),
705 esc_attr( $control_args['widget_id'] ),
706 // Input hidden
707 $control_args['input_prefix'],
708 esc_attr( $option ),
709 // Input value
710 $control_args['input_prefix'],
711 esc_attr( $option ),
712 checked( $value, true, false ),
713 // Label
714 esc_html( $label )
715 );
716
717 }
718
719
720 function make_simple_textarea( $control_args, $option, $label = null ) {
721 $value = '';
722
723 if ( isset( $control_args['settings'][ $option ] ) ) {
724 $value = esc_textarea( $control_args['settings'][ $option ] );
725 }
726
727 return sprintf(
728 '<label class="wc-field-textarea-%s" data-widget-id="%s">
729 <strong>%s</strong>
730 <textarea name="%s[%s]">%s</textarea>
731 </label>',
732 $this->get_field_classname( $option ),
733 esc_attr( $control_args['widget_id'] ),
734 // Label
735 esc_html( $label ),
736 // Input
737 $control_args['input_prefix'],
738 $option,
739 $value
740 );
741 }
742
743
744 function make_simple_textfield( $control_args, $option, $label_before = null, $label_after = null ) {
745 $value = false;
746
747 if ( isset( $control_args['settings'][ $option ] ) ) {
748 $value = esc_attr( $control_args['settings'][ $option ] );
749 }
750
751 return sprintf(
752 '<label class="wc-field-text-%s" data-widget-id="%s">
753 %s
754 <input type="text" name="%s[%s]" value="%s" />
755 %s
756 </label>',
757 $this->get_field_classname( $option ),
758 esc_attr( $control_args['widget_id'] ),
759 // Before
760 $label_before,
761 // Input
762 $control_args['input_prefix'],
763 $option,
764 esc_attr( $value ),
765 // After
766 esc_html( $label_after )
767 );
768 }
769
770
771 function make_simple_dropdown( $control_args, $option, $selection = array(), $label_before = null, $label_after = null ) {
772 $options = array();
773 $value = false;
774
775 if ( isset( $control_args['settings'][ $option ] ) ) {
776 $value = $control_args['settings'][ $option ];
777 }
778
779 if ( empty( $selection ) ) {
780 $options[] = sprintf(
781 '<option value="">%s</option>',
782 esc_html__( 'No options available', 'widget-context' )
783 );
784 }
785
786 foreach ( $selection as $sid => $svalue ) {
787 $options[] = sprintf(
788 '<option value="%s" %s>%s</option>',
789 esc_attr( $sid ),
790 selected( $value, $sid, false ),
791 esc_html( $svalue )
792 );
793 }
794
795 return sprintf(
796 '<label class="wc-field-select-%s" data-widget-id="%s">
797 %s
798 <select name="%s[%s]">
799 %s
800 </select>
801 %s
802 </label>',
803 $this->get_field_classname( $option ),
804 esc_attr( $control_args['widget_id'] ),
805 // Before
806 $label_before,
807 // Input
808 $control_args['input_prefix'],
809 $option,
810 implode( '', $options ),
811 // After
812 $label_after
813 );
814 }
815
816
817 /**
818 * Returns [part1][part2][partN] from array( 'part1', 'part2', 'part3' )
819 *
820 * @param array $parts i.e. array( 'part1', 'part2', 'part3' )
821 * @return string i.e. [part1][part2][partN]
822 */
823 function get_field_name( $parts ) {
824 return esc_attr( sprintf( '[%s]', implode( '][', $parts ) ) );
825 }
826
827 function get_field_classname( $name ) {
828 if ( is_array( $name ) ) {
829 $name = end( $name );
830 }
831
832 return sanitize_html_class( str_replace( '_', '-', $name ) );
833 }
834
835
836 /**
837 * Given option keys return its value
838 *
839 * @param array $parts i.e. array( 'part1', 'part2', 'part3' )
840 * @param array $options i.e. array( 'part1' => array( 'part2' => array( 'part3' => 'VALUE' ) ) )
841 * @return string Returns option value
842 */
843 function get_field_value( $parts, $options = null ) {
844 if ( null === $options ) {
845 $options = $this->context_options;
846 }
847
848 $value = false;
849
850 if ( empty( $parts ) || ! is_array( $parts ) ) {
851 return false;
852 }
853
854 $part = array_shift( $parts );
855
856 if ( ! empty( $parts ) && isset( $options[ $part ] ) && is_array( $options[ $part ] ) ) {
857 $value = $this->get_field_value( $parts, $options[ $part ] );
858 } elseif ( isset( $options[ $part ] ) ) {
859 return $options[ $part ];
860 }
861
862 return $value;
863 }
864
865
866 function fix_legacy_options( $options ) {
867 if ( empty( $options ) || ! is_array( $options ) ) {
868 return $options;
869 }
870
871 foreach ( $options as $widget_id => $option ) {
872 // This doesn't have an include/exclude rule defined
873 if ( ! isset( $option['incexc'] ) ) {
874 unset( $options[ $widget_id ] );
875 }
876
877 // We moved from [incexc] = 1/0 to [incexc][condition] = 1/0
878 if ( isset( $option['incexc'] ) && ! is_array( $option['incexc'] ) ) {
879 $options[ $widget_id ]['incexc'] = array( 'condition' => $option['incexc'] );
880 }
881
882 // Move notes from "general" group to "admin_notes"
883 if ( isset( $option['general']['notes'] ) ) {
884 $options[ $widget_id ]['admin_notes']['notes'] = $option['general']['notes'];
885 unset( $option['general']['notes'] );
886 }
887
888 // We moved word count out of location context group
889 if ( isset( $option['location']['check_wordcount'] ) ) {
890 $options[ $widget_id ]['word_count'] = array(
891 'check_wordcount' => true,
892 'check_wordcount_type' => $option['location']['check_wordcount_type'],
893 'word_count' => $option['location']['word_count'],
894 );
895 }
896 }
897
898 return $options;
899 }
900
901
902
903 /**
904 * Admin Settings
905 */
906
907
908 function widget_context_settings_menu() {
909 add_options_page(
910 __( 'Widget Context Settings', 'widget-context' ),
911 __( 'Widget Context', 'widget-context' ),
912 'manage_options',
913 $this->settings_name,
914 array( $this, 'widget_context_admin_view' )
915 );
916 }
917
918
919 function widget_context_settings_init() {
920 register_setting( $this->settings_name, $this->settings_name );
921 }
922
923
924 function widget_context_admin_view() {
925 $context_controls = array();
926
927 foreach ( $this->get_contexts() as $context_id => $context_args ) {
928 // Hide core modules from being disabled
929 if ( isset( $context_args['type'] ) && 'core' === $context_args['type'] ) {
930 continue;
931 }
932
933 if ( ! empty( $context_args['description'] ) ) {
934 $context_description = sprintf(
935 '<p class="context-desc">%s</p>',
936 esc_html( $context_args['description'] )
937 );
938 } else {
939 $context_description = null;
940 }
941
942 // Enable new modules by default
943 if ( ! isset( $this->context_settings['contexts'][ $context_id ] ) ) {
944 $this->context_settings['contexts'][ $context_id ] = 1;
945 }
946
947 $context_controls[] = sprintf(
948 '<li class="context-%s">
949 <label>
950 <input type="hidden" name="%s[contexts][%s]" value="0" />
951 <input type="checkbox" name="%s[contexts][%s]" value="1" %s /> %s
952 </label>
953 %s
954 </li>',
955 esc_attr( $context_id ),
956 $this->settings_name,
957 esc_attr( $context_id ),
958 $this->settings_name,
959 esc_attr( $context_id ),
960 checked( $this->context_settings['contexts'][ $context_id ], 1, false ),
961 esc_html( $context_args['label'] ),
962 $context_description
963 );
964 }
965
966 ?>
967 <div class="wrap wrap-widget-context">
968 <h2><?php esc_html_e( 'Widget Context Settings', 'widget-context' ); ?></h2>
969
970 <div class="widget-context-settings-wrap">
971
972 <div class="widget-context-form">
973 <form method="post" action="options.php">
974 <?php
975 settings_fields( $this->settings_name );
976 do_settings_sections( $this->settings_name );
977 ?>
978
979 <?php
980 printf(
981 '<div class="settings-section settings-section-modules">
982 <h3>%s</h3>
983 <ul>%s</ul>
984 </div>',
985 esc_html__( 'Enabled Context Modules', 'widget-context' ),
986 implode( '', $context_controls )
987 );
988 ?>
989
990 <?php
991 submit_button();
992 ?>
993 </form>
994 </div>
995
996 <div class="widget-context-sidebar">
997 <div class="wc-sidebar-in">
998
999 <div class="wc-sidebar-section wc-sidebar-credits">
1000 <p>
1001 <img src="https://gravatar.com/avatar/661eb21385c25c01ad64ab9e13b37331?s=120" alt="Kaspars Dambis" width="60" height="60" />
1002 <?php
1003 printf(
1004 // translators: %s: link with an anchor text.
1005 esc_html__( 'Widget Context is created and maintained by %s.', 'widget-context' ),
1006 '<a href="https://widgetcontext.com/about">Kaspars Dambis</a>'
1007 );
1008 ?>
1009 </p>
1010 </div>
1011
1012 <div class="wc-sidebar-section wc-sidebar-newsletter">
1013 <h3><?php esc_html_e( 'News & Updates', 'widget-context' ); ?></h3>
1014 <p><?php esc_html_e( 'Subscribe to receive news and updates about the plugin.', 'widget-context' ); ?></p>
1015 <form action="//osc.us2.list-manage.com/subscribe/post?u=e8d173fc54c0fc4286a2b52e8&amp;id=8afe96c5a3" method="post" target="_blank">
1016 <?php $user = wp_get_current_user(); ?>
1017 <p><label><?php _e( 'Your Name', 'widget-context' ); ?>: <input type="text" name="NAME" value="<?php echo esc_attr( sprintf( '%s %s', $user->first_name, $user->last_name ) ); ?>" /></label></p>
1018 <p><label><?php _e( 'Your Email', 'widget-context' ); ?>: <input type="text" name="EMAIL" value="<?php echo esc_attr( $user->user_email ); ?>" /></label></p>
1019 <p><input class="button" name="subscribe" type="submit" value="<?php esc_attr_e( 'Subscribe', 'widget-context' ); ?>" /></p>
1020 </form>
1021 <h3>
1022 <?php esc_html_e( 'Suggested Plugins', 'widget-context' ); ?>
1023 </h3>
1024 <p>
1025 <?php esc_html_e( 'Here are some of my other plugins:', 'widget-context' ); ?>
1026 </p>
1027 <ul>
1028 <li>
1029 <strong><small>NEW:</small></strong>
1030 <a href="https://blockcontext.com?utm_source=wc">Block Context</a> for showing or hiding Gutenberg blocks in context.
1031 </li>
1032 <li>
1033 <a href="https://preseto.com/go/cf7-storage?utm_source=wc">Storage for Contact Form 7</a> saves all Contact Form 7 submissions (including attachments) in your WordPress database.
1034 </li>
1035 <li>
1036 <a href="https://formcontrols.com/?utm_source=wc">Contact Form 7 Controls</a> adds a simple interface for managing Contact Form 7 form settings.
1037 </li>
1038 </ul>
1039 </div>
1040
1041 </div>
1042 </div>
1043
1044 </div>
1045 </div>
1046 <?php
1047
1048 }
1049
1050
1051 public function get_sidebars_widgets_copy() {
1052 return $this->sidebars_widgets_copy;
1053 }
1054
1055 }
1056