1

I am working on a widget for my theme. If I do a

print_r($insance) 

in the form function, the instance array is populated with the correct data. I have checked the database and the correct information is there in the options table for my widget.

My problem is that, if I do a

print_r($instance) 

for the front end, The array is empty and I get undefined indexes in the widget function. I have not been able to figure out what is wrong.

 class alliance_post_builder extends WP_Widget {

/**
 * Register widget with WordPress.
 */
function __construct() {
    parent::__construct(
        'alliance_post_builder', // Base ID
        __( 'Alliance post builder', 'alliance' ), // Name
        array( 'description' => __( 'A post builder', 'alliance' ), ) // Args
    );
}

/**
 * Front-end display of widget.
 *
 * @see WP_Widget::widget()
 *
 * @param array $args     Widget arguments.
 * @param array $instance Saved values from database.
 */
public function widget( $args, $instance ) {
    extract( $args );

    $sectionID = $instance['sectionID'];
    $title = $instance['title'];
    $category = $instance['category'];  

?><section id="<?php echo $sectionID; ?>"><?php
        print_r($instance);
    ?></section><?php
} 

    /**
 * Sanitize widget form values as they are saved.
 *
 * @see WP_Widget::update()
 *
 * @param array $new_instance Values just sent to be saved.
 * @param array $old_instance Previously saved values from database.
 *
 * @return array Updated safe values to be saved.
 */
function update( $new_instance, $old_instance ) {
    $instance = $old_instance;

    /* Strip tags for title and name to remove HTML (important for text inputs). */
    $instance['title'] = strip_tags( $new_instance['title'] );
    $instance['sectionID'] = strip_tags( $new_instance['sectionID'] );
    $instance['category'] = $new_instance['category'];

    return $instance;
}

/** 
 * Back-end widget form.
 *
 * @see WP_Widget::form()
 *
 * @param array $instance Previously saved values from database.
 */
public function form( $instance ) {

$defaults = array( 'title' => __('A new section', 'alliance'), 'sectionID' => __('', 'alliance'), 'category' => -1 );
$instance = wp_parse_args( (array) $instance, $defaults ); 

    ?>
    <p>
    <label for="<?php echo $this->get_field_id( 'sectionID' ); ?>"><?php _e( 'Section Id:' ); ?></label> 
    <input class="widefat" id="<?php echo $this->get_field_id( 'sectionID' ); ?>" name="<?php echo $this->get_field_name( 'sectionID' ); ?>" type="text" value="<?php echo esc_attr( $sectionID ); ?>">
    </p>

    <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( $title ); ?>">
    </p>
    <?php 
        wp_dropdown_categories( array(
        'name' => $this->get_field_name( 'category' ),
        'selected' => $instance["category"],
        'show_option_none'   => 'None',
    ) );
}
 }
  • This issue is a complete and total different issue. I have the values, they are in the database. My new problem is that the $instance array that is supposed to get passed to the widget function to display on the front end is emtpy. I can't make the suggested change in the previous post because I am not using that information. it is irrelevant to this question. There is no get_tags or get_categories being used in my widget at this time. – Jamie Dec 22 '14 at 14:01
  • My apologies then. I suggested to use get_categories as it is better suited, but OK, as you said, it is irrelevant here. Also, I suggested that post as there are problems with your widgets, like for one, you should never use extract() – Pieter Goosen Dec 22 '14 at 14:17
  • I only added that after following other blogs from reputable sources when things weren't working. I have checked line by line and don't see the issue – Jamie Dec 22 '14 at 17:21
3

Your widget really has a lot of issues and completely breaks my layout on my back-end widget page. I suggest that you start at the Widget API to learn the proper way how to code a widget

Here is a couple of issues I have picked up:

  • Reputable sources should not be suggesting or even use extract(). All traces of this function was completely removed from core, except one instance (as far as I can understand from the trac ticket) that has not yet been solved. This should say a lot about the function

  • Your widget form is the culprit for breaking my layout. I have not even tried to look at that as there are more than two issues here. I have just completely changed that and also used get_categories() as I previously suggested to get the dropdown working and stop my layout from breaking

  • Your widget function that should output the front end info is missing a lot of elements. I'm not sure about the exact layout you are after or what your plan is on usage, so I have just done the following: (This is the bare necessities that you should have)

    ?><section id="<?php echo $sectionID; ?>"><?php
    
    echo $args['before_widget'];
    if ( $title ) {
        echo $args['before_title'] . $title . $args['after_title'];
    }               
    echo "SOMETHING IS MISSING HERE";
    
    echo $args['after_widget']; 
    
    ?></section><?php
    
  • Class names should have the words starting with camelcase according the naming convention section in the coding standards

I have also added a cache inside the widget to speed it up

Here is a working example of how your widget should look like. I have tested it, it works on my side. I also get output on the front end with the code given, you will just need to modify this and add the missing parts where I stated echo "SOMETHING IS MISSING HERE";

/**
 * Alliance_Post_Builder widget class
 *
 * @since 1.0.0
*/
class Alliance_Post_Builder extends WP_Widget {

    public function __construct() {
    parent::__construct(
        'alliance_post_builder', // Base ID
        __( 'Alliance post builder', 'alliance' ), // Name
        array( 'description' => __( 'A post builder', 'alliance' ), ) // Args
    );
        $this->alt_option_name = 'widget_alliance_posts';

        add_action( 'save_post', array($this, 'flush_widget_cache') );
        add_action( 'deleted_post', array($this, 'flush_widget_cache') );
        add_action( 'switch_theme', array($this, 'flush_widget_cache') );
    }

    public function widget( $args, $instance ) {
        $cache = array();
        if ( ! $this->is_preview() ) {
            $cache = wp_cache_get( 'widget_alliance_build_posts', 'widget' );
        }

        if ( ! is_array( $cache ) ) {
            $cache = array();
        }

        if ( ! isset( $args['widget_id'] ) ) {
            $args['widget_id'] = $this->id;
        }

        if ( isset( $cache[ $args['widget_id'] ] ) ) {
            echo $cache[ $args['widget_id'] ];
            return;
        }

        ob_start();

        $title          = ( ! empty( $instance['title'] ) ) ? $instance['title'] : __( 'A new section', 'alliance' );
        /** This filter is documented in wp-includes/default-widgets.php */
        $title          = apply_filters( 'widget_title', $title, $instance, $this->id_base );
        $sectionID      = ( ! empty( $instance['sectionID'] ) ) ? $instance['sectionID'] : __( 'A new section', 'alliance' );
        $category       = $instance['category'];  


        ?><section id="<?php echo $sectionID; ?>"><?php

        echo $args['before_widget'];
        if ( $title ) {
            echo $args['before_title'] . $title . $args['after_title'];
        }               
        echo "SOMETHING IS MISSING HERE";

        echo $args['after_widget']; 

        ?></section><?php

        if ( ! $this->is_preview() ) {
            $cache[ $args['widget_id'] ] = ob_get_flush();
            wp_cache_set( 'widget_alliance_build_posts', $cache, 'widget' );
        } else {
            ob_end_flush();
        }
    }

    public function update( $new_instance, $old_instance ) {
        $instance                   = $old_instance;
        $instance['title']          = strip_tags( $new_instance['title'] );
        $instance['sectionID']      = strip_tags( $new_instance['sectionID'] );
        $instance['category']       = $new_instance['category'];
        $this->flush_widget_cache();

        $alloptions = wp_cache_get( 'alloptions', 'options' );
        if ( isset($alloptions['widget_alliance_posts']) )
            delete_option('widget_alliance_posts');

        return $instance;
    }

    public function flush_widget_cache() {
        wp_cache_delete('widget_alliance_build_posts', 'widget');
    }

    public function form( $instance ) {

        $title      = isset( $instance['title'] ) ? esc_attr( $instance['title'] ) : '';
        $sectionID  = isset( $instance['sectionID'] ) ? esc_attr( $instance['sectionID'] ) : '';
        $category   = isset( $instance['category'] ) ? $instance['category'] : -1;
        ?>

        <p>
            <label for="<?php echo $this->get_field_id( 'sectionID' ); ?>"><?php _e( 'Section Id:' ); ?></label> 
            <input class="widefat" id="<?php echo $this->get_field_id( 'sectionID' ); ?>" name="<?php echo $this->get_field_name( 'sectionID' ); ?>" type="text" value="<?php echo esc_attr( $sectionID ); ?>">
        </p>

        <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 $title; ?>" />
        </p>

        <p>
            <label for="<?php echo $this->get_field_id('category'); ?>"><?php _e( 'Category Name:' )?></label>
            <select id="<?php echo $this->get_field_id('category'); ?>" name="<?php echo $this->get_field_name('category'); ?>">
                <?php 
                $this->categories = get_categories();
                foreach ( $this->categories as $cat ) {
                    $selected = ( $cat->term_id == esc_attr( $category ) ) ? ' selected = "selected" ' : '';
                    $option = '<option '.$selected .'value="' . $cat->term_id;
                    $option = $option .'">';
                    $option = $option .$cat->name;
                    $option = $option .'</option>';
                    echo $option;
                }
                ?>
            </select>
        </p>

    <?php
    }

}

add_action( 'widgets_init', function () {
    register_widget( 'Alliance_Post_Builder' );
}); 
  • Thanks Peter. I will try this when I get home in a few hours. I did start with the widget API. That is where I got the bare bones for the widget. the version I had posted was after several hours of trying to figure out what was wrong. I did also try the get categories for the dropdown. After hours of trying, I succeeded with wp_dropdown_categories which is why I went with it. I appreciate your help and will study your working example to improve my code in the future. – Jamie Dec 22 '14 at 19:33
  • No problem. Take your time and test it properly. The choice is up to you if you want to use wp_dropdown_categories() or get_categories(). You need to use what you are comfortable with :-). I'm also off to be now. Enjoy – Pieter Goosen Dec 22 '14 at 19:37
  • No need to use esc_attr twice on variables in the form function. – developerbmw Aug 18 '15 at 20:56
0

I have the same issue with function widget($args, $instance). The problem is when I debug with var_dump($instance), it's array{} (empty array) and there are no values for widget settings.

So I forget that $instance variable and use the $this->get_settings() function to retrieve the settings of the widget. Works now. I hate the $instance variable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.