wp_nav_menu中用字符串替换Walker实例引发致命错误,求助
我之前碰到过一模一样的问题,这个致命错误的根源其实很好理解:
当你把walker参数传为字符串'My_Walker_Nav_Menu'时,在Customizer部分刷新的特定场景下,WordPress并没有正确实例化你的自定义Walker类——反而试图以静态方式调用类中的方法。而你的My_Walker_Nav_Menu是基于Walker_Nav_Menu的实例类,内部大量使用$this来访问实例属性和方法,静态调用时没有对象上下文,自然就触发了Using $this when not in object context的错误。
下面给你几个针对性的解决方案,按优先级从低到高:
方案1:检查并修复自定义Walker的基础实现
先确保你的My_Walker_Nav_Menu类本身没有语法或逻辑错误,这是最基础的修复步骤:
- 不要把
start_el、end_el、start_lvl这类核心Walker方法声明为static(这些方法本身就是实例方法) - 构造函数如果有参数,一定要设置默认值,避免实例化失败
- 所有使用
$this的代码都必须在实例方法内部,不要在类外部直接静态调用类方法
给你一个正确的示例模板:
class My_Walker_Nav_Menu extends Walker_Nav_Menu { // 构造函数可留空,或添加带默认值的初始化逻辑 public function __construct() { // 你的自定义初始化代码(如果需要) } // 重写start_el方法,$this在这里可以正常使用 public function start_el( &$output, $item, $depth = 0, $args = null, $id = 0 ) { // 你的自定义渲染逻辑 parent::start_el( $output, $item, $depth, $args, $id ); } // 自定义的辅助方法,同样是实例方法 private function handle_menu_item_classes( $item, $depth ) { // 使用$this访问类属性或其他方法都没问题 return $item->classes; } }
方案2:用过滤器自动转换字符串Walker为实例
如果方案1不能解决问题,大概率是Customizer部分刷新的回调逻辑没有正确处理字符串参数。这时候可以通过wp_nav_menu_args过滤器,在Customizer预览场景下自动把字符串Walker转换为实例:
add_filter( 'wp_nav_menu_args', function( $args ) { // 仅在Customizer预览中生效 if ( is_customize_preview() && isset( $args['walker'] ) && is_string( $args['walker'] ) ) { $walker_class = $args['walker']; // 确保类存在再实例化 if ( class_exists( $walker_class ) ) { $args['walker'] = new $walker_class(); } } return $args; } );
这个方法既满足了Customizer部分刷新对字符串参数的要求,又避免了静态调用的错误,相当于做了一层兼容转换。
方案3:直接修改Customizer部分刷新的渲染回调
如果你的菜单是通过Customizer的部分刷新来更新的,可以直接在渲染回调中手动实例化Walker,跳过字符串参数的坑:
假设你原来的部分刷新配置是这样的:
$wp_customize->add_partial( 'nav_menu_locations[primary]', array( 'selector' => '#primary-menu', 'render_callback' => function() { // 原来的调用:传字符串Walker导致错误 wp_nav_menu( array( 'walker' => 'My_Walker_Nav_Menu', 'theme_location' => 'primary' ) ); }, ) );
把它改成直接实例化Walker:
$wp_customize->add_partial( 'nav_menu_locations[primary]', array( 'selector' => '#primary-menu', 'render_callback' => function() { wp_nav_menu( array( 'walker' => new My_Walker_Nav_Menu(), 'theme_location' => 'primary' ) ); }, ) );
这样在部分刷新时直接使用实例化的Walker,既不会报错,又能正常触发部分刷新,不需要依赖字符串参数。
内容的提问来源于stack exchange,提问作者Mihai

