3 * WordPress Core Ajax Handlers.
6 * @subpackage Administration
10 * No-privilege Ajax handlers.
14 * Heartbeat API (experimental)
16 * Runs when the user is not logged in.
18 function wp_ajax_nopriv_heartbeat() {
21 // screen_id is the same as $current_screen->id and the JS global 'pagenow'
22 if ( ! empty($_POST['screen_id']) )
23 $screen_id = sanitize_key($_POST['screen_id']);
27 if ( ! empty($_POST['data']) ) {
28 $data = wp_unslash( (array) $_POST['data'] );
31 * Filter Heartbeat AJAX response in no-privilege environments.
35 * @param array|object $response The no-priv Heartbeat response object or array.
36 * @param array $data An array of data passed via $_POST.
37 * @param string $screen_id The screen id.
39 $response = apply_filters( 'heartbeat_nopriv_received', $response, $data, $screen_id );
43 * Filter Heartbeat AJAX response when no data is passed.
47 * @param array|object $response The Heartbeat response object or array.
48 * @param string $screen_id The screen id.
50 $response = apply_filters( 'heartbeat_nopriv_send', $response, $screen_id );
53 * Fires when Heartbeat ticks in no-privilege environments.
55 * Allows the transport to be easily replaced with long-polling.
59 * @param array|object $response The no-priv Heartbeat response.
60 * @param string $screen_id The screen id.
62 do_action( 'heartbeat_nopriv_tick', $response, $screen_id );
64 // send the current time according to the server
65 $response['server_time'] = time();
67 wp_send_json($response);
71 * GET-based Ajax handlers.
73 function wp_ajax_fetch_list() {
74 global $wp_list_table;
76 $list_class = $_GET['list_args']['class'];
77 check_ajax_referer( "fetch-list-$list_class", '_ajax_fetch_list_nonce' );
79 $wp_list_table = _get_list_table( $list_class, array( 'screen' => $_GET['list_args']['screen']['id'] ) );
80 if ( ! $wp_list_table )
83 if ( ! $wp_list_table->ajax_user_can() )
86 $wp_list_table->ajax_response();
90 function wp_ajax_ajax_tag_search() {
93 if ( isset( $_GET['tax'] ) ) {
94 $taxonomy = sanitize_key( $_GET['tax'] );
95 $tax = get_taxonomy( $taxonomy );
98 if ( ! current_user_can( $tax->cap->assign_terms ) )
104 $s = wp_unslash( $_GET['q'] );
106 $comma = _x( ',', 'tag delimiter' );
107 if ( ',' !== $comma )
108 $s = str_replace( $comma, ',', $s );
109 if ( false !== strpos( $s, ',' ) ) {
110 $s = explode( ',', $s );
111 $s = $s[count( $s ) - 1];
114 if ( strlen( $s ) < 2 )
115 wp_die(); // require 2 chars for matching
117 $results = get_terms( $taxonomy, array( 'name__like' => $s, 'fields' => 'names', 'hide_empty' => false ) );
119 echo join( $results, "\n" );
123 function wp_ajax_wp_compression_test() {
124 if ( !current_user_can( 'manage_options' ) )
127 if ( ini_get('zlib.output_compression') || 'ob_gzhandler' == ini_get('output_handler') ) {
128 update_site_option('can_compress_scripts', 0);
132 if ( isset($_GET['test']) ) {
133 header( 'Expires: Wed, 11 Jan 1984 05:00:00 GMT' );
134 header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
135 header( 'Cache-Control: no-cache, must-revalidate, max-age=0' );
136 header( 'Pragma: no-cache' );
137 header('Content-Type: application/x-javascript; charset=UTF-8');
138 $force_gzip = ( defined('ENFORCE_GZIP') && ENFORCE_GZIP );
139 $test_str = '"wpCompressionTest Lorem ipsum dolor sit amet consectetuer mollis sapien urna ut a. Eu nonummy condimentum fringilla tempor pretium platea vel nibh netus Maecenas. Hac molestie amet justo quis pellentesque est ultrices interdum nibh Morbi. Cras mattis pretium Phasellus ante ipsum ipsum ut sociis Suspendisse Lorem. Ante et non molestie. Porta urna Vestibulum egestas id congue nibh eu risus gravida sit. Ac augue auctor Ut et non a elit massa id sodales. Elit eu Nulla at nibh adipiscing mattis lacus mauris at tempus. Netus nibh quis suscipit nec feugiat eget sed lorem et urna. Pellentesque lacus at ut massa consectetuer ligula ut auctor semper Pellentesque. Ut metus massa nibh quam Curabitur molestie nec mauris congue. Volutpat molestie elit justo facilisis neque ac risus Ut nascetur tristique. Vitae sit lorem tellus et quis Phasellus lacus tincidunt nunc Fusce. Pharetra wisi Suspendisse mus sagittis libero lacinia Integer consequat ac Phasellus. Et urna ac cursus tortor aliquam Aliquam amet tellus volutpat Vestibulum. Justo interdum condimentum In augue congue tellus sollicitudin Quisque quis nibh."';
141 if ( 1 == $_GET['test'] ) {
144 } elseif ( 2 == $_GET['test'] ) {
145 if ( !isset($_SERVER['HTTP_ACCEPT_ENCODING']) )
147 if ( false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate') && function_exists('gzdeflate') && ! $force_gzip ) {
148 header('Content-Encoding: deflate');
149 $out = gzdeflate( $test_str, 1 );
150 } elseif ( false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') && function_exists('gzencode') ) {
151 header('Content-Encoding: gzip');
152 $out = gzencode( $test_str, 1 );
158 } elseif ( 'no' == $_GET['test'] ) {
159 update_site_option('can_compress_scripts', 0);
160 } elseif ( 'yes' == $_GET['test'] ) {
161 update_site_option('can_compress_scripts', 1);
168 function wp_ajax_imgedit_preview() {
169 $post_id = intval($_GET['postid']);
170 if ( empty($post_id) || !current_user_can('edit_post', $post_id) )
173 check_ajax_referer( "image_editor-$post_id" );
175 include_once( ABSPATH . 'wp-admin/includes/image-edit.php' );
176 if ( ! stream_preview_image($post_id) )
182 function wp_ajax_oembed_cache() {
185 $return = ( $wp_embed->cache_oembed( $_GET['post'] ) ) ? '1' : '0';
189 function wp_ajax_autocomplete_user() {
190 if ( ! is_multisite() || ! current_user_can( 'promote_users' ) || wp_is_large_network( 'users' ) )
193 /** This filter is documented in wp-admin/user-new.php */
194 if ( ! is_super_admin() && ! apply_filters( 'autocomplete_users_for_site_admins', false ) )
199 // Check the type of request
200 if ( isset( $_REQUEST['autocomplete_type'] ) )
201 $type = $_REQUEST['autocomplete_type'];
205 // Exclude current users of this blog
206 if ( isset( $_REQUEST['site_id'] ) )
207 $id = absint( $_REQUEST['site_id'] );
209 $id = get_current_blog_id();
211 $include_blog_users = ( $type == 'search' ? get_users( array( 'blog_id' => $id, 'fields' => 'ID' ) ) : array() );
212 $exclude_blog_users = ( $type == 'add' ? get_users( array( 'blog_id' => $id, 'fields' => 'ID' ) ) : array() );
214 $users = get_users( array(
216 'search' => '*' . $_REQUEST['term'] . '*',
217 'include' => $include_blog_users,
218 'exclude' => $exclude_blog_users,
219 'search_columns' => array( 'user_login', 'user_nicename', 'user_email' ),
222 foreach ( $users as $user ) {
224 /* translators: 1: user_login, 2: user_email */
225 'label' => sprintf( __( '%1$s (%2$s)' ), $user->user_login, $user->user_email ),
226 'value' => $user->user_login,
230 wp_die( json_encode( $return ) );
233 function wp_ajax_dashboard_widgets() {
234 require_once ABSPATH . 'wp-admin/includes/dashboard.php';
236 $pagenow = $_GET['pagenow'];
237 if ( $pagenow === 'dashboard-user' || $pagenow === 'dashboard-network' || $pagenow === 'dashboard' ) {
238 set_current_screen( $pagenow );
241 switch ( $_GET['widget'] ) {
242 case 'dashboard_primary' :
243 wp_dashboard_primary();
249 function wp_ajax_logged_in() {
258 * Sends back current comment total and new page links if they need to be updated.
260 * Contrary to normal success AJAX response ("1"), die with time() on success.
264 * @param int $comment_id
267 function _wp_ajax_delete_comment_response( $comment_id, $delta = -1 ) {
268 $total = isset( $_POST['_total'] ) ? (int) $_POST['_total'] : 0;
269 $per_page = isset( $_POST['_per_page'] ) ? (int) $_POST['_per_page'] : 0;
270 $page = isset( $_POST['_page'] ) ? (int) $_POST['_page'] : 0;
271 $url = isset( $_POST['_url'] ) ? esc_url_raw( $_POST['_url'] ) : '';
273 // JS didn't send us everything we need to know. Just die with success message
274 if ( !$total || !$per_page || !$page || !$url )
281 // Only do the expensive stuff on a page-break, and about 1 other time per page
282 if ( 0 == $total % $per_page || 1 == mt_rand( 1, $per_page ) ) {
284 $status = 'total_comments'; // What type of comment count are we looking for?
285 $parsed = parse_url( $url );
286 if ( isset( $parsed['query'] ) ) {
287 parse_str( $parsed['query'], $query_vars );
288 if ( !empty( $query_vars['comment_status'] ) )
289 $status = $query_vars['comment_status'];
290 if ( !empty( $query_vars['p'] ) )
291 $post_id = (int) $query_vars['p'];
294 $comment_count = wp_count_comments($post_id);
296 if ( isset( $comment_count->$status ) ) // We're looking for a known type of comment count
297 $total = $comment_count->$status;
298 // else use the decremented value from above
301 $time = time(); // The time since the last comment count
303 $x = new WP_Ajax_Response( array(
305 'id' => $comment_id, // here for completeness - not used
306 'supplemental' => array(
307 'total_items_i18n' => sprintf( _n( '1 item', '%s items', $total ), number_format_i18n( $total ) ),
308 'total_pages' => ceil( $total / $per_page ),
309 'total_pages_i18n' => number_format_i18n( ceil( $total / $per_page ) ),
318 * POST-based Ajax handlers.
321 function _wp_ajax_add_hierarchical_term() {
322 $action = $_POST['action'];
323 $taxonomy = get_taxonomy(substr($action, 4));
324 check_ajax_referer( $action, '_ajax_nonce-add-' . $taxonomy->name );
325 if ( !current_user_can( $taxonomy->cap->edit_terms ) )
327 $names = explode(',', $_POST['new'.$taxonomy->name]);
328 $parent = isset($_POST['new'.$taxonomy->name.'_parent']) ? (int) $_POST['new'.$taxonomy->name.'_parent'] : 0;
331 if ( $taxonomy->name == 'category' )
332 $post_category = isset($_POST['post_category']) ? (array) $_POST['post_category'] : array();
334 $post_category = ( isset($_POST['tax_input']) && isset($_POST['tax_input'][$taxonomy->name]) ) ? (array) $_POST['tax_input'][$taxonomy->name] : array();
335 $checked_categories = array_map( 'absint', (array) $post_category );
336 $popular_ids = wp_popular_terms_checklist($taxonomy->name, 0, 10, false);
338 foreach ( $names as $cat_name ) {
339 $cat_name = trim($cat_name);
340 $category_nicename = sanitize_title($cat_name);
341 if ( '' === $category_nicename )
343 if ( !$cat_id = term_exists( $cat_name, $taxonomy->name, $parent ) )
344 $cat_id = wp_insert_term( $cat_name, $taxonomy->name, array( 'parent' => $parent ) );
345 if ( is_wp_error( $cat_id ) )
347 else if ( is_array( $cat_id ) )
348 $cat_id = $cat_id['term_id'];
349 $checked_categories[] = $cat_id;
350 if ( $parent ) // Do these all at once in a second
353 wp_terms_checklist( 0, array( 'taxonomy' => $taxonomy->name, 'descendants_and_self' => $cat_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids ));
354 $data = ob_get_contents();
357 'what' => $taxonomy->name,
359 'data' => str_replace( array("\n", "\t"), '', $data),
364 if ( $parent ) { // Foncy - replace the parent and all its children
365 $parent = get_term( $parent, $taxonomy->name );
366 $term_id = $parent->term_id;
368 while ( $parent->parent ) { // get the top parent
369 $parent = get_term( $parent->parent, $taxonomy->name );
370 if ( is_wp_error( $parent ) )
372 $term_id = $parent->term_id;
376 wp_terms_checklist( 0, array('taxonomy' => $taxonomy->name, 'descendants_and_self' => $term_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids));
377 $data = ob_get_contents();
380 'what' => $taxonomy->name,
382 'data' => str_replace( array("\n", "\t"), '', $data),
388 wp_dropdown_categories( array(
389 'taxonomy' => $taxonomy->name, 'hide_empty' => 0, 'name' => 'new'.$taxonomy->name.'_parent', 'orderby' => 'name',
390 'hierarchical' => 1, 'show_option_none' => '— '.$taxonomy->labels->parent_item.' —'
392 $sup = ob_get_contents();
394 $add['supplemental'] = array( 'newcat_parent' => $sup );
396 $x = new WP_Ajax_Response( $add );
400 function wp_ajax_delete_comment() {
401 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
403 if ( !$comment = get_comment( $id ) )
405 if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) )
408 check_ajax_referer( "delete-comment_$id" );
409 $status = wp_get_comment_status( $comment->comment_ID );
412 if ( isset($_POST['trash']) && 1 == $_POST['trash'] ) {
413 if ( 'trash' == $status )
415 $r = wp_trash_comment( $comment->comment_ID );
416 } elseif ( isset($_POST['untrash']) && 1 == $_POST['untrash'] ) {
417 if ( 'trash' != $status )
419 $r = wp_untrash_comment( $comment->comment_ID );
420 if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'trash' ) // undo trash, not in trash
422 } elseif ( isset($_POST['spam']) && 1 == $_POST['spam'] ) {
423 if ( 'spam' == $status )
425 $r = wp_spam_comment( $comment->comment_ID );
426 } elseif ( isset($_POST['unspam']) && 1 == $_POST['unspam'] ) {
427 if ( 'spam' != $status )
429 $r = wp_unspam_comment( $comment->comment_ID );
430 if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'spam' ) // undo spam, not in spam
432 } elseif ( isset($_POST['delete']) && 1 == $_POST['delete'] ) {
433 $r = wp_delete_comment( $comment->comment_ID );
438 if ( $r ) // Decide if we need to send back '1' or a more complicated response including page links and comment counts
439 _wp_ajax_delete_comment_response( $comment->comment_ID, $delta );
443 function wp_ajax_delete_tag() {
444 $tag_id = (int) $_POST['tag_ID'];
445 check_ajax_referer( "delete-tag_$tag_id" );
447 $taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
448 $tax = get_taxonomy($taxonomy);
450 if ( !current_user_can( $tax->cap->delete_terms ) )
453 $tag = get_term( $tag_id, $taxonomy );
454 if ( !$tag || is_wp_error( $tag ) )
457 if ( wp_delete_term($tag_id, $taxonomy))
463 function wp_ajax_delete_link() {
464 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
466 check_ajax_referer( "delete-bookmark_$id" );
467 if ( !current_user_can( 'manage_links' ) )
470 $link = get_bookmark( $id );
471 if ( !$link || is_wp_error( $link ) )
474 if ( wp_delete_link( $id ) )
480 function wp_ajax_delete_meta() {
481 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
483 check_ajax_referer( "delete-meta_$id" );
484 if ( !$meta = get_metadata_by_mid( 'post', $id ) )
487 if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'delete_post_meta', $meta->post_id, $meta->meta_key ) )
489 if ( delete_meta( $meta->meta_id ) )
494 function wp_ajax_delete_post( $action ) {
495 if ( empty( $action ) )
496 $action = 'delete-post';
497 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
499 check_ajax_referer( "{$action}_$id" );
500 if ( !current_user_can( 'delete_post', $id ) )
503 if ( !get_post( $id ) )
506 if ( wp_delete_post( $id ) )
512 function wp_ajax_trash_post( $action ) {
513 if ( empty( $action ) )
514 $action = 'trash-post';
515 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
517 check_ajax_referer( "{$action}_$id" );
518 if ( !current_user_can( 'delete_post', $id ) )
521 if ( !get_post( $id ) )
524 if ( 'trash-post' == $action )
525 $done = wp_trash_post( $id );
527 $done = wp_untrash_post( $id );
535 function wp_ajax_untrash_post( $action ) {
536 if ( empty( $action ) )
537 $action = 'untrash-post';
538 wp_ajax_trash_post( $action );
541 function wp_ajax_delete_page( $action ) {
542 if ( empty( $action ) )
543 $action = 'delete-page';
544 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
546 check_ajax_referer( "{$action}_$id" );
547 if ( !current_user_can( 'delete_page', $id ) )
550 if ( ! get_post( $id ) )
553 if ( wp_delete_post( $id ) )
559 function wp_ajax_dim_comment() {
560 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
562 if ( !$comment = get_comment( $id ) ) {
563 $x = new WP_Ajax_Response( array(
565 'id' => new WP_Error('invalid_comment', sprintf(__('Comment %d does not exist'), $id))
570 if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) && ! current_user_can( 'moderate_comments' ) )
573 $current = wp_get_comment_status( $comment->comment_ID );
574 if ( isset( $_POST['new'] ) && $_POST['new'] == $current )
577 check_ajax_referer( "approve-comment_$id" );
578 if ( in_array( $current, array( 'unapproved', 'spam' ) ) )
579 $result = wp_set_comment_status( $comment->comment_ID, 'approve', true );
581 $result = wp_set_comment_status( $comment->comment_ID, 'hold', true );
583 if ( is_wp_error($result) ) {
584 $x = new WP_Ajax_Response( array(
591 // Decide if we need to send back '1' or a more complicated response including page links and comment counts
592 _wp_ajax_delete_comment_response( $comment->comment_ID );
596 function wp_ajax_add_link_category( $action ) {
597 if ( empty( $action ) )
598 $action = 'add-link-category';
599 check_ajax_referer( $action );
600 if ( !current_user_can( 'manage_categories' ) )
602 $names = explode(',', wp_unslash( $_POST['newcat'] ) );
603 $x = new WP_Ajax_Response();
604 foreach ( $names as $cat_name ) {
605 $cat_name = trim($cat_name);
606 $slug = sanitize_title($cat_name);
609 if ( !$cat_id = term_exists( $cat_name, 'link_category' ) )
610 $cat_id = wp_insert_term( $cat_name, 'link_category' );
611 if ( is_wp_error( $cat_id ) )
613 else if ( is_array( $cat_id ) )
614 $cat_id = $cat_id['term_id'];
615 $cat_name = esc_html( $cat_name );
617 'what' => 'link-category',
619 'data' => "<li id='link-category-$cat_id'><label for='in-link-category-$cat_id' class='selectit'><input value='" . esc_attr($cat_id) . "' type='checkbox' checked='checked' name='link_category[]' id='in-link-category-$cat_id'/> $cat_name</label></li>",
626 function wp_ajax_add_tag() {
627 global $wp_list_table;
629 check_ajax_referer( 'add-tag', '_wpnonce_add-tag' );
630 $post_type = !empty($_POST['post_type']) ? $_POST['post_type'] : 'post';
631 $taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
632 $tax = get_taxonomy($taxonomy);
634 if ( !current_user_can( $tax->cap->edit_terms ) )
637 $x = new WP_Ajax_Response();
639 $tag = wp_insert_term($_POST['tag-name'], $taxonomy, $_POST );
641 if ( !$tag || is_wp_error($tag) || (!$tag = get_term( $tag['term_id'], $taxonomy )) ) {
642 $message = __('An error has occurred. Please reload the page and try again.');
643 if ( is_wp_error($tag) && $tag->get_error_message() )
644 $message = $tag->get_error_message();
647 'what' => 'taxonomy',
648 'data' => new WP_Error('error', $message )
653 $wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => $_POST['screen'] ) );
656 if ( is_taxonomy_hierarchical($taxonomy) ) {
657 $level = count( get_ancestors( $tag->term_id, $taxonomy ) );
659 $wp_list_table->single_row( $tag, $level );
660 $noparents = ob_get_clean();
664 $wp_list_table->single_row( $tag );
665 $parents = ob_get_clean();
668 'what' => 'taxonomy',
669 'supplemental' => compact('parents', 'noparents')
673 'position' => $level,
674 'supplemental' => (array) $tag
679 function wp_ajax_get_tagcloud() {
680 if ( isset( $_POST['tax'] ) ) {
681 $taxonomy = sanitize_key( $_POST['tax'] );
682 $tax = get_taxonomy( $taxonomy );
685 if ( ! current_user_can( $tax->cap->assign_terms ) )
691 $tags = get_terms( $taxonomy, array( 'number' => 45, 'orderby' => 'count', 'order' => 'DESC' ) );
693 if ( empty( $tags ) )
694 wp_die( $tax->labels->not_found );
696 if ( is_wp_error( $tags ) )
697 wp_die( $tags->get_error_message() );
699 foreach ( $tags as $key => $tag ) {
700 $tags[ $key ]->link = '#';
701 $tags[ $key ]->id = $tag->term_id;
704 // We need raw tag names here, so don't filter the output
705 $return = wp_generate_tag_cloud( $tags, array('filter' => 0) );
707 if ( empty($return) )
715 function wp_ajax_get_comments( $action ) {
716 global $wp_list_table, $post_id;
717 if ( empty( $action ) )
718 $action = 'get-comments';
720 check_ajax_referer( $action );
722 if ( empty( $post_id ) && ! empty( $_REQUEST['p'] ) ) {
723 $id = absint( $_REQUEST['p'] );
724 if ( ! empty( $id ) )
728 if ( empty( $post_id ) )
731 $wp_list_table = _get_list_table( 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
733 if ( ! current_user_can( 'edit_post', $post_id ) )
736 $wp_list_table->prepare_items();
738 if ( !$wp_list_table->has_items() )
741 $x = new WP_Ajax_Response();
743 foreach ( $wp_list_table->items as $comment ) {
744 if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) )
746 get_comment( $comment );
747 $wp_list_table->single_row( $comment );
749 $comment_list_item = ob_get_contents();
753 'what' => 'comments',
754 'data' => $comment_list_item
759 function wp_ajax_replyto_comment( $action ) {
760 global $wp_list_table, $wpdb;
761 if ( empty( $action ) )
762 $action = 'replyto-comment';
764 check_ajax_referer( $action, '_ajax_nonce-replyto-comment' );
766 $comment_post_ID = (int) $_POST['comment_post_ID'];
767 $post = get_post( $comment_post_ID );
771 if ( !current_user_can( 'edit_post', $comment_post_ID ) )
774 if ( empty( $post->post_status ) )
776 elseif ( in_array($post->post_status, array('draft', 'pending', 'trash') ) )
777 wp_die( __('ERROR: you are replying to a comment on a draft post.') );
779 $user = wp_get_current_user();
780 if ( $user->exists() ) {
781 $user_ID = $user->ID;
782 $comment_author = wp_slash( $user->display_name );
783 $comment_author_email = wp_slash( $user->user_email );
784 $comment_author_url = wp_slash( $user->user_url );
785 $comment_content = trim($_POST['content']);
786 if ( current_user_can( 'unfiltered_html' ) ) {
787 if ( ! isset( $_POST['_wp_unfiltered_html_comment'] ) )
788 $_POST['_wp_unfiltered_html_comment'] = '';
790 if ( wp_create_nonce( 'unfiltered-html-comment' ) != $_POST['_wp_unfiltered_html_comment'] ) {
791 kses_remove_filters(); // start with a clean slate
792 kses_init_filters(); // set up the filters
796 wp_die( __( 'Sorry, you must be logged in to reply to a comment.' ) );
799 if ( '' == $comment_content )
800 wp_die( __( 'ERROR: please type a comment.' ) );
803 if ( isset( $_POST['comment_ID'] ) )
804 $comment_parent = absint( $_POST['comment_ID'] );
805 $comment_auto_approved = false;
806 $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_type', 'comment_parent', 'user_ID');
808 // automatically approve parent comment
809 if ( !empty($_POST['approve_parent']) ) {
810 $parent = get_comment( $comment_parent );
812 if ( $parent && $parent->comment_approved === '0' && $parent->comment_post_ID == $comment_post_ID ) {
813 if ( wp_set_comment_status( $parent->comment_ID, 'approve' ) )
814 $comment_auto_approved = true;
818 $comment_id = wp_new_comment( $commentdata );
819 $comment = get_comment($comment_id);
820 if ( ! $comment ) wp_die( 1 );
822 $position = ( isset($_POST['position']) && (int) $_POST['position'] ) ? (int) $_POST['position'] : '-1';
825 if ( isset( $_REQUEST['mode'] ) && 'dashboard' == $_REQUEST['mode'] ) {
826 require_once( ABSPATH . 'wp-admin/includes/dashboard.php' );
827 _wp_dashboard_recent_comments_row( $comment );
829 if ( isset( $_REQUEST['mode'] ) && 'single' == $_REQUEST['mode'] ) {
830 $wp_list_table = _get_list_table('WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
832 $wp_list_table = _get_list_table('WP_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
834 $wp_list_table->single_row( $comment );
836 $comment_list_item = ob_get_clean();
840 'id' => $comment->comment_ID,
841 'data' => $comment_list_item,
842 'position' => $position
845 if ( $comment_auto_approved )
846 $response['supplemental'] = array( 'parent_approved' => $parent->comment_ID );
848 $x = new WP_Ajax_Response();
849 $x->add( $response );
853 function wp_ajax_edit_comment() {
854 global $wp_list_table;
856 check_ajax_referer( 'replyto-comment', '_ajax_nonce-replyto-comment' );
858 $comment_id = (int) $_POST['comment_ID'];
859 if ( ! current_user_can( 'edit_comment', $comment_id ) )
862 if ( '' == $_POST['content'] )
863 wp_die( __( 'ERROR: please type a comment.' ) );
865 if ( isset( $_POST['status'] ) )
866 $_POST['comment_status'] = $_POST['status'];
869 $position = ( isset($_POST['position']) && (int) $_POST['position']) ? (int) $_POST['position'] : '-1';
870 $comments_status = isset($_POST['comments_listing']) ? $_POST['comments_listing'] : '';
872 $checkbox = ( isset($_POST['checkbox']) && true == $_POST['checkbox'] ) ? 1 : 0;
873 $wp_list_table = _get_list_table( $checkbox ? 'WP_Comments_List_Table' : 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
875 $comment = get_comment( $comment_id );
876 if ( empty( $comment->comment_ID ) )
880 $wp_list_table->single_row( $comment );
881 $comment_list_item = ob_get_clean();
883 $x = new WP_Ajax_Response();
886 'what' => 'edit_comment',
887 'id' => $comment->comment_ID,
888 'data' => $comment_list_item,
889 'position' => $position
895 function wp_ajax_add_menu_item() {
896 check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' );
898 if ( ! current_user_can( 'edit_theme_options' ) )
901 require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
903 // For performance reasons, we omit some object properties from the checklist.
904 // The following is a hacky way to restore them when adding non-custom items.
906 $menu_items_data = array();
907 foreach ( (array) $_POST['menu-item'] as $menu_item_data ) {
909 ! empty( $menu_item_data['menu-item-type'] ) &&
910 'custom' != $menu_item_data['menu-item-type'] &&
911 ! empty( $menu_item_data['menu-item-object-id'] )
913 switch( $menu_item_data['menu-item-type'] ) {
915 $_object = get_post( $menu_item_data['menu-item-object-id'] );
919 $_object = get_term( $menu_item_data['menu-item-object-id'], $menu_item_data['menu-item-object'] );
923 $_menu_items = array_map( 'wp_setup_nav_menu_item', array( $_object ) );
924 $_menu_item = array_shift( $_menu_items );
926 // Restore the missing menu item properties
927 $menu_item_data['menu-item-description'] = $_menu_item->description;
930 $menu_items_data[] = $menu_item_data;
933 $item_ids = wp_save_nav_menu_items( 0, $menu_items_data );
934 if ( is_wp_error( $item_ids ) )
937 $menu_items = array();
939 foreach ( (array) $item_ids as $menu_item_id ) {
940 $menu_obj = get_post( $menu_item_id );
941 if ( ! empty( $menu_obj->ID ) ) {
942 $menu_obj = wp_setup_nav_menu_item( $menu_obj );
943 $menu_obj->label = $menu_obj->title; // don't show "(pending)" in ajax-added items
944 $menu_items[] = $menu_obj;
949 * Filter the Walker class used when adding nav menu items.
953 * @param string $class The walker class to use. Default 'Walker_Nav_Menu_Edit'.
954 * @param int $menu_id The menu id, derived from $_POST['menu'].
956 $walker_class_name = apply_filters( 'wp_edit_nav_menu_walker', 'Walker_Nav_Menu_Edit', $_POST['menu'] );
958 if ( ! class_exists( $walker_class_name ) )
961 if ( ! empty( $menu_items ) ) {
967 'walker' => new $walker_class_name,
969 echo walk_nav_menu_tree( $menu_items, 0, (object) $args );
974 function wp_ajax_add_meta() {
975 check_ajax_referer( 'add-meta', '_ajax_nonce-add-meta' );
977 $pid = (int) $_POST['post_id'];
978 $post = get_post( $pid );
980 if ( isset($_POST['metakeyselect']) || isset($_POST['metakeyinput']) ) {
981 if ( !current_user_can( 'edit_post', $pid ) )
983 if ( isset($_POST['metakeyselect']) && '#NONE#' == $_POST['metakeyselect'] && empty($_POST['metakeyinput']) )
985 if ( $post->post_status == 'auto-draft' ) {
986 $save_POST = $_POST; // Backup $_POST
987 $_POST = array(); // Make it empty for edit_post()
988 $_POST['action'] = 'draft'; // Warning fix
989 $_POST['post_ID'] = $pid;
990 $_POST['post_type'] = $post->post_type;
991 $_POST['post_status'] = 'draft';
992 $now = current_time('timestamp', 1);
993 $_POST['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), date( get_option( 'date_format' ), $now ), date( get_option( 'time_format' ), $now ) );
995 if ( $pid = edit_post() ) {
996 if ( is_wp_error( $pid ) ) {
997 $x = new WP_Ajax_Response( array(
1003 $_POST = $save_POST; // Now we can restore original $_POST again
1004 if ( !$mid = add_meta( $pid ) )
1005 wp_die( __( 'Please provide a custom field value.' ) );
1009 } else if ( !$mid = add_meta( $pid ) ) {
1010 wp_die( __( 'Please provide a custom field value.' ) );
1013 $meta = get_metadata_by_mid( 'post', $mid );
1014 $pid = (int) $meta->post_id;
1015 $meta = get_object_vars( $meta );
1016 $x = new WP_Ajax_Response( array(
1019 'data' => _list_meta_row( $meta, $c ),
1021 'supplemental' => array('postid' => $pid)
1024 $mid = (int) key( $_POST['meta'] );
1025 $key = wp_unslash( $_POST['meta'][$mid]['key'] );
1026 $value = wp_unslash( $_POST['meta'][$mid]['value'] );
1027 if ( '' == trim($key) )
1028 wp_die( __( 'Please provide a custom field name.' ) );
1029 if ( '' == trim($value) )
1030 wp_die( __( 'Please provide a custom field value.' ) );
1031 if ( ! $meta = get_metadata_by_mid( 'post', $mid ) )
1032 wp_die( 0 ); // if meta doesn't exist
1033 if ( is_protected_meta( $meta->meta_key, 'post' ) || is_protected_meta( $key, 'post' ) ||
1034 ! current_user_can( 'edit_post_meta', $meta->post_id, $meta->meta_key ) ||
1035 ! current_user_can( 'edit_post_meta', $meta->post_id, $key ) )
1037 if ( $meta->meta_value != $value || $meta->meta_key != $key ) {
1038 if ( !$u = update_metadata_by_mid( 'post', $mid, $value, $key ) )
1039 wp_die( 0 ); // We know meta exists; we also know it's unchanged (or DB error, in which case there are bigger problems).
1042 $x = new WP_Ajax_Response( array(
1044 'id' => $mid, 'old_id' => $mid,
1045 'data' => _list_meta_row( array(
1047 'meta_value' => $value,
1051 'supplemental' => array('postid' => $meta->post_id)
1057 function wp_ajax_add_user( $action ) {
1058 global $wp_list_table;
1059 if ( empty( $action ) )
1060 $action = 'add-user';
1062 check_ajax_referer( $action );
1063 if ( ! current_user_can('create_users') )
1065 if ( ! $user_id = edit_user() ) {
1067 } elseif ( is_wp_error( $user_id ) ) {
1068 $x = new WP_Ajax_Response( array(
1074 $user_object = get_userdata( $user_id );
1076 $wp_list_table = _get_list_table('WP_Users_List_Table');
1078 $role = current( $user_object->roles );
1080 $x = new WP_Ajax_Response( array(
1083 'data' => $wp_list_table->single_row( $user_object, '', $role ),
1084 'supplemental' => array(
1085 'show-link' => sprintf(__( 'User <a href="#%s">%s</a> added' ), "user-$user_id", $user_object->user_login),
1092 function wp_ajax_autosave() {
1093 define( 'DOING_AUTOSAVE', true );
1095 check_ajax_referer( 'autosave', 'autosavenonce' );
1097 if ( ! empty( $_POST['catslist'] ) )
1098 $_POST['post_category'] = explode( ',', $_POST['catslist'] );
1099 if ( $_POST['post_type'] == 'page' || empty( $_POST['post_category'] ) )
1100 unset( $_POST['post_category'] );
1103 $supplemental = array();
1104 $id = $revision_id = 0;
1106 $post_id = (int) $_POST['post_id'];
1107 $_POST['ID'] = $_POST['post_ID'] = $post_id;
1108 $post = get_post( $post_id );
1109 if ( empty( $post->ID ) || ! current_user_can( 'edit_post', $post->ID ) )
1110 wp_die( __( 'You are not allowed to edit this post.' ) );
1112 if ( 'page' == $post->post_type && ! current_user_can( 'edit_page', $post->ID ) )
1113 wp_die( __( 'You are not allowed to edit this page.' ) );
1115 if ( 'auto-draft' == $post->post_status )
1116 $_POST['post_status'] = 'draft';
1118 if ( ! empty( $_POST['autosave'] ) ) {
1119 if ( ! wp_check_post_lock( $post->ID ) && get_current_user_id() == $post->post_author && ( 'auto-draft' == $post->post_status || 'draft' == $post->post_status ) ) {
1120 // Drafts and auto-drafts are just overwritten by autosave for the same user if the post is not locked
1123 // Non drafts or other users drafts are not overwritten. The autosave is stored in a special post revision for each user.
1124 $revision_id = wp_create_post_autosave( $post->ID );
1125 if ( is_wp_error($revision_id) )
1131 if ( ! is_wp_error($id) ) {
1132 /* translators: draft saved date format, see http://php.net/date */
1133 $draft_saved_date_format = __('g:i:s a');
1134 /* translators: %s: date and time */
1135 $data = sprintf( __('Draft saved at %s.'), date_i18n( $draft_saved_date_format ) );
1138 if ( ! empty( $_POST['auto_draft'] ) )
1139 $id = 0; // This tells us it didn't actually save
1144 // @todo Consider exposing any errors, rather than having 'Saving draft...'
1145 $x = new WP_Ajax_Response( array(
1146 'what' => 'autosave',
1149 'supplemental' => $supplemental
1154 function wp_ajax_closed_postboxes() {
1155 check_ajax_referer( 'closedpostboxes', 'closedpostboxesnonce' );
1156 $closed = isset( $_POST['closed'] ) ? explode( ',', $_POST['closed']) : array();
1157 $closed = array_filter($closed);
1159 $hidden = isset( $_POST['hidden'] ) ? explode( ',', $_POST['hidden']) : array();
1160 $hidden = array_filter($hidden);
1162 $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1164 if ( $page != sanitize_key( $page ) )
1167 if ( ! $user = wp_get_current_user() )
1170 if ( is_array($closed) )
1171 update_user_option($user->ID, "closedpostboxes_$page", $closed, true);
1173 if ( is_array($hidden) ) {
1174 $hidden = array_diff( $hidden, array('submitdiv', 'linksubmitdiv', 'manage-menu', 'create-menu') ); // postboxes that are always shown
1175 update_user_option($user->ID, "metaboxhidden_$page", $hidden, true);
1181 function wp_ajax_hidden_columns() {
1182 check_ajax_referer( 'screen-options-nonce', 'screenoptionnonce' );
1183 $hidden = isset( $_POST['hidden'] ) ? $_POST['hidden'] : '';
1184 $hidden = explode( ',', $_POST['hidden'] );
1185 $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1187 if ( $page != sanitize_key( $page ) )
1190 if ( ! $user = wp_get_current_user() )
1193 if ( is_array($hidden) )
1194 update_user_option($user->ID, "manage{$page}columnshidden", $hidden, true);
1199 function wp_ajax_update_welcome_panel() {
1200 check_ajax_referer( 'welcome-panel-nonce', 'welcomepanelnonce' );
1202 if ( ! current_user_can( 'edit_theme_options' ) )
1205 update_user_meta( get_current_user_id(), 'show_welcome_panel', empty( $_POST['visible'] ) ? 0 : 1 );
1210 function wp_ajax_menu_get_metabox() {
1211 if ( ! current_user_can( 'edit_theme_options' ) )
1214 require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
1216 if ( isset( $_POST['item-type'] ) && 'post_type' == $_POST['item-type'] ) {
1218 $callback = 'wp_nav_menu_item_post_type_meta_box';
1219 $items = (array) get_post_types( array( 'show_in_nav_menus' => true ), 'object' );
1220 } elseif ( isset( $_POST['item-type'] ) && 'taxonomy' == $_POST['item-type'] ) {
1222 $callback = 'wp_nav_menu_item_taxonomy_meta_box';
1223 $items = (array) get_taxonomies( array( 'show_ui' => true ), 'object' );
1226 if ( ! empty( $_POST['item-object'] ) && isset( $items[$_POST['item-object']] ) ) {
1227 $menus_meta_box_object = $items[ $_POST['item-object'] ];
1229 * Filter a nav menu meta box object.
1233 * @param object $menus_meta_box_object A nav menu meta box object, such as Page, Post, Category, Tag, etc.
1235 $item = apply_filters( 'nav_menu_meta_box_object', $menus_meta_box_object );
1237 call_user_func_array($callback, array(
1240 'id' => 'add-' . $item->name,
1241 'title' => $item->labels->name,
1242 'callback' => $callback,
1247 $markup = ob_get_clean();
1249 echo json_encode(array(
1250 'replace-id' => $type . '-' . $item->name,
1251 'markup' => $markup,
1258 function wp_ajax_wp_link_ajax() {
1259 check_ajax_referer( 'internal-linking', '_ajax_linking_nonce' );
1263 if ( isset( $_POST['search'] ) )
1264 $args['s'] = wp_unslash( $_POST['search'] );
1265 $args['pagenum'] = ! empty( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
1267 require(ABSPATH . WPINC . '/class-wp-editor.php');
1268 $results = _WP_Editors::wp_link_query( $args );
1270 if ( ! isset( $results ) )
1273 echo json_encode( $results );
1279 function wp_ajax_menu_locations_save() {
1280 if ( ! current_user_can( 'edit_theme_options' ) )
1282 check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' );
1283 if ( ! isset( $_POST['menu-locations'] ) )
1285 set_theme_mod( 'nav_menu_locations', array_map( 'absint', $_POST['menu-locations'] ) );
1289 function wp_ajax_meta_box_order() {
1290 check_ajax_referer( 'meta-box-order' );
1291 $order = isset( $_POST['order'] ) ? (array) $_POST['order'] : false;
1292 $page_columns = isset( $_POST['page_columns'] ) ? $_POST['page_columns'] : 'auto';
1294 if ( $page_columns != 'auto' )
1295 $page_columns = (int) $page_columns;
1297 $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1299 if ( $page != sanitize_key( $page ) )
1302 if ( ! $user = wp_get_current_user() )
1306 update_user_option($user->ID, "meta-box-order_$page", $order, true);
1308 if ( $page_columns )
1309 update_user_option($user->ID, "screen_layout_$page", $page_columns, true);
1314 function wp_ajax_menu_quick_search() {
1315 if ( ! current_user_can( 'edit_theme_options' ) )
1318 require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
1320 _wp_ajax_menu_quick_search( $_POST );
1325 function wp_ajax_get_permalink() {
1326 check_ajax_referer( 'getpermalink', 'getpermalinknonce' );
1327 $post_id = isset($_POST['post_id'])? intval($_POST['post_id']) : 0;
1328 wp_die( add_query_arg( array( 'preview' => 'true' ), get_permalink( $post_id ) ) );
1331 function wp_ajax_sample_permalink() {
1332 check_ajax_referer( 'samplepermalink', 'samplepermalinknonce' );
1333 $post_id = isset($_POST['post_id'])? intval($_POST['post_id']) : 0;
1334 $title = isset($_POST['new_title'])? $_POST['new_title'] : '';
1335 $slug = isset($_POST['new_slug'])? $_POST['new_slug'] : null;
1336 wp_die( get_sample_permalink_html( $post_id, $title, $slug ) );
1339 function wp_ajax_inline_save() {
1340 global $wp_list_table;
1342 check_ajax_referer( 'inlineeditnonce', '_inline_edit' );
1344 if ( ! isset($_POST['post_ID']) || ! ( $post_ID = (int) $_POST['post_ID'] ) )
1347 if ( 'page' == $_POST['post_type'] ) {
1348 if ( ! current_user_can( 'edit_page', $post_ID ) )
1349 wp_die( __( 'You are not allowed to edit this page.' ) );
1351 if ( ! current_user_can( 'edit_post', $post_ID ) )
1352 wp_die( __( 'You are not allowed to edit this post.' ) );
1355 if ( $last = wp_check_post_lock( $post_ID ) ) {
1356 $last_user = get_userdata( $last );
1357 $last_user_name = $last_user ? $last_user->display_name : __( 'Someone' );
1358 printf( $_POST['post_type'] == 'page' ? __( 'Saving is disabled: %s is currently editing this page.' ) : __( 'Saving is disabled: %s is currently editing this post.' ), esc_html( $last_user_name ) );
1364 $post = get_post( $post_ID, ARRAY_A );
1365 $post = wp_slash($post); //since it is from db
1367 $data['content'] = $post['post_content'];
1368 $data['excerpt'] = $post['post_excerpt'];
1371 $data['user_ID'] = get_current_user_id();
1373 if ( isset($data['post_parent']) )
1374 $data['parent_id'] = $data['post_parent'];
1377 if ( isset($data['keep_private']) && 'private' == $data['keep_private'] )
1378 $data['post_status'] = 'private';
1380 $data['post_status'] = $data['_status'];
1382 if ( empty($data['comment_status']) )
1383 $data['comment_status'] = 'closed';
1384 if ( empty($data['ping_status']) )
1385 $data['ping_status'] = 'closed';
1387 // Hack: wp_unique_post_slug() doesn't work for drafts, so we will fake that our post is published.
1388 if ( ! empty( $data['post_name'] ) && in_array( $post['post_status'], array( 'draft', 'pending' ) ) ) {
1389 $post['post_status'] = 'publish';
1390 $data['post_name'] = wp_unique_post_slug( $data['post_name'], $post['ID'], $post['post_status'], $post['post_type'], $post['post_parent'] );
1396 $wp_list_table = _get_list_table( 'WP_Posts_List_Table', array( 'screen' => $_POST['screen'] ) );
1398 $mode = $_POST['post_view'];
1401 $request_post = array( get_post( $_POST['post_ID'] ) );
1402 $parent = $request_post[0]->post_parent;
1404 while ( $parent > 0 ) {
1405 $parent_post = get_post( $parent );
1406 $parent = $parent_post->post_parent;
1410 $wp_list_table->display_rows( array( get_post( $_POST['post_ID'] ) ), $level );
1415 function wp_ajax_inline_save_tax() {
1416 global $wp_list_table;
1418 check_ajax_referer( 'taxinlineeditnonce', '_inline_edit' );
1420 $taxonomy = sanitize_key( $_POST['taxonomy'] );
1421 $tax = get_taxonomy( $taxonomy );
1425 if ( ! current_user_can( $tax->cap->edit_terms ) )
1428 $wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => 'edit-' . $taxonomy ) );
1430 if ( ! isset($_POST['tax_ID']) || ! ( $id = (int) $_POST['tax_ID'] ) )
1433 $tag = get_term( $id, $taxonomy );
1434 $_POST['description'] = $tag->description;
1436 $updated = wp_update_term($id, $taxonomy, $_POST);
1437 if ( $updated && !is_wp_error($updated) ) {
1438 $tag = get_term( $updated['term_id'], $taxonomy );
1439 if ( !$tag || is_wp_error( $tag ) ) {
1440 if ( is_wp_error($tag) && $tag->get_error_message() )
1441 wp_die( $tag->get_error_message() );
1442 wp_die( __( 'Item not updated.' ) );
1445 if ( is_wp_error($updated) && $updated->get_error_message() )
1446 wp_die( $updated->get_error_message() );
1447 wp_die( __( 'Item not updated.' ) );
1450 $parent = $tag->parent;
1451 while ( $parent > 0 ) {
1452 $parent_tag = get_term( $parent, $taxonomy );
1453 $parent = $parent_tag->parent;
1456 $wp_list_table->single_row( $tag, $level );
1460 function wp_ajax_find_posts() {
1463 check_ajax_referer( 'find-posts' );
1465 $post_types = get_post_types( array( 'public' => true ), 'objects' );
1466 unset( $post_types['attachment'] );
1468 $s = wp_unslash( $_POST['ps'] );
1469 $searchand = $search = '';
1471 'post_type' => array_keys( $post_types ),
1472 'post_status' => 'any',
1473 'posts_per_page' => 50,
1478 $posts = get_posts( $args );
1481 wp_die( __('No items found.') );
1483 $html = '<table class="widefat" cellspacing="0"><thead><tr><th class="found-radio"><br /></th><th>'.__('Title').'</th><th class="no-break">'.__('Type').'</th><th class="no-break">'.__('Date').'</th><th class="no-break">'.__('Status').'</th></tr></thead><tbody>';
1484 foreach ( $posts as $post ) {
1485 $title = trim( $post->post_title ) ? $post->post_title : __( '(no title)' );
1487 switch ( $post->post_status ) {
1490 $stat = __('Published');
1493 $stat = __('Scheduled');
1496 $stat = __('Pending Review');
1499 $stat = __('Draft');
1503 if ( '0000-00-00 00:00:00' == $post->post_date ) {
1506 /* translators: date format in table columns, see http://php.net/date */
1507 $time = mysql2date(__('Y/m/d'), $post->post_date);
1510 $html .= '<tr class="found-posts"><td class="found-radio"><input type="radio" id="found-'.$post->ID.'" name="found_post_id" value="' . esc_attr($post->ID) . '"></td>';
1511 $html .= '<td><label for="found-'.$post->ID.'">' . esc_html( $title ) . '</label></td><td class="no-break">' . esc_html( $post_types[$post->post_type]->labels->singular_name ) . '</td><td class="no-break">'.esc_html( $time ) . '</td><td class="no-break">' . esc_html( $stat ). ' </td></tr>' . "\n\n";
1514 $html .= '</tbody></table>';
1516 $x = new WP_Ajax_Response();
1523 function wp_ajax_widgets_order() {
1524 check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' );
1526 if ( !current_user_can('edit_theme_options') )
1529 unset( $_POST['savewidgets'], $_POST['action'] );
1531 // save widgets order for all sidebars
1532 if ( is_array($_POST['sidebars']) ) {
1533 $sidebars = array();
1534 foreach ( $_POST['sidebars'] as $key => $val ) {
1536 if ( !empty($val) ) {
1537 $val = explode(',', $val);
1538 foreach ( $val as $k => $v ) {
1539 if ( strpos($v, 'widget-') === false )
1542 $sb[$k] = substr($v, strpos($v, '_') + 1);
1545 $sidebars[$key] = $sb;
1547 wp_set_sidebars_widgets($sidebars);
1554 function wp_ajax_save_widget() {
1555 global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
1557 check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' );
1559 if ( !current_user_can('edit_theme_options') || !isset($_POST['id_base']) )
1562 unset( $_POST['savewidgets'], $_POST['action'] );
1565 * Fires early when editing the widgets displayed in sidebars.
1569 do_action( 'load-widgets.php' );
1572 * Fires early when editing the widgets displayed in sidebars.
1576 do_action( 'widgets.php' );
1579 * Fires early when editing the widgets displayed in sidebars.
1583 do_action( 'sidebar_admin_setup' );
1585 $id_base = $_POST['id_base'];
1586 $widget_id = $_POST['widget-id'];
1587 $sidebar_id = $_POST['sidebar'];
1588 $multi_number = !empty($_POST['multi_number']) ? (int) $_POST['multi_number'] : 0;
1589 $settings = isset($_POST['widget-' . $id_base]) && is_array($_POST['widget-' . $id_base]) ? $_POST['widget-' . $id_base] : false;
1590 $error = '<p>' . __('An error has occurred. Please reload the page and try again.') . '</p>';
1592 $sidebars = wp_get_sidebars_widgets();
1593 $sidebar = isset($sidebars[$sidebar_id]) ? $sidebars[$sidebar_id] : array();
1596 if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
1598 if ( !isset($wp_registered_widgets[$widget_id]) )
1601 $sidebar = array_diff( $sidebar, array($widget_id) );
1602 $_POST = array('sidebar' => $sidebar_id, 'widget-' . $id_base => array(), 'the-widget-id' => $widget_id, 'delete_widget' => '1');
1603 } elseif ( $settings && preg_match( '/__i__|%i%/', key($settings) ) ) {
1604 if ( !$multi_number )
1607 $_POST['widget-' . $id_base] = array( $multi_number => array_shift($settings) );
1608 $widget_id = $id_base . '-' . $multi_number;
1609 $sidebar[] = $widget_id;
1611 $_POST['widget-id'] = $sidebar;
1613 foreach ( (array) $wp_registered_widget_updates as $name => $control ) {
1615 if ( $name == $id_base ) {
1616 if ( !is_callable( $control['callback'] ) )
1620 call_user_func_array( $control['callback'], $control['params'] );
1626 if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
1627 $sidebars[$sidebar_id] = $sidebar;
1628 wp_set_sidebars_widgets($sidebars);
1629 echo "deleted:$widget_id";
1633 if ( !empty($_POST['add_new']) )
1636 if ( $form = $wp_registered_widget_controls[$widget_id] )
1637 call_user_func_array( $form['callback'], $form['params'] );
1642 function wp_ajax_upload_attachment() {
1643 check_ajax_referer( 'media-form' );
1645 if ( ! current_user_can( 'upload_files' ) )
1648 if ( isset( $_REQUEST['post_id'] ) ) {
1649 $post_id = $_REQUEST['post_id'];
1650 if ( ! current_user_can( 'edit_post', $post_id ) )
1656 $post_data = isset( $_REQUEST['post_data'] ) ? $_REQUEST['post_data'] : array();
1658 // If the context is custom header or background, make sure the uploaded file is an image.
1659 if ( isset( $post_data['context'] ) && in_array( $post_data['context'], array( 'custom-header', 'custom-background' ) ) ) {
1660 $wp_filetype = wp_check_filetype_and_ext( $_FILES['async-upload']['tmp_name'], $_FILES['async-upload']['name'], false );
1661 if ( ! wp_match_mime_types( 'image', $wp_filetype['type'] ) ) {
1662 echo json_encode( array(
1665 'message' => __( 'The uploaded file is not a valid image. Please try again.' ),
1666 'filename' => $_FILES['async-upload']['name'],
1674 $attachment_id = media_handle_upload( 'async-upload', $post_id, $post_data );
1676 if ( is_wp_error( $attachment_id ) ) {
1677 echo json_encode( array(
1680 'message' => $attachment_id->get_error_message(),
1681 'filename' => $_FILES['async-upload']['name'],
1688 if ( isset( $post_data['context'] ) && isset( $post_data['theme'] ) ) {
1689 if ( 'custom-background' === $post_data['context'] )
1690 update_post_meta( $attachment_id, '_wp_attachment_is_custom_background', $post_data['theme'] );
1692 if ( 'custom-header' === $post_data['context'] )
1693 update_post_meta( $attachment_id, '_wp_attachment_is_custom_header', $post_data['theme'] );
1696 if ( ! $attachment = wp_prepare_attachment_for_js( $attachment_id ) )
1699 echo json_encode( array(
1701 'data' => $attachment,
1707 function wp_ajax_image_editor() {
1708 $attachment_id = intval($_POST['postid']);
1709 if ( empty($attachment_id) || !current_user_can('edit_post', $attachment_id) )
1712 check_ajax_referer( "image_editor-$attachment_id" );
1713 include_once( ABSPATH . 'wp-admin/includes/image-edit.php' );
1716 switch ( $_POST['do'] ) {
1718 $msg = wp_save_image($attachment_id);
1719 $msg = json_encode($msg);
1723 $msg = wp_save_image($attachment_id);
1726 $msg = wp_restore_image($attachment_id);
1730 wp_image_editor($attachment_id, $msg);
1734 function wp_ajax_set_post_thumbnail() {
1735 $json = ! empty( $_REQUEST['json'] ); // New-style request
1737 $post_ID = intval( $_POST['post_id'] );
1738 if ( ! current_user_can( 'edit_post', $post_ID ) )
1741 $thumbnail_id = intval( $_POST['thumbnail_id'] );
1744 check_ajax_referer( "update-post_$post_ID" );
1746 check_ajax_referer( "set_post_thumbnail-$post_ID" );
1748 if ( $thumbnail_id == '-1' ) {
1749 if ( delete_post_thumbnail( $post_ID ) ) {
1750 $return = _wp_post_thumbnail_html( null, $post_ID );
1751 $json ? wp_send_json_success( $return ) : wp_die( $return );
1757 if ( set_post_thumbnail( $post_ID, $thumbnail_id ) ) {
1758 $return = _wp_post_thumbnail_html( $thumbnail_id, $post_ID );
1759 $json ? wp_send_json_success( $return ) : wp_die( $return );
1765 function wp_ajax_date_format() {
1766 wp_die( date_i18n( sanitize_option( 'date_format', $_POST['date'] ) ) );
1769 function wp_ajax_time_format() {
1770 wp_die( date_i18n( sanitize_option( 'time_format', $_POST['date'] ) ) );
1773 function wp_ajax_wp_fullscreen_save_post() {
1774 $post_id = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0;
1776 $post = $post_type = null;
1779 $post = get_post( $post_id );
1782 $post_type = $post->post_type;
1783 elseif ( isset( $_POST['post_type'] ) && post_type_exists( $_POST['post_type'] ) )
1784 $post_type = $_POST['post_type'];
1786 check_ajax_referer('update-post_' . $post_id, '_wpnonce');
1788 $post_id = edit_post();
1790 if ( is_wp_error($post_id) ) {
1791 if ( $post_id->get_error_message() )
1792 $message = $post_id->get_error_message();
1794 $message = __('Save failed');
1796 echo json_encode( array( 'message' => $message, 'last_edited' => '' ) );
1799 $message = __('Saved.');
1803 $last_date = mysql2date( get_option('date_format'), $post->post_modified );
1804 $last_time = mysql2date( get_option('time_format'), $post->post_modified );
1806 $last_date = date_i18n( get_option('date_format') );
1807 $last_time = date_i18n( get_option('time_format') );
1810 if ( $last_id = get_post_meta($post_id, '_edit_last', true) ) {
1811 $last_user = get_userdata($last_id);
1812 $last_edited = sprintf( __('Last edited by %1$s on %2$s at %3$s'), esc_html( $last_user->display_name ), $last_date, $last_time );
1814 $last_edited = sprintf( __('Last edited on %1$s at %2$s'), $last_date, $last_time );
1817 echo json_encode( array( 'message' => $message, 'last_edited' => $last_edited ) );
1821 function wp_ajax_wp_remove_post_lock() {
1822 if ( empty( $_POST['post_ID'] ) || empty( $_POST['active_post_lock'] ) )
1824 $post_id = (int) $_POST['post_ID'];
1825 if ( ! $post = get_post( $post_id ) )
1828 check_ajax_referer( 'update-post_' . $post_id );
1830 if ( ! current_user_can( 'edit_post', $post_id ) )
1833 $active_lock = array_map( 'absint', explode( ':', $_POST['active_post_lock'] ) );
1834 if ( $active_lock[1] != get_current_user_id() )
1838 * Filter the post lock window duration.
1842 * @param int $interval The interval in seconds the post lock duration should last, plus 5 seconds. Default 120.
1844 $new_lock = ( time() - apply_filters( 'wp_check_post_lock_window', 120 ) + 5 ) . ':' . $active_lock[1];
1845 update_post_meta( $post_id, '_edit_lock', $new_lock, implode( ':', $active_lock ) );
1849 function wp_ajax_dismiss_wp_pointer() {
1850 $pointer = $_POST['pointer'];
1851 if ( $pointer != sanitize_key( $pointer ) )
1854 // check_ajax_referer( 'dismiss-pointer_' . $pointer );
1856 $dismissed = array_filter( explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) ) );
1858 if ( in_array( $pointer, $dismissed ) )
1861 $dismissed[] = $pointer;
1862 $dismissed = implode( ',', $dismissed );
1864 update_user_meta( get_current_user_id(), 'dismissed_wp_pointers', $dismissed );
1869 * Get an attachment.
1873 function wp_ajax_get_attachment() {
1874 if ( ! isset( $_REQUEST['id'] ) )
1875 wp_send_json_error();
1877 if ( ! $id = absint( $_REQUEST['id'] ) )
1878 wp_send_json_error();
1880 if ( ! $post = get_post( $id ) )
1881 wp_send_json_error();
1883 if ( 'attachment' != $post->post_type )
1884 wp_send_json_error();
1886 if ( ! current_user_can( 'upload_files' ) )
1887 wp_send_json_error();
1889 if ( ! $attachment = wp_prepare_attachment_for_js( $id ) )
1890 wp_send_json_error();
1892 wp_send_json_success( $attachment );
1896 * Query for attachments.
1900 function wp_ajax_query_attachments() {
1901 if ( ! current_user_can( 'upload_files' ) )
1902 wp_send_json_error();
1904 $query = isset( $_REQUEST['query'] ) ? (array) $_REQUEST['query'] : array();
1905 $query = array_intersect_key( $query, array_flip( array(
1906 's', 'order', 'orderby', 'posts_per_page', 'paged', 'post_mime_type',
1907 'post_parent', 'post__in', 'post__not_in',
1910 $query['post_type'] = 'attachment';
1911 $query['post_status'] = 'inherit';
1912 if ( current_user_can( get_post_type_object( 'attachment' )->cap->read_private_posts ) )
1913 $query['post_status'] .= ',private';
1916 * Filter the arguments passed to WP_Query during an AJAX call for querying attachments.
1920 * @param array $query An array of query variables. @see WP_Query::parse_query()
1922 $query = apply_filters( 'ajax_query_attachments_args', $query );
1923 $query = new WP_Query( $query );
1925 $posts = array_map( 'wp_prepare_attachment_for_js', $query->posts );
1926 $posts = array_filter( $posts );
1928 wp_send_json_success( $posts );
1932 * Save attachment attributes.
1936 function wp_ajax_save_attachment() {
1937 if ( ! isset( $_REQUEST['id'] ) || ! isset( $_REQUEST['changes'] ) )
1938 wp_send_json_error();
1940 if ( ! $id = absint( $_REQUEST['id'] ) )
1941 wp_send_json_error();
1943 check_ajax_referer( 'update-post_' . $id, 'nonce' );
1945 if ( ! current_user_can( 'edit_post', $id ) )
1946 wp_send_json_error();
1948 $changes = $_REQUEST['changes'];
1949 $post = get_post( $id, ARRAY_A );
1951 if ( 'attachment' != $post['post_type'] )
1952 wp_send_json_error();
1954 if ( isset( $changes['title'] ) )
1955 $post['post_title'] = $changes['title'];
1957 if ( isset( $changes['caption'] ) )
1958 $post['post_excerpt'] = $changes['caption'];
1960 if ( isset( $changes['description'] ) )
1961 $post['post_content'] = $changes['description'];
1963 if ( isset( $changes['alt'] ) ) {
1964 $alt = wp_unslash( $changes['alt'] );
1965 if ( $alt != get_post_meta( $id, '_wp_attachment_image_alt', true ) ) {
1966 $alt = wp_strip_all_tags( $alt, true );
1967 update_post_meta( $id, '_wp_attachment_image_alt', wp_slash( $alt ) );
1971 wp_update_post( $post );
1972 wp_send_json_success();
1976 * Save backwards compatible attachment attributes.
1980 function wp_ajax_save_attachment_compat() {
1981 if ( ! isset( $_REQUEST['id'] ) )
1982 wp_send_json_error();
1984 if ( ! $id = absint( $_REQUEST['id'] ) )
1985 wp_send_json_error();
1987 if ( empty( $_REQUEST['attachments'] ) || empty( $_REQUEST['attachments'][ $id ] ) )
1988 wp_send_json_error();
1989 $attachment_data = $_REQUEST['attachments'][ $id ];
1991 check_ajax_referer( 'update-post_' . $id, 'nonce' );
1993 if ( ! current_user_can( 'edit_post', $id ) )
1994 wp_send_json_error();
1996 $post = get_post( $id, ARRAY_A );
1998 if ( 'attachment' != $post['post_type'] )
1999 wp_send_json_error();
2001 /** This filter is documented in wp-admin/includes/media.php */
2002 $post = apply_filters( 'attachment_fields_to_save', $post, $attachment_data );
2004 if ( isset( $post['errors'] ) ) {
2005 $errors = $post['errors']; // @todo return me and display me!
2006 unset( $post['errors'] );
2009 wp_update_post( $post );
2011 foreach ( get_attachment_taxonomies( $post ) as $taxonomy ) {
2012 if ( isset( $attachment_data[ $taxonomy ] ) )
2013 wp_set_object_terms( $id, array_map( 'trim', preg_split( '/,+/', $attachment_data[ $taxonomy ] ) ), $taxonomy, false );
2016 if ( ! $attachment = wp_prepare_attachment_for_js( $id ) )
2017 wp_send_json_error();
2019 wp_send_json_success( $attachment );
2022 function wp_ajax_save_attachment_order() {
2023 if ( ! isset( $_REQUEST['post_id'] ) )
2024 wp_send_json_error();
2026 if ( ! $post_id = absint( $_REQUEST['post_id'] ) )
2027 wp_send_json_error();
2029 if ( empty( $_REQUEST['attachments'] ) )
2030 wp_send_json_error();
2032 check_ajax_referer( 'update-post_' . $post_id, 'nonce' );
2034 $attachments = $_REQUEST['attachments'];
2036 if ( ! current_user_can( 'edit_post', $post_id ) )
2037 wp_send_json_error();
2039 $post = get_post( $post_id, ARRAY_A );
2041 foreach ( $attachments as $attachment_id => $menu_order ) {
2042 if ( ! current_user_can( 'edit_post', $attachment_id ) )
2044 if ( ! $attachment = get_post( $attachment_id ) )
2046 if ( 'attachment' != $attachment->post_type )
2049 wp_update_post( array( 'ID' => $attachment_id, 'menu_order' => $menu_order ) );
2052 wp_send_json_success();
2056 * Generates the HTML to send an attachment to the editor.
2057 * Backwards compatible with the media_send_to_editor filter and the chain
2058 * of filters that follow.
2062 function wp_ajax_send_attachment_to_editor() {
2063 check_ajax_referer( 'media-send-to-editor', 'nonce' );
2065 $attachment = wp_unslash( $_POST['attachment'] );
2067 $id = intval( $attachment['id'] );
2069 if ( ! $post = get_post( $id ) )
2070 wp_send_json_error();
2072 if ( 'attachment' != $post->post_type )
2073 wp_send_json_error();
2075 if ( current_user_can( 'edit_post', $id ) ) {
2076 // If this attachment is unattached, attach it. Primarily a back compat thing.
2077 if ( 0 == $post->post_parent && $insert_into_post_id = intval( $_POST['post_id'] ) ) {
2078 wp_update_post( array( 'ID' => $id, 'post_parent' => $insert_into_post_id ) );
2083 $html = $title = isset( $attachment['post_title'] ) ? $attachment['post_title'] : '';
2084 if ( ! empty( $attachment['url'] ) ) {
2085 $url = $attachment['url'];
2086 if ( strpos( $url, 'attachment_id') || get_attachment_link( $id ) == $url )
2087 $rel = ' rel="attachment wp-att-' . $id . '"';
2088 $html = '<a href="' . esc_url( $url ) . '"' . $rel . '>' . $html . '</a>';
2091 remove_filter( 'media_send_to_editor', 'image_media_send_to_editor' );
2093 if ( 'image' === substr( $post->post_mime_type, 0, 5 ) ) {
2094 $align = isset( $attachment['align'] ) ? $attachment['align'] : 'none';
2095 $size = isset( $attachment['image-size'] ) ? $attachment['image-size'] : 'medium';
2096 $alt = isset( $attachment['image_alt'] ) ? $attachment['image_alt'] : '';
2097 $caption = isset( $attachment['post_excerpt'] ) ? $attachment['post_excerpt'] : '';
2098 $title = ''; // We no longer insert title tags into <img> tags, as they are redundant.
2099 $html = get_image_send_to_editor( $id, $caption, $title, $align, $url, (bool) $rel, $size, $alt );
2100 } elseif ( 'video' === substr( $post->post_mime_type, 0, 5 ) || 'audio' === substr( $post->post_mime_type, 0, 5 ) ) {
2101 $html = stripslashes_deep( $_POST['html'] );
2104 /** This filter is documented in wp-admin/includes/media.php */
2105 $html = apply_filters( 'media_send_to_editor', $html, $id, $attachment );
2107 wp_send_json_success( $html );
2111 * Generates the HTML to send a non-image embed link to the editor.
2113 * Backwards compatible with the following filters:
2114 * - file_send_to_editor_url
2115 * - audio_send_to_editor_url
2116 * - video_send_to_editor_url
2120 function wp_ajax_send_link_to_editor() {
2121 check_ajax_referer( 'media-send-to-editor', 'nonce' );
2123 if ( ! $src = wp_unslash( $_POST['src'] ) )
2124 wp_send_json_error();
2126 if ( ! strpos( $src, '://' ) )
2127 $src = 'http://' . $src;
2129 if ( ! $src = esc_url_raw( $src ) )
2130 wp_send_json_error();
2132 if ( ! $title = trim( wp_unslash( $_POST['title'] ) ) )
2133 $title = wp_basename( $src );
2137 $html = '<a href="' . esc_url( $src ) . '">' . $title . '</a>';
2139 // Figure out what filter to run:
2141 if ( ( $ext = preg_replace( '/^.+?\.([^.]+)$/', '$1', $src ) ) && ( $ext_type = wp_ext2type( $ext ) )
2142 && ( 'audio' == $ext_type || 'video' == $ext_type ) )
2145 /** This filter is documented in wp-admin/includes/media.php */
2146 $html = apply_filters( $type . '_send_to_editor_url', $html, $src, $title );
2148 wp_send_json_success( $html );
2152 * Heartbeat API (experimental)
2154 * Runs when the user is logged in.
2156 function wp_ajax_heartbeat() {
2157 if ( empty( $_POST['_nonce'] ) )
2158 wp_send_json_error();
2160 $response = array();
2162 if ( false === wp_verify_nonce( $_POST['_nonce'], 'heartbeat-nonce' ) ) {
2163 // User is logged in but nonces have expired.
2164 $response['nonces_expired'] = true;
2165 wp_send_json($response);
2168 // screen_id is the same as $current_screen->id and the JS global 'pagenow'
2169 if ( ! empty($_POST['screen_id']) )
2170 $screen_id = sanitize_key($_POST['screen_id']);
2172 $screen_id = 'front';
2174 if ( ! empty($_POST['data']) ) {
2175 $data = (array) $_POST['data'];
2178 * Filter the Heartbeat response received.
2182 * @param array|object $response The Heartbeat response object or array.
2183 * @param array $data The $_POST data sent.
2184 * @param string $screen_id The screen id.
2186 $response = apply_filters( 'heartbeat_received', $response, $data, $screen_id );
2190 * Filter the Heartbeat response sent.
2194 * @param array|object $response The Heartbeat response object or array.
2195 * @param string $screen_id The screen id.
2197 $response = apply_filters( 'heartbeat_send', $response, $screen_id );
2200 * Fires when Heartbeat ticks in logged-in environments.
2202 * Allows the transport to be easily replaced with long-polling.
2206 * @param array|object $response The Heartbeat response object or array.
2207 * @param string $screen_id The screen id.
2209 do_action( 'heartbeat_tick', $response, $screen_id );
2211 // Send the current time according to the server
2212 $response['server_time'] = time();
2214 wp_send_json($response);
2217 function wp_ajax_get_revision_diffs() {
2218 require ABSPATH . 'wp-admin/includes/revision.php';
2220 if ( ! $post = get_post( (int) $_REQUEST['post_id'] ) )
2221 wp_send_json_error();
2223 if ( ! current_user_can( 'read_post', $post->ID ) )
2224 wp_send_json_error();
2226 // Really just pre-loading the cache here.
2227 if ( ! $revisions = wp_get_post_revisions( $post->ID, array( 'check_enabled' => false ) ) )
2228 wp_send_json_error();
2231 @set_time_limit( 0 );
2233 foreach ( $_REQUEST['compare'] as $compare_key ) {
2234 list( $compare_from, $compare_to ) = explode( ':', $compare_key ); // from:to
2237 'id' => $compare_key,
2238 'fields' => wp_get_revision_ui_diff( $post, $compare_from, $compare_to ),
2241 wp_send_json_success( $return );
2245 * Auto-save the selected color scheme for a user's own profile.
2249 function wp_ajax_save_user_color_scheme() {
2250 global $_wp_admin_css_colors;
2252 check_ajax_referer( 'save-color-scheme', 'nonce' );
2254 $color_scheme = sanitize_key( $_POST['color_scheme'] );
2256 if ( ! isset( $_wp_admin_css_colors[ $color_scheme ] ) ) {
2257 wp_send_json_error();
2260 update_user_meta( get_current_user_id(), 'admin_color', $color_scheme );
2261 wp_send_json_success();