函数文档

wp_ajax_parse_embed()

💡 云策文档标注

概述

wp_ajax_parse_embed() 是一个 WordPress Ajax 处理函数,用于解析并处理嵌入短代码,生成预览内容。它通过 POST 请求接收短代码字符串,执行权限检查、短代码解析、嵌入处理,并返回 JSON 响应,适用于编辑器中的嵌入预览功能。

关键要点

  • 函数通过 Ajax 处理 [embed] 短代码,用于在编辑器中预览嵌入内容。
  • 执行严格的权限检查:需要 edit_post 或 edit_posts 权限,确保用户有权访问相关文章。
  • 处理短代码解析:使用 get_shortcode_regex() 和 shortcode_parse_atts() 提取 URL 和属性。
  • 支持 SSL 处理:当管理员使用 SSL 时,尝试将 HTTP URL 转换为 HTTPS 以兼容安全环境。
  • 设置 content_width 以适配嵌入内容的宽度,基于 POST 参数 maxwidth。
  • 处理音频和视频短代码:添加必要的样式和脚本(如 mediaelement),确保媒体播放器正常工作。
  • 错误处理:在无法嵌入或 SSL 不匹配时,返回 JSON 错误响应,包含类型和消息。
  • 成功时返回包含解析后 HTML 和属性的 JSON 数据,可能附加 wp-embed.js 脚本用于嵌入内容。

代码示例

// 示例调用(假设通过 Ajax POST 请求)
// POST 数据应包含 'shortcode' 参数,例如 '[embed]https://example.com[/embed]'
// 可选参数:'post_ID' 和 'maxwidth'
// 函数内部处理并返回 JSON 响应,如:
// 成功:{ "success": true, "data": { "body": "<iframe...>", "attr": {...} } }
// 失败:{ "success": false, "data": { "type": "not-embeddable", "message": "..." } }

注意事项

  • 函数依赖于全局变量 $post、$wp_embed 和 $content_width,需确保在调用前正确初始化。
  • 权限检查基于 current_user_can(),确保仅授权用户可执行此操作,防止未授权访问。
  • SSL 处理逻辑:如果管理员使用 SSL 而 URL 为 HTTP,会尝试转换,但若提供者不支持 SSL,可能返回错误。
  • 音频和视频短代码处理时,会重置 $wp_scripts->done 并打印相关脚本,可能影响页面其他脚本加载。
  • 返回的 JSON 数据可能包含 'sandbox' 标志,用于指示是否需要 iframe 沙箱环境。

📄 原文内容

Applies Ajax handlers to a string.

Source

function wp_ajax_parse_embed() {
	global $post, $wp_embed, $content_width;

	if ( empty( $_POST['shortcode'] ) ) {
		wp_send_json_error();
	}

	$post_id = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0;

	if ( $post_id > 0 ) {
		$post = get_post( $post_id );

		if ( ! $post || ! current_user_can( 'edit_post', $post->ID ) ) {
			wp_send_json_error();
		}
		setup_postdata( $post );
	} elseif ( ! current_user_can( 'edit_posts' ) ) { // See WP_oEmbed_Controller::get_proxy_item_permissions_check().
		wp_send_json_error();
	}

	$shortcode = wp_unslash( $_POST['shortcode'] );

	preg_match( '/' . get_shortcode_regex() . '/s', $shortcode, $matches );
	$atts = shortcode_parse_atts( $matches[3] );

	if ( ! empty( $matches[5] ) ) {
		$url = $matches[5];
	} elseif ( ! empty( $atts['src'] ) ) {
		$url = $atts['src'];
	} else {
		$url = '';
	}

	$parsed                         = false;
	$wp_embed->return_false_on_fail = true;

	if ( 0 === $post_id ) {
		/*
		 * 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( '%^(\]*\])http://%i', '$1https://', $shortcode );
		$parsed        = $wp_embed->run_shortcode( $ssl_shortcode );

		if ( ! $parsed ) {
			$no_ssl_support = true;
		}
	}

	// 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'];
		} else {
			$content_width = min( $content_width, (int) $_POST['maxwidth'] );
		}
	}

	if ( $url && ! $parsed ) {
		$parsed = $wp_embed->run_shortcode( $shortcode );
	}

	if ( ! $parsed ) {
		wp_send_json_error(
			array(
				'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' ) ) {
		$styles     = '';
		$mce_styles = wpview_media_sandbox_styles();

		foreach ( $mce_styles as $style ) {
			$styles .= sprintf( '<link rel="stylesheet" href="%s" />', $style );
		}

		$html = do_shortcode( $parsed );

		global $wp_scripts;

		if ( ! empty( $wp_scripts ) ) {
			$wp_scripts->done = array();
		}

		ob_start();
		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.
		wp_send_json_error(
			array(
				'type'    => 'not-ssl',
				'message' => __( 'This preview is unavailable in the editor.' ),
			)
		);
	}

	$return = array(
		'body' => $parsed,
		'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' );
		} else {
			$script_src = includes_url( 'js/wp-embed.min.js' );
		}

		$return['head']    = '<script src="' . $script_src . '"></script>';
		$return['sandbox'] = true;
	}

	wp_send_json_success( $return );
}

Changelog

Version Description
4.0.0 Introduced.