WordPress自定义分类小部件报错:无法重复声明cat_count_span()
自定义分类小部件重复添加时致命错误的解决方法
问题说明
为主题创建Consulty_Widget_Categories自定义分类小部件后,同时添加到主侧边栏和页脚侧边栏时触发致命错误:
Fatal error: Cannot redeclare cat_count_span() (previously declared in E:\xampp\htdocs\repo\wp-content\plugins\consulty-core\widgets\categories\class-consulty-cats.php:157) in E:\xampp\htdocs\repo\wp-content\plugins\consulty-core\widgets\categories\class-consulty-cats.php on line 157
该错误由用于给分类文章计数添加span标签的cat_count_span()函数引发。
错误根源
问题出在**widget()方法内部定义了命名函数cat_count_span()**:每次小部件实例渲染时,都会尝试重新声明这个函数。当页面存在多个该小部件实例时,PHP不允许重复声明同名函数,因此抛出致命错误。
修复方案
有两种可靠的解决方式:
方案1:将函数改为类的静态方法
把cat_count_span()定义为类的静态方法,避免重复声明:
// 在类内部添加静态方法 public static function cat_count_span($links) { $links = str_replace('</a> (', '<span>(', $links); $links = str_replace(')', ')</span></a>', $links); return $links; } // 在widget()方法中调用过滤器时修改为: add_filter('wp_list_categories', array(__CLASS__, 'cat_count_span'));
方案2:使用匿名函数替代命名函数
直接在add_filter中使用匿名函数,彻底避免重复声明问题:
add_filter('wp_list_categories', function($links) { $links = str_replace('</a> (', '<span>(', $links); $links = str_replace(')', ')</span></a>', $links); return $links; });
修改后的完整代码
<?php /** * Widget API: WP_Widget_Categories class * * @package WordPress * @subpackage Widgets * @since 4.4.0 */ /** * Core class used to implement a Categories widget. * * @since 2.8.0 * * @see WP_Widget */ class Consulty_Widget_Categories extends WP_Widget { /** * Sets up a new Categories widget instance. * * @since 2.8.0 */ public function __construct() { $widget_ops = array( 'classname' => 'consulty_widget_categories', 'description' => __( 'A list or dropdown of categories By Consulty.' ), 'customize_selective_refresh' => true, 'show_instance_in_rest' => true, ); parent::__construct( 'consulty_categories', __( 'Consulty Categories' ), $widget_ops ); } /** * 静态方法:为分类计数添加span标签 */ public static function cat_count_span($links) { $links = str_replace('</a> (', '<span>(', $links); $links = str_replace(')', ')</span></a>', $links); return $links; } /** * Outputs the content for the current Categories widget instance. * * @since 2.8.0 * @since 4.2.0 Creates a unique HTML ID for the `select` element * if more than one instance is displayed on the page. * * @param array $args Display arguments including 'before_title', 'after_title', * 'before_widget', and 'after_widget'. * @param array $instance Settings for the current Categories widget instance. */ public function widget( $args, $instance ) { static $first_dropdown = true; $default_title = __( 'Categories' ); $title = ! empty( $instance['title'] ) ? $instance['title'] : $default_title; $title = apply_filters( 'widget_title', $title, $instance, $this->id_base ); $count = ! empty( $instance['count'] ) ? '1' : '0'; $hierarchical = ! empty( $instance['hierarchical'] ) ? '1' : '0'; $dropdown = ! empty( $instance['dropdown'] ) ? '1' : '0'; echo '<div class="sidebar-widget sidebar-categories">'; echo '<div class="widget-title">'; if ( $title ) { echo $args['before_title'] . $title . $args['after_title']; } echo '</div>';// End class="widget-title" $cat_args = array( 'orderby' => 'name', 'show_count' => $count, 'hierarchical' => $hierarchical, ); if ( $dropdown ) { printf( '<form action="%s" method="get">', esc_url( home_url() ) ); $dropdown_id = ( $first_dropdown ) ? 'cat' : "{$this->id_base}-dropdown-{$this->number}"; $first_dropdown = false; echo '<label class="screen-reader-text" for="' . esc_attr( $dropdown_id ) . '">' . $title . '</label>'; $cat_args['show_option_none'] = __( 'Select Category' ); $cat_args['id'] = $dropdown_id; wp_dropdown_categories( apply_filters( 'widget_categories_dropdown_args', $cat_args, $instance ) ); echo '</form>'; $type_attr = current_theme_supports( 'html5', 'script' ) ? '' : ' type="text/javascript"'; ?> <script<?php echo $type_attr; ?>> /* <![CDATA[ */ (function() { var dropdown = document.getElementById( "<?php echo esc_js( $dropdown_id ); ?>" ); function onCatChange() { if ( dropdown.options[ dropdown.selectedIndex ].value > 0 ) { dropdown.parentNode.submit(); } } dropdown.onchange = onCatChange; })(); /* ]]> */ </script> <?php } else { $format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml'; $format = apply_filters( 'navigation_widgets_format', $format ); if ( 'html5' === $format ) { $title = trim( strip_tags( $title ) ); $aria_label = $title ? $title : $default_title; echo '<nav aria-label="' . esc_attr( $aria_label ) . '">'; } ?> <div class="widget-content"> <ul class="categories-list clearfix"> <?php $cat_args['title_li'] = ''; // 使用类静态方法作为过滤器 add_filter('wp_list_categories', array(__CLASS__, 'cat_count_span')); wp_list_categories( apply_filters( 'widget_categories_args', $cat_args, $instance ) ); ?> </ul> </div><!-- /.widget-content --> <?php if ( 'html5' === $format ) { echo '</nav>'; } } echo '</div>';// End class="sidebar-widget sidebar-categories" } /** * Handles updating settings for the current Categories widget instance. * * @since 2.8.0 * * @param array $new_instance New settings for this instance as input by the user via * WP_Widget::form(). * @param array $old_instance Old settings for this instance. * @return array Updated settings to save. */ public function update( $new_instance, $old_instance ) { $instance = $old_instance; $instance['title'] = sanitize_text_field( $new_instance['title'] ); $instance['count'] = ! empty( $new_instance['count'] ) ? 1 : 0; $instance['hierarchical'] = ! empty( $new_instance['hierarchical'] ) ? 1 : 0; $instance['dropdown'] = ! empty( $new_instance['dropdown'] ) ? 1 : 0; return $instance; } /** * Outputs the settings form for the Categories widget. * * @since 2.8.0 * * @param array $instance Current settings. */ public function form( $instance ) { $instance = wp_parse_args( (array) $instance, array( 'title' => '' ) ); $count = isset( $instance['count'] ) ? (bool) $instance['count'] : false; $hierarchical = isset( $instance['hierarchical'] ) ? (bool) $instance['hierarchical'] : false; $dropdown = isset( $instance['dropdown'] ) ? (bool) $instance['dropdown'] : false; ?> <p> <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:' ); ?></label> <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $instance['title'] ); ?>" /> </p> <p> <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id( 'dropdown' ); ?>" name="<?php echo $this->get_field_name( 'dropdown' ); ?>" <?php checked( $dropdown ); ?> /> <label for="<?php echo $this->get_field_id( 'dropdown' ); ?>"><?php _e( 'Display as dropdown' ); ?></label> <br /> <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id( 'count' ); ?>" name="<?php echo $this->get_field_name( 'count' ); ?>" <?php checked( $count ); ?> /> <label for="<?php echo $this->get_field_id( 'count' ); ?>"><?php _e( 'Show post counts' ); ?></label> <br /> <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id( 'hierarchical' ); ?>" name="<?php echo $this->get_field_name( 'hierarchical' ); ?>" <?php checked( $hierarchical ); ?> /> <label for="<?php echo $this->get_field_id( 'hierarchical' ); ?>"><?php _e( 'Show hierarchy' ); ?></label> </p> <?php } } // Register and load the widget function consulty_register_custom_cat() { register_widget( 'Consulty_Widget_Categories' ); } add_action( 'widgets_init', 'consulty_register_custom_cat' );
内容的提问来源于stack exchange,提问作者Hatem Frere
相关产品推荐
相关产品推荐

