[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-admin/includes/ -> template.php (source)

   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 */
  12  require_once ABSPATH . 'wp-admin/includes/class-walker-category-checklist.php';
  13  
  14  /** WP_Internal_Pointers class */
  15  require_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   */
  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(
  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   */
  81  function 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   */
 209  function 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   */
 262  function 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   */
 306  function 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   */
 402  function 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   */
 532  function 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   */
 562  function 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   */
 610  function _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   */
 665  function 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   */
 781  function 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   */
 869  function 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   */
 892  function 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   */
 922  function 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   */
 947  function 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   */
1019  function 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 ) {
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   */
1123  function 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   */
1178  function _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   */
1233  function 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   */
1377  function 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   */
1427  function 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   */
1509  function 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   */
1580  function 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   */
1630  function 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   */
1669  function 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   */
1723  function 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   */
1757  function 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   */
1823  function 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   */
1868  function 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   */
1905  function 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   */
1923  function _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   */
1939  function _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   */
1955  function 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">
1970  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();}}};
1971  function tb_close(){var win=window.dialogArguments||opener||parent||top;win.tb_remove();}
1972  var 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(){
2023  var c = document.body.className;
2024  c = c.replace(/no-js/, 'js');
2025  document.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   */
2036  function 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   */
2078  function _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   */
2109  function 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   */
2181  function _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   */
2264  function 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   */
2340  function 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   */
2365  function 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   */
2416  function _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   */
2464  function 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   */
2492  function _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   */
2529  function 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   */
2580  function _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  }


Generated: Sun Apr 5 01:00:03 2020 Cross-referenced by PHPXref 0.7.1