singleton. * * @since 2.0 */ private function __construct() { add_action( 'widgets_init', array( $this, 'register_custom_sidebars' ) ); // Support translation via WPML plugin. add_action( 'register_sidebar', array( $this, 'translate_sidebar' ) ); if ( ! is_admin() ) { // Frontend hooks. add_action( 'wp_head', array( $this, 'replace_sidebars' ) ); add_action( 'wp', array( $this, 'store_original_post_id' ) ); /** * print styles for media query * * @since 3.2.0 */ add_action( 'wp_print_styles', array( $this, 'add_custom_css_for_media' ) ); } } /** * Add css styles for custom media width * * @since 3.2.0 */ public function add_custom_css_for_media() { global $wp_registered_sidebars, $_wp_sidebars_widgets; $defaults = self::get_options(); $replacements = $this->determine_replacements( $defaults ); foreach ( $replacements as $sb_id => $replace_info ) { if ( empty( $replace_info ) || ! is_array( $replace_info ) ) { continue; } $replacement = array_shift( $replace_info ); if ( isset( $defaults['screen'] ) && isset( $defaults['screen'][ $replacement ] ) ) { $css = ''; $css_before = array(); foreach ( $defaults['screen'][ $replacement ] as $css_size => $css_data ) { if ( empty( $css_data ) ) { continue; } foreach ( $css_data as $css_minmax => $css_mode ) { if ( empty( $css_size ) ) { continue; } if ( ! isset( $_wp_sidebars_widgets[ $replacement ] ) || empty( $_wp_sidebars_widgets[ $replacement ] ) ) { continue; } $css_selectors = array_map( array( $this, 'convert_do_css_id' ), $_wp_sidebars_widgets[ $replacement ] ); $css_before[] = sprintf( '%s { display: none }', implode( ', ', $css_selectors ) ); if ( 'max' === $css_minmax ) { $css .= sprintf( '@media screen and ( %s-width: %dpx ) { %s { display: %s; } }', esc_attr( $css_minmax ), esc_attr( $css_size ), implode( ', ', $css_selectors ), 'hide' === $css_mode ? 'none':'initial' ); $css .= PHP_EOL; } else { $css = sprintf( '@media screen and ( %s-width: %dpx ) { %s { display: %s; } }%s%s', esc_attr( $css_minmax ), esc_attr( $css_size ), implode( ', ', $css_selectors ), 'hide' === $css_mode ? 'none':'initial', PHP_EOL, $css ); } } } if ( ! empty( $css ) ) { $css_before = array_unique( $css_before ); echo ''; echo PHP_EOL; } } } } /** * Tell WordPress about the custom sidebars. */ public function register_custom_sidebars() { $sb = self::get_custom_sidebars(); $sb = CustomSidebars::sort_sidebars_by_name( $sb ); foreach ( $sb as $sidebar ) { /** * Filter sidebar options for custom sidebars. * * @since 2.0 * * @param array $sidebar Options used by WordPress to display * the sidebar. */ $sidebar = apply_filters( 'cs_sidebar_params', $sidebar ); register_sidebar( $sidebar ); } } /** * Stores the original post id before any plugin (buddypress) can modify this data, to show the proper sidebar. */ public function store_original_post_id() { global $post; if ( isset( $post->ID ) ) { $this->original_post_id = $post->ID; } } /** * Replace the sidebars on current page with some custom sidebars. * Sidebars are replaced by directly modifying the WordPress globals * `$_wp_sidebars_widgets` and `$wp_registered_sidebars` * * What it really does it not replacing a specific *sidebar* but simply * replacing all widgets inside the theme sidebars with the widgets of the * custom defined sidebars. */ public function replace_sidebars() { global $_wp_sidebars_widgets, $wp_registered_sidebars, $wp_registered_widgets; $custom_sidebars_explain = CustomSidebarsExplain::instance(); $expl = $custom_sidebars_explain->do_explain(); $expl && do_action( 'cs_explain', '

Replace sidebars

', true ); do_action( 'cs_before_replace_sidebars' ); /** * Original sidebar configuration by WordPress: * Lists sidebars and all widgets inside each sidebar. */ $original_widgets = $_wp_sidebars_widgets; $defaults = self::get_options(); /** * Fires before determining sidebar replacements. * * @param array $defaults Array of the default sidebars for the page. */ do_action( 'cs_predetermine_replacements', $defaults ); // Legacy handler with camelCase do_action( 'cs_predetermineReplacements', $defaults ); $replacements = $this->determine_replacements( $defaults ); foreach ( $replacements as $sb_id => $replace_info ) { if ( ! is_array( $replace_info ) || count( $replace_info ) < 3 ) { $expl && do_action( 'cs_explain', 'Replacement for "' . $sb_id . '": -none-' ); continue; } // Fix rare message "illegal offset type in isset or empty" $replacement = (string) @$replace_info[0]; $replacement_type = (string) @$replace_info[1]; $extra_index = (string) @$replace_info[2]; $check = $this->is_valid_replacement( $sb_id, $replacement, $replacement_type, $extra_index ); if ( $check && isset( $original_widgets[ $replacement ] ) ) { $expl && do_action( 'cs_explain', 'Replacement for "' . $sb_id . '": ' . $replacement ); if ( sizeof( $original_widgets[ $replacement ] ) == 0 ) { // No widgets on custom sidebar, show nothing. $wp_registered_widgets['csemptywidget'] = $this->get_empty_widget(); $_wp_sidebars_widgets[ $sb_id ] = array( 'csemptywidget' ); } else { $_wp_sidebars_widgets[ $sb_id ] = $original_widgets[ $replacement ]; /** * When custom sidebars use some wrapper code (before_title, * after_title, ...) then we need to strip-slashes for this * wrapper code to work properly */ $sidebar_for_replacing = $wp_registered_sidebars[ $replacement ]; if ( $this->has_wrapper_code( $sidebar_for_replacing ) ) { $sidebar_for_replacing = $this->clean_wrapper_code( $sidebar_for_replacing ); $wp_registered_sidebars[ $sb_id ] = $sidebar_for_replacing; } } $wp_registered_sidebars[ $sb_id ]['class'] = $replacement; } else { // endif: is_valid_replacement $expl && do_action( 'cs_explain', 'Replacement for "' . $sb_id . '": -none-' ); } } // endforeach } /** * THIS IS THE ACTUAL LOGIC OF THE PLUGIN * * Here we find out if some sidebars should be replaced, and if it is * replaced we determine which custom sidebar to use. * * @param array $options Plugin options with the replacement rules. * @return array List of the replaced sidebars. */ public function determine_replacements( $options ) { global $post, $sidebar_category; $sidebars = self::get_options( 'modifiable' ); $replacements_todo = sizeof( $sidebars ); $replacements = array(); $custom_sidebars_explain = CustomSidebarsExplain::instance(); $expl = $custom_sidebars_explain->do_explain(); foreach ( $sidebars as $sb ) { $replacements[ $sb ] = false; } // 1 |== Single posts/pages -------------------------------------------- if ( is_singular() && ! is_home() && ! is_front_page() ) { $post_type = get_post_type(); $post_type = apply_filters( 'cs_replace_post_type', $post_type, 'single' ); $expl && do_action( 'cs_explain', 'Type 1: Single ' . ucfirst( $post_type ) ); if ( ! self::supported_post_type( $post_type ) ) { $expl && do_action( 'cs_explain', 'Invalid post type, use default sidebars.' ); return $options; } // 1.1 Check if replacements are defined in the post metadata. $reps = self::get_post_meta( $this->original_post_id ); foreach ( $sidebars as $sb_id ) { if ( is_array( $reps ) && ! empty( $reps[ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $reps[ $sb_id ], 'particular', -1, ); $replacements_todo -= 1; } } // 1.2 Try to use the parents metadata. if ( $post->post_parent != 0 && $replacements_todo > 0 ) { $reps = self::get_post_meta( $post->post_parent ); foreach ( $sidebars as $sb_id ) { if ( $replacements[ $sb_id ] ) { continue; } if ( is_array( $reps ) && ! empty( $reps[ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $reps[ $sb_id ], 'particular', -1, ); $replacements_todo -= 1; } } } // 1.3 If no metadata set then use the category settings. if ( $replacements_todo > 0 ) { $categories = self::get_sorted_categories(); $ind = sizeof( $categories ) -1; while ( $replacements_todo > 0 && $ind >= 0 ) { $cat_id = $categories[ $ind ]->cat_ID; foreach ( $sidebars as $sb_id ) { if ( $replacements[ $sb_id ] ) { continue; } if ( ! empty( $options['category_single'][ $cat_id ][ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $options['category_single'][ $cat_id ][ $sb_id ], 'category_single', $sidebar_category, ); $replacements_todo -= 1; } } $ind -= 1; } } // 1.4 Look for post-type level replacements. if ( $replacements_todo > 0 ) { foreach ( $sidebars as $sb_id ) { if ( $replacements[ $sb_id ] ) { continue; } if ( isset( $options['post_type_single'][ $post_type ] ) && ! empty( $options['post_type_single'][ $post_type ][ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $options['post_type_single'][ $post_type ][ $sb_id ], 'post_type_single', $post_type, ); $replacements_todo -= 1; } } } } elseif ( is_category() ) { // 2 |== Category archive ---------------------------------------------- $expl && do_action( 'cs_explain', 'Type 2: Category Archive' ); /** * 2.1 Category archive */ foreach ( $sidebars as $sb_id ) { if ( ! $replacements[ $sb_id ] && isset( $options['category_archive'][ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $options['category_archive'][ $sb_id ], 'category_archive', 0, ); } } /** * 2.2 Start at current category and travel up all parents */ $category_object = get_queried_object(); $current_category = $category_object->term_id; if ( 0 != $current_category && $replacements_todo > 0 ) { foreach ( $sidebars as $sb_id ) { if ( isset( $options['category_archive'] ) && isset( $options['category_archive'][ $current_category ] ) && isset( $options['category_archive'][ $current_category ][ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $options['category_archive'][ $current_category ][ $sb_id ], 'category_archive', $current_category, ); } } $current_category = $category_object->category_parent; if ( 0 != $current_category ) { $category_object = get_category( $current_category ); } } } elseif ( is_search() ) { // 3 |== Search -------------------------------------------------------- // Must be before the post-type archive section; otherwise a search with // no results is recognized as post-type archive... $expl && do_action( 'cs_explain', 'Type 3: Search Results' ); foreach ( $sidebars as $sb_id ) { if ( ! empty( $options['search'][ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $options['search'][ $sb_id ], 'search', -1, ); } } } elseif ( ! is_tax() && ! is_404() && ! is_category() && ! is_singular() && get_post_type() != 'post' ) { // 4 |== Post-Tpe Archive ---------------------------------------------- // `get_post_type() != 'post'` .. post-archive = post-index (see 7) $post_type = get_post_type(); $post_type = apply_filters( 'cs_replace_post_type', $post_type, 'archive' ); $expl && do_action( 'cs_explain', 'Type 4: ' . ucfirst( $post_type ) . ' Archive' ); if ( ! self::supported_post_type( $post_type ) ) { $expl && do_action( 'cs_explain', 'Invalid post type, use default sidebars.' ); return $options; } foreach ( $sidebars as $sb_id ) { if ( isset( $options['post_type_archive'][ $post_type ] ) && ! empty( $options['post_type_archive'][ $post_type ][ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $options['post_type_archive'][ $post_type ][ $sb_id ], 'post_type_archive', $post_type, ); $replacements_todo -= 1; } } } elseif ( is_page() && ! is_front_page() ) { // 5 |== Page ---------------------------------------------------------- // `! is_front_page()` .. in case the site uses static front page. $post_type = get_post_type(); $post_type = apply_filters( 'cs_replace_post_type', $post_type, 'page' ); $expl && do_action( 'cs_explain', 'Type 5: ' . ucfirst( $post_type ) ); if ( ! self::supported_post_type( $post_type ) ) { $expl && do_action( 'cs_explain', 'Invalid post type, use default sidebars.' ); return $options; } // 5.1 Check if replacements are defined in the post metadata. $reps = self::get_post_meta( $this->original_post_id ); foreach ( $sidebars as $sb_id ) { if ( is_array( $reps ) && ! empty( $reps[ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $reps[ $sb_id ], 'particular', -1, ); $replacements_todo -= 1; } } // 5.2 Try to use the parents metadata. $post_orginal = $post; while ( $replacements_todo > 0 && $post->post_parent > 0 ) { if ( $replacements_todo > 0 ) { $reps = self::get_post_meta( $post->post_parent ); foreach ( $sidebars as $sb_id ) { if ( $replacements[ $sb_id ] ) { continue; } if ( is_array( $reps ) && ! empty( $reps[ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $reps[ $sb_id ], 'particular', -1, ); } } $post = get_post( $post->post_parent ); } } $post = $post_orginal; // 5.3 Look for post-type level replacements. if ( $replacements_todo > 0 ) { foreach ( $sidebars as $sb_id ) { if ( $replacements[ $sb_id ] ) { continue; } if ( isset( $options['post_type_single'][ $post_type ] ) && ! empty( $options['post_type_single'][ $post_type ][ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $options['post_type_single'][ $post_type ][ $sb_id ], 'post_type_single', $post_type, ); $replacements_todo -= 1; } } } } elseif ( is_front_page() ) { // 6 |== Front Page ---------------------------------------------------- /* * The front-page of the site. Either * - the post-index (default) or * - a static front-page. */ $expl && do_action( 'cs_explain', 'Type 6: Front Page' ); if ( ! is_home() ) { // A static front-page. Maybe we need the post-meta data... $reps_post = self::get_post_meta( $this->original_post_id ); $reps_parent = self::get_post_meta( $post->post_parent ); } foreach ( $sidebars as $sb_id ) { // First check if there is a 'Front Page' replacement. if ( ! empty( $options['blog'][ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $options['blog'][ $sb_id ], 'blog', -1, ); } else if ( ! is_home() ) { // There is no 'Front Page' reaplcement and this is a static // front page, so check if the page has a replacement. // 6.1 Check if replacements are defined in the post metadata. if ( is_array( $reps_post ) && ! empty( $reps_post[ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $reps_post[ $sb_id ], 'particular', -1, ); $replacements_todo -= 1; } // 6.2 Try to use the parents metadata. if ( $post->post_parent != 0 && $replacements_todo > 0 ) { if ( $replacements[ $sb_id ] ) { continue; } if ( is_array( $reps_parent ) && ! empty( $reps_parent[ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $reps_parent[ $sb_id ], 'particular', -1, ); $replacements_todo -= 1; } } } } } elseif ( is_home() ) { // 7 |== Post Index ---------------------------------------------------- /* * The post-index of the site. Either * - the front-page (default) * - when a static front page is used the post-index page. * * Note: When the default front-page is used the condition 6 * "is_front_page" above is used and this node is never executed. */ $expl && do_action( 'cs_explain', 'Type 7: Post Index' ); foreach ( $sidebars as $sb_id ) { if ( ! empty( $options['post_type_archive']['post'][ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $options['post_type_archive']['post'][ $sb_id ], 'postindex', -1, ); } } } elseif ( is_tag() ) { // 8 |== Tag archive --------------------------------------------------- $expl && do_action( 'cs_explain', 'Type 8: Tag Archive' ); foreach ( $sidebars as $sb_id ) { if ( ! empty( $options['tags'][ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $options['tags'][ $sb_id ], 'tags', -1, ); } } } elseif ( is_author() ) { // 9 |== Author archive ------------------------------------------------ $author_object = get_queried_object(); $current_author = $author_object->ID; $expl && do_action( 'cs_explain', 'Type 9: Author Archive (' . $current_author . ')' ); // 9.1 First check for specific authors. foreach ( $sidebars as $sb_id ) { if ( ! empty( $options['author_archive'][ $current_author ][ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $options['author_archive'][ $current_author ][ $sb_id ], 'author_archive', $current_author, ); $replacements_todo -= 1; } } // 9.2 Then check if there is an "Any authors" sidebar if ( $replacements_todo > 0 ) { foreach ( $sidebars as $sb_id ) { if ( $replacements[ $sb_id ] ) { continue; } if ( ! empty( $options['authors'][ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $options['authors'][ $sb_id ], 'authors', -1, ); } } } } elseif ( is_date() ) { // 10 |== Date archive ------------------------------------------------- $expl && do_action( 'cs_explain', 'Type 10: Date Archive' ); foreach ( $sidebars as $sb_id ) { if ( ! empty( $options['date'][ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $options['date'][ $sb_id ], 'date', -1, ); } } } elseif ( is_404() ) { // 11 |== 404 not found ------------------------------------------------ $expl && do_action( 'cs_explain', 'Type 11: 404 not found' ); foreach ( $sidebars as $sb_id ) { if ( ! empty( $options['404'][ $sb_id ] ) ) { $replacements[ $sb_id ] = array( $options['404'][ $sb_id ], '404', -1, ); } } } elseif ( is_tax() ) { // 12 |== Taxonomy Archive ---------------------------------------------- $current_term = get_queried_object(); $taxonomy = $current_term->taxonomy; $taxonomy = apply_filters( 'cs_replace_taxonomy', $taxonomy, 'archive' ); $expl && do_action( 'cs_explain', 'Type 12: ' . ucfirst( $taxonomy ) . ' Archive' ); foreach ( $sidebars as $sb_id ) { if ( isset( $options['taxonomies_archive'] ) && isset( $options['taxonomies_archive'][ $taxonomy ] ) && isset( $options['taxonomies_archive'][ $taxonomy ][ $sb_id ] ) ) { $expl && do_action( 'cs_explain', 'Replacement for custom taxonomy archive"' . $taxonomy ); $replacements[ $sb_id ] = array( $options['taxonomies_archive'][ $taxonomy ][ $sb_id ], 'taxonomies_archive', -1, ); } /** * replace for single taxonomy */ if ( isset( $options['taxonomies_single'] ) && isset( $options['taxonomies_single'][ $taxonomy ] ) && isset( $options['taxonomies_single'][ $taxonomy ][ $current_term->term_id ] ) && isset( $options['taxonomies_single'][ $taxonomy ][ $current_term->term_id ][ $sb_id ] ) ) { $expl && do_action( 'cs_explain', 'Replacement for custom taxonomy ("' . $taxonomy . ') - '.$current_term->name ); $replacements[ $sb_id ] = array( $options['taxonomies_single'][ $taxonomy ][ $current_term->term_id ][ $sb_id ], 'taxonomies_single', -1, ); } } } /** * Filter the replaced sidebars before they are processed by the plugin. * * @since 2.0 * @since 3.1.2 added param $options * * @param array $replacements List of the final/replaced sidebars. * @param array $options Custom Sidebars settings. */ $replacements = apply_filters( 'cs_replace_sidebars', $replacements, $options ); return $replacements; } /** * Makes sure that the replacement sidebar exists. * If the custom sidebar does not exist then the WordPress/Post options are * updated to remove the invalid option. * * @since 1.0.0 * @param string $sb_id The original sidebar (the one that is replaced). * @param string $replacement ID of the custom sidebar that should be used. * @param string $method Info where the replacement setting is saved. * @param int|string $extra_index Depends on $method - can be either one: * empty/post-type/category-ID * @return bool */ public function is_valid_replacement( $sb_id, $replacement, $method, $extra_index ) { global $wp_registered_sidebars; $options = self::get_options(); if ( isset( $wp_registered_sidebars[ $replacement ] ) ) { // Everything okay, we can use the replacement return true; } /* * The replacement sidebar was not registered. Something's wrong, so we * update the options and not try to replace this sidebar again. */ if ( 'particular' == $method ) { // Invalid replacement was found in post-meta data. $sidebars = self::get_post_meta( $this->original_post_id ); if ( $sidebars && isset( $sidebars[ $sb_id ] ) ) { unset( $sidebars[ $sb_id ] ); self::set_post_meta( $this->original_post_id, $sidebars ); } } else { // Invalid replacement is defined in wordpress options table. if ( isset( $options[ $method ] ) ) { if ( -1 != $extra_index && isset( $options[ $method ][ $extra_index ] ) && isset( $options[ $method ][ $extra_index ][ $sb_id ] ) ) { unset( $options[ $method ][ $extra_index ][ $sb_id ] ); self::set_options( $options ); } if ( 1 == $extra_index && isset( $options[ $method ] ) && isset( $options[ $method ][ $sb_id ] ) ) { unset( $options[ $method ][ $sb_id ] ); self::set_options( $options ); } } } return false; } /** * Returns an empty dummy-widget. This dummy widget is used when a custom * sidebar has no widgets. * * @since 1.0.0 */ public function get_empty_widget() { $widget = new CustomSidebarsEmptyPlugin(); return array( 'name' => 'CS Empty Widget', 'id' => 'csemptywidget', 'callback' => array( $widget, 'display_callback' ), 'params' => array( array( 'number' => 2 ) ), 'classname' => 'CustomSidebarsEmptyPlugin', 'description' => 'CS dummy widget', ); } /** * Checks if the specified sidebar uses custom wrapper code. * * @since 1.2 * @return bool */ public function has_wrapper_code( $sidebar ) { return ( strlen( trim( $sidebar['before_widget'] ) ) || strlen( trim( $sidebar['after_widget'] ) ) || strlen( trim( $sidebar['before_title'] ) ) || strlen( trim( $sidebar['after_title'] ) ) ); } /** * Clean the slashes of the custom sidebar wrapper code. * * @since 1.2 */ public function clean_wrapper_code( $sidebar ) { $sidebar['before_widget'] = stripslashes( $sidebar['before_widget'] ); $sidebar['after_widget'] = stripslashes( $sidebar['after_widget'] ); $sidebar['before_title'] = stripslashes( $sidebar['before_title'] ); $sidebar['after_title'] = stripslashes( $sidebar['after_title'] ); return $sidebar; } /** * Translates a sidebar using WPML right after it was registered. * * @since 2.0.9.7 * @param array $sidebar The sidebar that was registered */ public function translate_sidebar( $sidebar ) { if ( ! function_exists( 'icl_t' ) ) { return false; } global $wp_registered_sidebars; $context = 'Sidebar'; // Translate the name and description. $sidebar['name'] = icl_t( $context, $sidebar['id'] . '-name', $sidebar['name'] ); $sidebar['description'] = icl_t( $context, $sidebar['id'] . '-description', $sidebar['description'] ); $wp_registered_sidebars[ $sidebar['id'] ] = $sidebar; } /** * Convert to CSS ID. * * @since 3.2.0 */ private function convert_do_css_id( $v ) { return sprintf( '#%s', esc_attr( $v ) ); } };