PluginProbe ʕ •ᴥ•ʔ
Presto Player / 2.2.3-beta1
Presto Player v2.2.3-beta1
4.4.1 4.4.0 4.3.3 4.3.2 4.3.1 4.3.0 4.2.4 4.2.3 4.2.2 4.2.0 4.2.1 trunk 1.10.0 1.10.1 1.10.2 1.11.0 1.12.0 1.13.0 1.14.0 1.14.1 1.5.10 1.5.11 1.5.12 1.5.13 1.5.14 1.5.15 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.10 1.6.11 1.6.12 1.6.13 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.13 2.0.14 2.0.15 2.0.16 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.2.0 2.2.1 2.2.2 2.2.3 2.2.3-beta1 2.3.0 2.3.1 2.3.2 2.3.3 3.0.0 3.0.0-beta1 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.1.0 3.1.1 3.1.2 3.1.3 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4
presto-player / inc / Support / Block.php
presto-player / inc / Support Last commit date
Block.php 2 years ago BlockFinder.php 5 years ago DynamicData.php 5 years ago HasOneRelationship.php 5 years ago Integration.php 5 years ago Utility.php 4 years ago
Block.php
694 lines
1 <?php
2
3 namespace PrestoPlayer\Support;
4
5
6 use PrestoPlayer\Plugin;
7 use PrestoPlayer\Models\Video;
8 use PrestoPlayer\Models\Player;
9 use PrestoPlayer\Models\Preset;
10 use PrestoPlayer\Models\AudioPreset;
11 use PrestoPlayer\Models\Setting;
12 use PrestoPlayer\WPackio\Enqueue;
13 use PrestoPlayer\Support\DynamicData;
14 use PrestoPlayer\Integrations\LearnDash\LearnDash;
15
16 use function cli\err;
17
18 class Block
19 {
20 protected $enqueue;
21 protected $assets;
22 protected $video_assets;
23 protected $name = '';
24 protected $template_name = 'video';
25 public $services;
26
27 /**
28 * Attributes
29 *
30 * @var array
31 */
32 protected $attributes = [
33 'color' => [
34 'type' => 'string',
35 'default' => '#00b3ff',
36 ],
37 'blockAlignment' => [
38 'type' => 'string',
39 ],
40 'autoplay' => [
41 'type' => 'boolean'
42 ],
43 'id' => [
44 'type' => 'number',
45 ],
46 'src' => [
47 'type' => 'string'
48 ],
49 'imageID' => [
50 'type' => 'number',
51 ],
52 'poster' => [
53 'type' => 'string',
54 ],
55 'content' => [
56 'type' => 'boolean',
57 ],
58 'pip' => [
59 'type' => 'boolean',
60 'default' => true
61 ],
62 'fullscreen' => [
63 'type' => 'boolean',
64 'default' => true
65 ],
66 'captions' => [
67 'type' => 'boolean',
68 'default' => false
69 ],
70 'hideControls' => [
71 'type' => 'boolean',
72 'default' => true
73 ],
74 'playLarge' => [
75 'type' => 'boolean',
76 'default' => true
77 ],
78 'chapters' => [
79 'type' => 'array',
80 'default' => []
81 ],
82 'overlays' => [
83 'type' => 'array',
84 'default' => []
85 ],
86 'speed' => [
87 'type' => 'boolean',
88 'default' => true
89 ],
90 ];
91
92 /**
93 * Attributes to pass to web component
94 */
95 protected $component_attributes = [
96 'preset',
97 'chapters',
98 'overlays',
99 'tracks',
100 'branding',
101 'blockAttributes',
102 'config',
103 'skin',
104 'analytics',
105 'automations',
106 'provider',
107 'video_id',
108 'videoAttributes',
109 'audioAttributes',
110 'provider_video_id',
111 'youtube'
112 ];
113
114
115 public function __construct(bool $isPremium = false, $version = 1)
116 {
117 do_action('presto_player_before_block_output', [$this, 'middleware']);
118 }
119
120 /**
121 * Register the block type
122 *
123 * @return void
124 */
125 public function register()
126 {
127 $this->registerBlockType();
128 }
129
130 public function additionalAttributes()
131 {
132 return [];
133 }
134
135 /**
136 * Register dynamic block type
137 *
138 * @return void
139 */
140 public function registerBlockType()
141 {
142 register_block_type(
143 "presto-player/$this->name",
144 [
145 'attributes' => wp_parse_args($this->additionalAttributes(), $this->attributes),
146 'render_callback' => [$this, 'html'],
147 ]
148 );
149 }
150
151 /**
152 * Middleware to run before outputting template
153 * Should the block load?
154 *
155 * @param array $attributes
156 * @param string $content
157 * @return boolean
158 */
159 public function middleware($attributes, $content)
160 {
161 return true;
162 }
163
164 /**
165 * Sanitize attributes function
166 * Let's a parent class sanitize attributes before displaying
167 *
168 * @param array $attributes
169 * @param array $default_config
170 * @return array
171 */
172 public function sanitizeAttributes($attributes, $default_config)
173 {
174 return [];
175 }
176
177 /**
178 * Allow overriding attributes
179 *
180 * @param array $attributes
181 * @return array
182 */
183 public function overrideAttributes($attributes)
184 {
185 return apply_filters("presto_video_block_attributes_override", $attributes, $this);
186 }
187
188 /**
189 * Must sanitize attributes
190 *
191 * @param array $attributes
192 * @return array
193 */
194 private function _sanitizeAttibutes($attributes)
195 {
196
197 // attribute overrides
198 $attributes = $this->overrideAttributes($attributes);
199
200 // video id
201 $id = !empty($attributes['id']) ? $attributes['id'] : 0;
202
203 if ('audio' === $this->name) {
204 $preset = $this->getAudioPreset(!empty($attributes['preset']) ? $attributes['preset'] : 0);
205 $preset->type = 'audio';
206 } else {
207 $preset = $this->getPreset(!empty($attributes['preset']) ? $attributes['preset'] : 0);
208 }
209 $branding = $this->getBranding($preset);
210 $class = $this->getClasses($attributes);
211 $playerClass = $this->getPlayerClasses($id, $preset);
212 $styles = $this->getPlayerStyles($preset, $branding);
213 $css = $this->getCSS($id);
214 $src = !empty($attributes['src']) ? $attributes['src'] : '';
215
216 // use title or source.
217 if (empty($attributes['title'])) {
218 $video = $id ? (new Video($id)) : false;
219 $attributes['title'] = $video ? $video->title : $src;
220 }
221
222 // Default config
223 $default_config = apply_filters(
224 'presto_player/block/default_attributes', [
225 'type' => $this->name,
226 'css' => wp_kses_post($css),
227 'class' => $class,
228 'is_hls' => $this->isHls($src),
229 'styles' => $styles,
230 'skin' => $preset->skin,
231 'playerClass' => $playerClass,
232 'id' => $id,
233 'src' => $src,
234 'autoplay' => !empty($attributes['autoplay']),
235 'playsInline' => !empty($attributes['playsInline']),
236 'poster' => !empty($attributes['poster']) ? $attributes['poster'] : '',
237 'branding' => $branding,
238 'youtube' => [
239 'noCookie' => (bool) Setting::get('youtube', 'nocookie'),
240 'channelId' => sanitize_text_field(Setting::get('youtube', 'channel_id')),
241 'show_count' => !empty($preset->action_bar['show_count'])
242 ],
243 'preload' => !empty($attributes['preload']) ? $attributes['preload'] : '',
244 'tracks' => !empty($attributes['tracks']) ? (array) $attributes['tracks'] : [],
245 'preset' => $preset ? $preset->toArray() : [],
246 'chapters' => !empty($attributes['chapters']) ? $attributes['chapters'] : [],
247 'overlays' => DynamicData::replaceItems(!empty($attributes['overlays']) ? $attributes['overlays'] : [], 'text'),
248 'blockAttributes' => $attributes,
249 'provider' => $this->name,
250 'analytics' => Setting::get('analytics', 'enable', false),
251 'automations' => Setting::get('performance', 'automations', true),
252 'title' => !empty($attributes['title']) ? html_entity_decode($attributes['title']) : '',
253 ], $attributes
254 );
255
256 return wp_parse_args(
257 $this->sanitizeAttributes($attributes, $default_config),
258 $default_config
259 );
260 }
261
262 /**
263 * Get CSS from settings
264 * Is it an HLS playlist
265 *
266 * @param string $src
267 * @return boolean
268 */
269 public function isHls($src)
270 {
271 $src = !empty($src) ? $src : '';
272 return \strpos($src, '.m3u8') !== false;
273 }
274
275 /**
276 * Get CSS from settings
277 * Validates before output
278 *
279 * @param integer $id
280 * @return string
281 */
282 public function getCSS($id)
283 {
284 return apply_filters(
285 'presto_player/player/css',
286 Utility::sanitizeCSS(
287 Setting::get('branding', 'player_css'),
288 $id
289 )
290 );
291 }
292
293 /**
294 * Gets the preset
295 *
296 * @param integer $id Preset ID
297 * @return \PrestoPlayer\Models\Preset
298 */
299 public function getPreset($id)
300 {
301 $preset = new Preset(!empty($id) ? $id : 0);
302 $preset_id = $preset->id;
303
304 if (empty($preset_id)) {
305 $preset = $preset->findWhere(['slug' => 'default']);
306 }
307
308 // replace watermark text.
309 if (!empty($preset->watermark['enabled'])) {
310 $watermark_text = [
311 'text' => DynamicData::replaceText($preset->watermark['text'])
312 ];
313
314 $preset->watermark = wp_parse_args($watermark_text, $preset->watermark);
315 }
316
317 return apply_filters('presto_player/presto_player_presets/data', $preset, 'video');
318 }
319
320 /**
321 * Gets the audio preset
322 *
323 * @param integer $id Preset ID
324 * @return \PrestoPlayer\Models\AudioPreset
325 */
326 public function getAudioPreset($id)
327 {
328 $preset = new AudioPreset(!empty($id) ? $id : 0);
329 $preset_id = $preset->id;
330
331 if (empty($preset_id)) {
332 $preset = $preset->findWhere(['slug' => 'default']);
333 }
334
335 return apply_filters('presto_player/presto_player_presets/data', $preset, 'audio');
336 }
337
338 /**
339 * Get player branding
340 *
341 * @param \PrestoPlayer\Models\Preset $preset
342 * @return array
343 */
344 public function getBranding($preset)
345 {
346 $branding = Player::getBranding();
347
348 // sanitize with sensible defaults
349 $branding['color'] = !empty($branding['color']) ? sanitize_hex_color($branding['color']) : 'rgba(43,51,63,.7)';
350 $branding['logo_width'] = !empty($branding['logo_width']) ? $branding['logo_width'] : 150;
351 $branding['logo'] = !empty($branding['logo']) && !$preset->hide_logo ? $branding['logo'] : '';
352
353 return $branding;
354 }
355
356 /**
357 * Get block classes
358 *
359 * @param array $attributes
360 * @return string
361 */
362 public function getClasses($attributes)
363 {
364 $block_alignment = isset($attributes['align']) ? sanitize_text_field($attributes['align']) : '';
365 return !empty($block_alignment) ? 'align' . $block_alignment : '';
366 }
367
368 /**
369 * Get player classes
370 *
371 * @param integer $id
372 * @param \PrestoPlayer\Models\Preset $preset
373 * @return string
374 */
375 public function getPlayerClasses($id, $preset)
376 {
377 $skin = $preset->skin;
378 $playerClass = 'presto-video-id-' . (int) $id;
379 $playerClass .= ' presto-preset-id-' . (int) $preset->id;
380
381 if (!empty($skin)) {
382 $playerClass .= ' skin-' . sanitize_text_field($skin);
383 }
384
385 $caption_style = $preset->caption_style;
386 if (!empty($caption_style)) {
387 $playerClass .= ' caption-style-' . sanitize_html_class($caption_style);
388 }
389
390 if (!empty($attributes['className'])) {
391 $playerClass .= ' ' . (string) $attributes['className'];
392 }
393
394 return $playerClass;
395 }
396
397 /**
398 * Get player styles
399 *
400 * @param \PrestoPlayer\Models\Preset $preset
401 * @param array $branding
402 * @return string
403 */
404 public function getPlayerStyles($preset, $branding)
405 {
406
407 // Set brand color.
408 $background_color = ( !empty($preset->background_color) ? sanitize_hex_color($preset->background_color) : "var(--presto-player-highlight-color, " . sanitize_hex_color($branding['color']) . ")" );
409 $styles = '--plyr-color-main: ' . $background_color . '; ';
410
411 // video
412 if ($preset->caption_background) {
413 $styles .= '--plyr-captions-background: ' . sanitize_hex_color($preset->caption_background) . '; ';
414 }
415 if ($preset->border_radius) {
416 $styles .= '--presto-player-border-radius: ' . (int) $preset->border_radius . 'px; ';
417 }
418
419 if ($branding['logo_width']) {
420 $styles .= '--presto-player-logo-width: ' . (int) $branding['logo_width'] . 'px; ';
421 }
422 if (!empty($preset->email_collection['border_radius'])) {
423 $styles .= '--presto-player-email-border-radius: ' . (int) $preset->email_collection['border_radius'] . 'px; ';
424 }
425
426 // audio
427 if ($preset->type === 'audio') {
428 if ($preset->background_color) {
429 $styles .= '--plyr-audio-controls-background: ' . sanitize_hex_color($preset->background_color) . ';';
430 } else {
431 $styles .= '--plyr-audio-controls-background: ' . sanitize_hex_color($branding['color']) . ';';
432 }
433
434 if ($preset->control_color) {
435 $styles .= '--plyr-audio-control-color: ' . sanitize_hex_color($preset->control_color) . ';';
436 $styles .= '--plyr-range-thumb-background: ' . sanitize_hex_color($preset->control_color) . ';';
437 $styles .= '--plyr-range-fill-background: ' . sanitize_hex_color($preset->control_color) . ';';
438 $styles .= '--plyr-audio-progress-buffered-background: ' . Utility::hex2rgba(sanitize_hex_color($preset->control_color), 0.35) . ';';
439 $styles .= '--plyr-range-thumb-shadow: 0 1px 1px ' . Utility::hex2rgba(sanitize_hex_color($preset->control_color), 0.15) . ', 0 0 0 1px ' . Utility::hex2rgba(sanitize_hex_color($preset->control_color), 0.2) . ';';
440 } else {
441 $styles .= '--plyr-audio-control-color: #ffffff;';
442 $styles .= '--plyr-range-thumb-background: #ffffff;';
443 $styles .= '--plyr-range-fill-background: #ffffff;';
444 $styles .= '--plyr-audio-progress-buffered-background: ' . Utility::hex2rgba(sanitize_hex_color(sanitize_hex_color('#dcdcdc')), 0.35) . ';';
445 }
446 }
447
448 return $styles;
449 }
450
451 /**
452 * Get block attributes
453 *
454 * @param array $attributes
455 * @return array
456 */
457 public function getAttributes($attributes)
458 {
459 return $this->_sanitizeAttibutes($attributes);
460 }
461
462 /**
463 * Dynamic block output
464 *
465 * @param array $attributes
466 * @param string $content
467 * @return void
468 */
469 public function html($attributes, $content)
470 {
471 global $presto_player_instance;
472 if ($presto_player_instance === null) {
473 $presto_player_instance = 0;
474 }
475 $presto_player_instance++;
476
477 // html middleware
478 $load = $this->middleware($attributes, $content);
479
480 if (is_feed()) {
481 return $this->getFeedHtml($attributes);
482 }
483
484 if (LearnDash::isEnabled()) {
485 if (!LearnDash::shouldVideoLoad()) {
486 return false;
487 }
488 }
489
490 // let integrations filter loading capabilities
491 if (!apply_filters('presto_player_load_video', $load, $attributes, $content, $this->name)) {
492 // allow a custom fallback
493 if ($fallback = apply_filters('presto_player_load_video_fallback', false, $attributes, $content, $this)) {
494 return wp_kses_post($fallback);
495 }
496 return $this->getFallbackHTMLForUnauthorizeAccess();
497 }
498
499 // get template data
500 $data = apply_filters('presto_player_block_data', $this->getAttributes($attributes), $this);
501
502
503 // need and id and src
504 if (empty($data['id']) && empty($data['src'])) {
505 return false;
506 }
507
508 // TODO: child template system
509 ob_start();
510
511 if (!empty($data['id'])) {
512 echo "<!--presto-player:video_id=" . (int) $data['id'] . "-->";
513 }
514
515 if (file_exists(PRESTO_PLAYER_PLUGIN_DIR . "templates/{$this->template_name}.php")) {
516 include PRESTO_PLAYER_PLUGIN_DIR . "templates/{$this->template_name}.php";
517 }
518
519 $this->initComponentScript($data['id'], $data, $presto_player_instance);
520 $this->iframeFallback($data);
521
522 // output schema markup for optimized seo
523 $this->outputVideoSchemaMarkup($this->getSchema($data));
524
525 $template = ob_get_contents();
526 ob_end_clean();
527
528 return $template;
529
530 }
531
532 /**
533 * Get json data for video schema.
534 * https://developers.google.com/search/docs/appearance/structured-data/video#video-object
535 *
536 * @param array $data the block data
537 *
538 * @return array|bool
539 */
540 public function getSchema($data)
541 {
542
543 if (isset($data) && empty($data['id'])) {
544 return false;
545 }
546
547 if ('audio' === $data['type']) {
548 return false;
549 }
550
551 $visibility = $data['blockAttributes']['visibility'] ?? false;
552 if ($visibility && 'private' === $visibility) {
553 return false;
554 }
555
556 $title = $data['title'] ?? get_the_title();
557 if (empty($title)) {
558 return false;
559 }
560
561 $poster = $data['poster'] ?? '';
562 if (empty($poster)) {
563 return false;
564 }
565
566 $video = new Video((int) $data['id']);
567
568 return array(
569 // required:
570 '@context' => 'https://schema.org',
571 '@type' => 'VideoObject',
572 'name' => wp_kses_post($title),
573 'thumbnailUrl' => esc_url($poster),
574 'uploadDate' => wp_date('c', strtotime($video->getCreatedAt())),
575 // recommended:
576 'contentUrl' => esc_url($data['src'] ?? ''),
577 );
578
579 }
580
581 /**
582 * Output video schema markup.
583 *
584 * @param array $data the block data
585 *
586 * @return void|bool
587 */
588 public function outputVideoSchemaMarkup($data)
589 {
590
591 if (empty($data)) {
592 return false;
593 }
594
595 ?>
596 <script type="application/ld+json">
597 <?php
598 echo wp_json_encode($data);
599 ?>
600 </script>
601 <?php
602 }
603
604 /**
605 * Dynamically initialize component via script tag
606 * We have to do this because we cannot send arrays or object in plain html
607 */
608 public function initComponentScript($id = 0, $data = [], $instance = 1)
609 {
610 if (!$id) {
611 return;
612 }
613 ?>
614 <script>
615 var player = document.querySelector('presto-player#presto-player-<?php echo (int) $instance; ?>');
616 player.video_id = <?php echo (int) $id; ?>;
617 <?php
618 $attributes = apply_filters('presto_player/component/attributes', $this->component_attributes, $data);
619 foreach ($attributes as $attribute) { ?>
620 <?php if (isset($data[$attribute])) { ?>
621 player.<?php echo sanitize_text_field($attribute); ?> = <?php echo wp_json_encode($data[$attribute]); ?>;
622 <?php } ?>
623 <?php } ?>
624 </script>
625 <?php
626 }
627
628 /**
629 * Adds an iframe fallback script to the page in case js loading fails
630 *
631 * @return void
632 */
633 public function iframeFallback($data)
634 {
635 // must be vimeo or youtube
636 if (in_array($data['provider'], ['youtube', 'vimeo'])) {
637 add_filter('presto_player/scripts/load_iframe_fallback', '__return_true');
638 }
639 }
640
641 /**
642 * This function return HTML for unauthorized access or curtain.
643 *
644 * @return void
645 */
646 public function getFallbackHTMLForUnauthorizeAccess()
647 {
648 // Get the branding CSS variable.
649 $data = $this->getAttributes([]);
650 ob_start();
651 if (file_exists(PRESTO_PLAYER_PLUGIN_DIR . "templates/unauthorized.php")) {
652 include PRESTO_PLAYER_PLUGIN_DIR . "templates/unauthorized.php";
653 }
654 $template = ob_get_contents();
655 ob_end_clean();
656 return $template;
657 }
658
659 /**
660 * Return fallback html for feeds.
661 *
662 * @param array $atts array of attributes.
663 */
664 public function getFeedHtml($atts)
665 {
666 if (is_feed()) {
667 ob_start(); ?>
668
669 <?php if (in_array($this->name, array('self-hosted', 'bunny')) && !empty($atts['src'])) { ?>
670 <video controls preload="none">
671 <source src="<?php echo esc_url($atts['src']); ?>" />
672 </video>
673 <?php } ?>
674
675 <?php if ('audio' === $this->name && !empty($atts['src'])) { ?>
676 <audio controls preload="none">
677 <source src="<?php echo esc_url($atts['src']); ?>" />
678 </audio>
679 <?php } ?>
680
681 <?php if ('youtube' === $this->name && !empty($atts['video_id'])) { ?>
682 <?php echo wp_oembed_get('https://www.youtube.com/watch?v=' . $atts['video_id']); ?>
683 <?php } ?>
684
685 <?php if ('vimeo' === $this->name && !empty($atts['video_id'])) { ?>
686 <?php echo wp_oembed_get('https://vimeo.com/' . $atts['video_id']); ?>
687 <?php } ?>
688
689 <?php
690 return ob_get_clean();
691 }
692 }
693 }
694