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