Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks

Embed::fetch_embed_page_dataprivateWC 1.0

Fetch metadata from a WordPress embed page.

WordPress sites expose a {url}/embed/ endpoint that renders a post preview containing the title, excerpt, featured image, provider name, and site icon. This single fetch provides all the data needed for the rich embed card.

Method of the class: Embed{}

Hooks from the method

Returns

Array{. title: string, thumbnail_url: string, provider_name: string, provider_url: string, excerpt: string, site_icon_url: string } Embed page metadata.

Usage

// private - for code of main (parent) class only
$result = $this->fetch_embed_page_data( $url ): array;
$url(string) (required)
URL of the post to fetch metadata for.

Embed::fetch_embed_page_data() code WC 10.8.1

private function fetch_embed_page_data( string $url ): array {
	$empty_result = array(
		'title'         => '',
		'thumbnail_url' => '',
		'provider_name' => '',
		'provider_url'  => '',
		'excerpt'       => '',
		'site_icon_url' => '',
	);

	$parsed = wp_parse_url( $url );
	if ( empty( $parsed['scheme'] ) || empty( $parsed['host'] ) ) {
		return $empty_result;
	}
	$embed_url = $parsed['scheme'] . '://' . $parsed['host']
		. ( isset( $parsed['port'] ) ? ':' . $parsed['port'] : '' )
		. trailingslashit( $parsed['path'] ?? '/' ) . 'embed/';

	if ( ! $this->is_valid_url( $embed_url ) ) {
		return $empty_result;
	}

	$cache_key = 'wc_email_embed_pg_' . md5( $url );
	$cached    = get_transient( $cache_key );

	if ( false !== $cached && is_array( $cached )
		&& isset( $cached['title'], $cached['thumbnail_url'], $cached['provider_name'], $cached['provider_url'], $cached['excerpt'], $cached['site_icon_url'] )
		&& is_string( $cached['title'] ) && is_string( $cached['thumbnail_url'] )
		&& is_string( $cached['provider_name'] ) && is_string( $cached['provider_url'] )
		&& is_string( $cached['excerpt'] ) && is_string( $cached['site_icon_url'] )
	) {
		return array(
			'title'         => $cached['title'],
			'thumbnail_url' => $cached['thumbnail_url'],
			'provider_name' => $cached['provider_name'],
			'provider_url'  => $cached['provider_url'],
			'excerpt'       => $cached['excerpt'],
			'site_icon_url' => $cached['site_icon_url'],
		);
	}
	if ( is_string( $cached ) ) {
		// Negative cache (empty string from previous failure).
		return $empty_result;
	}

	/** This filter is documented in packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-embed.php */
	$cache_ttl = (int) apply_filters( 'oembed_ttl', DAY_IN_SECONDS, $url, array(), '' );

	$response = wp_safe_remote_get(
		$embed_url,
		array(
			'timeout'             => 5,
			'limit_response_size' => 150 * KB_IN_BYTES,
		)
	);

	if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
		set_transient( $cache_key, '', $cache_ttl );
		return $empty_result;
	}

	$body = wp_remote_retrieve_body( $response );
	if ( empty( $body ) ) {
		set_transient( $cache_key, '', $cache_ttl );
		return $empty_result;
	}

	// Parse HTML and extract metadata using XPath.
	$previous_libxml_errors = libxml_use_internal_errors( true );
	try {
		$dom = new \DOMDocument();
		$dom->loadHTML( '<?xml encoding="UTF-8">' . $body, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD );
		libxml_clear_errors();
	} finally {
		libxml_use_internal_errors( $previous_libxml_errors );
	}

	$xpath = new \DOMXPath( $dom );

	// Extract title from wp-embed-heading.
	$title         = '';
	$heading_nodes = $xpath->query( "//*[contains(concat(' ', normalize-space(@class), ' '), ' wp-embed-heading ')]" );
	$heading_node  = ( false !== $heading_nodes && $heading_nodes->length > 0 ) ? $heading_nodes->item( 0 ) : null;
	if ( $heading_node instanceof \DOMElement ) {
		$title = trim( $heading_node->textContent ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
	}

	// Extract thumbnail from featured image.
	$thumbnail_url  = '';
	$featured_nodes = $xpath->query( "//*[contains(concat(' ', normalize-space(@class), ' '), ' wp-embed-featured-image ')]//img" );
	$featured_node  = ( false !== $featured_nodes && $featured_nodes->length > 0 ) ? $featured_nodes->item( 0 ) : null;
	if ( $featured_node instanceof \DOMElement ) {
		$img_src = $featured_node->getAttribute( 'src' );
		if ( $this->is_valid_url( $img_src ) ) {
			$thumbnail_url = $img_src;
		}
	}

	// Extract provider name from site title.
	$provider_name    = '';
	$site_title_nodes = $xpath->query( "//*[contains(concat(' ', normalize-space(@class), ' '), ' wp-embed-site-title ')]//span" );
	$site_title_node  = ( false !== $site_title_nodes && $site_title_nodes->length > 0 ) ? $site_title_nodes->item( 0 ) : null;
	if ( $site_title_node instanceof \DOMElement ) {
		$provider_name = trim( $site_title_node->textContent ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
	}

	// Extract provider URL from site title link.
	$provider_url    = '';
	$site_link_nodes = $xpath->query( "//*[contains(concat(' ', normalize-space(@class), ' '), ' wp-embed-site-title ')]//a" );
	$site_link_node  = ( false !== $site_link_nodes && $site_link_nodes->length > 0 ) ? $site_link_nodes->item( 0 ) : null;
	if ( $site_link_node instanceof \DOMElement ) {
		$href = $site_link_node->getAttribute( 'href' );
		if ( $this->is_valid_url( $href ) ) {
			$provider_url = $href;
		}
	}

	// Extract excerpt.
	$excerpt       = '';
	$excerpt_nodes = $xpath->query( "//*[contains(concat(' ', normalize-space(@class), ' '), ' wp-embed-excerpt ')]" );
	$excerpt_node  = ( false !== $excerpt_nodes && $excerpt_nodes->length > 0 ) ? $excerpt_nodes->item( 0 ) : null;
	if ( $excerpt_node instanceof \DOMElement ) {
		$excerpt = trim( $excerpt_node->textContent ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
	}

	// Cap at 200 characters as a safety limit.
	if ( mb_strlen( $excerpt ) > 200 ) {
		$excerpt = mb_substr( $excerpt, 0, 200 );
		$excerpt = rtrim( $excerpt ) . '…';
	}

	// Extract site icon URL.
	$site_icon_url = '';
	$icon_nodes    = $xpath->query( "//img[contains(concat(' ', normalize-space(@class), ' '), ' wp-embed-site-icon ')]" );
	$icon_node     = ( false !== $icon_nodes && $icon_nodes->length > 0 ) ? $icon_nodes->item( 0 ) : null;
	if ( $icon_node instanceof \DOMElement ) {
		$icon_src = $icon_node->getAttribute( 'src' );
		if ( $this->is_valid_url( $icon_src ) ) {
			$site_icon_url = $icon_src;
		}
	}

	$result = array(
		'title'         => $title,
		'thumbnail_url' => $thumbnail_url,
		'provider_name' => $provider_name,
		'provider_url'  => $provider_url,
		'excerpt'       => $excerpt,
		'site_icon_url' => $site_icon_url,
	);

	set_transient( $cache_key, $result, $cache_ttl );
	return $result;
}