3 * Administration API: Core Ajax handlers
6 * @subpackage Administration
11 // No-privilege Ajax handlers.
15 * Ajax handler for the Heartbeat API in
16 * the no-privilege context.
18 * Runs when the user is not logged in.
22 function wp_ajax_nopriv_heartbeat() {
25 // screen_id is the same as $current_screen->id and the JS global 'pagenow'.
26 if ( ! empty($_POST['screen_id']) )
27 $screen_id = sanitize_key($_POST['screen_id']);
31 if ( ! empty($_POST['data']) ) {
32 $data = wp_unslash( (array) $_POST['data'] );
35 * Filter Heartbeat AJAX response in no-privilege environments.
39 * @param array|object $response The no-priv Heartbeat response object or array.
40 * @param array $data An array of data passed via $_POST.
41 * @param string $screen_id The screen id.
43 $response = apply_filters( 'heartbeat_nopriv_received', $response, $data, $screen_id );
47 * Filter Heartbeat AJAX response when no data is passed.
51 * @param array|object $response The Heartbeat response object or array.
52 * @param string $screen_id The screen id.
54 $response = apply_filters( 'heartbeat_nopriv_send', $response, $screen_id );
57 * Fires when Heartbeat ticks in no-privilege environments.
59 * Allows the transport to be easily replaced with long-polling.
63 * @param array|object $response The no-priv Heartbeat response.
64 * @param string $screen_id The screen id.
66 do_action( 'heartbeat_nopriv_tick', $response, $screen_id );
68 // Send the current time according to the server.
69 $response['server_time'] = time();
71 wp_send_json($response);
75 // GET-based Ajax handlers.
79 * Ajax handler for fetching a list table.
83 * @global WP_List_Table $wp_list_table
85 function wp_ajax_fetch_list() {
86 global $wp_list_table;
88 $list_class = $_GET['list_args']['class'];
89 check_ajax_referer( "fetch-list-$list_class", '_ajax_fetch_list_nonce' );
91 $wp_list_table = _get_list_table( $list_class, array( 'screen' => $_GET['list_args']['screen']['id'] ) );
92 if ( ! $wp_list_table )
95 if ( ! $wp_list_table->ajax_user_can() )
98 $wp_list_table->ajax_response();
104 * Ajax handler for tag search.
108 function wp_ajax_ajax_tag_search() {
109 if ( ! isset( $_GET['tax'] ) ) {
113 $taxonomy = sanitize_key( $_GET['tax'] );
114 $tax = get_taxonomy( $taxonomy );
119 if ( ! current_user_can( $tax->cap->assign_terms ) ) {
123 $s = wp_unslash( $_GET['q'] );
125 $comma = _x( ',', 'tag delimiter' );
126 if ( ',' !== $comma )
127 $s = str_replace( $comma, ',', $s );
128 if ( false !== strpos( $s, ',' ) ) {
129 $s = explode( ',', $s );
130 $s = $s[count( $s ) - 1];
135 * Filter the minimum number of characters required to fire a tag search via AJAX.
139 * @param int $characters The minimum number of characters required. Default 2.
140 * @param object $tax The taxonomy object.
141 * @param string $s The search term.
143 $term_search_min_chars = (int) apply_filters( 'term_search_min_chars', 2, $tax, $s );
146 * Require $term_search_min_chars chars for matching (default: 2)
147 * ensure it's a non-negative, non-zero integer.
149 if ( ( $term_search_min_chars == 0 ) || ( strlen( $s ) < $term_search_min_chars ) ){
153 $results = get_terms( $taxonomy, array( 'name__like' => $s, 'fields' => 'names', 'hide_empty' => false ) );
155 echo join( $results, "\n" );
160 * Ajax handler for compression testing.
164 function wp_ajax_wp_compression_test() {
165 if ( !current_user_can( 'manage_options' ) )
168 if ( ini_get('zlib.output_compression') || 'ob_gzhandler' == ini_get('output_handler') ) {
169 update_site_option('can_compress_scripts', 0);
173 if ( isset($_GET['test']) ) {
174 header( 'Expires: Wed, 11 Jan 1984 05:00:00 GMT' );
175 header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
176 header( 'Cache-Control: no-cache, must-revalidate, max-age=0' );
177 header( 'Pragma: no-cache' );
178 header('Content-Type: application/javascript; charset=UTF-8');
179 $force_gzip = ( defined('ENFORCE_GZIP') && ENFORCE_GZIP );
180 $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."';
182 if ( 1 == $_GET['test'] ) {
185 } elseif ( 2 == $_GET['test'] ) {
186 if ( !isset($_SERVER['HTTP_ACCEPT_ENCODING']) )
188 if ( false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate') && function_exists('gzdeflate') && ! $force_gzip ) {
189 header('Content-Encoding: deflate');
190 $out = gzdeflate( $test_str, 1 );
191 } elseif ( false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') && function_exists('gzencode') ) {
192 header('Content-Encoding: gzip');
193 $out = gzencode( $test_str, 1 );
199 } elseif ( 'no' == $_GET['test'] ) {
200 update_site_option('can_compress_scripts', 0);
201 } elseif ( 'yes' == $_GET['test'] ) {
202 update_site_option('can_compress_scripts', 1);
210 * Ajax handler for image editor previews.
214 function wp_ajax_imgedit_preview() {
215 $post_id = intval($_GET['postid']);
216 if ( empty($post_id) || !current_user_can('edit_post', $post_id) )
219 check_ajax_referer( "image_editor-$post_id" );
221 include_once( ABSPATH . 'wp-admin/includes/image-edit.php' );
222 if ( ! stream_preview_image($post_id) )
229 * Ajax handler for oEmbed caching.
233 * @global WP_Embed $wp_embed
235 function wp_ajax_oembed_cache() {
236 $GLOBALS['wp_embed']->cache_oembed( $_GET['post'] );
241 * Ajax handler for user autocomplete.
245 function wp_ajax_autocomplete_user() {
246 if ( ! is_multisite() || ! current_user_can( 'promote_users' ) || wp_is_large_network( 'users' ) )
249 /** This filter is documented in wp-admin/user-new.php */
250 if ( ! is_super_admin() && ! apply_filters( 'autocomplete_users_for_site_admins', false ) )
255 // Check the type of request
256 // Current allowed values are `add` and `search`
257 if ( isset( $_REQUEST['autocomplete_type'] ) && 'search' === $_REQUEST['autocomplete_type'] ) {
258 $type = $_REQUEST['autocomplete_type'];
263 // Check the desired field for value
264 // Current allowed values are `user_email` and `user_login`
265 if ( isset( $_REQUEST['autocomplete_field'] ) && 'user_email' === $_REQUEST['autocomplete_field'] ) {
266 $field = $_REQUEST['autocomplete_field'];
268 $field = 'user_login';
271 // Exclude current users of this blog
272 if ( isset( $_REQUEST['site_id'] ) ) {
273 $id = absint( $_REQUEST['site_id'] );
275 $id = get_current_blog_id();
278 $include_blog_users = ( $type == 'search' ? get_users( array( 'blog_id' => $id, 'fields' => 'ID' ) ) : array() );
279 $exclude_blog_users = ( $type == 'add' ? get_users( array( 'blog_id' => $id, 'fields' => 'ID' ) ) : array() );
281 $users = get_users( array(
283 'search' => '*' . $_REQUEST['term'] . '*',
284 'include' => $include_blog_users,
285 'exclude' => $exclude_blog_users,
286 'search_columns' => array( 'user_login', 'user_nicename', 'user_email' ),
289 foreach ( $users as $user ) {
291 /* translators: 1: user_login, 2: user_email */
292 'label' => sprintf( __( '%1$s (%2$s)' ), $user->user_login, $user->user_email ),
293 'value' => $user->$field,
297 wp_die( wp_json_encode( $return ) );
301 * Ajax handler for dashboard widgets.
305 function wp_ajax_dashboard_widgets() {
306 require_once ABSPATH . 'wp-admin/includes/dashboard.php';
308 $pagenow = $_GET['pagenow'];
309 if ( $pagenow === 'dashboard-user' || $pagenow === 'dashboard-network' || $pagenow === 'dashboard' ) {
310 set_current_screen( $pagenow );
313 switch ( $_GET['widget'] ) {
314 case 'dashboard_primary' :
315 wp_dashboard_primary();
322 * Ajax handler for Customizer preview logged-in status.
326 function wp_ajax_logged_in() {
335 * Sends back current comment total and new page links if they need to be updated.
337 * Contrary to normal success AJAX response ("1"), die with time() on success.
341 * @param int $comment_id
344 function _wp_ajax_delete_comment_response( $comment_id, $delta = -1 ) {
345 $total = isset( $_POST['_total'] ) ? (int) $_POST['_total'] : 0;
346 $per_page = isset( $_POST['_per_page'] ) ? (int) $_POST['_per_page'] : 0;
347 $page = isset( $_POST['_page'] ) ? (int) $_POST['_page'] : 0;
348 $url = isset( $_POST['_url'] ) ? esc_url_raw( $_POST['_url'] ) : '';
350 // JS didn't send us everything we need to know. Just die with success message
351 if ( ! $total || ! $per_page || ! $page || ! $url ) {
353 $comment = get_comment( $comment_id );
355 $counts = wp_count_comments();
357 $x = new WP_Ajax_Response( array(
359 // Here for completeness - not used.
361 'supplemental' => array(
362 'status' => $comment ? $comment->comment_approved : '',
363 'postId' => $comment ? $comment->comment_post_ID : '',
365 'in_moderation' => $counts->moderated,
366 'i18n_comments_text' => sprintf(
367 _n( '%s Comment', '%s Comments', $counts->approved ),
368 number_format_i18n( $counts->approved )
370 'i18n_moderation_text' => sprintf(
371 _nx( '%s in moderation', '%s in moderation', $counts->moderated, 'comments' ),
372 number_format_i18n( $counts->moderated )
383 // Only do the expensive stuff on a page-break, and about 1 other time per page
384 if ( 0 == $total % $per_page || 1 == mt_rand( 1, $per_page ) ) {
386 // What type of comment count are we looking for?
388 $parsed = parse_url( $url );
389 if ( isset( $parsed['query'] ) ) {
390 parse_str( $parsed['query'], $query_vars );
391 if ( !empty( $query_vars['comment_status'] ) )
392 $status = $query_vars['comment_status'];
393 if ( !empty( $query_vars['p'] ) )
394 $post_id = (int) $query_vars['p'];
397 $comment_count = wp_count_comments($post_id);
399 // We're looking for a known type of comment count.
400 if ( isset( $comment_count->$status ) )
401 $total = $comment_count->$status;
402 // Else use the decremented value from above.
405 // The time since the last comment count.
407 $comment = get_comment( $comment_id );
409 $x = new WP_Ajax_Response( array(
411 // Here for completeness - not used.
413 'supplemental' => array(
414 'status' => $comment ? $comment->comment_approved : '',
415 'postId' => $comment ? $comment->comment_post_ID : '',
416 'total_items_i18n' => sprintf( _n( '%s item', '%s items', $total ), number_format_i18n( $total ) ),
417 'total_pages' => ceil( $total / $per_page ),
418 'total_pages_i18n' => number_format_i18n( ceil( $total / $per_page ) ),
427 // POST-based Ajax handlers.
431 * Ajax handler for adding a hierarchical term.
435 function _wp_ajax_add_hierarchical_term() {
436 $action = $_POST['action'];
437 $taxonomy = get_taxonomy(substr($action, 4));
438 check_ajax_referer( $action, '_ajax_nonce-add-' . $taxonomy->name );
439 if ( !current_user_can( $taxonomy->cap->edit_terms ) )
441 $names = explode(',', $_POST['new'.$taxonomy->name]);
442 $parent = isset($_POST['new'.$taxonomy->name.'_parent']) ? (int) $_POST['new'.$taxonomy->name.'_parent'] : 0;
445 if ( $taxonomy->name == 'category' )
446 $post_category = isset($_POST['post_category']) ? (array) $_POST['post_category'] : array();
448 $post_category = ( isset($_POST['tax_input']) && isset($_POST['tax_input'][$taxonomy->name]) ) ? (array) $_POST['tax_input'][$taxonomy->name] : array();
449 $checked_categories = array_map( 'absint', (array) $post_category );
450 $popular_ids = wp_popular_terms_checklist($taxonomy->name, 0, 10, false);
452 foreach ( $names as $cat_name ) {
453 $cat_name = trim($cat_name);
454 $category_nicename = sanitize_title($cat_name);
455 if ( '' === $category_nicename )
457 if ( !$cat_id = term_exists( $cat_name, $taxonomy->name, $parent ) )
458 $cat_id = wp_insert_term( $cat_name, $taxonomy->name, array( 'parent' => $parent ) );
459 if ( is_wp_error( $cat_id ) ) {
461 } elseif ( is_array( $cat_id ) ) {
462 $cat_id = $cat_id['term_id'];
464 $checked_categories[] = $cat_id;
465 if ( $parent ) // Do these all at once in a second
470 wp_terms_checklist( 0, array( 'taxonomy' => $taxonomy->name, 'descendants_and_self' => $cat_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids ));
472 $data = ob_get_clean();
475 'what' => $taxonomy->name,
477 'data' => str_replace( array("\n", "\t"), '', $data),
482 if ( $parent ) { // Foncy - replace the parent and all its children
483 $parent = get_term( $parent, $taxonomy->name );
484 $term_id = $parent->term_id;
486 while ( $parent->parent ) { // get the top parent
487 $parent = get_term( $parent->parent, $taxonomy->name );
488 if ( is_wp_error( $parent ) )
490 $term_id = $parent->term_id;
495 wp_terms_checklist( 0, array('taxonomy' => $taxonomy->name, 'descendants_and_self' => $term_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids));
497 $data = ob_get_clean();
500 'what' => $taxonomy->name,
502 'data' => str_replace( array("\n", "\t"), '', $data),
509 wp_dropdown_categories( array(
510 'taxonomy' => $taxonomy->name, 'hide_empty' => 0, 'name' => 'new'.$taxonomy->name.'_parent', 'orderby' => 'name',
511 'hierarchical' => 1, 'show_option_none' => '— '.$taxonomy->labels->parent_item.' —'
514 $sup = ob_get_clean();
516 $add['supplemental'] = array( 'newcat_parent' => $sup );
518 $x = new WP_Ajax_Response( $add );
523 * Ajax handler for deleting a comment.
527 function wp_ajax_delete_comment() {
528 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
530 if ( !$comment = get_comment( $id ) )
532 if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) )
535 check_ajax_referer( "delete-comment_$id" );
536 $status = wp_get_comment_status( $comment );
539 if ( isset($_POST['trash']) && 1 == $_POST['trash'] ) {
540 if ( 'trash' == $status )
542 $r = wp_trash_comment( $comment );
543 } elseif ( isset($_POST['untrash']) && 1 == $_POST['untrash'] ) {
544 if ( 'trash' != $status )
546 $r = wp_untrash_comment( $comment );
547 if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'trash' ) // undo trash, not in trash
549 } elseif ( isset($_POST['spam']) && 1 == $_POST['spam'] ) {
550 if ( 'spam' == $status )
552 $r = wp_spam_comment( $comment );
553 } elseif ( isset($_POST['unspam']) && 1 == $_POST['unspam'] ) {
554 if ( 'spam' != $status )
556 $r = wp_unspam_comment( $comment );
557 if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'spam' ) // undo spam, not in spam
559 } elseif ( isset($_POST['delete']) && 1 == $_POST['delete'] ) {
560 $r = wp_delete_comment( $comment );
565 if ( $r ) // Decide if we need to send back '1' or a more complicated response including page links and comment counts
566 _wp_ajax_delete_comment_response( $comment->comment_ID, $delta );
571 * Ajax handler for deleting a tag.
575 function wp_ajax_delete_tag() {
576 $tag_id = (int) $_POST['tag_ID'];
577 check_ajax_referer( "delete-tag_$tag_id" );
579 $taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
580 $tax = get_taxonomy($taxonomy);
582 if ( !current_user_can( $tax->cap->delete_terms ) )
585 $tag = get_term( $tag_id, $taxonomy );
586 if ( !$tag || is_wp_error( $tag ) )
589 if ( wp_delete_term($tag_id, $taxonomy))
596 * Ajax handler for deleting a link.
600 function wp_ajax_delete_link() {
601 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
603 check_ajax_referer( "delete-bookmark_$id" );
604 if ( !current_user_can( 'manage_links' ) )
607 $link = get_bookmark( $id );
608 if ( !$link || is_wp_error( $link ) )
611 if ( wp_delete_link( $id ) )
618 * Ajax handler for deleting meta.
622 function wp_ajax_delete_meta() {
623 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
625 check_ajax_referer( "delete-meta_$id" );
626 if ( !$meta = get_metadata_by_mid( 'post', $id ) )
629 if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'delete_post_meta', $meta->post_id, $meta->meta_key ) )
631 if ( delete_meta( $meta->meta_id ) )
637 * Ajax handler for deleting a post.
641 * @param string $action Action to perform.
643 function wp_ajax_delete_post( $action ) {
644 if ( empty( $action ) )
645 $action = 'delete-post';
646 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
648 check_ajax_referer( "{$action}_$id" );
649 if ( !current_user_can( 'delete_post', $id ) )
652 if ( !get_post( $id ) )
655 if ( wp_delete_post( $id ) )
662 * Ajax handler for sending a post to the trash.
666 * @param string $action Action to perform.
668 function wp_ajax_trash_post( $action ) {
669 if ( empty( $action ) )
670 $action = 'trash-post';
671 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
673 check_ajax_referer( "{$action}_$id" );
674 if ( !current_user_can( 'delete_post', $id ) )
677 if ( !get_post( $id ) )
680 if ( 'trash-post' == $action )
681 $done = wp_trash_post( $id );
683 $done = wp_untrash_post( $id );
692 * Ajax handler to restore a post from the trash.
696 * @param string $action Action to perform.
698 function wp_ajax_untrash_post( $action ) {
699 if ( empty( $action ) )
700 $action = 'untrash-post';
701 wp_ajax_trash_post( $action );
707 * @param string $action
709 function wp_ajax_delete_page( $action ) {
710 if ( empty( $action ) )
711 $action = 'delete-page';
712 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
714 check_ajax_referer( "{$action}_$id" );
715 if ( !current_user_can( 'delete_page', $id ) )
718 if ( ! get_post( $id ) )
721 if ( wp_delete_post( $id ) )
728 * Ajax handler to dim a comment.
732 function wp_ajax_dim_comment() {
733 $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
735 if ( !$comment = get_comment( $id ) ) {
736 $x = new WP_Ajax_Response( array(
738 'id' => new WP_Error('invalid_comment', sprintf(__('Comment %d does not exist'), $id))
743 if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) && ! current_user_can( 'moderate_comments' ) )
746 $current = wp_get_comment_status( $comment );
747 if ( isset( $_POST['new'] ) && $_POST['new'] == $current )
750 check_ajax_referer( "approve-comment_$id" );
751 if ( in_array( $current, array( 'unapproved', 'spam' ) ) ) {
752 $result = wp_set_comment_status( $comment, 'approve', true );
754 $result = wp_set_comment_status( $comment, 'hold', true );
757 if ( is_wp_error($result) ) {
758 $x = new WP_Ajax_Response( array(
765 // Decide if we need to send back '1' or a more complicated response including page links and comment counts
766 _wp_ajax_delete_comment_response( $comment->comment_ID );
771 * Ajax handler for deleting a link category.
775 * @param string $action Action to perform.
777 function wp_ajax_add_link_category( $action ) {
778 if ( empty( $action ) )
779 $action = 'add-link-category';
780 check_ajax_referer( $action );
781 if ( !current_user_can( 'manage_categories' ) )
783 $names = explode(',', wp_unslash( $_POST['newcat'] ) );
784 $x = new WP_Ajax_Response();
785 foreach ( $names as $cat_name ) {
786 $cat_name = trim($cat_name);
787 $slug = sanitize_title($cat_name);
790 if ( !$cat_id = term_exists( $cat_name, 'link_category' ) )
791 $cat_id = wp_insert_term( $cat_name, 'link_category' );
792 if ( is_wp_error( $cat_id ) ) {
794 } elseif ( is_array( $cat_id ) ) {
795 $cat_id = $cat_id['term_id'];
797 $cat_name = esc_html( $cat_name );
799 'what' => 'link-category',
801 '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>",
809 * Ajax handler to add a tag.
813 * @global WP_List_Table $wp_list_table
815 function wp_ajax_add_tag() {
816 global $wp_list_table;
818 check_ajax_referer( 'add-tag', '_wpnonce_add-tag' );
819 $taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
820 $tax = get_taxonomy($taxonomy);
822 if ( !current_user_can( $tax->cap->edit_terms ) )
825 $x = new WP_Ajax_Response();
827 $tag = wp_insert_term($_POST['tag-name'], $taxonomy, $_POST );
829 if ( !$tag || is_wp_error($tag) || (!$tag = get_term( $tag['term_id'], $taxonomy )) ) {
830 $message = __('An error has occurred. Please reload the page and try again.');
831 if ( is_wp_error($tag) && $tag->get_error_message() )
832 $message = $tag->get_error_message();
835 'what' => 'taxonomy',
836 'data' => new WP_Error('error', $message )
841 $wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => $_POST['screen'] ) );
844 if ( is_taxonomy_hierarchical($taxonomy) ) {
845 $level = count( get_ancestors( $tag->term_id, $taxonomy, 'taxonomy' ) );
847 $wp_list_table->single_row( $tag, $level );
848 $noparents = ob_get_clean();
852 $wp_list_table->single_row( $tag );
853 $parents = ob_get_clean();
856 'what' => 'taxonomy',
857 'supplemental' => compact('parents', 'noparents')
861 'position' => $level,
862 'supplemental' => (array) $tag
868 * Ajax handler for getting a tagcloud.
872 function wp_ajax_get_tagcloud() {
873 if ( ! isset( $_POST['tax'] ) ) {
877 $taxonomy = sanitize_key( $_POST['tax'] );
878 $tax = get_taxonomy( $taxonomy );
883 if ( ! current_user_can( $tax->cap->assign_terms ) ) {
887 $tags = get_terms( $taxonomy, array( 'number' => 45, 'orderby' => 'count', 'order' => 'DESC' ) );
889 if ( empty( $tags ) )
890 wp_die( $tax->labels->not_found );
892 if ( is_wp_error( $tags ) )
893 wp_die( $tags->get_error_message() );
895 foreach ( $tags as $key => $tag ) {
896 $tags[ $key ]->link = '#';
897 $tags[ $key ]->id = $tag->term_id;
900 // We need raw tag names here, so don't filter the output
901 $return = wp_generate_tag_cloud( $tags, array('filter' => 0) );
903 if ( empty($return) )
912 * Ajax handler for getting comments.
916 * @global WP_List_Table $wp_list_table
917 * @global int $post_id
919 * @param string $action Action to perform.
921 function wp_ajax_get_comments( $action ) {
922 global $wp_list_table, $post_id;
923 if ( empty( $action ) )
924 $action = 'get-comments';
926 check_ajax_referer( $action );
928 if ( empty( $post_id ) && ! empty( $_REQUEST['p'] ) ) {
929 $id = absint( $_REQUEST['p'] );
930 if ( ! empty( $id ) )
934 if ( empty( $post_id ) )
937 $wp_list_table = _get_list_table( 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
939 if ( ! current_user_can( 'edit_post', $post_id ) )
942 $wp_list_table->prepare_items();
944 if ( !$wp_list_table->has_items() )
947 $x = new WP_Ajax_Response();
949 foreach ( $wp_list_table->items as $comment ) {
950 if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) )
952 get_comment( $comment );
953 $wp_list_table->single_row( $comment );
955 $comment_list_item = ob_get_clean();
958 'what' => 'comments',
959 'data' => $comment_list_item
965 * Ajax handler for replying to a comment.
969 * @global WP_List_Table $wp_list_table
971 * @param string $action Action to perform.
973 function wp_ajax_replyto_comment( $action ) {
974 global $wp_list_table;
975 if ( empty( $action ) )
976 $action = 'replyto-comment';
978 check_ajax_referer( $action, '_ajax_nonce-replyto-comment' );
980 $comment_post_ID = (int) $_POST['comment_post_ID'];
981 $post = get_post( $comment_post_ID );
985 if ( !current_user_can( 'edit_post', $comment_post_ID ) )
988 if ( empty( $post->post_status ) )
990 elseif ( in_array($post->post_status, array('draft', 'pending', 'trash') ) )
991 wp_die( __('ERROR: you are replying to a comment on a draft post.') );
993 $user = wp_get_current_user();
994 if ( $user->exists() ) {
995 $user_ID = $user->ID;
996 $comment_author = wp_slash( $user->display_name );
997 $comment_author_email = wp_slash( $user->user_email );
998 $comment_author_url = wp_slash( $user->user_url );
999 $comment_content = trim( $_POST['content'] );
1000 $comment_type = isset( $_POST['comment_type'] ) ? trim( $_POST['comment_type'] ) : '';
1001 if ( current_user_can( 'unfiltered_html' ) ) {
1002 if ( ! isset( $_POST['_wp_unfiltered_html_comment'] ) )
1003 $_POST['_wp_unfiltered_html_comment'] = '';
1005 if ( wp_create_nonce( 'unfiltered-html-comment' ) != $_POST['_wp_unfiltered_html_comment'] ) {
1006 kses_remove_filters(); // start with a clean slate
1007 kses_init_filters(); // set up the filters
1011 wp_die( __( 'Sorry, you must be logged in to reply to a comment.' ) );
1014 if ( '' == $comment_content )
1015 wp_die( __( 'ERROR: please type a comment.' ) );
1017 $comment_parent = 0;
1018 if ( isset( $_POST['comment_ID'] ) )
1019 $comment_parent = absint( $_POST['comment_ID'] );
1020 $comment_auto_approved = false;
1021 $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_type', 'comment_parent', 'user_ID');
1023 // Automatically approve parent comment.
1024 if ( !empty($_POST['approve_parent']) ) {
1025 $parent = get_comment( $comment_parent );
1027 if ( $parent && $parent->comment_approved === '0' && $parent->comment_post_ID == $comment_post_ID ) {
1028 if ( ! current_user_can( 'edit_comment', $parent->comment_ID ) ) {
1032 if ( wp_set_comment_status( $parent, 'approve' ) )
1033 $comment_auto_approved = true;
1037 $comment_id = wp_new_comment( $commentdata );
1038 $comment = get_comment($comment_id);
1039 if ( ! $comment ) wp_die( 1 );
1041 $position = ( isset($_POST['position']) && (int) $_POST['position'] ) ? (int) $_POST['position'] : '-1';
1044 if ( isset( $_REQUEST['mode'] ) && 'dashboard' == $_REQUEST['mode'] ) {
1045 require_once( ABSPATH . 'wp-admin/includes/dashboard.php' );
1046 _wp_dashboard_recent_comments_row( $comment );
1048 if ( isset( $_REQUEST['mode'] ) && 'single' == $_REQUEST['mode'] ) {
1049 $wp_list_table = _get_list_table('WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
1051 $wp_list_table = _get_list_table('WP_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
1053 $wp_list_table->single_row( $comment );
1055 $comment_list_item = ob_get_clean();
1058 'what' => 'comment',
1059 'id' => $comment->comment_ID,
1060 'data' => $comment_list_item,
1061 'position' => $position
1064 $counts = wp_count_comments();
1065 $response['supplemental'] = array(
1066 'in_moderation' => $counts->moderated,
1067 'i18n_comments_text' => sprintf(
1068 _n( '%s Comment', '%s Comments', $counts->approved ),
1069 number_format_i18n( $counts->approved )
1071 'i18n_moderation_text' => sprintf(
1072 _nx( '%s in moderation', '%s in moderation', $counts->moderated, 'comments' ),
1073 number_format_i18n( $counts->moderated )
1077 if ( $comment_auto_approved ) {
1078 $response['supplemental']['parent_approved'] = $parent->comment_ID;
1079 $response['supplemental']['parent_post_id'] = $parent->comment_post_ID;
1082 $x = new WP_Ajax_Response();
1083 $x->add( $response );
1088 * Ajax handler for editing a comment.
1092 * @global WP_List_Table $wp_list_table
1094 function wp_ajax_edit_comment() {
1095 global $wp_list_table;
1097 check_ajax_referer( 'replyto-comment', '_ajax_nonce-replyto-comment' );
1099 $comment_id = (int) $_POST['comment_ID'];
1100 if ( ! current_user_can( 'edit_comment', $comment_id ) )
1103 if ( '' == $_POST['content'] )
1104 wp_die( __( 'ERROR: please type a comment.' ) );
1106 if ( isset( $_POST['status'] ) )
1107 $_POST['comment_status'] = $_POST['status'];
1110 $position = ( isset($_POST['position']) && (int) $_POST['position']) ? (int) $_POST['position'] : '-1';
1111 $checkbox = ( isset($_POST['checkbox']) && true == $_POST['checkbox'] ) ? 1 : 0;
1112 $wp_list_table = _get_list_table( $checkbox ? 'WP_Comments_List_Table' : 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
1114 $comment = get_comment( $comment_id );
1115 if ( empty( $comment->comment_ID ) )
1119 $wp_list_table->single_row( $comment );
1120 $comment_list_item = ob_get_clean();
1122 $x = new WP_Ajax_Response();
1125 'what' => 'edit_comment',
1126 'id' => $comment->comment_ID,
1127 'data' => $comment_list_item,
1128 'position' => $position
1135 * Ajax handler for adding a menu item.
1139 function wp_ajax_add_menu_item() {
1140 check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' );
1142 if ( ! current_user_can( 'edit_theme_options' ) )
1145 require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
1147 // For performance reasons, we omit some object properties from the checklist.
1148 // The following is a hacky way to restore them when adding non-custom items.
1150 $menu_items_data = array();
1151 foreach ( (array) $_POST['menu-item'] as $menu_item_data ) {
1153 ! empty( $menu_item_data['menu-item-type'] ) &&
1154 'custom' != $menu_item_data['menu-item-type'] &&
1155 ! empty( $menu_item_data['menu-item-object-id'] )
1157 switch( $menu_item_data['menu-item-type'] ) {
1159 $_object = get_post( $menu_item_data['menu-item-object-id'] );
1162 case 'post_type_archive' :
1163 $_object = get_post_type_object( $menu_item_data['menu-item-object'] );
1167 $_object = get_term( $menu_item_data['menu-item-object-id'], $menu_item_data['menu-item-object'] );
1171 $_menu_items = array_map( 'wp_setup_nav_menu_item', array( $_object ) );
1172 $_menu_item = reset( $_menu_items );
1174 // Restore the missing menu item properties
1175 $menu_item_data['menu-item-description'] = $_menu_item->description;
1178 $menu_items_data[] = $menu_item_data;
1181 $item_ids = wp_save_nav_menu_items( 0, $menu_items_data );
1182 if ( is_wp_error( $item_ids ) )
1185 $menu_items = array();
1187 foreach ( (array) $item_ids as $menu_item_id ) {
1188 $menu_obj = get_post( $menu_item_id );
1189 if ( ! empty( $menu_obj->ID ) ) {
1190 $menu_obj = wp_setup_nav_menu_item( $menu_obj );
1191 $menu_obj->label = $menu_obj->title; // don't show "(pending)" in ajax-added items
1192 $menu_items[] = $menu_obj;
1196 /** This filter is documented in wp-admin/includes/nav-menu.php */
1197 $walker_class_name = apply_filters( 'wp_edit_nav_menu_walker', 'Walker_Nav_Menu_Edit', $_POST['menu'] );
1199 if ( ! class_exists( $walker_class_name ) )
1202 if ( ! empty( $menu_items ) ) {
1207 'link_before' => '',
1208 'walker' => new $walker_class_name,
1210 echo walk_nav_menu_tree( $menu_items, 0, (object) $args );
1216 * Ajax handler for adding meta.
1220 function wp_ajax_add_meta() {
1221 check_ajax_referer( 'add-meta', '_ajax_nonce-add-meta' );
1223 $pid = (int) $_POST['post_id'];
1224 $post = get_post( $pid );
1226 if ( isset($_POST['metakeyselect']) || isset($_POST['metakeyinput']) ) {
1227 if ( !current_user_can( 'edit_post', $pid ) )
1229 if ( isset($_POST['metakeyselect']) && '#NONE#' == $_POST['metakeyselect'] && empty($_POST['metakeyinput']) )
1232 // If the post is an autodraft, save the post as a draft and then attempt to save the meta.
1233 if ( $post->post_status == 'auto-draft' ) {
1234 $post_data = array();
1235 $post_data['action'] = 'draft'; // Warning fix
1236 $post_data['post_ID'] = $pid;
1237 $post_data['post_type'] = $post->post_type;
1238 $post_data['post_status'] = 'draft';
1239 $now = current_time('timestamp', 1);
1240 $post_data['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), date( get_option( 'date_format' ), $now ), date( get_option( 'time_format' ), $now ) );
1242 $pid = edit_post( $post_data );
1244 if ( is_wp_error( $pid ) ) {
1245 $x = new WP_Ajax_Response( array(
1252 if ( !$mid = add_meta( $pid ) )
1253 wp_die( __( 'Please provide a custom field value.' ) );
1257 } elseif ( ! $mid = add_meta( $pid ) ) {
1258 wp_die( __( 'Please provide a custom field value.' ) );
1261 $meta = get_metadata_by_mid( 'post', $mid );
1262 $pid = (int) $meta->post_id;
1263 $meta = get_object_vars( $meta );
1264 $x = new WP_Ajax_Response( array(
1267 'data' => _list_meta_row( $meta, $c ),
1269 'supplemental' => array('postid' => $pid)
1272 $mid = (int) key( $_POST['meta'] );
1273 $key = wp_unslash( $_POST['meta'][$mid]['key'] );
1274 $value = wp_unslash( $_POST['meta'][$mid]['value'] );
1275 if ( '' == trim($key) )
1276 wp_die( __( 'Please provide a custom field name.' ) );
1277 if ( '' == trim($value) )
1278 wp_die( __( 'Please provide a custom field value.' ) );
1279 if ( ! $meta = get_metadata_by_mid( 'post', $mid ) )
1280 wp_die( 0 ); // if meta doesn't exist
1281 if ( is_protected_meta( $meta->meta_key, 'post' ) || is_protected_meta( $key, 'post' ) ||
1282 ! current_user_can( 'edit_post_meta', $meta->post_id, $meta->meta_key ) ||
1283 ! current_user_can( 'edit_post_meta', $meta->post_id, $key ) )
1285 if ( $meta->meta_value != $value || $meta->meta_key != $key ) {
1286 if ( !$u = update_metadata_by_mid( 'post', $mid, $value, $key ) )
1287 wp_die( 0 ); // We know meta exists; we also know it's unchanged (or DB error, in which case there are bigger problems).
1290 $x = new WP_Ajax_Response( array(
1292 'id' => $mid, 'old_id' => $mid,
1293 'data' => _list_meta_row( array(
1295 'meta_value' => $value,
1299 'supplemental' => array('postid' => $meta->post_id)
1306 * Ajax handler for adding a user.
1310 * @global WP_List_Table $wp_list_table
1312 * @param string $action Action to perform.
1314 function wp_ajax_add_user( $action ) {
1315 global $wp_list_table;
1316 if ( empty( $action ) )
1317 $action = 'add-user';
1319 check_ajax_referer( $action );
1320 if ( ! current_user_can('create_users') )
1322 if ( ! $user_id = edit_user() ) {
1324 } elseif ( is_wp_error( $user_id ) ) {
1325 $x = new WP_Ajax_Response( array(
1331 $user_object = get_userdata( $user_id );
1333 $wp_list_table = _get_list_table('WP_Users_List_Table');
1335 $role = current( $user_object->roles );
1337 $x = new WP_Ajax_Response( array(
1340 'data' => $wp_list_table->single_row( $user_object, '', $role ),
1341 'supplemental' => array(
1342 'show-link' => sprintf(
1343 /* translators: %s: the new user */
1344 __( 'User %s added' ),
1345 '<a href="#user-' . $user_id . '">' . $user_object->user_login . '</a>'
1354 * Ajax handler for closed post boxes.
1358 function wp_ajax_closed_postboxes() {
1359 check_ajax_referer( 'closedpostboxes', 'closedpostboxesnonce' );
1360 $closed = isset( $_POST['closed'] ) ? explode( ',', $_POST['closed']) : array();
1361 $closed = array_filter($closed);
1363 $hidden = isset( $_POST['hidden'] ) ? explode( ',', $_POST['hidden']) : array();
1364 $hidden = array_filter($hidden);
1366 $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1368 if ( $page != sanitize_key( $page ) )
1371 if ( ! $user = wp_get_current_user() )
1374 if ( is_array($closed) )
1375 update_user_option($user->ID, "closedpostboxes_$page", $closed, true);
1377 if ( is_array($hidden) ) {
1378 $hidden = array_diff( $hidden, array('submitdiv', 'linksubmitdiv', 'manage-menu', 'create-menu') ); // postboxes that are always shown
1379 update_user_option($user->ID, "metaboxhidden_$page", $hidden, true);
1386 * Ajax handler for hidden columns.
1390 function wp_ajax_hidden_columns() {
1391 check_ajax_referer( 'screen-options-nonce', 'screenoptionnonce' );
1392 $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1394 if ( $page != sanitize_key( $page ) )
1397 if ( ! $user = wp_get_current_user() )
1400 $hidden = ! empty( $_POST['hidden'] ) ? explode( ',', $_POST['hidden'] ) : array();
1401 update_user_option( $user->ID, "manage{$page}columnshidden", $hidden, true );
1407 * Ajax handler for updating whether to display the welcome panel.
1411 function wp_ajax_update_welcome_panel() {
1412 check_ajax_referer( 'welcome-panel-nonce', 'welcomepanelnonce' );
1414 if ( ! current_user_can( 'edit_theme_options' ) )
1417 update_user_meta( get_current_user_id(), 'show_welcome_panel', empty( $_POST['visible'] ) ? 0 : 1 );
1423 * Ajax handler for retrieving menu meta boxes.
1427 function wp_ajax_menu_get_metabox() {
1428 if ( ! current_user_can( 'edit_theme_options' ) )
1431 require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
1433 if ( isset( $_POST['item-type'] ) && 'post_type' == $_POST['item-type'] ) {
1435 $callback = 'wp_nav_menu_item_post_type_meta_box';
1436 $items = (array) get_post_types( array( 'show_in_nav_menus' => true ), 'object' );
1437 } elseif ( isset( $_POST['item-type'] ) && 'taxonomy' == $_POST['item-type'] ) {
1439 $callback = 'wp_nav_menu_item_taxonomy_meta_box';
1440 $items = (array) get_taxonomies( array( 'show_ui' => true ), 'object' );
1443 if ( ! empty( $_POST['item-object'] ) && isset( $items[$_POST['item-object']] ) ) {
1444 $menus_meta_box_object = $items[ $_POST['item-object'] ];
1446 /** This filter is documented in wp-admin/includes/nav-menu.php */
1447 $item = apply_filters( 'nav_menu_meta_box_object', $menus_meta_box_object );
1449 call_user_func_array($callback, array(
1452 'id' => 'add-' . $item->name,
1453 'title' => $item->labels->name,
1454 'callback' => $callback,
1459 $markup = ob_get_clean();
1461 echo wp_json_encode(array(
1462 'replace-id' => $type . '-' . $item->name,
1463 'markup' => $markup,
1471 * Ajax handler for internal linking.
1475 function wp_ajax_wp_link_ajax() {
1476 check_ajax_referer( 'internal-linking', '_ajax_linking_nonce' );
1480 if ( isset( $_POST['search'] ) )
1481 $args['s'] = wp_unslash( $_POST['search'] );
1482 $args['pagenum'] = ! empty( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
1484 require(ABSPATH . WPINC . '/class-wp-editor.php');
1485 $results = _WP_Editors::wp_link_query( $args );
1487 if ( ! isset( $results ) )
1490 echo wp_json_encode( $results );
1497 * Ajax handler for menu locations save.
1501 function wp_ajax_menu_locations_save() {
1502 if ( ! current_user_can( 'edit_theme_options' ) )
1504 check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' );
1505 if ( ! isset( $_POST['menu-locations'] ) )
1507 set_theme_mod( 'nav_menu_locations', array_map( 'absint', $_POST['menu-locations'] ) );
1512 * Ajax handler for saving the meta box order.
1516 function wp_ajax_meta_box_order() {
1517 check_ajax_referer( 'meta-box-order' );
1518 $order = isset( $_POST['order'] ) ? (array) $_POST['order'] : false;
1519 $page_columns = isset( $_POST['page_columns'] ) ? $_POST['page_columns'] : 'auto';
1521 if ( $page_columns != 'auto' )
1522 $page_columns = (int) $page_columns;
1524 $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1526 if ( $page != sanitize_key( $page ) )
1529 if ( ! $user = wp_get_current_user() )
1533 update_user_option($user->ID, "meta-box-order_$page", $order, true);
1535 if ( $page_columns )
1536 update_user_option($user->ID, "screen_layout_$page", $page_columns, true);
1542 * Ajax handler for menu quick searching.
1546 function wp_ajax_menu_quick_search() {
1547 if ( ! current_user_can( 'edit_theme_options' ) )
1550 require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
1552 _wp_ajax_menu_quick_search( $_POST );
1558 * Ajax handler to retrieve a permalink.
1562 function wp_ajax_get_permalink() {
1563 check_ajax_referer( 'getpermalink', 'getpermalinknonce' );
1564 $post_id = isset($_POST['post_id'])? intval($_POST['post_id']) : 0;
1565 wp_die( get_preview_post_link( $post_id ) );
1569 * Ajax handler to retrieve a sample permalink.
1573 function wp_ajax_sample_permalink() {
1574 check_ajax_referer( 'samplepermalink', 'samplepermalinknonce' );
1575 $post_id = isset($_POST['post_id'])? intval($_POST['post_id']) : 0;
1576 $title = isset($_POST['new_title'])? $_POST['new_title'] : '';
1577 $slug = isset($_POST['new_slug'])? $_POST['new_slug'] : null;
1578 wp_die( get_sample_permalink_html( $post_id, $title, $slug ) );
1582 * Ajax handler for Quick Edit saving a post from a list table.
1586 * @global WP_List_Table $wp_list_table
1588 function wp_ajax_inline_save() {
1589 global $wp_list_table, $mode;
1591 check_ajax_referer( 'inlineeditnonce', '_inline_edit' );
1593 if ( ! isset($_POST['post_ID']) || ! ( $post_ID = (int) $_POST['post_ID'] ) )
1596 if ( 'page' == $_POST['post_type'] ) {
1597 if ( ! current_user_can( 'edit_page', $post_ID ) )
1598 wp_die( __( 'You are not allowed to edit this page.' ) );
1600 if ( ! current_user_can( 'edit_post', $post_ID ) )
1601 wp_die( __( 'You are not allowed to edit this post.' ) );
1604 if ( $last = wp_check_post_lock( $post_ID ) ) {
1605 $last_user = get_userdata( $last );
1606 $last_user_name = $last_user ? $last_user->display_name : __( 'Someone' );
1607 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 ) );
1613 $post = get_post( $post_ID, ARRAY_A );
1615 // Since it's coming from the database.
1616 $post = wp_slash($post);
1618 $data['content'] = $post['post_content'];
1619 $data['excerpt'] = $post['post_excerpt'];
1622 $data['user_ID'] = get_current_user_id();
1624 if ( isset($data['post_parent']) )
1625 $data['parent_id'] = $data['post_parent'];
1628 if ( isset( $data['keep_private'] ) && 'private' == $data['keep_private'] ) {
1629 $data['visibility'] = 'private';
1630 $data['post_status'] = 'private';
1632 $data['post_status'] = $data['_status'];
1635 if ( empty($data['comment_status']) )
1636 $data['comment_status'] = 'closed';
1637 if ( empty($data['ping_status']) )
1638 $data['ping_status'] = 'closed';
1640 // Exclude terms from taxonomies that are not supposed to appear in Quick Edit.
1641 if ( ! empty( $data['tax_input'] ) ) {
1642 foreach ( $data['tax_input'] as $taxonomy => $terms ) {
1643 $tax_object = get_taxonomy( $taxonomy );
1644 /** This filter is documented in wp-admin/includes/class-wp-posts-list-table.php */
1645 if ( ! apply_filters( 'quick_edit_show_taxonomy', $tax_object->show_in_quick_edit, $taxonomy, $post['post_type'] ) ) {
1646 unset( $data['tax_input'][ $taxonomy ] );
1651 // Hack: wp_unique_post_slug() doesn't work for drafts, so we will fake that our post is published.
1652 if ( ! empty( $data['post_name'] ) && in_array( $post['post_status'], array( 'draft', 'pending' ) ) ) {
1653 $post['post_status'] = 'publish';
1654 $data['post_name'] = wp_unique_post_slug( $data['post_name'], $post['ID'], $post['post_status'], $post['post_type'], $post['post_parent'] );
1660 $wp_list_table = _get_list_table( 'WP_Posts_List_Table', array( 'screen' => $_POST['screen'] ) );
1662 $mode = $_POST['post_view'] === 'excerpt' ? 'excerpt' : 'list';
1665 $request_post = array( get_post( $_POST['post_ID'] ) );
1666 $parent = $request_post[0]->post_parent;
1668 while ( $parent > 0 ) {
1669 $parent_post = get_post( $parent );
1670 $parent = $parent_post->post_parent;
1674 $wp_list_table->display_rows( array( get_post( $_POST['post_ID'] ) ), $level );
1680 * Ajax handler for quick edit saving for a term.
1684 * @global WP_List_Table $wp_list_table
1686 function wp_ajax_inline_save_tax() {
1687 global $wp_list_table;
1689 check_ajax_referer( 'taxinlineeditnonce', '_inline_edit' );
1691 $taxonomy = sanitize_key( $_POST['taxonomy'] );
1692 $tax = get_taxonomy( $taxonomy );
1696 if ( ! current_user_can( $tax->cap->edit_terms ) )
1699 $wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => 'edit-' . $taxonomy ) );
1701 if ( ! isset($_POST['tax_ID']) || ! ( $id = (int) $_POST['tax_ID'] ) )
1704 $tag = get_term( $id, $taxonomy );
1705 $_POST['description'] = $tag->description;
1707 $updated = wp_update_term($id, $taxonomy, $_POST);
1708 if ( $updated && !is_wp_error($updated) ) {
1709 $tag = get_term( $updated['term_id'], $taxonomy );
1710 if ( !$tag || is_wp_error( $tag ) ) {
1711 if ( is_wp_error($tag) && $tag->get_error_message() )
1712 wp_die( $tag->get_error_message() );
1713 wp_die( __( 'Item not updated.' ) );
1716 if ( is_wp_error($updated) && $updated->get_error_message() )
1717 wp_die( $updated->get_error_message() );
1718 wp_die( __( 'Item not updated.' ) );
1721 $parent = $tag->parent;
1722 while ( $parent > 0 ) {
1723 $parent_tag = get_term( $parent, $taxonomy );
1724 $parent = $parent_tag->parent;
1727 $wp_list_table->single_row( $tag, $level );
1732 * Ajax handler for querying posts for the Find Posts modal.
1734 * @see window.findPosts
1738 function wp_ajax_find_posts() {
1739 check_ajax_referer( 'find-posts' );
1741 $post_types = get_post_types( array( 'public' => true ), 'objects' );
1742 unset( $post_types['attachment'] );
1744 $s = wp_unslash( $_POST['ps'] );
1746 'post_type' => array_keys( $post_types ),
1747 'post_status' => 'any',
1748 'posts_per_page' => 50,
1753 $posts = get_posts( $args );
1756 wp_send_json_error( __( 'No items found.' ) );
1759 $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>';
1761 foreach ( $posts as $post ) {
1762 $title = trim( $post->post_title ) ? $post->post_title : __( '(no title)' );
1763 $alt = ( 'alternate' == $alt ) ? '' : 'alternate';
1765 switch ( $post->post_status ) {
1768 $stat = __('Published');
1771 $stat = __('Scheduled');
1774 $stat = __('Pending Review');
1777 $stat = __('Draft');
1781 if ( '0000-00-00 00:00:00' == $post->post_date ) {
1784 /* translators: date format in table columns, see http://php.net/date */
1785 $time = mysql2date(__('Y/m/d'), $post->post_date);
1788 $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>';
1789 $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";
1792 $html .= '</tbody></table>';
1794 wp_send_json_success( $html );
1798 * Ajax handler for saving the widgets order.
1802 function wp_ajax_widgets_order() {
1803 check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' );
1805 if ( !current_user_can('edit_theme_options') )
1808 unset( $_POST['savewidgets'], $_POST['action'] );
1810 // Save widgets order for all sidebars.
1811 if ( is_array($_POST['sidebars']) ) {
1812 $sidebars = array();
1813 foreach ( $_POST['sidebars'] as $key => $val ) {
1815 if ( !empty($val) ) {
1816 $val = explode(',', $val);
1817 foreach ( $val as $k => $v ) {
1818 if ( strpos($v, 'widget-') === false )
1821 $sb[$k] = substr($v, strpos($v, '_') + 1);
1824 $sidebars[$key] = $sb;
1826 wp_set_sidebars_widgets($sidebars);
1834 * Ajax handler for saving a widget.
1838 * @global array $wp_registered_widgets
1839 * @global array $wp_registered_widget_controls
1840 * @global array $wp_registered_widget_updates
1842 function wp_ajax_save_widget() {
1843 global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
1845 check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' );
1847 if ( !current_user_can('edit_theme_options') || !isset($_POST['id_base']) )
1850 unset( $_POST['savewidgets'], $_POST['action'] );
1853 * Fires early when editing the widgets displayed in sidebars.
1857 do_action( 'load-widgets.php' );
1860 * Fires early when editing the widgets displayed in sidebars.
1864 do_action( 'widgets.php' );
1866 /** This action is documented in wp-admin/widgets.php */
1867 do_action( 'sidebar_admin_setup' );
1869 $id_base = $_POST['id_base'];
1870 $widget_id = $_POST['widget-id'];
1871 $sidebar_id = $_POST['sidebar'];
1872 $multi_number = !empty($_POST['multi_number']) ? (int) $_POST['multi_number'] : 0;
1873 $settings = isset($_POST['widget-' . $id_base]) && is_array($_POST['widget-' . $id_base]) ? $_POST['widget-' . $id_base] : false;
1874 $error = '<p>' . __('An error has occurred. Please reload the page and try again.') . '</p>';
1876 $sidebars = wp_get_sidebars_widgets();
1877 $sidebar = isset($sidebars[$sidebar_id]) ? $sidebars[$sidebar_id] : array();
1880 if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
1882 if ( !isset($wp_registered_widgets[$widget_id]) )
1885 $sidebar = array_diff( $sidebar, array($widget_id) );
1886 $_POST = array('sidebar' => $sidebar_id, 'widget-' . $id_base => array(), 'the-widget-id' => $widget_id, 'delete_widget' => '1');
1888 /** This action is documented in wp-admin/widgets.php */
1889 do_action( 'delete_widget', $widget_id, $sidebar_id, $id_base );
1891 } elseif ( $settings && preg_match( '/__i__|%i%/', key($settings) ) ) {
1892 if ( !$multi_number )
1895 $_POST[ 'widget-' . $id_base ] = array( $multi_number => reset( $settings ) );
1896 $widget_id = $id_base . '-' . $multi_number;
1897 $sidebar[] = $widget_id;
1899 $_POST['widget-id'] = $sidebar;
1901 foreach ( (array) $wp_registered_widget_updates as $name => $control ) {
1903 if ( $name == $id_base ) {
1904 if ( !is_callable( $control['callback'] ) )
1908 call_user_func_array( $control['callback'], $control['params'] );
1914 if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
1915 $sidebars[$sidebar_id] = $sidebar;
1916 wp_set_sidebars_widgets($sidebars);
1917 echo "deleted:$widget_id";
1921 if ( !empty($_POST['add_new']) )
1924 if ( $form = $wp_registered_widget_controls[$widget_id] )
1925 call_user_func_array( $form['callback'], $form['params'] );
1931 * Ajax handler for saving a widget.
1935 * @global WP_Customize_Manager $wp_customize
1937 function wp_ajax_update_widget() {
1938 global $wp_customize;
1939 $wp_customize->widgets->wp_ajax_update_widget();
1943 * Ajax handler for removing inactive widgets.
1947 function wp_ajax_delete_inactive_widgets() {
1948 check_ajax_referer( 'remove-inactive-widgets', 'removeinactivewidgets' );
1950 if ( ! current_user_can( 'edit_theme_options' ) ) {
1954 unset( $_POST['removeinactivewidgets'], $_POST['action'] );
1956 do_action( 'load-widgets.php' );
1957 do_action( 'widgets.php' );
1958 do_action( 'sidebar_admin_setup' );
1960 $sidebars_widgets = wp_get_sidebars_widgets();
1962 foreach ( $sidebars_widgets['wp_inactive_widgets'] as $key => $widget_id ) {
1963 $pieces = explode( '-', $widget_id );
1964 $multi_number = array_pop( $pieces );
1965 $id_base = implode( '-', $pieces );
1966 $widget = get_option( 'widget_' . $id_base );
1967 unset( $widget[$multi_number] );
1968 update_option( 'widget_' . $id_base, $widget );
1969 unset( $sidebars_widgets['wp_inactive_widgets'][$key] );
1972 wp_set_sidebars_widgets( $sidebars_widgets );
1978 * Ajax handler for uploading attachments
1982 function wp_ajax_upload_attachment() {
1983 check_ajax_referer( 'media-form' );
1985 * This function does not use wp_send_json_success() / wp_send_json_error()
1986 * as the html4 Plupload handler requires a text/html content-type for older IE.
1987 * See https://core.trac.wordpress.org/ticket/31037
1990 if ( ! current_user_can( 'upload_files' ) ) {
1991 echo wp_json_encode( array(
1994 'message' => __( 'You do not have permission to upload files.' ),
1995 'filename' => $_FILES['async-upload']['name'],
2002 if ( isset( $_REQUEST['post_id'] ) ) {
2003 $post_id = $_REQUEST['post_id'];
2004 if ( ! current_user_can( 'edit_post', $post_id ) ) {
2005 echo wp_json_encode( array(
2008 'message' => __( "You don't have permission to attach files to this post." ),
2009 'filename' => $_FILES['async-upload']['name'],
2019 $post_data = isset( $_REQUEST['post_data'] ) ? $_REQUEST['post_data'] : array();
2021 // If the context is custom header or background, make sure the uploaded file is an image.
2022 if ( isset( $post_data['context'] ) && in_array( $post_data['context'], array( 'custom-header', 'custom-background' ) ) ) {
2023 $wp_filetype = wp_check_filetype_and_ext( $_FILES['async-upload']['tmp_name'], $_FILES['async-upload']['name'] );
2024 if ( ! wp_match_mime_types( 'image', $wp_filetype['type'] ) ) {
2025 echo wp_json_encode( array(
2028 'message' => __( 'The uploaded file is not a valid image. Please try again.' ),
2029 'filename' => $_FILES['async-upload']['name'],
2037 $attachment_id = media_handle_upload( 'async-upload', $post_id, $post_data );
2039 if ( is_wp_error( $attachment_id ) ) {
2040 echo wp_json_encode( array(
2043 'message' => $attachment_id->get_error_message(),
2044 'filename' => $_FILES['async-upload']['name'],
2051 if ( isset( $post_data['context'] ) && isset( $post_data['theme'] ) ) {
2052 if ( 'custom-background' === $post_data['context'] )
2053 update_post_meta( $attachment_id, '_wp_attachment_is_custom_background', $post_data['theme'] );
2055 if ( 'custom-header' === $post_data['context'] )
2056 update_post_meta( $attachment_id, '_wp_attachment_is_custom_header', $post_data['theme'] );
2059 if ( ! $attachment = wp_prepare_attachment_for_js( $attachment_id ) )
2062 echo wp_json_encode( array(
2064 'data' => $attachment,
2071 * Ajax handler for image editing.
2075 function wp_ajax_image_editor() {
2076 $attachment_id = intval($_POST['postid']);
2077 if ( empty($attachment_id) || !current_user_can('edit_post', $attachment_id) )
2080 check_ajax_referer( "image_editor-$attachment_id" );
2081 include_once( ABSPATH . 'wp-admin/includes/image-edit.php' );
2084 switch ( $_POST['do'] ) {
2086 $msg = wp_save_image($attachment_id);
2087 $msg = wp_json_encode($msg);
2091 $msg = wp_save_image($attachment_id);
2094 $msg = wp_restore_image($attachment_id);
2098 wp_image_editor($attachment_id, $msg);
2103 * Ajax handler for setting the featured image.
2107 function wp_ajax_set_post_thumbnail() {
2108 $json = ! empty( $_REQUEST['json'] ); // New-style request
2110 $post_ID = intval( $_POST['post_id'] );
2111 if ( ! current_user_can( 'edit_post', $post_ID ) )
2114 $thumbnail_id = intval( $_POST['thumbnail_id'] );
2117 check_ajax_referer( "update-post_$post_ID" );
2119 check_ajax_referer( "set_post_thumbnail-$post_ID" );
2121 if ( $thumbnail_id == '-1' ) {
2122 if ( delete_post_thumbnail( $post_ID ) ) {
2123 $return = _wp_post_thumbnail_html( null, $post_ID );
2124 $json ? wp_send_json_success( $return ) : wp_die( $return );
2130 if ( set_post_thumbnail( $post_ID, $thumbnail_id ) ) {
2131 $return = _wp_post_thumbnail_html( $thumbnail_id, $post_ID );
2132 $json ? wp_send_json_success( $return ) : wp_die( $return );
2139 * AJAX handler for setting the featured image for an attachment.
2143 * @see set_post_thumbnail()
2145 function wp_ajax_set_attachment_thumbnail() {
2146 if ( empty( $_POST['urls'] ) || ! is_array( $_POST['urls'] ) ) {
2147 wp_send_json_error();
2150 $thumbnail_id = (int) $_POST['thumbnail_id'];
2151 if ( empty( $thumbnail_id ) ) {
2152 wp_send_json_error();
2155 $post_ids = array();
2156 // For each URL, try to find its corresponding post ID.
2157 foreach ( $_POST['urls'] as $url ) {
2158 $post_id = attachment_url_to_postid( $url );
2159 if ( ! empty( $post_id ) ) {
2160 $post_ids[] = $post_id;
2164 if ( empty( $post_ids ) ) {
2165 wp_send_json_error();
2169 // For each found attachment, set its thumbnail.
2170 foreach ( $post_ids as $post_id ) {
2171 if ( ! current_user_can( 'edit_post', $post_id ) ) {
2175 if ( set_post_thumbnail( $post_id, $thumbnail_id ) ) {
2180 if ( 0 === $success ) {
2181 wp_send_json_error();
2183 wp_send_json_success();
2186 wp_send_json_error();
2190 * Ajax handler for date formatting.
2194 function wp_ajax_date_format() {
2195 wp_die( date_i18n( sanitize_option( 'date_format', wp_unslash( $_POST['date'] ) ) ) );
2199 * Ajax handler for time formatting.
2203 function wp_ajax_time_format() {
2204 wp_die( date_i18n( sanitize_option( 'time_format', wp_unslash( $_POST['date'] ) ) ) );
2208 * Ajax handler for saving posts from the fullscreen editor.
2213 function wp_ajax_wp_fullscreen_save_post() {
2214 $post_id = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0;
2219 $post = get_post( $post_id );
2221 check_ajax_referer('update-post_' . $post_id, '_wpnonce');
2223 $post_id = edit_post();
2225 if ( is_wp_error( $post_id ) ) {
2226 wp_send_json_error();
2230 $last_date = mysql2date( get_option('date_format'), $post->post_modified );
2231 $last_time = mysql2date( get_option('time_format'), $post->post_modified );
2233 $last_date = date_i18n( get_option('date_format') );
2234 $last_time = date_i18n( get_option('time_format') );
2237 if ( $last_id = get_post_meta( $post_id, '_edit_last', true ) ) {
2238 $last_user = get_userdata( $last_id );
2239 $last_edited = sprintf( __('Last edited by %1$s on %2$s at %3$s'), esc_html( $last_user->display_name ), $last_date, $last_time );
2241 $last_edited = sprintf( __('Last edited on %1$s at %2$s'), $last_date, $last_time );
2244 wp_send_json_success( array( 'last_edited' => $last_edited ) );
2248 * Ajax handler for removing a post lock.
2252 function wp_ajax_wp_remove_post_lock() {
2253 if ( empty( $_POST['post_ID'] ) || empty( $_POST['active_post_lock'] ) )
2255 $post_id = (int) $_POST['post_ID'];
2256 if ( ! $post = get_post( $post_id ) )
2259 check_ajax_referer( 'update-post_' . $post_id );
2261 if ( ! current_user_can( 'edit_post', $post_id ) )
2264 $active_lock = array_map( 'absint', explode( ':', $_POST['active_post_lock'] ) );
2265 if ( $active_lock[1] != get_current_user_id() )
2269 * Filter the post lock window duration.
2273 * @param int $interval The interval in seconds the post lock duration
2274 * should last, plus 5 seconds. Default 150.
2276 $new_lock = ( time() - apply_filters( 'wp_check_post_lock_window', 150 ) + 5 ) . ':' . $active_lock[1];
2277 update_post_meta( $post_id, '_edit_lock', $new_lock, implode( ':', $active_lock ) );
2282 * Ajax handler for dismissing a WordPress pointer.
2286 function wp_ajax_dismiss_wp_pointer() {
2287 $pointer = $_POST['pointer'];
2288 if ( $pointer != sanitize_key( $pointer ) )
2291 // check_ajax_referer( 'dismiss-pointer_' . $pointer );
2293 $dismissed = array_filter( explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) ) );
2295 if ( in_array( $pointer, $dismissed ) )
2298 $dismissed[] = $pointer;
2299 $dismissed = implode( ',', $dismissed );
2301 update_user_meta( get_current_user_id(), 'dismissed_wp_pointers', $dismissed );
2306 * Ajax handler for getting an attachment.
2310 function wp_ajax_get_attachment() {
2311 if ( ! isset( $_REQUEST['id'] ) )
2312 wp_send_json_error();
2314 if ( ! $id = absint( $_REQUEST['id'] ) )
2315 wp_send_json_error();
2317 if ( ! $post = get_post( $id ) )
2318 wp_send_json_error();
2320 if ( 'attachment' != $post->post_type )
2321 wp_send_json_error();
2323 if ( ! current_user_can( 'upload_files' ) )
2324 wp_send_json_error();
2326 if ( ! $attachment = wp_prepare_attachment_for_js( $id ) )
2327 wp_send_json_error();
2329 wp_send_json_success( $attachment );
2333 * Ajax handler for querying attachments.
2337 function wp_ajax_query_attachments() {
2338 if ( ! current_user_can( 'upload_files' ) )
2339 wp_send_json_error();
2341 $query = isset( $_REQUEST['query'] ) ? (array) $_REQUEST['query'] : array();
2343 's', 'order', 'orderby', 'posts_per_page', 'paged', 'post_mime_type',
2344 'post_parent', 'post__in', 'post__not_in', 'year', 'monthnum'
2346 foreach ( get_taxonomies_for_attachments( 'objects' ) as $t ) {
2347 if ( $t->query_var && isset( $query[ $t->query_var ] ) ) {
2348 $keys[] = $t->query_var;
2352 $query = array_intersect_key( $query, array_flip( $keys ) );
2353 $query['post_type'] = 'attachment';
2355 && ! empty( $_REQUEST['query']['post_status'] )
2356 && 'trash' === $_REQUEST['query']['post_status'] ) {
2357 $query['post_status'] = 'trash';
2359 $query['post_status'] = 'inherit';
2362 if ( current_user_can( get_post_type_object( 'attachment' )->cap->read_private_posts ) )
2363 $query['post_status'] .= ',private';
2366 * Filter the arguments passed to WP_Query during an AJAX
2367 * call for querying attachments.
2371 * @see WP_Query::parse_query()
2373 * @param array $query An array of query variables.
2375 $query = apply_filters( 'ajax_query_attachments_args', $query );
2376 $query = new WP_Query( $query );
2378 $posts = array_map( 'wp_prepare_attachment_for_js', $query->posts );
2379 $posts = array_filter( $posts );
2381 wp_send_json_success( $posts );
2385 * Ajax handler for updating attachment attributes.
2389 function wp_ajax_save_attachment() {
2390 if ( ! isset( $_REQUEST['id'] ) || ! isset( $_REQUEST['changes'] ) )
2391 wp_send_json_error();
2393 if ( ! $id = absint( $_REQUEST['id'] ) )
2394 wp_send_json_error();
2396 check_ajax_referer( 'update-post_' . $id, 'nonce' );
2398 if ( ! current_user_can( 'edit_post', $id ) )
2399 wp_send_json_error();
2401 $changes = $_REQUEST['changes'];
2402 $post = get_post( $id, ARRAY_A );
2404 if ( 'attachment' != $post['post_type'] )
2405 wp_send_json_error();
2407 if ( isset( $changes['parent'] ) )
2408 $post['post_parent'] = $changes['parent'];
2410 if ( isset( $changes['title'] ) )
2411 $post['post_title'] = $changes['title'];
2413 if ( isset( $changes['caption'] ) )
2414 $post['post_excerpt'] = $changes['caption'];
2416 if ( isset( $changes['description'] ) )
2417 $post['post_content'] = $changes['description'];
2419 if ( MEDIA_TRASH && isset( $changes['status'] ) )
2420 $post['post_status'] = $changes['status'];
2422 if ( isset( $changes['alt'] ) ) {
2423 $alt = wp_unslash( $changes['alt'] );
2424 if ( $alt != get_post_meta( $id, '_wp_attachment_image_alt', true ) ) {
2425 $alt = wp_strip_all_tags( $alt, true );
2426 update_post_meta( $id, '_wp_attachment_image_alt', wp_slash( $alt ) );
2430 if ( wp_attachment_is( 'audio', $post['ID'] ) ) {
2432 $id3data = wp_get_attachment_metadata( $post['ID'] );
2433 if ( ! is_array( $id3data ) ) {
2437 foreach ( wp_get_attachment_id3_keys( (object) $post, 'edit' ) as $key => $label ) {
2438 if ( isset( $changes[ $key ] ) ) {
2440 $id3data[ $key ] = sanitize_text_field( wp_unslash( $changes[ $key ] ) );
2445 wp_update_attachment_metadata( $id, $id3data );
2449 if ( MEDIA_TRASH && isset( $changes['status'] ) && 'trash' === $changes['status'] ) {
2450 wp_delete_post( $id );
2452 wp_update_post( $post );
2455 wp_send_json_success();
2459 * Ajax handler for saving backwards compatible attachment attributes.
2463 function wp_ajax_save_attachment_compat() {
2464 if ( ! isset( $_REQUEST['id'] ) )
2465 wp_send_json_error();
2467 if ( ! $id = absint( $_REQUEST['id'] ) )
2468 wp_send_json_error();
2470 if ( empty( $_REQUEST['attachments'] ) || empty( $_REQUEST['attachments'][ $id ] ) )
2471 wp_send_json_error();
2472 $attachment_data = $_REQUEST['attachments'][ $id ];
2474 check_ajax_referer( 'update-post_' . $id, 'nonce' );
2476 if ( ! current_user_can( 'edit_post', $id ) )
2477 wp_send_json_error();
2479 $post = get_post( $id, ARRAY_A );
2481 if ( 'attachment' != $post['post_type'] )
2482 wp_send_json_error();
2484 /** This filter is documented in wp-admin/includes/media.php */
2485 $post = apply_filters( 'attachment_fields_to_save', $post, $attachment_data );
2487 if ( isset( $post['errors'] ) ) {
2488 $errors = $post['errors']; // @todo return me and display me!
2489 unset( $post['errors'] );
2492 wp_update_post( $post );
2494 foreach ( get_attachment_taxonomies( $post ) as $taxonomy ) {
2495 if ( isset( $attachment_data[ $taxonomy ] ) )
2496 wp_set_object_terms( $id, array_map( 'trim', preg_split( '/,+/', $attachment_data[ $taxonomy ] ) ), $taxonomy, false );
2499 if ( ! $attachment = wp_prepare_attachment_for_js( $id ) )
2500 wp_send_json_error();
2502 wp_send_json_success( $attachment );
2506 * Ajax handler for saving the attachment order.
2510 function wp_ajax_save_attachment_order() {
2511 if ( ! isset( $_REQUEST['post_id'] ) )
2512 wp_send_json_error();
2514 if ( ! $post_id = absint( $_REQUEST['post_id'] ) )
2515 wp_send_json_error();
2517 if ( empty( $_REQUEST['attachments'] ) )
2518 wp_send_json_error();
2520 check_ajax_referer( 'update-post_' . $post_id, 'nonce' );
2522 $attachments = $_REQUEST['attachments'];
2524 if ( ! current_user_can( 'edit_post', $post_id ) )
2525 wp_send_json_error();
2527 foreach ( $attachments as $attachment_id => $menu_order ) {
2528 if ( ! current_user_can( 'edit_post', $attachment_id ) )
2530 if ( ! $attachment = get_post( $attachment_id ) )
2532 if ( 'attachment' != $attachment->post_type )
2535 wp_update_post( array( 'ID' => $attachment_id, 'menu_order' => $menu_order ) );
2538 wp_send_json_success();
2542 * Ajax handler for sending an attachment to the editor.
2544 * Generates the HTML to send an attachment to the editor.
2545 * Backwards compatible with the media_send_to_editor filter
2546 * and the chain of filters that follow.
2550 function wp_ajax_send_attachment_to_editor() {
2551 check_ajax_referer( 'media-send-to-editor', 'nonce' );
2553 $attachment = wp_unslash( $_POST['attachment'] );
2555 $id = intval( $attachment['id'] );
2557 if ( ! $post = get_post( $id ) )
2558 wp_send_json_error();
2560 if ( 'attachment' != $post->post_type )
2561 wp_send_json_error();
2563 if ( current_user_can( 'edit_post', $id ) ) {
2564 // If this attachment is unattached, attach it. Primarily a back compat thing.
2565 if ( 0 == $post->post_parent && $insert_into_post_id = intval( $_POST['post_id'] ) ) {
2566 wp_update_post( array( 'ID' => $id, 'post_parent' => $insert_into_post_id ) );
2571 $url = empty( $attachment['url'] ) ? '' : $attachment['url'];
2572 if ( strpos( $url, 'attachment_id') || get_attachment_link( $id ) == $url ) {
2573 $rel = 'attachment wp-att-' . $id;
2576 remove_filter( 'media_send_to_editor', 'image_media_send_to_editor' );
2578 if ( 'image' === substr( $post->post_mime_type, 0, 5 ) ) {
2579 $align = isset( $attachment['align'] ) ? $attachment['align'] : 'none';
2580 $size = isset( $attachment['image-size'] ) ? $attachment['image-size'] : 'medium';
2581 $alt = isset( $attachment['image_alt'] ) ? $attachment['image_alt'] : '';
2583 // No whitespace-only captions.
2584 $caption = isset( $attachment['post_excerpt'] ) ? $attachment['post_excerpt'] : '';
2585 if ( '' === trim( $caption ) ) {
2589 $title = ''; // We no longer insert title tags into <img> tags, as they are redundant.
2590 $html = get_image_send_to_editor( $id, $caption, $title, $align, $url, $rel, $size, $alt );
2591 } elseif ( wp_attachment_is( 'video', $post ) || wp_attachment_is( 'audio', $post ) ) {
2592 $html = stripslashes_deep( $_POST['html'] );
2594 $html = isset( $attachment['post_title'] ) ? $attachment['post_title'] : '';
2595 if ( ! empty( $url ) ) {
2596 $html = '<a href="' . esc_url( $url ) . '"' . 'rel="' . esc_attr( $rel ) . '">' . $html . '</a>';
2600 /** This filter is documented in wp-admin/includes/media.php */
2601 $html = apply_filters( 'media_send_to_editor', $html, $id, $attachment );
2603 wp_send_json_success( $html );
2607 * Ajax handler for sending a link to the editor.
2609 * Generates the HTML to send a non-image embed link to the editor.
2611 * Backwards compatible with the following filters:
2612 * - file_send_to_editor_url
2613 * - audio_send_to_editor_url
2614 * - video_send_to_editor_url
2618 * @global WP_Post $post
2619 * @global WP_Embed $wp_embed
2621 function wp_ajax_send_link_to_editor() {
2622 global $post, $wp_embed;
2624 check_ajax_referer( 'media-send-to-editor', 'nonce' );
2626 if ( ! $src = wp_unslash( $_POST['src'] ) )
2627 wp_send_json_error();
2629 if ( ! strpos( $src, '://' ) )
2630 $src = 'http://' . $src;
2632 if ( ! $src = esc_url_raw( $src ) )
2633 wp_send_json_error();
2635 if ( ! $link_text = trim( wp_unslash( $_POST['link_text'] ) ) )
2636 $link_text = wp_basename( $src );
2638 $post = get_post( isset( $_POST['post_id'] ) ? $_POST['post_id'] : 0 );
2640 // Ping WordPress for an embed.
2641 $check_embed = $wp_embed->run_shortcode( '[embed]'. $src .'[/embed]' );
2643 // Fallback that WordPress creates when no oEmbed was found.
2644 $fallback = $wp_embed->maybe_make_link( $src );
2646 if ( $check_embed !== $fallback ) {
2647 // TinyMCE view for [embed] will parse this
2648 $html = '[embed]' . $src . '[/embed]';
2649 } elseif ( $link_text ) {
2650 $html = '<a href="' . esc_url( $src ) . '">' . $link_text . '</a>';
2655 // Figure out what filter to run:
2657 if ( ( $ext = preg_replace( '/^.+?\.([^.]+)$/', '$1', $src ) ) && ( $ext_type = wp_ext2type( $ext ) )
2658 && ( 'audio' == $ext_type || 'video' == $ext_type ) )
2661 /** This filter is documented in wp-admin/includes/media.php */
2662 $html = apply_filters( $type . '_send_to_editor_url', $html, $src, $link_text );
2664 wp_send_json_success( $html );
2668 * Ajax handler for the Heartbeat API.
2670 * Runs when the user is logged in.
2674 function wp_ajax_heartbeat() {
2675 if ( empty( $_POST['_nonce'] ) ) {
2676 wp_send_json_error();
2679 $response = $data = array();
2680 $nonce_state = wp_verify_nonce( $_POST['_nonce'], 'heartbeat-nonce' );
2682 // screen_id is the same as $current_screen->id and the JS global 'pagenow'.
2683 if ( ! empty( $_POST['screen_id'] ) ) {
2684 $screen_id = sanitize_key($_POST['screen_id']);
2686 $screen_id = 'front';
2689 if ( ! empty( $_POST['data'] ) ) {
2690 $data = wp_unslash( (array) $_POST['data'] );
2693 if ( 1 !== $nonce_state ) {
2694 $response = apply_filters( 'wp_refresh_nonces', $response, $data, $screen_id );
2696 if ( false === $nonce_state ) {
2697 // User is logged in but nonces have expired.
2698 $response['nonces_expired'] = true;
2699 wp_send_json( $response );
2703 if ( ! empty( $data ) ) {
2705 * Filter the Heartbeat response received.
2709 * @param array|object $response The Heartbeat response object or array.
2710 * @param array $data The $_POST data sent.
2711 * @param string $screen_id The screen id.
2713 $response = apply_filters( 'heartbeat_received', $response, $data, $screen_id );
2717 * Filter the Heartbeat response sent.
2721 * @param array|object $response The Heartbeat response object or array.
2722 * @param string $screen_id The screen id.
2724 $response = apply_filters( 'heartbeat_send', $response, $screen_id );
2727 * Fires when Heartbeat ticks in logged-in environments.
2729 * Allows the transport to be easily replaced with long-polling.
2733 * @param array|object $response The Heartbeat response object or array.
2734 * @param string $screen_id The screen id.
2736 do_action( 'heartbeat_tick', $response, $screen_id );
2738 // Send the current time according to the server
2739 $response['server_time'] = time();
2741 wp_send_json( $response );
2745 * Ajax handler for getting revision diffs.
2749 function wp_ajax_get_revision_diffs() {
2750 require ABSPATH . 'wp-admin/includes/revision.php';
2752 if ( ! $post = get_post( (int) $_REQUEST['post_id'] ) )
2753 wp_send_json_error();
2755 if ( ! current_user_can( 'read_post', $post->ID ) )
2756 wp_send_json_error();
2758 // Really just pre-loading the cache here.
2759 if ( ! $revisions = wp_get_post_revisions( $post->ID, array( 'check_enabled' => false ) ) )
2760 wp_send_json_error();
2763 @set_time_limit( 0 );
2765 foreach ( $_REQUEST['compare'] as $compare_key ) {
2766 list( $compare_from, $compare_to ) = explode( ':', $compare_key ); // from:to
2769 'id' => $compare_key,
2770 'fields' => wp_get_revision_ui_diff( $post, $compare_from, $compare_to ),
2773 wp_send_json_success( $return );
2777 * Ajax handler for auto-saving the selected color scheme for
2778 * a user's own profile.
2782 * @global array $_wp_admin_css_colors
2784 function wp_ajax_save_user_color_scheme() {
2785 global $_wp_admin_css_colors;
2787 check_ajax_referer( 'save-color-scheme', 'nonce' );
2789 $color_scheme = sanitize_key( $_POST['color_scheme'] );
2791 if ( ! isset( $_wp_admin_css_colors[ $color_scheme ] ) ) {
2792 wp_send_json_error();
2795 $previous_color_scheme = get_user_meta( get_current_user_id(), 'admin_color', true );
2796 update_user_meta( get_current_user_id(), 'admin_color', $color_scheme );
2798 wp_send_json_success( array(
2799 'previousScheme' => 'admin-color-' . $previous_color_scheme,
2800 'currentScheme' => 'admin-color-' . $color_scheme
2805 * Ajax handler for getting themes from themes_api().
2809 * @global array $themes_allowedtags
2810 * @global array $theme_field_defaults
2812 function wp_ajax_query_themes() {
2813 global $themes_allowedtags, $theme_field_defaults;
2815 if ( ! current_user_can( 'install_themes' ) ) {
2816 wp_send_json_error();
2819 $args = wp_parse_args( wp_unslash( $_REQUEST['request'] ), array(
2821 'fields' => $theme_field_defaults
2824 if ( isset( $args['browse'] ) && 'favorites' === $args['browse'] && ! isset( $args['user'] ) ) {
2825 $user = get_user_option( 'wporg_favorites' );
2827 $args['user'] = $user;
2831 $old_filter = isset( $args['browse'] ) ? $args['browse'] : 'search';
2833 /** This filter is documented in wp-admin/includes/class-wp-theme-install-list-table.php */
2834 $args = apply_filters( 'install_themes_table_api_args_' . $old_filter, $args );
2836 $api = themes_api( 'query_themes', $args );
2838 if ( is_wp_error( $api ) ) {
2839 wp_send_json_error();
2842 $update_php = network_admin_url( 'update.php?action=install-theme' );
2843 foreach ( $api->themes as &$theme ) {
2844 $theme->install_url = add_query_arg( array(
2845 'theme' => $theme->slug,
2846 '_wpnonce' => wp_create_nonce( 'install-theme_' . $theme->slug )
2849 $theme->name = wp_kses( $theme->name, $themes_allowedtags );
2850 $theme->author = wp_kses( $theme->author, $themes_allowedtags );
2851 $theme->version = wp_kses( $theme->version, $themes_allowedtags );
2852 $theme->description = wp_kses( $theme->description, $themes_allowedtags );
2853 $theme->stars = wp_star_rating( array( 'rating' => $theme->rating, 'type' => 'percent', 'number' => $theme->num_ratings, 'echo' => false ) );
2854 $theme->num_ratings = number_format_i18n( $theme->num_ratings );
2855 $theme->preview_url = set_url_scheme( $theme->preview_url );
2858 wp_send_json_success( $api );
2862 * Apply [embed] AJAX handlers to a string.
2866 * @global WP_Post $post Global $post.
2867 * @global WP_Embed $wp_embed Embed API instance.
2868 * @global WP_Scripts $wp_scripts
2870 function wp_ajax_parse_embed() {
2871 global $post, $wp_embed;
2873 if ( ! $post = get_post( (int) $_POST['post_ID'] ) ) {
2874 wp_send_json_error();
2877 if ( empty( $_POST['shortcode'] ) || ! current_user_can( 'edit_post', $post->ID ) ) {
2878 wp_send_json_error();
2881 $shortcode = wp_unslash( $_POST['shortcode'] );
2883 preg_match( '/' . get_shortcode_regex() . '/s', $shortcode, $matches );
2884 $atts = shortcode_parse_atts( $matches[3] );
2885 if ( ! empty( $matches[5] ) ) {
2887 } elseif ( ! empty( $atts['src'] ) ) {
2888 $url = $atts['src'];
2894 setup_postdata( $post );
2896 $wp_embed->return_false_on_fail = true;
2898 if ( is_ssl() && 0 === strpos( $url, 'http://' ) ) {
2899 // Admin is ssl and the user pasted non-ssl URL.
2900 // Check if the provider supports ssl embeds and use that for the preview.
2901 $ssl_shortcode = preg_replace( '%^(\\[embed[^\\]]*\\])http://%i', '$1https://', $shortcode );
2902 $parsed = $wp_embed->run_shortcode( $ssl_shortcode );
2905 $no_ssl_support = true;
2909 if ( $url && ! $parsed ) {
2910 $parsed = $wp_embed->run_shortcode( $shortcode );
2914 wp_send_json_error( array(
2915 'type' => 'not-embeddable',
2916 'message' => sprintf( __( '%s failed to embed.' ), '<code>' . esc_html( $url ) . '</code>' ),
2920 if ( has_shortcode( $parsed, 'audio' ) || has_shortcode( $parsed, 'video' ) ) {
2922 $mce_styles = wpview_media_sandbox_styles();
2923 foreach ( $mce_styles as $style ) {
2924 $styles .= sprintf( '<link rel="stylesheet" href="%s"/>', $style );
2927 $html = do_shortcode( $parsed );
2930 if ( ! empty( $wp_scripts ) ) {
2931 $wp_scripts->done = array();
2934 wp_print_scripts( 'wp-mediaelement' );
2935 $scripts = ob_get_clean();
2937 $parsed = $styles . $html . $scripts;
2941 if ( ! empty( $no_ssl_support ) || ( is_ssl() && ( preg_match( '%<(iframe|script|embed) [^>]*src="http://%', $parsed ) ||
2942 preg_match( '%<link [^>]*href="http://%', $parsed ) ) ) ) {
2943 // Admin is ssl and the embed is not. Iframes, scripts, and other "active content" will be blocked.
2944 wp_send_json_error( array(
2945 'type' => 'not-ssl',
2946 'message' => __( 'This preview is unavailable in the editor.' ),
2950 wp_send_json_success( array(
2952 'attr' => $wp_embed->last_attr
2959 * @global WP_Post $post
2960 * @global WP_Scripts $wp_scripts
2962 function wp_ajax_parse_media_shortcode() {
2963 global $post, $wp_scripts;
2965 if ( empty( $_POST['shortcode'] ) ) {
2966 wp_send_json_error();
2969 $shortcode = wp_unslash( $_POST['shortcode'] );
2971 if ( ! empty( $_POST['post_ID'] ) ) {
2972 $post = get_post( (int) $_POST['post_ID'] );
2975 // the embed shortcode requires a post
2976 if ( ! $post || ! current_user_can( 'edit_post', $post->ID ) ) {
2977 if ( 'embed' === $shortcode ) {
2978 wp_send_json_error();
2981 setup_postdata( $post );
2984 $parsed = do_shortcode( $shortcode );
2986 if ( empty( $parsed ) ) {
2987 wp_send_json_error( array(
2988 'type' => 'no-items',
2989 'message' => __( 'No items found.' ),
2994 $styles = wpview_media_sandbox_styles();
2996 foreach ( $styles as $style ) {
2997 $head .= '<link type="text/css" rel="stylesheet" href="' . $style . '">';
3000 if ( ! empty( $wp_scripts ) ) {
3001 $wp_scripts->done = array();
3008 if ( 'playlist' === $_REQUEST['type'] ) {
3009 wp_underscore_playlist_templates();
3011 wp_print_scripts( 'wp-playlist' );
3013 wp_print_scripts( array( 'froogaloop', 'wp-mediaelement' ) );
3016 wp_send_json_success( array(
3018 'body' => ob_get_clean()
3023 * AJAX handler for destroying multiple open sessions for a user.
3027 function wp_ajax_destroy_sessions() {
3028 $user = get_userdata( (int) $_POST['user_id'] );
3030 if ( ! current_user_can( 'edit_user', $user->ID ) ) {
3032 } elseif ( ! wp_verify_nonce( $_POST['nonce'], 'update-user_' . $user->ID ) ) {
3038 wp_send_json_error( array(
3039 'message' => __( 'Could not log out user sessions. Please try again.' ),
3043 $sessions = WP_Session_Tokens::get_instance( $user->ID );
3045 if ( $user->ID === get_current_user_id() ) {
3046 $sessions->destroy_others( wp_get_session_token() );
3047 $message = __( 'You are now logged out everywhere else.' );
3049 $sessions->destroy_all();
3050 /* translators: 1: User's display name. */
3051 $message = sprintf( __( '%s has been logged out.' ), $user->display_name );
3054 wp_send_json_success( array( 'message' => $message ) );
3059 * AJAX handler for updating a plugin.
3063 * @see Plugin_Upgrader
3065 function wp_ajax_update_plugin() {
3066 global $wp_filesystem;
3068 $plugin = urldecode( $_POST['plugin'] );
3071 'update' => 'plugin',
3072 'plugin' => $plugin,
3073 'slug' => sanitize_key( $_POST['slug'] ),
3078 $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
3079 if ( $plugin_data['Version'] ) {
3080 $status['oldVersion'] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
3083 if ( ! current_user_can( 'update_plugins' ) ) {
3084 $status['error'] = __( 'You do not have sufficient permissions to update plugins for this site.' );
3085 wp_send_json_error( $status );
3088 check_ajax_referer( 'updates' );
3090 include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
3092 wp_update_plugins();
3094 $skin = new Automatic_Upgrader_Skin();
3095 $upgrader = new Plugin_Upgrader( $skin );
3096 $result = $upgrader->bulk_upgrade( array( $plugin ) );
3098 if ( is_array( $result ) && empty( $result[$plugin] ) && is_wp_error( $skin->result ) ) {
3099 $result = $skin->result;
3102 if ( is_array( $result ) && !empty( $result[ $plugin ] ) ) {
3103 $plugin_update_data = current( $result );
3106 * If the `update_plugins` site transient is empty (e.g. when you update
3107 * two plugins in quick succession before the transient repopulates),
3108 * this may be the return.
3110 * Preferably something can be done to ensure `update_plugins` isn't empty.
3111 * For now, surface some sort of error here.
3113 if ( $plugin_update_data === true ) {
3114 $status['error'] = __( 'Plugin update failed.' );
3115 wp_send_json_error( $status );
3118 $plugin_data = get_plugins( '/' . $result[ $plugin ]['destination_name'] );
3119 $plugin_data = reset( $plugin_data );
3121 if ( $plugin_data['Version'] ) {
3122 $status['newVersion'] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
3125 wp_send_json_success( $status );
3126 } else if ( is_wp_error( $result ) ) {
3127 $status['error'] = $result->get_error_message();
3128 wp_send_json_error( $status );
3130 } else if ( is_bool( $result ) && ! $result ) {
3131 $status['errorCode'] = 'unable_to_connect_to_filesystem';
3132 $status['error'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
3134 // Pass through the error from WP_Filesystem if one was raised
3135 if ( is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) {
3136 $status['error'] = $wp_filesystem->errors->get_error_message();
3139 wp_send_json_error( $status );
3142 // An unhandled error occured
3143 $status['error'] = __( 'Plugin update failed.' );
3144 wp_send_json_error( $status );
3149 * AJAX handler for saving a post from Press This.
3153 * @global WP_Press_This $wp_press_this
3155 function wp_ajax_press_this_save_post() {
3156 if ( empty( $GLOBALS['wp_press_this'] ) ) {
3157 include( ABSPATH . 'wp-admin/includes/class-wp-press-this.php' );
3160 $GLOBALS['wp_press_this']->save_post();
3164 * AJAX handler for creating new category from Press This.
3168 * @global WP_Press_This $wp_press_this
3170 function wp_ajax_press_this_add_category() {
3171 if ( empty( $GLOBALS['wp_press_this'] ) ) {
3172 include( ABSPATH . 'wp-admin/includes/class-wp-press-this.php' );
3175 $GLOBALS['wp_press_this']->add_category();
3179 * AJAX handler for cropping an image.
3183 * @global WP_Site_Icon $wp_site_icon
3185 function wp_ajax_crop_image() {
3186 $attachment_id = absint( $_POST['id'] );
3188 check_ajax_referer( 'image_editor-' . $attachment_id, 'nonce' );
3189 if ( ! current_user_can( 'customize' ) ) {
3190 wp_send_json_error();
3193 $context = str_replace( '_', '-', $_POST['context'] );
3194 $data = array_map( 'absint', $_POST['cropDetails'] );
3195 $cropped = wp_crop_image( $attachment_id, $data['x1'], $data['y1'], $data['width'], $data['height'], $data['dst_width'], $data['dst_height'] );
3197 if ( ! $cropped || is_wp_error( $cropped ) ) {
3198 wp_send_json_error( array( 'message' => __( 'Image could not be processed.' ) ) );
3201 switch ( $context ) {
3203 require_once ABSPATH . '/wp-admin/includes/class-wp-site-icon.php';
3204 global $wp_site_icon;
3206 // Skip creating a new attachment if the attachment is a Site Icon.
3207 if ( get_post_meta( $attachment_id, '_wp_attachment_context', true ) == $context ) {
3209 // Delete the temporary cropped file, we don't need it.
3210 wp_delete_file( $cropped );
3212 // Additional sizes in wp_prepare_attachment_for_js().
3213 add_filter( 'image_size_names_choose', array( $wp_site_icon, 'additional_sizes' ) );
3217 /** This filter is documented in wp-admin/custom-header.php */
3218 $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
3219 $object = $wp_site_icon->create_attachment_object( $cropped, $attachment_id );
3220 unset( $object['ID'] );
3222 // Update the attachment.
3223 add_filter( 'intermediate_image_sizes_advanced', array( $wp_site_icon, 'additional_sizes' ) );
3224 $attachment_id = $wp_site_icon->insert_attachment( $object, $cropped );
3225 remove_filter( 'intermediate_image_sizes_advanced', array( $wp_site_icon, 'additional_sizes' ) );
3227 // Additional sizes in wp_prepare_attachment_for_js().
3228 add_filter( 'image_size_names_choose', array( $wp_site_icon, 'additional_sizes' ) );
3234 * Fires before a cropped image is saved.
3236 * Allows to add filters to modify the way a cropped image is saved.
3240 * @param string $context The Customizer control requesting the cropped image.
3241 * @param int $attachment_id The attachment ID of the original image.
3242 * @param string $cropped Path to the cropped image file.
3244 do_action( 'wp_ajax_crop_image_pre_save', $context, $attachment_id, $cropped );
3246 /** This filter is documented in wp-admin/custom-header.php */
3247 $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
3249 $parent_url = wp_get_attachment_url( $attachment_id );
3250 $url = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url );
3252 $size = @getimagesize( $cropped );
3253 $image_type = ( $size ) ? $size['mime'] : 'image/jpeg';
3256 'post_title' => basename( $cropped ),
3257 'post_content' => $url,
3258 'post_mime_type' => $image_type,
3260 'context' => $context,
3263 $attachment_id = wp_insert_attachment( $object, $cropped );
3264 $metadata = wp_generate_attachment_metadata( $attachment_id, $cropped );
3267 * Filter the cropped image attachment metadata.
3271 * @see wp_generate_attachment_metadata()
3273 * @param array $metadata Attachment metadata.
3275 $metadata = apply_filters( 'wp_ajax_cropped_attachment_metadata', $metadata );
3276 wp_update_attachment_metadata( $attachment_id, $metadata );
3279 * Filter the attachment ID for a cropped image.
3283 * @param int $attachment_id The attachment ID of the cropped image.
3284 * @param string $context The Customizer control requesting the cropped image.
3286 $attachment_id = apply_filters( 'wp_ajax_cropped_attachment_id', $attachment_id, $context );
3289 wp_send_json_success( wp_prepare_attachment_for_js( $attachment_id ) );
3293 * Ajax handler for generating a password.
3297 function wp_ajax_generate_password() {
3298 wp_send_json_success( wp_generate_password( 24 ) );
3302 * Ajax handler for saving the user's WordPress.org username.
3306 function wp_ajax_save_wporg_username() {
3307 if ( ! current_user_can( 'install_themes' ) && ! current_user_can( 'install_plugins' ) ) {
3308 wp_send_json_error();
3311 $username = isset( $_REQUEST['username'] ) ? wp_unslash( $_REQUEST['username'] ) : false;
3313 if ( ! $username ) {
3314 wp_send_json_error();
3317 wp_send_json_success( update_user_meta( get_current_user_id(), 'wporg_favorites', $username ) );