run:R W Run
7.85 KB
2026-03-11 16:18:51
R W Run
3.54 KB
2026-03-11 16:18:51
R W Run
148.33 KB
2026-03-11 16:18:51
R W Run
11.45 KB
2026-03-11 16:18:51
R W Run
3.58 KB
2026-03-11 16:18:51
R W Run
2.53 KB
2026-03-11 16:18:51
R W Run
2.6 KB
2026-03-11 16:18:51
R W Run
6.59 KB
2026-03-11 16:18:51
R W Run
14.83 KB
2026-03-11 16:18:51
R W Run
21.18 KB
2026-03-11 16:18:51
R W Run
48.13 KB
2026-03-11 16:18:51
R W Run
4.07 KB
2026-03-11 16:18:51
R W Run
5.3 KB
2026-03-11 16:18:51
R W Run
8.28 KB
2026-03-11 16:18:51
R W Run
26.73 KB
2026-03-11 16:18:51
R W Run
2.8 KB
2026-03-11 16:18:51
R W Run
15.2 KB
2026-03-11 16:18:51
R W Run
192.08 KB
2026-03-11 16:18:51
R W Run
11.77 KB
2026-03-11 16:18:51
R W Run
3.2 KB
2026-03-11 16:18:51
R W Run
22.89 KB
2026-03-11 16:18:51
R W Run
12.77 KB
2026-03-11 16:18:51
R W Run
4.08 KB
2026-03-11 16:18:51
R W Run
26.27 KB
2026-03-11 16:18:51
R W Run
4.97 KB
2026-03-11 16:18:51
R W Run
5.57 KB
2026-03-11 16:18:51
R W Run
13.93 KB
2026-03-11 16:18:51
R W Run
4.09 KB
2026-03-11 16:18:51
R W Run
6.79 KB
2026-03-11 16:18:51
R W Run
60.45 KB
2026-03-11 16:18:51
R W Run
32.4 KB
2026-03-11 16:18:51
R W Run
18.24 KB
2026-03-11 16:18:51
R W Run
66.01 KB
2026-03-11 16:18:51
R W Run
23.84 KB
2026-03-11 16:18:51
R W Run
17.72 KB
2026-03-11 16:18:51
R W Run
22.71 KB
2026-03-11 16:18:51
R W Run
18.05 KB
2026-03-11 16:18:51
R W Run
22.76 KB
2026-03-11 16:18:51
R W Run
7.34 KB
2026-03-11 16:18:51
R W Run
4.51 KB
2026-03-11 16:18:51
R W Run
9.02 KB
2026-03-11 16:18:51
R W Run
1.46 KB
2026-03-11 16:18:51
R W Run
51.76 KB
2026-03-11 16:18:51
R W Run
25.29 KB
2026-03-11 16:18:51
R W Run
21.61 KB
2026-03-11 16:18:51
R W Run
27.77 KB
2026-03-11 16:18:51
R W Run
15.35 KB
2026-03-11 16:18:51
R W Run
24.54 KB
2026-03-11 16:18:51
R W Run
56.44 KB
2026-03-11 16:18:51
R W Run
1.42 KB
2026-03-11 16:18:51
R W Run
63.66 KB
2026-03-11 16:18:51
R W Run
31.9 KB
2026-03-11 16:18:51
R W Run
14.44 KB
2026-03-11 16:18:51
R W Run
36.47 KB
2026-03-11 16:18:51
R W Run
14 KB
2026-03-11 16:18:51
R W Run
121.89 KB
2026-03-11 16:18:51
R W Run
6.26 KB
2026-03-11 16:18:51
R W Run
20.73 KB
2026-03-11 16:18:51
R W Run
15.23 KB
2026-03-11 16:18:51
R W Run
10.14 KB
2026-03-11 16:18:51
R W Run
6.94 KB
2026-03-11 16:18:51
R W Run
1.44 KB
2026-03-11 16:18:51
R W Run
46.85 KB
2026-03-11 16:18:51
R W Run
18.61 KB
2026-03-11 16:18:51
R W Run
6.08 KB
2026-03-11 16:18:51
R W Run
20.06 KB
2026-03-11 16:18:51
R W Run
5.73 KB
2026-03-11 16:18:51
R W Run
68.18 KB
2026-03-11 16:18:51
R W Run
40.8 KB
2026-03-11 16:18:51
R W Run
1.44 KB
2026-03-11 16:18:51
R W Run
25.26 KB
2026-03-11 16:18:51
R W Run
95.94 KB
2026-03-11 16:18:51
R W Run
43.12 KB
2026-03-11 16:18:51
R W Run
41.73 KB
2026-03-11 16:18:51
R W Run
6.46 KB
2026-03-11 16:18:51
R W Run
3.71 KB
2026-03-11 16:18:51
R W Run
116.31 KB
2026-03-11 16:18:51
R W Run
9.39 KB
2026-03-11 16:18:51
R W Run
64.34 KB
2026-03-11 16:18:51
R W Run
44.73 KB
2026-03-11 16:18:51
R W Run
1.27 KB
2026-03-11 16:18:51
R W Run
3.68 KB
2026-03-11 16:18:51
R W Run
33.53 KB
2026-03-11 16:18:51
R W Run
48.84 KB
2026-03-11 16:18:51
R W Run
26.35 KB
2026-03-11 16:18:51
R W Run
1.12 KB
2026-03-11 16:18:51
R W Run
4.19 KB
2026-03-11 16:18:51
R W Run
38.19 KB
2026-03-11 16:18:51
R W Run
91.33 KB
2026-03-11 16:18:51
R W Run
80.39 KB
2026-03-11 16:18:51
R W Run
32.67 KB
2026-03-11 16:18:51
R W Run
16.18 KB
2026-03-11 16:18:51
R W Run
44.46 KB
2026-03-11 16:18:51
R W Run
6.23 KB
2026-03-11 16:18:51
R W Run
8.23 KB
2026-03-11 16:18:51
R W Run
96.96 KB
2026-03-11 16:18:51
R W Run
6.83 KB
2026-03-11 16:18:51
R W Run
46.62 KB
2026-03-11 16:18:51
R W Run
10.82 KB
2026-03-11 16:18:51
R W Run
68.86 KB
2026-03-11 16:18:51
R W Run
33.63 KB
2026-03-11 16:18:51
R W Run
113.3 KB
2026-03-11 16:18:51
R W Run
22.98 KB
2026-03-11 16:18:51
R W Run
10.66 KB
2026-03-11 16:18:51
R W Run
error_log
📄class-wp-screen.php
1<?php
2/**
3 * Screen API: WP_Screen class
4 *
5 * @package WordPress
6 * @subpackage Administration
7 * @since 4.4.0
8 */
9
10/**
11 * Core class used to implement an admin screen API.
12 *
13 * @since 3.3.0
14 */
15#[AllowDynamicProperties]
16final class WP_Screen {
17 /**
18 * Any action associated with the screen.
19 *
20 * 'add' for *-add.php and *-new.php screens. Empty otherwise.
21 *
22 * @since 3.3.0
23 * @var string
24 */
25 public $action;
26
27 /**
28 * The base type of the screen.
29 *
30 * This is typically the same as `$id` but with any post types and taxonomies stripped.
31 * For example, for an `$id` of 'edit-post' the base is 'edit'.
32 *
33 * @since 3.3.0
34 * @var string
35 */
36 public $base;
37
38 /**
39 * The number of columns to display. Access with get_columns().
40 *
41 * @since 3.4.0
42 * @var int
43 */
44 private $columns = 0;
45
46 /**
47 * The unique ID of the screen.
48 *
49 * @since 3.3.0
50 * @var string
51 */
52 public $id;
53
54 /**
55 * Which admin the screen is in. network | user | site | false
56 *
57 * @since 3.5.0
58 * @var string
59 */
60 protected $in_admin;
61
62 /**
63 * Whether the screen is in the network admin.
64 *
65 * Deprecated. Use in_admin() instead.
66 *
67 * @since 3.3.0
68 * @deprecated 3.5.0
69 * @var bool
70 */
71 public $is_network;
72
73 /**
74 * Whether the screen is in the user admin.
75 *
76 * Deprecated. Use in_admin() instead.
77 *
78 * @since 3.3.0
79 * @deprecated 3.5.0
80 * @var bool
81 */
82 public $is_user;
83
84 /**
85 * The base menu parent.
86 *
87 * This is derived from `$parent_file` by removing the query string and any .php extension.
88 * `$parent_file` values of 'edit.php?post_type=page' and 'edit.php?post_type=post'
89 * have a `$parent_base` of 'edit'.
90 *
91 * @since 3.3.0
92 * @var string|null
93 */
94 public $parent_base;
95
96 /**
97 * The parent_file for the screen per the admin menu system.
98 *
99 * Some `$parent_file` values are 'edit.php?post_type=page', 'edit.php', and 'options-general.php'.
100 *
101 * @since 3.3.0
102 * @var string|null
103 */
104 public $parent_file;
105
106 /**
107 * The post type associated with the screen, if any.
108 *
109 * The 'edit.php?post_type=page' screen has a post type of 'page'.
110 * The 'edit-tags.php?taxonomy=$taxonomy&post_type=page' screen has a post type of 'page'.
111 *
112 * @since 3.3.0
113 * @var string
114 */
115 public $post_type;
116
117 /**
118 * The taxonomy associated with the screen, if any.
119 *
120 * The 'edit-tags.php?taxonomy=category' screen has a taxonomy of 'category'.
121 *
122 * @since 3.3.0
123 * @var string
124 */
125 public $taxonomy;
126
127 /**
128 * The help tab data associated with the screen, if any.
129 *
130 * @since 3.3.0
131 * @var array
132 */
133 private $_help_tabs = array();
134
135 /**
136 * The help sidebar data associated with screen, if any.
137 *
138 * @since 3.3.0
139 * @var string
140 */
141 private $_help_sidebar = '';
142
143 /**
144 * The accessible hidden headings and text associated with the screen, if any.
145 *
146 * @since 4.4.0
147 * @var string[]
148 */
149 private $_screen_reader_content = array();
150
151 /**
152 * Stores old string-based help.
153 *
154 * @var array
155 */
156 private static $_old_compat_help = array();
157
158 /**
159 * The screen options associated with screen, if any.
160 *
161 * @since 3.3.0
162 * @var array
163 */
164 private $_options = array();
165
166 /**
167 * The screen object registry.
168 *
169 * @since 3.3.0
170 *
171 * @var array
172 */
173 private static $_registry = array();
174
175 /**
176 * Stores the result of the public show_screen_options function.
177 *
178 * @since 3.3.0
179 * @var bool
180 */
181 private $_show_screen_options;
182
183 /**
184 * Stores the 'screen_settings' section of screen options.
185 *
186 * @since 3.3.0
187 * @var string
188 */
189 private $_screen_settings;
190
191 /**
192 * Whether the screen is using the block editor.
193 *
194 * @since 5.0.0
195 * @var bool
196 */
197 public $is_block_editor = false;
198
199 /**
200 * Fetches a screen object.
201 *
202 * @since 3.3.0
203 *
204 * @global string $hook_suffix
205 *
206 * @param string|WP_Screen $hook_name Optional. The hook name (also known as the hook suffix) used to determine the screen.
207 * Defaults to the current $hook_suffix global.
208 * @return WP_Screen Screen object.
209 */
210 public static function get( $hook_name = '' ) {
211 if ( $hook_name instanceof WP_Screen ) {
212 return $hook_name;
213 }
214
215 $id = '';
216 $post_type = null;
217 $taxonomy = null;
218 $in_admin = false;
219 $action = '';
220 $is_block_editor = false;
221
222 if ( $hook_name ) {
223 $id = $hook_name;
224 } elseif ( ! empty( $GLOBALS['hook_suffix'] ) ) {
225 $id = $GLOBALS['hook_suffix'];
226 }
227
228 // For those pesky meta boxes.
229 if ( $hook_name && post_type_exists( $hook_name ) ) {
230 $post_type = $id;
231 $id = 'post'; // Changes later. Ends up being $base.
232 } else {
233 if ( str_ends_with( $id, '.php' ) ) {
234 $id = substr( $id, 0, -4 );
235 }
236
237 if ( in_array( $id, array( 'post-new', 'link-add', 'media-new', 'user-new' ), true ) ) {
238 $id = substr( $id, 0, -4 );
239 $action = 'add';
240 }
241 }
242
243 if ( ! $post_type && $hook_name ) {
244 if ( str_ends_with( $id, '-network' ) ) {
245 $id = substr( $id, 0, -8 );
246 $in_admin = 'network';
247 } elseif ( str_ends_with( $id, '-user' ) ) {
248 $id = substr( $id, 0, -5 );
249 $in_admin = 'user';
250 }
251
252 $id = sanitize_key( $id );
253 if ( 'edit-comments' !== $id && 'edit-tags' !== $id && str_starts_with( $id, 'edit-' ) ) {
254 $maybe = substr( $id, 5 );
255 if ( taxonomy_exists( $maybe ) ) {
256 $id = 'edit-tags';
257 $taxonomy = $maybe;
258 } elseif ( post_type_exists( $maybe ) ) {
259 $id = 'edit';
260 $post_type = $maybe;
261 }
262 }
263
264 if ( ! $in_admin ) {
265 $in_admin = 'site';
266 }
267 } else {
268 if ( defined( 'WP_NETWORK_ADMIN' ) && WP_NETWORK_ADMIN ) {
269 $in_admin = 'network';
270 } elseif ( defined( 'WP_USER_ADMIN' ) && WP_USER_ADMIN ) {
271 $in_admin = 'user';
272 } else {
273 $in_admin = 'site';
274 }
275 }
276
277 if ( 'index' === $id ) {
278 $id = 'dashboard';
279 } elseif ( 'front' === $id ) {
280 $in_admin = false;
281 }
282
283 $base = $id;
284
285 // If this is the current screen, see if we can be more accurate for post types and taxonomies.
286 if ( ! $hook_name ) {
287 if ( isset( $_REQUEST['post_type'] ) ) {
288 $post_type = post_type_exists( $_REQUEST['post_type'] ) ? $_REQUEST['post_type'] : false;
289 }
290 if ( isset( $_REQUEST['taxonomy'] ) ) {
291 $taxonomy = taxonomy_exists( $_REQUEST['taxonomy'] ) ? $_REQUEST['taxonomy'] : false;
292 }
293
294 switch ( $base ) {
295 case 'post':
296 if ( isset( $_GET['post'] ) && isset( $_POST['post_ID'] ) && (int) $_GET['post'] !== (int) $_POST['post_ID'] ) {
297 wp_die( __( 'A post ID mismatch has been detected.' ), __( 'Sorry, you are not allowed to edit this item.' ), 400 );
298 } elseif ( isset( $_GET['post'] ) ) {
299 $post_id = (int) $_GET['post'];
300 } elseif ( isset( $_POST['post_ID'] ) ) {
301 $post_id = (int) $_POST['post_ID'];
302 } else {
303 $post_id = 0;
304 }
305
306 if ( $post_id ) {
307 $post = get_post( $post_id );
308 if ( $post ) {
309 $post_type = $post->post_type;
310
311 /** This filter is documented in wp-admin/post.php */
312 $replace_editor = apply_filters( 'replace_editor', false, $post );
313
314 if ( ! $replace_editor ) {
315 $is_block_editor = use_block_editor_for_post( $post );
316 }
317 }
318 }
319 break;
320 case 'edit-tags':
321 case 'term':
322 if ( null === $post_type && is_object_in_taxonomy( 'post', $taxonomy ? $taxonomy : 'post_tag' ) ) {
323 $post_type = 'post';
324 }
325 break;
326 case 'upload':
327 $post_type = 'attachment';
328 break;
329 }
330 }
331
332 switch ( $base ) {
333 case 'post':
334 if ( null === $post_type ) {
335 $post_type = 'post';
336 }
337
338 // When creating a new post, use the default block editor support value for the post type.
339 if ( empty( $post_id ) ) {
340 $is_block_editor = use_block_editor_for_post_type( $post_type );
341 }
342
343 $id = $post_type;
344 break;
345 case 'edit':
346 if ( null === $post_type ) {
347 $post_type = 'post';
348 }
349 $id .= '-' . $post_type;
350 break;
351 case 'edit-tags':
352 case 'term':
353 if ( null === $taxonomy ) {
354 $taxonomy = 'post_tag';
355 }
356 // The edit-tags ID does not contain the post type. Look for it in the request.
357 if ( null === $post_type ) {
358 $post_type = 'post';
359 if ( isset( $_REQUEST['post_type'] ) && post_type_exists( $_REQUEST['post_type'] ) ) {
360 $post_type = $_REQUEST['post_type'];
361 }
362 }
363
364 $id = 'edit-' . $taxonomy;
365 break;
366 }
367
368 if ( 'network' === $in_admin ) {
369 $id .= '-network';
370 $base .= '-network';
371 } elseif ( 'user' === $in_admin ) {
372 $id .= '-user';
373 $base .= '-user';
374 }
375
376 if ( isset( self::$_registry[ $id ] ) ) {
377 $screen = self::$_registry[ $id ];
378 if ( get_current_screen() === $screen ) {
379 return $screen;
380 }
381 } else {
382 $screen = new self();
383 $screen->id = $id;
384 }
385
386 $screen->base = $base;
387 $screen->action = $action;
388 $screen->post_type = (string) $post_type;
389 $screen->taxonomy = (string) $taxonomy;
390 $screen->is_user = ( 'user' === $in_admin );
391 $screen->is_network = ( 'network' === $in_admin );
392 $screen->in_admin = $in_admin;
393 $screen->is_block_editor = $is_block_editor;
394
395 self::$_registry[ $id ] = $screen;
396
397 return $screen;
398 }
399
400 /**
401 * Makes the screen object the current screen.
402 *
403 * @see set_current_screen()
404 * @since 3.3.0
405 *
406 * @global WP_Screen $current_screen WordPress current screen object.
407 * @global string $typenow The post type of the current screen.
408 * @global string $taxnow The taxonomy of the current screen.
409 */
410 public function set_current_screen() {
411 global $current_screen, $taxnow, $typenow;
412
413 $current_screen = $this;
414 $typenow = $this->post_type;
415 $taxnow = $this->taxonomy;
416
417 /**
418 * Fires after the current screen has been set.
419 *
420 * @since 3.0.0
421 *
422 * @param WP_Screen $current_screen Current WP_Screen object.
423 */
424 do_action( 'current_screen', $current_screen );
425 }
426
427 /**
428 * Constructor
429 *
430 * @since 3.3.0
431 */
432 private function __construct() {}
433
434 /**
435 * Indicates whether the screen is in a particular admin.
436 *
437 * @since 3.5.0
438 *
439 * @param string $admin The admin to check against (network | user | site).
440 * If empty any of the three admins will result in true.
441 * @return bool True if the screen is in the indicated admin, false otherwise.
442 */
443 public function in_admin( $admin = null ) {
444 if ( empty( $admin ) ) {
445 return (bool) $this->in_admin;
446 }
447
448 return ( $admin === $this->in_admin );
449 }
450
451 /**
452 * Sets or returns whether the block editor is loading on the current screen.
453 *
454 * @since 5.0.0
455 *
456 * @param bool $set Optional. Sets whether the block editor is loading on the current screen or not.
457 * @return bool True if the block editor is being loaded, false otherwise.
458 */
459 public function is_block_editor( $set = null ) {
460 if ( null !== $set ) {
461 $this->is_block_editor = (bool) $set;
462 }
463
464 return $this->is_block_editor;
465 }
466
467 /**
468 * Sets the old string-based contextual help for the screen for backward compatibility.
469 *
470 * @since 3.3.0
471 *
472 * @param WP_Screen $screen A screen object.
473 * @param string $help Help text.
474 */
475 public static function add_old_compat_help( $screen, $help ) {
476 self::$_old_compat_help[ $screen->id ] = $help;
477 }
478
479 /**
480 * Sets the parent information for the screen.
481 *
482 * This is called in admin-header.php after the menu parent for the screen has been determined.
483 *
484 * @since 3.3.0
485 *
486 * @param string $parent_file The parent file of the screen. Typically the $parent_file global.
487 */
488 public function set_parentage( $parent_file ) {
489 $this->parent_file = $parent_file;
490 list( $this->parent_base ) = explode( '?', $parent_file );
491 $this->parent_base = str_replace( '.php', '', $this->parent_base );
492 }
493
494 /**
495 * Adds an option for the screen.
496 *
497 * Call this in template files after admin.php is loaded and before admin-header.php is loaded
498 * to add screen options.
499 *
500 * @since 3.3.0
501 *
502 * @param string $option Option ID.
503 * @param mixed $args Option-dependent arguments.
504 */
505 public function add_option( $option, $args = array() ) {
506 $this->_options[ $option ] = $args;
507 }
508
509 /**
510 * Removes an option from the screen.
511 *
512 * @since 3.8.0
513 *
514 * @param string $option Option ID.
515 */
516 public function remove_option( $option ) {
517 unset( $this->_options[ $option ] );
518 }
519
520 /**
521 * Removes all options from the screen.
522 *
523 * @since 3.8.0
524 */
525 public function remove_options() {
526 $this->_options = array();
527 }
528
529 /**
530 * Gets the options registered for the screen.
531 *
532 * @since 3.8.0
533 *
534 * @return array Options with arguments.
535 */
536 public function get_options() {
537 return $this->_options;
538 }
539
540 /**
541 * Gets the arguments for an option for the screen.
542 *
543 * @since 3.3.0
544 *
545 * @param string $option Option name.
546 * @param string|false $key Optional. Specific array key for when the option is an array.
547 * Default false.
548 * @return string The option value if set, null otherwise.
549 */
550 public function get_option( $option, $key = false ) {
551 if ( ! isset( $this->_options[ $option ] ) ) {
552 return null;
553 }
554 if ( $key ) {
555 if ( isset( $this->_options[ $option ][ $key ] ) ) {
556 return $this->_options[ $option ][ $key ];
557 }
558 return null;
559 }
560 return $this->_options[ $option ];
561 }
562
563 /**
564 * Gets the help tabs registered for the screen.
565 *
566 * @since 3.4.0
567 * @since 4.4.0 Help tabs are ordered by their priority.
568 *
569 * @return array Help tabs with arguments.
570 */
571 public function get_help_tabs() {
572 $help_tabs = $this->_help_tabs;
573
574 $priorities = array();
575 foreach ( $help_tabs as $help_tab ) {
576 if ( isset( $priorities[ $help_tab['priority'] ] ) ) {
577 $priorities[ $help_tab['priority'] ][] = $help_tab;
578 } else {
579 $priorities[ $help_tab['priority'] ] = array( $help_tab );
580 }
581 }
582
583 ksort( $priorities );
584
585 $sorted = array();
586 foreach ( $priorities as $list ) {
587 foreach ( $list as $tab ) {
588 $sorted[ $tab['id'] ] = $tab;
589 }
590 }
591
592 return $sorted;
593 }
594
595 /**
596 * Gets the arguments for a help tab.
597 *
598 * @since 3.4.0
599 *
600 * @param string $id Help Tab ID.
601 * @return array Help tab arguments.
602 */
603 public function get_help_tab( $id ) {
604 if ( ! isset( $this->_help_tabs[ $id ] ) ) {
605 return null;
606 }
607 return $this->_help_tabs[ $id ];
608 }
609
610 /**
611 * Adds a help tab to the contextual help for the screen.
612 *
613 * Call this on the `load-$pagenow` hook for the relevant screen,
614 * or fetch the `$current_screen` object, or use get_current_screen()
615 * and then call the method from the object.
616 *
617 * You may need to filter `$current_screen` using an if or switch statement
618 * to prevent new help tabs from being added to ALL admin screens.
619 *
620 * @since 3.3.0
621 * @since 4.4.0 The `$priority` argument was added.
622 *
623 * @param array $args {
624 * Array of arguments used to display the help tab.
625 *
626 * @type string $title Title for the tab. Default false.
627 * @type string $id Tab ID. Must be HTML-safe and should be unique for this menu.
628 * It is NOT allowed to contain any empty spaces. Default false.
629 * @type string $content Optional. Help tab content in plain text or HTML. Default empty string.
630 * @type callable $callback Optional. A callback to generate the tab content. Default false.
631 * @type int $priority Optional. The priority of the tab, used for ordering. Default 10.
632 * }
633 */
634 public function add_help_tab( $args ) {
635 $defaults = array(
636 'title' => false,
637 'id' => false,
638 'content' => '',
639 'callback' => false,
640 'priority' => 10,
641 );
642 $args = wp_parse_args( $args, $defaults );
643
644 $args['id'] = sanitize_html_class( $args['id'] );
645
646 // Ensure we have an ID and title.
647 if ( ! $args['id'] || ! $args['title'] ) {
648 return;
649 }
650
651 // Allows for overriding an existing tab with that ID.
652 $this->_help_tabs[ $args['id'] ] = $args;
653 }
654
655 /**
656 * Removes a help tab from the contextual help for the screen.
657 *
658 * @since 3.3.0
659 *
660 * @param string $id The help tab ID.
661 */
662 public function remove_help_tab( $id ) {
663 unset( $this->_help_tabs[ $id ] );
664 }
665
666 /**
667 * Removes all help tabs from the contextual help for the screen.
668 *
669 * @since 3.3.0
670 */
671 public function remove_help_tabs() {
672 $this->_help_tabs = array();
673 }
674
675 /**
676 * Gets the content from a contextual help sidebar.
677 *
678 * @since 3.4.0
679 *
680 * @return string Contents of the help sidebar.
681 */
682 public function get_help_sidebar() {
683 return $this->_help_sidebar;
684 }
685
686 /**
687 * Adds a sidebar to the contextual help for the screen.
688 *
689 * Call this in template files after admin.php is loaded and before admin-header.php is loaded
690 * to add a sidebar to the contextual help.
691 *
692 * @since 3.3.0
693 *
694 * @param string $content Sidebar content in plain text or HTML.
695 */
696 public function set_help_sidebar( $content ) {
697 $this->_help_sidebar = $content;
698 }
699
700 /**
701 * Gets the number of layout columns the user has selected.
702 *
703 * The layout_columns option controls the max number and default number of
704 * columns. This method returns the number of columns within that range selected
705 * by the user via Screen Options. If no selection has been made, the default
706 * provisioned in layout_columns is returned. If the screen does not support
707 * selecting the number of layout columns, 0 is returned.
708 *
709 * @since 3.4.0
710 *
711 * @return int Number of columns to display.
712 */
713 public function get_columns() {
714 return $this->columns;
715 }
716
717 /**
718 * Gets the accessible hidden headings and text used in the screen.
719 *
720 * @since 4.4.0
721 *
722 * @see set_screen_reader_content() For more information on the array format.
723 *
724 * @return string[] An associative array of screen reader text strings.
725 */
726 public function get_screen_reader_content() {
727 return $this->_screen_reader_content;
728 }
729
730 /**
731 * Gets a screen reader text string.
732 *
733 * @since 4.4.0
734 *
735 * @param string $key Screen reader text array named key.
736 * @return string Screen reader text string.
737 */
738 public function get_screen_reader_text( $key ) {
739 if ( ! isset( $this->_screen_reader_content[ $key ] ) ) {
740 return null;
741 }
742 return $this->_screen_reader_content[ $key ];
743 }
744
745 /**
746 * Adds accessible hidden headings and text for the screen.
747 *
748 * @since 4.4.0
749 *
750 * @param array $content {
751 * An associative array of screen reader text strings.
752 *
753 * @type string $heading_views Screen reader text for the filter links heading.
754 * Default 'Filter items list'.
755 * @type string $heading_pagination Screen reader text for the pagination heading.
756 * Default 'Items list navigation'.
757 * @type string $heading_list Screen reader text for the items list heading.
758 * Default 'Items list'.
759 * }
760 */
761 public function set_screen_reader_content( $content = array() ) {
762 $defaults = array(
763 'heading_views' => __( 'Filter items list' ),
764 'heading_pagination' => __( 'Items list navigation' ),
765 'heading_list' => __( 'Items list' ),
766 );
767 $content = wp_parse_args( $content, $defaults );
768
769 $this->_screen_reader_content = $content;
770 }
771
772 /**
773 * Removes all the accessible hidden headings and text for the screen.
774 *
775 * @since 4.4.0
776 */
777 public function remove_screen_reader_content() {
778 $this->_screen_reader_content = array();
779 }
780
781 /**
782 * Renders the screen's help section.
783 *
784 * This will trigger the deprecated filters for backward compatibility.
785 *
786 * @since 3.3.0
787 *
788 * @global string $screen_layout_columns
789 */
790 public function render_screen_meta() {
791
792 /**
793 * Filters the legacy contextual help list.
794 *
795 * @since 2.7.0
796 * @deprecated 3.3.0 Use {@see get_current_screen()->add_help_tab()} or
797 * {@see get_current_screen()->remove_help_tab()} instead.
798 *
799 * @param array $old_compat_help Old contextual help.
800 * @param WP_Screen $screen Current WP_Screen instance.
801 */
802 self::$_old_compat_help = apply_filters_deprecated(
803 'contextual_help_list',
804 array( self::$_old_compat_help, $this ),
805 '3.3.0',
806 'get_current_screen()->add_help_tab(), get_current_screen()->remove_help_tab()'
807 );
808
809 $old_help = isset( self::$_old_compat_help[ $this->id ] ) ? self::$_old_compat_help[ $this->id ] : '';
810
811 /**
812 * Filters the legacy contextual help text.
813 *
814 * @since 2.7.0
815 * @deprecated 3.3.0 Use {@see get_current_screen()->add_help_tab()} or
816 * {@see get_current_screen()->remove_help_tab()} instead.
817 *
818 * @param string $old_help Help text that appears on the screen.
819 * @param string $screen_id Screen ID.
820 * @param WP_Screen $screen Current WP_Screen instance.
821 */
822 $old_help = apply_filters_deprecated(
823 'contextual_help',
824 array( $old_help, $this->id, $this ),
825 '3.3.0',
826 'get_current_screen()->add_help_tab(), get_current_screen()->remove_help_tab()'
827 );
828
829 // Default help only if there is no old-style block of text and no new-style help tabs.
830 if ( empty( $old_help ) && ! $this->get_help_tabs() ) {
831
832 /**
833 * Filters the default legacy contextual help text.
834 *
835 * @since 2.8.0
836 * @deprecated 3.3.0 Use {@see get_current_screen()->add_help_tab()} or
837 * {@see get_current_screen()->remove_help_tab()} instead.
838 *
839 * @param string $old_help_default Default contextual help text.
840 */
841 $default_help = apply_filters_deprecated(
842 'default_contextual_help',
843 array( '' ),
844 '3.3.0',
845 'get_current_screen()->add_help_tab(), get_current_screen()->remove_help_tab()'
846 );
847 if ( $default_help ) {
848 $old_help = '<p>' . $default_help . '</p>';
849 }
850 }
851
852 if ( $old_help ) {
853 $this->add_help_tab(
854 array(
855 'id' => 'old-contextual-help',
856 'title' => __( 'Overview' ),
857 'content' => $old_help,
858 )
859 );
860 }
861
862 $help_sidebar = $this->get_help_sidebar();
863
864 $help_class = 'hidden';
865 if ( ! $help_sidebar ) {
866 $help_class .= ' no-sidebar';
867 }
868
869 // Time to render!
870 ?>
871 <div id="screen-meta" class="metabox-prefs">
872
873 <div id="contextual-help-wrap" class="<?php echo esc_attr( $help_class ); ?>" tabindex="-1" aria-label="<?php esc_attr_e( 'Contextual Help Tab' ); ?>">
874 <div id="contextual-help-back"></div>
875 <div id="contextual-help-columns">
876 <div class="contextual-help-tabs">
877 <ul>
878 <?php
879 $class = ' class="active"';
880 foreach ( $this->get_help_tabs() as $tab ) :
881 $link_id = "tab-link-{$tab['id']}";
882 $panel_id = "tab-panel-{$tab['id']}";
883 ?>
884
885 <li id="<?php echo esc_attr( $link_id ); ?>"<?php echo $class; ?>>
886 <a href="<?php echo esc_url( "#$panel_id" ); ?>" aria-controls="<?php echo esc_attr( $panel_id ); ?>">
887 <?php echo esc_html( $tab['title'] ); ?>
888 </a>
889 </li>
890 <?php
891 $class = '';
892 endforeach;
893 ?>
894 </ul>
895 </div>
896
897 <?php if ( $help_sidebar ) : ?>
898 <div class="contextual-help-sidebar">
899 <?php echo $help_sidebar; ?>
900 </div>
901 <?php endif; ?>
902
903 <div class="contextual-help-tabs-wrap">
904 <?php
905 $classes = 'help-tab-content active';
906 foreach ( $this->get_help_tabs() as $tab ) :
907 $panel_id = "tab-panel-{$tab['id']}";
908 ?>
909
910 <div id="<?php echo esc_attr( $panel_id ); ?>" class="<?php echo $classes; ?>">
911 <?php
912 // Print tab content.
913 echo $tab['content'];
914
915 // If it exists, fire tab callback.
916 if ( ! empty( $tab['callback'] ) ) {
917 call_user_func_array( $tab['callback'], array( $this, $tab ) );
918 }
919 ?>
920 </div>
921 <?php
922 $classes = 'help-tab-content';
923 endforeach;
924 ?>
925 </div>
926 </div>
927 </div>
928 <?php
929 // Setup layout columns.
930
931 /**
932 * Filters the array of screen layout columns.
933 *
934 * This hook provides back-compat for plugins using the back-compat
935 * Filters instead of add_screen_option().
936 *
937 * @since 2.8.0
938 *
939 * @param array $empty_columns Empty array.
940 * @param string $screen_id Screen ID.
941 * @param WP_Screen $screen Current WP_Screen instance.
942 */
943 $columns = apply_filters( 'screen_layout_columns', array(), $this->id, $this );
944
945 if ( ! empty( $columns ) && isset( $columns[ $this->id ] ) ) {
946 $this->add_option( 'layout_columns', array( 'max' => $columns[ $this->id ] ) );
947 }
948
949 if ( $this->get_option( 'layout_columns' ) ) {
950 $this->columns = (int) get_user_option( "screen_layout_$this->id" );
951
952 if ( ! $this->columns && $this->get_option( 'layout_columns', 'default' ) ) {
953 $this->columns = $this->get_option( 'layout_columns', 'default' );
954 }
955 }
956 $GLOBALS['screen_layout_columns'] = $this->columns; // Set the global for back-compat.
957
958 // Add screen options.
959 if ( $this->show_screen_options() ) {
960 $this->render_screen_options();
961 }
962 ?>
963 </div>
964 <?php
965 if ( ! $this->get_help_tabs() && ! $this->show_screen_options() ) {
966 return;
967 }
968 ?>
969 <div id="screen-meta-links">
970 <?php if ( $this->show_screen_options() ) : ?>
971 <div id="screen-options-link-wrap" class="hide-if-no-js screen-meta-toggle">
972 <button type="button" id="show-settings-link" class="button show-settings" aria-controls="screen-options-wrap" aria-expanded="false"><?php _e( 'Screen Options' ); ?></button>
973 </div>
974 <?php
975 endif;
976 if ( $this->get_help_tabs() ) :
977 ?>
978 <div id="contextual-help-link-wrap" class="hide-if-no-js screen-meta-toggle">
979 <button type="button" id="contextual-help-link" class="button show-settings" aria-controls="contextual-help-wrap" aria-expanded="false"><?php _e( 'Help' ); ?></button>
980 </div>
981 <?php endif; ?>
982 </div>
983 <?php
984 }
985
986 /**
987 * @since 3.3.0
988 *
989 * @global array $wp_meta_boxes Global meta box state.
990 *
991 * @return bool
992 */
993 public function show_screen_options() {
994 global $wp_meta_boxes;
995
996 if ( is_bool( $this->_show_screen_options ) ) {
997 return $this->_show_screen_options;
998 }
999
1000 $columns = get_column_headers( $this );
1001
1002 $show_screen = ! empty( $wp_meta_boxes[ $this->id ] ) || $columns || $this->get_option( 'per_page' );
1003
1004 $this->_screen_settings = '';
1005
1006 if ( 'post' === $this->base ) {
1007 $expand = '<fieldset class="editor-expand hidden"><legend>' . __( 'Additional settings' ) . '</legend><label for="editor-expand-toggle">';
1008 $expand .= '<input type="checkbox" id="editor-expand-toggle"' . checked( get_user_setting( 'editor_expand', 'on' ), 'on', false ) . ' />';
1009 $expand .= __( 'Enable full-height editor and distraction-free functionality.' ) . '</label></fieldset>';
1010 $this->_screen_settings = $expand;
1011 }
1012
1013 /**
1014 * Filters the screen settings text displayed in the Screen Options tab.
1015 *
1016 * @since 3.0.0
1017 *
1018 * @param string $screen_settings Screen settings.
1019 * @param WP_Screen $screen WP_Screen object.
1020 */
1021 $this->_screen_settings = apply_filters( 'screen_settings', $this->_screen_settings, $this );
1022
1023 if ( $this->_screen_settings || $this->_options ) {
1024 $show_screen = true;
1025 }
1026
1027 /**
1028 * Filters whether to show the Screen Options tab.
1029 *
1030 * @since 3.2.0
1031 *
1032 * @param bool $show_screen Whether to show Screen Options tab.
1033 * Default true.
1034 * @param WP_Screen $screen Current WP_Screen instance.
1035 */
1036 $this->_show_screen_options = apply_filters( 'screen_options_show_screen', $show_screen, $this );
1037 return $this->_show_screen_options;
1038 }
1039
1040 /**
1041 * Renders the screen options tab.
1042 *
1043 * @since 3.3.0
1044 *
1045 * @param array $options {
1046 * Options for the tab.
1047 *
1048 * @type bool $wrap Whether the screen-options-wrap div will be included. Defaults to true.
1049 * }
1050 */
1051 public function render_screen_options( $options = array() ) {
1052 $options = wp_parse_args(
1053 $options,
1054 array(
1055 'wrap' => true,
1056 )
1057 );
1058
1059 $wrapper_start = '';
1060 $wrapper_end = '';
1061 $form_start = '';
1062 $form_end = '';
1063
1064 // Output optional wrapper.
1065 if ( $options['wrap'] ) {
1066 $wrapper_start = '<div id="screen-options-wrap" class="hidden" tabindex="-1" aria-label="' . esc_attr__( 'Screen Options Tab' ) . '">';
1067 $wrapper_end = '</div>';
1068 }
1069
1070 // Don't output the form and nonce for the widgets accessibility mode links.
1071 if ( 'widgets' !== $this->base ) {
1072 $form_start = "\n<form id='adv-settings' method='post'>\n";
1073 $form_end = "\n" . wp_nonce_field( 'screen-options-nonce', 'screenoptionnonce', false, false ) . "\n</form>\n";
1074 }
1075
1076 echo $wrapper_start . $form_start;
1077
1078 $this->render_meta_boxes_preferences();
1079 $this->render_list_table_columns_preferences();
1080 $this->render_screen_layout();
1081 $this->render_per_page_options();
1082 $this->render_view_mode();
1083 echo $this->_screen_settings;
1084
1085 /**
1086 * Filters whether to show the Screen Options submit button.
1087 *
1088 * @since 4.4.0
1089 *
1090 * @param bool $show_button Whether to show Screen Options submit button.
1091 * Default false.
1092 * @param WP_Screen $screen Current WP_Screen instance.
1093 */
1094 $show_button = apply_filters( 'screen_options_show_submit', false, $this );
1095
1096 if ( $show_button ) {
1097 submit_button( __( 'Apply' ), 'primary', 'screen-options-apply', true );
1098 }
1099
1100 echo $form_end . $wrapper_end;
1101 }
1102
1103 /**
1104 * Renders the meta boxes preferences.
1105 *
1106 * @since 4.4.0
1107 *
1108 * @global array $wp_meta_boxes Global meta box state.
1109 */
1110 public function render_meta_boxes_preferences() {
1111 global $wp_meta_boxes;
1112
1113 if ( ! isset( $wp_meta_boxes[ $this->id ] ) ) {
1114 return;
1115 }
1116 ?>
1117 <fieldset class="metabox-prefs">
1118 <legend><?php _e( 'Screen elements' ); ?></legend>
1119 <p>
1120 <?php _e( 'Some screen elements can be shown or hidden by using the checkboxes.' ); ?>
1121 <?php _e( 'Expand or collapse the elements by clicking on their headings, and arrange them by dragging their headings or by clicking on the up and down arrows.' ); ?>
1122 </p>
1123 <div class="metabox-prefs-container">
1124 <?php
1125
1126 meta_box_prefs( $this );
1127
1128 if ( 'dashboard' === $this->id && has_action( 'welcome_panel' ) && current_user_can( 'edit_theme_options' ) ) {
1129 if ( isset( $_GET['welcome'] ) ) {
1130 $welcome_checked = empty( $_GET['welcome'] ) ? 0 : 1;
1131 update_user_meta( get_current_user_id(), 'show_welcome_panel', $welcome_checked );
1132 } else {
1133 $welcome_checked = (int) get_user_meta( get_current_user_id(), 'show_welcome_panel', true );
1134 if ( 2 === $welcome_checked && wp_get_current_user()->user_email !== get_option( 'admin_email' ) ) {
1135 $welcome_checked = false;
1136 }
1137 }
1138 echo '<label for="wp_welcome_panel-hide">';
1139 echo '<input type="checkbox" id="wp_welcome_panel-hide"' . checked( (bool) $welcome_checked, true, false ) . ' />';
1140 echo _x( 'Welcome', 'Welcome panel' ) . "</label>\n";
1141 }
1142 ?>
1143 </div>
1144 </fieldset>
1145 <?php
1146 }
1147
1148 /**
1149 * Renders the list table columns preferences.
1150 *
1151 * @since 4.4.0
1152 */
1153 public function render_list_table_columns_preferences() {
1154
1155 $columns = get_column_headers( $this );
1156 $hidden = get_hidden_columns( $this );
1157
1158 if ( ! $columns ) {
1159 return;
1160 }
1161
1162 $legend = ! empty( $columns['_title'] ) ? $columns['_title'] : __( 'Columns' );
1163 ?>
1164 <fieldset class="metabox-prefs">
1165 <legend><?php echo $legend; ?></legend>
1166 <?php
1167 $special = array( '_title', 'cb', 'comment', 'media', 'name', 'title', 'username', 'blogname' );
1168
1169 foreach ( $columns as $column => $title ) {
1170 // Can't hide these for they are special.
1171 if ( in_array( $column, $special, true ) ) {
1172 continue;
1173 }
1174
1175 if ( empty( $title ) ) {
1176 continue;
1177 }
1178
1179 /*
1180 * The Comments column uses HTML in the display name with some screen
1181 * reader text. Make sure to strip tags from the Comments column
1182 * title and any other custom column title plugins might add.
1183 */
1184 $title = wp_strip_all_tags( $title );
1185
1186 $id = "$column-hide";
1187 echo '<label>';
1188 echo '<input class="hide-column-tog" name="' . $id . '" type="checkbox" id="' . $id . '" value="' . $column . '"' . checked( ! in_array( $column, $hidden, true ), true, false ) . ' />';
1189 echo "$title</label>\n";
1190 }
1191 ?>
1192 </fieldset>
1193 <?php
1194 }
1195
1196 /**
1197 * Renders the option for number of columns on the page.
1198 *
1199 * @since 3.3.0
1200 */
1201 public function render_screen_layout() {
1202 if ( ! $this->get_option( 'layout_columns' ) ) {
1203 return;
1204 }
1205
1206 $screen_layout_columns = $this->get_columns();
1207 $num = $this->get_option( 'layout_columns', 'max' );
1208
1209 ?>
1210 <fieldset class='columns-prefs'>
1211 <legend class="screen-layout"><?php _e( 'Layout' ); ?></legend>
1212 <?php for ( $i = 1; $i <= $num; ++$i ) : ?>
1213 <label class="columns-prefs-<?php echo $i; ?>">
1214 <input type='radio' name='screen_columns' value='<?php echo esc_attr( $i ); ?>' <?php checked( $screen_layout_columns, $i ); ?> />
1215 <?php
1216 printf(
1217 /* translators: %s: Number of columns on the page. */
1218 _n( '%s column', '%s columns', $i ),
1219 number_format_i18n( $i )
1220 );
1221 ?>
1222 </label>
1223 <?php endfor; ?>
1224 </fieldset>
1225 <?php
1226 }
1227
1228 /**
1229 * Renders the items per page option.
1230 *
1231 * @since 3.3.0
1232 */
1233 public function render_per_page_options() {
1234 if ( null === $this->get_option( 'per_page' ) ) {
1235 return;
1236 }
1237
1238 $per_page_label = $this->get_option( 'per_page', 'label' );
1239 if ( null === $per_page_label ) {
1240 $per_page_label = __( 'Number of items per page:' );
1241 }
1242
1243 $option = $this->get_option( 'per_page', 'option' );
1244 if ( ! $option ) {
1245 $option = str_replace( '-', '_', "{$this->id}_per_page" );
1246 }
1247
1248 $per_page = (int) get_user_option( $option );
1249 if ( empty( $per_page ) || $per_page < 1 ) {
1250 $per_page = $this->get_option( 'per_page', 'default' );
1251 if ( ! $per_page ) {
1252 $per_page = 20;
1253 }
1254 }
1255
1256 if ( 'edit_comments_per_page' === $option ) {
1257 $comment_status = isset( $_REQUEST['comment_status'] ) ? $_REQUEST['comment_status'] : 'all';
1258
1259 /** This filter is documented in wp-admin/includes/class-wp-comments-list-table.php */
1260 $per_page = apply_filters( 'comments_per_page', $per_page, $comment_status );
1261 } elseif ( 'categories_per_page' === $option ) {
1262 /** This filter is documented in wp-admin/includes/class-wp-terms-list-table.php */
1263 $per_page = apply_filters( 'edit_categories_per_page', $per_page );
1264 } else {
1265 /** This filter is documented in wp-admin/includes/class-wp-list-table.php */
1266 $per_page = apply_filters( "{$option}", $per_page );
1267 }
1268
1269 // Back compat.
1270 if ( isset( $this->post_type ) ) {
1271 /** This filter is documented in wp-admin/includes/post.php */
1272 $per_page = apply_filters( 'edit_posts_per_page', $per_page, $this->post_type );
1273 }
1274
1275 // This needs a submit button.
1276 add_filter( 'screen_options_show_submit', '__return_true' );
1277
1278 ?>
1279 <fieldset class="screen-options">
1280 <legend><?php _e( 'Pagination' ); ?></legend>
1281 <?php if ( $per_page_label ) : ?>
1282 <label for="<?php echo esc_attr( $option ); ?>"><?php echo $per_page_label; ?></label>
1283 <input type="number" step="1" min="1" max="999" class="screen-per-page" name="wp_screen_options[value]"
1284 id="<?php echo esc_attr( $option ); ?>"
1285 value="<?php echo esc_attr( $per_page ); ?>" />
1286 <?php endif; ?>
1287 <input type="hidden" name="wp_screen_options[option]" value="<?php echo esc_attr( $option ); ?>" />
1288 </fieldset>
1289 <?php
1290 }
1291
1292 /**
1293 * Renders the list table view mode preferences.
1294 *
1295 * @since 4.4.0
1296 *
1297 * @global string $mode List table view mode.
1298 */
1299 public function render_view_mode() {
1300 global $mode;
1301
1302 $screen = get_current_screen();
1303
1304 // Currently only enabled for posts and comments lists.
1305 if ( 'edit' !== $screen->base && 'edit-comments' !== $screen->base ) {
1306 return;
1307 }
1308
1309 $view_mode_post_types = get_post_types( array( 'show_ui' => true ) );
1310
1311 /**
1312 * Filters the post types that have different view mode options.
1313 *
1314 * @since 4.4.0
1315 *
1316 * @param string[] $view_mode_post_types Array of post types that can change view modes.
1317 * Default post types with show_ui on.
1318 */
1319 $view_mode_post_types = apply_filters( 'view_mode_post_types', $view_mode_post_types );
1320
1321 if ( 'edit' === $screen->base && ! in_array( $this->post_type, $view_mode_post_types, true ) ) {
1322 return;
1323 }
1324
1325 if ( ! isset( $mode ) ) {
1326 $mode = get_user_setting( 'posts_list_mode', 'list' );
1327 }
1328
1329 // This needs a submit button.
1330 add_filter( 'screen_options_show_submit', '__return_true' );
1331 ?>
1332 <fieldset class="metabox-prefs view-mode">
1333 <legend><?php _e( 'View mode' ); ?></legend>
1334 <label for="list-view-mode">
1335 <input id="list-view-mode" type="radio" name="mode" value="list" <?php checked( 'list', $mode ); ?> />
1336 <?php _e( 'Compact view' ); ?>
1337 </label>
1338 <label for="excerpt-view-mode">
1339 <input id="excerpt-view-mode" type="radio" name="mode" value="excerpt" <?php checked( 'excerpt', $mode ); ?> />
1340 <?php _e( 'Extended view' ); ?>
1341 </label>
1342 </fieldset>
1343 <?php
1344 }
1345
1346 /**
1347 * Renders screen reader text.
1348 *
1349 * @since 4.4.0
1350 *
1351 * @param string $key The screen reader text array named key.
1352 * @param string $tag Optional. The HTML tag to wrap the screen reader text. Default h2.
1353 */
1354 public function render_screen_reader_content( $key = '', $tag = 'h2' ) {
1355
1356 if ( ! isset( $this->_screen_reader_content[ $key ] ) ) {
1357 return;
1358 }
1359 echo "<$tag class='screen-reader-text'>" . $this->_screen_reader_content[ $key ] . "</$tag>";
1360 }
1361}
1362
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