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


Generated: Tue Nov 19 01:00:03 2019 Cross-referenced by PHPXref 0.7.1