| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Widget API: WP_Widget base class 4 * 5 * @package WordPress 6 * @subpackage Widgets 7 * @since 4.4.0 8 */ 9 10 /** 11 * Core base class extended to register widgets. 12 * 13 * This class must be extended for each widget, and WP_Widget::widget() must be overridden. 14 * 15 * If adding widget options, WP_Widget::update() and WP_Widget::form() should also be overridden. 16 * 17 * @since 2.8.0 18 * @since 4.4.0 Moved to its own file from wp-includes/widgets.php 19 */ 20 #[AllowDynamicProperties] 21 class WP_Widget { 22 23 /** 24 * Root ID for all widgets of this type. 25 * 26 * @since 2.8.0 27 * @var mixed|string 28 */ 29 public $id_base; 30 31 /** 32 * Name for this widget type. 33 * 34 * @since 2.8.0 35 * @var string 36 */ 37 public $name; 38 39 /** 40 * Option name for this widget type. 41 * 42 * @since 2.8.0 43 * @var string 44 */ 45 public $option_name; 46 47 /** 48 * Alt option name for this widget type. 49 * 50 * @since 2.8.0 51 * @var string 52 */ 53 public $alt_option_name; 54 55 /** 56 * Option array passed to wp_register_sidebar_widget(). 57 * 58 * @since 2.8.0 59 * @var array 60 */ 61 public $widget_options; 62 63 /** 64 * Option array passed to wp_register_widget_control(). 65 * 66 * @since 2.8.0 67 * @var array 68 */ 69 public $control_options; 70 71 /** 72 * Unique ID number of the current instance. 73 * 74 * @since 2.8.0 75 * @var bool|int 76 */ 77 public $number = false; 78 79 /** 80 * Unique ID string of the current instance (id_base-number). 81 * 82 * @since 2.8.0 83 * @var bool|string 84 */ 85 public $id = false; 86 87 /** 88 * Whether the widget data has been updated. 89 * 90 * Set to true when the data is updated after a POST submit - ensures it does 91 * not happen twice. 92 * 93 * @since 2.8.0 94 * @var bool 95 */ 96 public $updated = false; 97 98 // 99 // Member functions that must be overridden by subclasses. 100 // 101 102 /** 103 * Echoes the widget content. 104 * 105 * Subclasses should override this function to generate their widget code. 106 * 107 * @since 2.8.0 108 * 109 * @param array $args Display arguments including 'before_title', 'after_title', 110 * 'before_widget', and 'after_widget'. 111 * @param array $instance The settings for the particular instance of the widget. 112 */ 113 public function widget( $args, $instance ) { 114 die( 'function WP_Widget::widget() must be overridden in a subclass.' ); 115 } 116 117 /** 118 * Updates a particular instance of a widget. 119 * 120 * This function should check that `$new_instance` is set correctly. The newly-calculated 121 * value of `$instance` should be returned. If false is returned, the instance won't be 122 * saved/updated. 123 * 124 * @since 2.8.0 125 * 126 * @param array $new_instance New settings for this instance as input by the user via 127 * WP_Widget::form(). 128 * @param array $old_instance Old settings for this instance. 129 * @return array Settings to save or bool false to cancel saving. 130 */ 131 public function update( $new_instance, $old_instance ) { 132 return $new_instance; 133 } 134 135 /** 136 * Outputs the settings update form. 137 * 138 * @since 2.8.0 139 * 140 * @param array $instance The settings for the particular instance of the widget. 141 * @return string|void Default return is 'noform'. A subclass which echoes its own 142 * form returns nothing. 143 */ 144 public function form( $instance ) { 145 echo '<p class="no-options-widget">' . __( 'There are no options for this widget.' ) . '</p>'; 146 return 'noform'; 147 } 148 149 // Functions you'll need to call. 150 151 /** 152 * PHP5 constructor. 153 * 154 * @since 2.8.0 155 * 156 * @param string $id_base Base ID for the widget, lowercase and unique. If left empty, 157 * a portion of the widget's PHP class name will be used. Has to be unique. 158 * @param string $name Name for the widget displayed on the configuration page. 159 * @param array $widget_options Optional. Widget options. See wp_register_sidebar_widget() for 160 * information on accepted arguments. Default empty array. 161 * @param array $control_options Optional. Widget control options. See wp_register_widget_control() for 162 * information on accepted arguments. Default empty array. 163 */ 164 public function __construct( $id_base, $name, $widget_options = array(), $control_options = array() ) { 165 if ( ! empty( $id_base ) ) { 166 $id_base = strtolower( $id_base ); 167 } else { 168 $id_base = preg_replace( '/(wp_)?widget_/', '', strtolower( get_class( $this ) ) ); 169 } 170 171 $this->id_base = $id_base; 172 $this->name = $name; 173 $this->option_name = 'widget_' . $this->id_base; 174 $this->widget_options = wp_parse_args( 175 $widget_options, 176 array( 177 'classname' => str_replace( '\\', '_', $this->option_name ), 178 'customize_selective_refresh' => false, 179 ) 180 ); 181 $this->control_options = wp_parse_args( $control_options, array( 'id_base' => $this->id_base ) ); 182 } 183 184 /** 185 * PHP4 constructor. 186 * 187 * @since 2.8.0 188 * @deprecated 4.3.0 Use __construct() instead. 189 * 190 * @see WP_Widget::__construct() 191 * 192 * @param string $id_base Base ID for the widget, lowercase and unique. If left empty, 193 * a portion of the widget's PHP class name will be used. Has to be unique. 194 * @param string $name Name for the widget displayed on the configuration page. 195 * @param array $widget_options Optional. Widget options. See wp_register_sidebar_widget() for 196 * information on accepted arguments. Default empty array. 197 * @param array $control_options Optional. Widget control options. See wp_register_widget_control() for 198 * information on accepted arguments. Default empty array. 199 */ 200 public function WP_Widget( $id_base, $name, $widget_options = array(), $control_options = array() ) { 201 _deprecated_constructor( 'WP_Widget', '4.3.0', get_class( $this ) ); 202 WP_Widget::__construct( $id_base, $name, $widget_options, $control_options ); 203 } 204 205 /** 206 * Constructs name attributes for use in form() fields 207 * 208 * This function should be used in form() methods to create name attributes for fields 209 * to be saved by update() 210 * 211 * @since 2.8.0 212 * @since 4.4.0 Array format field names are now accepted. 213 * 214 * @param string $field_name Field name. 215 * @return string Name attribute for `$field_name`. 216 */ 217 public function get_field_name( $field_name ) { 218 $pos = strpos( $field_name, '[' ); 219 220 if ( false !== $pos ) { 221 // Replace the first occurrence of '[' with ']['. 222 $field_name = '[' . substr_replace( $field_name, '][', $pos, strlen( '[' ) ); 223 } else { 224 $field_name = '[' . $field_name . ']'; 225 } 226 227 return 'widget-' . $this->id_base . '[' . $this->number . ']' . $field_name; 228 } 229 230 /** 231 * Constructs id attributes for use in WP_Widget::form() fields. 232 * 233 * This function should be used in form() methods to create id attributes 234 * for fields to be saved by WP_Widget::update(). 235 * 236 * @since 2.8.0 237 * @since 4.4.0 Array format field IDs are now accepted. 238 * 239 * @param string $field_name Field name. 240 * @return string ID attribute for `$field_name`. 241 */ 242 public function get_field_id( $field_name ) { 243 $field_name = str_replace( array( '[]', '[', ']' ), array( '', '-', '' ), $field_name ); 244 $field_name = trim( $field_name, '-' ); 245 246 return 'widget-' . $this->id_base . '-' . $this->number . '-' . $field_name; 247 } 248 249 /** 250 * Register all widget instances of this widget class. 251 * 252 * @since 2.8.0 253 */ 254 public function _register() { 255 $settings = $this->get_settings(); 256 $empty = true; 257 258 // When $settings is an array-like object, get an intrinsic array for use with array_keys(). 259 if ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) { 260 $settings = $settings->getArrayCopy(); 261 } 262 263 if ( is_array( $settings ) ) { 264 foreach ( array_keys( $settings ) as $number ) { 265 if ( is_numeric( $number ) ) { 266 $this->_set( $number ); 267 $this->_register_one( $number ); 268 $empty = false; 269 } 270 } 271 } 272 273 if ( $empty ) { 274 // If there are none, we register the widget's existence with a generic template. 275 $this->_set( 1 ); 276 $this->_register_one(); 277 } 278 } 279 280 /** 281 * Sets the internal order number for the widget instance. 282 * 283 * @since 2.8.0 284 * 285 * @param int $number The unique order number of this widget instance compared to other 286 * instances of the same class. 287 */ 288 public function _set( $number ) { 289 $this->number = $number; 290 $this->id = $this->id_base . '-' . $number; 291 } 292 293 /** 294 * Retrieves the widget display callback. 295 * 296 * @since 2.8.0 297 * 298 * @return callable Display callback. 299 */ 300 public function _get_display_callback() { 301 return array( $this, 'display_callback' ); 302 } 303 304 /** 305 * Retrieves the widget update callback. 306 * 307 * @since 2.8.0 308 * 309 * @return callable Update callback. 310 */ 311 public function _get_update_callback() { 312 return array( $this, 'update_callback' ); 313 } 314 315 /** 316 * Retrieves the form callback. 317 * 318 * @since 2.8.0 319 * 320 * @return callable Form callback. 321 */ 322 public function _get_form_callback() { 323 return array( $this, 'form_callback' ); 324 } 325 326 /** 327 * Determines whether the current request is inside the Customizer preview. 328 * 329 * If true -- the current request is inside the Customizer preview, then 330 * the object cache gets suspended and widgets should check this to decide 331 * whether they should store anything persistently to the object cache, 332 * to transients, or anywhere else. 333 * 334 * @since 3.9.0 335 * 336 * @global WP_Customize_Manager $wp_customize 337 * 338 * @return bool True if within the Customizer preview, false if not. 339 */ 340 public function is_preview() { 341 global $wp_customize; 342 return ( isset( $wp_customize ) && $wp_customize->is_preview() ); 343 } 344 345 /** 346 * Generates the actual widget content (Do NOT override). 347 * 348 * Finds the instance and calls WP_Widget::widget(). 349 * 350 * @since 2.8.0 351 * 352 * @param array $args Display arguments. See WP_Widget::widget() for information 353 * on accepted arguments. 354 * @param int|array $widget_args { 355 * Optional. Internal order number of the widget instance, or array of multi-widget arguments. 356 * Default 1. 357 * 358 * @type int $number Number increment used for multiples of the same widget. 359 * } 360 */ 361 public function display_callback( $args, $widget_args = 1 ) { 362 if ( is_numeric( $widget_args ) ) { 363 $widget_args = array( 'number' => $widget_args ); 364 } 365 366 $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); 367 $this->_set( $widget_args['number'] ); 368 $instances = $this->get_settings(); 369 370 if ( isset( $instances[ $this->number ] ) ) { 371 $instance = $instances[ $this->number ]; 372 373 /** 374 * Filters the settings for a particular widget instance. 375 * 376 * Returning false will effectively short-circuit display of the widget. 377 * 378 * @since 2.8.0 379 * 380 * @param array $instance The current widget instance's settings. 381 * @param WP_Widget $widget The current widget instance. 382 * @param array $args An array of default widget arguments. 383 */ 384 $instance = apply_filters( 'widget_display_callback', $instance, $this, $args ); 385 386 if ( false === $instance ) { 387 return; 388 } 389 390 $was_cache_addition_suspended = wp_suspend_cache_addition(); 391 if ( $this->is_preview() && ! $was_cache_addition_suspended ) { 392 wp_suspend_cache_addition( true ); 393 } 394 395 $this->widget( $args, $instance ); 396 397 if ( $this->is_preview() ) { 398 wp_suspend_cache_addition( $was_cache_addition_suspended ); 399 } 400 } 401 } 402 403 /** 404 * Handles changed settings (Do NOT override). 405 * 406 * @since 2.8.0 407 * 408 * @global array $wp_registered_widgets 409 * 410 * @param int $deprecated Not used. 411 */ 412 public function update_callback( $deprecated = 1 ) { 413 global $wp_registered_widgets; 414 415 $all_instances = $this->get_settings(); 416 417 // We need to update the data. 418 if ( $this->updated ) { 419 return; 420 } 421 422 if ( isset( $_POST['delete_widget'] ) && $_POST['delete_widget'] ) { 423 // Delete the settings for this instance of the widget. 424 if ( isset( $_POST['the-widget-id'] ) ) { 425 $del_id = $_POST['the-widget-id']; 426 } else { 427 return; 428 } 429 430 if ( isset( $wp_registered_widgets[ $del_id ]['params'][0]['number'] ) ) { 431 $number = $wp_registered_widgets[ $del_id ]['params'][0]['number']; 432 433 if ( $this->id_base . '-' . $number === $del_id ) { 434 unset( $all_instances[ $number ] ); 435 } 436 } 437 } else { 438 if ( isset( $_POST[ 'widget-' . $this->id_base ] ) && is_array( $_POST[ 'widget-' . $this->id_base ] ) ) { 439 $settings = $_POST[ 'widget-' . $this->id_base ]; 440 } elseif ( isset( $_POST['id_base'] ) && $_POST['id_base'] === $this->id_base ) { 441 $num = $_POST['multi_number'] ? (int) $_POST['multi_number'] : (int) $_POST['widget_number']; 442 $settings = array( $num => array() ); 443 } else { 444 return; 445 } 446 447 foreach ( $settings as $number => $new_instance ) { 448 $new_instance = stripslashes_deep( $new_instance ); 449 $this->_set( $number ); 450 451 $old_instance = $all_instances[ $number ] ?? array(); 452 453 $was_cache_addition_suspended = wp_suspend_cache_addition(); 454 if ( $this->is_preview() && ! $was_cache_addition_suspended ) { 455 wp_suspend_cache_addition( true ); 456 } 457 458 $instance = $this->update( $new_instance, $old_instance ); 459 460 if ( $this->is_preview() ) { 461 wp_suspend_cache_addition( $was_cache_addition_suspended ); 462 } 463 464 /** 465 * Filters a widget's settings before saving. 466 * 467 * Returning false will effectively short-circuit the widget's ability 468 * to update settings. 469 * 470 * @since 2.8.0 471 * 472 * @param array $instance The current widget instance's settings. 473 * @param array $new_instance Array of new widget settings. 474 * @param array $old_instance Array of old widget settings. 475 * @param WP_Widget $widget The current widget instance. 476 */ 477 $instance = apply_filters( 'widget_update_callback', $instance, $new_instance, $old_instance, $this ); 478 479 if ( false !== $instance ) { 480 $all_instances[ $number ] = $instance; 481 } 482 483 break; // Run only once. 484 } 485 } 486 487 $this->save_settings( $all_instances ); 488 $this->updated = true; 489 } 490 491 /** 492 * Generates the widget control form (Do NOT override). 493 * 494 * @since 2.8.0 495 * 496 * @param int|array $widget_args { 497 * Optional. Internal order number of the widget instance, or array of multi-widget arguments. 498 * Default 1. 499 * 500 * @type int $number Number increment used for multiples of the same widget. 501 * } 502 * @return string|null 503 */ 504 public function form_callback( $widget_args = 1 ) { 505 if ( is_numeric( $widget_args ) ) { 506 $widget_args = array( 'number' => $widget_args ); 507 } 508 509 $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); 510 $all_instances = $this->get_settings(); 511 512 if ( -1 === $widget_args['number'] ) { 513 // We echo out a form where 'number' can be set later. 514 $this->_set( '__i__' ); 515 $instance = array(); 516 } else { 517 $this->_set( $widget_args['number'] ); 518 $instance = $all_instances[ $widget_args['number'] ]; 519 } 520 521 /** 522 * Filters the widget instance's settings before displaying the control form. 523 * 524 * Returning false effectively short-circuits display of the control form. 525 * 526 * @since 2.8.0 527 * 528 * @param array $instance The current widget instance's settings. 529 * @param WP_Widget $widget The current widget instance. 530 */ 531 $instance = apply_filters( 'widget_form_callback', $instance, $this ); 532 533 $return = null; 534 535 if ( false !== $instance ) { 536 $return = $this->form( $instance ); 537 538 /** 539 * Fires at the end of the widget control form. 540 * 541 * Use this hook to add extra fields to the widget form. The hook 542 * is only fired if the value passed to the 'widget_form_callback' 543 * hook is not false. 544 * 545 * Note: If the widget has no form, the text echoed from the default 546 * form method can be hidden using CSS. 547 * 548 * @since 2.8.0 549 * 550 * @param WP_Widget $widget The widget instance (passed by reference). 551 * @param null|string $return Default 'noform'. Return null if new fields are added. 552 * @param array $instance An array of the widget's settings. 553 */ 554 do_action_ref_array( 'in_widget_form', array( &$this, &$return, $instance ) ); 555 } 556 557 return $return; 558 } 559 560 /** 561 * Registers an instance of the widget class. 562 * 563 * @since 2.8.0 564 * 565 * @param int $number Optional. The unique order number of this widget instance 566 * compared to other instances of the same class. Default -1. 567 */ 568 public function _register_one( $number = -1 ) { 569 wp_register_sidebar_widget( 570 $this->id, 571 $this->name, 572 $this->_get_display_callback(), 573 $this->widget_options, 574 array( 'number' => $number ) 575 ); 576 577 _register_widget_update_callback( 578 $this->id_base, 579 $this->_get_update_callback(), 580 $this->control_options, 581 array( 'number' => -1 ) 582 ); 583 584 _register_widget_form_callback( 585 $this->id, 586 $this->name, 587 $this->_get_form_callback(), 588 $this->control_options, 589 array( 'number' => $number ) 590 ); 591 } 592 593 /** 594 * Saves the settings for all instances of the widget class. 595 * 596 * @since 2.8.0 597 * 598 * @param array $settings Multi-dimensional array of widget instance settings. 599 */ 600 public function save_settings( $settings ) { 601 $settings['_multiwidget'] = 1; 602 update_option( $this->option_name, $settings ); 603 } 604 605 /** 606 * Retrieves the settings for all instances of the widget class. 607 * 608 * @since 2.8.0 609 * 610 * @return array Multi-dimensional array of widget instance settings. 611 */ 612 public function get_settings() { 613 614 $settings = get_option( $this->option_name ); 615 616 if ( false === $settings ) { 617 $settings = array(); 618 if ( isset( $this->alt_option_name ) ) { 619 // Get settings from alternative (legacy) option. 620 $settings = get_option( $this->alt_option_name, array() ); 621 622 // Delete the alternative (legacy) option as the new option will be created using `$this->option_name`. 623 delete_option( $this->alt_option_name ); 624 } 625 // Save an option so it can be autoloaded next time. 626 $this->save_settings( $settings ); 627 } 628 629 if ( ! is_array( $settings ) && ! ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) ) { 630 $settings = array(); 631 } 632 633 if ( ! empty( $settings ) && ! isset( $settings['_multiwidget'] ) ) { 634 // Old format, convert if single widget. 635 $settings = wp_convert_widget_settings( $this->id_base, $this->option_name, $settings ); 636 } 637 638 unset( $settings['_multiwidget'], $settings['__i__'] ); 639 640 return $settings; 641 } 642 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Fri Sep 11 08:20:31 2026 | Cross-referenced by PHPXref |