PluginProbe ʕ •ᴥ•ʔ
Custom Sidebars – Dynamic Sidebar Classic Widget Area Manager / 3.0.7.1
Custom Sidebars – Dynamic Sidebar Classic Widget Area Manager v3.0.7.1
trunk 2.1.2.0 3.0.0.0 3.0.0.1 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.7.1 3.0.8 3.0.8.1 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.3 3.31 3.32 3.35 3.36 3.37 3.38
custom-sidebars / inc / class-custom-sidebars.php
custom-sidebars / inc Last commit date
external 9 years ago class-custom-sidebars-checkup-notification.php 9 years ago class-custom-sidebars-cloning.php 9 years ago class-custom-sidebars-editor.php 9 years ago class-custom-sidebars-explain.php 9 years ago class-custom-sidebars-export.php 9 years ago class-custom-sidebars-replacer.php 9 years ago class-custom-sidebars-visibility.php 9 years ago class-custom-sidebars-widgets.php 9 years ago class-custom-sidebars.php 9 years ago
class-custom-sidebars.php
976 lines
1 <?php
2
3 // Load additional Pro-modules.
4 require_once CSB_INC_DIR . 'class-custom-sidebars-widgets.php';
5 require_once CSB_INC_DIR . 'class-custom-sidebars-editor.php';
6 require_once CSB_INC_DIR . 'class-custom-sidebars-replacer.php';
7 require_once CSB_INC_DIR . 'class-custom-sidebars-cloning.php';
8 require_once CSB_INC_DIR . 'class-custom-sidebars-visibility.php';
9 require_once CSB_INC_DIR . 'class-custom-sidebars-export.php';
10 require_once CSB_INC_DIR . 'class-custom-sidebars-explain.php';
11
12 require_once CSB_INC_DIR . 'class-custom-sidebars-checkup-notification.php';
13
14
15 /**
16 * Main plugin file.
17 * The CustomSidebars class encapsulates all our plugin logic.
18 */
19 class CustomSidebars {
20 /**
21 * Prefix used for the sidebar-ID of custom sidebars. This is also used to
22 * distinguish theme sidebars from custom sidebars.
23 * @var string
24 */
25 static protected $sidebar_prefix = 'cs-';
26
27 /**
28 * Capability required to use *any* of the plugin features. If user does not
29 * have this capability then he will not see any change on admin dashboard.
30 * @var string
31 */
32 static protected $cap_required = 'edit_theme_options';
33
34 /**
35 * URL to the documentation/info page of the pro plugin
36 * @var string
37 */
38 static public $pro_url = 'https://premium.wpmudev.org/project/custom-sidebars-pro/';
39
40 /**
41 * Flag that specifies if the page is loaded in accessibility mode.
42 * This plugin does not support accessibility mode!
43 * @var bool
44 * @since 2.0.9
45 */
46 static protected $accessibility_mode = false;
47
48 /**
49 * Returns the singleton instance of the custom sidebars class.
50 *
51 * @since 2.0
52 */
53 static public function instance() {
54 static $Inst = null;
55
56 // We can initialize the plugin once we know the current user:
57 // The lib3()->html->pointer() notification is based on current user...
58 if ( ! did_action( 'set_current_user' ) ) {
59 add_action( 'set_current_user', array( __CLASS__, 'instance' ) );
60 return null;
61 }
62
63 if ( null === $Inst ) {
64 $Inst = new CustomSidebars();
65 }
66
67 return $Inst;
68 }
69
70 /**
71 * Private, since it is a singleton.
72 * We directly initialize sidebar options when class is created.
73 */
74 private function __construct() {
75 add_action( 'admin_init', array( $this, 'admin_init' ) );
76 // Extensions use this hook to initialize themselfs.
77 do_action( 'cs_init' );
78 }
79
80 /**
81 * Admin init
82 *
83 * @since 3.0.5
84 */
85 public function admin_init() {
86
87 $plugin_title = 'Custom Sidebars';
88
89 /**
90 * ID of the WP-Pointer used to introduce the plugin upon activation
91 *
92 * ========== Pointer ==========
93 * Internal ID: wpmudcs1 [WPMUDev CustomSidebars 1]
94 * Point at: #menu-appearance (Appearance menu item)
95 * Title: Custom Sidebars
96 * Description: Create and edit custom sidebars in your widget screen!
97 * -------------------------------------------------------------------------
98 */
99
100 $user_id = get_current_user_id();
101 $dismissed_wp_pointers = get_user_meta( $user_id, 'dismissed_wp_pointers', true );
102 $dismissed_wp_pointers = explode( ',', $dismissed_wp_pointers );
103
104 if ( in_array( 'wpmudcs1', $dismissed_wp_pointers ) || wp_is_mobile() ) {
105 lib3()->ui->add( 'core', 'widgets.php' );
106 } else {
107 lib3()->ui->add( 'core' );
108 lib3()->html->pointer(
109 'wpmudcs1', // Internal Pointer-ID
110 '#menu-appearance', // Point at
111 $plugin_title,
112 sprintf(
113 __(
114 'Now you can create and edit custom sidebars in your ' .
115 '<a href="%1$s">Widgets screen</a>!', 'custom-sidebars'
116 ),
117 admin_url( 'widgets.php' )
118 ) // Body
119 );
120 }
121
122 // Find out if the page is loaded in accessibility mode.
123 $flag = isset( $_GET['widgets-access'] ) ? $_GET['widgets-access'] : get_user_setting( 'widgets_access' );
124 self::$accessibility_mode = ( 'on' == $flag );
125
126 // We don't support accessibility mode. Display a note to the user.
127 if ( true === self::$accessibility_mode ) {
128 $nonce = wp_create_nonce( 'widgets-access' );
129 lib3()->ui->admin_message(
130 sprintf(
131 __(
132 '<strong>Accessibility mode is not supported by the
133 %1$s plugin.</strong><br /><a href="%2$s">Click here</a>
134 to disable accessibility mode and use the %1$s plugin!',
135 'custom-sidebars'
136 ),
137 $plugin_title,
138 admin_url( 'widgets.php?widgets-access=off&_wpnonce='.urlencode( $nonce ) )
139 ),
140 'err',
141 'widgets'
142 );
143 } else {
144 // Load javascripts/css files
145 lib3()->ui->add( 'select', 'widgets.php' );
146 lib3()->ui->add( CSB_JS_URL . 'cs.min.js', 'widgets.php' );
147 lib3()->ui->add( CSB_CSS_URL . 'cs.css', 'widgets.php' );
148 lib3()->ui->add( CSB_CSS_URL . 'cs.css', 'edit.php' );
149
150 // AJAX actions
151 add_action( 'wp_ajax_cs-ajax', array( $this, 'ajax_handler' ) );
152
153 // Display a message after import.
154 if ( ! empty( $_GET['cs-msg'] ) ) {
155 $msg = base64_decode( $_GET['cs-msg'] );
156
157 // Prevent XSS attacks...
158 $kses_args = array(
159 'br' => array(),
160 'b' => array(),
161 'strong' => array(),
162 'i' => array(),
163 'em' => array(),
164 );
165 $msg = wp_kses( $msg, $kses_args );
166
167 if ( ! empty( $msg ) ) {
168 lib3()->ui->admin_message( $msg );
169 }
170 }
171 }
172
173 /**
174 * add links on plugin page.
175 */
176 add_filter( 'plugin_action_links_' . plugin_basename( CSB_PLUGIN ), array( $this, 'add_action_links' ), 10, 4 );
177
178 add_action( 'admin_footer', array( $this, 'print_templates' ) );
179 }
180
181
182 // =========================================================================
183 // == DATA ACCESS
184 // =========================================================================
185
186
187 /**
188 *
189 * ==1== PLUGIN OPTIONS
190 * Option-Key: cs_modifiable
191 *
192 * {
193 * // Sidebars that can be replaced:
194 * 'modifiable': [
195 * 'sidebar_1',
196 * 'sidebar_2'
197 * ],
198 *
199 * // Default replacements:
200 * 'post_type_single': [ // Former "defaults"
201 * 'post_type1': <replacement-def>,
202 * 'post_type2': <replacement-def>
203 * ],
204 * 'post_type_archive': [ // Former "post_type_pages"
205 * 'post_type1': <replacement-def>,
206 * 'post_type2': <replacement-def>
207 * ],
208 * 'category_single': [ // Former "category_posts"
209 * 'category_id1': <replacement-def>,
210 * 'category_id2': <replacement-def>
211 * ],
212 * 'category_archive': [ // Former "category_pages"
213 * 'category_id1': <replacement-def>,
214 * 'category_id2': <replacement-def>
215 * ],
216 * 'blog': <replacement-def>,
217 * 'tags': <replacement-def>,
218 * 'authors': <replacement-def>,
219 * 'search': <replacement-def>,
220 * 'date': <replacement-def>
221 * }
222 *
223 * ==2== REPLACEMENT-DEF
224 * Meta-Key: _cs_replacements
225 * Option-Key: cs_modifiable <replacement-def>
226 *
227 * {
228 * 'sidebar_1': 'custom_sb_id1',
229 * 'sidebar_2': 'custom_sb_id2'
230 * }
231 *
232 * ==3== SIDEBAR DEFINITION
233 * Option-Key: cs_sidebars
234 *
235 * Array of these objects
236 * {
237 * id: '', // sidebar-id
238 * name: '',
239 * description: '',
240 * before_title: '',
241 * after_title: '',
242 * before_widget: '',
243 * after_widget: ''
244 * }
245 *
246 * ==4== WIDGET LIST
247 * Option-Key: sidebars_widgets
248 *
249 * {
250 * 'sidebar_id': [
251 * 'widget_id1',
252 * 'widget_id2'
253 * ],
254 * 'sidebar_2': [
255 * ],
256 * 'sidebar_3': [
257 * 'widget_id1',
258 * 'widget_id3'
259 * ],
260 * }
261 */
262
263
264 /**
265 * If the specified variable is an array it will be returned. Otherwise
266 * an empty array is returned.
267 *
268 * @since 2.0
269 * @param mixed $val1 Value that maybe is an array.
270 * @param mixed $val2 Optional, Second value that maybe is an array.
271 * @return array
272 */
273 static public function get_array( $val1, $val2 = array() ) {
274 if ( is_array( $val1 ) ) {
275 return $val1;
276 } elseif ( is_array( $val2 ) ) {
277 return $val2;
278 } else {
279 return array();
280 }
281 }
282
283 /**
284 * Returns a list with sidebars that were marked as "modifiable".
285 * Also contains information on the default replacements of these sidebars.
286 *
287 * Option-Key: 'cs_modifiable' (1)
288 */
289 static public function get_options( $key = null ) {
290 static $Options = null;
291 $need_update = false;
292
293 if ( null === $Options ) {
294 $Options = get_option( 'cs_modifiable', array() );
295 if ( ! is_array( $Options ) ) {
296 $Options = array();
297 }
298
299 // List of modifiable sidebars.
300 if ( ! isset( $Options['modifiable'] ) || ! is_array( $Options['modifiable'] ) ) {
301 // By default we make ALL theme sidebars replaceable:
302 $all = self::get_sidebars( 'theme' );
303 $Options['modifiable'] = array_keys( $all );
304 $need_update = true;
305 }
306
307 /**
308 * In version 2.0 four config values have been renamed and are
309 * migrated in the following block:
310 */
311
312 /**
313 * set defaults
314 */
315 $keys = array(
316 'authors',
317 'blog',
318 'category_archive',
319 'category_pages',
320 'category_posts',
321 'category_single',
322 'date',
323 'defaults',
324 'post_type_archive',
325 'post_type_pages',
326 'post_type_single',
327 'search',
328 'tags',
329 );
330
331 foreach ( $keys as $k ) {
332 if ( isset( $Options[ $k ] ) ) {
333 continue;
334 }
335 $Options[ $k ] = null;
336 }
337
338 // Single/Archive pages - new names
339 $Options['post_type_single'] = self::get_array(
340 $Options['post_type_single'], // new name
341 $Options['defaults'] // old name
342 );
343 $Options['post_type_archive'] = self::get_array(
344 $Options['post_type_archive'], // new name
345 $Options['post_type_pages'] // old name
346 );
347 $Options['category_single'] = self::get_array(
348 $Options['category_single'], // new name
349 $Options['category_posts'] // old name
350 );
351 $Options['category_archive'] = self::get_array(
352 $Options['category_archive'], // new name
353 $Options['category_pages'] // old name
354 );
355
356 // Remove old item names from the array.
357 if ( isset( $Options['defaults'] ) ) {
358 unset( $Options['defaults'] );
359 $need_update = true;
360 }
361 if ( isset( $Options['post_type_pages'] ) ) {
362 unset( $Options['post_type_pages'] );
363 $need_update = true;
364 }
365 if ( isset( $Options['category_posts'] ) ) {
366 unset( $Options['category_posts'] );
367 $need_update = true;
368 }
369 if ( isset( $Options['category_pages'] ) ) {
370 unset( $Options['category_pages'] );
371 $need_update = true;
372 }
373
374 // Special archive pages
375 $keys = array( 'blog', 'tags', 'authors', 'search', 'date' );
376 foreach ( $keys as $temporary_key ) {
377 if ( isset( $Options[ $temporary_key ] ) ) {
378 $Options[ $temporary_key ] = self::get_array( $Options[ $temporary_key ] );
379 } else {
380 $Options[ $temporary_key ] = array();
381 }
382 }
383
384 $Options = self::validate_options( $Options );
385 if ( $need_update ) {
386 self::set_options( $Options );
387 }
388 }
389 if ( ! empty( $key ) ) {
390 return isset( $Options[ $key ] )? $Options[ $key ] : null;
391 } else {
392 return $Options;
393 }
394 }
395
396 /**
397 * Saves the sidebar options to DB.
398 *
399 * Option-Key: 'cs_modifiable' (1)
400 * @since 2.0
401 * @param array $value The options array.
402 */
403 static public function set_options( $value ) {
404 // Permission check.
405 if ( ! current_user_can( self::$cap_required ) ) {
406 return;
407 }
408
409 update_option( 'cs_modifiable', $value );
410 }
411
412 /**
413 * Removes invalid settings from the options array.
414 *
415 * @since 1.0.4
416 * @param array $data This array will be validated and returned.
417 * @return array
418 */
419 static public function validate_options( $data = null ) {
420 $data = (is_object( $data ) ? (array) $data : $data );
421 if ( ! is_array( $data ) ) {
422 return array();
423 }
424 $valid = array_keys( self::get_sidebars( 'theme' ) );
425 $current = array();
426 if ( isset( $data['modifiable'] ) ) {
427 $current = self::get_array( $data['modifiable'] );
428 }
429 // Get all the sidebars that are modifiable AND exist.
430 $modifiable = array_intersect( $valid, $current );
431 $data['modifiable'] = $modifiable;
432 return $data;
433 }
434
435 /**
436 * Returns a list with all custom sidebars that were created by the user.
437 * Array of custom sidebars
438 *
439 * Option-Key: 'cs_sidebars' (3)
440 */
441 static public function get_custom_sidebars() {
442 $sidebars = get_option( 'cs_sidebars', array() );
443 if ( ! is_array( $sidebars ) ) {
444 $sidebars = array();
445 }
446
447 // Remove invalid items.
448 foreach ( $sidebars as $key => $data ) {
449 if ( ! is_array( $data ) ) {
450 unset( $sidebars[ $key ] );
451 }
452 }
453
454 return $sidebars;
455 }
456
457 /**
458 * Saves the custom sidebars to DB.
459 *
460 * Option-Key: 'cs_sidebars' (3)
461 * @since 2.0
462 */
463 static public function set_custom_sidebars( $value ) {
464 // Permission check.
465 if ( ! current_user_can( self::$cap_required ) ) {
466 return;
467 }
468
469 update_option( 'cs_sidebars', $value );
470 }
471
472 /**
473 * Returns a list of all registered sidebars including a list of their
474 * widgets (this is stored inside a WordPress core option).
475 *
476 * Option-Key: 'sidebars_widgets' (4)
477 * @since 2.0
478 */
479 static public function get_sidebar_widgets() {
480 return get_option( 'sidebars_widgets', array() );
481 }
482
483 /**
484 * Update the WordPress core settings for sidebar widgets:
485 * 1. Add empty widget information for new sidebars.
486 * 2. Remove widget information for sidebars that no longer exist.
487 *
488 * Option-Key: 'sidebars_widgets' (4)
489 */
490 static public function refresh_sidebar_widgets() {
491 // Contains an array of all sidebars and widgets inside each sidebar.
492 $widgetized_sidebars = self::get_sidebar_widgets();
493
494 $cs_sidebars = self::get_custom_sidebars();
495 $delete_widgetized_sidebars = array();
496
497 foreach ( $widgetized_sidebars as $id => $bar ) {
498 if ( substr( $id, 0, 3 ) == self::$sidebar_prefix ) {
499 $found = false;
500 foreach ( $cs_sidebars as $csbar ) {
501 if ( $csbar['id'] == $id ) {
502 $found = true;
503 }
504 }
505 if ( ! $found ) {
506 $delete_widgetized_sidebars[] = $id;
507 }
508 }
509 }
510
511 $all_ids = array_keys( $widgetized_sidebars );
512 foreach ( $cs_sidebars as $cs ) {
513 $sb_id = $cs['id'];
514 if ( ! in_array( $sb_id, $all_ids ) ) {
515 $widgetized_sidebars[ $sb_id ] = array();
516 }
517 }
518
519 foreach ( $delete_widgetized_sidebars as $id ) {
520 unset( $widgetized_sidebars[ $id ] );
521 }
522
523 update_option( 'sidebars_widgets', $widgetized_sidebars );
524 }
525
526 /**
527 * Returns the custom sidebar metadata of a single post.
528 *
529 * Meta-Key: '_cs_replacements' (2)
530 * @since 2.0
531 */
532 static public function get_post_meta( $post_id ) {
533 $data = get_post_meta( $post_id, '_cs_replacements', true );
534 if ( ! is_array( $data ) ) {
535 $data = array();
536 }
537 return $data;
538 }
539
540 /**
541 * Saves custom sidebar metadata to a single post.
542 *
543 * Meta-Key: '_cs_replacements' (2)
544 * @since 2.0
545 * @param int $post_id
546 * @param array $data When array is empty the meta data will be deleted.
547 */
548 static public function set_post_meta( $post_id, $data ) {
549 if ( ! empty( $data ) ) {
550 update_post_meta( $post_id, '_cs_replacements', $data );
551 } else {
552 delete_post_meta( $post_id, '_cs_replacements' );
553 }
554 }
555
556 /**
557 * Returns a list of all sidebars available.
558 * Depending on the parameter this will be either all sidebars or only
559 * sidebars defined by the current theme.
560 *
561 * @param string $type [all|cust|theme] What kind of sidebars to return.
562 */
563 static public function get_sidebars( $type = 'theme' ) {
564 global $wp_registered_sidebars;
565 $allsidebars = CustomSidebars::sort_sidebars_by_name( $wp_registered_sidebars );
566 $result = array();
567
568 // Remove inactive sidebars.
569 foreach ( $allsidebars as $sb_id => $sidebar ) {
570 if ( false !== strpos( $sidebar['class'], 'inactive-sidebar' ) ) {
571 unset( $allsidebars[ $sb_id ] );
572 }
573 }
574
575 ksort( $allsidebars );
576 if ( 'all' == $type ) {
577 $result = $allsidebars;
578 } elseif ( 'cust' == $type ) {
579 foreach ( $allsidebars as $key => $sb ) {
580 // Only keep custom sidebars in the results.
581 if ( substr( $key, 0, 3 ) == self::$sidebar_prefix ) {
582 $result[ $key ] = $sb;
583 }
584 }
585 } elseif ( 'theme' == $type ) {
586 foreach ( $allsidebars as $key => $sb ) {
587 // Remove custom sidebars from results.
588 if ( substr( $key, 0, 3 ) != self::$sidebar_prefix ) {
589 $result[ $key ] = $sb;
590 }
591 }
592 }
593
594 return $result;
595 }
596
597 /**
598 * Returns the sidebar with the specified ID.
599 * Sidebar can be both a custom sidebar or theme sidebar.
600 *
601 * @param string $id Sidebar-ID.
602 * @param string $type [all|cust|theme] What kind of sidebars to check.
603 */
604 static public function get_sidebar( $id, $type = 'all' ) {
605 if ( empty( $id ) ) { return false; }
606
607 // Get all sidebars
608 $sidebars = self::get_sidebars( $type );
609
610 if ( isset( $sidebars[ $id ] ) ) {
611 return $sidebars[ $id ];
612 } else {
613 return false;
614 }
615 }
616
617 /**
618 * Get sidebar replacement information for a single post.
619 */
620 static public function get_replacements( $postid ) {
621 $replacements = self::get_post_meta( $postid );
622 if ( ! is_array( $replacements ) ) {
623 $replacements = array();
624 } else {
625 $replacements = $replacements;
626 }
627 return $replacements;
628 }
629
630 /**
631 * Returns true, when the specified post type supports custom sidebars.
632 *
633 * @since 2.0
634 * @param object|string $posttype The posttype to validate. Either the
635 * posttype name or the full posttype object.
636 * @return bool
637 */
638 static public function supported_post_type( $posttype ) {
639 $Ignored_types = null;
640 $Response = array();
641
642 if ( null === $Ignored_types ) {
643 $Ignored_types = get_post_types(
644 array( 'public' => false ),
645 'names'
646 );
647 $Ignored_types[] = 'attachment';
648 }
649
650 if ( is_object( $posttype ) ) {
651 $posttype = $posttype->name;
652 }
653
654 if ( ! isset( $Response[ $posttype ] ) ) {
655 $response = ! in_array( $posttype, $Ignored_types );
656
657 /**
658 * Filters the support-flag. The flag defines if the posttype supports
659 * custom sidebars or not.
660 *
661 * @since 2.0
662 *
663 * @param bool $response Flag if the posttype is supported.
664 * @param string $posttype Name of the posttype that is checked.
665 */
666 $response = apply_filters( 'cs_support_posttype', $response, $posttype );
667 $Response[ $posttype ] = $response;
668 }
669
670 return $Response[ $posttype ];
671 }
672
673 /**
674 * Returns a list of all post types that support custom sidebars.
675 *
676 * @uses self::supported_post_type()
677 * @param string $type [names|objects] Defines details of return data.
678 * @return array List of posttype names or objects, depending on the param.
679 */
680 static public function get_post_types( $type = 'names' ) {
681 $Valid = array();
682
683 if ( 'objects' != $type ) {
684 $type = 'names';
685 }
686
687 if ( ! isset( $Valid[ $type ] ) ) {
688 $all = get_post_types( array(), $type );
689 $Valid[ $type ] = array();
690
691 foreach ( $all as $post_type ) {
692 if ( self::supported_post_type( $post_type ) ) {
693 $Valid[ $type ][] = $post_type;
694 }
695 }
696 }
697
698 return $Valid[ $type ];
699 }
700
701 /**
702 * Returns a list of all taxonomies that support custom sidebars.
703 *
704 * @since 3.0.7
705 *
706 * @uses self::supported_post_type()
707 * @param string $type [names|objects] Defines details of return data.
708 * @return array List of posttype names or objects, depending on the param.
709 */
710 static public function get_taxonomies( $type = 'names', $_builtin = true ) {
711 $Valid = array();
712 if ( 'objects' != $type ) {
713 $type = 'names';
714 }
715 if ( ! isset( $Valid[ $type ] ) ) {
716 $all = get_taxonomies( array( 'public' => true, '_builtin' => $_builtin ), $type );
717 $Valid[ $type ] = array();
718 foreach ( $all as $one ) {
719 $Valid[ $type ][] = $one;
720 }
721 }
722 return $Valid[ $type ];
723 }
724
725 /**
726 * Returns an array of all categories.
727 *
728 * @since 2.0
729 * @return array List of categories, including empty ones.
730 */
731 static public function get_all_categories() {
732 $args = array(
733 'hide_empty' => 0,
734 'taxonomy' => 'category',
735 );
736
737 return get_categories( $args );
738 }
739
740 /**
741 * Returns a sorted list of all category terms of the current post.
742 * This information is used to find sidebar replacements.
743 *
744 * @uses self::cmp_cat_level()
745 */
746 static public function get_sorted_categories( $post_id = null ) {
747 static $Sorted = array();
748
749 // Return categories of current post when no post_id is specified.
750 $post_id = empty( $post_id ) ? get_the_ID() : $post_id;
751
752 if ( ! isset( $Sorted[ $post_id ] ) ) {
753 $Sorted[ $post_id ] = get_the_category( $post_id );
754 usort( $Sorted[ $post_id ], array( __CLASS__, 'cmp_cat_level' ) );
755 }
756 return $Sorted[ $post_id ];
757 }
758
759 /**
760 * Helper function used to sort categories.
761 *
762 * @uses self::get_category_level()
763 */
764 static public function cmp_cat_level( $cat1, $cat2 ) {
765 $l1 = self::get_category_level( $cat1->cat_ID );
766 $l2 = self::get_category_level( $cat2->cat_ID );
767 if ( $l1 == $l2 ) {
768 return strcasecmp( $cat1->name, $cat1->name );
769 } else {
770 return $l1 < $l2 ? 1 : -1;
771 }
772 }
773
774 /**
775 * Helper function used to sort categories.
776 */
777 static public function get_category_level( $catid ) {
778 if ( ! $catid ) {
779 return 0;
780 }
781
782 $cat = get_category( $catid );
783 return 1 + self::get_category_level( $cat->category_parent );
784 }
785
786 // =========================================================================
787 // == AJAX FUNCTIONS
788 // =========================================================================
789
790 /**
791 * Output JSON data and die()
792 *
793 * @since 1.0.0
794 */
795 static protected function json_response( $obj ) {
796 // Flush any output that was made prior to this function call
797 while ( 0 < ob_get_level() ) { ob_end_clean(); }
798
799 header( 'Content-Type: application/json' );
800 echo json_encode( (object) $obj );
801 die();
802 }
803
804 /**
805 * Output HTML data and die()
806 *
807 * @since 2.0
808 */
809 static protected function plain_response( $data ) {
810 // Flush any output that was made prior to this function call
811 while ( 0 < ob_get_level() ) { ob_end_clean(); }
812
813 header( 'Content-Type: text/plain' );
814 echo '' . $data;
815 die();
816 }
817
818 /**
819 * Sets the response object to ERR state with the specified message/reason.
820 *
821 * @since 2.0
822 * @param object $req Initial response object.
823 * @param string $message Error message or reason; already translated.
824 * @return object Updated response object.
825 */
826 static protected function req_err( $req, $message ) {
827 $req->status = 'ERR';
828 $req->message = $message;
829 return $req;
830 }
831
832 /**
833 * All Ajax request are handled by this function.
834 * It analyzes the post-data and calls the required functions to execute
835 * the requested action.
836 *
837 * --------------------------------
838 *
839 * IMPORTANT! ANY SERVER RESPONSE MUST BE MADE VIA ONE OF THESE FUNCTIONS!
840 * Using direct `echo` or include an html file will not work.
841 *
842 * self::json_response( $obj )
843 * self::plain_response( $text )
844 *
845 * --------------------------------
846 *
847 * @since 1.0.0
848 */
849 public function ajax_handler() {
850 // Permission check.
851 if ( ! current_user_can( self::$cap_required ) ) {
852 return;
853 }
854
855 // Try to disable debug output for ajax handlers of this plugin.
856 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
857 defined( 'WP_DEBUG_DISPLAY' ) || define( 'WP_DEBUG_DISPLAY', false );
858 defined( 'WP_DEBUG_LOG' ) || define( 'WP_DEBUG_LOG', true );
859 }
860 // Catch any unexpected output via output buffering.
861 ob_start();
862
863 $action = isset( $_POST['do'] )? $_POST['do']:null;
864 $get_action = isset( $_GET['do'] )? $_GET['do']:null;
865
866 /**
867 * Notify all extensions about the ajax call.
868 *
869 * @since 2.0
870 * @param string $action The specified ajax action.
871 */
872 do_action( 'cs_ajax_request', $action );
873
874 /**
875 * Notify all extensions about the GET ajax call.
876 *
877 * @since 2.0.9.7
878 * @param string $action The specified ajax action.
879 */
880 do_action( 'cs_ajax_request_get', $get_action );
881 }
882
883 /**
884 * This function will sort an array by key 'name'.
885 *
886 * @since 2.1.1.2
887 *
888 * @param $a Mixed - first value to compare.
889 * @param $b Mixed - secound value to compare.
890 * @return integer value of comparation.
891 */
892 public static function sort_sidebars_cmp_function( $a, $b ) {
893 if ( ! isset( $a['name'] ) || ! isset( $b['name'] ) ) {
894 return 0;
895 }
896 if ( function_exists( 'mb_strtolower' ) ) {
897 $a_name = mb_strtolower( $a['name'] );
898 $b_name = mb_strtolower( $b['name'] );
899 } else {
900 $a_name = strtolower( $a['name'] );
901 $b_name = strtolower( $b['name'] );
902 }
903 if ( $a_name == $b_name ) {
904 return 0;
905 }
906 return ($a_name < $b_name ) ? -1 : 1;
907 }
908
909 /**
910 * Returns sidebars sorted by name.
911 *
912 * @since 2.1.1.2
913 *
914 * @param array $available Array of sidebars.
915 * @return array Sorted array of sidebars.
916 */
917 public static function sort_sidebars_by_name( $available ) {
918 if ( empty( $available ) ) {
919 return $available;
920 }
921 foreach ( $available as $key => $data ) {
922 $available[ $key ]['cs-key'] = $key;
923 }
924 usort( $available, array( __CLASS__, 'sort_sidebars_cmp_function' ) );
925 $sorted = array();
926 foreach ( $available as $data ) {
927 $sorted[ $data['cs-key'] ] = $data;
928 }
929 return $sorted;
930 }
931
932 /**
933 * Add "support" and (configure) "widgets" on plugin list page
934 *
935 * @since 2.1.1.8
936 *
937 */
938 public function add_action_links( $actions, $plugin_file, $plugin_data, $context ) {
939 if ( current_user_can( 'edit_theme_options' ) ) {
940 $actions['widgets'] = sprintf(
941 '<a href="%s">%s</a>',
942 esc_url( admin_url( 'widgets.php' ) ),
943 __( 'Widgets', 'custom-sidebars' )
944 );
945 }
946 $url = 'https://wordpress.org/support/plugin/custom-sidebars';
947
948 $actions['support'] = sprintf(
949 '<a href="%s">%s</a>',
950 esc_url( $url ),
951 __( 'Support', 'custom-sidebars' )
952 );
953 return $actions;
954 }
955
956 /**
957 * Print JavaScript template.
958 *
959 * @since 3.0.1
960 */
961 public function print_templates() {
962 wp_enqueue_script( 'wp-util' );
963 ?>
964 <script type="text/html" id="tmpl-custom-sidebars-new">
965
966 <div class="custom-sidebars-add-new">
967
968 <p><?php esc_html_e( 'Create a custom sidebar to get started.', 'custom-sidebars' ); ?></p>
969
970 </div>
971
972 </script>
973 <?php
974 }
975 };
976