wp/wp-admin/includes/ajax-actions.php
changeset 7 cf61fcea0001
parent 5 5e2f62d02dcd
child 9 177826044cd9
equal deleted inserted replaced
6:490d5cc509ed 7:cf61fcea0001
     1 <?php
     1 <?php
     2 /**
     2 /**
     3  * WordPress Core Ajax Handlers.
     3  * Administration API: Core Ajax handlers
     4  *
     4  *
     5  * @package WordPress
     5  * @package WordPress
     6  * @subpackage Administration
     6  * @subpackage Administration
       
     7  * @since 2.1.0
     7  */
     8  */
     8 
     9 
     9 //
    10 //
    10 // No-privilege Ajax handlers.
    11 // No-privilege Ajax handlers.
    11 //
    12 //
    29 
    30 
    30 	if ( ! empty($_POST['data']) ) {
    31 	if ( ! empty($_POST['data']) ) {
    31 		$data = wp_unslash( (array) $_POST['data'] );
    32 		$data = wp_unslash( (array) $_POST['data'] );
    32 
    33 
    33 		/**
    34 		/**
    34 		 * Filter Heartbeat AJAX response in no-privilege environments.
    35 		 * Filters Heartbeat Ajax response in no-privilege environments.
    35 		 *
    36 		 *
    36 		 * @since 3.6.0
    37 		 * @since 3.6.0
    37 		 *
    38 		 *
    38 		 * @param array|object $response  The no-priv Heartbeat response object or array.
    39 		 * @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 array        $data      An array of data passed via $_POST.
    41 		 */
    42 		 */
    42 		$response = apply_filters( 'heartbeat_nopriv_received', $response, $data, $screen_id );
    43 		$response = apply_filters( 'heartbeat_nopriv_received', $response, $data, $screen_id );
    43 	}
    44 	}
    44 
    45 
    45 	/**
    46 	/**
    46 	 * Filter Heartbeat AJAX response when no data is passed.
    47 	 * Filters Heartbeat Ajax response when no data is passed.
    47 	 *
    48 	 *
    48 	 * @since 3.6.0
    49 	 * @since 3.6.0
    49 	 *
    50 	 *
    50 	 * @param array|object $response  The Heartbeat response object or array.
    51 	 * @param array|object $response  The Heartbeat response object or array.
    51 	 * @param string       $screen_id The screen id.
    52 	 * @param string       $screen_id The screen id.
    78  * Ajax handler for fetching a list table.
    79  * Ajax handler for fetching a list table.
    79  *
    80  *
    80  * @since 3.1.0
    81  * @since 3.1.0
    81  */
    82  */
    82 function wp_ajax_fetch_list() {
    83 function wp_ajax_fetch_list() {
    83 	global $wp_list_table;
       
    84 
       
    85 	$list_class = $_GET['list_args']['class'];
    84 	$list_class = $_GET['list_args']['class'];
    86 	check_ajax_referer( "fetch-list-$list_class", '_ajax_fetch_list_nonce' );
    85 	check_ajax_referer( "fetch-list-$list_class", '_ajax_fetch_list_nonce' );
    87 
    86 
    88 	$wp_list_table = _get_list_table( $list_class, array( 'screen' => $_GET['list_args']['screen']['id'] ) );
    87 	$wp_list_table = _get_list_table( $list_class, array( 'screen' => $_GET['list_args']['screen']['id'] ) );
    89 	if ( ! $wp_list_table )
    88 	if ( ! $wp_list_table ) {
    90 		wp_die( 0 );
    89 		wp_die( 0 );
    91 
    90 	}
    92 	if ( ! $wp_list_table->ajax_user_can() )
    91 
       
    92 	if ( ! $wp_list_table->ajax_user_can() ) {
    93 		wp_die( -1 );
    93 		wp_die( -1 );
       
    94 	}
    94 
    95 
    95 	$wp_list_table->ajax_response();
    96 	$wp_list_table->ajax_response();
    96 
    97 
    97 	wp_die( 0 );
    98 	wp_die( 0 );
    98 }
    99 }
   127 		$s = $s[count( $s ) - 1];
   128 		$s = $s[count( $s ) - 1];
   128 	}
   129 	}
   129 	$s = trim( $s );
   130 	$s = trim( $s );
   130 
   131 
   131 	/**
   132 	/**
   132 	 * Filter the minimum number of characters required to fire a tag search via AJAX.
   133 	 * Filters the minimum number of characters required to fire a tag search via Ajax.
   133 	 *
   134 	 *
   134 	 * @since 4.0.0
   135 	 * @since 4.0.0
   135 	 *
   136 	 *
   136 	 * @param int    $characters The minimum number of characters required. Default 2.
   137 	 * @param int         $characters The minimum number of characters required. Default 2.
   137 	 * @param object $tax        The taxonomy object.
   138 	 * @param WP_Taxonomy $tax        The taxonomy object.
   138 	 * @param string $s          The search term.
   139 	 * @param string      $s          The search term.
   139 	 */
   140 	 */
   140 	$term_search_min_chars = (int) apply_filters( 'term_search_min_chars', 2, $tax, $s );
   141 	$term_search_min_chars = (int) apply_filters( 'term_search_min_chars', 2, $tax, $s );
   141 
   142 
   142 	/*
   143 	/*
   143 	 * Require $term_search_min_chars chars for matching (default: 2)
   144 	 * Require $term_search_min_chars chars for matching (default: 2)
   169 
   170 
   170 	if ( isset($_GET['test']) ) {
   171 	if ( isset($_GET['test']) ) {
   171 		header( 'Expires: Wed, 11 Jan 1984 05:00:00 GMT' );
   172 		header( 'Expires: Wed, 11 Jan 1984 05:00:00 GMT' );
   172 		header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
   173 		header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
   173 		header( 'Cache-Control: no-cache, must-revalidate, max-age=0' );
   174 		header( 'Cache-Control: no-cache, must-revalidate, max-age=0' );
   174 		header( 'Pragma: no-cache' );
       
   175 		header('Content-Type: application/javascript; charset=UTF-8');
   175 		header('Content-Type: application/javascript; charset=UTF-8');
   176 		$force_gzip = ( defined('ENFORCE_GZIP') && ENFORCE_GZIP );
   176 		$force_gzip = ( defined('ENFORCE_GZIP') && ENFORCE_GZIP );
   177 		$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."';
   177 		$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."';
   178 
   178 
   179 		 if ( 1 == $_GET['test'] ) {
   179 		 if ( 1 == $_GET['test'] ) {
   192 				wp_die( -1 );
   192 				wp_die( -1 );
   193 			}
   193 			}
   194 			echo $out;
   194 			echo $out;
   195 			wp_die();
   195 			wp_die();
   196 		} elseif ( 'no' == $_GET['test'] ) {
   196 		} elseif ( 'no' == $_GET['test'] ) {
       
   197 			check_ajax_referer( 'update_can_compress_scripts' );
   197 			update_site_option('can_compress_scripts', 0);
   198 			update_site_option('can_compress_scripts', 0);
   198 		} elseif ( 'yes' == $_GET['test'] ) {
   199 		} elseif ( 'yes' == $_GET['test'] ) {
       
   200 			check_ajax_referer( 'update_can_compress_scripts' );
   199 			update_site_option('can_compress_scripts', 1);
   201 			update_site_option('can_compress_scripts', 1);
   200 		}
   202 		}
   201 	}
   203 	}
   202 
   204 
   203 	wp_die( 0 );
   205 	wp_die( 0 );
   224 
   226 
   225 /**
   227 /**
   226  * Ajax handler for oEmbed caching.
   228  * Ajax handler for oEmbed caching.
   227  *
   229  *
   228  * @since 3.1.0
   230  * @since 3.1.0
       
   231  *
       
   232  * @global WP_Embed $wp_embed
   229  */
   233  */
   230 function wp_ajax_oembed_cache() {
   234 function wp_ajax_oembed_cache() {
   231 	$GLOBALS['wp_embed']->cache_oembed( $_GET['post'] );
   235 	$GLOBALS['wp_embed']->cache_oembed( $_GET['post'] );
   232 	wp_die( 0 );
   236 	wp_die( 0 );
   233 }
   237 }
   240 function wp_ajax_autocomplete_user() {
   244 function wp_ajax_autocomplete_user() {
   241 	if ( ! is_multisite() || ! current_user_can( 'promote_users' ) || wp_is_large_network( 'users' ) )
   245 	if ( ! is_multisite() || ! current_user_can( 'promote_users' ) || wp_is_large_network( 'users' ) )
   242 		wp_die( -1 );
   246 		wp_die( -1 );
   243 
   247 
   244 	/** This filter is documented in wp-admin/user-new.php */
   248 	/** This filter is documented in wp-admin/user-new.php */
   245 	if ( ! is_super_admin() && ! apply_filters( 'autocomplete_users_for_site_admins', false ) )
   249 	if ( ! current_user_can( 'manage_network_users' ) && ! apply_filters( 'autocomplete_users_for_site_admins', false ) )
   246 		wp_die( -1 );
   250 		wp_die( -1 );
   247 
   251 
   248 	$return = array();
   252 	$return = array();
   249 
   253 
   250 	// Check the type of request
   254 	// Check the type of request
   282 	) );
   286 	) );
   283 
   287 
   284 	foreach ( $users as $user ) {
   288 	foreach ( $users as $user ) {
   285 		$return[] = array(
   289 		$return[] = array(
   286 			/* translators: 1: user_login, 2: user_email */
   290 			/* translators: 1: user_login, 2: user_email */
   287 			'label' => sprintf( __( '%1$s (%2$s)' ), $user->user_login, $user->user_email ),
   291 			'label' => sprintf( _x( '%1$s (%2$s)', 'user autocomplete result' ), $user->user_login, $user->user_email ),
   288 			'value' => $user->$field,
   292 			'value' => $user->$field,
   289 		);
   293 		);
   290 	}
   294 	}
   291 
   295 
   292 	wp_die( wp_json_encode( $return ) );
   296 	wp_die( wp_json_encode( $return ) );
       
   297 }
       
   298 
       
   299 /**
       
   300  * Handles AJAX requests for community events
       
   301  *
       
   302  * @since 4.8.0
       
   303  */
       
   304 function wp_ajax_get_community_events() {
       
   305 	require_once( ABSPATH . 'wp-admin/includes/class-wp-community-events.php' );
       
   306 
       
   307 	check_ajax_referer( 'community_events' );
       
   308 
       
   309 	$search         = isset( $_POST['location'] ) ? wp_unslash( $_POST['location'] ) : '';
       
   310 	$timezone       = isset( $_POST['timezone'] ) ? wp_unslash( $_POST['timezone'] ) : '';
       
   311 	$user_id        = get_current_user_id();
       
   312 	$saved_location = get_user_option( 'community-events-location', $user_id );
       
   313 	$events_client  = new WP_Community_Events( $user_id, $saved_location );
       
   314 	$events         = $events_client->get_events( $search, $timezone );
       
   315 	$ip_changed     = false;
       
   316 
       
   317 	if ( is_wp_error( $events ) ) {
       
   318 		wp_send_json_error( array(
       
   319 			'error' => $events->get_error_message(),
       
   320 		) );
       
   321 	} else {
       
   322 		if ( empty( $saved_location['ip'] ) && ! empty( $events['location']['ip'] ) ) {
       
   323 			$ip_changed = true;
       
   324 		} elseif ( isset( $saved_location['ip'] ) && ! empty( $events['location']['ip'] ) && $saved_location['ip'] !== $events['location']['ip'] ) {
       
   325 			$ip_changed = true;
       
   326 		}
       
   327 
       
   328 		/*
       
   329 		 * The location should only be updated when it changes. The API doesn't always return
       
   330 		 * a full location; sometimes it's missing the description or country. The location
       
   331 		 * that was saved during the initial request is known to be good and complete, though.
       
   332 		 * It should be left in tact until the user explicitly changes it (either by manually
       
   333 		 * searching for a new location, or by changing their IP address).
       
   334 		 *
       
   335 		 * If the location were updated with an incomplete response from the API, then it could
       
   336 		 * break assumptions that the UI makes (e.g., that there will always be a description
       
   337 		 * that corresponds to a latitude/longitude location).
       
   338 		 *
       
   339 		 * The location is stored network-wide, so that the user doesn't have to set it on each site.
       
   340 		 */
       
   341 		if ( $ip_changed || $search ) {
       
   342 			update_user_option( $user_id, 'community-events-location', $events['location'], true );
       
   343 		}
       
   344 
       
   345 		wp_send_json_success( $events );
       
   346 	}
   293 }
   347 }
   294 
   348 
   295 /**
   349 /**
   296  * Ajax handler for dashboard widgets.
   350  * Ajax handler for dashboard widgets.
   297  *
   351  *
   327 //
   381 //
   328 
   382 
   329 /**
   383 /**
   330  * Sends back current comment total and new page links if they need to be updated.
   384  * Sends back current comment total and new page links if they need to be updated.
   331  *
   385  *
   332  * Contrary to normal success AJAX response ("1"), die with time() on success.
   386  * Contrary to normal success Ajax response ("1"), die with time() on success.
   333  *
   387  *
       
   388  * @access private
   334  * @since 2.7.0
   389  * @since 2.7.0
   335  *
   390  *
   336  * @param int $comment_id
   391  * @param int $comment_id
   337  * @return die
   392  * @param int $delta
   338  */
   393  */
   339 function _wp_ajax_delete_comment_response( $comment_id, $delta = -1 ) {
   394 function _wp_ajax_delete_comment_response( $comment_id, $delta = -1 ) {
   340 	$total    = isset( $_POST['_total'] )    ? (int) $_POST['_total']    : 0;
   395 	$total    = isset( $_POST['_total'] )    ? (int) $_POST['_total']    : 0;
   341 	$per_page = isset( $_POST['_per_page'] ) ? (int) $_POST['_per_page'] : 0;
   396 	$per_page = isset( $_POST['_per_page'] ) ? (int) $_POST['_per_page'] : 0;
   342 	$page     = isset( $_POST['_page'] )     ? (int) $_POST['_page']     : 0;
   397 	$page     = isset( $_POST['_page'] )     ? (int) $_POST['_page']     : 0;
   343 	$url      = isset( $_POST['_url'] )      ? esc_url_raw( $_POST['_url'] ) : '';
   398 	$url      = isset( $_POST['_url'] )      ? esc_url_raw( $_POST['_url'] ) : '';
   344 
   399 
   345 	// JS didn't send us everything we need to know. Just die with success message
   400 	// JS didn't send us everything we need to know. Just die with success message
   346 	if ( !$total || !$per_page || !$page || !$url )
   401 	if ( ! $total || ! $per_page || ! $page || ! $url ) {
   347 		wp_die( time() );
   402 		$time           = time();
       
   403 		$comment        = get_comment( $comment_id );
       
   404 		$comment_status = '';
       
   405 		$comment_link   = '';
       
   406 
       
   407 		if ( $comment ) {
       
   408 			$comment_status = $comment->comment_approved;
       
   409 		}
       
   410 
       
   411 		if ( 1 === (int) $comment_status ) {
       
   412 			$comment_link = get_comment_link( $comment );
       
   413 		}
       
   414 
       
   415 		$counts = wp_count_comments();
       
   416 
       
   417 		$x = new WP_Ajax_Response( array(
       
   418 			'what' => 'comment',
       
   419 			// Here for completeness - not used.
       
   420 			'id' => $comment_id,
       
   421 			'supplemental' => array(
       
   422 				'status' => $comment_status,
       
   423 				'postId' => $comment ? $comment->comment_post_ID : '',
       
   424 				'time' => $time,
       
   425 				'in_moderation' => $counts->moderated,
       
   426 				'i18n_comments_text' => sprintf(
       
   427 					_n( '%s Comment', '%s Comments', $counts->approved ),
       
   428 					number_format_i18n( $counts->approved )
       
   429 				),
       
   430 				'i18n_moderation_text' => sprintf(
       
   431 					_nx( '%s in moderation', '%s in moderation', $counts->moderated, 'comments' ),
       
   432 					number_format_i18n( $counts->moderated )
       
   433 				),
       
   434 				'comment_link' => $comment_link,
       
   435 			)
       
   436 		) );
       
   437 		$x->send();
       
   438 	}
   348 
   439 
   349 	$total += $delta;
   440 	$total += $delta;
   350 	if ( $total < 0 )
   441 	if ( $total < 0 )
   351 		$total = 0;
   442 		$total = 0;
   352 
   443 
   353 	// Only do the expensive stuff on a page-break, and about 1 other time per page
   444 	// Only do the expensive stuff on a page-break, and about 1 other time per page
   354 	if ( 0 == $total % $per_page || 1 == mt_rand( 1, $per_page ) ) {
   445 	if ( 0 == $total % $per_page || 1 == mt_rand( 1, $per_page ) ) {
   355 		$post_id = 0;
   446 		$post_id = 0;
   356 		$status = 'total_comments'; // What type of comment count are we looking for?
   447 		// What type of comment count are we looking for?
       
   448 		$status = 'all';
   357 		$parsed = parse_url( $url );
   449 		$parsed = parse_url( $url );
   358 		if ( isset( $parsed['query'] ) ) {
   450 		if ( isset( $parsed['query'] ) ) {
   359 			parse_str( $parsed['query'], $query_vars );
   451 			parse_str( $parsed['query'], $query_vars );
   360 			if ( !empty( $query_vars['comment_status'] ) )
   452 			if ( !empty( $query_vars['comment_status'] ) )
   361 				$status = $query_vars['comment_status'];
   453 				$status = $query_vars['comment_status'];
   362 			if ( !empty( $query_vars['p'] ) )
   454 			if ( !empty( $query_vars['p'] ) )
   363 				$post_id = (int) $query_vars['p'];
   455 				$post_id = (int) $query_vars['p'];
   364 		}
   456 			if ( ! empty( $query_vars['comment_type'] ) )
   365 
   457 				$type = $query_vars['comment_type'];
   366 		$comment_count = wp_count_comments($post_id);
   458 		}
   367 
   459 
   368 		// We're looking for a known type of comment count.
   460 		if ( empty( $type ) ) {
   369 		if ( isset( $comment_count->$status ) )
   461 			// Only use the comment count if not filtering by a comment_type.
   370 			$total = $comment_count->$status;
   462 			$comment_count = wp_count_comments($post_id);
   371 			// Else use the decremented value from above.
   463 
       
   464 			// We're looking for a known type of comment count.
       
   465 			if ( isset( $comment_count->$status ) ) {
       
   466 				$total = $comment_count->$status;
       
   467 			}
       
   468 		}
       
   469 		// Else use the decremented value from above.
   372 	}
   470 	}
   373 
   471 
   374 	// The time since the last comment count.
   472 	// The time since the last comment count.
   375 	$time = time();
   473 	$time = time();
       
   474 	$comment = get_comment( $comment_id );
   376 
   475 
   377 	$x = new WP_Ajax_Response( array(
   476 	$x = new WP_Ajax_Response( array(
   378 		'what' => 'comment',
   477 		'what' => 'comment',
   379 		// Here for completeness - not used.
   478 		// Here for completeness - not used.
   380 		'id' => $comment_id,
   479 		'id' => $comment_id,
   381 		'supplemental' => array(
   480 		'supplemental' => array(
       
   481 			'status' => $comment ? $comment->comment_approved : '',
       
   482 			'postId' => $comment ? $comment->comment_post_ID : '',
   382 			'total_items_i18n' => sprintf( _n( '%s item', '%s items', $total ), number_format_i18n( $total ) ),
   483 			'total_items_i18n' => sprintf( _n( '%s item', '%s items', $total ), number_format_i18n( $total ) ),
   383 			'total_pages' => ceil( $total / $per_page ),
   484 			'total_pages' => ceil( $total / $per_page ),
   384 			'total_pages_i18n' => number_format_i18n( ceil( $total / $per_page ) ),
   485 			'total_pages_i18n' => number_format_i18n( ceil( $total / $per_page ) ),
   385 			'total' => $total,
   486 			'total' => $total,
   386 			'time' => $time
   487 			'time' => $time
   394 //
   495 //
   395 
   496 
   396 /**
   497 /**
   397  * Ajax handler for adding a hierarchical term.
   498  * Ajax handler for adding a hierarchical term.
   398  *
   499  *
       
   500  * @access private
   399  * @since 3.1.0
   501  * @since 3.1.0
   400  */
   502  */
   401 function _wp_ajax_add_hierarchical_term() {
   503 function _wp_ajax_add_hierarchical_term() {
   402 	$action = $_POST['action'];
   504 	$action = $_POST['action'];
   403 	$taxonomy = get_taxonomy(substr($action, 4));
   505 	$taxonomy = get_taxonomy(substr($action, 4));
   418 	foreach ( $names as $cat_name ) {
   520 	foreach ( $names as $cat_name ) {
   419 		$cat_name = trim($cat_name);
   521 		$cat_name = trim($cat_name);
   420 		$category_nicename = sanitize_title($cat_name);
   522 		$category_nicename = sanitize_title($cat_name);
   421 		if ( '' === $category_nicename )
   523 		if ( '' === $category_nicename )
   422 			continue;
   524 			continue;
   423 		if ( !$cat_id = term_exists( $cat_name, $taxonomy->name, $parent ) )
   525 
   424 			$cat_id = wp_insert_term( $cat_name, $taxonomy->name, array( 'parent' => $parent ) );
   526 		$cat_id = wp_insert_term( $cat_name, $taxonomy->name, array( 'parent' => $parent ) );
   425 		if ( is_wp_error( $cat_id ) ) {
   527 		if ( ! $cat_id || is_wp_error( $cat_id ) ) {
   426 			continue;
   528 			continue;
   427 		} elseif ( is_array( $cat_id ) ) {
   529 		} else {
   428 			$cat_id = $cat_id['term_id'];
   530 			$cat_id = $cat_id['term_id'];
   429 		}
   531 		}
   430 		$checked_categories[] = $cat_id;
   532 		$checked_categories[] = $cat_id;
   431 		if ( $parent ) // Do these all at once in a second
   533 		if ( $parent ) // Do these all at once in a second
   432 			continue;
   534 			continue;
       
   535 
   433 		ob_start();
   536 		ob_start();
   434 			wp_terms_checklist( 0, array( 'taxonomy' => $taxonomy->name, 'descendants_and_self' => $cat_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids ));
   537 
   435 		$data = ob_get_contents();
   538 		wp_terms_checklist( 0, array( 'taxonomy' => $taxonomy->name, 'descendants_and_self' => $cat_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids ));
   436 		ob_end_clean();
   539 
       
   540 		$data = ob_get_clean();
       
   541 
   437 		$add = array(
   542 		$add = array(
   438 			'what' => $taxonomy->name,
   543 			'what' => $taxonomy->name,
   439 			'id' => $cat_id,
   544 			'id' => $cat_id,
   440 			'data' => str_replace( array("\n", "\t"), '', $data),
   545 			'data' => str_replace( array("\n", "\t"), '', $data),
   441 			'position' => -1
   546 			'position' => -1
   452 				break;
   557 				break;
   453 			$term_id = $parent->term_id;
   558 			$term_id = $parent->term_id;
   454 		}
   559 		}
   455 
   560 
   456 		ob_start();
   561 		ob_start();
   457 			wp_terms_checklist( 0, array('taxonomy' => $taxonomy->name, 'descendants_and_self' => $term_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids));
   562 
   458 		$data = ob_get_contents();
   563 		wp_terms_checklist( 0, array('taxonomy' => $taxonomy->name, 'descendants_and_self' => $term_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids));
   459 		ob_end_clean();
   564 
       
   565 		$data = ob_get_clean();
       
   566 
   460 		$add = array(
   567 		$add = array(
   461 			'what' => $taxonomy->name,
   568 			'what' => $taxonomy->name,
   462 			'id' => $term_id,
   569 			'id' => $term_id,
   463 			'data' => str_replace( array("\n", "\t"), '', $data),
   570 			'data' => str_replace( array("\n", "\t"), '', $data),
   464 			'position' => -1
   571 			'position' => -1
   465 		);
   572 		);
   466 	}
   573 	}
   467 
   574 
   468 	ob_start();
   575 	ob_start();
   469 		wp_dropdown_categories( array(
   576 
   470 			'taxonomy' => $taxonomy->name, 'hide_empty' => 0, 'name' => 'new'.$taxonomy->name.'_parent', 'orderby' => 'name',
   577 	wp_dropdown_categories( array(
   471 			'hierarchical' => 1, 'show_option_none' => '&mdash; '.$taxonomy->labels->parent_item.' &mdash;'
   578 		'taxonomy' => $taxonomy->name, 'hide_empty' => 0, 'name' => 'new'.$taxonomy->name.'_parent', 'orderby' => 'name',
   472 		) );
   579 		'hierarchical' => 1, 'show_option_none' => '&mdash; '.$taxonomy->labels->parent_item.' &mdash;'
   473 	$sup = ob_get_contents();
   580 	) );
   474 	ob_end_clean();
   581 
       
   582 	$sup = ob_get_clean();
       
   583 
   475 	$add['supplemental'] = array( 'newcat_parent' => $sup );
   584 	$add['supplemental'] = array( 'newcat_parent' => $sup );
   476 
   585 
   477 	$x = new WP_Ajax_Response( $add );
   586 	$x = new WP_Ajax_Response( $add );
   478 	$x->send();
   587 	$x->send();
   479 }
   588 }
   490 		wp_die( time() );
   599 		wp_die( time() );
   491 	if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) )
   600 	if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) )
   492 		wp_die( -1 );
   601 		wp_die( -1 );
   493 
   602 
   494 	check_ajax_referer( "delete-comment_$id" );
   603 	check_ajax_referer( "delete-comment_$id" );
   495 	$status = wp_get_comment_status( $comment->comment_ID );
   604 	$status = wp_get_comment_status( $comment );
   496 
   605 
   497 	$delta = -1;
   606 	$delta = -1;
   498 	if ( isset($_POST['trash']) && 1 == $_POST['trash'] ) {
   607 	if ( isset($_POST['trash']) && 1 == $_POST['trash'] ) {
   499 		if ( 'trash' == $status )
   608 		if ( 'trash' == $status )
   500 			wp_die( time() );
   609 			wp_die( time() );
   501 		$r = wp_trash_comment( $comment->comment_ID );
   610 		$r = wp_trash_comment( $comment );
   502 	} elseif ( isset($_POST['untrash']) && 1 == $_POST['untrash'] ) {
   611 	} elseif ( isset($_POST['untrash']) && 1 == $_POST['untrash'] ) {
   503 		if ( 'trash' != $status )
   612 		if ( 'trash' != $status )
   504 			wp_die( time() );
   613 			wp_die( time() );
   505 		$r = wp_untrash_comment( $comment->comment_ID );
   614 		$r = wp_untrash_comment( $comment );
   506 		if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'trash' ) // undo trash, not in trash
   615 		if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'trash' ) // undo trash, not in trash
   507 			$delta = 1;
   616 			$delta = 1;
   508 	} elseif ( isset($_POST['spam']) && 1 == $_POST['spam'] ) {
   617 	} elseif ( isset($_POST['spam']) && 1 == $_POST['spam'] ) {
   509 		if ( 'spam' == $status )
   618 		if ( 'spam' == $status )
   510 			wp_die( time() );
   619 			wp_die( time() );
   511 		$r = wp_spam_comment( $comment->comment_ID );
   620 		$r = wp_spam_comment( $comment );
   512 	} elseif ( isset($_POST['unspam']) && 1 == $_POST['unspam'] ) {
   621 	} elseif ( isset($_POST['unspam']) && 1 == $_POST['unspam'] ) {
   513 		if ( 'spam' != $status )
   622 		if ( 'spam' != $status )
   514 			wp_die( time() );
   623 			wp_die( time() );
   515 		$r = wp_unspam_comment( $comment->comment_ID );
   624 		$r = wp_unspam_comment( $comment );
   516 		if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'spam' ) // undo spam, not in spam
   625 		if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'spam' ) // undo spam, not in spam
   517 			$delta = 1;
   626 			$delta = 1;
   518 	} elseif ( isset($_POST['delete']) && 1 == $_POST['delete'] ) {
   627 	} elseif ( isset($_POST['delete']) && 1 == $_POST['delete'] ) {
   519 		$r = wp_delete_comment( $comment->comment_ID );
   628 		$r = wp_delete_comment( $comment );
   520 	} else {
   629 	} else {
   521 		wp_die( -1 );
   630 		wp_die( -1 );
   522 	}
   631 	}
   523 
   632 
   524 	if ( $r ) // Decide if we need to send back '1' or a more complicated response including page links and comment counts
   633 	if ( $r ) // Decide if we need to send back '1' or a more complicated response including page links and comment counts
   533  */
   642  */
   534 function wp_ajax_delete_tag() {
   643 function wp_ajax_delete_tag() {
   535 	$tag_id = (int) $_POST['tag_ID'];
   644 	$tag_id = (int) $_POST['tag_ID'];
   536 	check_ajax_referer( "delete-tag_$tag_id" );
   645 	check_ajax_referer( "delete-tag_$tag_id" );
   537 
   646 
       
   647 	if ( ! current_user_can( 'delete_term', $tag_id ) ) {
       
   648 		wp_die( -1 );
       
   649 	}
       
   650 
   538 	$taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
   651 	$taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
   539 	$tax = get_taxonomy($taxonomy);
       
   540 
       
   541 	if ( !current_user_can( $tax->cap->delete_terms ) )
       
   542 		wp_die( -1 );
       
   543 
       
   544 	$tag = get_term( $tag_id, $taxonomy );
   652 	$tag = get_term( $tag_id, $taxonomy );
   545 	if ( !$tag || is_wp_error( $tag ) )
   653 	if ( !$tag || is_wp_error( $tag ) )
   546 		wp_die( 1 );
   654 		wp_die( 1 );
   547 
   655 
   548 	if ( wp_delete_term($tag_id, $taxonomy))
   656 	if ( wp_delete_term($tag_id, $taxonomy))
   658 	if ( empty( $action ) )
   766 	if ( empty( $action ) )
   659 		$action = 'untrash-post';
   767 		$action = 'untrash-post';
   660 	wp_ajax_trash_post( $action );
   768 	wp_ajax_trash_post( $action );
   661 }
   769 }
   662 
   770 
       
   771 /**
       
   772  * @since 3.1.0
       
   773  *
       
   774  * @param string $action
       
   775  */
   663 function wp_ajax_delete_page( $action ) {
   776 function wp_ajax_delete_page( $action ) {
   664 	if ( empty( $action ) )
   777 	if ( empty( $action ) )
   665 		$action = 'delete-page';
   778 		$action = 'delete-page';
   666 	$id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
   779 	$id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
   667 
   780 
   695 	}
   808 	}
   696 
   809 
   697 	if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) && ! current_user_can( 'moderate_comments' ) )
   810 	if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) && ! current_user_can( 'moderate_comments' ) )
   698 		wp_die( -1 );
   811 		wp_die( -1 );
   699 
   812 
   700 	$current = wp_get_comment_status( $comment->comment_ID );
   813 	$current = wp_get_comment_status( $comment );
   701 	if ( isset( $_POST['new'] ) && $_POST['new'] == $current )
   814 	if ( isset( $_POST['new'] ) && $_POST['new'] == $current )
   702 		wp_die( time() );
   815 		wp_die( time() );
   703 
   816 
   704 	check_ajax_referer( "approve-comment_$id" );
   817 	check_ajax_referer( "approve-comment_$id" );
   705 	if ( in_array( $current, array( 'unapproved', 'spam' ) ) )
   818 	if ( in_array( $current, array( 'unapproved', 'spam' ) ) ) {
   706 		$result = wp_set_comment_status( $comment->comment_ID, 'approve', true );
   819 		$result = wp_set_comment_status( $comment, 'approve', true );
   707 	else
   820 	} else {
   708 		$result = wp_set_comment_status( $comment->comment_ID, 'hold', true );
   821 		$result = wp_set_comment_status( $comment, 'hold', true );
       
   822 	}
   709 
   823 
   710 	if ( is_wp_error($result) ) {
   824 	if ( is_wp_error($result) ) {
   711 		$x = new WP_Ajax_Response( array(
   825 		$x = new WP_Ajax_Response( array(
   712 			'what' => 'comment',
   826 			'what' => 'comment',
   713 			'id' => $result
   827 			'id' => $result
   719 	_wp_ajax_delete_comment_response( $comment->comment_ID );
   833 	_wp_ajax_delete_comment_response( $comment->comment_ID );
   720 	wp_die( 0 );
   834 	wp_die( 0 );
   721 }
   835 }
   722 
   836 
   723 /**
   837 /**
   724  * Ajax handler for deleting a link category.
   838  * Ajax handler for adding a link category.
   725  *
   839  *
   726  * @since 3.1.0
   840  * @since 3.1.0
   727  *
   841  *
   728  * @param string $action Action to perform.
   842  * @param string $action Action to perform.
   729  */
   843  */
   730 function wp_ajax_add_link_category( $action ) {
   844 function wp_ajax_add_link_category( $action ) {
   731 	if ( empty( $action ) )
   845 	if ( empty( $action ) )
   732 		$action = 'add-link-category';
   846 		$action = 'add-link-category';
   733 	check_ajax_referer( $action );
   847 	check_ajax_referer( $action );
   734 	if ( !current_user_can( 'manage_categories' ) )
   848 	$tax = get_taxonomy( 'link_category' );
       
   849 	if ( ! current_user_can( $tax->cap->manage_terms ) ) {
   735 		wp_die( -1 );
   850 		wp_die( -1 );
       
   851 	}
   736 	$names = explode(',', wp_unslash( $_POST['newcat'] ) );
   852 	$names = explode(',', wp_unslash( $_POST['newcat'] ) );
   737 	$x = new WP_Ajax_Response();
   853 	$x = new WP_Ajax_Response();
   738 	foreach ( $names as $cat_name ) {
   854 	foreach ( $names as $cat_name ) {
   739 		$cat_name = trim($cat_name);
   855 		$cat_name = trim($cat_name);
   740 		$slug = sanitize_title($cat_name);
   856 		$slug = sanitize_title($cat_name);
   741 		if ( '' === $slug )
   857 		if ( '' === $slug )
   742 			continue;
   858 			continue;
   743 		if ( !$cat_id = term_exists( $cat_name, 'link_category' ) )
   859 
   744 			$cat_id = wp_insert_term( $cat_name, 'link_category' );
   860 		$cat_id = wp_insert_term( $cat_name, 'link_category' );
   745 		if ( is_wp_error( $cat_id ) ) {
   861 		if ( ! $cat_id || is_wp_error( $cat_id ) ) {
   746 			continue;
   862 			continue;
   747 		} elseif ( is_array( $cat_id ) ) {
   863 		} else {
   748 			$cat_id = $cat_id['term_id'];
   864 			$cat_id = $cat_id['term_id'];
   749 		}
   865 		}
   750 		$cat_name = esc_html( $cat_name );
   866 		$cat_name = esc_html( $cat_name );
   751 		$x->add( array(
   867 		$x->add( array(
   752 			'what' => 'link-category',
   868 			'what' => 'link-category',
   762  * Ajax handler to add a tag.
   878  * Ajax handler to add a tag.
   763  *
   879  *
   764  * @since 3.1.0
   880  * @since 3.1.0
   765  */
   881  */
   766 function wp_ajax_add_tag() {
   882 function wp_ajax_add_tag() {
   767 	global $wp_list_table;
       
   768 
       
   769 	check_ajax_referer( 'add-tag', '_wpnonce_add-tag' );
   883 	check_ajax_referer( 'add-tag', '_wpnonce_add-tag' );
   770 	$taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
   884 	$taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
   771 	$tax = get_taxonomy($taxonomy);
   885 	$tax = get_taxonomy($taxonomy);
   772 
   886 
   773 	if ( !current_user_can( $tax->cap->edit_terms ) )
   887 	if ( !current_user_can( $tax->cap->edit_terms ) )
   804 	$parents = ob_get_clean();
   918 	$parents = ob_get_clean();
   805 
   919 
   806 	$x->add( array(
   920 	$x->add( array(
   807 		'what' => 'taxonomy',
   921 		'what' => 'taxonomy',
   808 		'supplemental' => compact('parents', 'noparents')
   922 		'supplemental' => compact('parents', 'noparents')
   809 		) );
   923 	) );
   810 	$x->add( array(
   924 	$x->add( array(
   811 		'what' => 'term',
   925 		'what' => 'term',
   812 		'position' => $level,
   926 		'position' => $level,
   813 		'supplemental' => (array) $tag
   927 		'supplemental' => (array) $tag
   814 		) );
   928 	) );
   815 	$x->send();
   929 	$x->send();
   816 }
   930 }
   817 
   931 
   818 /**
   932 /**
   819  * Ajax handler for getting a tagcloud.
   933  * Ajax handler for getting a tagcloud.
   847 		$tags[ $key ]->link = '#';
   961 		$tags[ $key ]->link = '#';
   848 		$tags[ $key ]->id = $tag->term_id;
   962 		$tags[ $key ]->id = $tag->term_id;
   849 	}
   963 	}
   850 
   964 
   851 	// We need raw tag names here, so don't filter the output
   965 	// We need raw tag names here, so don't filter the output
   852 	$return = wp_generate_tag_cloud( $tags, array('filter' => 0) );
   966 	$return = wp_generate_tag_cloud( $tags, array( 'filter' => 0, 'format' => 'list' ) );
   853 
   967 
   854 	if ( empty($return) )
   968 	if ( empty($return) )
   855 		wp_die( 0 );
   969 		wp_die( 0 );
   856 
   970 
   857 	echo $return;
   971 	echo $return;
   862 /**
   976 /**
   863  * Ajax handler for getting comments.
   977  * Ajax handler for getting comments.
   864  *
   978  *
   865  * @since 3.1.0
   979  * @since 3.1.0
   866  *
   980  *
       
   981  * @global int           $post_id
       
   982  *
   867  * @param string $action Action to perform.
   983  * @param string $action Action to perform.
   868  */
   984  */
   869 function wp_ajax_get_comments( $action ) {
   985 function wp_ajax_get_comments( $action ) {
   870 	global $wp_list_table, $post_id;
   986 	global $post_id;
   871 	if ( empty( $action ) )
   987 	if ( empty( $action ) ) {
   872 		$action = 'get-comments';
   988 		$action = 'get-comments';
   873 
   989 	}
   874 	check_ajax_referer( $action );
   990 	check_ajax_referer( $action );
   875 
   991 
   876 	if ( empty( $post_id ) && ! empty( $_REQUEST['p'] ) ) {
   992 	if ( empty( $post_id ) && ! empty( $_REQUEST['p'] ) ) {
   877 		$id = absint( $_REQUEST['p'] );
   993 		$id = absint( $_REQUEST['p'] );
   878 		if ( ! empty( $id ) )
   994 		if ( ! empty( $id ) ) {
   879 			$post_id = $id;
   995 			$post_id = $id;
   880 	}
   996 		}
   881 
   997 	}
   882 	if ( empty( $post_id ) )
   998 
       
   999 	if ( empty( $post_id ) ) {
   883 		wp_die( -1 );
  1000 		wp_die( -1 );
       
  1001 	}
   884 
  1002 
   885 	$wp_list_table = _get_list_table( 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
  1003 	$wp_list_table = _get_list_table( 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
   886 
  1004 
   887 	if ( ! current_user_can( 'edit_post', $post_id ) )
  1005 	if ( ! current_user_can( 'edit_post', $post_id ) ) {
   888 		wp_die( -1 );
  1006 		wp_die( -1 );
       
  1007 	}
   889 
  1008 
   890 	$wp_list_table->prepare_items();
  1009 	$wp_list_table->prepare_items();
   891 
  1010 
   892 	if ( !$wp_list_table->has_items() )
  1011 	if ( ! $wp_list_table->has_items() ) {
   893 		wp_die( 1 );
  1012 		wp_die( 1 );
       
  1013 	}
   894 
  1014 
   895 	$x = new WP_Ajax_Response();
  1015 	$x = new WP_Ajax_Response();
   896 	ob_start();
  1016 	ob_start();
   897 	foreach ( $wp_list_table->items as $comment ) {
  1017 	foreach ( $wp_list_table->items as $comment ) {
   898 		if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) )
  1018 		if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) && 0 === $comment->comment_approved )
   899 			continue;
  1019 			continue;
   900 		get_comment( $comment );
  1020 		get_comment( $comment );
   901 		$wp_list_table->single_row( $comment );
  1021 		$wp_list_table->single_row( $comment );
   902 	}
  1022 	}
   903 	$comment_list_item = ob_get_contents();
  1023 	$comment_list_item = ob_get_clean();
   904 	ob_end_clean();
       
   905 
  1024 
   906 	$x->add( array(
  1025 	$x->add( array(
   907 		'what' => 'comments',
  1026 		'what' => 'comments',
   908 		'data' => $comment_list_item
  1027 		'data' => $comment_list_item
   909 	) );
  1028 	) );
   916  * @since 3.1.0
  1035  * @since 3.1.0
   917  *
  1036  *
   918  * @param string $action Action to perform.
  1037  * @param string $action Action to perform.
   919  */
  1038  */
   920 function wp_ajax_replyto_comment( $action ) {
  1039 function wp_ajax_replyto_comment( $action ) {
   921 	global $wp_list_table;
       
   922 	if ( empty( $action ) )
  1040 	if ( empty( $action ) )
   923 		$action = 'replyto-comment';
  1041 		$action = 'replyto-comment';
   924 
  1042 
   925 	check_ajax_referer( $action, '_ajax_nonce-replyto-comment' );
  1043 	check_ajax_referer( $action, '_ajax_nonce-replyto-comment' );
   926 
  1044 
   970 	// Automatically approve parent comment.
  1088 	// Automatically approve parent comment.
   971 	if ( !empty($_POST['approve_parent']) ) {
  1089 	if ( !empty($_POST['approve_parent']) ) {
   972 		$parent = get_comment( $comment_parent );
  1090 		$parent = get_comment( $comment_parent );
   973 
  1091 
   974 		if ( $parent && $parent->comment_approved === '0' && $parent->comment_post_ID == $comment_post_ID ) {
  1092 		if ( $parent && $parent->comment_approved === '0' && $parent->comment_post_ID == $comment_post_ID ) {
   975 			if ( wp_set_comment_status( $parent->comment_ID, 'approve' ) )
  1093 			if ( ! current_user_can( 'edit_comment', $parent->comment_ID ) ) {
       
  1094 				wp_die( -1 );
       
  1095 			}
       
  1096 
       
  1097 			if ( wp_set_comment_status( $parent, 'approve' ) )
   976 				$comment_auto_approved = true;
  1098 				$comment_auto_approved = true;
   977 		}
  1099 		}
   978 	}
  1100 	}
   979 
  1101 
   980 	$comment_id = wp_new_comment( $commentdata );
  1102 	$comment_id = wp_new_comment( $commentdata );
       
  1103 
       
  1104 	if ( is_wp_error( $comment_id ) ) {
       
  1105 		wp_die( $comment_id->get_error_message() );
       
  1106 	}
       
  1107 
   981 	$comment = get_comment($comment_id);
  1108 	$comment = get_comment($comment_id);
   982 	if ( ! $comment ) wp_die( 1 );
  1109 	if ( ! $comment ) wp_die( 1 );
   983 
  1110 
   984 	$position = ( isset($_POST['position']) && (int) $_POST['position'] ) ? (int) $_POST['position'] : '-1';
  1111 	$position = ( isset($_POST['position']) && (int) $_POST['position'] ) ? (int) $_POST['position'] : '-1';
   985 
  1112 
  1002 		'id' => $comment->comment_ID,
  1129 		'id' => $comment->comment_ID,
  1003 		'data' => $comment_list_item,
  1130 		'data' => $comment_list_item,
  1004 		'position' => $position
  1131 		'position' => $position
  1005 	);
  1132 	);
  1006 
  1133 
  1007 	if ( $comment_auto_approved )
  1134 	$counts = wp_count_comments();
  1008 		$response['supplemental'] = array( 'parent_approved' => $parent->comment_ID );
  1135 	$response['supplemental'] = array(
       
  1136 		'in_moderation' => $counts->moderated,
       
  1137 		'i18n_comments_text' => sprintf(
       
  1138 			_n( '%s Comment', '%s Comments', $counts->approved ),
       
  1139 			number_format_i18n( $counts->approved )
       
  1140 		),
       
  1141 		'i18n_moderation_text' => sprintf(
       
  1142 			_nx( '%s in moderation', '%s in moderation', $counts->moderated, 'comments' ),
       
  1143 			number_format_i18n( $counts->moderated )
       
  1144 		)
       
  1145 	);
       
  1146 
       
  1147 	if ( $comment_auto_approved ) {
       
  1148 		$response['supplemental']['parent_approved'] = $parent->comment_ID;
       
  1149 		$response['supplemental']['parent_post_id'] = $parent->comment_post_ID;
       
  1150 	}
  1009 
  1151 
  1010 	$x = new WP_Ajax_Response();
  1152 	$x = new WP_Ajax_Response();
  1011 	$x->add( $response );
  1153 	$x->add( $response );
  1012 	$x->send();
  1154 	$x->send();
  1013 }
  1155 }
  1016  * Ajax handler for editing a comment.
  1158  * Ajax handler for editing a comment.
  1017  *
  1159  *
  1018  * @since 3.1.0
  1160  * @since 3.1.0
  1019  */
  1161  */
  1020 function wp_ajax_edit_comment() {
  1162 function wp_ajax_edit_comment() {
  1021 	global $wp_list_table;
       
  1022 
       
  1023 	check_ajax_referer( 'replyto-comment', '_ajax_nonce-replyto-comment' );
  1163 	check_ajax_referer( 'replyto-comment', '_ajax_nonce-replyto-comment' );
  1024 
  1164 
  1025 	$comment_id = (int) $_POST['comment_ID'];
  1165 	$comment_id = (int) $_POST['comment_ID'];
  1026 	if ( ! current_user_can( 'edit_comment', $comment_id ) )
  1166 	if ( ! current_user_can( 'edit_comment', $comment_id ) )
  1027 		wp_die( -1 );
  1167 		wp_die( -1 );
  1083 			switch( $menu_item_data['menu-item-type'] ) {
  1223 			switch( $menu_item_data['menu-item-type'] ) {
  1084 				case 'post_type' :
  1224 				case 'post_type' :
  1085 					$_object = get_post( $menu_item_data['menu-item-object-id'] );
  1225 					$_object = get_post( $menu_item_data['menu-item-object-id'] );
  1086 				break;
  1226 				break;
  1087 
  1227 
       
  1228 				case 'post_type_archive' :
       
  1229 					$_object = get_post_type_object( $menu_item_data['menu-item-object'] );
       
  1230 				break;
       
  1231 
  1088 				case 'taxonomy' :
  1232 				case 'taxonomy' :
  1089 					$_object = get_term( $menu_item_data['menu-item-object-id'], $menu_item_data['menu-item-object'] );
  1233 					$_object = get_term( $menu_item_data['menu-item-object-id'], $menu_item_data['menu-item-object'] );
  1090 				break;
  1234 				break;
  1091 			}
  1235 			}
  1092 
  1236 
  1151 		if ( isset($_POST['metakeyselect']) && '#NONE#' == $_POST['metakeyselect'] && empty($_POST['metakeyinput']) )
  1295 		if ( isset($_POST['metakeyselect']) && '#NONE#' == $_POST['metakeyselect'] && empty($_POST['metakeyinput']) )
  1152 			wp_die( 1 );
  1296 			wp_die( 1 );
  1153 
  1297 
  1154 		// If the post is an autodraft, save the post as a draft and then attempt to save the meta.
  1298 		// If the post is an autodraft, save the post as a draft and then attempt to save the meta.
  1155 		if ( $post->post_status == 'auto-draft' ) {
  1299 		if ( $post->post_status == 'auto-draft' ) {
  1156 			$save_POST = $_POST; // Backup $_POST
  1300 			$post_data = array();
  1157 			$_POST = array(); // Make it empty for edit_post()
  1301 			$post_data['action'] = 'draft'; // Warning fix
  1158 			$_POST['action'] = 'draft'; // Warning fix
  1302 			$post_data['post_ID'] = $pid;
  1159 			$_POST['post_ID'] = $pid;
  1303 			$post_data['post_type'] = $post->post_type;
  1160 			$_POST['post_type'] = $post->post_type;
  1304 			$post_data['post_status'] = 'draft';
  1161 			$_POST['post_status'] = 'draft';
       
  1162 			$now = current_time('timestamp', 1);
  1305 			$now = current_time('timestamp', 1);
  1163 			$_POST['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), date( get_option( 'date_format' ), $now ), date( get_option( 'time_format' ), $now ) );
  1306 			/* translators: 1: Post creation date, 2: Post creation time */
  1164 
  1307 			$post_data['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), date( __( 'F j, Y' ), $now ), date( __( 'g:i a' ), $now ) );
  1165 			if ( $pid = edit_post() ) {
  1308 
       
  1309 			$pid = edit_post( $post_data );
       
  1310 			if ( $pid ) {
  1166 				if ( is_wp_error( $pid ) ) {
  1311 				if ( is_wp_error( $pid ) ) {
  1167 					$x = new WP_Ajax_Response( array(
  1312 					$x = new WP_Ajax_Response( array(
  1168 						'what' => 'meta',
  1313 						'what' => 'meta',
  1169 						'data' => $pid
  1314 						'data' => $pid
  1170 					) );
  1315 					) );
  1171 					$x->send();
  1316 					$x->send();
  1172 				}
  1317 				}
  1173 				$_POST = $save_POST; // Now we can restore original $_POST again
  1318 
  1174 				if ( !$mid = add_meta( $pid ) )
  1319 				if ( !$mid = add_meta( $pid ) )
  1175 					wp_die( __( 'Please provide a custom field value.' ) );
  1320 					wp_die( __( 'Please provide a custom field value.' ) );
  1176 			} else {
  1321 			} else {
  1177 				wp_die( 0 );
  1322 				wp_die( 0 );
  1178 			}
  1323 			}
  1230  * @since 3.1.0
  1375  * @since 3.1.0
  1231  *
  1376  *
  1232  * @param string $action Action to perform.
  1377  * @param string $action Action to perform.
  1233  */
  1378  */
  1234 function wp_ajax_add_user( $action ) {
  1379 function wp_ajax_add_user( $action ) {
  1235 	global $wp_list_table;
  1380 	if ( empty( $action ) ) {
  1236 	if ( empty( $action ) )
       
  1237 		$action = 'add-user';
  1381 		$action = 'add-user';
       
  1382 	}
  1238 
  1383 
  1239 	check_ajax_referer( $action );
  1384 	check_ajax_referer( $action );
  1240 	if ( ! current_user_can('create_users') )
  1385 	if ( ! current_user_can('create_users') )
  1241 		wp_die( -1 );
  1386 		wp_die( -1 );
  1242 	if ( ! $user_id = edit_user() ) {
  1387 	if ( ! $user_id = edit_user() ) {
  1257 	$x = new WP_Ajax_Response( array(
  1402 	$x = new WP_Ajax_Response( array(
  1258 		'what' => 'user',
  1403 		'what' => 'user',
  1259 		'id' => $user_id,
  1404 		'id' => $user_id,
  1260 		'data' => $wp_list_table->single_row( $user_object, '', $role ),
  1405 		'data' => $wp_list_table->single_row( $user_object, '', $role ),
  1261 		'supplemental' => array(
  1406 		'supplemental' => array(
  1262 			'show-link' => sprintf(__( 'User <a href="#%s">%s</a> added' ), "user-$user_id", $user_object->user_login),
  1407 			'show-link' => sprintf(
       
  1408 				/* translators: %s: the new user */
       
  1409 				__( 'User %s added' ),
       
  1410 				'<a href="#user-' . $user_id . '">' . $user_object->user_login . '</a>'
       
  1411 			),
  1263 			'role' => $role,
  1412 			'role' => $role,
  1264 		)
  1413 		)
  1265 	) );
  1414 	) );
  1266 	$x->send();
  1415 	$x->send();
  1267 }
  1416 }
  1303  *
  1452  *
  1304  * @since 3.1.0
  1453  * @since 3.1.0
  1305  */
  1454  */
  1306 function wp_ajax_hidden_columns() {
  1455 function wp_ajax_hidden_columns() {
  1307 	check_ajax_referer( 'screen-options-nonce', 'screenoptionnonce' );
  1456 	check_ajax_referer( 'screen-options-nonce', 'screenoptionnonce' );
  1308 	$hidden = explode( ',', isset( $_POST['hidden'] ) ? $_POST['hidden'] : '' );
       
  1309 	$page = isset( $_POST['page'] ) ? $_POST['page'] : '';
  1457 	$page = isset( $_POST['page'] ) ? $_POST['page'] : '';
  1310 
  1458 
  1311 	if ( $page != sanitize_key( $page ) )
  1459 	if ( $page != sanitize_key( $page ) )
  1312 		wp_die( 0 );
  1460 		wp_die( 0 );
  1313 
  1461 
  1314 	if ( ! $user = wp_get_current_user() )
  1462 	if ( ! $user = wp_get_current_user() )
  1315 		wp_die( -1 );
  1463 		wp_die( -1 );
  1316 
  1464 
  1317 	if ( is_array($hidden) )
  1465 	$hidden = ! empty( $_POST['hidden'] ) ? explode( ',', $_POST['hidden'] ) : array();
  1318 		update_user_option($user->ID, "manage{$page}columnshidden", $hidden, true);
  1466 	update_user_option( $user->ID, "manage{$page}columnshidden", $hidden, true );
  1319 
  1467 
  1320 	wp_die( 1 );
  1468 	wp_die( 1 );
  1321 }
  1469 }
  1322 
  1470 
  1323 /**
  1471 /**
  1330 
  1478 
  1331 	if ( ! current_user_can( 'edit_theme_options' ) )
  1479 	if ( ! current_user_can( 'edit_theme_options' ) )
  1332 		wp_die( -1 );
  1480 		wp_die( -1 );
  1333 
  1481 
  1334 	update_user_meta( get_current_user_id(), 'show_welcome_panel', empty( $_POST['visible'] ) ? 0 : 1 );
  1482 	update_user_meta( get_current_user_id(), 'show_welcome_panel', empty( $_POST['visible'] ) ? 0 : 1 );
       
  1483 
       
  1484 	wp_die( 1 );
       
  1485 }
       
  1486 
       
  1487 /**
       
  1488  * Ajax handler for updating whether to display the Try Gutenberg panel.
       
  1489  *
       
  1490  * @since 4.9.8
       
  1491  */
       
  1492 function wp_ajax_update_try_gutenberg_panel() {
       
  1493 	check_ajax_referer( 'try-gutenberg-panel-nonce', 'trygutenbergpanelnonce' );
       
  1494 
       
  1495 	update_user_meta( get_current_user_id(), 'show_try_gutenberg_panel', empty( $_POST['visible'] ) ? 0 : 1 );
  1335 
  1496 
  1336 	wp_die( 1 );
  1497 	wp_die( 1 );
  1337 }
  1498 }
  1338 
  1499 
  1339 /**
  1500 /**
  1392 function wp_ajax_wp_link_ajax() {
  1553 function wp_ajax_wp_link_ajax() {
  1393 	check_ajax_referer( 'internal-linking', '_ajax_linking_nonce' );
  1554 	check_ajax_referer( 'internal-linking', '_ajax_linking_nonce' );
  1394 
  1555 
  1395 	$args = array();
  1556 	$args = array();
  1396 
  1557 
  1397 	if ( isset( $_POST['search'] ) )
  1558 	if ( isset( $_POST['search'] ) ) {
  1398 		$args['s'] = wp_unslash( $_POST['search'] );
  1559 		$args['s'] = wp_unslash( $_POST['search'] );
       
  1560 	}
       
  1561 
       
  1562 	if ( isset( $_POST['term'] ) ) {
       
  1563 		$args['s'] = wp_unslash( $_POST['term'] );
       
  1564 	}
       
  1565 
  1399 	$args['pagenum'] = ! empty( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
  1566 	$args['pagenum'] = ! empty( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
  1400 
  1567 
  1401 	require(ABSPATH . WPINC . '/class-wp-editor.php');
  1568 	if ( ! class_exists( '_WP_Editors', false ) ) {
       
  1569 		require( ABSPATH . WPINC . '/class-wp-editor.php' );
       
  1570 	}
       
  1571 
  1402 	$results = _WP_Editors::wp_link_query( $args );
  1572 	$results = _WP_Editors::wp_link_query( $args );
  1403 
  1573 
  1404 	if ( ! isset( $results ) )
  1574 	if ( ! isset( $results ) )
  1405 		wp_die( 0 );
  1575 		wp_die( 0 );
  1406 
  1576 
  1477  * @since 3.1.0
  1647  * @since 3.1.0
  1478  */
  1648  */
  1479 function wp_ajax_get_permalink() {
  1649 function wp_ajax_get_permalink() {
  1480 	check_ajax_referer( 'getpermalink', 'getpermalinknonce' );
  1650 	check_ajax_referer( 'getpermalink', 'getpermalinknonce' );
  1481 	$post_id = isset($_POST['post_id'])? intval($_POST['post_id']) : 0;
  1651 	$post_id = isset($_POST['post_id'])? intval($_POST['post_id']) : 0;
  1482 	wp_die( add_query_arg( array( 'preview' => 'true' ), get_permalink( $post_id ) ) );
  1652 	wp_die( get_preview_post_link( $post_id ) );
  1483 }
  1653 }
  1484 
  1654 
  1485 /**
  1655 /**
  1486  * Ajax handler to retrieve a sample permalink.
  1656  * Ajax handler to retrieve a sample permalink.
  1487  *
  1657  *
  1497 
  1667 
  1498 /**
  1668 /**
  1499  * Ajax handler for Quick Edit saving a post from a list table.
  1669  * Ajax handler for Quick Edit saving a post from a list table.
  1500  *
  1670  *
  1501  * @since 3.1.0
  1671  * @since 3.1.0
       
  1672  *
       
  1673  * @global string $mode List table view mode.
  1502  */
  1674  */
  1503 function wp_ajax_inline_save() {
  1675 function wp_ajax_inline_save() {
  1504 	global $wp_list_table;
  1676 	global $mode;
  1505 
  1677 
  1506 	check_ajax_referer( 'inlineeditnonce', '_inline_edit' );
  1678 	check_ajax_referer( 'inlineeditnonce', '_inline_edit' );
  1507 
  1679 
  1508 	if ( ! isset($_POST['post_ID']) || ! ( $post_ID = (int) $_POST['post_ID'] ) )
  1680 	if ( ! isset($_POST['post_ID']) || ! ( $post_ID = (int) $_POST['post_ID'] ) )
  1509 		wp_die();
  1681 		wp_die();
  1510 
  1682 
  1511 	if ( 'page' == $_POST['post_type'] ) {
  1683 	if ( 'page' == $_POST['post_type'] ) {
  1512 		if ( ! current_user_can( 'edit_page', $post_ID ) )
  1684 		if ( ! current_user_can( 'edit_page', $post_ID ) )
  1513 			wp_die( __( 'You are not allowed to edit this page.' ) );
  1685 			wp_die( __( 'Sorry, you are not allowed to edit this page.' ) );
  1514 	} else {
  1686 	} else {
  1515 		if ( ! current_user_can( 'edit_post', $post_ID ) )
  1687 		if ( ! current_user_can( 'edit_post', $post_ID ) )
  1516 			wp_die( __( 'You are not allowed to edit this post.' ) );
  1688 			wp_die( __( 'Sorry, you are not allowed to edit this post.' ) );
  1517 	}
  1689 	}
  1518 
  1690 
  1519 	if ( $last = wp_check_post_lock( $post_ID ) ) {
  1691 	if ( $last = wp_check_post_lock( $post_ID ) ) {
  1520 		$last_user = get_userdata( $last );
  1692 		$last_user = get_userdata( $last );
  1521 		$last_user_name = $last_user ? $last_user->display_name : __( 'Someone' );
  1693 		$last_user_name = $last_user ? $last_user->display_name : __( 'Someone' );
  1538 
  1710 
  1539 	if ( isset($data['post_parent']) )
  1711 	if ( isset($data['post_parent']) )
  1540 		$data['parent_id'] = $data['post_parent'];
  1712 		$data['parent_id'] = $data['post_parent'];
  1541 
  1713 
  1542 	// Status.
  1714 	// Status.
  1543 	if ( isset($data['keep_private']) && 'private' == $data['keep_private'] )
  1715 	if ( isset( $data['keep_private'] ) && 'private' == $data['keep_private'] ) {
       
  1716 		$data['visibility']  = 'private';
  1544 		$data['post_status'] = 'private';
  1717 		$data['post_status'] = 'private';
  1545 	else
  1718 	} else {
  1546 		$data['post_status'] = $data['_status'];
  1719 		$data['post_status'] = $data['_status'];
       
  1720 	}
  1547 
  1721 
  1548 	if ( empty($data['comment_status']) )
  1722 	if ( empty($data['comment_status']) )
  1549 		$data['comment_status'] = 'closed';
  1723 		$data['comment_status'] = 'closed';
  1550 	if ( empty($data['ping_status']) )
  1724 	if ( empty($data['ping_status']) )
  1551 		$data['ping_status'] = 'closed';
  1725 		$data['ping_status'] = 'closed';
  1570 	// Update the post.
  1744 	// Update the post.
  1571 	edit_post();
  1745 	edit_post();
  1572 
  1746 
  1573 	$wp_list_table = _get_list_table( 'WP_Posts_List_Table', array( 'screen' => $_POST['screen'] ) );
  1747 	$wp_list_table = _get_list_table( 'WP_Posts_List_Table', array( 'screen' => $_POST['screen'] ) );
  1574 
  1748 
       
  1749 	$mode = $_POST['post_view'] === 'excerpt' ? 'excerpt' : 'list';
       
  1750 
  1575 	$level = 0;
  1751 	$level = 0;
  1576 	$request_post = array( get_post( $_POST['post_ID'] ) );
  1752 	if ( is_post_type_hierarchical( $wp_list_table->screen->post_type ) ) {
  1577 	$parent = $request_post[0]->post_parent;
  1753 		$request_post = array( get_post( $_POST['post_ID'] ) );
  1578 
  1754 		$parent       = $request_post[0]->post_parent;
  1579 	while ( $parent > 0 ) {
  1755 
  1580 		$parent_post = get_post( $parent );
  1756 		while ( $parent > 0 ) {
  1581 		$parent = $parent_post->post_parent;
  1757 			$parent_post = get_post( $parent );
  1582 		$level++;
  1758 			$parent      = $parent_post->post_parent;
       
  1759 			$level++;
       
  1760 		}
  1583 	}
  1761 	}
  1584 
  1762 
  1585 	$wp_list_table->display_rows( array( get_post( $_POST['post_ID'] ) ), $level );
  1763 	$wp_list_table->display_rows( array( get_post( $_POST['post_ID'] ) ), $level );
  1586 
  1764 
  1587 	wp_die();
  1765 	wp_die();
  1591  * Ajax handler for quick edit saving for a term.
  1769  * Ajax handler for quick edit saving for a term.
  1592  *
  1770  *
  1593  * @since 3.1.0
  1771  * @since 3.1.0
  1594  */
  1772  */
  1595 function wp_ajax_inline_save_tax() {
  1773 function wp_ajax_inline_save_tax() {
  1596 	global $wp_list_table;
       
  1597 
       
  1598 	check_ajax_referer( 'taxinlineeditnonce', '_inline_edit' );
  1774 	check_ajax_referer( 'taxinlineeditnonce', '_inline_edit' );
  1599 
  1775 
  1600 	$taxonomy = sanitize_key( $_POST['taxonomy'] );
  1776 	$taxonomy = sanitize_key( $_POST['taxonomy'] );
  1601 	$tax = get_taxonomy( $taxonomy );
  1777 	$tax = get_taxonomy( $taxonomy );
  1602 	if ( ! $tax )
  1778 	if ( ! $tax )
  1603 		wp_die( 0 );
  1779 		wp_die( 0 );
  1604 
  1780 
  1605 	if ( ! current_user_can( $tax->cap->edit_terms ) )
  1781 	if ( ! isset( $_POST['tax_ID'] ) || ! ( $id = (int) $_POST['tax_ID'] ) ) {
  1606 		wp_die( -1 );
  1782 		wp_die( -1 );
       
  1783 	}
       
  1784 
       
  1785 	if ( ! current_user_can( 'edit_term', $id ) ) {
       
  1786 		wp_die( -1 );
       
  1787 	}
  1607 
  1788 
  1608 	$wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => 'edit-' . $taxonomy ) );
  1789 	$wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => 'edit-' . $taxonomy ) );
  1609 
       
  1610 	if ( ! isset($_POST['tax_ID']) || ! ( $id = (int) $_POST['tax_ID'] ) )
       
  1611 		wp_die( -1 );
       
  1612 
  1790 
  1613 	$tag = get_term( $id, $taxonomy );
  1791 	$tag = get_term( $id, $taxonomy );
  1614 	$_POST['description'] = $tag->description;
  1792 	$_POST['description'] = $tag->description;
  1615 
  1793 
  1616 	$updated = wp_update_term($id, $taxonomy, $_POST);
  1794 	$updated = wp_update_term($id, $taxonomy, $_POST);
  1688 		}
  1866 		}
  1689 
  1867 
  1690 		if ( '0000-00-00 00:00:00' == $post->post_date ) {
  1868 		if ( '0000-00-00 00:00:00' == $post->post_date ) {
  1691 			$time = '';
  1869 			$time = '';
  1692 		} else {
  1870 		} else {
  1693 			/* translators: date format in table columns, see http://php.net/date */
  1871 			/* translators: date format in table columns, see https://secure.php.net/date */
  1694 			$time = mysql2date(__('Y/m/d'), $post->post_date);
  1872 			$time = mysql2date(__('Y/m/d'), $post->post_date);
  1695 		}
  1873 		}
  1696 
  1874 
  1697 		$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>';
  1875 		$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>';
  1698 		$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";
  1876 		$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";
  1717 	unset( $_POST['savewidgets'], $_POST['action'] );
  1895 	unset( $_POST['savewidgets'], $_POST['action'] );
  1718 
  1896 
  1719 	// Save widgets order for all sidebars.
  1897 	// Save widgets order for all sidebars.
  1720 	if ( is_array($_POST['sidebars']) ) {
  1898 	if ( is_array($_POST['sidebars']) ) {
  1721 		$sidebars = array();
  1899 		$sidebars = array();
  1722 		foreach ( $_POST['sidebars'] as $key => $val ) {
  1900 		foreach ( wp_unslash( $_POST['sidebars'] ) as $key => $val ) {
  1723 			$sb = array();
  1901 			$sb = array();
  1724 			if ( !empty($val) ) {
  1902 			if ( !empty($val) ) {
  1725 				$val = explode(',', $val);
  1903 				$val = explode(',', $val);
  1726 				foreach ( $val as $k => $v ) {
  1904 				foreach ( $val as $k => $v ) {
  1727 					if ( strpos($v, 'widget-') === false )
  1905 					if ( strpos($v, 'widget-') === false )
  1741 
  1919 
  1742 /**
  1920 /**
  1743  * Ajax handler for saving a widget.
  1921  * Ajax handler for saving a widget.
  1744  *
  1922  *
  1745  * @since 3.1.0
  1923  * @since 3.1.0
       
  1924  *
       
  1925  * @global array $wp_registered_widgets
       
  1926  * @global array $wp_registered_widget_controls
       
  1927  * @global array $wp_registered_widget_updates
  1746  */
  1928  */
  1747 function wp_ajax_save_widget() {
  1929 function wp_ajax_save_widget() {
  1748 	global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
  1930 	global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
  1749 
  1931 
  1750 	check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' );
  1932 	check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' );
  1769 	do_action( 'widgets.php' );
  1951 	do_action( 'widgets.php' );
  1770 
  1952 
  1771 	/** This action is documented in wp-admin/widgets.php */
  1953 	/** This action is documented in wp-admin/widgets.php */
  1772 	do_action( 'sidebar_admin_setup' );
  1954 	do_action( 'sidebar_admin_setup' );
  1773 
  1955 
  1774 	$id_base = $_POST['id_base'];
  1956 	$id_base = wp_unslash( $_POST['id_base'] );
  1775 	$widget_id = $_POST['widget-id'];
  1957 	$widget_id = wp_unslash( $_POST['widget-id'] );
  1776 	$sidebar_id = $_POST['sidebar'];
  1958 	$sidebar_id = $_POST['sidebar'];
  1777 	$multi_number = !empty($_POST['multi_number']) ? (int) $_POST['multi_number'] : 0;
  1959 	$multi_number = !empty($_POST['multi_number']) ? (int) $_POST['multi_number'] : 0;
  1778 	$settings = isset($_POST['widget-' . $id_base]) && is_array($_POST['widget-' . $id_base]) ? $_POST['widget-' . $id_base] : false;
  1960 	$settings = isset($_POST['widget-' . $id_base]) && is_array($_POST['widget-' . $id_base]) ? $_POST['widget-' . $id_base] : false;
  1779 	$error = '<p>' . __('An error has occurred. Please reload the page and try again.') . '</p>';
  1961 	$error = '<p>' . __('An error has occurred. Please reload the page and try again.') . '</p>';
  1780 
  1962 
  1787 		if ( !isset($wp_registered_widgets[$widget_id]) )
  1969 		if ( !isset($wp_registered_widgets[$widget_id]) )
  1788 			wp_die( $error );
  1970 			wp_die( $error );
  1789 
  1971 
  1790 		$sidebar = array_diff( $sidebar, array($widget_id) );
  1972 		$sidebar = array_diff( $sidebar, array($widget_id) );
  1791 		$_POST = array('sidebar' => $sidebar_id, 'widget-' . $id_base => array(), 'the-widget-id' => $widget_id, 'delete_widget' => '1');
  1973 		$_POST = array('sidebar' => $sidebar_id, 'widget-' . $id_base => array(), 'the-widget-id' => $widget_id, 'delete_widget' => '1');
       
  1974 
       
  1975 		/** This action is documented in wp-admin/widgets.php */
       
  1976 		do_action( 'delete_widget', $widget_id, $sidebar_id, $id_base );
       
  1977 
  1792 	} elseif ( $settings && preg_match( '/__i__|%i%/', key($settings) ) ) {
  1978 	} elseif ( $settings && preg_match( '/__i__|%i%/', key($settings) ) ) {
  1793 		if ( !$multi_number )
  1979 		if ( !$multi_number )
  1794 			wp_die( $error );
  1980 			wp_die( $error );
  1795 
  1981 
  1796 		$_POST[ 'widget-' . $id_base ] = array( $multi_number => reset( $settings ) );
  1982 		$_POST[ 'widget-' . $id_base ] = array( $multi_number => reset( $settings ) );
  1830 
  2016 
  1831 /**
  2017 /**
  1832  * Ajax handler for saving a widget.
  2018  * Ajax handler for saving a widget.
  1833  *
  2019  *
  1834  * @since 3.9.0
  2020  * @since 3.9.0
       
  2021  *
       
  2022  * @global WP_Customize_Manager $wp_customize
  1835  */
  2023  */
  1836 function wp_ajax_update_widget() {
  2024 function wp_ajax_update_widget() {
  1837 	global $wp_customize;
  2025 	global $wp_customize;
  1838 	$wp_customize->widgets->wp_ajax_update_widget();
  2026 	$wp_customize->widgets->wp_ajax_update_widget();
       
  2027 }
       
  2028 
       
  2029 /**
       
  2030  * Ajax handler for removing inactive widgets.
       
  2031  *
       
  2032  * @since 4.4.0
       
  2033  */
       
  2034 function wp_ajax_delete_inactive_widgets() {
       
  2035 	check_ajax_referer( 'remove-inactive-widgets', 'removeinactivewidgets' );
       
  2036 
       
  2037 	if ( ! current_user_can( 'edit_theme_options' ) ) {
       
  2038 		wp_die( -1 );
       
  2039 	}
       
  2040 
       
  2041 	unset( $_POST['removeinactivewidgets'], $_POST['action'] );
       
  2042 	/** This action is documented in wp-admin/includes/ajax-actions.php */
       
  2043 	do_action( 'load-widgets.php' );
       
  2044 	/** This action is documented in wp-admin/includes/ajax-actions.php */
       
  2045 	do_action( 'widgets.php' );
       
  2046 	/** This action is documented in wp-admin/widgets.php */
       
  2047 	do_action( 'sidebar_admin_setup' );
       
  2048 
       
  2049 	$sidebars_widgets = wp_get_sidebars_widgets();
       
  2050 
       
  2051 	foreach ( $sidebars_widgets['wp_inactive_widgets'] as $key => $widget_id ) {
       
  2052 		$pieces = explode( '-', $widget_id );
       
  2053 		$multi_number = array_pop( $pieces );
       
  2054 		$id_base = implode( '-', $pieces );
       
  2055 		$widget = get_option( 'widget_' . $id_base );
       
  2056 		unset( $widget[$multi_number] );
       
  2057 		update_option( 'widget_' . $id_base, $widget );
       
  2058 		unset( $sidebars_widgets['wp_inactive_widgets'][$key] );
       
  2059 	}
       
  2060 
       
  2061 	wp_set_sidebars_widgets( $sidebars_widgets );
       
  2062 
       
  2063 	wp_die();
  1839 }
  2064 }
  1840 
  2065 
  1841 /**
  2066 /**
  1842  * Ajax handler for uploading attachments
  2067  * Ajax handler for uploading attachments
  1843  *
  2068  *
  1853 
  2078 
  1854 	if ( ! current_user_can( 'upload_files' ) ) {
  2079 	if ( ! current_user_can( 'upload_files' ) ) {
  1855 		echo wp_json_encode( array(
  2080 		echo wp_json_encode( array(
  1856 			'success' => false,
  2081 			'success' => false,
  1857 			'data'    => array(
  2082 			'data'    => array(
  1858 				'message'  => __( "You don't have permission to upload files." ),
  2083 				'message'  => __( 'Sorry, you are not allowed to upload files.' ),
  1859 				'filename' => $_FILES['async-upload']['name'],
  2084 				'filename' => $_FILES['async-upload']['name'],
  1860 			)
  2085 			)
  1861 		) );
  2086 		) );
  1862 
  2087 
  1863 		wp_die();
  2088 		wp_die();
  1867 		$post_id = $_REQUEST['post_id'];
  2092 		$post_id = $_REQUEST['post_id'];
  1868 		if ( ! current_user_can( 'edit_post', $post_id ) ) {
  2093 		if ( ! current_user_can( 'edit_post', $post_id ) ) {
  1869 			echo wp_json_encode( array(
  2094 			echo wp_json_encode( array(
  1870 				'success' => false,
  2095 				'success' => false,
  1871 				'data'    => array(
  2096 				'data'    => array(
  1872 					'message'  => __( "You don't have permission to attach files to this post." ),
  2097 					'message'  => __( 'Sorry, you are not allowed to attach files to this post.' ),
  1873 					'filename' => $_FILES['async-upload']['name'],
  2098 					'filename' => $_FILES['async-upload']['name'],
  1874 				)
  2099 				)
  1875 			) );
  2100 			) );
  1876 
  2101 
  1877 			wp_die();
  2102 			wp_die();
  1998 
  2223 
  1999 	wp_die( 0 );
  2224 	wp_die( 0 );
  2000 }
  2225 }
  2001 
  2226 
  2002 /**
  2227 /**
  2003  * AJAX handler for setting the featured image for an attachment.
  2228  * Ajax handler for retrieving HTML for the featured image.
       
  2229  *
       
  2230  * @since 4.6.0
       
  2231  */
       
  2232 function wp_ajax_get_post_thumbnail_html() {
       
  2233 	$post_ID = intval( $_POST['post_id'] );
       
  2234 
       
  2235 	check_ajax_referer( "update-post_$post_ID" );
       
  2236 
       
  2237 	if ( ! current_user_can( 'edit_post', $post_ID ) ) {
       
  2238 		wp_die( -1 );
       
  2239 	}
       
  2240 
       
  2241 	$thumbnail_id = intval( $_POST['thumbnail_id'] );
       
  2242 
       
  2243 	// For backward compatibility, -1 refers to no featured image.
       
  2244 	if ( -1 === $thumbnail_id ) {
       
  2245 		$thumbnail_id = null;
       
  2246 	}
       
  2247 
       
  2248 	$return = _wp_post_thumbnail_html( $thumbnail_id, $post_ID );
       
  2249 	wp_send_json_success( $return );
       
  2250 }
       
  2251 
       
  2252 /**
       
  2253  * Ajax handler for setting the featured image for an attachment.
  2004  *
  2254  *
  2005  * @since 4.0.0
  2255  * @since 4.0.0
  2006  *
  2256  *
  2007  * @see set_post_thumbnail()
  2257  * @see set_post_thumbnail()
  2008  */
  2258  */
  2070 
  2320 
  2071 /**
  2321 /**
  2072  * Ajax handler for saving posts from the fullscreen editor.
  2322  * Ajax handler for saving posts from the fullscreen editor.
  2073  *
  2323  *
  2074  * @since 3.1.0
  2324  * @since 3.1.0
       
  2325  * @deprecated 4.3.0
  2075  */
  2326  */
  2076 function wp_ajax_wp_fullscreen_save_post() {
  2327 function wp_ajax_wp_fullscreen_save_post() {
  2077 	$post_id = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0;
  2328 	$post_id = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0;
  2078 
  2329 
  2079 	$post = null;
  2330 	$post = null;
  2088 	if ( is_wp_error( $post_id ) ) {
  2339 	if ( is_wp_error( $post_id ) ) {
  2089 		wp_send_json_error();
  2340 		wp_send_json_error();
  2090 	}
  2341 	}
  2091 
  2342 
  2092 	if ( $post ) {
  2343 	if ( $post ) {
  2093 		$last_date = mysql2date( get_option('date_format'), $post->post_modified );
  2344 		$last_date = mysql2date( __( 'F j, Y' ), $post->post_modified );
  2094 		$last_time = mysql2date( get_option('time_format'), $post->post_modified );
  2345 		$last_time = mysql2date( __( 'g:i a' ), $post->post_modified );
  2095 	} else {
  2346 	} else {
  2096 		$last_date = date_i18n( get_option('date_format') );
  2347 		$last_date = date_i18n( __( 'F j, Y' ) );
  2097 		$last_time = date_i18n( get_option('time_format') );
  2348 		$last_time = date_i18n( __( 'g:i a' ) );
  2098 	}
  2349 	}
  2099 
  2350 
  2100 	if ( $last_id = get_post_meta( $post_id, '_edit_last', true ) ) {
  2351 	if ( $last_id = get_post_meta( $post_id, '_edit_last', true ) ) {
  2101 		$last_user = get_userdata( $last_id );
  2352 		$last_user = get_userdata( $last_id );
  2102 		$last_edited = sprintf( __('Last edited by %1$s on %2$s at %3$s'), esc_html( $last_user->display_name ), $last_date, $last_time );
  2353 		$last_edited = sprintf( __('Last edited by %1$s on %2$s at %3$s'), esc_html( $last_user->display_name ), $last_date, $last_time );
  2127 	$active_lock = array_map( 'absint', explode( ':', $_POST['active_post_lock'] ) );
  2378 	$active_lock = array_map( 'absint', explode( ':', $_POST['active_post_lock'] ) );
  2128 	if ( $active_lock[1] != get_current_user_id() )
  2379 	if ( $active_lock[1] != get_current_user_id() )
  2129 		wp_die( 0 );
  2380 		wp_die( 0 );
  2130 
  2381 
  2131 	/**
  2382 	/**
  2132 	 * Filter the post lock window duration.
  2383 	 * Filters the post lock window duration.
  2133 	 *
  2384 	 *
  2134 	 * @since 3.3.0
  2385 	 * @since 3.3.0
  2135 	 *
  2386 	 *
  2136 	 * @param int $interval The interval in seconds the post lock duration
  2387 	 * @param int $interval The interval in seconds the post lock duration
  2137 	 *                      should last, plus 5 seconds. Default 150.
  2388 	 *                      should last, plus 5 seconds. Default 150.
  2202 		wp_send_json_error();
  2453 		wp_send_json_error();
  2203 
  2454 
  2204 	$query = isset( $_REQUEST['query'] ) ? (array) $_REQUEST['query'] : array();
  2455 	$query = isset( $_REQUEST['query'] ) ? (array) $_REQUEST['query'] : array();
  2205 	$keys = array(
  2456 	$keys = array(
  2206 		's', 'order', 'orderby', 'posts_per_page', 'paged', 'post_mime_type',
  2457 		's', 'order', 'orderby', 'posts_per_page', 'paged', 'post_mime_type',
  2207 		'post_parent', 'post__in', 'post__not_in', 'year', 'monthnum'
  2458 		'post_parent', 'author', 'post__in', 'post__not_in', 'year', 'monthnum'
  2208 	);
  2459 	);
  2209 	foreach ( get_taxonomies_for_attachments( 'objects' ) as $t ) {
  2460 	foreach ( get_taxonomies_for_attachments( 'objects' ) as $t ) {
  2210 		if ( $t->query_var && isset( $query[ $t->query_var ] ) ) {
  2461 		if ( $t->query_var && isset( $query[ $t->query_var ] ) ) {
  2211 			$keys[] = $t->query_var;
  2462 			$keys[] = $t->query_var;
  2212 		}
  2463 		}
  2223 	}
  2474 	}
  2224 
  2475 
  2225 	if ( current_user_can( get_post_type_object( 'attachment' )->cap->read_private_posts ) )
  2476 	if ( current_user_can( get_post_type_object( 'attachment' )->cap->read_private_posts ) )
  2226 		$query['post_status'] .= ',private';
  2477 		$query['post_status'] .= ',private';
  2227 
  2478 
       
  2479 	// Filter query clauses to include filenames.
       
  2480 	if ( isset( $query['s'] ) ) {
       
  2481 		add_filter( 'posts_clauses', '_filter_query_attachment_filenames' );
       
  2482 	}
       
  2483 
  2228 	/**
  2484 	/**
  2229 	 * Filter the arguments passed to WP_Query during an AJAX
  2485 	 * Filters the arguments passed to WP_Query during an Ajax
  2230 	 * call for querying attachments.
  2486 	 * call for querying attachments.
  2231 	 *
  2487 	 *
  2232 	 * @since 3.7.0
  2488 	 * @since 3.7.0
  2233 	 *
  2489 	 *
  2234 	 * @see WP_Query::parse_query()
  2490 	 * @see WP_Query::parse_query()
  2317 
  2573 
  2318 	wp_send_json_success();
  2574 	wp_send_json_success();
  2319 }
  2575 }
  2320 
  2576 
  2321 /**
  2577 /**
  2322  * Ajax handler for saving backwards compatible attachment attributes.
  2578  * Ajax handler for saving backward compatible attachment attributes.
  2323  *
  2579  *
  2324  * @since 3.5.0
  2580  * @since 3.5.0
  2325  */
  2581  */
  2326 function wp_ajax_save_attachment_compat() {
  2582 function wp_ajax_save_attachment_compat() {
  2327 	if ( ! isset( $_REQUEST['id'] ) )
  2583 	if ( ! isset( $_REQUEST['id'] ) )
  2403 
  2659 
  2404 /**
  2660 /**
  2405  * Ajax handler for sending an attachment to the editor.
  2661  * Ajax handler for sending an attachment to the editor.
  2406  *
  2662  *
  2407  * Generates the HTML to send an attachment to the editor.
  2663  * Generates the HTML to send an attachment to the editor.
  2408  * Backwards compatible with the media_send_to_editor filter
  2664  * Backward compatible with the {@see 'media_send_to_editor'} filter
  2409  * and the chain of filters that follow.
  2665  * and the chain of filters that follow.
  2410  *
  2666  *
  2411  * @since 3.5.0
  2667  * @since 3.5.0
  2412  */
  2668  */
  2413 function wp_ajax_send_attachment_to_editor() {
  2669 function wp_ajax_send_attachment_to_editor() {
  2428 		if ( 0 == $post->post_parent && $insert_into_post_id = intval( $_POST['post_id'] ) ) {
  2684 		if ( 0 == $post->post_parent && $insert_into_post_id = intval( $_POST['post_id'] ) ) {
  2429 			wp_update_post( array( 'ID' => $id, 'post_parent' => $insert_into_post_id ) );
  2685 			wp_update_post( array( 'ID' => $id, 'post_parent' => $insert_into_post_id ) );
  2430 		}
  2686 		}
  2431 	}
  2687 	}
  2432 
  2688 
  2433 	$rel = $url = '';
  2689 	$url = empty( $attachment['url'] ) ? '' : $attachment['url'];
  2434 	$html = isset( $attachment['post_title'] ) ? $attachment['post_title'] : '';
  2690 	$rel = ( strpos( $url, 'attachment_id') || get_attachment_link( $id ) == $url );
  2435 	if ( ! empty( $attachment['url'] ) ) {
       
  2436 		$url = $attachment['url'];
       
  2437 		if ( strpos( $url, 'attachment_id') || get_attachment_link( $id ) == $url )
       
  2438 			$rel = ' rel="attachment wp-att-' . $id . '"';
       
  2439 		$html = '<a href="' . esc_url( $url ) . '"' . $rel . '>' . $html . '</a>';
       
  2440 	}
       
  2441 
  2691 
  2442 	remove_filter( 'media_send_to_editor', 'image_media_send_to_editor' );
  2692 	remove_filter( 'media_send_to_editor', 'image_media_send_to_editor' );
  2443 
  2693 
  2444 	if ( 'image' === substr( $post->post_mime_type, 0, 5 ) ) {
  2694 	if ( 'image' === substr( $post->post_mime_type, 0, 5 ) ) {
  2445 		$align = isset( $attachment['align'] ) ? $attachment['align'] : 'none';
  2695 		$align = isset( $attachment['align'] ) ? $attachment['align'] : 'none';
  2451 		if ( '' === trim( $caption ) ) {
  2701 		if ( '' === trim( $caption ) ) {
  2452 			$caption = '';
  2702 			$caption = '';
  2453 		}
  2703 		}
  2454 
  2704 
  2455 		$title = ''; // We no longer insert title tags into <img> tags, as they are redundant.
  2705 		$title = ''; // We no longer insert title tags into <img> tags, as they are redundant.
  2456 		$html = get_image_send_to_editor( $id, $caption, $title, $align, $url, (bool) $rel, $size, $alt );
  2706 		$html = get_image_send_to_editor( $id, $caption, $title, $align, $url, $rel, $size, $alt );
  2457 	} elseif ( wp_attachment_is( 'video', $post ) || wp_attachment_is( 'audio', $post )  ) {
  2707 	} elseif ( wp_attachment_is( 'video', $post ) || wp_attachment_is( 'audio', $post )  ) {
  2458 		$html = stripslashes_deep( $_POST['html'] );
  2708 		$html = stripslashes_deep( $_POST['html'] );
       
  2709 	} else {
       
  2710 		$html = isset( $attachment['post_title'] ) ? $attachment['post_title'] : '';
       
  2711 		$rel = $rel ? ' rel="attachment wp-att-' . $id . '"' : ''; // Hard-coded string, $id is already sanitized
       
  2712 
       
  2713 		if ( ! empty( $url ) ) {
       
  2714 			$html = '<a href="' . esc_url( $url ) . '"' . $rel . '>' . $html . '</a>';
       
  2715 		}
  2459 	}
  2716 	}
  2460 
  2717 
  2461 	/** This filter is documented in wp-admin/includes/media.php */
  2718 	/** This filter is documented in wp-admin/includes/media.php */
  2462 	$html = apply_filters( 'media_send_to_editor', $html, $id, $attachment );
  2719 	$html = apply_filters( 'media_send_to_editor', $html, $id, $attachment );
  2463 
  2720 
  2467 /**
  2724 /**
  2468  * Ajax handler for sending a link to the editor.
  2725  * Ajax handler for sending a link to the editor.
  2469  *
  2726  *
  2470  * Generates the HTML to send a non-image embed link to the editor.
  2727  * Generates the HTML to send a non-image embed link to the editor.
  2471  *
  2728  *
  2472  * Backwards compatible with the following filters:
  2729  * Backward compatible with the following filters:
  2473  * - file_send_to_editor_url
  2730  * - file_send_to_editor_url
  2474  * - audio_send_to_editor_url
  2731  * - audio_send_to_editor_url
  2475  * - video_send_to_editor_url
  2732  * - video_send_to_editor_url
  2476  *
  2733  *
  2477  * @since 3.5.0
  2734  * @since 3.5.0
       
  2735  *
       
  2736  * @global WP_Post  $post
       
  2737  * @global WP_Embed $wp_embed
  2478  */
  2738  */
  2479 function wp_ajax_send_link_to_editor() {
  2739 function wp_ajax_send_link_to_editor() {
  2480 	global $post, $wp_embed;
  2740 	global $post, $wp_embed;
  2481 
  2741 
  2482 	check_ajax_referer( 'media-send-to-editor', 'nonce' );
  2742 	check_ajax_referer( 'media-send-to-editor', 'nonce' );
  2515 	if ( ( $ext = preg_replace( '/^.+?\.([^.]+)$/', '$1', $src ) ) && ( $ext_type = wp_ext2type( $ext ) )
  2775 	if ( ( $ext = preg_replace( '/^.+?\.([^.]+)$/', '$1', $src ) ) && ( $ext_type = wp_ext2type( $ext ) )
  2516 		&& ( 'audio' == $ext_type || 'video' == $ext_type ) )
  2776 		&& ( 'audio' == $ext_type || 'video' == $ext_type ) )
  2517 			$type = $ext_type;
  2777 			$type = $ext_type;
  2518 
  2778 
  2519 	/** This filter is documented in wp-admin/includes/media.php */
  2779 	/** This filter is documented in wp-admin/includes/media.php */
  2520 	$html = apply_filters( $type . '_send_to_editor_url', $html, $src, $link_text );
  2780 	$html = apply_filters( "{$type}_send_to_editor_url", $html, $src, $link_text );
  2521 
  2781 
  2522 	wp_send_json_success( $html );
  2782 	wp_send_json_success( $html );
  2523 }
  2783 }
  2524 
  2784 
  2525 /**
  2785 /**
  2528  * Runs when the user is logged in.
  2788  * Runs when the user is logged in.
  2529  *
  2789  *
  2530  * @since 3.6.0
  2790  * @since 3.6.0
  2531  */
  2791  */
  2532 function wp_ajax_heartbeat() {
  2792 function wp_ajax_heartbeat() {
  2533 	if ( empty( $_POST['_nonce'] ) )
  2793 	if ( empty( $_POST['_nonce'] ) ) {
  2534 		wp_send_json_error();
  2794 		wp_send_json_error();
  2535 
  2795 	}
  2536 	$response = array();
  2796 
  2537 
  2797 	$response = $data = array();
  2538 	if ( false === wp_verify_nonce( $_POST['_nonce'], 'heartbeat-nonce' ) ) {
  2798 	$nonce_state = wp_verify_nonce( $_POST['_nonce'], 'heartbeat-nonce' );
  2539 		// User is logged in but nonces have expired.
       
  2540 		$response['nonces_expired'] = true;
       
  2541 		wp_send_json($response);
       
  2542 	}
       
  2543 
  2799 
  2544 	// screen_id is the same as $current_screen->id and the JS global 'pagenow'.
  2800 	// screen_id is the same as $current_screen->id and the JS global 'pagenow'.
  2545 	if ( ! empty($_POST['screen_id']) )
  2801 	if ( ! empty( $_POST['screen_id'] ) ) {
  2546 		$screen_id = sanitize_key($_POST['screen_id']);
  2802 		$screen_id = sanitize_key($_POST['screen_id']);
  2547 	else
  2803 	} else {
  2548 		$screen_id = 'front';
  2804 		$screen_id = 'front';
  2549 
  2805 	}
  2550 	if ( ! empty($_POST['data']) ) {
  2806 
       
  2807 	if ( ! empty( $_POST['data'] ) ) {
  2551 		$data = wp_unslash( (array) $_POST['data'] );
  2808 		$data = wp_unslash( (array) $_POST['data'] );
  2552 
  2809 	}
       
  2810 
       
  2811 	if ( 1 !== $nonce_state ) {
       
  2812 		$response = apply_filters( 'wp_refresh_nonces', $response, $data, $screen_id );
       
  2813 
       
  2814 		if ( false === $nonce_state ) {
       
  2815 			// User is logged in but nonces have expired.
       
  2816 			$response['nonces_expired'] = true;
       
  2817 			wp_send_json( $response );
       
  2818 		}
       
  2819 	}
       
  2820 
       
  2821 	if ( ! empty( $data ) ) {
  2553 		/**
  2822 		/**
  2554 		 * Filter the Heartbeat response received.
  2823 		 * Filters the Heartbeat response received.
  2555 		 *
  2824 		 *
  2556 		 * @since 3.6.0
  2825 		 * @since 3.6.0
  2557 		 *
  2826 		 *
  2558 		 * @param array|object $response  The Heartbeat response object or array.
  2827 		 * @param array  $response  The Heartbeat response.
  2559 		 * @param array        $data      The $_POST data sent.
  2828 		 * @param array  $data      The $_POST data sent.
  2560 		 * @param string       $screen_id The screen id.
  2829 		 * @param string $screen_id The screen id.
  2561 		 */
  2830 		 */
  2562 		$response = apply_filters( 'heartbeat_received', $response, $data, $screen_id );
  2831 		$response = apply_filters( 'heartbeat_received', $response, $data, $screen_id );
  2563 	}
  2832 	}
  2564 
  2833 
  2565 	/**
  2834 	/**
  2566 	 * Filter the Heartbeat response sent.
  2835 	 * Filters the Heartbeat response sent.
  2567 	 *
  2836 	 *
  2568 	 * @since 3.6.0
  2837 	 * @since 3.6.0
  2569 	 *
  2838 	 *
  2570 	 * @param array|object $response  The Heartbeat response object or array.
  2839 	 * @param array  $response  The Heartbeat response.
  2571 	 * @param string       $screen_id The screen id.
  2840 	 * @param string $screen_id The screen id.
  2572 	 */
  2841 	 */
  2573 	$response = apply_filters( 'heartbeat_send', $response, $screen_id );
  2842 	$response = apply_filters( 'heartbeat_send', $response, $screen_id );
  2574 
  2843 
  2575 	/**
  2844 	/**
  2576 	 * Fires when Heartbeat ticks in logged-in environments.
  2845 	 * Fires when Heartbeat ticks in logged-in environments.
  2577 	 *
  2846 	 *
  2578 	 * Allows the transport to be easily replaced with long-polling.
  2847 	 * Allows the transport to be easily replaced with long-polling.
  2579 	 *
  2848 	 *
  2580 	 * @since 3.6.0
  2849 	 * @since 3.6.0
  2581 	 *
  2850 	 *
  2582 	 * @param array|object $response  The Heartbeat response object or array.
  2851 	 * @param array  $response  The Heartbeat response.
  2583 	 * @param string       $screen_id The screen id.
  2852 	 * @param string $screen_id The screen id.
  2584 	 */
  2853 	 */
  2585 	do_action( 'heartbeat_tick', $response, $screen_id );
  2854 	do_action( 'heartbeat_tick', $response, $screen_id );
  2586 
  2855 
  2587 	// Send the current time according to the server
  2856 	// Send the current time according to the server
  2588 	$response['server_time'] = time();
  2857 	$response['server_time'] = time();
  2589 
  2858 
  2590 	wp_send_json($response);
  2859 	wp_send_json( $response );
  2591 }
  2860 }
  2592 
  2861 
  2593 /**
  2862 /**
  2594  * Ajax handler for getting revision diffs.
  2863  * Ajax handler for getting revision diffs.
  2595  *
  2864  *
  2599 	require ABSPATH . 'wp-admin/includes/revision.php';
  2868 	require ABSPATH . 'wp-admin/includes/revision.php';
  2600 
  2869 
  2601 	if ( ! $post = get_post( (int) $_REQUEST['post_id'] ) )
  2870 	if ( ! $post = get_post( (int) $_REQUEST['post_id'] ) )
  2602 		wp_send_json_error();
  2871 		wp_send_json_error();
  2603 
  2872 
  2604 	if ( ! current_user_can( 'read_post', $post->ID ) )
  2873 	if ( ! current_user_can( 'edit_post', $post->ID ) )
  2605 		wp_send_json_error();
  2874 		wp_send_json_error();
  2606 
  2875 
  2607 	// Really just pre-loading the cache here.
  2876 	// Really just pre-loading the cache here.
  2608 	if ( ! $revisions = wp_get_post_revisions( $post->ID, array( 'check_enabled' => false ) ) )
  2877 	if ( ! $revisions = wp_get_post_revisions( $post->ID, array( 'check_enabled' => false ) ) )
  2609 		wp_send_json_error();
  2878 		wp_send_json_error();
  2625 /**
  2894 /**
  2626  * Ajax handler for auto-saving the selected color scheme for
  2895  * Ajax handler for auto-saving the selected color scheme for
  2627  * a user's own profile.
  2896  * a user's own profile.
  2628  *
  2897  *
  2629  * @since 3.8.0
  2898  * @since 3.8.0
       
  2899  *
       
  2900  * @global array $_wp_admin_css_colors
  2630  */
  2901  */
  2631 function wp_ajax_save_user_color_scheme() {
  2902 function wp_ajax_save_user_color_scheme() {
  2632 	global $_wp_admin_css_colors;
  2903 	global $_wp_admin_css_colors;
  2633 
  2904 
  2634 	check_ajax_referer( 'save-color-scheme', 'nonce' );
  2905 	check_ajax_referer( 'save-color-scheme', 'nonce' );
  2650 
  2921 
  2651 /**
  2922 /**
  2652  * Ajax handler for getting themes from themes_api().
  2923  * Ajax handler for getting themes from themes_api().
  2653  *
  2924  *
  2654  * @since 3.9.0
  2925  * @since 3.9.0
       
  2926  *
       
  2927  * @global array $themes_allowedtags
       
  2928  * @global array $theme_field_defaults
  2655  */
  2929  */
  2656 function wp_ajax_query_themes() {
  2930 function wp_ajax_query_themes() {
  2657 	global $themes_allowedtags, $theme_field_defaults;
  2931 	global $themes_allowedtags, $theme_field_defaults;
  2658 
  2932 
  2659 	if ( ! current_user_can( 'install_themes' ) ) {
  2933 	if ( ! current_user_can( 'install_themes' ) ) {
  2662 
  2936 
  2663 	$args = wp_parse_args( wp_unslash( $_REQUEST['request'] ), array(
  2937 	$args = wp_parse_args( wp_unslash( $_REQUEST['request'] ), array(
  2664 		'per_page' => 20,
  2938 		'per_page' => 20,
  2665 		'fields'   => $theme_field_defaults
  2939 		'fields'   => $theme_field_defaults
  2666 	) );
  2940 	) );
       
  2941 
       
  2942 	if ( isset( $args['browse'] ) && 'favorites' === $args['browse'] && ! isset( $args['user'] ) ) {
       
  2943 		$user = get_user_option( 'wporg_favorites' );
       
  2944 		if ( $user ) {
       
  2945 			$args['user'] = $user;
       
  2946 		}
       
  2947 	}
  2667 
  2948 
  2668 	$old_filter = isset( $args['browse'] ) ? $args['browse'] : 'search';
  2949 	$old_filter = isset( $args['browse'] ) ? $args['browse'] : 'search';
  2669 
  2950 
  2670 	/** This filter is documented in wp-admin/includes/class-wp-theme-install-list-table.php */
  2951 	/** This filter is documented in wp-admin/includes/class-wp-theme-install-list-table.php */
  2671 	$args = apply_filters( 'install_themes_table_api_args_' . $old_filter, $args );
  2952 	$args = apply_filters( 'install_themes_table_api_args_' . $old_filter, $args );
  2681 		$theme->install_url = add_query_arg( array(
  2962 		$theme->install_url = add_query_arg( array(
  2682 			'theme'    => $theme->slug,
  2963 			'theme'    => $theme->slug,
  2683 			'_wpnonce' => wp_create_nonce( 'install-theme_' . $theme->slug )
  2964 			'_wpnonce' => wp_create_nonce( 'install-theme_' . $theme->slug )
  2684 		), $update_php );
  2965 		), $update_php );
  2685 
  2966 
       
  2967 		if ( current_user_can( 'switch_themes' ) ) {
       
  2968 			if ( is_multisite() ) {
       
  2969 				$theme->activate_url = add_query_arg( array(
       
  2970 					'action'   => 'enable',
       
  2971 					'_wpnonce' => wp_create_nonce( 'enable-theme_' . $theme->slug ),
       
  2972 					'theme'    => $theme->slug,
       
  2973 				), network_admin_url( 'themes.php' ) );
       
  2974 			} else {
       
  2975 				$theme->activate_url = add_query_arg( array(
       
  2976 					'action'     => 'activate',
       
  2977 					'_wpnonce'   => wp_create_nonce( 'switch-theme_' . $theme->slug ),
       
  2978 					'stylesheet' => $theme->slug,
       
  2979 				), admin_url( 'themes.php' ) );
       
  2980 			}
       
  2981 		}
       
  2982 
       
  2983 		if ( ! is_multisite() && current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
       
  2984 			$theme->customize_url = add_query_arg( array(
       
  2985 				'return' => urlencode( network_admin_url( 'theme-install.php', 'relative' ) ),
       
  2986 			), wp_customize_url( $theme->slug ) );
       
  2987 		}
       
  2988 
  2686 		$theme->name        = wp_kses( $theme->name, $themes_allowedtags );
  2989 		$theme->name        = wp_kses( $theme->name, $themes_allowedtags );
  2687 		$theme->author      = wp_kses( $theme->author, $themes_allowedtags );
  2990 		$theme->author      = wp_kses( $theme->author, $themes_allowedtags );
  2688 		$theme->version     = wp_kses( $theme->version, $themes_allowedtags );
  2991 		$theme->version     = wp_kses( $theme->version, $themes_allowedtags );
  2689 		$theme->description = wp_kses( $theme->description, $themes_allowedtags );
  2992 		$theme->description = wp_kses( $theme->description, $themes_allowedtags );
  2690 		$theme->num_ratings = sprintf( _n( '(based on %s rating)', '(based on %s ratings)', $theme->num_ratings ), number_format_i18n( $theme->num_ratings ) );
  2993 		$theme->stars       = wp_star_rating( array( 'rating' => $theme->rating, 'type' => 'percent', 'number' => $theme->num_ratings, 'echo' => false ) );
       
  2994 		$theme->num_ratings = number_format_i18n( $theme->num_ratings );
  2691 		$theme->preview_url = set_url_scheme( $theme->preview_url );
  2995 		$theme->preview_url = set_url_scheme( $theme->preview_url );
  2692 	}
  2996 	}
  2693 
  2997 
  2694 	wp_send_json_success( $api );
  2998 	wp_send_json_success( $api );
  2695 }
  2999 }
  2696 
  3000 
  2697 /**
  3001 /**
  2698  * Apply [embed] AJAX handlers to a string.
  3002  * Apply [embed] Ajax handlers to a string.
  2699  *
  3003  *
  2700  * @since 4.0.0
  3004  * @since 4.0.0
  2701  *
  3005  *
  2702  * @global WP_Post  $post     Global $post.
  3006  * @global WP_Post    $post       Global $post.
  2703  * @global WP_Embed $wp_embed Embed API instance.
  3007  * @global WP_Embed   $wp_embed   Embed API instance.
       
  3008  * @global WP_Scripts $wp_scripts
       
  3009  * @global int        $content_width
  2704  */
  3010  */
  2705 function wp_ajax_parse_embed() {
  3011 function wp_ajax_parse_embed() {
  2706 	global $post, $wp_embed;
  3012 	global $post, $wp_embed, $content_width;
  2707 
  3013 
  2708 	if ( ! $post = get_post( (int) $_POST['post_ID'] ) ) {
  3014 	if ( empty( $_POST['shortcode'] ) ) {
  2709 		wp_send_json_error();
  3015 		wp_send_json_error();
  2710 	}
  3016 	}
  2711 
  3017 	$post_id = isset( $_POST[ 'post_ID' ] ) ? intval( $_POST[ 'post_ID' ] ) : 0;
  2712 	if ( empty( $_POST['shortcode'] ) || ! current_user_can( 'edit_post', $post->ID ) ) {
  3018 	if ( $post_id > 0 ) {
       
  3019 		$post = get_post( $post_id );
       
  3020 		if ( ! $post || ! current_user_can( 'edit_post', $post->ID ) ) {
       
  3021 			wp_send_json_error();
       
  3022 		}
       
  3023 		setup_postdata( $post );
       
  3024 	} elseif ( ! current_user_can( 'edit_posts' ) ) { // See WP_oEmbed_Controller::get_proxy_item_permissions_check().
  2713 		wp_send_json_error();
  3025 		wp_send_json_error();
  2714 	}
  3026 	}
  2715 
  3027 
  2716 	$shortcode = wp_unslash( $_POST['shortcode'] );
  3028 	$shortcode = wp_unslash( $_POST['shortcode'] );
  2717 	$url = str_replace( '[embed]', '', str_replace( '[/embed]', '', $shortcode ) );
  3029 
       
  3030 	preg_match( '/' . get_shortcode_regex() . '/s', $shortcode, $matches );
       
  3031 	$atts = shortcode_parse_atts( $matches[3] );
       
  3032 	if ( ! empty( $matches[5] ) ) {
       
  3033 		$url = $matches[5];
       
  3034 	} elseif ( ! empty( $atts['src'] ) ) {
       
  3035 		$url = $atts['src'];
       
  3036 	} else {
       
  3037 		$url = '';
       
  3038 	}
  2718 
  3039 
  2719 	$parsed = false;
  3040 	$parsed = false;
  2720 	setup_postdata( $post );
       
  2721 
       
  2722 	$wp_embed->return_false_on_fail = true;
  3041 	$wp_embed->return_false_on_fail = true;
  2723 
  3042 
  2724 	if ( is_ssl() && preg_match( '%^\\[embed[^\\]]*\\]http://%i', $shortcode ) ) {
  3043 	if ( 0 === $post_id ) {
       
  3044 		/*
       
  3045 		 * Refresh oEmbeds cached outside of posts that are past their TTL.
       
  3046 		 * Posts are excluded because they have separate logic for refreshing
       
  3047 		 * their post meta caches. See WP_Embed::cache_oembed().
       
  3048 		 */
       
  3049 		$wp_embed->usecache = false;
       
  3050 	}
       
  3051 
       
  3052 	if ( is_ssl() && 0 === strpos( $url, 'http://' ) ) {
  2725 		// Admin is ssl and the user pasted non-ssl URL.
  3053 		// Admin is ssl and the user pasted non-ssl URL.
  2726 		// Check if the provider supports ssl embeds and use that for the preview.
  3054 		// Check if the provider supports ssl embeds and use that for the preview.
  2727 		$ssl_shortcode = preg_replace( '%^(\\[embed[^\\]]*\\])http://%i', '$1https://', $shortcode );
  3055 		$ssl_shortcode = preg_replace( '%^(\\[embed[^\\]]*\\])http://%i', '$1https://', $shortcode );
  2728 		$parsed = $wp_embed->run_shortcode( $ssl_shortcode );
  3056 		$parsed = $wp_embed->run_shortcode( $ssl_shortcode );
  2729 
  3057 
  2730 		if ( ! $parsed ) {
  3058 		if ( ! $parsed ) {
  2731 			$no_ssl_support = true;
  3059 			$no_ssl_support = true;
  2732 		}
  3060 		}
  2733 	}
  3061 	}
  2734 
  3062 
  2735 	if ( ! $parsed ) {
  3063 	// Set $content_width so any embeds fit in the destination iframe.
       
  3064 	if ( isset( $_POST['maxwidth'] ) && is_numeric( $_POST['maxwidth'] ) && $_POST['maxwidth'] > 0 ) {
       
  3065 		if ( ! isset( $content_width ) ) {
       
  3066 			$content_width = intval( $_POST['maxwidth'] );
       
  3067 		} else {
       
  3068 			$content_width = min( $content_width, intval( $_POST['maxwidth'] ) );
       
  3069 		}
       
  3070 	}
       
  3071 
       
  3072 	if ( $url && ! $parsed ) {
  2736 		$parsed = $wp_embed->run_shortcode( $shortcode );
  3073 		$parsed = $wp_embed->run_shortcode( $shortcode );
  2737 	}
  3074 	}
  2738 
  3075 
  2739 	if ( ! $parsed ) {
  3076 	if ( ! $parsed ) {
  2740 		wp_send_json_error( array(
  3077 		wp_send_json_error( array(
  2755 		global $wp_scripts;
  3092 		global $wp_scripts;
  2756 		if ( ! empty( $wp_scripts ) ) {
  3093 		if ( ! empty( $wp_scripts ) ) {
  2757 			$wp_scripts->done = array();
  3094 			$wp_scripts->done = array();
  2758 		}
  3095 		}
  2759 		ob_start();
  3096 		ob_start();
  2760 		wp_print_scripts( 'wp-mediaelement' );
  3097 		wp_print_scripts( array( 'mediaelement-vimeo', 'wp-mediaelement' ) );
  2761 		$scripts = ob_get_clean();
  3098 		$scripts = ob_get_clean();
  2762 
  3099 
  2763 		$parsed = $styles . $html . $scripts;
  3100 		$parsed = $styles . $html . $scripts;
  2764 	}
  3101 	}
  2765 
       
  2766 
  3102 
  2767 	if ( ! empty( $no_ssl_support ) || ( is_ssl() && ( preg_match( '%<(iframe|script|embed) [^>]*src="http://%', $parsed ) ||
  3103 	if ( ! empty( $no_ssl_support ) || ( is_ssl() && ( preg_match( '%<(iframe|script|embed) [^>]*src="http://%', $parsed ) ||
  2768 		preg_match( '%<link [^>]*href="http://%', $parsed ) ) ) ) {
  3104 		preg_match( '%<link [^>]*href="http://%', $parsed ) ) ) ) {
  2769 		// Admin is ssl and the embed is not. Iframes, scripts, and other "active content" will be blocked.
  3105 		// Admin is ssl and the embed is not. Iframes, scripts, and other "active content" will be blocked.
  2770 		wp_send_json_error( array(
  3106 		wp_send_json_error( array(
  2771 			'type' => 'not-ssl',
  3107 			'type' => 'not-ssl',
  2772 			'message' => __( 'This preview is unavailable in the editor.' ),
  3108 			'message' => __( 'This preview is unavailable in the editor.' ),
  2773 		) );
  3109 		) );
  2774 	}
  3110 	}
  2775 
  3111 
  2776 	wp_send_json_success( array(
  3112 	$return = array(
  2777 		'body' => $parsed
  3113 		'body' => $parsed,
  2778 	) );
  3114 		'attr' => $wp_embed->last_attr
  2779 }
  3115 	);
  2780 
  3116 
       
  3117 	if ( strpos( $parsed, 'class="wp-embedded-content' ) ) {
       
  3118 		if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
       
  3119 			$script_src = includes_url( 'js/wp-embed.js' );
       
  3120 		} else {
       
  3121 			$script_src = includes_url( 'js/wp-embed.min.js' );
       
  3122 		}
       
  3123 
       
  3124 		$return['head'] = '<script src="' . $script_src . '"></script>';
       
  3125 		$return['sandbox'] = true;
       
  3126 	}
       
  3127 
       
  3128 	wp_send_json_success( $return );
       
  3129 }
       
  3130 
       
  3131 /**
       
  3132  * @since 4.0.0
       
  3133  *
       
  3134  * @global WP_Post    $post
       
  3135  * @global WP_Scripts $wp_scripts
       
  3136  */
  2781 function wp_ajax_parse_media_shortcode() {
  3137 function wp_ajax_parse_media_shortcode() {
  2782 	global $post, $wp_scripts;
  3138 	global $post, $wp_scripts;
  2783 
  3139 
  2784 	if ( empty( $_POST['shortcode'] ) ) {
  3140 	if ( empty( $_POST['shortcode'] ) ) {
  2785 		wp_send_json_error();
  3141 		wp_send_json_error();
  2827 	if ( 'playlist' === $_REQUEST['type'] ) {
  3183 	if ( 'playlist' === $_REQUEST['type'] ) {
  2828 		wp_underscore_playlist_templates();
  3184 		wp_underscore_playlist_templates();
  2829 
  3185 
  2830 		wp_print_scripts( 'wp-playlist' );
  3186 		wp_print_scripts( 'wp-playlist' );
  2831 	} else {
  3187 	} else {
  2832 		wp_print_scripts( array( 'froogaloop', 'wp-mediaelement' ) );
  3188 		wp_print_scripts( array( 'mediaelement-vimeo', 'wp-mediaelement' ) );
  2833 	}
  3189 	}
  2834 
  3190 
  2835 	wp_send_json_success( array(
  3191 	wp_send_json_success( array(
  2836 		'head' => $head,
  3192 		'head' => $head,
  2837 		'body' => ob_get_clean()
  3193 		'body' => ob_get_clean()
  2838 	) );
  3194 	) );
  2839 }
  3195 }
  2840 
  3196 
  2841 /**
  3197 /**
  2842  * AJAX handler for destroying multiple open sessions for a user.
  3198  * Ajax handler for destroying multiple open sessions for a user.
  2843  *
  3199  *
  2844  * @since 4.1.0
  3200  * @since 4.1.0
  2845  */
  3201  */
  2846 function wp_ajax_destroy_sessions() {
  3202 function wp_ajax_destroy_sessions() {
  2847 
       
  2848 	$user = get_userdata( (int) $_POST['user_id'] );
  3203 	$user = get_userdata( (int) $_POST['user_id'] );
  2849 	if ( $user ) {
  3204 	if ( $user ) {
  2850 		if ( ! current_user_can( 'edit_user', $user->ID ) ) {
  3205 		if ( ! current_user_can( 'edit_user', $user->ID ) ) {
  2851 			$user = false;
  3206 			$user = false;
  2852 		} elseif ( ! wp_verify_nonce( $_POST['nonce'], 'update-user_' . $user->ID ) ) {
  3207 		} elseif ( ! wp_verify_nonce( $_POST['nonce'], 'update-user_' . $user->ID ) ) {
  2865 	if ( $user->ID === get_current_user_id() ) {
  3220 	if ( $user->ID === get_current_user_id() ) {
  2866 		$sessions->destroy_others( wp_get_session_token() );
  3221 		$sessions->destroy_others( wp_get_session_token() );
  2867 		$message = __( 'You are now logged out everywhere else.' );
  3222 		$message = __( 'You are now logged out everywhere else.' );
  2868 	} else {
  3223 	} else {
  2869 		$sessions->destroy_all();
  3224 		$sessions->destroy_all();
  2870 		/* translators: 1: User's display name. */
  3225 		/* translators: %s: User's display name. */
  2871 		$message = sprintf( __( '%s has been logged out.' ), $user->display_name );
  3226 		$message = sprintf( __( '%s has been logged out.' ), $user->display_name );
  2872 	}
  3227 	}
  2873 
  3228 
  2874 	wp_send_json_success( array( 'message' => $message ) );
  3229 	wp_send_json_success( array( 'message' => $message ) );
  2875 }
  3230 }
  2876 
  3231 
  2877 
  3232 /**
  2878 /**
  3233  * Ajax handler for cropping an image.
  2879  * AJAX handler for updating a plugin.
  3234  *
  2880  *
  3235  * @since 4.3.0
  2881  * @since 4.2.0
  3236  */
  2882  *
  3237 function wp_ajax_crop_image() {
  2883  * @see Plugin_Upgrader
  3238 	$attachment_id = absint( $_POST['id'] );
  2884  */
  3239 
  2885 function wp_ajax_update_plugin() {
  3240 	check_ajax_referer( 'image_editor-' . $attachment_id, 'nonce' );
  2886 	$plugin = urldecode( $_POST['plugin'] );
  3241 	if ( empty( $attachment_id ) || ! current_user_can( 'edit_post', $attachment_id ) ) {
       
  3242 		wp_send_json_error();
       
  3243 	}
       
  3244 
       
  3245 	$context = str_replace( '_', '-', $_POST['context'] );
       
  3246 	$data    = array_map( 'absint', $_POST['cropDetails'] );
       
  3247 	$cropped = wp_crop_image( $attachment_id, $data['x1'], $data['y1'], $data['width'], $data['height'], $data['dst_width'], $data['dst_height'] );
       
  3248 
       
  3249 	if ( ! $cropped || is_wp_error( $cropped ) ) {
       
  3250 		wp_send_json_error( array( 'message' => __( 'Image could not be processed.' ) ) );
       
  3251 	}
       
  3252 
       
  3253 	switch ( $context ) {
       
  3254 		case 'site-icon':
       
  3255 			require_once ABSPATH . '/wp-admin/includes/class-wp-site-icon.php';
       
  3256 			$wp_site_icon = new WP_Site_Icon();
       
  3257 
       
  3258 			// Skip creating a new attachment if the attachment is a Site Icon.
       
  3259 			if ( get_post_meta( $attachment_id, '_wp_attachment_context', true ) == $context ) {
       
  3260 
       
  3261 				// Delete the temporary cropped file, we don't need it.
       
  3262 				wp_delete_file( $cropped );
       
  3263 
       
  3264 				// Additional sizes in wp_prepare_attachment_for_js().
       
  3265 				add_filter( 'image_size_names_choose', array( $wp_site_icon, 'additional_sizes' ) );
       
  3266 				break;
       
  3267 			}
       
  3268 
       
  3269 			/** This filter is documented in wp-admin/custom-header.php */
       
  3270 			$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
       
  3271 			$object  = $wp_site_icon->create_attachment_object( $cropped, $attachment_id );
       
  3272 			unset( $object['ID'] );
       
  3273 
       
  3274 			// Update the attachment.
       
  3275 			add_filter( 'intermediate_image_sizes_advanced', array( $wp_site_icon, 'additional_sizes' ) );
       
  3276 			$attachment_id = $wp_site_icon->insert_attachment( $object, $cropped );
       
  3277 			remove_filter( 'intermediate_image_sizes_advanced', array( $wp_site_icon, 'additional_sizes' ) );
       
  3278 
       
  3279 			// Additional sizes in wp_prepare_attachment_for_js().
       
  3280 			add_filter( 'image_size_names_choose', array( $wp_site_icon, 'additional_sizes' ) );
       
  3281 			break;
       
  3282 
       
  3283 		default:
       
  3284 
       
  3285 			/**
       
  3286 			 * Fires before a cropped image is saved.
       
  3287 			 *
       
  3288 			 * Allows to add filters to modify the way a cropped image is saved.
       
  3289 			 *
       
  3290 			 * @since 4.3.0
       
  3291 			 *
       
  3292 			 * @param string $context       The Customizer control requesting the cropped image.
       
  3293 			 * @param int    $attachment_id The attachment ID of the original image.
       
  3294 			 * @param string $cropped       Path to the cropped image file.
       
  3295 			 */
       
  3296 			do_action( 'wp_ajax_crop_image_pre_save', $context, $attachment_id, $cropped );
       
  3297 
       
  3298 			/** This filter is documented in wp-admin/custom-header.php */
       
  3299 			$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication.
       
  3300 
       
  3301 			$parent_url = wp_get_attachment_url( $attachment_id );
       
  3302 			$url        = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url );
       
  3303 
       
  3304 			$size       = @getimagesize( $cropped );
       
  3305 			$image_type = ( $size ) ? $size['mime'] : 'image/jpeg';
       
  3306 
       
  3307 			$object = array(
       
  3308 				'post_title'     => basename( $cropped ),
       
  3309 				'post_content'   => $url,
       
  3310 				'post_mime_type' => $image_type,
       
  3311 				'guid'           => $url,
       
  3312 				'context'        => $context,
       
  3313 			);
       
  3314 
       
  3315 			$attachment_id = wp_insert_attachment( $object, $cropped );
       
  3316 			$metadata = wp_generate_attachment_metadata( $attachment_id, $cropped );
       
  3317 
       
  3318 			/**
       
  3319 			 * Filters the cropped image attachment metadata.
       
  3320 			 *
       
  3321 			 * @since 4.3.0
       
  3322 			 *
       
  3323 			 * @see wp_generate_attachment_metadata()
       
  3324 			 *
       
  3325 			 * @param array $metadata Attachment metadata.
       
  3326 			 */
       
  3327 			$metadata = apply_filters( 'wp_ajax_cropped_attachment_metadata', $metadata );
       
  3328 			wp_update_attachment_metadata( $attachment_id, $metadata );
       
  3329 
       
  3330 			/**
       
  3331 			 * Filters the attachment ID for a cropped image.
       
  3332 			 *
       
  3333 			 * @since 4.3.0
       
  3334 			 *
       
  3335 			 * @param int    $attachment_id The attachment ID of the cropped image.
       
  3336 			 * @param string $context       The Customizer control requesting the cropped image.
       
  3337 			 */
       
  3338 			$attachment_id = apply_filters( 'wp_ajax_cropped_attachment_id', $attachment_id, $context );
       
  3339 	}
       
  3340 
       
  3341 	wp_send_json_success( wp_prepare_attachment_for_js( $attachment_id ) );
       
  3342 }
       
  3343 
       
  3344 /**
       
  3345  * Ajax handler for generating a password.
       
  3346  *
       
  3347  * @since 4.4.0
       
  3348  */
       
  3349 function wp_ajax_generate_password() {
       
  3350 	wp_send_json_success( wp_generate_password( 24 ) );
       
  3351 }
       
  3352 
       
  3353 /**
       
  3354  * Ajax handler for saving the user's WordPress.org username.
       
  3355  *
       
  3356  * @since 4.4.0
       
  3357  */
       
  3358 function wp_ajax_save_wporg_username() {
       
  3359 	if ( ! current_user_can( 'install_themes' ) && ! current_user_can( 'install_plugins' ) ) {
       
  3360 		wp_send_json_error();
       
  3361 	}
       
  3362 
       
  3363 	check_ajax_referer( 'save_wporg_username_' . get_current_user_id() );
       
  3364 
       
  3365 	$username = isset( $_REQUEST['username'] ) ? wp_unslash( $_REQUEST['username'] ) : false;
       
  3366 
       
  3367 	if ( ! $username ) {
       
  3368 		wp_send_json_error();
       
  3369 	}
       
  3370 
       
  3371 	wp_send_json_success( update_user_meta( get_current_user_id(), 'wporg_favorites', $username ) );
       
  3372 }
       
  3373 
       
  3374 /**
       
  3375  * Ajax handler for installing a theme.
       
  3376  *
       
  3377  * @since 4.6.0
       
  3378  *
       
  3379  * @see Theme_Upgrader
       
  3380  *
       
  3381  * @global WP_Filesystem_Base $wp_filesystem Subclass
       
  3382  */
       
  3383 function wp_ajax_install_theme() {
       
  3384 	check_ajax_referer( 'updates' );
       
  3385 
       
  3386 	if ( empty( $_POST['slug'] ) ) {
       
  3387 		wp_send_json_error( array(
       
  3388 			'slug'         => '',
       
  3389 			'errorCode'    => 'no_theme_specified',
       
  3390 			'errorMessage' => __( 'No theme specified.' ),
       
  3391 		) );
       
  3392 	}
       
  3393 
       
  3394 	$slug = sanitize_key( wp_unslash( $_POST['slug'] ) );
  2887 
  3395 
  2888 	$status = array(
  3396 	$status = array(
  2889 		'update'     => 'plugin',
  3397 		'install' => 'theme',
  2890 		'plugin'     => $plugin,
  3398 		'slug'    => $slug,
  2891 		'slug'       => sanitize_key( $_POST['slug'] ),
  3399 	);
       
  3400 
       
  3401 	if ( ! current_user_can( 'install_themes' ) ) {
       
  3402 		$status['errorMessage'] = __( 'Sorry, you are not allowed to install themes on this site.' );
       
  3403 		wp_send_json_error( $status );
       
  3404 	}
       
  3405 
       
  3406 	include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
       
  3407 	include_once( ABSPATH . 'wp-admin/includes/theme.php' );
       
  3408 
       
  3409 	$api = themes_api( 'theme_information', array(
       
  3410 		'slug'   => $slug,
       
  3411 		'fields' => array( 'sections' => false ),
       
  3412 	) );
       
  3413 
       
  3414 	if ( is_wp_error( $api ) ) {
       
  3415 		$status['errorMessage'] = $api->get_error_message();
       
  3416 		wp_send_json_error( $status );
       
  3417 	}
       
  3418 
       
  3419 	$skin     = new WP_Ajax_Upgrader_Skin();
       
  3420 	$upgrader = new Theme_Upgrader( $skin );
       
  3421 	$result   = $upgrader->install( $api->download_link );
       
  3422 
       
  3423 	if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
       
  3424 		$status['debug'] = $skin->get_upgrade_messages();
       
  3425 	}
       
  3426 
       
  3427 	if ( is_wp_error( $result ) ) {
       
  3428 		$status['errorCode']    = $result->get_error_code();
       
  3429 		$status['errorMessage'] = $result->get_error_message();
       
  3430 		wp_send_json_error( $status );
       
  3431 	} elseif ( is_wp_error( $skin->result ) ) {
       
  3432 		$status['errorCode']    = $skin->result->get_error_code();
       
  3433 		$status['errorMessage'] = $skin->result->get_error_message();
       
  3434 		wp_send_json_error( $status );
       
  3435 	} elseif ( $skin->get_errors()->get_error_code() ) {
       
  3436 		$status['errorMessage'] = $skin->get_error_messages();
       
  3437 		wp_send_json_error( $status );
       
  3438 	} elseif ( is_null( $result ) ) {
       
  3439 		global $wp_filesystem;
       
  3440 
       
  3441 		$status['errorCode']    = 'unable_to_connect_to_filesystem';
       
  3442 		$status['errorMessage'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
       
  3443 
       
  3444 		// Pass through the error from WP_Filesystem if one was raised.
       
  3445 		if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) {
       
  3446 			$status['errorMessage'] = esc_html( $wp_filesystem->errors->get_error_message() );
       
  3447 		}
       
  3448 
       
  3449 		wp_send_json_error( $status );
       
  3450 	}
       
  3451 
       
  3452 	$status['themeName'] = wp_get_theme( $slug )->get( 'Name' );
       
  3453 
       
  3454 	if ( current_user_can( 'switch_themes' ) ) {
       
  3455 		if ( is_multisite() ) {
       
  3456 			$status['activateUrl'] = add_query_arg( array(
       
  3457 				'action'   => 'enable',
       
  3458 				'_wpnonce' => wp_create_nonce( 'enable-theme_' . $slug ),
       
  3459 				'theme'    => $slug,
       
  3460 			), network_admin_url( 'themes.php' ) );
       
  3461 		} else {
       
  3462 			$status['activateUrl'] = add_query_arg( array(
       
  3463 				'action'     => 'activate',
       
  3464 				'_wpnonce'   => wp_create_nonce( 'switch-theme_' . $slug ),
       
  3465 				'stylesheet' => $slug,
       
  3466 			), admin_url( 'themes.php' ) );
       
  3467 		}
       
  3468 	}
       
  3469 
       
  3470 	if ( ! is_multisite() && current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
       
  3471 		$status['customizeUrl'] = add_query_arg( array(
       
  3472 			'return' => urlencode( network_admin_url( 'theme-install.php', 'relative' ) ),
       
  3473 		), wp_customize_url( $slug ) );
       
  3474 	}
       
  3475 
       
  3476 	/*
       
  3477 	 * See WP_Theme_Install_List_Table::_get_theme_status() if we wanted to check
       
  3478 	 * on post-installation status.
       
  3479 	 */
       
  3480 	wp_send_json_success( $status );
       
  3481 }
       
  3482 
       
  3483 /**
       
  3484  * Ajax handler for updating a theme.
       
  3485  *
       
  3486  * @since 4.6.0
       
  3487  *
       
  3488  * @see Theme_Upgrader
       
  3489  *
       
  3490  * @global WP_Filesystem_Base $wp_filesystem Subclass
       
  3491  */
       
  3492 function wp_ajax_update_theme() {
       
  3493 	check_ajax_referer( 'updates' );
       
  3494 
       
  3495 	if ( empty( $_POST['slug'] ) ) {
       
  3496 		wp_send_json_error( array(
       
  3497 			'slug'         => '',
       
  3498 			'errorCode'    => 'no_theme_specified',
       
  3499 			'errorMessage' => __( 'No theme specified.' ),
       
  3500 		) );
       
  3501 	}
       
  3502 
       
  3503 	$stylesheet = preg_replace( '/[^A-z0-9_\-]/', '', wp_unslash( $_POST['slug'] ) );
       
  3504 	$status     = array(
       
  3505 		'update'     => 'theme',
       
  3506 		'slug'       => $stylesheet,
  2892 		'oldVersion' => '',
  3507 		'oldVersion' => '',
  2893 		'newVersion' => '',
  3508 		'newVersion' => '',
  2894 	);
  3509 	);
  2895 	$plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
  3510 
       
  3511 	if ( ! current_user_can( 'update_themes' ) ) {
       
  3512 		$status['errorMessage'] = __( 'Sorry, you are not allowed to update themes for this site.' );
       
  3513 		wp_send_json_error( $status );
       
  3514 	}
       
  3515 
       
  3516 	$theme = wp_get_theme( $stylesheet );
       
  3517 	if ( $theme->exists() ) {
       
  3518 		$status['oldVersion'] = $theme->get( 'Version' );
       
  3519 	}
       
  3520 
       
  3521 	include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
       
  3522 
       
  3523 	$current = get_site_transient( 'update_themes' );
       
  3524 	if ( empty( $current ) ) {
       
  3525 		wp_update_themes();
       
  3526 	}
       
  3527 
       
  3528 	$skin     = new WP_Ajax_Upgrader_Skin();
       
  3529 	$upgrader = new Theme_Upgrader( $skin );
       
  3530 	$result   = $upgrader->bulk_upgrade( array( $stylesheet ) );
       
  3531 
       
  3532 	if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
       
  3533 		$status['debug'] = $skin->get_upgrade_messages();
       
  3534 	}
       
  3535 
       
  3536 	if ( is_wp_error( $skin->result ) ) {
       
  3537 		$status['errorCode']    = $skin->result->get_error_code();
       
  3538 		$status['errorMessage'] = $skin->result->get_error_message();
       
  3539 		wp_send_json_error( $status );
       
  3540 	} elseif ( $skin->get_errors()->get_error_code() ) {
       
  3541 		$status['errorMessage'] = $skin->get_error_messages();
       
  3542 		wp_send_json_error( $status );
       
  3543 	} elseif ( is_array( $result ) && ! empty( $result[ $stylesheet ] ) ) {
       
  3544 
       
  3545 		// Theme is already at the latest version.
       
  3546 		if ( true === $result[ $stylesheet ] ) {
       
  3547 			$status['errorMessage'] = $upgrader->strings['up_to_date'];
       
  3548 			wp_send_json_error( $status );
       
  3549 		}
       
  3550 
       
  3551 		$theme = wp_get_theme( $stylesheet );
       
  3552 		if ( $theme->exists() ) {
       
  3553 			$status['newVersion'] = $theme->get( 'Version' );
       
  3554 		}
       
  3555 
       
  3556 		wp_send_json_success( $status );
       
  3557 	} elseif ( false === $result ) {
       
  3558 		global $wp_filesystem;
       
  3559 
       
  3560 		$status['errorCode']    = 'unable_to_connect_to_filesystem';
       
  3561 		$status['errorMessage'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
       
  3562 
       
  3563 		// Pass through the error from WP_Filesystem if one was raised.
       
  3564 		if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) {
       
  3565 			$status['errorMessage'] = esc_html( $wp_filesystem->errors->get_error_message() );
       
  3566 		}
       
  3567 
       
  3568 		wp_send_json_error( $status );
       
  3569 	}
       
  3570 
       
  3571 	// An unhandled error occurred.
       
  3572 	$status['errorMessage'] = __( 'Update failed.' );
       
  3573 	wp_send_json_error( $status );
       
  3574 }
       
  3575 
       
  3576 /**
       
  3577  * Ajax handler for deleting a theme.
       
  3578  *
       
  3579  * @since 4.6.0
       
  3580  *
       
  3581  * @see delete_theme()
       
  3582  *
       
  3583  * @global WP_Filesystem_Base $wp_filesystem Subclass
       
  3584  */
       
  3585 function wp_ajax_delete_theme() {
       
  3586 	check_ajax_referer( 'updates' );
       
  3587 
       
  3588 	if ( empty( $_POST['slug'] ) ) {
       
  3589 		wp_send_json_error( array(
       
  3590 			'slug'         => '',
       
  3591 			'errorCode'    => 'no_theme_specified',
       
  3592 			'errorMessage' => __( 'No theme specified.' ),
       
  3593 		) );
       
  3594 	}
       
  3595 
       
  3596 	$stylesheet = preg_replace( '/[^A-z0-9_\-]/', '', wp_unslash( $_POST['slug'] ) );
       
  3597 	$status     = array(
       
  3598 		'delete' => 'theme',
       
  3599 		'slug'   => $stylesheet,
       
  3600 	);
       
  3601 
       
  3602 	if ( ! current_user_can( 'delete_themes' ) ) {
       
  3603 		$status['errorMessage'] = __( 'Sorry, you are not allowed to delete themes on this site.' );
       
  3604 		wp_send_json_error( $status );
       
  3605 	}
       
  3606 
       
  3607 	if ( ! wp_get_theme( $stylesheet )->exists() ) {
       
  3608 		$status['errorMessage'] = __( 'The requested theme does not exist.' );
       
  3609 		wp_send_json_error( $status );
       
  3610 	}
       
  3611 
       
  3612 	// Check filesystem credentials. `delete_theme()` will bail otherwise.
       
  3613 	$url = wp_nonce_url( 'themes.php?action=delete&stylesheet=' . urlencode( $stylesheet ), 'delete-theme_' . $stylesheet );
       
  3614 	ob_start();
       
  3615 	$credentials = request_filesystem_credentials( $url );
       
  3616 	ob_end_clean();
       
  3617 	if ( false === $credentials || ! WP_Filesystem( $credentials ) ) {
       
  3618 		global $wp_filesystem;
       
  3619 
       
  3620 		$status['errorCode']    = 'unable_to_connect_to_filesystem';
       
  3621 		$status['errorMessage'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
       
  3622 
       
  3623 		// Pass through the error from WP_Filesystem if one was raised.
       
  3624 		if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) {
       
  3625 			$status['errorMessage'] = esc_html( $wp_filesystem->errors->get_error_message() );
       
  3626 		}
       
  3627 
       
  3628 		wp_send_json_error( $status );
       
  3629 	}
       
  3630 
       
  3631 	include_once( ABSPATH . 'wp-admin/includes/theme.php' );
       
  3632 
       
  3633 	$result = delete_theme( $stylesheet );
       
  3634 
       
  3635 	if ( is_wp_error( $result ) ) {
       
  3636 		$status['errorMessage'] = $result->get_error_message();
       
  3637 		wp_send_json_error( $status );
       
  3638 	} elseif ( false === $result ) {
       
  3639 		$status['errorMessage'] = __( 'Theme could not be deleted.' );
       
  3640 		wp_send_json_error( $status );
       
  3641 	}
       
  3642 
       
  3643 	wp_send_json_success( $status );
       
  3644 }
       
  3645 
       
  3646 /**
       
  3647  * Ajax handler for installing a plugin.
       
  3648  *
       
  3649  * @since 4.6.0
       
  3650  *
       
  3651  * @see Plugin_Upgrader
       
  3652  *
       
  3653  * @global WP_Filesystem_Base $wp_filesystem Subclass
       
  3654  */
       
  3655 function wp_ajax_install_plugin() {
       
  3656 	check_ajax_referer( 'updates' );
       
  3657 
       
  3658 	if ( empty( $_POST['slug'] ) ) {
       
  3659 		wp_send_json_error( array(
       
  3660 			'slug'         => '',
       
  3661 			'errorCode'    => 'no_plugin_specified',
       
  3662 			'errorMessage' => __( 'No plugin specified.' ),
       
  3663 		) );
       
  3664 	}
       
  3665 
       
  3666 	$status = array(
       
  3667 		'install' => 'plugin',
       
  3668 		'slug'    => sanitize_key( wp_unslash( $_POST['slug'] ) ),
       
  3669 	);
       
  3670 
       
  3671 	if ( ! current_user_can( 'install_plugins' ) ) {
       
  3672 		$status['errorMessage'] = __( 'Sorry, you are not allowed to install plugins on this site.' );
       
  3673 		wp_send_json_error( $status );
       
  3674 	}
       
  3675 
       
  3676 	include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
       
  3677 	include_once( ABSPATH . 'wp-admin/includes/plugin-install.php' );
       
  3678 
       
  3679 	$api = plugins_api( 'plugin_information', array(
       
  3680 		'slug'   => sanitize_key( wp_unslash( $_POST['slug'] ) ),
       
  3681 		'fields' => array(
       
  3682 			'sections' => false,
       
  3683 		),
       
  3684 	) );
       
  3685 
       
  3686 	if ( is_wp_error( $api ) ) {
       
  3687 		$status['errorMessage'] = $api->get_error_message();
       
  3688 		wp_send_json_error( $status );
       
  3689 	}
       
  3690 
       
  3691 	$status['pluginName'] = $api->name;
       
  3692 
       
  3693 	$skin     = new WP_Ajax_Upgrader_Skin();
       
  3694 	$upgrader = new Plugin_Upgrader( $skin );
       
  3695 	$result   = $upgrader->install( $api->download_link );
       
  3696 
       
  3697 	if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
       
  3698 		$status['debug'] = $skin->get_upgrade_messages();
       
  3699 	}
       
  3700 
       
  3701 	if ( is_wp_error( $result ) ) {
       
  3702 		$status['errorCode']    = $result->get_error_code();
       
  3703 		$status['errorMessage'] = $result->get_error_message();
       
  3704 		wp_send_json_error( $status );
       
  3705 	} elseif ( is_wp_error( $skin->result ) ) {
       
  3706 		$status['errorCode']    = $skin->result->get_error_code();
       
  3707 		$status['errorMessage'] = $skin->result->get_error_message();
       
  3708 		wp_send_json_error( $status );
       
  3709 	} elseif ( $skin->get_errors()->get_error_code() ) {
       
  3710 		$status['errorMessage'] = $skin->get_error_messages();
       
  3711 		wp_send_json_error( $status );
       
  3712 	} elseif ( is_null( $result ) ) {
       
  3713 		global $wp_filesystem;
       
  3714 
       
  3715 		$status['errorCode']    = 'unable_to_connect_to_filesystem';
       
  3716 		$status['errorMessage'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
       
  3717 
       
  3718 		// Pass through the error from WP_Filesystem if one was raised.
       
  3719 		if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) {
       
  3720 			$status['errorMessage'] = esc_html( $wp_filesystem->errors->get_error_message() );
       
  3721 		}
       
  3722 
       
  3723 		wp_send_json_error( $status );
       
  3724 	}
       
  3725 
       
  3726 	$install_status = install_plugin_install_status( $api );
       
  3727 	$pagenow = isset( $_POST['pagenow'] ) ? sanitize_key( $_POST['pagenow'] ) : '';
       
  3728 
       
  3729 	// If installation request is coming from import page, do not return network activation link.
       
  3730 	$plugins_url = ( 'import' === $pagenow ) ? admin_url( 'plugins.php' ) : network_admin_url( 'plugins.php' );
       
  3731 
       
  3732 	if ( current_user_can( 'activate_plugin', $install_status['file'] ) && is_plugin_inactive( $install_status['file'] ) ) {
       
  3733 		$status['activateUrl'] = add_query_arg( array(
       
  3734 			'_wpnonce' => wp_create_nonce( 'activate-plugin_' . $install_status['file'] ),
       
  3735 			'action'   => 'activate',
       
  3736 			'plugin'   => $install_status['file'],
       
  3737 		), $plugins_url );
       
  3738 	}
       
  3739 
       
  3740 	if ( is_multisite() && current_user_can( 'manage_network_plugins' ) && 'import' !== $pagenow ) {
       
  3741 		$status['activateUrl'] = add_query_arg( array( 'networkwide' => 1 ), $status['activateUrl'] );
       
  3742 	}
       
  3743 
       
  3744 	wp_send_json_success( $status );
       
  3745 }
       
  3746 
       
  3747 /**
       
  3748  * Ajax handler for updating a plugin.
       
  3749  *
       
  3750  * @since 4.2.0
       
  3751  *
       
  3752  * @see Plugin_Upgrader
       
  3753  *
       
  3754  * @global WP_Filesystem_Base $wp_filesystem Subclass
       
  3755  */
       
  3756 function wp_ajax_update_plugin() {
       
  3757 	check_ajax_referer( 'updates' );
       
  3758 
       
  3759 	if ( empty( $_POST['plugin'] ) || empty( $_POST['slug'] ) ) {
       
  3760 		wp_send_json_error( array(
       
  3761 			'slug'         => '',
       
  3762 			'errorCode'    => 'no_plugin_specified',
       
  3763 			'errorMessage' => __( 'No plugin specified.' ),
       
  3764 		) );
       
  3765 	}
       
  3766 
       
  3767 	$plugin = plugin_basename( sanitize_text_field( wp_unslash( $_POST['plugin'] ) ) );
       
  3768 
       
  3769 	$status = array(
       
  3770 		'update'     => 'plugin',
       
  3771 		'slug'       => sanitize_key( wp_unslash( $_POST['slug'] ) ),
       
  3772 		'oldVersion' => '',
       
  3773 		'newVersion' => '',
       
  3774 	);
       
  3775 
       
  3776 	if ( ! current_user_can( 'update_plugins' ) || 0 !== validate_file( $plugin ) ) {
       
  3777 		$status['errorMessage'] = __( 'Sorry, you are not allowed to update plugins for this site.' );
       
  3778 		wp_send_json_error( $status );
       
  3779 	}
       
  3780 
       
  3781 	$plugin_data          = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
       
  3782 	$status['plugin']     = $plugin;
       
  3783 	$status['pluginName'] = $plugin_data['Name'];
       
  3784 
  2896 	if ( $plugin_data['Version'] ) {
  3785 	if ( $plugin_data['Version'] ) {
       
  3786 		/* translators: %s: Plugin version */
  2897 		$status['oldVersion'] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
  3787 		$status['oldVersion'] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
  2898 	}
  3788 	}
  2899 
  3789 
  2900 	if ( ! current_user_can( 'update_plugins' ) ) {
       
  2901 		$status['error'] = __( 'You do not have sufficient permissions to update plugins on this site.' );
       
  2902  		wp_send_json_error( $status );
       
  2903 	}
       
  2904 
       
  2905 	check_ajax_referer( 'updates' );
       
  2906 
       
  2907 	include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
  3790 	include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
  2908 
  3791 
  2909 	$current = get_site_transient( 'update_plugins' );
  3792 	wp_update_plugins();
  2910 	if ( empty( $current ) ) {
  3793 
  2911 		wp_update_plugins();
  3794 	$skin     = new WP_Ajax_Upgrader_Skin();
  2912 	}
  3795 	$upgrader = new Plugin_Upgrader( $skin );
  2913 
  3796 	$result   = $upgrader->bulk_upgrade( array( $plugin ) );
  2914 	$upgrader = new Plugin_Upgrader( new Automatic_Upgrader_Skin() );
  3797 
  2915 	$result = $upgrader->bulk_upgrade( array( $plugin ) );
  3798 	if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
  2916 
  3799 		$status['debug'] = $skin->get_upgrade_messages();
  2917 	if ( is_array( $result ) ) {
  3800 	}
       
  3801 
       
  3802 	if ( is_wp_error( $skin->result ) ) {
       
  3803 		$status['errorCode']    = $skin->result->get_error_code();
       
  3804 		$status['errorMessage'] = $skin->result->get_error_message();
       
  3805 		wp_send_json_error( $status );
       
  3806 	} elseif ( $skin->get_errors()->get_error_code() ) {
       
  3807 		$status['errorMessage'] = $skin->get_error_messages();
       
  3808 		wp_send_json_error( $status );
       
  3809 	} elseif ( is_array( $result ) && ! empty( $result[ $plugin ] ) ) {
  2918 		$plugin_update_data = current( $result );
  3810 		$plugin_update_data = current( $result );
  2919 
  3811 
  2920 		/*
  3812 		/*
  2921 		 * If the `update_plugins` site transient is empty (e.g. when you update
  3813 		 * If the `update_plugins` site transient is empty (e.g. when you update
  2922 		 * two plugins in quick succession before the transient repopulates),
  3814 		 * two plugins in quick succession before the transient repopulates),
  2923 		 * this may be the return.
  3815 		 * this may be the return.
  2924 		 *
  3816 		 *
  2925 		 * Preferably something can be done to ensure `update_plugins` isn't empty.
  3817 		 * Preferably something can be done to ensure `update_plugins` isn't empty.
  2926 		 * For now, surface some sort of error here.
  3818 		 * For now, surface some sort of error here.
  2927 		 */
  3819 		 */
  2928 		if ( $plugin_update_data === true ) {
  3820 		if ( true === $plugin_update_data ) {
  2929  			wp_send_json_error( $status );
  3821 			$status['errorMessage'] = __( 'Plugin update failed.' );
  2930 		}
  3822 			wp_send_json_error( $status );
  2931 
  3823 		}
  2932 		$plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
  3824 
       
  3825 		$plugin_data = get_plugins( '/' . $result[ $plugin ]['destination_name'] );
       
  3826 		$plugin_data = reset( $plugin_data );
  2933 
  3827 
  2934 		if ( $plugin_data['Version'] ) {
  3828 		if ( $plugin_data['Version'] ) {
       
  3829 			/* translators: %s: Plugin version */
  2935 			$status['newVersion'] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
  3830 			$status['newVersion'] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
  2936 		}
  3831 		}
  2937 
       
  2938 		wp_send_json_success( $status );
  3832 		wp_send_json_success( $status );
  2939 	} else if ( is_wp_error( $result ) ) {
  3833 	} elseif ( false === $result ) {
  2940 		$status['error'] = $result->get_error_message();
  3834 		global $wp_filesystem;
  2941  		wp_send_json_error( $status );
  3835 
  2942 	} else if ( is_bool( $result ) && ! $result ) {
  3836 		$status['errorCode']    = 'unable_to_connect_to_filesystem';
  2943 		$status['errorCode'] = 'unable_to_connect_to_filesystem';
  3837 		$status['errorMessage'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
  2944 		$status['error'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
  3838 
       
  3839 		// Pass through the error from WP_Filesystem if one was raised.
       
  3840 		if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) {
       
  3841 			$status['errorMessage'] = esc_html( $wp_filesystem->errors->get_error_message() );
       
  3842 		}
       
  3843 
  2945 		wp_send_json_error( $status );
  3844 		wp_send_json_error( $status );
  2946 	}
  3845 	}
  2947 }
  3846 
  2948 
  3847 	// An unhandled error occurred.
  2949 /**
  3848 	$status['errorMessage'] = __( 'Plugin update failed.' );
  2950  * AJAX handler for saving a post from Press This.
  3849 	wp_send_json_error( $status );
  2951  *
  3850 }
  2952  * @since 4.2.0
  3851 
  2953  */
  3852 /**
  2954 function wp_ajax_press_this_save_post() {
  3853  * Ajax handler for deleting a plugin.
  2955 	if ( empty( $GLOBALS['wp_press_this'] ) ) {
  3854  *
  2956 		include( ABSPATH . 'wp-admin/includes/class-wp-press-this.php' );
  3855  * @since 4.6.0
  2957 	}
  3856  *
  2958 
  3857  * @see delete_plugins()
  2959 	$GLOBALS['wp_press_this']->save_post();
  3858  *
  2960 }
  3859  * @global WP_Filesystem_Base $wp_filesystem Subclass
  2961 
  3860  */
  2962 /**
  3861 function wp_ajax_delete_plugin() {
  2963  * AJAX handler for creating new category from Press This.
  3862 	check_ajax_referer( 'updates' );
  2964  *
  3863 
  2965  * @since 4.2.0
  3864 	if ( empty( $_POST['slug'] ) || empty( $_POST['plugin'] ) ) {
  2966  */
  3865 		wp_send_json_error( array(
  2967 function wp_ajax_press_this_add_category() {
  3866 			'slug'         => '',
  2968 	if ( empty( $GLOBALS['wp_press_this'] ) ) {
  3867 			'errorCode'    => 'no_plugin_specified',
  2969 		include( ABSPATH . 'wp-admin/includes/class-wp-press-this.php' );
  3868 			'errorMessage' => __( 'No plugin specified.' ),
  2970 	}
  3869 		) );
  2971 
  3870 	}
  2972 	$GLOBALS['wp_press_this']->add_category();
  3871 
  2973 }
  3872 	$plugin = plugin_basename( sanitize_text_field( wp_unslash( $_POST['plugin'] ) ) );
       
  3873 
       
  3874 	$status = array(
       
  3875 		'delete' => 'plugin',
       
  3876 		'slug'   => sanitize_key( wp_unslash( $_POST['slug'] ) ),
       
  3877 	);
       
  3878 
       
  3879 	if ( ! current_user_can( 'delete_plugins' ) || 0 !== validate_file( $plugin ) ) {
       
  3880 		$status['errorMessage'] = __( 'Sorry, you are not allowed to delete plugins for this site.' );
       
  3881 		wp_send_json_error( $status );
       
  3882 	}
       
  3883 
       
  3884 	$plugin_data          = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
       
  3885 	$status['plugin']     = $plugin;
       
  3886 	$status['pluginName'] = $plugin_data['Name'];
       
  3887 
       
  3888 	if ( is_plugin_active( $plugin ) ) {
       
  3889 		$status['errorMessage'] = __( 'You cannot delete a plugin while it is active on the main site.' );
       
  3890 		wp_send_json_error( $status );
       
  3891 	}
       
  3892 
       
  3893 	// Check filesystem credentials. `delete_plugins()` will bail otherwise.
       
  3894 	$url = wp_nonce_url( 'plugins.php?action=delete-selected&verify-delete=1&checked[]=' . $plugin, 'bulk-plugins' );
       
  3895 	ob_start();
       
  3896 	$credentials = request_filesystem_credentials( $url );
       
  3897 	ob_end_clean();
       
  3898 	if ( false === $credentials || ! WP_Filesystem( $credentials ) ) {
       
  3899 		global $wp_filesystem;
       
  3900 
       
  3901 		$status['errorCode']    = 'unable_to_connect_to_filesystem';
       
  3902 		$status['errorMessage'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.' );
       
  3903 
       
  3904 		// Pass through the error from WP_Filesystem if one was raised.
       
  3905 		if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) {
       
  3906 			$status['errorMessage'] = esc_html( $wp_filesystem->errors->get_error_message() );
       
  3907 		}
       
  3908 
       
  3909 		wp_send_json_error( $status );
       
  3910 	}
       
  3911 
       
  3912 	$result = delete_plugins( array( $plugin ) );
       
  3913 
       
  3914 	if ( is_wp_error( $result ) ) {
       
  3915 		$status['errorMessage'] = $result->get_error_message();
       
  3916 		wp_send_json_error( $status );
       
  3917 	} elseif ( false === $result ) {
       
  3918 		$status['errorMessage'] = __( 'Plugin could not be deleted.' );
       
  3919 		wp_send_json_error( $status );
       
  3920 	}
       
  3921 
       
  3922 	wp_send_json_success( $status );
       
  3923 }
       
  3924 
       
  3925 /**
       
  3926  * Ajax handler for searching plugins.
       
  3927  *
       
  3928  * @since 4.6.0
       
  3929  *
       
  3930  * @global string $s Search term.
       
  3931  */
       
  3932 function wp_ajax_search_plugins() {
       
  3933 	check_ajax_referer( 'updates' );
       
  3934 
       
  3935 	$pagenow = isset( $_POST['pagenow'] ) ? sanitize_key( $_POST['pagenow'] ) : '';
       
  3936 	if ( 'plugins-network' === $pagenow || 'plugins' === $pagenow ) {
       
  3937 		set_current_screen( $pagenow );
       
  3938 	}
       
  3939 
       
  3940 	/** @var WP_Plugins_List_Table $wp_list_table */
       
  3941 	$wp_list_table = _get_list_table( 'WP_Plugins_List_Table', array(
       
  3942 		'screen' => get_current_screen(),
       
  3943 	) );
       
  3944 
       
  3945 	$status = array();
       
  3946 
       
  3947 	if ( ! $wp_list_table->ajax_user_can() ) {
       
  3948 		$status['errorMessage'] = __( 'Sorry, you are not allowed to manage plugins for this site.' );
       
  3949 		wp_send_json_error( $status );
       
  3950 	}
       
  3951 
       
  3952 	// Set the correct requester, so pagination works.
       
  3953 	$_SERVER['REQUEST_URI'] = add_query_arg( array_diff_key( $_POST, array(
       
  3954 		'_ajax_nonce' => null,
       
  3955 		'action'      => null,
       
  3956 	) ), network_admin_url( 'plugins.php', 'relative' ) );
       
  3957 
       
  3958 	$GLOBALS['s'] = wp_unslash( $_POST['s'] );
       
  3959 
       
  3960 	$wp_list_table->prepare_items();
       
  3961 
       
  3962 	ob_start();
       
  3963 	$wp_list_table->display();
       
  3964 	$status['count'] = count( $wp_list_table->items );
       
  3965 	$status['items'] = ob_get_clean();
       
  3966 
       
  3967 	wp_send_json_success( $status );
       
  3968 }
       
  3969 
       
  3970 /**
       
  3971  * Ajax handler for searching plugins to install.
       
  3972  *
       
  3973  * @since 4.6.0
       
  3974  */
       
  3975 function wp_ajax_search_install_plugins() {
       
  3976 	check_ajax_referer( 'updates' );
       
  3977 
       
  3978 	$pagenow = isset( $_POST['pagenow'] ) ? sanitize_key( $_POST['pagenow'] ) : '';
       
  3979 	if ( 'plugin-install-network' === $pagenow || 'plugin-install' === $pagenow ) {
       
  3980 		set_current_screen( $pagenow );
       
  3981 	}
       
  3982 
       
  3983 	/** @var WP_Plugin_Install_List_Table $wp_list_table */
       
  3984 	$wp_list_table = _get_list_table( 'WP_Plugin_Install_List_Table', array(
       
  3985 		'screen' => get_current_screen(),
       
  3986 	) );
       
  3987 
       
  3988 	$status = array();
       
  3989 
       
  3990 	if ( ! $wp_list_table->ajax_user_can() ) {
       
  3991 		$status['errorMessage'] = __( 'Sorry, you are not allowed to manage plugins for this site.' );
       
  3992 		wp_send_json_error( $status );
       
  3993 	}
       
  3994 
       
  3995 	// Set the correct requester, so pagination works.
       
  3996 	$_SERVER['REQUEST_URI'] = add_query_arg( array_diff_key( $_POST, array(
       
  3997 		'_ajax_nonce' => null,
       
  3998 		'action'      => null,
       
  3999 	) ), network_admin_url( 'plugin-install.php', 'relative' ) );
       
  4000 
       
  4001 	$wp_list_table->prepare_items();
       
  4002 
       
  4003 	ob_start();
       
  4004 	$wp_list_table->display();
       
  4005 	$status['count'] = (int) $wp_list_table->get_pagination_arg( 'total_items' );
       
  4006 	$status['items'] = ob_get_clean();
       
  4007 
       
  4008 	wp_send_json_success( $status );
       
  4009 }
       
  4010 
       
  4011 /**
       
  4012  * Ajax handler for editing a theme or plugin file.
       
  4013  *
       
  4014  * @since 4.9.0
       
  4015  * @see wp_edit_theme_plugin_file()
       
  4016  */
       
  4017 function wp_ajax_edit_theme_plugin_file() {
       
  4018 	$r = wp_edit_theme_plugin_file( wp_unslash( $_POST ) ); // Validation of args is done in wp_edit_theme_plugin_file().
       
  4019 	if ( is_wp_error( $r ) ) {
       
  4020 		wp_send_json_error( array_merge(
       
  4021 			array(
       
  4022 				'code' => $r->get_error_code(),
       
  4023 				'message' => $r->get_error_message(),
       
  4024 			),
       
  4025 			(array) $r->get_error_data()
       
  4026 		) );
       
  4027 	} else {
       
  4028 		wp_send_json_success( array(
       
  4029 			'message' => __( 'File edited successfully.' ),
       
  4030 		) );
       
  4031 	}
       
  4032 }
       
  4033 
       
  4034 /**
       
  4035  * Ajax handler for exporting a user's personal data.
       
  4036  *
       
  4037  * @since 4.9.6
       
  4038  */
       
  4039 function wp_ajax_wp_privacy_export_personal_data() {
       
  4040 
       
  4041 	if ( empty( $_POST['id'] ) ) {
       
  4042 		wp_send_json_error( __( 'Missing request ID.' ) );
       
  4043 	}
       
  4044 	$request_id = (int) $_POST['id'];
       
  4045 
       
  4046 	if ( $request_id < 1 ) {
       
  4047 		wp_send_json_error( __( 'Invalid request ID.' ) );
       
  4048 	}
       
  4049 
       
  4050 	if ( ! current_user_can( 'export_others_personal_data' ) ) {
       
  4051 		wp_send_json_error( __( 'Invalid request.' ) );
       
  4052 	}
       
  4053 
       
  4054 	check_ajax_referer( 'wp-privacy-export-personal-data-' . $request_id, 'security' );
       
  4055 
       
  4056 	// Get the request data.
       
  4057 	$request = wp_get_user_request_data( $request_id );
       
  4058 
       
  4059 	if ( ! $request || 'export_personal_data' !== $request->action_name ) {
       
  4060 		wp_send_json_error( __( 'Invalid request type.' ) );
       
  4061 	}
       
  4062 
       
  4063 	$email_address = $request->email;
       
  4064 	if ( ! is_email( $email_address ) ) {
       
  4065 		wp_send_json_error( __( 'A valid email address must be given.' ) );
       
  4066 	}
       
  4067 
       
  4068 	if ( ! isset( $_POST['exporter'] ) ) {
       
  4069 		wp_send_json_error( __( 'Missing exporter index.' ) );
       
  4070 	}
       
  4071 	$exporter_index = (int) $_POST['exporter'];
       
  4072 
       
  4073 	if ( ! isset( $_POST['page'] ) ) {
       
  4074 		wp_send_json_error( __( 'Missing page index.' ) );
       
  4075 	}
       
  4076 	$page = (int) $_POST['page'];
       
  4077 
       
  4078 	$send_as_email = isset( $_POST['sendAsEmail'] ) ? ( 'true' === $_POST['sendAsEmail'] ) : false;
       
  4079 
       
  4080 	/**
       
  4081 	 * Filters the array of exporter callbacks.
       
  4082 	 *
       
  4083 	 * @since 4.9.6
       
  4084 	 *
       
  4085 	 * @param array $args {
       
  4086 	 *     An array of callable exporters of personal data. Default empty array.
       
  4087 	 *
       
  4088 	 *     @type array {
       
  4089 	 *         Array of personal data exporters.
       
  4090 	 *
       
  4091 	 *         @type string $callback               Callable exporter function that accepts an
       
  4092 	 *                                              email address and a page and returns an array
       
  4093 	 *                                              of name => value pairs of personal data.
       
  4094 	 *         @type string $exporter_friendly_name Translated user facing friendly name for the
       
  4095 	 *                                              exporter.
       
  4096 	 *     }
       
  4097 	 * }
       
  4098 	 */
       
  4099 	$exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() );
       
  4100 
       
  4101 	if ( ! is_array( $exporters ) ) {
       
  4102 		wp_send_json_error( __( 'An exporter has improperly used the registration filter.' ) );
       
  4103 	}
       
  4104 
       
  4105 	// Do we have any registered exporters?
       
  4106 	if ( 0 < count( $exporters ) ) {
       
  4107 		if ( $exporter_index < 1 ) {
       
  4108 			wp_send_json_error( __( 'Exporter index cannot be negative.' ) );
       
  4109 		}
       
  4110 
       
  4111 		if ( $exporter_index > count( $exporters ) ) {
       
  4112 			wp_send_json_error( __( 'Exporter index out of range.' ) );
       
  4113 		}
       
  4114 
       
  4115 		if ( $page < 1 ) {
       
  4116 			wp_send_json_error( __( 'Page index cannot be less than one.' ) );
       
  4117 		}
       
  4118 
       
  4119 		$exporter_keys = array_keys( $exporters );
       
  4120 		$exporter_key  = $exporter_keys[ $exporter_index - 1 ];
       
  4121 		$exporter      = $exporters[ $exporter_key ];
       
  4122 
       
  4123 		if ( ! is_array( $exporter ) ) {
       
  4124 			wp_send_json_error(
       
  4125 				/* translators: %s: array index */
       
  4126 				sprintf( __( 'Expected an array describing the exporter at index %s.' ), $exporter_key )
       
  4127 			);
       
  4128 		}
       
  4129 		if ( ! array_key_exists( 'exporter_friendly_name', $exporter ) ) {
       
  4130 			wp_send_json_error(
       
  4131 				/* translators: %s: array index */
       
  4132 				sprintf( __( 'Exporter array at index %s does not include a friendly name.' ), $exporter_key )
       
  4133 			);
       
  4134 		}
       
  4135 		if ( ! array_key_exists( 'callback', $exporter ) ) {
       
  4136 			wp_send_json_error(
       
  4137 				/* translators: %s: exporter friendly name */
       
  4138 				sprintf( __( 'Exporter does not include a callback: %s.' ), esc_html( $exporter['exporter_friendly_name'] ) )
       
  4139 			);
       
  4140 		}
       
  4141 		if ( ! is_callable( $exporter['callback'] ) ) {
       
  4142 			wp_send_json_error(
       
  4143 				/* translators: %s: exporter friendly name */
       
  4144 				sprintf( __( 'Exporter callback is not a valid callback: %s.' ), esc_html( $exporter['exporter_friendly_name'] ) )
       
  4145 			);
       
  4146 		}
       
  4147 
       
  4148 		$callback               = $exporter['callback'];
       
  4149 		$exporter_friendly_name = $exporter['exporter_friendly_name'];
       
  4150 
       
  4151 		$response = call_user_func( $callback, $email_address, $page );
       
  4152 		if ( is_wp_error( $response ) ) {
       
  4153 			wp_send_json_error( $response );
       
  4154 		}
       
  4155 
       
  4156 		if ( ! is_array( $response ) ) {
       
  4157 			wp_send_json_error(
       
  4158 				/* translators: %s: exporter friendly name */
       
  4159 				sprintf( __( 'Expected response as an array from exporter: %s.' ), esc_html( $exporter_friendly_name ) )
       
  4160 			);
       
  4161 		}
       
  4162 		if ( ! array_key_exists( 'data', $response ) ) {
       
  4163 			wp_send_json_error(
       
  4164 				/* translators: %s: exporter friendly name */
       
  4165 				sprintf( __( 'Expected data in response array from exporter: %s.' ), esc_html( $exporter_friendly_name ) )
       
  4166 			);
       
  4167 		}
       
  4168 		if ( ! is_array( $response['data'] ) ) {
       
  4169 			wp_send_json_error(
       
  4170 				/* translators: %s: exporter friendly name */
       
  4171 				sprintf( __( 'Expected data array in response array from exporter: %s.' ), esc_html( $exporter_friendly_name ) )
       
  4172 			);
       
  4173 		}
       
  4174 		if ( ! array_key_exists( 'done', $response ) ) {
       
  4175 			wp_send_json_error(
       
  4176 				/* translators: %s: exporter friendly name */
       
  4177 				sprintf( __( 'Expected done (boolean) in response array from exporter: %s.' ), esc_html( $exporter_friendly_name ) )
       
  4178 			);
       
  4179 		}
       
  4180 	} else {
       
  4181 		// No exporters, so we're done.
       
  4182 		$exporter_key = '';
       
  4183 
       
  4184 		$response = array(
       
  4185 			'data' => array(),
       
  4186 			'done' => true,
       
  4187 		);
       
  4188 	}
       
  4189 
       
  4190 	/**
       
  4191 	 * Filters a page of personal data exporter data. Used to build the export report.
       
  4192 	 *
       
  4193 	 * Allows the export response to be consumed by destinations in addition to Ajax.
       
  4194 	 *
       
  4195 	 * @since 4.9.6
       
  4196 	 *
       
  4197 	 * @param array  $response        The personal data for the given exporter and page.
       
  4198 	 * @param int    $exporter_index  The index of the exporter that provided this data.
       
  4199 	 * @param string $email_address   The email address associated with this personal data.
       
  4200 	 * @param int    $page            The page for this response.
       
  4201 	 * @param int    $request_id      The privacy request post ID associated with this request.
       
  4202 	 * @param bool   $send_as_email   Whether the final results of the export should be emailed to the user.
       
  4203 	 * @param string $exporter_key    The key (slug) of the exporter that provided this data.
       
  4204 	 */
       
  4205 	$response = apply_filters( 'wp_privacy_personal_data_export_page', $response, $exporter_index, $email_address, $page, $request_id, $send_as_email, $exporter_key );
       
  4206 
       
  4207 	if ( is_wp_error( $response ) ) {
       
  4208 		wp_send_json_error( $response );
       
  4209 	}
       
  4210 
       
  4211 	wp_send_json_success( $response );
       
  4212 }
       
  4213 
       
  4214 /**
       
  4215  * Ajax handler for erasing personal data.
       
  4216  *
       
  4217  * @since 4.9.6
       
  4218  */
       
  4219 function wp_ajax_wp_privacy_erase_personal_data() {
       
  4220 
       
  4221 	if ( empty( $_POST['id'] ) ) {
       
  4222 		wp_send_json_error( __( 'Missing request ID.' ) );
       
  4223 	}
       
  4224 
       
  4225 	$request_id = (int) $_POST['id'];
       
  4226 
       
  4227 	if ( $request_id < 1 ) {
       
  4228 		wp_send_json_error( __( 'Invalid request ID.' ) );
       
  4229 	}
       
  4230 
       
  4231 	// Both capabilities are required to avoid confusion, see `_wp_personal_data_removal_page()`.
       
  4232 	if ( ! current_user_can( 'erase_others_personal_data' ) || ! current_user_can( 'delete_users' ) ) {
       
  4233 		wp_send_json_error( __( 'Invalid request.' ) );
       
  4234 	}
       
  4235 
       
  4236 	check_ajax_referer( 'wp-privacy-erase-personal-data-' . $request_id, 'security' );
       
  4237 
       
  4238 	// Get the request data.
       
  4239 	$request = wp_get_user_request_data( $request_id );
       
  4240 
       
  4241 	if ( ! $request || 'remove_personal_data' !== $request->action_name ) {
       
  4242 		wp_send_json_error( __( 'Invalid request ID.' ) );
       
  4243 	}
       
  4244 
       
  4245 	$email_address = $request->email;
       
  4246 
       
  4247 	if ( ! is_email( $email_address ) ) {
       
  4248 		wp_send_json_error( __( 'Invalid email address in request.' ) );
       
  4249 	}
       
  4250 
       
  4251 	if ( ! isset( $_POST['eraser'] ) ) {
       
  4252 		wp_send_json_error( __( 'Missing eraser index.' ) );
       
  4253 	}
       
  4254 
       
  4255 	$eraser_index = (int) $_POST['eraser'];
       
  4256 
       
  4257 	if ( ! isset( $_POST['page'] ) ) {
       
  4258 		wp_send_json_error( __( 'Missing page index.' ) );
       
  4259 	}
       
  4260 
       
  4261 	$page = (int) $_POST['page'];
       
  4262 
       
  4263 	/**
       
  4264 	 * Filters the array of personal data eraser callbacks.
       
  4265 	 *
       
  4266 	 * @since 4.9.6
       
  4267 	 *
       
  4268 	 * @param array $args {
       
  4269 	 *     An array of callable erasers of personal data. Default empty array.
       
  4270 	 *
       
  4271 	 *     @type array {
       
  4272 	 *         Array of personal data exporters.
       
  4273 	 *
       
  4274 	 *         @type string $callback               Callable eraser that accepts an email address and
       
  4275 	 *                                              a page and returns an array with boolean values for
       
  4276 	 *                                              whether items were removed or retained and any messages
       
  4277 	 *                                              from the eraser, as well as if additional pages are
       
  4278 	 *                                              available.
       
  4279 	 *         @type string $exporter_friendly_name Translated user facing friendly name for the eraser.
       
  4280 	 *     }
       
  4281 	 * }
       
  4282 	 */
       
  4283 	$erasers = apply_filters( 'wp_privacy_personal_data_erasers', array() );
       
  4284 
       
  4285 	// Do we have any registered erasers?
       
  4286 	if ( 0 < count( $erasers ) ) {
       
  4287 
       
  4288 		if ( $eraser_index < 1 ) {
       
  4289 			wp_send_json_error( __( 'Eraser index cannot be less than one.' ) );
       
  4290 		}
       
  4291 
       
  4292 		if ( $eraser_index > count( $erasers ) ) {
       
  4293 			wp_send_json_error( __( 'Eraser index is out of range.' ) );
       
  4294 		}
       
  4295 
       
  4296 		if ( $page < 1 ) {
       
  4297 			wp_send_json_error( __( 'Page index cannot be less than one.' ) );
       
  4298 		}
       
  4299 
       
  4300 		$eraser_keys = array_keys( $erasers );
       
  4301 		$eraser_key  = $eraser_keys[ $eraser_index - 1 ];
       
  4302 		$eraser      = $erasers[ $eraser_key ];
       
  4303 
       
  4304 		if ( ! is_array( $eraser ) ) {
       
  4305 			/* translators: %d: array index */
       
  4306 			wp_send_json_error( sprintf( __( 'Expected an array describing the eraser at index %d.' ), $eraser_index ) );
       
  4307 		}
       
  4308 
       
  4309 		if ( ! array_key_exists( 'callback', $eraser ) ) {
       
  4310 			/* translators: %d: array index */
       
  4311 			wp_send_json_error( sprintf( __( 'Eraser array at index %d does not include a callback.' ), $eraser_index ) );
       
  4312 		}
       
  4313 
       
  4314 		if ( ! is_callable( $eraser['callback'] ) ) {
       
  4315 			/* translators: %d: array index */
       
  4316 			wp_send_json_error( sprintf( __( 'Eraser callback at index %d is not a valid callback.' ), $eraser_index ) );
       
  4317 		}
       
  4318 
       
  4319 		if ( ! array_key_exists( 'eraser_friendly_name', $eraser ) ) {
       
  4320 			/* translators: %d: array index */
       
  4321 			wp_send_json_error( sprintf( __( 'Eraser array at index %d does not include a friendly name.' ), $eraser_index ) );
       
  4322 		}
       
  4323 
       
  4324 		$callback             = $eraser['callback'];
       
  4325 		$eraser_friendly_name = $eraser['eraser_friendly_name'];
       
  4326 
       
  4327 		$response = call_user_func( $callback, $email_address, $page );
       
  4328 
       
  4329 		if ( is_wp_error( $response ) ) {
       
  4330 			wp_send_json_error( $response );
       
  4331 		}
       
  4332 
       
  4333 		if ( ! is_array( $response ) ) {
       
  4334 			wp_send_json_error(
       
  4335 				sprintf(
       
  4336 					/* translators: 1: eraser friendly name, 2: array index */
       
  4337 					__( 'Did not receive array from %1$s eraser (index %2$d).' ),
       
  4338 					esc_html( $eraser_friendly_name ),
       
  4339 					$eraser_index
       
  4340 				)
       
  4341 			);
       
  4342 		}
       
  4343 
       
  4344 		if ( ! array_key_exists( 'items_removed', $response ) ) {
       
  4345 			wp_send_json_error(
       
  4346 				sprintf(
       
  4347 					/* translators: 1: eraser friendly name, 2: array index */
       
  4348 					__( 'Expected items_removed key in response array from %1$s eraser (index %2$d).' ),
       
  4349 					esc_html( $eraser_friendly_name ),
       
  4350 					$eraser_index
       
  4351 				)
       
  4352 			);
       
  4353 		}
       
  4354 
       
  4355 		if ( ! array_key_exists( 'items_retained', $response ) ) {
       
  4356 			wp_send_json_error(
       
  4357 				sprintf(
       
  4358 					/* translators: 1: eraser friendly name, 2: array index */
       
  4359 					__( 'Expected items_retained key in response array from %1$s eraser (index %2$d).' ),
       
  4360 					esc_html( $eraser_friendly_name ),
       
  4361 					$eraser_index
       
  4362 				)
       
  4363 			);
       
  4364 		}
       
  4365 
       
  4366 		if ( ! array_key_exists( 'messages', $response ) ) {
       
  4367 			wp_send_json_error(
       
  4368 				sprintf(
       
  4369 					/* translators: 1: eraser friendly name, 2: array index */
       
  4370 					__( 'Expected messages key in response array from %1$s eraser (index %2$d).' ),
       
  4371 					esc_html( $eraser_friendly_name ),
       
  4372 					$eraser_index
       
  4373 				)
       
  4374 			);
       
  4375 		}
       
  4376 
       
  4377 		if ( ! is_array( $response['messages'] ) ) {
       
  4378 			wp_send_json_error(
       
  4379 				sprintf(
       
  4380 					/* translators: 1: eraser friendly name, 2: array index */
       
  4381 					__( 'Expected messages key to reference an array in response array from %1$s eraser (index %2$d).' ),
       
  4382 					esc_html( $eraser_friendly_name ),
       
  4383 					$eraser_index
       
  4384 				)
       
  4385 			);
       
  4386 		}
       
  4387 
       
  4388 		if ( ! array_key_exists( 'done', $response ) ) {
       
  4389 			wp_send_json_error(
       
  4390 				sprintf(
       
  4391 					/* translators: 1: eraser friendly name, 2: array index */
       
  4392 					__( 'Expected done flag in response array from %1$s eraser (index %2$d).' ),
       
  4393 					esc_html( $eraser_friendly_name ),
       
  4394 					$eraser_index
       
  4395 				)
       
  4396 			);
       
  4397 		}
       
  4398 	} else {
       
  4399 		// No erasers, so we're done.
       
  4400 		$eraser_key = '';
       
  4401 
       
  4402 		$response = array(
       
  4403 			'items_removed'  => false,
       
  4404 			'items_retained' => false,
       
  4405 			'messages'       => array(),
       
  4406 			'done'           => true,
       
  4407 		);
       
  4408 	}
       
  4409 
       
  4410 	/**
       
  4411 	 * Filters a page of personal data eraser data.
       
  4412 	 *
       
  4413 	 * Allows the erasure response to be consumed by destinations in addition to Ajax.
       
  4414 	 *
       
  4415 	 * @since 4.9.6
       
  4416 	 *
       
  4417 	 * @param array  $response        The personal data for the given exporter and page.
       
  4418 	 * @param int    $eraser_index    The index of the eraser that provided this data.
       
  4419 	 * @param string $email_address   The email address associated with this personal data.
       
  4420 	 * @param int    $page            The page for this response.
       
  4421 	 * @param int    $request_id      The privacy request post ID associated with this request.
       
  4422 	 * @param string $eraser_key      The key (slug) of the eraser that provided this data.
       
  4423 	 */
       
  4424 	$response = apply_filters( 'wp_privacy_personal_data_erasure_page', $response, $eraser_index, $email_address, $page, $request_id, $eraser_key );
       
  4425 
       
  4426 	if ( is_wp_error( $response ) ) {
       
  4427 		wp_send_json_error( $response );
       
  4428 	}
       
  4429 
       
  4430 	wp_send_json_success( $response );
       
  4431 }