3 * Template WordPress Administration API.
5 * A Big Mess. Also some neat functions that are nicely written.
8 * @subpackage Administration
11 /** Walker_Category_Checklist class */
12 require_once( ABSPATH . 'wp-admin/includes/class-walker-category-checklist.php' );
14 /** WP_Internal_Pointers class */
15 require_once( ABSPATH . 'wp-admin/includes/class-wp-internal-pointers.php' );
18 // Category Checklists
22 * Output an unordered list of checkbox input elements labeled with category names.
26 * @see wp_terms_checklist()
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.
32 * @param array $selected_cats Optional. List of categories to mark as checked. Default false.
33 * @param array $popular_cats Optional. List of categories to receive the "popular-category" class.
35 * @param object $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.
40 function 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( $post_id, array(
42 'taxonomy' => 'category',
43 'descendants_and_self' => $descendants_and_self,
44 'selected_cats' => $selected_cats,
45 'popular_cats' => $popular_cats,
47 'checked_ontop' => $checked_ontop
52 * Output an unordered list of checkbox input elements labelled with term names.
54 * Taxonomy-independent version of wp_category_checklist().
57 * @since 4.4.0 Introduced the `$echo` argument.
59 * @param int $post_id Optional. Post ID. Default 0.
60 * @param array|string $args {
61 * Optional. Array or string of arguments for generating a terms checklist. Default empty array.
63 * @type int $descendants_and_self ID of the category to output along with its descendants.
65 * @type array $selected_cats List of categories to mark as checked. Default false.
66 * @type array $popular_cats List of categories to receive the "popular-category" class.
68 * @type object $walker Walker object to use to build the output.
69 * Default is a Walker_Category_Checklist instance.
70 * @type string $taxonomy Taxonomy to generate the checklist for. Default 'category'.
71 * @type bool $checked_ontop Whether to move checked items out of the hierarchy and to
72 * the top of the list. Default true.
73 * @type bool $echo Whether to echo the generated markup. False to return the markup instead
74 * of echoing it. Default true.
77 function wp_terms_checklist( $post_id = 0, $args = array() ) {
79 'descendants_and_self' => 0,
80 'selected_cats' => false,
81 'popular_cats' => false,
83 'taxonomy' => 'category',
84 'checked_ontop' => true,
89 * Filters the taxonomy terms checklist arguments.
93 * @see wp_terms_checklist()
95 * @param array $args An array of arguments.
96 * @param int $post_id The post ID.
98 $params = apply_filters( 'wp_terms_checklist_args', $args, $post_id );
100 $r = wp_parse_args( $params, $defaults );
102 if ( empty( $r['walker'] ) || ! ( $r['walker'] instanceof Walker ) ) {
103 $walker = new Walker_Category_Checklist;
105 $walker = $r['walker'];
108 $taxonomy = $r['taxonomy'];
109 $descendants_and_self = (int) $r['descendants_and_self'];
111 $args = array( 'taxonomy' => $taxonomy );
113 $tax = get_taxonomy( $taxonomy );
114 $args['disabled'] = ! current_user_can( $tax->cap->assign_terms );
116 $args['list_only'] = ! empty( $r['list_only'] );
118 if ( is_array( $r['selected_cats'] ) ) {
119 $args['selected_cats'] = $r['selected_cats'];
120 } elseif ( $post_id ) {
121 $args['selected_cats'] = wp_get_object_terms( $post_id, $taxonomy, array_merge( $args, array( 'fields' => 'ids' ) ) );
123 $args['selected_cats'] = array();
125 if ( is_array( $r['popular_cats'] ) ) {
126 $args['popular_cats'] = $r['popular_cats'];
128 $args['popular_cats'] = get_terms( $taxonomy, array(
130 'orderby' => 'count',
133 'hierarchical' => false
136 if ( $descendants_and_self ) {
137 $categories = (array) get_terms( $taxonomy, array(
138 'child_of' => $descendants_and_self,
142 $self = get_term( $descendants_and_self, $taxonomy );
143 array_unshift( $categories, $self );
145 $categories = (array) get_terms( $taxonomy, array( 'get' => 'all' ) );
150 if ( $r['checked_ontop'] ) {
151 // Post process $categories rather than adding an exclude to the get_terms() query to keep the query the same across all posts (for any query cache)
152 $checked_categories = array();
153 $keys = array_keys( $categories );
155 foreach ( $keys as $k ) {
156 if ( in_array( $categories[$k]->term_id, $args['selected_cats'] ) ) {
157 $checked_categories[] = $categories[$k];
158 unset( $categories[$k] );
162 // Put checked cats on top
163 $output .= call_user_func_array( array( $walker, 'walk' ), array( $checked_categories, 0, $args ) );
165 // Then the rest of them
166 $output .= call_user_func_array( array( $walker, 'walk' ), array( $categories, 0, $args ) );
176 * Retrieve a list of the most popular terms from the specified taxonomy.
178 * If the $echo argument is true then the elements for a list of checkbox
179 * `<input>` elements labelled with the names of the selected terms is output.
180 * If the $post_ID global isn't empty then the terms associated with that
181 * post will be marked as checked.
185 * @param string $taxonomy Taxonomy to retrieve terms from.
186 * @param int $default Not used.
187 * @param int $number Number of terms to retrieve. Defaults to 10.
188 * @param bool $echo Optionally output the list as well. Defaults to true.
189 * @return array List of popular term IDs.
191 function wp_popular_terms_checklist( $taxonomy, $default = 0, $number = 10, $echo = true ) {
194 if ( $post && $post->ID )
195 $checked_terms = wp_get_object_terms($post->ID, $taxonomy, array('fields'=>'ids'));
197 $checked_terms = array();
199 $terms = get_terms( $taxonomy, array( 'orderby' => 'count', 'order' => 'DESC', 'number' => $number, 'hierarchical' => false ) );
201 $tax = get_taxonomy($taxonomy);
203 $popular_ids = array();
204 foreach ( (array) $terms as $term ) {
205 $popular_ids[] = $term->term_id;
206 if ( !$echo ) // Hack for Ajax use.
208 $id = "popular-$taxonomy-$term->term_id";
209 $checked = in_array( $term->term_id, $checked_terms ) ? 'checked="checked"' : '';
212 <li id="<?php echo $id; ?>" class="popular-category">
213 <label class="selectit">
214 <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 ) ); ?> />
216 /** This filter is documented in wp-includes/category-template.php */
217 echo esc_html( apply_filters( 'the_category', $term->name ) );
228 * Outputs a link category checklist element.
232 * @param int $link_id
234 function wp_link_category_checklist( $link_id = 0 ) {
237 $checked_categories = array();
240 $checked_categories = wp_get_link_cats( $link_id );
241 // No selected categories, strange
242 if ( ! count( $checked_categories ) ) {
243 $checked_categories[] = $default;
246 $checked_categories[] = $default;
249 $categories = get_terms( 'link_category', array( 'orderby' => 'name', 'hide_empty' => 0 ) );
251 if ( empty( $categories ) )
254 foreach ( $categories as $category ) {
255 $cat_id = $category->term_id;
257 /** This filter is documented in wp-includes/category-template.php */
258 $name = esc_html( apply_filters( 'the_category', $category->name ) );
259 $checked = in_array( $cat_id, $checked_categories ) ? ' checked="checked"' : '';
260 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>";
265 * Adds hidden fields with the data for use in the inline editor for posts and pages.
269 * @param WP_Post $post Post object.
271 function get_inline_data($post) {
272 $post_type_object = get_post_type_object($post->post_type);
273 if ( ! current_user_can( 'edit_post', $post->ID ) )
276 $title = esc_textarea( trim( $post->post_title ) );
278 /** This filter is documented in wp-admin/edit-tag-form.php */
280 <div class="hidden" id="inline_' . $post->ID . '">
281 <div class="post_title">' . $title . '</div>' .
282 /** This filter is documented in wp-admin/edit-tag-form.php */
283 '<div class="post_name">' . apply_filters( 'editable_slug', $post->post_name, $post ) . '</div>
284 <div class="post_author">' . $post->post_author . '</div>
285 <div class="comment_status">' . esc_html( $post->comment_status ) . '</div>
286 <div class="ping_status">' . esc_html( $post->ping_status ) . '</div>
287 <div class="_status">' . esc_html( $post->post_status ) . '</div>
288 <div class="jj">' . mysql2date( 'd', $post->post_date, false ) . '</div>
289 <div class="mm">' . mysql2date( 'm', $post->post_date, false ) . '</div>
290 <div class="aa">' . mysql2date( 'Y', $post->post_date, false ) . '</div>
291 <div class="hh">' . mysql2date( 'H', $post->post_date, false ) . '</div>
292 <div class="mn">' . mysql2date( 'i', $post->post_date, false ) . '</div>
293 <div class="ss">' . mysql2date( 's', $post->post_date, false ) . '</div>
294 <div class="post_password">' . esc_html( $post->post_password ) . '</div>';
296 if ( $post_type_object->hierarchical ) {
297 echo '<div class="post_parent">' . $post->post_parent . '</div>';
300 echo '<div class="page_template">' . ( $post->page_template ? esc_html( $post->page_template ) : 'default' ) . '</div>';
302 if ( post_type_supports( $post->post_type, 'page-attributes' ) ) {
303 echo '<div class="menu_order">' . $post->menu_order . '</div>';
306 $taxonomy_names = get_object_taxonomies( $post->post_type );
307 foreach ( $taxonomy_names as $taxonomy_name) {
308 $taxonomy = get_taxonomy( $taxonomy_name );
310 if ( $taxonomy->hierarchical && $taxonomy->show_ui ) {
312 $terms = get_object_term_cache( $post->ID, $taxonomy_name );
313 if ( false === $terms ) {
314 $terms = wp_get_object_terms( $post->ID, $taxonomy_name );
315 wp_cache_add( $post->ID, wp_list_pluck( $terms, 'term_id' ), $taxonomy_name . '_relationships' );
317 $term_ids = empty( $terms ) ? array() : wp_list_pluck( $terms, 'term_id' );
319 echo '<div class="post_category" id="' . $taxonomy_name . '_' . $post->ID . '">' . implode( ',', $term_ids ) . '</div>';
321 } elseif ( $taxonomy->show_ui ) {
323 $terms_to_edit = get_terms_to_edit( $post->ID, $taxonomy_name );
324 if ( ! is_string( $terms_to_edit ) ) {
328 echo '<div class="tags_input" id="'.$taxonomy_name.'_'.$post->ID.'">'
329 . esc_html( str_replace( ',', ', ', $terms_to_edit ) ) . '</div>';
334 if ( !$post_type_object->hierarchical )
335 echo '<div class="sticky">' . (is_sticky($post->ID) ? 'sticky' : '') . '</div>';
337 if ( post_type_supports( $post->post_type, 'post-formats' ) )
338 echo '<div class="post_format">' . esc_html( get_post_format( $post->ID ) ) . '</div>';
344 * Outputs the in-line comment reply-to form in the Comments list table.
348 * @global WP_List_Table $wp_list_table
350 * @param int $position
351 * @param bool $checkbox
352 * @param string $mode
353 * @param bool $table_row
355 function wp_comment_reply( $position = 1, $checkbox = false, $mode = 'single', $table_row = true ) {
356 global $wp_list_table;
358 * Filters the in-line comment reply-to form output in the Comments
361 * Returning a non-empty value here will short-circuit display
362 * of the in-line comment-reply form in the Comments list table,
363 * echoing the returned value instead.
367 * @see wp_comment_reply()
369 * @param string $content The reply-to form content.
370 * @param array $args An array of default args.
372 $content = apply_filters( 'wp_comment_reply', '', array( 'position' => $position, 'checkbox' => $checkbox, 'mode' => $mode ) );
374 if ( ! empty($content) ) {
379 if ( ! $wp_list_table ) {
380 if ( $mode == 'single' ) {
381 $wp_list_table = _get_list_table('WP_Post_Comments_List_Table');
383 $wp_list_table = _get_list_table('WP_Comments_List_Table');
389 <?php if ( $table_row ) : ?>
390 <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">
392 <div id="com-reply" style="display:none;"><div id="replyrow" style="display:none;">
394 <fieldset class="comment-reply">
396 <span class="hidden" id="editlegend"><?php _e( 'Edit Comment' ); ?></span>
397 <span class="hidden" id="replyhead"><?php _e( 'Reply to Comment' ); ?></span>
398 <span class="hidden" id="addhead"><?php _e( 'Add new Comment' ); ?></span>
401 <div id="replycontainer">
402 <label for="replycontent" class="screen-reader-text"><?php _e( 'Comment' ); ?></label>
404 $quicktags_settings = array( 'buttons' => 'strong,em,link,block,del,ins,img,ul,ol,li,code,close' );
405 wp_editor( '', 'replycontent', array( 'media_buttons' => false, 'tinymce' => false, 'quicktags' => $quicktags_settings ) );
409 <div id="edithead" style="display:none;">
411 <label for="author-name"><?php _e( 'Name' ) ?></label>
412 <input type="text" name="newcomment_author" size="50" value="" id="author-name" />
416 <label for="author-email"><?php _e('Email') ?></label>
417 <input type="text" name="newcomment_author_email" size="50" value="" id="author-email" />
421 <label for="author-url"><?php _e('URL') ?></label>
422 <input type="text" id="author-url" name="newcomment_author_url" class="code" size="103" value="" />
426 <p id="replysubmit" class="submit">
427 <a href="#comments-form" class="save button button-primary alignright">
428 <span id="addbtn" style="display:none;"><?php _e('Add Comment'); ?></span>
429 <span id="savebtn" style="display:none;"><?php _e('Update Comment'); ?></span>
430 <span id="replybtn" style="display:none;"><?php _e('Submit Reply'); ?></span></a>
431 <a href="#comments-form" class="cancel button alignleft"><?php _e('Cancel'); ?></a>
432 <span class="waiting spinner"></span>
433 <span class="error" style="display:none;"></span>
436 <input type="hidden" name="action" id="action" value="" />
437 <input type="hidden" name="comment_ID" id="comment_ID" value="" />
438 <input type="hidden" name="comment_post_ID" id="comment_post_ID" value="" />
439 <input type="hidden" name="status" id="status" value="" />
440 <input type="hidden" name="position" id="position" value="<?php echo $position; ?>" />
441 <input type="hidden" name="checkbox" id="checkbox" value="<?php echo $checkbox ? 1 : 0; ?>" />
442 <input type="hidden" name="mode" id="mode" value="<?php echo esc_attr($mode); ?>" />
444 wp_nonce_field( 'replyto-comment', '_ajax_nonce-replyto-comment', false );
445 if ( current_user_can( 'unfiltered_html' ) )
446 wp_nonce_field( 'unfiltered-html-comment', '_wp_unfiltered_html_comment', false );
449 <?php if ( $table_row ) : ?>
450 </td></tr></tbody></table>
459 * Output 'undo move to trash' text for comments
463 function wp_comment_trashnotice() {
465 <div class="hidden" id="trash-undo-holder">
466 <div class="trash-undo-inside"><?php printf(__('Comment by %s moved to the trash.'), '<strong></strong>'); ?> <span class="undo untrash"><a href="#"><?php _e('Undo'); ?></a></span></div>
468 <div class="hidden" id="spam-undo-holder">
469 <div class="spam-undo-inside"><?php printf(__('Comment by %s marked as spam.'), '<strong></strong>'); ?> <span class="undo unspam"><a href="#"><?php _e('Undo'); ?></a></span></div>
475 * Outputs a post's public meta data in the Custom Fields meta box.
481 function list_meta( $meta ) {
485 <table id="list-table" style="display: none;">
488 <th class="left">' . _x( 'Name', 'meta name' ) . '</th>
489 <th>' . __( 'Value' ) . '</th>
492 <tbody id="the-list" data-wp-lists="list:meta">
495 </table>'; //TBODY needed for list-manipulation JS
500 <table id="list-table">
503 <th class="left"><?php _ex( 'Name', 'meta name' ) ?></th>
504 <th><?php _e( 'Value' ) ?></th>
507 <tbody id='the-list' data-wp-lists='list:meta'>
509 foreach ( $meta as $entry )
510 echo _list_meta_row( $entry, $count );
518 * Outputs a single row of public meta data in the Custom Fields meta box.
522 * @staticvar string $update_nonce
524 * @param array $entry
528 function _list_meta_row( $entry, &$count ) {
529 static $update_nonce = '';
531 if ( is_protected_meta( $entry['meta_key'], 'post' ) )
534 if ( ! $update_nonce )
535 $update_nonce = wp_create_nonce( 'add-meta' );
540 if ( is_serialized( $entry['meta_value'] ) ) {
541 if ( is_serialized_string( $entry['meta_value'] ) ) {
542 // This is a serialized string, so we should display it.
543 $entry['meta_value'] = maybe_unserialize( $entry['meta_value'] );
545 // This is a serialized array/object so we should NOT display it.
551 $entry['meta_key'] = esc_attr($entry['meta_key']);
552 $entry['meta_value'] = esc_textarea( $entry['meta_value'] ); // using a <textarea />
553 $entry['meta_id'] = (int) $entry['meta_id'];
555 $delete_nonce = wp_create_nonce( 'delete-meta_' . $entry['meta_id'] );
557 $r .= "\n\t<tr id='meta-{$entry['meta_id']}'>";
558 $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']}' />";
560 $r .= "\n\t\t<div class='submit'>";
561 $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" ) );
563 $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" ) );
565 $r .= wp_nonce_field( 'change-meta', '_ajax_nonce', false, false );
568 $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>";
573 * Prints the form in the Custom Fields meta box.
577 * @global wpdb $wpdb WordPress database abstraction object.
579 * @param WP_Post $post Optional. The post being edited.
581 function meta_form( $post = null ) {
583 $post = get_post( $post );
586 * Filters values for the meta key dropdown in the Custom Fields meta box.
588 * Returning a non-null value will effectively short-circuit and avoid a
589 * potentially expensive query against postmeta.
593 * @param array|null $keys Pre-defined meta keys to be used in place of a postmeta query. Default null.
594 * @param WP_Post $post The current post object.
596 $keys = apply_filters( 'postmeta_form_keys', null, $post );
598 if ( null === $keys ) {
600 * Filters the number of custom fields to retrieve for the drop-down
601 * in the Custom Fields meta box.
605 * @param int $limit Number of custom fields to retrieve. Default 30.
607 $limit = apply_filters( 'postmeta_form_limit', 30 );
608 $sql = "SELECT DISTINCT meta_key
610 WHERE meta_key NOT BETWEEN '_' AND '_z'
611 HAVING meta_key NOT LIKE %s
614 $keys = $wpdb->get_col( $wpdb->prepare( $sql, $wpdb->esc_like( '_' ) . '%', $limit ) );
618 natcasesort( $keys );
619 $meta_key_input_id = 'metakeyselect';
621 $meta_key_input_id = 'metakeyinput';
624 <p><strong><?php _e( 'Add New Custom Field:' ) ?></strong></p>
628 <th class="left"><label for="<?php echo $meta_key_input_id; ?>"><?php _ex( 'Name', 'meta name' ) ?></label></th>
629 <th><label for="metavalue"><?php _e( 'Value' ) ?></label></th>
635 <td id="newmetaleft" class="left">
636 <?php if ( $keys ) { ?>
637 <select id="metakeyselect" name="metakeyselect">
638 <option value="#NONE#"><?php _e( '— Select —' ); ?></option>
641 foreach ( $keys as $key ) {
642 if ( is_protected_meta( $key, 'post' ) || ! current_user_can( 'add_post_meta', $post->ID, $key ) )
644 echo "\n<option value='" . esc_attr($key) . "'>" . esc_html($key) . "</option>";
648 <input class="hide-if-js" type="text" id="metakeyinput" name="metakeyinput" value="" />
649 <a href="#postcustomstuff" class="hide-if-no-js" onclick="jQuery('#metakeyinput, #metakeyselect, #enternew, #cancelnew').toggle();return false;">
650 <span id="enternew"><?php _e('Enter new'); ?></span>
651 <span id="cancelnew" class="hidden"><?php _e('Cancel'); ?></span></a>
653 <input type="text" id="metakeyinput" name="metakeyinput" value="" />
656 <td><textarea id="metavalue" name="metavalue" rows="2" cols="25"></textarea></td>
661 <?php submit_button( __( 'Add Custom Field' ), '', 'addmeta', false, array( 'id' => 'newmeta-submit', 'data-wp-lists' => 'add:the-list:newmeta' ) ); ?>
663 <?php wp_nonce_field( 'add-meta', '_ajax_nonce-add-meta', false ); ?>
672 * Print out HTML form date elements for editing post or comment publish date.
675 * @since 4.4.0 Converted to use get_comment() instead of the global `$comment`.
677 * @global WP_Locale $wp_locale
679 * @param int|bool $edit Accepts 1|true for editing the date, 0|false for adding the date.
680 * @param int|bool $for_post Accepts 1|true for applying the date to a post, 0|false for a comment.
681 * @param int $tab_index The tabindex attribute to add. Default 0.
682 * @param int|bool $multi Optional. Whether the additional fields and buttons should be added.
685 function touch_time( $edit = 1, $for_post = 1, $tab_index = 0, $multi = 0 ) {
690 $edit = ! ( in_array($post->post_status, array('draft', 'pending') ) && (!$post->post_date_gmt || '0000-00-00 00:00:00' == $post->post_date_gmt ) );
692 $tab_index_attribute = '';
693 if ( (int) $tab_index > 0 )
694 $tab_index_attribute = " tabindex=\"$tab_index\"";
696 // todo: Remove this?
697 // 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 />';
699 $time_adj = current_time('timestamp');
700 $post_date = ($for_post) ? $post->post_date : get_comment()->comment_date;
701 $jj = ($edit) ? mysql2date( 'd', $post_date, false ) : gmdate( 'd', $time_adj );
702 $mm = ($edit) ? mysql2date( 'm', $post_date, false ) : gmdate( 'm', $time_adj );
703 $aa = ($edit) ? mysql2date( 'Y', $post_date, false ) : gmdate( 'Y', $time_adj );
704 $hh = ($edit) ? mysql2date( 'H', $post_date, false ) : gmdate( 'H', $time_adj );
705 $mn = ($edit) ? mysql2date( 'i', $post_date, false ) : gmdate( 'i', $time_adj );
706 $ss = ($edit) ? mysql2date( 's', $post_date, false ) : gmdate( 's', $time_adj );
708 $cur_jj = gmdate( 'd', $time_adj );
709 $cur_mm = gmdate( 'm', $time_adj );
710 $cur_aa = gmdate( 'Y', $time_adj );
711 $cur_hh = gmdate( 'H', $time_adj );
712 $cur_mn = gmdate( 'i', $time_adj );
714 $month = '<label><span class="screen-reader-text">' . __( 'Month' ) . '</span><select ' . ( $multi ? '' : 'id="mm" ' ) . 'name="mm"' . $tab_index_attribute . ">\n";
715 for ( $i = 1; $i < 13; $i = $i +1 ) {
716 $monthnum = zeroise($i, 2);
717 $monthtext = $wp_locale->get_month_abbrev( $wp_locale->get_month( $i ) );
718 $month .= "\t\t\t" . '<option value="' . $monthnum . '" data-text="' . $monthtext . '" ' . selected( $monthnum, $mm, false ) . '>';
719 /* translators: 1: month number (01, 02, etc.), 2: month abbreviation */
720 $month .= sprintf( __( '%1$s-%2$s' ), $monthnum, $monthtext ) . "</option>\n";
722 $month .= '</select></label>';
724 $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>';
725 $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>';
726 $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>';
727 $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>';
729 echo '<div class="timestamp-wrap">';
730 /* translators: 1: month, 2: day, 3: year, 4: hour, 5: minute */
731 printf( __( '%1$s %2$s, %3$s @ %4$s:%5$s' ), $month, $day, $year, $hour, $minute );
733 echo '</div><input type="hidden" id="ss" name="ss" value="' . $ss . '" />';
735 if ( $multi ) return;
739 'mm' => array( $mm, $cur_mm ),
740 'jj' => array( $jj, $cur_jj ),
741 'aa' => array( $aa, $cur_aa ),
742 'hh' => array( $hh, $cur_hh ),
743 'mn' => array( $mn, $cur_mn ),
745 foreach ( $map as $timeunit => $value ) {
746 list( $unit, $curr ) = $value;
748 echo '<input type="hidden" id="hidden_' . $timeunit . '" name="hidden_' . $timeunit . '" value="' . $unit . '" />' . "\n";
749 $cur_timeunit = 'cur_' . $timeunit;
750 echo '<input type="hidden" id="' . $cur_timeunit . '" name="' . $cur_timeunit . '" value="' . $curr . '" />' . "\n";
755 <a href="#edit_timestamp" class="save-timestamp hide-if-no-js button"><?php _e('OK'); ?></a>
756 <a href="#edit_timestamp" class="cancel-timestamp hide-if-no-js button-cancel"><?php _e('Cancel'); ?></a>
762 * Print out option HTML elements for the page templates drop-down.
765 * @since 4.7.0 Added the `$post_type` parameter.
767 * @param string $default Optional. The template file name. Default empty.
768 * @param string $post_type Optional. Post type to get templates for. Default 'post'.
770 function page_template_dropdown( $default = '', $post_type = 'page' ) {
771 $templates = get_page_templates( null, $post_type );
773 foreach ( array_keys( $templates ) as $template ) {
774 $selected = selected( $default, $templates[ $template ], false );
775 echo "\n\t<option value='" . $templates[ $template ] . "' $selected>$template</option>";
780 * Print out option HTML elements for the page parents drop-down.
783 * @since 4.4.0 `$post` argument was added.
785 * @global wpdb $wpdb WordPress database abstraction object.
787 * @param int $default Optional. The default page ID to be pre-selected. Default 0.
788 * @param int $parent Optional. The parent page ID. Default 0.
789 * @param int $level Optional. Page depth level. Default 0.
790 * @param int|WP_Post $post Post ID or WP_Post object.
792 * @return null|false Boolean False if page has no children, otherwise print out html elements
794 function parent_dropdown( $default = 0, $parent = 0, $level = 0, $post = null ) {
796 $post = get_post( $post );
797 $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) );
800 foreach ( $items as $item ) {
801 // A page cannot be its own parent.
802 if ( $post && $post->ID && $item->ID == $post->ID )
805 $pad = str_repeat( ' ', $level * 3 );
806 $selected = selected( $default, $item->ID, false );
808 echo "\n\t<option class='level-$level' value='$item->ID' $selected>$pad " . esc_html($item->post_title) . "</option>";
809 parent_dropdown( $default, $item->ID, $level +1 );
817 * Print out option html elements for role selectors.
821 * @param string $selected Slug for the role that should be already selected.
823 function wp_dropdown_roles( $selected = '' ) {
827 $editable_roles = array_reverse( get_editable_roles() );
829 foreach ( $editable_roles as $role => $details ) {
830 $name = translate_user_role($details['name'] );
831 if ( $selected == $role ) // preselect specified role
832 $p = "\n\t<option selected='selected' value='" . esc_attr($role) . "'>$name</option>";
834 $r .= "\n\t<option value='" . esc_attr($role) . "'>$name</option>";
840 * Outputs the form used by the importers to accept the data to be imported
844 * @param string $action The action attribute for the form.
846 function wp_import_upload_form( $action ) {
849 * Filters the maximum allowed upload size for import files.
853 * @see wp_max_upload_size()
855 * @param int $max_upload_size Allowed upload size. Default 1 MB.
857 $bytes = apply_filters( 'import_upload_size_limit', wp_max_upload_size() );
858 $size = size_format( $bytes );
859 $upload_dir = wp_upload_dir();
860 if ( ! empty( $upload_dir['error'] ) ) :
861 ?><div class="error"><p><?php _e('Before you can upload your import file, you will need to fix the following error:'); ?></p>
862 <p><strong><?php echo $upload_dir['error']; ?></strong></p></div><?php
865 <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' ) ); ?>">
867 <label for="upload"><?php _e( 'Choose a file from your computer:' ); ?></label> (<?php printf( __('Maximum size: %s' ), $size ); ?>)
868 <input type="file" id="upload" name="import" size="25" />
869 <input type="hidden" name="action" value="save" />
870 <input type="hidden" name="max_file_size" value="<?php echo $bytes; ?>" />
872 <?php submit_button( __('Upload file and import'), 'primary' ); ?>
879 * Adds a meta box to one or more screens.
882 * @since 4.4.0 The `$screen` parameter now accepts an array of screen IDs.
884 * @global array $wp_meta_boxes
886 * @param string $id Meta box ID (used in the 'id' attribute for the meta box).
887 * @param string $title Title of the meta box.
888 * @param callable $callback Function that fills the box with the desired content.
889 * The function should echo its output.
890 * @param string|array|WP_Screen $screen Optional. The screen or screens on which to show the box
891 * (such as a post type, 'link', or 'comment'). Accepts a single
892 * screen ID, WP_Screen object, or array of screen IDs. Default
893 * is the current screen.
894 * @param string $context Optional. The context within the screen where the boxes
895 * should display. Available contexts vary from screen to
896 * screen. Post edit screen contexts include 'normal', 'side',
897 * and 'advanced'. Comments screen contexts include 'normal'
898 * and 'side'. Menus meta boxes (accordion sections) all use
899 * the 'side' context. Global default is 'advanced'.
900 * @param string $priority Optional. The priority within the context where the boxes
901 * should show ('high', 'low'). Default 'default'.
902 * @param array $callback_args Optional. Data that should be set as the $args property
903 * of the box array (which is the second parameter passed
904 * to your callback). Default null.
906 function add_meta_box( $id, $title, $callback, $screen = null, $context = 'advanced', $priority = 'default', $callback_args = null ) {
907 global $wp_meta_boxes;
909 if ( empty( $screen ) ) {
910 $screen = get_current_screen();
911 } elseif ( is_string( $screen ) ) {
912 $screen = convert_to_screen( $screen );
913 } elseif ( is_array( $screen ) ) {
914 foreach ( $screen as $single_screen ) {
915 add_meta_box( $id, $title, $callback, $single_screen, $context, $priority, $callback_args );
919 if ( ! isset( $screen->id ) ) {
925 if ( !isset($wp_meta_boxes) )
926 $wp_meta_boxes = array();
927 if ( !isset($wp_meta_boxes[$page]) )
928 $wp_meta_boxes[$page] = array();
929 if ( !isset($wp_meta_boxes[$page][$context]) )
930 $wp_meta_boxes[$page][$context] = array();
932 foreach ( array_keys($wp_meta_boxes[$page]) as $a_context ) {
933 foreach ( array('high', 'core', 'default', 'low') as $a_priority ) {
934 if ( !isset($wp_meta_boxes[$page][$a_context][$a_priority][$id]) )
937 // If a core box was previously added or removed by a plugin, don't add.
938 if ( 'core' == $priority ) {
939 // If core box previously deleted, don't add
940 if ( false === $wp_meta_boxes[$page][$a_context][$a_priority][$id] )
944 * If box was added with default priority, give it core priority to
945 * maintain sort order.
947 if ( 'default' == $a_priority ) {
948 $wp_meta_boxes[$page][$a_context]['core'][$id] = $wp_meta_boxes[$page][$a_context]['default'][$id];
949 unset($wp_meta_boxes[$page][$a_context]['default'][$id]);
953 // If no priority given and id already present, use existing priority.
954 if ( empty($priority) ) {
955 $priority = $a_priority;
957 * Else, if we're adding to the sorted priority, we don't know the title
958 * or callback. Grab them from the previously added context/priority.
960 } elseif ( 'sorted' == $priority ) {
961 $title = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['title'];
962 $callback = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['callback'];
963 $callback_args = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['args'];
965 // An id can be in only one priority and one context.
966 if ( $priority != $a_priority || $context != $a_context )
967 unset($wp_meta_boxes[$page][$a_context][$a_priority][$id]);
971 if ( empty($priority) )
974 if ( !isset($wp_meta_boxes[$page][$context][$priority]) )
975 $wp_meta_boxes[$page][$context][$priority] = array();
977 $wp_meta_boxes[$page][$context][$priority][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback, 'args' => $callback_args);
981 * Meta-Box template function
985 * @global array $wp_meta_boxes
987 * @staticvar bool $already_sorted
988 * @param string|WP_Screen $screen Screen identifier
989 * @param string $context box context
990 * @param mixed $object gets passed to the box callback function as first parameter
991 * @return int number of meta_boxes
993 function do_meta_boxes( $screen, $context, $object ) {
994 global $wp_meta_boxes;
995 static $already_sorted = false;
997 if ( empty( $screen ) )
998 $screen = get_current_screen();
999 elseif ( is_string( $screen ) )
1000 $screen = convert_to_screen( $screen );
1002 $page = $screen->id;
1004 $hidden = get_hidden_meta_boxes( $screen );
1006 printf('<div id="%s-sortables" class="meta-box-sortables">', htmlspecialchars($context));
1008 // Grab the ones the user has manually sorted. Pull them out of their previous context/priority and into the one the user chose
1009 if ( ! $already_sorted && $sorted = get_user_option( "meta-box-order_$page" ) ) {
1010 foreach ( $sorted as $box_context => $ids ) {
1011 foreach ( explode( ',', $ids ) as $id ) {
1012 if ( $id && 'dashboard_browser_nag' !== $id ) {
1013 add_meta_box( $id, null, null, $screen, $box_context, 'sorted' );
1019 $already_sorted = true;
1023 if ( isset( $wp_meta_boxes[ $page ][ $context ] ) ) {
1024 foreach ( array( 'high', 'sorted', 'core', 'default', 'low' ) as $priority ) {
1025 if ( isset( $wp_meta_boxes[ $page ][ $context ][ $priority ]) ) {
1026 foreach ( (array) $wp_meta_boxes[ $page ][ $context ][ $priority ] as $box ) {
1027 if ( false == $box || ! $box['title'] )
1030 $hidden_class = in_array($box['id'], $hidden) ? ' hide-if-js' : '';
1031 echo '<div id="' . $box['id'] . '" class="postbox ' . postbox_classes($box['id'], $page) . $hidden_class . '" ' . '>' . "\n";
1032 if ( 'dashboard_browser_nag' != $box['id'] ) {
1033 $widget_title = $box[ 'title' ];
1035 if ( is_array( $box[ 'args' ] ) && isset( $box[ 'args' ][ '__widget_basename' ] ) ) {
1036 $widget_title = $box[ 'args' ][ '__widget_basename' ];
1037 // Do not pass this parameter to the user callback function.
1038 unset( $box[ 'args' ][ '__widget_basename' ] );
1041 echo '<button type="button" class="handlediv button-link" aria-expanded="true">';
1042 echo '<span class="screen-reader-text">' . sprintf( __( 'Toggle panel: %s' ), $widget_title ) . '</span>';
1043 echo '<span class="toggle-indicator" aria-hidden="true"></span>';
1046 echo "<h2 class='hndle'><span>{$box['title']}</span></h2>\n";
1047 echo '<div class="inside">' . "\n";
1048 call_user_func($box['callback'], $object, $box);
1063 * Removes a meta box from one or more screens.
1066 * @since 4.4.0 The `$screen` parameter now accepts an array of screen IDs.
1068 * @global array $wp_meta_boxes
1070 * @param string $id Meta box ID (used in the 'id' attribute for the meta box).
1071 * @param string|array|WP_Screen $screen The screen or screens on which the meta box is shown (such as a
1072 * post type, 'link', or 'comment'). Accepts a single screen ID,
1073 * WP_Screen object, or array of screen IDs.
1074 * @param string $context The context within the screen where the box is set to display.
1075 * Contexts vary from screen to screen. Post edit screen contexts
1076 * include 'normal', 'side', and 'advanced'. Comments screen contexts
1077 * include 'normal' and 'side'. Menus meta boxes (accordion sections)
1078 * all use the 'side' context.
1080 function remove_meta_box( $id, $screen, $context ) {
1081 global $wp_meta_boxes;
1083 if ( empty( $screen ) ) {
1084 $screen = get_current_screen();
1085 } elseif ( is_string( $screen ) ) {
1086 $screen = convert_to_screen( $screen );
1087 } elseif ( is_array( $screen ) ) {
1088 foreach ( $screen as $single_screen ) {
1089 remove_meta_box( $id, $single_screen, $context );
1093 if ( ! isset( $screen->id ) ) {
1097 $page = $screen->id;
1099 if ( !isset($wp_meta_boxes) )
1100 $wp_meta_boxes = array();
1101 if ( !isset($wp_meta_boxes[$page]) )
1102 $wp_meta_boxes[$page] = array();
1103 if ( !isset($wp_meta_boxes[$page][$context]) )
1104 $wp_meta_boxes[$page][$context] = array();
1106 foreach ( array('high', 'core', 'default', 'low') as $priority )
1107 $wp_meta_boxes[$page][$context][$priority][$id] = false;
1111 * Meta Box Accordion Template Function
1113 * Largely made up of abstracted code from do_meta_boxes(), this
1114 * function serves to build meta boxes as list items for display as
1115 * a collapsible accordion.
1119 * @uses global $wp_meta_boxes Used to retrieve registered meta boxes.
1121 * @param string|object $screen The screen identifier.
1122 * @param string $context The meta box context.
1123 * @param mixed $object gets passed to the section callback function as first parameter.
1124 * @return int number of meta boxes as accordion sections.
1126 function do_accordion_sections( $screen, $context, $object ) {
1127 global $wp_meta_boxes;
1129 wp_enqueue_script( 'accordion' );
1131 if ( empty( $screen ) )
1132 $screen = get_current_screen();
1133 elseif ( is_string( $screen ) )
1134 $screen = convert_to_screen( $screen );
1136 $page = $screen->id;
1138 $hidden = get_hidden_meta_boxes( $screen );
1140 <div id="side-sortables" class="accordion-container">
1141 <ul class="outer-border">
1144 $first_open = false;
1146 if ( isset( $wp_meta_boxes[ $page ][ $context ] ) ) {
1147 foreach ( array( 'high', 'core', 'default', 'low' ) as $priority ) {
1148 if ( isset( $wp_meta_boxes[ $page ][ $context ][ $priority ] ) ) {
1149 foreach ( $wp_meta_boxes[ $page ][ $context ][ $priority ] as $box ) {
1150 if ( false == $box || ! $box['title'] )
1153 $hidden_class = in_array( $box['id'], $hidden ) ? 'hide-if-js' : '';
1156 if ( ! $first_open && empty( $hidden_class ) ) {
1158 $open_class = 'open';
1161 <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'] ); ?>">
1162 <h3 class="accordion-section-title hndle" tabindex="0">
1163 <?php echo esc_html( $box['title'] ); ?>
1164 <span class="screen-reader-text"><?php _e( 'Press return or enter to open this section' ); ?></span>
1166 <div class="accordion-section-content <?php postbox_classes( $box['id'], $page ); ?>">
1167 <div class="inside">
1168 <?php call_user_func( $box['callback'], $object, $box ); ?>
1169 </div><!-- .inside -->
1170 </div><!-- .accordion-section-content -->
1171 </li><!-- .accordion-section -->
1178 </ul><!-- .outer-border -->
1179 </div><!-- .accordion-container -->
1185 * Add a new section to a settings page.
1187 * Part of the Settings API. Use this to define new settings sections for an admin page.
1188 * Show settings sections in your admin page callback function with do_settings_sections().
1189 * Add settings fields to your section with add_settings_field()
1191 * The $callback argument should be the name of a function that echoes out any
1192 * content you want to show at the top of the settings section before the actual
1193 * fields. It can output nothing if you want.
1197 * @global $wp_settings_sections Storage array of all settings sections added to admin pages
1199 * @param string $id Slug-name to identify the section. Used in the 'id' attribute of tags.
1200 * @param string $title Formatted title of the section. Shown as the heading for the section.
1201 * @param callable $callback Function that echos out any content at the top of the section (between heading and fields).
1202 * @param string $page The slug-name of the settings page on which to show the section. Built-in pages include
1203 * 'general', 'reading', 'writing', 'discussion', 'media', etc. Create your own using
1204 * add_options_page();
1206 function add_settings_section($id, $title, $callback, $page) {
1207 global $wp_settings_sections;
1209 if ( 'misc' == $page ) {
1210 _deprecated_argument( __FUNCTION__, '3.0.0', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'misc' ) );
1214 if ( 'privacy' == $page ) {
1215 _deprecated_argument( __FUNCTION__, '3.5.0', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'privacy' ) );
1219 $wp_settings_sections[$page][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback);
1223 * Add a new field to a section of a settings page
1225 * Part of the Settings API. Use this to define a settings field that will show
1226 * as part of a settings section inside a settings page. The fields are shown using
1227 * do_settings_fields() in do_settings-sections()
1229 * The $callback argument should be the name of a function that echoes out the
1230 * html input tags for this setting field. Use get_option() to retrieve existing
1234 * @since 4.2.0 The `$class` argument was added.
1236 * @global $wp_settings_fields Storage array of settings fields and info about their pages/sections
1238 * @param string $id Slug-name to identify the field. Used in the 'id' attribute of tags.
1239 * @param string $title Formatted title of the field. Shown as the label for the field
1241 * @param callable $callback Function that fills the field with the desired form inputs. The
1242 * function should echo its output.
1243 * @param string $page The slug-name of the settings page on which to show the section
1244 * (general, reading, writing, ...).
1245 * @param string $section Optional. The slug-name of the section of the settings page
1246 * in which to show the box. Default 'default'.
1247 * @param array $args {
1248 * Optional. Extra arguments used when outputting the field.
1250 * @type string $label_for When supplied, the setting title will be wrapped
1251 * in a `<label>` element, its `for` attribute populated
1253 * @type string $class CSS Class to be added to the `<tr>` element when the
1257 function add_settings_field($id, $title, $callback, $page, $section = 'default', $args = array()) {
1258 global $wp_settings_fields;
1260 if ( 'misc' == $page ) {
1261 _deprecated_argument( __FUNCTION__, '3.0.0', __( 'The miscellaneous options group has been removed. Use another settings group.' ) );
1265 if ( 'privacy' == $page ) {
1266 _deprecated_argument( __FUNCTION__, '3.5.0', __( 'The privacy options group has been removed. Use another settings group.' ) );
1270 $wp_settings_fields[$page][$section][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback, 'args' => $args);
1274 * Prints out all settings sections added to a particular settings page
1276 * Part of the Settings API. Use this in a settings page callback function
1277 * to output all the sections and fields that were added to that $page with
1278 * add_settings_section() and add_settings_field()
1280 * @global $wp_settings_sections Storage array of all settings sections added to admin pages
1281 * @global $wp_settings_fields Storage array of settings fields and info about their pages/sections
1284 * @param string $page The slug name of the page whose settings sections you want to output
1286 function do_settings_sections( $page ) {
1287 global $wp_settings_sections, $wp_settings_fields;
1289 if ( ! isset( $wp_settings_sections[$page] ) )
1292 foreach ( (array) $wp_settings_sections[$page] as $section ) {
1293 if ( $section['title'] )
1294 echo "<h2>{$section['title']}</h2>\n";
1296 if ( $section['callback'] )
1297 call_user_func( $section['callback'], $section );
1299 if ( ! isset( $wp_settings_fields ) || !isset( $wp_settings_fields[$page] ) || !isset( $wp_settings_fields[$page][$section['id']] ) )
1301 echo '<table class="form-table">';
1302 do_settings_fields( $page, $section['id'] );
1308 * Print out the settings fields for a particular settings section
1310 * Part of the Settings API. Use this in a settings page to output
1311 * a specific section. Should normally be called by do_settings_sections()
1312 * rather than directly.
1314 * @global $wp_settings_fields Storage array of settings fields and their pages/sections
1318 * @param string $page Slug title of the admin page who's settings fields you want to show.
1319 * @param string $section Slug title of the settings section who's fields you want to show.
1321 function do_settings_fields($page, $section) {
1322 global $wp_settings_fields;
1324 if ( ! isset( $wp_settings_fields[$page][$section] ) )
1327 foreach ( (array) $wp_settings_fields[$page][$section] as $field ) {
1330 if ( ! empty( $field['args']['class'] ) ) {
1331 $class = ' class="' . esc_attr( $field['args']['class'] ) . '"';
1334 echo "<tr{$class}>";
1336 if ( ! empty( $field['args']['label_for'] ) ) {
1337 echo '<th scope="row"><label for="' . esc_attr( $field['args']['label_for'] ) . '">' . $field['title'] . '</label></th>';
1339 echo '<th scope="row">' . $field['title'] . '</th>';
1343 call_user_func($field['callback'], $field['args']);
1350 * Register a settings error to be displayed to the user
1352 * Part of the Settings API. Use this to show messages to users about settings validation
1353 * problems, missing settings or anything else.
1355 * Settings errors should be added inside the $sanitize_callback function defined in
1356 * register_setting() for a given setting to give feedback about the submission.
1358 * By default messages will show immediately after the submission that generated the error.
1359 * Additional calls to settings_errors() can be used to show errors even when the settings
1360 * page is first accessed.
1364 * @global array $wp_settings_errors Storage array of errors registered during this pageload
1366 * @param string $setting Slug title of the setting to which this error applies
1367 * @param string $code Slug-name to identify the error. Used as part of 'id' attribute in HTML output.
1368 * @param string $message The formatted message text to display to the user (will be shown inside styled
1369 * `<div>` and `<p>` tags).
1370 * @param string $type Optional. Message type, controls HTML class. Accepts 'error' or 'updated'.
1373 function add_settings_error( $setting, $code, $message, $type = 'error' ) {
1374 global $wp_settings_errors;
1376 $wp_settings_errors[] = array(
1377 'setting' => $setting,
1379 'message' => $message,
1385 * Fetch settings errors registered by add_settings_error()
1387 * Checks the $wp_settings_errors array for any errors declared during the current
1388 * pageload and returns them.
1390 * If changes were just submitted ($_GET['settings-updated']) and settings errors were saved
1391 * to the 'settings_errors' transient then those errors will be returned instead. This
1392 * is used to pass errors back across pageloads.
1394 * Use the $sanitize argument to manually re-sanitize the option before returning errors.
1395 * This is useful if you have errors or notices you want to show even when the user
1396 * hasn't submitted data (i.e. when they first load an options page, or in the {@see 'admin_notices'}
1401 * @global array $wp_settings_errors Storage array of errors registered during this pageload
1403 * @param string $setting Optional slug title of a specific setting who's errors you want.
1404 * @param boolean $sanitize Whether to re-sanitize the setting value before returning errors.
1405 * @return array Array of settings errors
1407 function get_settings_errors( $setting = '', $sanitize = false ) {
1408 global $wp_settings_errors;
1411 * If $sanitize is true, manually re-run the sanitization for this option
1412 * This allows the $sanitize_callback from register_setting() to run, adding
1413 * any settings errors you want to show by default.
1416 sanitize_option( $setting, get_option( $setting ) );
1418 // If settings were passed back from options.php then use them.
1419 if ( isset( $_GET['settings-updated'] ) && $_GET['settings-updated'] && get_transient( 'settings_errors' ) ) {
1420 $wp_settings_errors = array_merge( (array) $wp_settings_errors, get_transient( 'settings_errors' ) );
1421 delete_transient( 'settings_errors' );
1424 // Check global in case errors have been added on this pageload.
1425 if ( ! count( $wp_settings_errors ) )
1428 // Filter the results to those of a specific setting if one was set.
1430 $setting_errors = array();
1431 foreach ( (array) $wp_settings_errors as $key => $details ) {
1432 if ( $setting == $details['setting'] )
1433 $setting_errors[] = $wp_settings_errors[$key];
1435 return $setting_errors;
1438 return $wp_settings_errors;
1442 * Display settings errors registered by add_settings_error().
1444 * Part of the Settings API. Outputs a div for each error retrieved by
1445 * get_settings_errors().
1447 * This is called automatically after a settings page based on the
1448 * Settings API is submitted. Errors should be added during the validation
1449 * callback function for a setting defined in register_setting().
1451 * The $sanitize option is passed into get_settings_errors() and will
1452 * re-run the setting sanitization
1453 * on its current value.
1455 * The $hide_on_update option will cause errors to only show when the settings
1456 * page is first loaded. if the user has already saved new values it will be
1457 * hidden to avoid repeating messages already shown in the default error
1458 * reporting after submission. This is useful to show general errors like
1459 * missing settings when the user arrives at the settings page.
1463 * @param string $setting Optional slug title of a specific setting who's errors you want.
1464 * @param bool $sanitize Whether to re-sanitize the setting value before returning errors.
1465 * @param bool $hide_on_update If set to true errors will not be shown if the settings page has
1466 * already been submitted.
1468 function settings_errors( $setting = '', $sanitize = false, $hide_on_update = false ) {
1470 if ( $hide_on_update && ! empty( $_GET['settings-updated'] ) )
1473 $settings_errors = get_settings_errors( $setting, $sanitize );
1475 if ( empty( $settings_errors ) )
1479 foreach ( $settings_errors as $key => $details ) {
1480 $css_id = 'setting-error-' . $details['code'];
1481 $css_class = $details['type'] . ' settings-error notice is-dismissible';
1482 $output .= "<div id='$css_id' class='$css_class'> \n";
1483 $output .= "<p><strong>{$details['message']}</strong></p>";
1484 $output .= "</div> \n";
1490 * Outputs the modal window used for attaching media to posts or pages in the media-listing screen.
1494 * @param string $found_action
1496 function find_posts_div($found_action = '') {
1498 <div id="find-posts" class="find-box" style="display: none;">
1499 <div id="find-posts-head" class="find-box-head">
1500 <?php _e( 'Attach to existing content' ); ?>
1501 <button type="button" id="find-posts-close"><span class="screen-reader-text"><?php _e( 'Close media attachment panel' ); ?></button>
1503 <div class="find-box-inside">
1504 <div class="find-box-search">
1505 <?php if ( $found_action ) { ?>
1506 <input type="hidden" name="found_action" value="<?php echo esc_attr($found_action); ?>" />
1508 <input type="hidden" name="affected" id="affected" value="" />
1509 <?php wp_nonce_field( 'find-posts', '_ajax_nonce', false ); ?>
1510 <label class="screen-reader-text" for="find-posts-input"><?php _e( 'Search' ); ?></label>
1511 <input type="text" id="find-posts-input" name="ps" value="" />
1512 <span class="spinner"></span>
1513 <input type="button" id="find-posts-search" value="<?php esc_attr_e( 'Search' ); ?>" class="button" />
1514 <div class="clear"></div>
1516 <div id="find-posts-response"></div>
1518 <div class="find-box-buttons">
1519 <?php submit_button( __( 'Select' ), 'primary alignright', 'find-posts-submit', false ); ?>
1520 <div class="clear"></div>
1527 * Displays the post password.
1529 * The password is passed through esc_attr() to ensure that it is safe for placing in an html attribute.
1533 function the_post_password() {
1535 if ( isset( $post->post_password ) )
1536 echo esc_attr( $post->post_password );
1540 * Get the post title.
1542 * The post title is fetched and if it is blank then a default string is
1547 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
1548 * @return string The post title if set.
1550 function _draft_or_post_title( $post = 0 ) {
1551 $title = get_the_title( $post );
1552 if ( empty( $title ) )
1553 $title = __( '(no title)' );
1554 return esc_html( $title );
1558 * Displays the search query.
1560 * A simple wrapper to display the "s" parameter in a `GET` URI. This function
1561 * should only be used when the_search_query() cannot.
1565 function _admin_search_query() {
1566 echo isset($_REQUEST['s']) ? esc_attr( wp_unslash( $_REQUEST['s'] ) ) : '';
1570 * Generic Iframe header for use with Thickbox
1574 * @global string $hook_suffix
1575 * @global string $admin_body_class
1576 * @global WP_Locale $wp_locale
1578 * @param string $title Optional. Title of the Iframe page. Default empty.
1579 * @param bool $deprecated Not used.
1581 function iframe_header( $title = '', $deprecated = false ) {
1582 show_admin_bar( false );
1583 global $hook_suffix, $admin_body_class, $wp_locale;
1584 $admin_body_class = preg_replace('/[^a-z0-9_-]+/i', '-', $hook_suffix);
1586 $current_screen = get_current_screen();
1588 @header( 'Content-Type: ' . get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ) );
1589 _wp_admin_html_begin();
1591 <title><?php bloginfo('name') ?> › <?php echo $title ?> — <?php _e('WordPress'); ?></title>
1593 wp_enqueue_style( 'colors' );
1595 <script type="text/javascript">
1596 addLoadEvent = 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();}}};
1597 function tb_close(){var win=window.dialogArguments||opener||parent||top;win.tb_remove();}
1598 var ajaxurl = '<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>',
1599 pagenow = '<?php echo $current_screen->id; ?>',
1600 typenow = '<?php echo $current_screen->post_type; ?>',
1601 adminpage = '<?php echo $admin_body_class; ?>',
1602 thousandsSeparator = '<?php echo addslashes( $wp_locale->number_format['thousands_sep'] ); ?>',
1603 decimalPoint = '<?php echo addslashes( $wp_locale->number_format['decimal_point'] ); ?>',
1604 isRtl = <?php echo (int) is_rtl(); ?>;
1607 /** This action is documented in wp-admin/admin-header.php */
1608 do_action( 'admin_enqueue_scripts', $hook_suffix );
1610 /** This action is documented in wp-admin/admin-header.php */
1611 do_action( "admin_print_styles-$hook_suffix" );
1613 /** This action is documented in wp-admin/admin-header.php */
1614 do_action( 'admin_print_styles' );
1616 /** This action is documented in wp-admin/admin-header.php */
1617 do_action( "admin_print_scripts-$hook_suffix" );
1619 /** This action is documented in wp-admin/admin-header.php */
1620 do_action( 'admin_print_scripts' );
1622 /** This action is documented in wp-admin/admin-header.php */
1623 do_action( "admin_head-$hook_suffix" );
1625 /** This action is documented in wp-admin/admin-header.php */
1626 do_action( 'admin_head' );
1628 $admin_body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_user_locale() ) ) );
1631 $admin_body_class .= ' rtl';
1636 /** This filter is documented in wp-admin/admin-header.php */
1637 $admin_body_classes = apply_filters( 'admin_body_class', '' );
1641 * @global string $body_id
1643 if ( isset($GLOBALS['body_id']) ) echo ' id="' . $GLOBALS['body_id'] . '"'; ?> class="wp-admin wp-core-ui no-js iframe <?php echo $admin_body_classes . ' ' . $admin_body_class; ?>">
1644 <script type="text/javascript">
1646 var c = document.body.className;
1647 c = c.replace(/no-js/, 'js');
1648 document.body.className = c;
1655 * Generic Iframe footer for use with Thickbox
1659 function iframe_footer() {
1661 * We're going to hide any footer output on iFrame pages,
1662 * but run the hooks anyway since they output JavaScript
1663 * or other needed content.
1667 * @global string $hook_suffix
1669 global $hook_suffix;
1671 <div class="hidden">
1673 /** This action is documented in wp-admin/admin-footer.php */
1674 do_action( 'admin_footer', $hook_suffix );
1676 /** This action is documented in wp-admin/admin-footer.php */
1677 do_action( "admin_print_footer_scripts-$hook_suffix" );
1679 /** This action is documented in wp-admin/admin-footer.php */
1680 do_action( 'admin_print_footer_scripts' );
1683 <script type="text/javascript">if(typeof wpOnload=="function")wpOnload();</script>
1691 * @param WP_Post $post
1693 function _post_states($post) {
1694 $post_states = array();
1695 if ( isset( $_REQUEST['post_status'] ) )
1696 $post_status = $_REQUEST['post_status'];
1700 if ( !empty($post->post_password) )
1701 $post_states['protected'] = __('Password protected');
1702 if ( 'private' == $post->post_status && 'private' != $post_status )
1703 $post_states['private'] = __('Private');
1704 if ( 'draft' == $post->post_status && 'draft' != $post_status )
1705 $post_states['draft'] = __('Draft');
1706 if ( 'pending' == $post->post_status && 'pending' != $post_status )
1707 $post_states['pending'] = _x('Pending', 'post status');
1708 if ( is_sticky($post->ID) )
1709 $post_states['sticky'] = __('Sticky');
1711 if ( 'future' === $post->post_status ) {
1712 $post_states['scheduled'] = __( 'Scheduled' );
1715 if ( 'page' === get_option( 'show_on_front' ) ) {
1716 if ( intval( get_option( 'page_on_front' ) ) === $post->ID ) {
1717 $post_states['page_on_front'] = __( 'Front Page' );
1720 if ( intval( get_option( 'page_for_posts' ) ) === $post->ID ) {
1721 $post_states['page_for_posts'] = __( 'Posts Page' );
1726 * Filters the default post display states used in the posts list table.
1730 * @param array $post_states An array of post display states.
1731 * @param WP_Post $post The current post object.
1733 $post_states = apply_filters( 'display_post_states', $post_states, $post );
1735 if ( ! empty($post_states) ) {
1736 $state_count = count($post_states);
1739 foreach ( $post_states as $state ) {
1741 ( $i == $state_count ) ? $sep = '' : $sep = ', ';
1742 echo "<span class='post-state'>$state$sep</span>";
1750 * @param WP_Post $post
1752 function _media_states( $post ) {
1753 $media_states = array();
1754 $stylesheet = get_option('stylesheet');
1756 if ( current_theme_supports( 'custom-header') ) {
1757 $meta_header = get_post_meta($post->ID, '_wp_attachment_is_custom_header', true );
1759 if ( is_random_header_image() ) {
1760 $header_images = wp_list_pluck( get_uploaded_header_images(), 'attachment_id' );
1762 if ( $meta_header == $stylesheet && in_array( $post->ID, $header_images ) ) {
1763 $media_states[] = __( 'Header Image' );
1766 $header_image = get_header_image();
1768 // Display "Header Image" if the image was ever used as a header image
1769 if ( ! empty( $meta_header ) && $meta_header == $stylesheet && $header_image !== wp_get_attachment_url( $post->ID ) ) {
1770 $media_states[] = __( 'Header Image' );
1773 // Display "Current Header Image" if the image is currently the header image
1774 if ( $header_image && $header_image == wp_get_attachment_url( $post->ID ) ) {
1775 $media_states[] = __( 'Current Header Image' );
1780 if ( current_theme_supports( 'custom-background') ) {
1781 $meta_background = get_post_meta($post->ID, '_wp_attachment_is_custom_background', true );
1783 if ( ! empty( $meta_background ) && $meta_background == $stylesheet ) {
1784 $media_states[] = __( 'Background Image' );
1786 $background_image = get_background_image();
1787 if ( $background_image && $background_image == wp_get_attachment_url( $post->ID ) ) {
1788 $media_states[] = __( 'Current Background Image' );
1793 if ( $post->ID == get_option( 'site_icon' ) ) {
1794 $media_states[] = __( 'Site Icon' );
1797 if ( $post->ID == get_theme_mod( 'site_logo' ) ) {
1798 $media_states[] = __( 'Logo' );
1802 * Filters the default media display states for items in the Media list table.
1806 * @param array $media_states An array of media states. Default 'Header Image',
1807 * 'Background Image', 'Site Icon', 'Logo'.
1809 $media_states = apply_filters( 'display_media_states', $media_states );
1811 if ( ! empty( $media_states ) ) {
1812 $state_count = count( $media_states );
1815 foreach ( $media_states as $state ) {
1817 ( $i == $state_count ) ? $sep = '' : $sep = ', ';
1818 echo "<span class='post-state'>$state$sep</span>";
1824 * Test support for compressing JavaScript from PHP
1826 * Outputs JavaScript that tests if compression from PHP works as expected
1827 * and sets an option with the result. Has no effect when the current user
1828 * is not an administrator. To run the test again the option 'can_compress_scripts'
1829 * has to be deleted.
1833 function compression_test() {
1835 <script type="text/javascript">
1836 var compressionNonce = <?php echo wp_json_encode( wp_create_nonce( 'update_can_compress_scripts' ) ); ?>;
1837 var testCompression = {
1838 get : function(test) {
1840 if ( window.XMLHttpRequest ) {
1841 x = new XMLHttpRequest();
1843 try{x=new ActiveXObject('Msxml2.XMLHTTP');}catch(e){try{x=new ActiveXObject('Microsoft.XMLHTTP');}catch(e){};}
1847 x.onreadystatechange = function() {
1849 if ( x.readyState == 4 ) {
1850 r = x.responseText.substr(0, 18);
1851 h = x.getResponseHeader('Content-Encoding');
1852 testCompression.check(r, h, test);
1856 x.open('GET', ajaxurl + '?action=wp-compression-test&test='+test+'&_ajax_nonce='+compressionNonce+'&'+(new Date()).getTime(), true);
1861 check : function(r, h, test) {
1862 if ( ! r && ! test )
1866 if ( h && ( h.match(/deflate/i) || h.match(/gzip/i) ) )
1875 if ( '"wpCompressionTest' == r )
1882 testCompression.check();
1888 * Echoes a submit button, with provided text and appropriate class(es).
1892 * @see get_submit_button()
1894 * @param string $text The text of the button (defaults to 'Save Changes')
1895 * @param string $type Optional. The type and CSS class(es) of the button. Core values
1896 * include 'primary', 'secondary', 'delete'. Default 'primary'
1897 * @param string $name The HTML name of the submit button. Defaults to "submit". If no
1898 * id attribute is given in $other_attributes below, $name will be
1899 * used as the button's id.
1900 * @param bool $wrap True if the output button should be wrapped in a paragraph tag,
1901 * false otherwise. Defaults to true
1902 * @param array|string $other_attributes Other attributes that should be output with the button, mapping
1903 * attributes to their values, such as setting tabindex to 1, etc.
1904 * These key/value attribute pairs will be output as attribute="value",
1905 * where attribute is the key. Other attributes can also be provided
1906 * as a string such as 'tabindex="1"', though the array format is
1907 * preferred. Default null.
1909 function submit_button( $text = null, $type = 'primary', $name = 'submit', $wrap = true, $other_attributes = null ) {
1910 echo get_submit_button( $text, $type, $name, $wrap, $other_attributes );
1914 * Returns a submit button, with provided text and appropriate class
1918 * @param string $text Optional. The text of the button. Default 'Save Changes'.
1919 * @param string $type Optional. The type of button. Accepts 'primary', 'secondary',
1920 * or 'delete'. Default 'primary large'.
1921 * @param string $name Optional. The HTML name of the submit button. Defaults to "submit".
1922 * If no id attribute is given in $other_attributes below, `$name` will
1923 * be used as the button's id. Default 'submit'.
1924 * @param bool $wrap Optional. True if the output button should be wrapped in a paragraph
1925 * tag, false otherwise. Default true.
1926 * @param array|string $other_attributes Optional. Other attributes that should be output with the button,
1927 * mapping attributes to their values, such as `array( 'tabindex' => '1' )`.
1928 * These attributes will be output as `attribute="value"`, such as
1929 * `tabindex="1"`. Other attributes can also be provided as a string such
1930 * as `tabindex="1"`, though the array format is typically cleaner.
1932 * @return string Submit button HTML.
1934 function get_submit_button( $text = '', $type = 'primary large', $name = 'submit', $wrap = true, $other_attributes = '' ) {
1935 if ( ! is_array( $type ) )
1936 $type = explode( ' ', $type );
1938 $button_shorthand = array( 'primary', 'small', 'large' );
1939 $classes = array( 'button' );
1940 foreach ( $type as $t ) {
1941 if ( 'secondary' === $t || 'button-secondary' === $t )
1943 $classes[] = in_array( $t, $button_shorthand ) ? 'button-' . $t : $t;
1945 // Remove empty items, remove duplicate items, and finally build a string.
1946 $class = implode( ' ', array_unique( array_filter( $classes ) ) );
1948 $text = $text ? $text : __( 'Save Changes' );
1950 // Default the id attribute to $name unless an id was specifically provided in $other_attributes
1952 if ( is_array( $other_attributes ) && isset( $other_attributes['id'] ) ) {
1953 $id = $other_attributes['id'];
1954 unset( $other_attributes['id'] );
1958 if ( is_array( $other_attributes ) ) {
1959 foreach ( $other_attributes as $attribute => $value ) {
1960 $attributes .= $attribute . '="' . esc_attr( $value ) . '" '; // Trailing space is important
1962 } elseif ( ! empty( $other_attributes ) ) { // Attributes provided as a string
1963 $attributes = $other_attributes;
1966 // Don't output empty name and id attributes.
1967 $name_attr = $name ? ' name="' . esc_attr( $name ) . '"' : '';
1968 $id_attr = $id ? ' id="' . esc_attr( $id ) . '"' : '';
1970 $button = '<input type="submit"' . $name_attr . $id_attr . ' class="' . esc_attr( $class );
1971 $button .= '" value="' . esc_attr( $text ) . '" ' . $attributes . ' />';
1974 $button = '<p class="submit">' . $button . '</p>';
1982 * @global bool $is_IE
1984 function _wp_admin_html_begin() {
1987 $admin_html_class = ( is_admin_bar_showing() ) ? 'wp-toolbar' : '';
1990 @header('X-UA-Compatible: IE=edge');
1995 <html xmlns="http://www.w3.org/1999/xhtml" class="ie8 <?php echo $admin_html_class; ?>" <?php
1997 * Fires inside the HTML tag in the admin header.
2001 do_action( 'admin_xml_ns' );
2002 ?> <?php language_attributes(); ?>>
2004 <!--[if !(IE 8) ]><!-->
2005 <html xmlns="http://www.w3.org/1999/xhtml" class="<?php echo $admin_html_class; ?>" <?php
2006 /** This action is documented in wp-admin/includes/template.php */
2007 do_action( 'admin_xml_ns' );
2008 ?> <?php language_attributes(); ?>>
2011 <meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php echo get_option('blog_charset'); ?>" />
2016 * Convert a screen string to a screen object
2020 * @param string $hook_name The hook name (also known as the hook suffix) used to determine the screen.
2021 * @return WP_Screen Screen object.
2023 function convert_to_screen( $hook_name ) {
2024 if ( ! class_exists( 'WP_Screen' ) ) {
2025 _doing_it_wrong( 'convert_to_screen(), add_meta_box()', __( "Likely direct inclusion of wp-admin/includes/template.php in order to use add_meta_box(). This is very wrong. Hook the add_meta_box() call into the add_meta_boxes action instead." ), '3.3.0' );
2026 return (object) array( 'id' => '_invalid', 'base' => '_are_belong_to_us' );
2029 return WP_Screen::get( $hook_name );
2033 * Output the HTML for restoring the post data from DOM storage
2038 function _local_storage_notice() {
2040 <div id="local-storage-notice" class="hidden notice is-dismissible">
2041 <p class="local-restore">
2042 <?php _e( 'The backup of this post in your browser is different from the version below.' ); ?>
2043 <button type="button" class="button restore-backup"><?php _e('Restore the backup'); ?></button>
2046 <?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.' ); ?>
2053 * Output a HTML element with a star rating for a given rating.
2055 * Outputs a HTML element with the star rating exposed on a 0..5 scale in
2056 * half star increments (ie. 1, 1.5, 2 stars). Optionally, if specified, the
2057 * number of ratings may also be displayed by passing the $number parameter.
2060 * @since 4.4.0 Introduced the `echo` parameter.
2062 * @param array $args {
2063 * Optional. Array of star ratings arguments.
2065 * @type int $rating The rating to display, expressed in either a 0.5 rating increment,
2066 * or percentage. Default 0.
2067 * @type string $type Format that the $rating is in. Valid values are 'rating' (default),
2068 * or, 'percent'. Default 'rating'.
2069 * @type int $number The number of ratings that makes up this rating. Default 0.
2070 * @type bool $echo Whether to echo the generated markup. False to return the markup instead
2071 * of echoing it. Default true.
2074 function wp_star_rating( $args = array() ) {
2081 $r = wp_parse_args( $args, $defaults );
2083 // Non-english decimal places when the $rating is coming from a string
2084 $rating = str_replace( ',', '.', $r['rating'] );
2086 // Convert Percentage to star rating, 0..5 in .5 increments
2087 if ( 'percent' == $r['type'] ) {
2088 $rating = round( $rating / 10, 0 ) / 2;
2091 // Calculate the number of each type of star needed
2092 $full_stars = floor( $rating );
2093 $half_stars = ceil( $rating - $full_stars );
2094 $empty_stars = 5 - $full_stars - $half_stars;
2096 if ( $r['number'] ) {
2097 /* translators: 1: The rating, 2: The number of ratings */
2098 $format = _n( '%1$s rating based on %2$s rating', '%1$s rating based on %2$s ratings', $r['number'] );
2099 $title = sprintf( $format, number_format_i18n( $rating, 1 ), number_format_i18n( $r['number'] ) );
2101 /* translators: 1: The rating */
2102 $title = sprintf( __( '%s rating' ), number_format_i18n( $rating, 1 ) );
2105 $output = '<div class="star-rating">';
2106 $output .= '<span class="screen-reader-text">' . $title . '</span>';
2107 $output .= str_repeat( '<div class="star star-full" aria-hidden="true"></div>', $full_stars );
2108 $output .= str_repeat( '<div class="star star-half" aria-hidden="true"></div>', $half_stars );
2109 $output .= str_repeat( '<div class="star star-empty" aria-hidden="true"></div>', $empty_stars );
2110 $output .= '</div>';
2120 * Output a notice when editing the page for posts (internal use only).
2125 function _wp_posts_page_notice() {
2126 echo '<div class="notice notice-warning inline"><p>' . __( 'You are currently editing the page that shows your latest posts.' ) . '</p></div>';