: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @param string $screen_id The screen ID.
$response = apply_filters( 'heartbeat_received', $response, $data, $screen_id );
* Filters the Heartbeat response sent.
* @param array $response The Heartbeat response.
* @param string $screen_id The screen ID.
$response = apply_filters( 'heartbeat_send', $response, $screen_id );
* Fires when Heartbeat ticks in logged-in environments.
* Allows the transport to be easily replaced with long-polling.
* @param array $response The Heartbeat response.
* @param string $screen_id The screen ID.
do_action( 'heartbeat_tick', $response, $screen_id );
// Send the current time according to the server.
$response['server_time'] = time();
wp_send_json( $response );
* Handles getting revision diffs via AJAX.
function wp_ajax_get_revision_diffs() {
require ABSPATH . 'wp-admin/includes/revision.php';
$post = get_post( (int) $_REQUEST['post_id'] );
if ( ! current_user_can( 'edit_post', $post->ID ) ) {
// Really just pre-loading the cache here.
$revisions = wp_get_post_revisions( $post->ID, array( 'check_enabled' => false ) );
if ( function_exists( 'set_time_limit' ) ) {
foreach ( $_REQUEST['compare'] as $compare_key ) {
list( $compare_from, $compare_to ) = explode( ':', $compare_key ); // from:to
'fields' => wp_get_revision_ui_diff( $post, $compare_from, $compare_to ),
wp_send_json_success( $return );
* Handles auto-saving the selected color scheme for
* a user's own profile via AJAX.
* @global array $_wp_admin_css_colors
function wp_ajax_save_user_color_scheme() {
global $_wp_admin_css_colors;
check_ajax_referer( 'save-color-scheme', 'nonce' );
$color_scheme = sanitize_key( $_POST['color_scheme'] );
if ( ! isset( $_wp_admin_css_colors[ $color_scheme ] ) ) {
$previous_color_scheme = get_user_meta( get_current_user_id(), 'admin_color', true );
update_user_meta( get_current_user_id(), 'admin_color', $color_scheme );
'previousScheme' => 'admin-color-' . $previous_color_scheme,
'currentScheme' => 'admin-color-' . $color_scheme,
* Handles getting themes from themes_api() via AJAX.
* @global array $themes_allowedtags
* @global array $theme_field_defaults
function wp_ajax_query_themes() {
global $themes_allowedtags, $theme_field_defaults;
if ( ! current_user_can( 'install_themes' ) ) {
wp_unslash( $_REQUEST['request'] ),
(array) $theme_field_defaults,
'reviews_url' => true, // Explicitly request the reviews URL to be linked from the Add Themes screen.
if ( isset( $args['browse'] ) && 'favorites' === $args['browse'] && ! isset( $args['user'] ) ) {
$user = get_user_option( 'wporg_favorites' );
$old_filter = isset( $args['browse'] ) ? $args['browse'] : 'search';
/** This filter is documented in wp-admin/includes/class-wp-theme-install-list-table.php */
$args = apply_filters( 'install_themes_table_api_args_' . $old_filter, $args );
$api = themes_api( 'query_themes', $args );
if ( is_wp_error( $api ) ) {
$update_php = network_admin_url( 'update.php?action=install-theme' );
$installed_themes = search_theme_directories();
if ( false === $installed_themes ) {
$installed_themes = array();
foreach ( $installed_themes as $theme_slug => $theme_data ) {
if ( str_contains( $theme_slug, '/' ) ) {
unset( $installed_themes[ $theme_slug ] );
foreach ( $api->themes as &$theme ) {
$theme->install_url = add_query_arg(
'_wpnonce' => wp_create_nonce( 'install-theme_' . $theme->slug ),
if ( current_user_can( 'switch_themes' ) ) {
$theme->activate_url = add_query_arg(
'_wpnonce' => wp_create_nonce( 'enable-theme_' . $theme->slug ),
network_admin_url( 'themes.php' )
$theme->activate_url = add_query_arg(
'_wpnonce' => wp_create_nonce( 'switch-theme_' . $theme->slug ),
'stylesheet' => $theme->slug,
admin_url( 'themes.php' )
$is_theme_installed = array_key_exists( $theme->slug, $installed_themes );
// We only care about installed themes.
$theme->block_theme = $is_theme_installed && wp_get_theme( $theme->slug )->is_block_theme();
if ( ! is_multisite() && current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
$customize_url = $theme->block_theme ? admin_url( 'site-editor.php' ) : wp_customize_url( $theme->slug );
$theme->customize_url = add_query_arg(
'return' => urlencode( network_admin_url( 'theme-install.php', 'relative' ) ),
$theme->name = wp_kses( $theme->name, $themes_allowedtags );
$theme->author = wp_kses( $theme->author['display_name'], $themes_allowedtags );
$theme->version = wp_kses( $theme->version, $themes_allowedtags );
$theme->description = wp_kses( $theme->description, $themes_allowedtags );
$theme->stars = wp_star_rating(
'rating' => $theme->rating,
'number' => $theme->num_ratings,
$theme->num_ratings = number_format_i18n( $theme->num_ratings );
$theme->preview_url = set_url_scheme( $theme->preview_url );
$theme->compatible_wp = is_wp_version_compatible( $theme->requires );
$theme->compatible_php = is_php_version_compatible( $theme->requires_php );
wp_send_json_success( $api );
* Applies [embed] Ajax handlers to a string.
* @global WP_Post $post Global post object.
* @global WP_Embed $wp_embed WordPress Embed object.
* @global WP_Scripts $wp_scripts
* @global int $content_width
function wp_ajax_parse_embed() {
global $post, $wp_embed, $content_width;
if ( empty( $_POST['shortcode'] ) ) {
$post_id = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0;
$post = get_post( $post_id );
if ( ! $post || ! current_user_can( 'edit_post', $post->ID ) ) {
} elseif ( ! current_user_can( 'edit_posts' ) ) { // See WP_oEmbed_Controller::get_proxy_item_permissions_check().
$shortcode = wp_unslash( $_POST['shortcode'] );
preg_match( '/' . get_shortcode_regex() . '/s', $shortcode, $matches );
$atts = shortcode_parse_atts( $matches[3] );
if ( ! empty( $matches[5] ) ) {
} elseif ( ! empty( $atts['src'] ) ) {
$wp_embed->return_false_on_fail = true;
* Refresh oEmbeds cached outside of posts that are past their TTL.
* Posts are excluded because they have separate logic for refreshing
* their post meta caches. See WP_Embed::cache_oembed().
$wp_embed->usecache = false;
if ( is_ssl() && str_starts_with( $url, 'http://' ) ) {
* Admin is ssl and the user pasted non-ssl URL.
* Check if the provider supports ssl embeds and use that for the preview.
$ssl_shortcode = preg_replace( '%^(\\[embed[^\\]]*\\])http://%i', '$1https://', $shortcode );
$parsed = $wp_embed->run_shortcode( $ssl_shortcode );
// Set $content_width so any embeds fit in the destination iframe.
if ( isset( $_POST['maxwidth'] ) && is_numeric( $_POST['maxwidth'] ) && $_POST['maxwidth'] > 0 ) {
if ( ! isset( $content_width ) ) {
$content_width = (int) $_POST['maxwidth'];
$content_width = min( $content_width, (int) $_POST['maxwidth'] );
if ( $url && ! $parsed ) {
$parsed = $wp_embed->run_shortcode( $shortcode );
'type' => 'not-embeddable',
/* translators: %s: URL that could not be embedded. */
'message' => sprintf( __( '%s failed to embed.' ), '<code>' . esc_html( $url ) . '</code>' ),
if ( has_shortcode( $parsed, 'audio' ) || has_shortcode( $parsed, 'video' ) ) {
$mce_styles = wpview_media_sandbox_styles();
foreach ( $mce_styles as $style ) {
$styles .= sprintf( '<link rel="stylesheet" href="%s" />', $style );
$html = do_shortcode( $parsed );
if ( ! empty( $wp_scripts ) ) {
$wp_scripts->done = array();
wp_print_scripts( array( 'mediaelement-vimeo', 'wp-mediaelement' ) );
$scripts = ob_get_clean();
$parsed = $styles . $html . $scripts;
if ( ! empty( $no_ssl_support ) || ( is_ssl() && ( preg_match( '%<(iframe|script|embed) [^>]*src="http://%', $parsed ) ||
preg_match( '%<link [^>]*href="http://%', $parsed ) ) ) ) {
// Admin is ssl and the embed is not. Iframes, scripts, and other "active content" will be blocked.
'message' => __( 'This preview is unavailable in the editor.' ),
'attr' => $wp_embed->last_attr,
if ( str_contains( $parsed, 'class="wp-embedded-content' ) ) {
if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
$script_src = includes_url( 'js/wp-embed.js' );
$script_src = includes_url( 'js/wp-embed.min.js' );
$return['head'] = '<script src="' . $script_src . '"></script>';
$return['sandbox'] = true;
wp_send_json_success( $return );
* @global WP_Post $post Global post object.
* @global WP_Scripts $wp_scripts
function wp_ajax_parse_media_shortcode() {
global $post, $wp_scripts;
if ( empty( $_POST['shortcode'] ) ) {
$shortcode = wp_unslash( $_POST['shortcode'] );
// Only process previews for media related shortcodes:
$found_shortcodes = get_shortcode_tags_in_content( $shortcode );
$media_shortcodes = array(
$other_shortcodes = array_diff( $found_shortcodes, $media_shortcodes );
if ( ! empty( $other_shortcodes ) ) {
if ( ! empty( $_POST['post_ID'] ) ) {
$post = get_post( (int) $_POST['post_ID'] );
// The embed shortcode requires a post.
if ( ! $post || ! current_user_can( 'edit_post', $post->ID ) ) {
if ( in_array( 'embed', $found_shortcodes, true ) ) {
$parsed = do_shortcode( $shortcode );
if ( empty( $parsed ) ) {
'message' => __( 'No items found.' ),
$styles = wpview_media_sandbox_styles();
foreach ( $styles as $style ) {
$head .= '<link type="text/css" rel="stylesheet" href="' . $style . '">';
if ( ! empty( $wp_scripts ) ) {
$wp_scripts->done = array();
if ( 'playlist' === $_REQUEST['type'] ) {
wp_underscore_playlist_templates();
wp_print_scripts( 'wp-playlist' );
wp_print_scripts( array( 'mediaelement-vimeo', 'wp-mediaelement' ) );
'body' => ob_get_clean(),
* Handles destroying multiple open sessions for a user via AJAX.
function wp_ajax_destroy_sessions() {
$user = get_userdata( (int) $_POST['user_id'] );
if ( ! current_user_can( 'edit_user', $user->ID ) ) {
} elseif ( ! wp_verify_nonce( $_POST['nonce'], 'update-user_' . $user->ID ) ) {
'message' => __( 'Could not log out user sessions. Please try again.' ),
$sessions = WP_Session_Tokens::get_instance( $user->ID );
if ( get_current_user_id() === $user->ID ) {
$sessions->destroy_others( wp_get_session_token() );
$message = __( 'You are now logged out everywhere else.' );
$sessions->destroy_all();
/* translators: %s: User's display name. */
$message = sprintf( __( '%s has been logged out.' ), $user->display_name );
wp_send_json_success( array( 'message' => $message ) );