WordPress 3.9.1
[autoinstalls/wordpress.git] / wp-admin / includes / ajax-actions.php
1 <?php
2 /**
3  * WordPress Core Ajax Handlers.
4  *
5  * @package WordPress
6  * @subpackage Administration
7  */
8
9 /*
10  * No-privilege Ajax handlers.
11  */
12
13 /**
14  * Heartbeat API (experimental)
15  *
16  * Runs when the user is not logged in.
17  */
18 function wp_ajax_nopriv_heartbeat() {
19         $response = array();
20
21         // screen_id is the same as $current_screen->id and the JS global 'pagenow'
22         if ( ! empty($_POST['screen_id']) )
23                 $screen_id = sanitize_key($_POST['screen_id']);
24         else
25                 $screen_id = 'front';
26
27         if ( ! empty($_POST['data']) ) {
28                 $data = wp_unslash( (array) $_POST['data'] );
29
30                 /**
31                  * Filter Heartbeat AJAX response in no-privilege environments.
32                  *
33                  * @since 3.6.0
34                  *
35                  * @param array|object $response  The no-priv Heartbeat response object or array.
36                  * @param array        $data      An array of data passed via $_POST.
37                  * @param string       $screen_id The screen id.
38                  */
39                 $response = apply_filters( 'heartbeat_nopriv_received', $response, $data, $screen_id );
40         }
41
42         /**
43          * Filter Heartbeat AJAX response when no data is passed.
44          *
45          * @since 3.6.0
46          *
47          * @param array|object $response  The Heartbeat response object or array.
48          * @param string       $screen_id The screen id.
49          */
50         $response = apply_filters( 'heartbeat_nopriv_send', $response, $screen_id );
51
52         /**
53          * Fires when Heartbeat ticks in no-privilege environments.
54          *
55          * Allows the transport to be easily replaced with long-polling.
56          *
57          * @since 3.6.0
58          *
59          * @param array|object $response  The no-priv Heartbeat response.
60          * @param string       $screen_id The screen id.
61          */
62         do_action( 'heartbeat_nopriv_tick', $response, $screen_id );
63
64         // send the current time according to the server
65         $response['server_time'] = time();
66
67         wp_send_json($response);
68 }
69
70 /*
71  * GET-based Ajax handlers.
72  */
73 function wp_ajax_fetch_list() {
74         global $wp_list_table;
75
76         $list_class = $_GET['list_args']['class'];
77         check_ajax_referer( "fetch-list-$list_class", '_ajax_fetch_list_nonce' );
78
79         $wp_list_table = _get_list_table( $list_class, array( 'screen' => $_GET['list_args']['screen']['id'] ) );
80         if ( ! $wp_list_table )
81                 wp_die( 0 );
82
83         if ( ! $wp_list_table->ajax_user_can() )
84                 wp_die( -1 );
85
86         $wp_list_table->ajax_response();
87
88         wp_die( 0 );
89 }
90 function wp_ajax_ajax_tag_search() {
91         global $wpdb;
92
93         if ( isset( $_GET['tax'] ) ) {
94                 $taxonomy = sanitize_key( $_GET['tax'] );
95                 $tax = get_taxonomy( $taxonomy );
96                 if ( ! $tax )
97                         wp_die( 0 );
98                 if ( ! current_user_can( $tax->cap->assign_terms ) )
99                         wp_die( -1 );
100         } else {
101                 wp_die( 0 );
102         }
103
104         $s = wp_unslash( $_GET['q'] );
105
106         $comma = _x( ',', 'tag delimiter' );
107         if ( ',' !== $comma )
108                 $s = str_replace( $comma, ',', $s );
109         if ( false !== strpos( $s, ',' ) ) {
110                 $s = explode( ',', $s );
111                 $s = $s[count( $s ) - 1];
112         }
113         $s = trim( $s );
114         if ( strlen( $s ) < 2 )
115                 wp_die(); // require 2 chars for matching
116
117         $results = get_terms( $taxonomy, array( 'name__like' => $s, 'fields' => 'names', 'hide_empty' => false ) );
118
119         echo join( $results, "\n" );
120         wp_die();
121 }
122
123 function wp_ajax_wp_compression_test() {
124         if ( !current_user_can( 'manage_options' ) )
125                 wp_die( -1 );
126
127         if ( ini_get('zlib.output_compression') || 'ob_gzhandler' == ini_get('output_handler') ) {
128                 update_site_option('can_compress_scripts', 0);
129                 wp_die( 0 );
130         }
131
132         if ( isset($_GET['test']) ) {
133                 header( 'Expires: Wed, 11 Jan 1984 05:00:00 GMT' );
134                 header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
135                 header( 'Cache-Control: no-cache, must-revalidate, max-age=0' );
136                 header( 'Pragma: no-cache' );
137                 header('Content-Type: application/x-javascript; charset=UTF-8');
138                 $force_gzip = ( defined('ENFORCE_GZIP') && ENFORCE_GZIP );
139                 $test_str = '"wpCompressionTest Lorem ipsum dolor sit amet consectetuer mollis sapien urna ut a. Eu nonummy condimentum fringilla tempor pretium platea vel nibh netus Maecenas. Hac molestie amet justo quis pellentesque est ultrices interdum nibh Morbi. Cras mattis pretium Phasellus ante ipsum ipsum ut sociis Suspendisse Lorem. Ante et non molestie. Porta urna Vestibulum egestas id congue nibh eu risus gravida sit. Ac augue auctor Ut et non a elit massa id sodales. Elit eu Nulla at nibh adipiscing mattis lacus mauris at tempus. Netus nibh quis suscipit nec feugiat eget sed lorem et urna. Pellentesque lacus at ut massa consectetuer ligula ut auctor semper Pellentesque. Ut metus massa nibh quam Curabitur molestie nec mauris congue. Volutpat molestie elit justo facilisis neque ac risus Ut nascetur tristique. Vitae sit lorem tellus et quis Phasellus lacus tincidunt nunc Fusce. Pharetra wisi Suspendisse mus sagittis libero lacinia Integer consequat ac Phasellus. Et urna ac cursus tortor aliquam Aliquam amet tellus volutpat Vestibulum. Justo interdum condimentum In augue congue tellus sollicitudin Quisque quis nibh."';
140
141                  if ( 1 == $_GET['test'] ) {
142                         echo $test_str;
143                         wp_die();
144                  } elseif ( 2 == $_GET['test'] ) {
145                         if ( !isset($_SERVER['HTTP_ACCEPT_ENCODING']) )
146                                 wp_die( -1 );
147                         if ( false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate') && function_exists('gzdeflate') && ! $force_gzip ) {
148                                 header('Content-Encoding: deflate');
149                                 $out = gzdeflate( $test_str, 1 );
150                         } elseif ( false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') && function_exists('gzencode') ) {
151                                 header('Content-Encoding: gzip');
152                                 $out = gzencode( $test_str, 1 );
153                         } else {
154                                 wp_die( -1 );
155                         }
156                         echo $out;
157                         wp_die();
158                 } elseif ( 'no' == $_GET['test'] ) {
159                         update_site_option('can_compress_scripts', 0);
160                 } elseif ( 'yes' == $_GET['test'] ) {
161                         update_site_option('can_compress_scripts', 1);
162                 }
163         }
164
165         wp_die( 0 );
166 }
167
168 function wp_ajax_imgedit_preview() {
169         $post_id = intval($_GET['postid']);
170         if ( empty($post_id) || !current_user_can('edit_post', $post_id) )
171                 wp_die( -1 );
172
173         check_ajax_referer( "image_editor-$post_id" );
174
175         include_once( ABSPATH . 'wp-admin/includes/image-edit.php' );
176         if ( ! stream_preview_image($post_id) )
177                 wp_die( -1 );
178
179         wp_die();
180 }
181
182 function wp_ajax_oembed_cache() {
183         global $wp_embed;
184
185         $return = ( $wp_embed->cache_oembed( $_GET['post'] ) ) ? '1' : '0';
186         wp_die( $return );
187 }
188
189 function wp_ajax_autocomplete_user() {
190         if ( ! is_multisite() || ! current_user_can( 'promote_users' ) || wp_is_large_network( 'users' ) )
191                 wp_die( -1 );
192
193         /** This filter is documented in wp-admin/user-new.php */
194         if ( ! is_super_admin() && ! apply_filters( 'autocomplete_users_for_site_admins', false ) )
195                 wp_die( -1 );
196
197         $return = array();
198
199         // Check the type of request
200         // Current allowed values are `add` and `search`
201         if ( isset( $_REQUEST['autocomplete_type'] ) && 'search' === $_REQUEST['autocomplete_type'] ) {
202                 $type = $_REQUEST['autocomplete_type'];
203         } else {
204                 $type = 'add';
205         }
206
207         // Check the desired field for value
208         // Current allowed values are `user_email` and `user_login`
209         if ( isset( $_REQUEST['autocomplete_field'] ) && 'user_email' === $_REQUEST['autocomplete_field'] ) {
210                 $field = $_REQUEST['autocomplete_field'];
211         } else {
212                 $field = 'user_login';
213         }
214
215         // Exclude current users of this blog
216         if ( isset( $_REQUEST['site_id'] ) ) {
217                 $id = absint( $_REQUEST['site_id'] );
218         } else {
219                 $id = get_current_blog_id();
220         }
221
222         $include_blog_users = ( $type == 'search' ? get_users( array( 'blog_id' => $id, 'fields' => 'ID' ) ) : array() );
223         $exclude_blog_users = ( $type == 'add' ? get_users( array( 'blog_id' => $id, 'fields' => 'ID' ) ) : array() );
224
225         $users = get_users( array(
226                 'blog_id' => false,
227                 'search'  => '*' . $_REQUEST['term'] . '*',
228                 'include' => $include_blog_users,
229                 'exclude' => $exclude_blog_users,
230                 'search_columns' => array( 'user_login', 'user_nicename', 'user_email' ),
231         ) );
232
233         foreach ( $users as $user ) {
234                 $return[] = array(
235                         /* translators: 1: user_login, 2: user_email */
236                         'label' => sprintf( __( '%1$s (%2$s)' ), $user->user_login, $user->user_email ),
237                         'value' => $user->$field,
238                 );
239         }
240
241         wp_die( json_encode( $return ) );
242 }
243
244 function wp_ajax_dashboard_widgets() {
245         require_once ABSPATH . 'wp-admin/includes/dashboard.php';
246
247         $pagenow = $_GET['pagenow'];
248         if ( $pagenow === 'dashboard-user' || $pagenow === 'dashboard-network' || $pagenow === 'dashboard' ) {
249                 set_current_screen( $pagenow );
250         }
251
252         switch ( $_GET['widget'] ) {
253                 case 'dashboard_primary' :
254                         wp_dashboard_primary();
255                         break;
256         }
257         wp_die();
258 }
259
260 function wp_ajax_logged_in() {
261         wp_die( 1 );
262 }
263
264 /*
265  * Ajax helper.
266  */
267
268 /**
269  * Sends back current comment total and new page links if they need to be updated.
270  *
271  * Contrary to normal success AJAX response ("1"), die with time() on success.
272  *
273  * @since 2.7.0
274  *
275  * @param int $comment_id
276  * @return die
277  */
278 function _wp_ajax_delete_comment_response( $comment_id, $delta = -1 ) {
279         $total    = isset( $_POST['_total'] )    ? (int) $_POST['_total']    : 0;
280         $per_page = isset( $_POST['_per_page'] ) ? (int) $_POST['_per_page'] : 0;
281         $page     = isset( $_POST['_page'] )     ? (int) $_POST['_page']     : 0;
282         $url      = isset( $_POST['_url'] )      ? esc_url_raw( $_POST['_url'] ) : '';
283
284         // JS didn't send us everything we need to know. Just die with success message
285         if ( !$total || !$per_page || !$page || !$url )
286                 wp_die( time() );
287
288         $total += $delta;
289         if ( $total < 0 )
290                 $total = 0;
291
292         // Only do the expensive stuff on a page-break, and about 1 other time per page
293         if ( 0 == $total % $per_page || 1 == mt_rand( 1, $per_page ) ) {
294                 $post_id = 0;
295                 $status = 'total_comments'; // What type of comment count are we looking for?
296                 $parsed = parse_url( $url );
297                 if ( isset( $parsed['query'] ) ) {
298                         parse_str( $parsed['query'], $query_vars );
299                         if ( !empty( $query_vars['comment_status'] ) )
300                                 $status = $query_vars['comment_status'];
301                         if ( !empty( $query_vars['p'] ) )
302                                 $post_id = (int) $query_vars['p'];
303                 }
304
305                 $comment_count = wp_count_comments($post_id);
306
307                 if ( isset( $comment_count->$status ) ) // We're looking for a known type of comment count
308                         $total = $comment_count->$status;
309                         // else use the decremented value from above
310         }
311
312         $time = time(); // The time since the last comment count
313
314         $x = new WP_Ajax_Response( array(
315                 'what' => 'comment',
316                 'id' => $comment_id, // here for completeness - not used
317                 'supplemental' => array(
318                         'total_items_i18n' => sprintf( _n( '1 item', '%s items', $total ), number_format_i18n( $total ) ),
319                         'total_pages' => ceil( $total / $per_page ),
320                         'total_pages_i18n' => number_format_i18n( ceil( $total / $per_page ) ),
321                         'total' => $total,
322                         'time' => $time
323                 )
324         ) );
325         $x->send();
326 }
327
328 /*
329  * POST-based Ajax handlers.
330  */
331
332 function _wp_ajax_add_hierarchical_term() {
333         $action = $_POST['action'];
334         $taxonomy = get_taxonomy(substr($action, 4));
335         check_ajax_referer( $action, '_ajax_nonce-add-' . $taxonomy->name );
336         if ( !current_user_can( $taxonomy->cap->edit_terms ) )
337                 wp_die( -1 );
338         $names = explode(',', $_POST['new'.$taxonomy->name]);
339         $parent = isset($_POST['new'.$taxonomy->name.'_parent']) ? (int) $_POST['new'.$taxonomy->name.'_parent'] : 0;
340         if ( 0 > $parent )
341                 $parent = 0;
342         if ( $taxonomy->name == 'category' )
343                 $post_category = isset($_POST['post_category']) ? (array) $_POST['post_category'] : array();
344         else
345                 $post_category = ( isset($_POST['tax_input']) && isset($_POST['tax_input'][$taxonomy->name]) ) ? (array) $_POST['tax_input'][$taxonomy->name] : array();
346         $checked_categories = array_map( 'absint', (array) $post_category );
347         $popular_ids = wp_popular_terms_checklist($taxonomy->name, 0, 10, false);
348
349         foreach ( $names as $cat_name ) {
350                 $cat_name = trim($cat_name);
351                 $category_nicename = sanitize_title($cat_name);
352                 if ( '' === $category_nicename )
353                         continue;
354                 if ( !$cat_id = term_exists( $cat_name, $taxonomy->name, $parent ) )
355                         $cat_id = wp_insert_term( $cat_name, $taxonomy->name, array( 'parent' => $parent ) );
356                 if ( is_wp_error( $cat_id ) )
357                         continue;
358                 else if ( is_array( $cat_id ) )
359                         $cat_id = $cat_id['term_id'];
360                 $checked_categories[] = $cat_id;
361                 if ( $parent ) // Do these all at once in a second
362                         continue;
363                 ob_start();
364                         wp_terms_checklist( 0, array( 'taxonomy' => $taxonomy->name, 'descendants_and_self' => $cat_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids ));
365                 $data = ob_get_contents();
366                 ob_end_clean();
367                 $add = array(
368                         'what' => $taxonomy->name,
369                         'id' => $cat_id,
370                         'data' => str_replace( array("\n", "\t"), '', $data),
371                         'position' => -1
372                 );
373         }
374
375         if ( $parent ) { // Foncy - replace the parent and all its children
376                 $parent = get_term( $parent, $taxonomy->name );
377                 $term_id = $parent->term_id;
378
379                 while ( $parent->parent ) { // get the top parent
380                         $parent = get_term( $parent->parent, $taxonomy->name );
381                         if ( is_wp_error( $parent ) )
382                                 break;
383                         $term_id = $parent->term_id;
384                 }
385
386                 ob_start();
387                         wp_terms_checklist( 0, array('taxonomy' => $taxonomy->name, 'descendants_and_self' => $term_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids));
388                 $data = ob_get_contents();
389                 ob_end_clean();
390                 $add = array(
391                         'what' => $taxonomy->name,
392                         'id' => $term_id,
393                         'data' => str_replace( array("\n", "\t"), '', $data),
394                         'position' => -1
395                 );
396         }
397
398         ob_start();
399                 wp_dropdown_categories( array(
400                         'taxonomy' => $taxonomy->name, 'hide_empty' => 0, 'name' => 'new'.$taxonomy->name.'_parent', 'orderby' => 'name',
401                         'hierarchical' => 1, 'show_option_none' => '&mdash; '.$taxonomy->labels->parent_item.' &mdash;'
402                 ) );
403         $sup = ob_get_contents();
404         ob_end_clean();
405         $add['supplemental'] = array( 'newcat_parent' => $sup );
406
407         $x = new WP_Ajax_Response( $add );
408         $x->send();
409 }
410
411 function wp_ajax_delete_comment() {
412         $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
413
414         if ( !$comment = get_comment( $id ) )
415                 wp_die( time() );
416         if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) )
417                 wp_die( -1 );
418
419         check_ajax_referer( "delete-comment_$id" );
420         $status = wp_get_comment_status( $comment->comment_ID );
421
422         $delta = -1;
423         if ( isset($_POST['trash']) && 1 == $_POST['trash'] ) {
424                 if ( 'trash' == $status )
425                         wp_die( time() );
426                 $r = wp_trash_comment( $comment->comment_ID );
427         } elseif ( isset($_POST['untrash']) && 1 == $_POST['untrash'] ) {
428                 if ( 'trash' != $status )
429                         wp_die( time() );
430                 $r = wp_untrash_comment( $comment->comment_ID );
431                 if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'trash' ) // undo trash, not in trash
432                         $delta = 1;
433         } elseif ( isset($_POST['spam']) && 1 == $_POST['spam'] ) {
434                 if ( 'spam' == $status )
435                         wp_die( time() );
436                 $r = wp_spam_comment( $comment->comment_ID );
437         } elseif ( isset($_POST['unspam']) && 1 == $_POST['unspam'] ) {
438                 if ( 'spam' != $status )
439                         wp_die( time() );
440                 $r = wp_unspam_comment( $comment->comment_ID );
441                 if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'spam' ) // undo spam, not in spam
442                         $delta = 1;
443         } elseif ( isset($_POST['delete']) && 1 == $_POST['delete'] ) {
444                 $r = wp_delete_comment( $comment->comment_ID );
445         } else {
446                 wp_die( -1 );
447         }
448
449         if ( $r ) // Decide if we need to send back '1' or a more complicated response including page links and comment counts
450                 _wp_ajax_delete_comment_response( $comment->comment_ID, $delta );
451         wp_die( 0 );
452 }
453
454 function wp_ajax_delete_tag() {
455         $tag_id = (int) $_POST['tag_ID'];
456         check_ajax_referer( "delete-tag_$tag_id" );
457
458         $taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
459         $tax = get_taxonomy($taxonomy);
460
461         if ( !current_user_can( $tax->cap->delete_terms ) )
462                 wp_die( -1 );
463
464         $tag = get_term( $tag_id, $taxonomy );
465         if ( !$tag || is_wp_error( $tag ) )
466                 wp_die( 1 );
467
468         if ( wp_delete_term($tag_id, $taxonomy))
469                 wp_die( 1 );
470         else
471                 wp_die( 0 );
472 }
473
474 function wp_ajax_delete_link() {
475         $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
476
477         check_ajax_referer( "delete-bookmark_$id" );
478         if ( !current_user_can( 'manage_links' ) )
479                 wp_die( -1 );
480
481         $link = get_bookmark( $id );
482         if ( !$link || is_wp_error( $link ) )
483                 wp_die( 1 );
484
485         if ( wp_delete_link( $id ) )
486                 wp_die( 1 );
487         else
488                 wp_die( 0 );
489 }
490
491 function wp_ajax_delete_meta() {
492         $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
493
494         check_ajax_referer( "delete-meta_$id" );
495         if ( !$meta = get_metadata_by_mid( 'post', $id ) )
496                 wp_die( 1 );
497
498         if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'delete_post_meta',  $meta->post_id, $meta->meta_key ) )
499                 wp_die( -1 );
500         if ( delete_meta( $meta->meta_id ) )
501                 wp_die( 1 );
502         wp_die( 0 );
503 }
504
505 function wp_ajax_delete_post( $action ) {
506         if ( empty( $action ) )
507                 $action = 'delete-post';
508         $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
509
510         check_ajax_referer( "{$action}_$id" );
511         if ( !current_user_can( 'delete_post', $id ) )
512                 wp_die( -1 );
513
514         if ( !get_post( $id ) )
515                 wp_die( 1 );
516
517         if ( wp_delete_post( $id ) )
518                 wp_die( 1 );
519         else
520                 wp_die( 0 );
521 }
522
523 function wp_ajax_trash_post( $action ) {
524         if ( empty( $action ) )
525                 $action = 'trash-post';
526         $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
527
528         check_ajax_referer( "{$action}_$id" );
529         if ( !current_user_can( 'delete_post', $id ) )
530                 wp_die( -1 );
531
532         if ( !get_post( $id ) )
533                 wp_die( 1 );
534
535         if ( 'trash-post' == $action )
536                 $done = wp_trash_post( $id );
537         else
538                 $done = wp_untrash_post( $id );
539
540         if ( $done )
541                 wp_die( 1 );
542
543         wp_die( 0 );
544 }
545
546 function wp_ajax_untrash_post( $action ) {
547         if ( empty( $action ) )
548                 $action = 'untrash-post';
549         wp_ajax_trash_post( $action );
550 }
551
552 function wp_ajax_delete_page( $action ) {
553         if ( empty( $action ) )
554                 $action = 'delete-page';
555         $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
556
557         check_ajax_referer( "{$action}_$id" );
558         if ( !current_user_can( 'delete_page', $id ) )
559                 wp_die( -1 );
560
561         if ( ! get_post( $id ) )
562                 wp_die( 1 );
563
564         if ( wp_delete_post( $id ) )
565                 wp_die( 1 );
566         else
567                 wp_die( 0 );
568 }
569
570 function wp_ajax_dim_comment() {
571         $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
572
573         if ( !$comment = get_comment( $id ) ) {
574                 $x = new WP_Ajax_Response( array(
575                         'what' => 'comment',
576                         'id' => new WP_Error('invalid_comment', sprintf(__('Comment %d does not exist'), $id))
577                 ) );
578                 $x->send();
579         }
580
581         if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) && ! current_user_can( 'moderate_comments' ) )
582                 wp_die( -1 );
583
584         $current = wp_get_comment_status( $comment->comment_ID );
585         if ( isset( $_POST['new'] ) && $_POST['new'] == $current )
586                 wp_die( time() );
587
588         check_ajax_referer( "approve-comment_$id" );
589         if ( in_array( $current, array( 'unapproved', 'spam' ) ) )
590                 $result = wp_set_comment_status( $comment->comment_ID, 'approve', true );
591         else
592                 $result = wp_set_comment_status( $comment->comment_ID, 'hold', true );
593
594         if ( is_wp_error($result) ) {
595                 $x = new WP_Ajax_Response( array(
596                         'what' => 'comment',
597                         'id' => $result
598                 ) );
599                 $x->send();
600         }
601
602         // Decide if we need to send back '1' or a more complicated response including page links and comment counts
603         _wp_ajax_delete_comment_response( $comment->comment_ID );
604         wp_die( 0 );
605 }
606
607 function wp_ajax_add_link_category( $action ) {
608         if ( empty( $action ) )
609                 $action = 'add-link-category';
610         check_ajax_referer( $action );
611         if ( !current_user_can( 'manage_categories' ) )
612                 wp_die( -1 );
613         $names = explode(',', wp_unslash( $_POST['newcat'] ) );
614         $x = new WP_Ajax_Response();
615         foreach ( $names as $cat_name ) {
616                 $cat_name = trim($cat_name);
617                 $slug = sanitize_title($cat_name);
618                 if ( '' === $slug )
619                         continue;
620                 if ( !$cat_id = term_exists( $cat_name, 'link_category' ) )
621                         $cat_id = wp_insert_term( $cat_name, 'link_category' );
622                 if ( is_wp_error( $cat_id ) )
623                         continue;
624                 else if ( is_array( $cat_id ) )
625                         $cat_id = $cat_id['term_id'];
626                 $cat_name = esc_html( $cat_name );
627                 $x->add( array(
628                         'what' => 'link-category',
629                         'id' => $cat_id,
630                         'data' => "<li id='link-category-$cat_id'><label for='in-link-category-$cat_id' class='selectit'><input value='" . esc_attr($cat_id) . "' type='checkbox' checked='checked' name='link_category[]' id='in-link-category-$cat_id'/> $cat_name</label></li>",
631                         'position' => -1
632                 ) );
633         }
634         $x->send();
635 }
636
637 function wp_ajax_add_tag() {
638         global $wp_list_table;
639
640         check_ajax_referer( 'add-tag', '_wpnonce_add-tag' );
641         $post_type = !empty($_POST['post_type']) ? $_POST['post_type'] : 'post';
642         $taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
643         $tax = get_taxonomy($taxonomy);
644
645         if ( !current_user_can( $tax->cap->edit_terms ) )
646                 wp_die( -1 );
647
648         $x = new WP_Ajax_Response();
649
650         $tag = wp_insert_term($_POST['tag-name'], $taxonomy, $_POST );
651
652         if ( !$tag || is_wp_error($tag) || (!$tag = get_term( $tag['term_id'], $taxonomy )) ) {
653                 $message = __('An error has occurred. Please reload the page and try again.');
654                 if ( is_wp_error($tag) && $tag->get_error_message() )
655                         $message = $tag->get_error_message();
656
657                 $x->add( array(
658                         'what' => 'taxonomy',
659                         'data' => new WP_Error('error', $message )
660                 ) );
661                 $x->send();
662         }
663
664         $wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => $_POST['screen'] ) );
665
666         $level = 0;
667         if ( is_taxonomy_hierarchical($taxonomy) ) {
668                 $level = count( get_ancestors( $tag->term_id, $taxonomy ) );
669                 ob_start();
670                 $wp_list_table->single_row( $tag, $level );
671                 $noparents = ob_get_clean();
672         }
673
674         ob_start();
675         $wp_list_table->single_row( $tag );
676         $parents = ob_get_clean();
677
678         $x->add( array(
679                 'what' => 'taxonomy',
680                 'supplemental' => compact('parents', 'noparents')
681                 ) );
682         $x->add( array(
683                 'what' => 'term',
684                 'position' => $level,
685                 'supplemental' => (array) $tag
686                 ) );
687         $x->send();
688 }
689
690 function wp_ajax_get_tagcloud() {
691         if ( isset( $_POST['tax'] ) ) {
692                 $taxonomy = sanitize_key( $_POST['tax'] );
693                 $tax = get_taxonomy( $taxonomy );
694                 if ( ! $tax )
695                         wp_die( 0 );
696                 if ( ! current_user_can( $tax->cap->assign_terms ) )
697                         wp_die( -1 );
698         } else {
699                 wp_die( 0 );
700         }
701
702         $tags = get_terms( $taxonomy, array( 'number' => 45, 'orderby' => 'count', 'order' => 'DESC' ) );
703
704         if ( empty( $tags ) )
705                 wp_die( $tax->labels->not_found );
706
707         if ( is_wp_error( $tags ) )
708                 wp_die( $tags->get_error_message() );
709
710         foreach ( $tags as $key => $tag ) {
711                 $tags[ $key ]->link = '#';
712                 $tags[ $key ]->id = $tag->term_id;
713         }
714
715         // We need raw tag names here, so don't filter the output
716         $return = wp_generate_tag_cloud( $tags, array('filter' => 0) );
717
718         if ( empty($return) )
719                 wp_die( 0 );
720
721         echo $return;
722
723         wp_die();
724 }
725
726 function wp_ajax_get_comments( $action ) {
727         global $wp_list_table, $post_id;
728         if ( empty( $action ) )
729                 $action = 'get-comments';
730
731         check_ajax_referer( $action );
732
733         if ( empty( $post_id ) && ! empty( $_REQUEST['p'] ) ) {
734                 $id = absint( $_REQUEST['p'] );
735                 if ( ! empty( $id ) )
736                         $post_id = $id;
737         }
738
739         if ( empty( $post_id ) )
740                 wp_die( -1 );
741
742         $wp_list_table = _get_list_table( 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
743
744         if ( ! current_user_can( 'edit_post', $post_id ) )
745                 wp_die( -1 );
746
747         $wp_list_table->prepare_items();
748
749         if ( !$wp_list_table->has_items() )
750                 wp_die( 1 );
751
752         $x = new WP_Ajax_Response();
753         ob_start();
754         foreach ( $wp_list_table->items as $comment ) {
755                 if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) )
756                         continue;
757                 get_comment( $comment );
758                 $wp_list_table->single_row( $comment );
759         }
760         $comment_list_item = ob_get_contents();
761         ob_end_clean();
762
763         $x->add( array(
764                 'what' => 'comments',
765                 'data' => $comment_list_item
766         ) );
767         $x->send();
768 }
769
770 function wp_ajax_replyto_comment( $action ) {
771         global $wp_list_table, $wpdb;
772         if ( empty( $action ) )
773                 $action = 'replyto-comment';
774
775         check_ajax_referer( $action, '_ajax_nonce-replyto-comment' );
776
777         $comment_post_ID = (int) $_POST['comment_post_ID'];
778         $post = get_post( $comment_post_ID );
779         if ( ! $post )
780                 wp_die( -1 );
781
782         if ( !current_user_can( 'edit_post', $comment_post_ID ) )
783                 wp_die( -1 );
784
785         if ( empty( $post->post_status ) )
786                 wp_die( 1 );
787         elseif ( in_array($post->post_status, array('draft', 'pending', 'trash') ) )
788                 wp_die( __('ERROR: you are replying to a comment on a draft post.') );
789
790         $user = wp_get_current_user();
791         if ( $user->exists() ) {
792                 $user_ID = $user->ID;
793                 $comment_author       = wp_slash( $user->display_name );
794                 $comment_author_email = wp_slash( $user->user_email );
795                 $comment_author_url   = wp_slash( $user->user_url );
796                 $comment_content      = trim($_POST['content']);
797                 if ( current_user_can( 'unfiltered_html' ) ) {
798                         if ( ! isset( $_POST['_wp_unfiltered_html_comment'] ) )
799                                 $_POST['_wp_unfiltered_html_comment'] = '';
800
801                         if ( wp_create_nonce( 'unfiltered-html-comment' ) != $_POST['_wp_unfiltered_html_comment'] ) {
802                                 kses_remove_filters(); // start with a clean slate
803                                 kses_init_filters(); // set up the filters
804                         }
805                 }
806         } else {
807                 wp_die( __( 'Sorry, you must be logged in to reply to a comment.' ) );
808         }
809
810         if ( '' == $comment_content )
811                 wp_die( __( 'ERROR: please type a comment.' ) );
812
813         $comment_parent = 0;
814         if ( isset( $_POST['comment_ID'] ) )
815                 $comment_parent = absint( $_POST['comment_ID'] );
816         $comment_auto_approved = false;
817         $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_type', 'comment_parent', 'user_ID');
818
819         // automatically approve parent comment
820         if ( !empty($_POST['approve_parent']) ) {
821                 $parent = get_comment( $comment_parent );
822
823                 if ( $parent && $parent->comment_approved === '0' && $parent->comment_post_ID == $comment_post_ID ) {
824                         if ( wp_set_comment_status( $parent->comment_ID, 'approve' ) )
825                                 $comment_auto_approved = true;
826                 }
827         }
828
829         $comment_id = wp_new_comment( $commentdata );
830         $comment = get_comment($comment_id);
831         if ( ! $comment ) wp_die( 1 );
832
833         $position = ( isset($_POST['position']) && (int) $_POST['position'] ) ? (int) $_POST['position'] : '-1';
834
835         ob_start();
836         if ( isset( $_REQUEST['mode'] ) && 'dashboard' == $_REQUEST['mode'] ) {
837                 require_once( ABSPATH . 'wp-admin/includes/dashboard.php' );
838                 _wp_dashboard_recent_comments_row( $comment );
839         } else {
840                 if ( isset( $_REQUEST['mode'] ) && 'single' == $_REQUEST['mode'] ) {
841                         $wp_list_table = _get_list_table('WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
842                 } else {
843                         $wp_list_table = _get_list_table('WP_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
844                 }
845                 $wp_list_table->single_row( $comment );
846         }
847         $comment_list_item = ob_get_clean();
848
849         $response =  array(
850                 'what' => 'comment',
851                 'id' => $comment->comment_ID,
852                 'data' => $comment_list_item,
853                 'position' => $position
854         );
855
856         if ( $comment_auto_approved )
857                 $response['supplemental'] = array( 'parent_approved' => $parent->comment_ID );
858
859         $x = new WP_Ajax_Response();
860         $x->add( $response );
861         $x->send();
862 }
863
864 function wp_ajax_edit_comment() {
865         global $wp_list_table;
866
867         check_ajax_referer( 'replyto-comment', '_ajax_nonce-replyto-comment' );
868
869         $comment_id = (int) $_POST['comment_ID'];
870         if ( ! current_user_can( 'edit_comment', $comment_id ) )
871                 wp_die( -1 );
872
873         if ( '' == $_POST['content'] )
874                 wp_die( __( 'ERROR: please type a comment.' ) );
875
876         if ( isset( $_POST['status'] ) )
877                 $_POST['comment_status'] = $_POST['status'];
878         edit_comment();
879
880         $position = ( isset($_POST['position']) && (int) $_POST['position']) ? (int) $_POST['position'] : '-1';
881         $comments_status = isset($_POST['comments_listing']) ? $_POST['comments_listing'] : '';
882
883         $checkbox = ( isset($_POST['checkbox']) && true == $_POST['checkbox'] ) ? 1 : 0;
884         $wp_list_table = _get_list_table( $checkbox ? 'WP_Comments_List_Table' : 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
885
886         $comment = get_comment( $comment_id );
887         if ( empty( $comment->comment_ID ) )
888                 wp_die( -1 );
889
890         ob_start();
891         $wp_list_table->single_row( $comment );
892         $comment_list_item = ob_get_clean();
893
894         $x = new WP_Ajax_Response();
895
896         $x->add( array(
897                 'what' => 'edit_comment',
898                 'id' => $comment->comment_ID,
899                 'data' => $comment_list_item,
900                 'position' => $position
901         ));
902
903         $x->send();
904 }
905
906 function wp_ajax_add_menu_item() {
907         check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' );
908
909         if ( ! current_user_can( 'edit_theme_options' ) )
910                 wp_die( -1 );
911
912         require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
913
914         // For performance reasons, we omit some object properties from the checklist.
915         // The following is a hacky way to restore them when adding non-custom items.
916
917         $menu_items_data = array();
918         foreach ( (array) $_POST['menu-item'] as $menu_item_data ) {
919                 if (
920                         ! empty( $menu_item_data['menu-item-type'] ) &&
921                         'custom' != $menu_item_data['menu-item-type'] &&
922                         ! empty( $menu_item_data['menu-item-object-id'] )
923                 ) {
924                         switch( $menu_item_data['menu-item-type'] ) {
925                                 case 'post_type' :
926                                         $_object = get_post( $menu_item_data['menu-item-object-id'] );
927                                 break;
928
929                                 case 'taxonomy' :
930                                         $_object = get_term( $menu_item_data['menu-item-object-id'], $menu_item_data['menu-item-object'] );
931                                 break;
932                         }
933
934                         $_menu_items = array_map( 'wp_setup_nav_menu_item', array( $_object ) );
935                         $_menu_item = array_shift( $_menu_items );
936
937                         // Restore the missing menu item properties
938                         $menu_item_data['menu-item-description'] = $_menu_item->description;
939                 }
940
941                 $menu_items_data[] = $menu_item_data;
942         }
943
944         $item_ids = wp_save_nav_menu_items( 0, $menu_items_data );
945         if ( is_wp_error( $item_ids ) )
946                 wp_die( 0 );
947
948         $menu_items = array();
949
950         foreach ( (array) $item_ids as $menu_item_id ) {
951                 $menu_obj = get_post( $menu_item_id );
952                 if ( ! empty( $menu_obj->ID ) ) {
953                         $menu_obj = wp_setup_nav_menu_item( $menu_obj );
954                         $menu_obj->label = $menu_obj->title; // don't show "(pending)" in ajax-added items
955                         $menu_items[] = $menu_obj;
956                 }
957         }
958
959         /**
960          * Filter the Walker class used when adding nav menu items.
961          *
962          * @since 3.4.0
963          *
964          * @param string $class   The walker class to use. Default 'Walker_Nav_Menu_Edit'.
965          * @param int    $menu_id The menu id, derived from $_POST['menu'].
966          */
967         $walker_class_name = apply_filters( 'wp_edit_nav_menu_walker', 'Walker_Nav_Menu_Edit', $_POST['menu'] );
968
969         if ( ! class_exists( $walker_class_name ) )
970                 wp_die( 0 );
971
972         if ( ! empty( $menu_items ) ) {
973                 $args = array(
974                         'after' => '',
975                         'before' => '',
976                         'link_after' => '',
977                         'link_before' => '',
978                         'walker' => new $walker_class_name,
979                 );
980                 echo walk_nav_menu_tree( $menu_items, 0, (object) $args );
981         }
982         wp_die();
983 }
984
985 function wp_ajax_add_meta() {
986         check_ajax_referer( 'add-meta', '_ajax_nonce-add-meta' );
987         $c = 0;
988         $pid = (int) $_POST['post_id'];
989         $post = get_post( $pid );
990
991         if ( isset($_POST['metakeyselect']) || isset($_POST['metakeyinput']) ) {
992                 if ( !current_user_can( 'edit_post', $pid ) )
993                         wp_die( -1 );
994                 if ( isset($_POST['metakeyselect']) && '#NONE#' == $_POST['metakeyselect'] && empty($_POST['metakeyinput']) )
995                         wp_die( 1 );
996                 if ( $post->post_status == 'auto-draft' ) {
997                         $save_POST = $_POST; // Backup $_POST
998                         $_POST = array(); // Make it empty for edit_post()
999                         $_POST['action'] = 'draft'; // Warning fix
1000                         $_POST['post_ID'] = $pid;
1001                         $_POST['post_type'] = $post->post_type;
1002                         $_POST['post_status'] = 'draft';
1003                         $now = current_time('timestamp', 1);
1004                         $_POST['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), date( get_option( 'date_format' ), $now ), date( get_option( 'time_format' ), $now ) );
1005
1006                         if ( $pid = edit_post() ) {
1007                                 if ( is_wp_error( $pid ) ) {
1008                                         $x = new WP_Ajax_Response( array(
1009                                                 'what' => 'meta',
1010                                                 'data' => $pid
1011                                         ) );
1012                                         $x->send();
1013                                 }
1014                                 $_POST = $save_POST; // Now we can restore original $_POST again
1015                                 if ( !$mid = add_meta( $pid ) )
1016                                         wp_die( __( 'Please provide a custom field value.' ) );
1017                         } else {
1018                                 wp_die( 0 );
1019                         }
1020                 } else if ( !$mid = add_meta( $pid ) ) {
1021                         wp_die( __( 'Please provide a custom field value.' ) );
1022                 }
1023
1024                 $meta = get_metadata_by_mid( 'post', $mid );
1025                 $pid = (int) $meta->post_id;
1026                 $meta = get_object_vars( $meta );
1027                 $x = new WP_Ajax_Response( array(
1028                         'what' => 'meta',
1029                         'id' => $mid,
1030                         'data' => _list_meta_row( $meta, $c ),
1031                         'position' => 1,
1032                         'supplemental' => array('postid' => $pid)
1033                 ) );
1034         } else { // Update?
1035                 $mid = (int) key( $_POST['meta'] );
1036                 $key = wp_unslash( $_POST['meta'][$mid]['key'] );
1037                 $value = wp_unslash( $_POST['meta'][$mid]['value'] );
1038                 if ( '' == trim($key) )
1039                         wp_die( __( 'Please provide a custom field name.' ) );
1040                 if ( '' == trim($value) )
1041                         wp_die( __( 'Please provide a custom field value.' ) );
1042                 if ( ! $meta = get_metadata_by_mid( 'post', $mid ) )
1043                         wp_die( 0 ); // if meta doesn't exist
1044                 if ( is_protected_meta( $meta->meta_key, 'post' ) || is_protected_meta( $key, 'post' ) ||
1045                         ! current_user_can( 'edit_post_meta', $meta->post_id, $meta->meta_key ) ||
1046                         ! current_user_can( 'edit_post_meta', $meta->post_id, $key ) )
1047                         wp_die( -1 );
1048                 if ( $meta->meta_value != $value || $meta->meta_key != $key ) {
1049                         if ( !$u = update_metadata_by_mid( 'post', $mid, $value, $key ) )
1050                                 wp_die( 0 ); // We know meta exists; we also know it's unchanged (or DB error, in which case there are bigger problems).
1051                 }
1052
1053                 $x = new WP_Ajax_Response( array(
1054                         'what' => 'meta',
1055                         'id' => $mid, 'old_id' => $mid,
1056                         'data' => _list_meta_row( array(
1057                                 'meta_key' => $key,
1058                                 'meta_value' => $value,
1059                                 'meta_id' => $mid
1060                         ), $c ),
1061                         'position' => 0,
1062                         'supplemental' => array('postid' => $meta->post_id)
1063                 ) );
1064         }
1065         $x->send();
1066 }
1067
1068 function wp_ajax_add_user( $action ) {
1069         global $wp_list_table;
1070         if ( empty( $action ) )
1071                 $action = 'add-user';
1072
1073         check_ajax_referer( $action );
1074         if ( ! current_user_can('create_users') )
1075                 wp_die( -1 );
1076         if ( ! $user_id = edit_user() ) {
1077                 wp_die( 0 );
1078         } elseif ( is_wp_error( $user_id ) ) {
1079                 $x = new WP_Ajax_Response( array(
1080                         'what' => 'user',
1081                         'id' => $user_id
1082                 ) );
1083                 $x->send();
1084         }
1085         $user_object = get_userdata( $user_id );
1086
1087         $wp_list_table = _get_list_table('WP_Users_List_Table');
1088
1089         $role = current( $user_object->roles );
1090
1091         $x = new WP_Ajax_Response( array(
1092                 'what' => 'user',
1093                 'id' => $user_id,
1094                 'data' => $wp_list_table->single_row( $user_object, '', $role ),
1095                 'supplemental' => array(
1096                         'show-link' => sprintf(__( 'User <a href="#%s">%s</a> added' ), "user-$user_id", $user_object->user_login),
1097                         'role' => $role,
1098                 )
1099         ) );
1100         $x->send();
1101 }
1102
1103 function wp_ajax_closed_postboxes() {
1104         check_ajax_referer( 'closedpostboxes', 'closedpostboxesnonce' );
1105         $closed = isset( $_POST['closed'] ) ? explode( ',', $_POST['closed']) : array();
1106         $closed = array_filter($closed);
1107
1108         $hidden = isset( $_POST['hidden'] ) ? explode( ',', $_POST['hidden']) : array();
1109         $hidden = array_filter($hidden);
1110
1111         $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1112
1113         if ( $page != sanitize_key( $page ) )
1114                 wp_die( 0 );
1115
1116         if ( ! $user = wp_get_current_user() )
1117                 wp_die( -1 );
1118
1119         if ( is_array($closed) )
1120                 update_user_option($user->ID, "closedpostboxes_$page", $closed, true);
1121
1122         if ( is_array($hidden) ) {
1123                 $hidden = array_diff( $hidden, array('submitdiv', 'linksubmitdiv', 'manage-menu', 'create-menu') ); // postboxes that are always shown
1124                 update_user_option($user->ID, "metaboxhidden_$page", $hidden, true);
1125         }
1126
1127         wp_die( 1 );
1128 }
1129
1130 function wp_ajax_hidden_columns() {
1131         check_ajax_referer( 'screen-options-nonce', 'screenoptionnonce' );
1132         $hidden = isset( $_POST['hidden'] ) ? $_POST['hidden'] : '';
1133         $hidden = explode( ',', $_POST['hidden'] );
1134         $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1135
1136         if ( $page != sanitize_key( $page ) )
1137                 wp_die( 0 );
1138
1139         if ( ! $user = wp_get_current_user() )
1140                 wp_die( -1 );
1141
1142         if ( is_array($hidden) )
1143                 update_user_option($user->ID, "manage{$page}columnshidden", $hidden, true);
1144
1145         wp_die( 1 );
1146 }
1147
1148 function wp_ajax_update_welcome_panel() {
1149         check_ajax_referer( 'welcome-panel-nonce', 'welcomepanelnonce' );
1150
1151         if ( ! current_user_can( 'edit_theme_options' ) )
1152                 wp_die( -1 );
1153
1154         update_user_meta( get_current_user_id(), 'show_welcome_panel', empty( $_POST['visible'] ) ? 0 : 1 );
1155
1156         wp_die( 1 );
1157 }
1158
1159 function wp_ajax_menu_get_metabox() {
1160         if ( ! current_user_can( 'edit_theme_options' ) )
1161                 wp_die( -1 );
1162
1163         require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
1164
1165         if ( isset( $_POST['item-type'] ) && 'post_type' == $_POST['item-type'] ) {
1166                 $type = 'posttype';
1167                 $callback = 'wp_nav_menu_item_post_type_meta_box';
1168                 $items = (array) get_post_types( array( 'show_in_nav_menus' => true ), 'object' );
1169         } elseif ( isset( $_POST['item-type'] ) && 'taxonomy' == $_POST['item-type'] ) {
1170                 $type = 'taxonomy';
1171                 $callback = 'wp_nav_menu_item_taxonomy_meta_box';
1172                 $items = (array) get_taxonomies( array( 'show_ui' => true ), 'object' );
1173         }
1174
1175         if ( ! empty( $_POST['item-object'] ) && isset( $items[$_POST['item-object']] ) ) {
1176                 $menus_meta_box_object = $items[ $_POST['item-object'] ];
1177                 /**
1178                  * Filter a nav menu meta box object.
1179                  *
1180                  * @since 3.0.0
1181                  *
1182                  * @param object $menus_meta_box_object A nav menu meta box object, such as Page,
1183                  *                                      Post, Category, Tag, etc.
1184                  */
1185                 $item = apply_filters( 'nav_menu_meta_box_object', $menus_meta_box_object );
1186                 ob_start();
1187                 call_user_func_array($callback, array(
1188                         null,
1189                         array(
1190                                 'id' => 'add-' . $item->name,
1191                                 'title' => $item->labels->name,
1192                                 'callback' => $callback,
1193                                 'args' => $item,
1194                         )
1195                 ));
1196
1197                 $markup = ob_get_clean();
1198
1199                 echo json_encode(array(
1200                         'replace-id' => $type . '-' . $item->name,
1201                         'markup' => $markup,
1202                 ));
1203         }
1204
1205         wp_die();
1206 }
1207
1208 function wp_ajax_wp_link_ajax() {
1209         check_ajax_referer( 'internal-linking', '_ajax_linking_nonce' );
1210
1211         $args = array();
1212
1213         if ( isset( $_POST['search'] ) )
1214                 $args['s'] = wp_unslash( $_POST['search'] );
1215         $args['pagenum'] = ! empty( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
1216
1217         require(ABSPATH . WPINC . '/class-wp-editor.php');
1218         $results = _WP_Editors::wp_link_query( $args );
1219
1220         if ( ! isset( $results ) )
1221                 wp_die( 0 );
1222
1223         echo json_encode( $results );
1224         echo "\n";
1225
1226         wp_die();
1227 }
1228
1229 function wp_ajax_menu_locations_save() {
1230         if ( ! current_user_can( 'edit_theme_options' ) )
1231                 wp_die( -1 );
1232         check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' );
1233         if ( ! isset( $_POST['menu-locations'] ) )
1234                 wp_die( 0 );
1235         set_theme_mod( 'nav_menu_locations', array_map( 'absint', $_POST['menu-locations'] ) );
1236         wp_die( 1 );
1237 }
1238
1239 function wp_ajax_meta_box_order() {
1240         check_ajax_referer( 'meta-box-order' );
1241         $order = isset( $_POST['order'] ) ? (array) $_POST['order'] : false;
1242         $page_columns = isset( $_POST['page_columns'] ) ? $_POST['page_columns'] : 'auto';
1243
1244         if ( $page_columns != 'auto' )
1245                 $page_columns = (int) $page_columns;
1246
1247         $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
1248
1249         if ( $page != sanitize_key( $page ) )
1250                 wp_die( 0 );
1251
1252         if ( ! $user = wp_get_current_user() )
1253                 wp_die( -1 );
1254
1255         if ( $order )
1256                 update_user_option($user->ID, "meta-box-order_$page", $order, true);
1257
1258         if ( $page_columns )
1259                 update_user_option($user->ID, "screen_layout_$page", $page_columns, true);
1260
1261         wp_die( 1 );
1262 }
1263
1264 function wp_ajax_menu_quick_search() {
1265         if ( ! current_user_can( 'edit_theme_options' ) )
1266                 wp_die( -1 );
1267
1268         require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
1269
1270         _wp_ajax_menu_quick_search( $_POST );
1271
1272         wp_die();
1273 }
1274
1275 function wp_ajax_get_permalink() {
1276         check_ajax_referer( 'getpermalink', 'getpermalinknonce' );
1277         $post_id = isset($_POST['post_id'])? intval($_POST['post_id']) : 0;
1278         wp_die( add_query_arg( array( 'preview' => 'true' ), get_permalink( $post_id ) ) );
1279 }
1280
1281 function wp_ajax_sample_permalink() {
1282         check_ajax_referer( 'samplepermalink', 'samplepermalinknonce' );
1283         $post_id = isset($_POST['post_id'])? intval($_POST['post_id']) : 0;
1284         $title = isset($_POST['new_title'])? $_POST['new_title'] : '';
1285         $slug = isset($_POST['new_slug'])? $_POST['new_slug'] : null;
1286         wp_die( get_sample_permalink_html( $post_id, $title, $slug ) );
1287 }
1288
1289 function wp_ajax_inline_save() {
1290         global $wp_list_table;
1291
1292         check_ajax_referer( 'inlineeditnonce', '_inline_edit' );
1293
1294         if ( ! isset($_POST['post_ID']) || ! ( $post_ID = (int) $_POST['post_ID'] ) )
1295                 wp_die();
1296
1297         if ( 'page' == $_POST['post_type'] ) {
1298                 if ( ! current_user_can( 'edit_page', $post_ID ) )
1299                         wp_die( __( 'You are not allowed to edit this page.' ) );
1300         } else {
1301                 if ( ! current_user_can( 'edit_post', $post_ID ) )
1302                         wp_die( __( 'You are not allowed to edit this post.' ) );
1303         }
1304
1305         if ( $last = wp_check_post_lock( $post_ID ) ) {
1306                 $last_user = get_userdata( $last );
1307                 $last_user_name = $last_user ? $last_user->display_name : __( 'Someone' );
1308                 printf( $_POST['post_type'] == 'page' ? __( 'Saving is disabled: %s is currently editing this page.' ) : __( 'Saving is disabled: %s is currently editing this post.' ),        esc_html( $last_user_name ) );
1309                 wp_die();
1310         }
1311
1312         $data = &$_POST;
1313
1314         $post = get_post( $post_ID, ARRAY_A );
1315         $post = wp_slash($post); //since it is from db
1316
1317         $data['content'] = $post['post_content'];
1318         $data['excerpt'] = $post['post_excerpt'];
1319
1320         // rename
1321         $data['user_ID'] = get_current_user_id();
1322
1323         if ( isset($data['post_parent']) )
1324                 $data['parent_id'] = $data['post_parent'];
1325
1326         // status
1327         if ( isset($data['keep_private']) && 'private' == $data['keep_private'] )
1328                 $data['post_status'] = 'private';
1329         else
1330                 $data['post_status'] = $data['_status'];
1331
1332         if ( empty($data['comment_status']) )
1333                 $data['comment_status'] = 'closed';
1334         if ( empty($data['ping_status']) )
1335                 $data['ping_status'] = 'closed';
1336
1337         // Hack: wp_unique_post_slug() doesn't work for drafts, so we will fake that our post is published.
1338         if ( ! empty( $data['post_name'] ) && in_array( $post['post_status'], array( 'draft', 'pending' ) ) ) {
1339                 $post['post_status'] = 'publish';
1340                 $data['post_name'] = wp_unique_post_slug( $data['post_name'], $post['ID'], $post['post_status'], $post['post_type'], $post['post_parent'] );
1341         }
1342
1343         // update the post
1344         edit_post();
1345
1346         $wp_list_table = _get_list_table( 'WP_Posts_List_Table', array( 'screen' => $_POST['screen'] ) );
1347
1348         $mode = $_POST['post_view'];
1349
1350         $level = 0;
1351         $request_post = array( get_post( $_POST['post_ID'] ) );
1352         $parent = $request_post[0]->post_parent;
1353
1354         while ( $parent > 0 ) {
1355                 $parent_post = get_post( $parent );
1356                 $parent = $parent_post->post_parent;
1357                 $level++;
1358         }
1359
1360         $wp_list_table->display_rows( array( get_post( $_POST['post_ID'] ) ), $level );
1361
1362         wp_die();
1363 }
1364
1365 function wp_ajax_inline_save_tax() {
1366         global $wp_list_table;
1367
1368         check_ajax_referer( 'taxinlineeditnonce', '_inline_edit' );
1369
1370         $taxonomy = sanitize_key( $_POST['taxonomy'] );
1371         $tax = get_taxonomy( $taxonomy );
1372         if ( ! $tax )
1373                 wp_die( 0 );
1374
1375         if ( ! current_user_can( $tax->cap->edit_terms ) )
1376                 wp_die( -1 );
1377
1378         $wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => 'edit-' . $taxonomy ) );
1379
1380         if ( ! isset($_POST['tax_ID']) || ! ( $id = (int) $_POST['tax_ID'] ) )
1381                 wp_die( -1 );
1382
1383         $tag = get_term( $id, $taxonomy );
1384         $_POST['description'] = $tag->description;
1385
1386         $updated = wp_update_term($id, $taxonomy, $_POST);
1387         if ( $updated && !is_wp_error($updated) ) {
1388                 $tag = get_term( $updated['term_id'], $taxonomy );
1389                 if ( !$tag || is_wp_error( $tag ) ) {
1390                         if ( is_wp_error($tag) && $tag->get_error_message() )
1391                                 wp_die( $tag->get_error_message() );
1392                         wp_die( __( 'Item not updated.' ) );
1393                 }
1394         } else {
1395                 if ( is_wp_error($updated) && $updated->get_error_message() )
1396                         wp_die( $updated->get_error_message() );
1397                 wp_die( __( 'Item not updated.' ) );
1398         }
1399         $level = 0;
1400         $parent = $tag->parent;
1401         while ( $parent > 0 ) {
1402                 $parent_tag = get_term( $parent, $taxonomy );
1403                 $parent = $parent_tag->parent;
1404                 $level++;
1405         }
1406         $wp_list_table->single_row( $tag, $level );
1407         wp_die();
1408 }
1409
1410 function wp_ajax_find_posts() {
1411         global $wpdb;
1412
1413         check_ajax_referer( 'find-posts' );
1414
1415         $post_types = get_post_types( array( 'public' => true ), 'objects' );
1416         unset( $post_types['attachment'] );
1417
1418         $s = wp_unslash( $_POST['ps'] );
1419         $searchand = $search = '';
1420         $args = array(
1421                 'post_type' => array_keys( $post_types ),
1422                 'post_status' => 'any',
1423                 'posts_per_page' => 50,
1424         );
1425         if ( '' !== $s )
1426                 $args['s'] = $s;
1427
1428         $posts = get_posts( $args );
1429
1430         if ( ! $posts )
1431                 wp_die( __('No items found.') );
1432
1433         $html = '<table class="widefat"><thead><tr><th class="found-radio"><br /></th><th>'.__('Title').'</th><th class="no-break">'.__('Type').'</th><th class="no-break">'.__('Date').'</th><th class="no-break">'.__('Status').'</th></tr></thead><tbody>';
1434         $alt = '';
1435         foreach ( $posts as $post ) {
1436                 $title = trim( $post->post_title ) ? $post->post_title : __( '(no title)' );
1437                 $alt = ( 'alternate' == $alt ) ? '' : 'alternate';
1438
1439                 switch ( $post->post_status ) {
1440                         case 'publish' :
1441                         case 'private' :
1442                                 $stat = __('Published');
1443                                 break;
1444                         case 'future' :
1445                                 $stat = __('Scheduled');
1446                                 break;
1447                         case 'pending' :
1448                                 $stat = __('Pending Review');
1449                                 break;
1450                         case 'draft' :
1451                                 $stat = __('Draft');
1452                                 break;
1453                 }
1454
1455                 if ( '0000-00-00 00:00:00' == $post->post_date ) {
1456                         $time = '';
1457                 } else {
1458                         /* translators: date format in table columns, see http://php.net/date */
1459                         $time = mysql2date(__('Y/m/d'), $post->post_date);
1460                 }
1461
1462                 $html .= '<tr class="' . trim( 'found-posts ' . $alt ) . '"><td class="found-radio"><input type="radio" id="found-'.$post->ID.'" name="found_post_id" value="' . esc_attr($post->ID) . '"></td>';
1463                 $html .= '<td><label for="found-'.$post->ID.'">' . esc_html( $title ) . '</label></td><td class="no-break">' . esc_html( $post_types[$post->post_type]->labels->singular_name ) . '</td><td class="no-break">'.esc_html( $time ) . '</td><td class="no-break">' . esc_html( $stat ). ' </td></tr>' . "\n\n";
1464         }
1465
1466         $html .= '</tbody></table>';
1467
1468         wp_send_json_success( $html );
1469 }
1470
1471 function wp_ajax_widgets_order() {
1472         check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' );
1473
1474         if ( !current_user_can('edit_theme_options') )
1475                 wp_die( -1 );
1476
1477         unset( $_POST['savewidgets'], $_POST['action'] );
1478
1479         // save widgets order for all sidebars
1480         if ( is_array($_POST['sidebars']) ) {
1481                 $sidebars = array();
1482                 foreach ( $_POST['sidebars'] as $key => $val ) {
1483                         $sb = array();
1484                         if ( !empty($val) ) {
1485                                 $val = explode(',', $val);
1486                                 foreach ( $val as $k => $v ) {
1487                                         if ( strpos($v, 'widget-') === false )
1488                                                 continue;
1489
1490                                         $sb[$k] = substr($v, strpos($v, '_') + 1);
1491                                 }
1492                         }
1493                         $sidebars[$key] = $sb;
1494                 }
1495                 wp_set_sidebars_widgets($sidebars);
1496                 wp_die( 1 );
1497         }
1498
1499         wp_die( -1 );
1500 }
1501
1502 function wp_ajax_save_widget() {
1503         global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
1504
1505         check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' );
1506
1507         if ( !current_user_can('edit_theme_options') || !isset($_POST['id_base']) )
1508                 wp_die( -1 );
1509
1510         unset( $_POST['savewidgets'], $_POST['action'] );
1511
1512         /**
1513          * Fires early when editing the widgets displayed in sidebars.
1514          *
1515          * @since 2.8.0
1516          */
1517         do_action( 'load-widgets.php' );
1518
1519         /**
1520          * Fires early when editing the widgets displayed in sidebars.
1521          *
1522          * @since 2.8.0
1523          */
1524         do_action( 'widgets.php' );
1525
1526         /** This action is documented in wp-admin/widgets.php */
1527         do_action( 'sidebar_admin_setup' );
1528
1529         $id_base = $_POST['id_base'];
1530         $widget_id = $_POST['widget-id'];
1531         $sidebar_id = $_POST['sidebar'];
1532         $multi_number = !empty($_POST['multi_number']) ? (int) $_POST['multi_number'] : 0;
1533         $settings = isset($_POST['widget-' . $id_base]) && is_array($_POST['widget-' . $id_base]) ? $_POST['widget-' . $id_base] : false;
1534         $error = '<p>' . __('An error has occurred. Please reload the page and try again.') . '</p>';
1535
1536         $sidebars = wp_get_sidebars_widgets();
1537         $sidebar = isset($sidebars[$sidebar_id]) ? $sidebars[$sidebar_id] : array();
1538
1539         // delete
1540         if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
1541
1542                 if ( !isset($wp_registered_widgets[$widget_id]) )
1543                         wp_die( $error );
1544
1545                 $sidebar = array_diff( $sidebar, array($widget_id) );
1546                 $_POST = array('sidebar' => $sidebar_id, 'widget-' . $id_base => array(), 'the-widget-id' => $widget_id, 'delete_widget' => '1');
1547         } elseif ( $settings && preg_match( '/__i__|%i%/', key($settings) ) ) {
1548                 if ( !$multi_number )
1549                         wp_die( $error );
1550
1551                 $_POST['widget-' . $id_base] = array( $multi_number => array_shift($settings) );
1552                 $widget_id = $id_base . '-' . $multi_number;
1553                 $sidebar[] = $widget_id;
1554         }
1555         $_POST['widget-id'] = $sidebar;
1556
1557         foreach ( (array) $wp_registered_widget_updates as $name => $control ) {
1558
1559                 if ( $name == $id_base ) {
1560                         if ( !is_callable( $control['callback'] ) )
1561                                 continue;
1562
1563                         ob_start();
1564                                 call_user_func_array( $control['callback'], $control['params'] );
1565                         ob_end_clean();
1566                         break;
1567                 }
1568         }
1569
1570         if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
1571                 $sidebars[$sidebar_id] = $sidebar;
1572                 wp_set_sidebars_widgets($sidebars);
1573                 echo "deleted:$widget_id";
1574                 wp_die();
1575         }
1576
1577         if ( !empty($_POST['add_new']) )
1578                 wp_die();
1579
1580         if ( $form = $wp_registered_widget_controls[$widget_id] )
1581                 call_user_func_array( $form['callback'], $form['params'] );
1582
1583         wp_die();
1584 }
1585
1586 function wp_ajax_update_widget() {
1587         global $wp_customize;
1588         $wp_customize->widgets->wp_ajax_update_widget();
1589 }
1590
1591 function wp_ajax_upload_attachment() {
1592         check_ajax_referer( 'media-form' );
1593
1594         if ( ! current_user_can( 'upload_files' ) )
1595                 wp_die();
1596
1597         if ( isset( $_REQUEST['post_id'] ) ) {
1598                 $post_id = $_REQUEST['post_id'];
1599                 if ( ! current_user_can( 'edit_post', $post_id ) )
1600                         wp_die();
1601         } else {
1602                 $post_id = null;
1603         }
1604
1605         $post_data = isset( $_REQUEST['post_data'] ) ? $_REQUEST['post_data'] : array();
1606
1607         // If the context is custom header or background, make sure the uploaded file is an image.
1608         if ( isset( $post_data['context'] ) && in_array( $post_data['context'], array( 'custom-header', 'custom-background' ) ) ) {
1609                 $wp_filetype = wp_check_filetype_and_ext( $_FILES['async-upload']['tmp_name'], $_FILES['async-upload']['name'], false );
1610                 if ( ! wp_match_mime_types( 'image', $wp_filetype['type'] ) ) {
1611                         echo json_encode( array(
1612                                 'success' => false,
1613                                 'data'    => array(
1614                                         'message'  => __( 'The uploaded file is not a valid image. Please try again.' ),
1615                                         'filename' => $_FILES['async-upload']['name'],
1616                                 )
1617                         ) );
1618
1619                         wp_die();
1620                 }
1621         }
1622
1623         $attachment_id = media_handle_upload( 'async-upload', $post_id, $post_data );
1624
1625         if ( is_wp_error( $attachment_id ) ) {
1626                 echo json_encode( array(
1627                         'success' => false,
1628                         'data'    => array(
1629                                 'message'  => $attachment_id->get_error_message(),
1630                                 'filename' => $_FILES['async-upload']['name'],
1631                         )
1632                 ) );
1633
1634                 wp_die();
1635         }
1636
1637         if ( isset( $post_data['context'] ) && isset( $post_data['theme'] ) ) {
1638                 if ( 'custom-background' === $post_data['context'] )
1639                         update_post_meta( $attachment_id, '_wp_attachment_is_custom_background', $post_data['theme'] );
1640
1641                 if ( 'custom-header' === $post_data['context'] )
1642                         update_post_meta( $attachment_id, '_wp_attachment_is_custom_header', $post_data['theme'] );
1643         }
1644
1645         if ( ! $attachment = wp_prepare_attachment_for_js( $attachment_id ) )
1646                 wp_die();
1647
1648         echo json_encode( array(
1649                 'success' => true,
1650                 'data'    => $attachment,
1651         ) );
1652
1653         wp_die();
1654 }
1655
1656 function wp_ajax_image_editor() {
1657         $attachment_id = intval($_POST['postid']);
1658         if ( empty($attachment_id) || !current_user_can('edit_post', $attachment_id) )
1659                 wp_die( -1 );
1660
1661         check_ajax_referer( "image_editor-$attachment_id" );
1662         include_once( ABSPATH . 'wp-admin/includes/image-edit.php' );
1663
1664         $msg = false;
1665         switch ( $_POST['do'] ) {
1666                 case 'save' :
1667                         $msg = wp_save_image($attachment_id);
1668                         $msg = json_encode($msg);
1669                         wp_die( $msg );
1670                         break;
1671                 case 'scale' :
1672                         $msg = wp_save_image($attachment_id);
1673                         break;
1674                 case 'restore' :
1675                         $msg = wp_restore_image($attachment_id);
1676                         break;
1677         }
1678
1679         wp_image_editor($attachment_id, $msg);
1680         wp_die();
1681 }
1682
1683 function wp_ajax_set_post_thumbnail() {
1684         $json = ! empty( $_REQUEST['json'] ); // New-style request
1685
1686         $post_ID = intval( $_POST['post_id'] );
1687         if ( ! current_user_can( 'edit_post', $post_ID ) )
1688                 wp_die( -1 );
1689
1690         $thumbnail_id = intval( $_POST['thumbnail_id'] );
1691
1692         if ( $json )
1693                 check_ajax_referer( "update-post_$post_ID" );
1694         else
1695                 check_ajax_referer( "set_post_thumbnail-$post_ID" );
1696
1697         if ( $thumbnail_id == '-1' ) {
1698                 if ( delete_post_thumbnail( $post_ID ) ) {
1699                         $return = _wp_post_thumbnail_html( null, $post_ID );
1700                         $json ? wp_send_json_success( $return ) : wp_die( $return );
1701                 } else {
1702                         wp_die( 0 );
1703                 }
1704         }
1705
1706         if ( set_post_thumbnail( $post_ID, $thumbnail_id ) ) {
1707                 $return = _wp_post_thumbnail_html( $thumbnail_id, $post_ID );
1708                 $json ? wp_send_json_success( $return ) : wp_die( $return );
1709         }
1710
1711         wp_die( 0 );
1712 }
1713
1714 function wp_ajax_date_format() {
1715         wp_die( date_i18n( sanitize_option( 'date_format', wp_unslash( $_POST['date'] ) ) ) );
1716 }
1717
1718 function wp_ajax_time_format() {
1719         wp_die( date_i18n( sanitize_option( 'time_format', wp_unslash( $_POST['date'] ) ) ) );
1720 }
1721
1722 function wp_ajax_wp_fullscreen_save_post() {
1723         $post_id = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0;
1724
1725         $post = $post_type = null;
1726
1727         if ( $post_id )
1728                 $post = get_post( $post_id );
1729
1730         if ( $post )
1731                 $post_type = $post->post_type;
1732         elseif ( isset( $_POST['post_type'] ) && post_type_exists( $_POST['post_type'] ) )
1733                 $post_type = $_POST['post_type'];
1734
1735         check_ajax_referer('update-post_' . $post_id, '_wpnonce');
1736
1737         $post_id = edit_post();
1738
1739         if ( is_wp_error( $post_id ) ) {
1740                 wp_send_json_error();
1741         }
1742
1743         if ( $post ) {
1744                 $last_date = mysql2date( get_option('date_format'), $post->post_modified );
1745                 $last_time = mysql2date( get_option('time_format'), $post->post_modified );
1746         } else {
1747                 $last_date = date_i18n( get_option('date_format') );
1748                 $last_time = date_i18n( get_option('time_format') );
1749         }
1750
1751         if ( $last_id = get_post_meta( $post_id, '_edit_last', true ) ) {
1752                 $last_user = get_userdata( $last_id );
1753                 $last_edited = sprintf( __('Last edited by %1$s on %2$s at %3$s'), esc_html( $last_user->display_name ), $last_date, $last_time );
1754         } else {
1755                 $last_edited = sprintf( __('Last edited on %1$s at %2$s'), $last_date, $last_time );
1756         }
1757
1758         wp_send_json_success( array( 'last_edited' => $last_edited ) );
1759 }
1760
1761 function wp_ajax_wp_remove_post_lock() {
1762         if ( empty( $_POST['post_ID'] ) || empty( $_POST['active_post_lock'] ) )
1763                 wp_die( 0 );
1764         $post_id = (int) $_POST['post_ID'];
1765         if ( ! $post = get_post( $post_id ) )
1766                 wp_die( 0 );
1767
1768         check_ajax_referer( 'update-post_' . $post_id );
1769
1770         if ( ! current_user_can( 'edit_post', $post_id ) )
1771                 wp_die( -1 );
1772
1773         $active_lock = array_map( 'absint', explode( ':', $_POST['active_post_lock'] ) );
1774         if ( $active_lock[1] != get_current_user_id() )
1775                 wp_die( 0 );
1776
1777         /**
1778          * Filter the post lock window duration.
1779          *
1780          * @since 3.3.0
1781          *
1782          * @param int $interval The interval in seconds the post lock duration
1783          *                      should last, plus 5 seconds. Default 150.
1784          */
1785         $new_lock = ( time() - apply_filters( 'wp_check_post_lock_window', 150 ) + 5 ) . ':' . $active_lock[1];
1786         update_post_meta( $post_id, '_edit_lock', $new_lock, implode( ':', $active_lock ) );
1787         wp_die( 1 );
1788 }
1789
1790 function wp_ajax_dismiss_wp_pointer() {
1791         $pointer = $_POST['pointer'];
1792         if ( $pointer != sanitize_key( $pointer ) )
1793                 wp_die( 0 );
1794
1795 //      check_ajax_referer( 'dismiss-pointer_' . $pointer );
1796
1797         $dismissed = array_filter( explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) ) );
1798
1799         if ( in_array( $pointer, $dismissed ) )
1800                 wp_die( 0 );
1801
1802         $dismissed[] = $pointer;
1803         $dismissed = implode( ',', $dismissed );
1804
1805         update_user_meta( get_current_user_id(), 'dismissed_wp_pointers', $dismissed );
1806         wp_die( 1 );
1807 }
1808
1809 /**
1810  * Get an attachment.
1811  *
1812  * @since 3.5.0
1813  */
1814 function wp_ajax_get_attachment() {
1815         if ( ! isset( $_REQUEST['id'] ) )
1816                 wp_send_json_error();
1817
1818         if ( ! $id = absint( $_REQUEST['id'] ) )
1819                 wp_send_json_error();
1820
1821         if ( ! $post = get_post( $id ) )
1822                 wp_send_json_error();
1823
1824         if ( 'attachment' != $post->post_type )
1825                 wp_send_json_error();
1826
1827         if ( ! current_user_can( 'upload_files' ) )
1828                 wp_send_json_error();
1829
1830         if ( ! $attachment = wp_prepare_attachment_for_js( $id ) )
1831                 wp_send_json_error();
1832
1833         wp_send_json_success( $attachment );
1834 }
1835
1836 /**
1837  * Query for attachments.
1838  *
1839  * @since 3.5.0
1840  */
1841 function wp_ajax_query_attachments() {
1842         if ( ! current_user_can( 'upload_files' ) )
1843                 wp_send_json_error();
1844
1845         $query = isset( $_REQUEST['query'] ) ? (array) $_REQUEST['query'] : array();
1846         $query = array_intersect_key( $query, array_flip( array(
1847                 's', 'order', 'orderby', 'posts_per_page', 'paged', 'post_mime_type',
1848                 'post_parent', 'post__in', 'post__not_in',
1849         ) ) );
1850
1851         $query['post_type'] = 'attachment';
1852         $query['post_status'] = 'inherit';
1853         if ( current_user_can( get_post_type_object( 'attachment' )->cap->read_private_posts ) )
1854                 $query['post_status'] .= ',private';
1855
1856         /**
1857          * Filter the arguments passed to WP_Query during an AJAX
1858          * call for querying attachments.
1859          *
1860          * @since 3.7.0
1861          *
1862          * @see WP_Query::parse_query()
1863          *
1864          * @param array $query An array of query variables.
1865          */
1866         $query = apply_filters( 'ajax_query_attachments_args', $query );
1867         $query = new WP_Query( $query );
1868
1869         $posts = array_map( 'wp_prepare_attachment_for_js', $query->posts );
1870         $posts = array_filter( $posts );
1871
1872         wp_send_json_success( $posts );
1873 }
1874
1875 /**
1876  * Save attachment attributes.
1877  *
1878  * @since 3.5.0
1879  */
1880 function wp_ajax_save_attachment() {
1881         if ( ! isset( $_REQUEST['id'] ) || ! isset( $_REQUEST['changes'] ) )
1882                 wp_send_json_error();
1883
1884         if ( ! $id = absint( $_REQUEST['id'] ) )
1885                 wp_send_json_error();
1886
1887         check_ajax_referer( 'update-post_' . $id, 'nonce' );
1888
1889         if ( ! current_user_can( 'edit_post', $id ) )
1890                 wp_send_json_error();
1891
1892         $changes = $_REQUEST['changes'];
1893         $post    = get_post( $id, ARRAY_A );
1894
1895         if ( 'attachment' != $post['post_type'] )
1896                 wp_send_json_error();
1897
1898         if ( isset( $changes['title'] ) )
1899                 $post['post_title'] = $changes['title'];
1900
1901         if ( isset( $changes['caption'] ) )
1902                 $post['post_excerpt'] = $changes['caption'];
1903
1904         if ( isset( $changes['description'] ) )
1905                 $post['post_content'] = $changes['description'];
1906
1907         if ( isset( $changes['alt'] ) ) {
1908                 $alt = wp_unslash( $changes['alt'] );
1909                 if ( $alt != get_post_meta( $id, '_wp_attachment_image_alt', true ) ) {
1910                         $alt = wp_strip_all_tags( $alt, true );
1911                         update_post_meta( $id, '_wp_attachment_image_alt', wp_slash( $alt ) );
1912                 }
1913         }
1914
1915         wp_update_post( $post );
1916         wp_send_json_success();
1917 }
1918
1919 /**
1920  * Save backwards compatible attachment attributes.
1921  *
1922  * @since 3.5.0
1923  */
1924 function wp_ajax_save_attachment_compat() {
1925         if ( ! isset( $_REQUEST['id'] ) )
1926                 wp_send_json_error();
1927
1928         if ( ! $id = absint( $_REQUEST['id'] ) )
1929                 wp_send_json_error();
1930
1931         if ( empty( $_REQUEST['attachments'] ) || empty( $_REQUEST['attachments'][ $id ] ) )
1932                 wp_send_json_error();
1933         $attachment_data = $_REQUEST['attachments'][ $id ];
1934
1935         check_ajax_referer( 'update-post_' . $id, 'nonce' );
1936
1937         if ( ! current_user_can( 'edit_post', $id ) )
1938                 wp_send_json_error();
1939
1940         $post = get_post( $id, ARRAY_A );
1941
1942         if ( 'attachment' != $post['post_type'] )
1943                 wp_send_json_error();
1944
1945         /** This filter is documented in wp-admin/includes/media.php */
1946         $post = apply_filters( 'attachment_fields_to_save', $post, $attachment_data );
1947
1948         if ( isset( $post['errors'] ) ) {
1949                 $errors = $post['errors']; // @todo return me and display me!
1950                 unset( $post['errors'] );
1951         }
1952
1953         wp_update_post( $post );
1954
1955         foreach ( get_attachment_taxonomies( $post ) as $taxonomy ) {
1956                 if ( isset( $attachment_data[ $taxonomy ] ) )
1957                         wp_set_object_terms( $id, array_map( 'trim', preg_split( '/,+/', $attachment_data[ $taxonomy ] ) ), $taxonomy, false );
1958         }
1959
1960         if ( ! $attachment = wp_prepare_attachment_for_js( $id ) )
1961                 wp_send_json_error();
1962
1963         wp_send_json_success( $attachment );
1964 }
1965
1966 function wp_ajax_save_attachment_order() {
1967         if ( ! isset( $_REQUEST['post_id'] ) )
1968                 wp_send_json_error();
1969
1970         if ( ! $post_id = absint( $_REQUEST['post_id'] ) )
1971                 wp_send_json_error();
1972
1973         if ( empty( $_REQUEST['attachments'] ) )
1974                 wp_send_json_error();
1975
1976         check_ajax_referer( 'update-post_' . $post_id, 'nonce' );
1977
1978         $attachments = $_REQUEST['attachments'];
1979
1980         if ( ! current_user_can( 'edit_post', $post_id ) )
1981                 wp_send_json_error();
1982
1983         $post = get_post( $post_id, ARRAY_A );
1984
1985         foreach ( $attachments as $attachment_id => $menu_order ) {
1986                 if ( ! current_user_can( 'edit_post', $attachment_id ) )
1987                         continue;
1988                 if ( ! $attachment = get_post( $attachment_id ) )
1989                         continue;
1990                 if ( 'attachment' != $attachment->post_type )
1991                         continue;
1992
1993                 wp_update_post( array( 'ID' => $attachment_id, 'menu_order' => $menu_order ) );
1994         }
1995
1996         wp_send_json_success();
1997 }
1998
1999 /**
2000  * Generates the HTML to send an attachment to the editor.
2001  * Backwards compatible with the media_send_to_editor filter and the chain
2002  * of filters that follow.
2003  *
2004  * @since 3.5.0
2005  */
2006 function wp_ajax_send_attachment_to_editor() {
2007         check_ajax_referer( 'media-send-to-editor', 'nonce' );
2008
2009         $attachment = wp_unslash( $_POST['attachment'] );
2010
2011         $id = intval( $attachment['id'] );
2012
2013         if ( ! $post = get_post( $id ) )
2014                 wp_send_json_error();
2015
2016         if ( 'attachment' != $post->post_type )
2017                 wp_send_json_error();
2018
2019         if ( current_user_can( 'edit_post', $id ) ) {
2020                 // If this attachment is unattached, attach it. Primarily a back compat thing.
2021                 if ( 0 == $post->post_parent && $insert_into_post_id = intval( $_POST['post_id'] ) ) {
2022                         wp_update_post( array( 'ID' => $id, 'post_parent' => $insert_into_post_id ) );
2023                 }
2024         }
2025
2026         $rel = $url = '';
2027         $html = $title = isset( $attachment['post_title'] ) ? $attachment['post_title'] : '';
2028         if ( ! empty( $attachment['url'] ) ) {
2029                 $url = $attachment['url'];
2030                 if ( strpos( $url, 'attachment_id') || get_attachment_link( $id ) == $url )
2031                         $rel = ' rel="attachment wp-att-' . $id . '"';
2032                 $html = '<a href="' . esc_url( $url ) . '"' . $rel . '>' . $html . '</a>';
2033         }
2034
2035         remove_filter( 'media_send_to_editor', 'image_media_send_to_editor' );
2036
2037         if ( 'image' === substr( $post->post_mime_type, 0, 5 ) ) {
2038                 $align = isset( $attachment['align'] ) ? $attachment['align'] : 'none';
2039                 $size = isset( $attachment['image-size'] ) ? $attachment['image-size'] : 'medium';
2040                 $alt = isset( $attachment['image_alt'] ) ? $attachment['image_alt'] : '';
2041                 $caption = isset( $attachment['post_excerpt'] ) ? $attachment['post_excerpt'] : '';
2042                 $title = ''; // We no longer insert title tags into <img> tags, as they are redundant.
2043                 $html = get_image_send_to_editor( $id, $caption, $title, $align, $url, (bool) $rel, $size, $alt );
2044         } elseif ( 'video' === substr( $post->post_mime_type, 0, 5 ) || 'audio' === substr( $post->post_mime_type, 0, 5 )  ) {
2045                 $html = stripslashes_deep( $_POST['html'] );
2046         }
2047
2048         /** This filter is documented in wp-admin/includes/media.php */
2049         $html = apply_filters( 'media_send_to_editor', $html, $id, $attachment );
2050
2051         wp_send_json_success( $html );
2052 }
2053
2054 /**
2055  * Generates the HTML to send a non-image embed link to the editor.
2056  *
2057  * Backwards compatible with the following filters:
2058  * - file_send_to_editor_url
2059  * - audio_send_to_editor_url
2060  * - video_send_to_editor_url
2061  *
2062  * @since 3.5.0
2063  */
2064 function wp_ajax_send_link_to_editor() {
2065         check_ajax_referer( 'media-send-to-editor', 'nonce' );
2066
2067         if ( ! $src = wp_unslash( $_POST['src'] ) )
2068                 wp_send_json_error();
2069
2070         if ( ! strpos( $src, '://' ) )
2071                 $src = 'http://' . $src;
2072
2073         if ( ! $src = esc_url_raw( $src ) )
2074                 wp_send_json_error();
2075
2076         if ( ! $title = trim( wp_unslash( $_POST['title'] ) ) )
2077                 $title = wp_basename( $src );
2078
2079         $html = '';
2080         if ( $title )
2081                 $html = '<a href="' . esc_url( $src ) . '">' . $title . '</a>';
2082
2083         // Figure out what filter to run:
2084         $type = 'file';
2085         if ( ( $ext = preg_replace( '/^.+?\.([^.]+)$/', '$1', $src ) ) && ( $ext_type = wp_ext2type( $ext ) )
2086                 && ( 'audio' == $ext_type || 'video' == $ext_type ) )
2087                         $type = $ext_type;
2088
2089         /** This filter is documented in wp-admin/includes/media.php */
2090         $html = apply_filters( $type . '_send_to_editor_url', $html, $src, $title );
2091
2092         wp_send_json_success( $html );
2093 }
2094
2095 /**
2096  * Heartbeat API (experimental)
2097  *
2098  * Runs when the user is logged in.
2099  */
2100 function wp_ajax_heartbeat() {
2101         if ( empty( $_POST['_nonce'] ) )
2102                 wp_send_json_error();
2103
2104         $response = array();
2105
2106         if ( false === wp_verify_nonce( $_POST['_nonce'], 'heartbeat-nonce' ) ) {
2107                 // User is logged in but nonces have expired.
2108                 $response['nonces_expired'] = true;
2109                 wp_send_json($response);
2110         }
2111
2112         // screen_id is the same as $current_screen->id and the JS global 'pagenow'
2113         if ( ! empty($_POST['screen_id']) )
2114                 $screen_id = sanitize_key($_POST['screen_id']);
2115         else
2116                 $screen_id = 'front';
2117
2118         if ( ! empty($_POST['data']) ) {
2119                 $data = wp_unslash( (array) $_POST['data'] );
2120
2121                 /**
2122                  * Filter the Heartbeat response received.
2123                  *
2124                  * @since 3.6.0
2125                  *
2126                  * @param array|object $response  The Heartbeat response object or array.
2127                  * @param array        $data      The $_POST data sent.
2128                  * @param string       $screen_id The screen id.
2129                  */
2130                 $response = apply_filters( 'heartbeat_received', $response, $data, $screen_id );
2131         }
2132
2133         /**
2134          * Filter the Heartbeat response sent.
2135          *
2136          * @since 3.6.0
2137          *
2138          * @param array|object $response  The Heartbeat response object or array.
2139          * @param string       $screen_id The screen id.
2140          */
2141         $response = apply_filters( 'heartbeat_send', $response, $screen_id );
2142
2143         /**
2144          * Fires when Heartbeat ticks in logged-in environments.
2145          *
2146          * Allows the transport to be easily replaced with long-polling.
2147          *
2148          * @since 3.6.0
2149          *
2150          * @param array|object $response  The Heartbeat response object or array.
2151          * @param string       $screen_id The screen id.
2152          */
2153         do_action( 'heartbeat_tick', $response, $screen_id );
2154
2155         // Send the current time according to the server
2156         $response['server_time'] = time();
2157
2158         wp_send_json($response);
2159 }
2160
2161 function wp_ajax_get_revision_diffs() {
2162         require ABSPATH . 'wp-admin/includes/revision.php';
2163
2164         if ( ! $post = get_post( (int) $_REQUEST['post_id'] ) )
2165                 wp_send_json_error();
2166
2167         if ( ! current_user_can( 'read_post', $post->ID ) )
2168                 wp_send_json_error();
2169
2170         // Really just pre-loading the cache here.
2171         if ( ! $revisions = wp_get_post_revisions( $post->ID, array( 'check_enabled' => false ) ) )
2172                 wp_send_json_error();
2173
2174         $return = array();
2175         @set_time_limit( 0 );
2176
2177         foreach ( $_REQUEST['compare'] as $compare_key ) {
2178                 list( $compare_from, $compare_to ) = explode( ':', $compare_key ); // from:to
2179
2180                 $return[] = array(
2181                         'id' => $compare_key,
2182                         'fields' => wp_get_revision_ui_diff( $post, $compare_from, $compare_to ),
2183                 );
2184         }
2185         wp_send_json_success( $return );
2186 }
2187
2188 /**
2189  * Auto-save the selected color scheme for a user's own profile.
2190  *
2191  * @since  3.8.0
2192  */
2193 function wp_ajax_save_user_color_scheme() {
2194         global $_wp_admin_css_colors;
2195
2196         check_ajax_referer( 'save-color-scheme', 'nonce' );
2197
2198         $color_scheme = sanitize_key( $_POST['color_scheme'] );
2199
2200         if ( ! isset( $_wp_admin_css_colors[ $color_scheme ] ) ) {
2201                 wp_send_json_error();
2202         }
2203
2204         update_user_meta( get_current_user_id(), 'admin_color', $color_scheme );
2205         wp_send_json_success();
2206 }
2207
2208 /**
2209  * Get themes from themes_api().
2210  *
2211  * @since 3.9.0
2212  */
2213 function wp_ajax_query_themes() {
2214         global $themes_allowedtags, $theme_field_defaults;
2215
2216         if ( ! current_user_can( 'install_themes' ) ) {
2217                 wp_send_json_error();
2218         }
2219
2220         $args = wp_parse_args( wp_unslash( $_REQUEST['request'] ), array(
2221                 'per_page' => 20,
2222                 'fields'   => $theme_field_defaults
2223         ) );
2224
2225         $old_filter = isset( $args['browse'] ) ? $args['browse'] : 'search';
2226
2227         /** This filter is documented in wp-admin/includes/class-wp-theme-install-list-table.php */
2228         $args = apply_filters( 'install_themes_table_api_args_' . $old_filter, $args );
2229
2230         $api = themes_api( 'query_themes', $args );
2231
2232         if ( is_wp_error( $api ) ) {
2233                 wp_send_json_error();
2234         }
2235
2236         $update_php = network_admin_url( 'update.php?action=install-theme' );
2237         foreach ( $api->themes as &$theme ) {
2238                 $theme->install_url = add_query_arg( array(
2239                         'theme'    => $theme->slug,
2240                         '_wpnonce' => wp_create_nonce( 'install-theme_' . $theme->slug )
2241                 ), $update_php );
2242
2243                 $theme->name        = wp_kses( $theme->name, $themes_allowedtags );
2244                 $theme->author      = wp_kses( $theme->author, $themes_allowedtags );
2245                 $theme->version     = wp_kses( $theme->version, $themes_allowedtags );
2246                 $theme->description = wp_kses( $theme->description, $themes_allowedtags );
2247                 $theme->num_ratings = sprintf( _n( '(based on %s rating)', '(based on %s ratings)', $theme->num_ratings ), number_format_i18n( $theme->num_ratings ) );
2248         }
2249
2250         wp_send_json_success( $api );
2251 }