Changeset 33746 for trunk/src/wp-includes/widget-functions.php
- Timestamp:
- 08/26/2015 02:39:50 AM (9 years ago)
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/widget-functions.php
r33745 r33746 1 1 <?php 2 2 /** 3 * API for creating dynamic sidebar without hardcoding functionality into4 * themes. Includes both internal WordPress routines and theme use routines.5 *6 * This functionality was found in a plugin before WordPress 2.2 release which7 * included it in the core from that point on.8 *9 * @link https://codex.wordpress.org/Plugins/WordPress_Widgets WordPress Widgets10 * @link https://codex.wordpress.org/Plugins/WordPress_Widgets_Api Widgets API11 *12 3 * @package WordPress 13 4 * @subpackage Widgets 14 5 */ 15 16 /**17 * This class must be extended for each widget and WP_Widget::widget(), WP_Widget::update()18 * and WP_Widget::form() need to be over-ridden.19 *20 * @package WordPress21 * @subpackage Widgets22 * @since 2.8.023 */24 class WP_Widget {25 26 /**27 * Root ID for all widgets of this type.28 *29 * @since 2.8.030 * @access public31 * @var mixed|string32 */33 public $id_base;34 35 /**36 * Name for this widget type.37 *38 * @since 2.8.039 * @access public40 * @var string41 */42 public $name;43 44 /**45 * Option array passed to {@see wp_register_sidebar_widget()}.46 *47 * @since 2.8.048 * @access public49 * @var array50 */51 public $widget_options;52 53 /**54 * Option array passed to {@see wp_register_widget_control()}.55 *56 * @since 2.8.057 * @access public58 * @var array59 */60 public $control_options;61 62 /**63 * Unique ID number of the current instance.64 *65 * @since 2.8.066 * @access public67 * @var bool|int68 */69 public $number = false;70 71 /**72 * Unique ID string of the current instance (id_base-number).73 *74 * @since 2.8.075 * @access public76 * @var bool|string77 */78 public $id = false;79 80 /**81 * Whether the widget data has been updated.82 *83 * Set to true when the data is updated after a POST submit - ensures it does84 * not happen twice.85 *86 * @since 2.8.087 * @access public88 * @var bool89 */90 public $updated = false;91 92 // Member functions that you must over-ride.93 94 /**95 * Echo the widget content.96 *97 * Subclasses should over-ride this function to generate their widget code.98 *99 * @since 2.8.0100 * @access public101 *102 * @param array $args Display arguments including before_title, after_title,103 * before_widget, and after_widget.104 * @param array $instance The settings for the particular instance of the widget.105 */106 public function widget( $args, $instance ) {107 die('function WP_Widget::widget() must be over-ridden in a sub-class.');108 }109 110 /**111 * Update a particular instance.112 *113 * This function should check that $new_instance is set correctly. The newly-calculated114 * value of `$instance` should be returned. If false is returned, the instance won't be115 * saved/updated.116 *117 * @since 2.8.0118 * @access public119 *120 * @param array $new_instance New settings for this instance as input by the user via121 * {@see WP_Widget::form()}.122 * @param array $old_instance Old settings for this instance.123 * @return array Settings to save or bool false to cancel saving.124 */125 public function update( $new_instance, $old_instance ) {126 return $new_instance;127 }128 129 /**130 * Output the settings update form.131 *132 * @since 2.8.0133 * @access public134 *135 * @param array $instance Current settings.136 * @return string Default return is 'noform'.137 */138 public function form($instance) {139 echo '<p class="no-options-widget">' . __('There are no options for this widget.') . '</p>';140 return 'noform';141 }142 143 // Functions you'll need to call.144 145 /**146 * PHP5 constructor.147 *148 * @since 2.8.0149 * @access public150 *151 * @param string $id_base Optional Base ID for the widget, lowercase and unique. If left empty,152 * a portion of the widget's class name will be used Has to be unique.153 * @param string $name Name for the widget displayed on the configuration page.154 * @param array $widget_options Optional. Widget options. See {@see wp_register_sidebar_widget()} for155 * information on accepted arguments. Default empty array.156 * @param array $control_options Optional. Widget control options. See {@see wp_register_widget_control()}157 * for information on accepted arguments. Default empty array.158 */159 public function __construct( $id_base, $name, $widget_options = array(), $control_options = array() ) {160 $this->id_base = empty($id_base) ? preg_replace( '/(wp_)?widget_/', '', strtolower(get_class($this)) ) : strtolower($id_base);161 $this->name = $name;162 $this->option_name = 'widget_' . $this->id_base;163 $this->widget_options = wp_parse_args( $widget_options, array('classname' => $this->option_name) );164 $this->control_options = wp_parse_args( $control_options, array('id_base' => $this->id_base) );165 }166 167 /**168 * PHP4 constructor169 *170 * @param string $id_base171 * @param string $name172 * @param array $widget_options173 * @param array $control_options174 */175 public function WP_Widget( $id_base, $name, $widget_options = array(), $control_options = array() ) {176 _deprecated_constructor( 'WP_Widget', '4.3.0' );177 WP_Widget::__construct( $id_base, $name, $widget_options, $control_options );178 }179 180 /**181 * Constructs name attributes for use in form() fields182 *183 * This function should be used in form() methods to create name attributes for fields to be saved by update()184 *185 * @param string $field_name Field name186 * @return string Name attribute for $field_name187 */188 public function get_field_name($field_name) {189 return 'widget-' . $this->id_base . '[' . $this->number . '][' . $field_name . ']';190 }191 192 /**193 * Constructs id attributes for use in {@see WP_Widget::form()} fields.194 *195 * This function should be used in form() methods to create id attributes196 * for fields to be saved by {@see WP_Widget::update()}.197 *198 * @since 2.8.0199 * @access public200 *201 * @param string $field_name Field name.202 * @return string ID attribute for `$field_name`.203 */204 public function get_field_id( $field_name ) {205 return 'widget-' . $this->id_base . '-' . $this->number . '-' . $field_name;206 }207 208 /**209 * Register all widget instances of this widget class.210 *211 * @since 2.8.0212 * @access private213 */214 public function _register() {215 $settings = $this->get_settings();216 $empty = true;217 218 // When $settings is an array-like object, get an intrinsic array for use with array_keys().219 if ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) {220 $settings = $settings->getArrayCopy();221 }222 223 if ( is_array( $settings ) ) {224 foreach ( array_keys( $settings ) as $number ) {225 if ( is_numeric( $number ) ) {226 $this->_set( $number );227 $this->_register_one( $number );228 $empty = false;229 }230 }231 }232 233 if ( $empty ) {234 // If there are none, we register the widget's existence with a generic template.235 $this->_set( 1 );236 $this->_register_one();237 }238 }239 240 /**241 * Set the internal order number for the widget instance.242 *243 * @since 2.8.0244 * @access private245 *246 * @param int $number The unique order number of this widget instance compared to other247 * instances of the same class.248 */249 public function _set($number) {250 $this->number = $number;251 $this->id = $this->id_base . '-' . $number;252 }253 254 /**255 * @return callback256 */257 public function _get_display_callback() {258 return array($this, 'display_callback');259 }260 /**261 * @return callback262 */263 public function _get_update_callback() {264 return array($this, 'update_callback');265 }266 /**267 * @return callback268 */269 public function _get_form_callback() {270 return array($this, 'form_callback');271 }272 273 /**274 * Determine whether the current request is inside the Customizer preview.275 *276 * If true -- the current request is inside the Customizer preview, then277 * the object cache gets suspended and widgets should check this to decide278 * whether they should store anything persistently to the object cache,279 * to transients, or anywhere else.280 *281 * @since 3.9.0282 * @access public283 *284 * @global WP_Customize_Manager $wp_customize285 *286 * @return bool True if within the Customizer preview, false if not.287 */288 public function is_preview() {289 global $wp_customize;290 return ( isset( $wp_customize ) && $wp_customize->is_preview() ) ;291 }292 293 /**294 * Generate the actual widget content (Do NOT override).295 *296 * Finds the instance and calls {@see WP_Widget::widget()}.297 *298 * @since 2.8.0299 * @access public300 *301 * @param array $args Display arguments. See {@see WP_Widget::widget()} for information302 * on accepted arguments.303 * @param int|array $widget_args {304 * Optional. Internal order number of the widget instance, or array of multi-widget arguments.305 * Default 1.306 *307 * @type int $number Number increment used for multiples of the same widget.308 * }309 */310 public function display_callback( $args, $widget_args = 1 ) {311 if ( is_numeric( $widget_args ) ) {312 $widget_args = array( 'number' => $widget_args );313 }314 315 $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );316 $this->_set( $widget_args['number'] );317 $instances = $this->get_settings();318 319 if ( array_key_exists( $this->number, $instances ) ) {320 $instance = $instances[ $this->number ];321 322 /**323 * Filter the settings for a particular widget instance.324 *325 * Returning false will effectively short-circuit display of the widget.326 *327 * @since 2.8.0328 *329 * @param array $instance The current widget instance's settings.330 * @param WP_Widget $this The current widget instance.331 * @param array $args An array of default widget arguments.332 */333 $instance = apply_filters( 'widget_display_callback', $instance, $this, $args );334 335 if ( false === $instance ) {336 return;337 }338 339 $was_cache_addition_suspended = wp_suspend_cache_addition();340 if ( $this->is_preview() && ! $was_cache_addition_suspended ) {341 wp_suspend_cache_addition( true );342 }343 344 $this->widget( $args, $instance );345 346 if ( $this->is_preview() ) {347 wp_suspend_cache_addition( $was_cache_addition_suspended );348 }349 }350 }351 352 /**353 * Deal with changed settings (Do NOT override).354 *355 * @since 2.8.0356 * @access public357 *358 * @global array $wp_registered_widgets359 *360 * @param int $deprecated Not used.361 */362 public function update_callback( $deprecated = 1 ) {363 global $wp_registered_widgets;364 365 $all_instances = $this->get_settings();366 367 // We need to update the data368 if ( $this->updated )369 return;370 371 if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {372 // Delete the settings for this instance of the widget373 if ( isset($_POST['the-widget-id']) )374 $del_id = $_POST['the-widget-id'];375 else376 return;377 378 if ( isset($wp_registered_widgets[$del_id]['params'][0]['number']) ) {379 $number = $wp_registered_widgets[$del_id]['params'][0]['number'];380 381 if ( $this->id_base . '-' . $number == $del_id )382 unset($all_instances[$number]);383 }384 } else {385 if ( isset($_POST['widget-' . $this->id_base]) && is_array($_POST['widget-' . $this->id_base]) ) {386 $settings = $_POST['widget-' . $this->id_base];387 } elseif ( isset($_POST['id_base']) && $_POST['id_base'] == $this->id_base ) {388 $num = $_POST['multi_number'] ? (int) $_POST['multi_number'] : (int) $_POST['widget_number'];389 $settings = array( $num => array() );390 } else {391 return;392 }393 394 foreach ( $settings as $number => $new_instance ) {395 $new_instance = stripslashes_deep($new_instance);396 $this->_set($number);397 398 $old_instance = isset($all_instances[$number]) ? $all_instances[$number] : array();399 400 $was_cache_addition_suspended = wp_suspend_cache_addition();401 if ( $this->is_preview() && ! $was_cache_addition_suspended ) {402 wp_suspend_cache_addition( true );403 }404 405 $instance = $this->update( $new_instance, $old_instance );406 407 if ( $this->is_preview() ) {408 wp_suspend_cache_addition( $was_cache_addition_suspended );409 }410 411 /**412 * Filter a widget's settings before saving.413 *414 * Returning false will effectively short-circuit the widget's ability415 * to update settings.416 *417 * @since 2.8.0418 *419 * @param array $instance The current widget instance's settings.420 * @param array $new_instance Array of new widget settings.421 * @param array $old_instance Array of old widget settings.422 * @param WP_Widget $this The current widget instance.423 */424 $instance = apply_filters( 'widget_update_callback', $instance, $new_instance, $old_instance, $this );425 if ( false !== $instance ) {426 $all_instances[$number] = $instance;427 }428 429 break; // run only once430 }431 }432 433 $this->save_settings($all_instances);434 $this->updated = true;435 }436 437 /**438 * Generate the widget control form (Do NOT override).439 *440 * @since 2.8.0441 * @access public442 *443 * @param int|array $widget_args Widget instance number or array of widget arguments.444 * @return string|null445 */446 public function form_callback( $widget_args = 1 ) {447 if ( is_numeric($widget_args) )448 $widget_args = array( 'number' => $widget_args );449 450 $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );451 $all_instances = $this->get_settings();452 453 if ( -1 == $widget_args['number'] ) {454 // We echo out a form where 'number' can be set later455 $this->_set('__i__');456 $instance = array();457 } else {458 $this->_set($widget_args['number']);459 $instance = $all_instances[ $widget_args['number'] ];460 }461 462 /**463 * Filter the widget instance's settings before displaying the control form.464 *465 * Returning false effectively short-circuits display of the control form.466 *467 * @since 2.8.0468 *469 * @param array $instance The current widget instance's settings.470 * @param WP_Widget $this The current widget instance.471 */472 $instance = apply_filters( 'widget_form_callback', $instance, $this );473 474 $return = null;475 if ( false !== $instance ) {476 $return = $this->form($instance);477 478 /**479 * Fires at the end of the widget control form.480 *481 * Use this hook to add extra fields to the widget form. The hook482 * is only fired if the value passed to the 'widget_form_callback'483 * hook is not false.484 *485 * Note: If the widget has no form, the text echoed from the default486 * form method can be hidden using CSS.487 *488 * @since 2.8.0489 *490 * @param WP_Widget $this The widget instance, passed by reference.491 * @param null $return Return null if new fields are added.492 * @param array $instance An array of the widget's settings.493 */494 do_action_ref_array( 'in_widget_form', array( &$this, &$return, $instance ) );495 }496 return $return;497 }498 499 /**500 * Register an instance of the widget class.501 *502 * @since 2.8.0503 * @access private504 *505 * @param integer $number Optional. The unique order number of this widget instance506 * compared to other instances of the same class. Default -1.507 */508 public function _register_one( $number = -1 ) {509 wp_register_sidebar_widget( $this->id, $this->name, $this->_get_display_callback(), $this->widget_options, array( 'number' => $number ) );510 _register_widget_update_callback( $this->id_base, $this->_get_update_callback(), $this->control_options, array( 'number' => -1 ) );511 _register_widget_form_callback( $this->id, $this->name, $this->_get_form_callback(), $this->control_options, array( 'number' => $number ) );512 }513 514 /**515 * Save the settings for all instances of the widget class.516 *517 * @since 2.8.0518 * @access public519 *520 * @param array $settings Multi-dimensional array of widget instance settings.521 */522 public function save_settings( $settings ) {523 $settings['_multiwidget'] = 1;524 update_option( $this->option_name, $settings );525 }526 527 /**528 * Get the settings for all instances of the widget class.529 *530 * @since 2.8.0531 * @access public532 *533 * @return array Multi-dimensional array of widget instance settings.534 */535 public function get_settings() {536 537 $settings = get_option( $this->option_name );538 539 if ( false === $settings && isset( $this->alt_option_name ) ) {540 $settings = get_option( $this->alt_option_name );541 }542 543 if ( ! is_array( $settings ) && ! ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) ) {544 $settings = array();545 }546 547 if ( ! empty( $settings ) && ! isset( $settings['_multiwidget'] ) ) {548 // Old format, convert if single widget.549 $settings = wp_convert_widget_settings( $this->id_base, $this->option_name, $settings );550 }551 552 unset( $settings['_multiwidget'], $settings['__i__'] );553 return $settings;554 }555 }556 557 /**558 * Singleton that registers and instantiates WP_Widget classes.559 *560 * @package WordPress561 * @subpackage Widgets562 * @since 2.8.0563 */564 class WP_Widget_Factory {565 public $widgets = array();566 567 /**568 * PHP5 constructor.569 */570 public function __construct() {571 add_action( 'widgets_init', array( $this, '_register_widgets' ), 100 );572 }573 574 /**575 * PHP4 constructor.576 */577 public function WP_Widget_Factory() {578 _deprecated_constructor( 'WP_Widget_Factory', '4.2.0' );579 self::__construct();580 }581 582 /**583 * Register a widget subclass.584 *585 * @since 2.8.0586 * @access public587 *588 * @param string $widget_class The name of a {@see WP_Widget} subclass.589 */590 public function register( $widget_class ) {591 $this->widgets[$widget_class] = new $widget_class();592 }593 594 /**595 * Un-register a widget subclass.596 *597 * @since 2.8.0598 * @access public599 *600 * @param string $widget_class The name of a {@see WP_Widget} subclass.601 */602 public function unregister( $widget_class ) {603 unset( $this->widgets[ $widget_class ] );604 }605 606 /**607 * Utility method for adding widgets to the registered widgets global.608 *609 * @since 2.8.0610 * @access public611 *612 * @global array $wp_registered_widgets613 */614 public function _register_widgets() {615 global $wp_registered_widgets;616 $keys = array_keys($this->widgets);617 $registered = array_keys($wp_registered_widgets);618 $registered = array_map('_get_widget_id_base', $registered);619 620 foreach ( $keys as $key ) {621 // don't register new widget if old widget with the same id is already registered622 if ( in_array($this->widgets[$key]->id_base, $registered, true) ) {623 unset($this->widgets[$key]);624 continue;625 }626 627 $this->widgets[$key]->_register();628 }629 }630 }631 632 /* Global Variables */633 634 /** @ignore */635 global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;636 637 /**638 * Stores the sidebars, since many themes can have more than one.639 *640 * @global array $wp_registered_sidebars641 * @since 2.2.0642 */643 $wp_registered_sidebars = array();644 645 /**646 * Stores the registered widgets.647 *648 * @global array $wp_registered_widgets649 * @since 2.2.0650 */651 $wp_registered_widgets = array();652 653 /**654 * Stores the registered widget control (options).655 *656 * @global array $wp_registered_widget_controls657 * @since 2.2.0658 */659 $wp_registered_widget_controls = array();660 /**661 * @global array $wp_registered_widget_updates662 */663 $wp_registered_widget_updates = array();664 665 /**666 * Private667 *668 * @global array $_wp_sidebars_widgets669 */670 $_wp_sidebars_widgets = array();671 672 /**673 * Private674 *675 * @global array $_wp_deprecated_widgets_callbacks676 */677 $GLOBALS['_wp_deprecated_widgets_callbacks'] = array(678 'wp_widget_pages',679 'wp_widget_pages_control',680 'wp_widget_calendar',681 'wp_widget_calendar_control',682 'wp_widget_archives',683 'wp_widget_archives_control',684 'wp_widget_links',685 'wp_widget_meta',686 'wp_widget_meta_control',687 'wp_widget_search',688 'wp_widget_recent_entries',689 'wp_widget_recent_entries_control',690 'wp_widget_tag_cloud',691 'wp_widget_tag_cloud_control',692 'wp_widget_categories',693 'wp_widget_categories_control',694 'wp_widget_text',695 'wp_widget_text_control',696 'wp_widget_rss',697 'wp_widget_rss_control',698 'wp_widget_recent_comments',699 'wp_widget_recent_comments_control'700 );701 6 702 7 /* Template tags & API functions */
Note: See TracChangeset
for help on using the changeset viewer.