WordPress PHP Cross Reference Web Logs

Source: /wp-admin/includes/template.php - 1867 lines - 68382 bytes - Summary - Text - Print

Description: Template WordPress Administration API. A Big Mess. Also some neat functions that are nicely written.

   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  //
  12  // Category Checklists
  13  //
  14  
  15  /**
  16   * Walker to output an unordered list of category checkbox <input> elements.
  17   *
  18   * @see Walker
  19   * @see wp_category_checklist()
  20   * @see wp_terms_checklist()
  21   * @since 2.5.1
  22   */
  23  class Walker_Category_Checklist extends Walker {
  24      var $tree_type = 'category';
  25      var $db_fields = array ('parent' => 'parent', 'id' => 'term_id'); //TODO: decouple this
  26  
  27  	function start_lvl( &$output, $depth = 0, $args = array() ) {
  28          $indent = str_repeat("\t", $depth);
  29          $output .= "$indent<ul class='children'>\n";
  30      }
  31  
  32  	function end_lvl( &$output, $depth = 0, $args = array() ) {
  33          $indent = str_repeat("\t", $depth);
  34          $output .= "$indent</ul>\n";
  35      }
  36  
  37  	function start_el( &$output, $category, $depth, $args, $id = 0 ) {
  38          extract($args);
  39          if ( empty($taxonomy) )
  40              $taxonomy = 'category';
  41  
  42          if ( $taxonomy == 'category' )
  43              $name = 'post_category';
  44          else
  45              $name = 'tax_input['.$taxonomy.']';
  46  
  47          $class = in_array( $category->term_id, $popular_cats ) ? ' class="popular-category"' : '';
  48          $output .= "\n<li id='{$taxonomy}-{$category->term_id}'$class>" . '<label class="selectit"><input value="' . $category->term_id . '" type="checkbox" name="'.$name.'[]" id="in-'.$taxonomy.'-' . $category->term_id . '"' . checked( in_array( $category->term_id, $selected_cats ), true, false ) . disabled( empty( $args['disabled'] ), false, false ) . ' /> ' . esc_html( apply_filters('the_category', $category->name )) . '</label>';
  49      }
  50  
  51  	function end_el( &$output, $category, $depth = 0, $args = array() ) {
  52          $output .= "</li>\n";
  53      }
  54  }
  55  
  56  /**
  57   * Output an unordered list of checkbox <input> elements labelled
  58   * with category names.
  59   *
  60   * @see wp_terms_checklist()
  61   * @since 2.5.1
  62   *
  63   * @param int $post_id Mark categories associated with this post as checked. $selected_cats must not be an array.
  64   * @param int $descendants_and_self ID of the category to output along with its descendents.
  65   * @param bool|array $selected_cats List of categories to mark as checked.
  66   * @param bool|array $popular_cats Override the list of categories that receive the "popular-category" class.
  67   * @param object $walker Walker object to use to build the output.
  68   * @param bool $checked_ontop Move checked items out of the hierarchy and to the top of the list.
  69   */
  70  function wp_category_checklist( $post_id = 0, $descendants_and_self = 0, $selected_cats = false, $popular_cats = false, $walker = null, $checked_ontop = true ) {
  71      wp_terms_checklist( $post_id, array(
  72          'taxonomy' => 'category',
  73          'descendants_and_self' => $descendants_and_self,
  74          'selected_cats' => $selected_cats,
  75          'popular_cats' => $popular_cats,
  76          'walker' => $walker,
  77          'checked_ontop' => $checked_ontop
  78      ) );
  79  }
  80  
  81  /**
  82   * Output an unordered list of checkbox <input> elements labelled
  83   * with term names. Taxonomy independent version of wp_category_checklist().
  84   *
  85   * @since 3.0.0
  86   *
  87   * @param int $post_id
  88   * @param array $args
  89   */
  90  function wp_terms_checklist($post_id = 0, $args = array()) {
  91       $defaults = array(
  92          'descendants_and_self' => 0,
  93          'selected_cats' => false,
  94          'popular_cats' => false,
  95          'walker' => null,
  96          'taxonomy' => 'category',
  97          'checked_ontop' => true
  98      );
  99      $args = apply_filters( 'wp_terms_checklist_args', $args, $post_id );
 100  
 101      extract( wp_parse_args($args, $defaults), EXTR_SKIP );
 102  
 103      if ( empty($walker) || !is_a($walker, 'Walker') )
 104          $walker = new Walker_Category_Checklist;
 105  
 106      $descendants_and_self = (int) $descendants_and_self;
 107  
 108      $args = array('taxonomy' => $taxonomy);
 109  
 110      $tax = get_taxonomy($taxonomy);
 111      $args['disabled'] = !current_user_can($tax->cap->assign_terms);
 112  
 113      if ( is_array( $selected_cats ) )
 114          $args['selected_cats'] = $selected_cats;
 115      elseif ( $post_id )
 116          $args['selected_cats'] = wp_get_object_terms($post_id, $taxonomy, array_merge($args, array('fields' => 'ids')));
 117      else
 118          $args['selected_cats'] = array();
 119  
 120      if ( is_array( $popular_cats ) )
 121          $args['popular_cats'] = $popular_cats;
 122      else
 123          $args['popular_cats'] = get_terms( $taxonomy, array( 'fields' => 'ids', 'orderby' => 'count', 'order' => 'DESC', 'number' => 10, 'hierarchical' => false ) );
 124  
 125      if ( $descendants_and_self ) {
 126          $categories = (array) get_terms($taxonomy, array( 'child_of' => $descendants_and_self, 'hierarchical' => 0, 'hide_empty' => 0 ) );
 127          $self = get_term( $descendants_and_self, $taxonomy );
 128          array_unshift( $categories, $self );
 129      } else {
 130          $categories = (array) get_terms($taxonomy, array('get' => 'all'));
 131      }
 132  
 133      if ( $checked_ontop ) {
 134          // 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)
 135          $checked_categories = array();
 136          $keys = array_keys( $categories );
 137  
 138          foreach( $keys as $k ) {
 139              if ( in_array( $categories[$k]->term_id, $args['selected_cats'] ) ) {
 140                  $checked_categories[] = $categories[$k];
 141                  unset( $categories[$k] );
 142              }
 143          }
 144  
 145          // Put checked cats on top
 146          echo call_user_func_array(array(&$walker, 'walk'), array($checked_categories, 0, $args));
 147      }
 148      // Then the rest of them
 149      echo call_user_func_array(array(&$walker, 'walk'), array($categories, 0, $args));
 150  }
 151  
 152  /**
 153   * Retrieve a list of the most popular terms from the specified taxonomy.
 154   *
 155   * If the $echo argument is true then the elements for a list of checkbox
 156   * <input> elements labelled with the names of the selected terms is output.
 157   * If the $post_ID global isn't empty then the terms associated with that
 158   * post will be marked as checked.
 159   *
 160   * @since 2.5.0
 161   *
 162   * @param string $taxonomy Taxonomy to retrieve terms from.
 163   * @param int $default Unused.
 164   * @param int $number Number of terms to retrieve. Defaults to 10.
 165   * @param bool $echo Optionally output the list as well. Defaults to true.
 166   * @return array List of popular term IDs.
 167   */
 168  function wp_popular_terms_checklist( $taxonomy, $default = 0, $number = 10, $echo = true ) {
 169      $post = get_post();
 170  
 171      if ( $post && $post->ID )
 172          $checked_terms = wp_get_object_terms($post->ID, $taxonomy, array('fields'=>'ids'));
 173      else
 174          $checked_terms = array();
 175  
 176      $terms = get_terms( $taxonomy, array( 'orderby' => 'count', 'order' => 'DESC', 'number' => $number, 'hierarchical' => false ) );
 177  
 178      $tax = get_taxonomy($taxonomy);
 179      if ( ! current_user_can($tax->cap->assign_terms) )
 180          $disabled = 'disabled="disabled"';
 181      else
 182          $disabled = '';
 183  
 184      $popular_ids = array();
 185      foreach ( (array) $terms as $term ) {
 186          $popular_ids[] = $term->term_id;
 187          if ( !$echo ) // hack for AJAX use
 188              continue;
 189          $id = "popular-$taxonomy-$term->term_id";
 190          $checked = in_array( $term->term_id, $checked_terms ) ? 'checked="checked"' : '';
 191          ?>
 192  
 193          <li id="<?php echo $id; ?>" class="popular-category">
 194              <label class="selectit">
 195              <input id="in-<?php echo $id; ?>" type="checkbox" <?php echo $checked; ?> value="<?php echo (int) $term->term_id; ?>" <?php echo $disabled ?>/>
 196                  <?php echo esc_html( apply_filters( 'the_category', $term->name ) ); ?>
 197              </label>
 198          </li>
 199  
 200          <?php
 201      }
 202      return $popular_ids;
 203  }
 204  
 205  /**
 206   * {@internal Missing Short Description}}
 207   *
 208   * @since 2.5.1
 209   *
 210   * @param unknown_type $link_id
 211   */
 212  function wp_link_category_checklist( $link_id = 0 ) {
 213      $default = 1;
 214  
 215      if ( $link_id ) {
 216          $checked_categories = wp_get_link_cats( $link_id );
 217          // No selected categories, strange
 218          if ( ! count( $checked_categories ) )
 219              $checked_categories[] = $default;
 220      } else {
 221          $checked_categories[] = $default;
 222      }
 223  
 224      $categories = get_terms( 'link_category', array( 'orderby' => 'name', 'hide_empty' => 0 ) );
 225  
 226      if ( empty( $categories ) )
 227          return;
 228  
 229      foreach ( $categories as $category ) {
 230          $cat_id = $category->term_id;
 231          $name = esc_html( apply_filters( 'the_category', $category->name ) );
 232          $checked = in_array( $cat_id, $checked_categories ) ? ' checked="checked"' : '';
 233          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>";
 234      }
 235  }
 236  
 237  // adds hidden fields with the data for use in the inline editor for posts and pages
 238  /**
 239   * {@internal Missing Short Description}}
 240   *
 241   * @since 2.7.0
 242   *
 243   * @param unknown_type $post
 244   */
 245  function get_inline_data($post) {
 246      $post_type_object = get_post_type_object($post->post_type);
 247      if ( ! current_user_can($post_type_object->cap->edit_post, $post->ID) )
 248          return;
 249  
 250      $title = esc_textarea( trim( $post->post_title ) );
 251  
 252      echo '
 253  <div class="hidden" id="inline_' . $post->ID . '">
 254      <div class="post_title">' . $title . '</div>
 255      <div class="post_name">' . apply_filters('editable_slug', $post->post_name) . '</div>
 256      <div class="post_author">' . $post->post_author . '</div>
 257      <div class="comment_status">' . esc_html( $post->comment_status ) . '</div>
 258      <div class="ping_status">' . esc_html( $post->ping_status ) . '</div>
 259      <div class="_status">' . esc_html( $post->post_status ) . '</div>
 260      <div class="jj">' . mysql2date( 'd', $post->post_date, false ) . '</div>
 261      <div class="mm">' . mysql2date( 'm', $post->post_date, false ) . '</div>
 262      <div class="aa">' . mysql2date( 'Y', $post->post_date, false ) . '</div>
 263      <div class="hh">' . mysql2date( 'H', $post->post_date, false ) . '</div>
 264      <div class="mn">' . mysql2date( 'i', $post->post_date, false ) . '</div>
 265      <div class="ss">' . mysql2date( 's', $post->post_date, false ) . '</div>
 266      <div class="post_password">' . esc_html( $post->post_password ) . '</div>';
 267  
 268      if ( $post_type_object->hierarchical )
 269          echo '<div class="post_parent">' . $post->post_parent . '</div>';
 270  
 271      if ( $post->post_type == 'page' )
 272          echo '<div class="page_template">' . esc_html( get_post_meta( $post->ID, '_wp_page_template', true ) ) . '</div>';
 273  
 274      if ( post_type_supports( $post->post_type, 'page-attributes' ) )
 275          echo '<div class="menu_order">' . $post->menu_order . '</div>';
 276  
 277      $taxonomy_names = get_object_taxonomies( $post->post_type );
 278      foreach ( $taxonomy_names as $taxonomy_name) {
 279          $taxonomy = get_taxonomy( $taxonomy_name );
 280  
 281          if ( $taxonomy->hierarchical && $taxonomy->show_ui ) {
 282                  echo '<div class="post_category" id="' . $taxonomy_name . '_' . $post->ID . '">'
 283                      . implode( ',', wp_get_object_terms( $post->ID, $taxonomy_name, array( 'fields' => 'ids' ) ) ) . '</div>';
 284          } elseif ( $taxonomy->show_ui ) {
 285              echo '<div class="tags_input" id="'.$taxonomy_name.'_'.$post->ID.'">'
 286                  . esc_html( str_replace( ',', ', ', get_terms_to_edit( $post->ID, $taxonomy_name ) ) ) . '</div>';
 287          }
 288      }
 289  
 290      if ( !$post_type_object->hierarchical )
 291          echo '<div class="sticky">' . (is_sticky($post->ID) ? 'sticky' : '') . '</div>';
 292  
 293      if ( post_type_supports( $post->post_type, 'post-formats' ) )
 294          echo '<div class="post_format">' . esc_html( get_post_format( $post->ID ) ) . '</div>';
 295  
 296      echo '</div>';
 297  }
 298  
 299  /**
 300   * {@internal Missing Short Description}}
 301   *
 302   * @since 2.7.0
 303   *
 304   * @param unknown_type $position
 305   * @param unknown_type $checkbox
 306   * @param unknown_type $mode
 307   */
 308  function wp_comment_reply($position = '1', $checkbox = false, $mode = 'single', $table_row = true) {
 309      // allow plugin to replace the popup content
 310      $content = apply_filters( 'wp_comment_reply', '', array('position' => $position, 'checkbox' => $checkbox, 'mode' => $mode) );
 311  
 312      if ( ! empty($content) ) {
 313          echo $content;
 314          return;
 315      }
 316  
 317      if ( $mode == 'single' ) {
 318          $wp_list_table = _get_list_table('WP_Post_Comments_List_Table');
 319      } else {
 320          $wp_list_table = _get_list_table('WP_Comments_List_Table');
 321      }
 322  
 323  ?>
 324  <form method="get" action="">
 325  <?php if ( $table_row ) : ?>
 326  <table style="display:none;"><tbody id="com-reply"><tr id="replyrow" style="display:none;"><td colspan="<?php echo $wp_list_table->get_column_count(); ?>" class="colspanchange">
 327  <?php else : ?>
 328  <div id="com-reply" style="display:none;"><div id="replyrow" style="display:none;">
 329  <?php endif; ?>
 330      <div id="replyhead" style="display:none;"><h5><?php _e( 'Reply to Comment' ); ?></h5></div>
 331      <div id="addhead" style="display:none;"><h5><?php _e('Add new Comment'); ?></h5></div>
 332      <div id="edithead" style="display:none;">
 333          <div class="inside">
 334          <label for="author"><?php _e('Name') ?></label>
 335          <input type="text" name="newcomment_author" size="50" value="" id="author" />
 336          </div>
 337  
 338          <div class="inside">
 339          <label for="author-email"><?php _e('E-mail') ?></label>
 340          <input type="text" name="newcomment_author_email" size="50" value="" id="author-email" />
 341          </div>
 342  
 343          <div class="inside">
 344          <label for="author-url"><?php _e('URL') ?></label>
 345          <input type="text" id="author-url" name="newcomment_author_url" size="103" value="" />
 346          </div>
 347          <div style="clear:both;"></div>
 348      </div>
 349  
 350      <div id="replycontainer">
 351      <?php
 352      $quicktags_settings = array( 'buttons' => 'strong,em,link,block,del,ins,img,ul,ol,li,code,spell,close' );
 353      wp_editor( '', 'replycontent', array( 'media_buttons' => false, 'tinymce' => false, 'quicktags' => $quicktags_settings ) );
 354      ?>
 355      </div>
 356  
 357      <p id="replysubmit" class="submit">
 358      <a href="#comments-form" class="save button-primary alignright">
 359      <span id="addbtn" style="display:none;"><?php _e('Add Comment'); ?></span>
 360      <span id="savebtn" style="display:none;"><?php _e('Update Comment'); ?></span>
 361      <span id="replybtn" style="display:none;"><?php _e('Submit Reply'); ?></span></a>
 362      <a href="#comments-form" class="cancel button-secondary alignleft"><?php _e('Cancel'); ?></a>
 363      <span class="waiting spinner"></span>
 364      <span class="error" style="display:none;"></span>
 365      <br class="clear" />
 366      </p>
 367  
 368      <input type="hidden" name="user_ID" id="user_ID" value="<?php echo get_current_user_id(); ?>" />
 369      <input type="hidden" name="action" id="action" value="" />
 370      <input type="hidden" name="comment_ID" id="comment_ID" value="" />
 371      <input type="hidden" name="comment_post_ID" id="comment_post_ID" value="" />
 372      <input type="hidden" name="status" id="status" value="" />
 373      <input type="hidden" name="position" id="position" value="<?php echo $position; ?>" />
 374      <input type="hidden" name="checkbox" id="checkbox" value="<?php echo $checkbox ? 1 : 0; ?>" />
 375      <input type="hidden" name="mode" id="mode" value="<?php echo esc_attr($mode); ?>" />
 376      <?php
 377          wp_nonce_field( 'replyto-comment', '_ajax_nonce-replyto-comment', false );
 378          if ( current_user_can( 'unfiltered_html' ) )
 379              wp_nonce_field( 'unfiltered-html-comment', '_wp_unfiltered_html_comment', false );
 380      ?>
 381  <?php if ( $table_row ) : ?>
 382  </td></tr></tbody></table>
 383  <?php else : ?>
 384  </div></div>
 385  <?php endif; ?>
 386  </form>
 387  <?php
 388  }
 389  
 390  /**
 391   * Output 'undo move to trash' text for comments
 392   *
 393   * @since 2.9.0
 394   */
 395  function wp_comment_trashnotice() {
 396  ?>
 397  <div class="hidden" id="trash-undo-holder">
 398      <div class="trash-undo-inside"><?php printf(__('Comment by %s moved to the trash.'), '<strong></strong>'); ?> <span class="undo untrash"><a href="#"><?php _e('Undo'); ?></a></span></div>
 399  </div>
 400  <div class="hidden" id="spam-undo-holder">
 401      <div class="spam-undo-inside"><?php printf(__('Comment by %s marked as spam.'), '<strong></strong>'); ?> <span class="undo unspam"><a href="#"><?php _e('Undo'); ?></a></span></div>
 402  </div>
 403  <?php
 404  }
 405  
 406  /**
 407   * {@internal Missing Short Description}}
 408   *
 409   * @since 1.2.0
 410   *
 411   * @param unknown_type $meta
 412   */
 413  function list_meta( $meta ) {
 414      // Exit if no meta
 415      if ( ! $meta ) {
 416          echo '
 417  <table id="list-table" style="display: none;">
 418      <thead>
 419      <tr>
 420          <th class="left">' . _x( 'Name', 'meta name' ) . '</th>
 421          <th>' . __( 'Value' ) . '</th>
 422      </tr>
 423      </thead>
 424      <tbody id="the-list" data-wp-lists="list:meta">
 425      <tr><td></td></tr>
 426      </tbody>
 427  </table>'; //TBODY needed for list-manipulation JS
 428          return;
 429      }
 430      $count = 0;
 431  ?>
 432  <table id="list-table">
 433      <thead>
 434      <tr>
 435          <th class="left"><?php _ex( 'Name', 'meta name' ) ?></th>
 436          <th><?php _e( 'Value' ) ?></th>
 437      </tr>
 438      </thead>
 439      <tbody id='the-list' data-wp-lists='list:meta'>
 440  <?php
 441      foreach ( $meta as $entry )
 442          echo _list_meta_row( $entry, $count );
 443  ?>
 444      </tbody>
 445  </table>
 446  <?php
 447  }
 448  
 449  /**
 450   * {@internal Missing Short Description}}
 451   *
 452   * @since 2.5.0
 453   *
 454   * @param unknown_type $entry
 455   * @param unknown_type $count
 456   * @return unknown
 457   */
 458  function _list_meta_row( $entry, &$count ) {
 459      static $update_nonce = false;
 460  
 461      if ( is_protected_meta( $entry['meta_key'], 'post' ) )
 462          return;
 463  
 464      if ( !$update_nonce )
 465          $update_nonce = wp_create_nonce( 'add-meta' );
 466  
 467      $r = '';
 468      ++ $count;
 469      if ( $count % 2 )
 470          $style = 'alternate';
 471      else
 472          $style = '';
 473  
 474      if ( is_serialized( $entry['meta_value'] ) ) {
 475          if ( is_serialized_string( $entry['meta_value'] ) ) {
 476              // this is a serialized string, so we should display it
 477              $entry['meta_value'] = maybe_unserialize( $entry['meta_value'] );
 478          } else {
 479              // this is a serialized array/object so we should NOT display it
 480              --$count;
 481              return;
 482          }
 483      }
 484  
 485      $entry['meta_key'] = esc_attr($entry['meta_key']);
 486      $entry['meta_value'] = esc_textarea( $entry['meta_value'] ); // using a <textarea />
 487      $entry['meta_id'] = (int) $entry['meta_id'];
 488  
 489      $delete_nonce = wp_create_nonce( 'delete-meta_' . $entry['meta_id'] );
 490  
 491      $r .= "\n\t<tr id='meta-{$entry['meta_id']}' class='$style'>";
 492      $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']}' />";
 493  
 494      $r .= "\n\t\t<div class='submit'>";
 495      $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" ) );
 496      $r .= "\n\t\t";
 497      $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" ) );
 498      $r .= "</div>";
 499      $r .= wp_nonce_field( 'change-meta', '_ajax_nonce', false, false );
 500      $r .= "</td>";
 501  
 502      $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>";
 503      return $r;
 504  }
 505  
 506  /**
 507   * {@internal Missing Short Description}}
 508   *
 509   * @since 1.2.0
 510   */
 511  function meta_form() {
 512      global $wpdb;
 513      $limit = (int) apply_filters( 'postmeta_form_limit', 30 );
 514      $keys = $wpdb->get_col( "
 515          SELECT meta_key
 516          FROM $wpdb->postmeta
 517          GROUP BY meta_key
 518          HAVING meta_key NOT LIKE '\_%'
 519          ORDER BY meta_key
 520          LIMIT $limit" );
 521      if ( $keys )
 522          natcasesort($keys);
 523  ?>
 524  <p><strong><?php _e( 'Add New Custom Field:' ) ?></strong></p>
 525  <table id="newmeta">
 526  <thead>
 527  <tr>
 528  <th class="left"><label for="metakeyselect"><?php _ex( 'Name', 'meta name' ) ?></label></th>
 529  <th><label for="metavalue"><?php _e( 'Value' ) ?></label></th>
 530  </tr>
 531  </thead>
 532  
 533  <tbody>
 534  <tr>
 535  <td id="newmetaleft" class="left">
 536  <?php if ( $keys ) { ?>
 537  <select id="metakeyselect" name="metakeyselect">
 538  <option value="#NONE#"><?php _e( '&mdash; Select &mdash;' ); ?></option>
 539  <?php
 540  
 541      foreach ( $keys as $key ) {
 542          echo "\n<option value='" . esc_attr($key) . "'>" . esc_html($key) . "</option>";
 543      }
 544  ?>
 545  </select>
 546  <input class="hide-if-js" type="text" id="metakeyinput" name="metakeyinput" value="" />
 547  <a href="#postcustomstuff" class="hide-if-no-js" onclick="jQuery('#metakeyinput, #metakeyselect, #enternew, #cancelnew').toggle();return false;">
 548  <span id="enternew"><?php _e('Enter new'); ?></span>
 549  <span id="cancelnew" class="hidden"><?php _e('Cancel'); ?></span></a>
 550  <?php } else { ?>
 551  <input type="text" id="metakeyinput" name="metakeyinput" value="" />
 552  <?php } ?>
 553  </td>
 554  <td><textarea id="metavalue" name="metavalue" rows="2" cols="25"></textarea></td>
 555  </tr>
 556  
 557  <tr><td colspan="2">
 558  <div class="submit">
 559  <?php submit_button( __( 'Add Custom Field' ), 'secondary', 'addmeta', false, array( 'id' => 'newmeta-submit', 'data-wp-lists' => 'add:the-list:newmeta' ) ); ?>
 560  </div>
 561  <?php wp_nonce_field( 'add-meta', '_ajax_nonce-add-meta', false ); ?>
 562  </td></tr>
 563  </tbody>
 564  </table>
 565  <?php
 566  
 567  }
 568  
 569  /**
 570   * {@internal Missing Short Description}}
 571   *
 572   * @since 0.71
 573   *
 574   * @param unknown_type $edit
 575   * @param unknown_type $for_post
 576   * @param unknown_type $tab_index
 577   * @param unknown_type $multi
 578   */
 579  function touch_time( $edit = 1, $for_post = 1, $tab_index = 0, $multi = 0 ) {
 580      global $wp_locale, $comment;
 581      $post = get_post();
 582  
 583      if ( $for_post )
 584          $edit = ! ( in_array($post->post_status, array('draft', 'pending') ) && (!$post->post_date_gmt || '0000-00-00 00:00:00' == $post->post_date_gmt ) );
 585  
 586      $tab_index_attribute = '';
 587      if ( (int) $tab_index > 0 )
 588          $tab_index_attribute = " tabindex=\"$tab_index\"";
 589  
 590      // 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 />';
 591  
 592      $time_adj = current_time('timestamp');
 593      $post_date = ($for_post) ? $post->post_date : $comment->comment_date;
 594      $jj = ($edit) ? mysql2date( 'd', $post_date, false ) : gmdate( 'd', $time_adj );
 595      $mm = ($edit) ? mysql2date( 'm', $post_date, false ) : gmdate( 'm', $time_adj );
 596      $aa = ($edit) ? mysql2date( 'Y', $post_date, false ) : gmdate( 'Y', $time_adj );
 597      $hh = ($edit) ? mysql2date( 'H', $post_date, false ) : gmdate( 'H', $time_adj );
 598      $mn = ($edit) ? mysql2date( 'i', $post_date, false ) : gmdate( 'i', $time_adj );
 599      $ss = ($edit) ? mysql2date( 's', $post_date, false ) : gmdate( 's', $time_adj );
 600  
 601      $cur_jj = gmdate( 'd', $time_adj );
 602      $cur_mm = gmdate( 'm', $time_adj );
 603      $cur_aa = gmdate( 'Y', $time_adj );
 604      $cur_hh = gmdate( 'H', $time_adj );
 605      $cur_mn = gmdate( 'i', $time_adj );
 606  
 607      $month = "<select " . ( $multi ? '' : 'id="mm" ' ) . "name=\"mm\"$tab_index_attribute>\n";
 608      for ( $i = 1; $i < 13; $i = $i +1 ) {
 609          $monthnum = zeroise($i, 2);
 610          $month .= "\t\t\t" . '<option value="' . $monthnum . '"';
 611          if ( $i == $mm )
 612              $month .= ' selected="selected"';
 613          /* translators: 1: month number (01, 02, etc.), 2: month abbreviation */
 614          $month .= '>' . sprintf( __( '%1$s-%2$s' ), $monthnum, $wp_locale->get_month_abbrev( $wp_locale->get_month( $i ) ) ) . "</option>\n";
 615      }
 616      $month .= '</select>';
 617  
 618      $day = '<input type="text" ' . ( $multi ? '' : 'id="jj" ' ) . 'name="jj" value="' . $jj . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" />';
 619      $year = '<input type="text" ' . ( $multi ? '' : 'id="aa" ' ) . 'name="aa" value="' . $aa . '" size="4" maxlength="4"' . $tab_index_attribute . ' autocomplete="off" />';
 620      $hour = '<input type="text" ' . ( $multi ? '' : 'id="hh" ' ) . 'name="hh" value="' . $hh . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" />';
 621      $minute = '<input type="text" ' . ( $multi ? '' : 'id="mn" ' ) . 'name="mn" value="' . $mn . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" />';
 622  
 623      echo '<div class="timestamp-wrap">';
 624      /* translators: 1: month input, 2: day input, 3: year input, 4: hour input, 5: minute input */
 625      printf(__('%1$s%2$s, %3$s @ %4$s : %5$s'), $month, $day, $year, $hour, $minute);
 626  
 627      echo '</div><input type="hidden" id="ss" name="ss" value="' . $ss . '" />';
 628  
 629      if ( $multi ) return;
 630  
 631      echo "\n\n";
 632      foreach ( array('mm', 'jj', 'aa', 'hh', 'mn') as $timeunit ) {
 633          echo '<input type="hidden" id="hidden_' . $timeunit . '" name="hidden_' . $timeunit . '" value="' . $$timeunit . '" />' . "\n";
 634          $cur_timeunit = 'cur_' . $timeunit;
 635          echo '<input type="hidden" id="'. $cur_timeunit . '" name="'. $cur_timeunit . '" value="' . $$cur_timeunit . '" />' . "\n";
 636      }
 637  ?>
 638  
 639  <p>
 640  <a href="#edit_timestamp" class="save-timestamp hide-if-no-js button"><?php _e('OK'); ?></a>
 641  <a href="#edit_timestamp" class="cancel-timestamp hide-if-no-js"><?php _e('Cancel'); ?></a>
 642  </p>
 643  <?php
 644  }
 645  
 646  /**
 647   * {@internal Missing Short Description}}
 648   *
 649   * @since 1.5.0
 650   *
 651   * @param unknown_type $default
 652   */
 653  function page_template_dropdown( $default = '' ) {
 654      $templates = get_page_templates();
 655      ksort( $templates );
 656      foreach (array_keys( $templates ) as $template )
 657          : if ( $default == $templates[$template] )
 658              $selected = " selected='selected'";
 659          else
 660              $selected = '';
 661      echo "\n\t<option value='".$templates[$template]."' $selected>$template</option>";
 662      endforeach;
 663  }
 664  
 665  /**
 666   * {@internal Missing Short Description}}
 667   *
 668   * @since 1.5.0
 669   *
 670   * @param unknown_type $default
 671   * @param unknown_type $parent
 672   * @param unknown_type $level
 673   * @return unknown
 674   */
 675  function parent_dropdown( $default = 0, $parent = 0, $level = 0 ) {
 676      global $wpdb;
 677      $post = get_post();
 678      $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) );
 679  
 680      if ( $items ) {
 681          foreach ( $items as $item ) {
 682              // A page cannot be its own parent.
 683              if ( $post->ID && $item->ID == $post->ID )
 684                  continue;
 685  
 686              $pad = str_repeat( '&nbsp;', $level * 3 );
 687              if ( $item->ID == $default)
 688                  $current = ' selected="selected"';
 689              else
 690                  $current = '';
 691  
 692              echo "\n\t<option class='level-$level' value='$item->ID'$current>$pad " . esc_html($item->post_title) . "</option>";
 693              parent_dropdown( $default, $item->ID, $level +1 );
 694          }
 695      } else {
 696          return false;
 697      }
 698  }
 699  
 700  /**
 701   * {@internal Missing Short Description}}
 702   *
 703   * @since 2.0.0
 704   *
 705   * @param unknown_type $id
 706   * @return unknown
 707   */
 708  function the_attachment_links( $id = false ) {
 709      $id = (int) $id;
 710      $post = get_post( $id );
 711  
 712      if ( $post->post_type != 'attachment' )
 713          return false;
 714  
 715      $icon = wp_get_attachment_image( $post->ID, 'thumbnail', true );
 716      $attachment_data = wp_get_attachment_metadata( $id );
 717      $thumb = isset( $attachment_data['thumb'] );
 718  ?>
 719  <form id="the-attachment-links">
 720  <table>
 721      <col />
 722      <col class="widefat" />
 723      <tr>
 724          <th scope="row"><?php _e( 'URL' ) ?></th>
 725          <td><textarea rows="1" cols="40" type="text" class="attachmentlinks" readonly="readonly"><?php echo esc_textarea( wp_get_attachment_url() ); ?></textarea></td>
 726      </tr>
 727  <?php if ( $icon ) : ?>
 728      <tr>
 729          <th scope="row"><?php $thumb ? _e( 'Thumbnail linked to file' ) : _e( 'Image linked to file' ); ?></th>
 730          <td><textarea rows="1" cols="40" type="text" class="attachmentlinks" readonly="readonly"><a href="<?php echo wp_get_attachment_url(); ?>"><?php echo $icon ?></a></textarea></td>
 731      </tr>
 732      <tr>
 733          <th scope="row"><?php $thumb ? _e( 'Thumbnail linked to page' ) : _e( 'Image linked to page' ); ?></th>
 734          <td><textarea rows="1" cols="40" type="text" class="attachmentlinks" readonly="readonly"><a href="<?php echo get_attachment_link( $post->ID ) ?>" rel="attachment wp-att-<?php echo $post->ID; ?>"><?php echo $icon ?></a></textarea></td>
 735      </tr>
 736  <?php else : ?>
 737      <tr>
 738          <th scope="row"><?php _e( 'Link to file' ) ?></th>
 739          <td><textarea rows="1" cols="40" type="text" class="attachmentlinks" readonly="readonly"><a href="<?php echo wp_get_attachment_url(); ?>" class="attachmentlink"><?php echo basename( wp_get_attachment_url() ); ?></a></textarea></td>
 740      </tr>
 741      <tr>
 742          <th scope="row"><?php _e( 'Link to page' ) ?></th>
 743          <td><textarea rows="1" cols="40" type="text" class="attachmentlinks" readonly="readonly"><a href="<?php echo get_attachment_link( $post->ID ) ?>" rel="attachment wp-att-<?php echo $post->ID ?>"><?php the_title(); ?></a></textarea></td>
 744      </tr>
 745  <?php endif; ?>
 746  </table>
 747  </form>
 748  <?php
 749  }
 750  
 751  /**
 752   * Print out <option> html elements for role selectors
 753   *
 754   * @since 2.1.0
 755   *
 756   * @param string $selected slug for the role that should be already selected
 757   */
 758  function wp_dropdown_roles( $selected = false ) {
 759      $p = '';
 760      $r = '';
 761  
 762      $editable_roles = get_editable_roles();
 763  
 764      foreach ( $editable_roles as $role => $details ) {
 765          $name = translate_user_role($details['name'] );
 766          if ( $selected == $role ) // preselect specified role
 767              $p = "\n\t<option selected='selected' value='" . esc_attr($role) . "'>$name</option>";
 768          else
 769              $r .= "\n\t<option value='" . esc_attr($role) . "'>$name</option>";
 770      }
 771      echo $p . $r;
 772  }
 773  
 774  /**
 775   * Outputs the form used by the importers to accept the data to be imported
 776   *
 777   * @since 2.0.0
 778   *
 779   * @param string $action The action attribute for the form.
 780   */
 781  function wp_import_upload_form( $action ) {
 782      $bytes = apply_filters( 'import_upload_size_limit', wp_max_upload_size() );
 783      $size = wp_convert_bytes_to_hr( $bytes );
 784      $upload_dir = wp_upload_dir();
 785      if ( ! empty( $upload_dir['error'] ) ) :
 786          ?><div class="error"><p><?php _e('Before you can upload your import file, you will need to fix the following error:'); ?></p>
 787          <p><strong><?php echo $upload_dir['error']; ?></strong></p></div><?php
 788      else :
 789  ?>
 790  <form enctype="multipart/form-data" id="import-upload-form" method="post" class="wp-upload-form" action="<?php echo esc_attr(wp_nonce_url($action, 'import-upload')); ?>">
 791  <p>
 792  <label for="upload"><?php _e( 'Choose a file from your computer:' ); ?></label> (<?php printf( __('Maximum size: %s' ), $size ); ?>)
 793  <input type="file" id="upload" name="import" size="25" />
 794  <input type="hidden" name="action" value="save" />
 795  <input type="hidden" name="max_file_size" value="<?php echo $bytes; ?>" />
 796  </p>
 797  <?php submit_button( __('Upload file and import'), 'button' ); ?>
 798  </form>
 799  <?php
 800      endif;
 801  }
 802  
 803  /**
 804   * Add a meta box to an edit form.
 805   *
 806   * @since 2.5.0
 807   *
 808   * @param string $id String for use in the 'id' attribute of tags.
 809   * @param string $title Title of the meta box.
 810   * @param string $callback Function that fills the box with the desired content. The function should echo its output.
 811   * @param string|object $screen Optional. The screen on which to show the box (post, page, link). Defaults to current screen.
 812   * @param string $context Optional. The context within the page where the boxes should show ('normal', 'advanced').
 813   * @param string $priority Optional. The priority within the context where the boxes should show ('high', 'low').
 814   */
 815  function add_meta_box( $id, $title, $callback, $screen = null, $context = 'advanced', $priority = 'default', $callback_args = null ) {
 816      global $wp_meta_boxes;
 817  
 818      if ( empty( $screen ) )
 819          $screen = get_current_screen();
 820      elseif ( is_string( $screen ) )
 821          $screen = convert_to_screen( $screen );
 822  
 823      $page = $screen->id;
 824  
 825      if ( !isset($wp_meta_boxes) )
 826          $wp_meta_boxes = array();
 827      if ( !isset($wp_meta_boxes[$page]) )
 828          $wp_meta_boxes[$page] = array();
 829      if ( !isset($wp_meta_boxes[$page][$context]) )
 830          $wp_meta_boxes[$page][$context] = array();
 831  
 832      foreach ( array_keys($wp_meta_boxes[$page]) as $a_context ) {
 833          foreach ( array('high', 'core', 'default', 'low') as $a_priority ) {
 834              if ( !isset($wp_meta_boxes[$page][$a_context][$a_priority][$id]) )
 835                  continue;
 836  
 837              // If a core box was previously added or removed by a plugin, don't add.
 838              if ( 'core' == $priority ) {
 839                  // If core box previously deleted, don't add
 840                  if ( false === $wp_meta_boxes[$page][$a_context][$a_priority][$id] )
 841                      return;
 842                  // If box was added with default priority, give it core priority to maintain sort order
 843                  if ( 'default' == $a_priority ) {
 844                      $wp_meta_boxes[$page][$a_context]['core'][$id] = $wp_meta_boxes[$page][$a_context]['default'][$id];
 845                      unset($wp_meta_boxes[$page][$a_context]['default'][$id]);
 846                  }
 847                  return;
 848              }
 849              // If no priority given and id already present, use existing priority
 850              if ( empty($priority) ) {
 851                  $priority = $a_priority;
 852              // else if we're adding to the sorted priority, we don't know the title or callback. Grab them from the previously added context/priority.
 853              } elseif ( 'sorted' == $priority ) {
 854                  $title = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['title'];
 855                  $callback = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['callback'];
 856                  $callback_args = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['args'];
 857              }
 858              // An id can be in only one priority and one context
 859              if ( $priority != $a_priority || $context != $a_context )
 860                  unset($wp_meta_boxes[$page][$a_context][$a_priority][$id]);
 861          }
 862      }
 863  
 864      if ( empty($priority) )
 865          $priority = 'low';
 866  
 867      if ( !isset($wp_meta_boxes[$page][$context][$priority]) )
 868          $wp_meta_boxes[$page][$context][$priority] = array();
 869  
 870      $wp_meta_boxes[$page][$context][$priority][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback, 'args' => $callback_args);
 871  }
 872  
 873  /**
 874   * Meta-Box template function
 875   *
 876   * @since 2.5.0
 877   *
 878   * @param string|object $screen Screen identifier
 879   * @param string $context box context
 880   * @param mixed $object gets passed to the box callback function as first parameter
 881   * @return int number of meta_boxes
 882   */
 883  function do_meta_boxes( $screen, $context, $object ) {
 884      global $wp_meta_boxes;
 885      static $already_sorted = false;
 886  
 887      if ( empty( $screen ) )
 888          $screen = get_current_screen();
 889      elseif ( is_string( $screen ) )
 890          $screen = convert_to_screen( $screen );
 891  
 892      $page = $screen->id;
 893  
 894      $hidden = get_hidden_meta_boxes( $screen );
 895  
 896      printf('<div id="%s-sortables" class="meta-box-sortables">', htmlspecialchars($context));
 897  
 898      $i = 0;
 899      do {
 900          // Grab the ones the user has manually sorted. Pull them out of their previous context/priority and into the one the user chose
 901          if ( !$already_sorted && $sorted = get_user_option( "meta-box-order_$page" ) ) {
 902              foreach ( $sorted as $box_context => $ids ) {
 903                  foreach ( explode(',', $ids ) as $id ) {
 904                      if ( $id && 'dashboard_browser_nag' !== $id )
 905                          add_meta_box( $id, null, null, $screen, $box_context, 'sorted' );
 906                  }
 907              }
 908          }
 909          $already_sorted = true;
 910  
 911          if ( !isset($wp_meta_boxes) || !isset($wp_meta_boxes[$page]) || !isset($wp_meta_boxes[$page][$context]) )
 912              break;
 913  
 914          foreach ( array('high', 'sorted', 'core', 'default', 'low') as $priority ) {
 915              if ( isset($wp_meta_boxes[$page][$context][$priority]) ) {
 916                  foreach ( (array) $wp_meta_boxes[$page][$context][$priority] as $box ) {
 917                      if ( false == $box || ! $box['title'] )
 918                          continue;
 919                      $i++;
 920                      $style = '';
 921                      $hidden_class = in_array($box['id'], $hidden) ? ' hide-if-js' : '';
 922                      echo '<div id="' . $box['id'] . '" class="postbox ' . postbox_classes($box['id'], $page) . $hidden_class . '" ' . '>' . "\n";
 923                      if ( 'dashboard_browser_nag' != $box['id'] )
 924                          echo '<div class="handlediv" title="' . esc_attr__('Click to toggle') . '"><br /></div>';
 925                      echo "<h3 class='hndle'><span>{$box['title']}</span></h3>\n";
 926                      echo '<div class="inside">' . "\n";
 927                      call_user_func($box['callback'], $object, $box);
 928                      echo "</div>\n";
 929                      echo "</div>\n";
 930                  }
 931              }
 932          }
 933      } while(0);
 934  
 935      echo "</div>";
 936  
 937      return $i;
 938  
 939  }
 940  
 941  /**
 942   * Remove a meta box from an edit form.
 943   *
 944   * @since 2.6.0
 945   *
 946   * @param string $id String for use in the 'id' attribute of tags.
 947   * @param string|object $screen The screen on which to show the box (post, page, link).
 948   * @param string $context The context within the page where the boxes should show ('normal', 'advanced').
 949   */
 950  function remove_meta_box($id, $screen, $context) {
 951      global $wp_meta_boxes;
 952  
 953      if ( empty( $screen ) )
 954          $screen = get_current_screen();
 955      elseif ( is_string( $screen ) )
 956          $screen = convert_to_screen( $screen );
 957  
 958      $page = $screen->id;
 959  
 960      if ( !isset($wp_meta_boxes) )
 961          $wp_meta_boxes = array();
 962      if ( !isset($wp_meta_boxes[$page]) )
 963          $wp_meta_boxes[$page] = array();
 964      if ( !isset($wp_meta_boxes[$page][$context]) )
 965          $wp_meta_boxes[$page][$context] = array();
 966  
 967      foreach ( array('high', 'core', 'default', 'low') as $priority )
 968          $wp_meta_boxes[$page][$context][$priority][$id] = false;
 969  }
 970  
 971  /**
 972   * Add a new section to a settings page.
 973   *
 974   * Part of the Settings API. Use this to define new settings sections for an admin page.
 975   * Show settings sections in your admin page callback function with do_settings_sections().
 976   * Add settings fields to your section with add_settings_field()
 977   *
 978   * The $callback argument should be the name of a function that echoes out any
 979   * content you want to show at the top of the settings section before the actual
 980   * fields. It can output nothing if you want.
 981   *
 982   * @since 2.7.0
 983   *
 984   * @global $wp_settings_sections Storage array of all settings sections added to admin pages
 985   *
 986   * @param string $id Slug-name to identify the section. Used in the 'id' attribute of tags.
 987   * @param string $title Formatted title of the section. Shown as the heading for the section.
 988   * @param string $callback Function that echos out any content at the top of the section (between heading and fields).
 989   * @param string $page The slug-name of the settings page on which to show the section. Built-in pages include 'general', 'reading', 'writing', 'discussion', 'media', etc. Create your own using add_options_page();
 990   */
 991  function add_settings_section($id, $title, $callback, $page) {
 992      global $wp_settings_sections;
 993  
 994      if ( 'misc' == $page ) {
 995          _deprecated_argument( __FUNCTION__, '3.0', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'misc' ) );
 996          $page = 'general';
 997      }
 998  
 999      if ( 'privacy' == $page ) {
1000          _deprecated_argument( __FUNCTION__, '3.5', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'privacy' ) );
1001          $page = 'reading';
1002      }
1003  
1004      if ( !isset($wp_settings_sections) )
1005          $wp_settings_sections = array();
1006      if ( !isset($wp_settings_sections[$page]) )
1007          $wp_settings_sections[$page] = array();
1008      if ( !isset($wp_settings_sections[$page][$id]) )
1009          $wp_settings_sections[$page][$id] = array();
1010  
1011      $wp_settings_sections[$page][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback);
1012  }
1013  
1014  /**
1015   * Add a new field to a section of a settings page
1016   *
1017   * Part of the Settings API. Use this to define a settings field that will show
1018   * as part of a settings section inside a settings page. The fields are shown using
1019   * do_settings_fields() in do_settings-sections()
1020   *
1021   * The $callback argument should be the name of a function that echoes out the
1022   * html input tags for this setting field. Use get_option() to retrieve existing
1023   * values to show.
1024   *
1025   * @since 2.7.0
1026   *
1027   * @global $wp_settings_fields Storage array of settings fields and info about their pages/sections
1028   *
1029   * @param string $id Slug-name to identify the field. Used in the 'id' attribute of tags.
1030   * @param string $title Formatted title of the field. Shown as the label for the field during output.
1031   * @param string $callback Function that fills the field with the desired form inputs. The function should echo its output.
1032   * @param string $page The slug-name of the settings page on which to show the section (general, reading, writing, ...).
1033   * @param string $section The slug-name of the section of the settings page in which to show the box (default, ...).
1034   * @param array $args Additional arguments
1035   */
1036  function add_settings_field($id, $title, $callback, $page, $section = 'default', $args = array()) {
1037      global $wp_settings_fields;
1038  
1039      if ( 'misc' == $page ) {
1040          _deprecated_argument( __FUNCTION__, '3.0', __( 'The miscellaneous options group has been removed. Use another settings group.' ) );
1041          $page = 'general';
1042      }
1043  
1044      if ( 'privacy' == $page ) {
1045          _deprecated_argument( __FUNCTION__, '3.5', __( 'The privacy options group has been removed. Use another settings group.' ) );
1046          $page = 'reading';
1047      }
1048  
1049      if ( !isset($wp_settings_fields) )
1050          $wp_settings_fields = array();
1051      if ( !isset($wp_settings_fields[$page]) )
1052          $wp_settings_fields[$page] = array();
1053      if ( !isset($wp_settings_fields[$page][$section]) )
1054          $wp_settings_fields[$page][$section] = array();
1055  
1056      $wp_settings_fields[$page][$section][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback, 'args' => $args);
1057  }
1058  
1059  /**
1060   * Prints out all settings sections added to a particular settings page
1061   *
1062   * Part of the Settings API. Use this in a settings page callback function
1063   * to output all the sections and fields that were added to that $page with
1064   * add_settings_section() and add_settings_field()
1065   *
1066   * @global $wp_settings_sections Storage array of all settings sections added to admin pages
1067   * @global $wp_settings_fields Storage array of settings fields and info about their pages/sections
1068   * @since 2.7.0
1069   *
1070   * @param string $page The slug name of the page whos settings sections you want to output
1071   */
1072  function do_settings_sections( $page ) {
1073      global $wp_settings_sections, $wp_settings_fields;
1074  
1075      if ( ! isset( $wp_settings_sections ) || !isset( $wp_settings_sections[$page] ) )
1076          return;
1077  
1078      foreach ( (array) $wp_settings_sections[$page] as $section ) {
1079          if ( $section['title'] )
1080              echo "<h3>{$section['title']}</h3>\n";
1081  
1082          if ( $section['callback'] )
1083              call_user_func( $section['callback'], $section );
1084  
1085          if ( ! isset( $wp_settings_fields ) || !isset( $wp_settings_fields[$page] ) || !isset( $wp_settings_fields[$page][$section['id']] ) )
1086              continue;
1087          echo '<table class="form-table">';
1088          do_settings_fields( $page, $section['id'] );
1089          echo '</table>';
1090      }
1091  }
1092  
1093  /**
1094   * Print out the settings fields for a particular settings section
1095   *
1096   * Part of the Settings API. Use this in a settings page to output
1097   * a specific section. Should normally be called by do_settings_sections()
1098   * rather than directly.
1099   *
1100   * @global $wp_settings_fields Storage array of settings fields and their pages/sections
1101   *
1102   * @since 2.7.0
1103   *
1104   * @param string $page Slug title of the admin page who's settings fields you want to show.
1105   * @param section $section Slug title of the settings section who's fields you want to show.
1106   */
1107  function do_settings_fields($page, $section) {
1108      global $wp_settings_fields;
1109  
1110      if ( !isset($wp_settings_fields) || !isset($wp_settings_fields[$page]) || !isset($wp_settings_fields[$page][$section]) )
1111          return;
1112  
1113      foreach ( (array) $wp_settings_fields[$page][$section] as $field ) {
1114          echo '<tr valign="top">';
1115          if ( !empty($field['args']['label_for']) )
1116              echo '<th scope="row"><label for="' . esc_attr( $field['args']['label_for'] ) . '">' . $field['title'] . '</label></th>';
1117          else
1118              echo '<th scope="row">' . $field['title'] . '</th>';
1119          echo '<td>';
1120          call_user_func($field['callback'], $field['args']);
1121          echo '</td>';
1122          echo '</tr>';
1123      }
1124  }
1125  
1126  /**
1127   * Register a settings error to be displayed to the user
1128   *
1129   * Part of the Settings API. Use this to show messages to users about settings validation
1130   * problems, missing settings or anything else.
1131   *
1132   * Settings errors should be added inside the $sanitize_callback function defined in
1133   * register_setting() for a given setting to give feedback about the submission.
1134   *
1135   * By default messages will show immediately after the submission that generated the error.
1136   * Additional calls to settings_errors() can be used to show errors even when the settings
1137   * page is first accessed.
1138   *
1139   * @since 3.0.0
1140   *
1141   * @global array $wp_settings_errors Storage array of errors registered during this pageload
1142   *
1143   * @param string $setting Slug title of the setting to which this error applies
1144   * @param string $code Slug-name to identify the error. Used as part of 'id' attribute in HTML output.
1145   * @param string $message The formatted message text to display to the user (will be shown inside styled <div> and <p>)
1146   * @param string $type The type of message it is, controls HTML class. Use 'error' or 'updated'.
1147   */
1148  function add_settings_error( $setting, $code, $message, $type = 'error' ) {
1149      global $wp_settings_errors;
1150  
1151      if ( !isset($wp_settings_errors) )
1152          $wp_settings_errors = array();
1153  
1154      $new_error = array(
1155          'setting' => $setting,
1156          'code' => $code,
1157          'message' => $message,
1158          'type' => $type
1159      );
1160      $wp_settings_errors[] = $new_error;
1161  }
1162  
1163  /**
1164   * Fetch settings errors registered by add_settings_error()
1165   *
1166   * Checks the $wp_settings_errors array for any errors declared during the current
1167   * pageload and returns them.
1168   *
1169   * If changes were just submitted ($_GET['settings-updated']) and settings errors were saved
1170   * to the 'settings_errors' transient then those errors will be returned instead. This
1171   * is used to pass errors back across pageloads.
1172   *
1173   * Use the $sanitize argument to manually re-sanitize the option before returning errors.
1174   * This is useful if you have errors or notices you want to show even when the user
1175   * hasn't submitted data (i.e. when they first load an options page, or in admin_notices action hook)
1176   *
1177   * @since 3.0.0
1178   *
1179   * @global array $wp_settings_errors Storage array of errors registered during this pageload
1180   *
1181   * @param string $setting Optional slug title of a specific setting who's errors you want.
1182   * @param boolean $sanitize Whether to re-sanitize the setting value before returning errors.
1183   * @return array Array of settings errors
1184   */
1185  function get_settings_errors( $setting = '', $sanitize = false ) {
1186      global $wp_settings_errors;
1187  
1188      // If $sanitize is true, manually re-run the sanitizisation for this option
1189      // This allows the $sanitize_callback from register_setting() to run, adding
1190      // any settings errors you want to show by default.
1191      if ( $sanitize )
1192          sanitize_option( $setting, get_option( $setting ) );
1193  
1194      // If settings were passed back from options.php then use them
1195      if ( isset( $_GET['settings-updated'] ) && $_GET['settings-updated'] && get_transient( 'settings_errors' ) ) {
1196          $wp_settings_errors = array_merge( (array) $wp_settings_errors, get_transient( 'settings_errors' ) );
1197          delete_transient( 'settings_errors' );
1198      }
1199  
1200      // Check global in case errors have been added on this pageload
1201      if ( ! count( $wp_settings_errors ) )
1202          return array();
1203  
1204      // Filter the results to those of a specific setting if one was set
1205      if ( $setting ) {
1206          $setting_errors = array();
1207          foreach ( (array) $wp_settings_errors as $key => $details ) {
1208              if ( $setting == $details['setting'] )
1209                  $setting_errors[] = $wp_settings_errors[$key];
1210          }
1211          return $setting_errors;
1212      }
1213  
1214      return $wp_settings_errors;
1215  }
1216  
1217  /**
1218   * Display settings errors registered by add_settings_error()
1219   *
1220   * Part of the Settings API. Outputs a <div> for each error retrieved by get_settings_errors().
1221   *
1222   * This is called automatically after a settings page based on the Settings API is submitted.
1223   * Errors should be added during the validation callback function for a setting defined in register_setting()
1224   *
1225   * The $sanitize option is passed into get_settings_errors() and will re-run the setting sanitization
1226   * on its current value.
1227   *
1228   * The $hide_on_update option will cause errors to only show when the settings page is first loaded.
1229   * if the user has already saved new values it will be hidden to avoid repeating messages already
1230   * shown in the default error reporting after submission. This is useful to show general errors like missing
1231   * settings when the user arrives at the settings page.
1232   *
1233   * @since 3.0.0
1234   *
1235   * @param string $setting Optional slug title of a specific setting who's errors you want.
1236   * @param boolean $sanitize Whether to re-sanitize the setting value before returning errors.
1237   * @param boolean $hide_on_update If set to true errors will not be shown if the settings page has already been submitted.
1238   */
1239  function settings_errors( $setting = '', $sanitize = false, $hide_on_update = false ) {
1240  
1241      if ( $hide_on_update && ! empty( $_GET['settings-updated'] ) )
1242          return;
1243  
1244      $settings_errors = get_settings_errors( $setting, $sanitize );
1245  
1246      if ( empty( $settings_errors ) )
1247          return;
1248  
1249      $output = '';
1250      foreach ( $settings_errors as $key => $details ) {
1251          $css_id = 'setting-error-' . $details['code'];
1252          $css_class = $details['type'] . ' settings-error';
1253          $output .= "<div id='$css_id' class='$css_class'> \n";
1254          $output .= "<p><strong>{$details['message']}</strong></p>";
1255          $output .= "</div> \n";
1256      }
1257      echo $output;
1258  }
1259  
1260  /**
1261   * {@internal Missing Short Description}}
1262   *
1263   * @since 2.7.0
1264   *
1265   * @param unknown_type $found_action
1266   */
1267  function find_posts_div($found_action = '') {
1268  ?>
1269      <div id="find-posts" class="find-box" style="display:none;">
1270          <div id="find-posts-head" class="find-box-head"><?php _e('Find Posts or Pages'); ?></div>
1271          <div class="find-box-inside">
1272              <div class="find-box-search">
1273                  <?php if ( $found_action ) { ?>
1274                      <input type="hidden" name="found_action" value="<?php echo esc_attr($found_action); ?>" />
1275                  <?php } ?>
1276  
1277                  <input type="hidden" name="affected" id="affected" value="" />
1278                  <?php wp_nonce_field( 'find-posts', '_ajax_nonce', false ); ?>
1279                  <label class="screen-reader-text" for="find-posts-input"><?php _e( 'Search' ); ?></label>
1280                  <input type="text" id="find-posts-input" name="ps" value="" />
1281                  <span class="spinner"></span>
1282                  <input type="button" id="find-posts-search" value="<?php esc_attr_e( 'Search' ); ?>" class="button" />
1283              </div>
1284              <div id="find-posts-response"></div>
1285          </div>
1286          <div class="find-box-buttons">
1287              <input id="find-posts-close" type="button" class="button alignleft" value="<?php esc_attr_e('Close'); ?>" />
1288              <?php submit_button( __( 'Select' ), 'button-primary alignright', 'find-posts-submit', false ); ?>
1289          </div>
1290      </div>
1291  <?php
1292  }
1293  
1294  /**
1295   * Display the post password.
1296   *
1297   * The password is passed through {@link esc_attr()} to ensure that it
1298   * is safe for placing in an html attribute.
1299   *
1300   * @uses attr
1301   * @since 2.7.0
1302   */
1303  function the_post_password() {
1304      $post = get_post();
1305      if ( isset( $post->post_password ) )
1306          echo esc_attr( $post->post_password );
1307  }
1308  
1309  /**
1310   * Get the post title.
1311   *
1312   * The post title is fetched and if it is blank then a default string is
1313   * returned.
1314   *
1315   * @since 2.7.0
1316   * @param mixed $post Post id or object. If not supplied the global $post is used.
1317   * @return string The post title if set
1318   */
1319  function _draft_or_post_title( $post = 0 ) {
1320      $title = get_the_title( $post );
1321      if ( empty( $title ) )
1322          $title = __( '(no title)' );
1323      return $title;
1324  }
1325  
1326  /**
1327   * Display the search query.
1328   *
1329   * A simple wrapper to display the "s" parameter in a GET URI. This function
1330   * should only be used when {@link the_search_query()} cannot.
1331   *
1332   * @uses attr
1333   * @since 2.7.0
1334   *
1335   */
1336  function _admin_search_query() {
1337      echo isset($_REQUEST['s']) ? esc_attr( stripslashes( $_REQUEST['s'] ) ) : '';
1338  }
1339  
1340  /**
1341   * Generic Iframe header for use with Thickbox
1342   *
1343   * @since 2.7.0
1344   * @param string $title Title of the Iframe page.
1345   * @param bool $limit_styles Limit styles to colour-related styles only (unless others are enqueued).
1346   *
1347   */
1348  function iframe_header( $title = '', $limit_styles = false ) {
1349      show_admin_bar( false );
1350      global $hook_suffix, $current_user, $admin_body_class, $wp_locale;
1351      $admin_body_class = preg_replace('/[^a-z0-9_-]+/i', '-', $hook_suffix);
1352  
1353      $current_screen = get_current_screen();
1354  
1355      @header( 'Content-Type: ' . get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ) );
1356      _wp_admin_html_begin();
1357  ?>
1358  <title><?php bloginfo('name') ?> &rsaquo; <?php echo $title ?> &#8212; <?php _e('WordPress'); ?></title>
1359  <?php
1360  wp_enqueue_style( 'colors' );
1361  ?>
1362  <script type="text/javascript">
1363  //<![CDATA[
1364  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();}}};
1365  function tb_close(){var win=window.dialogArguments||opener||parent||top;win.tb_remove();}
1366  var userSettings = {
1367          'url': '<?php echo SITECOOKIEPATH; ?>',
1368          'uid': '<?php if ( ! isset($current_user) ) $current_user = wp_get_current_user(); echo $current_user->ID; ?>',
1369          'time':'<?php echo time() ?>'
1370      },
1371      ajaxurl = '<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>',
1372      pagenow = '<?php echo $current_screen->id; ?>',
1373      typenow = '<?php echo $current_screen->post_type; ?>',
1374      adminpage = '<?php echo $admin_body_class; ?>',
1375      thousandsSeparator = '<?php echo addslashes( $wp_locale->number_format['thousands_sep'] ); ?>',
1376      decimalPoint = '<?php echo addslashes( $wp_locale->number_format['decimal_point'] ); ?>',
1377      isRtl = <?php echo (int) is_rtl(); ?>;
1378  //]]>
1379  </script>
1380  <?php
1381  do_action('admin_enqueue_scripts', $hook_suffix);
1382  do_action("admin_print_styles-$hook_suffix");
1383  do_action('admin_print_styles');
1384  do_action("admin_print_scripts-$hook_suffix");
1385  do_action('admin_print_scripts');
1386  do_action("admin_head-$hook_suffix");
1387  do_action('admin_head');
1388  
1389  $admin_body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
1390  ?>
1391  </head>
1392  <body<?php if ( isset($GLOBALS['body_id']) ) echo ' id="' . $GLOBALS['body_id'] . '"'; ?> class="wp-admin wp-core-ui no-js iframe <?php echo apply_filters( 'admin_body_class', '' ) . ' ' . $admin_body_class; ?>">
1393  <script type="text/javascript">
1394  //<![CDATA[
1395  (function(){
1396  var c = document.body.className;
1397  c = c.replace(/no-js/, 'js');
1398  document.body.className = c;
1399  })();
1400  //]]>
1401  </script>
1402  <?php
1403  }
1404  
1405  /**
1406   * Generic Iframe footer for use with Thickbox
1407   *
1408   * @since 2.7.0
1409   *
1410   */
1411  function iframe_footer() {
1412      //We're going to hide any footer output on iframe pages, but run the hooks anyway since they output Javascript or other needed content. ?>
1413      <div class="hidden">
1414  <?php
1415      do_action('admin_footer', '');
1416      do_action('admin_print_footer_scripts'); ?>
1417      </div>
1418  <script type="text/javascript">if(typeof wpOnload=="function")wpOnload();</script>
1419  </body>
1420  </html>
1421  <?php
1422  }
1423  
1424  function _post_states($post) {
1425      $post_states = array();
1426      if ( isset( $_REQUEST['post_status'] ) )
1427          $post_status = $_REQUEST['post_status'];
1428      else
1429          $post_status = '';
1430  
1431      if ( !empty($post->post_password) )
1432          $post_states['protected'] = __('Password protected');
1433      if ( 'private' == $post->post_status && 'private' != $post_status )
1434          $post_states['private'] = __('Private');
1435      if ( 'draft' == $post->post_status && 'draft' != $post_status )
1436          $post_states['draft'] = __('Draft');
1437      if ( 'pending' == $post->post_status && 'pending' != $post_status )
1438          /* translators: post state */
1439          $post_states['pending'] = _x('Pending', 'post state');
1440      if ( is_sticky($post->ID) )
1441          $post_states['sticky'] = __('Sticky');
1442  
1443      $post_states = apply_filters( 'display_post_states', $post_states );
1444  
1445      if ( ! empty($post_states) ) {
1446          $state_count = count($post_states);
1447          $i = 0;
1448          echo ' - ';
1449          foreach ( $post_states as $state ) {
1450              ++$i;
1451              ( $i == $state_count ) ? $sep = '' : $sep = ', ';
1452              echo "<span class='post-state'>$state$sep</span>";
1453          }
1454      }
1455  
1456      if ( get_post_format( $post->ID ) )
1457          echo ' - <span class="post-state-format">' . get_post_format_string( get_post_format( $post->ID ) ) . '</span>';
1458  }
1459  
1460  function _media_states( $post ) {
1461      $media_states = array();
1462      $stylesheet = get_option('stylesheet');
1463  
1464      if ( current_theme_supports( 'custom-header') ) {
1465          $meta_header = get_post_meta($post->ID, '_wp_attachment_is_custom_header', true );
1466          if ( ! empty( $meta_header ) && $meta_header == $stylesheet )
1467              $media_states[] = __( 'Header Image' );
1468      }
1469  
1470      if ( current_theme_supports( 'custom-background') ) {
1471          $meta_background = get_post_meta($post->ID, '_wp_attachment_is_custom_background', true );
1472          if ( ! empty( $meta_background ) && $meta_background == $stylesheet )
1473              $media_states[] = __( 'Background Image' );
1474      }
1475  
1476      $media_states = apply_filters( 'display_media_states', $media_states );
1477  
1478      if ( ! empty( $media_states ) ) {
1479          $state_count = count( $media_states );
1480          $i = 0;
1481          echo ' - ';
1482          foreach ( $media_states as $state ) {
1483              ++$i;
1484              ( $i == $state_count ) ? $sep = '' : $sep = ', ';
1485              echo "<span class='post-state'>$state$sep</span>";
1486          }
1487      }
1488  }
1489  
1490  /**
1491   * Test support for compressing JavaScript from PHP
1492   *
1493   * Outputs JavaScript that tests if compression from PHP works as expected
1494   * and sets an option with the result. Has no effect when the current user
1495   * is not an administrator. To run the test again the option 'can_compress_scripts'
1496   * has to be deleted.
1497   *
1498   * @since 2.8.0
1499   */
1500  function compression_test() {
1501  ?>
1502      <script type="text/javascript">
1503      /* <![CDATA[ */
1504      var testCompression = {
1505          get : function(test) {
1506              var x;
1507              if ( window.XMLHttpRequest ) {
1508                  x = new XMLHttpRequest();
1509              } else {
1510                  try{x=new ActiveXObject('Msxml2.XMLHTTP');}catch(e){try{x=new ActiveXObject('Microsoft.XMLHTTP');}catch(e){};}
1511              }
1512  
1513              if (x) {
1514                  x.onreadystatechange = function() {
1515                      var r, h;
1516                      if ( x.readyState == 4 ) {
1517                          r = x.responseText.substr(0, 18);
1518                          h = x.getResponseHeader('Content-Encoding');
1519                          testCompression.check(r, h, test);
1520                      }
1521                  }
1522  
1523                  x.open('GET', ajaxurl + '?action=wp-compression-test&test='+test+'&'+(new Date()).getTime(), true);
1524                  x.send('');
1525              }
1526          },
1527  
1528          check : function(r, h, test) {
1529              if ( ! r && ! test )
1530                  this.get(1);
1531  
1532              if ( 1 == test ) {
1533                  if ( h && ( h.match(/deflate/i) || h.match(/gzip/i) ) )
1534                      this.get('no');
1535                  else
1536                      this.get(2);
1537  
1538                  return;
1539              }
1540  
1541              if ( 2 == test ) {
1542                  if ( '"wpCompressionTest' == r )
1543                      this.get('yes');
1544                  else
1545                      this.get('no');
1546              }
1547          }
1548      };
1549      testCompression.check();
1550      /* ]]> */
1551      </script>
1552  <?php
1553  }
1554  
1555  /**
1556   * Echos a submit button, with provided text and appropriate class
1557   *
1558   * @since 3.1.0
1559   *
1560   * @param string $text The text of the button (defaults to 'Save Changes')
1561   * @param string $type The type of button. One of: primary, secondary, delete
1562   * @param string $name The HTML name of the submit button. Defaults to "submit". If no id attribute
1563   *               is given in $other_attributes below, $name will be used as the button's id.
1564   * @param bool $wrap True if the output button should be wrapped in a paragraph tag,
1565   *                false otherwise. Defaults to true
1566   * @param array|string $other_attributes Other attributes that should be output with the button,
1567   *                     mapping attributes to their values, such as array( 'tabindex' => '1' ).
1568   *                     These attributes will be output as attribute="value", such as tabindex="1".
1569   *                     Defaults to no other attributes. Other attributes can also be provided as a
1570   *                     string such as 'tabindex="1"', though the array format is typically cleaner.
1571   */
1572  function submit_button( $text = null, $type = 'primary', $name = 'submit', $wrap = true, $other_attributes = null ) {
1573      echo get_submit_button( $text, $type, $name, $wrap, $other_attributes );
1574  }
1575  
1576  /**
1577   * Returns a submit button, with provided text and appropriate class
1578   *
1579   * @since 3.1.0
1580   *
1581   * @param string $text The text of the button (defaults to 'Save Changes')
1582   * @param string $type The type of button. One of: primary, secondary, delete
1583   * @param string $name The HTML name of the submit button. Defaults to "submit". If no id attribute
1584   *               is given in $other_attributes below, $name will be used as the button's id.
1585   * @param bool $wrap True if the output button should be wrapped in a paragraph tag,
1586   *                false otherwise. Defaults to true
1587   * @param array|string $other_attributes Other attributes that should be output with the button,
1588   *                     mapping attributes to their values, such as array( 'tabindex' => '1' ).
1589   *                     These attributes will be output as attribute="value", such as tabindex="1".
1590   *                     Defaults to no other attributes. Other attributes can also be provided as a
1591   *                     string such as 'tabindex="1"', though the array format is typically cleaner.
1592   */
1593  function get_submit_button( $text = null, $type = 'primary large', $name = 'submit', $wrap = true, $other_attributes = null ) {
1594      if ( ! is_array( $type ) )
1595          $type = explode( ' ', $type );
1596  
1597      $button_shorthand = array( 'primary', 'small', 'large' );
1598      $classes = array( 'button' );
1599      foreach ( $type as $t ) {
1600          if ( 'secondary' === $t || 'button-secondary' === $t )
1601              continue;
1602          $classes[] = in_array( $t, $button_shorthand ) ? 'button-' . $t : $t;
1603      }
1604      $class = implode( ' ', array_unique( $classes ) );
1605  
1606      if ( 'delete' === $type )
1607          $class = 'button-secondary delete';
1608  
1609      $text = $text ? $text : __( 'Save Changes' );
1610  
1611      // Default the id attribute to $name unless an id was specifically provided in $other_attributes
1612      $id = $name;
1613      if ( is_array( $other_attributes ) && isset( $other_attributes['id'] ) ) {
1614          $id = $other_attributes['id'];
1615          unset( $other_attributes['id'] );
1616      }
1617  
1618      $attributes = '';
1619      if ( is_array( $other_attributes ) ) {
1620          foreach ( $other_attributes as $attribute => $value ) {
1621              $attributes .= $attribute . '="' . esc_attr( $value ) . '" '; // Trailing space is important
1622          }
1623      } else if ( !empty( $other_attributes ) ) { // Attributes provided as a string
1624          $attributes = $other_attributes;
1625      }
1626  
1627      $button = '<input type="submit" name="' . esc_attr( $name ) . '" id="' . esc_attr( $id ) . '" class="' . esc_attr( $class );
1628      $button    .= '" value="' . esc_attr( $text ) . '" ' . $attributes . ' />';
1629  
1630      if ( $wrap ) {
1631          $button = '<p class="submit">' . $button . '</p>';
1632      }
1633  
1634      return $button;
1635  }
1636  
1637  function _wp_admin_html_begin() {
1638      $admin_html_class = ( is_admin_bar_showing() ) ? 'wp-toolbar' : '';
1639  ?>
1640  <!DOCTYPE html>
1641  <!--[if IE 8]>
1642  <html xmlns="http://www.w3.org/1999/xhtml" class="ie8 <?php echo $admin_html_class; ?>" <?php do_action('admin_xml_ns'); ?> <?php language_attributes(); ?>>
1643  <![endif]-->
1644  <!--[if !(IE 8) ]><!-->
1645  <html xmlns="http://www.w3.org/1999/xhtml" class="<?php echo $admin_html_class; ?>" <?php do_action('admin_xml_ns'); ?> <?php language_attributes(); ?>>
1646  <!--<![endif]-->
1647  <head>
1648  <meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php echo get_option('blog_charset'); ?>" />
1649  <?php
1650  }
1651  
1652  final class WP_Internal_Pointers {
1653      /**
1654       * Initializes the new feature pointers.
1655       *
1656       * @since 3.3.0
1657       *
1658       * All pointers can be disabled using the following:
1659       *     remove_action( 'admin_enqueue_scripts', array( 'WP_Internal_Pointers', 'enqueue_scripts' ) );
1660       *
1661       * Individual pointers (e.g. wp330_toolbar) can be disabled using the following:
1662       *     remove_action( 'admin_print_footer_scripts', array( 'WP_Internal_Pointers', 'pointer_wp330_toolbar' ) );
1663       */
1664  	public static function enqueue_scripts( $hook_suffix ) {
1665          /*
1666           * Register feature pointers
1667           * Format: array( hook_suffix => pointer_id )
1668           */
1669  
1670          $registered_pointers = array(
1671              'index.php'    => 'wp330_toolbar',
1672              'post-new.php' => 'wp350_media',
1673              'post.php'     => 'wp350_media',
1674              'themes.php'   => array( 'wp330_saving_widgets', 'wp340_customize_current_theme_link' ),
1675              'appearance_page_custom-header' => 'wp340_choose_image_from_library',
1676              'appearance_page_custom-background' => 'wp340_choose_image_from_library',
1677          );
1678  
1679          // Check if screen related pointer is registered
1680          if ( empty( $registered_pointers[ $hook_suffix ] ) )
1681              return;
1682  
1683          $pointers = (array) $registered_pointers[ $hook_suffix ];
1684  
1685          $caps_required = array(
1686              'wp330_saving_widgets' => array( 'edit_theme_options', 'switch_themes' ),
1687              'wp340_customize_current_theme_link' => array( 'edit_theme_options' ),
1688              'wp340_choose_image_from_library' => array( 'edit_theme_options' ),
1689              'wp350_media' => array( 'upload_files' ),
1690          );
1691  
1692          // Get dismissed pointers
1693          $dismissed = explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
1694  
1695          $got_pointers = false;
1696          foreach ( array_diff( $pointers, $dismissed ) as $pointer ) {
1697              if ( isset( $caps_required[ $pointer ] ) ) {
1698                  foreach ( $caps_required[ $pointer ] as $cap ) {
1699                      if ( ! current_user_can( $cap ) )
1700                          continue 2;
1701                  }
1702              }
1703  
1704              // Bind pointer print function
1705              add_action( 'admin_print_footer_scripts', array( 'WP_Internal_Pointers', 'pointer_' . $pointer ) );
1706              $got_pointers = true;
1707          }
1708  
1709          if ( ! $got_pointers )
1710              return;
1711  
1712          // Add pointers script and style to queue
1713          wp_enqueue_style( 'wp-pointer' );
1714          wp_enqueue_script( 'wp-pointer' );
1715      }
1716  
1717      /**
1718       * Print the pointer javascript data.
1719       *
1720       * @since 3.3.0
1721       *
1722       * @param string $pointer_id The pointer ID.
1723       * @param string $selector The HTML elements, on which the pointer should be attached.
1724       * @param array  $args Arguments to be passed to the pointer JS (see wp-pointer.js).
1725       */
1726  	private static function print_js( $pointer_id, $selector, $args ) {
1727          if ( empty( $pointer_id ) || empty( $selector ) || empty( $args ) || empty( $args['content'] ) )
1728              return;
1729  
1730          ?>
1731          <script type="text/javascript">
1732          //<![CDATA[
1733          (function($){
1734              var options = <?php echo json_encode( $args ); ?>, setup;
1735  
1736              if ( ! options )
1737                  return;
1738  
1739              options = $.extend( options, {
1740                  close: function() {
1741                      $.post( ajaxurl, {
1742                          pointer: '<?php echo $pointer_id; ?>',
1743                          action: 'dismiss-wp-pointer'
1744                      });
1745                  }
1746              });
1747  
1748              setup = function() {
1749                  $('<?php echo $selector; ?>').pointer( options ).pointer('open');
1750              };
1751  
1752              if ( options.position && options.position.defer_loading )
1753                  $(window).bind( 'load.wp-pointers', setup );
1754              else
1755                  $(document).ready( setup );
1756  
1757          })( jQuery );
1758          //]]>
1759          </script>
1760          <?php
1761      }
1762  
1763  	public static function pointer_wp330_toolbar() {
1764          $content  = '<h3>' . __( 'New Feature: Toolbar' ) . '</h3>';
1765          $content .= '<p>' .  __( 'We&#8217;ve combined the admin bar and the old Dashboard header into one persistent toolbar. Hover over the toolbar items to see what&#8217;s new.' ) . '</p>';
1766  
1767          if ( is_multisite() && is_super_admin() )
1768              $content .= '<p>' . __( 'Network Admin is now located in the My Sites menu.' ) . '</p>';
1769  
1770          WP_Internal_Pointers::print_js( 'wp330_toolbar', '#wpadminbar', array(
1771              'content'  => $content,
1772              'position' => array( 'edge' => 'top', 'align' => 'center' ),
1773          ) );
1774      }
1775  
1776      /**
1777       * Print 'Updated Media Uploader' for 3.3.0.
1778       *
1779       * @since 3.3.0
1780       */
1781  	public static function pointer_wp330_media_uploader() {}
1782  
1783      /**
1784       * Print 'New Feature: Saving Widgets' for 3.3.0.
1785       *
1786       * @since 3.3.0
1787       */
1788  	public static function pointer_wp330_saving_widgets() {
1789          $content  = '<h3>' . __( 'New Feature: Saving Widgets' ) . '</h3>';
1790          $content .= '<p>' . __( 'If you change your mind and revert to your previous theme, we&#8217;ll put the widgets back the way you had them.' ) . '</p>';
1791  
1792          WP_Internal_Pointers::print_js( 'wp330_saving_widgets', '#message2', array(
1793              'content'  => $content,
1794              'position' => array( 'edge' => 'top', 'align' => is_rtl() ? 'right' : 'left' ),
1795          ) );
1796      }
1797  
1798      /**
1799       * Print 'New Feature: Current Theme Customize Link' for 3.4.0.
1800       *
1801       * @since 3.4.0
1802       */
1803  	public static function pointer_wp340_customize_current_theme_link() {
1804          $content  = '<h3>' . __( 'New Feature: Customizer' ) . '</h3>';
1805          $content .= '<p>' . __( 'Click Customize to change the header, background, title and menus of the current theme, all in one place.' ) . '</p>';
1806          $content .= '<p>' . __( 'Click the Live Preview links in the Available Themes list below to customize and preview another theme before activating it.' ) . '</p>';
1807  
1808          WP_Internal_Pointers::print_js( 'wp340_customize_current_theme_link', '#customize-current-theme-link', array(
1809              'content'  => $content,
1810              'position' => array( 'edge' => 'top', 'align' => is_rtl() ? 'right' : 'left', 'offset' => is_rtl() ? '32 0' : '-32 0' ),
1811          ) );
1812      }
1813  
1814      /**
1815       * Print 'New Feature: Choose Image from Library' for 3.4.0.
1816       *
1817       * @since 3.4.0
1818       */
1819  	public static function pointer_wp340_choose_image_from_library() {
1820          $content  = '<h3>' . __( 'New Feature: Choose Image from Library' ) . '</h3>';
1821          $content .= '<p>' . __( 'Want to use an image you uploaded earlier? Select it from your media library instead of uploading it again.' ) . '</p>';
1822  
1823          WP_Internal_Pointers::print_js( 'wp340_choose_image_from_library', '#choose-from-library-link', array(
1824              'content'  => $content,
1825              'position' => array( 'edge' => 'top', 'align' => is_rtl() ? 'right' : 'left', 'defer_loading' => true ),
1826          ) );
1827      }
1828  
1829  	public static function pointer_wp350_media() {
1830          $content  = '<h3>' . __( 'New Media Manager' ) . '</h3>';
1831          $content .= '<p>' . __( 'Uploading files and creating image galleries has a whole new look. Check it out!' ) . '</p>';
1832  
1833          self::print_js( 'wp350_media', '.insert-media', array(
1834              'content'  => $content,
1835              'position' => array( 'edge' => is_rtl() ? 'right' : 'left', 'align' => 'center' ),
1836          ) );
1837      }
1838  
1839      /**
1840       * Prevents new users from seeing existing 'new feature' pointers.
1841       *
1842       * @since 3.3.0
1843       */
1844  	public static function dismiss_pointers_for_new_users( $user_id ) {
1845          add_user_meta( $user_id, 'dismissed_wp_pointers', 'wp330_toolbar,wp330_saving_widgets,wp340_choose_image_from_library,wp340_customize_current_theme_link,wp350_media' );
1846      }
1847  }
1848  
1849  add_action( 'admin_enqueue_scripts', array( 'WP_Internal_Pointers', 'enqueue_scripts'                ) );
1850  add_action( 'user_register',         array( 'WP_Internal_Pointers', 'dismiss_pointers_for_new_users' ) );
1851  
1852  /**
1853   * Convert a screen string to a screen object
1854   *
1855   * @since 3.0.0
1856   *
1857   * @param string $hook_name The hook name (also known as the hook suffix) used to determine the screen.
1858   * @return WP_Screen Screen object.
1859   */
1860  function convert_to_screen( $hook_name ) {
1861      if ( ! class_exists( 'WP_Screen' ) ) {
1862          _doing_it_wrong( 'convert_to_screen(), add_meta_box()', __( "Likely direct inclusion of wp-admin/includes/template.php in order to use add_meta_box(). This is very wrong. Hook the add_meta_box() call into the add_meta_boxes action instead." ), '3.3' );
1863          return (object) array( 'id' => '_invalid', 'base' => '_are_belong_to_us' );
1864      }
1865  
1866      return WP_Screen::get( $hook_name );
1867  }

title

Description

title

Description

title

Description

title

title

Body