Don't like ads? PRO users don't see any ads ;-)
Guest

Alex Tingle

By: a guest on Nov 30th, 2008  |  syntax: PHP  |  size: 11.49 KB  |  hits: 4,984  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. <?php  if(!class_exists('MultiWidget')):
  2.  
  3. /*
  4. Copyright (c) 2008 Alex Tingle.
  5. (Based upon pattern for multi-widget, in Wordpress 2.6 wp-includes/widget.php.)
  6.  
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU General Public License
  9. as published by the Free Software Foundation; either version 2
  10. of the License, or (at your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  20. */
  21.  
  22.  
  23. /** This class wraps up lots of secret knowledge about how to make
  24.  *  Wordpress "multi" widgets. These are widgets that allow more than one
  25.  *  instance to be created. The standard "Text" widget is a simple example.
  26.  *
  27.  *  You must extend this class and over-ride three member functions.
  28.  *  Scroll to the bottom of the file for a fully working example.
  29.  */
  30. class MultiWidget
  31. {
  32.   //
  33.   // Interesting member variables.
  34.  
  35.   var $id_base;         ///< Root id for all widgets of this type.
  36.   var $name;            ///< Name for this widget type.
  37.   var $widget_options;  ///< Option array passed to wp_register_sidebar_widget()
  38.   var $control_options; ///< Option array passed to wp_register_widget_control()
  39.  
  40.   var $number =false; ///< Unique ID number of the current instance.
  41.   var $id =false; ///< Unique ID string of the current instance (id_base-number)
  42.  
  43.  
  44.   //
  45.   // Member functions that you must over-ride.
  46.  
  47.   /** Echo the actual widget content. Subclasses should over-ride this function
  48.    *  to generate their widget code. */
  49.   function widget($args,$instance)
  50.   {
  51.     die('function MultiWidget::widget() must be over-ridden in a sub-class.');
  52.   }
  53.  
  54.  
  55.   /** Update a particular instance.
  56.    *  This function should check that $new_instance is set correctly.
  57.    *  The newly calculated value of $instance should be returned. */
  58.   function control_update($new_instance, $old_instance)
  59.   {
  60.     die('function MultiWidget::control_update() must be over-ridden in a sub-class.');
  61.   }
  62.  
  63.  
  64.   /** Echo a control form for the current instance. */
  65.   function control_form($instance)
  66.   {
  67.     die('function MultiWidget::control_form() must be over-ridden in a sub-class.');
  68.   }
  69.  
  70.  
  71.   //
  72.   // Functions you'll need to call.
  73.  
  74.   /** CONSTRUCTOR
  75.    *   widget_options: passed to wp_register_sidebar_widget()
  76.    *   - description
  77.    *   - classname
  78.    *   control_options: passed to wp_register_widget_control()
  79.    *   - width
  80.    *   - height
  81.    */
  82.   function MultiWidget(
  83.       $id_base,
  84.       $name,
  85.       $widget_options = array(),
  86.       $control_options = array()
  87.     )
  88.   {
  89.     $this->id_base = $id_base;
  90.     $this->name = $name;
  91.     $this->option_name = 'multiwidget_'.$id_base;
  92.     $this->widget_options =
  93.       wp_parse_args( $widget_options, array('classname'=>$this->option_name) );
  94.     $this->control_options =
  95.       wp_parse_args( $control_options, array('id_base'=>$this->id_base) );
  96.     // Set true when we update the data after a POST submit - makes sure we
  97.     // don't do it twice.
  98.     $this->updated = false;
  99.   }
  100.  
  101.  
  102.   /** Helper function to be called by control_form().
  103.    *  Returns an HTML name for the field. */
  104.   function get_field_name($field_name)
  105.   {
  106.     return 'widget-'.$this->id_base.'['.$this->number.']['.$field_name.']';
  107.   }
  108.  
  109.  
  110.   /** Helper function to be called by control_form().
  111.    *  Returns an HTML id for the field. */
  112.   function get_field_id($field_name)
  113.   {
  114.     return 'widget-'.$this->id_base.'-'.$this->number.'-'.$field_name;
  115.   }
  116.  
  117.  
  118.   /** Registers this widget-type.
  119.    *  Must be called during the 'widget_init' action. */
  120.   function register()
  121.   {
  122.     if( !$all_instances = get_option($this->option_name) )
  123.       $all_instances = array();
  124.  
  125.     $registered = false;
  126.     foreach( array_keys($all_instances) as $number )
  127.     {
  128.       // Old widgets can have null values for some reason
  129.       if( !isset($all_instances[$number]['__multiwidget']) )
  130.         continue;
  131.       $this->_set($number);
  132.       $registered = true;
  133.       $this->_register_one($number);
  134.     }
  135.  
  136.     // If there are none, we register the widget's existance with a
  137.     // generic template
  138.     if( !$registered )
  139.     {
  140.       $this->_set(1);
  141.       $this->_register_one();
  142.     }
  143.   }
  144.  
  145.  
  146.   //
  147.   // PRIVATE FUNCTIONS. Don't worry about these.
  148.  
  149.   function _set($number)
  150.   {
  151.     $this->number = $number;
  152.     $this->id = $this->id_base.'-'.$number;
  153.   }
  154.  
  155.  
  156.   function _get_widget_callback()
  157.   {
  158.     return array(&$this,'widget_callback');
  159.   }
  160.  
  161.  
  162.   function _get_control_callback()
  163.   {
  164.     return array(&$this,'control_callback');
  165.   }
  166.  
  167.  
  168.   /** Generate the actual widget content.
  169.    *  Just finds the instance and calls widget().
  170.    *  Do NOT over-ride this function. */
  171.   function widget_callback($args, $widget_args = 1)
  172.   {
  173.     if( is_numeric($widget_args) )
  174.       $widget_args = array( 'number' => $widget_args );
  175.     $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
  176.     $this->_set( $widget_args['number'] );
  177.  
  178.     // Data is stored as array:
  179.     //  array( number => data for that instance of the widget, ... )
  180.     $all_instances = get_option($this->option_name);
  181.     if( isset($all_instances[$this->number]) )
  182.       $this->widget($args,$all_instances[$this->number]);
  183.   }
  184.  
  185.  
  186.   /** Deal with changed settings and generate the control form.
  187.    *  Do NOT over-ride this function. */
  188.   function control_callback($widget_args = 1)
  189.   {
  190.     global $wp_registered_widgets;
  191.  
  192.     if( is_numeric($widget_args) )
  193.       $widget_args = array( 'number' => $widget_args );
  194.     $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
  195.  
  196.     // Data is stored as array:
  197.     //  array( number => data for that instance of the widget, ... )
  198.     $all_instances = get_option($this->option_name);
  199.     if( !is_array($all_instances) )
  200.       $all_instances = array();
  201.  
  202.     // We need to update the data
  203.     if( !$this->updated && !empty($_POST['sidebar']) )
  204.     {
  205.       // Tells us what sidebar to put the data in
  206.       $sidebar = (string) $_POST['sidebar'];
  207.  
  208.       $sidebars_widgets = wp_get_sidebars_widgets();
  209.       if( isset($sidebars_widgets[$sidebar]) )
  210.         $this_sidebar =& $sidebars_widgets[$sidebar];
  211.       else
  212.         $this_sidebar = array();
  213.  
  214.       foreach( $this_sidebar as $_widget_id )
  215.       {
  216.         // Remove all widgets of this type from the sidebar.  We'll add the
  217.         // new data in a second.  This makes sure we don't get any duplicate
  218.         // data since widget ids aren't necessarily persistent across multiple
  219.         // updates
  220.         if( $this->_get_widget_callback() ==
  221.               $wp_registered_widgets[$_widget_id]['callback'] &&
  222.             isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) )
  223.         {
  224.           $number = $wp_registered_widgets[$_widget_id]['params'][0]['number'];
  225.           if( !in_array( $this->id_base.'-'.$number, $_POST['widget-id'] ) )
  226.           {
  227.             // the widget has been removed.
  228.             unset($all_instances[$number]);
  229.           }
  230.         }
  231.       }
  232.  
  233.       foreach( (array)$_POST['widget-'.$this->id_base] as $number=>$new_instance)
  234.       {
  235.         $this->_set($number);
  236.         if( isset($all_instances[$number]) )
  237.           $instance = $this->control_update($new_instance,$all_instances[$number]);
  238.         else
  239.           $instance = $this->control_update($new_instance,array());
  240.         if( !empty($instance) )
  241.         {
  242.           $instance['__multiwidget'] = $number;
  243.           $all_instances[$number] = $instance;
  244.         }
  245.       }
  246.  
  247.       update_option($this->option_name, $all_instances);
  248.       $this->updated = true; // So that we don't go through this more than once
  249.     }
  250.  
  251.     // Here we echo out the form
  252.     if( -1 == $widget_args['number'] )
  253.     {
  254.       // We echo out a template for a form which can be converted to a
  255.       // specific form later via JS
  256.       $this->_set('%i%');
  257.       $instance = array();
  258.     }
  259.     else
  260.     {
  261.       $this->_set($widget_args['number']);
  262.       $instance = $all_instances[ $widget_args['number'] ];
  263.     }
  264.     $this->control_form($instance);
  265.   }
  266.  
  267.  
  268.   /** Helper function: Registers a single instance. */
  269.   function _register_one($number = -1)
  270.   {
  271.     wp_register_sidebar_widget(
  272.         $this->id,
  273.         $this->name,
  274.         $this->_get_widget_callback(),
  275.         $this->widget_options,
  276.         array( 'number' => $number )
  277.       );
  278.     wp_register_widget_control(
  279.         $this->id,
  280.         $this->name,
  281.         $this->_get_control_callback(),
  282.         $this->control_options,
  283.         array( 'number' => $number )
  284.       );
  285.   }
  286.  
  287. } // end class MultiWidget
  288.  
  289.  
  290.  
  291. /*
  292.  
  293. //
  294. // Example MultiWidget. Use this as a template for your own.
  295. //
  296.  
  297. class ExampleMultiWidget extends MultiWidget
  298. {
  299.   function ExampleMultiWidget()
  300.   {
  301.     $this->MultiWidget(
  302.         'example-multi', // id_base
  303.         'ExampleMulti', // name
  304.         array('description'=>__('Widget which allows multiple instances'))
  305.       );
  306.   }
  307.  
  308.  
  309.   // Echo the actual widget content. Subclasses should over-ride this function
  310.   // to generate their widget code.
  311.   function widget($args,$instance)
  312.   {
  313.     extract($args,EXTR_SKIP);
  314.     echo $before_widget;
  315.     echo   $before_title . $instance['title'] . $after_title;
  316.     echo   $instance['content'];
  317.     echo $after_widget;
  318.   }
  319.  
  320.  
  321.   // Update a particular instance.
  322.   // This function should check that $new_instance is set correctly.
  323.   // The newly calculated value of $instance should be returned.
  324.   function control_update($new_instance, $old_instance)
  325.   {
  326.     if( !isset($new_instance['title']) ) // user clicked cancel
  327.         return false;
  328.     $instance = $old_instance;
  329.     $instance['title'] = wp_specialchars( $new_instance['title'] );
  330.     $instance['content'] = wp_specialchars( $new_instance['content'] );
  331.     return $instance;
  332.   }
  333.  
  334.  
  335.   // Echo a control form for the current instance.
  336.   // The form has inputs with names like widget-ID_BASE[$number][FIELD_NAME]
  337.   // so that all data for that instance of the widget are stored in one
  338.   // $_POST variable: $_POST['widget-ID_BASE'][$number]
  339.   function control_form($instance)
  340.   {
  341. ?>
  342.     <p>
  343.  
  344.      <label for="<?php echo $this->get_field_id('title') ?>">
  345.       <?php _e('Title:'); ?>
  346.       <input class="widefat" id="<?php echo $this->get_field_id('title') ?>"
  347.        name="<?php echo $this->get_field_name('title') ?>" type="text"
  348.        value="<?php echo htmlspecialchars($instance['title'],ENT_QUOTES) ?>" />
  349.      </label>
  350.  
  351.      <label for="<?php echo $this->get_field_id('content') ?>">
  352.       <?php _e('Content:'); ?>
  353.       <input class="widefat" id="<?php echo $this->get_field_id('content') ?>"
  354.        name="<?php echo $this->get_field_name('content') ?>" type="text"
  355.        value="<?php echo htmlspecialchars($instance['content'],ENT_QUOTES) ?>" />
  356.      </label>
  357.  
  358.      <input type="hidden" id="<?php echo $this->get_field_id('submit') ?>"
  359.       name="<?php echo $this->get_field_name('submit') ?>" value="1" />
  360.  
  361.     </p>
  362. <?php
  363.   }
  364.  
  365. } // end class ExampleMultiWidget
  366.  
  367.  
  368. // Finally create an object for the widget-type and register it.
  369. $example_multi = new ExampleMultiWidget();
  370. add_action( 'widgets_init', array($example_multi,'register') );
  371.  
  372. */
  373.  
  374. endif ?>