~canonical-sysadmins/wordpress/4.7.2

« back to all changes in this revision

Viewing changes to wp-admin/includes/ajax-actions.php

  • Committer: Jacek Nykis
  • Date: 2015-01-05 16:17:05 UTC
  • Revision ID: jacek.nykis@canonical.com-20150105161705-w544l1h5mcg7u4w9
Initial commit

Show diffs side-by-side

added added

removed removed

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