Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
46 / 46
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
Video_Block_Email_Renderer
100.00% covered (success)
100.00%
46 / 46
100.00% covered (success)
100.00%
3 / 3
14
100.00% covered (success)
100.00%
1 / 1
 render
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
8
 render_link
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
3
 get_videopress_url
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2/**
3 * VideoPress video block email renderer class.
4 *
5 * @package automattic/jetpack-videopress
6 */
7
8namespace Automattic\Jetpack\VideoPress;
9
10/**
11 * Handles rendering VideoPress video blocks for email contexts.
12 */
13class Video_Block_Email_Renderer {
14
15    /**
16     * Render VideoPress video block for email.
17     *
18     * @param string $block_content     The original block HTML content.
19     * @param array  $parsed_block      The parsed block data including attributes.
20     * @param object $rendering_context Email rendering context.
21     *
22     * @return string
23     */
24    public static function render( $block_content, $parsed_block, $rendering_context ) {
25        // Validate input parameters and required dependencies.
26        if ( ! isset( $parsed_block['attrs'] ) || ! is_array( $parsed_block['attrs'] ) ||
27            ! class_exists( '\Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Embed' ) ) {
28            return '';
29        }
30
31        $attributes = $parsed_block['attrs'];
32
33        // Get the VideoPress URL from the guid attribute.
34        $videopress_url = self::get_videopress_url( $attributes );
35
36        if ( empty( $videopress_url ) ) {
37            return '';
38        }
39
40        // For private videos, render a simple link to the post since the video isn't accessible on VideoPress.
41        // The isPrivate attribute is pre-computed by the block editor based on video and site settings.
42        if ( isset( $attributes['isPrivate'] ) && true === $attributes['isPrivate'] ) {
43            return self::render_link( $parsed_block );
44        }
45
46        // Create a mock embed block structure that WooCommerce's embed renderer can handle.
47        // The embed renderer will detect VideoPress from the URL and render it appropriately.
48        $mock_embed_block = array(
49            'blockName' => 'core/embed',
50            'attrs'     => array(
51                'url'              => $videopress_url,
52                'providerNameSlug' => 'videopress',
53            ),
54            'innerHTML' => sprintf(
55                '<figure class="wp-block-embed is-type-video is-provider-videopress"><div class="wp-block-embed__wrapper">%s</div></figure>',
56                esc_url( $videopress_url )
57            ),
58        );
59
60        // Preserve email_attrs if present (used for spacing/width calculations).
61        if ( ! empty( $parsed_block['email_attrs'] ) ) {
62            $mock_embed_block['email_attrs'] = $parsed_block['email_attrs'];
63        }
64
65        // Use WooCommerce's core embed renderer.
66        // @phan-suppress-next-line PhanUndeclaredClassMethod -- Optional WooCommerce dependency, checked with class_exists() above.
67        $woo_embed_renderer = new \Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Embed();
68
69        // @phan-suppress-next-line PhanUndeclaredClassMethod -- Optional WooCommerce dependency, checked with class_exists() above.
70        return $woo_embed_renderer->render( $mock_embed_block['innerHTML'], $mock_embed_block, $rendering_context );
71    }
72
73    /**
74     * Render a simple link for private VideoPress videos in emails.
75     * Links to the post containing the video since private videos aren't accessible on VideoPress.
76     *
77     * @param array $parsed_block The parsed block data.
78     *
79     * @return string The rendered link HTML.
80     */
81    private static function render_link( $parsed_block ) {
82        $post_url = get_the_permalink();
83
84        if ( empty( $post_url ) ) {
85            return '';
86        }
87
88        $link_text = __( 'Visit the post to watch the video', 'jetpack-videopress-pkg' );
89
90        $link_html = sprintf(
91            '<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>',
92            esc_url( $post_url ),
93            esc_html( $link_text )
94        );
95
96        // Wrap with spacing if email_attrs are present.
97        $email_attrs = $parsed_block['email_attrs'] ?? array();
98        if ( ! empty( $email_attrs['padding'] ) ) {
99            $link_html = sprintf(
100                '<p style="padding: %s;">%s</p>',
101                esc_attr( $email_attrs['padding'] ),
102                $link_html
103            );
104        }
105
106        return $link_html;
107    }
108
109    /**
110     * Get the VideoPress URL from block attributes for email rendering.
111     *
112     * @param array $attributes Block attributes.
113     *
114     * @return string VideoPress URL or empty string.
115     */
116    private static function get_videopress_url( $attributes ) {
117        // Construct URL from guid attribute.
118        if ( ! empty( $attributes['guid'] ) ) {
119            $guid = $attributes['guid'];
120
121            // VideoPress guids are alphanumeric only (e.g., "nfbj0J36").
122            // Validate format to prevent any injection issues.
123            if ( preg_match( '/^[a-zA-Z0-9]+$/', $guid ) ) {
124                return 'https://videopress.com/v/' . $guid;
125            }
126        }
127
128        return '';
129    }
130}