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( '— Select —' ); ?></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( ' ', $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') ?> › <?php echo $title ?> — <?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’ve combined the admin bar and the old Dashboard header into one persistent toolbar. Hover over the toolbar items to see what’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’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
Body
title
Description
Body
title
Description
Body
title
Body
title