Indirect modification of overloaded property WP_Post::$classes has no effect

I’m working on a child theme and while everything works the Walker_Nav_Menu and Walker classes are causing all the fuss. My parent theme overrides Walker_Nav_Menu as below:

if ( ! class_exists( 'Zen_Menu_Walker' ) ) {

class Zen_Menu_Walker extends Walker_Nav_Menu {

    public function display_element( $element, &$children_elements, $max_depth, $depth = 0, $args, &$output ) {
        $element->has_children = ! empty( $children_elements[ $element->ID ] );
        $element->classes[]    = ( $element->current || $element->current_item_ancestor ) ? 'active' : '';
        $element->classes[]    = ( $element->has_children && 1 !== $max_depth ) ? 'has-dropdown' : '';

        parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
    }

    public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
        $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

        $classes   = empty( $item->classes ) ? array() : (array) $item->classes;
        $classes[] = 'menu-item-' . $item->ID;

        $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) );
        $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';

        $id = apply_filters( 'nav_menu_item_id', 'menu-item-' . $item->ID, $item, $args, $depth );
        $id = $id ? ' id="' . esc_attr( $id ) . '"' : '';

        $output .= $indent . '<li' . $id . $class_names . '>';

        $atts           = array();
        $atts['title']  = ! empty( $item->attr_title ) ? $item->attr_title : '';
        $atts['target'] = ! empty( $item->target ) ? $item->target : '';
        $atts['rel']    = ! empty( $item->xfn ) ? $item->xfn : '';
        $atts['href']   = ! empty( $item->url ) ? $item->url : '';

        $atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );

        $attributes="";
        foreach ( $atts as $attr => $value ) {
            if ( ! empty( $value ) ) {
                //$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
                $attributes .= ' ' . $attr . '="' . $value . '"';
            }
        }

        $item_output = $args->before;
        $item_output .= '<a' . $attributes . '>';
        /** This filter is documented in wp-includes/post-template.php */
        $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
        $item_output .= '</a>';
        $item_output .= $args->after;

        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }

    public function start_lvl( &$output, $depth = 0, $args = array() ) {
        $output .= "\n<ul class=\"sub-menu dropdown\">\n";
    }

}
}

This works without any fatal errors in parent theme. But inside child theme it produces fatal error:

Notice: Indirect modification of overloaded property WP_Post::$classes has no effect in /srv/www/htdocs/wpsite/wp-content/themes/zen-theme/class.menu.php on line 45

Did some digging on Stackoverflow and Google and the only references I found were:

  • https://stackoverflow.com/questions/13421661/getting-indirect-modification-of-overloaded-property-has-no-effect-notice
  • https://stackoverflow.com/questions/10454779/php-indirect-modification-of-overloaded-property
  • https://stackoverflow.com/questions/20053269/indirect-modification-of-overloaded-element-of-splfixedarray-has-no-effect
  • https://gist.github.com/awshout/3943026#gistcomment-676280

A buggy day indeed… I’m using PHP 5.6 and from what I read:

“As of PHP 5.3.0, you will get a warning saying that “call-time pass-by-reference” is deprecated when you use & in foo(&$a);. And as of PHP 5.4.0, call-time pass-by-reference was removed, so using it will raise a fatal error. ”

Any guesses why this is happening…

1 Answer
1

If “line 45” is the one that starts with $element->classes[] in your display_element method then try something like this:

public function display_element( $element, &$children_elements, $max_depth, $depth = 0, $args, &$output ) {
    $element->has_children = ! empty( $children_elements[ $element->ID ] );

    if ( ! isset( $element->classes ) ) {
        $element->classes = array();
    }

    $element->classes[]    = ( $element->current || $element->current_item_ancestor ) ? 'active' : '';
    $element->classes[]    = ( $element->has_children && 1 !== $max_depth ) ? 'has-dropdown' : '';        

    parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
}

The problem may be that the display_element function receives an element that doesn’t have that classes property set in which case you are trying to push data to an array that isn’t referenced anywhere except that instance only.

EDIT: Also, why are you using the display_element function when you can insert those classes in the start_el function which itself gets called by display_element with that element passed to it?

Leave a Comment