| [ 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 * @final 417 */ 418 public function update_callback( $deprecated = 1 ) { 419 global $wp_registered_widgets; 420 421 $all_instances = $this->get_settings(); 422 423 // We need to update the data. 424 if ( $this->updated ) { 425 return; 426 } 427 428 if ( isset( $_POST['delete_widget'] ) && $_POST['delete_widget'] ) { 429 // Delete the settings for this instance of the widget. 430 if ( isset( $_POST['the-widget-id'] ) ) { 431 $del_id = $_POST['the-widget-id']; 432 } else { 433 return; 434 } 435 436 if ( isset( $wp_registered_widgets[ $del_id ]['params'][0]['number'] ) ) { 437 $number = $wp_registered_widgets[ $del_id ]['params'][0]['number']; 438 439 if ( $this->id_base . '-' . $number === $del_id ) { 440 unset( $all_instances[ $number ] ); 441 } 442 } 443 } else { 444 if ( isset( $_POST[ 'widget-' . $this->id_base ] ) && is_array( $_POST[ 'widget-' . $this->id_base ] ) ) { 445 $settings = $_POST[ 'widget-' . $this->id_base ]; 446 } elseif ( isset( $_POST['id_base'] ) && $_POST['id_base'] === $this->id_base ) { 447 $num = $_POST['multi_number'] ? (int) $_POST['multi_number'] : (int) $_POST['widget_number']; 448 $settings = array( $num => array() ); 449 } else { 450 return; 451 } 452 453 foreach ( $settings as $number => $new_instance ) { 454 $new_instance = stripslashes_deep( $new_instance ); 455 $this->_set( $number ); 456 457 $old_instance = $all_instances[ $number ] ?? array(); 458 459 $was_cache_addition_suspended = wp_suspend_cache_addition(); 460 if ( $this->is_preview() && ! $was_cache_addition_suspended ) { 461 wp_suspend_cache_addition( true ); 462 } 463 464 $instance = $this->update( $new_instance, $old_instance ); 465 466 if ( $this->is_preview() ) { 467 wp_suspend_cache_addition( $was_cache_addition_suspended ); 468 } 469 470 /** 471 * Filters a widget's settings before saving. 472 * 473 * Returning false will effectively short-circuit the widget's ability 474 * to update settings. 475 * 476 * @since 2.8.0 477 * 478 * @param array $instance The current widget instance's settings. 479 * @param array $new_instance Array of new widget settings. 480 * @param array $old_instance Array of old widget settings. 481 * @param WP_Widget $widget The current widget instance. 482 */ 483 $instance = apply_filters( 'widget_update_callback', $instance, $new_instance, $old_instance, $this ); 484 485 if ( false !== $instance ) { 486 $all_instances[ $number ] = $instance; 487 } 488 489 break; // Run only once. 490 } 491 } 492 493 $this->save_settings( $all_instances ); 494 $this->updated = true; 495 } 496 497 /** 498 * Generates the widget control form (Do NOT override). 499 * 500 * @since 2.8.0 501 * 502 * @param int|array $widget_args { 503 * Optional. Internal order number of the widget instance, or array of multi-widget arguments. 504 * Default 1. 505 * 506 * @type int $number Number increment used for multiples of the same widget. 507 * } 508 * @return string|null 509 * 510 * @final 511 */ 512 public function form_callback( $widget_args = 1 ) { 513 if ( is_numeric( $widget_args ) ) { 514 $widget_args = array( 'number' => $widget_args ); 515 } 516 517 $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); 518 $all_instances = $this->get_settings(); 519 520 if ( -1 === $widget_args['number'] ) { 521 // We echo out a form where 'number' can be set later. 522 $this->_set( '__i__' ); 523 $instance = array(); 524 } else { 525 $this->_set( $widget_args['number'] ); 526 $instance = $all_instances[ $widget_args['number'] ]; 527 } 528 529 /** 530 * Filters the widget instance's settings before displaying the control form. 531 * 532 * Returning false effectively short-circuits display of the control form. 533 * 534 * @since 2.8.0 535 * 536 * @param array $instance The current widget instance's settings. 537 * @param WP_Widget $widget The current widget instance. 538 */ 539 $instance = apply_filters( 'widget_form_callback', $instance, $this ); 540 541 $return = null; 542 543 if ( false !== $instance ) { 544 $return = $this->form( $instance ); 545 546 /** 547 * Fires at the end of the widget control form. 548 * 549 * Use this hook to add extra fields to the widget form. The hook 550 * is only fired if the value passed to the 'widget_form_callback' 551 * hook is not false. 552 * 553 * Note: If the widget has no form, the text echoed from the default 554 * form method can be hidden using CSS. 555 * 556 * @since 2.8.0 557 * 558 * @param WP_Widget $widget The widget instance (passed by reference). 559 * @param null|string $return Default 'noform'. Return null if new fields are added. 560 * @param array $instance An array of the widget's settings. 561 */ 562 do_action_ref_array( 'in_widget_form', array( &$this, &$return, $instance ) ); 563 } 564 565 return $return; 566 } 567 568 /** 569 * Registers an instance of the widget class. 570 * 571 * @since 2.8.0 572 * 573 * @param int $number Optional. The unique order number of this widget instance 574 * compared to other instances of the same class. Default -1. 575 */ 576 public function _register_one( $number = -1 ) { 577 wp_register_sidebar_widget( 578 $this->id, 579 $this->name, 580 $this->_get_display_callback(), 581 $this->widget_options, 582 array( 'number' => $number ) 583 ); 584 585 _register_widget_update_callback( 586 $this->id_base, 587 $this->_get_update_callback(), 588 $this->control_options, 589 array( 'number' => -1 ) 590 ); 591 592 _register_widget_form_callback( 593 $this->id, 594 $this->name, 595 $this->_get_form_callback(), 596 $this->control_options, 597 array( 'number' => $number ) 598 ); 599 } 600 601 /** 602 * Saves the settings for all instances of the widget class. 603 * 604 * @since 2.8.0 605 * 606 * @param array $settings Multi-dimensional array of widget instance settings. 607 */ 608 public function save_settings( $settings ) { 609 $settings['_multiwidget'] = 1; 610 update_option( $this->option_name, $settings ); 611 } 612 613 /** 614 * Retrieves the settings for all instances of the widget class. 615 * 616 * @since 2.8.0 617 * 618 * @return array Multi-dimensional array of widget instance settings. 619 */ 620 public function get_settings() { 621 622 $settings = get_option( $this->option_name ); 623 624 if ( false === $settings ) { 625 $settings = array(); 626 if ( isset( $this->alt_option_name ) ) { 627 // Get settings from alternative (legacy) option. 628 $settings = get_option( $this->alt_option_name, array() ); 629 630 // Delete the alternative (legacy) option as the new option will be created using `$this->option_name`. 631 delete_option( $this->alt_option_name ); 632 } 633 // Save an option so it can be autoloaded next time. 634 $this->save_settings( $settings ); 635 } 636 637 if ( ! is_array( $settings ) && ! ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) ) { 638 $settings = array(); 639 } 640 641 if ( ! empty( $settings ) && ! isset( $settings['_multiwidget'] ) ) { 642 // Old format, convert if single widget. 643 $settings = wp_convert_widget_settings( $this->id_base, $this->option_name, $settings ); 644 } 645 646 unset( $settings['_multiwidget'], $settings['__i__'] ); 647 648 return $settings; 649 } 650 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Fri Oct 30 08:20:34 2026 | Cross-referenced by PHPXref |