Commit 89d52b995ee for woocommerce
commit 89d52b995eefe2db58b50ad1ccf8af9b3c3194c0
Author: Bero <1199991+bgrgicak@users.noreply.github.com>
Date: Fri Oct 30 08:58:36 2026 +0100
Add configured gallery video to shared product links (#70284)
diff --git a/plugins/woocommerce/changelog/add-open-graph-media b/plugins/woocommerce/changelog/add-open-graph-media
new file mode 100644
index 00000000000..3cb3c6344f3
--- /dev/null
+++ b/plugins/woocommerce/changelog/add-open-graph-media
@@ -0,0 +1,4 @@
+Significance: minor
+Type: add
+
+Include configured product gallery video in shared product links when gallery videos are enabled.
diff --git a/plugins/woocommerce/src/Internal/StructuredData/OpenGraphMarkup.php b/plugins/woocommerce/src/Internal/StructuredData/OpenGraphMarkup.php
index 4277ed8a18a..78c8bbe49a0 100644
--- a/plugins/woocommerce/src/Internal/StructuredData/OpenGraphMarkup.php
+++ b/plugins/woocommerce/src/Internal/StructuredData/OpenGraphMarkup.php
@@ -47,6 +47,11 @@ class OpenGraphMarkup {
'match' => '/^og:image(?::|$)/D',
'exists' => false,
),
+ 'video' => array(
+ 'detect' => '/^og:video(?::url)?$/D',
+ 'match' => '/^og:video(?::|$)/D',
+ 'exists' => false,
+ ),
);
$processor = new WP_HTML_Tag_Processor( $html );
diff --git a/plugins/woocommerce/src/Internal/StructuredData/ProductMediaSources.php b/plugins/woocommerce/src/Internal/StructuredData/ProductMediaSources.php
new file mode 100644
index 00000000000..11c56360036
--- /dev/null
+++ b/plugins/woocommerce/src/Internal/StructuredData/ProductMediaSources.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Product gallery video sources.
+ *
+ * @package WooCommerce
+ */
+
+declare( strict_types = 1 );
+
+namespace Automattic\WooCommerce\Internal\StructuredData;
+
+use Automattic\WooCommerce\Internal\ProductGallery\ProductMediaGallery;
+use WC_Product;
+
+defined( 'ABSPATH' ) || exit;
+
+/**
+ * Reads configured gallery video independently of its metadata output format.
+ *
+ * @internal
+ */
+class ProductMediaSources {
+
+ /**
+ * Find the first usable gallery video when product gallery videos are enabled.
+ *
+ * @since 11.4.0
+ *
+ * @param WC_Product $product Product being shared.
+ * @return array<string, array<string, string>>
+ */
+ public function get_sources( WC_Product $product ): array {
+ if ( ProductMediaGallery::is_feature_enabled() ) {
+ $videos = ProductMediaGallery::get_stored_video_gallery_items( $product );
+ $ids = array_filter( array_map( 'absint', array_merge( array_column( $videos, 'id' ), array_column( $videos, 'poster_id' ) ) ) );
+ if ( ! empty( $ids ) ) {
+ // Prime caches to reduce future queries.
+ _prime_post_caches( array_unique( $ids ), false, false );
+ }
+ }
+
+ $sources = array();
+ foreach ( ProductMediaGallery::get_product_media_gallery_items( $product, array( 'resolve_video_posters' => false ) ) as $item ) {
+ if ( 'video' !== ( $item['media_type'] ?? '' ) ) {
+ continue;
+ }
+ $id = (int) ( $item['id'] ?? 0 );
+ $url = $id ? wp_get_attachment_url( $id ) : ( $item['url'] ?? '' );
+ $metadata = $id ? wp_get_attachment_metadata( $id ) : array();
+ $metadata = is_array( $metadata ) ? $metadata : array();
+ if ( $id ) {
+ $metadata['type'] = get_post_mime_type( $id );
+ }
+ $source = self::get_media_details( is_string( $url ) ? $url : '', $metadata );
+ if ( $source ) {
+ $sources['video'] = $source;
+ break;
+ }
+ }
+
+ return $sources;
+ }
+
+ /**
+ * Validate a gallery video URL and its available MIME type and dimensions.
+ *
+ * @param string $url Media URL.
+ * @param array<string, mixed> $metadata Media details.
+ * @return array<string, string>
+ */
+ private static function get_media_details( string $url, array $metadata ): array {
+ $url = esc_url_raw( $url, array( 'http', 'https' ) );
+ if ( ! in_array( wp_parse_url( $url, PHP_URL_SCHEME ), array( 'http', 'https' ), true ) ) {
+ return array();
+ }
+ $details = array( 'url' => $url );
+ $type = $metadata['type'] ?? wp_check_filetype( (string) wp_parse_url( $url, PHP_URL_PATH ) )['type'];
+ if ( is_string( $type ) && 0 === strpos( $type, 'video/' ) ) {
+ $details['type'] = $type;
+ }
+ foreach ( array( 'width', 'height' ) as $dimension ) {
+ $value = $metadata[ $dimension ] ?? null;
+ if ( is_scalar( $value ) && ctype_digit( (string) $value ) && (int) $value > 0 ) {
+ $details[ $dimension ] = (string) $value;
+ }
+ }
+ return $details;
+ }
+}
diff --git a/plugins/woocommerce/src/Internal/StructuredData/ProductOpenGraphTags.php b/plugins/woocommerce/src/Internal/StructuredData/ProductOpenGraphTags.php
index bd63d2ed65d..b1fc6224db7 100644
--- a/plugins/woocommerce/src/Internal/StructuredData/ProductOpenGraphTags.php
+++ b/plugins/woocommerce/src/Internal/StructuredData/ProductOpenGraphTags.php
@@ -49,6 +49,18 @@ class ProductOpenGraphTags {
}
$tags[] = array( 'twitter:card' => $image ? 'summary_large_image' : 'summary' );
+ foreach ( wc_get_container()->get( ProductMediaSources::class )->get_sources( $product ) as $media => $source ) {
+ $root = 'og:' . $media;
+ $group = array();
+ foreach ( $source as $detail => $value ) {
+ $group[ 'url' === $detail ? $root : $root . ':' . $detail ] = $value;
+ }
+ if ( 'https' === wp_parse_url( $source['url'], PHP_URL_SCHEME ) ) {
+ $group[ $root . ':secure_url' ] = $source['url'];
+ }
+ $tags[] = $group;
+ }
+
return $tags;
}