[ 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  //
  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      global $post_ID;
 170  
 171      if ( $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="" tabindex="101" 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="" tabindex="102" 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="" tabindex="103" />
 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, 'tabindex' => 104 ) );
 354      ?>
 355      </div>
 356  
 357      <p id="replysubmit" class="submit">
 358      <a href="#comments-form" class="cancel button-secondary alignleft" tabindex="106"><?php _e('Cancel'); ?></a>
 359      <a href="#comments-form" class="save button-primary alignright" tabindex="104">
 360      <span id="addbtn" style="display:none;"><?php _e('Add Comment'); ?></span>
 361      <span id="savebtn" style="display:none;"><?php _e('Update Comment'); ?></span>
 362      <span id="replybtn" style="display:none;"><?php _e('Submit Reply'); ?></span></a>
 363      <img class="waiting" style="display:none;" src="<?php echo esc_url( admin_url( 'images/wpspin_light.gif' ) ); ?>" alt="" />
 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" class="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' class='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]' tabindex='6' type='text' size='20' value='{$entry['meta_key']}' />";
 493  
 494      $r .= "\n\t\t<div class='submit'>";
 495      $r .= get_submit_button( __( 'Delete' ), "delete:the-list:meta-{$entry['meta_id']}::_ajax_nonce=$delete_nonce deletemeta", "deletemeta[{$entry['meta_id']}]", false, array( 'tabindex' => '6' ) );
 496      $r .= "\n\t\t";
 497      $r .= get_submit_button( __( 'Update' ), "add:the-list:meta-{$entry['meta_id']}::_ajax_nonce-add-meta=$update_nonce updatemeta" , 'updatemeta', false, array( 'tabindex' => '6' ) );
 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]' tabindex='6' 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" tabindex="7">
 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" tabindex="7" 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" tabindex="7" value="" />
 552  <?php } ?>
 553  </td>
 554  <td><textarea id="metavalue" name="metavalue" rows="2" cols="25" tabindex="8"></textarea></td>
 555  </tr>
 556  
 557  <tr><td colspan="2" class="submit">
 558  <?php submit_button( __( 'Add Custom Field' ), 'add:the-list:newmeta', 'addmeta', false, array( 'id' => 'addmetasub', 'tabindex' => '9' ) ); ?>
 559  <?php wp_nonce_field( 'add-meta', '_ajax_nonce-add-meta', false ); ?>
 560  </td></tr>
 561  </tbody>
 562  </table>
 563  <?php
 564  
 565  }
 566  
 567  /**
 568   * {@internal Missing Short Description}}
 569   *
 570   * @since 0.71
 571   *
 572   * @param unknown_type $edit
 573   * @param unknown_type $for_post
 574   * @param unknown_type $tab_index
 575   * @param unknown_type $multi
 576   */
 577  function touch_time( $edit = 1, $for_post = 1, $tab_index = 0, $multi = 0 ) {
 578      global $wp_locale, $post, $comment;
 579  
 580      if ( $for_post )
 581          $edit = ! ( in_array($post->post_status, array('draft', 'pending') ) && (!$post->post_date_gmt || '0000-00-00 00:00:00' == $post->post_date_gmt ) );
 582  
 583      $tab_index_attribute = '';
 584      if ( (int) $tab_index > 0 )
 585          $tab_index_attribute = " tabindex=\"$tab_index\"";
 586  
 587      // 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 />';
 588  
 589      $time_adj = current_time('timestamp');
 590      $post_date = ($for_post) ? $post->post_date : $comment->comment_date;
 591      $jj = ($edit) ? mysql2date( 'd', $post_date, false ) : gmdate( 'd', $time_adj );
 592      $mm = ($edit) ? mysql2date( 'm', $post_date, false ) : gmdate( 'm', $time_adj );
 593      $aa = ($edit) ? mysql2date( 'Y', $post_date, false ) : gmdate( 'Y', $time_adj );
 594      $hh = ($edit) ? mysql2date( 'H', $post_date, false ) : gmdate( 'H', $time_adj );
 595      $mn = ($edit) ? mysql2date( 'i', $post_date, false ) : gmdate( 'i', $time_adj );
 596      $ss = ($edit) ? mysql2date( 's', $post_date, false ) : gmdate( 's', $time_adj );
 597  
 598      $cur_jj = gmdate( 'd', $time_adj );
 599      $cur_mm = gmdate( 'm', $time_adj );
 600      $cur_aa = gmdate( 'Y', $time_adj );
 601      $cur_hh = gmdate( 'H', $time_adj );
 602      $cur_mn = gmdate( 'i', $time_adj );
 603  
 604      $month = "<select " . ( $multi ? '' : 'id="mm" ' ) . "name=\"mm\"$tab_index_attribute>\n";
 605      for ( $i = 1; $i < 13; $i = $i +1 ) {
 606          $monthnum = zeroise($i, 2);
 607          $month .= "\t\t\t" . '<option value="' . $monthnum . '"';
 608          if ( $i == $mm )
 609              $month .= ' selected="selected"';
 610          /* translators: 1: month number (01, 02, etc.), 2: month abbreviation */
 611          $month .= '>' . sprintf( __( '%1$s-%2$s' ), $monthnum, $wp_locale->get_month_abbrev( $wp_locale->get_month( $i ) ) ) . "</option>\n";
 612      }
 613      $month .= '</select>';
 614  
 615      $day = '<input type="text" ' . ( $multi ? '' : 'id="jj" ' ) . 'name="jj" value="' . $jj . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" />';
 616      $year = '<input type="text" ' . ( $multi ? '' : 'id="aa" ' ) . 'name="aa" value="' . $aa . '" size="4" maxlength="4"' . $tab_index_attribute . ' autocomplete="off" />';
 617      $hour = '<input type="text" ' . ( $multi ? '' : 'id="hh" ' ) . 'name="hh" value="' . $hh . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" />';
 618      $minute = '<input type="text" ' . ( $multi ? '' : 'id="mn" ' ) . 'name="mn" value="' . $mn . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" />';
 619  
 620      echo '<div class="timestamp-wrap">';
 621      /* translators: 1: month input, 2: day input, 3: year input, 4: hour input, 5: minute input */
 622      printf(__('%1$s%2$s, %3$s @ %4$s : %5$s'), $month, $day, $year, $hour, $minute);
 623  
 624      echo '</div><input type="hidden" id="ss" name="ss" value="' . $ss . '" />';
 625  
 626      if ( $multi ) return;
 627  
 628      echo "\n\n";
 629      foreach ( array('mm', 'jj', 'aa', 'hh', 'mn') as $timeunit ) {
 630          echo '<input type="hidden" id="hidden_' . $timeunit . '" name="hidden_' . $timeunit . '" value="' . $$timeunit . '" />' . "\n";
 631          $cur_timeunit = 'cur_' . $timeunit;
 632          echo '<input type="hidden" id="'. $cur_timeunit . '" name="'. $cur_timeunit . '" value="' . $$cur_timeunit . '" />' . "\n";
 633      }
 634  ?>
 635  
 636  <p>
 637  <a href="#edit_timestamp" class="save-timestamp hide-if-no-js button"><?php _e('OK'); ?></a>
 638  <a href="#edit_timestamp" class="cancel-timestamp hide-if-no-js"><?php _e('Cancel'); ?></a>
 639  </p>
 640  <?php
 641  }
 642  
 643  /**
 644   * {@internal Missing Short Description}}
 645   *
 646   * @since 1.5.0
 647   *
 648   * @param unknown_type $default
 649   */
 650  function page_template_dropdown( $default = '' ) {
 651      $templates = get_page_templates();
 652      ksort( $templates );
 653      foreach (array_keys( $templates ) as $template )
 654          : if ( $default == $templates[$template] )
 655              $selected = " selected='selected'";
 656          else
 657              $selected = '';
 658      echo "\n\t<option value='".$templates[$template]."' $selected>$template</option>";
 659      endforeach;
 660  }
 661  
 662  /**
 663   * {@internal Missing Short Description}}
 664   *
 665   * @since 1.5.0
 666   *
 667   * @param unknown_type $default
 668   * @param unknown_type $parent
 669   * @param unknown_type $level
 670   * @return unknown
 671   */
 672  function parent_dropdown( $default = 0, $parent = 0, $level = 0 ) {
 673      global $wpdb, $post_ID;
 674      $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) );
 675  
 676      if ( $items ) {
 677          foreach ( $items as $item ) {
 678              // A page cannot be its own parent.
 679              if (!empty ( $post_ID ) ) {
 680                  if ( $item->ID == $post_ID ) {
 681                      continue;
 682                  }
 683              }
 684              $pad = str_repeat( '&nbsp;', $level * 3 );
 685              if ( $item->ID == $default)
 686                  $current = ' selected="selected"';
 687              else
 688                  $current = '';
 689  
 690              echo "\n\t<option class='level-$level' value='$item->ID'$current>$pad " . esc_html($item->post_title) . "</option>";
 691              parent_dropdown( $default, $item->ID, $level +1 );
 692          }
 693      } else {
 694          return false;
 695      }
 696  }
 697  
 698  /**
 699   * {@internal Missing Short Description}}
 700   *
 701   * @since 2.0.0
 702   *
 703   * @param unknown_type $id
 704   * @return unknown
 705   */
 706  function the_attachment_links( $id = false ) {
 707      $id = (int) $id;
 708      $post = & get_post( $id );
 709  
 710      if ( $post->post_type != 'attachment' )
 711          return false;
 712  
 713      $icon = wp_get_attachment_image( $post->ID, 'thumbnail', true );
 714      $attachment_data = wp_get_attachment_metadata( $id );
 715      $thumb = isset( $attachment_data['thumb'] );
 716  ?>
 717  <form id="the-attachment-links">
 718  <table>
 719      <col />
 720      <col class="widefat" />
 721      <tr>
 722          <th scope="row"><?php _e( 'URL' ) ?></th>
 723          <td><textarea rows="1" cols="40" type="text" class="attachmentlinks" readonly="readonly"><?php echo esc_textarea( wp_get_attachment_url() ); ?></textarea></td>
 724      </tr>
 725  <?php if ( $icon ) : ?>
 726      <tr>
 727          <th scope="row"><?php $thumb ? _e( 'Thumbnail linked to file' ) : _e( 'Image linked to file' ); ?></th>
 728          <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>
 729      </tr>
 730      <tr>
 731          <th scope="row"><?php $thumb ? _e( 'Thumbnail linked to page' ) : _e( 'Image linked to page' ); ?></th>
 732          <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>
 733      </tr>
 734  <?php else : ?>
 735      <tr>
 736          <th scope="row"><?php _e( 'Link to file' ) ?></th>
 737          <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>
 738      </tr>
 739      <tr>
 740          <th scope="row"><?php _e( 'Link to page' ) ?></th>
 741          <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>
 742      </tr>
 743  <?php endif; ?>
 744  </table>
 745  </form>
 746  <?php
 747  }
 748  
 749  /**
 750   * Print out <option> html elements for role selectors
 751   *
 752   * @since 2.1.0
 753   *
 754   * @param string $selected slug for the role that should be already selected
 755   */
 756  function wp_dropdown_roles( $selected = false ) {
 757      $p = '';
 758      $r = '';
 759  
 760      $editable_roles = get_editable_roles();
 761  
 762      foreach ( $editable_roles as $role => $details ) {
 763          $name = translate_user_role($details['name'] );
 764          if ( $selected == $role ) // preselect specified role
 765              $p = "\n\t<option selected='selected' value='" . esc_attr($role) . "'>$name</option>";
 766          else
 767              $r .= "\n\t<option value='" . esc_attr($role) . "'>$name</option>";
 768      }
 769      echo $p . $r;
 770  }
 771  
 772  /**
 773   * {@internal Missing Short Description}}
 774   *
 775   * @since 2.3.0
 776   *
 777   * @param unknown_type $size
 778   * @return unknown
 779   */
 780  function wp_convert_hr_to_bytes( $size ) {
 781      $size = strtolower($size);
 782      $bytes = (int) $size;
 783      if ( strpos($size, 'k') !== false )
 784          $bytes = intval($size) * 1024;
 785      elseif ( strpos($size, 'm') !== false )
 786          $bytes = intval($size) * 1024 * 1024;
 787      elseif ( strpos($size, 'g') !== false )
 788          $bytes = intval($size) * 1024 * 1024 * 1024;
 789      return $bytes;
 790  }
 791  
 792  /**
 793   * {@internal Missing Short Description}}
 794   *
 795   * @since 2.3.0
 796   *
 797   * @param unknown_type $bytes
 798   * @return unknown
 799   */
 800  function wp_convert_bytes_to_hr( $bytes ) {
 801      $units = array( 0 => 'B', 1 => 'kB', 2 => 'MB', 3 => 'GB' );
 802      $log = log( $bytes, 1024 );
 803      $power = (int) $log;
 804      $size = pow(1024, $log - $power);
 805      return $size . $units[$power];
 806  }
 807  
 808  /**
 809   * {@internal Missing Short Description}}
 810   *
 811   * @since 2.5.0
 812   *
 813   * @return unknown
 814   */
 815  function wp_max_upload_size() {
 816      $u_bytes = wp_convert_hr_to_bytes( ini_get( 'upload_max_filesize' ) );
 817      $p_bytes = wp_convert_hr_to_bytes( ini_get( 'post_max_size' ) );
 818      $bytes = apply_filters( 'upload_size_limit', min($u_bytes, $p_bytes), $u_bytes, $p_bytes );
 819      return $bytes;
 820  }
 821  
 822  /**
 823   * Outputs the form used by the importers to accept the data to be imported
 824   *
 825   * @since 2.0.0
 826   *
 827   * @param string $action The action attribute for the form.
 828   */
 829  function wp_import_upload_form( $action ) {
 830      $bytes = apply_filters( 'import_upload_size_limit', wp_max_upload_size() );
 831      $size = wp_convert_bytes_to_hr( $bytes );
 832      $upload_dir = wp_upload_dir();
 833      if ( ! empty( $upload_dir['error'] ) ) :
 834          ?><div class="error"><p><?php _e('Before you can upload your import file, you will need to fix the following error:'); ?></p>
 835          <p><strong><?php echo $upload_dir['error']; ?></strong></p></div><?php
 836      else :
 837  ?>
 838  <form enctype="multipart/form-data" id="import-upload-form" method="post" action="<?php echo esc_attr(wp_nonce_url($action, 'import-upload')); ?>">
 839  <p>
 840  <label for="upload"><?php _e( 'Choose a file from your computer:' ); ?></label> (<?php printf( __('Maximum size: %s' ), $size ); ?>)
 841  <input type="file" id="upload" name="import" size="25" />
 842  <input type="hidden" name="action" value="save" />
 843  <input type="hidden" name="max_file_size" value="<?php echo $bytes; ?>" />
 844  </p>
 845  <?php submit_button( __('Upload file and import'), 'button' ); ?>
 846  </form>
 847  <?php
 848      endif;
 849  }
 850  
 851  /**
 852   * Add a meta box to an edit form.
 853   *
 854   * @since 2.5.0
 855   *
 856   * @param string $id String for use in the 'id' attribute of tags.
 857   * @param string $title Title of the meta box.
 858   * @param string $callback Function that fills the box with the desired content. The function should echo its output.
 859   * @param string|object $screen Optional. The screen on which to show the box (post, page, link). Defaults to current screen.
 860   * @param string $context Optional. The context within the page where the boxes should show ('normal', 'advanced').
 861   * @param string $priority Optional. The priority within the context where the boxes should show ('high', 'low').
 862   */
 863  function add_meta_box( $id, $title, $callback, $screen = null, $context = 'advanced', $priority = 'default', $callback_args = null ) {
 864      global $wp_meta_boxes;
 865  
 866      if ( empty( $screen ) )
 867          $screen = get_current_screen();
 868      elseif ( is_string( $screen ) )
 869          $screen = convert_to_screen( $screen );
 870  
 871      $page = $screen->id;
 872  
 873      if ( !isset($wp_meta_boxes) )
 874          $wp_meta_boxes = array();
 875      if ( !isset($wp_meta_boxes[$page]) )
 876          $wp_meta_boxes[$page] = array();
 877      if ( !isset($wp_meta_boxes[$page][$context]) )
 878          $wp_meta_boxes[$page][$context] = array();
 879  
 880      foreach ( array_keys($wp_meta_boxes[$page]) as $a_context ) {
 881          foreach ( array('high', 'core', 'default', 'low') as $a_priority ) {
 882              if ( !isset($wp_meta_boxes[$page][$a_context][$a_priority][$id]) )
 883                  continue;
 884  
 885              // If a core box was previously added or removed by a plugin, don't add.
 886              if ( 'core' == $priority ) {
 887                  // If core box previously deleted, don't add
 888                  if ( false === $wp_meta_boxes[$page][$a_context][$a_priority][$id] )
 889                      return;
 890                  // If box was added with default priority, give it core priority to maintain sort order
 891                  if ( 'default' == $a_priority ) {
 892                      $wp_meta_boxes[$page][$a_context]['core'][$id] = $wp_meta_boxes[$page][$a_context]['default'][$id];
 893                      unset($wp_meta_boxes[$page][$a_context]['default'][$id]);
 894                  }
 895                  return;
 896              }
 897              // If no priority given and id already present, use existing priority
 898              if ( empty($priority) ) {
 899                  $priority = $a_priority;
 900              // 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.
 901              } elseif ( 'sorted' == $priority ) {
 902                  $title = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['title'];
 903                  $callback = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['callback'];
 904                  $callback_args = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['args'];
 905              }
 906              // An id can be in only one priority and one context
 907              if ( $priority != $a_priority || $context != $a_context )
 908                  unset($wp_meta_boxes[$page][$a_context][$a_priority][$id]);
 909          }
 910      }
 911  
 912      if ( empty($priority) )
 913          $priority = 'low';
 914  
 915      if ( !isset($wp_meta_boxes[$page][$context][$priority]) )
 916          $wp_meta_boxes[$page][$context][$priority] = array();
 917  
 918      $wp_meta_boxes[$page][$context][$priority][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback, 'args' => $callback_args);
 919  }
 920  
 921  /**
 922   * Meta-Box template function
 923   *
 924   * @since 2.5.0
 925   *
 926   * @param string|object $screen Screen identifier
 927   * @param string $context box context
 928   * @param mixed $object gets passed to the box callback function as first parameter
 929   * @return int number of meta_boxes
 930   */
 931  function do_meta_boxes( $screen, $context, $object ) {
 932      global $wp_meta_boxes;
 933      static $already_sorted = false;
 934  
 935      if ( empty( $screen ) )
 936          $screen = get_current_screen();
 937      elseif ( is_string( $screen ) )
 938          $screen = convert_to_screen( $screen );
 939  
 940      $page = $screen->id;
 941  
 942      $hidden = get_hidden_meta_boxes( $screen );
 943  
 944      printf('<div id="%s-sortables" class="meta-box-sortables">', htmlspecialchars($context));
 945  
 946      $i = 0;
 947      do {
 948          // Grab the ones the user has manually sorted. Pull them out of their previous context/priority and into the one the user chose
 949          if ( !$already_sorted && $sorted = get_user_option( "meta-box-order_$page" ) ) {
 950              foreach ( $sorted as $box_context => $ids ) {
 951                  foreach ( explode(',', $ids ) as $id ) {
 952                      if ( $id && 'dashboard_browser_nag' !== $id )
 953                          add_meta_box( $id, null, null, $screen, $box_context, 'sorted' );
 954                  }
 955              }
 956          }
 957          $already_sorted = true;
 958  
 959          if ( !isset($wp_meta_boxes) || !isset($wp_meta_boxes[$page]) || !isset($wp_meta_boxes[$page][$context]) )
 960              break;
 961  
 962          foreach ( array('high', 'sorted', 'core', 'default', 'low') as $priority ) {
 963              if ( isset($wp_meta_boxes[$page][$context][$priority]) ) {
 964                  foreach ( (array) $wp_meta_boxes[$page][$context][$priority] as $box ) {
 965                      if ( false == $box || ! $box['title'] )
 966                          continue;
 967                      $i++;
 968                      $style = '';
 969                      $hidden_class = in_array($box['id'], $hidden) ? ' hide-if-js' : '';
 970                      echo '<div id="' . $box['id'] . '" class="postbox ' . postbox_classes($box['id'], $page) . $hidden_class . '" ' . '>' . "\n";
 971                      if ( 'dashboard_browser_nag' != $box['id'] )
 972                          echo '<div class="handlediv" title="' . esc_attr__('Click to toggle') . '"><br /></div>';
 973                      echo "<h3 class='hndle'><span>{$box['title']}</span></h3>\n";
 974                      echo '<div class="inside">' . "\n";
 975                      call_user_func($box['callback'], $object, $box);
 976                      echo "</div>\n";
 977                      echo "</div>\n";
 978                  }
 979              }
 980          }
 981      } while(0);
 982  
 983      echo "</div>";
 984  
 985      return $i;
 986  
 987  }
 988  
 989  /**
 990   * Remove a meta box from an edit form.
 991   *
 992   * @since 2.6.0
 993   *
 994   * @param string $id String for use in the 'id' attribute of tags.
 995   * @param string|object $screen The screen on which to show the box (post, page, link).
 996   * @param string $context The context within the page where the boxes should show ('normal', 'advanced').
 997   */
 998  function remove_meta_box($id, $screen, $context) {
 999      global $wp_meta_boxes;
1000  
1001      if ( empty( $screen ) )
1002          $screen = get_current_screen();
1003      elseif ( is_string( $screen ) )
1004          $screen = convert_to_screen( $screen );
1005  
1006      $page = $screen->id;
1007  
1008      if ( !isset($wp_meta_boxes) )
1009          $wp_meta_boxes = array();
1010      if ( !isset($wp_meta_boxes[$page]) )
1011          $wp_meta_boxes[$page] = array();
1012      if ( !isset($wp_meta_boxes[$page][$context]) )
1013          $wp_meta_boxes[$page][$context] = array();
1014  
1015      foreach ( array('high', 'core', 'default', 'low') as $priority )
1016          $wp_meta_boxes[$page][$context][$priority][$id] = false;
1017  }
1018  
1019  /**
1020   * Add a new section to a settings page.
1021   *
1022   * Part of the Settings API. Use this to define new settings sections for an admin page.
1023   * Show settings sections in your admin page callback function with do_settings_sections().
1024   * Add settings fields to your section with add_settings_field()
1025   *
1026   * The $callback argument should be the name of a function that echoes out any
1027   * content you want to show at the top of the settings section before the actual
1028   * fields. It can output nothing if you want.
1029   *
1030   * @since 2.7.0
1031   *
1032   * @global $wp_settings_sections Storage array of all settings sections added to admin pages
1033   *
1034   * @param string $id Slug-name to identify the section. Used in the 'id' attribute of tags.
1035   * @param string $title Formatted title of the section. Shown as the heading for the section.
1036   * @param string $callback Function that echos out any content at the top of the section (between heading and fields).
1037   * @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();
1038   */
1039  function add_settings_section($id, $title, $callback, $page) {
1040      global $wp_settings_sections;
1041  
1042      if ( 'misc' == $page ) {
1043          _deprecated_argument( __FUNCTION__, '3.0', __( 'The miscellaneous options group has been removed. Use another settings group.' ) );
1044          $page = 'general';
1045      }
1046  
1047      if ( !isset($wp_settings_sections) )
1048          $wp_settings_sections = array();
1049      if ( !isset($wp_settings_sections[$page]) )
1050          $wp_settings_sections[$page] = array();
1051      if ( !isset($wp_settings_sections[$page][$id]) )
1052          $wp_settings_sections[$page][$id] = array();
1053  
1054      $wp_settings_sections[$page][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback);
1055  }
1056  
1057  /**
1058   * Add a new field to a section of a settings page
1059   *
1060   * Part of the Settings API. Use this to define a settings field that will show
1061   * as part of a settings section inside a settings page. The fields are shown using
1062   * do_settings_fields() in do_settings-sections()
1063   *
1064   * The $callback argument should be the name of a function that echoes out the
1065   * html input tags for this setting field. Use get_option() to retrieve existing
1066   * values to show.
1067   *
1068   * @since 2.7.0
1069   *
1070   * @global $wp_settings_fields Storage array of settings fields and info about their pages/sections
1071   *
1072   * @param string $id Slug-name to identify the field. Used in the 'id' attribute of tags.
1073   * @param string $title Formatted title of the field. Shown as the label for the field during output.
1074   * @param string $callback Function that fills the field with the desired form inputs. The function should echo its output.
1075   * @param string $page The slug-name of the settings page on which to show the section (general, reading, writing, ...).
1076   * @param string $section The slug-name of the section of the settings page in which to show the box (default, ...).
1077   * @param array $args Additional arguments
1078   */
1079  function add_settings_field($id, $title, $callback, $page, $section = 'default', $args = array()) {
1080      global $wp_settings_fields;
1081  
1082      if ( 'misc' == $page ) {
1083          _deprecated_argument( __FUNCTION__, '3.0', __( 'The miscellaneous options group has been removed. Use another settings group.' ) );
1084          $page = 'general';
1085      }
1086  
1087      if ( !isset($wp_settings_fields) )
1088          $wp_settings_fields = array();
1089      if ( !isset($wp_settings_fields[$page]) )
1090          $wp_settings_fields[$page] = array();
1091      if ( !isset($wp_settings_fields[$page][$section]) )
1092          $wp_settings_fields[$page][$section] = array();
1093  
1094      $wp_settings_fields[$page][$section][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback, 'args' => $args);
1095  }
1096  
1097  /**
1098   * Prints out all settings sections added to a particular settings page
1099   *
1100   * Part of the Settings API. Use this in a settings page callback function
1101   * to output all the sections and fields that were added to that $page with
1102   * add_settings_section() and add_settings_field()
1103   *
1104   * @global $wp_settings_sections Storage array of all settings sections added to admin pages
1105   * @global $wp_settings_fields Storage array of settings fields and info about their pages/sections
1106   * @since 2.7.0
1107   *
1108   * @param string $page The slug name of the page whos settings sections you want to output
1109   */
1110  function do_settings_sections($page) {
1111      global $wp_settings_sections, $wp_settings_fields;
1112  
1113      if ( !isset($wp_settings_sections) || !isset($wp_settings_sections[$page]) )
1114          return;
1115  
1116      foreach ( (array) $wp_settings_sections[$page] as $section ) {
1117          if ( $section['title'] )
1118              echo "<h3>{$section['title']}</h3>\n";
1119          call_user_func($section['callback'], $section);
1120          if ( !isset($wp_settings_fields) || !isset($wp_settings_fields[$page]) || !isset($wp_settings_fields[$page][$section['id']]) )
1121              continue;
1122          echo '<table class="form-table">';
1123          do_settings_fields($page, $section['id']);
1124          echo '</table>';
1125      }
1126  }
1127  
1128  /**
1129   * Print out the settings fields for a particular settings section
1130   *
1131   * Part of the Settings API. Use this in a settings page to output
1132   * a specific section. Should normally be called by do_settings_sections()
1133   * rather than directly.
1134   *
1135   * @global $wp_settings_fields Storage array of settings fields and their pages/sections
1136   *
1137   * @since 2.7.0
1138   *
1139   * @param string $page Slug title of the admin page who's settings fields you want to show.
1140   * @param section $section Slug title of the settings section who's fields you want to show.
1141   */
1142  function do_settings_fields($page, $section) {
1143      global $wp_settings_fields;
1144  
1145      if ( !isset($wp_settings_fields) || !isset($wp_settings_fields[$page]) || !isset($wp_settings_fields[$page][$section]) )
1146          return;
1147  
1148      foreach ( (array) $wp_settings_fields[$page][$section] as $field ) {
1149          echo '<tr valign="top">';
1150          if ( !empty($field['args']['label_for']) )
1151              echo '<th scope="row"><label for="' . $field['args']['label_for'] . '">' . $field['title'] . '</label></th>';
1152          else
1153              echo '<th scope="row">' . $field['title'] . '</th>';
1154          echo '<td>';
1155          call_user_func($field['callback'], $field['args']);
1156          echo '</td>';
1157          echo '</tr>';
1158      }
1159  }
1160  
1161  /**
1162   * Register a settings error to be displayed to the user
1163   *
1164   * Part of the Settings API. Use this to show messages to users about settings validation
1165   * problems, missing settings or anything else.
1166   *
1167   * Settings errors should be added inside the $sanitize_callback function defined in
1168   * register_setting() for a given setting to give feedback about the submission.
1169   *
1170   * By default messages will show immediately after the submission that generated the error.
1171   * Additional calls to settings_errors() can be used to show errors even when the settings
1172   * page is first accessed.
1173   *
1174   * @since 3.0.0
1175   *
1176   * @global array $wp_settings_errors Storage array of errors registered during this pageload
1177   *
1178   * @param string $setting Slug title of the setting to which this error applies
1179   * @param string $code Slug-name to identify the error. Used as part of 'id' attribute in HTML output.
1180   * @param string $message The formatted message text to display to the user (will be shown inside styled <div> and <p>)
1181   * @param string $type The type of message it is, controls HTML class. Use 'error' or 'updated'.
1182   */
1183  function add_settings_error( $setting, $code, $message, $type = 'error' ) {
1184      global $wp_settings_errors;
1185  
1186      if ( !isset($wp_settings_errors) )
1187          $wp_settings_errors = array();
1188  
1189      $new_error = array(
1190          'setting' => $setting,
1191          'code' => $code,
1192          'message' => $message,
1193          'type' => $type
1194      );
1195      $wp_settings_errors[] = $new_error;
1196  }
1197  
1198  /**
1199   * Fetch settings errors registered by add_settings_error()
1200   *
1201   * Checks the $wp_settings_errors array for any errors declared during the current
1202   * pageload and returns them.
1203   *
1204   * If changes were just submitted ($_GET['settings-updated']) and settings errors were saved
1205   * to the 'settings_errors' transient then those errors will be returned instead. This
1206   * is used to pass errors back across pageloads.
1207   *
1208   * Use the $sanitize argument to manually re-sanitize the option before returning errors.
1209   * This is useful if you have errors or notices you want to show even when the user
1210   * hasn't submitted data (i.e. when they first load an options page, or in admin_notices action hook)
1211   *
1212   * @since 3.0.0
1213   *
1214   * @global array $wp_settings_errors Storage array of errors registered during this pageload
1215   *
1216   * @param string $setting Optional slug title of a specific setting who's errors you want.
1217   * @param boolean $sanitize Whether to re-sanitize the setting value before returning errors.
1218   * @return array Array of settings errors
1219   */
1220  function get_settings_errors( $setting = '', $sanitize = false ) {
1221      global $wp_settings_errors;
1222  
1223      // If $sanitize is true, manually re-run the sanitizisation for this option
1224      // This allows the $sanitize_callback from register_setting() to run, adding
1225      // any settings errors you want to show by default.
1226      if ( $sanitize )
1227          sanitize_option( $setting, get_option($setting));
1228  
1229      // If settings were passed back from options.php then use them
1230      // Ignore transients if $sanitize is true, we don't want the old values anyway
1231      if ( isset($_GET['settings-updated']) && $_GET['settings-updated'] && get_transient('settings_errors') ) {
1232          $settings_errors = get_transient('settings_errors');
1233          delete_transient('settings_errors');
1234      // Otherwise check global in case validation has been run on this pageload
1235      } elseif ( count( $wp_settings_errors ) ) {
1236          $settings_errors = $wp_settings_errors;
1237      } else {
1238          return;
1239      }
1240  
1241      // Filter the results to those of a specific setting if one was set
1242      if ( $setting ) {
1243          foreach ( (array) $settings_errors as $key => $details )
1244              if ( $setting != $details['setting'] )
1245                  unset( $settings_errors[$key] );
1246      }
1247      return $settings_errors;
1248  }
1249  
1250  /**
1251   * Display settings errors registered by add_settings_error()
1252   *
1253   * Part of the Settings API. Outputs a <div> for each error retrieved by get_settings_errors().
1254   *
1255   * This is called automatically after a settings page based on the Settings API is submitted.
1256   * Errors should be added during the validation callback function for a setting defined in register_setting()
1257   *
1258   * The $sanitize option is passed into get_settings_errors() and will re-run the setting sanitization
1259   * on its current value.
1260   *
1261   * The $hide_on_update option will cause errors to only show when the settings page is first loaded.
1262   * if the user has already saved new values it will be hidden to avoid repeating messages already
1263   * shown in the default error reporting after submission. This is useful to show general errors like missing
1264   * settings when the user arrives at the settings page.
1265   *
1266   * @since 3.0.0
1267   *
1268   * @param string $setting Optional slug title of a specific setting who's errors you want.
1269   * @param boolean $sanitize Whether to re-sanitize the setting value before returning errors.
1270   * @param boolean $hide_on_update If set to true errors will not be shown if the settings page has already been submitted.
1271   */
1272  function settings_errors( $setting = '', $sanitize = false, $hide_on_update = false ) {
1273  
1274      if ( $hide_on_update && ! empty( $_GET['settings-updated'] ) )
1275          return;
1276  
1277      $settings_errors = get_settings_errors( $setting, $sanitize );
1278  
1279      if ( ! is_array( $settings_errors ) )
1280          return;
1281  
1282      $output = '';
1283      foreach ( $settings_errors as $key => $details ) {
1284          $css_id = 'setting-error-' . $details['code'];
1285          $css_class = $details['type'] . ' settings-error';
1286          $output .= "<div id='$css_id' class='$css_class'> \n";
1287          $output .= "<p><strong>{$details['message']}</strong></p>";
1288          $output .= "</div> \n";
1289      }
1290      echo $output;
1291  }
1292  
1293  /**
1294   * {@internal Missing Short Description}}
1295   *
1296   * @since 2.7.0
1297   *
1298   * @param unknown_type $found_action
1299   */
1300  function find_posts_div($found_action = '') {
1301  ?>
1302      <div id="find-posts" class="find-box" style="display:none;">
1303          <div id="find-posts-head" class="find-box-head"><?php _e('Find Posts or Pages'); ?></div>
1304          <div class="find-box-inside">
1305              <div class="find-box-search">
1306                  <?php if ( $found_action ) { ?>
1307                      <input type="hidden" name="found_action" value="<?php echo esc_attr($found_action); ?>" />
1308                  <?php } ?>
1309  
1310                  <input type="hidden" name="affected" id="affected" value="" />
1311                  <?php wp_nonce_field( 'find-posts', '_ajax_nonce', false ); ?>
1312                  <label class="screen-reader-text" for="find-posts-input"><?php _e( 'Search' ); ?></label>
1313                  <input type="text" id="find-posts-input" name="ps" value="" />
1314                  <input type="button" id="find-posts-search" value="<?php esc_attr_e( 'Search' ); ?>" class="button" /><br />
1315  
1316                  <?php
1317                  $post_types = get_post_types( array('public' => true), 'objects' );
1318                  foreach ( $post_types as $post ) {
1319                      if ( 'attachment' == $post->name )
1320                          continue;
1321                  ?>
1322                  <input type="radio" name="find-posts-what" id="find-posts-<?php echo esc_attr($post->name); ?>" value="<?php echo esc_attr($post->name); ?>" <?php checked($post->name, 'post'); ?> />
1323                  <label for="find-posts-<?php echo esc_attr($post->name); ?>"><?php echo $post->label; ?></label>
1324                  <?php
1325                  } ?>
1326              </div>
1327              <div id="find-posts-response"></div>
1328          </div>
1329          <div class="find-box-buttons">
1330              <input id="find-posts-close" type="button" class="button alignleft" value="<?php esc_attr_e('Close'); ?>" />
1331              <?php submit_button( __( 'Select' ), 'button-primary alignright', 'find-posts-submit', false ); ?>
1332          </div>
1333      </div>
1334  <?php
1335  }
1336  
1337  /**
1338   * Display the post password.
1339   *
1340   * The password is passed through {@link esc_attr()} to ensure that it
1341   * is safe for placing in an html attribute.
1342   *
1343   * @uses attr
1344   * @since 2.7.0
1345   */
1346  function the_post_password() {
1347      global $post;
1348      if ( isset( $post->post_password ) ) echo esc_attr( $post->post_password );
1349  }
1350  
1351  /**
1352   * Get the post title.
1353   *
1354   * The post title is fetched and if it is blank then a default string is
1355   * returned.
1356   *
1357   * @since 2.7.0
1358   * @param int $post_id The post id. If not supplied the global $post is used.
1359   * @return string The post title if set
1360   */
1361  function _draft_or_post_title( $post_id = 0 ) {
1362      $title = get_the_title($post_id);
1363      if ( empty($title) )
1364          $title = __('(no title)');
1365      return $title;
1366  }
1367  
1368  /**
1369   * Display the search query.
1370   *
1371   * A simple wrapper to display the "s" parameter in a GET URI. This function
1372   * should only be used when {@link the_search_query()} cannot.
1373   *
1374   * @uses attr
1375   * @since 2.7.0
1376   *
1377   */
1378  function _admin_search_query() {
1379      echo isset($_REQUEST['s']) ? esc_attr( stripslashes( $_REQUEST['s'] ) ) : '';
1380  }
1381  
1382  /**
1383   * Generic Iframe header for use with Thickbox
1384   *
1385   * @since 2.7.0
1386   * @param string $title Title of the Iframe page.
1387   * @param bool $limit_styles Limit styles to colour-related styles only (unless others are enqueued).
1388   *
1389   */
1390  function iframe_header( $title = '', $limit_styles = false ) {
1391      show_admin_bar( false );
1392      global $hook_suffix, $current_user, $admin_body_class, $wp_locale;
1393      $admin_body_class = preg_replace('/[^a-z0-9_-]+/i', '-', $hook_suffix);
1394  
1395      $current_screen = get_current_screen();
1396  
1397      _wp_admin_html_begin();
1398  ?>
1399  <title><?php bloginfo('name') ?> &rsaquo; <?php echo $title ?> &#8212; <?php _e('WordPress'); ?></title>
1400  <?php
1401  wp_enqueue_style( 'colors' );
1402  ?>
1403  <script type="text/javascript">
1404  //<![CDATA[
1405  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();}}};
1406  function tb_close(){var win=window.dialogArguments||opener||parent||top;win.tb_remove();}
1407  var userSettings = {
1408          'url': '<?php echo SITECOOKIEPATH; ?>',
1409          'uid': '<?php if ( ! isset($current_user) ) $current_user = wp_get_current_user(); echo $current_user->ID; ?>',
1410          'time':'<?php echo time() ?>'
1411      },
1412      ajaxurl = '<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>',
1413      pagenow = '<?php echo $current_screen->id; ?>',
1414      typenow = '<?php echo $current_screen->post_type; ?>',
1415      adminpage = '<?php echo $admin_body_class; ?>',
1416      thousandsSeparator = '<?php echo addslashes( $wp_locale->number_format['thousands_sep'] ); ?>',
1417      decimalPoint = '<?php echo addslashes( $wp_locale->number_format['decimal_point'] ); ?>',
1418      isRtl = <?php echo (int) is_rtl(); ?>;
1419  //]]>
1420  </script>
1421  <?php
1422  do_action('admin_enqueue_scripts', $hook_suffix);
1423  do_action("admin_print_styles-$hook_suffix");
1424  do_action('admin_print_styles');
1425  do_action("admin_print_scripts-$hook_suffix");
1426  do_action('admin_print_scripts');
1427  do_action("admin_head-$hook_suffix");
1428  do_action('admin_head');
1429  
1430  $admin_body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
1431  ?>
1432  </head>
1433  <body<?php if ( isset($GLOBALS['body_id']) ) echo ' id="' . $GLOBALS['body_id'] . '"'; ?> class="wp-admin no-js iframe <?php echo apply_filters( 'admin_body_class', '' ) . ' ' . $admin_body_class; ?>">
1434  <script type="text/javascript">
1435  //<![CDATA[
1436  (function(){
1437  var c = document.body.className;
1438  c = c.replace(/no-js/, 'js');
1439  document.body.className = c;
1440  })();
1441  //]]>
1442  </script>
1443  <?php
1444  }
1445  
1446  /**
1447   * Generic Iframe footer for use with Thickbox
1448   *
1449   * @since 2.7.0
1450   *
1451   */
1452  function iframe_footer() {
1453      //We're going to hide any footer output on iframe pages, but run the hooks anyway since they output Javascript or other needed content. ?>
1454      <div class="hidden">
1455  <?php
1456      do_action('admin_footer', '');
1457      do_action('admin_print_footer_scripts'); ?>
1458      </div>
1459  <script type="text/javascript">if(typeof wpOnload=="function")wpOnload();</script>
1460  </body>
1461  </html>
1462  <?php
1463  }
1464  
1465  function _post_states($post) {
1466      $post_states = array();
1467      if ( isset( $_REQUEST['post_status'] ) )
1468          $post_status = $_REQUEST['post_status'];
1469      else
1470          $post_status = '';
1471  
1472      if ( !empty($post->post_password) )
1473          $post_states['protected'] = __('Password protected');
1474      if ( 'private' == $post->post_status && 'private' != $post_status )
1475          $post_states['private'] = __('Private');
1476      if ( 'draft' == $post->post_status && 'draft' != $post_status )
1477          $post_states['draft'] = __('Draft');
1478      if ( 'pending' == $post->post_status && 'pending' != $post_status )
1479          /* translators: post state */
1480          $post_states['pending'] = _x('Pending', 'post state');
1481      if ( is_sticky($post->ID) )
1482          $post_states['sticky'] = __('Sticky');
1483  
1484      $post_states = apply_filters( 'display_post_states', $post_states );
1485  
1486      if ( ! empty($post_states) ) {
1487          $state_count = count($post_states);
1488          $i = 0;
1489          echo ' - ';
1490          foreach ( $post_states as $state ) {
1491              ++$i;
1492              ( $i == $state_count ) ? $sep = '' : $sep = ', ';
1493              echo "<span class='post-state'>$state$sep</span>";
1494          }
1495      }
1496  
1497      if ( get_post_format( $post->ID ) )
1498          echo ' - <span class="post-state-format">' . get_post_format_string( get_post_format( $post->ID ) ) . '</span>';
1499  }
1500  
1501  function _media_states( $post ) {
1502      $media_states = array();
1503      $stylesheet = get_option('stylesheet');
1504  
1505      if ( current_theme_supports( 'custom-header') ) {
1506          $meta_header = get_post_meta($post->ID, '_wp_attachment_is_custom_header', true );
1507          if ( ! empty( $meta_header ) && $meta_header == $stylesheet )
1508              $media_states[] = __( 'Header Image' );
1509      }
1510  
1511      if ( current_theme_supports( 'custom-background') ) {
1512          $meta_background = get_post_meta($post->ID, '_wp_attachment_is_custom_background', true );
1513          if ( ! empty( $meta_background ) && $meta_background == $stylesheet )
1514              $media_states[] = __( 'Background Image' );
1515      }
1516  
1517      $media_states = apply_filters( 'display_media_states', $media_states );
1518  
1519      if ( ! empty( $media_states ) ) {
1520          $state_count = count( $media_states );
1521          $i = 0;
1522          echo ' - ';
1523          foreach ( $media_states as $state ) {
1524              ++$i;
1525              ( $i == $state_count ) ? $sep = '' : $sep = ', ';
1526              echo "<span class='post-state'>$state$sep</span>";
1527          }
1528      }
1529  }
1530  
1531  /**
1532   * Test support for compressing JavaScript from PHP
1533   *
1534   * Outputs JavaScript that tests if compression from PHP works as expected
1535   * and sets an option with the result. Has no effect when the current user
1536   * is not an administrator. To run the test again the option 'can_compress_scripts'
1537   * has to be deleted.
1538   *
1539   * @since 2.8.0
1540   */
1541  function compression_test() {
1542  ?>
1543      <script type="text/javascript">
1544      /* <![CDATA[ */
1545      var testCompression = {
1546          get : function(test) {
1547              var x;
1548              if ( window.XMLHttpRequest ) {
1549                  x = new XMLHttpRequest();
1550              } else {
1551                  try{x=new ActiveXObject('Msxml2.XMLHTTP');}catch(e){try{x=new ActiveXObject('Microsoft.XMLHTTP');}catch(e){};}
1552              }
1553  
1554              if (x) {
1555                  x.onreadystatechange = function() {
1556                      var r, h;
1557                      if ( x.readyState == 4 ) {
1558                          r = x.responseText.substr(0, 18);
1559                          h = x.getResponseHeader('Content-Encoding');
1560                          testCompression.check(r, h, test);
1561                      }
1562                  }
1563  
1564                  x.open('GET', ajaxurl + '?action=wp-compression-test&test='+test+'&'+(new Date()).getTime(), true);
1565                  x.send('');
1566              }
1567          },
1568  
1569          check : function(r, h, test) {
1570              if ( ! r && ! test )
1571                  this.get(1);
1572  
1573              if ( 1 == test ) {
1574                  if ( h && ( h.match(/deflate/i) || h.match(/gzip/i) ) )
1575                      this.get('no');
1576                  else
1577                      this.get(2);
1578  
1579                  return;
1580              }
1581  
1582              if ( 2 == test ) {
1583                  if ( '"wpCompressionTest' == r )
1584                      this.get('yes');
1585                  else
1586                      this.get('no');
1587              }
1588          }
1589      };
1590      testCompression.check();
1591      /* ]]> */
1592      </script>
1593  <?php
1594  }
1595  
1596  /**
1597   * Echos a submit button, with provided text and appropriate class
1598   *
1599   * @since 3.1.0
1600   *
1601   * @param string $text The text of the button (defaults to 'Save Changes')
1602   * @param string $type The type of button. One of: primary, secondary, delete
1603   * @param string $name The HTML name of the submit button. Defaults to "submit". If no id attribute
1604   *               is given in $other_attributes below, $name will be used as the button's id.
1605   * @param bool $wrap True if the output button should be wrapped in a paragraph tag,
1606   *                false otherwise. Defaults to true
1607   * @param array|string $other_attributes Other attributes that should be output with the button,
1608   *                     mapping attributes to their values, such as array( 'tabindex' => '1' ).
1609   *                     These attributes will be output as attribute="value", such as tabindex="1".
1610   *                     Defaults to no other attributes. Other attributes can also be provided as a
1611   *                     string such as 'tabindex="1"', though the array format is typically cleaner.
1612   */
1613  function submit_button( $text = null, $type = 'primary', $name = 'submit', $wrap = true, $other_attributes = null ) {
1614      echo get_submit_button( $text, $type, $name, $wrap, $other_attributes );
1615  }
1616  
1617  /**
1618   * Returns a submit button, with provided text and appropriate class
1619   *
1620   * @since 3.1.0
1621   *
1622   * @param string $text The text of the button (defaults to 'Save Changes')
1623   * @param string $type The type of button. One of: primary, secondary, delete
1624   * @param string $name The HTML name of the submit button. Defaults to "submit". If no id attribute
1625   *               is given in $other_attributes below, $name will be used as the button's id.
1626   * @param bool $wrap True if the output button should be wrapped in a paragraph tag,
1627   *                false otherwise. Defaults to true
1628   * @param array|string $other_attributes Other attributes that should be output with the button,
1629   *                     mapping attributes to their values, such as array( 'tabindex' => '1' ).
1630   *                     These attributes will be output as attribute="value", such as tabindex="1".
1631   *                     Defaults to no other attributes. Other attributes can also be provided as a
1632   *                     string such as 'tabindex="1"', though the array format is typically cleaner.
1633   */
1634  function get_submit_button( $text = null, $type = 'primary', $name = 'submit', $wrap = true, $other_attributes = null ) {
1635      switch ( $type ) :
1636          case 'primary' :
1637          case 'secondary' :
1638              $class = 'button-' . $type;
1639              break;
1640          case 'delete' :
1641              $class = 'button-secondary delete';
1642              break;
1643          default :
1644              $class = $type; // Custom cases can just pass in the classes they want to be used
1645      endswitch;
1646      $text = ( null == $text ) ? __( 'Save Changes' ) : $text;
1647  
1648      // Default the id attribute to $name unless an id was specifically provided in $other_attributes
1649      $id = $name;
1650      if ( is_array( $other_attributes ) && isset( $other_attributes['id'] ) ) {
1651          $id = $other_attributes['id'];
1652          unset( $other_attributes['id'] );
1653      }
1654  
1655      $attributes = '';
1656      if ( is_array( $other_attributes ) ) {
1657          foreach ( $other_attributes as $attribute => $value ) {
1658              $attributes .= $attribute . '="' . esc_attr( $value ) . '" '; // Trailing space is important
1659          }
1660      } else if ( !empty( $other_attributes ) ) { // Attributes provided as a string
1661          $attributes = $other_attributes;
1662      }
1663  
1664      $button = '<input type="submit" name="' . esc_attr( $name ) . '" id="' . esc_attr( $id ) . '" class="' . esc_attr( $class );
1665      $button    .= '" value="' . esc_attr( $text ) . '" ' . $attributes . ' />';
1666  
1667      if ( $wrap ) {
1668          $button = '<p class="submit">' . $button . '</p>';
1669      }
1670  
1671      return $button;
1672  }
1673  
1674  function _wp_admin_html_begin() {
1675  ?>
1676  <!DOCTYPE html>
1677  <!--[if IE 8]>
1678  <html xmlns="http://www.w3.org/1999/xhtml" class="ie8" <?php do_action('admin_xml_ns'); ?> <?php language_attributes(); ?>>
1679  <![endif]-->
1680  <!--[if !(IE 8) ]><!-->
1681  <html xmlns="http://www.w3.org/1999/xhtml" <?php do_action('admin_xml_ns'); ?> <?php language_attributes(); ?>>
1682  <!--<![endif]-->
1683  <head>
1684  <meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php echo get_option('blog_charset'); ?>" />
1685  <?php
1686  }
1687  
1688  final class WP_Internal_Pointers {
1689      /**
1690       * Initializes the new feature pointers.
1691       *
1692       * @since 3.3.0
1693       *
1694       * All pointers can be disabled using the following:
1695       *     remove_action( 'admin_enqueue_scripts', array( 'WP_Internal_Pointers', 'enqueue_scripts' ) );
1696       *
1697       * Individual pointers (e.g. wp330_toolbar) can be disabled using the following:
1698       *     remove_action( 'admin_print_footer_scripts', array( 'WP_Internal_Pointers', 'pointer_wp330_toolbar' ) );
1699       */
1700  	public static function enqueue_scripts( $hook_suffix ) {
1701          /*
1702           * Register feature pointers
1703           * Format: array( hook_suffix => pointer_id )
1704           */
1705  
1706          $registered_pointers = array(
1707              'index.php'    => 'wp330_toolbar',
1708              'post-new.php' => 'wp330_media_uploader',
1709              'post.php'     => 'wp330_media_uploader',
1710              'themes.php'   => array( 'wp330_saving_widgets', 'wp340_customize_current_theme_link' ),
1711              'appearance_page_custom-header' => 'wp340_choose_image_from_library',
1712              'appearance_page_custom-background' => 'wp340_choose_image_from_library',
1713          );
1714  
1715          // Check if screen related pointer is registered
1716          if ( empty( $registered_pointers[ $hook_suffix ] ) )
1717              return;
1718  
1719          $pointers = (array) $registered_pointers[ $hook_suffix ];
1720  
1721          $caps_required = array(
1722              'wp330_media_uploader' => array( 'upload_files' ),
1723              'wp330_saving_widgets' => array( 'edit_theme_options', 'switch_themes' ),
1724              'wp340_customize_current_theme_link' => array( 'edit_theme_options' ),
1725              'wp340_choose_image_from_library' => array( 'edit_theme_options' ),
1726          );
1727  
1728          // Get dismissed pointers
1729          $dismissed = explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
1730  
1731          $got_pointers = false;
1732          foreach ( array_diff( $pointers, $dismissed ) as $pointer ) {
1733              if ( isset( $caps_required[ $pointer ] ) ) {
1734                  foreach ( $caps_required[ $pointer ] as $cap ) {
1735                      if ( ! current_user_can( $cap ) )
1736                          continue 2;
1737                  }
1738              }
1739  
1740              // Bind pointer print function
1741              add_action( 'admin_print_footer_scripts', array( 'WP_Internal_Pointers', 'pointer_' . $pointer ) );
1742              $got_pointers = true;
1743          }
1744  
1745          if ( ! $got_pointers )
1746              return;
1747  
1748          // Add pointers script and style to queue
1749          wp_enqueue_style( 'wp-pointer' );
1750          wp_enqueue_script( 'wp-pointer' );
1751      }
1752  
1753      /**
1754       * Print the pointer javascript data.
1755       *
1756       * @since 3.3.0
1757       *
1758       * @param string $pointer_id The pointer ID.
1759       * @param string $selector The HTML elements, on which the pointer should be attached.
1760       * @param array  $args Arguments to be passed to the pointer JS (see wp-pointer.dev.js).
1761       */
1762  	private static function print_js( $pointer_id, $selector, $args ) {
1763          if ( empty( $pointer_id ) || empty( $selector ) || empty( $args ) || empty( $args['content'] ) )
1764              return;
1765  
1766          ?>
1767          <script type="text/javascript">
1768          //<![CDATA[
1769          (function($){
1770              var options = <?php echo json_encode( $args ); ?>, setup;
1771  
1772              if ( ! options )
1773                  return;
1774  
1775              options = $.extend( options, {
1776                  close: function() {
1777                      $.post( ajaxurl, {
1778                          pointer: '<?php echo $pointer_id; ?>',
1779                          action: 'dismiss-wp-pointer'
1780                      });
1781                  }
1782              });
1783  
1784              setup = function() {
1785                  $('<?php echo $selector; ?>').pointer( options ).pointer('open');
1786              };
1787  
1788              if ( options.position && options.position.defer_loading )
1789                  $(window).bind( 'load.wp-pointers', setup );
1790              else
1791                  $(document).ready( setup );
1792  
1793          })( jQuery );
1794          //]]>
1795          </script>
1796          <?php
1797      }
1798  
1799  	public static function pointer_wp330_toolbar() {
1800          $content  = '<h3>' . __( 'New Feature: Toolbar' ) . '</h3>';
1801          $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>';
1802  
1803          if ( is_multisite() && is_super_admin() )
1804              $content .= '<p>' . __( 'Network Admin is now located in the My Sites menu.' ) . '</p>';
1805  
1806          WP_Internal_Pointers::print_js( 'wp330_toolbar', '#wpadminbar', array(
1807              'content'  => $content,
1808              'position' => array( 'edge' => 'top', 'align' => 'center' ),
1809          ) );
1810      }
1811  
1812      /**
1813       * Print 'Updated Media Uploader' for 3.3.0.
1814       *
1815       * @since 3.3.0
1816       */
1817  	public static function pointer_wp330_media_uploader() {
1818          $content  = '<h3>' . __( 'Updated Media Uploader' ) . '</h3>';
1819          $content .= '<p>' . __( 'The single media icon now launches the uploader for all file types, and the new drag and drop interface makes uploading a breeze.' ) . '</p>';
1820  
1821          WP_Internal_Pointers::print_js( 'wp330_media_uploader', '#content-add_media', array(
1822              'content'  => $content,
1823              'position' => array( 'edge' => is_rtl() ? 'right' : 'left', 'align' => 'center' ),
1824          ) );
1825      }
1826  
1827      /**
1828       * Print 'New Feature: Saving Widgets' for 3.3.0.
1829       *
1830       * @since 3.3.0
1831       */
1832  	public static function pointer_wp330_saving_widgets() {
1833          $content  = '<h3>' . __( 'New Feature: Saving Widgets' ) . '</h3>';
1834          $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>';
1835  
1836          WP_Internal_Pointers::print_js( 'wp330_saving_widgets', '#message2', array(
1837              'content'  => $content,
1838              'position' => array( 'edge' => 'top', 'align' => is_rtl() ? 'right' : 'left' ),
1839          ) );
1840      }
1841  
1842      /**
1843       * Print 'New Feature: Current Theme Customize Link' for 3.4.0.
1844       *
1845       * @since 3.4.0
1846       */
1847  	public static function pointer_wp340_customize_current_theme_link() {
1848          $content  = '<h3>' . __( 'New Feature: Customizer' ) . '</h3>';
1849          $content .= '<p>' . __( 'Click Customize to change the header, background, title and menus of the current theme, all in one place.' ) . '</p>';
1850          $content .= '<p>' . __( 'Click the Live Preview links in the Available Themes list below to customize and preview another theme before activating it.' ) . '</p>';
1851  
1852          WP_Internal_Pointers::print_js( 'wp340_customize_current_theme_link', '#customize-current-theme-link', array(
1853              'content'  => $content,
1854              'position' => array( 'edge' => 'top', 'align' => is_rtl() ? 'right' : 'left', 'offset' => is_rtl() ? '32 0' : '-32 0' ),
1855          ) );
1856      }
1857  
1858      /**
1859       * Print 'New Feature: Choose Image from Library' for 3.4.0.
1860       *
1861       * @since 3.4.0
1862       */
1863  	public static function pointer_wp340_choose_image_from_library() {
1864          $content  = '<h3>' . __( 'New Feature: Choose Image from Library' ) . '</h3>';
1865          $content .= '<p>' . __( 'Want to use an image you uploaded earlier? Select it from your media library instead of uploading it again.' ) . '</p>';
1866  
1867          WP_Internal_Pointers::print_js( 'wp340_choose_image_from_library', '#choose-from-library-link', array(
1868              'content'  => $content,
1869              'position' => array( 'edge' => 'top', 'align' => is_rtl() ? 'right' : 'left', 'defer_loading' => true ),
1870          ) );
1871      }
1872  
1873      /**
1874       * Prevents new users from seeing existing 'new feature' pointers.
1875       *
1876       * @since 3.3.0
1877       */
1878  	public static function dismiss_pointers_for_new_users( $user_id ) {
1879          add_user_meta( $user_id, 'dismissed_wp_pointers', 'wp330_toolbar,wp330_media_uploader,wp330_saving_widgets' );
1880      }
1881  }
1882  
1883  add_action( 'admin_enqueue_scripts', array( 'WP_Internal_Pointers', 'enqueue_scripts'                ) );
1884  add_action( 'user_register',         array( 'WP_Internal_Pointers', 'dismiss_pointers_for_new_users' ) );
1885  
1886  /**
1887   * Convert a screen string to a screen object
1888   *
1889   * @since 3.0.0
1890   *
1891   * @param string $hook_name The hook name (also known as the hook suffix) used to determine the screen.
1892   * @return WP_Screen Screen object.
1893   */
1894  function convert_to_screen( $hook_name ) {
1895      if ( ! class_exists( 'WP_Screen' ) ) {
1896          _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' );
1897          return (object) array( 'id' => '_invalid', 'base' => '_are_belong_to_us' );
1898      }
1899  
1900      return WP_Screen::get( $hook_name );
1901  }


Generated: Fri May 25 03:56:23 2012 Hosted by follow the white rabbit.