Make WordPress Core

Ticket #50019: template.php

File template.php, 88.5 KB (added by coolmann, 6 years ago)

edited template.php

Line 
1<?php
2/**
3 * Template WordPress Administration API.
4 *
5 * A Big Mess. Also some neat functions that are nicely written.
6 *
7 * @package WordPress
8 * @subpackage Administration
9 */
10
11/** Walker_Category_Checklist class */
12require_once ABSPATH . 'wp-admin/includes/class-walker-category-checklist.php';
13
14/** WP_Internal_Pointers class */
15require_once ABSPATH . 'wp-admin/includes/class-wp-internal-pointers.php';
16
17//
18// Category Checklists.
19//
20
21/**
22 * Output an unordered list of checkbox input elements labeled with category names.
23 *
24 * @since 2.5.1
25 *
26 * @see wp_terms_checklist()
27 *
28 * @param int $post_id Optional. Post to generate a categories checklist for. Default 0.
29 * $selected_cats must not be an array. Default 0.
30 * @param int $descendants_and_self Optional. ID of the category to output along with its descendants.
31 * Default 0.
32 * @param int[] $selected_cats Optional. Array of category IDs to mark as checked. Default false.
33 * @param int[] $popular_cats Optional. Array of category IDs to receive the "popular-category" class.
34 * Default false.
35 * @param Walker $walker Optional. Walker object to use to build the output.
36 * Default is a Walker_Category_Checklist instance.
37 * @param bool $checked_ontop Optional. Whether to move checked items out of the hierarchy and to
38 * the top of the list. Default true.
39 */
40function wp_category_checklist( $post_id = 0, $descendants_and_self = 0, $selected_cats = false, $popular_cats = false, $walker = null, $checked_ontop = true ) {
41 wp_terms_checklist(
42 $post_id,
43 array(
44 'taxonomy' => 'category',
45 'descendants_and_self' => $descendants_and_self,
46 'selected_cats' => $selected_cats,
47 'popular_cats' => $popular_cats,
48 'walker' => $walker,
49 'checked_ontop' => $checked_ontop,
50 )
51 );
52}
53
54/**
55 * Output an unordered list of checkbox input elements labelled with term names.
56 *
57 * Taxonomy-independent version of wp_category_checklist().
58 *
59 * @since 3.0.0
60 * @since 4.4.0 Introduced the `$echo` argument.
61 *
62 * @param int $post_id Optional. Post ID. Default 0.
63 * @param array|string $args {
64 * Optional. Array or string of arguments for generating a terms checklist. Default empty array.
65 *
66 * @type int $descendants_and_self ID of the category to output along with its descendants.
67 * Default 0.
68 * @type int[] $selected_cats Array of category IDs to mark as checked. Default false.
69 * @type int[] $popular_cats Array of category IDs to receive the "popular-category" class.
70 * Default false.
71 * @type Walker $walker Walker object to use to build the output.
72 * Default is a Walker_Category_Checklist instance.
73 * @type string $taxonomy Taxonomy to generate the checklist for. Default 'category'.
74 * @type bool $checked_ontop Whether to move checked items out of the hierarchy and to
75 * the top of the list. Default true.
76 * @type bool $echo Whether to echo the generated markup. False to return the markup instead
77 * of echoing it. Default true.
78 * }
79 * @return string HTML list of input elements.
80 */
81function wp_terms_checklist( $post_id = 0, $args = array() ) {
82 $defaults = array(
83 'descendants_and_self' => 0,
84 'selected_cats' => false,
85 'popular_cats' => false,
86 'walker' => null,
87 'taxonomy' => 'category',
88 'checked_ontop' => true,
89 'echo' => true,
90 );
91
92 /**
93 * Filters the taxonomy terms checklist arguments.
94 *
95 * @since 3.4.0
96 *
97 * @see wp_terms_checklist()
98 *
99 * @param array $args An array of arguments.
100 * @param int $post_id The post ID.
101 */
102 $params = apply_filters( 'wp_terms_checklist_args', $args, $post_id );
103
104 $parsed_args = wp_parse_args( $params, $defaults );
105
106 if ( empty( $parsed_args['walker'] ) || ! ( $parsed_args['walker'] instanceof Walker ) ) {
107 $walker = new Walker_Category_Checklist;
108 } else {
109 $walker = $parsed_args['walker'];
110 }
111
112 $taxonomy = $parsed_args['taxonomy'];
113 $descendants_and_self = (int) $parsed_args['descendants_and_self'];
114
115 $args = array( 'taxonomy' => $taxonomy );
116
117 $tax = get_taxonomy( $taxonomy );
118 $args['disabled'] = ! current_user_can( $tax->cap->assign_terms );
119
120 $args['list_only'] = ! empty( $parsed_args['list_only'] );
121
122 if ( is_array( $parsed_args['selected_cats'] ) ) {
123 $args['selected_cats'] = $parsed_args['selected_cats'];
124 } elseif ( $post_id ) {
125 $args['selected_cats'] = wp_get_object_terms( $post_id, $taxonomy, array_merge( $args, array( 'fields' => 'ids' ) ) );
126 } else {
127 $args['selected_cats'] = array();
128 }
129
130 if ( is_array( $parsed_args['popular_cats'] ) ) {
131 $args['popular_cats'] = $parsed_args['popular_cats'];
132 } else {
133 $args['popular_cats'] = get_terms(
134 array(
135 'taxonomy' => $taxonomy,
136 'fields' => 'ids',
137 'orderby' => 'count',
138 'order' => 'DESC',
139 'number' => 10,
140 'hierarchical' => false,
141 )
142 );
143 }
144
145 if ( $descendants_and_self ) {
146 $categories = (array) get_terms(
147 array(
148 'taxonomy' => $taxonomy,
149 'child_of' => $descendants_and_self,
150 'hierarchical' => 0,
151 'hide_empty' => 0,
152 )
153 );
154 $self = get_term( $descendants_and_self, $taxonomy );
155 array_unshift( $categories, $self );
156 } else {
157 $categories = (array) get_terms(
158 array(
159 'taxonomy' => $taxonomy,
160 'get' => 'all',
161 )
162 );
163 }
164
165 $output = '';
166
167 if ( $parsed_args['checked_ontop'] ) {
168 // Post-process $categories rather than adding an exclude to the get_terms() query
169 // to keep the query the same across all posts (for any query cache).
170 $checked_categories = array();
171 $keys = array_keys( $categories );
172
173 foreach ( $keys as $k ) {
174 if ( in_array( $categories[ $k ]->term_id, $args['selected_cats'] ) ) {
175 $checked_categories[] = $categories[ $k ];
176 unset( $categories[ $k ] );
177 }
178 }
179
180 // Put checked categories on top.
181 $output .= $walker->walk( $checked_categories, 0, $args );
182 }
183 // Then the rest of them.
184 $output .= $walker->walk( $categories, 0, $args );
185
186 if ( $parsed_args['echo'] ) {
187 echo $output;
188 }
189
190 return $output;
191}
192
193/**
194 * Retrieve a list of the most popular terms from the specified taxonomy.
195 *
196 * If the $echo argument is true then the elements for a list of checkbox
197 * `<input>` elements labelled with the names of the selected terms is output.
198 * If the $post_ID global isn't empty then the terms associated with that
199 * post will be marked as checked.
200 *
201 * @since 2.5.0
202 *
203 * @param string $taxonomy Taxonomy to retrieve terms from.
204 * @param int $default Not used.
205 * @param int $number Number of terms to retrieve. Defaults to 10.
206 * @param bool $echo Optionally output the list as well. Defaults to true.
207 * @return int[] Array of popular term IDs.
208 */
209function wp_popular_terms_checklist( $taxonomy, $default = 0, $number = 10, $echo = true ) {
210 $post = get_post();
211
212 if ( $post && $post->ID ) {
213 $checked_terms = wp_get_object_terms( $post->ID, $taxonomy, array( 'fields' => 'ids' ) );
214 } else {
215 $checked_terms = array();
216 }
217
218 $terms = get_terms(
219 array(
220 'taxonomy' => $taxonomy,
221 'orderby' => 'count',
222 'order' => 'DESC',
223 'number' => $number,
224 'hierarchical' => false,
225 )
226 );
227
228 $tax = get_taxonomy( $taxonomy );
229
230 $popular_ids = array();
231 foreach ( (array) $terms as $term ) {
232 $popular_ids[] = $term->term_id;
233 if ( ! $echo ) { // Hack for Ajax use.
234 continue;
235 }
236 $id = "popular-$taxonomy-$term->term_id";
237 $checked = in_array( $term->term_id, $checked_terms ) ? 'checked="checked"' : '';
238 ?>
239
240 <li id="<?php echo $id; ?>" class="popular-category">
241 <label class="selectit">
242 <input id="in-<?php echo $id; ?>" type="checkbox" <?php echo $checked; ?> value="<?php echo (int) $term->term_id; ?>" <?php disabled( ! current_user_can( $tax->cap->assign_terms ) ); ?> />
243 <?php
244 /** This filter is documented in wp-includes/category-template.php */
245 echo esc_html( apply_filters( 'the_category', $term->name, '', '' ) );
246 ?>
247 </label>
248 </li>
249
250 <?php
251 }
252 return $popular_ids;
253}
254
255/**
256 * Outputs a link category checklist element.
257 *
258 * @since 2.5.1
259 *
260 * @param int $link_id
261 */
262function wp_link_category_checklist( $link_id = 0 ) {
263 $default = 1;
264
265 $checked_categories = array();
266
267 if ( $link_id ) {
268 $checked_categories = wp_get_link_cats( $link_id );
269 // No selected categories, strange.
270 if ( ! count( $checked_categories ) ) {
271 $checked_categories[] = $default;
272 }
273 } else {
274 $checked_categories[] = $default;
275 }
276
277 $categories = get_terms(
278 array(
279 'taxonomy' => 'link_category',
280 'orderby' => 'name',
281 'hide_empty' => 0,
282 )
283 );
284
285 if ( empty( $categories ) ) {
286 return;
287 }
288
289 foreach ( $categories as $category ) {
290 $cat_id = $category->term_id;
291
292 /** This filter is documented in wp-includes/category-template.php */
293 $name = esc_html( apply_filters( 'the_category', $category->name, '', '' ) );
294 $checked = in_array( $cat_id, $checked_categories ) ? ' checked="checked"' : '';
295 echo '<li id="link-category-', $cat_id, '"><label for="in-link-category-', $cat_id, '" class="selectit"><input value="', $cat_id, '" type="checkbox" name="link_category[]" id="in-link-category-', $cat_id, '"', $checked, '/> ', $name, '</label></li>';
296 }
297}
298
299/**
300 * Adds hidden fields with the data for use in the inline editor for posts and pages.
301 *
302 * @since 2.7.0
303 *
304 * @param WP_Post $post Post object.
305 */
306function get_inline_data( $post ) {
307 $post_type_object = get_post_type_object( $post->post_type );
308 if ( ! current_user_can( 'edit_post', $post->ID ) ) {
309 return;
310 }
311
312 $title = esc_textarea( trim( $post->post_title ) );
313
314 echo '
315<div class="hidden" id="inline_' . $post->ID . '">
316 <div class="post_title">' . $title . '</div>' .
317 /** This filter is documented in wp-admin/edit-tag-form.php */
318 '<div class="post_name">' . apply_filters( 'editable_slug', $post->post_name, $post ) . '</div>
319 <div class="post_author">' . $post->post_author . '</div>
320 <div class="comment_status">' . esc_html( $post->comment_status ) . '</div>
321 <div class="ping_status">' . esc_html( $post->ping_status ) . '</div>
322 <div class="_status">' . esc_html( $post->post_status ) . '</div>
323 <div class="jj">' . mysql2date( 'd', $post->post_date, false ) . '</div>
324 <div class="mm">' . mysql2date( 'm', $post->post_date, false ) . '</div>
325 <div class="aa">' . mysql2date( 'Y', $post->post_date, false ) . '</div>
326 <div class="hh">' . mysql2date( 'H', $post->post_date, false ) . '</div>
327 <div class="mn">' . mysql2date( 'i', $post->post_date, false ) . '</div>
328 <div class="ss">' . mysql2date( 's', $post->post_date, false ) . '</div>
329 <div class="post_password">' . esc_html( $post->post_password ) . '</div>';
330
331 if ( $post_type_object->hierarchical ) {
332 echo '<div class="post_parent">' . $post->post_parent . '</div>';
333 }
334
335 echo '<div class="page_template">' . ( $post->page_template ? esc_html( $post->page_template ) : 'default' ) . '</div>';
336
337 if ( post_type_supports( $post->post_type, 'page-attributes' ) ) {
338 echo '<div class="menu_order">' . $post->menu_order . '</div>';
339 }
340
341 $taxonomy_names = get_object_taxonomies( $post->post_type );
342 foreach ( $taxonomy_names as $taxonomy_name ) {
343 $taxonomy = get_taxonomy( $taxonomy_name );
344
345 if ( $taxonomy->hierarchical && $taxonomy->show_ui ) {
346
347 $terms = get_object_term_cache( $post->ID, $taxonomy_name );
348 if ( false === $terms ) {
349 $terms = wp_get_object_terms( $post->ID, $taxonomy_name );
350 wp_cache_add( $post->ID, wp_list_pluck( $terms, 'term_id' ), $taxonomy_name . '_relationships' );
351 }
352 $term_ids = empty( $terms ) ? array() : wp_list_pluck( $terms, 'term_id' );
353
354 echo '<div class="post_category" id="' . $taxonomy_name . '_' . $post->ID . '">' . implode( ',', $term_ids ) . '</div>';
355
356 } elseif ( $taxonomy->show_ui ) {
357
358 $terms_to_edit = get_terms_to_edit( $post->ID, $taxonomy_name );
359 if ( ! is_string( $terms_to_edit ) ) {
360 $terms_to_edit = '';
361 }
362
363 echo '<div class="tags_input" id="' . $taxonomy_name . '_' . $post->ID . '">'
364 . esc_html( str_replace( ',', ', ', $terms_to_edit ) ) . '</div>';
365
366 }
367 }
368
369 if ( ! $post_type_object->hierarchical ) {
370 echo '<div class="sticky">' . ( is_sticky( $post->ID ) ? 'sticky' : '' ) . '</div>';
371 }
372
373 if ( post_type_supports( $post->post_type, 'post-formats' ) ) {
374 echo '<div class="post_format">' . esc_html( get_post_format( $post->ID ) ) . '</div>';
375 }
376
377 /**
378 * Fires after outputting the fields for the inline editor for posts and pages.
379 *
380 * @since 4.9.8
381 *
382 * @param WP_Post $post The current post object.
383 * @param WP_Post_Type $post_type_object The current post's post type object.
384 */
385 do_action( 'add_inline_data', $post, $post_type_object );
386
387 echo '</div>';
388}
389
390/**
391 * Outputs the in-line comment reply-to form in the Comments list table.
392 *
393 * @since 2.7.0
394 *
395 * @global WP_List_Table $wp_list_table
396 *
397 * @param int $position
398 * @param bool $checkbox
399 * @param string $mode
400 * @param bool $table_row
401 */
402function wp_comment_reply( $position = 1, $checkbox = false, $mode = 'single', $table_row = true ) {
403 global $wp_list_table;
404 /**
405 * Filters the in-line comment reply-to form output in the Comments
406 * list table.
407 *
408 * Returning a non-empty value here will short-circuit display
409 * of the in-line comment-reply form in the Comments list table,
410 * echoing the returned value instead.
411 *
412 * @since 2.7.0
413 *
414 * @see wp_comment_reply()
415 *
416 * @param string $content The reply-to form content.
417 * @param array $args An array of default args.
418 */
419 $content = apply_filters(
420 'wp_comment_reply',
421 '',
422 array(
423 'position' => $position,
424 'checkbox' => $checkbox,
425 'mode' => $mode,
426 )
427 );
428
429 if ( ! empty( $content ) ) {
430 echo $content;
431 return;
432 }
433
434 if ( ! $wp_list_table ) {
435 if ( 'single' === $mode ) {
436 $wp_list_table = _get_list_table( 'WP_Post_Comments_List_Table' );
437 } else {
438 $wp_list_table = _get_list_table( 'WP_Comments_List_Table' );
439 }
440 }
441
442 ?>
443<form method="get">
444 <?php if ( $table_row ) : ?>
445<table style="display:none;"><tbody id="com-reply"><tr id="replyrow" class="inline-edit-row" style="display:none;"><td colspan="<?php echo $wp_list_table->get_column_count(); ?>" class="colspanchange">
446<?php else : ?>
447<div id="com-reply" style="display:none;"><div id="replyrow" style="display:none;">
448<?php endif; ?>
449 <fieldset class="comment-reply">
450 <legend>
451 <span class="hidden" id="editlegend"><?php _e( 'Edit Comment' ); ?></span>
452 <span class="hidden" id="replyhead"><?php _e( 'Reply to Comment' ); ?></span>
453 <span class="hidden" id="addhead"><?php _e( 'Add new Comment' ); ?></span>
454 </legend>
455
456 <div id="replycontainer">
457 <label for="replycontent" class="screen-reader-text"><?php _e( 'Comment' ); ?></label>
458 <?php
459 $quicktags_settings = array( 'buttons' => 'strong,em,link,block,del,ins,img,ul,ol,li,code,close' );
460 wp_editor(
461 '',
462 'replycontent',
463 array(
464 'media_buttons' => false,
465 'tinymce' => false,
466 'quicktags' => $quicktags_settings,
467 )
468 );
469 ?>
470 </div>
471
472 <div id="edithead" style="display:none;">
473 <div class="inside">
474 <label for="author-name"><?php _e( 'Name' ); ?></label>
475 <input type="text" name="newcomment_author" size="50" value="" id="author-name" />
476 </div>
477
478 <div class="inside">
479 <label for="author-email"><?php _e( 'Email' ); ?></label>
480 <input type="text" name="newcomment_author_email" size="50" value="" id="author-email" />
481 </div>
482
483 <div class="inside">
484 <label for="author-url"><?php _e( 'URL' ); ?></label>
485 <input type="text" id="author-url" name="newcomment_author_url" class="code" size="103" value="" />
486 </div>
487 </div>
488
489 <div id="replysubmit" class="submit">
490 <p class="reply-submit-buttons">
491 <button type="button" class="save button button-primary">
492 <span id="addbtn" style="display: none;"><?php _e( 'Add Comment' ); ?></span>
493 <span id="savebtn" style="display: none;"><?php _e( 'Update Comment' ); ?></span>
494 <span id="replybtn" style="display: none;"><?php _e( 'Submit Reply' ); ?></span>
495 </button>
496 <button type="button" class="cancel button"><?php _e( 'Cancel' ); ?></button>
497 <span class="waiting spinner"></span>
498 </p>
499 <div class="notice notice-error notice-alt inline hidden">
500 <p class="error"></p>
501 </div>
502 </div>
503
504 <input type="hidden" name="action" id="action" value="" />
505 <input type="hidden" name="comment_ID" id="comment_ID" value="" />
506 <input type="hidden" name="comment_post_ID" id="comment_post_ID" value="" />
507 <input type="hidden" name="status" id="status" value="" />
508 <input type="hidden" name="position" id="position" value="<?php echo $position; ?>" />
509 <input type="hidden" name="checkbox" id="checkbox" value="<?php echo $checkbox ? 1 : 0; ?>" />
510 <input type="hidden" name="mode" id="mode" value="<?php echo esc_attr( $mode ); ?>" />
511 <?php
512 wp_nonce_field( 'replyto-comment', '_ajax_nonce-replyto-comment', false );
513 if ( current_user_can( 'unfiltered_html' ) ) {
514 wp_nonce_field( 'unfiltered-html-comment', '_wp_unfiltered_html_comment', false );
515 }
516 ?>
517 </fieldset>
518 <?php if ( $table_row ) : ?>
519</td></tr></tbody></table>
520 <?php else : ?>
521</div></div>
522 <?php endif; ?>
523</form>
524 <?php
525}
526
527/**
528 * Output 'undo move to Trash' text for comments
529 *
530 * @since 2.9.0
531 */
532function wp_comment_trashnotice() {
533 ?>
534<div class="hidden" id="trash-undo-holder">
535 <div class="trash-undo-inside">
536 <?php
537 /* translators: %s: Comment author, filled by AJAX. */
538 printf( __( 'Comment by %s moved to the Trash.' ), '<strong></strong>' );
539 ?>
540 <span class="undo untrash"><a href="#"><?php _e( 'Undo' ); ?></a></span>
541 </div>
542</div>
543<div class="hidden" id="spam-undo-holder">
544 <div class="spam-undo-inside">
545 <?php
546 /* translators: %s: Comment author, filled by AJAX. */
547 printf( __( 'Comment by %s marked as spam.' ), '<strong></strong>' );
548 ?>
549 <span class="undo unspam"><a href="#"><?php _e( 'Undo' ); ?></a></span>
550 </div>
551</div>
552 <?php
553}
554
555/**
556 * Outputs a post's public meta data in the Custom Fields meta box.
557 *
558 * @since 1.2.0
559 *
560 * @param array $meta
561 */
562function list_meta( $meta ) {
563 // Exit if no meta.
564 if ( ! $meta ) {
565 echo '
566<table id="list-table" style="display: none;">
567 <thead>
568 <tr>
569 <th class="left">' . _x( 'Name', 'meta name' ) . '</th>
570 <th>' . __( 'Value' ) . '</th>
571 </tr>
572 </thead>
573 <tbody id="the-list" data-wp-lists="list:meta">
574 <tr><td></td></tr>
575 </tbody>
576</table>'; // TBODY needed for list-manipulation JS.
577 return;
578 }
579 $count = 0;
580 ?>
581<table id="list-table">
582 <thead>
583 <tr>
584 <th class="left"><?php _ex( 'Name', 'meta name' ); ?></th>
585 <th><?php _e( 'Value' ); ?></th>
586 </tr>
587 </thead>
588 <tbody id='the-list' data-wp-lists='list:meta'>
589 <?php
590 foreach ( $meta as $entry ) {
591 echo _list_meta_row( $entry, $count );
592 }
593 ?>
594 </tbody>
595</table>
596 <?php
597}
598
599/**
600 * Outputs a single row of public meta data in the Custom Fields meta box.
601 *
602 * @since 2.5.0
603 *
604 * @staticvar string $update_nonce
605 *
606 * @param array $entry
607 * @param int $count
608 * @return string
609 */
610function _list_meta_row( $entry, &$count ) {
611 static $update_nonce = '';
612
613 if ( is_protected_meta( $entry['meta_key'], 'post' ) ) {
614 return '';
615 }
616
617 if ( ! $update_nonce ) {
618 $update_nonce = wp_create_nonce( 'add-meta' );
619 }
620
621 $r = '';
622 ++ $count;
623
624 if ( is_serialized( $entry['meta_value'] ) ) {
625 if ( is_serialized_string( $entry['meta_value'] ) ) {
626 // This is a serialized string, so we should display it.
627 $entry['meta_value'] = maybe_unserialize( $entry['meta_value'] );
628 } else {
629 // This is a serialized array/object so we should NOT display it.
630 --$count;
631 return '';
632 }
633 }
634
635 $entry['meta_key'] = esc_attr( $entry['meta_key'] );
636 $entry['meta_value'] = esc_textarea( $entry['meta_value'] ); // Using a <textarea />.
637 $entry['meta_id'] = (int) $entry['meta_id'];
638
639 $delete_nonce = wp_create_nonce( 'delete-meta_' . $entry['meta_id'] );
640
641 $r .= "\n\t<tr id='meta-{$entry['meta_id']}'>";
642 $r .= "\n\t\t<td class='left'><label class='screen-reader-text' for='meta-{$entry['meta_id']}-key'>" . __( 'Key' ) . "</label><input name='meta[{$entry['meta_id']}][key]' id='meta-{$entry['meta_id']}-key' type='text' size='20' value='{$entry['meta_key']}' />";
643
644 $r .= "\n\t\t<div class='submit'>";
645 $r .= get_submit_button( __( 'Delete' ), 'deletemeta small', "deletemeta[{$entry['meta_id']}]", false, array( 'data-wp-lists' => "delete:the-list:meta-{$entry['meta_id']}::_ajax_nonce=$delete_nonce" ) );
646 $r .= "\n\t\t";
647 $r .= get_submit_button( __( 'Update' ), 'updatemeta small', "meta-{$entry['meta_id']}-submit", false, array( 'data-wp-lists' => "add:the-list:meta-{$entry['meta_id']}::_ajax_nonce-add-meta=$update_nonce" ) );
648 $r .= '</div>';
649 $r .= wp_nonce_field( 'change-meta', '_ajax_nonce', false, false );
650 $r .= '</td>';
651
652 $r .= "\n\t\t<td><label class='screen-reader-text' for='meta-{$entry['meta_id']}-value'>" . __( 'Value' ) . "</label><textarea name='meta[{$entry['meta_id']}][value]' id='meta-{$entry['meta_id']}-value' rows='2' cols='30'>{$entry['meta_value']}</textarea></td>\n\t</tr>";
653 return $r;
654}
655
656/**
657 * Prints the form in the Custom Fields meta box.
658 *
659 * @since 1.2.0
660 *
661 * @global wpdb $wpdb WordPress database abstraction object.
662 *
663 * @param WP_Post $post Optional. The post being edited.
664 */
665function meta_form( $post = null ) {
666 global $wpdb;
667 $post = get_post( $post );
668
669 /**
670 * Filters values for the meta key dropdown in the Custom Fields meta box.
671 *
672 * Returning a non-null value will effectively short-circuit and avoid a
673 * potentially expensive query against postmeta.
674 *
675 * @since 4.4.0
676 *
677 * @param array|null $keys Pre-defined meta keys to be used in place of a postmeta query. Default null.
678 * @param WP_Post $post The current post object.
679 */
680 $keys = apply_filters( 'postmeta_form_keys', null, $post );
681
682 if ( null === $keys ) {
683 /**
684 * Filters the number of custom fields to retrieve for the drop-down
685 * in the Custom Fields meta box.
686 *
687 * @since 2.1.0
688 *
689 * @param int $limit Number of custom fields to retrieve. Default 30.
690 */
691 $limit = apply_filters( 'postmeta_form_limit', 30 );
692 $sql = "SELECT DISTINCT meta_key
693 FROM $wpdb->postmeta
694 WHERE meta_key NOT BETWEEN '_' AND '_z'
695 HAVING meta_key NOT LIKE %s
696 ORDER BY meta_key
697 LIMIT %d";
698 $keys = $wpdb->get_col( $wpdb->prepare( $sql, $wpdb->esc_like( '_' ) . '%', $limit ) );
699 }
700
701 if ( $keys ) {
702 natcasesort( $keys );
703 $meta_key_input_id = 'metakeyselect';
704 } else {
705 $meta_key_input_id = 'metakeyinput';
706 }
707 ?>
708<p><strong><?php _e( 'Add New Custom Field:' ); ?></strong></p>
709<table id="newmeta">
710<thead>
711<tr>
712<th class="left"><label for="<?php echo $meta_key_input_id; ?>"><?php _ex( 'Name', 'meta name' ); ?></label></th>
713<th><label for="metavalue"><?php _e( 'Value' ); ?></label></th>
714</tr>
715</thead>
716
717<tbody>
718<tr>
719<td id="newmetaleft" class="left">
720 <?php if ( $keys ) { ?>
721<select id="metakeyselect" name="metakeyselect">
722<option value="#NONE#"><?php _e( '&mdash; Select &mdash;' ); ?></option>
723 <?php
724
725 foreach ( $keys as $key ) {
726 if ( is_protected_meta( $key, 'post' ) || ! current_user_can( 'add_post_meta', $post->ID, $key ) ) {
727 continue;
728 }
729 echo "\n<option value='" . esc_attr( $key ) . "'>" . esc_html( $key ) . '</option>';
730 }
731 ?>
732</select>
733<input class="hide-if-js" type="text" id="metakeyinput" name="metakeyinput" value="" />
734<a href="#postcustomstuff" class="hide-if-no-js" onclick="jQuery('#metakeyinput, #metakeyselect, #enternew, #cancelnew').toggle();return false;">
735<span id="enternew"><?php _e( 'Enter new' ); ?></span>
736<span id="cancelnew" class="hidden"><?php _e( 'Cancel' ); ?></span></a>
737<?php } else { ?>
738<input type="text" id="metakeyinput" name="metakeyinput" value="" />
739<?php } ?>
740</td>
741<td><textarea id="metavalue" name="metavalue" rows="2" cols="25"></textarea></td>
742</tr>
743
744<tr><td colspan="2">
745<div class="submit">
746 <?php
747 submit_button(
748 __( 'Add Custom Field' ),
749 '',
750 'addmeta',
751 false,
752 array(
753 'id' => 'newmeta-submit',
754 'data-wp-lists' => 'add:the-list:newmeta',
755 )
756 );
757 ?>
758</div>
759 <?php wp_nonce_field( 'add-meta', '_ajax_nonce-add-meta', false ); ?>
760</td></tr>
761</tbody>
762</table>
763 <?php
764
765}
766
767/**
768 * Print out HTML form date elements for editing post or comment publish date.
769 *
770 * @since 0.71
771 * @since 4.4.0 Converted to use get_comment() instead of the global `$comment`.
772 *
773 * @global WP_Locale $wp_locale WordPress date and time locale object.
774 *
775 * @param int|bool $edit Accepts 1|true for editing the date, 0|false for adding the date.
776 * @param int|bool $for_post Accepts 1|true for applying the date to a post, 0|false for a comment.
777 * @param int $tab_index The tabindex attribute to add. Default 0.
778 * @param int|bool $multi Optional. Whether the additional fields and buttons should be added.
779 * Default 0|false.
780 */
781function touch_time( $edit = 1, $for_post = 1, $tab_index = 0, $multi = 0 ) {
782 global $wp_locale;
783 $post = get_post();
784
785 if ( $for_post ) {
786 $edit = ! ( in_array( $post->post_status, array( 'draft', 'pending' ) ) && ( ! $post->post_date_gmt || '0000-00-00 00:00:00' == $post->post_date_gmt ) );
787 }
788
789 $tab_index_attribute = '';
790 if ( (int) $tab_index > 0 ) {
791 $tab_index_attribute = " tabindex=\"$tab_index\"";
792 }
793
794 // @todo Remove this?
795 // echo '<label for="timestamp" style="display: block;"><input type="checkbox" class="checkbox" name="edit_date" value="1" id="timestamp"'.$tab_index_attribute.' /> '.__( 'Edit timestamp' ).'</label><br />';
796
797 $post_date = ( $for_post ) ? $post->post_date : get_comment()->comment_date;
798 $jj = ( $edit ) ? mysql2date( 'd', $post_date, false ) : current_time( 'd' );
799 $mm = ( $edit ) ? mysql2date( 'm', $post_date, false ) : current_time( 'm' );
800 $aa = ( $edit ) ? mysql2date( 'Y', $post_date, false ) : current_time( 'Y' );
801 $hh = ( $edit ) ? mysql2date( 'H', $post_date, false ) : current_time( 'H' );
802 $mn = ( $edit ) ? mysql2date( 'i', $post_date, false ) : current_time( 'i' );
803 $ss = ( $edit ) ? mysql2date( 's', $post_date, false ) : current_time( 's' );
804
805 $cur_jj = current_time( 'd' );
806 $cur_mm = current_time( 'm' );
807 $cur_aa = current_time( 'Y' );
808 $cur_hh = current_time( 'H' );
809 $cur_mn = current_time( 'i' );
810
811 $month = '<label><span class="screen-reader-text">' . __( 'Month' ) . '</span><select ' . ( $multi ? '' : 'id="mm" ' ) . 'name="mm"' . $tab_index_attribute . ">\n";
812 for ( $i = 1; $i < 13; $i = $i + 1 ) {
813 $monthnum = zeroise( $i, 2 );
814 $monthtext = $wp_locale->get_month_abbrev( $wp_locale->get_month( $i ) );
815 $month .= "\t\t\t" . '<option value="' . $monthnum . '" data-text="' . $monthtext . '" ' . selected( $monthnum, $mm, false ) . '>';
816 /* translators: 1: Month number (01, 02, etc.), 2: Month abbreviation. */
817 $month .= sprintf( __( '%1$s-%2$s' ), $monthnum, $monthtext ) . "</option>\n";
818 }
819 $month .= '</select></label>';
820
821 $day = '<label><span class="screen-reader-text">' . __( 'Day' ) . '</span><input type="text" ' . ( $multi ? '' : 'id="jj" ' ) . 'name="jj" value="' . $jj . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" /></label>';
822 $year = '<label><span class="screen-reader-text">' . __( 'Year' ) . '</span><input type="text" ' . ( $multi ? '' : 'id="aa" ' ) . 'name="aa" value="' . $aa . '" size="4" maxlength="4"' . $tab_index_attribute . ' autocomplete="off" /></label>';
823 $hour = '<label><span class="screen-reader-text">' . __( 'Hour' ) . '</span><input type="text" ' . ( $multi ? '' : 'id="hh" ' ) . 'name="hh" value="' . $hh . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" /></label>';
824 $minute = '<label><span class="screen-reader-text">' . __( 'Minute' ) . '</span><input type="text" ' . ( $multi ? '' : 'id="mn" ' ) . 'name="mn" value="' . $mn . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" /></label>';
825
826 echo '<div class="timestamp-wrap">';
827 /* translators: 1: Month, 2: Day, 3: Year, 4: Hour, 5: Minute. */
828 printf( __( '%1$s %2$s, %3$s at %4$s:%5$s' ), $month, $day, $year, $hour, $minute );
829
830 echo '</div><input type="hidden" id="ss" name="ss" value="' . $ss . '" />';
831
832 if ( $multi ) {
833 return;
834 }
835
836 echo "\n\n";
837 $map = array(
838 'mm' => array( $mm, $cur_mm ),
839 'jj' => array( $jj, $cur_jj ),
840 'aa' => array( $aa, $cur_aa ),
841 'hh' => array( $hh, $cur_hh ),
842 'mn' => array( $mn, $cur_mn ),
843 );
844 foreach ( $map as $timeunit => $value ) {
845 list( $unit, $curr ) = $value;
846
847 echo '<input type="hidden" id="hidden_' . $timeunit . '" name="hidden_' . $timeunit . '" value="' . $unit . '" />' . "\n";
848 $cur_timeunit = 'cur_' . $timeunit;
849 echo '<input type="hidden" id="' . $cur_timeunit . '" name="' . $cur_timeunit . '" value="' . $curr . '" />' . "\n";
850 }
851 ?>
852
853<p>
854<a href="#edit_timestamp" class="save-timestamp hide-if-no-js button"><?php _e( 'OK' ); ?></a>
855<a href="#edit_timestamp" class="cancel-timestamp hide-if-no-js button-cancel"><?php _e( 'Cancel' ); ?></a>
856</p>
857 <?php
858}
859
860/**
861 * Print out option HTML elements for the page templates drop-down.
862 *
863 * @since 1.5.0
864 * @since 4.7.0 Added the `$post_type` parameter.
865 *
866 * @param string $default Optional. The template file name. Default empty.
867 * @param string $post_type Optional. Post type to get templates for. Default 'post'.
868 */
869function page_template_dropdown( $default = '', $post_type = 'page' ) {
870 $templates = get_page_templates( null, $post_type );
871 ksort( $templates );
872 foreach ( array_keys( $templates ) as $template ) {
873 $selected = selected( $default, $templates[ $template ], false );
874 echo "\n\t<option value='" . esc_attr( $templates[ $template ] ) . "' $selected>" . esc_html( $template ) . '</option>';
875 }
876}
877
878/**
879 * Print out option HTML elements for the page parents drop-down.
880 *
881 * @since 1.5.0
882 * @since 4.4.0 `$post` argument was added.
883 *
884 * @global wpdb $wpdb WordPress database abstraction object.
885 *
886 * @param int $default Optional. The default page ID to be pre-selected. Default 0.
887 * @param int $parent Optional. The parent page ID. Default 0.
888 * @param int $level Optional. Page depth level. Default 0.
889 * @param int|WP_Post $post Post ID or WP_Post object.
890 * @return void|false Void on success, false if the page has no children.
891 */
892function parent_dropdown( $default = 0, $parent = 0, $level = 0, $post = null ) {
893 global $wpdb;
894 $post = get_post( $post );
895 $items = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_parent, post_title FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'page' ORDER BY menu_order", $parent ) );
896
897 if ( $items ) {
898 foreach ( $items as $item ) {
899 // A page cannot be its own parent.
900 if ( $post && $post->ID && $item->ID == $post->ID ) {
901 continue;
902 }
903
904 $pad = str_repeat( '&nbsp;', $level * 3 );
905 $selected = selected( $default, $item->ID, false );
906
907 echo "\n\t<option class='level-$level' value='$item->ID' $selected>$pad " . esc_html( $item->post_title ) . '</option>';
908 parent_dropdown( $default, $item->ID, $level + 1 );
909 }
910 } else {
911 return false;
912 }
913}
914
915/**
916 * Print out option html elements for role selectors.
917 *
918 * @since 2.1.0
919 *
920 * @param string $selected Slug for the role that should be already selected.
921 */
922function wp_dropdown_roles( $selected = '' ) {
923 $r = '';
924
925 $editable_roles = array_reverse( get_editable_roles() );
926
927 foreach ( $editable_roles as $role => $details ) {
928 $name = translate_user_role( $details['name'] );
929 // Preselect specified role.
930 if ( $selected == $role ) {
931 $r .= "\n\t<option selected='selected' value='" . esc_attr( $role ) . "'>$name</option>";
932 } else {
933 $r .= "\n\t<option value='" . esc_attr( $role ) . "'>$name</option>";
934 }
935 }
936
937 echo $r;
938}
939
940/**
941 * Outputs the form used by the importers to accept the data to be imported
942 *
943 * @since 2.0.0
944 *
945 * @param string $action The action attribute for the form.
946 */
947function wp_import_upload_form( $action ) {
948
949 /**
950 * Filters the maximum allowed upload size for import files.
951 *
952 * @since 2.3.0
953 *
954 * @see wp_max_upload_size()
955 *
956 * @param int $max_upload_size Allowed upload size. Default 1 MB.
957 */
958 $bytes = apply_filters( 'import_upload_size_limit', wp_max_upload_size() );
959 $size = size_format( $bytes );
960 $upload_dir = wp_upload_dir();
961 if ( ! empty( $upload_dir['error'] ) ) :
962 ?>
963 <div class="error"><p><?php _e( 'Before you can upload your import file, you will need to fix the following error:' ); ?></p>
964 <p><strong><?php echo $upload_dir['error']; ?></strong></p></div>
965 <?php
966 else :
967 ?>
968<form enctype="multipart/form-data" id="import-upload-form" method="post" class="wp-upload-form" action="<?php echo esc_url( wp_nonce_url( $action, 'import-upload' ) ); ?>">
969<p>
970 <?php
971 printf(
972 '<label for="upload">%s</label> (%s)',
973 __( 'Choose a file from your computer:' ),
974 /* translators: %s: Maximum allowed file size. */
975 sprintf( __( 'Maximum size: %s' ), $size )
976 );
977 ?>
978<input type="file" id="upload" name="import" size="25" />
979<input type="hidden" name="action" value="save" />
980<input type="hidden" name="max_file_size" value="<?php echo $bytes; ?>" />
981</p>
982 <?php submit_button( __( 'Upload file and import' ), 'primary' ); ?>
983</form>
984 <?php
985 endif;
986}
987
988/**
989 * Adds a meta box to one or more screens.
990 *
991 * @since 2.5.0
992 * @since 4.4.0 The `$screen` parameter now accepts an array of screen IDs.
993 *
994 * @global array $wp_meta_boxes
995 *
996 * @param string $id Meta box ID (used in the 'id' attribute for the meta box).
997 * @param string $title Title of the meta box.
998 * @param callable $callback Function that fills the box with the desired content.
999 * The function should echo its output.
1000 * @param string|array|WP_Screen $screen Optional. The screen or screens on which to show the box
1001 * (such as a post type, 'link', or 'comment'). Accepts a single
1002 * screen ID, WP_Screen object, or array of screen IDs. Default
1003 * is the current screen. If you have used add_menu_page() or
1004 * add_submenu_page() to create a new screen (and hence screen_id),
1005 * make sure your menu slug conforms to the limits of sanitize_key()
1006 * otherwise the 'screen' menu may not correctly render on your page.
1007 * @param string $context Optional. The context within the screen where the boxes
1008 * should display. Available contexts vary from screen to
1009 * screen. Post edit screen contexts include 'normal', 'side',
1010 * and 'advanced'. Comments screen contexts include 'normal'
1011 * and 'side'. Menus meta boxes (accordion sections) all use
1012 * the 'side' context. Global default is 'advanced'.
1013 * @param string $priority Optional. The priority within the context where the boxes
1014 * should show ('high', 'low'). Default 'default'.
1015 * @param array $callback_args Optional. Data that should be set as the $args property
1016 * of the box array (which is the second parameter passed
1017 * to your callback). Default null.
1018 */
1019function add_meta_box( $id, $title, $callback, $screen = null, $context = 'advanced', $priority = 'default', $callback_args = null ) {
1020 global $wp_meta_boxes;
1021
1022 if ( empty( $screen ) ) {
1023 $screen = get_current_screen();
1024 } elseif ( is_string( $screen ) ) {
1025 $screen = convert_to_screen( $screen );
1026 } elseif ( is_array( $screen ) ) {
1027 foreach ( $screen as $single_screen ) {
1028 add_meta_box( $id, $title, $callback, $single_screen, $context, $priority, $callback_args );
1029 }
1030 }
1031
1032 if ( ! isset( $screen->id ) ) {
1033 return;
1034 }
1035
1036 $page = $screen->id;
1037
1038 if ( ! isset( $wp_meta_boxes ) ) {
1039 $wp_meta_boxes = array();
1040 }
1041 if ( ! isset( $wp_meta_boxes[ $page ] ) ) {
1042 $wp_meta_boxes[ $page ] = array();
1043 }
1044 if ( ! isset( $wp_meta_boxes[ $page ][ $context ] ) ) {
1045 $wp_meta_boxes[ $page ][ $context ] = array();
1046 }
1047
1048 foreach ( array_keys( $wp_meta_boxes[ $page ] ) as $a_context ) {
1049 foreach ( array( 'high', 'core', 'default', 'low' ) as $a_priority ) {
1050 if ( ! isset( $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ] ) ) {
1051 continue;
1052 }
1053
1054 // If a core box was previously added or removed by a plugin, don't add.
1055 if ( 'core' == $priority ) {
1056 // If core box previously deleted, don't add.
1057 if ( false === $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ] ) {
1058 return;
1059 }
1060
1061 /*
1062 * If box was added with default priority, give it core priority to
1063 * maintain sort order.
1064 */
1065 if ( 'default' == $a_priority ) {
1066 $wp_meta_boxes[ $page ][ $a_context ]['core'][ $id ] = $wp_meta_boxes[ $page ][ $a_context ]['default'][ $id ];
1067 unset( $wp_meta_boxes[ $page ][ $a_context ]['default'][ $id ] );
1068 }
1069 return;
1070 }
1071 // If no priority given and ID already present, use existing priority.
1072 if ( empty( $priority ) ) {
1073 $priority = $a_priority;
1074 /*
1075 * Else, if we're adding to the sorted priority, we don't know the title
1076 * or callback. Grab them from the previously added context/priority.
1077 */
1078 } elseif ( 'sorted' == $priority && is_array( $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ] ) ) {
1079 $title = $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ]['title'];
1080 $callback = $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ]['callback'];
1081 $callback_args = $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ]['args'];
1082 }
1083 // An ID can be in only one priority and one context.
1084 if ( $priority != $a_priority || $context != $a_context ) {
1085 unset( $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ] );
1086 }
1087 }
1088 }
1089
1090 if ( empty( $priority ) ) {
1091 $priority = 'low';
1092 }
1093
1094 if ( ! isset( $wp_meta_boxes[ $page ][ $context ][ $priority ] ) ) {
1095 $wp_meta_boxes[ $page ][ $context ][ $priority ] = array();
1096 }
1097
1098 $wp_meta_boxes[ $page ][ $context ][ $priority ][ $id ] = array(
1099 'id' => $id,
1100 'title' => $title,
1101 'callback' => $callback,
1102 'args' => $callback_args,
1103 );
1104}
1105
1106
1107/**
1108 * Function that renders a "fake" meta box with an information message,
1109 * shown on the block editor, when an incompatible meta box is found.
1110 *
1111 * @since 5.0.0
1112 *
1113 * @param mixed $object The data object being rendered on this screen.
1114 * @param array $box {
1115 * Custom formats meta box arguments.
1116 *
1117 * @type string $id Meta box 'id' attribute.
1118 * @type string $title Meta box title.
1119 * @type callable $old_callback The original callback for this meta box.
1120 * @type array $args Extra meta box arguments.
1121 * }
1122 */
1123function do_block_editor_incompatible_meta_box( $object, $box ) {
1124 $plugin = _get_plugin_from_callback( $box['old_callback'] );
1125 $plugins = get_plugins();
1126 echo '<p>';
1127 if ( $plugin ) {
1128 /* translators: %s: The name of the plugin that generated this meta box. */
1129 printf( __( "This meta box, from the %s plugin, isn't compatible with the block editor." ), "<strong>{$plugin['Name']}</strong>" );
1130 } else {
1131 _e( "This meta box isn't compatible with the block editor." );
1132 }
1133 echo '</p>';
1134
1135 if ( empty( $plugins['classic-editor/classic-editor.php'] ) ) {
1136 if ( current_user_can( 'install_plugins' ) ) {
1137 echo '<p>';
1138 printf(
1139 /* translators: %s: A link to install the Classic Editor plugin. */
1140 __( 'Please install the <a href="%s">Classic Editor plugin</a> to use this meta box.' ),
1141 esc_url( wp_nonce_url( self_admin_url( 'plugin-install.php?tab=favorites&user=wordpressdotorg&save=0' ), 'save_wporg_username_' . get_current_user_id() ) )
1142 );
1143 echo '</p>';
1144 }
1145 } elseif ( is_plugin_inactive( 'classic-editor/classic-editor.php' ) ) {
1146 if ( current_user_can( 'activate_plugins' ) ) {
1147 $activate_url = wp_nonce_url( self_admin_url( 'plugins.php?action=activate&plugin=classic-editor/classic-editor.php' ), 'activate-plugin_classic-editor/classic-editor.php' );
1148 echo '<p>';
1149 /* translators: %s: A link to activate the Classic Editor plugin. */
1150 printf( __( 'Please activate the <a href="%s">Classic Editor plugin</a> to use this meta box.' ), esc_url( $activate_url ) );
1151 echo '</p>';
1152 }
1153 } elseif ( $object instanceof WP_Post ) {
1154 $edit_url = add_query_arg(
1155 array(
1156 'classic-editor' => '',
1157 'classic-editor__forget' => '',
1158 ),
1159 get_edit_post_link( $object )
1160 );
1161 echo '<p>';
1162 /* translators: %s: A link to use the Classic Editor plugin. */
1163 printf( __( 'Please open the <a href="%s">classic editor</a> to use this meta box.' ), esc_url( $edit_url ) );
1164 echo '</p>';
1165 }
1166}
1167
1168/**
1169 * Internal helper function to find the plugin from a meta box callback.
1170 *
1171 * @since 5.0.0
1172 *
1173 * @access private
1174 *
1175 * @param callable $callback The callback function to check.
1176 * @return array|null The plugin that the callback belongs to, or null if it doesn't belong to a plugin.
1177 */
1178function _get_plugin_from_callback( $callback ) {
1179 try {
1180 if ( is_array( $callback ) ) {
1181 $reflection = new ReflectionMethod( $callback[0], $callback[1] );
1182 } elseif ( is_string( $callback ) && false !== strpos( $callback, '::' ) ) {
1183 $reflection = new ReflectionMethod( $callback );
1184 } else {
1185 $reflection = new ReflectionFunction( $callback );
1186 }
1187 } catch ( ReflectionException $exception ) {
1188 // We could not properly reflect on the callable, so we abort here.
1189 return null;
1190 }
1191
1192 // Don't show an error if it's an internal PHP function.
1193 if ( ! $reflection->isInternal() ) {
1194
1195 // Only show errors if the meta box was registered by a plugin.
1196 $filename = wp_normalize_path( $reflection->getFileName() );
1197 $plugin_dir = wp_normalize_path( WP_PLUGIN_DIR );
1198 if ( strpos( $filename, $plugin_dir ) === 0 ) {
1199 $filename = str_replace( $plugin_dir, '', $filename );
1200 $filename = preg_replace( '|^/([^/]*/).*$|', '\\1', $filename );
1201
1202 $plugins = get_plugins();
1203 foreach ( $plugins as $name => $plugin ) {
1204 if ( strpos( $name, $filename ) === 0 ) {
1205 return $plugin;
1206 }
1207 }
1208 }
1209 }
1210
1211 return null;
1212}
1213
1214/**
1215 * Meta-Box template function.
1216 *
1217 * @since 2.5.0
1218 *
1219 * @global array $wp_meta_boxes
1220 *
1221 * @staticvar bool $already_sorted
1222 *
1223 * @param string|WP_Screen $screen Screen identifier. If you have used add_menu_page() or
1224 * add_submenu_page() to create a new screen (and hence screen_id)
1225 * make sure your menu slug conforms to the limits of sanitize_key()
1226 * otherwise the 'screen' menu may not correctly render on your page.
1227 * @param string $context The screen context for which to display meta boxes.
1228 * @param mixed $object Gets passed to the first parameter of the meta box callback function.
1229 * Often this is the object that's the focus of the current screen, for
1230 * example a `WP_Post` or `WP_Comment` object.
1231 * @return int number of meta_boxes
1232 */
1233function do_meta_boxes( $screen, $context, $object ) {
1234 global $wp_meta_boxes;
1235 static $already_sorted = false;
1236
1237 if ( empty( $screen ) ) {
1238 $screen = get_current_screen();
1239 } elseif ( is_string( $screen ) ) {
1240 $screen = convert_to_screen( $screen );
1241 }
1242
1243 $page = $screen->id;
1244
1245 $hidden = get_hidden_meta_boxes( $screen );
1246
1247 printf( '<div id="%s-sortables" class="meta-box-sortables">', esc_attr( $context ) );
1248
1249 // Grab the ones the user has manually sorted.
1250 // Pull them out of their previous context/priority and into the one the user chose.
1251 $sorted = get_user_option( "meta-box-order_$page" );
1252 if ( ! $already_sorted && $sorted ) {
1253 foreach ( $sorted as $box_context => $ids ) {
1254 foreach ( explode( ',', $ids ) as $id ) {
1255 if ( $id && 'dashboard_browser_nag' !== $id ) {
1256 add_meta_box( $id, null, null, $screen, $box_context, 'sorted' );
1257 }
1258 }
1259 }
1260 }
1261
1262 $already_sorted = true;
1263
1264 $i = 0;
1265
1266 if ( isset( $wp_meta_boxes[ $page ][ $context ] ) ) {
1267 foreach ( array( 'high', 'sorted', 'core', 'default', 'low' ) as $priority ) {
1268 if ( isset( $wp_meta_boxes[ $page ][ $context ][ $priority ] ) ) {
1269 foreach ( (array) $wp_meta_boxes[ $page ][ $context ][ $priority ] as $box ) {
1270 if ( false == $box || ! $box['title'] ) {
1271 continue;
1272 }
1273
1274 $block_compatible = true;
1275 if ( is_array( $box['args'] ) ) {
1276 // If a meta box is just here for back compat, don't show it in the block editor.
1277 if ( $screen->is_block_editor() && isset( $box['args']['__back_compat_meta_box'] ) && $box['args']['__back_compat_meta_box'] ) {
1278 continue;
1279 }
1280
1281 if ( isset( $box['args']['__block_editor_compatible_meta_box'] ) ) {
1282 $block_compatible = (bool) $box['args']['__block_editor_compatible_meta_box'];
1283 unset( $box['args']['__block_editor_compatible_meta_box'] );
1284 }
1285
1286 // If the meta box is declared as incompatible with the block editor, override the callback function.
1287 if ( ! $block_compatible && $screen->is_block_editor() ) {
1288 $box['old_callback'] = $box['callback'];
1289 $box['callback'] = 'do_block_editor_incompatible_meta_box';
1290 }
1291
1292 if ( isset( $box['args']['__back_compat_meta_box'] ) ) {
1293 $block_compatible = $block_compatible || (bool) $box['args']['__back_compat_meta_box'];
1294 unset( $box['args']['__back_compat_meta_box'] );
1295 }
1296 }
1297
1298 $i++;
1299 // get_hidden_meta_boxes() doesn't apply in the block editor.
1300 $hidden_class = ( ! $screen->is_block_editor() && in_array( $box['id'], $hidden ) ) ? ' hide-if-js' : '';
1301 echo '<div id="' . $box['id'] . '" class="postbox ' . postbox_classes( $box['id'], $page ) . $hidden_class . '" ' . '>' . "\n";
1302 if ( 'dashboard_browser_nag' != $box['id'] ) {
1303 $widget_title = $box['title'];
1304
1305 if ( is_array( $box['args'] ) && isset( $box['args']['__widget_basename'] ) ) {
1306 $widget_title = $box['args']['__widget_basename'];
1307 // Do not pass this parameter to the user callback function.
1308 unset( $box['args']['__widget_basename'] );
1309 }
1310
1311 echo '<button type="button" class="handlediv" aria-expanded="true">';
1312 echo '<span class="screen-reader-text">' . sprintf(
1313 /* translators: %s: Meta box title. */
1314 __( 'Toggle panel: %s' ),
1315 $widget_title
1316 ) . '</span>';
1317 echo '<span class="toggle-indicator" aria-hidden="true"></span>';
1318 echo '</button>';
1319 }
1320 echo '<h2 class="hndle">';
1321 if ( 'dashboard_php_nag' === $box['id'] ) {
1322 echo '<span aria-hidden="true" class="dashicons dashicons-warning"></span>';
1323 echo '<span class="screen-reader-text">' . __( 'Warning:' ) . ' </span>';
1324 }
1325 echo "<span>{$box['title']}</span>";
1326 echo "</h2>\n";
1327 echo '<div class="inside">' . "\n";
1328
1329 if ( WP_DEBUG && ! $block_compatible && 'edit' === $screen->parent_base && ! $screen->is_block_editor() && ! isset( $_GET['meta-box-loader'] ) ) {
1330 $plugin = _get_plugin_from_callback( $box['callback'] );
1331 if ( $plugin ) {
1332 ?>
1333 <div class="error inline">
1334 <p>
1335 <?php
1336 /* translators: %s: The name of the plugin that generated this meta box. */
1337 printf( __( "This meta box, from the %s plugin, isn't compatible with the block editor." ), "<strong>{$plugin['Name']}</strong>" );
1338 ?>
1339 </p>
1340 </div>
1341 <?php
1342 }
1343 }
1344
1345 call_user_func( $box['callback'], $object, $box );
1346 echo "</div>\n";
1347 echo "</div>\n";
1348 }
1349 }
1350 }
1351 }
1352
1353 echo '</div>';
1354
1355 return $i;
1356
1357}
1358
1359/**
1360 * Removes a meta box from one or more screens.
1361 *
1362 * @since 2.6.0
1363 * @since 4.4.0 The `$screen` parameter now accepts an array of screen IDs.
1364 *
1365 * @global array $wp_meta_boxes
1366 *
1367 * @param string $id Meta box ID (used in the 'id' attribute for the meta box).
1368 * @param string|array|WP_Screen $screen The screen or screens on which the meta box is shown (such as a
1369 * post type, 'link', or 'comment'). Accepts a single screen ID,
1370 * WP_Screen object, or array of screen IDs.
1371 * @param string $context The context within the screen where the box is set to display.
1372 * Contexts vary from screen to screen. Post edit screen contexts
1373 * include 'normal', 'side', and 'advanced'. Comments screen contexts
1374 * include 'normal' and 'side'. Menus meta boxes (accordion sections)
1375 * all use the 'side' context.
1376 */
1377function remove_meta_box( $id, $screen, $context ) {
1378 global $wp_meta_boxes;
1379
1380 if ( empty( $screen ) ) {
1381 $screen = get_current_screen();
1382 } elseif ( is_string( $screen ) ) {
1383 $screen = convert_to_screen( $screen );
1384 } elseif ( is_array( $screen ) ) {
1385 foreach ( $screen as $single_screen ) {
1386 remove_meta_box( $id, $single_screen, $context );
1387 }
1388 }
1389
1390 if ( ! isset( $screen->id ) ) {
1391 return;
1392 }
1393
1394 $page = $screen->id;
1395
1396 if ( ! isset( $wp_meta_boxes ) ) {
1397 $wp_meta_boxes = array();
1398 }
1399 if ( ! isset( $wp_meta_boxes[ $page ] ) ) {
1400 $wp_meta_boxes[ $page ] = array();
1401 }
1402 if ( ! isset( $wp_meta_boxes[ $page ][ $context ] ) ) {
1403 $wp_meta_boxes[ $page ][ $context ] = array();
1404 }
1405
1406 foreach ( array( 'high', 'core', 'default', 'low' ) as $priority ) {
1407 $wp_meta_boxes[ $page ][ $context ][ $priority ][ $id ] = false;
1408 }
1409}
1410
1411/**
1412 * Meta Box Accordion Template Function.
1413 *
1414 * Largely made up of abstracted code from do_meta_boxes(), this
1415 * function serves to build meta boxes as list items for display as
1416 * a collapsible accordion.
1417 *
1418 * @since 3.6.0
1419 *
1420 * @uses global $wp_meta_boxes Used to retrieve registered meta boxes.
1421 *
1422 * @param string|object $screen The screen identifier.
1423 * @param string $context The meta box context.
1424 * @param mixed $object gets passed to the section callback function as first parameter.
1425 * @return int number of meta boxes as accordion sections.
1426 */
1427function do_accordion_sections( $screen, $context, $object ) {
1428 global $wp_meta_boxes;
1429
1430 wp_enqueue_script( 'accordion' );
1431
1432 if ( empty( $screen ) ) {
1433 $screen = get_current_screen();
1434 } elseif ( is_string( $screen ) ) {
1435 $screen = convert_to_screen( $screen );
1436 }
1437
1438 $page = $screen->id;
1439
1440 $hidden = get_hidden_meta_boxes( $screen );
1441 ?>
1442 <div id="side-sortables" class="accordion-container">
1443 <ul class="outer-border">
1444 <?php
1445 $i = 0;
1446 $first_open = false;
1447
1448 if ( isset( $wp_meta_boxes[ $page ][ $context ] ) ) {
1449 foreach ( array( 'high', 'core', 'default', 'low' ) as $priority ) {
1450 if ( isset( $wp_meta_boxes[ $page ][ $context ][ $priority ] ) ) {
1451 foreach ( $wp_meta_boxes[ $page ][ $context ][ $priority ] as $box ) {
1452 if ( false == $box || ! $box['title'] ) {
1453 continue;
1454 }
1455 $i++;
1456 $hidden_class = in_array( $box['id'], $hidden ) ? 'hide-if-js' : '';
1457
1458 $open_class = '';
1459 if ( ! $first_open && empty( $hidden_class ) ) {
1460 $first_open = true;
1461 $open_class = 'open';
1462 }
1463 ?>
1464 <li class="control-section accordion-section <?php echo $hidden_class; ?> <?php echo $open_class; ?> <?php echo esc_attr( $box['id'] ); ?>" id="<?php echo esc_attr( $box['id'] ); ?>">
1465 <h3 class="accordion-section-title hndle" tabindex="0">
1466 <?php echo esc_html( $box['title'] ); ?>
1467 <span class="screen-reader-text"><?php _e( 'Press return or enter to open this section' ); ?></span>
1468 </h3>
1469 <div class="accordion-section-content <?php postbox_classes( $box['id'], $page ); ?>">
1470 <div class="inside">
1471 <?php call_user_func( $box['callback'], $object, $box ); ?>
1472 </div><!-- .inside -->
1473 </div><!-- .accordion-section-content -->
1474 </li><!-- .accordion-section -->
1475 <?php
1476 }
1477 }
1478 }
1479 }
1480 ?>
1481 </ul><!-- .outer-border -->
1482 </div><!-- .accordion-container -->
1483 <?php
1484 return $i;
1485}
1486
1487/**
1488 * Add a new section to a settings page.
1489 *
1490 * Part of the Settings API. Use this to define new settings sections for an admin page.
1491 * Show settings sections in your admin page callback function with do_settings_sections().
1492 * Add settings fields to your section with add_settings_field().
1493 *
1494 * The $callback argument should be the name of a function that echoes out any
1495 * content you want to show at the top of the settings section before the actual
1496 * fields. It can output nothing if you want.
1497 *
1498 * @since 2.7.0
1499 *
1500 * @global $wp_settings_sections Storage array of all settings sections added to admin pages.
1501 *
1502 * @param string $id Slug-name to identify the section. Used in the 'id' attribute of tags.
1503 * @param string $title Formatted title of the section. Shown as the heading for the section.
1504 * @param callable $callback Function that echos out any content at the top of the section (between heading and fields).
1505 * @param string $page The slug-name of the settings page on which to show the section. Built-in pages include
1506 * 'general', 'reading', 'writing', 'discussion', 'media', etc. Create your own using
1507 * add_options_page();
1508 */
1509function add_settings_section( $id, $title, $callback, $page ) {
1510 global $wp_settings_sections;
1511
1512 if ( 'misc' == $page ) {
1513 _deprecated_argument(
1514 __FUNCTION__,
1515 '3.0.0',
1516 sprintf(
1517 /* translators: %s: misc */
1518 __( 'The "%s" options group has been removed. Use another settings group.' ),
1519 'misc'
1520 )
1521 );
1522 $page = 'general';
1523 }
1524
1525 if ( 'privacy' == $page ) {
1526 _deprecated_argument(
1527 __FUNCTION__,
1528 '3.5.0',
1529 sprintf(
1530 /* translators: %s: privacy */
1531 __( 'The "%s" options group has been removed. Use another settings group.' ),
1532 'privacy'
1533 )
1534 );
1535 $page = 'reading';
1536 }
1537
1538 $wp_settings_sections[ $page ][ $id ] = array(
1539 'id' => $id,
1540 'title' => $title,
1541 'callback' => $callback,
1542 );
1543}
1544
1545/**
1546 * Add a new field to a section of a settings page.
1547 *
1548 * Part of the Settings API. Use this to define a settings field that will show
1549 * as part of a settings section inside a settings page. The fields are shown using
1550 * do_settings_fields() in do_settings-sections()
1551 *
1552 * The $callback argument should be the name of a function that echoes out the
1553 * html input tags for this setting field. Use get_option() to retrieve existing
1554 * values to show.
1555 *
1556 * @since 2.7.0
1557 * @since 4.2.0 The `$class` argument was added.
1558 *
1559 * @global $wp_settings_fields Storage array of settings fields and info about their pages/sections.
1560 *
1561 * @param string $id Slug-name to identify the field. Used in the 'id' attribute of tags.
1562 * @param string $title Formatted title of the field. Shown as the label for the field
1563 * during output.
1564 * @param callable $callback Function that fills the field with the desired form inputs. The
1565 * function should echo its output.
1566 * @param string $page The slug-name of the settings page on which to show the section
1567 * (general, reading, writing, ...).
1568 * @param string $section Optional. The slug-name of the section of the settings page
1569 * in which to show the box. Default 'default'.
1570 * @param array $args {
1571 * Optional. Extra arguments used when outputting the field.
1572 *
1573 * @type string $label_for When supplied, the setting title will be wrapped
1574 * in a `<label>` element, its `for` attribute populated
1575 * with this value.
1576 * @type string $class CSS Class to be added to the `<tr>` element when the
1577 * field is output.
1578 * }
1579 */
1580function add_settings_field( $id, $title, $callback, $page, $section = 'default', $args = array() ) {
1581 global $wp_settings_fields;
1582
1583 if ( 'misc' == $page ) {
1584 _deprecated_argument(
1585 __FUNCTION__,
1586 '3.0.0',
1587 sprintf(
1588 /* translators: %s: misc */
1589 __( 'The "%s" options group has been removed. Use another settings group.' ),
1590 'misc'
1591 )
1592 );
1593 $page = 'general';
1594 }
1595
1596 if ( 'privacy' == $page ) {
1597 _deprecated_argument(
1598 __FUNCTION__,
1599 '3.5.0',
1600 sprintf(
1601 /* translators: %s: privacy */
1602 __( 'The "%s" options group has been removed. Use another settings group.' ),
1603 'privacy'
1604 )
1605 );
1606 $page = 'reading';
1607 }
1608
1609 $wp_settings_fields[ $page ][ $section ][ $id ] = array(
1610 'id' => $id,
1611 'title' => $title,
1612 'callback' => $callback,
1613 'args' => $args,
1614 );
1615}
1616
1617/**
1618 * Prints out all settings sections added to a particular settings page
1619 *
1620 * Part of the Settings API. Use this in a settings page callback function
1621 * to output all the sections and fields that were added to that $page with
1622 * add_settings_section() and add_settings_field()
1623 *
1624 * @global $wp_settings_sections Storage array of all settings sections added to admin pages.
1625 * @global $wp_settings_fields Storage array of settings fields and info about their pages/sections.
1626 * @since 2.7.0
1627 *
1628 * @param string $page The slug name of the page whose settings sections you want to output.
1629 */
1630function do_settings_sections( $page ) {
1631 global $wp_settings_sections, $wp_settings_fields;
1632
1633 if ( ! isset( $wp_settings_sections[ $page ] ) ) {
1634 return;
1635 }
1636
1637 foreach ( (array) $wp_settings_sections[ $page ] as $section ) {
1638 if ( $section['title'] ) {
1639 echo "<h2>{$section['title']}</h2>\n";
1640 }
1641
1642 if ( $section['callback'] ) {
1643 call_user_func( $section['callback'], $section );
1644 }
1645
1646 if ( ! isset( $wp_settings_fields ) || ! isset( $wp_settings_fields[ $page ] ) || ! isset( $wp_settings_fields[ $page ][ $section['id'] ] ) ) {
1647 continue;
1648 }
1649 echo '<table class="form-table" role="presentation">';
1650 do_settings_fields( $page, $section['id'] );
1651 echo '</table>';
1652 }
1653}
1654
1655/**
1656 * Print out the settings fields for a particular settings section.
1657 *
1658 * Part of the Settings API. Use this in a settings page to output
1659 * a specific section. Should normally be called by do_settings_sections()
1660 * rather than directly.
1661 *
1662 * @global $wp_settings_fields Storage array of settings fields and their pages/sections.
1663 *
1664 * @since 2.7.0
1665 *
1666 * @param string $page Slug title of the admin page whose settings fields you want to show.
1667 * @param string $section Slug title of the settings section whose fields you want to show.
1668 */
1669function do_settings_fields( $page, $section ) {
1670 global $wp_settings_fields;
1671
1672 if ( ! isset( $wp_settings_fields[ $page ][ $section ] ) ) {
1673 return;
1674 }
1675
1676 foreach ( (array) $wp_settings_fields[ $page ][ $section ] as $field ) {
1677 $class = '';
1678
1679 if ( ! empty( $field['args']['class'] ) ) {
1680 $class = ' class="' . esc_attr( $field['args']['class'] ) . '"';
1681 }
1682
1683 echo "<tr{$class}>";
1684
1685 if ( ! empty( $field['args']['label_for'] ) ) {
1686 echo '<th scope="row"><label for="' . esc_attr( $field['args']['label_for'] ) . '">' . $field['title'] . '</label></th>';
1687 } else {
1688 echo '<th scope="row">' . $field['title'] . '</th>';
1689 }
1690
1691 echo '<td>';
1692 call_user_func( $field['callback'], $field['args'] );
1693 echo '</td>';
1694 echo '</tr>';
1695 }
1696}
1697
1698/**
1699 * Register a settings error to be displayed to the user.
1700 *
1701 * Part of the Settings API. Use this to show messages to users about settings validation
1702 * problems, missing settings or anything else.
1703 *
1704 * Settings errors should be added inside the $sanitize_callback function defined in
1705 * register_setting() for a given setting to give feedback about the submission.
1706 *
1707 * By default messages will show immediately after the submission that generated the error.
1708 * Additional calls to settings_errors() can be used to show errors even when the settings
1709 * page is first accessed.
1710 *
1711 * @since 3.0.0
1712 * @since 5.3.0 Added `warning` and `info` as possible values for `$type`.
1713 *
1714 * @global array $wp_settings_errors Storage array of errors registered during this pageload
1715 *
1716 * @param string $setting Slug title of the setting to which this error applies.
1717 * @param string $code Slug-name to identify the error. Used as part of 'id' attribute in HTML output.
1718 * @param string $message The formatted message text to display to the user (will be shown inside styled
1719 * `<div>` and `<p>` tags).
1720 * @param string $type Optional. Message type, controls HTML class. Possible values include 'error',
1721 * 'success', 'warning', 'info'. Default 'error'.
1722 */
1723function add_settings_error( $setting, $code, $message, $type = 'error' ) {
1724 global $wp_settings_errors;
1725
1726 $wp_settings_errors[] = array(
1727 'setting' => $setting,
1728 'code' => $code,
1729 'message' => $message,
1730 'type' => $type,
1731 );
1732}
1733
1734/**
1735 * Fetch settings errors registered by add_settings_error().
1736 *
1737 * Checks the $wp_settings_errors array for any errors declared during the current
1738 * pageload and returns them.
1739 *
1740 * If changes were just submitted ($_GET['settings-updated']) and settings errors were saved
1741 * to the 'settings_errors' transient then those errors will be returned instead. This
1742 * is used to pass errors back across pageloads.
1743 *
1744 * Use the $sanitize argument to manually re-sanitize the option before returning errors.
1745 * This is useful if you have errors or notices you want to show even when the user
1746 * hasn't submitted data (i.e. when they first load an options page, or in the {@see 'admin_notices'}
1747 * action hook).
1748 *
1749 * @since 3.0.0
1750 *
1751 * @global array $wp_settings_errors Storage array of errors registered during this pageload
1752 *
1753 * @param string $setting Optional slug title of a specific setting whose errors you want.
1754 * @param boolean $sanitize Whether to re-sanitize the setting value before returning errors.
1755 * @return array Array of settings errors.
1756 */
1757function get_settings_errors( $setting = '', $sanitize = false ) {
1758 global $wp_settings_errors;
1759
1760 /*
1761 * If $sanitize is true, manually re-run the sanitization for this option
1762 * This allows the $sanitize_callback from register_setting() to run, adding
1763 * any settings errors you want to show by default.
1764 */
1765 if ( $sanitize ) {
1766 sanitize_option( $setting, get_option( $setting ) );
1767 }
1768
1769 // If settings were passed back from options.php then use them.
1770 if ( isset( $_GET['settings-updated'] ) && $_GET['settings-updated'] && get_transient( 'settings_errors' ) ) {
1771 $wp_settings_errors = array_merge( (array) $wp_settings_errors, get_transient( 'settings_errors' ) );
1772 delete_transient( 'settings_errors' );
1773 }
1774
1775 // Check global in case errors have been added on this pageload.
1776 if ( empty( $wp_settings_errors ) ) {
1777 return array();
1778 }
1779
1780 // Filter the results to those of a specific setting if one was set.
1781 if ( $setting ) {
1782 $setting_errors = array();
1783 foreach ( (array) $wp_settings_errors as $key => $details ) {
1784 if ( $setting == $details['setting'] ) {
1785 $setting_errors[] = $wp_settings_errors[ $key ];
1786 }
1787 }
1788 return $setting_errors;
1789 }
1790
1791 return $wp_settings_errors;
1792}
1793
1794/**
1795 * Display settings errors registered by add_settings_error().
1796 *
1797 * Part of the Settings API. Outputs a div for each error retrieved by
1798 * get_settings_errors().
1799 *
1800 * This is called automatically after a settings page based on the
1801 * Settings API is submitted. Errors should be added during the validation
1802 * callback function for a setting defined in register_setting().
1803 *
1804 * The $sanitize option is passed into get_settings_errors() and will
1805 * re-run the setting sanitization
1806 * on its current value.
1807 *
1808 * The $hide_on_update option will cause errors to only show when the settings
1809 * page is first loaded. if the user has already saved new values it will be
1810 * hidden to avoid repeating messages already shown in the default error
1811 * reporting after submission. This is useful to show general errors like
1812 * missing settings when the user arrives at the settings page.
1813 *
1814 * @since 3.0.0
1815 * @since 5.3.0 Legacy `error` and `updated` CSS classes are mapped to
1816 * `notice-error` and `notice-success`.
1817 *
1818 * @param string $setting Optional slug title of a specific setting whose errors you want.
1819 * @param bool $sanitize Whether to re-sanitize the setting value before returning errors.
1820 * @param bool $hide_on_update If set to true errors will not be shown if the settings page has
1821 * already been submitted.
1822 */
1823function settings_errors( $setting = '', $sanitize = false, $hide_on_update = false ) {
1824
1825 if ( $hide_on_update && ! empty( $_GET['settings-updated'] ) ) {
1826 return;
1827 }
1828
1829 $settings_errors = get_settings_errors( $setting, $sanitize );
1830
1831 if ( empty( $settings_errors ) ) {
1832 return;
1833 }
1834
1835 $output = '';
1836 foreach ( $settings_errors as $key => $details ) {
1837 if ( 'updated' === $details['type'] ) {
1838 $details['type'] = 'success';
1839 }
1840
1841 if ( in_array( $details['type'], array( 'error', 'success', 'warning', 'info' ) ) ) {
1842 $details['type'] = 'notice-' . $details['type'];
1843 }
1844
1845 $css_id = sprintf(
1846 'setting-error-%s',
1847 esc_attr( $details['code'] )
1848 );
1849 $css_class = sprintf(
1850 'notice %s settings-error is-dismissible',
1851 esc_attr( $details['type'] )
1852 );
1853
1854 $output .= "<div id='$css_id' class='$css_class'> \n";
1855 $output .= "<p><strong>{$details['message']}</strong></p>";
1856 $output .= "</div> \n";
1857 }
1858 echo $output;
1859}
1860
1861/**
1862 * Outputs the modal window used for attaching media to posts or pages in the media-listing screen.
1863 *
1864 * @since 2.7.0
1865 *
1866 * @param string $found_action
1867 */
1868function find_posts_div( $found_action = '' ) {
1869 ?>
1870 <div id="find-posts" class="find-box" style="display: none;">
1871 <div id="find-posts-head" class="find-box-head">
1872 <?php _e( 'Attach to existing content' ); ?>
1873 <button type="button" id="find-posts-close"><span class="screen-reader-text"><?php _e( 'Close media attachment panel' ); ?></span></button>
1874 </div>
1875 <div class="find-box-inside">
1876 <div class="find-box-search">
1877 <?php if ( $found_action ) { ?>
1878 <input type="hidden" name="found_action" value="<?php echo esc_attr( $found_action ); ?>" />
1879 <?php } ?>
1880 <input type="hidden" name="affected" id="affected" value="" />
1881 <?php wp_nonce_field( 'find-posts', '_ajax_nonce', false ); ?>
1882 <label class="screen-reader-text" for="find-posts-input"><?php _e( 'Search' ); ?></label>
1883 <input type="text" id="find-posts-input" name="ps" value="" />
1884 <span class="spinner"></span>
1885 <input type="button" id="find-posts-search" value="<?php esc_attr_e( 'Search' ); ?>" class="button" />
1886 <div class="clear"></div>
1887 </div>
1888 <div id="find-posts-response"></div>
1889 </div>
1890 <div class="find-box-buttons">
1891 <?php submit_button( __( 'Select' ), 'primary alignright', 'find-posts-submit', false ); ?>
1892 <div class="clear"></div>
1893 </div>
1894 </div>
1895 <?php
1896}
1897
1898/**
1899 * Displays the post password.
1900 *
1901 * The password is passed through esc_attr() to ensure that it is safe for placing in an html attribute.
1902 *
1903 * @since 2.7.0
1904 */
1905function the_post_password() {
1906 $post = get_post();
1907 if ( isset( $post->post_password ) ) {
1908 echo esc_attr( $post->post_password );
1909 }
1910}
1911
1912/**
1913 * Get the post title.
1914 *
1915 * The post title is fetched and if it is blank then a default string is
1916 * returned.
1917 *
1918 * @since 2.7.0
1919 *
1920 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
1921 * @return string The post title if set.
1922 */
1923function _draft_or_post_title( $post = 0 ) {
1924 $title = get_the_title( $post );
1925 if ( empty( $title ) ) {
1926 $title = __( '(no title)' );
1927 }
1928 return esc_html( $title );
1929}
1930
1931/**
1932 * Displays the search query.
1933 *
1934 * A simple wrapper to display the "s" parameter in a `GET` URI. This function
1935 * should only be used when the_search_query() cannot.
1936 *
1937 * @since 2.7.0
1938 */
1939function _admin_search_query() {
1940 echo isset( $_REQUEST['s'] ) ? esc_attr( wp_unslash( $_REQUEST['s'] ) ) : '';
1941}
1942
1943/**
1944 * Generic Iframe header for use with Thickbox
1945 *
1946 * @since 2.7.0
1947 *
1948 * @global string $hook_suffix
1949 * @global string $admin_body_class
1950 * @global WP_Locale $wp_locale WordPress date and time locale object.
1951 *
1952 * @param string $title Optional. Title of the Iframe page. Default empty.
1953 * @param bool $deprecated Not used.
1954 */
1955function iframe_header( $title = '', $deprecated = false ) {
1956 show_admin_bar( false );
1957 global $hook_suffix, $admin_body_class, $wp_locale;
1958 $admin_body_class = preg_replace( '/[^a-z0-9_-]+/i', '-', $hook_suffix );
1959
1960 $current_screen = get_current_screen();
1961
1962 header( 'Content-Type: ' . get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ) );
1963 _wp_admin_html_begin();
1964 ?>
1965<title><?php bloginfo( 'name' ); ?> &rsaquo; <?php echo $title; ?> &#8212; <?php _e( 'WordPress' ); ?></title>
1966 <?php
1967 wp_enqueue_style( 'colors' );
1968 ?>
1969<script type="text/javascript">
1970addLoadEvent = function(func){if(typeof jQuery!="undefined")jQuery(document).ready(func);else if(typeof wpOnload!='function'){wpOnload=func;}else{var oldonload=wpOnload;wpOnload=function(){oldonload();func();}}};
1971function tb_close(){var win=window.dialogArguments||opener||parent||top;win.tb_remove();}
1972var ajaxurl = '<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>',
1973 pagenow = '<?php echo $current_screen->id; ?>',
1974 typenow = '<?php echo $current_screen->post_type; ?>',
1975 adminpage = '<?php echo $admin_body_class; ?>',
1976 thousandsSeparator = '<?php echo addslashes( $wp_locale->number_format['thousands_sep'] ); ?>',
1977 decimalPoint = '<?php echo addslashes( $wp_locale->number_format['decimal_point'] ); ?>',
1978 isRtl = <?php echo (int) is_rtl(); ?>;
1979</script>
1980 <?php
1981 /** This action is documented in wp-admin/admin-header.php */
1982 do_action( 'admin_enqueue_scripts', $hook_suffix );
1983
1984 /** This action is documented in wp-admin/admin-header.php */
1985 do_action( "admin_print_styles-{$hook_suffix}" ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
1986
1987 /** This action is documented in wp-admin/admin-header.php */
1988 do_action( 'admin_print_styles' );
1989
1990 /** This action is documented in wp-admin/admin-header.php */
1991 do_action( "admin_print_scripts-{$hook_suffix}" ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
1992
1993 /** This action is documented in wp-admin/admin-header.php */
1994 do_action( 'admin_print_scripts' );
1995
1996 /** This action is documented in wp-admin/admin-header.php */
1997 do_action( "admin_head-{$hook_suffix}" ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
1998
1999 /** This action is documented in wp-admin/admin-header.php */
2000 do_action( 'admin_head' );
2001
2002 $admin_body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_user_locale() ) ) );
2003
2004 if ( is_rtl() ) {
2005 $admin_body_class .= ' rtl';
2006 }
2007
2008 ?>
2009</head>
2010 <?php
2011 /**
2012 * @global string $body_id
2013 */
2014 $admin_body_id = isset( $GLOBALS['body_id'] ) ? 'id="' . $GLOBALS['body_id'] . '" ' : '';
2015
2016 /** This filter is documented in wp-admin/admin-header.php */
2017 $admin_body_classes = apply_filters( 'admin_body_class', '' );
2018 $admin_body_classes = ltrim( $admin_body_classes . ' ' . $admin_body_class );
2019 ?>
2020<body <?php echo $admin_body_id; ?>class="wp-admin wp-core-ui no-js iframe <?php echo $admin_body_classes; ?>">
2021<script type="text/javascript">
2022(function(){
2023var c = document.body.className;
2024c = c.replace(/no-js/, 'js');
2025document.body.className = c;
2026})();
2027</script>
2028 <?php
2029}
2030
2031/**
2032 * Generic Iframe footer for use with Thickbox
2033 *
2034 * @since 2.7.0
2035 */
2036function iframe_footer() {
2037 /*
2038 * We're going to hide any footer output on iFrame pages,
2039 * but run the hooks anyway since they output JavaScript
2040 * or other needed content.
2041 */
2042
2043 /**
2044 * @global string $hook_suffix
2045 */
2046 global $hook_suffix;
2047 ?>
2048 <div class="hidden">
2049 <?php
2050 /** This action is documented in wp-admin/admin-footer.php */
2051 do_action( 'admin_footer', $hook_suffix );
2052
2053 /** This action is documented in wp-admin/admin-footer.php */
2054 do_action( "admin_print_footer_scripts-{$hook_suffix}" ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
2055
2056 /** This action is documented in wp-admin/admin-footer.php */
2057 do_action( 'admin_print_footer_scripts' );
2058 ?>
2059 </div>
2060<script type="text/javascript">if(typeof wpOnload=="function")wpOnload();</script>
2061</body>
2062</html>
2063 <?php
2064}
2065
2066/**
2067 * Function to echo or return the post states as HTML.
2068 *
2069 * @since 2.7.0
2070 * @since 5.3.0 Added the `$echo` parameter and a return value.
2071 *
2072 * @see get_post_states()
2073 *
2074 * @param WP_Post $post The post to retrieve states for.
2075 * @param bool $echo Optional. Whether to echo the post states as an HTML string. Default true.
2076 * @return string Post states string.
2077 */
2078function _post_states( $post, $echo = true ) {
2079 $post_states = get_post_states( $post );
2080 $post_states_string = '';
2081
2082 if ( ! empty( $post_states ) ) {
2083 $state_count = count( $post_states );
2084 $i = 0;
2085
2086 $post_states_string .= ' &mdash; ';
2087 foreach ( $post_states as $state ) {
2088 ++$i;
2089 ( $i == $state_count ) ? $sep = '' : $sep = ', ';
2090 $post_states_string .= "<span class='post-state'>$state$sep</span>";
2091 }
2092 }
2093
2094 if ( $echo ) {
2095 echo $post_states_string;
2096 }
2097
2098 return $post_states_string;
2099}
2100
2101/**
2102 * Retrieves an array of post states from a post.
2103 *
2104 * @since 5.3.0
2105 *
2106 * @param WP_Post $post The post to retrieve states for.
2107 * @return string[] Array of post state labels keyed by their state.
2108 */
2109function get_post_states( $post ) {
2110 $post_states = array();
2111 if ( isset( $_REQUEST['post_status'] ) ) {
2112 $post_status = $_REQUEST['post_status'];
2113 } else {
2114 $post_status = '';
2115 }
2116
2117 if ( ! empty( $post->post_password ) ) {
2118 $post_states['protected'] = _x( 'Password protected', 'post status' );
2119 }
2120
2121 if ( 'private' == $post->post_status && 'private' != $post_status ) {
2122 $post_states['private'] = _x( 'Private', 'post status' );
2123 }
2124
2125 if ( 'draft' === $post->post_status ) {
2126 if ( get_post_meta( $post->ID, '_customize_changeset_uuid', true ) ) {
2127 $post_states[] = __( 'Customization Draft' );
2128 } elseif ( 'draft' !== $post_status ) {
2129 $post_states['draft'] = _x( 'Draft', 'post status' );
2130 }
2131 } elseif ( 'trash' === $post->post_status && get_post_meta( $post->ID, '_customize_changeset_uuid', true ) ) {
2132 $post_states[] = _x( 'Customization Draft', 'post status' );
2133 }
2134
2135 if ( 'pending' == $post->post_status && 'pending' != $post_status ) {
2136 $post_states['pending'] = _x( 'Pending', 'post status' );
2137 }
2138
2139 if ( is_sticky( $post->ID ) ) {
2140 $post_states['sticky'] = _x( 'Sticky', 'post status' );
2141 }
2142
2143 if ( 'future' === $post->post_status ) {
2144 $post_states['scheduled'] = _x( 'Scheduled', 'post status' );
2145 }
2146
2147 if ( 'page' === get_option( 'show_on_front' ) ) {
2148 if ( intval( get_option( 'page_on_front' ) ) === $post->ID ) {
2149 $post_states['page_on_front'] = _x( 'Front Page', 'page label' );
2150 }
2151
2152 if ( intval( get_option( 'page_for_posts' ) ) === $post->ID ) {
2153 $post_states['page_for_posts'] = _x( 'Posts Page', 'page label' );
2154 }
2155 }
2156
2157 if ( intval( get_option( 'wp_page_for_privacy_policy' ) ) === $post->ID ) {
2158 $post_states['page_for_privacy_policy'] = _x( 'Privacy Policy Page', 'page label' );
2159 }
2160
2161 /**
2162 * Filters the default post display states used in the posts list table.
2163 *
2164 * @since 2.8.0
2165 * @since 3.6.0 Added the `$post` parameter.
2166 *
2167 * @param string[] $post_states An array of post display states.
2168 * @param WP_Post $post The current post object.
2169 */
2170 return apply_filters( 'display_post_states', $post_states, $post );
2171}
2172
2173/**
2174 * Function to echo the attachment media states as HTML.
2175 *
2176 * @since 3.2.0
2177 *
2178 * @param WP_Post $post The attachment post to retrieve states for.
2179 * @return string Media states string.
2180 */
2181function _media_states( $post ) {
2182 $media_states = array();
2183 $stylesheet = get_option( 'stylesheet' );
2184
2185 if ( current_theme_supports( 'custom-header' ) ) {
2186 $meta_header = get_post_meta( $post->ID, '_wp_attachment_is_custom_header', true );
2187
2188 if ( is_random_header_image() ) {
2189 $header_images = wp_list_pluck( get_uploaded_header_images(), 'attachment_id' );
2190
2191 if ( $meta_header == $stylesheet && in_array( $post->ID, $header_images ) ) {
2192 $media_states[] = __( 'Header Image' );
2193 }
2194 } else {
2195 $header_image = get_header_image();
2196
2197 // Display "Header Image" if the image was ever used as a header image.
2198 if ( ! empty( $meta_header ) && $meta_header === $stylesheet && wp_get_attachment_url( $post->ID ) !== $header_image ) {
2199 $media_states[] = __( 'Header Image' );
2200 }
2201
2202 // Display "Current Header Image" if the image is currently the header image.
2203 if ( $header_image && wp_get_attachment_url( $post->ID ) === $header_image ) {
2204 $media_states[] = __( 'Current Header Image' );
2205 }
2206 }
2207 }
2208
2209 if ( current_theme_supports( 'custom-background' ) ) {
2210 $meta_background = get_post_meta( $post->ID, '_wp_attachment_is_custom_background', true );
2211
2212 if ( ! empty( $meta_background ) && $meta_background === $stylesheet ) {
2213 $media_states[] = __( 'Background Image' );
2214
2215 $background_image = get_background_image();
2216 if ( $background_image && wp_get_attachment_url( $post->ID ) === $background_image ) {
2217 $media_states[] = __( 'Current Background Image' );
2218 }
2219 }
2220 }
2221
2222 if ( get_option( 'site_icon' ) == $post->ID ) {
2223 $media_states[] = __( 'Site Icon' );
2224 }
2225
2226 if ( get_theme_mod( 'custom_logo' ) == $post->ID ) {
2227 $media_states[] = __( 'Logo' );
2228 }
2229
2230 /**
2231 * Filters the default media display states for items in the Media list table.
2232 *
2233 * @since 3.2.0
2234 * @since 4.8.0 Added the `$post` parameter.
2235 *
2236 * @param string[] $media_states An array of media states. Default 'Header Image',
2237 * 'Background Image', 'Site Icon', 'Logo'.
2238 * @param WP_Post $post The current attachment object.
2239 */
2240 $media_states = apply_filters( 'display_media_states', $media_states, $post );
2241
2242 if ( ! empty( $media_states ) ) {
2243 $state_count = count( $media_states );
2244 $i = 0;
2245 echo ' &mdash; ';
2246 foreach ( $media_states as $state ) {
2247 ++$i;
2248 ( $i == $state_count ) ? $sep = '' : $sep = ', ';
2249 echo "<span class='post-state'>$state$sep</span>";
2250 }
2251 }
2252}
2253
2254/**
2255 * Test support for compressing JavaScript from PHP
2256 *
2257 * Outputs JavaScript that tests if compression from PHP works as expected
2258 * and sets an option with the result. Has no effect when the current user
2259 * is not an administrator. To run the test again the option 'can_compress_scripts'
2260 * has to be deleted.
2261 *
2262 * @since 2.8.0
2263 */
2264function compression_test() {
2265 ?>
2266 <script type="text/javascript">
2267 var compressionNonce = <?php echo wp_json_encode( wp_create_nonce( 'update_can_compress_scripts' ) ); ?>;
2268 var testCompression = {
2269 get : function(test) {
2270 var x;
2271 if ( window.XMLHttpRequest ) {
2272 x = new XMLHttpRequest();
2273 } else {
2274 try{x=new ActiveXObject('Msxml2.XMLHTTP');}catch(e){try{x=new ActiveXObject('Microsoft.XMLHTTP');}catch(e){};}
2275 }
2276
2277 if (x) {
2278 x.onreadystatechange = function() {
2279 var r, h;
2280 if ( x.readyState == 4 ) {
2281 r = x.responseText.substr(0, 18);
2282 h = x.getResponseHeader('Content-Encoding');
2283 testCompression.check(r, h, test);
2284 }
2285 };
2286
2287 x.open('GET', ajaxurl + '?action=wp-compression-test&test='+test+'&_ajax_nonce='+compressionNonce+'&'+(new Date()).getTime(), true);
2288 x.send('');
2289 }
2290 },
2291
2292 check : function(r, h, test) {
2293 if ( ! r && ! test )
2294 this.get(1);
2295
2296 if ( 1 == test ) {
2297 if ( h && ( h.match(/deflate/i) || h.match(/gzip/i) ) )
2298 this.get('no');
2299 else
2300 this.get(2);
2301
2302 return;
2303 }
2304
2305 if ( 2 == test ) {
2306 if ( '"wpCompressionTest' == r )
2307 this.get('yes');
2308 else
2309 this.get('no');
2310 }
2311 }
2312 };
2313 testCompression.check();
2314 </script>
2315 <?php
2316}
2317
2318/**
2319 * Echoes a submit button, with provided text and appropriate class(es).
2320 *
2321 * @since 3.1.0
2322 *
2323 * @see get_submit_button()
2324 *
2325 * @param string $text The text of the button (defaults to 'Save Changes')
2326 * @param string $type Optional. The type and CSS class(es) of the button. Core values
2327 * include 'primary', 'small', and 'large'. Default 'primary'.
2328 * @param string $name The HTML name of the submit button. Defaults to "submit". If no
2329 * id attribute is given in $other_attributes below, $name will be
2330 * used as the button's id.
2331 * @param bool $wrap True if the output button should be wrapped in a paragraph tag,
2332 * false otherwise. Defaults to true.
2333 * @param array|string $other_attributes Other attributes that should be output with the button, mapping
2334 * attributes to their values, such as setting tabindex to 1, etc.
2335 * These key/value attribute pairs will be output as attribute="value",
2336 * where attribute is the key. Other attributes can also be provided
2337 * as a string such as 'tabindex="1"', though the array format is
2338 * preferred. Default null.
2339 */
2340function submit_button( $text = null, $type = 'primary', $name = 'submit', $wrap = true, $other_attributes = null ) {
2341 echo get_submit_button( $text, $type, $name, $wrap, $other_attributes );
2342}
2343
2344/**
2345 * Returns a submit button, with provided text and appropriate class
2346 *
2347 * @since 3.1.0
2348 *
2349 * @param string $text Optional. The text of the button. Default 'Save Changes'.
2350 * @param string $type Optional. The type and CSS class(es) of the button. Core values
2351 * include 'primary', 'small', and 'large'. Default 'primary large'.
2352 * @param string $name Optional. The HTML name of the submit button. Defaults to "submit".
2353 * If no id attribute is given in $other_attributes below, `$name` will
2354 * be used as the button's id. Default 'submit'.
2355 * @param bool $wrap Optional. True if the output button should be wrapped in a paragraph
2356 * tag, false otherwise. Default true.
2357 * @param array|string $other_attributes Optional. Other attributes that should be output with the button,
2358 * mapping attributes to their values, such as `array( 'tabindex' => '1' )`.
2359 * These attributes will be output as `attribute="value"`, such as
2360 * `tabindex="1"`. Other attributes can also be provided as a string such
2361 * as `tabindex="1"`, though the array format is typically cleaner.
2362 * Default empty.
2363 * @return string Submit button HTML.
2364 */
2365function get_submit_button( $text = '', $type = 'primary large', $name = 'submit', $wrap = true, $other_attributes = '' ) {
2366 if ( ! is_array( $type ) ) {
2367 $type = explode( ' ', $type );
2368 }
2369
2370 $button_shorthand = array( 'primary', 'small', 'large' );
2371 $classes = array( 'button' );
2372 foreach ( $type as $t ) {
2373 if ( 'secondary' === $t || 'button-secondary' === $t ) {
2374 continue;
2375 }
2376 $classes[] = in_array( $t, $button_shorthand ) ? 'button-' . $t : $t;
2377 }
2378 // Remove empty items, remove duplicate items, and finally build a string.
2379 $class = implode( ' ', array_unique( array_filter( $classes ) ) );
2380
2381 $text = $text ? $text : __( 'Save Changes' );
2382
2383 // Default the id attribute to $name unless an id was specifically provided in $other_attributes.
2384 $id = $name;
2385 if ( is_array( $other_attributes ) && isset( $other_attributes['id'] ) ) {
2386 $id = $other_attributes['id'];
2387 unset( $other_attributes['id'] );
2388 }
2389
2390 $attributes = '';
2391 if ( is_array( $other_attributes ) ) {
2392 foreach ( $other_attributes as $attribute => $value ) {
2393 $attributes .= $attribute . '="' . esc_attr( $value ) . '" '; // Trailing space is important.
2394 }
2395 } elseif ( ! empty( $other_attributes ) ) { // Attributes provided as a string.
2396 $attributes = $other_attributes;
2397 }
2398
2399 // Don't output empty name and id attributes.
2400 $name_attr = $name ? ' name="' . esc_attr( $name ) . '"' : '';
2401 $id_attr = $id ? ' id="' . esc_attr( $id ) . '"' : '';
2402
2403 $button = '<input type="submit"' . $name_attr . $id_attr . ' class="' . esc_attr( $class );
2404 $button .= '" value="' . esc_attr( $text ) . '" ' . $attributes . ' />';
2405
2406 if ( $wrap ) {
2407 $button = '<p class="submit">' . $button . '</p>';
2408 }
2409
2410 return $button;
2411}
2412
2413/**
2414 * @global bool $is_IE
2415 */
2416function _wp_admin_html_begin() {
2417 global $is_IE;
2418
2419 $admin_html_class = ( is_admin_bar_showing() ) ? 'wp-toolbar' : '';
2420
2421 if ( $is_IE ) {
2422 header( 'X-UA-Compatible: IE=edge' );
2423 }
2424
2425 ?>
2426<!DOCTYPE html>
2427<!--[if IE 8]>
2428<html xmlns="http://www.w3.org/1999/xhtml" class="ie8 <?php echo $admin_html_class; ?>"
2429 <?php
2430 /**
2431 * Fires inside the HTML tag in the admin header.
2432 *
2433 * @since 2.2.0
2434 */
2435 do_action( 'admin_xml_ns' );
2436
2437 language_attributes();
2438 ?>
2439 >
2440<![endif]-->
2441<!--[if !(IE 8) ]><!-->
2442<html xmlns="http://www.w3.org/1999/xhtml" class="<?php echo $admin_html_class; ?>"
2443 <?php
2444 /** This action is documented in wp-admin/includes/template.php */
2445 do_action( 'admin_xml_ns' );
2446
2447 language_attributes();
2448 ?>
2449 >
2450<!--<![endif]-->
2451<head>
2452<meta http-equiv="Content-Type" content="<?php bloginfo( 'html_type' ); ?>; charset=<?php echo get_option( 'blog_charset' ); ?>" />
2453 <?php
2454}
2455
2456/**
2457 * Convert a screen string to a screen object
2458 *
2459 * @since 3.0.0
2460 *
2461 * @param string $hook_name The hook name (also known as the hook suffix) used to determine the screen.
2462 * @return WP_Screen Screen object.
2463 */
2464function convert_to_screen( $hook_name ) {
2465 if ( ! class_exists( 'WP_Screen' ) ) {
2466 _doing_it_wrong(
2467 'convert_to_screen(), add_meta_box()',
2468 sprintf(
2469 /* translators: 1: wp-admin/includes/template.php, 2: add_meta_box(), 3: add_meta_boxes */
2470 __( 'Likely direct inclusion of %1$s in order to use %2$s. This is very wrong. Hook the %2$s call into the %3$s action instead.' ),
2471 '<code>wp-admin/includes/template.php</code>',
2472 '<code>add_meta_box()</code>',
2473 '<code>add_meta_boxes</code>'
2474 ),
2475 '3.3.0'
2476 );
2477 return (object) array(
2478 'id' => '_invalid',
2479 'base' => '_are_belong_to_us',
2480 );
2481 }
2482
2483 return WP_Screen::get( $hook_name );
2484}
2485
2486/**
2487 * Output the HTML for restoring the post data from DOM storage
2488 *
2489 * @since 3.6.0
2490 * @access private
2491 */
2492function _local_storage_notice() {
2493 ?>
2494 <div id="local-storage-notice" class="hidden notice is-dismissible">
2495 <p class="local-restore">
2496 <?php _e( 'The backup of this post in your browser is different from the version below.' ); ?>
2497 <button type="button" class="button restore-backup"><?php _e( 'Restore the backup' ); ?></button>
2498 </p>
2499 <p class="help">
2500 <?php _e( 'This will replace the current editor content with the last backup version. You can use undo and redo in the editor to get the old content back or to return to the restored version.' ); ?>
2501 </p>
2502 </div>
2503 <?php
2504}
2505
2506/**
2507 * Output a HTML element with a star rating for a given rating.
2508 *
2509 * Outputs a HTML element with the star rating exposed on a 0..5 scale in
2510 * half star increments (ie. 1, 1.5, 2 stars). Optionally, if specified, the
2511 * number of ratings may also be displayed by passing the $number parameter.
2512 *
2513 * @since 3.8.0
2514 * @since 4.4.0 Introduced the `echo` parameter.
2515 *
2516 * @param array $args {
2517 * Optional. Array of star ratings arguments.
2518 *
2519 * @type int|float $rating The rating to display, expressed in either a 0.5 rating increment,
2520 * or percentage. Default 0.
2521 * @type string $type Format that the $rating is in. Valid values are 'rating' (default),
2522 * or, 'percent'. Default 'rating'.
2523 * @type int $number The number of ratings that makes up this rating. Default 0.
2524 * @type bool $echo Whether to echo the generated markup. False to return the markup instead
2525 * of echoing it. Default true.
2526 * }
2527 * @return string Star rating HTML.
2528 */
2529function wp_star_rating( $args = array() ) {
2530 $defaults = array(
2531 'rating' => 0,
2532 'type' => 'rating',
2533 'number' => 0,
2534 'echo' => true,
2535 );
2536 $parsed_args = wp_parse_args( $args, $defaults );
2537
2538 // Non-English decimal places when the $rating is coming from a string.
2539 $rating = (float) str_replace( ',', '.', $parsed_args['rating'] );
2540
2541 // Convert percentage to star rating, 0..5 in .5 increments.
2542 if ( 'percent' === $parsed_args['type'] ) {
2543 $rating = round( $rating / 10, 0 ) / 2;
2544 }
2545
2546 // Calculate the number of each type of star needed.
2547 $full_stars = floor( $rating );
2548 $half_stars = ceil( $rating - $full_stars );
2549 $empty_stars = 5 - $full_stars - $half_stars;
2550
2551 if ( $parsed_args['number'] ) {
2552 /* translators: 1: The rating, 2: The number of ratings. */
2553 $format = _n( '%1$s rating based on %2$s rating', '%1$s rating based on %2$s ratings', $parsed_args['number'] );
2554 $title = sprintf( $format, number_format_i18n( $rating, 1 ), number_format_i18n( $parsed_args['number'] ) );
2555 } else {
2556 /* translators: %s: The rating. */
2557 $title = sprintf( __( '%s rating' ), number_format_i18n( $rating, 1 ) );
2558 }
2559
2560 $output = '<div class="star-rating">';
2561 $output .= '<span class="screen-reader-text">' . $title . '</span>';
2562 $output .= str_repeat( '<div class="star star-full" aria-hidden="true"></div>', $full_stars );
2563 $output .= str_repeat( '<div class="star star-half" aria-hidden="true"></div>', $half_stars );
2564 $output .= str_repeat( '<div class="star star-empty" aria-hidden="true"></div>', $empty_stars );
2565 $output .= '</div>';
2566
2567 if ( $parsed_args['echo'] ) {
2568 echo $output;
2569 }
2570
2571 return $output;
2572}
2573
2574/**
2575 * Output a notice when editing the page for posts (internal use only).
2576 *
2577 * @ignore
2578 * @since 4.2.0
2579 */
2580function _wp_posts_page_notice() {
2581 echo '<div class="notice notice-warning inline"><p>' . __( 'You are currently editing the page that shows your latest posts.' ) . '</p></div>';
2582}