Saving widget gets an undefined variable

I am developing a widget for cached feeds. The widget itself works exactly as I want but I noticed that if I were to delete the widget and then add a new one (or simply just add a new one) on the first save I get an undefined variable error. This is in the admin Appearence->widgets section.

Notice: Undefined index: cached_feed1450-3 in D:\Sites\test.dev\wordpress\wp-admin\includes\ajax-actions.php on line 1578

It looks to me that this may be a WordPress issue since that line is:

if ( $form = $wp_registered_widget_controls[$widget_id] )

I guess they need to check isset

I am pasting my widget here to make sure that this isn't an issue with my widget but confirmation that this is a WordPress bug. I really hope its the latter...

Thanks for you help is identifying this issue.

EDIT:

This error only happens on when saving a new widget. It only seems to happen with my widget. When editing it's not an issue.

I have a bootstrap for loading the plugin. I use this add_action( 'widgets_init', array('BootStrap1450', 'addWidgets') ); in the

/**
 * Initialize the BootStrap
 */
public static function init() {
    require_once(A1450COM_LIBRARY_PATH.'Functions1450.php');

    // Initialize proper components (do not put into a hook!)
    if (is_admin()) {
        require_once(A1450COM_LIBRARY_PATH.'BackEnd1450.php');
    } else {
        require_once(A1450COM_LIBRARY_PATH.'FrontEnd1450.php');
        FrontEnd1450::init(); // Call manually
    }

    // Initiation of WP hook
    add_action( 'init', array('BootStrap1450', 'initWP') );
    add_action( 'widgets_init', array('BootStrap1450', 'addWidgets') );
} 

addWidgets is:

/**
 * Adds widgets
 */
public static function addWidgets() {
    include_once(A1450COM_WIDGETS_PATH.'CachedFeed1450.php');
}

The widget file then follows:

?php
/**
 * An RSS feed widget with cache controls
 * @package WordPress
 * @subpackage Cached Feed Widget
 * @author Jeremy
 */
class CachedFeed1450 extends WP_Widget {
    const TEXT_DOMAIN = 'cachedfeed';
    const COUNT_LIMIT = 20;

    /**
     * Register widget with WordPress.
     */
    public function __construct() {

        $widget_options = array(
            'description' = __( 'A cached feed widget that gives you custom settings per feed.', self::TEXT_DOMAIN )
        );

        $control_options = array(
            'width' = 300
        );

        parent::__construct(
            'cached_feed1450', // Base ID
            __('Cached Feed', self::TEXT_DOMAIN), // Name
            $widget_options,
            $control_options
        );
    }

    /**
     * Front-end display of widget.
     * *Currently only set for google news feed.
     * @todo Create a feed object to handle multiple feeds different data structures
     *
     * @see WP_Widget::widget()
     *
     * @param array $args     Widget arguments.
     * @param array $instance Saved values from database.
     */
    public function widget( $args, $instance ) {
        extract( $args );
        $title = apply_filters( 'widget_title', $instance['title'] );
        $feedURL = $instance['feed'];
        $count = absint($instance['count']);
        $showWidgetTitle = $instance['show_widget_title'];
        $showTitle = $instance['show_title'];
        $showContent = $instance['show_content'];
        $showAuthor = $instance['show_author'];
        $showDate = $instance['show_date'];
        $enableCache = $instance['enable_cache'];
        $cacheLifetime = $instance['cache_lifetime'];

        echo $before_widget;
        if ( $showWidgetTitle  !empty( $title ) ) {
            echo $before_title . $title . $after_title;
        }

        $results = self::getFeed($widget_id, $feedURL, $count);
        if (!empty($results)) {
            echo 'ul';
            // @todo Design a decent layout
            foreach($results as $feed) {
                echo 'li';

                if ($showTitle)
                    echo $feed-title;

                if ($showContent)
                    echo $feed-description;

                if ($showDate)
                    echo $feed-pubDate;

//                echo $feed-link;

                echo '/li';
            }
            echo '/ul';
        }
        echo $after_widget;
        return;
    }

    /**
     * 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.
     */
    public function update( $new_instance, $old_instance ) {

        $instance = $old_instance; // Sets defaults to old values
        $instance['title'] = strip_tags($new_instance['title']);
        $instance['feed'] = strip_tags($new_instance['feed']);
        $instance['count'] =  absint($new_instance['count']);
        $instance['show_title'] = !empty($new_instance['show_title']) ? '1' : '0';
        $instance['show_content'] = !empty($new_instance['show_content']) ? '1' : '0';
        $instance['show_author'] = !empty($new_instance['show_author']) ? '1' : '0';
        $instance['show_date'] = !empty($new_instance['show_date']) ? '1' : '0';
        $instance['enable_cache'] = !empty($new_instance['enable_cache']) ? '1' : '0';
        $instance['show_widget_title'] = !empty($new_instance['show_widget_title']) ? '1' : '0';
        $instance['cache_lifetime'] =  absint($new_instance['cache_lifetime']) * 60; // * 60 is to convert the seconds to minutes

        // Clean the array
        array_walk($instance, array(__CLASS__, 'trim'));

        // Fail-safe
        if (empty($instance['feed'])) {
            return false;
        }
        return $instance;
    }

    /**
     * Workaround to trim array on array_walk
     * @param $value
     */
    public static function trim($value) {
        $value = trim($value);
    }

    /**
     * Back-end widget form.
     *
     * @see WP_Widget::form()
     *
     * @param array $instance Previously saved values from database.
     */
    public function form( $instance ) {
        // Build data
        $title = !empty($instance[ 'title' ]) ? $instance[ 'title' ] : '';
        $feed = !empty($instance[ 'feed' ]) ? $instance[ 'feed' ] : '';
        $count = !empty($instance[ 'count' ]) ? $instance[ 'count' ] : 0;
        $cacheLifetime = !empty($instance[ 'cache_lifetime' ]) ? ($instance[ 'cache_lifetime' ] / 60) : 3600; // Default is 1 hour
        $showTitle = !empty($instance[ 'show_title' ]) ? true : false;
        $showContent = !empty($instance[ 'show_content' ]) ? true : false;
        $showAuthor = !empty($instance[ 'show_author' ]) ? true : false;
        $showDate = !empty($instance[ 'show_date' ]) ? true : false;
        $enableCache = !empty($instance[ 'enable_cache' ]) ? true : false;
        $showWidgetTitle = !empty($instance[ 'show_widget_title' ]) ? true : false;
        ?
        p
            label for="?php echo $this-get_field_id( 'feed' ); ?"?php _e( 'Feed URL:', self::TEXT_DOMAIN ); ?/label
            input class="widefat" id="?php echo $this-get_field_id( 'feed' ); ?" name="?php echo $this-get_field_name( 'feed' ); ?" type="text" value="?php echo esc_attr( $feed ); ?" /
        /p
        p
            label for="?php echo $this-get_field_id( 'title' ); ?"?php _e( 'Title: (optional)', self::TEXT_DOMAIN ); ?/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
        p
            input type="checkbox" id="?php echo $this-get_field_id( 'show_widget_title' ); ?" name="?php echo $this-get_field_name( 'show_widget_title' ); ?" value="1" ?php checked($showWidgetTitle, 1) ? /
            label for="?php echo $this-get_field_id( 'show_widget_title' ); ?"?php _e( 'Display the widget title?', self::TEXT_DOMAIN ); ?/label
        /p
        p
            label for="?php echo $this-get_field_id( 'count' ); ?"?php _e( 'How many items would you like to display?:', self::TEXT_DOMAIN ); ?/label
            select id="?php echo $this-get_field_id( 'count' ); ?" name="?php echo $this-get_field_name( 'count' ); ?" 
                ?php
                for($i=1; $i = self::COUNT_LIMIT; $i++) {
                    echo 'option value="'.$i.'" '.selected($i, $count, false).''.$i.'/option';
                }
                ?
            /select
        /p

        p
            input type="checkbox" id="?php echo $this-get_field_id( 'show_title' ); ?" name="?php echo $this-get_field_name( 'show_title' ); ?" value="1" ?php checked($showTitle, 1) ? /
            label for="?php echo $this-get_field_id( 'show_title' ); ?"?php _e( 'Display the item title?', self::TEXT_DOMAIN ); ?/label
        /p
        p
            input type="checkbox" id="?php echo $this-get_field_id( 'show_content' ); ?" name="?php echo $this-get_field_name( 'show_content' ); ?" value="1" ?php checked($showContent, 1) ? /
            label for="?php echo $this-get_field_id( 'show_content' ); ?"?php _e( 'Display item content?', self::TEXT_DOMAIN ); ?/label
        /p
        p
            input type="checkbox" id="?php echo $this-get_field_id( 'show_author' ); ?" name="?php echo $this-get_field_name( 'show_author' ); ?" value="1" ?php checked($showAuthor, 1) ? /
            label for="?php echo $this-get_field_id( 'show_author' ); ?"?php _e( 'Display item author if available?', self::TEXT_DOMAIN ); ?/label
        /p
        p
            input type="checkbox" id="?php echo $this-get_field_id( 'show_date' ); ?" name="?php echo $this-get_field_name( 'show_date' ); ?" value="1" ?php checked($showDate, 1) ? /
            label for="?php echo $this-get_field_id( 'show_date' ); ?"?php _e( 'Display item date?', self::TEXT_DOMAIN ); ?/label
        /p
        p
            input type="checkbox" id="?php echo $this-get_field_id( 'enable_cache' ); ?" name="?php echo $this-get_field_name( 'enable_cache' ); ?" value="1" ?php checked($enableCache, 1) ? class="cachedform-cache-toggle" /
            label for="?php echo $this-get_field_id( 'enable_cache' ); ?"?php _e( 'Enable Cache?', self::TEXT_DOMAIN ); ?/label
        /p
        p
            label for="?php echo $this-get_field_id( 'cache_lifetime' ); ?"?php _e( 'Cache lifetime:', self::TEXT_DOMAIN ); ?/label
            input id="?php echo $this-get_field_id( 'cache_lifetime' ); ?" name="?php echo $this-get_field_name( 'cache_lifetime' ); ?" type="text" value="?php echo esc_attr( $cacheLifetime ); ?" /
            span class="description"?php _e('In minutes', self::TEXT_DOMAIN); ?/span
        /p

        ?php
    }

    /**
     * Get the feed data
     * @param string $id
     * @param string $feed_url
     * @param int $limit
     * @param bool $sendRaw
     * @param null $cacheTime
     * @return array|SimpleXmlElement
     */
    private function getFeed($id, $feed_url, $limit = 0, $sendRaw = false, $cacheTime = 0) {
        if (empty($cacheTime)) {
            $cacheTime = 3600; // 1 hour cache by default
        }

        // Define cache file
        $cache_file = get_theme_root() . DIRECTORY_SEPARATOR . get_template() . DIRECTORY_SEPARATOR . 'cached-feed-'.$id.'.xml';

        // Check for cache
        $tmpFileModifiedDate = @filemtime($cache_file);
        $timedif = time() - $tmpFileModifiedDate;
        if (file_exists($cache_file)  $timedif  $cacheTime) {
            $string = file_get_contents($cache_file);
        } else {
            $string = @file_get_contents($feed_url);
            // Check if an error and attempt a quick fix
            if ($string === false) {
                $string = @file_get_contents(urlencode($feed_url));
            }
            if ($string === false) {
                trigger_error(__('Cached Feed Error - Fetch feed content', self::TEXT_DOMAIN));
                return false;
            }
            if ($string) {
                $f = fopen($cache_file, 'w');
                if ($f === false) {
                    trigger_error(__('Cached Feed Error - Failed to write to cache file', self::TEXT_DOMAIN));
                    return false; // Failed to write to file
                }
                if ($f) {
                    fwrite($f, $string, strlen($string));
                    fclose($f);
                }
            }
        }

        // Return empty array if no data
        if (!$string) {
            return array();
        }

        // Get content from XML
        $x = new SimpleXmlElement($string);
        if ($sendRaw) {
            return $x;
        }
        $entries = array();
        $i = 0;
        foreach ($x-channel-item as $entry) {
            if ($limit  0  $i = $limit) {
                continue;
            }
            $entries[] = $entry;
            $i++;
        }
//            die('pre'.print_r($entries, true).'/pre');
        return $entries;
    }
}
register_widget( 'CachedFeed' );

Topic bug bug-tracking widgets Wordpress

Category Web


I am willing to be that since you have not initialized the widgets pool it cannot be duplicated.

So within your main class or plugin file you would add this:

For Class:

add_action ( 'widgets_init', array (
    &$this,
    'my_widgets' 
) );

For .php file

add_action ( 'widgets_init', 'my_widgets');

then create your function

public function my_widgets(){
    register_widget ( 'CachedFeed' );
}

Of course don't forget to include your widget class.

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.