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 // Current allowed values are `add` and `search`
201 if ( isset( $_REQUEST['autocomplete_type'] ) && 'search' === $_REQUEST['autocomplete_type'] ) {
202 $type = $_REQUEST['autocomplete_type'];
207 // Check the desired field for value
208 // Current allowed values are `user_email` and `user_login`
209 if ( isset( $_REQUEST['autocomplete_field'] ) && 'user_email' === $_REQUEST['autocomplete_field'] ) {
210 $field = $_REQUEST['autocomplete_field'];
212 $field = 'user_login';
215 // Exclude current users of this blog
216 if ( isset( $_REQUEST['site_id'] ) ) {
217 $id = absint( $_REQUEST['site_id'] );
219 $id = get_current_blog_id();
222 $include_blog_users = ( $type == 'search' ? get_users( array( 'blog_id' => $id, 'fields' => 'ID' ) ) : array() );
223 $exclude_blog_users = ( $type == 'add' ? get_users( array( 'blog_id' => $id, 'fields' => 'ID' ) ) : array() );
225 $users = get_users( array(
227 'search' => '*' . $_REQUEST['term'] . '*',
228 'include' => $include_blog_users,
229 'exclude' => $exclude_blog_users,
230 'search_columns' => array( 'user_login', 'user_nicename', 'user_email' ),
233 foreach ( $users as $user ) {
235 /* translators: 1: user_login, 2: user_email */
236 'label' => sprintf( __( '%1$s (%2$s)' ), $user->user_login, $user->user_email ),
237 'value' => $user->$field,
241 wp_die( json_encode( $return ) );
244 function wp_ajax_dashboard_widgets() {
245 require_once ABSPATH . 'wp-admin/includes/dashboard.php';
247 $pagenow = $_GET['pagenow'];
248 if ( $pagenow === 'dashboard-user' || $pagenow === 'dashboard-network' || $pagenow === 'dashboard' ) {
249 set_current_screen( $pagenow );
252 switch ( $_GET['widget'] ) {
253 case 'dashboard_primary' :
254 wp_dashboard_primary();
260 function wp_ajax_logged_in() {
269 * Sends back current comment total and new page links if they need to be updated.
271 * Contrary to normal success AJAX response ("1"), die with time() on success.
275 * @param int $comment_id
278 function _wp_ajax_delete_comment_response( $comment_id, $delta = -1 ) {
279 $total = isset( $_POST['_total'] ) ? (int) $_POST['_total'] : 0;
280 $per_page = isset( $_POST['_per_page'] ) ? (int) $_POST['_per_page'] : 0;
281 $page = isset( $_POST['_page'] ) ? (int) $_POST['_page'] : 0;
282 $url = isset( $_POST['_url'] ) ? esc_url_raw( $_POST['_url'] ) : '';
284 // JS didn't send us everything we need to know. Just die with success message
285 if ( !$total || !$per_page || !$page || !$url )
292 // Only do the expensive stuff on a page-break, and about 1 other time per page
293 if ( 0 == $total % $per_page || 1 == mt_rand( 1, $per_page ) ) {
295 $status = 'total_comments'; // What type of comment count are we looking for?
296 $parsed = parse_url( $url );
297 if ( isset( $parsed['query'] ) ) {
298 parse_str( $parsed['query'], $query_vars );
299 if ( !empty( $query_vars['comment_status'] ) )
300 $status = $query_vars['comment_status'];
301 if ( !empty( $query_vars['p'] ) )
302 $post_id = (int) $query_vars['p'];
305 $comment_count = wp_count_comments($post_id);
307 if ( isset( $comment_count->$status ) ) // We're looking for a known type of comment count
308 $total = $comment_count->$status;
309 // else use the decremented value from above
312 $time = time(); // The time since the last comment count
314 $x = new WP_Ajax_Response( array(
316 'id' => $comment_id, // here for completeness - not used
317 'supplemental' => array(
318 'total_items_i18n' => sprintf( _n( '1 item', '%s items', $total ), number_format_i18n( $total ) ),
319 'total_pages' => ceil( $total / $per_page ),
320 'total_pages_i18n' => number_format_i18n( ceil( $total / $per_page ) ),
329 * POST-based Ajax handlers.
332 function _wp_ajax_add_hierarchical_term() {
333 $action = $_POST['action'];
334 $taxonomy = get_taxonomy(substr($action, 4));
335 check_ajax_referer( $action, '_ajax_nonce-add-' . $taxonomy->name );
336 if ( !current_user_can( $taxonomy->cap->edit_terms ) )
338 $names = explode(',', $_POST['new'.$taxonomy->name]);
339 $parent = isset($_POST['new'.$taxonomy->name.'_parent']) ? (int) $_POST['new'.$taxonomy->name.'_parent'] : 0;
342 if ( $taxonomy->name == 'category' )
343 $post_category = isset($_POST['post_category']) ? (array) $_POST['post_category'] : array();
345 $post_category = ( isset($_POST['tax_input']) && isset($_POST['tax_input'][$taxonomy->name]) ) ? (array) $_POST['tax_input'][$taxonomy->name] : array();
346 $checked_categories = array_map( 'absint', (array) $post_category );
347 $popular_ids = wp_popular_terms_checklist($taxonomy->name, 0, 10, false);
349 foreach ( $names as $cat_name ) {
350 $cat_name = trim($cat_name);
351 $category_nicename = sanitize_title($cat_name);
352 if ( '' === $category_nicename )
354 if ( !$cat_id = term_exists( $cat_name, $taxonomy->name, $parent ) )
355 $cat_id = wp_insert_term( $cat_name, $taxonomy->name, array( 'parent' => $parent ) );
356 if ( is_wp_error( $cat_id ) )
358 else if ( is_array( $cat_id ) )
359 $cat_id = $cat_id['term_id'];
360 $checked_categories[] = $cat_id;
361 if ( $parent ) // Do these all at once in a second
364 wp_terms_checklist( 0, array( 'taxonomy' => $taxonomy->name, 'descendants_and_self' => $cat_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids ));
365 $data = ob_get_contents();
368 'what' => $taxonomy->name,
370 'data' => str_replace( array("\n", "\t"), '', $data),
375 if ( $parent ) { // Foncy - replace the parent and all its children
376 $parent = get_term( $parent, $taxonomy->name );
377 $term_id = $parent->term_id;
379 while ( $parent->parent ) { // get the top parent
380 $parent = get_term( $parent->parent, $taxonomy->name );
381 if ( is_wp_error( $parent ) )
383 $term_id = $parent->term_id;
387 wp_terms_checklist( 0, array('taxonomy' => $taxonomy->name, 'descendants_and_self' => $term_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids));
388 $data = ob_get_contents();
391 'what' => $taxonomy->name,
393 'data' => str_replace( array("\n", "\t"), '', $data),
399 wp_dropdown_categories( array(
400 'taxonomy' => $taxonomy->name, 'hide_empty' => 0, 'name' => 'new'.$taxonomy->name.'_parent', 'orderby' => 'name',
401 'hierarchical' => 1, 'show_option_none' => '— '.$taxonomy->labels->parent_item.' —'
403 $sup = ob_get_contents();
405 $add['supplemental'] = array( 'newcat_parent' => $sup );
407 $x = new WP_Ajax_Response( $add );
411 function wp_ajax_delete_comment() {
412 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
414 if ( !$comment = get_comment( $id ) )
416 if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) )
419 check_ajax_referer( "delete-comment_$id" );
420 $status = wp_get_comment_status( $comment->comment_ID );
423 if ( isset($_POST['trash']) && 1 == $_POST['trash'] ) {
424 if ( 'trash' == $status )
426 $r = wp_trash_comment( $comment->comment_ID );
427 } elseif ( isset($_POST['untrash']) && 1 == $_POST['untrash'] ) {
428 if ( 'trash' != $status )
430 $r = wp_untrash_comment( $comment->comment_ID );
431 if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'trash' ) // undo trash, not in trash
433 } elseif ( isset($_POST['spam']) && 1 == $_POST['spam'] ) {
434 if ( 'spam' == $status )
436 $r = wp_spam_comment( $comment->comment_ID );
437 } elseif ( isset($_POST['unspam']) && 1 == $_POST['unspam'] ) {
438 if ( 'spam' != $status )
440 $r = wp_unspam_comment( $comment->comment_ID );
441 if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'spam' ) // undo spam, not in spam
443 } elseif ( isset($_POST['delete']) && 1 == $_POST['delete'] ) {
444 $r = wp_delete_comment( $comment->comment_ID );
449 if ( $r ) // Decide if we need to send back '1' or a more complicated response including page links and comment counts
450 _wp_ajax_delete_comment_response( $comment->comment_ID, $delta );
454 function wp_ajax_delete_tag() {
455 $tag_id = (int) $_POST['tag_ID'];
456 check_ajax_referer( "delete-tag_$tag_id" );
458 $taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
459 $tax = get_taxonomy($taxonomy);
461 if ( !current_user_can( $tax->cap->delete_terms ) )
464 $tag = get_term( $tag_id, $taxonomy );
465 if ( !$tag || is_wp_error( $tag ) )
468 if ( wp_delete_term($tag_id, $taxonomy))
474 function wp_ajax_delete_link() {
475 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
477 check_ajax_referer( "delete-bookmark_$id" );
478 if ( !current_user_can( 'manage_links' ) )
481 $link = get_bookmark( $id );
482 if ( !$link || is_wp_error( $link ) )
485 if ( wp_delete_link( $id ) )
491 function wp_ajax_delete_meta() {
492 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
494 check_ajax_referer( "delete-meta_$id" );
495 if ( !$meta = get_metadata_by_mid( 'post', $id ) )
498 if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'delete_post_meta', $meta->post_id, $meta->meta_key ) )
500 if ( delete_meta( $meta->meta_id ) )
505 function wp_ajax_delete_post( $action ) {
506 if ( empty( $action ) )
507 $action = 'delete-post';
508 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
510 check_ajax_referer( "{$action}_$id" );
511 if ( !current_user_can( 'delete_post', $id ) )
514 if ( !get_post( $id ) )
517 if ( wp_delete_post( $id ) )
523 function wp_ajax_trash_post( $action ) {
524 if ( empty( $action ) )
525 $action = 'trash-post';
526 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
528 check_ajax_referer( "{$action}_$id" );
529 if ( !current_user_can( 'delete_post', $id ) )
532 if ( !get_post( $id ) )
535 if ( 'trash-post' == $action )
536 $done = wp_trash_post( $id );
538 $done = wp_untrash_post( $id );
546 function wp_ajax_untrash_post( $action ) {
547 if ( empty( $action ) )
548 $action = 'untrash-post';
549 wp_ajax_trash_post( $action );
552 function wp_ajax_delete_page( $action ) {
553 if ( empty( $action ) )
554 $action = 'delete-page';
555 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
557 check_ajax_referer( "{$action}_$id" );
558 if ( !current_user_can( 'delete_page', $id ) )
561 if ( ! get_post( $id ) )
564 if ( wp_delete_post( $id ) )
570 function wp_ajax_dim_comment() {
571 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
573 if ( !$comment = get_comment( $id ) ) {
574 $x = new WP_Ajax_Response( array(
576 'id' => new WP_Error('invalid_comment', sprintf(__('Comment %d does not exist'), $id))
581 if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) && ! current_user_can( 'moderate_comments' ) )
584 $current = wp_get_comment_status( $comment->comment_ID );
585 if ( isset( $_POST['new'] ) && $_POST['new'] == $current )
588 check_ajax_referer( "approve-comment_$id" );
589 if ( in_array( $current, array( 'unapproved', 'spam' ) ) )
590 $result = wp_set_comment_status( $comment->comment_ID, 'approve', true );
592 $result = wp_set_comment_status( $comment->comment_ID, 'hold', true );
594 if ( is_wp_error($result) ) {
595 $x = new WP_Ajax_Response( array(
602 // Decide if we need to send back '1' or a more complicated response including page links and comment counts
603 _wp_ajax_delete_comment_response( $comment->comment_ID );
607 function wp_ajax_add_link_category( $action ) {
608 if ( empty( $action ) )
609 $action = 'add-link-category';
610 check_ajax_referer( $action );
611 if ( !current_user_can( 'manage_categories' ) )
613 $names = explode(',', wp_unslash( $_POST['newcat'] ) );
614 $x = new WP_Ajax_Response();
615 foreach ( $names as $cat_name ) {
616 $cat_name = trim($cat_name);
617 $slug = sanitize_title($cat_name);
620 if ( !$cat_id = term_exists( $cat_name, 'link_category' ) )
621 $cat_id = wp_insert_term( $cat_name, 'link_category' );
622 if ( is_wp_error( $cat_id ) )
624 else if ( is_array( $cat_id ) )
625 $cat_id = $cat_id['term_id'];
626 $cat_name = esc_html( $cat_name );
628 'what' => 'link-category',
630 '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>",
637 function wp_ajax_add_tag() {
638 global $wp_list_table;
640 check_ajax_referer( 'add-tag', '_wpnonce_add-tag' );
641 $post_type = !empty($_POST['post_type']) ? $_POST['post_type'] : 'post';
642 $taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
643 $tax = get_taxonomy($taxonomy);
645 if ( !current_user_can( $tax->cap->edit_terms ) )
648 $x = new WP_Ajax_Response();
650 $tag = wp_insert_term($_POST['tag-name'], $taxonomy, $_POST );
652 if ( !$tag || is_wp_error($tag) || (!$tag = get_term( $tag['term_id'], $taxonomy )) ) {
653 $message = __('An error has occurred. Please reload the page and try again.');
654 if ( is_wp_error($tag) && $tag->get_error_message() )
655 $message = $tag->get_error_message();
658 'what' => 'taxonomy',
659 'data' => new WP_Error('error', $message )
664 $wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => $_POST['screen'] ) );
667 if ( is_taxonomy_hierarchical($taxonomy) ) {
668 $level = count( get_ancestors( $tag->term_id, $taxonomy ) );
670 $wp_list_table->single_row( $tag, $level );
671 $noparents = ob_get_clean();
675 $wp_list_table->single_row( $tag );
676 $parents = ob_get_clean();
679 'what' => 'taxonomy',
680 'supplemental' => compact('parents', 'noparents')
684 'position' => $level,
685 'supplemental' => (array) $tag
690 function wp_ajax_get_tagcloud() {
691 if ( isset( $_POST['tax'] ) ) {
692 $taxonomy = sanitize_key( $_POST['tax'] );
693 $tax = get_taxonomy( $taxonomy );
696 if ( ! current_user_can( $tax->cap->assign_terms ) )
702 $tags = get_terms( $taxonomy, array( 'number' => 45, 'orderby' => 'count', 'order' => 'DESC' ) );
704 if ( empty( $tags ) )
705 wp_die( $tax->labels->not_found );
707 if ( is_wp_error( $tags ) )
708 wp_die( $tags->get_error_message() );
710 foreach ( $tags as $key => $tag ) {
711 $tags[ $key ]->link = '#';
712 $tags[ $key ]->id = $tag->term_id;
715 // We need raw tag names here, so don't filter the output
716 $return = wp_generate_tag_cloud( $tags, array('filter' => 0) );
718 if ( empty($return) )
726 function wp_ajax_get_comments( $action ) {
727 global $wp_list_table, $post_id;
728 if ( empty( $action ) )
729 $action = 'get-comments';
731 check_ajax_referer( $action );
733 if ( empty( $post_id ) && ! empty( $_REQUEST['p'] ) ) {
734 $id = absint( $_REQUEST['p'] );
735 if ( ! empty( $id ) )
739 if ( empty( $post_id ) )
742 $wp_list_table = _get_list_table( 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
744 if ( ! current_user_can( 'edit_post', $post_id ) )
747 $wp_list_table->prepare_items();
749 if ( !$wp_list_table->has_items() )
752 $x = new WP_Ajax_Response();
754 foreach ( $wp_list_table->items as $comment ) {
755 if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) )
757 get_comment( $comment );
758 $wp_list_table->single_row( $comment );
760 $comment_list_item = ob_get_contents();
764 'what' => 'comments',
765 'data' => $comment_list_item
770 function wp_ajax_replyto_comment( $action ) {
771 global $wp_list_table, $wpdb;
772 if ( empty( $action ) )
773 $action = 'replyto-comment';
775 check_ajax_referer( $action, '_ajax_nonce-replyto-comment' );
777 $comment_post_ID = (int) $_POST['comment_post_ID'];
778 $post = get_post( $comment_post_ID );
782 if ( !current_user_can( 'edit_post', $comment_post_ID ) )
785 if ( empty( $post->post_status ) )
787 elseif ( in_array($post->post_status, array('draft', 'pending', 'trash') ) )
788 wp_die( __('ERROR: you are replying to a comment on a draft post.') );
790 $user = wp_get_current_user();
791 if ( $user->exists() ) {
792 $user_ID = $user->ID;
793 $comment_author = wp_slash( $user->display_name );
794 $comment_author_email = wp_slash( $user->user_email );
795 $comment_author_url = wp_slash( $user->user_url );
796 $comment_content = trim($_POST['content']);
797 if ( current_user_can( 'unfiltered_html' ) ) {
798 if ( ! isset( $_POST['_wp_unfiltered_html_comment'] ) )
799 $_POST['_wp_unfiltered_html_comment'] = '';
801 if ( wp_create_nonce( 'unfiltered-html-comment' ) != $_POST['_wp_unfiltered_html_comment'] ) {
802 kses_remove_filters(); // start with a clean slate
803 kses_init_filters(); // set up the filters
807 wp_die( __( 'Sorry, you must be logged in to reply to a comment.' ) );
810 if ( '' == $comment_content )
811 wp_die( __( 'ERROR: please type a comment.' ) );
814 if ( isset( $_POST['comment_ID'] ) )
815 $comment_parent = absint( $_POST['comment_ID'] );
816 $comment_auto_approved = false;
817 $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_type', 'comment_parent', 'user_ID');
819 // automatically approve parent comment
820 if ( !empty($_POST['approve_parent']) ) {
821 $parent = get_comment( $comment_parent );
823 if ( $parent && $parent->comment_approved === '0' && $parent->comment_post_ID == $comment_post_ID ) {
824 if ( wp_set_comment_status( $parent->comment_ID, 'approve' ) )
825 $comment_auto_approved = true;
829 $comment_id = wp_new_comment( $commentdata );
830 $comment = get_comment($comment_id);
831 if ( ! $comment ) wp_die( 1 );
833 $position = ( isset($_POST['position']) && (int) $_POST['position'] ) ? (int) $_POST['position'] : '-1';
836 if ( isset( $_REQUEST['mode'] ) && 'dashboard' == $_REQUEST['mode'] ) {
837 require_once( ABSPATH . 'wp-admin/includes/dashboard.php' );
838 _wp_dashboard_recent_comments_row( $comment );
840 if ( isset( $_REQUEST['mode'] ) && 'single' == $_REQUEST['mode'] ) {
841 $wp_list_table = _get_list_table('WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
843 $wp_list_table = _get_list_table('WP_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
845 $wp_list_table->single_row( $comment );
847 $comment_list_item = ob_get_clean();
851 'id' => $comment->comment_ID,
852 'data' => $comment_list_item,
853 'position' => $position
856 if ( $comment_auto_approved )
857 $response['supplemental'] = array( 'parent_approved' => $parent->comment_ID );
859 $x = new WP_Ajax_Response();
860 $x->add( $response );
864 function wp_ajax_edit_comment() {
865 global $wp_list_table;
867 check_ajax_referer( 'replyto-comment', '_ajax_nonce-replyto-comment' );
869 $comment_id = (int) $_POST['comment_ID'];
870 if ( ! current_user_can( 'edit_comment', $comment_id ) )
873 if ( '' == $_POST['content'] )
874 wp_die( __( 'ERROR: please type a comment.' ) );
876 if ( isset( $_POST['status'] ) )
877 $_POST['comment_status'] = $_POST['status'];
880 $position = ( isset($_POST['position']) && (int) $_POST['position']) ? (int) $_POST['position'] : '-1';
881 $comments_status = isset($_POST['comments_listing']) ? $_POST['comments_listing'] : '';
883 $checkbox = ( isset($_POST['checkbox']) && true == $_POST['checkbox'] ) ? 1 : 0;
884 $wp_list_table = _get_list_table( $checkbox ? 'WP_Comments_List_Table' : 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
886 $comment = get_comment( $comment_id );
887 if ( empty( $comment->comment_ID ) )
891 $wp_list_table->single_row( $comment );
892 $comment_list_item = ob_get_clean();
894 $x = new WP_Ajax_Response();
897 'what' => 'edit_comment',
898 'id' => $comment->comment_ID,
899 'data' => $comment_list_item,
900 'position' => $position
906 function wp_ajax_add_menu_item() {
907 check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' );
909 if ( ! current_user_can( 'edit_theme_options' ) )
912 require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
914 // For performance reasons, we omit some object properties from the checklist.
915 // The following is a hacky way to restore them when adding non-custom items.
917 $menu_items_data = array();
918 foreach ( (array) $_POST['menu-item'] as $menu_item_data ) {
920 ! empty( $menu_item_data['menu-item-type'] ) &&
921 'custom' != $menu_item_data['menu-item-type'] &&
922 ! empty( $menu_item_data['menu-item-object-id'] )
924 switch( $menu_item_data['menu-item-type'] ) {
926 $_object = get_post( $menu_item_data['menu-item-object-id'] );
930 $_object = get_term( $menu_item_data['menu-item-object-id'], $menu_item_data['menu-item-object'] );
934 $_menu_items = array_map( 'wp_setup_nav_menu_item', array( $_object ) );
935 $_menu_item = array_shift( $_menu_items );
937 // Restore the missing menu item properties
938 $menu_item_data['menu-item-description'] = $_menu_item->description;
941 $menu_items_data[] = $menu_item_data;
944 $item_ids = wp_save_nav_menu_items( 0, $menu_items_data );
945 if ( is_wp_error( $item_ids ) )
948 $menu_items = array();
950 foreach ( (array) $item_ids as $menu_item_id ) {
951 $menu_obj = get_post( $menu_item_id );
952 if ( ! empty( $menu_obj->ID ) ) {
953 $menu_obj = wp_setup_nav_menu_item( $menu_obj );
954 $menu_obj->label = $menu_obj->title; // don't show "(pending)" in ajax-added items
955 $menu_items[] = $menu_obj;
960 * Filter the Walker class used when adding nav menu items.
964 * @param string $class The walker class to use. Default 'Walker_Nav_Menu_Edit'.
965 * @param int $menu_id The menu id, derived from $_POST['menu'].
967 $walker_class_name = apply_filters( 'wp_edit_nav_menu_walker', 'Walker_Nav_Menu_Edit', $_POST['menu'] );
969 if ( ! class_exists( $walker_class_name ) )
972 if ( ! empty( $menu_items ) ) {
978 'walker' => new $walker_class_name,
980 echo walk_nav_menu_tree( $menu_items, 0, (object) $args );
985 function wp_ajax_add_meta() {
986 check_ajax_referer( 'add-meta', '_ajax_nonce-add-meta' );
988 $pid = (int) $_POST['post_id'];
989 $post = get_post( $pid );
991 if ( isset($_POST['metakeyselect']) || isset($_POST['metakeyinput']) ) {
992 if ( !current_user_can( 'edit_post', $pid ) )
994 if ( isset($_POST['metakeyselect']) && '#NONE#' == $_POST['metakeyselect'] && empty($_POST['metakeyinput']) )
996 if ( $post->post_status == 'auto-draft' ) {
997 $save_POST = $_POST; // Backup $_POST
998 $_POST = array(); // Make it empty for edit_post()
999 $_POST['action'] = 'draft'; // Warning fix
1000 $_POST['post_ID'] = $pid;
1001 $_POST['post_type'] = $post->post_type;
1002 $_POST['post_status'] = 'draft';
1003 $now = current_time('timestamp', 1);
1004 $_POST['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), date( get_option( 'date_format' ), $now ), date( get_option( 'time_format' ), $now ) );
1006 if ( $pid = edit_post() ) {
1007 if ( is_wp_error( $pid ) ) {
1008 $x = new WP_Ajax_Response( array(
1014 $_POST = $save_POST; // Now we can restore original $_POST again
1015 if ( !$mid = add_meta( $pid ) )
1016 wp_die( __( 'Please provide a custom field value.' ) );
1020 } else if ( !$mid = add_meta( $pid ) ) {
1021 wp_die( __( 'Please provide a custom field value.' ) );
1024 $meta = get_metadata_by_mid( 'post', $mid );
1025 $pid = (int) $meta->post_id;
1026 $meta = get_object_vars( $meta );
1027 $x = new WP_Ajax_Response( array(
1030 'data' => _list_meta_row( $meta, $c ),
1032 'supplemental' => array('postid' => $pid)
1035 $mid = (int) key( $_POST['meta'] );
1036 $key = wp_unslash( $_POST['meta'][$mid]['key'] );
1037 $value = wp_unslash( $_POST['meta'][$mid]['value'] );
1038 if ( '' == trim($key) )
1039 wp_die( __( 'Please provide a custom field name.' ) );
1040 if ( '' == trim($value) )
1041 wp_die( __( 'Please provide a custom field value.' ) );
1042 if ( ! $meta = get_metadata_by_mid( 'post', $mid ) )
1043 wp_die( 0 ); // if meta doesn't exist
1044 if ( is_protected_meta( $meta->meta_key, 'post' ) || is_protected_meta( $key, 'post' ) ||
1045 ! current_user_can( 'edit_post_meta', $meta->post_id, $meta->meta_key ) ||
1046 ! current_user_can( 'edit_post_meta', $meta->post_id, $key ) )
1048 if ( $meta->meta_value != $value || $meta->meta_key != $key ) {
1049 if ( !$u = update_metadata_by_mid( 'post', $mid, $value, $key ) )
1050 wp_die( 0 ); // We know meta exists; we also know it's unchanged (or DB error, in which case there are bigger problems).
1053 $x = new WP_Ajax_Response( array(
1055 'id' => $mid, 'old_id' => $mid,
1056 'data' => _list_meta_row( array(
1058 'meta_value' => $value,
1062 'supplemental' => array('postid' => $meta->post_id)
1068 function wp_ajax_add_user( $action ) {
1069 global $wp_list_table;
1070 if ( empty( $action ) )
1071 $action = 'add-user';
1073 check_ajax_referer( $action );
1074 if ( ! current_user_can('create_users') )
1076 if ( ! $user_id = edit_user() ) {
1078 } elseif ( is_wp_error( $user_id ) ) {
1079 $x = new WP_Ajax_Response( array(
1085 $user_object = get_userdata( $user_id );
1087 $wp_list_table = _get_list_table('WP_Users_List_Table');
1089 $role = current( $user_object->roles );
1091 $x = new WP_Ajax_Response( array(
1094 'data' => $wp_list_table->single_row( $user_object, '', $role ),
1095 'supplemental' => array(
1096 'show-link' => sprintf(__( 'User <a href="#%s">%s</a> added' ), "user-$user_id", $user_object->user_login),
1103 function wp_ajax_closed_postboxes() {
1104 check_ajax_referer( 'closedpostboxes', 'closedpostboxesnonce' );
1105 $closed = isset( $_POST['closed'] ) ? explode( ',', $_POST['closed']) : array();
1106 $closed = array_filter($closed);
1108 $hidden = isset( $_POST['hidden'] ) ? explode( ',', $_POST['hidden']) : array();
1109 $hidden = array_filter($hidden);
1111 $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1113 if ( $page != sanitize_key( $page ) )
1116 if ( ! $user = wp_get_current_user() )
1119 if ( is_array($closed) )
1120 update_user_option($user->ID, "closedpostboxes_$page", $closed, true);
1122 if ( is_array($hidden) ) {
1123 $hidden = array_diff( $hidden, array('submitdiv', 'linksubmitdiv', 'manage-menu', 'create-menu') ); // postboxes that are always shown
1124 update_user_option($user->ID, "metaboxhidden_$page", $hidden, true);
1130 function wp_ajax_hidden_columns() {
1131 check_ajax_referer( 'screen-options-nonce', 'screenoptionnonce' );
1132 $hidden = isset( $_POST['hidden'] ) ? $_POST['hidden'] : '';
1133 $hidden = explode( ',', $_POST['hidden'] );
1134 $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1136 if ( $page != sanitize_key( $page ) )
1139 if ( ! $user = wp_get_current_user() )
1142 if ( is_array($hidden) )
1143 update_user_option($user->ID, "manage{$page}columnshidden", $hidden, true);
1148 function wp_ajax_update_welcome_panel() {
1149 check_ajax_referer( 'welcome-panel-nonce', 'welcomepanelnonce' );
1151 if ( ! current_user_can( 'edit_theme_options' ) )
1154 update_user_meta( get_current_user_id(), 'show_welcome_panel', empty( $_POST['visible'] ) ? 0 : 1 );
1159 function wp_ajax_menu_get_metabox() {
1160 if ( ! current_user_can( 'edit_theme_options' ) )
1163 require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
1165 if ( isset( $_POST['item-type'] ) && 'post_type' == $_POST['item-type'] ) {
1167 $callback = 'wp_nav_menu_item_post_type_meta_box';
1168 $items = (array) get_post_types( array( 'show_in_nav_menus' => true ), 'object' );
1169 } elseif ( isset( $_POST['item-type'] ) && 'taxonomy' == $_POST['item-type'] ) {
1171 $callback = 'wp_nav_menu_item_taxonomy_meta_box';
1172 $items = (array) get_taxonomies( array( 'show_ui' => true ), 'object' );
1175 if ( ! empty( $_POST['item-object'] ) && isset( $items[$_POST['item-object']] ) ) {
1176 $menus_meta_box_object = $items[ $_POST['item-object'] ];
1178 * Filter a nav menu meta box object.
1182 * @param object $menus_meta_box_object A nav menu meta box object, such as Page,
1183 * Post, Category, Tag, etc.
1185 $item = apply_filters( 'nav_menu_meta_box_object', $menus_meta_box_object );
1187 call_user_func_array($callback, array(
1190 'id' => 'add-' . $item->name,
1191 'title' => $item->labels->name,
1192 'callback' => $callback,
1197 $markup = ob_get_clean();
1199 echo json_encode(array(
1200 'replace-id' => $type . '-' . $item->name,
1201 'markup' => $markup,
1208 function wp_ajax_wp_link_ajax() {
1209 check_ajax_referer( 'internal-linking', '_ajax_linking_nonce' );
1213 if ( isset( $_POST['search'] ) )
1214 $args['s'] = wp_unslash( $_POST['search'] );
1215 $args['pagenum'] = ! empty( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
1217 require(ABSPATH . WPINC . '/class-wp-editor.php');
1218 $results = _WP_Editors::wp_link_query( $args );
1220 if ( ! isset( $results ) )
1223 echo json_encode( $results );
1229 function wp_ajax_menu_locations_save() {
1230 if ( ! current_user_can( 'edit_theme_options' ) )
1232 check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' );
1233 if ( ! isset( $_POST['menu-locations'] ) )
1235 set_theme_mod( 'nav_menu_locations', array_map( 'absint', $_POST['menu-locations'] ) );
1239 function wp_ajax_meta_box_order() {
1240 check_ajax_referer( 'meta-box-order' );
1241 $order = isset( $_POST['order'] ) ? (array) $_POST['order'] : false;
1242 $page_columns = isset( $_POST['page_columns'] ) ? $_POST['page_columns'] : 'auto';
1244 if ( $page_columns != 'auto' )
1245 $page_columns = (int) $page_columns;
1247 $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1249 if ( $page != sanitize_key( $page ) )
1252 if ( ! $user = wp_get_current_user() )
1256 update_user_option($user->ID, "meta-box-order_$page", $order, true);
1258 if ( $page_columns )
1259 update_user_option($user->ID, "screen_layout_$page", $page_columns, true);
1264 function wp_ajax_menu_quick_search() {
1265 if ( ! current_user_can( 'edit_theme_options' ) )
1268 require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
1270 _wp_ajax_menu_quick_search( $_POST );
1275 function wp_ajax_get_permalink() {
1276 check_ajax_referer( 'getpermalink', 'getpermalinknonce' );
1277 $post_id = isset($_POST['post_id'])? intval($_POST['post_id']) : 0;
1278 wp_die( add_query_arg( array( 'preview' => 'true' ), get_permalink( $post_id ) ) );
1281 function wp_ajax_sample_permalink() {
1282 check_ajax_referer( 'samplepermalink', 'samplepermalinknonce' );
1283 $post_id = isset($_POST['post_id'])? intval($_POST['post_id']) : 0;
1284 $title = isset($_POST['new_title'])? $_POST['new_title'] : '';
1285 $slug = isset($_POST['new_slug'])? $_POST['new_slug'] : null;
1286 wp_die( get_sample_permalink_html( $post_id, $title, $slug ) );
1289 function wp_ajax_inline_save() {
1290 global $wp_list_table;
1292 check_ajax_referer( 'inlineeditnonce', '_inline_edit' );
1294 if ( ! isset($_POST['post_ID']) || ! ( $post_ID = (int) $_POST['post_ID'] ) )
1297 if ( 'page' == $_POST['post_type'] ) {
1298 if ( ! current_user_can( 'edit_page', $post_ID ) )
1299 wp_die( __( 'You are not allowed to edit this page.' ) );
1301 if ( ! current_user_can( 'edit_post', $post_ID ) )
1302 wp_die( __( 'You are not allowed to edit this post.' ) );
1305 if ( $last = wp_check_post_lock( $post_ID ) ) {
1306 $last_user = get_userdata( $last );
1307 $last_user_name = $last_user ? $last_user->display_name : __( 'Someone' );
1308 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 ) );
1314 $post = get_post( $post_ID, ARRAY_A );
1315 $post = wp_slash($post); //since it is from db
1317 $data['content'] = $post['post_content'];
1318 $data['excerpt'] = $post['post_excerpt'];
1321 $data['user_ID'] = get_current_user_id();
1323 if ( isset($data['post_parent']) )
1324 $data['parent_id'] = $data['post_parent'];
1327 if ( isset($data['keep_private']) && 'private' == $data['keep_private'] )
1328 $data['post_status'] = 'private';
1330 $data['post_status'] = $data['_status'];
1332 if ( empty($data['comment_status']) )
1333 $data['comment_status'] = 'closed';
1334 if ( empty($data['ping_status']) )
1335 $data['ping_status'] = 'closed';
1337 // Hack: wp_unique_post_slug() doesn't work for drafts, so we will fake that our post is published.
1338 if ( ! empty( $data['post_name'] ) && in_array( $post['post_status'], array( 'draft', 'pending' ) ) ) {
1339 $post['post_status'] = 'publish';
1340 $data['post_name'] = wp_unique_post_slug( $data['post_name'], $post['ID'], $post['post_status'], $post['post_type'], $post['post_parent'] );
1346 $wp_list_table = _get_list_table( 'WP_Posts_List_Table', array( 'screen' => $_POST['screen'] ) );
1348 $mode = $_POST['post_view'];
1351 $request_post = array( get_post( $_POST['post_ID'] ) );
1352 $parent = $request_post[0]->post_parent;
1354 while ( $parent > 0 ) {
1355 $parent_post = get_post( $parent );
1356 $parent = $parent_post->post_parent;
1360 $wp_list_table->display_rows( array( get_post( $_POST['post_ID'] ) ), $level );
1365 function wp_ajax_inline_save_tax() {
1366 global $wp_list_table;
1368 check_ajax_referer( 'taxinlineeditnonce', '_inline_edit' );
1370 $taxonomy = sanitize_key( $_POST['taxonomy'] );
1371 $tax = get_taxonomy( $taxonomy );
1375 if ( ! current_user_can( $tax->cap->edit_terms ) )
1378 $wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => 'edit-' . $taxonomy ) );
1380 if ( ! isset($_POST['tax_ID']) || ! ( $id = (int) $_POST['tax_ID'] ) )
1383 $tag = get_term( $id, $taxonomy );
1384 $_POST['description'] = $tag->description;
1386 $updated = wp_update_term($id, $taxonomy, $_POST);
1387 if ( $updated && !is_wp_error($updated) ) {
1388 $tag = get_term( $updated['term_id'], $taxonomy );
1389 if ( !$tag || is_wp_error( $tag ) ) {
1390 if ( is_wp_error($tag) && $tag->get_error_message() )
1391 wp_die( $tag->get_error_message() );
1392 wp_die( __( 'Item not updated.' ) );
1395 if ( is_wp_error($updated) && $updated->get_error_message() )
1396 wp_die( $updated->get_error_message() );
1397 wp_die( __( 'Item not updated.' ) );
1400 $parent = $tag->parent;
1401 while ( $parent > 0 ) {
1402 $parent_tag = get_term( $parent, $taxonomy );
1403 $parent = $parent_tag->parent;
1406 $wp_list_table->single_row( $tag, $level );
1410 function wp_ajax_find_posts() {
1413 check_ajax_referer( 'find-posts' );
1415 $post_types = get_post_types( array( 'public' => true ), 'objects' );
1416 unset( $post_types['attachment'] );
1418 $s = wp_unslash( $_POST['ps'] );
1419 $searchand = $search = '';
1421 'post_type' => array_keys( $post_types ),
1422 'post_status' => 'any',
1423 'posts_per_page' => 50,
1428 $posts = get_posts( $args );
1431 wp_die( __('No items found.') );
1433 $html = '<table class="widefat"><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>';
1435 foreach ( $posts as $post ) {
1436 $title = trim( $post->post_title ) ? $post->post_title : __( '(no title)' );
1437 $alt = ( 'alternate' == $alt ) ? '' : 'alternate';
1439 switch ( $post->post_status ) {
1442 $stat = __('Published');
1445 $stat = __('Scheduled');
1448 $stat = __('Pending Review');
1451 $stat = __('Draft');
1455 if ( '0000-00-00 00:00:00' == $post->post_date ) {
1458 /* translators: date format in table columns, see http://php.net/date */
1459 $time = mysql2date(__('Y/m/d'), $post->post_date);
1462 $html .= '<tr class="' . trim( 'found-posts ' . $alt ) . '"><td class="found-radio"><input type="radio" id="found-'.$post->ID.'" name="found_post_id" value="' . esc_attr($post->ID) . '"></td>';
1463 $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";
1466 $html .= '</tbody></table>';
1468 wp_send_json_success( $html );
1471 function wp_ajax_widgets_order() {
1472 check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' );
1474 if ( !current_user_can('edit_theme_options') )
1477 unset( $_POST['savewidgets'], $_POST['action'] );
1479 // save widgets order for all sidebars
1480 if ( is_array($_POST['sidebars']) ) {
1481 $sidebars = array();
1482 foreach ( $_POST['sidebars'] as $key => $val ) {
1484 if ( !empty($val) ) {
1485 $val = explode(',', $val);
1486 foreach ( $val as $k => $v ) {
1487 if ( strpos($v, 'widget-') === false )
1490 $sb[$k] = substr($v, strpos($v, '_') + 1);
1493 $sidebars[$key] = $sb;
1495 wp_set_sidebars_widgets($sidebars);
1502 function wp_ajax_save_widget() {
1503 global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
1505 check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' );
1507 if ( !current_user_can('edit_theme_options') || !isset($_POST['id_base']) )
1510 unset( $_POST['savewidgets'], $_POST['action'] );
1513 * Fires early when editing the widgets displayed in sidebars.
1517 do_action( 'load-widgets.php' );
1520 * Fires early when editing the widgets displayed in sidebars.
1524 do_action( 'widgets.php' );
1526 /** This action is documented in wp-admin/widgets.php */
1527 do_action( 'sidebar_admin_setup' );
1529 $id_base = $_POST['id_base'];
1530 $widget_id = $_POST['widget-id'];
1531 $sidebar_id = $_POST['sidebar'];
1532 $multi_number = !empty($_POST['multi_number']) ? (int) $_POST['multi_number'] : 0;
1533 $settings = isset($_POST['widget-' . $id_base]) && is_array($_POST['widget-' . $id_base]) ? $_POST['widget-' . $id_base] : false;
1534 $error = '<p>' . __('An error has occurred. Please reload the page and try again.') . '</p>';
1536 $sidebars = wp_get_sidebars_widgets();
1537 $sidebar = isset($sidebars[$sidebar_id]) ? $sidebars[$sidebar_id] : array();
1540 if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
1542 if ( !isset($wp_registered_widgets[$widget_id]) )
1545 $sidebar = array_diff( $sidebar, array($widget_id) );
1546 $_POST = array('sidebar' => $sidebar_id, 'widget-' . $id_base => array(), 'the-widget-id' => $widget_id, 'delete_widget' => '1');
1547 } elseif ( $settings && preg_match( '/__i__|%i%/', key($settings) ) ) {
1548 if ( !$multi_number )
1551 $_POST['widget-' . $id_base] = array( $multi_number => array_shift($settings) );
1552 $widget_id = $id_base . '-' . $multi_number;
1553 $sidebar[] = $widget_id;
1555 $_POST['widget-id'] = $sidebar;
1557 foreach ( (array) $wp_registered_widget_updates as $name => $control ) {
1559 if ( $name == $id_base ) {
1560 if ( !is_callable( $control['callback'] ) )
1564 call_user_func_array( $control['callback'], $control['params'] );
1570 if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
1571 $sidebars[$sidebar_id] = $sidebar;
1572 wp_set_sidebars_widgets($sidebars);
1573 echo "deleted:$widget_id";
1577 if ( !empty($_POST['add_new']) )
1580 if ( $form = $wp_registered_widget_controls[$widget_id] )
1581 call_user_func_array( $form['callback'], $form['params'] );
1586 function wp_ajax_update_widget() {
1587 global $wp_customize;
1588 $wp_customize->widgets->wp_ajax_update_widget();
1591 function wp_ajax_upload_attachment() {
1592 check_ajax_referer( 'media-form' );
1594 if ( ! current_user_can( 'upload_files' ) )
1597 if ( isset( $_REQUEST['post_id'] ) ) {
1598 $post_id = $_REQUEST['post_id'];
1599 if ( ! current_user_can( 'edit_post', $post_id ) )
1605 $post_data = isset( $_REQUEST['post_data'] ) ? $_REQUEST['post_data'] : array();
1607 // If the context is custom header or background, make sure the uploaded file is an image.
1608 if ( isset( $post_data['context'] ) && in_array( $post_data['context'], array( 'custom-header', 'custom-background' ) ) ) {
1609 $wp_filetype = wp_check_filetype_and_ext( $_FILES['async-upload']['tmp_name'], $_FILES['async-upload']['name'], false );
1610 if ( ! wp_match_mime_types( 'image', $wp_filetype['type'] ) ) {
1611 echo json_encode( array(
1614 'message' => __( 'The uploaded file is not a valid image. Please try again.' ),
1615 'filename' => $_FILES['async-upload']['name'],
1623 $attachment_id = media_handle_upload( 'async-upload', $post_id, $post_data );
1625 if ( is_wp_error( $attachment_id ) ) {
1626 echo json_encode( array(
1629 'message' => $attachment_id->get_error_message(),
1630 'filename' => $_FILES['async-upload']['name'],
1637 if ( isset( $post_data['context'] ) && isset( $post_data['theme'] ) ) {
1638 if ( 'custom-background' === $post_data['context'] )
1639 update_post_meta( $attachment_id, '_wp_attachment_is_custom_background', $post_data['theme'] );
1641 if ( 'custom-header' === $post_data['context'] )
1642 update_post_meta( $attachment_id, '_wp_attachment_is_custom_header', $post_data['theme'] );
1645 if ( ! $attachment = wp_prepare_attachment_for_js( $attachment_id ) )
1648 echo json_encode( array(
1650 'data' => $attachment,
1656 function wp_ajax_image_editor() {
1657 $attachment_id = intval($_POST['postid']);
1658 if ( empty($attachment_id) || !current_user_can('edit_post', $attachment_id) )
1661 check_ajax_referer( "image_editor-$attachment_id" );
1662 include_once( ABSPATH . 'wp-admin/includes/image-edit.php' );
1665 switch ( $_POST['do'] ) {
1667 $msg = wp_save_image($attachment_id);
1668 $msg = json_encode($msg);
1672 $msg = wp_save_image($attachment_id);
1675 $msg = wp_restore_image($attachment_id);
1679 wp_image_editor($attachment_id, $msg);
1683 function wp_ajax_set_post_thumbnail() {
1684 $json = ! empty( $_REQUEST['json'] ); // New-style request
1686 $post_ID = intval( $_POST['post_id'] );
1687 if ( ! current_user_can( 'edit_post', $post_ID ) )
1690 $thumbnail_id = intval( $_POST['thumbnail_id'] );
1693 check_ajax_referer( "update-post_$post_ID" );
1695 check_ajax_referer( "set_post_thumbnail-$post_ID" );
1697 if ( $thumbnail_id == '-1' ) {
1698 if ( delete_post_thumbnail( $post_ID ) ) {
1699 $return = _wp_post_thumbnail_html( null, $post_ID );
1700 $json ? wp_send_json_success( $return ) : wp_die( $return );
1706 if ( set_post_thumbnail( $post_ID, $thumbnail_id ) ) {
1707 $return = _wp_post_thumbnail_html( $thumbnail_id, $post_ID );
1708 $json ? wp_send_json_success( $return ) : wp_die( $return );
1714 function wp_ajax_date_format() {
1715 wp_die( date_i18n( sanitize_option( 'date_format', wp_unslash( $_POST['date'] ) ) ) );
1718 function wp_ajax_time_format() {
1719 wp_die( date_i18n( sanitize_option( 'time_format', wp_unslash( $_POST['date'] ) ) ) );
1722 function wp_ajax_wp_fullscreen_save_post() {
1723 $post_id = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0;
1725 $post = $post_type = null;
1728 $post = get_post( $post_id );
1731 $post_type = $post->post_type;
1732 elseif ( isset( $_POST['post_type'] ) && post_type_exists( $_POST['post_type'] ) )
1733 $post_type = $_POST['post_type'];
1735 check_ajax_referer('update-post_' . $post_id, '_wpnonce');
1737 $post_id = edit_post();
1739 if ( is_wp_error( $post_id ) ) {
1740 wp_send_json_error();
1744 $last_date = mysql2date( get_option('date_format'), $post->post_modified );
1745 $last_time = mysql2date( get_option('time_format'), $post->post_modified );
1747 $last_date = date_i18n( get_option('date_format') );
1748 $last_time = date_i18n( get_option('time_format') );
1751 if ( $last_id = get_post_meta( $post_id, '_edit_last', true ) ) {
1752 $last_user = get_userdata( $last_id );
1753 $last_edited = sprintf( __('Last edited by %1$s on %2$s at %3$s'), esc_html( $last_user->display_name ), $last_date, $last_time );
1755 $last_edited = sprintf( __('Last edited on %1$s at %2$s'), $last_date, $last_time );
1758 wp_send_json_success( array( 'last_edited' => $last_edited ) );
1761 function wp_ajax_wp_remove_post_lock() {
1762 if ( empty( $_POST['post_ID'] ) || empty( $_POST['active_post_lock'] ) )
1764 $post_id = (int) $_POST['post_ID'];
1765 if ( ! $post = get_post( $post_id ) )
1768 check_ajax_referer( 'update-post_' . $post_id );
1770 if ( ! current_user_can( 'edit_post', $post_id ) )
1773 $active_lock = array_map( 'absint', explode( ':', $_POST['active_post_lock'] ) );
1774 if ( $active_lock[1] != get_current_user_id() )
1778 * Filter the post lock window duration.
1782 * @param int $interval The interval in seconds the post lock duration
1783 * should last, plus 5 seconds. Default 150.
1785 $new_lock = ( time() - apply_filters( 'wp_check_post_lock_window', 150 ) + 5 ) . ':' . $active_lock[1];
1786 update_post_meta( $post_id, '_edit_lock', $new_lock, implode( ':', $active_lock ) );
1790 function wp_ajax_dismiss_wp_pointer() {
1791 $pointer = $_POST['pointer'];
1792 if ( $pointer != sanitize_key( $pointer ) )
1795 // check_ajax_referer( 'dismiss-pointer_' . $pointer );
1797 $dismissed = array_filter( explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) ) );
1799 if ( in_array( $pointer, $dismissed ) )
1802 $dismissed[] = $pointer;
1803 $dismissed = implode( ',', $dismissed );
1805 update_user_meta( get_current_user_id(), 'dismissed_wp_pointers', $dismissed );
1810 * Get an attachment.
1814 function wp_ajax_get_attachment() {
1815 if ( ! isset( $_REQUEST['id'] ) )
1816 wp_send_json_error();
1818 if ( ! $id = absint( $_REQUEST['id'] ) )
1819 wp_send_json_error();
1821 if ( ! $post = get_post( $id ) )
1822 wp_send_json_error();
1824 if ( 'attachment' != $post->post_type )
1825 wp_send_json_error();
1827 if ( ! current_user_can( 'upload_files' ) )
1828 wp_send_json_error();
1830 if ( ! $attachment = wp_prepare_attachment_for_js( $id ) )
1831 wp_send_json_error();
1833 wp_send_json_success( $attachment );
1837 * Query for attachments.
1841 function wp_ajax_query_attachments() {
1842 if ( ! current_user_can( 'upload_files' ) )
1843 wp_send_json_error();
1845 $query = isset( $_REQUEST['query'] ) ? (array) $_REQUEST['query'] : array();
1846 $query = array_intersect_key( $query, array_flip( array(
1847 's', 'order', 'orderby', 'posts_per_page', 'paged', 'post_mime_type',
1848 'post_parent', 'post__in', 'post__not_in',
1851 $query['post_type'] = 'attachment';
1852 $query['post_status'] = 'inherit';
1853 if ( current_user_can( get_post_type_object( 'attachment' )->cap->read_private_posts ) )
1854 $query['post_status'] .= ',private';
1857 * Filter the arguments passed to WP_Query during an AJAX
1858 * call for querying attachments.
1862 * @see WP_Query::parse_query()
1864 * @param array $query An array of query variables.
1866 $query = apply_filters( 'ajax_query_attachments_args', $query );
1867 $query = new WP_Query( $query );
1869 $posts = array_map( 'wp_prepare_attachment_for_js', $query->posts );
1870 $posts = array_filter( $posts );
1872 wp_send_json_success( $posts );
1876 * Save attachment attributes.
1880 function wp_ajax_save_attachment() {
1881 if ( ! isset( $_REQUEST['id'] ) || ! isset( $_REQUEST['changes'] ) )
1882 wp_send_json_error();
1884 if ( ! $id = absint( $_REQUEST['id'] ) )
1885 wp_send_json_error();
1887 check_ajax_referer( 'update-post_' . $id, 'nonce' );
1889 if ( ! current_user_can( 'edit_post', $id ) )
1890 wp_send_json_error();
1892 $changes = $_REQUEST['changes'];
1893 $post = get_post( $id, ARRAY_A );
1895 if ( 'attachment' != $post['post_type'] )
1896 wp_send_json_error();
1898 if ( isset( $changes['title'] ) )
1899 $post['post_title'] = $changes['title'];
1901 if ( isset( $changes['caption'] ) )
1902 $post['post_excerpt'] = $changes['caption'];
1904 if ( isset( $changes['description'] ) )
1905 $post['post_content'] = $changes['description'];
1907 if ( isset( $changes['alt'] ) ) {
1908 $alt = wp_unslash( $changes['alt'] );
1909 if ( $alt != get_post_meta( $id, '_wp_attachment_image_alt', true ) ) {
1910 $alt = wp_strip_all_tags( $alt, true );
1911 update_post_meta( $id, '_wp_attachment_image_alt', wp_slash( $alt ) );
1915 wp_update_post( $post );
1916 wp_send_json_success();
1920 * Save backwards compatible attachment attributes.
1924 function wp_ajax_save_attachment_compat() {
1925 if ( ! isset( $_REQUEST['id'] ) )
1926 wp_send_json_error();
1928 if ( ! $id = absint( $_REQUEST['id'] ) )
1929 wp_send_json_error();
1931 if ( empty( $_REQUEST['attachments'] ) || empty( $_REQUEST['attachments'][ $id ] ) )
1932 wp_send_json_error();
1933 $attachment_data = $_REQUEST['attachments'][ $id ];
1935 check_ajax_referer( 'update-post_' . $id, 'nonce' );
1937 if ( ! current_user_can( 'edit_post', $id ) )
1938 wp_send_json_error();
1940 $post = get_post( $id, ARRAY_A );
1942 if ( 'attachment' != $post['post_type'] )
1943 wp_send_json_error();
1945 /** This filter is documented in wp-admin/includes/media.php */
1946 $post = apply_filters( 'attachment_fields_to_save', $post, $attachment_data );
1948 if ( isset( $post['errors'] ) ) {
1949 $errors = $post['errors']; // @todo return me and display me!
1950 unset( $post['errors'] );
1953 wp_update_post( $post );
1955 foreach ( get_attachment_taxonomies( $post ) as $taxonomy ) {
1956 if ( isset( $attachment_data[ $taxonomy ] ) )
1957 wp_set_object_terms( $id, array_map( 'trim', preg_split( '/,+/', $attachment_data[ $taxonomy ] ) ), $taxonomy, false );
1960 if ( ! $attachment = wp_prepare_attachment_for_js( $id ) )
1961 wp_send_json_error();
1963 wp_send_json_success( $attachment );
1966 function wp_ajax_save_attachment_order() {
1967 if ( ! isset( $_REQUEST['post_id'] ) )
1968 wp_send_json_error();
1970 if ( ! $post_id = absint( $_REQUEST['post_id'] ) )
1971 wp_send_json_error();
1973 if ( empty( $_REQUEST['attachments'] ) )
1974 wp_send_json_error();
1976 check_ajax_referer( 'update-post_' . $post_id, 'nonce' );
1978 $attachments = $_REQUEST['attachments'];
1980 if ( ! current_user_can( 'edit_post', $post_id ) )
1981 wp_send_json_error();
1983 $post = get_post( $post_id, ARRAY_A );
1985 foreach ( $attachments as $attachment_id => $menu_order ) {
1986 if ( ! current_user_can( 'edit_post', $attachment_id ) )
1988 if ( ! $attachment = get_post( $attachment_id ) )
1990 if ( 'attachment' != $attachment->post_type )
1993 wp_update_post( array( 'ID' => $attachment_id, 'menu_order' => $menu_order ) );
1996 wp_send_json_success();
2000 * Generates the HTML to send an attachment to the editor.
2001 * Backwards compatible with the media_send_to_editor filter and the chain
2002 * of filters that follow.
2006 function wp_ajax_send_attachment_to_editor() {
2007 check_ajax_referer( 'media-send-to-editor', 'nonce' );
2009 $attachment = wp_unslash( $_POST['attachment'] );
2011 $id = intval( $attachment['id'] );
2013 if ( ! $post = get_post( $id ) )
2014 wp_send_json_error();
2016 if ( 'attachment' != $post->post_type )
2017 wp_send_json_error();
2019 if ( current_user_can( 'edit_post', $id ) ) {
2020 // If this attachment is unattached, attach it. Primarily a back compat thing.
2021 if ( 0 == $post->post_parent && $insert_into_post_id = intval( $_POST['post_id'] ) ) {
2022 wp_update_post( array( 'ID' => $id, 'post_parent' => $insert_into_post_id ) );
2027 $html = $title = isset( $attachment['post_title'] ) ? $attachment['post_title'] : '';
2028 if ( ! empty( $attachment['url'] ) ) {
2029 $url = $attachment['url'];
2030 if ( strpos( $url, 'attachment_id') || get_attachment_link( $id ) == $url )
2031 $rel = ' rel="attachment wp-att-' . $id . '"';
2032 $html = '<a href="' . esc_url( $url ) . '"' . $rel . '>' . $html . '</a>';
2035 remove_filter( 'media_send_to_editor', 'image_media_send_to_editor' );
2037 if ( 'image' === substr( $post->post_mime_type, 0, 5 ) ) {
2038 $align = isset( $attachment['align'] ) ? $attachment['align'] : 'none';
2039 $size = isset( $attachment['image-size'] ) ? $attachment['image-size'] : 'medium';
2040 $alt = isset( $attachment['image_alt'] ) ? $attachment['image_alt'] : '';
2041 $caption = isset( $attachment['post_excerpt'] ) ? $attachment['post_excerpt'] : '';
2042 $title = ''; // We no longer insert title tags into <img> tags, as they are redundant.
2043 $html = get_image_send_to_editor( $id, $caption, $title, $align, $url, (bool) $rel, $size, $alt );
2044 } elseif ( 'video' === substr( $post->post_mime_type, 0, 5 ) || 'audio' === substr( $post->post_mime_type, 0, 5 ) ) {
2045 $html = stripslashes_deep( $_POST['html'] );
2048 /** This filter is documented in wp-admin/includes/media.php */
2049 $html = apply_filters( 'media_send_to_editor', $html, $id, $attachment );
2051 wp_send_json_success( $html );
2055 * Generates the HTML to send a non-image embed link to the editor.
2057 * Backwards compatible with the following filters:
2058 * - file_send_to_editor_url
2059 * - audio_send_to_editor_url
2060 * - video_send_to_editor_url
2064 function wp_ajax_send_link_to_editor() {
2065 check_ajax_referer( 'media-send-to-editor', 'nonce' );
2067 if ( ! $src = wp_unslash( $_POST['src'] ) )
2068 wp_send_json_error();
2070 if ( ! strpos( $src, '://' ) )
2071 $src = 'http://' . $src;
2073 if ( ! $src = esc_url_raw( $src ) )
2074 wp_send_json_error();
2076 if ( ! $title = trim( wp_unslash( $_POST['title'] ) ) )
2077 $title = wp_basename( $src );
2081 $html = '<a href="' . esc_url( $src ) . '">' . $title . '</a>';
2083 // Figure out what filter to run:
2085 if ( ( $ext = preg_replace( '/^.+?\.([^.]+)$/', '$1', $src ) ) && ( $ext_type = wp_ext2type( $ext ) )
2086 && ( 'audio' == $ext_type || 'video' == $ext_type ) )
2089 /** This filter is documented in wp-admin/includes/media.php */
2090 $html = apply_filters( $type . '_send_to_editor_url', $html, $src, $title );
2092 wp_send_json_success( $html );
2096 * Heartbeat API (experimental)
2098 * Runs when the user is logged in.
2100 function wp_ajax_heartbeat() {
2101 if ( empty( $_POST['_nonce'] ) )
2102 wp_send_json_error();
2104 $response = array();
2106 if ( false === wp_verify_nonce( $_POST['_nonce'], 'heartbeat-nonce' ) ) {
2107 // User is logged in but nonces have expired.
2108 $response['nonces_expired'] = true;
2109 wp_send_json($response);
2112 // screen_id is the same as $current_screen->id and the JS global 'pagenow'
2113 if ( ! empty($_POST['screen_id']) )
2114 $screen_id = sanitize_key($_POST['screen_id']);
2116 $screen_id = 'front';
2118 if ( ! empty($_POST['data']) ) {
2119 $data = wp_unslash( (array) $_POST['data'] );
2122 * Filter the Heartbeat response received.
2126 * @param array|object $response The Heartbeat response object or array.
2127 * @param array $data The $_POST data sent.
2128 * @param string $screen_id The screen id.
2130 $response = apply_filters( 'heartbeat_received', $response, $data, $screen_id );
2134 * Filter the Heartbeat response sent.
2138 * @param array|object $response The Heartbeat response object or array.
2139 * @param string $screen_id The screen id.
2141 $response = apply_filters( 'heartbeat_send', $response, $screen_id );
2144 * Fires when Heartbeat ticks in logged-in environments.
2146 * Allows the transport to be easily replaced with long-polling.
2150 * @param array|object $response The Heartbeat response object or array.
2151 * @param string $screen_id The screen id.
2153 do_action( 'heartbeat_tick', $response, $screen_id );
2155 // Send the current time according to the server
2156 $response['server_time'] = time();
2158 wp_send_json($response);
2161 function wp_ajax_get_revision_diffs() {
2162 require ABSPATH . 'wp-admin/includes/revision.php';
2164 if ( ! $post = get_post( (int) $_REQUEST['post_id'] ) )
2165 wp_send_json_error();
2167 if ( ! current_user_can( 'read_post', $post->ID ) )
2168 wp_send_json_error();
2170 // Really just pre-loading the cache here.
2171 if ( ! $revisions = wp_get_post_revisions( $post->ID, array( 'check_enabled' => false ) ) )
2172 wp_send_json_error();
2175 @set_time_limit( 0 );
2177 foreach ( $_REQUEST['compare'] as $compare_key ) {
2178 list( $compare_from, $compare_to ) = explode( ':', $compare_key ); // from:to
2181 'id' => $compare_key,
2182 'fields' => wp_get_revision_ui_diff( $post, $compare_from, $compare_to ),
2185 wp_send_json_success( $return );
2189 * Auto-save the selected color scheme for a user's own profile.
2193 function wp_ajax_save_user_color_scheme() {
2194 global $_wp_admin_css_colors;
2196 check_ajax_referer( 'save-color-scheme', 'nonce' );
2198 $color_scheme = sanitize_key( $_POST['color_scheme'] );
2200 if ( ! isset( $_wp_admin_css_colors[ $color_scheme ] ) ) {
2201 wp_send_json_error();
2204 update_user_meta( get_current_user_id(), 'admin_color', $color_scheme );
2205 wp_send_json_success();
2209 * Get themes from themes_api().
2213 function wp_ajax_query_themes() {
2214 global $themes_allowedtags, $theme_field_defaults;
2216 if ( ! current_user_can( 'install_themes' ) ) {
2217 wp_send_json_error();
2220 $args = wp_parse_args( wp_unslash( $_REQUEST['request'] ), array(
2222 'fields' => $theme_field_defaults
2225 $old_filter = isset( $args['browse'] ) ? $args['browse'] : 'search';
2227 /** This filter is documented in wp-admin/includes/class-wp-theme-install-list-table.php */
2228 $args = apply_filters( 'install_themes_table_api_args_' . $old_filter, $args );
2230 $api = themes_api( 'query_themes', $args );
2232 if ( is_wp_error( $api ) ) {
2233 wp_send_json_error();
2236 $update_php = network_admin_url( 'update.php?action=install-theme' );
2237 foreach ( $api->themes as &$theme ) {
2238 $theme->install_url = add_query_arg( array(
2239 'theme' => $theme->slug,
2240 '_wpnonce' => wp_create_nonce( 'install-theme_' . $theme->slug )
2243 $theme->name = wp_kses( $theme->name, $themes_allowedtags );
2244 $theme->author = wp_kses( $theme->author, $themes_allowedtags );
2245 $theme->version = wp_kses( $theme->version, $themes_allowedtags );
2246 $theme->description = wp_kses( $theme->description, $themes_allowedtags );
2247 $theme->num_ratings = sprintf( _n( '(based on %s rating)', '(based on %s ratings)', $theme->num_ratings ), number_format_i18n( $theme->num_ratings ) );
2250 wp_send_json_success( $api );