PluginProbe
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization / 4.2.13
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization v4.2.13
4.2.13 4.2.12 4.2.11 4.2.10 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 2.5.5 2.5.6 2.5.7 3.0.0 3.0.1 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.11.0 3.11.1 3.11.2 3.11.3 3.12.0 3.12.1 All 134 releases
optimole-wp / inc / video_player.php

video_player.php in Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization 4.2.13, at inc/video_player.php

400 lines 13.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Video Player
5 *
6 * @since 4.0.0
7 */
8 class Optml_Video_Player {
9
10 /**
11 * Block attributes
12 *
13 * @var array
14 */
15 private $block_attributes = [
16 'url' => [
17 'type' => 'string',
18 'default' => '',
19 ],
20 'primaryColor' => [
21 'type' => 'string',
22 'default' => '#577BF9',
23 ],
24 'aspectRatio' => [
25 'type' => 'string',
26 'default' => 'auto',
27 ],
28 'loop' => [
29 'type' => 'boolean',
30 'default' => false,
31 ],
32 'hideControls' => [
33 'type' => 'boolean',
34 'default' => false,
35 ],
36 ];
37
38 const LOCALIZATION_VAR = 'OMVideoPlayerBlock';
39
40 /**
41 * Icons
42 *
43 * @var array
44 */
45 private $icons = [
46 'play' => '<symbol id="optml-play-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--optml-ctrl-ico-col, #fff)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-play"><polygon points="6 3 20 12 6 21 6 3"/></symbol>',
47 'volume-mute' => '<symbol id="optml-volume-mute-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--optml-ctrl-ico-col, #fff)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-volume-x"><path d="M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z"/><line x1="22" x2="16" y1="9" y2="15"/><line x1="16" x2="22" y1="9" y2="15"/></symbol>',
48 'volume-high' => '<symbol id="optml-volume-high-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--optml-ctrl-ico-col, #fff)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-volume-2"><path d="M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z"/><path d="M16 9a5 5 0 0 1 0 6"/><path d="M19.364 18.364a9 9 0 0 0 0-12.728"/></symbol>',
49 'volume-low' => '<symbol id="optml-volume-low-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--optml-ctrl-ico-col, #fff)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-volume-1"><path d="M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z"/><path d="M16 9a5 5 0 0 1 0 6"/></symbol>',
50 'spinner' => '<symbol id="optml-loader-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--optml-ctrl-ico-col, #fff)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-loader"><path d="M12 2v4"/><path d="m16.2 7.8 2.9-2.9"/><path d="M18 12h4"/><path d="m16.2 16.2 2.9 2.9"/><path d="M12 18v4"/><path d="m4.9 19.1 2.9-2.9"/><path d="M2 12h4"/><path d="m4.9 4.9 2.9 2.9"/></symbol>',
51 'maximize' => '<symbol id="optml-maximize-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--optml-ctrl-ico-col, #fff)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize"><path d="M8 3H5a2 2 0 0 0-2 2v3"/><path d="M21 8V5a2 2 0 0 0-2-2h-3"/><path d="M3 16v3a2 2 0 0 0 2 2h3"/><path d="M16 21h3a2 2 0 0 0 2-2v-3"/></symbol>',
52 'minimize' => '<symbol id="optml-minimize-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--optml-ctrl-ico-col, #fff)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-minimize"><path d="M8 3v3a2 2 0 0 1-2 2H3"/><path d="M21 8h-3a2 2 0 0 1-2-2V3"/><path d="M3 16h3a2 2 0 0 1 2 2v3"/><path d="M16 21v-3a2 2 0 0 1 2-2h3"/></symbol>',
53 'pause' => '<symbol id="optml-pause-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--optml-ctrl-ico-col, #fff)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-pause"><rect x="14" y="4" width="4" height="16" rx="1"/><rect x="6" y="4" width="4" height="16" rx="1"/></symbol>',
54 ];
55
56 /**
57 * Constructor.
58 *
59 * @since 4.0.0
60 */
61 public function __construct() {
62 $settings = new Optml_Settings();
63
64 if ( ! $settings->is_connected() ) {
65 return;
66 }
67
68 add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_admin_video_player_assets' ] );
69 add_action( 'admin_head', [ $this, 'add_editor_player_icons' ] );
70 add_action( 'wp_enqueue_scripts', [ $this, 'maybe_enqueue_video_player_script' ] );
71 add_action( 'init', [ $this, 'register_video_player_block' ] );
72 }
73
74 /**
75 * Enqueue the admin video player assets.
76 *
77 * @since 4.0.0
78 */
79 public function enqueue_admin_video_player_assets() {
80 $asset_file = include OPTML_PATH . 'assets/build/video-player/editor/editor.asset.php';
81
82 if ( empty( $asset_file ) ) {
83 return;
84 }
85
86 $handle = 'optimole-video-player-editor';
87
88 wp_register_script(
89 $handle,
90 OPTML_URL . 'assets/build/video-player/editor/editor.js',
91 array_merge( $asset_file['dependencies'] ),
92 $asset_file['version'],
93 true
94 );
95
96 wp_localize_script( $handle, 'OMVideoPlayerBlock', $this->get_localization( true ) );
97 wp_enqueue_script( $handle );
98
99 wp_enqueue_style( $handle, OPTML_URL . 'assets/build/video-player/frontend/style-frontend.css', [], $asset_file['version'] );
100 }
101
102 /**
103 * Add the video player icons to the editor.
104 *
105 * @since 4.0.0
106 */
107 public function add_editor_player_icons() {
108 $screen = get_current_screen();
109 if ( ! $screen || ! $screen->is_block_editor() ) {
110 return;
111 }
112
113 $this->render_player_icons();
114 }
115
116 /**
117 * Maybe enqueue the video player component script.
118 *
119 * @since 4.0.0
120 */
121 public function maybe_enqueue_video_player_script() {
122 if ( ! has_block( 'optimole/video-player' ) ) {
123 return;
124 }
125
126 $this->enqueue_video_player_component_script();
127 $this->render_player_icons();
128 }
129
130 /**
131 * Enqueue the video player component script.
132 *
133 * @since 4.0.0
134 */
135 private function enqueue_video_player_component_script() {
136 $asset_file = include OPTML_PATH . 'assets/build/video-player/frontend/frontend.asset.php';
137
138 if ( empty( $asset_file ) ) {
139 return;
140 }
141
142 wp_register_script(
143 'optimole-video-player-component',
144 OPTML_URL . 'assets/build/video-player/frontend/frontend.js',
145 $asset_file['dependencies'],
146 );
147
148 wp_localize_script( 'optimole-video-player-component', self::LOCALIZATION_VAR, $this->get_localization() );
149 wp_enqueue_script( 'optimole-video-player-component' );
150
151 wp_enqueue_style(
152 'optimole-video-player-component',
153 OPTML_URL . 'assets/build/video-player/frontend/style-frontend.css',
154 [],
155 $asset_file['version']
156 );
157 }
158
159 /**
160 * Render the video player icons
161 *
162 * @since 4.0.0
163 */
164 private function render_player_icons() {
165 ?>
166 <svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
167 <?php foreach ( $this->icons as $icon_id => $icon_svg ) : ?>
168 <?php echo $icon_svg; ?>
169 <?php endforeach; ?>
170 </svg>
171 <?php
172 }
173
174 /**
175 * Register the video player block.
176 *
177 * @since 4.0.0
178 */
179 public function register_video_player_block() {
180 register_block_type(
181 'optimole/video-player',
182 [
183 'render_callback' => [ $this, 'render_video_player_block' ],
184 'attributes' => $this->block_attributes,
185 'supports' => [
186 'align' => true,
187 ],
188 ]
189 );
190 }
191
192 /**
193 * Render the video player block.
194 *
195 * @param array $attributes The block attributes.
196 * @return string The video player block markup.
197 *
198 * @since 4.0.0
199 */
200 public function render_video_player_block( $attributes, $content, $block ) {
201 $attributes = wp_parse_args( $attributes, $this->get_default_attributes() );
202
203 $style = [
204 '--om-primary-color' => $attributes['primaryColor'],
205 '--om-aspect-ratio' => $this->sanitize_aspect_ratio( $attributes['aspectRatio'] ),
206 ];
207
208 if ( isset( $attributes['style'] ) ) {
209 $style = array_merge( $style, $this->block_style_attributes_to_css_array( $attributes['style'] ) );
210 }
211
212 $css = array_map(
213 function ( $key, $value ) {
214 return $key . ': ' . $value;
215 },
216 array_keys( $style ),
217 $style
218 );
219
220 $tag_attributes = [
221 'video-src' => esc_url( $attributes['url'] ),
222 'loop' => $attributes['loop'] ? 'true' : 'false',
223 'hide-controls' => $attributes['hideControls'] ? 'true' : 'false',
224 'style' => esc_attr( implode( ';', $css ) ),
225 ];
226
227 $tag_attributes = array_map(
228 function ( $key, $value ) {
229 return $key . '="' . $value . '"';
230 },
231 array_keys( $tag_attributes ),
232 $tag_attributes
233 );
234
235 // Alignment and custom classes already come from block supports, so no attribute is forwarded here.
236 return sprintf(
237 '<div %s><optimole-video-player %s></optimole-video-player></div>',
238 get_block_wrapper_attributes(),
239 implode( ' ', $tag_attributes ),
240 );
241 }
242
243 /**
244 * Get the localization strings.
245 *
246 * @param boolean $editor Whether to get the localization for the editor.
247 * @return array The localization strings.
248 *
249 * @since 4.0.0
250 */
251 private function get_localization( $editor = false ) {
252 $strings = [
253 'play' => __( 'Play', 'optimole-wp' ),
254 'pause' => __( 'Pause', 'optimole-wp' ),
255 'mute' => __( 'Mute', 'optimole-wp' ),
256 'unmute' => __( 'Unmute', 'optimole-wp' ),
257 'fullscreen' => __( 'Fullscreen', 'optimole-wp' ),
258 'exitFullscreen' => __( 'Exit Fullscreen', 'optimole-wp' ),
259 ];
260
261 if ( ! $editor ) {
262 return $strings;
263 }
264
265 $options = new Optml_Settings();
266 $cdn_url = $options->get_cdn_url();
267
268 return array_merge(
269 $strings,
270 [
271 'domain' => $cdn_url,
272 'blockTitle' => __( 'Optimole Video', 'optimole-wp' ),
273 'blockDescription' => __( 'Optimole Video', 'optimole-wp' ),
274 'aspectRatioLabel' => __( 'Aspect Ratio', 'optimole-wp' ),
275 'urlLabel' => __( 'Video URL', 'optimole-wp' ),
276 'urlHelp' => __( 'Enter the URL of the video you want to display.', 'optimole-wp' ),
277 'editLabel' => __( 'Change URL', 'optimole-wp' ),
278 'loopLabel' => __( 'Loop Video', 'optimole-wp' ),
279 'hideControlsLabel' => __( 'Hide Video Controls Bar', 'optimole-wp' ),
280 // translators: %s is 'Optimole Dashboard'.
281 'invalidUrlError' => sprintf( __( 'Invalid URL. Please enter a valid video URL from %s', 'optimole-wp' ), '<a target="_blank" href="https://dashboard.optimole.com">' . __( 'Optimole Dashboard', 'optimole-wp' ) . '</a>' ),
282 'auto' => __( 'Auto', 'optimole-wp' ),
283 'save' => __( 'Save', 'optimole-wp' ),
284 'primaryColorLabel' => __( 'Controls color', 'optimole-wp' ),
285 ]
286 );
287 }
288
289 /**
290 * Convert the block style attributes to a css array.
291 *
292 * @param array $attributes The block attributes.
293 * @return array The css array.
294 *
295 * @since 4.0.0
296 */
297 private function block_style_attributes_to_css_array( $attributes ) {
298 $css = [];
299
300 if ( ! isset( $attributes['spacing'] ) || ! is_array( $attributes['spacing'] ) ) {
301 return $css;
302 }
303
304 $allowed_props = [ 'margin', 'padding' ];
305 $allowed_directions = [ 'top', 'right', 'bottom', 'left' ];
306
307 foreach ( $attributes['spacing'] as $css_prop_prefix => $values ) {
308 if ( ! in_array( $css_prop_prefix, $allowed_props, true ) || ! is_array( $values ) ) {
309 continue;
310 }
311
312 foreach ( $values as $direction => $value ) {
313 if ( ! in_array( $direction, $allowed_directions, true ) || ! is_string( $value ) ) {
314 continue;
315 }
316
317 $value = $this->core_var_to_css_var( $value );
318
319 if ( ! $this->is_safe_css_length( $value ) ) {
320 continue;
321 }
322
323 $css[ $css_prop_prefix . '-' . $direction ] = $value;
324 }
325 }
326
327 return $css;
328 }
329
330 /**
331 * Get the default value of every declared block attribute.
332 *
333 * @return array<string, mixed> The default attributes.
334 */
335 private function get_default_attributes() {
336 $defaults = [];
337
338 foreach ( $this->block_attributes as $name => $schema ) {
339 if ( ! isset( $schema['default'] ) ) {
340 continue;
341 }
342
343 $defaults[ $name ] = $schema['default'];
344 }
345
346 return $defaults;
347 }
348
349 /**
350 * Sanitize the player aspect ratio, falling back to the default when it is not a known one.
351 *
352 * @param mixed $aspect_ratio The aspect ratio to sanitize.
353 * @return string The sanitized aspect ratio.
354 */
355 private function sanitize_aspect_ratio( $aspect_ratio ) {
356 $allowed = [ 'auto', '16/9', '4/3', '1/1', '9/16', '1/2', '2/1' ];
357
358 if ( is_string( $aspect_ratio ) && in_array( $aspect_ratio, $allowed, true ) ) {
359 return $aspect_ratio;
360 }
361
362 return $this->block_attributes['aspectRatio']['default'];
363 }
364
365 /**
366 * Whether a value is a css length or a core preset variable.
367 *
368 * @param string $value The value to check.
369 * @return bool Whether the value is safe to use as a css length.
370 */
371 private function is_safe_css_length( $value ) {
372 if ( preg_match( '/^var\(--wp--[a-z0-9-]+\)$/i', $value ) ) {
373 return true;
374 }
375
376 // Number plus an optional unit; no css separator can pass this shape.
377 return (bool) preg_match( '/^-?(?:\d+|\d*\.\d+)(?:%|[a-z]{1,6})?$/i', $value );
378 }
379
380 /**
381 * Convert a core var to a css var.
382 * e.g.: var:preset|spacing|50 -> var(--wp--preset--spacing--50)
383 *
384 * @param string $css_value The css value.
385 * @return string The css var.
386 *
387 * @since 4.0.0
388 */
389 private function core_var_to_css_var( $css_value ) {
390 if ( strpos( $css_value, 'var:' ) !== 0 ) {
391 return $css_value;
392 }
393
394 $css_value = str_replace( 'var:', '', $css_value );
395 $css_value = str_replace( '|', '--', $css_value );
396
397 return 'var(--wp--' . $css_value . ')';
398 }
399 }
400