[ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Core Widgets API 4 * 5 * This API is used for creating dynamic sidebar without hardcoding functionality into 6 * themes 7 * 8 * Includes both internal WordPress routines and theme-use routines. 9 * 10 * This functionality was found in a plugin before the WordPress 2.2 release, which 11 * included it in the core from that point on. 12 * 13 * @link https://wordpress.org/support/article/wordpress-widgets/ 14 * @link https://developer.wordpress.org/themes/functionality/widgets/ 15 * 16 * @package WordPress 17 * @subpackage Widgets 18 * @since 2.2.0 19 */ 20 21 // 22 // Global Variables. 23 // 24 25 /** @ignore */ 26 global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates; 27 28 /** 29 * Stores the sidebars, since many themes can have more than one. 30 * 31 * @global array $wp_registered_sidebars Registered sidebars. 32 * @since 2.2.0 33 */ 34 $wp_registered_sidebars = array(); 35 36 /** 37 * Stores the registered widgets. 38 * 39 * @global array $wp_registered_widgets 40 * @since 2.2.0 41 */ 42 $wp_registered_widgets = array(); 43 44 /** 45 * Stores the registered widget controls (options). 46 * 47 * @global array $wp_registered_widget_controls 48 * @since 2.2.0 49 */ 50 $wp_registered_widget_controls = array(); 51 /** 52 * @global array $wp_registered_widget_updates 53 */ 54 $wp_registered_widget_updates = array(); 55 56 /** 57 * Private 58 * 59 * @global array $_wp_sidebars_widgets 60 */ 61 $_wp_sidebars_widgets = array(); 62 63 /** 64 * Private 65 * 66 * @global array $_wp_deprecated_widgets_callbacks 67 */ 68 $GLOBALS['_wp_deprecated_widgets_callbacks'] = array( 69 'wp_widget_pages', 70 'wp_widget_pages_control', 71 'wp_widget_calendar', 72 'wp_widget_calendar_control', 73 'wp_widget_archives', 74 'wp_widget_archives_control', 75 'wp_widget_links', 76 'wp_widget_meta', 77 'wp_widget_meta_control', 78 'wp_widget_search', 79 'wp_widget_recent_entries', 80 'wp_widget_recent_entries_control', 81 'wp_widget_tag_cloud', 82 'wp_widget_tag_cloud_control', 83 'wp_widget_categories', 84 'wp_widget_categories_control', 85 'wp_widget_text', 86 'wp_widget_text_control', 87 'wp_widget_rss', 88 'wp_widget_rss_control', 89 'wp_widget_recent_comments', 90 'wp_widget_recent_comments_control', 91 ); 92 93 // 94 // Template tags & API functions. 95 // 96 97 /** 98 * Register a widget 99 * 100 * Registers a WP_Widget widget 101 * 102 * @since 2.8.0 103 * @since 4.6.0 Updated the `$widget` parameter to also accept a WP_Widget instance object 104 * instead of simply a `WP_Widget` subclass name. 105 * 106 * @see WP_Widget 107 * 108 * @global WP_Widget_Factory $wp_widget_factory 109 * 110 * @param string|WP_Widget $widget Either the name of a `WP_Widget` subclass or an instance of a `WP_Widget` subclass. 111 */ 112 function register_widget( $widget ) { 113 global $wp_widget_factory; 114 115 $wp_widget_factory->register( $widget ); 116 } 117 118 /** 119 * Unregisters a widget. 120 * 121 * Unregisters a WP_Widget widget. Useful for un-registering default widgets. 122 * Run within a function hooked to the {@see 'widgets_init'} action. 123 * 124 * @since 2.8.0 125 * @since 4.6.0 Updated the `$widget` parameter to also accept a WP_Widget instance object 126 * instead of simply a `WP_Widget` subclass name. 127 * 128 * @see WP_Widget 129 * 130 * @global WP_Widget_Factory $wp_widget_factory 131 * 132 * @param string|WP_Widget $widget Either the name of a `WP_Widget` subclass or an instance of a `WP_Widget` subclass. 133 */ 134 function unregister_widget( $widget ) { 135 global $wp_widget_factory; 136 137 $wp_widget_factory->unregister( $widget ); 138 } 139 140 /** 141 * Creates multiple sidebars. 142 * 143 * If you wanted to quickly create multiple sidebars for a theme or internally. 144 * This function will allow you to do so. If you don't pass the 'name' and/or 145 * 'id' in `$args`, then they will be built for you. 146 * 147 * @since 2.2.0 148 * 149 * @see register_sidebar() The second parameter is documented by register_sidebar() and is the same here. 150 * 151 * @global array $wp_registered_sidebars The new sidebars are stored in this array by sidebar ID. 152 * 153 * @param int $number Optional. Number of sidebars to create. Default 1. 154 * @param array|string $args { 155 * Optional. Array or string of arguments for building a sidebar. 156 * 157 * @type string $id The base string of the unique identifier for each sidebar. If provided, and multiple 158 * sidebars are being defined, the ID will have "-2" appended, and so on. 159 * Default 'sidebar-' followed by the number the sidebar creation is currently at. 160 * @type string $name The name or title for the sidebars displayed in the admin dashboard. If registering 161 * more than one sidebar, include '%d' in the string as a placeholder for the uniquely 162 * assigned number for each sidebar. 163 * Default 'Sidebar' for the first sidebar, otherwise 'Sidebar %d'. 164 * } 165 */ 166 function register_sidebars( $number = 1, $args = array() ) { 167 global $wp_registered_sidebars; 168 $number = (int) $number; 169 170 if ( is_string( $args ) ) { 171 parse_str( $args, $args ); 172 } 173 174 for ( $i = 1; $i <= $number; $i++ ) { 175 $_args = $args; 176 177 if ( $number > 1 ) { 178 if ( isset( $args['name'] ) ) { 179 $_args['name'] = sprintf( $args['name'], $i ); 180 } else { 181 /* translators: %d: Sidebar number. */ 182 $_args['name'] = sprintf( __( 'Sidebar %d' ), $i ); 183 } 184 } else { 185 $_args['name'] = isset( $args['name'] ) ? $args['name'] : __( 'Sidebar' ); 186 } 187 188 // Custom specified ID's are suffixed if they exist already. 189 // Automatically generated sidebar names need to be suffixed regardless starting at -0. 190 if ( isset( $args['id'] ) ) { 191 $_args['id'] = $args['id']; 192 $n = 2; // Start at -2 for conflicting custom IDs. 193 while ( is_registered_sidebar( $_args['id'] ) ) { 194 $_args['id'] = $args['id'] . '-' . $n++; 195 } 196 } else { 197 $n = count( $wp_registered_sidebars ); 198 do { 199 $_args['id'] = 'sidebar-' . ++$n; 200 } while ( is_registered_sidebar( $_args['id'] ) ); 201 } 202 register_sidebar( $_args ); 203 } 204 } 205 206 /** 207 * Builds the definition for a single sidebar and returns the ID. 208 * 209 * Accepts either a string or an array and then parses that against a set 210 * of default arguments for the new sidebar. WordPress will automatically 211 * generate a sidebar ID and name based on the current number of registered 212 * sidebars if those arguments are not included. 213 * 214 * When allowing for automatic generation of the name and ID parameters, keep 215 * in mind that the incrementor for your sidebar can change over time depending 216 * on what other plugins and themes are installed. 217 * 218 * If theme support for 'widgets' has not yet been added when this function is 219 * called, it will be automatically enabled through the use of add_theme_support() 220 * 221 * @since 2.2.0 222 * @since 5.6.0 Added the `before_sidebar` and `after_sidebar` arguments. 223 * 224 * @global array $wp_registered_sidebars Registered sidebars. 225 * 226 * @param array|string $args { 227 * Optional. Array or string of arguments for the sidebar being registered. 228 * 229 * @type string $name The name or title of the sidebar displayed in the Widgets 230 * interface. Default 'Sidebar $instance'. 231 * @type string $id The unique identifier by which the sidebar will be called. 232 * Default 'sidebar-$instance'. 233 * @type string $description Description of the sidebar, displayed in the Widgets interface. 234 * Default empty string. 235 * @type string $class Extra CSS class to assign to the sidebar in the Widgets interface. 236 * Default empty. 237 * @type string $before_widget HTML content to prepend to each widget's HTML output when assigned 238 * to this sidebar. Receives the widget's ID attribute as `%1$s` 239 * and class name as `%2$s`. Default is an opening list item element. 240 * @type string $after_widget HTML content to append to each widget's HTML output when assigned 241 * to this sidebar. Default is a closing list item element. 242 * @type string $before_title HTML content to prepend to the sidebar title when displayed. 243 * Default is an opening h2 element. 244 * @type string $after_title HTML content to append to the sidebar title when displayed. 245 * Default is a closing h2 element. 246 * @type string $before_sidebar HTML content to prepend to the sidebar when displayed. 247 * Receives the `$id` argument as `%1$s` and `$class` as `%2$s`. 248 * Outputs after the {@see 'dynamic_sidebar_before'} action. 249 * Default empty string. 250 * @type string $after_sidebar HTML content to append to the sidebar when displayed. 251 * Outputs before the {@see 'dynamic_sidebar_after'} action. 252 * Default empty string. 253 * } 254 * @return string Sidebar ID added to $wp_registered_sidebars global. 255 */ 256 function register_sidebar( $args = array() ) { 257 global $wp_registered_sidebars; 258 259 $i = count( $wp_registered_sidebars ) + 1; 260 261 $id_is_empty = empty( $args['id'] ); 262 263 $defaults = array( 264 /* translators: %d: Sidebar number. */ 265 'name' => sprintf( __( 'Sidebar %d' ), $i ), 266 'id' => "sidebar-$i", 267 'description' => '', 268 'class' => '', 269 'before_widget' => '<li id="%1$s" class="widget %2$s">', 270 'after_widget' => "</li>\n", 271 'before_title' => '<h2 class="widgettitle">', 272 'after_title' => "</h2>\n", 273 'before_sidebar' => '', 274 'after_sidebar' => '', 275 ); 276 277 /** 278 * Filters the sidebar default arguments. 279 * 280 * @since 5.3.0 281 * 282 * @see register_sidebar() 283 * 284 * @param array $defaults The default sidebar arguments. 285 */ 286 $sidebar = wp_parse_args( $args, apply_filters( 'register_sidebar_defaults', $defaults ) ); 287 288 if ( $id_is_empty ) { 289 _doing_it_wrong( 290 __FUNCTION__, 291 sprintf( 292 /* translators: 1: The 'id' argument, 2: Sidebar name, 3: Recommended 'id' value. */ 293 __( 'No %1$s was set in the arguments array for the "%2$s" sidebar. Defaulting to "%3$s". Manually set the %1$s to "%3$s" to silence this notice and keep existing sidebar content.' ), 294 '<code>id</code>', 295 $sidebar['name'], 296 $sidebar['id'] 297 ), 298 '4.2.0' 299 ); 300 } 301 302 $wp_registered_sidebars[ $sidebar['id'] ] = $sidebar; 303 304 add_theme_support( 'widgets' ); 305 306 /** 307 * Fires once a sidebar has been registered. 308 * 309 * @since 3.0.0 310 * 311 * @param array $sidebar Parsed arguments for the registered sidebar. 312 */ 313 do_action( 'register_sidebar', $sidebar ); 314 315 return $sidebar['id']; 316 } 317 318 /** 319 * Removes a sidebar from the list. 320 * 321 * @since 2.2.0 322 * 323 * @global array $wp_registered_sidebars Registered sidebars. 324 * 325 * @param string|int $sidebar_id The ID of the sidebar when it was registered. 326 */ 327 function unregister_sidebar( $sidebar_id ) { 328 global $wp_registered_sidebars; 329 330 unset( $wp_registered_sidebars[ $sidebar_id ] ); 331 } 332 333 /** 334 * Checks if a sidebar is registered. 335 * 336 * @since 4.4.0 337 * 338 * @global array $wp_registered_sidebars Registered sidebars. 339 * 340 * @param string|int $sidebar_id The ID of the sidebar when it was registered. 341 * @return bool True if the sidebar is registered, false otherwise. 342 */ 343 function is_registered_sidebar( $sidebar_id ) { 344 global $wp_registered_sidebars; 345 346 return isset( $wp_registered_sidebars[ $sidebar_id ] ); 347 } 348 349 /** 350 * Register an instance of a widget. 351 * 352 * The default widget option is 'classname' that can be overridden. 353 * 354 * The function can also be used to un-register widgets when `$output_callback` 355 * parameter is an empty string. 356 * 357 * @since 2.2.0 358 * @since 5.3.0 Formalized the existing and already documented `...$params` parameter 359 * by adding it to the function signature. 360 * 361 * @global array $wp_registered_widgets Uses stored registered widgets. 362 * @global array $wp_registered_widget_controls Stores the registered widget controls (options). 363 * @global array $wp_registered_widget_updates 364 * @global array $_wp_deprecated_widgets_callbacks 365 * 366 * @param int|string $id Widget ID. 367 * @param string $name Widget display title. 368 * @param callable $output_callback Run when widget is called. 369 * @param array $options { 370 * Optional. An array of supplementary widget options for the instance. 371 * 372 * @type string $classname Class name for the widget's HTML container. Default is a shortened 373 * version of the output callback name. 374 * @type string $description Widget description for display in the widget administration 375 * panel and/or theme. 376 * } 377 * @param mixed ...$params Optional additional parameters to pass to the callback function when it's called. 378 */ 379 function wp_register_sidebar_widget( $id, $name, $output_callback, $options = array(), ...$params ) { 380 global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates, $_wp_deprecated_widgets_callbacks; 381 382 $id = strtolower( $id ); 383 384 if ( empty( $output_callback ) ) { 385 unset( $wp_registered_widgets[ $id ] ); 386 return; 387 } 388 389 $id_base = _get_widget_id_base( $id ); 390 if ( in_array( $output_callback, $_wp_deprecated_widgets_callbacks, true ) && ! is_callable( $output_callback ) ) { 391 unset( $wp_registered_widget_controls[ $id ] ); 392 unset( $wp_registered_widget_updates[ $id_base ] ); 393 return; 394 } 395 396 $defaults = array( 'classname' => $output_callback ); 397 $options = wp_parse_args( $options, $defaults ); 398 $widget = array( 399 'name' => $name, 400 'id' => $id, 401 'callback' => $output_callback, 402 'params' => $params, 403 ); 404 $widget = array_merge( $widget, $options ); 405 406 if ( is_callable( $output_callback ) && ( ! isset( $wp_registered_widgets[ $id ] ) || did_action( 'widgets_init' ) ) ) { 407 408 /** 409 * Fires once for each registered widget. 410 * 411 * @since 3.0.0 412 * 413 * @param array $widget An array of default widget arguments. 414 */ 415 do_action( 'wp_register_sidebar_widget', $widget ); 416 $wp_registered_widgets[ $id ] = $widget; 417 } 418 } 419 420 /** 421 * Retrieve description for widget. 422 * 423 * When registering widgets, the options can also include 'description' that 424 * describes the widget for display on the widget administration panel or 425 * in the theme. 426 * 427 * @since 2.5.0 428 * 429 * @global array $wp_registered_widgets 430 * 431 * @param int|string $id Widget ID. 432 * @return string|void Widget description, if available. 433 */ 434 function wp_widget_description( $id ) { 435 if ( ! is_scalar( $id ) ) { 436 return; 437 } 438 439 global $wp_registered_widgets; 440 441 if ( isset( $wp_registered_widgets[ $id ]['description'] ) ) { 442 return esc_html( $wp_registered_widgets[ $id ]['description'] ); 443 } 444 } 445 446 /** 447 * Retrieve description for a sidebar. 448 * 449 * When registering sidebars a 'description' parameter can be included that 450 * describes the sidebar for display on the widget administration panel. 451 * 452 * @since 2.9.0 453 * 454 * @global array $wp_registered_sidebars Registered sidebars. 455 * 456 * @param string $id sidebar ID. 457 * @return string|void Sidebar description, if available. 458 */ 459 function wp_sidebar_description( $id ) { 460 if ( ! is_scalar( $id ) ) { 461 return; 462 } 463 464 global $wp_registered_sidebars; 465 466 if ( isset( $wp_registered_sidebars[ $id ]['description'] ) ) { 467 return wp_kses( $wp_registered_sidebars[ $id ]['description'], 'sidebar_description' ); 468 } 469 } 470 471 /** 472 * Remove widget from sidebar. 473 * 474 * @since 2.2.0 475 * 476 * @param int|string $id Widget ID. 477 */ 478 function wp_unregister_sidebar_widget( $id ) { 479 480 /** 481 * Fires just before a widget is removed from a sidebar. 482 * 483 * @since 3.0.0 484 * 485 * @param int $id The widget ID. 486 */ 487 do_action( 'wp_unregister_sidebar_widget', $id ); 488 489 wp_register_sidebar_widget( $id, '', '' ); 490 wp_unregister_widget_control( $id ); 491 } 492 493 /** 494 * Registers widget control callback for customizing options. 495 * 496 * @since 2.2.0 497 * @since 5.3.0 Formalized the existing and already documented `...$params` parameter 498 * by adding it to the function signature. 499 * 500 * @global array $wp_registered_widget_controls 501 * @global array $wp_registered_widget_updates 502 * @global array $wp_registered_widgets 503 * @global array $_wp_deprecated_widgets_callbacks 504 * 505 * @param int|string $id Sidebar ID. 506 * @param string $name Sidebar display name. 507 * @param callable $control_callback Run when sidebar is displayed. 508 * @param array $options { 509 * Optional. Array or string of control options. Default empty array. 510 * 511 * @type int $height Never used. Default 200. 512 * @type int $width Width of the fully expanded control form (but try hard to use the default width). 513 * Default 250. 514 * @type int|string $id_base Required for multi-widgets, i.e widgets that allow multiple instances such as the 515 * text widget. The widget id will end up looking like `{$id_base}-{$unique_number}`. 516 * } 517 * @param mixed ...$params Optional additional parameters to pass to the callback function when it's called. 518 */ 519 function wp_register_widget_control( $id, $name, $control_callback, $options = array(), ...$params ) { 520 global $wp_registered_widget_controls, $wp_registered_widget_updates, $wp_registered_widgets, $_wp_deprecated_widgets_callbacks; 521 522 $id = strtolower( $id ); 523 $id_base = _get_widget_id_base( $id ); 524 525 if ( empty( $control_callback ) ) { 526 unset( $wp_registered_widget_controls[ $id ] ); 527 unset( $wp_registered_widget_updates[ $id_base ] ); 528 return; 529 } 530 531 if ( in_array( $control_callback, $_wp_deprecated_widgets_callbacks, true ) && ! is_callable( $control_callback ) ) { 532 unset( $wp_registered_widgets[ $id ] ); 533 return; 534 } 535 536 if ( isset( $wp_registered_widget_controls[ $id ] ) && ! did_action( 'widgets_init' ) ) { 537 return; 538 } 539 540 $defaults = array( 541 'width' => 250, 542 'height' => 200, 543 ); // Height is never used. 544 $options = wp_parse_args( $options, $defaults ); 545 $options['width'] = (int) $options['width']; 546 $options['height'] = (int) $options['height']; 547 548 $widget = array( 549 'name' => $name, 550 'id' => $id, 551 'callback' => $control_callback, 552 'params' => $params, 553 ); 554 $widget = array_merge( $widget, $options ); 555 556 $wp_registered_widget_controls[ $id ] = $widget; 557 558 if ( isset( $wp_registered_widget_updates[ $id_base ] ) ) { 559 return; 560 } 561 562 if ( isset( $widget['params'][0]['number'] ) ) { 563 $widget['params'][0]['number'] = -1; 564 } 565 566 unset( $widget['width'], $widget['height'], $widget['name'], $widget['id'] ); 567 $wp_registered_widget_updates[ $id_base ] = $widget; 568 } 569 570 /** 571 * Registers the update callback for a widget. 572 * 573 * @since 2.8.0 574 * @since 5.3.0 Formalized the existing and already documented `...$params` parameter 575 * by adding it to the function signature. 576 * 577 * @global array $wp_registered_widget_updates 578 * 579 * @param string $id_base The base ID of a widget created by extending WP_Widget. 580 * @param callable $update_callback Update callback method for the widget. 581 * @param array $options Optional. Widget control options. See wp_register_widget_control(). 582 * Default empty array. 583 * @param mixed ...$params Optional additional parameters to pass to the callback function when it's called. 584 */ 585 function _register_widget_update_callback( $id_base, $update_callback, $options = array(), ...$params ) { 586 global $wp_registered_widget_updates; 587 588 if ( isset( $wp_registered_widget_updates[ $id_base ] ) ) { 589 if ( empty( $update_callback ) ) { 590 unset( $wp_registered_widget_updates[ $id_base ] ); 591 } 592 return; 593 } 594 595 $widget = array( 596 'callback' => $update_callback, 597 'params' => $params, 598 ); 599 600 $widget = array_merge( $widget, $options ); 601 $wp_registered_widget_updates[ $id_base ] = $widget; 602 } 603 604 /** 605 * Registers the form callback for a widget. 606 * 607 * @since 2.8.0 608 * @since 5.3.0 Formalized the existing and already documented `...$params` parameter 609 * by adding it to the function signature. 610 * 611 * @global array $wp_registered_widget_controls 612 * 613 * @param int|string $id Widget ID. 614 * @param string $name Name attribute for the widget. 615 * @param callable $form_callback Form callback. 616 * @param array $options Optional. Widget control options. See wp_register_widget_control(). 617 * Default empty array. 618 * @param mixed ...$params Optional additional parameters to pass to the callback function when it's called. 619 */ 620 621 function _register_widget_form_callback( $id, $name, $form_callback, $options = array(), ...$params ) { 622 global $wp_registered_widget_controls; 623 624 $id = strtolower( $id ); 625 626 if ( empty( $form_callback ) ) { 627 unset( $wp_registered_widget_controls[ $id ] ); 628 return; 629 } 630 631 if ( isset( $wp_registered_widget_controls[ $id ] ) && ! did_action( 'widgets_init' ) ) { 632 return; 633 } 634 635 $defaults = array( 636 'width' => 250, 637 'height' => 200, 638 ); 639 $options = wp_parse_args( $options, $defaults ); 640 $options['width'] = (int) $options['width']; 641 $options['height'] = (int) $options['height']; 642 643 $widget = array( 644 'name' => $name, 645 'id' => $id, 646 'callback' => $form_callback, 647 'params' => $params, 648 ); 649 $widget = array_merge( $widget, $options ); 650 651 $wp_registered_widget_controls[ $id ] = $widget; 652 } 653 654 /** 655 * Remove control callback for widget. 656 * 657 * @since 2.2.0 658 * 659 * @param int|string $id Widget ID. 660 */ 661 function wp_unregister_widget_control( $id ) { 662 wp_register_widget_control( $id, '', '' ); 663 } 664 665 /** 666 * Display dynamic sidebar. 667 * 668 * By default this displays the default sidebar or 'sidebar-1'. If your theme specifies the 'id' or 669 * 'name' parameter for its registered sidebars you can pass an ID or name as the $index parameter. 670 * Otherwise, you can pass in a numerical index to display the sidebar at that index. 671 * 672 * @since 2.2.0 673 * 674 * @global array $wp_registered_sidebars Registered sidebars. 675 * @global array $wp_registered_widgets Registered widgets. 676 * 677 * @param int|string $index Optional. Index, name or ID of dynamic sidebar. Default 1. 678 * @return bool True, if widget sidebar was found and called. False if not found or not called. 679 */ 680 function dynamic_sidebar( $index = 1 ) { 681 global $wp_registered_sidebars, $wp_registered_widgets; 682 683 if ( is_int( $index ) ) { 684 $index = "sidebar-$index"; 685 } else { 686 $index = sanitize_title( $index ); 687 foreach ( (array) $wp_registered_sidebars as $key => $value ) { 688 if ( sanitize_title( $value['name'] ) === $index ) { 689 $index = $key; 690 break; 691 } 692 } 693 } 694 695 $sidebars_widgets = wp_get_sidebars_widgets(); 696 if ( empty( $wp_registered_sidebars[ $index ] ) || empty( $sidebars_widgets[ $index ] ) || ! is_array( $sidebars_widgets[ $index ] ) ) { 697 /** This action is documented in wp-includes/widget.php */ 698 do_action( 'dynamic_sidebar_before', $index, false ); 699 /** This action is documented in wp-includes/widget.php */ 700 do_action( 'dynamic_sidebar_after', $index, false ); 701 /** This filter is documented in wp-includes/widget.php */ 702 return apply_filters( 'dynamic_sidebar_has_widgets', false, $index ); 703 } 704 705 $sidebar = $wp_registered_sidebars[ $index ]; 706 707 $sidebar['before_sidebar'] = sprintf( $sidebar['before_sidebar'], $sidebar['id'], $sidebar['class'] ); 708 709 /** 710 * Fires before widgets are rendered in a dynamic sidebar. 711 * 712 * Note: The action also fires for empty sidebars, and on both the front end 713 * and back end, including the Inactive Widgets sidebar on the Widgets screen. 714 * 715 * @since 3.9.0 716 * 717 * @param int|string $index Index, name, or ID of the dynamic sidebar. 718 * @param bool $has_widgets Whether the sidebar is populated with widgets. 719 * Default true. 720 */ 721 do_action( 'dynamic_sidebar_before', $index, true ); 722 723 if ( ! is_admin() && ! empty( $sidebar['before_sidebar'] ) ) { 724 echo $sidebar['before_sidebar']; 725 } 726 727 $did_one = false; 728 foreach ( (array) $sidebars_widgets[ $index ] as $id ) { 729 730 if ( ! isset( $wp_registered_widgets[ $id ] ) ) { 731 continue; 732 } 733 734 $params = array_merge( 735 array( 736 array_merge( 737 $sidebar, 738 array( 739 'widget_id' => $id, 740 'widget_name' => $wp_registered_widgets[ $id ]['name'], 741 ) 742 ), 743 ), 744 (array) $wp_registered_widgets[ $id ]['params'] 745 ); 746 747 // Substitute HTML `id` and `class` attributes into `before_widget`. 748 $classname_ = ''; 749 foreach ( (array) $wp_registered_widgets[ $id ]['classname'] as $cn ) { 750 if ( is_string( $cn ) ) { 751 $classname_ .= '_' . $cn; 752 } elseif ( is_object( $cn ) ) { 753 $classname_ .= '_' . get_class( $cn ); 754 } 755 } 756 $classname_ = ltrim( $classname_, '_' ); 757 $params[0]['before_widget'] = sprintf( $params[0]['before_widget'], $id, $classname_ ); 758 759 /** 760 * Filters the parameters passed to a widget's display callback. 761 * 762 * Note: The filter is evaluated on both the front end and back end, 763 * including for the Inactive Widgets sidebar on the Widgets screen. 764 * 765 * @since 2.5.0 766 * 767 * @see register_sidebar() 768 * 769 * @param array $params { 770 * @type array $args { 771 * An array of widget display arguments. 772 * 773 * @type string $name Name of the sidebar the widget is assigned to. 774 * @type string $id ID of the sidebar the widget is assigned to. 775 * @type string $description The sidebar description. 776 * @type string $class CSS class applied to the sidebar container. 777 * @type string $before_widget HTML markup to prepend to each widget in the sidebar. 778 * @type string $after_widget HTML markup to append to each widget in the sidebar. 779 * @type string $before_title HTML markup to prepend to the widget title when displayed. 780 * @type string $after_title HTML markup to append to the widget title when displayed. 781 * @type string $widget_id ID of the widget. 782 * @type string $widget_name Name of the widget. 783 * } 784 * @type array $widget_args { 785 * An array of multi-widget arguments. 786 * 787 * @type int $number Number increment used for multiples of the same widget. 788 * } 789 * } 790 */ 791 $params = apply_filters( 'dynamic_sidebar_params', $params ); 792 793 $callback = $wp_registered_widgets[ $id ]['callback']; 794 795 /** 796 * Fires before a widget's display callback is called. 797 * 798 * Note: The action fires on both the front end and back end, including 799 * for widgets in the Inactive Widgets sidebar on the Widgets screen. 800 * 801 * The action is not fired for empty sidebars. 802 * 803 * @since 3.0.0 804 * 805 * @param array $widget { 806 * An associative array of widget arguments. 807 * 808 * @type string $name Name of the widget. 809 * @type string $id Widget ID. 810 * @type callable $callback When the hook is fired on the front end, `$callback` is an array 811 * containing the widget object. Fired on the back end, `$callback` 812 * is 'wp_widget_control', see `$_callback`. 813 * @type array $params An associative array of multi-widget arguments. 814 * @type string $classname CSS class applied to the widget container. 815 * @type string $description The widget description. 816 * @type array $_callback When the hook is fired on the back end, `$_callback` is populated 817 * with an array containing the widget object, see `$callback`. 818 * } 819 */ 820 do_action( 'dynamic_sidebar', $wp_registered_widgets[ $id ] ); 821 822 if ( is_callable( $callback ) ) { 823 call_user_func_array( $callback, $params ); 824 $did_one = true; 825 } 826 } 827 828 if ( ! is_admin() && ! empty( $sidebar['after_sidebar'] ) ) { 829 echo $sidebar['after_sidebar']; 830 } 831 832 /** 833 * Fires after widgets are rendered in a dynamic sidebar. 834 * 835 * Note: The action also fires for empty sidebars, and on both the front end 836 * and back end, including the Inactive Widgets sidebar on the Widgets screen. 837 * 838 * @since 3.9.0 839 * 840 * @param int|string $index Index, name, or ID of the dynamic sidebar. 841 * @param bool $has_widgets Whether the sidebar is populated with widgets. 842 * Default true. 843 */ 844 do_action( 'dynamic_sidebar_after', $index, true ); 845 846 /** 847 * Filters whether a sidebar has widgets. 848 * 849 * Note: The filter is also evaluated for empty sidebars, and on both the front end 850 * and back end, including the Inactive Widgets sidebar on the Widgets screen. 851 * 852 * @since 3.9.0 853 * 854 * @param bool $did_one Whether at least one widget was rendered in the sidebar. 855 * Default false. 856 * @param int|string $index Index, name, or ID of the dynamic sidebar. 857 */ 858 return apply_filters( 'dynamic_sidebar_has_widgets', $did_one, $index ); 859 } 860 861 /** 862 * Determines whether a given widget is displayed on the front end. 863 * 864 * Either $callback or $id_base can be used 865 * $id_base is the first argument when extending WP_Widget class 866 * Without the optional $widget_id parameter, returns the ID of the first sidebar 867 * in which the first instance of the widget with the given callback or $id_base is found. 868 * With the $widget_id parameter, returns the ID of the sidebar where 869 * the widget with that callback/$id_base AND that ID is found. 870 * 871 * NOTE: $widget_id and $id_base are the same for single widgets. To be effective 872 * this function has to run after widgets have initialized, at action {@see 'init'} or later. 873 * 874 * For more information on this and similar theme functions, check out 875 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 876 * Conditional Tags} article in the Theme Developer Handbook. 877 * 878 * @since 2.2.0 879 * 880 * @global array $wp_registered_widgets 881 * 882 * @param callable|false $callback Optional. Widget callback to check. Default false. 883 * @param int|false $widget_id Optional. Widget ID. Optional, but needed for checking. 884 * Default false. 885 * @param string|false $id_base Optional. The base ID of a widget created by extending WP_Widget. 886 * Default false. 887 * @param bool $skip_inactive Optional. Whether to check in 'wp_inactive_widgets'. 888 * Default true. 889 * @return string|false ID of the sidebar in which the widget is active, 890 * false if the widget is not active. 891 */ 892 function is_active_widget( $callback = false, $widget_id = false, $id_base = false, $skip_inactive = true ) { 893 global $wp_registered_widgets; 894 895 $sidebars_widgets = wp_get_sidebars_widgets(); 896 897 if ( is_array( $sidebars_widgets ) ) { 898 foreach ( $sidebars_widgets as $sidebar => $widgets ) { 899 if ( $skip_inactive && ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) ) { 900 continue; 901 } 902 903 if ( is_array( $widgets ) ) { 904 foreach ( $widgets as $widget ) { 905 if ( ( $callback && isset( $wp_registered_widgets[ $widget ]['callback'] ) && $wp_registered_widgets[ $widget ]['callback'] === $callback ) || ( $id_base && _get_widget_id_base( $widget ) === $id_base ) ) { 906 if ( ! $widget_id || $widget_id === $wp_registered_widgets[ $widget ]['id'] ) { 907 return $sidebar; 908 } 909 } 910 } 911 } 912 } 913 } 914 return false; 915 } 916 917 /** 918 * Determines whether the dynamic sidebar is enabled and used by the theme. 919 * 920 * For more information on this and similar theme functions, check out 921 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 922 * Conditional Tags} article in the Theme Developer Handbook. 923 * 924 * @since 2.2.0 925 * 926 * @global array $wp_registered_widgets Registered widgets. 927 * @global array $wp_registered_sidebars Registered sidebars. 928 * 929 * @return bool True if using widgets, false otherwise. 930 */ 931 function is_dynamic_sidebar() { 932 global $wp_registered_widgets, $wp_registered_sidebars; 933 934 $sidebars_widgets = get_option( 'sidebars_widgets' ); 935 936 foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) { 937 if ( ! empty( $sidebars_widgets[ $index ] ) ) { 938 foreach ( (array) $sidebars_widgets[ $index ] as $widget ) { 939 if ( array_key_exists( $widget, $wp_registered_widgets ) ) { 940 return true; 941 } 942 } 943 } 944 } 945 946 return false; 947 } 948 949 /** 950 * Determines whether a sidebar contains widgets. 951 * 952 * For more information on this and similar theme functions, check out 953 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 954 * Conditional Tags} article in the Theme Developer Handbook. 955 * 956 * @since 2.8.0 957 * 958 * @param string|int $index Sidebar name, id or number to check. 959 * @return bool True if the sidebar has widgets, false otherwise. 960 */ 961 function is_active_sidebar( $index ) { 962 $index = ( is_int( $index ) ) ? "sidebar-$index" : sanitize_title( $index ); 963 $sidebars_widgets = wp_get_sidebars_widgets(); 964 $is_active_sidebar = ! empty( $sidebars_widgets[ $index ] ); 965 966 /** 967 * Filters whether a dynamic sidebar is considered "active". 968 * 969 * @since 3.9.0 970 * 971 * @param bool $is_active_sidebar Whether or not the sidebar should be considered "active". 972 * In other words, whether the sidebar contains any widgets. 973 * @param int|string $index Index, name, or ID of the dynamic sidebar. 974 */ 975 return apply_filters( 'is_active_sidebar', $is_active_sidebar, $index ); 976 } 977 978 // 979 // Internal Functions. 980 // 981 982 /** 983 * Retrieve full list of sidebars and their widget instance IDs. 984 * 985 * Will upgrade sidebar widget list, if needed. Will also save updated list, if 986 * needed. 987 * 988 * @since 2.2.0 989 * @access private 990 * 991 * @global array $_wp_sidebars_widgets 992 * @global array $sidebars_widgets 993 * 994 * @param bool $deprecated Not used (argument deprecated). 995 * @return array Upgraded list of widgets to version 3 array format when called from the admin. 996 */ 997 function wp_get_sidebars_widgets( $deprecated = true ) { 998 if ( true !== $deprecated ) { 999 _deprecated_argument( __FUNCTION__, '2.8.1' ); 1000 } 1001 1002 global $_wp_sidebars_widgets, $sidebars_widgets; 1003 1004 // If loading from front page, consult $_wp_sidebars_widgets rather than options 1005 // to see if wp_convert_widget_settings() has made manipulations in memory. 1006 if ( ! is_admin() ) { 1007 if ( empty( $_wp_sidebars_widgets ) ) { 1008 $_wp_sidebars_widgets = get_option( 'sidebars_widgets', array() ); 1009 } 1010 1011 $sidebars_widgets = $_wp_sidebars_widgets; 1012 } else { 1013 $sidebars_widgets = get_option( 'sidebars_widgets', array() ); 1014 } 1015 1016 if ( is_array( $sidebars_widgets ) && isset( $sidebars_widgets['array_version'] ) ) { 1017 unset( $sidebars_widgets['array_version'] ); 1018 } 1019 1020 /** 1021 * Filters the list of sidebars and their widgets. 1022 * 1023 * @since 2.7.0 1024 * 1025 * @param array $sidebars_widgets An associative array of sidebars and their widgets. 1026 */ 1027 return apply_filters( 'sidebars_widgets', $sidebars_widgets ); 1028 } 1029 1030 /** 1031 * Set the sidebar widget option to update sidebars. 1032 * 1033 * @since 2.2.0 1034 * @access private 1035 * 1036 * @global array $_wp_sidebars_widgets 1037 * @param array $sidebars_widgets Sidebar widgets and their settings. 1038 */ 1039 function wp_set_sidebars_widgets( $sidebars_widgets ) { 1040 global $_wp_sidebars_widgets; 1041 1042 // Clear cached value used in wp_get_sidebars_widgets(). 1043 $_wp_sidebars_widgets = null; 1044 1045 if ( ! isset( $sidebars_widgets['array_version'] ) ) { 1046 $sidebars_widgets['array_version'] = 3; 1047 } 1048 1049 update_option( 'sidebars_widgets', $sidebars_widgets ); 1050 } 1051 1052 /** 1053 * Retrieve default registered sidebars list. 1054 * 1055 * @since 2.2.0 1056 * @access private 1057 * 1058 * @global array $wp_registered_sidebars Registered sidebars. 1059 * 1060 * @return array 1061 */ 1062 function wp_get_widget_defaults() { 1063 global $wp_registered_sidebars; 1064 1065 $defaults = array(); 1066 1067 foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) { 1068 $defaults[ $index ] = array(); 1069 } 1070 1071 return $defaults; 1072 } 1073 1074 /** 1075 * Converts the widget settings from single to multi-widget format. 1076 * 1077 * @since 2.8.0 1078 * 1079 * @global array $_wp_sidebars_widgets 1080 * 1081 * @param string $base_name Root ID for all widgets of this type. 1082 * @param string $option_name Option name for this widget type. 1083 * @param array $settings The array of widget instance settings. 1084 * @return array The array of widget settings converted to multi-widget format. 1085 */ 1086 function wp_convert_widget_settings( $base_name, $option_name, $settings ) { 1087 // This test may need expanding. 1088 $single = false; 1089 $changed = false; 1090 1091 if ( empty( $settings ) ) { 1092 $single = true; 1093 } else { 1094 foreach ( array_keys( $settings ) as $number ) { 1095 if ( 'number' === $number ) { 1096 continue; 1097 } 1098 if ( ! is_numeric( $number ) ) { 1099 $single = true; 1100 break; 1101 } 1102 } 1103 } 1104 1105 if ( $single ) { 1106 $settings = array( 2 => $settings ); 1107 1108 // If loading from the front page, update sidebar in memory but don't save to options. 1109 if ( is_admin() ) { 1110 $sidebars_widgets = get_option( 'sidebars_widgets' ); 1111 } else { 1112 if ( empty( $GLOBALS['_wp_sidebars_widgets'] ) ) { 1113 $GLOBALS['_wp_sidebars_widgets'] = get_option( 'sidebars_widgets', array() ); 1114 } 1115 $sidebars_widgets = &$GLOBALS['_wp_sidebars_widgets']; 1116 } 1117 1118 foreach ( (array) $sidebars_widgets as $index => $sidebar ) { 1119 if ( is_array( $sidebar ) ) { 1120 foreach ( $sidebar as $i => $name ) { 1121 if ( $base_name === $name ) { 1122 $sidebars_widgets[ $index ][ $i ] = "$name-2"; 1123 $changed = true; 1124 break 2; 1125 } 1126 } 1127 } 1128 } 1129 1130 if ( is_admin() && $changed ) { 1131 update_option( 'sidebars_widgets', $sidebars_widgets ); 1132 } 1133 } 1134 1135 $settings['_multiwidget'] = 1; 1136 if ( is_admin() ) { 1137 update_option( $option_name, $settings ); 1138 } 1139 1140 return $settings; 1141 } 1142 1143 /** 1144 * Output an arbitrary widget as a template tag. 1145 * 1146 * @since 2.8.0 1147 * 1148 * @global WP_Widget_Factory $wp_widget_factory 1149 * 1150 * @param string $widget The widget's PHP class name (see class-wp-widget.php). 1151 * @param array $instance Optional. The widget's instance settings. Default empty array. 1152 * @param array $args { 1153 * Optional. Array of arguments to configure the display of the widget. 1154 * 1155 * @type string $before_widget HTML content that will be prepended to the widget's HTML output. 1156 * Default `<div class="widget %s">`, where `%s` is the widget's class name. 1157 * @type string $after_widget HTML content that will be appended to the widget's HTML output. 1158 * Default `</div>`. 1159 * @type string $before_title HTML content that will be prepended to the widget's title when displayed. 1160 * Default `<h2 class="widgettitle">`. 1161 * @type string $after_title HTML content that will be appended to the widget's title when displayed. 1162 * Default `</h2>`. 1163 * } 1164 */ 1165 function the_widget( $widget, $instance = array(), $args = array() ) { 1166 global $wp_widget_factory; 1167 1168 if ( ! isset( $wp_widget_factory->widgets[ $widget ] ) ) { 1169 _doing_it_wrong( 1170 __FUNCTION__, 1171 sprintf( 1172 /* translators: %s: register_widget() */ 1173 __( 'Widgets need to be registered using %s, before they can be displayed.' ), 1174 '<code>register_widget()</code>' 1175 ), 1176 '4.9.0' 1177 ); 1178 return; 1179 } 1180 1181 $widget_obj = $wp_widget_factory->widgets[ $widget ]; 1182 if ( ! ( $widget_obj instanceof WP_Widget ) ) { 1183 return; 1184 } 1185 1186 $default_args = array( 1187 'before_widget' => '<div class="widget %s">', 1188 'after_widget' => '</div>', 1189 'before_title' => '<h2 class="widgettitle">', 1190 'after_title' => '</h2>', 1191 ); 1192 $args = wp_parse_args( $args, $default_args ); 1193 $args['before_widget'] = sprintf( $args['before_widget'], $widget_obj->widget_options['classname'] ); 1194 1195 $instance = wp_parse_args( $instance ); 1196 1197 /** This filter is documented in wp-includes/class-wp-widget.php */ 1198 $instance = apply_filters( 'widget_display_callback', $instance, $widget_obj, $args ); 1199 1200 if ( false === $instance ) { 1201 return; 1202 } 1203 1204 /** 1205 * Fires before rendering the requested widget. 1206 * 1207 * @since 3.0.0 1208 * 1209 * @param string $widget The widget's class name. 1210 * @param array $instance The current widget instance's settings. 1211 * @param array $args An array of the widget's sidebar arguments. 1212 */ 1213 do_action( 'the_widget', $widget, $instance, $args ); 1214 1215 $widget_obj->_set( -1 ); 1216 $widget_obj->widget( $args, $instance ); 1217 } 1218 1219 /** 1220 * Retrieves the widget ID base value. 1221 * 1222 * @since 2.8.0 1223 * 1224 * @param string $id Widget ID. 1225 * @return string Widget ID base. 1226 */ 1227 function _get_widget_id_base( $id ) { 1228 return preg_replace( '/-[0-9]+$/', '', $id ); 1229 } 1230 1231 /** 1232 * Handle sidebars config after theme change 1233 * 1234 * @access private 1235 * @since 3.3.0 1236 * 1237 * @global array $sidebars_widgets 1238 */ 1239 function _wp_sidebars_changed() { 1240 global $sidebars_widgets; 1241 1242 if ( ! is_array( $sidebars_widgets ) ) { 1243 $sidebars_widgets = wp_get_sidebars_widgets(); 1244 } 1245 1246 retrieve_widgets( true ); 1247 } 1248 1249 /** 1250 * Look for "lost" widgets, this has to run at least on each theme change. 1251 * 1252 * @since 2.8.0 1253 * 1254 * @global array $wp_registered_sidebars Registered sidebars. 1255 * @global array $sidebars_widgets 1256 * @global array $wp_registered_widgets Registered widgets. 1257 * 1258 * @param string|bool $theme_changed Whether the theme was changed as a boolean. A value 1259 * of 'customize' defers updates for the Customizer. 1260 * @return array Updated sidebars widgets. 1261 */ 1262 function retrieve_widgets( $theme_changed = false ) { 1263 global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets; 1264 1265 $registered_sidebars_keys = array_keys( $wp_registered_sidebars ); 1266 $registered_widgets_ids = array_keys( $wp_registered_widgets ); 1267 1268 if ( ! is_array( get_theme_mod( 'sidebars_widgets' ) ) ) { 1269 if ( empty( $sidebars_widgets ) ) { 1270 return array(); 1271 } 1272 1273 unset( $sidebars_widgets['array_version'] ); 1274 1275 $sidebars_widgets_keys = array_keys( $sidebars_widgets ); 1276 sort( $sidebars_widgets_keys ); 1277 sort( $registered_sidebars_keys ); 1278 1279 if ( $sidebars_widgets_keys === $registered_sidebars_keys ) { 1280 $sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids ); 1281 1282 return $sidebars_widgets; 1283 } 1284 } 1285 1286 // Discard invalid, theme-specific widgets from sidebars. 1287 $sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids ); 1288 $sidebars_widgets = wp_map_sidebars_widgets( $sidebars_widgets ); 1289 1290 // Find hidden/lost multi-widget instances. 1291 $shown_widgets = array_merge( ...array_values( $sidebars_widgets ) ); 1292 $lost_widgets = array_diff( $registered_widgets_ids, $shown_widgets ); 1293 1294 foreach ( $lost_widgets as $key => $widget_id ) { 1295 $number = preg_replace( '/.+?-([0-9]+)$/', '$1', $widget_id ); 1296 1297 // Only keep active and default widgets. 1298 if ( is_numeric( $number ) && (int) $number < 2 ) { 1299 unset( $lost_widgets[ $key ] ); 1300 } 1301 } 1302 $sidebars_widgets['wp_inactive_widgets'] = array_merge( $lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets'] ); 1303 1304 if ( 'customize' !== $theme_changed ) { 1305 wp_set_sidebars_widgets( $sidebars_widgets ); 1306 } 1307 1308 return $sidebars_widgets; 1309 } 1310 1311 /** 1312 * Compares a list of sidebars with their widgets against an allowed list. 1313 * 1314 * @since 4.9.0 1315 * @since 4.9.2 Always tries to restore widget assignments from previous data, not just if sidebars needed mapping. 1316 * 1317 * @param array $existing_sidebars_widgets List of sidebars and their widget instance IDs. 1318 * @return array Mapped sidebars widgets. 1319 */ 1320 function wp_map_sidebars_widgets( $existing_sidebars_widgets ) { 1321 global $wp_registered_sidebars; 1322 1323 $new_sidebars_widgets = array( 1324 'wp_inactive_widgets' => array(), 1325 ); 1326 1327 // Short-circuit if there are no sidebars to map. 1328 if ( ! is_array( $existing_sidebars_widgets ) || empty( $existing_sidebars_widgets ) ) { 1329 return $new_sidebars_widgets; 1330 } 1331 1332 foreach ( $existing_sidebars_widgets as $sidebar => $widgets ) { 1333 if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) { 1334 $new_sidebars_widgets['wp_inactive_widgets'] = array_merge( $new_sidebars_widgets['wp_inactive_widgets'], (array) $widgets ); 1335 unset( $existing_sidebars_widgets[ $sidebar ] ); 1336 } 1337 } 1338 1339 // If old and new theme have just one sidebar, map it and we're done. 1340 if ( 1 === count( $existing_sidebars_widgets ) && 1 === count( $wp_registered_sidebars ) ) { 1341 $new_sidebars_widgets[ key( $wp_registered_sidebars ) ] = array_pop( $existing_sidebars_widgets ); 1342 1343 return $new_sidebars_widgets; 1344 } 1345 1346 // Map locations with the same slug. 1347 $existing_sidebars = array_keys( $existing_sidebars_widgets ); 1348 1349 foreach ( $wp_registered_sidebars as $sidebar => $name ) { 1350 if ( in_array( $sidebar, $existing_sidebars, true ) ) { 1351 $new_sidebars_widgets[ $sidebar ] = $existing_sidebars_widgets[ $sidebar ]; 1352 unset( $existing_sidebars_widgets[ $sidebar ] ); 1353 } elseif ( ! array_key_exists( $sidebar, $new_sidebars_widgets ) ) { 1354 $new_sidebars_widgets[ $sidebar ] = array(); 1355 } 1356 } 1357 1358 // If there are more sidebars, try to map them. 1359 if ( ! empty( $existing_sidebars_widgets ) ) { 1360 1361 /* 1362 * If old and new theme both have sidebars that contain phrases 1363 * from within the same group, make an educated guess and map it. 1364 */ 1365 $common_slug_groups = array( 1366 array( 'sidebar', 'primary', 'main', 'right' ), 1367 array( 'second', 'left' ), 1368 array( 'sidebar-2', 'footer', 'bottom' ), 1369 array( 'header', 'top' ), 1370 ); 1371 1372 // Go through each group... 1373 foreach ( $common_slug_groups as $slug_group ) { 1374 1375 // ...and see if any of these slugs... 1376 foreach ( $slug_group as $slug ) { 1377 1378 // ...and any of the new sidebars... 1379 foreach ( $wp_registered_sidebars as $new_sidebar => $args ) { 1380 1381 // ...actually match! 1382 if ( false === stripos( $new_sidebar, $slug ) && false === stripos( $slug, $new_sidebar ) ) { 1383 continue; 1384 } 1385 1386 // Then see if any of the existing sidebars... 1387 foreach ( $existing_sidebars_widgets as $sidebar => $widgets ) { 1388 1389 // ...and any slug in the same group... 1390 foreach ( $slug_group as $slug ) { 1391 1392 // ... have a match as well. 1393 if ( false === stripos( $sidebar, $slug ) && false === stripos( $slug, $sidebar ) ) { 1394 continue; 1395 } 1396 1397 // Make sure this sidebar wasn't mapped and removed previously. 1398 if ( ! empty( $existing_sidebars_widgets[ $sidebar ] ) ) { 1399 1400 // We have a match that can be mapped! 1401 $new_sidebars_widgets[ $new_sidebar ] = array_merge( $new_sidebars_widgets[ $new_sidebar ], $existing_sidebars_widgets[ $sidebar ] ); 1402 1403 // Remove the mapped sidebar so it can't be mapped again. 1404 unset( $existing_sidebars_widgets[ $sidebar ] ); 1405 1406 // Go back and check the next new sidebar. 1407 continue 3; 1408 } 1409 } // End foreach ( $slug_group as $slug ). 1410 } // End foreach ( $existing_sidebars_widgets as $sidebar => $widgets ). 1411 } // End foreach ( $wp_registered_sidebars as $new_sidebar => $args ). 1412 } // End foreach ( $slug_group as $slug ). 1413 } // End foreach ( $common_slug_groups as $slug_group ). 1414 } 1415 1416 // Move any left over widgets to inactive sidebar. 1417 foreach ( $existing_sidebars_widgets as $widgets ) { 1418 if ( is_array( $widgets ) && ! empty( $widgets ) ) { 1419 $new_sidebars_widgets['wp_inactive_widgets'] = array_merge( $new_sidebars_widgets['wp_inactive_widgets'], $widgets ); 1420 } 1421 } 1422 1423 // Sidebars_widgets settings from when this theme was previously active. 1424 $old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' ); 1425 $old_sidebars_widgets = isset( $old_sidebars_widgets['data'] ) ? $old_sidebars_widgets['data'] : false; 1426 1427 if ( is_array( $old_sidebars_widgets ) ) { 1428 1429 // Remove empty sidebars, no need to map those. 1430 $old_sidebars_widgets = array_filter( $old_sidebars_widgets ); 1431 1432 // Only check sidebars that are empty or have not been mapped to yet. 1433 foreach ( $new_sidebars_widgets as $new_sidebar => $new_widgets ) { 1434 if ( array_key_exists( $new_sidebar, $old_sidebars_widgets ) && ! empty( $new_widgets ) ) { 1435 unset( $old_sidebars_widgets[ $new_sidebar ] ); 1436 } 1437 } 1438 1439 // Remove orphaned widgets, we're only interested in previously active sidebars. 1440 foreach ( $old_sidebars_widgets as $sidebar => $widgets ) { 1441 if ( 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) { 1442 unset( $old_sidebars_widgets[ $sidebar ] ); 1443 } 1444 } 1445 1446 $old_sidebars_widgets = _wp_remove_unregistered_widgets( $old_sidebars_widgets ); 1447 1448 if ( ! empty( $old_sidebars_widgets ) ) { 1449 1450 // Go through each remaining sidebar... 1451 foreach ( $old_sidebars_widgets as $old_sidebar => $old_widgets ) { 1452 1453 // ...and check every new sidebar... 1454 foreach ( $new_sidebars_widgets as $new_sidebar => $new_widgets ) { 1455 1456 // ...for every widget we're trying to revive. 1457 foreach ( $old_widgets as $key => $widget_id ) { 1458 $active_key = array_search( $widget_id, $new_widgets, true ); 1459 1460 // If the widget is used elsewhere... 1461 if ( false !== $active_key ) { 1462 1463 // ...and that elsewhere is inactive widgets... 1464 if ( 'wp_inactive_widgets' === $new_sidebar ) { 1465 1466 // ...remove it from there and keep the active version... 1467 unset( $new_sidebars_widgets['wp_inactive_widgets'][ $active_key ] ); 1468 } else { 1469 1470 // ...otherwise remove it from the old sidebar and keep it in the new one. 1471 unset( $old_sidebars_widgets[ $old_sidebar ][ $key ] ); 1472 } 1473 } // End if ( $active_key ). 1474 } // End foreach ( $old_widgets as $key => $widget_id ). 1475 } // End foreach ( $new_sidebars_widgets as $new_sidebar => $new_widgets ). 1476 } // End foreach ( $old_sidebars_widgets as $old_sidebar => $old_widgets ). 1477 } // End if ( ! empty( $old_sidebars_widgets ) ). 1478 1479 // Restore widget settings from when theme was previously active. 1480 $new_sidebars_widgets = array_merge( $new_sidebars_widgets, $old_sidebars_widgets ); 1481 } 1482 1483 return $new_sidebars_widgets; 1484 } 1485 1486 /** 1487 * Compares a list of sidebars with their widgets against an allowed list. 1488 * 1489 * @since 4.9.0 1490 * 1491 * @param array $sidebars_widgets List of sidebars and their widget instance IDs. 1492 * @param array $allowed_widget_ids Optional. List of widget IDs to compare against. Default: Registered widgets. 1493 * @return array Sidebars with allowed widgets. 1494 */ 1495 function _wp_remove_unregistered_widgets( $sidebars_widgets, $allowed_widget_ids = array() ) { 1496 if ( empty( $allowed_widget_ids ) ) { 1497 $allowed_widget_ids = array_keys( $GLOBALS['wp_registered_widgets'] ); 1498 } 1499 1500 foreach ( $sidebars_widgets as $sidebar => $widgets ) { 1501 if ( is_array( $widgets ) ) { 1502 $sidebars_widgets[ $sidebar ] = array_intersect( $widgets, $allowed_widget_ids ); 1503 } 1504 } 1505 1506 return $sidebars_widgets; 1507 } 1508 1509 /** 1510 * Display the RSS entries in a list. 1511 * 1512 * @since 2.5.0 1513 * 1514 * @param string|array|object $rss RSS url. 1515 * @param array $args Widget arguments. 1516 */ 1517 function wp_widget_rss_output( $rss, $args = array() ) { 1518 if ( is_string( $rss ) ) { 1519 $rss = fetch_feed( $rss ); 1520 } elseif ( is_array( $rss ) && isset( $rss['url'] ) ) { 1521 $args = $rss; 1522 $rss = fetch_feed( $rss['url'] ); 1523 } elseif ( ! is_object( $rss ) ) { 1524 return; 1525 } 1526 1527 if ( is_wp_error( $rss ) ) { 1528 if ( is_admin() || current_user_can( 'manage_options' ) ) { 1529 echo '<p><strong>' . __( 'RSS Error:' ) . '</strong> ' . $rss->get_error_message() . '</p>'; 1530 } 1531 return; 1532 } 1533 1534 $default_args = array( 1535 'show_author' => 0, 1536 'show_date' => 0, 1537 'show_summary' => 0, 1538 'items' => 0, 1539 ); 1540 $args = wp_parse_args( $args, $default_args ); 1541 1542 $items = (int) $args['items']; 1543 if ( $items < 1 || 20 < $items ) { 1544 $items = 10; 1545 } 1546 $show_summary = (int) $args['show_summary']; 1547 $show_author = (int) $args['show_author']; 1548 $show_date = (int) $args['show_date']; 1549 1550 if ( ! $rss->get_item_quantity() ) { 1551 echo '<ul><li>' . __( 'An error has occurred, which probably means the feed is down. Try again later.' ) . '</li></ul>'; 1552 $rss->__destruct(); 1553 unset( $rss ); 1554 return; 1555 } 1556 1557 echo '<ul>'; 1558 foreach ( $rss->get_items( 0, $items ) as $item ) { 1559 $link = $item->get_link(); 1560 while ( stristr( $link, 'http' ) !== $link ) { 1561 $link = substr( $link, 1 ); 1562 } 1563 $link = esc_url( strip_tags( $link ) ); 1564 1565 $title = esc_html( trim( strip_tags( $item->get_title() ) ) ); 1566 if ( empty( $title ) ) { 1567 $title = __( 'Untitled' ); 1568 } 1569 1570 $desc = html_entity_decode( $item->get_description(), ENT_QUOTES, get_option( 'blog_charset' ) ); 1571 $desc = esc_attr( wp_trim_words( $desc, 55, ' […]' ) ); 1572 1573 $summary = ''; 1574 if ( $show_summary ) { 1575 $summary = $desc; 1576 1577 // Change existing [...] to […]. 1578 if ( '[...]' === substr( $summary, -5 ) ) { 1579 $summary = substr( $summary, 0, -5 ) . '[…]'; 1580 } 1581 1582 $summary = '<div class="rssSummary">' . esc_html( $summary ) . '</div>'; 1583 } 1584 1585 $date = ''; 1586 if ( $show_date ) { 1587 $date = $item->get_date( 'U' ); 1588 1589 if ( $date ) { 1590 $date = ' <span class="rss-date">' . date_i18n( get_option( 'date_format' ), $date ) . '</span>'; 1591 } 1592 } 1593 1594 $author = ''; 1595 if ( $show_author ) { 1596 $author = $item->get_author(); 1597 if ( is_object( $author ) ) { 1598 $author = $author->get_name(); 1599 $author = ' <cite>' . esc_html( strip_tags( $author ) ) . '</cite>'; 1600 } 1601 } 1602 1603 if ( '' === $link ) { 1604 echo "<li>$title{$date}{$summary}{$author}</li>"; 1605 } elseif ( $show_summary ) { 1606 echo "<li><a class='rsswidget' href='$link'>$title</a>{$date}{$summary}{$author}</li>"; 1607 } else { 1608 echo "<li><a class='rsswidget' href='$link'>$title</a>{$date}{$author}</li>"; 1609 } 1610 } 1611 echo '</ul>'; 1612 $rss->__destruct(); 1613 unset( $rss ); 1614 } 1615 1616 /** 1617 * Display RSS widget options form. 1618 * 1619 * The options for what fields are displayed for the RSS form are all booleans 1620 * and are as follows: 'url', 'title', 'items', 'show_summary', 'show_author', 1621 * 'show_date'. 1622 * 1623 * @since 2.5.0 1624 * 1625 * @param array|string $args Values for input fields. 1626 * @param array $inputs Override default display options. 1627 */ 1628 function wp_widget_rss_form( $args, $inputs = null ) { 1629 $default_inputs = array( 1630 'url' => true, 1631 'title' => true, 1632 'items' => true, 1633 'show_summary' => true, 1634 'show_author' => true, 1635 'show_date' => true, 1636 ); 1637 $inputs = wp_parse_args( $inputs, $default_inputs ); 1638 1639 $args['title'] = isset( $args['title'] ) ? $args['title'] : ''; 1640 $args['url'] = isset( $args['url'] ) ? $args['url'] : ''; 1641 $args['items'] = isset( $args['items'] ) ? (int) $args['items'] : 0; 1642 1643 if ( $args['items'] < 1 || 20 < $args['items'] ) { 1644 $args['items'] = 10; 1645 } 1646 1647 $args['show_summary'] = isset( $args['show_summary'] ) ? (int) $args['show_summary'] : (int) $inputs['show_summary']; 1648 $args['show_author'] = isset( $args['show_author'] ) ? (int) $args['show_author'] : (int) $inputs['show_author']; 1649 $args['show_date'] = isset( $args['show_date'] ) ? (int) $args['show_date'] : (int) $inputs['show_date']; 1650 1651 if ( ! empty( $args['error'] ) ) { 1652 echo '<p class="widget-error"><strong>' . __( 'RSS Error:' ) . '</strong> ' . $args['error'] . '</p>'; 1653 } 1654 1655 $esc_number = esc_attr( $args['number'] ); 1656 if ( $inputs['url'] ) : 1657 ?> 1658 <p><label for="rss-url-<?php echo $esc_number; ?>"><?php _e( 'Enter the RSS feed URL here:' ); ?></label> 1659 <input class="widefat" id="rss-url-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][url]" type="text" value="<?php echo esc_url( $args['url'] ); ?>" /></p> 1660 <?php endif; if ( $inputs['title'] ) : ?> 1661 <p><label for="rss-title-<?php echo $esc_number; ?>"><?php _e( 'Give the feed a title (optional):' ); ?></label> 1662 <input class="widefat" id="rss-title-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][title]" type="text" value="<?php echo esc_attr( $args['title'] ); ?>" /></p> 1663 <?php endif; if ( $inputs['items'] ) : ?> 1664 <p><label for="rss-items-<?php echo $esc_number; ?>"><?php _e( 'How many items would you like to display?' ); ?></label> 1665 <select id="rss-items-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][items]"> 1666 <?php 1667 for ( $i = 1; $i <= 20; ++$i ) { 1668 echo "<option value='$i' " . selected( $args['items'], $i, false ) . ">$i</option>"; 1669 } 1670 ?> 1671 </select></p> 1672 <?php endif; if ( $inputs['show_summary'] || $inputs['show_author'] || $inputs['show_date'] ) : ?> 1673 <p> 1674 <?php if ( $inputs['show_summary'] ) : ?> 1675 <input id="rss-show-summary-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][show_summary]" type="checkbox" value="1" <?php checked( $args['show_summary'] ); ?> /> 1676 <label for="rss-show-summary-<?php echo $esc_number; ?>"><?php _e( 'Display item content?' ); ?></label><br /> 1677 <?php endif; if ( $inputs['show_author'] ) : ?> 1678 <input id="rss-show-author-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][show_author]" type="checkbox" value="1" <?php checked( $args['show_author'] ); ?> /> 1679 <label for="rss-show-author-<?php echo $esc_number; ?>"><?php _e( 'Display item author if available?' ); ?></label><br /> 1680 <?php endif; if ( $inputs['show_date'] ) : ?> 1681 <input id="rss-show-date-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][show_date]" type="checkbox" value="1" <?php checked( $args['show_date'] ); ?>/> 1682 <label for="rss-show-date-<?php echo $esc_number; ?>"><?php _e( 'Display item date?' ); ?></label><br /> 1683 <?php endif; ?> 1684 </p> 1685 <?php 1686 endif; // End of display options. 1687 foreach ( array_keys( $default_inputs ) as $input ) : 1688 if ( 'hidden' === $inputs[ $input ] ) : 1689 $id = str_replace( '_', '-', $input ); 1690 ?> 1691 <input type="hidden" id="rss-<?php echo esc_attr( $id ); ?>-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][<?php echo esc_attr( $input ); ?>]" value="<?php echo esc_attr( $args[ $input ] ); ?>" /> 1692 <?php 1693 endif; 1694 endforeach; 1695 } 1696 1697 /** 1698 * Process RSS feed widget data and optionally retrieve feed items. 1699 * 1700 * The feed widget can not have more than 20 items or it will reset back to the 1701 * default, which is 10. 1702 * 1703 * The resulting array has the feed title, feed url, feed link (from channel), 1704 * feed items, error (if any), and whether to show summary, author, and date. 1705 * All respectively in the order of the array elements. 1706 * 1707 * @since 2.5.0 1708 * 1709 * @param array $widget_rss RSS widget feed data. Expects unescaped data. 1710 * @param bool $check_feed Optional. Whether to check feed for errors. Default true. 1711 * @return array 1712 */ 1713 function wp_widget_rss_process( $widget_rss, $check_feed = true ) { 1714 $items = (int) $widget_rss['items']; 1715 if ( $items < 1 || 20 < $items ) { 1716 $items = 10; 1717 } 1718 $url = esc_url_raw( strip_tags( $widget_rss['url'] ) ); 1719 $title = isset( $widget_rss['title'] ) ? trim( strip_tags( $widget_rss['title'] ) ) : ''; 1720 $show_summary = isset( $widget_rss['show_summary'] ) ? (int) $widget_rss['show_summary'] : 0; 1721 $show_author = isset( $widget_rss['show_author'] ) ? (int) $widget_rss['show_author'] : 0; 1722 $show_date = isset( $widget_rss['show_date'] ) ? (int) $widget_rss['show_date'] : 0; 1723 1724 if ( $check_feed ) { 1725 $rss = fetch_feed( $url ); 1726 $error = false; 1727 $link = ''; 1728 if ( is_wp_error( $rss ) ) { 1729 $error = $rss->get_error_message(); 1730 } else { 1731 $link = esc_url( strip_tags( $rss->get_permalink() ) ); 1732 while ( stristr( $link, 'http' ) !== $link ) { 1733 $link = substr( $link, 1 ); 1734 } 1735 1736 $rss->__destruct(); 1737 unset( $rss ); 1738 } 1739 } 1740 1741 return compact( 'title', 'url', 'link', 'items', 'error', 'show_summary', 'show_author', 'show_date' ); 1742 } 1743 1744 /** 1745 * Registers all of the default WordPress widgets on startup. 1746 * 1747 * Calls {@see 'widgets_init'} action after all of the WordPress widgets have been registered. 1748 * 1749 * @since 2.2.0 1750 */ 1751 function wp_widgets_init() { 1752 if ( ! is_blog_installed() ) { 1753 return; 1754 } 1755 1756 register_widget( 'WP_Widget_Pages' ); 1757 1758 register_widget( 'WP_Widget_Calendar' ); 1759 1760 register_widget( 'WP_Widget_Archives' ); 1761 1762 if ( get_option( 'link_manager_enabled' ) ) { 1763 register_widget( 'WP_Widget_Links' ); 1764 } 1765 1766 register_widget( 'WP_Widget_Media_Audio' ); 1767 1768 register_widget( 'WP_Widget_Media_Image' ); 1769 1770 register_widget( 'WP_Widget_Media_Gallery' ); 1771 1772 register_widget( 'WP_Widget_Media_Video' ); 1773 1774 register_widget( 'WP_Widget_Meta' ); 1775 1776 register_widget( 'WP_Widget_Search' ); 1777 1778 register_widget( 'WP_Widget_Text' ); 1779 1780 register_widget( 'WP_Widget_Categories' ); 1781 1782 register_widget( 'WP_Widget_Recent_Posts' ); 1783 1784 register_widget( 'WP_Widget_Recent_Comments' ); 1785 1786 register_widget( 'WP_Widget_RSS' ); 1787 1788 register_widget( 'WP_Widget_Tag_Cloud' ); 1789 1790 register_widget( 'WP_Nav_Menu_Widget' ); 1791 1792 register_widget( 'WP_Widget_Custom_HTML' ); 1793 1794 /** 1795 * Fires after all default WordPress widgets have been registered. 1796 * 1797 * @since 2.2.0 1798 */ 1799 do_action( 'widgets_init' ); 1800 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Jan 27 01:00:08 2021 | Cross-referenced by PHPXref 0.7.1 |