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