3
* WordPress Core Ajax Handlers.
6
* @subpackage Administration
10
// No-privilege Ajax handlers.
14
* Ajax handler for the Heartbeat API in
15
* the no-privilege context.
17
* Runs when the user is not logged in.
21
function wp_ajax_nopriv_heartbeat() {
24
// screen_id is the same as $current_screen->id and the JS global 'pagenow'.
25
if ( ! empty($_POST['screen_id']) )
26
$screen_id = sanitize_key($_POST['screen_id']);
30
if ( ! empty($_POST['data']) ) {
31
$data = wp_unslash( (array) $_POST['data'] );
34
* Filter Heartbeat AJAX response in no-privilege environments.
38
* @param array|object $response The no-priv Heartbeat response object or array.
39
* @param array $data An array of data passed via $_POST.
40
* @param string $screen_id The screen id.
42
$response = apply_filters( 'heartbeat_nopriv_received', $response, $data, $screen_id );
46
* Filter Heartbeat AJAX response when no data is passed.
50
* @param array|object $response The Heartbeat response object or array.
51
* @param string $screen_id The screen id.
53
$response = apply_filters( 'heartbeat_nopriv_send', $response, $screen_id );
56
* Fires when Heartbeat ticks in no-privilege environments.
58
* Allows the transport to be easily replaced with long-polling.
62
* @param array|object $response The no-priv Heartbeat response.
63
* @param string $screen_id The screen id.
65
do_action( 'heartbeat_nopriv_tick', $response, $screen_id );
67
// Send the current time according to the server.
68
$response['server_time'] = time();
70
wp_send_json($response);
74
// GET-based Ajax handlers.
78
* Ajax handler for fetching a list table.
82
function wp_ajax_fetch_list() {
83
global $wp_list_table;
85
$list_class = $_GET['list_args']['class'];
86
check_ajax_referer( "fetch-list-$list_class", '_ajax_fetch_list_nonce' );
88
$wp_list_table = _get_list_table( $list_class, array( 'screen' => $_GET['list_args']['screen']['id'] ) );
89
if ( ! $wp_list_table )
92
if ( ! $wp_list_table->ajax_user_can() )
95
$wp_list_table->ajax_response();
101
* Ajax handler for tag search.
105
function wp_ajax_ajax_tag_search() {
106
if ( isset( $_GET['tax'] ) ) {
107
$taxonomy = sanitize_key( $_GET['tax'] );
108
$tax = get_taxonomy( $taxonomy );
111
if ( ! current_user_can( $tax->cap->assign_terms ) )
117
$s = wp_unslash( $_GET['q'] );
119
$comma = _x( ',', 'tag delimiter' );
120
if ( ',' !== $comma )
121
$s = str_replace( $comma, ',', $s );
122
if ( false !== strpos( $s, ',' ) ) {
123
$s = explode( ',', $s );
124
$s = $s[count( $s ) - 1];
129
* Filter the minimum number of characters required to fire a tag search via AJAX.
133
* @param int $characters The minimum number of characters required. Default 2.
134
* @param object $tax The taxonomy object.
135
* @param string $s The search term.
137
$term_search_min_chars = (int) apply_filters( 'term_search_min_chars', 2, $tax, $s );
140
* Require $term_search_min_chars chars for matching (default: 2)
141
* ensure it's a non-negative, non-zero integer.
143
if ( ( $term_search_min_chars == 0 ) || ( strlen( $s ) < $term_search_min_chars ) ){
147
$results = get_terms( $taxonomy, array( 'name__like' => $s, 'fields' => 'names', 'hide_empty' => false ) );
149
echo join( $results, "\n" );
154
* Ajax handler for compression testing.
158
function wp_ajax_wp_compression_test() {
159
if ( !current_user_can( 'manage_options' ) )
162
if ( ini_get('zlib.output_compression') || 'ob_gzhandler' == ini_get('output_handler') ) {
163
update_site_option('can_compress_scripts', 0);
167
if ( isset($_GET['test']) ) {
168
header( 'Expires: Wed, 11 Jan 1984 05:00:00 GMT' );
169
header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
170
header( 'Cache-Control: no-cache, must-revalidate, max-age=0' );
171
header( 'Pragma: no-cache' );
172
header('Content-Type: application/x-javascript; charset=UTF-8');
173
$force_gzip = ( defined('ENFORCE_GZIP') && ENFORCE_GZIP );
174
$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."';
176
if ( 1 == $_GET['test'] ) {
179
} elseif ( 2 == $_GET['test'] ) {
180
if ( !isset($_SERVER['HTTP_ACCEPT_ENCODING']) )
182
if ( false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate') && function_exists('gzdeflate') && ! $force_gzip ) {
183
header('Content-Encoding: deflate');
184
$out = gzdeflate( $test_str, 1 );
185
} elseif ( false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') && function_exists('gzencode') ) {
186
header('Content-Encoding: gzip');
187
$out = gzencode( $test_str, 1 );
193
} elseif ( 'no' == $_GET['test'] ) {
194
update_site_option('can_compress_scripts', 0);
195
} elseif ( 'yes' == $_GET['test'] ) {
196
update_site_option('can_compress_scripts', 1);
204
* Ajax handler for image editor previews.
208
function wp_ajax_imgedit_preview() {
209
$post_id = intval($_GET['postid']);
210
if ( empty($post_id) || !current_user_can('edit_post', $post_id) )
213
check_ajax_referer( "image_editor-$post_id" );
215
include_once( ABSPATH . 'wp-admin/includes/image-edit.php' );
216
if ( ! stream_preview_image($post_id) )
223
* Ajax handler for oEmbed caching.
227
function wp_ajax_oembed_cache() {
228
$GLOBALS['wp_embed']->cache_oembed( $_GET['post'] );
233
* Ajax handler for user autocomplete.
237
function wp_ajax_autocomplete_user() {
238
if ( ! is_multisite() || ! current_user_can( 'promote_users' ) || wp_is_large_network( 'users' ) )
241
/** This filter is documented in wp-admin/user-new.php */
242
if ( ! is_super_admin() && ! apply_filters( 'autocomplete_users_for_site_admins', false ) )
247
// Check the type of request
248
// Current allowed values are `add` and `search`
249
if ( isset( $_REQUEST['autocomplete_type'] ) && 'search' === $_REQUEST['autocomplete_type'] ) {
250
$type = $_REQUEST['autocomplete_type'];
255
// Check the desired field for value
256
// Current allowed values are `user_email` and `user_login`
257
if ( isset( $_REQUEST['autocomplete_field'] ) && 'user_email' === $_REQUEST['autocomplete_field'] ) {
258
$field = $_REQUEST['autocomplete_field'];
260
$field = 'user_login';
263
// Exclude current users of this blog
264
if ( isset( $_REQUEST['site_id'] ) ) {
265
$id = absint( $_REQUEST['site_id'] );
267
$id = get_current_blog_id();
270
$include_blog_users = ( $type == 'search' ? get_users( array( 'blog_id' => $id, 'fields' => 'ID' ) ) : array() );
271
$exclude_blog_users = ( $type == 'add' ? get_users( array( 'blog_id' => $id, 'fields' => 'ID' ) ) : array() );
273
$users = get_users( array(
275
'search' => '*' . $_REQUEST['term'] . '*',
276
'include' => $include_blog_users,
277
'exclude' => $exclude_blog_users,
278
'search_columns' => array( 'user_login', 'user_nicename', 'user_email' ),
281
foreach ( $users as $user ) {
283
/* translators: 1: user_login, 2: user_email */
284
'label' => sprintf( __( '%1$s (%2$s)' ), $user->user_login, $user->user_email ),
285
'value' => $user->$field,
289
wp_die( json_encode( $return ) );
293
* Ajax handler for dashboard widgets.
297
function wp_ajax_dashboard_widgets() {
298
require_once ABSPATH . 'wp-admin/includes/dashboard.php';
300
$pagenow = $_GET['pagenow'];
301
if ( $pagenow === 'dashboard-user' || $pagenow === 'dashboard-network' || $pagenow === 'dashboard' ) {
302
set_current_screen( $pagenow );
305
switch ( $_GET['widget'] ) {
306
case 'dashboard_primary' :
307
wp_dashboard_primary();
314
* Ajax handler for Customizer preview logged-in status.
318
function wp_ajax_logged_in() {
327
* Sends back current comment total and new page links if they need to be updated.
329
* Contrary to normal success AJAX response ("1"), die with time() on success.
333
* @param int $comment_id
336
function _wp_ajax_delete_comment_response( $comment_id, $delta = -1 ) {
337
$total = isset( $_POST['_total'] ) ? (int) $_POST['_total'] : 0;
338
$per_page = isset( $_POST['_per_page'] ) ? (int) $_POST['_per_page'] : 0;
339
$page = isset( $_POST['_page'] ) ? (int) $_POST['_page'] : 0;
340
$url = isset( $_POST['_url'] ) ? esc_url_raw( $_POST['_url'] ) : '';
342
// JS didn't send us everything we need to know. Just die with success message
343
if ( !$total || !$per_page || !$page || !$url )
350
// Only do the expensive stuff on a page-break, and about 1 other time per page
351
if ( 0 == $total % $per_page || 1 == mt_rand( 1, $per_page ) ) {
353
$status = 'total_comments'; // What type of comment count are we looking for?
354
$parsed = parse_url( $url );
355
if ( isset( $parsed['query'] ) ) {
356
parse_str( $parsed['query'], $query_vars );
357
if ( !empty( $query_vars['comment_status'] ) )
358
$status = $query_vars['comment_status'];
359
if ( !empty( $query_vars['p'] ) )
360
$post_id = (int) $query_vars['p'];
363
$comment_count = wp_count_comments($post_id);
365
// We're looking for a known type of comment count.
366
if ( isset( $comment_count->$status ) )
367
$total = $comment_count->$status;
368
// Else use the decremented value from above.
371
// The time since the last comment count.
374
$x = new WP_Ajax_Response( array(
376
// Here for completeness - not used.
378
'supplemental' => array(
379
'total_items_i18n' => sprintf( _n( '1 item', '%s items', $total ), number_format_i18n( $total ) ),
380
'total_pages' => ceil( $total / $per_page ),
381
'total_pages_i18n' => number_format_i18n( ceil( $total / $per_page ) ),
390
// POST-based Ajax handlers.
394
* Ajax handler for adding a hierarchical term.
398
function _wp_ajax_add_hierarchical_term() {
399
$action = $_POST['action'];
400
$taxonomy = get_taxonomy(substr($action, 4));
401
check_ajax_referer( $action, '_ajax_nonce-add-' . $taxonomy->name );
402
if ( !current_user_can( $taxonomy->cap->edit_terms ) )
404
$names = explode(',', $_POST['new'.$taxonomy->name]);
405
$parent = isset($_POST['new'.$taxonomy->name.'_parent']) ? (int) $_POST['new'.$taxonomy->name.'_parent'] : 0;
408
if ( $taxonomy->name == 'category' )
409
$post_category = isset($_POST['post_category']) ? (array) $_POST['post_category'] : array();
411
$post_category = ( isset($_POST['tax_input']) && isset($_POST['tax_input'][$taxonomy->name]) ) ? (array) $_POST['tax_input'][$taxonomy->name] : array();
412
$checked_categories = array_map( 'absint', (array) $post_category );
413
$popular_ids = wp_popular_terms_checklist($taxonomy->name, 0, 10, false);
415
foreach ( $names as $cat_name ) {
416
$cat_name = trim($cat_name);
417
$category_nicename = sanitize_title($cat_name);
418
if ( '' === $category_nicename )
420
if ( !$cat_id = term_exists( $cat_name, $taxonomy->name, $parent ) )
421
$cat_id = wp_insert_term( $cat_name, $taxonomy->name, array( 'parent' => $parent ) );
422
if ( is_wp_error( $cat_id ) )
424
else if ( is_array( $cat_id ) )
425
$cat_id = $cat_id['term_id'];
426
$checked_categories[] = $cat_id;
427
if ( $parent ) // Do these all at once in a second
430
wp_terms_checklist( 0, array( 'taxonomy' => $taxonomy->name, 'descendants_and_self' => $cat_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids ));
431
$data = ob_get_contents();
434
'what' => $taxonomy->name,
436
'data' => str_replace( array("\n", "\t"), '', $data),
441
if ( $parent ) { // Foncy - replace the parent and all its children
442
$parent = get_term( $parent, $taxonomy->name );
443
$term_id = $parent->term_id;
445
while ( $parent->parent ) { // get the top parent
446
$parent = get_term( $parent->parent, $taxonomy->name );
447
if ( is_wp_error( $parent ) )
449
$term_id = $parent->term_id;
453
wp_terms_checklist( 0, array('taxonomy' => $taxonomy->name, 'descendants_and_self' => $term_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids));
454
$data = ob_get_contents();
457
'what' => $taxonomy->name,
459
'data' => str_replace( array("\n", "\t"), '', $data),
465
wp_dropdown_categories( array(
466
'taxonomy' => $taxonomy->name, 'hide_empty' => 0, 'name' => 'new'.$taxonomy->name.'_parent', 'orderby' => 'name',
467
'hierarchical' => 1, 'show_option_none' => '— '.$taxonomy->labels->parent_item.' —'
469
$sup = ob_get_contents();
471
$add['supplemental'] = array( 'newcat_parent' => $sup );
473
$x = new WP_Ajax_Response( $add );
478
* Ajax handler for deleting a comment.
482
function wp_ajax_delete_comment() {
483
$id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
485
if ( !$comment = get_comment( $id ) )
487
if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) )
490
check_ajax_referer( "delete-comment_$id" );
491
$status = wp_get_comment_status( $comment->comment_ID );
494
if ( isset($_POST['trash']) && 1 == $_POST['trash'] ) {
495
if ( 'trash' == $status )
497
$r = wp_trash_comment( $comment->comment_ID );
498
} elseif ( isset($_POST['untrash']) && 1 == $_POST['untrash'] ) {
499
if ( 'trash' != $status )
501
$r = wp_untrash_comment( $comment->comment_ID );
502
if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'trash' ) // undo trash, not in trash
504
} elseif ( isset($_POST['spam']) && 1 == $_POST['spam'] ) {
505
if ( 'spam' == $status )
507
$r = wp_spam_comment( $comment->comment_ID );
508
} elseif ( isset($_POST['unspam']) && 1 == $_POST['unspam'] ) {
509
if ( 'spam' != $status )
511
$r = wp_unspam_comment( $comment->comment_ID );
512
if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'spam' ) // undo spam, not in spam
514
} elseif ( isset($_POST['delete']) && 1 == $_POST['delete'] ) {
515
$r = wp_delete_comment( $comment->comment_ID );
520
if ( $r ) // Decide if we need to send back '1' or a more complicated response including page links and comment counts
521
_wp_ajax_delete_comment_response( $comment->comment_ID, $delta );
526
* Ajax handler for deleting a tag.
530
function wp_ajax_delete_tag() {
531
$tag_id = (int) $_POST['tag_ID'];
532
check_ajax_referer( "delete-tag_$tag_id" );
534
$taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
535
$tax = get_taxonomy($taxonomy);
537
if ( !current_user_can( $tax->cap->delete_terms ) )
540
$tag = get_term( $tag_id, $taxonomy );
541
if ( !$tag || is_wp_error( $tag ) )
544
if ( wp_delete_term($tag_id, $taxonomy))
551
* Ajax handler for deleting a link.
555
function wp_ajax_delete_link() {
556
$id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
558
check_ajax_referer( "delete-bookmark_$id" );
559
if ( !current_user_can( 'manage_links' ) )
562
$link = get_bookmark( $id );
563
if ( !$link || is_wp_error( $link ) )
566
if ( wp_delete_link( $id ) )
573
* Ajax handler for deleting meta.
577
function wp_ajax_delete_meta() {
578
$id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
580
check_ajax_referer( "delete-meta_$id" );
581
if ( !$meta = get_metadata_by_mid( 'post', $id ) )
584
if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'delete_post_meta', $meta->post_id, $meta->meta_key ) )
586
if ( delete_meta( $meta->meta_id ) )
592
* Ajax handler for deleting a post.
596
* @param string $action Action to perform.
598
function wp_ajax_delete_post( $action ) {
599
if ( empty( $action ) )
600
$action = 'delete-post';
601
$id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
603
check_ajax_referer( "{$action}_$id" );
604
if ( !current_user_can( 'delete_post', $id ) )
607
if ( !get_post( $id ) )
610
if ( wp_delete_post( $id ) )
617
* Ajax handler for sending a post to the trash.
621
* @param string $action Action to perform.
623
function wp_ajax_trash_post( $action ) {
624
if ( empty( $action ) )
625
$action = 'trash-post';
626
$id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
628
check_ajax_referer( "{$action}_$id" );
629
if ( !current_user_can( 'delete_post', $id ) )
632
if ( !get_post( $id ) )
635
if ( 'trash-post' == $action )
636
$done = wp_trash_post( $id );
638
$done = wp_untrash_post( $id );
647
* Ajax handler to restore a post from the trash.
651
* @param string $action Action to perform.
653
function wp_ajax_untrash_post( $action ) {
654
if ( empty( $action ) )
655
$action = 'untrash-post';
656
wp_ajax_trash_post( $action );
659
function wp_ajax_delete_page( $action ) {
660
if ( empty( $action ) )
661
$action = 'delete-page';
662
$id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
664
check_ajax_referer( "{$action}_$id" );
665
if ( !current_user_can( 'delete_page', $id ) )
668
if ( ! get_post( $id ) )
671
if ( wp_delete_post( $id ) )
678
* Ajax handler to dim a comment.
682
function wp_ajax_dim_comment() {
683
$id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
685
if ( !$comment = get_comment( $id ) ) {
686
$x = new WP_Ajax_Response( array(
688
'id' => new WP_Error('invalid_comment', sprintf(__('Comment %d does not exist'), $id))
693
if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) && ! current_user_can( 'moderate_comments' ) )
696
$current = wp_get_comment_status( $comment->comment_ID );
697
if ( isset( $_POST['new'] ) && $_POST['new'] == $current )
700
check_ajax_referer( "approve-comment_$id" );
701
if ( in_array( $current, array( 'unapproved', 'spam' ) ) )
702
$result = wp_set_comment_status( $comment->comment_ID, 'approve', true );
704
$result = wp_set_comment_status( $comment->comment_ID, 'hold', true );
706
if ( is_wp_error($result) ) {
707
$x = new WP_Ajax_Response( array(
714
// Decide if we need to send back '1' or a more complicated response including page links and comment counts
715
_wp_ajax_delete_comment_response( $comment->comment_ID );
720
* Ajax handler for deleting a link category.
724
* @param string $action Action to perform.
726
function wp_ajax_add_link_category( $action ) {
727
if ( empty( $action ) )
728
$action = 'add-link-category';
729
check_ajax_referer( $action );
730
if ( !current_user_can( 'manage_categories' ) )
732
$names = explode(',', wp_unslash( $_POST['newcat'] ) );
733
$x = new WP_Ajax_Response();
734
foreach ( $names as $cat_name ) {
735
$cat_name = trim($cat_name);
736
$slug = sanitize_title($cat_name);
739
if ( !$cat_id = term_exists( $cat_name, 'link_category' ) )
740
$cat_id = wp_insert_term( $cat_name, 'link_category' );
741
if ( is_wp_error( $cat_id ) )
743
else if ( is_array( $cat_id ) )
744
$cat_id = $cat_id['term_id'];
745
$cat_name = esc_html( $cat_name );
747
'what' => 'link-category',
749
'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>",
757
* Ajax handler to add a tag.
761
function wp_ajax_add_tag() {
762
global $wp_list_table;
764
check_ajax_referer( 'add-tag', '_wpnonce_add-tag' );
765
$taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
766
$tax = get_taxonomy($taxonomy);
768
if ( !current_user_can( $tax->cap->edit_terms ) )
771
$x = new WP_Ajax_Response();
773
$tag = wp_insert_term($_POST['tag-name'], $taxonomy, $_POST );
775
if ( !$tag || is_wp_error($tag) || (!$tag = get_term( $tag['term_id'], $taxonomy )) ) {
776
$message = __('An error has occurred. Please reload the page and try again.');
777
if ( is_wp_error($tag) && $tag->get_error_message() )
778
$message = $tag->get_error_message();
781
'what' => 'taxonomy',
782
'data' => new WP_Error('error', $message )
787
$wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => $_POST['screen'] ) );
790
if ( is_taxonomy_hierarchical($taxonomy) ) {
791
$level = count( get_ancestors( $tag->term_id, $taxonomy ) );
793
$wp_list_table->single_row( $tag, $level );
794
$noparents = ob_get_clean();
798
$wp_list_table->single_row( $tag );
799
$parents = ob_get_clean();
802
'what' => 'taxonomy',
803
'supplemental' => compact('parents', 'noparents')
807
'position' => $level,
808
'supplemental' => (array) $tag
814
* Ajax handler for getting a tagcloud.
818
function wp_ajax_get_tagcloud() {
819
if ( isset( $_POST['tax'] ) ) {
820
$taxonomy = sanitize_key( $_POST['tax'] );
821
$tax = get_taxonomy( $taxonomy );
824
if ( ! current_user_can( $tax->cap->assign_terms ) )
830
$tags = get_terms( $taxonomy, array( 'number' => 45, 'orderby' => 'count', 'order' => 'DESC' ) );
832
if ( empty( $tags ) )
833
wp_die( $tax->labels->not_found );
835
if ( is_wp_error( $tags ) )
836
wp_die( $tags->get_error_message() );
838
foreach ( $tags as $key => $tag ) {
839
$tags[ $key ]->link = '#';
840
$tags[ $key ]->id = $tag->term_id;
843
// We need raw tag names here, so don't filter the output
844
$return = wp_generate_tag_cloud( $tags, array('filter' => 0) );
846
if ( empty($return) )
855
* Ajax handler for getting comments.
859
* @param string $action Action to perform.
861
function wp_ajax_get_comments( $action ) {
862
global $wp_list_table, $post_id;
863
if ( empty( $action ) )
864
$action = 'get-comments';
866
check_ajax_referer( $action );
868
if ( empty( $post_id ) && ! empty( $_REQUEST['p'] ) ) {
869
$id = absint( $_REQUEST['p'] );
870
if ( ! empty( $id ) )
874
if ( empty( $post_id ) )
877
$wp_list_table = _get_list_table( 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
879
if ( ! current_user_can( 'edit_post', $post_id ) )
882
$wp_list_table->prepare_items();
884
if ( !$wp_list_table->has_items() )
887
$x = new WP_Ajax_Response();
889
foreach ( $wp_list_table->items as $comment ) {
890
if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) )
892
get_comment( $comment );
893
$wp_list_table->single_row( $comment );
895
$comment_list_item = ob_get_contents();
899
'what' => 'comments',
900
'data' => $comment_list_item
906
* Ajax handler for replying to a comment.
910
* @param string $action Action to perform.
912
function wp_ajax_replyto_comment( $action ) {
913
global $wp_list_table;
914
if ( empty( $action ) )
915
$action = 'replyto-comment';
917
check_ajax_referer( $action, '_ajax_nonce-replyto-comment' );
919
$comment_post_ID = (int) $_POST['comment_post_ID'];
920
$post = get_post( $comment_post_ID );
924
if ( !current_user_can( 'edit_post', $comment_post_ID ) )
927
if ( empty( $post->post_status ) )
929
elseif ( in_array($post->post_status, array('draft', 'pending', 'trash') ) )
930
wp_die( __('ERROR: you are replying to a comment on a draft post.') );
932
$user = wp_get_current_user();
933
if ( $user->exists() ) {
934
$user_ID = $user->ID;
935
$comment_author = wp_slash( $user->display_name );
936
$comment_author_email = wp_slash( $user->user_email );
937
$comment_author_url = wp_slash( $user->user_url );
938
$comment_content = trim($_POST['content']);
939
if ( current_user_can( 'unfiltered_html' ) ) {
940
if ( ! isset( $_POST['_wp_unfiltered_html_comment'] ) )
941
$_POST['_wp_unfiltered_html_comment'] = '';
943
if ( wp_create_nonce( 'unfiltered-html-comment' ) != $_POST['_wp_unfiltered_html_comment'] ) {
944
kses_remove_filters(); // start with a clean slate
945
kses_init_filters(); // set up the filters
949
wp_die( __( 'Sorry, you must be logged in to reply to a comment.' ) );
952
if ( '' == $comment_content )
953
wp_die( __( 'ERROR: please type a comment.' ) );
956
if ( isset( $_POST['comment_ID'] ) )
957
$comment_parent = absint( $_POST['comment_ID'] );
958
$comment_auto_approved = false;
959
$commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_type', 'comment_parent', 'user_ID');
961
// Automatically approve parent comment.
962
if ( !empty($_POST['approve_parent']) ) {
963
$parent = get_comment( $comment_parent );
965
if ( $parent && $parent->comment_approved === '0' && $parent->comment_post_ID == $comment_post_ID ) {
966
if ( wp_set_comment_status( $parent->comment_ID, 'approve' ) )
967
$comment_auto_approved = true;
971
$comment_id = wp_new_comment( $commentdata );
972
$comment = get_comment($comment_id);
973
if ( ! $comment ) wp_die( 1 );
975
$position = ( isset($_POST['position']) && (int) $_POST['position'] ) ? (int) $_POST['position'] : '-1';
978
if ( isset( $_REQUEST['mode'] ) && 'dashboard' == $_REQUEST['mode'] ) {
979
require_once( ABSPATH . 'wp-admin/includes/dashboard.php' );
980
_wp_dashboard_recent_comments_row( $comment );
982
if ( isset( $_REQUEST['mode'] ) && 'single' == $_REQUEST['mode'] ) {
983
$wp_list_table = _get_list_table('WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
985
$wp_list_table = _get_list_table('WP_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
987
$wp_list_table->single_row( $comment );
989
$comment_list_item = ob_get_clean();
993
'id' => $comment->comment_ID,
994
'data' => $comment_list_item,
995
'position' => $position
998
if ( $comment_auto_approved )
999
$response['supplemental'] = array( 'parent_approved' => $parent->comment_ID );
1001
$x = new WP_Ajax_Response();
1002
$x->add( $response );
1007
* Ajax handler for editing a comment.
1011
function wp_ajax_edit_comment() {
1012
global $wp_list_table;
1014
check_ajax_referer( 'replyto-comment', '_ajax_nonce-replyto-comment' );
1016
$comment_id = (int) $_POST['comment_ID'];
1017
if ( ! current_user_can( 'edit_comment', $comment_id ) )
1020
if ( '' == $_POST['content'] )
1021
wp_die( __( 'ERROR: please type a comment.' ) );
1023
if ( isset( $_POST['status'] ) )
1024
$_POST['comment_status'] = $_POST['status'];
1027
$position = ( isset($_POST['position']) && (int) $_POST['position']) ? (int) $_POST['position'] : '-1';
1028
$checkbox = ( isset($_POST['checkbox']) && true == $_POST['checkbox'] ) ? 1 : 0;
1029
$wp_list_table = _get_list_table( $checkbox ? 'WP_Comments_List_Table' : 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
1031
$comment = get_comment( $comment_id );
1032
if ( empty( $comment->comment_ID ) )
1036
$wp_list_table->single_row( $comment );
1037
$comment_list_item = ob_get_clean();
1039
$x = new WP_Ajax_Response();
1042
'what' => 'edit_comment',
1043
'id' => $comment->comment_ID,
1044
'data' => $comment_list_item,
1045
'position' => $position
1052
* Ajax handler for adding a menu item.
1056
function wp_ajax_add_menu_item() {
1057
check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' );
1059
if ( ! current_user_can( 'edit_theme_options' ) )
1062
require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
1064
// For performance reasons, we omit some object properties from the checklist.
1065
// The following is a hacky way to restore them when adding non-custom items.
1067
$menu_items_data = array();
1068
foreach ( (array) $_POST['menu-item'] as $menu_item_data ) {
1070
! empty( $menu_item_data['menu-item-type'] ) &&
1071
'custom' != $menu_item_data['menu-item-type'] &&
1072
! empty( $menu_item_data['menu-item-object-id'] )
1074
switch( $menu_item_data['menu-item-type'] ) {
1076
$_object = get_post( $menu_item_data['menu-item-object-id'] );
1080
$_object = get_term( $menu_item_data['menu-item-object-id'], $menu_item_data['menu-item-object'] );
1084
$_menu_items = array_map( 'wp_setup_nav_menu_item', array( $_object ) );
1085
$_menu_item = array_shift( $_menu_items );
1087
// Restore the missing menu item properties
1088
$menu_item_data['menu-item-description'] = $_menu_item->description;
1091
$menu_items_data[] = $menu_item_data;
1094
$item_ids = wp_save_nav_menu_items( 0, $menu_items_data );
1095
if ( is_wp_error( $item_ids ) )
1098
$menu_items = array();
1100
foreach ( (array) $item_ids as $menu_item_id ) {
1101
$menu_obj = get_post( $menu_item_id );
1102
if ( ! empty( $menu_obj->ID ) ) {
1103
$menu_obj = wp_setup_nav_menu_item( $menu_obj );
1104
$menu_obj->label = $menu_obj->title; // don't show "(pending)" in ajax-added items
1105
$menu_items[] = $menu_obj;
1109
/** This filter is documented in wp-admin/includes/nav-menu.php */
1110
$walker_class_name = apply_filters( 'wp_edit_nav_menu_walker', 'Walker_Nav_Menu_Edit', $_POST['menu'] );
1112
if ( ! class_exists( $walker_class_name ) )
1115
if ( ! empty( $menu_items ) ) {
1120
'link_before' => '',
1121
'walker' => new $walker_class_name,
1123
echo walk_nav_menu_tree( $menu_items, 0, (object) $args );
1129
* Ajax handler for adding meta.
1133
function wp_ajax_add_meta() {
1134
check_ajax_referer( 'add-meta', '_ajax_nonce-add-meta' );
1136
$pid = (int) $_POST['post_id'];
1137
$post = get_post( $pid );
1139
if ( isset($_POST['metakeyselect']) || isset($_POST['metakeyinput']) ) {
1140
if ( !current_user_can( 'edit_post', $pid ) )
1142
if ( isset($_POST['metakeyselect']) && '#NONE#' == $_POST['metakeyselect'] && empty($_POST['metakeyinput']) )
1144
if ( $post->post_status == 'auto-draft' ) {
1145
$save_POST = $_POST; // Backup $_POST
1146
$_POST = array(); // Make it empty for edit_post()
1147
$_POST['action'] = 'draft'; // Warning fix
1148
$_POST['post_ID'] = $pid;
1149
$_POST['post_type'] = $post->post_type;
1150
$_POST['post_status'] = 'draft';
1151
$now = current_time('timestamp', 1);
1152
$_POST['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), date( get_option( 'date_format' ), $now ), date( get_option( 'time_format' ), $now ) );
1154
if ( $pid = edit_post() ) {
1155
if ( is_wp_error( $pid ) ) {
1156
$x = new WP_Ajax_Response( array(
1162
$_POST = $save_POST; // Now we can restore original $_POST again
1163
if ( !$mid = add_meta( $pid ) )
1164
wp_die( __( 'Please provide a custom field value.' ) );
1168
} else if ( !$mid = add_meta( $pid ) ) {
1169
wp_die( __( 'Please provide a custom field value.' ) );
1172
$meta = get_metadata_by_mid( 'post', $mid );
1173
$pid = (int) $meta->post_id;
1174
$meta = get_object_vars( $meta );
1175
$x = new WP_Ajax_Response( array(
1178
'data' => _list_meta_row( $meta, $c ),
1180
'supplemental' => array('postid' => $pid)
1183
$mid = (int) key( $_POST['meta'] );
1184
$key = wp_unslash( $_POST['meta'][$mid]['key'] );
1185
$value = wp_unslash( $_POST['meta'][$mid]['value'] );
1186
if ( '' == trim($key) )
1187
wp_die( __( 'Please provide a custom field name.' ) );
1188
if ( '' == trim($value) )
1189
wp_die( __( 'Please provide a custom field value.' ) );
1190
if ( ! $meta = get_metadata_by_mid( 'post', $mid ) )
1191
wp_die( 0 ); // if meta doesn't exist
1192
if ( is_protected_meta( $meta->meta_key, 'post' ) || is_protected_meta( $key, 'post' ) ||
1193
! current_user_can( 'edit_post_meta', $meta->post_id, $meta->meta_key ) ||
1194
! current_user_can( 'edit_post_meta', $meta->post_id, $key ) )
1196
if ( $meta->meta_value != $value || $meta->meta_key != $key ) {
1197
if ( !$u = update_metadata_by_mid( 'post', $mid, $value, $key ) )
1198
wp_die( 0 ); // We know meta exists; we also know it's unchanged (or DB error, in which case there are bigger problems).
1201
$x = new WP_Ajax_Response( array(
1203
'id' => $mid, 'old_id' => $mid,
1204
'data' => _list_meta_row( array(
1206
'meta_value' => $value,
1210
'supplemental' => array('postid' => $meta->post_id)
1217
* Ajax handler for adding a user.
1221
* @param string $action Action to perform.
1223
function wp_ajax_add_user( $action ) {
1224
global $wp_list_table;
1225
if ( empty( $action ) )
1226
$action = 'add-user';
1228
check_ajax_referer( $action );
1229
if ( ! current_user_can('create_users') )
1231
if ( ! $user_id = edit_user() ) {
1233
} elseif ( is_wp_error( $user_id ) ) {
1234
$x = new WP_Ajax_Response( array(
1240
$user_object = get_userdata( $user_id );
1242
$wp_list_table = _get_list_table('WP_Users_List_Table');
1244
$role = current( $user_object->roles );
1246
$x = new WP_Ajax_Response( array(
1249
'data' => $wp_list_table->single_row( $user_object, '', $role ),
1250
'supplemental' => array(
1251
'show-link' => sprintf(__( 'User <a href="#%s">%s</a> added' ), "user-$user_id", $user_object->user_login),
1259
* Ajax handler for closed post boxes.
1263
function wp_ajax_closed_postboxes() {
1264
check_ajax_referer( 'closedpostboxes', 'closedpostboxesnonce' );
1265
$closed = isset( $_POST['closed'] ) ? explode( ',', $_POST['closed']) : array();
1266
$closed = array_filter($closed);
1268
$hidden = isset( $_POST['hidden'] ) ? explode( ',', $_POST['hidden']) : array();
1269
$hidden = array_filter($hidden);
1271
$page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1273
if ( $page != sanitize_key( $page ) )
1276
if ( ! $user = wp_get_current_user() )
1279
if ( is_array($closed) )
1280
update_user_option($user->ID, "closedpostboxes_$page", $closed, true);
1282
if ( is_array($hidden) ) {
1283
$hidden = array_diff( $hidden, array('submitdiv', 'linksubmitdiv', 'manage-menu', 'create-menu') ); // postboxes that are always shown
1284
update_user_option($user->ID, "metaboxhidden_$page", $hidden, true);
1291
* Ajax handler for hidden columns.
1295
function wp_ajax_hidden_columns() {
1296
check_ajax_referer( 'screen-options-nonce', 'screenoptionnonce' );
1297
$hidden = explode( ',', isset( $_POST['hidden'] ) ? $_POST['hidden'] : '' );
1298
$page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1300
if ( $page != sanitize_key( $page ) )
1303
if ( ! $user = wp_get_current_user() )
1306
if ( is_array($hidden) )
1307
update_user_option($user->ID, "manage{$page}columnshidden", $hidden, true);
1313
* Ajax handler for updating whether to display the welcome panel.
1317
function wp_ajax_update_welcome_panel() {
1318
check_ajax_referer( 'welcome-panel-nonce', 'welcomepanelnonce' );
1320
if ( ! current_user_can( 'edit_theme_options' ) )
1323
update_user_meta( get_current_user_id(), 'show_welcome_panel', empty( $_POST['visible'] ) ? 0 : 1 );
1329
* Ajax handler for retrieving menu meta boxes.
1333
function wp_ajax_menu_get_metabox() {
1334
if ( ! current_user_can( 'edit_theme_options' ) )
1337
require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
1339
if ( isset( $_POST['item-type'] ) && 'post_type' == $_POST['item-type'] ) {
1341
$callback = 'wp_nav_menu_item_post_type_meta_box';
1342
$items = (array) get_post_types( array( 'show_in_nav_menus' => true ), 'object' );
1343
} elseif ( isset( $_POST['item-type'] ) && 'taxonomy' == $_POST['item-type'] ) {
1345
$callback = 'wp_nav_menu_item_taxonomy_meta_box';
1346
$items = (array) get_taxonomies( array( 'show_ui' => true ), 'object' );
1349
if ( ! empty( $_POST['item-object'] ) && isset( $items[$_POST['item-object']] ) ) {
1350
$menus_meta_box_object = $items[ $_POST['item-object'] ];
1352
/** This filter is documented in wp-admin/includes/nav-menu.php */
1353
$item = apply_filters( 'nav_menu_meta_box_object', $menus_meta_box_object );
1355
call_user_func_array($callback, array(
1358
'id' => 'add-' . $item->name,
1359
'title' => $item->labels->name,
1360
'callback' => $callback,
1365
$markup = ob_get_clean();
1367
echo json_encode(array(
1368
'replace-id' => $type . '-' . $item->name,
1369
'markup' => $markup,
1377
* Ajax handler for internal linking.
1381
function wp_ajax_wp_link_ajax() {
1382
check_ajax_referer( 'internal-linking', '_ajax_linking_nonce' );
1386
if ( isset( $_POST['search'] ) )
1387
$args['s'] = wp_unslash( $_POST['search'] );
1388
$args['pagenum'] = ! empty( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
1390
require(ABSPATH . WPINC . '/class-wp-editor.php');
1391
$results = _WP_Editors::wp_link_query( $args );
1393
if ( ! isset( $results ) )
1396
echo json_encode( $results );
1403
* Ajax handler for menu locations save.
1407
function wp_ajax_menu_locations_save() {
1408
if ( ! current_user_can( 'edit_theme_options' ) )
1410
check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' );
1411
if ( ! isset( $_POST['menu-locations'] ) )
1413
set_theme_mod( 'nav_menu_locations', array_map( 'absint', $_POST['menu-locations'] ) );
1418
* Ajax handler for saving the meta box order.
1422
function wp_ajax_meta_box_order() {
1423
check_ajax_referer( 'meta-box-order' );
1424
$order = isset( $_POST['order'] ) ? (array) $_POST['order'] : false;
1425
$page_columns = isset( $_POST['page_columns'] ) ? $_POST['page_columns'] : 'auto';
1427
if ( $page_columns != 'auto' )
1428
$page_columns = (int) $page_columns;
1430
$page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1432
if ( $page != sanitize_key( $page ) )
1435
if ( ! $user = wp_get_current_user() )
1439
update_user_option($user->ID, "meta-box-order_$page", $order, true);
1441
if ( $page_columns )
1442
update_user_option($user->ID, "screen_layout_$page", $page_columns, true);
1448
* Ajax handler for menu quick searching.
1452
function wp_ajax_menu_quick_search() {
1453
if ( ! current_user_can( 'edit_theme_options' ) )
1456
require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
1458
_wp_ajax_menu_quick_search( $_POST );
1464
* Ajax handler to retrieve a permalink.
1468
function wp_ajax_get_permalink() {
1469
check_ajax_referer( 'getpermalink', 'getpermalinknonce' );
1470
$post_id = isset($_POST['post_id'])? intval($_POST['post_id']) : 0;
1471
wp_die( add_query_arg( array( 'preview' => 'true' ), get_permalink( $post_id ) ) );
1475
* Ajax handler to retrieve a sample permalink.
1479
function wp_ajax_sample_permalink() {
1480
check_ajax_referer( 'samplepermalink', 'samplepermalinknonce' );
1481
$post_id = isset($_POST['post_id'])? intval($_POST['post_id']) : 0;
1482
$title = isset($_POST['new_title'])? $_POST['new_title'] : '';
1483
$slug = isset($_POST['new_slug'])? $_POST['new_slug'] : null;
1484
wp_die( get_sample_permalink_html( $post_id, $title, $slug ) );
1488
* Ajax handler for quick edit saving for a post.
1492
function wp_ajax_inline_save() {
1493
global $wp_list_table;
1495
check_ajax_referer( 'inlineeditnonce', '_inline_edit' );
1497
if ( ! isset($_POST['post_ID']) || ! ( $post_ID = (int) $_POST['post_ID'] ) )
1500
if ( 'page' == $_POST['post_type'] ) {
1501
if ( ! current_user_can( 'edit_page', $post_ID ) )
1502
wp_die( __( 'You are not allowed to edit this page.' ) );
1504
if ( ! current_user_can( 'edit_post', $post_ID ) )
1505
wp_die( __( 'You are not allowed to edit this post.' ) );
1508
if ( $last = wp_check_post_lock( $post_ID ) ) {
1509
$last_user = get_userdata( $last );
1510
$last_user_name = $last_user ? $last_user->display_name : __( 'Someone' );
1511
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 ) );
1517
$post = get_post( $post_ID, ARRAY_A );
1519
// Since it's coming from the database.
1520
$post = wp_slash($post);
1522
$data['content'] = $post['post_content'];
1523
$data['excerpt'] = $post['post_excerpt'];
1526
$data['user_ID'] = get_current_user_id();
1528
if ( isset($data['post_parent']) )
1529
$data['parent_id'] = $data['post_parent'];
1532
if ( isset($data['keep_private']) && 'private' == $data['keep_private'] )
1533
$data['post_status'] = 'private';
1535
$data['post_status'] = $data['_status'];
1537
if ( empty($data['comment_status']) )
1538
$data['comment_status'] = 'closed';
1539
if ( empty($data['ping_status']) )
1540
$data['ping_status'] = 'closed';
1542
// Hack: wp_unique_post_slug() doesn't work for drafts, so we will fake that our post is published.
1543
if ( ! empty( $data['post_name'] ) && in_array( $post['post_status'], array( 'draft', 'pending' ) ) ) {
1544
$post['post_status'] = 'publish';
1545
$data['post_name'] = wp_unique_post_slug( $data['post_name'], $post['ID'], $post['post_status'], $post['post_type'], $post['post_parent'] );
1551
$wp_list_table = _get_list_table( 'WP_Posts_List_Table', array( 'screen' => $_POST['screen'] ) );
1554
$request_post = array( get_post( $_POST['post_ID'] ) );
1555
$parent = $request_post[0]->post_parent;
1557
while ( $parent > 0 ) {
1558
$parent_post = get_post( $parent );
1559
$parent = $parent_post->post_parent;
1563
$wp_list_table->display_rows( array( get_post( $_POST['post_ID'] ) ), $level );
1569
* Ajax handler for quick edit saving for a term.
1573
function wp_ajax_inline_save_tax() {
1574
global $wp_list_table;
1576
check_ajax_referer( 'taxinlineeditnonce', '_inline_edit' );
1578
$taxonomy = sanitize_key( $_POST['taxonomy'] );
1579
$tax = get_taxonomy( $taxonomy );
1583
if ( ! current_user_can( $tax->cap->edit_terms ) )
1586
$wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => 'edit-' . $taxonomy ) );
1588
if ( ! isset($_POST['tax_ID']) || ! ( $id = (int) $_POST['tax_ID'] ) )
1591
$tag = get_term( $id, $taxonomy );
1592
$_POST['description'] = $tag->description;
1594
$updated = wp_update_term($id, $taxonomy, $_POST);
1595
if ( $updated && !is_wp_error($updated) ) {
1596
$tag = get_term( $updated['term_id'], $taxonomy );
1597
if ( !$tag || is_wp_error( $tag ) ) {
1598
if ( is_wp_error($tag) && $tag->get_error_message() )
1599
wp_die( $tag->get_error_message() );
1600
wp_die( __( 'Item not updated.' ) );
1603
if ( is_wp_error($updated) && $updated->get_error_message() )
1604
wp_die( $updated->get_error_message() );
1605
wp_die( __( 'Item not updated.' ) );
1608
$parent = $tag->parent;
1609
while ( $parent > 0 ) {
1610
$parent_tag = get_term( $parent, $taxonomy );
1611
$parent = $parent_tag->parent;
1614
$wp_list_table->single_row( $tag, $level );
1619
* Ajax handler for finding posts.
1623
function wp_ajax_find_posts() {
1624
check_ajax_referer( 'find-posts' );
1626
$post_types = get_post_types( array( 'public' => true ), 'objects' );
1627
unset( $post_types['attachment'] );
1629
$s = wp_unslash( $_POST['ps'] );
1631
'post_type' => array_keys( $post_types ),
1632
'post_status' => 'any',
1633
'posts_per_page' => 50,
1638
$posts = get_posts( $args );
1641
wp_send_json_error( __( 'No items found.' ) );
1644
$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>';
1646
foreach ( $posts as $post ) {
1647
$title = trim( $post->post_title ) ? $post->post_title : __( '(no title)' );
1648
$alt = ( 'alternate' == $alt ) ? '' : 'alternate';
1650
switch ( $post->post_status ) {
1653
$stat = __('Published');
1656
$stat = __('Scheduled');
1659
$stat = __('Pending Review');
1662
$stat = __('Draft');
1666
if ( '0000-00-00 00:00:00' == $post->post_date ) {
1669
/* translators: date format in table columns, see http://php.net/date */
1670
$time = mysql2date(__('Y/m/d'), $post->post_date);
1673
$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>';
1674
$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";
1677
$html .= '</tbody></table>';
1679
wp_send_json_success( $html );
1683
* Ajax handler for saving the widgets order.
1687
function wp_ajax_widgets_order() {
1688
check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' );
1690
if ( !current_user_can('edit_theme_options') )
1693
unset( $_POST['savewidgets'], $_POST['action'] );
1695
// Save widgets order for all sidebars.
1696
if ( is_array($_POST['sidebars']) ) {
1697
$sidebars = array();
1698
foreach ( $_POST['sidebars'] as $key => $val ) {
1700
if ( !empty($val) ) {
1701
$val = explode(',', $val);
1702
foreach ( $val as $k => $v ) {
1703
if ( strpos($v, 'widget-') === false )
1706
$sb[$k] = substr($v, strpos($v, '_') + 1);
1709
$sidebars[$key] = $sb;
1711
wp_set_sidebars_widgets($sidebars);
1719
* Ajax handler for saving a widget.
1723
function wp_ajax_save_widget() {
1724
global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
1726
check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' );
1728
if ( !current_user_can('edit_theme_options') || !isset($_POST['id_base']) )
1731
unset( $_POST['savewidgets'], $_POST['action'] );
1734
* Fires early when editing the widgets displayed in sidebars.
1738
do_action( 'load-widgets.php' );
1741
* Fires early when editing the widgets displayed in sidebars.
1745
do_action( 'widgets.php' );
1747
/** This action is documented in wp-admin/widgets.php */
1748
do_action( 'sidebar_admin_setup' );
1750
$id_base = $_POST['id_base'];
1751
$widget_id = $_POST['widget-id'];
1752
$sidebar_id = $_POST['sidebar'];
1753
$multi_number = !empty($_POST['multi_number']) ? (int) $_POST['multi_number'] : 0;
1754
$settings = isset($_POST['widget-' . $id_base]) && is_array($_POST['widget-' . $id_base]) ? $_POST['widget-' . $id_base] : false;
1755
$error = '<p>' . __('An error has occurred. Please reload the page and try again.') . '</p>';
1757
$sidebars = wp_get_sidebars_widgets();
1758
$sidebar = isset($sidebars[$sidebar_id]) ? $sidebars[$sidebar_id] : array();
1761
if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
1763
if ( !isset($wp_registered_widgets[$widget_id]) )
1766
$sidebar = array_diff( $sidebar, array($widget_id) );
1767
$_POST = array('sidebar' => $sidebar_id, 'widget-' . $id_base => array(), 'the-widget-id' => $widget_id, 'delete_widget' => '1');
1768
} elseif ( $settings && preg_match( '/__i__|%i%/', key($settings) ) ) {
1769
if ( !$multi_number )
1772
$_POST['widget-' . $id_base] = array( $multi_number => array_shift($settings) );
1773
$widget_id = $id_base . '-' . $multi_number;
1774
$sidebar[] = $widget_id;
1776
$_POST['widget-id'] = $sidebar;
1778
foreach ( (array) $wp_registered_widget_updates as $name => $control ) {
1780
if ( $name == $id_base ) {
1781
if ( !is_callable( $control['callback'] ) )
1785
call_user_func_array( $control['callback'], $control['params'] );
1791
if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
1792
$sidebars[$sidebar_id] = $sidebar;
1793
wp_set_sidebars_widgets($sidebars);
1794
echo "deleted:$widget_id";
1798
if ( !empty($_POST['add_new']) )
1801
if ( $form = $wp_registered_widget_controls[$widget_id] )
1802
call_user_func_array( $form['callback'], $form['params'] );
1808
* Ajax handler for saving a widget.
1812
function wp_ajax_update_widget() {
1813
global $wp_customize;
1814
$wp_customize->widgets->wp_ajax_update_widget();
1818
* Ajax handler for uploading attachments
1822
function wp_ajax_upload_attachment() {
1823
check_ajax_referer( 'media-form' );
1825
if ( ! current_user_can( 'upload_files' ) )
1828
if ( isset( $_REQUEST['post_id'] ) ) {
1829
$post_id = $_REQUEST['post_id'];
1830
if ( ! current_user_can( 'edit_post', $post_id ) )
1836
$post_data = isset( $_REQUEST['post_data'] ) ? $_REQUEST['post_data'] : array();
1838
// If the context is custom header or background, make sure the uploaded file is an image.
1839
if ( isset( $post_data['context'] ) && in_array( $post_data['context'], array( 'custom-header', 'custom-background' ) ) ) {
1840
$wp_filetype = wp_check_filetype_and_ext( $_FILES['async-upload']['tmp_name'], $_FILES['async-upload']['name'], false );
1841
if ( ! wp_match_mime_types( 'image', $wp_filetype['type'] ) ) {
1842
echo json_encode( array(
1845
'message' => __( 'The uploaded file is not a valid image. Please try again.' ),
1846
'filename' => $_FILES['async-upload']['name'],
1854
$attachment_id = media_handle_upload( 'async-upload', $post_id, $post_data );
1856
if ( is_wp_error( $attachment_id ) ) {
1857
echo json_encode( array(
1860
'message' => $attachment_id->get_error_message(),
1861
'filename' => $_FILES['async-upload']['name'],
1868
if ( isset( $post_data['context'] ) && isset( $post_data['theme'] ) ) {
1869
if ( 'custom-background' === $post_data['context'] )
1870
update_post_meta( $attachment_id, '_wp_attachment_is_custom_background', $post_data['theme'] );
1872
if ( 'custom-header' === $post_data['context'] )
1873
update_post_meta( $attachment_id, '_wp_attachment_is_custom_header', $post_data['theme'] );
1876
if ( ! $attachment = wp_prepare_attachment_for_js( $attachment_id ) )
1879
echo json_encode( array(
1881
'data' => $attachment,
1888
* Ajax handler for image editing.
1892
function wp_ajax_image_editor() {
1893
$attachment_id = intval($_POST['postid']);
1894
if ( empty($attachment_id) || !current_user_can('edit_post', $attachment_id) )
1897
check_ajax_referer( "image_editor-$attachment_id" );
1898
include_once( ABSPATH . 'wp-admin/includes/image-edit.php' );
1901
switch ( $_POST['do'] ) {
1903
$msg = wp_save_image($attachment_id);
1904
$msg = json_encode($msg);
1908
$msg = wp_save_image($attachment_id);
1911
$msg = wp_restore_image($attachment_id);
1915
wp_image_editor($attachment_id, $msg);
1920
* Ajax handler for setting the featured image.
1924
function wp_ajax_set_post_thumbnail() {
1925
$json = ! empty( $_REQUEST['json'] ); // New-style request
1927
$post_ID = intval( $_POST['post_id'] );
1928
if ( ! current_user_can( 'edit_post', $post_ID ) )
1931
$thumbnail_id = intval( $_POST['thumbnail_id'] );
1934
check_ajax_referer( "update-post_$post_ID" );
1936
check_ajax_referer( "set_post_thumbnail-$post_ID" );
1938
if ( $thumbnail_id == '-1' ) {
1939
if ( delete_post_thumbnail( $post_ID ) ) {
1940
$return = _wp_post_thumbnail_html( null, $post_ID );
1941
$json ? wp_send_json_success( $return ) : wp_die( $return );
1947
if ( set_post_thumbnail( $post_ID, $thumbnail_id ) ) {
1948
$return = _wp_post_thumbnail_html( $thumbnail_id, $post_ID );
1949
$json ? wp_send_json_success( $return ) : wp_die( $return );
1956
* AJAX handler for setting the featured image for an attachment.
1960
* @see set_post_thumbnail()
1962
function wp_ajax_set_attachment_thumbnail() {
1963
if ( empty( $_POST['urls'] ) || ! is_array( $_POST['urls'] ) ) {
1964
wp_send_json_error();
1967
$thumbnail_id = (int) $_POST['thumbnail_id'];
1968
if ( empty( $thumbnail_id ) ) {
1969
wp_send_json_error();
1972
$post_ids = array();
1973
// For each URL, try to find its corresponding post ID.
1974
foreach ( $_POST['urls'] as $url ) {
1975
$post_id = attachment_url_to_postid( $url );
1976
if ( ! empty( $post_id ) ) {
1977
$post_ids[] = $post_id;
1981
if ( empty( $post_ids ) ) {
1982
wp_send_json_error();
1986
// For each found attachment, set its thumbnail.
1987
foreach ( $post_ids as $post_id ) {
1988
if ( ! current_user_can( 'edit_post', $post_id ) ) {
1992
if ( set_post_thumbnail( $post_id, $thumbnail_id ) ) {
1997
if ( 0 === $success ) {
1998
wp_send_json_error();
2000
wp_send_json_success();
2003
wp_send_json_error();
2007
* Ajax handler for date formatting.
2011
function wp_ajax_date_format() {
2012
wp_die( date_i18n( sanitize_option( 'date_format', wp_unslash( $_POST['date'] ) ) ) );
2016
* Ajax handler for time formatting.
2020
function wp_ajax_time_format() {
2021
wp_die( date_i18n( sanitize_option( 'time_format', wp_unslash( $_POST['date'] ) ) ) );
2025
* Ajax handler for saving posts from the fullscreen editor.
2029
function wp_ajax_wp_fullscreen_save_post() {
2030
$post_id = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0;
2035
$post = get_post( $post_id );
2037
check_ajax_referer('update-post_' . $post_id, '_wpnonce');
2039
$post_id = edit_post();
2041
if ( is_wp_error( $post_id ) ) {
2042
wp_send_json_error();
2046
$last_date = mysql2date( get_option('date_format'), $post->post_modified );
2047
$last_time = mysql2date( get_option('time_format'), $post->post_modified );
2049
$last_date = date_i18n( get_option('date_format') );
2050
$last_time = date_i18n( get_option('time_format') );
2053
if ( $last_id = get_post_meta( $post_id, '_edit_last', true ) ) {
2054
$last_user = get_userdata( $last_id );
2055
$last_edited = sprintf( __('Last edited by %1$s on %2$s at %3$s'), esc_html( $last_user->display_name ), $last_date, $last_time );
2057
$last_edited = sprintf( __('Last edited on %1$s at %2$s'), $last_date, $last_time );
2060
wp_send_json_success( array( 'last_edited' => $last_edited ) );
2064
* Ajax handler for removing a post lock.
2068
function wp_ajax_wp_remove_post_lock() {
2069
if ( empty( $_POST['post_ID'] ) || empty( $_POST['active_post_lock'] ) )
2071
$post_id = (int) $_POST['post_ID'];
2072
if ( ! $post = get_post( $post_id ) )
2075
check_ajax_referer( 'update-post_' . $post_id );
2077
if ( ! current_user_can( 'edit_post', $post_id ) )
2080
$active_lock = array_map( 'absint', explode( ':', $_POST['active_post_lock'] ) );
2081
if ( $active_lock[1] != get_current_user_id() )
2085
* Filter the post lock window duration.
2089
* @param int $interval The interval in seconds the post lock duration
2090
* should last, plus 5 seconds. Default 150.
2092
$new_lock = ( time() - apply_filters( 'wp_check_post_lock_window', 150 ) + 5 ) . ':' . $active_lock[1];
2093
update_post_meta( $post_id, '_edit_lock', $new_lock, implode( ':', $active_lock ) );
2098
* Ajax handler for dismissing a WordPress pointer.
2102
function wp_ajax_dismiss_wp_pointer() {
2103
$pointer = $_POST['pointer'];
2104
if ( $pointer != sanitize_key( $pointer ) )
2107
// check_ajax_referer( 'dismiss-pointer_' . $pointer );
2109
$dismissed = array_filter( explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) ) );
2111
if ( in_array( $pointer, $dismissed ) )
2114
$dismissed[] = $pointer;
2115
$dismissed = implode( ',', $dismissed );
2117
update_user_meta( get_current_user_id(), 'dismissed_wp_pointers', $dismissed );
2122
* Ajax handler for getting an attachment.
2126
function wp_ajax_get_attachment() {
2127
if ( ! isset( $_REQUEST['id'] ) )
2128
wp_send_json_error();
2130
if ( ! $id = absint( $_REQUEST['id'] ) )
2131
wp_send_json_error();
2133
if ( ! $post = get_post( $id ) )
2134
wp_send_json_error();
2136
if ( 'attachment' != $post->post_type )
2137
wp_send_json_error();
2139
if ( ! current_user_can( 'upload_files' ) )
2140
wp_send_json_error();
2142
if ( ! $attachment = wp_prepare_attachment_for_js( $id ) )
2143
wp_send_json_error();
2145
wp_send_json_success( $attachment );
2149
* Ajax handler for querying for attachments.
2153
function wp_ajax_query_attachments() {
2154
if ( ! current_user_can( 'upload_files' ) )
2155
wp_send_json_error();
2157
$query = isset( $_REQUEST['query'] ) ? (array) $_REQUEST['query'] : array();
2158
$query = array_intersect_key( $query, array_flip( array(
2159
's', 'order', 'orderby', 'posts_per_page', 'paged', 'post_mime_type',
2160
'post_parent', 'post__in', 'post__not_in', 'year', 'monthnum'
2163
$query['post_type'] = 'attachment';
2165
&& ! empty( $_REQUEST['query']['post_status'] )
2166
&& 'trash' === $_REQUEST['query']['post_status'] ) {
2167
$query['post_status'] = 'trash';
2169
$query['post_status'] = 'inherit';
2172
if ( current_user_can( get_post_type_object( 'attachment' )->cap->read_private_posts ) )
2173
$query['post_status'] .= ',private';
2176
* Filter the arguments passed to WP_Query during an AJAX
2177
* call for querying attachments.
2181
* @see WP_Query::parse_query()
2183
* @param array $query An array of query variables.
2185
$query = apply_filters( 'ajax_query_attachments_args', $query );
2186
$query = new WP_Query( $query );
2188
$posts = array_map( 'wp_prepare_attachment_for_js', $query->posts );
2189
$posts = array_filter( $posts );
2191
wp_send_json_success( $posts );
2195
* Ajax handler for saving attachment attributes.
2199
function wp_ajax_save_attachment() {
2200
if ( ! isset( $_REQUEST['id'] ) || ! isset( $_REQUEST['changes'] ) )
2201
wp_send_json_error();
2203
if ( ! $id = absint( $_REQUEST['id'] ) )
2204
wp_send_json_error();
2206
check_ajax_referer( 'update-post_' . $id, 'nonce' );
2208
if ( ! current_user_can( 'edit_post', $id ) )
2209
wp_send_json_error();
2211
$changes = $_REQUEST['changes'];
2212
$post = get_post( $id, ARRAY_A );
2214
if ( 'attachment' != $post['post_type'] )
2215
wp_send_json_error();
2217
if ( isset( $changes['title'] ) )
2218
$post['post_title'] = $changes['title'];
2220
if ( isset( $changes['caption'] ) )
2221
$post['post_excerpt'] = $changes['caption'];
2223
if ( isset( $changes['description'] ) )
2224
$post['post_content'] = $changes['description'];
2226
if ( MEDIA_TRASH && isset( $changes['status'] ) )
2227
$post['post_status'] = $changes['status'];
2229
if ( isset( $changes['alt'] ) ) {
2230
$alt = wp_unslash( $changes['alt'] );
2231
if ( $alt != get_post_meta( $id, '_wp_attachment_image_alt', true ) ) {
2232
$alt = wp_strip_all_tags( $alt, true );
2233
update_post_meta( $id, '_wp_attachment_image_alt', wp_slash( $alt ) );
2237
if ( 0 === strpos( $post['post_mime_type'], 'audio/' ) ) {
2239
$id3data = wp_get_attachment_metadata( $post['ID'] );
2240
if ( ! is_array( $id3data ) ) {
2244
foreach ( wp_get_attachment_id3_keys( (object) $post, 'edit' ) as $key => $label ) {
2245
if ( isset( $changes[ $key ] ) ) {
2247
$id3data[ $key ] = sanitize_text_field( wp_unslash( $changes[ $key ] ) );
2252
wp_update_attachment_metadata( $id, $id3data );
2256
if ( MEDIA_TRASH && isset( $changes['status'] ) && 'trash' === $changes['status'] ) {
2257
wp_delete_post( $id );
2259
wp_update_post( $post );
2262
wp_send_json_success();
2266
* Ajax handler for saving backwards compatible attachment attributes.
2270
function wp_ajax_save_attachment_compat() {
2271
if ( ! isset( $_REQUEST['id'] ) )
2272
wp_send_json_error();
2274
if ( ! $id = absint( $_REQUEST['id'] ) )
2275
wp_send_json_error();
2277
if ( empty( $_REQUEST['attachments'] ) || empty( $_REQUEST['attachments'][ $id ] ) )
2278
wp_send_json_error();
2279
$attachment_data = $_REQUEST['attachments'][ $id ];
2281
check_ajax_referer( 'update-post_' . $id, 'nonce' );
2283
if ( ! current_user_can( 'edit_post', $id ) )
2284
wp_send_json_error();
2286
$post = get_post( $id, ARRAY_A );
2288
if ( 'attachment' != $post['post_type'] )
2289
wp_send_json_error();
2291
/** This filter is documented in wp-admin/includes/media.php */
2292
$post = apply_filters( 'attachment_fields_to_save', $post, $attachment_data );
2294
if ( isset( $post['errors'] ) ) {
2295
$errors = $post['errors']; // @todo return me and display me!
2296
unset( $post['errors'] );
2299
wp_update_post( $post );
2301
foreach ( get_attachment_taxonomies( $post ) as $taxonomy ) {
2302
if ( isset( $attachment_data[ $taxonomy ] ) )
2303
wp_set_object_terms( $id, array_map( 'trim', preg_split( '/,+/', $attachment_data[ $taxonomy ] ) ), $taxonomy, false );
2306
if ( ! $attachment = wp_prepare_attachment_for_js( $id ) )
2307
wp_send_json_error();
2309
wp_send_json_success( $attachment );
2313
* Ajax handler for saving the attachment order.
2317
function wp_ajax_save_attachment_order() {
2318
if ( ! isset( $_REQUEST['post_id'] ) )
2319
wp_send_json_error();
2321
if ( ! $post_id = absint( $_REQUEST['post_id'] ) )
2322
wp_send_json_error();
2324
if ( empty( $_REQUEST['attachments'] ) )
2325
wp_send_json_error();
2327
check_ajax_referer( 'update-post_' . $post_id, 'nonce' );
2329
$attachments = $_REQUEST['attachments'];
2331
if ( ! current_user_can( 'edit_post', $post_id ) )
2332
wp_send_json_error();
2334
foreach ( $attachments as $attachment_id => $menu_order ) {
2335
if ( ! current_user_can( 'edit_post', $attachment_id ) )
2337
if ( ! $attachment = get_post( $attachment_id ) )
2339
if ( 'attachment' != $attachment->post_type )
2342
wp_update_post( array( 'ID' => $attachment_id, 'menu_order' => $menu_order ) );
2345
wp_send_json_success();
2349
* Ajax handler for sending an attachment to the editor.
2351
* Generates the HTML to send an attachment to the editor.
2352
* Backwards compatible with the media_send_to_editor filter
2353
* and the chain of filters that follow.
2357
function wp_ajax_send_attachment_to_editor() {
2358
check_ajax_referer( 'media-send-to-editor', 'nonce' );
2360
$attachment = wp_unslash( $_POST['attachment'] );
2362
$id = intval( $attachment['id'] );
2364
if ( ! $post = get_post( $id ) )
2365
wp_send_json_error();
2367
if ( 'attachment' != $post->post_type )
2368
wp_send_json_error();
2370
if ( current_user_can( 'edit_post', $id ) ) {
2371
// If this attachment is unattached, attach it. Primarily a back compat thing.
2372
if ( 0 == $post->post_parent && $insert_into_post_id = intval( $_POST['post_id'] ) ) {
2373
wp_update_post( array( 'ID' => $id, 'post_parent' => $insert_into_post_id ) );
2378
$html = isset( $attachment['post_title'] ) ? $attachment['post_title'] : '';
2379
if ( ! empty( $attachment['url'] ) ) {
2380
$url = $attachment['url'];
2381
if ( strpos( $url, 'attachment_id') || get_attachment_link( $id ) == $url )
2382
$rel = ' rel="attachment wp-att-' . $id . '"';
2383
$html = '<a href="' . esc_url( $url ) . '"' . $rel . '>' . $html . '</a>';
2386
remove_filter( 'media_send_to_editor', 'image_media_send_to_editor' );
2388
if ( 'image' === substr( $post->post_mime_type, 0, 5 ) ) {
2389
$align = isset( $attachment['align'] ) ? $attachment['align'] : 'none';
2390
$size = isset( $attachment['image-size'] ) ? $attachment['image-size'] : 'medium';
2391
$alt = isset( $attachment['image_alt'] ) ? $attachment['image_alt'] : '';
2392
$caption = isset( $attachment['post_excerpt'] ) ? $attachment['post_excerpt'] : '';
2393
$title = ''; // We no longer insert title tags into <img> tags, as they are redundant.
2394
$html = get_image_send_to_editor( $id, $caption, $title, $align, $url, (bool) $rel, $size, $alt );
2395
} elseif ( 'video' === substr( $post->post_mime_type, 0, 5 ) || 'audio' === substr( $post->post_mime_type, 0, 5 ) ) {
2396
$html = stripslashes_deep( $_POST['html'] );
2399
/** This filter is documented in wp-admin/includes/media.php */
2400
$html = apply_filters( 'media_send_to_editor', $html, $id, $attachment );
2402
wp_send_json_success( $html );
2406
* Ajax handler for sending a link to the editor.
2408
* Generates the HTML to send a non-image embed link to the editor.
2410
* Backwards compatible with the following filters:
2411
* - file_send_to_editor_url
2412
* - audio_send_to_editor_url
2413
* - video_send_to_editor_url
2417
function wp_ajax_send_link_to_editor() {
2418
global $post, $wp_embed;
2420
check_ajax_referer( 'media-send-to-editor', 'nonce' );
2422
if ( ! $src = wp_unslash( $_POST['src'] ) )
2423
wp_send_json_error();
2425
if ( ! strpos( $src, '://' ) )
2426
$src = 'http://' . $src;
2428
if ( ! $src = esc_url_raw( $src ) )
2429
wp_send_json_error();
2431
if ( ! $title = trim( wp_unslash( $_POST['title'] ) ) )
2432
$title = wp_basename( $src );
2434
$post = get_post( isset( $_POST['post_id'] ) ? $_POST['post_id'] : 0 );
2436
// Ping WordPress for an embed.
2437
$check_embed = $wp_embed->run_shortcode( '[embed]'. $src .'[/embed]' );
2439
// Fallback that WordPress creates when no oEmbed was found.
2440
$fallback = $wp_embed->maybe_make_link( $src );
2442
if ( $check_embed !== $fallback ) {
2443
// TinyMCE view for [embed] will parse this
2444
$html = '[embed]' . $src . '[/embed]';
2445
} elseif ( $title ) {
2446
$html = '<a href="' . esc_url( $src ) . '">' . $title . '</a>';
2451
// Figure out what filter to run:
2453
if ( ( $ext = preg_replace( '/^.+?\.([^.]+)$/', '$1', $src ) ) && ( $ext_type = wp_ext2type( $ext ) )
2454
&& ( 'audio' == $ext_type || 'video' == $ext_type ) )
2457
/** This filter is documented in wp-admin/includes/media.php */
2458
$html = apply_filters( $type . '_send_to_editor_url', $html, $src, $title );
2460
wp_send_json_success( $html );
2464
* Ajax handler for the Heartbeat API.
2466
* Runs when the user is logged in.
2470
function wp_ajax_heartbeat() {
2471
if ( empty( $_POST['_nonce'] ) )
2472
wp_send_json_error();
2474
$response = array();
2476
if ( false === wp_verify_nonce( $_POST['_nonce'], 'heartbeat-nonce' ) ) {
2477
// User is logged in but nonces have expired.
2478
$response['nonces_expired'] = true;
2479
wp_send_json($response);
2482
// screen_id is the same as $current_screen->id and the JS global 'pagenow'.
2483
if ( ! empty($_POST['screen_id']) )
2484
$screen_id = sanitize_key($_POST['screen_id']);
2486
$screen_id = 'front';
2488
if ( ! empty($_POST['data']) ) {
2489
$data = wp_unslash( (array) $_POST['data'] );
2492
* Filter the Heartbeat response received.
2496
* @param array|object $response The Heartbeat response object or array.
2497
* @param array $data The $_POST data sent.
2498
* @param string $screen_id The screen id.
2500
$response = apply_filters( 'heartbeat_received', $response, $data, $screen_id );
2504
* Filter the Heartbeat response sent.
2508
* @param array|object $response The Heartbeat response object or array.
2509
* @param string $screen_id The screen id.
2511
$response = apply_filters( 'heartbeat_send', $response, $screen_id );
2514
* Fires when Heartbeat ticks in logged-in environments.
2516
* Allows the transport to be easily replaced with long-polling.
2520
* @param array|object $response The Heartbeat response object or array.
2521
* @param string $screen_id The screen id.
2523
do_action( 'heartbeat_tick', $response, $screen_id );
2525
// Send the current time according to the server
2526
$response['server_time'] = time();
2528
wp_send_json($response);
2532
* Ajax handler for getting revision diffs.
2536
function wp_ajax_get_revision_diffs() {
2537
require ABSPATH . 'wp-admin/includes/revision.php';
2539
if ( ! $post = get_post( (int) $_REQUEST['post_id'] ) )
2540
wp_send_json_error();
2542
if ( ! current_user_can( 'read_post', $post->ID ) )
2543
wp_send_json_error();
2545
// Really just pre-loading the cache here.
2546
if ( ! $revisions = wp_get_post_revisions( $post->ID, array( 'check_enabled' => false ) ) )
2547
wp_send_json_error();
2550
@set_time_limit( 0 );
2552
foreach ( $_REQUEST['compare'] as $compare_key ) {
2553
list( $compare_from, $compare_to ) = explode( ':', $compare_key ); // from:to
2556
'id' => $compare_key,
2557
'fields' => wp_get_revision_ui_diff( $post, $compare_from, $compare_to ),
2560
wp_send_json_success( $return );
2564
* Ajax handler for auto-saving the selected color scheme for
2565
* a user's own profile.
2569
function wp_ajax_save_user_color_scheme() {
2570
global $_wp_admin_css_colors;
2572
check_ajax_referer( 'save-color-scheme', 'nonce' );
2574
$color_scheme = sanitize_key( $_POST['color_scheme'] );
2576
if ( ! isset( $_wp_admin_css_colors[ $color_scheme ] ) ) {
2577
wp_send_json_error();
2580
update_user_meta( get_current_user_id(), 'admin_color', $color_scheme );
2581
wp_send_json_success();
2585
* Ajax handler for getting themes from themes_api().
2589
function wp_ajax_query_themes() {
2590
global $themes_allowedtags, $theme_field_defaults;
2592
if ( ! current_user_can( 'install_themes' ) ) {
2593
wp_send_json_error();
2596
$args = wp_parse_args( wp_unslash( $_REQUEST['request'] ), array(
2598
'fields' => $theme_field_defaults
2601
$old_filter = isset( $args['browse'] ) ? $args['browse'] : 'search';
2603
/** This filter is documented in wp-admin/includes/class-wp-theme-install-list-table.php */
2604
$args = apply_filters( 'install_themes_table_api_args_' . $old_filter, $args );
2606
$api = themes_api( 'query_themes', $args );
2608
if ( is_wp_error( $api ) ) {
2609
wp_send_json_error();
2612
$update_php = network_admin_url( 'update.php?action=install-theme' );
2613
foreach ( $api->themes as &$theme ) {
2614
$theme->install_url = add_query_arg( array(
2615
'theme' => $theme->slug,
2616
'_wpnonce' => wp_create_nonce( 'install-theme_' . $theme->slug )
2619
$theme->name = wp_kses( $theme->name, $themes_allowedtags );
2620
$theme->author = wp_kses( $theme->author, $themes_allowedtags );
2621
$theme->version = wp_kses( $theme->version, $themes_allowedtags );
2622
$theme->description = wp_kses( $theme->description, $themes_allowedtags );
2623
$theme->num_ratings = sprintf( _n( '(based on %s rating)', '(based on %s ratings)', $theme->num_ratings ), number_format_i18n( $theme->num_ratings ) );
2624
$theme->preview_url = set_url_scheme( $theme->preview_url );
2627
wp_send_json_success( $api );
2631
* Apply [embed] AJAX handlers to a string.
2635
* @global WP_Post $post Global $post.
2636
* @global WP_Embed $wp_embed Embed API instance.
2638
function wp_ajax_parse_embed() {
2639
global $post, $wp_embed;
2641
if ( ! $post = get_post( (int) $_POST['post_ID'] ) ) {
2642
wp_send_json_error();
2645
if ( empty( $_POST['shortcode'] ) || ! current_user_can( 'edit_post', $post->ID ) ) {
2646
wp_send_json_error();
2649
$shortcode = wp_unslash( $_POST['shortcode'] );
2650
$url = str_replace( '[embed]', '', str_replace( '[/embed]', '', $shortcode ) );
2652
setup_postdata( $post );
2654
$wp_embed->return_false_on_fail = true;
2656
if ( is_ssl() && preg_match( '%^\\[embed[^\\]]*\\]http://%i', $shortcode ) ) {
2657
// Admin is ssl and the user pasted non-ssl URL.
2658
// Check if the provider supports ssl embeds and use that for the preview.
2659
$ssl_shortcode = preg_replace( '%^(\\[embed[^\\]]*\\])http://%i', '$1https://', $shortcode );
2660
$parsed = $wp_embed->run_shortcode( $ssl_shortcode );
2663
$no_ssl_support = true;
2668
$parsed = $wp_embed->run_shortcode( $shortcode );
2672
wp_send_json_error( array(
2673
'type' => 'not-embeddable',
2674
'message' => sprintf( __( '%s failed to embed.' ), '<code>' . esc_html( $url ) . '</code>' ),
2678
if ( has_shortcode( $parsed, 'audio' ) || has_shortcode( $parsed, 'video' ) ) {
2680
$mce_styles = wpview_media_sandbox_styles();
2681
foreach ( $mce_styles as $style ) {
2682
$styles .= sprintf( '<link rel="stylesheet" href="%s"/>', $style );
2685
$html = do_shortcode( $parsed );
2688
if ( ! empty( $wp_scripts ) ) {
2689
$wp_scripts->done = array();
2692
wp_print_scripts( 'wp-mediaelement' );
2693
$scripts = ob_get_clean();
2695
$parsed = $styles . $html . $scripts;
2699
if ( ! empty( $no_ssl_support ) || ( is_ssl() && ( preg_match( '%<(iframe|script|embed) [^>]*src="http://%', $parsed ) ||
2700
preg_match( '%<link [^>]*href="http://%', $parsed ) ) ) ) {
2701
// Admin is ssl and the embed is not. Iframes, scripts, and other "active content" will be blocked.
2702
wp_send_json_error( array(
2703
'type' => 'not-ssl',
2704
'message' => sprintf( __( 'Preview not available. %s cannot be embedded securely.' ), '<code>' . esc_html( $url ) . '</code>' ),
2708
wp_send_json_success( array(
2713
function wp_ajax_parse_media_shortcode() {
2714
global $post, $wp_scripts;
2716
if ( ! $post = get_post( (int) $_POST['post_ID'] ) ) {
2717
wp_send_json_error();
2720
if ( empty( $_POST['shortcode'] ) || ! current_user_can( 'edit_post', $post->ID ) ) {
2721
wp_send_json_error();
2724
setup_postdata( $post );
2725
$shortcode = do_shortcode( wp_unslash( $_POST['shortcode'] ) );
2727
if ( empty( $shortcode ) ) {
2728
wp_send_json_error( array(
2729
'type' => 'no-items',
2730
'message' => __( 'No items found.' ),
2735
$styles = wpview_media_sandbox_styles();
2737
foreach ( $styles as $style ) {
2738
$head .= '<link type="text/css" rel="stylesheet" href="' . $style . '">';
2741
if ( ! empty( $wp_scripts ) ) {
2742
$wp_scripts->done = array();
2749
if ( 'playlist' === $_REQUEST['type'] ) {
2750
wp_underscore_playlist_templates();
2752
wp_print_scripts( 'wp-playlist' );
2754
wp_print_scripts( 'wp-mediaelement' );
2757
wp_send_json_success( array(
2759
'body' => ob_get_clean()