run:R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
23.8 KB
2026-03-11 16:18:51
R W Run
7.8 KB
2026-03-11 16:18:52
R W Run
36.1 KB
2026-03-11 16:18:51
R W Run
11.9 KB
2026-03-11 16:18:52
R W Run
18.94 KB
2026-03-11 16:18:52
R W Run
7.35 KB
2026-03-11 16:18:52
R W Run
28.6 KB
2026-03-11 16:18:51
R W Run
316 By
2026-03-11 16:18:51
R W Run
12.9 KB
2026-03-11 16:18:51
R W Run
61.02 KB
2026-03-11 16:18:52
R W Run
15 KB
2026-03-11 16:18:51
R W Run
112.05 KB
2026-03-11 16:18:51
R W Run
12.47 KB
2026-03-11 16:18:51
R W Run
15.07 KB
2026-03-11 16:18:52
R W Run
9.84 KB
2026-03-11 16:18:52
R W Run
13.17 KB
2026-03-11 16:18:52
R W Run
33.83 KB
2026-03-11 16:18:51
R W Run
42.63 KB
2026-03-11 16:18:51
R W Run
55.71 KB
2026-03-11 16:18:52
R W Run
12.53 KB
2026-03-11 16:18:51
R W Run
2.55 KB
2026-03-11 16:18:52
R W Run
28.92 KB
2026-03-11 16:18:52
R W Run
539 By
2026-03-11 16:18:51
R W Run
367 By
2026-03-11 16:18:52
R W Run
42.65 KB
2026-03-11 16:18:51
R W Run
401 By
2026-03-11 16:18:51
R W Run
6.61 KB
2026-03-11 16:18:51
R W Run
664 By
2026-03-11 16:18:52
R W Run
20.63 KB
2026-03-11 16:18:51
R W Run
2.18 KB
2026-03-11 16:18:52
R W Run
453 By
2026-03-11 16:18:52
R W Run
457 By
2026-03-11 16:18:51
R W Run
36.83 KB
2026-03-11 16:18:52
R W Run
2.41 KB
2026-03-11 16:18:52
R W Run
8.28 KB
2026-03-11 16:18:51
R W Run
13.89 KB
2026-03-11 16:18:51
R W Run
11.76 KB
2026-03-11 16:18:51
R W Run
2.65 KB
2026-03-11 16:18:51
R W Run
7.43 KB
2026-03-11 16:18:51
R W Run
17.46 KB
2026-03-11 16:18:51
R W Run
5.14 KB
2026-03-11 16:18:52
R W Run
16.7 KB
2026-03-11 16:18:51
R W Run
8.28 KB
2026-03-11 16:18:52
R W Run
2.92 KB
2026-03-11 16:18:52
R W Run
1.32 KB
2026-03-11 16:18:51
R W Run
4.6 KB
2026-03-11 16:18:52
R W Run
11.62 KB
2026-03-11 16:18:52
R W Run
2.5 KB
2026-03-11 16:18:51
R W Run
1.97 KB
2026-03-11 16:18:51
R W Run
11.25 KB
2026-03-11 16:18:52
R W Run
5.32 KB
2026-03-11 16:18:51
R W Run
10.99 KB
2026-03-11 16:18:52
R W Run
68.32 KB
2026-03-11 16:18:51
R W Run
6.34 KB
2026-03-11 16:18:51
R W Run
5.49 KB
2026-03-11 16:18:51
R W Run
1.99 KB
2026-03-11 16:18:52
R W Run
7.02 KB
2026-03-11 16:18:51
R W Run
4.91 KB
2026-03-11 16:18:52
R W Run
16.86 KB
2026-03-11 16:18:51
R W Run
24.23 KB
2026-03-11 16:18:51
R W Run
3.97 KB
2026-03-11 16:18:51
R W Run
47.66 KB
2026-03-11 16:18:51
R W Run
9.22 KB
2026-03-11 16:18:51
R W Run
25.51 KB
2026-03-11 16:18:51
R W Run
198.38 KB
2026-03-11 16:18:52
R W Run
56.65 KB
2026-03-11 16:18:51
R W Run
10.46 KB
2026-03-11 16:18:51
R W Run
10.95 KB
2026-03-11 16:18:52
R W Run
29.26 KB
2026-03-11 16:18:51
R W Run
70.91 KB
2026-03-11 16:18:52
R W Run
35.3 KB
2026-03-11 16:18:52
R W Run
16.61 KB
2026-03-11 16:18:52
R W Run
2.57 KB
2026-03-11 16:18:52
R W Run
39.83 KB
2026-03-11 16:18:51
R W Run
70.64 KB
2026-03-11 16:18:51
R W Run
15.56 KB
2026-03-11 16:18:52
R W Run
7.33 KB
2026-03-11 16:18:52
R W Run
253 By
2026-03-11 16:18:51
R W Run
7.96 KB
2026-03-11 16:18:52
R W Run
3.23 KB
2026-03-11 16:18:52
R W Run
969 By
2026-03-11 16:18:52
R W Run
16.28 KB
2026-03-11 16:18:51
R W Run
7.22 KB
2026-03-11 16:18:51
R W Run
12.95 KB
2026-03-11 16:18:51
R W Run
6.53 KB
2026-03-11 16:18:51
R W Run
3.42 KB
2026-03-11 16:18:52
R W Run
5.84 KB
2026-03-11 16:18:51
R W Run
1.97 KB
2026-03-11 16:18:51
R W Run
4.3 KB
2026-03-11 16:18:52
R W Run
2.91 KB
2026-03-11 16:18:51
R W Run
16.46 KB
2026-03-11 16:18:52
R W Run
40.6 KB
2026-03-11 16:18:51
R W Run
20.22 KB
2026-03-11 16:18:51
R W Run
36.11 KB
2026-03-11 16:18:52
R W Run
17.01 KB
2026-03-11 16:18:51
R W Run
7.27 KB
2026-03-11 16:18:52
R W Run
6.62 KB
2026-03-11 16:18:52
R W Run
16.49 KB
2026-03-11 16:18:52
R W Run
1.79 KB
2026-03-11 16:18:52
R W Run
29.82 KB
2026-03-11 16:18:51
R W Run
6.67 KB
2026-03-11 16:18:52
R W Run
8.98 KB
2026-03-11 16:18:52
R W Run
19.42 KB
2026-03-11 16:18:51
R W Run
12.01 KB
2026-03-11 16:18:51
R W Run
17.11 KB
2026-03-11 16:18:51
R W Run
6.74 KB
2026-03-11 16:18:52
R W Run
30.93 KB
2026-03-11 16:18:51
R W Run
4.99 KB
2026-03-11 16:18:51
R W Run
4.25 KB
2026-03-11 16:18:51
R W Run
24.72 KB
2026-03-11 16:18:51
R W Run
29.96 KB
2026-03-11 16:18:52
R W Run
6.41 KB
2026-03-11 16:18:51
R W Run
160 KB
2026-03-11 16:18:51
R W Run
6.72 KB
2026-03-11 16:18:52
R W Run
10.92 KB
2026-03-11 16:18:51
R W Run
4.77 KB
2026-03-11 16:18:51
R W Run
3.38 KB
2026-03-11 16:18:51
R W Run
11.18 KB
2026-03-11 16:18:51
R W Run
62.19 KB
2026-03-11 16:18:51
R W Run
2.46 KB
2026-03-11 16:18:51
R W Run
9.17 KB
2026-03-11 16:18:51
R W Run
32.15 KB
2026-03-11 16:18:51
R W Run
34.05 KB
2026-03-11 16:18:52
R W Run
7.15 KB
2026-03-11 16:18:51
R W Run
3.47 KB
2026-03-11 16:18:52
R W Run
1.87 KB
2026-03-11 16:18:52
R W Run
30.91 KB
2026-03-11 16:18:51
R W Run
7.29 KB
2026-03-11 16:18:52
R W Run
7.35 KB
2026-03-11 16:18:51
R W Run
12.54 KB
2026-03-11 16:18:51
R W Run
19.12 KB
2026-03-11 16:18:51
R W Run
18.12 KB
2026-03-11 16:18:52
R W Run
39.99 KB
2026-03-11 16:18:52
R W Run
5.17 KB
2026-03-11 16:18:52
R W Run
979 By
2026-03-11 16:18:51
R W Run
18.44 KB
2026-03-11 16:18:52
R W Run
10.24 KB
2026-03-11 16:18:51
R W Run
1.77 KB
2026-03-11 16:18:52
R W Run
34.9 KB
2026-03-11 16:18:51
R W Run
7.19 KB
2026-03-11 16:18:52
R W Run
160.5 KB
2026-03-11 16:18:51
R W Run
64.27 KB
2026-03-11 16:18:51
R W Run
27.95 KB
2026-03-11 16:18:51
R W Run
4.69 KB
2026-03-11 16:18:51
R W Run
2.94 KB
2026-03-11 16:18:51
R W Run
43.13 KB
2026-03-11 16:18:52
R W Run
2.25 KB
2026-03-11 16:18:52
R W Run
22.5 KB
2026-03-11 16:18:51
R W Run
13.01 KB
2026-03-11 16:18:52
R W Run
3.27 KB
2026-03-11 16:18:51
R W Run
18 KB
2026-03-11 16:18:51
R W Run
210.4 KB
2026-03-11 16:18:52
R W Run
25.86 KB
2026-03-11 16:18:52
R W Run
115.85 KB
2026-03-11 16:18:51
R W Run
373 By
2026-03-11 16:18:52
R W Run
343 By
2026-03-11 16:18:52
R W Run
338 By
2026-03-11 16:18:51
R W Run
100.73 KB
2026-03-11 16:18:52
R W Run
130.93 KB
2026-03-11 16:18:51
R W Run
19.1 KB
2026-03-11 16:18:51
R W Run
17.41 KB
2026-03-11 16:18:52
R W Run
41.98 KB
2026-03-11 16:18:52
R W Run
400 By
2026-03-11 16:18:52
R W Run
11.1 KB
2026-03-11 16:18:52
R W Run
37.02 KB
2026-03-11 16:18:51
R W Run
2.24 KB
2026-03-11 16:18:51
R W Run
188.13 KB
2026-03-11 16:18:51
R W Run
338 By
2026-03-11 16:18:51
R W Run
38 KB
2026-03-11 16:18:51
R W Run
4.02 KB
2026-03-11 16:18:52
R W Run
5.38 KB
2026-03-11 16:18:51
R W Run
3.05 KB
2026-03-11 16:18:52
R W Run
2.61 KB
2026-03-11 16:18:51
R W Run
1.16 KB
2026-03-11 16:18:52
R W Run
4.04 KB
2026-03-11 16:18:51
R W Run
3.71 KB
2026-03-11 16:18:51
R W Run
24.6 KB
2026-03-11 16:18:51
R W Run
9.56 KB
2026-03-11 16:18:51
R W Run
346.43 KB
2026-03-11 16:18:52
R W Run
281.84 KB
2026-03-11 16:18:52
R W Run
14.95 KB
2026-03-11 16:18:51
R W Run
8.44 KB
2026-03-11 16:18:52
R W Run
168.95 KB
2026-03-11 16:18:52
R W Run
20.71 KB
2026-03-11 16:18:52
R W Run
25.27 KB
2026-03-11 16:18:51
R W Run
5.72 KB
2026-03-11 16:18:51
R W Run
4.63 KB
2026-03-11 16:18:52
R W Run
81.73 KB
2026-03-11 16:18:51
R W Run
67.18 KB
2026-03-11 16:18:51
R W Run
156.36 KB
2026-03-11 16:18:52
R W Run
55.19 KB
2026-03-11 16:18:51
R W Run
162 By
2026-03-11 16:18:51
R W Run
61.72 KB
2026-03-11 16:18:51
R W Run
216.06 KB
2026-03-11 16:18:52
R W Run
65.09 KB
2026-03-11 16:18:51
R W Run
25.24 KB
2026-03-11 16:18:52
R W Run
4.81 KB
2026-03-11 16:18:51
R W Run
6.48 KB
2026-03-11 16:18:52
R W Run
21.25 KB
2026-03-11 16:18:51
R W Run
2.79 KB
2026-03-11 16:18:52
R W Run
89.69 KB
2026-03-11 16:18:52
R W Run
19.42 KB
2026-03-11 16:18:52
R W Run
3.69 KB
2026-03-11 16:18:52
R W Run
4.11 KB
2026-03-11 16:18:51
R W Run
40.74 KB
2026-03-11 16:18:51
R W Run
25.38 KB
2026-03-11 16:18:51
R W Run
43.31 KB
2026-03-11 16:18:52
R W Run
102.57 KB
2026-03-11 16:18:52
R W Run
6.18 KB
2026-03-11 16:18:51
R W Run
124.47 KB
2026-03-11 16:18:52
R W Run
35.65 KB
2026-03-11 16:18:52
R W Run
6.94 KB
2026-03-11 16:18:52
R W Run
67.04 KB
2026-03-11 16:18:52
R W Run
10.62 KB
2026-03-11 16:18:51
R W Run
289.35 KB
2026-03-11 16:18:52
R W Run
36.23 KB
2026-03-11 16:18:51
R W Run
200 By
2026-03-11 16:18:52
R W Run
200 By
2026-03-11 16:18:52
R W Run
98.29 KB
2026-03-11 16:18:52
R W Run
30.02 KB
2026-03-11 16:18:52
R W Run
19.03 KB
2026-03-11 16:18:52
R W Run
5.06 KB
2026-03-11 16:18:52
R W Run
255 By
2026-03-11 16:18:51
R W Run
22.66 KB
2026-03-11 16:18:52
R W Run
154.63 KB
2026-03-11 16:18:51
R W Run
9.68 KB
2026-03-11 16:18:51
R W Run
258 By
2026-03-11 16:18:51
R W Run
23.49 KB
2026-03-11 16:18:51
R W Run
3.16 KB
2026-03-11 16:18:51
R W Run
8.4 KB
2026-03-11 16:18:52
R W Run
441 By
2026-03-11 16:18:51
R W Run
7.39 KB
2026-03-11 16:18:51
R W Run
173 KB
2026-03-11 16:18:52
R W Run
544 By
2026-03-11 16:18:52
R W Run
4.17 KB
2026-03-11 16:18:51
R W Run
35.97 KB
2026-03-11 16:18:52
R W Run
1.69 KB
2026-03-11 16:18:51
R W Run
2.84 KB
2026-03-11 16:18:52
R W Run
6.09 KB
2026-03-11 16:18:51
R W Run
8.71 KB
2026-03-11 16:18:51
R W Run
131.84 KB
2026-03-11 16:18:51
R W Run
37.45 KB
2026-03-11 16:18:51
R W Run
173.89 KB
2026-03-11 16:18:51
R W Run
7.09 KB
2026-03-11 16:18:51
R W Run
6.41 KB
2026-03-11 16:18:51
R W Run
1.08 KB
2026-03-11 16:18:51
R W Run
69.46 KB
2026-03-11 16:18:52
R W Run
445 By
2026-03-11 16:18:51
R W Run
799 By
2026-03-11 16:18:52
R W Run
error_log
📄widgets.php
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/documentation/article/manage-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 */
26global $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 * @since 2.2.0
32 *
33 * @global array $wp_registered_sidebars The registered sidebars.
34 */
35$wp_registered_sidebars = array();
36
37/**
38 * Stores the registered widgets.
39 *
40 * @since 2.2.0
41 *
42 * @global array $wp_registered_widgets The registered widgets.
43 */
44$wp_registered_widgets = array();
45
46/**
47 * Stores the registered widget controls (options).
48 *
49 * @since 2.2.0
50 *
51 * @global array $wp_registered_widget_controls The registered widget controls.
52 */
53$wp_registered_widget_controls = array();
54
55/**
56 * Stores the registered widget updates.
57 *
58 * @since 2.8.0
59 *
60 * @global array $wp_registered_widget_updates The registered widget updates.
61 */
62$wp_registered_widget_updates = array();
63
64/**
65 * Private
66 *
67 * @global array $_wp_sidebars_widgets
68 */
69$_wp_sidebars_widgets = array();
70
71/**
72 * Private
73 *
74 * @global array $_wp_deprecated_widgets_callbacks
75 */
76$GLOBALS['_wp_deprecated_widgets_callbacks'] = array(
77 'wp_widget_pages',
78 'wp_widget_pages_control',
79 'wp_widget_calendar',
80 'wp_widget_calendar_control',
81 'wp_widget_archives',
82 'wp_widget_archives_control',
83 'wp_widget_links',
84 'wp_widget_meta',
85 'wp_widget_meta_control',
86 'wp_widget_search',
87 'wp_widget_recent_entries',
88 'wp_widget_recent_entries_control',
89 'wp_widget_tag_cloud',
90 'wp_widget_tag_cloud_control',
91 'wp_widget_categories',
92 'wp_widget_categories_control',
93 'wp_widget_text',
94 'wp_widget_text_control',
95 'wp_widget_rss',
96 'wp_widget_rss_control',
97 'wp_widget_recent_comments',
98 'wp_widget_recent_comments_control',
99);
100
101//
102// Template tags & API functions.
103//
104
105/**
106 * Registers a widget.
107 *
108 * Registers a WP_Widget widget
109 *
110 * @since 2.8.0
111 * @since 4.6.0 Updated the `$widget` parameter to also accept a WP_Widget instance object
112 * instead of simply a `WP_Widget` subclass name.
113 *
114 * @see WP_Widget
115 *
116 * @global WP_Widget_Factory $wp_widget_factory
117 *
118 * @param string|WP_Widget $widget Either the name of a `WP_Widget` subclass or an instance of a `WP_Widget` subclass.
119 */
120function register_widget( $widget ) {
121 global $wp_widget_factory;
122
123 $wp_widget_factory->register( $widget );
124}
125
126/**
127 * Unregisters a widget.
128 *
129 * Unregisters a WP_Widget widget. Useful for un-registering default widgets.
130 * Run within a function hooked to the {@see 'widgets_init'} action.
131 *
132 * @since 2.8.0
133 * @since 4.6.0 Updated the `$widget` parameter to also accept a WP_Widget instance object
134 * instead of simply a `WP_Widget` subclass name.
135 *
136 * @see WP_Widget
137 *
138 * @global WP_Widget_Factory $wp_widget_factory
139 *
140 * @param string|WP_Widget $widget Either the name of a `WP_Widget` subclass or an instance of a `WP_Widget` subclass.
141 */
142function unregister_widget( $widget ) {
143 global $wp_widget_factory;
144
145 $wp_widget_factory->unregister( $widget );
146}
147
148/**
149 * Creates multiple sidebars.
150 *
151 * If you wanted to quickly create multiple sidebars for a theme or internally.
152 * This function will allow you to do so. If you don't pass the 'name' and/or
153 * 'id' in `$args`, then they will be built for you.
154 *
155 * @since 2.2.0
156 *
157 * @see register_sidebar() The second parameter is documented by register_sidebar() and is the same here.
158 *
159 * @global array $wp_registered_sidebars The new sidebars are stored in this array by sidebar ID.
160 *
161 * @param int $number Optional. Number of sidebars to create. Default 1.
162 * @param array|string $args {
163 * Optional. Array or string of arguments for building a sidebar.
164 *
165 * @type string $id The base string of the unique identifier for each sidebar. If provided, and multiple
166 * sidebars are being defined, the ID will have "-2" appended, and so on.
167 * Default 'sidebar-' followed by the number the sidebar creation is currently at.
168 * @type string $name The name or title for the sidebars displayed in the admin dashboard. If registering
169 * more than one sidebar, include '%d' in the string as a placeholder for the uniquely
170 * assigned number for each sidebar.
171 * Default 'Sidebar' for the first sidebar, otherwise 'Sidebar %d'.
172 * }
173 */
174function register_sidebars( $number = 1, $args = array() ) {
175 global $wp_registered_sidebars;
176 $number = (int) $number;
177
178 if ( is_string( $args ) ) {
179 parse_str( $args, $args );
180 }
181
182 for ( $i = 1; $i <= $number; $i++ ) {
183 $_args = $args;
184
185 if ( $number > 1 ) {
186 if ( isset( $args['name'] ) ) {
187 $_args['name'] = sprintf( $args['name'], $i );
188 } else {
189 /* translators: %d: Sidebar number. */
190 $_args['name'] = sprintf( __( 'Sidebar %d' ), $i );
191 }
192 } else {
193 $_args['name'] = isset( $args['name'] ) ? $args['name'] : __( 'Sidebar' );
194 }
195
196 /*
197 * Custom specified ID's are suffixed if they exist already.
198 * Automatically generated sidebar names need to be suffixed regardless starting at -0.
199 */
200 if ( isset( $args['id'] ) ) {
201 $_args['id'] = $args['id'];
202 $n = 2; // Start at -2 for conflicting custom IDs.
203 while ( is_registered_sidebar( $_args['id'] ) ) {
204 $_args['id'] = $args['id'] . '-' . $n++;
205 }
206 } else {
207 $n = count( $wp_registered_sidebars );
208 do {
209 $_args['id'] = 'sidebar-' . ++$n;
210 } while ( is_registered_sidebar( $_args['id'] ) );
211 }
212 register_sidebar( $_args );
213 }
214}
215
216/**
217 * Builds the definition for a single sidebar and returns the ID.
218 *
219 * Accepts either a string or an array and then parses that against a set
220 * of default arguments for the new sidebar. WordPress will automatically
221 * generate a sidebar ID and name based on the current number of registered
222 * sidebars if those arguments are not included.
223 *
224 * When allowing for automatic generation of the name and ID parameters, keep
225 * in mind that the incrementor for your sidebar can change over time depending
226 * on what other plugins and themes are installed.
227 *
228 * If theme support for 'widgets' has not yet been added when this function is
229 * called, it will be automatically enabled through the use of add_theme_support().
230 *
231 * @since 2.2.0
232 * @since 5.6.0 Added the `before_sidebar` and `after_sidebar` arguments.
233 * @since 5.9.0 Added the `show_in_rest` argument.
234 *
235 * @global array $wp_registered_sidebars The registered sidebars.
236 *
237 * @param array|string $args {
238 * Optional. Array or string of arguments for the sidebar being registered.
239 *
240 * @type string $name The name or title of the sidebar displayed in the Widgets
241 * interface. Default 'Sidebar $instance'.
242 * @type string $id The unique identifier by which the sidebar will be called.
243 * Default 'sidebar-$instance'.
244 * @type string $description Description of the sidebar, displayed in the Widgets interface.
245 * Default empty string.
246 * @type string $class Extra CSS class to assign to the sidebar in the Widgets interface.
247 * Default empty.
248 * @type string $before_widget HTML content to prepend to each widget's HTML output when assigned
249 * to this sidebar. Receives the widget's ID attribute as `%1$s`
250 * and class name as `%2$s`. Default is an opening list item element.
251 * @type string $after_widget HTML content to append to each widget's HTML output when assigned
252 * to this sidebar. Default is a closing list item element.
253 * @type string $before_title HTML content to prepend to the sidebar title when displayed.
254 * Default is an opening h2 element.
255 * @type string $after_title HTML content to append to the sidebar title when displayed.
256 * Default is a closing h2 element.
257 * @type string $before_sidebar HTML content to prepend to the sidebar when displayed.
258 * Receives the `$id` argument as `%1$s` and `$class` as `%2$s`.
259 * Outputs after the {@see 'dynamic_sidebar_before'} action.
260 * Default empty string.
261 * @type string $after_sidebar HTML content to append to the sidebar when displayed.
262 * Outputs before the {@see 'dynamic_sidebar_after'} action.
263 * Default empty string.
264 * @type bool $show_in_rest Whether to show this sidebar publicly in the REST API.
265 * Defaults to only showing the sidebar to administrator users.
266 * }
267 * @return string Sidebar ID added to $wp_registered_sidebars global.
268 */
269function register_sidebar( $args = array() ) {
270 global $wp_registered_sidebars;
271
272 $i = count( $wp_registered_sidebars ) + 1;
273
274 $id_is_empty = empty( $args['id'] );
275
276 $defaults = array(
277 /* translators: %d: Sidebar number. */
278 'name' => sprintf( __( 'Sidebar %d' ), $i ),
279 'id' => "sidebar-$i",
280 'description' => '',
281 'class' => '',
282 'before_widget' => '<li id="%1$s" class="widget %2$s">',
283 'after_widget' => "</li>\n",
284 'before_title' => '<h2 class="widgettitle">',
285 'after_title' => "</h2>\n",
286 'before_sidebar' => '',
287 'after_sidebar' => '',
288 'show_in_rest' => false,
289 );
290
291 /**
292 * Filters the sidebar default arguments.
293 *
294 * @since 5.3.0
295 *
296 * @see register_sidebar()
297 *
298 * @param array $defaults The default sidebar arguments.
299 */
300 $sidebar = wp_parse_args( $args, apply_filters( 'register_sidebar_defaults', $defaults ) );
301
302 if ( $id_is_empty ) {
303 _doing_it_wrong(
304 __FUNCTION__,
305 sprintf(
306 /* translators: 1: The 'id' argument, 2: Sidebar name, 3: Recommended 'id' value. */
307 __( '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.' ),
308 '<code>id</code>',
309 $sidebar['name'],
310 $sidebar['id']
311 ),
312 '4.2.0'
313 );
314 }
315
316 $wp_registered_sidebars[ $sidebar['id'] ] = $sidebar;
317
318 add_theme_support( 'widgets' );
319
320 /**
321 * Fires once a sidebar has been registered.
322 *
323 * @since 3.0.0
324 *
325 * @param array $sidebar Parsed arguments for the registered sidebar.
326 */
327 do_action( 'register_sidebar', $sidebar );
328
329 return $sidebar['id'];
330}
331
332/**
333 * Removes a sidebar from the list.
334 *
335 * @since 2.2.0
336 *
337 * @global array $wp_registered_sidebars The registered sidebars.
338 *
339 * @param string|int $sidebar_id The ID of the sidebar when it was registered.
340 */
341function unregister_sidebar( $sidebar_id ) {
342 global $wp_registered_sidebars;
343
344 unset( $wp_registered_sidebars[ $sidebar_id ] );
345}
346
347/**
348 * Checks if a sidebar is registered.
349 *
350 * @since 4.4.0
351 *
352 * @global array $wp_registered_sidebars The registered sidebars.
353 *
354 * @param string|int $sidebar_id The ID of the sidebar when it was registered.
355 * @return bool True if the sidebar is registered, false otherwise.
356 */
357function is_registered_sidebar( $sidebar_id ) {
358 global $wp_registered_sidebars;
359
360 return isset( $wp_registered_sidebars[ $sidebar_id ] );
361}
362
363/**
364 * Registers an instance of a widget.
365 *
366 * The default widget option is 'classname' that can be overridden.
367 *
368 * The function can also be used to un-register widgets when `$output_callback`
369 * parameter is an empty string.
370 *
371 * @since 2.2.0
372 * @since 5.3.0 Formalized the existing and already documented `...$params` parameter
373 * by adding it to the function signature.
374 * @since 5.8.0 Added show_instance_in_rest option.
375 *
376 * @global array $wp_registered_widgets Uses stored registered widgets.
377 * @global array $wp_registered_widget_controls Stores the registered widget controls (options).
378 * @global array $wp_registered_widget_updates The registered widget updates.
379 * @global array $_wp_deprecated_widgets_callbacks
380 *
381 * @param int|string $id Widget ID.
382 * @param string $name Widget display title.
383 * @param callable $output_callback Run when widget is called.
384 * @param array $options {
385 * Optional. An array of supplementary widget options for the instance.
386 *
387 * @type string $classname Class name for the widget's HTML container. Default is a shortened
388 * version of the output callback name.
389 * @type string $description Widget description for display in the widget administration
390 * panel and/or theme.
391 * @type bool $show_instance_in_rest Whether to show the widget's instance settings in the REST API.
392 * Only available for WP_Widget based widgets.
393 * }
394 * @param mixed ...$params Optional additional parameters to pass to the callback function when it's called.
395 */
396function wp_register_sidebar_widget( $id, $name, $output_callback, $options = array(), ...$params ) {
397 global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates, $_wp_deprecated_widgets_callbacks;
398
399 $id = strtolower( $id );
400
401 if ( empty( $output_callback ) ) {
402 unset( $wp_registered_widgets[ $id ] );
403 return;
404 }
405
406 $id_base = _get_widget_id_base( $id );
407 if ( in_array( $output_callback, $_wp_deprecated_widgets_callbacks, true ) && ! is_callable( $output_callback ) ) {
408 unset( $wp_registered_widget_controls[ $id ] );
409 unset( $wp_registered_widget_updates[ $id_base ] );
410 return;
411 }
412
413 $defaults = array( 'classname' => $output_callback );
414 $options = wp_parse_args( $options, $defaults );
415 $widget = array(
416 'name' => $name,
417 'id' => $id,
418 'callback' => $output_callback,
419 'params' => $params,
420 );
421 $widget = array_merge( $widget, $options );
422
423 if ( is_callable( $output_callback ) && ( ! isset( $wp_registered_widgets[ $id ] ) || did_action( 'widgets_init' ) ) ) {
424
425 /**
426 * Fires once for each registered widget.
427 *
428 * @since 3.0.0
429 *
430 * @param array $widget An array of default widget arguments.
431 */
432 do_action( 'wp_register_sidebar_widget', $widget );
433 $wp_registered_widgets[ $id ] = $widget;
434 }
435}
436
437/**
438 * Retrieves description for widget.
439 *
440 * When registering widgets, the options can also include 'description' that
441 * describes the widget for display on the widget administration panel or
442 * in the theme.
443 *
444 * @since 2.5.0
445 *
446 * @global array $wp_registered_widgets The registered widgets.
447 *
448 * @param int|string $id Widget ID.
449 * @return string|void Widget description, if available.
450 */
451function wp_widget_description( $id ) {
452 if ( ! is_scalar( $id ) ) {
453 return;
454 }
455
456 global $wp_registered_widgets;
457
458 if ( isset( $wp_registered_widgets[ $id ]['description'] ) ) {
459 return esc_html( $wp_registered_widgets[ $id ]['description'] );
460 }
461}
462
463/**
464 * Retrieves description for a sidebar.
465 *
466 * When registering sidebars a 'description' parameter can be included that
467 * describes the sidebar for display on the widget administration panel.
468 *
469 * @since 2.9.0
470 *
471 * @global array $wp_registered_sidebars The registered sidebars.
472 *
473 * @param string $id sidebar ID.
474 * @return string|void Sidebar description, if available.
475 */
476function wp_sidebar_description( $id ) {
477 if ( ! is_scalar( $id ) ) {
478 return;
479 }
480
481 global $wp_registered_sidebars;
482
483 if ( isset( $wp_registered_sidebars[ $id ]['description'] ) ) {
484 return wp_kses( $wp_registered_sidebars[ $id ]['description'], 'sidebar_description' );
485 }
486}
487
488/**
489 * Remove widget from sidebar.
490 *
491 * @since 2.2.0
492 *
493 * @param int|string $id Widget ID.
494 */
495function wp_unregister_sidebar_widget( $id ) {
496
497 /**
498 * Fires just before a widget is removed from a sidebar.
499 *
500 * @since 3.0.0
501 *
502 * @param int|string $id The widget ID.
503 */
504 do_action( 'wp_unregister_sidebar_widget', $id );
505
506 wp_register_sidebar_widget( $id, '', '' );
507 wp_unregister_widget_control( $id );
508}
509
510/**
511 * Registers widget control callback for customizing options.
512 *
513 * @since 2.2.0
514 * @since 5.3.0 Formalized the existing and already documented `...$params` parameter
515 * by adding it to the function signature.
516 *
517 * @global array $wp_registered_widget_controls The registered widget controls.
518 * @global array $wp_registered_widget_updates The registered widget updates.
519 * @global array $wp_registered_widgets The registered widgets.
520 * @global array $_wp_deprecated_widgets_callbacks
521 *
522 * @param int|string $id Sidebar ID.
523 * @param string $name Sidebar display name.
524 * @param callable $control_callback Run when sidebar is displayed.
525 * @param array $options {
526 * Optional. Array or string of control options. Default empty array.
527 *
528 * @type int $height Never used. Default 200.
529 * @type int $width Width of the fully expanded control form (but try hard to use the default width).
530 * Default 250.
531 * @type int|string $id_base Required for multi-widgets, i.e widgets that allow multiple instances such as the
532 * text widget. The widget ID will end up looking like `{$id_base}-{$unique_number}`.
533 * }
534 * @param mixed ...$params Optional additional parameters to pass to the callback function when it's called.
535 */
536function wp_register_widget_control( $id, $name, $control_callback, $options = array(), ...$params ) {
537 global $wp_registered_widget_controls, $wp_registered_widget_updates, $wp_registered_widgets, $_wp_deprecated_widgets_callbacks;
538
539 $id = strtolower( $id );
540 $id_base = _get_widget_id_base( $id );
541
542 if ( empty( $control_callback ) ) {
543 unset( $wp_registered_widget_controls[ $id ] );
544 unset( $wp_registered_widget_updates[ $id_base ] );
545 return;
546 }
547
548 if ( in_array( $control_callback, $_wp_deprecated_widgets_callbacks, true ) && ! is_callable( $control_callback ) ) {
549 unset( $wp_registered_widgets[ $id ] );
550 return;
551 }
552
553 if ( isset( $wp_registered_widget_controls[ $id ] ) && ! did_action( 'widgets_init' ) ) {
554 return;
555 }
556
557 $defaults = array(
558 'width' => 250,
559 'height' => 200,
560 ); // Height is never used.
561 $options = wp_parse_args( $options, $defaults );
562 $options['width'] = (int) $options['width'];
563 $options['height'] = (int) $options['height'];
564
565 $widget = array(
566 'name' => $name,
567 'id' => $id,
568 'callback' => $control_callback,
569 'params' => $params,
570 );
571 $widget = array_merge( $widget, $options );
572
573 $wp_registered_widget_controls[ $id ] = $widget;
574
575 if ( isset( $wp_registered_widget_updates[ $id_base ] ) ) {
576 return;
577 }
578
579 if ( isset( $widget['params'][0]['number'] ) ) {
580 $widget['params'][0]['number'] = -1;
581 }
582
583 unset( $widget['width'], $widget['height'], $widget['name'], $widget['id'] );
584 $wp_registered_widget_updates[ $id_base ] = $widget;
585}
586
587/**
588 * Registers the update callback for a widget.
589 *
590 * @since 2.8.0
591 * @since 5.3.0 Formalized the existing and already documented `...$params` parameter
592 * by adding it to the function signature.
593 *
594 * @global array $wp_registered_widget_updates The registered widget updates.
595 *
596 * @param string $id_base The base ID of a widget created by extending WP_Widget.
597 * @param callable $update_callback Update callback method for the widget.
598 * @param array $options Optional. Widget control options. See wp_register_widget_control().
599 * Default empty array.
600 * @param mixed ...$params Optional additional parameters to pass to the callback function when it's called.
601 */
602function _register_widget_update_callback( $id_base, $update_callback, $options = array(), ...$params ) {
603 global $wp_registered_widget_updates;
604
605 if ( isset( $wp_registered_widget_updates[ $id_base ] ) ) {
606 if ( empty( $update_callback ) ) {
607 unset( $wp_registered_widget_updates[ $id_base ] );
608 }
609 return;
610 }
611
612 $widget = array(
613 'callback' => $update_callback,
614 'params' => $params,
615 );
616
617 $widget = array_merge( $widget, $options );
618 $wp_registered_widget_updates[ $id_base ] = $widget;
619}
620
621/**
622 * Registers the form callback for a widget.
623 *
624 * @since 2.8.0
625 * @since 5.3.0 Formalized the existing and already documented `...$params` parameter
626 * by adding it to the function signature.
627 *
628 * @global array $wp_registered_widget_controls The registered widget controls.
629 *
630 * @param int|string $id Widget ID.
631 * @param string $name Name attribute for the widget.
632 * @param callable $form_callback Form callback.
633 * @param array $options Optional. Widget control options. See wp_register_widget_control().
634 * Default empty array.
635 * @param mixed ...$params Optional additional parameters to pass to the callback function when it's called.
636 */
637
638function _register_widget_form_callback( $id, $name, $form_callback, $options = array(), ...$params ) {
639 global $wp_registered_widget_controls;
640
641 $id = strtolower( $id );
642
643 if ( empty( $form_callback ) ) {
644 unset( $wp_registered_widget_controls[ $id ] );
645 return;
646 }
647
648 if ( isset( $wp_registered_widget_controls[ $id ] ) && ! did_action( 'widgets_init' ) ) {
649 return;
650 }
651
652 $defaults = array(
653 'width' => 250,
654 'height' => 200,
655 );
656 $options = wp_parse_args( $options, $defaults );
657 $options['width'] = (int) $options['width'];
658 $options['height'] = (int) $options['height'];
659
660 $widget = array(
661 'name' => $name,
662 'id' => $id,
663 'callback' => $form_callback,
664 'params' => $params,
665 );
666 $widget = array_merge( $widget, $options );
667
668 $wp_registered_widget_controls[ $id ] = $widget;
669}
670
671/**
672 * Removes control callback for widget.
673 *
674 * @since 2.2.0
675 *
676 * @param int|string $id Widget ID.
677 */
678function wp_unregister_widget_control( $id ) {
679 wp_register_widget_control( $id, '', '' );
680}
681
682/**
683 * Displays dynamic sidebar.
684 *
685 * By default this displays the default sidebar or 'sidebar-1'. If your theme specifies the 'id' or
686 * 'name' parameter for its registered sidebars you can pass an ID or name as the $index parameter.
687 * Otherwise, you can pass in a numerical index to display the sidebar at that index.
688 *
689 * @since 2.2.0
690 *
691 * @global array $wp_registered_sidebars The registered sidebars.
692 * @global array $wp_registered_widgets The registered widgets.
693 *
694 * @param int|string $index Optional. Index, name or ID of dynamic sidebar. Default 1.
695 * @return bool True, if widget sidebar was found and called. False if not found or not called.
696 */
697function dynamic_sidebar( $index = 1 ) {
698 global $wp_registered_sidebars, $wp_registered_widgets;
699
700 if ( is_int( $index ) ) {
701 $index = "sidebar-$index";
702 } else {
703 $index = sanitize_title( $index );
704 foreach ( (array) $wp_registered_sidebars as $key => $value ) {
705 if ( sanitize_title( $value['name'] ) === $index ) {
706 $index = $key;
707 break;
708 }
709 }
710 }
711
712 $sidebars_widgets = wp_get_sidebars_widgets();
713 if ( empty( $wp_registered_sidebars[ $index ] ) || empty( $sidebars_widgets[ $index ] ) || ! is_array( $sidebars_widgets[ $index ] ) ) {
714 /** This action is documented in wp-includes/widget.php */
715 do_action( 'dynamic_sidebar_before', $index, false );
716 /** This action is documented in wp-includes/widget.php */
717 do_action( 'dynamic_sidebar_after', $index, false );
718 /** This filter is documented in wp-includes/widget.php */
719 return apply_filters( 'dynamic_sidebar_has_widgets', false, $index );
720 }
721
722 $sidebar = $wp_registered_sidebars[ $index ];
723
724 $sidebar['before_sidebar'] = sprintf( $sidebar['before_sidebar'], $sidebar['id'], $sidebar['class'] );
725
726 /**
727 * Fires before widgets are rendered in a dynamic sidebar.
728 *
729 * Note: The action also fires for empty sidebars, and on both the front end
730 * and back end, including the Inactive Widgets sidebar on the Widgets screen.
731 *
732 * @since 3.9.0
733 *
734 * @param int|string $index Index, name, or ID of the dynamic sidebar.
735 * @param bool $has_widgets Whether the sidebar is populated with widgets.
736 * Default true.
737 */
738 do_action( 'dynamic_sidebar_before', $index, true );
739
740 if ( ! is_admin() && ! empty( $sidebar['before_sidebar'] ) ) {
741 echo $sidebar['before_sidebar'];
742 }
743
744 $did_one = false;
745 foreach ( (array) $sidebars_widgets[ $index ] as $id ) {
746
747 if ( ! isset( $wp_registered_widgets[ $id ] ) ) {
748 continue;
749 }
750
751 $params = array_merge(
752 array(
753 array_merge(
754 $sidebar,
755 array(
756 'widget_id' => $id,
757 'widget_name' => $wp_registered_widgets[ $id ]['name'],
758 )
759 ),
760 ),
761 (array) $wp_registered_widgets[ $id ]['params']
762 );
763
764 // Substitute HTML `id` and `class` attributes into `before_widget`.
765 $classname_ = '';
766 foreach ( (array) $wp_registered_widgets[ $id ]['classname'] as $cn ) {
767 if ( is_string( $cn ) ) {
768 $classname_ .= '_' . $cn;
769 } elseif ( is_object( $cn ) ) {
770 $classname_ .= '_' . get_class( $cn );
771 }
772 }
773 $classname_ = ltrim( $classname_, '_' );
774
775 $params[0]['before_widget'] = sprintf(
776 $params[0]['before_widget'],
777 str_replace( '\\', '_', $id ),
778 $classname_
779 );
780
781 /**
782 * Filters the parameters passed to a widget's display callback.
783 *
784 * Note: The filter is evaluated on both the front end and back end,
785 * including for the Inactive Widgets sidebar on the Widgets screen.
786 *
787 * @since 2.5.0
788 *
789 * @see register_sidebar()
790 *
791 * @param array $params {
792 * @type array $args {
793 * An array of widget display arguments.
794 *
795 * @type string $name Name of the sidebar the widget is assigned to.
796 * @type string $id ID of the sidebar the widget is assigned to.
797 * @type string $description The sidebar description.
798 * @type string $class CSS class applied to the sidebar container.
799 * @type string $before_widget HTML markup to prepend to each widget in the sidebar.
800 * @type string $after_widget HTML markup to append to each widget in the sidebar.
801 * @type string $before_title HTML markup to prepend to the widget title when displayed.
802 * @type string $after_title HTML markup to append to the widget title when displayed.
803 * @type string $widget_id ID of the widget.
804 * @type string $widget_name Name of the widget.
805 * }
806 * @type array $widget_args {
807 * An array of multi-widget arguments.
808 *
809 * @type int $number Number increment used for multiples of the same widget.
810 * }
811 * }
812 */
813 $params = apply_filters( 'dynamic_sidebar_params', $params );
814
815 $callback = $wp_registered_widgets[ $id ]['callback'];
816
817 /**
818 * Fires before a widget's display callback is called.
819 *
820 * Note: The action fires on both the front end and back end, including
821 * for widgets in the Inactive Widgets sidebar on the Widgets screen.
822 *
823 * The action is not fired for empty sidebars.
824 *
825 * @since 3.0.0
826 *
827 * @param array $widget {
828 * An associative array of widget arguments.
829 *
830 * @type string $name Name of the widget.
831 * @type string $id Widget ID.
832 * @type callable $callback When the hook is fired on the front end, `$callback` is an array
833 * containing the widget object. Fired on the back end, `$callback`
834 * is 'wp_widget_control', see `$_callback`.
835 * @type array $params An associative array of multi-widget arguments.
836 * @type string $classname CSS class applied to the widget container.
837 * @type string $description The widget description.
838 * @type array $_callback When the hook is fired on the back end, `$_callback` is populated
839 * with an array containing the widget object, see `$callback`.
840 * }
841 */
842 do_action( 'dynamic_sidebar', $wp_registered_widgets[ $id ] );
843
844 if ( is_callable( $callback ) ) {
845 call_user_func_array( $callback, $params );
846 $did_one = true;
847 }
848 }
849
850 if ( ! is_admin() && ! empty( $sidebar['after_sidebar'] ) ) {
851 echo $sidebar['after_sidebar'];
852 }
853
854 /**
855 * Fires after widgets are rendered in a dynamic sidebar.
856 *
857 * Note: The action also fires for empty sidebars, and on both the front end
858 * and back end, including the Inactive Widgets sidebar on the Widgets screen.
859 *
860 * @since 3.9.0
861 *
862 * @param int|string $index Index, name, or ID of the dynamic sidebar.
863 * @param bool $has_widgets Whether the sidebar is populated with widgets.
864 * Default true.
865 */
866 do_action( 'dynamic_sidebar_after', $index, true );
867
868 /**
869 * Filters whether a sidebar has widgets.
870 *
871 * Note: The filter is also evaluated for empty sidebars, and on both the front end
872 * and back end, including the Inactive Widgets sidebar on the Widgets screen.
873 *
874 * @since 3.9.0
875 *
876 * @param bool $did_one Whether at least one widget was rendered in the sidebar.
877 * Default false.
878 * @param int|string $index Index, name, or ID of the dynamic sidebar.
879 */
880 return apply_filters( 'dynamic_sidebar_has_widgets', $did_one, $index );
881}
882
883/**
884 * Determines whether a given widget is displayed on the front end.
885 *
886 * Either $callback or $id_base can be used.
887 * $id_base is the first argument when extending WP_Widget class.
888 * Without the optional $widget_id parameter, returns the ID of the first sidebar
889 * in which the first instance of the widget with the given callback or $id_base is found.
890 * With the $widget_id parameter, returns the ID of the sidebar where
891 * the widget with that callback/$id_base AND that ID is found.
892 *
893 * NOTE: $widget_id and $id_base are the same for single widgets. To be effective
894 * this function has to run after widgets have initialized, at action {@see 'init'} or later.
895 *
896 * For more information on this and similar theme functions, check out
897 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
898 * Conditional Tags} article in the Theme Developer Handbook.
899 *
900 * @since 2.2.0
901 *
902 * @global array $wp_registered_widgets The registered widgets.
903 *
904 * @param callable|false $callback Optional. Widget callback to check. Default false.
905 * @param string|false $widget_id Optional. Widget ID. Optional, but needed for checking.
906 * Default false.
907 * @param string|false $id_base Optional. The base ID of a widget created by extending WP_Widget.
908 * Default false.
909 * @param bool $skip_inactive Optional. Whether to check in 'wp_inactive_widgets'.
910 * Default true.
911 * @return string|false ID of the sidebar in which the widget is active,
912 * false if the widget is not active.
913 */
914function is_active_widget( $callback = false, $widget_id = false, $id_base = false, $skip_inactive = true ) {
915 global $wp_registered_widgets;
916
917 $sidebars_widgets = wp_get_sidebars_widgets();
918
919 if ( is_array( $sidebars_widgets ) ) {
920 foreach ( $sidebars_widgets as $sidebar => $widgets ) {
921 if ( $skip_inactive && ( 'wp_inactive_widgets' === $sidebar || str_starts_with( $sidebar, 'orphaned_widgets' ) ) ) {
922 continue;
923 }
924
925 if ( is_array( $widgets ) ) {
926 foreach ( $widgets as $widget ) {
927 if ( ( $callback && isset( $wp_registered_widgets[ $widget ]['callback'] ) && $wp_registered_widgets[ $widget ]['callback'] === $callback ) || ( $id_base && _get_widget_id_base( $widget ) === $id_base ) ) {
928 if ( ! $widget_id || $widget_id === $wp_registered_widgets[ $widget ]['id'] ) {
929 return $sidebar;
930 }
931 }
932 }
933 }
934 }
935 }
936 return false;
937}
938
939/**
940 * Determines whether the dynamic sidebar is enabled and used by the theme.
941 *
942 * For more information on this and similar theme functions, check out
943 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
944 * Conditional Tags} article in the Theme Developer Handbook.
945 *
946 * @since 2.2.0
947 *
948 * @global array $wp_registered_widgets The registered widgets.
949 * @global array $wp_registered_sidebars The registered sidebars.
950 *
951 * @return bool True if using widgets, false otherwise.
952 */
953function is_dynamic_sidebar() {
954 global $wp_registered_widgets, $wp_registered_sidebars;
955
956 $sidebars_widgets = get_option( 'sidebars_widgets' );
957
958 foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) {
959 if ( ! empty( $sidebars_widgets[ $index ] ) ) {
960 foreach ( (array) $sidebars_widgets[ $index ] as $widget ) {
961 if ( array_key_exists( $widget, $wp_registered_widgets ) ) {
962 return true;
963 }
964 }
965 }
966 }
967
968 return false;
969}
970
971/**
972 * Determines whether a sidebar contains widgets.
973 *
974 * For more information on this and similar theme functions, check out
975 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
976 * Conditional Tags} article in the Theme Developer Handbook.
977 *
978 * @since 2.8.0
979 *
980 * @param string|int $index Sidebar name, id or number to check.
981 * @return bool True if the sidebar has widgets, false otherwise.
982 */
983function is_active_sidebar( $index ) {
984 $index = ( is_int( $index ) ) ? "sidebar-$index" : sanitize_title( $index );
985 $sidebars_widgets = wp_get_sidebars_widgets();
986 $is_active_sidebar = ! empty( $sidebars_widgets[ $index ] );
987
988 /**
989 * Filters whether a dynamic sidebar is considered "active".
990 *
991 * @since 3.9.0
992 *
993 * @param bool $is_active_sidebar Whether or not the sidebar should be considered "active".
994 * In other words, whether the sidebar contains any widgets.
995 * @param int|string $index Index, name, or ID of the dynamic sidebar.
996 */
997 return apply_filters( 'is_active_sidebar', $is_active_sidebar, $index );
998}
999
1000//
1001// Internal Functions.
1002//
1003
1004/**
1005 * Retrieves the full list of sidebars and their widget instance IDs.
1006 *
1007 * Will upgrade sidebar widget list, if needed. Will also save updated list, if
1008 * needed.
1009 *
1010 * @since 2.2.0
1011 * @access private
1012 *
1013 * @global array $_wp_sidebars_widgets
1014 * @global array $sidebars_widgets
1015 *
1016 * @param bool $deprecated Not used (argument deprecated).
1017 * @return array Upgraded list of widgets to version 3 array format when called from the admin.
1018 */
1019function wp_get_sidebars_widgets( $deprecated = true ) {
1020 if ( true !== $deprecated ) {
1021 _deprecated_argument( __FUNCTION__, '2.8.1' );
1022 }
1023
1024 global $_wp_sidebars_widgets, $sidebars_widgets;
1025
1026 /*
1027 * If loading from front page, consult $_wp_sidebars_widgets rather than options
1028 * to see if wp_convert_widget_settings() has made manipulations in memory.
1029 */
1030 if ( ! is_admin() ) {
1031 if ( empty( $_wp_sidebars_widgets ) ) {
1032 $_wp_sidebars_widgets = get_option( 'sidebars_widgets', array() );
1033 }
1034
1035 $sidebars_widgets = $_wp_sidebars_widgets;
1036 } else {
1037 $sidebars_widgets = get_option( 'sidebars_widgets', array() );
1038 }
1039
1040 if ( is_array( $sidebars_widgets ) && isset( $sidebars_widgets['array_version'] ) ) {
1041 unset( $sidebars_widgets['array_version'] );
1042 }
1043
1044 /**
1045 * Filters the list of sidebars and their widgets.
1046 *
1047 * @since 2.7.0
1048 *
1049 * @param array $sidebars_widgets An associative array of sidebars and their widgets.
1050 */
1051 return apply_filters( 'sidebars_widgets', $sidebars_widgets );
1052}
1053
1054/**
1055 * Retrieves the registered sidebar with the given ID.
1056 *
1057 * @since 5.9.0
1058 *
1059 * @global array $wp_registered_sidebars The registered sidebars.
1060 *
1061 * @param string $id The sidebar ID.
1062 * @return array|null The discovered sidebar, or null if it is not registered.
1063 */
1064function wp_get_sidebar( $id ) {
1065 global $wp_registered_sidebars;
1066
1067 foreach ( (array) $wp_registered_sidebars as $sidebar ) {
1068 if ( $sidebar['id'] === $id ) {
1069 return $sidebar;
1070 }
1071 }
1072
1073 if ( 'wp_inactive_widgets' === $id ) {
1074 return array(
1075 'id' => 'wp_inactive_widgets',
1076 'name' => __( 'Inactive widgets' ),
1077 );
1078 }
1079
1080 return null;
1081}
1082
1083/**
1084 * Sets the sidebar widget option to update sidebars.
1085 *
1086 * @since 2.2.0
1087 * @access private
1088 *
1089 * @global array $_wp_sidebars_widgets
1090 * @param array $sidebars_widgets Sidebar widgets and their settings.
1091 */
1092function wp_set_sidebars_widgets( $sidebars_widgets ) {
1093 global $_wp_sidebars_widgets;
1094
1095 // Clear cached value used in wp_get_sidebars_widgets().
1096 $_wp_sidebars_widgets = null;
1097
1098 if ( ! isset( $sidebars_widgets['array_version'] ) ) {
1099 $sidebars_widgets['array_version'] = 3;
1100 }
1101
1102 update_option( 'sidebars_widgets', $sidebars_widgets );
1103}
1104
1105/**
1106 * Retrieves default registered sidebars list.
1107 *
1108 * @since 2.2.0
1109 * @access private
1110 *
1111 * @global array $wp_registered_sidebars The registered sidebars.
1112 *
1113 * @return array
1114 */
1115function wp_get_widget_defaults() {
1116 global $wp_registered_sidebars;
1117
1118 $defaults = array();
1119
1120 foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) {
1121 $defaults[ $index ] = array();
1122 }
1123
1124 return $defaults;
1125}
1126
1127/**
1128 * Converts the widget settings from single to multi-widget format.
1129 *
1130 * @since 2.8.0
1131 *
1132 * @global array $_wp_sidebars_widgets
1133 *
1134 * @param string $base_name Root ID for all widgets of this type.
1135 * @param string $option_name Option name for this widget type.
1136 * @param array $settings The array of widget instance settings.
1137 * @return array The array of widget settings converted to multi-widget format.
1138 */
1139function wp_convert_widget_settings( $base_name, $option_name, $settings ) {
1140 // This test may need expanding.
1141 $single = false;
1142 $changed = false;
1143
1144 if ( empty( $settings ) ) {
1145 $single = true;
1146 } else {
1147 foreach ( array_keys( $settings ) as $number ) {
1148 if ( 'number' === $number ) {
1149 continue;
1150 }
1151 if ( ! is_numeric( $number ) ) {
1152 $single = true;
1153 break;
1154 }
1155 }
1156 }
1157
1158 if ( $single ) {
1159 $settings = array( 2 => $settings );
1160
1161 // If loading from the front page, update sidebar in memory but don't save to options.
1162 if ( is_admin() ) {
1163 $sidebars_widgets = get_option( 'sidebars_widgets' );
1164 } else {
1165 if ( empty( $GLOBALS['_wp_sidebars_widgets'] ) ) {
1166 $GLOBALS['_wp_sidebars_widgets'] = get_option( 'sidebars_widgets', array() );
1167 }
1168 $sidebars_widgets = &$GLOBALS['_wp_sidebars_widgets'];
1169 }
1170
1171 foreach ( (array) $sidebars_widgets as $index => $sidebar ) {
1172 if ( is_array( $sidebar ) ) {
1173 foreach ( $sidebar as $i => $name ) {
1174 if ( $base_name === $name ) {
1175 $sidebars_widgets[ $index ][ $i ] = "$name-2";
1176 $changed = true;
1177 break 2;
1178 }
1179 }
1180 }
1181 }
1182
1183 if ( is_admin() && $changed ) {
1184 update_option( 'sidebars_widgets', $sidebars_widgets );
1185 }
1186 }
1187
1188 $settings['_multiwidget'] = 1;
1189 if ( is_admin() ) {
1190 update_option( $option_name, $settings );
1191 }
1192
1193 return $settings;
1194}
1195
1196/**
1197 * Outputs an arbitrary widget as a template tag.
1198 *
1199 * @since 2.8.0
1200 *
1201 * @global WP_Widget_Factory $wp_widget_factory
1202 *
1203 * @param string $widget The widget's PHP class name (see class-wp-widget.php).
1204 * @param array $instance Optional. The widget's instance settings. Default empty array.
1205 * @param array $args {
1206 * Optional. Array of arguments to configure the display of the widget.
1207 *
1208 * @type string $before_widget HTML content that will be prepended to the widget's HTML output.
1209 * Default `<div class="widget %s">`, where `%s` is the widget's class name.
1210 * @type string $after_widget HTML content that will be appended to the widget's HTML output.
1211 * Default `</div>`.
1212 * @type string $before_title HTML content that will be prepended to the widget's title when displayed.
1213 * Default `<h2 class="widgettitle">`.
1214 * @type string $after_title HTML content that will be appended to the widget's title when displayed.
1215 * Default `</h2>`.
1216 * }
1217 */
1218function the_widget( $widget, $instance = array(), $args = array() ) {
1219 global $wp_widget_factory;
1220
1221 if ( ! isset( $wp_widget_factory->widgets[ $widget ] ) ) {
1222 _doing_it_wrong(
1223 __FUNCTION__,
1224 sprintf(
1225 /* translators: %s: register_widget() */
1226 __( 'Widgets need to be registered using %s, before they can be displayed.' ),
1227 '<code>register_widget()</code>'
1228 ),
1229 '4.9.0'
1230 );
1231 return;
1232 }
1233
1234 $widget_obj = $wp_widget_factory->widgets[ $widget ];
1235 if ( ! ( $widget_obj instanceof WP_Widget ) ) {
1236 return;
1237 }
1238
1239 $default_args = array(
1240 'before_widget' => '<div class="widget %s">',
1241 'after_widget' => '</div>',
1242 'before_title' => '<h2 class="widgettitle">',
1243 'after_title' => '</h2>',
1244 );
1245 $args = wp_parse_args( $args, $default_args );
1246 $args['before_widget'] = sprintf( $args['before_widget'], $widget_obj->widget_options['classname'] );
1247
1248 $instance = wp_parse_args( $instance );
1249
1250 /** This filter is documented in wp-includes/class-wp-widget.php */
1251 $instance = apply_filters( 'widget_display_callback', $instance, $widget_obj, $args );
1252
1253 if ( false === $instance ) {
1254 return;
1255 }
1256
1257 /**
1258 * Fires before rendering the requested widget.
1259 *
1260 * @since 3.0.0
1261 *
1262 * @param string $widget The widget's class name.
1263 * @param array $instance The current widget instance's settings.
1264 * @param array $args An array of the widget's sidebar arguments.
1265 */
1266 do_action( 'the_widget', $widget, $instance, $args );
1267
1268 $widget_obj->_set( -1 );
1269 $widget_obj->widget( $args, $instance );
1270}
1271
1272/**
1273 * Retrieves the widget ID base value.
1274 *
1275 * @since 2.8.0
1276 *
1277 * @param string $id Widget ID.
1278 * @return string Widget ID base.
1279 */
1280function _get_widget_id_base( $id ) {
1281 return preg_replace( '/-[0-9]+$/', '', $id );
1282}
1283
1284/**
1285 * Handles sidebars config after theme change.
1286 *
1287 * @access private
1288 * @since 3.3.0
1289 *
1290 * @global array $sidebars_widgets
1291 */
1292function _wp_sidebars_changed() {
1293 global $sidebars_widgets;
1294
1295 if ( ! is_array( $sidebars_widgets ) ) {
1296 $sidebars_widgets = wp_get_sidebars_widgets();
1297 }
1298
1299 retrieve_widgets( true );
1300}
1301
1302/**
1303 * Validates and remaps any "orphaned" widgets to wp_inactive_widgets sidebar,
1304 * and saves the widget settings. This has to run at least on each theme change.
1305 *
1306 * For example, let's say theme A has a "footer" sidebar, and theme B doesn't have one.
1307 * After switching from theme A to theme B, all the widgets previously assigned
1308 * to the footer would be inaccessible. This function detects this scenario, and
1309 * moves all the widgets previously assigned to the footer under wp_inactive_widgets.
1310 *
1311 * Despite the word "retrieve" in the name, this function actually updates the database
1312 * and the global `$sidebars_widgets`. For that reason it should not be run on front end,
1313 * unless the `$theme_changed` value is 'customize' (to bypass the database write).
1314 *
1315 * @since 2.8.0
1316 *
1317 * @global array $wp_registered_sidebars The registered sidebars.
1318 * @global array $sidebars_widgets
1319 * @global array $wp_registered_widgets The registered widgets.
1320 *
1321 * @param string|bool $theme_changed Whether the theme was changed as a boolean. A value
1322 * of 'customize' defers updates for the Customizer.
1323 * @return array Updated sidebars widgets.
1324 */
1325function retrieve_widgets( $theme_changed = false ) {
1326 global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;
1327
1328 $registered_sidebars_keys = array_keys( $wp_registered_sidebars );
1329 $registered_widgets_ids = array_keys( $wp_registered_widgets );
1330
1331 if ( ! is_array( get_theme_mod( 'sidebars_widgets' ) ) ) {
1332 if ( empty( $sidebars_widgets ) ) {
1333 return array();
1334 }
1335
1336 unset( $sidebars_widgets['array_version'] );
1337
1338 $sidebars_widgets_keys = array_keys( $sidebars_widgets );
1339 sort( $sidebars_widgets_keys );
1340 sort( $registered_sidebars_keys );
1341
1342 if ( $sidebars_widgets_keys === $registered_sidebars_keys ) {
1343 $sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids );
1344
1345 return $sidebars_widgets;
1346 }
1347 }
1348
1349 // Discard invalid, theme-specific widgets from sidebars.
1350 $sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids );
1351 $sidebars_widgets = wp_map_sidebars_widgets( $sidebars_widgets );
1352
1353 // Replace non-array values inside the array with an empty array.
1354 foreach ( $sidebars_widgets as $key => $value ) {
1355 if ( ! is_array( $value ) ) {
1356 $sidebars_widgets[ $key ] = array();
1357 }
1358 }
1359
1360 // Find hidden/lost multi-widget instances.
1361 $shown_widgets = array_merge( ...array_values( $sidebars_widgets ) );
1362 $lost_widgets = array_diff( $registered_widgets_ids, $shown_widgets );
1363
1364 foreach ( $lost_widgets as $key => $widget_id ) {
1365 $number = preg_replace( '/.+?-([0-9]+)$/', '$1', $widget_id );
1366
1367 // Only keep active and default widgets.
1368 if ( is_numeric( $number ) && (int) $number < 2 ) {
1369 unset( $lost_widgets[ $key ] );
1370 }
1371 }
1372 $sidebars_widgets['wp_inactive_widgets'] = array_merge( $lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets'] );
1373
1374 if ( 'customize' !== $theme_changed ) {
1375 // Update the widgets settings in the database.
1376 wp_set_sidebars_widgets( $sidebars_widgets );
1377 }
1378
1379 return $sidebars_widgets;
1380}
1381
1382/**
1383 * Compares a list of sidebars with their widgets against an allowed list.
1384 *
1385 * @since 4.9.0
1386 * @since 4.9.2 Always tries to restore widget assignments from previous data, not just if sidebars needed mapping.
1387 *
1388 * @global array $wp_registered_sidebars The registered sidebars.
1389 *
1390 * @param array $existing_sidebars_widgets List of sidebars and their widget instance IDs.
1391 * @return array Mapped sidebars widgets.
1392 */
1393function wp_map_sidebars_widgets( $existing_sidebars_widgets ) {
1394 global $wp_registered_sidebars;
1395
1396 $new_sidebars_widgets = array(
1397 'wp_inactive_widgets' => array(),
1398 );
1399
1400 // Short-circuit if there are no sidebars to map.
1401 if ( ! is_array( $existing_sidebars_widgets ) || empty( $existing_sidebars_widgets ) ) {
1402 return $new_sidebars_widgets;
1403 }
1404
1405 foreach ( $existing_sidebars_widgets as $sidebar => $widgets ) {
1406 if ( 'wp_inactive_widgets' === $sidebar || str_starts_with( $sidebar, 'orphaned_widgets' ) ) {
1407 $new_sidebars_widgets['wp_inactive_widgets'] = array_merge( $new_sidebars_widgets['wp_inactive_widgets'], (array) $widgets );
1408 unset( $existing_sidebars_widgets[ $sidebar ] );
1409 }
1410 }
1411
1412 // If old and new theme have just one sidebar, map it and we're done.
1413 if ( 1 === count( $existing_sidebars_widgets ) && 1 === count( $wp_registered_sidebars ) ) {
1414 $new_sidebars_widgets[ key( $wp_registered_sidebars ) ] = array_pop( $existing_sidebars_widgets );
1415
1416 return $new_sidebars_widgets;
1417 }
1418
1419 // Map locations with the same slug.
1420 $existing_sidebars = array_keys( $existing_sidebars_widgets );
1421
1422 foreach ( $wp_registered_sidebars as $sidebar => $name ) {
1423 if ( in_array( $sidebar, $existing_sidebars, true ) ) {
1424 $new_sidebars_widgets[ $sidebar ] = $existing_sidebars_widgets[ $sidebar ];
1425 unset( $existing_sidebars_widgets[ $sidebar ] );
1426 } elseif ( ! array_key_exists( $sidebar, $new_sidebars_widgets ) ) {
1427 $new_sidebars_widgets[ $sidebar ] = array();
1428 }
1429 }
1430
1431 // If there are more sidebars, try to map them.
1432 if ( ! empty( $existing_sidebars_widgets ) ) {
1433
1434 /*
1435 * If old and new theme both have sidebars that contain phrases
1436 * from within the same group, make an educated guess and map it.
1437 */
1438 $common_slug_groups = array(
1439 array( 'sidebar', 'primary', 'main', 'right' ),
1440 array( 'second', 'left' ),
1441 array( 'sidebar-2', 'footer', 'bottom' ),
1442 array( 'header', 'top' ),
1443 );
1444
1445 // Go through each group...
1446 foreach ( $common_slug_groups as $slug_group ) {
1447
1448 // ...and see if any of these slugs...
1449 foreach ( $slug_group as $slug ) {
1450
1451 // ...and any of the new sidebars...
1452 foreach ( $wp_registered_sidebars as $new_sidebar => $args ) {
1453
1454 // ...actually match!
1455 if ( false === stripos( $new_sidebar, $slug ) && false === stripos( $slug, $new_sidebar ) ) {
1456 continue;
1457 }
1458
1459 // Then see if any of the existing sidebars...
1460 foreach ( $existing_sidebars_widgets as $sidebar => $widgets ) {
1461
1462 // ...and any slug in the same group...
1463 foreach ( $slug_group as $slug ) {
1464
1465 // ... have a match as well.
1466 if ( false === stripos( $sidebar, $slug ) && false === stripos( $slug, $sidebar ) ) {
1467 continue;
1468 }
1469
1470 // Make sure this sidebar wasn't mapped and removed previously.
1471 if ( ! empty( $existing_sidebars_widgets[ $sidebar ] ) ) {
1472
1473 // We have a match that can be mapped!
1474 $new_sidebars_widgets[ $new_sidebar ] = array_merge( $new_sidebars_widgets[ $new_sidebar ], $existing_sidebars_widgets[ $sidebar ] );
1475
1476 // Remove the mapped sidebar so it can't be mapped again.
1477 unset( $existing_sidebars_widgets[ $sidebar ] );
1478
1479 // Go back and check the next new sidebar.
1480 continue 3;
1481 }
1482 } // End foreach ( $slug_group as $slug ).
1483 } // End foreach ( $existing_sidebars_widgets as $sidebar => $widgets ).
1484 } // End foreach ( $wp_registered_sidebars as $new_sidebar => $args ).
1485 } // End foreach ( $slug_group as $slug ).
1486 } // End foreach ( $common_slug_groups as $slug_group ).
1487 }
1488
1489 // Move any left over widgets to inactive sidebar.
1490 foreach ( $existing_sidebars_widgets as $widgets ) {
1491 if ( is_array( $widgets ) && ! empty( $widgets ) ) {
1492 $new_sidebars_widgets['wp_inactive_widgets'] = array_merge( $new_sidebars_widgets['wp_inactive_widgets'], $widgets );
1493 }
1494 }
1495
1496 // Sidebars_widgets settings from when this theme was previously active.
1497 $old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' );
1498 $old_sidebars_widgets = isset( $old_sidebars_widgets['data'] ) ? $old_sidebars_widgets['data'] : false;
1499
1500 if ( is_array( $old_sidebars_widgets ) ) {
1501
1502 // Remove empty sidebars, no need to map those.
1503 $old_sidebars_widgets = array_filter( $old_sidebars_widgets );
1504
1505 // Only check sidebars that are empty or have not been mapped to yet.
1506 foreach ( $new_sidebars_widgets as $new_sidebar => $new_widgets ) {
1507 if ( array_key_exists( $new_sidebar, $old_sidebars_widgets ) && ! empty( $new_widgets ) ) {
1508 unset( $old_sidebars_widgets[ $new_sidebar ] );
1509 }
1510 }
1511
1512 // Remove orphaned widgets, we're only interested in previously active sidebars.
1513 foreach ( $old_sidebars_widgets as $sidebar => $widgets ) {
1514 if ( str_starts_with( $sidebar, 'orphaned_widgets' ) ) {
1515 unset( $old_sidebars_widgets[ $sidebar ] );
1516 }
1517 }
1518
1519 $old_sidebars_widgets = _wp_remove_unregistered_widgets( $old_sidebars_widgets );
1520
1521 // Replace non-array values inside the array with an empty array.
1522 foreach ( $new_sidebars_widgets as $key => $value ) {
1523 if ( ! is_array( $value ) ) {
1524 $new_sidebars_widgets[ $key ] = array();
1525 }
1526 }
1527
1528 if ( ! empty( $old_sidebars_widgets ) ) {
1529
1530 // Go through each remaining sidebar...
1531 foreach ( $old_sidebars_widgets as $old_sidebar => $old_widgets ) {
1532
1533 // ...and check every new sidebar...
1534 foreach ( $new_sidebars_widgets as $new_sidebar => $new_widgets ) {
1535
1536 // ...for every widget we're trying to revive.
1537 foreach ( $old_widgets as $key => $widget_id ) {
1538 $active_key = array_search( $widget_id, $new_widgets, true );
1539
1540 // If the widget is used elsewhere...
1541 if ( false !== $active_key ) {
1542
1543 // ...and that elsewhere is inactive widgets...
1544 if ( 'wp_inactive_widgets' === $new_sidebar ) {
1545
1546 // ...remove it from there and keep the active version...
1547 unset( $new_sidebars_widgets['wp_inactive_widgets'][ $active_key ] );
1548 } else {
1549
1550 // ...otherwise remove it from the old sidebar and keep it in the new one.
1551 unset( $old_sidebars_widgets[ $old_sidebar ][ $key ] );
1552 }
1553 } // End if ( $active_key ).
1554 } // End foreach ( $old_widgets as $key => $widget_id ).
1555 } // End foreach ( $new_sidebars_widgets as $new_sidebar => $new_widgets ).
1556 } // End foreach ( $old_sidebars_widgets as $old_sidebar => $old_widgets ).
1557 } // End if ( ! empty( $old_sidebars_widgets ) ).
1558
1559 // Restore widget settings from when theme was previously active.
1560 $new_sidebars_widgets = array_merge( $new_sidebars_widgets, $old_sidebars_widgets );
1561 }
1562
1563 return $new_sidebars_widgets;
1564}
1565
1566/**
1567 * Compares a list of sidebars with their widgets against an allowed list.
1568 *
1569 * @since 4.9.0
1570 *
1571 * @global array $wp_registered_widgets The registered widgets.
1572 *
1573 * @param array $sidebars_widgets List of sidebars and their widget instance IDs.
1574 * @param array $allowed_widget_ids Optional. List of widget IDs to compare against. Default: Registered widgets.
1575 * @return array Sidebars with allowed widgets.
1576 */
1577function _wp_remove_unregistered_widgets( $sidebars_widgets, $allowed_widget_ids = array() ) {
1578 if ( empty( $allowed_widget_ids ) ) {
1579 $allowed_widget_ids = array_keys( $GLOBALS['wp_registered_widgets'] );
1580 }
1581
1582 foreach ( $sidebars_widgets as $sidebar => $widgets ) {
1583 if ( is_array( $widgets ) ) {
1584 $sidebars_widgets[ $sidebar ] = array_intersect( $widgets, $allowed_widget_ids );
1585 }
1586 }
1587
1588 return $sidebars_widgets;
1589}
1590
1591/**
1592 * Displays the RSS entries in a list.
1593 *
1594 * @since 2.5.0
1595 *
1596 * @param string|array|object $rss RSS url.
1597 * @param array $args Widget arguments.
1598 */
1599function wp_widget_rss_output( $rss, $args = array() ) {
1600 if ( is_string( $rss ) ) {
1601 $rss = fetch_feed( $rss );
1602 } elseif ( is_array( $rss ) && isset( $rss['url'] ) ) {
1603 $args = $rss;
1604 $rss = fetch_feed( $rss['url'] );
1605 } elseif ( ! is_object( $rss ) ) {
1606 return;
1607 }
1608
1609 if ( is_wp_error( $rss ) ) {
1610 if ( is_admin() || current_user_can( 'manage_options' ) ) {
1611 echo '<p><strong>' . __( 'RSS Error:' ) . '</strong> ' . esc_html( $rss->get_error_message() ) . '</p>';
1612 }
1613 return;
1614 }
1615
1616 $default_args = array(
1617 'show_author' => 0,
1618 'show_date' => 0,
1619 'show_summary' => 0,
1620 'items' => 0,
1621 );
1622 $args = wp_parse_args( $args, $default_args );
1623
1624 $items = (int) $args['items'];
1625 if ( $items < 1 || 20 < $items ) {
1626 $items = 10;
1627 }
1628 $show_summary = (int) $args['show_summary'];
1629 $show_author = (int) $args['show_author'];
1630 $show_date = (int) $args['show_date'];
1631
1632 if ( ! $rss->get_item_quantity() ) {
1633 echo '<ul><li>' . __( 'An error has occurred, which probably means the feed is down. Try again later.' ) . '</li></ul>';
1634 $rss->__destruct();
1635 unset( $rss );
1636 return;
1637 }
1638
1639 echo '<ul>';
1640 foreach ( $rss->get_items( 0, $items ) as $item ) {
1641 $link = $item->get_link();
1642 while ( ! empty( $link ) && stristr( $link, 'http' ) !== $link ) {
1643 $link = substr( $link, 1 );
1644 }
1645 $link = esc_url( strip_tags( $link ) );
1646
1647 $title = esc_html( trim( strip_tags( $item->get_title() ) ) );
1648 if ( empty( $title ) ) {
1649 $title = __( 'Untitled' );
1650 }
1651
1652 $desc = html_entity_decode( $item->get_description(), ENT_QUOTES, get_option( 'blog_charset' ) );
1653 $desc = esc_attr( wp_trim_words( $desc, 55, ' [&hellip;]' ) );
1654
1655 $summary = '';
1656 if ( $show_summary ) {
1657 $summary = $desc;
1658
1659 // Change existing [...] to [&hellip;].
1660 if ( str_ends_with( $summary, '[...]' ) ) {
1661 $summary = substr( $summary, 0, -5 ) . '[&hellip;]';
1662 }
1663
1664 $summary = '<div class="rssSummary">' . esc_html( $summary ) . '</div>';
1665 }
1666
1667 $date = '';
1668 if ( $show_date ) {
1669 $date = $item->get_date( 'U' );
1670
1671 if ( $date ) {
1672 $date = ' <span class="rss-date">' . date_i18n( get_option( 'date_format' ), $date ) . '</span>';
1673 }
1674 }
1675
1676 $author = '';
1677 if ( $show_author ) {
1678 $author = $item->get_author();
1679 if ( is_object( $author ) ) {
1680 $author = $author->get_name();
1681 $author = ' <cite>' . esc_html( strip_tags( $author ) ) . '</cite>';
1682 }
1683 }
1684
1685 if ( '' === $link ) {
1686 echo "<li>$title{$date}{$summary}{$author}</li>";
1687 } elseif ( $show_summary ) {
1688 echo "<li><a class='rsswidget' href='$link'>$title</a>{$date}{$summary}{$author}</li>";
1689 } else {
1690 echo "<li><a class='rsswidget' href='$link'>$title</a>{$date}{$author}</li>";
1691 }
1692 }
1693 echo '</ul>';
1694 $rss->__destruct();
1695 unset( $rss );
1696}
1697
1698/**
1699 * Displays RSS widget options form.
1700 *
1701 * The options for what fields are displayed for the RSS form are all booleans
1702 * and are as follows: 'url', 'title', 'items', 'show_summary', 'show_author',
1703 * 'show_date'.
1704 *
1705 * @since 2.5.0
1706 *
1707 * @param array|string $args Values for input fields.
1708 * @param array $inputs Override default display options.
1709 */
1710function wp_widget_rss_form( $args, $inputs = null ) {
1711 $default_inputs = array(
1712 'url' => true,
1713 'title' => true,
1714 'items' => true,
1715 'show_summary' => true,
1716 'show_author' => true,
1717 'show_date' => true,
1718 );
1719 $inputs = wp_parse_args( $inputs, $default_inputs );
1720
1721 $args['title'] = isset( $args['title'] ) ? $args['title'] : '';
1722 $args['url'] = isset( $args['url'] ) ? $args['url'] : '';
1723 $args['items'] = isset( $args['items'] ) ? (int) $args['items'] : 0;
1724
1725 if ( $args['items'] < 1 || 20 < $args['items'] ) {
1726 $args['items'] = 10;
1727 }
1728
1729 $args['show_summary'] = isset( $args['show_summary'] ) ? (int) $args['show_summary'] : (int) $inputs['show_summary'];
1730 $args['show_author'] = isset( $args['show_author'] ) ? (int) $args['show_author'] : (int) $inputs['show_author'];
1731 $args['show_date'] = isset( $args['show_date'] ) ? (int) $args['show_date'] : (int) $inputs['show_date'];
1732
1733 if ( ! empty( $args['error'] ) ) {
1734 echo '<p class="widget-error"><strong>' . __( 'RSS Error:' ) . '</strong> ' . esc_html( $args['error'] ) . '</p>';
1735 }
1736
1737 $esc_number = esc_attr( $args['number'] );
1738 if ( $inputs['url'] ) :
1739 ?>
1740 <p><label for="rss-url-<?php echo $esc_number; ?>"><?php _e( 'Enter the RSS feed URL here:' ); ?></label>
1741 <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>
1742<?php endif; if ( $inputs['title'] ) : ?>
1743 <p><label for="rss-title-<?php echo $esc_number; ?>"><?php _e( 'Give the feed a title (optional):' ); ?></label>
1744 <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>
1745<?php endif; if ( $inputs['items'] ) : ?>
1746 <p><label for="rss-items-<?php echo $esc_number; ?>"><?php _e( 'How many items would you like to display?' ); ?></label>
1747 <select id="rss-items-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][items]">
1748 <?php
1749 for ( $i = 1; $i <= 20; ++$i ) {
1750 echo "<option value='$i' " . selected( $args['items'], $i, false ) . ">$i</option>";
1751 }
1752 ?>
1753 </select></p>
1754<?php endif; if ( $inputs['show_summary'] || $inputs['show_author'] || $inputs['show_date'] ) : ?>
1755 <p>
1756 <?php if ( $inputs['show_summary'] ) : ?>
1757 <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'] ); ?> />
1758 <label for="rss-show-summary-<?php echo $esc_number; ?>"><?php _e( 'Display item content?' ); ?></label><br />
1759 <?php endif; if ( $inputs['show_author'] ) : ?>
1760 <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'] ); ?> />
1761 <label for="rss-show-author-<?php echo $esc_number; ?>"><?php _e( 'Display item author if available?' ); ?></label><br />
1762 <?php endif; if ( $inputs['show_date'] ) : ?>
1763 <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'] ); ?> />
1764 <label for="rss-show-date-<?php echo $esc_number; ?>"><?php _e( 'Display item date?' ); ?></label><br />
1765 <?php endif; ?>
1766 </p>
1767 <?php
1768 endif; // End of display options.
1769foreach ( array_keys( $default_inputs ) as $input ) :
1770 if ( 'hidden' === $inputs[ $input ] ) :
1771 $id = str_replace( '_', '-', $input );
1772 ?>
1773<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 ] ); ?>" />
1774 <?php
1775 endif;
1776 endforeach;
1777}
1778
1779/**
1780 * Processes RSS feed widget data and optionally retrieve feed items.
1781 *
1782 * The feed widget can not have more than 20 items or it will reset back to the
1783 * default, which is 10.
1784 *
1785 * The resulting array has the feed title, feed url, feed link (from channel),
1786 * feed items, error (if any), and whether to show summary, author, and date.
1787 * All respectively in the order of the array elements.
1788 *
1789 * @since 2.5.0
1790 *
1791 * @param array $widget_rss RSS widget feed data. Expects unescaped data.
1792 * @param bool $check_feed Optional. Whether to check feed for errors. Default true.
1793 * @return array
1794 */
1795function wp_widget_rss_process( $widget_rss, $check_feed = true ) {
1796 $items = (int) $widget_rss['items'];
1797 if ( $items < 1 || 20 < $items ) {
1798 $items = 10;
1799 }
1800 $url = sanitize_url( strip_tags( $widget_rss['url'] ) );
1801 $title = isset( $widget_rss['title'] ) ? trim( strip_tags( $widget_rss['title'] ) ) : '';
1802 $show_summary = isset( $widget_rss['show_summary'] ) ? (int) $widget_rss['show_summary'] : 0;
1803 $show_author = isset( $widget_rss['show_author'] ) ? (int) $widget_rss['show_author'] : 0;
1804 $show_date = isset( $widget_rss['show_date'] ) ? (int) $widget_rss['show_date'] : 0;
1805 $error = false;
1806 $link = '';
1807
1808 if ( $check_feed ) {
1809 $rss = fetch_feed( $url );
1810
1811 if ( is_wp_error( $rss ) ) {
1812 $error = $rss->get_error_message();
1813 } else {
1814 $link = esc_url( strip_tags( $rss->get_permalink() ) );
1815 while ( stristr( $link, 'http' ) !== $link ) {
1816 $link = substr( $link, 1 );
1817 }
1818
1819 $rss->__destruct();
1820 unset( $rss );
1821 }
1822 }
1823
1824 return compact( 'title', 'url', 'link', 'items', 'error', 'show_summary', 'show_author', 'show_date' );
1825}
1826
1827/**
1828 * Registers all of the default WordPress widgets on startup.
1829 *
1830 * Calls {@see 'widgets_init'} action after all of the WordPress widgets have been registered.
1831 *
1832 * @since 2.2.0
1833 */
1834function wp_widgets_init() {
1835 if ( ! is_blog_installed() ) {
1836 return;
1837 }
1838
1839 register_widget( 'WP_Widget_Pages' );
1840
1841 register_widget( 'WP_Widget_Calendar' );
1842
1843 register_widget( 'WP_Widget_Archives' );
1844
1845 if ( get_option( 'link_manager_enabled' ) ) {
1846 register_widget( 'WP_Widget_Links' );
1847 }
1848
1849 register_widget( 'WP_Widget_Media_Audio' );
1850
1851 register_widget( 'WP_Widget_Media_Image' );
1852
1853 register_widget( 'WP_Widget_Media_Gallery' );
1854
1855 register_widget( 'WP_Widget_Media_Video' );
1856
1857 register_widget( 'WP_Widget_Meta' );
1858
1859 register_widget( 'WP_Widget_Search' );
1860
1861 register_widget( 'WP_Widget_Text' );
1862
1863 register_widget( 'WP_Widget_Categories' );
1864
1865 register_widget( 'WP_Widget_Recent_Posts' );
1866
1867 register_widget( 'WP_Widget_Recent_Comments' );
1868
1869 register_widget( 'WP_Widget_RSS' );
1870
1871 register_widget( 'WP_Widget_Tag_Cloud' );
1872
1873 register_widget( 'WP_Nav_Menu_Widget' );
1874
1875 register_widget( 'WP_Widget_Custom_HTML' );
1876
1877 register_widget( 'WP_Widget_Block' );
1878
1879 /**
1880 * Fires after all default WordPress widgets have been registered.
1881 *
1882 * @since 2.2.0
1883 */
1884 do_action( 'widgets_init' );
1885}
1886
1887/**
1888 * Enables the widgets block editor. This is hooked into 'after_setup_theme' so
1889 * that the block editor is enabled by default but can be disabled by themes.
1890 *
1891 * @since 5.8.0
1892 *
1893 * @access private
1894 */
1895function wp_setup_widgets_block_editor() {
1896 add_theme_support( 'widgets-block-editor' );
1897}
1898
1899/**
1900 * Determines whether or not to use the block editor to manage widgets.
1901 * Defaults to true unless a theme has removed support for widgets-block-editor
1902 * or a plugin has filtered the return value of this function.
1903 *
1904 * @since 5.8.0
1905 *
1906 * @return bool Whether to use the block editor to manage widgets.
1907 */
1908function wp_use_widgets_block_editor() {
1909 /**
1910 * Filters whether to use the block editor to manage widgets.
1911 *
1912 * @since 5.8.0
1913 *
1914 * @param bool $use_widgets_block_editor Whether to use the block editor to manage widgets.
1915 */
1916 return apply_filters(
1917 'use_widgets_block_editor',
1918 get_theme_support( 'widgets-block-editor' )
1919 );
1920}
1921
1922/**
1923 * Converts a widget ID into its id_base and number components.
1924 *
1925 * @since 5.8.0
1926 *
1927 * @param string $id Widget ID.
1928 * @return array Array containing a widget's id_base and number components.
1929 */
1930function wp_parse_widget_id( $id ) {
1931 $parsed = array();
1932
1933 if ( preg_match( '/^(.+)-(\d+)$/', $id, $matches ) ) {
1934 $parsed['id_base'] = $matches[1];
1935 $parsed['number'] = (int) $matches[2];
1936 } else {
1937 // Likely an old single widget.
1938 $parsed['id_base'] = $id;
1939 }
1940
1941 return $parsed;
1942}
1943
1944/**
1945 * Finds the sidebar that a given widget belongs to.
1946 *
1947 * @since 5.8.0
1948 *
1949 * @param string $widget_id The widget ID to look for.
1950 * @return string|null The found sidebar's ID, or null if it was not found.
1951 */
1952function wp_find_widgets_sidebar( $widget_id ) {
1953 foreach ( wp_get_sidebars_widgets() as $sidebar_id => $widget_ids ) {
1954 foreach ( $widget_ids as $maybe_widget_id ) {
1955 if ( $maybe_widget_id === $widget_id ) {
1956 return (string) $sidebar_id;
1957 }
1958 }
1959 }
1960
1961 return null;
1962}
1963
1964/**
1965 * Assigns a widget to the given sidebar.
1966 *
1967 * @since 5.8.0
1968 *
1969 * @param string $widget_id The widget ID to assign.
1970 * @param string $sidebar_id The sidebar ID to assign to. If empty, the widget won't be added to any sidebar.
1971 */
1972function wp_assign_widget_to_sidebar( $widget_id, $sidebar_id ) {
1973 $sidebars = wp_get_sidebars_widgets();
1974
1975 foreach ( $sidebars as $maybe_sidebar_id => $widgets ) {
1976 foreach ( $widgets as $i => $maybe_widget_id ) {
1977 if ( $widget_id === $maybe_widget_id && $sidebar_id !== $maybe_sidebar_id ) {
1978 unset( $sidebars[ $maybe_sidebar_id ][ $i ] );
1979 // We could technically break 2 here, but continue looping in case the ID is duplicated.
1980 continue 2;
1981 }
1982 }
1983 }
1984
1985 if ( $sidebar_id ) {
1986 $sidebars[ $sidebar_id ][] = $widget_id;
1987 }
1988
1989 wp_set_sidebars_widgets( $sidebars );
1990}
1991
1992/**
1993 * Calls the render callback of a widget and returns the output.
1994 *
1995 * @since 5.8.0
1996 *
1997 * @global array $wp_registered_widgets The registered widgets.
1998 * @global array $wp_registered_sidebars The registered sidebars.
1999 *
2000 * @param string $widget_id Widget ID.
2001 * @param string $sidebar_id Sidebar ID.
2002 * @return string
2003 */
2004function wp_render_widget( $widget_id, $sidebar_id ) {
2005 global $wp_registered_widgets, $wp_registered_sidebars;
2006
2007 if ( ! isset( $wp_registered_widgets[ $widget_id ] ) ) {
2008 return '';
2009 }
2010
2011 if ( isset( $wp_registered_sidebars[ $sidebar_id ] ) ) {
2012 $sidebar = $wp_registered_sidebars[ $sidebar_id ];
2013 } elseif ( 'wp_inactive_widgets' === $sidebar_id ) {
2014 $sidebar = array();
2015 } else {
2016 return '';
2017 }
2018
2019 $params = array_merge(
2020 array(
2021 array_merge(
2022 $sidebar,
2023 array(
2024 'widget_id' => $widget_id,
2025 'widget_name' => $wp_registered_widgets[ $widget_id ]['name'],
2026 )
2027 ),
2028 ),
2029 (array) $wp_registered_widgets[ $widget_id ]['params']
2030 );
2031
2032 // Substitute HTML `id` and `class` attributes into `before_widget`.
2033 $classname_ = '';
2034 foreach ( (array) $wp_registered_widgets[ $widget_id ]['classname'] as $cn ) {
2035 if ( is_string( $cn ) ) {
2036 $classname_ .= '_' . $cn;
2037 } elseif ( is_object( $cn ) ) {
2038 $classname_ .= '_' . get_class( $cn );
2039 }
2040 }
2041 $classname_ = ltrim( $classname_, '_' );
2042 $params[0]['before_widget'] = sprintf( $params[0]['before_widget'], $widget_id, $classname_ );
2043
2044 /** This filter is documented in wp-includes/widgets.php */
2045 $params = apply_filters( 'dynamic_sidebar_params', $params );
2046
2047 $callback = $wp_registered_widgets[ $widget_id ]['callback'];
2048
2049 ob_start();
2050
2051 /** This filter is documented in wp-includes/widgets.php */
2052 do_action( 'dynamic_sidebar', $wp_registered_widgets[ $widget_id ] );
2053
2054 if ( is_callable( $callback ) ) {
2055 call_user_func_array( $callback, $params );
2056 }
2057
2058 return ob_get_clean();
2059}
2060
2061/**
2062 * Calls the control callback of a widget and returns the output.
2063 *
2064 * @since 5.8.0
2065 *
2066 * @global array $wp_registered_widget_controls The registered widget controls.
2067 *
2068 * @param string $id Widget ID.
2069 * @return string|null
2070 */
2071function wp_render_widget_control( $id ) {
2072 global $wp_registered_widget_controls;
2073
2074 if ( ! isset( $wp_registered_widget_controls[ $id ]['callback'] ) ) {
2075 return null;
2076 }
2077
2078 $callback = $wp_registered_widget_controls[ $id ]['callback'];
2079 $params = $wp_registered_widget_controls[ $id ]['params'];
2080
2081 ob_start();
2082
2083 if ( is_callable( $callback ) ) {
2084 call_user_func_array( $callback, $params );
2085 }
2086
2087 return ob_get_clean();
2088}
2089
2090/**
2091 * Displays a _doing_it_wrong() message for conflicting widget editor scripts.
2092 *
2093 * The 'wp-editor' script module is exposed as window.wp.editor. This overrides
2094 * the legacy TinyMCE editor module which is required by the widgets editor.
2095 * Because of that conflict, these two shouldn't be enqueued together.
2096 * See https://core.trac.wordpress.org/ticket/53569.
2097 *
2098 * There is also another conflict related to styles where the block widgets
2099 * editor is hidden if a block enqueues 'wp-edit-post' stylesheet.
2100 * See https://core.trac.wordpress.org/ticket/53569.
2101 *
2102 * @since 5.8.0
2103 * @access private
2104 *
2105 * @global WP_Scripts $wp_scripts
2106 * @global WP_Styles $wp_styles
2107 */
2108function wp_check_widget_editor_deps() {
2109 global $wp_scripts, $wp_styles;
2110
2111 if (
2112 $wp_scripts->query( 'wp-edit-widgets', 'enqueued' ) ||
2113 $wp_scripts->query( 'wp-customize-widgets', 'enqueued' )
2114 ) {
2115 if ( $wp_scripts->query( 'wp-editor', 'enqueued' ) ) {
2116 _doing_it_wrong(
2117 'wp_enqueue_script()',
2118 sprintf(
2119 /* translators: 1: 'wp-editor', 2: 'wp-edit-widgets', 3: 'wp-customize-widgets'. */
2120 __( '"%1$s" script should not be enqueued together with the new widgets editor (%2$s or %3$s).' ),
2121 'wp-editor',
2122 'wp-edit-widgets',
2123 'wp-customize-widgets'
2124 ),
2125 '5.8.0'
2126 );
2127 }
2128 if ( $wp_styles->query( 'wp-edit-post', 'enqueued' ) ) {
2129 _doing_it_wrong(
2130 'wp_enqueue_style()',
2131 sprintf(
2132 /* translators: 1: 'wp-edit-post', 2: 'wp-edit-widgets', 3: 'wp-customize-widgets'. */
2133 __( '"%1$s" style should not be enqueued together with the new widgets editor (%2$s or %3$s).' ),
2134 'wp-edit-post',
2135 'wp-edit-widgets',
2136 'wp-customize-widgets'
2137 ),
2138 '5.8.0'
2139 );
2140 }
2141 }
2142}
2143
2144/**
2145 * Registers the previous theme's sidebars for the block themes.
2146 *
2147 * @since 6.2.0
2148 * @access private
2149 *
2150 * @global array $wp_registered_sidebars The registered sidebars.
2151 */
2152function _wp_block_theme_register_classic_sidebars() {
2153 global $wp_registered_sidebars;
2154
2155 if ( ! wp_is_block_theme() ) {
2156 return;
2157 }
2158
2159 $classic_sidebars = get_theme_mod( 'wp_classic_sidebars' );
2160 if ( empty( $classic_sidebars ) ) {
2161 return;
2162 }
2163
2164 // Don't use `register_sidebar` since it will enable the `widgets` support for a theme.
2165 foreach ( $classic_sidebars as $sidebar ) {
2166 $wp_registered_sidebars[ $sidebar['id'] ] = $sidebar;
2167 }
2168}
2169
Ui Ux Design – Teachers Night Out

Get in Touch

© 2024 Teachers Night Out. All Rights Reserved.