Dashboard
PHP:
8.4.22
OS:
Linux
User:
provencez
/
/
home
/
provencez
/
www
/
wp-content
/
plugins
/
flexa-block
/
build
/
blocks
/
video-popup
📤 Upload
📝 New File
📁 New Folder
Close
Editing: render.php
<?php /** * Video Popup block — server-side render. * * CSS is generated at save time by Video_Popup_CSS and printed inline on the * front end. This file outputs the trigger (thumbnail / button / text) plus a * hidden lightbox container; view.ts injects the iframe/<video> into the player * on demand and removes it on close (so the video stops). The provider URL is * parsed to an embed base here and travels to view.ts in escaped data-* * attributes. Output is escaped; the play icon runs through HTML_Helpers::svg_kses. * * @package Flexa\Block * * @var array $attributes Block attributes. * @var string $content Save content (unused — dynamic block). * @var WP_Block $block Block instance. */ if ( ! defined( 'ABSPATH' ) ) { exit; } // phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- $attributes provided by WP block API. use Flexa\Block\HTML_Helpers; $block_id = $attributes['blockId'] ?? ''; if ( '' === $block_id ) { return; } $anchor = $attributes['anchor'] ?? ''; $source = in_array( $attributes['videoSource'] ?? 'youtube', [ 'youtube', 'vimeo', 'mp4' ], true ) ? $attributes['videoSource'] : 'youtube'; $url = trim( (string) ( $attributes['videoUrl'] ?? '' ) ); $display = 'inline' === ( $attributes['displayMode'] ?? 'popup' ) ? 'inline' : 'popup'; $trigger = in_array( $attributes['trigger'] ?? 'thumbnail', [ 'thumbnail', 'button', 'text' ], true ) ? $attributes['trigger'] : 'thumbnail'; // Inline mode always uses the thumbnail façade — it turns into the player in // place, so the button / text triggers (which belong to the popup) don't apply. if ( 'inline' === $display ) { $trigger = 'thumbnail'; } // --- Resolve the embed base URL + (for YouTube) a fallback thumbnail. -------- // The auto thumbnail uses maxresdefault.jpg (true 16:9, no baked-in letterbox // bars). hqdefault.jpg is 4:3 with black bars, which show through at 4:3 / 1:1. // When maxres is missing YouTube returns a 120×90 grey image (HTTP 200, so no // onerror fires) — view.ts detects that by naturalWidth and swaps to $yt_thumb_fb. $embed = ''; $yt_thumb = ''; $yt_thumb_fb = ''; if ( 'youtube' === $source ) { if ( preg_match( '~(?:youtube\.com/(?:watch\?v=|embed/|shorts/|v/)|youtu\.be/)([A-Za-z0-9_-]{11})~', $url, $m ) ) { $embed = 'https://www.youtube.com/embed/' . $m[1] . '?rel=0&playsinline=1'; $yt_thumb = 'https://img.youtube.com/vi/' . $m[1] . '/maxresdefault.jpg'; $yt_thumb_fb = 'https://img.youtube.com/vi/' . $m[1] . '/mqdefault.jpg'; } } elseif ( 'vimeo' === $source ) { if ( preg_match( '~vimeo\.com/(?:video/)?(\d+)~', $url, $m ) ) { $embed = 'https://player.vimeo.com/video/' . $m[1]; } } elseif ( 'mp4' === $source ) { $embed = $url; } // Nothing playable → don't render an empty, non-functional trigger. if ( '' === $embed ) { return; } $autoplay = false !== ( $attributes['autoplay'] ?? true ); // --- Play icon (shared with edit.tsx's fallback triangle). ------------------- $play_glyph = '<svg class="flexa-icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M8 5v14l11-7z" fill="currentColor" /></svg>'; $icon = $attributes['playIcon'] ?? []; $icon_html = ''; if ( 'upload' === ( $icon['source'] ?? 'none' ) && '' !== (string) ( $icon['url'] ?? '' ) ) { $icon_html = '<img class="flexa-icon" src="' . esc_url( $icon['url'] ) . '" alt="" width="24" height="24" loading="lazy" />'; } elseif ( '' !== (string) ( $icon['markup'] ?? '' ) ) { $icon_html = HTML_Helpers::svg_kses( $icon['markup'] ); } if ( '' === $icon_html ) { $icon_html = $play_glyph; } $play_html = '<span class="flexa-video-popup__play" aria-hidden="true">' . $icon_html . '</span>'; // --- Trigger markup ---------------------------------------------------------- $aria_label = esc_attr__( 'Play video', 'flexa-block' ); if ( 'button' === $trigger ) { $label = (string) ( $attributes['buttonText'] ?? 'Play Video' ); $trigger_html = '<button type="button" class="flexa-video-popup__trigger flexa-video-popup__button wp-element-button" aria-label="' . $aria_label . '">' . $play_html . '<span class="flexa-video-popup__button-text">' . esc_html( $label ) . '</span>' . '</button>'; } elseif ( 'text' === $trigger ) { $label = (string) ( $attributes['linkText'] ?? 'Watch the video' ); $trigger_html = '<button type="button" class="flexa-video-popup__trigger flexa-video-popup__text" aria-label="' . $aria_label . '">' . $play_html . '<span class="flexa-video-popup__text-label">' . esc_html( $label ) . '</span>' . '</button>'; } else { $thumb = $attributes['thumbnailImage'] ?? []; $thumb_url = (string) ( $thumb['url'] ?? '' ); $thumb_alt = (string) ( $thumb['alt'] ?? '' ); // Only the auto YouTube thumbnail carries a fallback (view.ts swaps it when // maxresdefault is missing); a user-picked image never does. $thumb_fb = ''; if ( '' === $thumb_url && '' !== $yt_thumb ) { $thumb_url = $yt_thumb; $thumb_fb = $yt_thumb_fb; } $fb_attr = '' !== $thumb_fb ? ' data-vp-fallback="' . esc_url( $thumb_fb ) . '"' : ''; $image_html = '' !== $thumb_url ? '<img class="flexa-video-popup__image" src="' . esc_url( $thumb_url ) . '" alt="' . esc_attr( $thumb_alt ) . '" loading="lazy" decoding="async"' . $fb_attr . ' />' : '<span class="flexa-video-popup__placeholder" aria-hidden="true"></span>'; $trigger_html = '<button type="button" class="flexa-video-popup__trigger flexa-video-popup__thumb" aria-label="' . $aria_label . '">' . '<span class="flexa-video-popup__media">' . $image_html . '<span class="flexa-video-popup__scrim" aria-hidden="true"></span>' . $play_html . '</span>' . '</button>'; } // --- Hidden lightbox container (popup mode only; view.ts injects the player on // demand). Inline mode plays inside the thumbnail media instead, so no lightbox. $lightbox_html = ''; if ( 'inline' !== $display ) { $lightbox_html = '<div class="flexa-video-popup__lightbox" role="dialog" aria-modal="true" aria-label="' . esc_attr__( 'Video', 'flexa-block' ) . '" hidden>' . '<div class="flexa-video-popup__backdrop"></div>' . '<div class="flexa-video-popup__dialog">' . '<button type="button" class="flexa-video-popup__close" aria-label="' . esc_attr__( 'Close', 'flexa-block' ) . '">×</button>' . '<div class="flexa-video-popup__player"></div>' . '</div>' . '</div>'; } // --- Wrapper ----------------------------------------------------------------- $classes = [ 'flexa-video-popup', 'flexa-video-popup--' . $trigger, 'flexa-video-popup-' . sanitize_html_class( $block_id ), ]; if ( 'inline' === $display ) { $classes[] = 'flexa-video-popup--inline'; } $classes = HTML_Helpers::build_wrapper_classes( $classes, $attributes ); $wrapper_args = [ 'class' => implode( ' ', $classes ) ]; if ( $anchor ) { $wrapper_args['id'] = sanitize_html_class( $anchor ); } $wrapper_attributes = get_block_wrapper_attributes( $wrapper_args ); $data_attrs = HTML_Helpers::build_data_attrs( $attributes ); $video_attrs = ' data-video-type="' . esc_attr( $source ) . '"'; $video_attrs .= ' data-video-src="' . esc_url( $embed ) . '"'; $video_attrs .= ' data-autoplay="' . ( $autoplay ? '1' : '0' ) . '"'; $video_attrs .= ' data-display-mode="' . esc_attr( $display ) . '"'; printf( '<div %1$s%2$s%3$s>%4$s%5$s</div>', $wrapper_attributes, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- built via get_block_wrapper_attributes. $video_attrs, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- values escaped with esc_attr/esc_url above. $data_attrs, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- keys sanitized, values escaped in helper. $trigger_html, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- icon via svg_kses, labels esc_html'd, src escaped above. $lightbox_html // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- static markup + esc_attr'd labels above. );
Save
Cancel