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 https://cardgames4educators.com Wed, 16 Oct 2024 22:24:18 +0000 en-US hourly 1 https://wordpress.org/?v=6.9.4 https://cardgames4educators.com/wp-content/uploads/2024/06/cropped-Card-4-Educators-logo-32x32.png Ui Ux Design – Teachers Night Out https://cardgames4educators.com 32 32 Masters In English How English Speaker https://cardgames4educators.com/masters-in-english-how-english-speaker/ https://cardgames4educators.com/masters-in-english-how-english-speaker/#comments Mon, 27 May 2024 08:54:45 +0000 https://themexriver.com/wp/kadu/?p=1

Erat himenaeos neque id sagittis massa. Hac suscipit pulvinar dignissim platea magnis eu. Don tellus a pharetra inceptos efficitur dui pulvinar. Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent pulvinar odio volutpat parturient. Quisque risus finibus suspendisse mus purus magnis facilisi condimentum consectetur dui. Curae elit suspendisse cursus vehicula.

Turpis taciti class non vel pretium quis pulvinar tempor lobortis nunc. Libero phasellus parturient sapien volutpat malesuada ornare. Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae. Porta est tempor ex eget feugiat vulputate ipsum. Justo nec iaculis habitant diam arcu fermentum.

We offer comprehen sive emplo ment services such as assistance wit employer compliance.Our company is your strategic HR partner as instead of HR. john smithson

Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae.

Exploring Learning Landscapes in Academic

Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent.

]]>
https://cardgames4educators.com/masters-in-english-how-english-speaker/feed/ 1