| [ 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 * @phpstan-return non-falsy-string 218 */ 219 public function get_field_name( $field_name ) { 220 $pos = strpos( $field_name, '[' ); 221 222 if ( false !== $pos ) { 223 // Replace the first occurrence of '[' with ']['. 224 $field_name = '[' . substr_replace( $field_name, '][', $pos, strlen( '[' ) ); 225 } else { 226 $field_name = '[' . $field_name . ']'; 227 } 228 229 return 'widget-' . $this->id_base . '[' . $this->number . ']' . $field_name; 230 } 231 232 /** 233 * Constructs id attributes for use in WP_Widget::form() fields. 234 * 235 * This function should be used in form() methods to create id attributes 236 * for fields to be saved by WP_Widget::update(). 237 * 238 * @since 2.8.0 239 * @since 4.4.0 Array format field IDs are now accepted. 240 * 241 * @param string $field_name Field name. 242 * @return string ID attribute for `$field_name`. 243 * 244 * @phpstan-return non-falsy-string 245 */ 246 public function get_field_id( $field_name ) { 247 $field_name = str_replace( array( '[]', '[', ']' ), array( '', '-', '' ), $field_name ); 248 $field_name = trim( $field_name, '-' ); 249 250 return 'widget-' . $this->id_base . '-' . $this->number . '-' . $field_name; 251 } 252 253 /** 254 * Register all widget instances of this widget class. 255 * 256 * @since 2.8.0 257 */ 258 public function _register() { 259 $settings = $this->get_settings(); 260 $empty = true; 261 262 // When $settings is an array-like object, get an intrinsic array for use with array_keys(). 263 if ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) { 264 $settings = $settings->getArrayCopy(); 265 } 266 267 if ( is_array( $settings ) ) { 268 foreach ( array_keys( $settings ) as $number ) { 269 if ( is_numeric( $number ) ) { 270 $this->_set( $number ); 271 $this->_register_one( $number ); 272 $empty = false; 273 } 274 } 275 } 276 277 if ( $empty ) { 278 // If there are none, we register the widget's existence with a generic template. 279 $this->_set( 1 ); 280 $this->_register_one(); 281 } 282 } 283 284 /** 285 * Sets the internal order number for the widget instance. 286 * 287 * @since 2.8.0 288 * 289 * @param int $number The unique order number of this widget instance compared to other 290 * instances of the same class. 291 */ 292 public function _set( $number ) { 293 $this->number = $number; 294 $this->id = $this->id_base . '-' . $number; 295 } 296 297 /** 298 * Retrieves the widget display callback. 299 * 300 * @since 2.8.0 301 * 302 * @return callable Display callback. 303 */ 304 public function _get_display_callback() { 305 return array( $this, 'display_callback' ); 306 } 307 308 /** 309 * Retrieves the widget update callback. 310 * 311 * @since 2.8.0 312 * 313 * @return callable Update callback. 314 */ 315 public function _get_update_callback() { 316 return array( $this, 'update_callback' ); 317 } 318 319 /** 320 * Retrieves the form callback. 321 * 322 * @since 2.8.0 323 * 324 * @return callable Form callback. 325 */ 326 public function _get_form_callback() { 327 return array( $this, 'form_callback' ); 328 } 329 330 /** 331 * Determines whether the current request is inside the Customizer preview. 332 * 333 * If true -- the current request is inside the Customizer preview, then 334 * the object cache gets suspended and widgets should check this to decide 335 * whether they should store anything persistently to the object cache, 336 * to transients, or anywhere else. 337 * 338 * @since 3.9.0 339 * 340 * @global WP_Customize_Manager $wp_customize 341 * 342 * @return bool True if within the Customizer preview, false if not. 343 */ 344 public function is_preview() { 345 global $wp_customize; 346 return ( isset( $wp_customize ) && $wp_customize->is_preview() ); 347 } 348 349 /** 350 * Generates the actual widget content (Do NOT override). 351 * 352 * Finds the instance and calls WP_Widget::widget(). 353 * 354 * @since 2.8.0 355 * 356 * @param array $args Display arguments. See WP_Widget::widget() for information 357 * on accepted arguments. 358 * @param int|array $widget_args { 359 * Optional. Internal order number of the widget instance, or array of multi-widget arguments. 360 * Default 1. 361 * 362 * @type int $number Number increment used for multiples of the same widget. 363 * } 364 */ 365 public function display_callback( $args, $widget_args = 1 ) { 366 if ( is_numeric( $widget_args ) ) { 367 $widget_args = array( 'number' => $widget_args ); 368 } 369 370 $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); 371 $this->_set( $widget_args['number'] ); 372 $instances = $this->get_settings(); 373 374 if ( isset( $instances[ $this->number ] ) ) { 375 $instance = $instances[ $this->number ]; 376 377 /** 378 * Filters the settings for a particular widget instance. 379 * 380 * Returning false will effectively short-circuit display of the widget. 381 * 382 * @since 2.8.0 383 * 384 * @param array $instance The current widget instance's settings. 385 * @param WP_Widget $widget The current widget instance. 386 * @param array $args An array of default widget arguments. 387 */ 388 $instance = apply_filters( 'widget_display_callback', $instance, $this, $args ); 389 390 if ( false === $instance ) { 391 return; 392 } 393 394 $was_cache_addition_suspended = wp_suspend_cache_addition(); 395 if ( $this->is_preview() && ! $was_cache_addition_suspended ) { 396 wp_suspend_cache_addition( true ); 397 } 398 399 $this->widget( $args, $instance ); 400 401 if ( $this->is_preview() ) { 402 wp_suspend_cache_addition( $was_cache_addition_suspended ); 403 } 404 } 405 } 406 407 /** 408 * Handles changed settings (Do NOT override). 409 * 410 * @since 2.8.0 411 * 412 * @global array $wp_registered_widgets 413 * 414 * @param int $deprecated Not used. 415 */ 416 public function update_callback( $deprecated = 1 ) { 417 global $wp_registered_widgets; 418 419 $all_instances = $this->get_settings(); 420 421 // We need to update the data. 422 if ( $this->updated ) { 423 return; 424 } 425 426 if ( isset( $_POST['delete_widget'] ) && $_POST['delete_widget'] ) { 427 // Delete the settings for this instance of the widget. 428 if ( isset( $_POST['the-widget-id'] ) ) { 429 $del_id = $_POST['the-widget-id']; 430 } else { 431 return; 432 } 433 434 if ( isset( $wp_registered_widgets[ $del_id ]['params'][0]['number'] ) ) { 435 $number = $wp_registered_widgets[ $del_id ]['params'][0]['number']; 436 437 if ( $this->id_base . '-' . $number === $del_id ) { 438 unset( $all_instances[ $number ] ); 439 } 440 } 441 } else { 442 if ( isset( $_POST[ 'widget-' . $this->id_base ] ) && is_array( $_POST[ 'widget-' . $this->id_base ] ) ) { 443 $settings = $_POST[ 'widget-' . $this->id_base ]; 444 } elseif ( isset( $_POST['id_base'] ) && $_POST['id_base'] === $this->id_base ) { 445 $num = $_POST['multi_number'] ? (int) $_POST['multi_number'] : (int) $_POST['widget_number']; 446 $settings = array( $num => array() ); 447 } else { 448 return; 449 } 450 451 foreach ( $settings as $number => $new_instance ) { 452 $new_instance = stripslashes_deep( $new_instance ); 453 $this->_set( $number ); 454 455 $old_instance = $all_instances[ $number ] ?? array(); 456 457 $was_cache_addition_suspended = wp_suspend_cache_addition(); 458 if ( $this->is_preview() && ! $was_cache_addition_suspended ) { 459 wp_suspend_cache_addition( true ); 460 } 461 462 $instance = $this->update( $new_instance, $old_instance ); 463 464 if ( $this->is_preview() ) { 465 wp_suspend_cache_addition( $was_cache_addition_suspended ); 466 } 467 468 /** 469 * Filters a widget's settings before saving. 470 * 471 * Returning false will effectively short-circuit the widget's ability 472 * to update settings. 473 * 474 * @since 2.8.0 475 * 476 * @param array $instance The current widget instance's settings. 477 * @param array $new_instance Array of new widget settings. 478 * @param array $old_instance Array of old widget settings. 479 * @param WP_Widget $widget The current widget instance. 480 */ 481 $instance = apply_filters( 'widget_update_callback', $instance, $new_instance, $old_instance, $this ); 482 483 if ( false !== $instance ) { 484 $all_instances[ $number ] = $instance; 485 } 486 487 break; // Run only once. 488 } 489 } 490 491 $this->save_settings( $all_instances ); 492 $this->updated = true; 493 } 494 495 /** 496 * Generates the widget control form (Do NOT override). 497 * 498 * @since 2.8.0 499 * 500 * @param int|array $widget_args { 501 * Optional. Internal order number of the widget instance, or array of multi-widget arguments. 502 * Default 1. 503 * 504 * @type int $number Number increment used for multiples of the same widget. 505 * } 506 * @return string|null 507 */ 508 public function form_callback( $widget_args = 1 ) { 509 if ( is_numeric( $widget_args ) ) { 510 $widget_args = array( 'number' => $widget_args ); 511 } 512 513 $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); 514 $all_instances = $this->get_settings(); 515 516 if ( -1 === $widget_args['number'] ) { 517 // We echo out a form where 'number' can be set later. 518 $this->_set( '__i__' ); 519 $instance = array(); 520 } else { 521 $this->_set( $widget_args['number'] ); 522 $instance = $all_instances[ $widget_args['number'] ]; 523 } 524 525 /** 526 * Filters the widget instance's settings before displaying the control form. 527 * 528 * Returning false effectively short-circuits display of the control form. 529 * 530 * @since 2.8.0 531 * 532 * @param array $instance The current widget instance's settings. 533 * @param WP_Widget $widget The current widget instance. 534 */ 535 $instance = apply_filters( 'widget_form_callback', $instance, $this ); 536 537 $return = null; 538 539 if ( false !== $instance ) { 540 $return = $this->form( $instance ); 541 542 /** 543 * Fires at the end of the widget control form. 544 * 545 * Use this hook to add extra fields to the widget form. The hook 546 * is only fired if the value passed to the 'widget_form_callback' 547 * hook is not false. 548 * 549 * Note: If the widget has no form, the text echoed from the default 550 * form method can be hidden using CSS. 551 * 552 * @since 2.8.0 553 * 554 * @param WP_Widget $widget The widget instance (passed by reference). 555 * @param null|string $return Default 'noform'. Return null if new fields are added. 556 * @param array $instance An array of the widget's settings. 557 */ 558 do_action_ref_array( 'in_widget_form', array( &$this, &$return, $instance ) ); 559 } 560 561 return $return; 562 } 563 564 /** 565 * Registers an instance of the widget class. 566 * 567 * @since 2.8.0 568 * 569 * @param int $number Optional. The unique order number of this widget instance 570 * compared to other instances of the same class. Default -1. 571 */ 572 public function _register_one( $number = -1 ) { 573 wp_register_sidebar_widget( 574 $this->id, 575 $this->name, 576 $this->_get_display_callback(), 577 $this->widget_options, 578 array( 'number' => $number ) 579 ); 580 581 _register_widget_update_callback( 582 $this->id_base, 583 $this->_get_update_callback(), 584 $this->control_options, 585 array( 'number' => -1 ) 586 ); 587 588 _register_widget_form_callback( 589 $this->id, 590 $this->name, 591 $this->_get_form_callback(), 592 $this->control_options, 593 array( 'number' => $number ) 594 ); 595 } 596 597 /** 598 * Saves the settings for all instances of the widget class. 599 * 600 * @since 2.8.0 601 * 602 * @param array $settings Multi-dimensional array of widget instance settings. 603 */ 604 public function save_settings( $settings ) { 605 $settings['_multiwidget'] = 1; 606 update_option( $this->option_name, $settings ); 607 } 608 609 /** 610 * Retrieves the settings for all instances of the widget class. 611 * 612 * @since 2.8.0 613 * 614 * @return array Multi-dimensional array of widget instance settings. 615 */ 616 public function get_settings() { 617 618 $settings = get_option( $this->option_name ); 619 620 if ( false === $settings ) { 621 $settings = array(); 622 if ( isset( $this->alt_option_name ) ) { 623 // Get settings from alternative (legacy) option. 624 $settings = get_option( $this->alt_option_name, array() ); 625 626 // Delete the alternative (legacy) option as the new option will be created using `$this->option_name`. 627 delete_option( $this->alt_option_name ); 628 } 629 // Save an option so it can be autoloaded next time. 630 $this->save_settings( $settings ); 631 } 632 633 if ( ! is_array( $settings ) && ! ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) ) { 634 $settings = array(); 635 } 636 637 if ( ! empty( $settings ) && ! isset( $settings['_multiwidget'] ) ) { 638 // Old format, convert if single widget. 639 $settings = wp_convert_widget_settings( $this->id_base, $this->option_name, $settings ); 640 } 641 642 unset( $settings['_multiwidget'], $settings['__i__'] ); 643 644 return $settings; 645 } 646 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sat Oct 10 08:20:33 2026 | Cross-referenced by PHPXref |