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 switch ( $_GET['widget'] ) {
237 case 'dashboard_incoming_links' :
238 wp_dashboard_incoming_links();
240 case 'dashboard_primary' :
241 wp_dashboard_primary();
243 case 'dashboard_secondary' :
244 wp_dashboard_secondary();
246 case 'dashboard_plugins' :
247 wp_dashboard_plugins();
253 function wp_ajax_logged_in() {
262 * Sends back current comment total and new page links if they need to be updated.
264 * Contrary to normal success AJAX response ("1"), die with time() on success.
268 * @param int $comment_id
271 function _wp_ajax_delete_comment_response( $comment_id, $delta = -1 ) {
272 $total = isset( $_POST['_total'] ) ? (int) $_POST['_total'] : 0;
273 $per_page = isset( $_POST['_per_page'] ) ? (int) $_POST['_per_page'] : 0;
274 $page = isset( $_POST['_page'] ) ? (int) $_POST['_page'] : 0;
275 $url = isset( $_POST['_url'] ) ? esc_url_raw( $_POST['_url'] ) : '';
277 // JS didn't send us everything we need to know. Just die with success message
278 if ( !$total || !$per_page || !$page || !$url )
285 // Only do the expensive stuff on a page-break, and about 1 other time per page
286 if ( 0 == $total % $per_page || 1 == mt_rand( 1, $per_page ) ) {
288 $status = 'total_comments'; // What type of comment count are we looking for?
289 $parsed = parse_url( $url );
290 if ( isset( $parsed['query'] ) ) {
291 parse_str( $parsed['query'], $query_vars );
292 if ( !empty( $query_vars['comment_status'] ) )
293 $status = $query_vars['comment_status'];
294 if ( !empty( $query_vars['p'] ) )
295 $post_id = (int) $query_vars['p'];
298 $comment_count = wp_count_comments($post_id);
300 if ( isset( $comment_count->$status ) ) // We're looking for a known type of comment count
301 $total = $comment_count->$status;
302 // else use the decremented value from above
305 $time = time(); // The time since the last comment count
307 $x = new WP_Ajax_Response( array(
309 'id' => $comment_id, // here for completeness - not used
310 'supplemental' => array(
311 'total_items_i18n' => sprintf( _n( '1 item', '%s items', $total ), number_format_i18n( $total ) ),
312 'total_pages' => ceil( $total / $per_page ),
313 'total_pages_i18n' => number_format_i18n( ceil( $total / $per_page ) ),
322 * POST-based Ajax handlers.
325 function _wp_ajax_add_hierarchical_term() {
326 $action = $_POST['action'];
327 $taxonomy = get_taxonomy(substr($action, 4));
328 check_ajax_referer( $action, '_ajax_nonce-add-' . $taxonomy->name );
329 if ( !current_user_can( $taxonomy->cap->edit_terms ) )
331 $names = explode(',', $_POST['new'.$taxonomy->name]);
332 $parent = isset($_POST['new'.$taxonomy->name.'_parent']) ? (int) $_POST['new'.$taxonomy->name.'_parent'] : 0;
335 if ( $taxonomy->name == 'category' )
336 $post_category = isset($_POST['post_category']) ? (array) $_POST['post_category'] : array();
338 $post_category = ( isset($_POST['tax_input']) && isset($_POST['tax_input'][$taxonomy->name]) ) ? (array) $_POST['tax_input'][$taxonomy->name] : array();
339 $checked_categories = array_map( 'absint', (array) $post_category );
340 $popular_ids = wp_popular_terms_checklist($taxonomy->name, 0, 10, false);
342 foreach ( $names as $cat_name ) {
343 $cat_name = trim($cat_name);
344 $category_nicename = sanitize_title($cat_name);
345 if ( '' === $category_nicename )
347 if ( !$cat_id = term_exists( $cat_name, $taxonomy->name, $parent ) )
348 $cat_id = wp_insert_term( $cat_name, $taxonomy->name, array( 'parent' => $parent ) );
349 if ( is_wp_error( $cat_id ) )
351 else if ( is_array( $cat_id ) )
352 $cat_id = $cat_id['term_id'];
353 $checked_categories[] = $cat_id;
354 if ( $parent ) // Do these all at once in a second
357 wp_terms_checklist( 0, array( 'taxonomy' => $taxonomy->name, 'descendants_and_self' => $cat_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids ));
358 $data = ob_get_contents();
361 'what' => $taxonomy->name,
363 'data' => str_replace( array("\n", "\t"), '', $data),
368 if ( $parent ) { // Foncy - replace the parent and all its children
369 $parent = get_term( $parent, $taxonomy->name );
370 $term_id = $parent->term_id;
372 while ( $parent->parent ) { // get the top parent
373 $parent = get_term( $parent->parent, $taxonomy->name );
374 if ( is_wp_error( $parent ) )
376 $term_id = $parent->term_id;
380 wp_terms_checklist( 0, array('taxonomy' => $taxonomy->name, 'descendants_and_self' => $term_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids));
381 $data = ob_get_contents();
384 'what' => $taxonomy->name,
386 'data' => str_replace( array("\n", "\t"), '', $data),
392 wp_dropdown_categories( array(
393 'taxonomy' => $taxonomy->name, 'hide_empty' => 0, 'name' => 'new'.$taxonomy->name.'_parent', 'orderby' => 'name',
394 'hierarchical' => 1, 'show_option_none' => '— '.$taxonomy->labels->parent_item.' —'
396 $sup = ob_get_contents();
398 $add['supplemental'] = array( 'newcat_parent' => $sup );
400 $x = new WP_Ajax_Response( $add );
404 function wp_ajax_delete_comment() {
405 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
407 if ( !$comment = get_comment( $id ) )
409 if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) )
412 check_ajax_referer( "delete-comment_$id" );
413 $status = wp_get_comment_status( $comment->comment_ID );
416 if ( isset($_POST['trash']) && 1 == $_POST['trash'] ) {
417 if ( 'trash' == $status )
419 $r = wp_trash_comment( $comment->comment_ID );
420 } elseif ( isset($_POST['untrash']) && 1 == $_POST['untrash'] ) {
421 if ( 'trash' != $status )
423 $r = wp_untrash_comment( $comment->comment_ID );
424 if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'trash' ) // undo trash, not in trash
426 } elseif ( isset($_POST['spam']) && 1 == $_POST['spam'] ) {
427 if ( 'spam' == $status )
429 $r = wp_spam_comment( $comment->comment_ID );
430 } elseif ( isset($_POST['unspam']) && 1 == $_POST['unspam'] ) {
431 if ( 'spam' != $status )
433 $r = wp_unspam_comment( $comment->comment_ID );
434 if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'spam' ) // undo spam, not in spam
436 } elseif ( isset($_POST['delete']) && 1 == $_POST['delete'] ) {
437 $r = wp_delete_comment( $comment->comment_ID );
442 if ( $r ) // Decide if we need to send back '1' or a more complicated response including page links and comment counts
443 _wp_ajax_delete_comment_response( $comment->comment_ID, $delta );
447 function wp_ajax_delete_tag() {
448 $tag_id = (int) $_POST['tag_ID'];
449 check_ajax_referer( "delete-tag_$tag_id" );
451 $taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
452 $tax = get_taxonomy($taxonomy);
454 if ( !current_user_can( $tax->cap->delete_terms ) )
457 $tag = get_term( $tag_id, $taxonomy );
458 if ( !$tag || is_wp_error( $tag ) )
461 if ( wp_delete_term($tag_id, $taxonomy))
467 function wp_ajax_delete_link() {
468 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
470 check_ajax_referer( "delete-bookmark_$id" );
471 if ( !current_user_can( 'manage_links' ) )
474 $link = get_bookmark( $id );
475 if ( !$link || is_wp_error( $link ) )
478 if ( wp_delete_link( $id ) )
484 function wp_ajax_delete_meta() {
485 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
487 check_ajax_referer( "delete-meta_$id" );
488 if ( !$meta = get_metadata_by_mid( 'post', $id ) )
491 if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'delete_post_meta', $meta->post_id, $meta->meta_key ) )
493 if ( delete_meta( $meta->meta_id ) )
498 function wp_ajax_delete_post( $action ) {
499 if ( empty( $action ) )
500 $action = 'delete-post';
501 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
503 check_ajax_referer( "{$action}_$id" );
504 if ( !current_user_can( 'delete_post', $id ) )
507 if ( !get_post( $id ) )
510 if ( wp_delete_post( $id ) )
516 function wp_ajax_trash_post( $action ) {
517 if ( empty( $action ) )
518 $action = 'trash-post';
519 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
521 check_ajax_referer( "{$action}_$id" );
522 if ( !current_user_can( 'delete_post', $id ) )
525 if ( !get_post( $id ) )
528 if ( 'trash-post' == $action )
529 $done = wp_trash_post( $id );
531 $done = wp_untrash_post( $id );
539 function wp_ajax_untrash_post( $action ) {
540 if ( empty( $action ) )
541 $action = 'untrash-post';
542 wp_ajax_trash_post( $action );
545 function wp_ajax_delete_page( $action ) {
546 if ( empty( $action ) )
547 $action = 'delete-page';
548 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
550 check_ajax_referer( "{$action}_$id" );
551 if ( !current_user_can( 'delete_page', $id ) )
554 if ( ! get_post( $id ) )
557 if ( wp_delete_post( $id ) )
563 function wp_ajax_dim_comment() {
564 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
566 if ( !$comment = get_comment( $id ) ) {
567 $x = new WP_Ajax_Response( array(
569 'id' => new WP_Error('invalid_comment', sprintf(__('Comment %d does not exist'), $id))
574 if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) && ! current_user_can( 'moderate_comments' ) )
577 $current = wp_get_comment_status( $comment->comment_ID );
578 if ( isset( $_POST['new'] ) && $_POST['new'] == $current )
581 check_ajax_referer( "approve-comment_$id" );
582 if ( in_array( $current, array( 'unapproved', 'spam' ) ) )
583 $result = wp_set_comment_status( $comment->comment_ID, 'approve', true );
585 $result = wp_set_comment_status( $comment->comment_ID, 'hold', true );
587 if ( is_wp_error($result) ) {
588 $x = new WP_Ajax_Response( array(
595 // Decide if we need to send back '1' or a more complicated response including page links and comment counts
596 _wp_ajax_delete_comment_response( $comment->comment_ID );
600 function wp_ajax_add_link_category( $action ) {
601 if ( empty( $action ) )
602 $action = 'add-link-category';
603 check_ajax_referer( $action );
604 if ( !current_user_can( 'manage_categories' ) )
606 $names = explode(',', wp_unslash( $_POST['newcat'] ) );
607 $x = new WP_Ajax_Response();
608 foreach ( $names as $cat_name ) {
609 $cat_name = trim($cat_name);
610 $slug = sanitize_title($cat_name);
613 if ( !$cat_id = term_exists( $cat_name, 'link_category' ) )
614 $cat_id = wp_insert_term( $cat_name, 'link_category' );
615 if ( is_wp_error( $cat_id ) )
617 else if ( is_array( $cat_id ) )
618 $cat_id = $cat_id['term_id'];
619 $cat_name = esc_html( $cat_name );
621 'what' => 'link-category',
623 '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>",
630 function wp_ajax_add_tag() {
631 global $wp_list_table;
633 check_ajax_referer( 'add-tag', '_wpnonce_add-tag' );
634 $post_type = !empty($_POST['post_type']) ? $_POST['post_type'] : 'post';
635 $taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
636 $tax = get_taxonomy($taxonomy);
638 if ( !current_user_can( $tax->cap->edit_terms ) )
641 $x = new WP_Ajax_Response();
643 $tag = wp_insert_term($_POST['tag-name'], $taxonomy, $_POST );
645 if ( !$tag || is_wp_error($tag) || (!$tag = get_term( $tag['term_id'], $taxonomy )) ) {
646 $message = __('An error has occurred. Please reload the page and try again.');
647 if ( is_wp_error($tag) && $tag->get_error_message() )
648 $message = $tag->get_error_message();
651 'what' => 'taxonomy',
652 'data' => new WP_Error('error', $message )
657 $wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => $_POST['screen'] ) );
660 if ( is_taxonomy_hierarchical($taxonomy) ) {
661 $level = count( get_ancestors( $tag->term_id, $taxonomy ) );
663 $wp_list_table->single_row( $tag, $level );
664 $noparents = ob_get_clean();
668 $wp_list_table->single_row( $tag );
669 $parents = ob_get_clean();
672 'what' => 'taxonomy',
673 'supplemental' => compact('parents', 'noparents')
677 'position' => $level,
678 'supplemental' => (array) $tag
683 function wp_ajax_get_tagcloud() {
684 if ( isset( $_POST['tax'] ) ) {
685 $taxonomy = sanitize_key( $_POST['tax'] );
686 $tax = get_taxonomy( $taxonomy );
689 if ( ! current_user_can( $tax->cap->assign_terms ) )
695 $tags = get_terms( $taxonomy, array( 'number' => 45, 'orderby' => 'count', 'order' => 'DESC' ) );
697 if ( empty( $tags ) )
698 wp_die( $tax->labels->not_found );
700 if ( is_wp_error( $tags ) )
701 wp_die( $tags->get_error_message() );
703 foreach ( $tags as $key => $tag ) {
704 $tags[ $key ]->link = '#';
705 $tags[ $key ]->id = $tag->term_id;
708 // We need raw tag names here, so don't filter the output
709 $return = wp_generate_tag_cloud( $tags, array('filter' => 0) );
711 if ( empty($return) )
719 function wp_ajax_get_comments( $action ) {
720 global $wp_list_table, $post_id;
721 if ( empty( $action ) )
722 $action = 'get-comments';
724 check_ajax_referer( $action );
726 if ( empty( $post_id ) && ! empty( $_REQUEST['p'] ) ) {
727 $id = absint( $_REQUEST['p'] );
728 if ( ! empty( $id ) )
732 if ( empty( $post_id ) )
735 $wp_list_table = _get_list_table( 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
737 if ( ! current_user_can( 'edit_post', $post_id ) )
740 $wp_list_table->prepare_items();
742 if ( !$wp_list_table->has_items() )
745 $x = new WP_Ajax_Response();
747 foreach ( $wp_list_table->items as $comment ) {
748 if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) )
750 get_comment( $comment );
751 $wp_list_table->single_row( $comment );
753 $comment_list_item = ob_get_contents();
757 'what' => 'comments',
758 'data' => $comment_list_item
763 function wp_ajax_replyto_comment( $action ) {
764 global $wp_list_table, $wpdb;
765 if ( empty( $action ) )
766 $action = 'replyto-comment';
768 check_ajax_referer( $action, '_ajax_nonce-replyto-comment' );
770 $comment_post_ID = (int) $_POST['comment_post_ID'];
771 $post = get_post( $comment_post_ID );
775 if ( !current_user_can( 'edit_post', $comment_post_ID ) )
778 if ( empty( $post->post_status ) )
780 elseif ( in_array($post->post_status, array('draft', 'pending', 'trash') ) )
781 wp_die( __('ERROR: you are replying to a comment on a draft post.') );
783 $user = wp_get_current_user();
784 if ( $user->exists() ) {
785 $user_ID = $user->ID;
786 $comment_author = wp_slash( $user->display_name );
787 $comment_author_email = wp_slash( $user->user_email );
788 $comment_author_url = wp_slash( $user->user_url );
789 $comment_content = trim($_POST['content']);
790 if ( current_user_can( 'unfiltered_html' ) ) {
791 if ( ! isset( $_POST['_wp_unfiltered_html_comment'] ) )
792 $_POST['_wp_unfiltered_html_comment'] = '';
794 if ( wp_create_nonce( 'unfiltered-html-comment' ) != $_POST['_wp_unfiltered_html_comment'] ) {
795 kses_remove_filters(); // start with a clean slate
796 kses_init_filters(); // set up the filters
800 wp_die( __( 'Sorry, you must be logged in to reply to a comment.' ) );
803 if ( '' == $comment_content )
804 wp_die( __( 'ERROR: please type a comment.' ) );
807 if ( isset( $_POST['comment_ID'] ) )
808 $comment_parent = absint( $_POST['comment_ID'] );
809 $comment_auto_approved = false;
810 $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_type', 'comment_parent', 'user_ID');
812 // automatically approve parent comment
813 if ( !empty($_POST['approve_parent']) ) {
814 $parent = get_comment( $comment_parent );
816 if ( $parent && $parent->comment_approved === '0' && $parent->comment_post_ID == $comment_post_ID ) {
817 if ( wp_set_comment_status( $parent->comment_ID, 'approve' ) )
818 $comment_auto_approved = true;
822 $comment_id = wp_new_comment( $commentdata );
823 $comment = get_comment($comment_id);
824 if ( ! $comment ) wp_die( 1 );
826 $position = ( isset($_POST['position']) && (int) $_POST['position'] ) ? (int) $_POST['position'] : '-1';
829 if ( isset( $_REQUEST['mode'] ) && 'dashboard' == $_REQUEST['mode'] ) {
830 require_once( ABSPATH . 'wp-admin/includes/dashboard.php' );
831 _wp_dashboard_recent_comments_row( $comment );
833 if ( isset( $_REQUEST['mode'] ) && 'single' == $_REQUEST['mode'] ) {
834 $wp_list_table = _get_list_table('WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
836 $wp_list_table = _get_list_table('WP_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
838 $wp_list_table->single_row( $comment );
840 $comment_list_item = ob_get_clean();
844 'id' => $comment->comment_ID,
845 'data' => $comment_list_item,
846 'position' => $position
849 if ( $comment_auto_approved )
850 $response['supplemental'] = array( 'parent_approved' => $parent->comment_ID );
852 $x = new WP_Ajax_Response();
853 $x->add( $response );
857 function wp_ajax_edit_comment() {
858 global $wp_list_table;
860 check_ajax_referer( 'replyto-comment', '_ajax_nonce-replyto-comment' );
862 $comment_id = (int) $_POST['comment_ID'];
863 if ( ! current_user_can( 'edit_comment', $comment_id ) )
866 if ( '' == $_POST['content'] )
867 wp_die( __( 'ERROR: please type a comment.' ) );
869 if ( isset( $_POST['status'] ) )
870 $_POST['comment_status'] = $_POST['status'];
873 $position = ( isset($_POST['position']) && (int) $_POST['position']) ? (int) $_POST['position'] : '-1';
874 $comments_status = isset($_POST['comments_listing']) ? $_POST['comments_listing'] : '';
876 $checkbox = ( isset($_POST['checkbox']) && true == $_POST['checkbox'] ) ? 1 : 0;
877 $wp_list_table = _get_list_table( $checkbox ? 'WP_Comments_List_Table' : 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
879 $comment = get_comment( $comment_id );
880 if ( empty( $comment->comment_ID ) )
884 $wp_list_table->single_row( $comment );
885 $comment_list_item = ob_get_clean();
887 $x = new WP_Ajax_Response();
890 'what' => 'edit_comment',
891 'id' => $comment->comment_ID,
892 'data' => $comment_list_item,
893 'position' => $position
899 function wp_ajax_add_menu_item() {
900 check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' );
902 if ( ! current_user_can( 'edit_theme_options' ) )
905 require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
907 // For performance reasons, we omit some object properties from the checklist.
908 // The following is a hacky way to restore them when adding non-custom items.
910 $menu_items_data = array();
911 foreach ( (array) $_POST['menu-item'] as $menu_item_data ) {
913 ! empty( $menu_item_data['menu-item-type'] ) &&
914 'custom' != $menu_item_data['menu-item-type'] &&
915 ! empty( $menu_item_data['menu-item-object-id'] )
917 switch( $menu_item_data['menu-item-type'] ) {
919 $_object = get_post( $menu_item_data['menu-item-object-id'] );
923 $_object = get_term( $menu_item_data['menu-item-object-id'], $menu_item_data['menu-item-object'] );
927 $_menu_items = array_map( 'wp_setup_nav_menu_item', array( $_object ) );
928 $_menu_item = array_shift( $_menu_items );
930 // Restore the missing menu item properties
931 $menu_item_data['menu-item-description'] = $_menu_item->description;
934 $menu_items_data[] = $menu_item_data;
937 $item_ids = wp_save_nav_menu_items( 0, $menu_items_data );
938 if ( is_wp_error( $item_ids ) )
941 $menu_items = array();
943 foreach ( (array) $item_ids as $menu_item_id ) {
944 $menu_obj = get_post( $menu_item_id );
945 if ( ! empty( $menu_obj->ID ) ) {
946 $menu_obj = wp_setup_nav_menu_item( $menu_obj );
947 $menu_obj->label = $menu_obj->title; // don't show "(pending)" in ajax-added items
948 $menu_items[] = $menu_obj;
953 * Filter the Walker class used when adding nav menu items.
957 * @param string $class The walker class to use. Default 'Walker_Nav_Menu_Edit'.
958 * @param int $menu_id The menu id, derived from $_POST['menu'].
960 $walker_class_name = apply_filters( 'wp_edit_nav_menu_walker', 'Walker_Nav_Menu_Edit', $_POST['menu'] );
962 if ( ! class_exists( $walker_class_name ) )
965 if ( ! empty( $menu_items ) ) {
971 'walker' => new $walker_class_name,
973 echo walk_nav_menu_tree( $menu_items, 0, (object) $args );
978 function wp_ajax_add_meta() {
979 check_ajax_referer( 'add-meta', '_ajax_nonce-add-meta' );
981 $pid = (int) $_POST['post_id'];
982 $post = get_post( $pid );
984 if ( isset($_POST['metakeyselect']) || isset($_POST['metakeyinput']) ) {
985 if ( !current_user_can( 'edit_post', $pid ) )
987 if ( isset($_POST['metakeyselect']) && '#NONE#' == $_POST['metakeyselect'] && empty($_POST['metakeyinput']) )
989 if ( $post->post_status == 'auto-draft' ) {
990 $save_POST = $_POST; // Backup $_POST
991 $_POST = array(); // Make it empty for edit_post()
992 $_POST['action'] = 'draft'; // Warning fix
993 $_POST['post_ID'] = $pid;
994 $_POST['post_type'] = $post->post_type;
995 $_POST['post_status'] = 'draft';
996 $now = current_time('timestamp', 1);
997 $_POST['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), date( get_option( 'date_format' ), $now ), date( get_option( 'time_format' ), $now ) );
999 if ( $pid = edit_post() ) {
1000 if ( is_wp_error( $pid ) ) {
1001 $x = new WP_Ajax_Response( array(
1007 $_POST = $save_POST; // Now we can restore original $_POST again
1008 if ( !$mid = add_meta( $pid ) )
1009 wp_die( __( 'Please provide a custom field value.' ) );
1013 } else if ( !$mid = add_meta( $pid ) ) {
1014 wp_die( __( 'Please provide a custom field value.' ) );
1017 $meta = get_metadata_by_mid( 'post', $mid );
1018 $pid = (int) $meta->post_id;
1019 $meta = get_object_vars( $meta );
1020 $x = new WP_Ajax_Response( array(
1023 'data' => _list_meta_row( $meta, $c ),
1025 'supplemental' => array('postid' => $pid)
1028 $mid = (int) key( $_POST['meta'] );
1029 $key = wp_unslash( $_POST['meta'][$mid]['key'] );
1030 $value = wp_unslash( $_POST['meta'][$mid]['value'] );
1031 if ( '' == trim($key) )
1032 wp_die( __( 'Please provide a custom field name.' ) );
1033 if ( '' == trim($value) )
1034 wp_die( __( 'Please provide a custom field value.' ) );
1035 if ( ! $meta = get_metadata_by_mid( 'post', $mid ) )
1036 wp_die( 0 ); // if meta doesn't exist
1037 if ( is_protected_meta( $meta->meta_key, 'post' ) || is_protected_meta( $key, 'post' ) ||
1038 ! current_user_can( 'edit_post_meta', $meta->post_id, $meta->meta_key ) ||
1039 ! current_user_can( 'edit_post_meta', $meta->post_id, $key ) )
1041 if ( $meta->meta_value != $value || $meta->meta_key != $key ) {
1042 if ( !$u = update_metadata_by_mid( 'post', $mid, $value, $key ) )
1043 wp_die( 0 ); // We know meta exists; we also know it's unchanged (or DB error, in which case there are bigger problems).
1046 $x = new WP_Ajax_Response( array(
1048 'id' => $mid, 'old_id' => $mid,
1049 'data' => _list_meta_row( array(
1051 'meta_value' => $value,
1055 'supplemental' => array('postid' => $meta->post_id)
1061 function wp_ajax_add_user( $action ) {
1062 global $wp_list_table;
1063 if ( empty( $action ) )
1064 $action = 'add-user';
1066 check_ajax_referer( $action );
1067 if ( ! current_user_can('create_users') )
1069 if ( ! $user_id = edit_user() ) {
1071 } elseif ( is_wp_error( $user_id ) ) {
1072 $x = new WP_Ajax_Response( array(
1078 $user_object = get_userdata( $user_id );
1080 $wp_list_table = _get_list_table('WP_Users_List_Table');
1082 $role = current( $user_object->roles );
1084 $x = new WP_Ajax_Response( array(
1087 'data' => $wp_list_table->single_row( $user_object, '', $role ),
1088 'supplemental' => array(
1089 'show-link' => sprintf(__( 'User <a href="#%s">%s</a> added' ), "user-$user_id", $user_object->user_login),
1096 function wp_ajax_autosave() {
1097 define( 'DOING_AUTOSAVE', true );
1099 check_ajax_referer( 'autosave', 'autosavenonce' );
1101 if ( ! empty( $_POST['catslist'] ) )
1102 $_POST['post_category'] = explode( ',', $_POST['catslist'] );
1103 if ( $_POST['post_type'] == 'page' || empty( $_POST['post_category'] ) )
1104 unset( $_POST['post_category'] );
1107 $supplemental = array();
1108 $id = $revision_id = 0;
1110 $post_id = (int) $_POST['post_id'];
1111 $_POST['ID'] = $_POST['post_ID'] = $post_id;
1112 $post = get_post( $post_id );
1113 if ( empty( $post->ID ) || ! current_user_can( 'edit_post', $post->ID ) )
1114 wp_die( __( 'You are not allowed to edit this post.' ) );
1116 if ( 'page' == $post->post_type && ! current_user_can( 'edit_page', $post->ID ) )
1117 wp_die( __( 'You are not allowed to edit this page.' ) );
1119 if ( 'auto-draft' == $post->post_status )
1120 $_POST['post_status'] = 'draft';
1122 if ( ! empty( $_POST['autosave'] ) ) {
1123 if ( ! wp_check_post_lock( $post->ID ) && get_current_user_id() == $post->post_author && ( 'auto-draft' == $post->post_status || 'draft' == $post->post_status ) ) {
1124 // Drafts and auto-drafts are just overwritten by autosave for the same user if the post is not locked
1127 // Non drafts or other users drafts are not overwritten. The autosave is stored in a special post revision for each user.
1128 $revision_id = wp_create_post_autosave( $post->ID );
1129 if ( is_wp_error($revision_id) )
1135 if ( ! is_wp_error($id) ) {
1136 /* translators: draft saved date format, see http://php.net/date */
1137 $draft_saved_date_format = __('g:i:s a');
1138 /* translators: %s: date and time */
1139 $data = sprintf( __('Draft saved at %s.'), date_i18n( $draft_saved_date_format ) );
1142 if ( ! empty( $_POST['auto_draft'] ) )
1143 $id = 0; // This tells us it didn't actually save
1148 // @todo Consider exposing any errors, rather than having 'Saving draft...'
1149 $x = new WP_Ajax_Response( array(
1150 'what' => 'autosave',
1153 'supplemental' => $supplemental
1158 function wp_ajax_closed_postboxes() {
1159 check_ajax_referer( 'closedpostboxes', 'closedpostboxesnonce' );
1160 $closed = isset( $_POST['closed'] ) ? explode( ',', $_POST['closed']) : array();
1161 $closed = array_filter($closed);
1163 $hidden = isset( $_POST['hidden'] ) ? explode( ',', $_POST['hidden']) : array();
1164 $hidden = array_filter($hidden);
1166 $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1168 if ( $page != sanitize_key( $page ) )
1171 if ( ! $user = wp_get_current_user() )
1174 if ( is_array($closed) )
1175 update_user_option($user->ID, "closedpostboxes_$page", $closed, true);
1177 if ( is_array($hidden) ) {
1178 $hidden = array_diff( $hidden, array('submitdiv', 'linksubmitdiv', 'manage-menu', 'create-menu') ); // postboxes that are always shown
1179 update_user_option($user->ID, "metaboxhidden_$page", $hidden, true);
1185 function wp_ajax_hidden_columns() {
1186 check_ajax_referer( 'screen-options-nonce', 'screenoptionnonce' );
1187 $hidden = isset( $_POST['hidden'] ) ? $_POST['hidden'] : '';
1188 $hidden = explode( ',', $_POST['hidden'] );
1189 $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1191 if ( $page != sanitize_key( $page ) )
1194 if ( ! $user = wp_get_current_user() )
1197 if ( is_array($hidden) )
1198 update_user_option($user->ID, "manage{$page}columnshidden", $hidden, true);
1203 function wp_ajax_update_welcome_panel() {
1204 check_ajax_referer( 'welcome-panel-nonce', 'welcomepanelnonce' );
1206 if ( ! current_user_can( 'edit_theme_options' ) )
1209 update_user_meta( get_current_user_id(), 'show_welcome_panel', empty( $_POST['visible'] ) ? 0 : 1 );
1214 function wp_ajax_menu_get_metabox() {
1215 if ( ! current_user_can( 'edit_theme_options' ) )
1218 require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
1220 if ( isset( $_POST['item-type'] ) && 'post_type' == $_POST['item-type'] ) {
1222 $callback = 'wp_nav_menu_item_post_type_meta_box';
1223 $items = (array) get_post_types( array( 'show_in_nav_menus' => true ), 'object' );
1224 } elseif ( isset( $_POST['item-type'] ) && 'taxonomy' == $_POST['item-type'] ) {
1226 $callback = 'wp_nav_menu_item_taxonomy_meta_box';
1227 $items = (array) get_taxonomies( array( 'show_ui' => true ), 'object' );
1230 if ( ! empty( $_POST['item-object'] ) && isset( $items[$_POST['item-object']] ) ) {
1231 $menus_meta_box_object = $items[ $_POST['item-object'] ];
1233 * Filter a nav menu meta box object.
1237 * @param object $menus_meta_box_object A nav menu meta box object, such as Page, Post, Category, Tag, etc.
1239 $item = apply_filters( 'nav_menu_meta_box_object', $menus_meta_box_object );
1241 call_user_func_array($callback, array(
1244 'id' => 'add-' . $item->name,
1245 'title' => $item->labels->name,
1246 'callback' => $callback,
1251 $markup = ob_get_clean();
1253 echo json_encode(array(
1254 'replace-id' => $type . '-' . $item->name,
1255 'markup' => $markup,
1262 function wp_ajax_wp_link_ajax() {
1263 check_ajax_referer( 'internal-linking', '_ajax_linking_nonce' );
1267 if ( isset( $_POST['search'] ) )
1268 $args['s'] = wp_unslash( $_POST['search'] );
1269 $args['pagenum'] = ! empty( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
1271 require(ABSPATH . WPINC . '/class-wp-editor.php');
1272 $results = _WP_Editors::wp_link_query( $args );
1274 if ( ! isset( $results ) )
1277 echo json_encode( $results );
1283 function wp_ajax_menu_locations_save() {
1284 if ( ! current_user_can( 'edit_theme_options' ) )
1286 check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' );
1287 if ( ! isset( $_POST['menu-locations'] ) )
1289 set_theme_mod( 'nav_menu_locations', array_map( 'absint', $_POST['menu-locations'] ) );
1293 function wp_ajax_meta_box_order() {
1294 check_ajax_referer( 'meta-box-order' );
1295 $order = isset( $_POST['order'] ) ? (array) $_POST['order'] : false;
1296 $page_columns = isset( $_POST['page_columns'] ) ? $_POST['page_columns'] : 'auto';
1298 if ( $page_columns != 'auto' )
1299 $page_columns = (int) $page_columns;
1301 $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1303 if ( $page != sanitize_key( $page ) )
1306 if ( ! $user = wp_get_current_user() )
1310 update_user_option($user->ID, "meta-box-order_$page", $order, true);
1312 if ( $page_columns )
1313 update_user_option($user->ID, "screen_layout_$page", $page_columns, true);
1318 function wp_ajax_menu_quick_search() {
1319 if ( ! current_user_can( 'edit_theme_options' ) )
1322 require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
1324 _wp_ajax_menu_quick_search( $_POST );
1329 function wp_ajax_get_permalink() {
1330 check_ajax_referer( 'getpermalink', 'getpermalinknonce' );
1331 $post_id = isset($_POST['post_id'])? intval($_POST['post_id']) : 0;
1332 wp_die( add_query_arg( array( 'preview' => 'true' ), get_permalink( $post_id ) ) );
1335 function wp_ajax_sample_permalink() {
1336 check_ajax_referer( 'samplepermalink', 'samplepermalinknonce' );
1337 $post_id = isset($_POST['post_id'])? intval($_POST['post_id']) : 0;
1338 $title = isset($_POST['new_title'])? $_POST['new_title'] : '';
1339 $slug = isset($_POST['new_slug'])? $_POST['new_slug'] : null;
1340 wp_die( get_sample_permalink_html( $post_id, $title, $slug ) );
1343 function wp_ajax_inline_save() {
1344 global $wp_list_table;
1346 check_ajax_referer( 'inlineeditnonce', '_inline_edit' );
1348 if ( ! isset($_POST['post_ID']) || ! ( $post_ID = (int) $_POST['post_ID'] ) )
1351 if ( 'page' == $_POST['post_type'] ) {
1352 if ( ! current_user_can( 'edit_page', $post_ID ) )
1353 wp_die( __( 'You are not allowed to edit this page.' ) );
1355 if ( ! current_user_can( 'edit_post', $post_ID ) )
1356 wp_die( __( 'You are not allowed to edit this post.' ) );
1359 if ( $last = wp_check_post_lock( $post_ID ) ) {
1360 $last_user = get_userdata( $last );
1361 $last_user_name = $last_user ? $last_user->display_name : __( 'Someone' );
1362 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 ) );
1368 $post = get_post( $post_ID, ARRAY_A );
1369 $post = wp_slash($post); //since it is from db
1371 $data['content'] = $post['post_content'];
1372 $data['excerpt'] = $post['post_excerpt'];
1375 $data['user_ID'] = get_current_user_id();
1377 if ( isset($data['post_parent']) )
1378 $data['parent_id'] = $data['post_parent'];
1381 if ( isset($data['keep_private']) && 'private' == $data['keep_private'] )
1382 $data['post_status'] = 'private';
1384 $data['post_status'] = $data['_status'];
1386 if ( empty($data['comment_status']) )
1387 $data['comment_status'] = 'closed';
1388 if ( empty($data['ping_status']) )
1389 $data['ping_status'] = 'closed';
1391 // Hack: wp_unique_post_slug() doesn't work for drafts, so we will fake that our post is published.
1392 if ( ! empty( $data['post_name'] ) && in_array( $post['post_status'], array( 'draft', 'pending' ) ) ) {
1393 $post['post_status'] = 'publish';
1394 $data['post_name'] = wp_unique_post_slug( $data['post_name'], $post['ID'], $post['post_status'], $post['post_type'], $post['post_parent'] );
1400 $wp_list_table = _get_list_table( 'WP_Posts_List_Table', array( 'screen' => $_POST['screen'] ) );
1402 $mode = $_POST['post_view'];
1405 $request_post = array( get_post( $_POST['post_ID'] ) );
1406 $parent = $request_post[0]->post_parent;
1408 while ( $parent > 0 ) {
1409 $parent_post = get_post( $parent );
1410 $parent = $parent_post->post_parent;
1414 $wp_list_table->display_rows( array( get_post( $_POST['post_ID'] ) ), $level );
1419 function wp_ajax_inline_save_tax() {
1420 global $wp_list_table;
1422 check_ajax_referer( 'taxinlineeditnonce', '_inline_edit' );
1424 $taxonomy = sanitize_key( $_POST['taxonomy'] );
1425 $tax = get_taxonomy( $taxonomy );
1429 if ( ! current_user_can( $tax->cap->edit_terms ) )
1432 $wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => 'edit-' . $taxonomy ) );
1434 if ( ! isset($_POST['tax_ID']) || ! ( $id = (int) $_POST['tax_ID'] ) )
1437 $tag = get_term( $id, $taxonomy );
1438 $_POST['description'] = $tag->description;
1440 $updated = wp_update_term($id, $taxonomy, $_POST);
1441 if ( $updated && !is_wp_error($updated) ) {
1442 $tag = get_term( $updated['term_id'], $taxonomy );
1443 if ( !$tag || is_wp_error( $tag ) ) {
1444 if ( is_wp_error($tag) && $tag->get_error_message() )
1445 wp_die( $tag->get_error_message() );
1446 wp_die( __( 'Item not updated.' ) );
1449 if ( is_wp_error($updated) && $updated->get_error_message() )
1450 wp_die( $updated->get_error_message() );
1451 wp_die( __( 'Item not updated.' ) );
1454 $parent = $tag->parent;
1455 while ( $parent > 0 ) {
1456 $parent_tag = get_term( $parent, $taxonomy );
1457 $parent = $parent_tag->parent;
1460 $wp_list_table->single_row( $tag, $level );
1464 function wp_ajax_find_posts() {
1467 check_ajax_referer( 'find-posts' );
1469 $post_types = get_post_types( array( 'public' => true ), 'objects' );
1470 unset( $post_types['attachment'] );
1472 $s = wp_unslash( $_POST['ps'] );
1473 $searchand = $search = '';
1475 'post_type' => array_keys( $post_types ),
1476 'post_status' => 'any',
1477 'posts_per_page' => 50,
1482 $posts = get_posts( $args );
1485 wp_die( __('No items found.') );
1487 $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>';
1488 foreach ( $posts as $post ) {
1489 $title = trim( $post->post_title ) ? $post->post_title : __( '(no title)' );
1491 switch ( $post->post_status ) {
1494 $stat = __('Published');
1497 $stat = __('Scheduled');
1500 $stat = __('Pending Review');
1503 $stat = __('Draft');
1507 if ( '0000-00-00 00:00:00' == $post->post_date ) {
1510 /* translators: date format in table columns, see http://php.net/date */
1511 $time = mysql2date(__('Y/m/d'), $post->post_date);
1514 $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>';
1515 $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";
1518 $html .= '</tbody></table>';
1520 $x = new WP_Ajax_Response();
1527 function wp_ajax_widgets_order() {
1528 check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' );
1530 if ( !current_user_can('edit_theme_options') )
1533 unset( $_POST['savewidgets'], $_POST['action'] );
1535 // save widgets order for all sidebars
1536 if ( is_array($_POST['sidebars']) ) {
1537 $sidebars = array();
1538 foreach ( $_POST['sidebars'] as $key => $val ) {
1540 if ( !empty($val) ) {
1541 $val = explode(',', $val);
1542 foreach ( $val as $k => $v ) {
1543 if ( strpos($v, 'widget-') === false )
1546 $sb[$k] = substr($v, strpos($v, '_') + 1);
1549 $sidebars[$key] = $sb;
1551 wp_set_sidebars_widgets($sidebars);
1558 function wp_ajax_save_widget() {
1559 global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
1561 check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' );
1563 if ( !current_user_can('edit_theme_options') || !isset($_POST['id_base']) )
1566 unset( $_POST['savewidgets'], $_POST['action'] );
1569 * Fires early when editing the widgets displayed in sidebars.
1573 do_action( 'load-widgets.php' );
1576 * Fires early when editing the widgets displayed in sidebars.
1580 do_action( 'widgets.php' );
1583 * Fires early when editing the widgets displayed in sidebars.
1587 do_action( 'sidebar_admin_setup' );
1589 $id_base = $_POST['id_base'];
1590 $widget_id = $_POST['widget-id'];
1591 $sidebar_id = $_POST['sidebar'];
1592 $multi_number = !empty($_POST['multi_number']) ? (int) $_POST['multi_number'] : 0;
1593 $settings = isset($_POST['widget-' . $id_base]) && is_array($_POST['widget-' . $id_base]) ? $_POST['widget-' . $id_base] : false;
1594 $error = '<p>' . __('An error has occurred. Please reload the page and try again.') . '</p>';
1596 $sidebars = wp_get_sidebars_widgets();
1597 $sidebar = isset($sidebars[$sidebar_id]) ? $sidebars[$sidebar_id] : array();
1600 if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
1602 if ( !isset($wp_registered_widgets[$widget_id]) )
1605 $sidebar = array_diff( $sidebar, array($widget_id) );
1606 $_POST = array('sidebar' => $sidebar_id, 'widget-' . $id_base => array(), 'the-widget-id' => $widget_id, 'delete_widget' => '1');
1607 } elseif ( $settings && preg_match( '/__i__|%i%/', key($settings) ) ) {
1608 if ( !$multi_number )
1611 $_POST['widget-' . $id_base] = array( $multi_number => array_shift($settings) );
1612 $widget_id = $id_base . '-' . $multi_number;
1613 $sidebar[] = $widget_id;
1615 $_POST['widget-id'] = $sidebar;
1617 foreach ( (array) $wp_registered_widget_updates as $name => $control ) {
1619 if ( $name == $id_base ) {
1620 if ( !is_callable( $control['callback'] ) )
1624 call_user_func_array( $control['callback'], $control['params'] );
1630 if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
1631 $sidebars[$sidebar_id] = $sidebar;
1632 wp_set_sidebars_widgets($sidebars);
1633 echo "deleted:$widget_id";
1637 if ( !empty($_POST['add_new']) )
1640 if ( $form = $wp_registered_widget_controls[$widget_id] )
1641 call_user_func_array( $form['callback'], $form['params'] );
1646 function wp_ajax_upload_attachment() {
1647 check_ajax_referer( 'media-form' );
1649 if ( ! current_user_can( 'upload_files' ) )
1652 if ( isset( $_REQUEST['post_id'] ) ) {
1653 $post_id = $_REQUEST['post_id'];
1654 if ( ! current_user_can( 'edit_post', $post_id ) )
1660 $post_data = isset( $_REQUEST['post_data'] ) ? $_REQUEST['post_data'] : array();
1662 // If the context is custom header or background, make sure the uploaded file is an image.
1663 if ( isset( $post_data['context'] ) && in_array( $post_data['context'], array( 'custom-header', 'custom-background' ) ) ) {
1664 $wp_filetype = wp_check_filetype_and_ext( $_FILES['async-upload']['tmp_name'], $_FILES['async-upload']['name'], false );
1665 if ( ! wp_match_mime_types( 'image', $wp_filetype['type'] ) ) {
1666 echo json_encode( array(
1669 'message' => __( 'The uploaded file is not a valid image. Please try again.' ),
1670 'filename' => $_FILES['async-upload']['name'],
1678 $attachment_id = media_handle_upload( 'async-upload', $post_id, $post_data );
1680 if ( is_wp_error( $attachment_id ) ) {
1681 echo json_encode( array(
1684 'message' => $attachment_id->get_error_message(),
1685 'filename' => $_FILES['async-upload']['name'],
1692 if ( isset( $post_data['context'] ) && isset( $post_data['theme'] ) ) {
1693 if ( 'custom-background' === $post_data['context'] )
1694 update_post_meta( $attachment_id, '_wp_attachment_is_custom_background', $post_data['theme'] );
1696 if ( 'custom-header' === $post_data['context'] )
1697 update_post_meta( $attachment_id, '_wp_attachment_is_custom_header', $post_data['theme'] );
1700 if ( ! $attachment = wp_prepare_attachment_for_js( $attachment_id ) )
1703 echo json_encode( array(
1705 'data' => $attachment,
1711 function wp_ajax_image_editor() {
1712 $attachment_id = intval($_POST['postid']);
1713 if ( empty($attachment_id) || !current_user_can('edit_post', $attachment_id) )
1716 check_ajax_referer( "image_editor-$attachment_id" );
1717 include_once( ABSPATH . 'wp-admin/includes/image-edit.php' );
1720 switch ( $_POST['do'] ) {
1722 $msg = wp_save_image($attachment_id);
1723 $msg = json_encode($msg);
1727 $msg = wp_save_image($attachment_id);
1730 $msg = wp_restore_image($attachment_id);
1734 wp_image_editor($attachment_id, $msg);
1738 function wp_ajax_set_post_thumbnail() {
1739 $json = ! empty( $_REQUEST['json'] ); // New-style request
1741 $post_ID = intval( $_POST['post_id'] );
1742 if ( ! current_user_can( 'edit_post', $post_ID ) )
1745 $thumbnail_id = intval( $_POST['thumbnail_id'] );
1748 check_ajax_referer( "update-post_$post_ID" );
1750 check_ajax_referer( "set_post_thumbnail-$post_ID" );
1752 if ( $thumbnail_id == '-1' ) {
1753 if ( delete_post_thumbnail( $post_ID ) ) {
1754 $return = _wp_post_thumbnail_html( null, $post_ID );
1755 $json ? wp_send_json_success( $return ) : wp_die( $return );
1761 if ( set_post_thumbnail( $post_ID, $thumbnail_id ) ) {
1762 $return = _wp_post_thumbnail_html( $thumbnail_id, $post_ID );
1763 $json ? wp_send_json_success( $return ) : wp_die( $return );
1769 function wp_ajax_date_format() {
1770 wp_die( date_i18n( sanitize_option( 'date_format', $_POST['date'] ) ) );
1773 function wp_ajax_time_format() {
1774 wp_die( date_i18n( sanitize_option( 'time_format', $_POST['date'] ) ) );
1777 function wp_ajax_wp_fullscreen_save_post() {
1778 $post_id = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0;
1780 $post = $post_type = null;
1783 $post = get_post( $post_id );
1786 $post_type = $post->post_type;
1787 elseif ( isset( $_POST['post_type'] ) && post_type_exists( $_POST['post_type'] ) )
1788 $post_type = $_POST['post_type'];
1790 check_ajax_referer('update-post_' . $post_id, '_wpnonce');
1792 $post_id = edit_post();
1794 if ( is_wp_error($post_id) ) {
1795 if ( $post_id->get_error_message() )
1796 $message = $post_id->get_error_message();
1798 $message = __('Save failed');
1800 echo json_encode( array( 'message' => $message, 'last_edited' => '' ) );
1803 $message = __('Saved.');
1807 $last_date = mysql2date( get_option('date_format'), $post->post_modified );
1808 $last_time = mysql2date( get_option('time_format'), $post->post_modified );
1810 $last_date = date_i18n( get_option('date_format') );
1811 $last_time = date_i18n( get_option('time_format') );
1814 if ( $last_id = get_post_meta($post_id, '_edit_last', true) ) {
1815 $last_user = get_userdata($last_id);
1816 $last_edited = sprintf( __('Last edited by %1$s on %2$s at %3$s'), esc_html( $last_user->display_name ), $last_date, $last_time );
1818 $last_edited = sprintf( __('Last edited on %1$s at %2$s'), $last_date, $last_time );
1821 echo json_encode( array( 'message' => $message, 'last_edited' => $last_edited ) );
1825 function wp_ajax_wp_remove_post_lock() {
1826 if ( empty( $_POST['post_ID'] ) || empty( $_POST['active_post_lock'] ) )
1828 $post_id = (int) $_POST['post_ID'];
1829 if ( ! $post = get_post( $post_id ) )
1832 check_ajax_referer( 'update-post_' . $post_id );
1834 if ( ! current_user_can( 'edit_post', $post_id ) )
1837 $active_lock = array_map( 'absint', explode( ':', $_POST['active_post_lock'] ) );
1838 if ( $active_lock[1] != get_current_user_id() )
1842 * Filter the post lock window duration.
1846 * @param int $interval The interval in seconds the post lock duration should last, plus 5 seconds. Default 120.
1848 $new_lock = ( time() - apply_filters( 'wp_check_post_lock_window', 120 ) + 5 ) . ':' . $active_lock[1];
1849 update_post_meta( $post_id, '_edit_lock', $new_lock, implode( ':', $active_lock ) );
1853 function wp_ajax_dismiss_wp_pointer() {
1854 $pointer = $_POST['pointer'];
1855 if ( $pointer != sanitize_key( $pointer ) )
1858 // check_ajax_referer( 'dismiss-pointer_' . $pointer );
1860 $dismissed = array_filter( explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) ) );
1862 if ( in_array( $pointer, $dismissed ) )
1865 $dismissed[] = $pointer;
1866 $dismissed = implode( ',', $dismissed );
1868 update_user_meta( get_current_user_id(), 'dismissed_wp_pointers', $dismissed );
1873 * Get an attachment.
1877 function wp_ajax_get_attachment() {
1878 if ( ! isset( $_REQUEST['id'] ) )
1879 wp_send_json_error();
1881 if ( ! $id = absint( $_REQUEST['id'] ) )
1882 wp_send_json_error();
1884 if ( ! $post = get_post( $id ) )
1885 wp_send_json_error();
1887 if ( 'attachment' != $post->post_type )
1888 wp_send_json_error();
1890 if ( ! current_user_can( 'upload_files' ) )
1891 wp_send_json_error();
1893 if ( ! $attachment = wp_prepare_attachment_for_js( $id ) )
1894 wp_send_json_error();
1896 wp_send_json_success( $attachment );
1900 * Query for attachments.
1904 function wp_ajax_query_attachments() {
1905 if ( ! current_user_can( 'upload_files' ) )
1906 wp_send_json_error();
1908 $query = isset( $_REQUEST['query'] ) ? (array) $_REQUEST['query'] : array();
1909 $query = array_intersect_key( $query, array_flip( array(
1910 's', 'order', 'orderby', 'posts_per_page', 'paged', 'post_mime_type',
1911 'post_parent', 'post__in', 'post__not_in',
1914 $query['post_type'] = 'attachment';
1915 $query['post_status'] = 'inherit';
1916 if ( current_user_can( get_post_type_object( 'attachment' )->cap->read_private_posts ) )
1917 $query['post_status'] .= ',private';
1920 * Filter the arguments passed to WP_Query during an AJAX call for querying attachments.
1924 * @param array $query An array of query variables. @see WP_Query::parse_query()
1926 $query = apply_filters( 'ajax_query_attachments_args', $query );
1927 $query = new WP_Query( $query );
1929 $posts = array_map( 'wp_prepare_attachment_for_js', $query->posts );
1930 $posts = array_filter( $posts );
1932 wp_send_json_success( $posts );
1936 * Save attachment attributes.
1940 function wp_ajax_save_attachment() {
1941 if ( ! isset( $_REQUEST['id'] ) || ! isset( $_REQUEST['changes'] ) )
1942 wp_send_json_error();
1944 if ( ! $id = absint( $_REQUEST['id'] ) )
1945 wp_send_json_error();
1947 check_ajax_referer( 'update-post_' . $id, 'nonce' );
1949 if ( ! current_user_can( 'edit_post', $id ) )
1950 wp_send_json_error();
1952 $changes = $_REQUEST['changes'];
1953 $post = get_post( $id, ARRAY_A );
1955 if ( 'attachment' != $post['post_type'] )
1956 wp_send_json_error();
1958 if ( isset( $changes['title'] ) )
1959 $post['post_title'] = $changes['title'];
1961 if ( isset( $changes['caption'] ) )
1962 $post['post_excerpt'] = $changes['caption'];
1964 if ( isset( $changes['description'] ) )
1965 $post['post_content'] = $changes['description'];
1967 if ( isset( $changes['alt'] ) ) {
1968 $alt = wp_unslash( $changes['alt'] );
1969 if ( $alt != get_post_meta( $id, '_wp_attachment_image_alt', true ) ) {
1970 $alt = wp_strip_all_tags( $alt, true );
1971 update_post_meta( $id, '_wp_attachment_image_alt', wp_slash( $alt ) );
1975 wp_update_post( $post );
1976 wp_send_json_success();
1980 * Save backwards compatible attachment attributes.
1984 function wp_ajax_save_attachment_compat() {
1985 if ( ! isset( $_REQUEST['id'] ) )
1986 wp_send_json_error();
1988 if ( ! $id = absint( $_REQUEST['id'] ) )
1989 wp_send_json_error();
1991 if ( empty( $_REQUEST['attachments'] ) || empty( $_REQUEST['attachments'][ $id ] ) )
1992 wp_send_json_error();
1993 $attachment_data = $_REQUEST['attachments'][ $id ];
1995 check_ajax_referer( 'update-post_' . $id, 'nonce' );
1997 if ( ! current_user_can( 'edit_post', $id ) )
1998 wp_send_json_error();
2000 $post = get_post( $id, ARRAY_A );
2002 if ( 'attachment' != $post['post_type'] )
2003 wp_send_json_error();
2005 /** This filter is documented in wp-admin/includes/media.php */
2006 $post = apply_filters( 'attachment_fields_to_save', $post, $attachment_data );
2008 if ( isset( $post['errors'] ) ) {
2009 $errors = $post['errors']; // @todo return me and display me!
2010 unset( $post['errors'] );
2013 wp_update_post( $post );
2015 foreach ( get_attachment_taxonomies( $post ) as $taxonomy ) {
2016 if ( isset( $attachment_data[ $taxonomy ] ) )
2017 wp_set_object_terms( $id, array_map( 'trim', preg_split( '/,+/', $attachment_data[ $taxonomy ] ) ), $taxonomy, false );
2020 if ( ! $attachment = wp_prepare_attachment_for_js( $id ) )
2021 wp_send_json_error();
2023 wp_send_json_success( $attachment );
2026 function wp_ajax_save_attachment_order() {
2027 if ( ! isset( $_REQUEST['post_id'] ) )
2028 wp_send_json_error();
2030 if ( ! $post_id = absint( $_REQUEST['post_id'] ) )
2031 wp_send_json_error();
2033 if ( empty( $_REQUEST['attachments'] ) )
2034 wp_send_json_error();
2036 check_ajax_referer( 'update-post_' . $post_id, 'nonce' );
2038 $attachments = $_REQUEST['attachments'];
2040 if ( ! current_user_can( 'edit_post', $post_id ) )
2041 wp_send_json_error();
2043 $post = get_post( $post_id, ARRAY_A );
2045 foreach ( $attachments as $attachment_id => $menu_order ) {
2046 if ( ! current_user_can( 'edit_post', $attachment_id ) )
2048 if ( ! $attachment = get_post( $attachment_id ) )
2050 if ( 'attachment' != $attachment->post_type )
2053 wp_update_post( array( 'ID' => $attachment_id, 'menu_order' => $menu_order ) );
2056 wp_send_json_success();
2060 * Generates the HTML to send an attachment to the editor.
2061 * Backwards compatible with the media_send_to_editor filter and the chain
2062 * of filters that follow.
2066 function wp_ajax_send_attachment_to_editor() {
2067 check_ajax_referer( 'media-send-to-editor', 'nonce' );
2069 $attachment = wp_unslash( $_POST['attachment'] );
2071 $id = intval( $attachment['id'] );
2073 if ( ! $post = get_post( $id ) )
2074 wp_send_json_error();
2076 if ( 'attachment' != $post->post_type )
2077 wp_send_json_error();
2079 if ( current_user_can( 'edit_post', $id ) ) {
2080 // If this attachment is unattached, attach it. Primarily a back compat thing.
2081 if ( 0 == $post->post_parent && $insert_into_post_id = intval( $_POST['post_id'] ) ) {
2082 wp_update_post( array( 'ID' => $id, 'post_parent' => $insert_into_post_id ) );
2087 $html = $title = isset( $attachment['post_title'] ) ? $attachment['post_title'] : '';
2088 if ( ! empty( $attachment['url'] ) ) {
2089 $url = $attachment['url'];
2090 if ( strpos( $url, 'attachment_id') || get_attachment_link( $id ) == $url )
2091 $rel = ' rel="attachment wp-att-' . $id . '"';
2092 $html = '<a href="' . esc_url( $url ) . '"' . $rel . '>' . $html . '</a>';
2095 remove_filter( 'media_send_to_editor', 'image_media_send_to_editor' );
2097 if ( 'image' === substr( $post->post_mime_type, 0, 5 ) ) {
2098 $align = isset( $attachment['align'] ) ? $attachment['align'] : 'none';
2099 $size = isset( $attachment['image-size'] ) ? $attachment['image-size'] : 'medium';
2100 $alt = isset( $attachment['image_alt'] ) ? $attachment['image_alt'] : '';
2101 $caption = isset( $attachment['post_excerpt'] ) ? $attachment['post_excerpt'] : '';
2102 $title = ''; // We no longer insert title tags into <img> tags, as they are redundant.
2103 $html = get_image_send_to_editor( $id, $caption, $title, $align, $url, (bool) $rel, $size, $alt );
2104 } elseif ( 'video' === substr( $post->post_mime_type, 0, 5 ) || 'audio' === substr( $post->post_mime_type, 0, 5 ) ) {
2105 $html = stripslashes_deep( $_POST['html'] );
2108 /** This filter is documented in wp-admin/includes/media.php */
2109 $html = apply_filters( 'media_send_to_editor', $html, $id, $attachment );
2111 wp_send_json_success( $html );
2115 * Generates the HTML to send a non-image embed link to the editor.
2117 * Backwards compatible with the following filters:
2118 * - file_send_to_editor_url
2119 * - audio_send_to_editor_url
2120 * - video_send_to_editor_url
2124 function wp_ajax_send_link_to_editor() {
2125 check_ajax_referer( 'media-send-to-editor', 'nonce' );
2127 if ( ! $src = wp_unslash( $_POST['src'] ) )
2128 wp_send_json_error();
2130 if ( ! strpos( $src, '://' ) )
2131 $src = 'http://' . $src;
2133 if ( ! $src = esc_url_raw( $src ) )
2134 wp_send_json_error();
2136 if ( ! $title = trim( wp_unslash( $_POST['title'] ) ) )
2137 $title = wp_basename( $src );
2141 $html = '<a href="' . esc_url( $src ) . '">' . $title . '</a>';
2143 // Figure out what filter to run:
2145 if ( ( $ext = preg_replace( '/^.+?\.([^.]+)$/', '$1', $src ) ) && ( $ext_type = wp_ext2type( $ext ) )
2146 && ( 'audio' == $ext_type || 'video' == $ext_type ) )
2149 /** This filter is documented in wp-admin/includes/media.php */
2150 $html = apply_filters( $type . '_send_to_editor_url', $html, $src, $title );
2152 wp_send_json_success( $html );
2156 * Heartbeat API (experimental)
2158 * Runs when the user is logged in.
2160 function wp_ajax_heartbeat() {
2161 if ( empty( $_POST['_nonce'] ) )
2162 wp_send_json_error();
2164 $response = array();
2166 if ( false === wp_verify_nonce( $_POST['_nonce'], 'heartbeat-nonce' ) ) {
2167 // User is logged in but nonces have expired.
2168 $response['nonces_expired'] = true;
2169 wp_send_json($response);
2172 // screen_id is the same as $current_screen->id and the JS global 'pagenow'
2173 if ( ! empty($_POST['screen_id']) )
2174 $screen_id = sanitize_key($_POST['screen_id']);
2176 $screen_id = 'front';
2178 if ( ! empty($_POST['data']) ) {
2179 $data = (array) $_POST['data'];
2182 * Filter the Heartbeat response received.
2186 * @param array|object $response The Heartbeat response object or array.
2187 * @param array $data The $_POST data sent.
2188 * @param string $screen_id The screen id.
2190 $response = apply_filters( 'heartbeat_received', $response, $data, $screen_id );
2194 * Filter the Heartbeat response sent.
2198 * @param array|object $response The Heartbeat response object or array.
2199 * @param string $screen_id The screen id.
2201 $response = apply_filters( 'heartbeat_send', $response, $screen_id );
2204 * Fires when Heartbeat ticks in logged-in environments.
2206 * Allows the transport to be easily replaced with long-polling.
2210 * @param array|object $response The Heartbeat response object or array.
2211 * @param string $screen_id The screen id.
2213 do_action( 'heartbeat_tick', $response, $screen_id );
2215 // Send the current time according to the server
2216 $response['server_time'] = time();
2218 wp_send_json($response);
2221 function wp_ajax_get_revision_diffs() {
2222 require ABSPATH . 'wp-admin/includes/revision.php';
2224 if ( ! $post = get_post( (int) $_REQUEST['post_id'] ) )
2225 wp_send_json_error();
2227 if ( ! current_user_can( 'read_post', $post->ID ) )
2228 wp_send_json_error();
2230 // Really just pre-loading the cache here.
2231 if ( ! $revisions = wp_get_post_revisions( $post->ID, array( 'check_enabled' => false ) ) )
2232 wp_send_json_error();
2235 @set_time_limit( 0 );
2237 foreach ( $_REQUEST['compare'] as $compare_key ) {
2238 list( $compare_from, $compare_to ) = explode( ':', $compare_key ); // from:to
2241 'id' => $compare_key,
2242 'fields' => wp_get_revision_ui_diff( $post, $compare_from, $compare_to ),
2245 wp_send_json_success( $return );