/*
Copyright (c) 2008 Alex Tingle.
(Based upon pattern for multi-widget, in Wordpress 2.6 wp-includes/widget.php.)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** This class wraps up lots of secret knowledge about how to make
* Wordpress "multi" widgets. These are widgets that allow more than one
* instance to be created. The standard "Text" widget is a simple example.
*
* You must extend this class and over-ride three member functions.
* Scroll to the bottom of the file for a fully working example.
*/
class MultiWidget
{
//
// Interesting member variables.
var $id_base; ///< Root id for all widgets of this type.
var $name; ///< Name for this widget type.
var $widget_options; ///< Option array passed to wp_register_sidebar_widget()
var $control_options; ///< Option array passed to wp_register_widget_control()
var $number =false; ///< Unique ID number of the current instance.
var $id =false; ///< Unique ID string of the current instance (id_base-number)
//
// Member functions that you must over-ride.
/** Echo the actual widget content. Subclasses should over-ride this function
* to generate their widget code. */
function widget($args,$instance)
{
die('function MultiWidget::widget() must be over-ridden in a sub-class.');
}
/** Update a particular instance.
* This function should check that $new_instance is set correctly.
* The newly calculated value of $instance should be returned. */
function control_update($new_instance, $old_instance)
{
die('function MultiWidget::control_update() must be over-ridden in a sub-class.');
}
/** Echo a control form for the current instance. */
function control_form($instance)
{
die('function MultiWidget::control_form() must be over-ridden in a sub-class.');
}
//
// Functions you'll need to call.
/** CONSTRUCTOR
* widget_options: passed to wp_register_sidebar_widget()
* - description
* - classname
* control_options: passed to wp_register_widget_control()
* - width
* - height
*/
function MultiWidget(
$id_base,
$name,
$widget_options = array(),
$control_options = array()
)
{
$this->id_base = $id_base;
$this->name = $name;
$this->option_name = 'multiwidget_'.$id_base;
$this->widget_options =
wp_parse_args
( $widget_options, array('classname'=>$this->option_name) );
$this->control_options =
wp_parse_args
( $control_options, array('id_base'=>$this->id_base) );
// Set true when we update the data after a POST submit - makes sure we
// don't do it twice.
$this->updated = false;
}
/** Helper function to be called by control_form().
* Returns an HTML name for the field. */
function get_field_name($field_name)
{
return 'widget-'.$this->id_base.'['.$this->number.']['.$field_name.']';
}
/** Helper function to be called by control_form().
* Returns an HTML id for the field. */
function get_field_id($field_name)
{
return 'widget-'.$this->id_base.'-'.$this->number.'-'.$field_name;
}
/** Registers this widget-type.
* Must be called during the 'widget_init' action. */
function register()
{
if( !$all_instances = get_option($this->option_name) )
$all_instances = array();
$registered = false;
{
// Old widgets can have null values for some reason
if( !isset($all_instances[$number]['__multiwidget']) )
continue;
$this->_set($number);
$registered = true;
$this->_register_one($number);
}
// If there are none, we register the widget's existance with a
// generic template
if( !$registered )
{
$this->_set(1);
$this->_register_one();
}
}
//
// PRIVATE FUNCTIONS. Don't worry about these.
function _set($number)
{
$this->number = $number;
$this->id = $this->id_base.'-'.$number;
}
function _get_widget_callback()
{
return array(&$this,'widget_callback');
}
function _get_control_callback()
{
return array(&$this,'control_callback');
}
/** Generate the actual widget content.
* Just finds the instance and calls widget().
* Do NOT over-ride this function. */
function widget_callback($args, $widget_args = 1)
{
$widget_args = array( 'number' => $widget_args );
$widget_args = wp_parse_args
( $widget_args, array( 'number' => -1
) );
$this->_set( $widget_args['number'] );
// Data is stored as array:
// array( number => data for that instance of the widget, ... )
$all_instances = get_option($this->option_name);
if( isset($all_instances[$this->number]) )
$this->widget($args,$all_instances[$this->number]);
}
/** Deal with changed settings and generate the control form.
* Do NOT over-ride this function. */
function control_callback($widget_args = 1)
{
global $wp_registered_widgets;
$widget_args = array( 'number' => $widget_args );
$widget_args = wp_parse_args
( $widget_args, array( 'number' => -1
) );
// Data is stored as array:
// array( number => data for that instance of the widget, ... )
$all_instances = get_option($this->option_name);
$all_instances = array();
// We need to update the data
if( !$this->updated && !empty($_POST['sidebar']) )
{
// Tells us what sidebar to put the data in
$sidebar = (string) $_POST['sidebar'];
$sidebars_widgets = wp_get_sidebars_widgets();
if( isset($sidebars_widgets[$sidebar]) )
$this_sidebar =& $sidebars_widgets[$sidebar];
else
foreach( $this_sidebar as $_widget_id )
{
// Remove all widgets of this type from the sidebar. We'll add the
// new data in a second. This makes sure we don't get any duplicate
// data since widget ids aren't necessarily persistent across multiple
// updates
if( $this->_get_widget_callback() ==
$wp_registered_widgets[$_widget_id]['callback'] &&
isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) )
{
$number = $wp_registered_widgets[$_widget_id]['params'][0]['number'];
if( !in_array( $this->id_base.'-'.$number, $_POST['widget-id'] ) )
{
// the widget has been removed.
unset($all_instances[$number]);
}
}
}
foreach( (array)$_POST['widget-'.$this->id_base] as $number=>$new_instance)
{
$this->_set($number);
if( isset($all_instances[$number]) )
$instance = $this->control_update($new_instance,$all_instances[$number]);
else
$instance = $this->control_update($new_instance,array());
{
$instance['__multiwidget'] = $number;
$all_instances[$number] = $instance;
}
}
update_option($this->option_name, $all_instances);
$this->updated = true; // So that we don't go through this more than once
}
// Here we echo out the form
if( -1 == $widget_args['number'] )
{
// We echo out a template for a form which can be converted to a
// specific form later via JS
$this->_set('%i%');
}
else
{
$this->_set($widget_args['number']);
$instance = $all_instances[ $widget_args['number'] ];
}
$this->control_form($instance);
}
/** Helper function: Registers a single instance. */
function _register_one($number = -1)
{
wp_register_sidebar_widget(
$this->id,
$this->name,
$this->_get_widget_callback(),
$this->widget_options,
array( 'number' => $number )
);
wp_register_widget_control(
$this->id,
$this->name,
$this->_get_control_callback(),
$this->control_options,
array( 'number' => $number )
);
}
} // end class MultiWidget
/*
//
// Example MultiWidget. Use this as a template for your own.
//
class ExampleMultiWidget extends MultiWidget
{
function ExampleMultiWidget()
{
$this->MultiWidget(
'example-multi', // id_base
'ExampleMulti', // name
array('description'=>__('Widget which allows multiple instances'))
);
}
// Echo the actual widget content. Subclasses should over-ride this function
// to generate their widget code.
function widget($args,$instance)
{
extract($args,EXTR_SKIP);
echo $before_widget;
echo $before_title . $instance['title'] . $after_title;
echo $instance['content'];
echo $after_widget;
}
// Update a particular instance.
// This function should check that $new_instance is set correctly.
// The newly calculated value of $instance should be returned.
function control_update($new_instance, $old_instance)
{
if( !isset($new_instance['title']) ) // user clicked cancel
return false;
$instance = $old_instance;
$instance['title'] = wp_specialchars( $new_instance['title'] );
$instance['content'] = wp_specialchars( $new_instance['content'] );
return $instance;
}
// Echo a control form for the current instance.
// The form has inputs with names like widget-ID_BASE[$number][FIELD_NAME]
// so that all data for that instance of the widget are stored in one
// $_POST variable: $_POST['widget-ID_BASE'][$number]
function control_form($instance)
{
?>
<p>
<label for="<?php echo $this->get_field_id('title') ?>">
<?php _e('Title:'); ?>
<input class="widefat" id="<?php echo $this->get_field_id('title') ?>"
name="<?php echo $this->get_field_name('title') ?>" type="text"
</label>
<label for="<?php echo $this->get_field_id('content') ?>">
<?php _e('Content:'); ?>
<input class="widefat" id="<?php echo $this->get_field_id('content') ?>"
name="<?php echo $this->get_field_name('content') ?>" type="text"
</label>
<input type="hidden" id="<?php echo $this->get_field_id('submit') ?>"
name="<?php echo $this->get_field_name('submit') ?>" value="1" />
</p>
<?php
}
} // end class ExampleMultiWidget
// Finally create an object for the widget-type and register it.
$example_multi = new ExampleMultiWidget();
add_action
( 'widgets_init', array($example_multi,'register') );
*/
endif ?>