PluginProbe ʕ •ᴥ•ʔ
Presto Player / 4.3.1
Presto Player v4.3.1
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 / Services / Scripts.php
presto-player / inc / Services Last commit date
API 1 month ago Blocks 10 months ago License 1 month ago AdminNotice.php 3 weeks ago AdminNotices.php 3 weeks ago AjaxActions.php 3 weeks ago Blocks.php 1 year ago Compatibility.php 10 months ago Learn.php 1 month ago Menu.php 1 month ago Migrations.php 1 year ago NpsSurvey.php 5 months ago Onboarding.php 3 weeks ago Player.php 4 days ago PluginInstaller.php 1 month ago PreloadService.php 1 year ago ProCompatibility.php 1 month ago ReusableVideos.php 2 weeks ago RewriteRulesManager.php 1 year ago Scripts.php 2 weeks ago Settings.php 1 month ago Shortcodes.php 1 month ago Streamer.php 3 weeks ago Translation.php 3 weeks ago Usage.php 3 weeks ago VideoPostType.php 2 weeks ago
Scripts.php
562 lines
1 <?php
2 /**
3 * Scripts Service for Presto Player.
4 *
5 * This file contains the Scripts class which handles registration and enqueuing of scripts and styles.
6 *
7 * @package PrestoPlayer
8 * @subpackage Services
9 */
10
11 namespace PrestoPlayer\Services;
12
13 use PrestoPlayer\Plugin;
14 use PrestoPlayer\Models\Block;
15 use PrestoPlayer\Models\Setting;
16 use PrestoPlayer\Pro\Services\API\RestBunnyTranscriptionController;
17 use PrestoPlayer\Services\License\License;
18
19 /**
20 * Scripts class for handling script and style registration and enqueuing.
21 */
22 class Scripts {
23
24 /**
25 * Register scripts used throughout the plugin.
26 *
27 * @return void
28 */
29 public function register() {
30 add_action( 'enqueue_block_assets', array( $this, 'registerPrestoComponents' ) );
31 add_action( 'init', array( $this, 'registerPrestoComponents' ) );
32 add_filter( 'script_loader_tag', array( $this, 'prestoComponentsTag' ), 10, 3 );
33
34 // block assets.
35 add_action( 'enqueue_block_editor_assets', array( $this, 'blockEditorAssets' ) );
36 add_action( 'enqueue_block_assets', array( $this, 'blockAssets' ) );
37 add_filter( 'block_editor_settings_all', array( $this, 'iframeCdnFix' ) );
38
39 // learndash.
40 add_action( 'admin_enqueue_scripts', array( $this, 'learndashAdminScripts' ) );
41
42 // elementor editor scripts.
43 add_action( 'elementor/frontend/before_enqueue_scripts', array( $this, 'elementorPreviewScripts' ) );
44 add_action( 'elementor/frontend/before_enqueue_scripts', array( $this, 'blockAssets' ) );
45
46 add_action( 'after_setup_theme', array( $this, 'addAppearanceToolsSupport' ), 99999 );
47
48 // custom template styles.
49 add_action( 'wp_enqueue_scripts', array( $this, 'presto_player_custom_template_styles' ) );
50
51 add_action( 'wp_enqueue_scripts', array( $this, 'registerPopupScript' ) );
52 }
53
54 /**
55 * Add support for Appearance Tools.
56 *
57 * @return void
58 */
59 public function addAppearanceToolsSupport() {
60 add_theme_support( 'appearance-tools' );
61 add_theme_support( 'border' );
62 }
63
64 /**
65 * Enqueue LearnDash admin scripts.
66 *
67 * @param string $hook_suffix The current admin page.
68 * @return void
69 */
70 public function learndashAdminScripts( $hook_suffix ) {
71 global $post_type;
72
73 // must be on learndash page.
74 if ( ! in_array( $post_type, array( 'sfwd-lessons', 'sfwd-topic' ), true ) ) {
75 return;
76 }
77
78 // must be on new post page.
79 if ( ! in_array( $hook_suffix, array( 'post.php', 'post-new.php' ), true ) ) {
80 return;
81 }
82
83 $assets = include trailingslashit( PRESTO_PLAYER_PLUGIN_DIR ) . 'dist/learndash.asset.php';
84 wp_enqueue_script(
85 'surecart/learndash/admin',
86 trailingslashit( PRESTO_PLAYER_PLUGIN_URL ) . 'dist/learndash.js',
87 array_merge( array( 'jquery' ), $assets['dependencies'] ),
88 $assets['version'],
89 true
90 );
91 }
92
93 /**
94 * Add a type="module" to our components tag to lazy load them.
95 *
96 * @param string $tag The <script> tag for the enqueued script.
97 * @param string $handle The script's registered handle.
98 * @param string $source The script's source URL.
99 * @return string The modified script tag.
100 */
101 public function prestoComponentsTag( $tag, $handle, $source ) {
102 if ( 'presto-components' === $handle ) {
103 // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
104 $tag = '<script src="' . $source . '" type="module" defer></script>';
105 }
106
107 return $tag;
108 }
109
110 /**
111 * Register our components.
112 *
113 * @return void
114 */
115 public function registerPrestoComponents() {
116
117 $file = is_admin() || ! Setting::get( 'performance', 'module_enabled' ) ? 'src/player/player-static.js' : 'dist/components/web-components/web-components.esm.js';
118
119 wp_register_script(
120 'hls.js',
121 PRESTO_PLAYER_PLUGIN_URL . 'src/libraries/hls.min.js',
122 array(),
123 '1.4.8',
124 true
125 );
126
127 $deps = array(
128 'jquery',
129 'wp-hooks',
130 'wp-i18n',
131 );
132
133 if ( is_admin() ) {
134 $deps[] = 'hls.js';
135 }
136
137 wp_register_script(
138 'presto-components',
139 PRESTO_PLAYER_PLUGIN_URL . $file,
140 $deps,
141 filemtime( PRESTO_PLAYER_PLUGIN_DIR . $file ),
142 true
143 );
144
145 wp_localize_script(
146 'presto-components',
147 'prestoComponents',
148 array(
149 'url' => PRESTO_PLAYER_PLUGIN_URL . 'dist/components/web-components/web-components.esm.js?ver=' . filemtime( PRESTO_PLAYER_PLUGIN_DIR . 'dist/components/web-components/web-components.esm.js' ),
150 )
151 );
152
153 if ( function_exists( 'wp_set_script_translations' ) ) {
154 wp_set_script_translations( 'presto-components', 'presto-player' );
155 }
156
157 wp_localize_script(
158 'presto-components',
159 'prestoPlayer',
160 apply_filters(
161 'presto-settings-block-js-options',
162 array(
163 'plugin_url' => esc_url_raw( trailingslashit( PRESTO_PLAYER_PLUGIN_URL ) ),
164 'logged_in' => is_user_logged_in(),
165 'root' => esc_url_raw( get_rest_url() ),
166 'nonce' => wp_create_nonce( 'wp_rest' ),
167 'ajaxurl' => admin_url( 'admin-ajax.php' ),
168 'isAdmin' => is_admin(),
169 'isSetup' => array(
170 'bunny' => false,
171 ),
172 'proVersion' => Plugin::proVersion(),
173 'isPremium' => Plugin::isPro(),
174 'isProPluginActive' => class_exists( '\PrestoPlayer\Pro\Plugin' ),
175 'hasLicenseKey' => License::hasKey(),
176 'dashboardUrl' => admin_url( 'admin.php?page=presto-dashboard' ),
177 'wpVersionString' => 'wp/v2/',
178 'prestoVersionString' => 'presto-player/v1/',
179 'debug' => defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG,
180 'debug_navigator' => defined( 'PRESTO_DEBUG_NAVIGATOR' ) && PRESTO_DEBUG_NAVIGATOR,
181 'i18n' => Translation::geti18n(),
182 'trackViews' => apply_filters( 'presto_player_daily_views_enabled', true ),
183 )
184 )
185 );
186 }
187
188 /**
189 * Elementor scripts (needed speifically on preview pages).
190 *
191 * @return void
192 */
193 public function elementorPreviewScripts() {
194 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only preview-context detection; no state change.
195 if ( ! isset( $_GET['elementor-preview'] ) ) {
196 return;
197 }
198
199 $assets = include trailingslashit( PRESTO_PLAYER_PLUGIN_DIR ) . 'dist/elementor.asset.php';
200 wp_enqueue_script(
201 'surecart/elementor',
202 trailingslashit( PRESTO_PLAYER_PLUGIN_URL ) . 'dist/elementor.js',
203 array_merge( array( 'jquery', 'hls.js' ), $assets['dependencies'] ),
204 $assets['version'],
205 true
206 );
207
208 wp_localize_script(
209 'surecart/elementor',
210 'prestoEditorData',
211 array(
212 'proVersion' => Plugin::proVersion(),
213 'isPremium' => Plugin::isPro(),
214 'root' => esc_url_raw( get_rest_url() ),
215 'nonce' => wp_create_nonce( 'wp_rest' ),
216 'wpVersionString' => 'wp/v2/',
217 'siteURL' => esc_url_raw( untrailingslashit( get_site_url( get_current_blog_id() ) ) ),
218 )
219 );
220 }
221
222 /**
223 * Block Editor Assets.
224 *
225 * @return void
226 */
227 public function blockEditorAssets() {
228 if ( ! is_admin() ) {
229 return;
230 }
231
232 $assets = include trailingslashit( PRESTO_PLAYER_PLUGIN_DIR ) . 'dist/blocks.asset.php';
233 wp_enqueue_script(
234 'surecart/blocks/admin',
235 trailingslashit( PRESTO_PLAYER_PLUGIN_URL ) . 'dist/blocks.js',
236 array_merge( array( 'presto-components', 'hls.js', 'regenerator-runtime' ), $assets['dependencies'] ),
237 $assets['version'],
238 true
239 );
240 wp_localize_script(
241 'surecart/blocks/admin',
242 'prestoPlayer',
243 apply_filters(
244 'presto_player_admin_script_options',
245 array(
246 'plugin_url' => esc_url_raw( trailingslashit( PRESTO_PLAYER_PLUGIN_URL ) ),
247 'root' => esc_url_raw( get_rest_url() ),
248 'nonce' => wp_create_nonce( 'wp_rest' ),
249 'ajaxurl' => admin_url( 'admin-ajax.php' ),
250 'isAdmin' => is_admin(),
251 'proVersion' => Plugin::proVersion(),
252 'isPremium' => Plugin::isPro(),
253 'isProPluginActive' => class_exists( '\PrestoPlayer\Pro\Plugin' ),
254 'hasLicenseKey' => License::hasKey(),
255 'dashboardUrl' => admin_url( 'admin.php?page=presto-dashboard' ),
256 'hasRequiredProVersion' => array(
257 'popups' => Plugin::hasRequiredProVersion( 'popups' ),
258 ),
259 'isSetup' => array(
260 'bunny' => false,
261 ),
262 'wpVersionString' => 'wp/v2/',
263 'prestoVersionString' => 'presto-player/v1/',
264 'defaults' => array(
265 'color' => Setting::getDefaultColor(),
266 ),
267 'i18n' => Translation::geti18n(),
268 )
269 )
270 );
271
272 if ( function_exists( 'wp_set_script_translations' ) ) {
273 wp_set_script_translations( 'surecart/blocks/admin', 'presto-player' );
274 }
275
276 wp_localize_script( 'surecart/blocks/admin', 'scIcons', array( 'path' => esc_url_raw( plugin_dir_url( PRESTO_PLAYER_PLUGIN_FILE ) . 'dist/icon-assets' ) ) );
277
278 // Get transcription endpoints if available (Pro feature).
279 $transcription_endpoints = array();
280 if ( class_exists( RestBunnyTranscriptionController::class ) ) {
281 $transcription_endpoints = array(
282 'captions' => RestBunnyTranscriptionController::get_captions_path(),
283 'transcribe' => RestBunnyTranscriptionController::get_transcribe_path(),
284 'deleteCaption' => RestBunnyTranscriptionController::get_delete_caption_path(),
285 'clearCache' => RestBunnyTranscriptionController::get_clear_cache_path(),
286 );
287 }
288
289 wp_localize_script(
290 'surecart/blocks/admin',
291 'prestoPlayerAdmin',
292 apply_filters(
293 'presto_player_admin_block_script_options',
294 array(
295 'root' => esc_url_raw( get_rest_url() ),
296 'nonce' => wp_create_nonce( 'wp_rest' ),
297 'logged_in' => is_user_logged_in(),
298 'ajaxurl' => admin_url( 'admin-ajax.php' ),
299 'wp_max_upload_size' => wp_max_upload_size(),
300 'isAdmin' => is_admin(),
301 'proVersion' => Plugin::proVersion(),
302 'isPremium' => Plugin::isPro(),
303 'isSetup' => array(
304 'bunny' => false,
305 ),
306 'wpVersionString' => 'wp/v2/',
307 'prestoVersionString' => 'presto-player/v1/',
308 'defaults' => array(
309 'color' => Setting::getDefaultColor(),
310 ),
311 'transcriptionEndpoints' => $transcription_endpoints,
312 )
313 )
314 );
315 }
316
317 /**
318 * Checks if the current page contains a Presto Player.
319 *
320 * Examines various conditions including global variables, block presence,
321 * shortcodes, and page builder environments to determine if a player exists.
322 *
323 * @return bool True if a player is detected, false otherwise.
324 */
325 public function hasPlayer() {
326 // global is the most reliable between page builders.
327 global $load_presto_js;
328 if ( $load_presto_js ) {
329 return true;
330 }
331
332 // must be a singular page.
333 if ( ! is_singular() ) {
334 return false;
335 }
336
337 $id = get_the_ID();
338 $widget_blocks = get_option( 'widget_block' );
339
340 // change to see if we have one of our blocks.
341 $types = Block::getBlockTypes();
342 foreach ( $types as $type ) {
343 if ( has_block( $type, $id ) ) {
344 return true;
345 }
346
347 if ( ! empty( $widget_blocks ) ) {
348 foreach ( $widget_blocks as $block ) {
349 $content = isset( $block['content'] ) ? $block['content'] : '';
350 if ( ! empty( $content ) && has_block( $type, $content ) ) {
351 return true;
352 }
353 }
354 }
355 }
356
357 // check for data-presto-config (player rendered).
358 $wp_post = get_post( $id );
359 $post_content = '';
360 if ( $wp_post instanceof \WP_Post ) {
361 $post_content = $wp_post->post_content;
362 }
363 $has_player = false !== strpos( $post_content, 'data-presto-config' );
364 if ( $has_player ) {
365 return true;
366 }
367
368 // check that we have a shortcode.
369 if ( has_shortcode( $post_content, 'presto_player' ) ) {
370 return true;
371 }
372
373 // Read-only request-context detection for page builders; no state change, so nonce verification does not apply.
374 // phpcs:disable WordPress.Security.NonceVerification.Recommended
375 // enable on Elementor.
376 if ( ! empty( $_GET['action'] ) && 'elementor' === $_GET['action'] ) {
377 return true;
378 }
379 if ( isset( $_GET['elementor-preview'] ) ) {
380 return true;
381 }
382
383 // load for beaver builder.
384 if ( isset( $_GET['fl_builder'] ) ) {
385 return true;
386 }
387
388 // tutor LMS.
389 global $post;
390 if ( ! empty( $post->post_type ) && $post->post_type ) {
391 if ( defined( 'TUTOR_VERSION' ) && 'lesson' === $post->post_type ) {
392 return true;
393 }
394 }
395
396 // load for Divi builder.
397 if ( isset( $_GET['et_fb'] ) ) {
398 return true;
399 }
400 // phpcs:enable WordPress.Security.NonceVerification.Recommended
401
402 // do we have the player.
403 return $has_player;
404 }
405
406 /**
407 * Add global player styles inline.
408 *
409 * @return void
410 */
411 public function globalStyles() {
412 ?>
413 <style>
414 <?php readfile( PRESTO_PLAYER_PLUGIN_DIR . 'src/player/global.css' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- Inlining a static plugin-bundled CSS file from a trusted constant path. ?>
415 </style>
416 <?php
417 }
418
419 /**
420 * Load JavaScript for the plugin.
421 *
422 * @return void
423 */
424 public function loadJavascript() {
425 // global styles.
426 if ( ! wp_doing_ajax() && ! defined( 'REST_REQUEST' ) && ! defined( 'PRESTO_TESTSUITE' ) ) {
427 $this->globalStyles();
428 }
429 wp_enqueue_script( 'presto-components' );
430 }
431
432 /**
433 * Block frontend assets.
434 *
435 * @return void
436 */
437 public function blockAssets() {
438 if ( is_admin() ) {
439 $assets = include trailingslashit( PRESTO_PLAYER_PLUGIN_DIR ) . 'dist/blocks.asset.php';
440 // Depend on dashicons so it loads inside the WP 7.0 block editor iframe;
441 // block UIs (e.g. popup trigger picker) use dashicons that the iframe
442 // would otherwise not have.
443 wp_enqueue_style( 'surecart/blocks/admin', trailingslashit( PRESTO_PLAYER_PLUGIN_URL ) . 'dist/blocks.css', array( 'dashicons' ), $assets['version'] );
444 }
445
446 // don't output if it doesn't have our block.
447 if ( ! apply_filters( 'presto_player_load_js', $this->hasPlayer() ) ) {
448 return;
449 }
450
451 $this->loadJavascript();
452
453 // fallback styles and script to load iframes.
454 add_action(
455 'wp_footer',
456 function () {
457 if ( is_admin() ) {
458 return;
459 }
460 if ( ! apply_filters( 'presto_player/scripts/load_iframe_fallback', false ) ) {
461 return;
462 }
463 $this->printFallbackScriptsAndStyles();
464 }
465 );
466 }
467
468 /**
469 * Fix CDN 403 errors inside the block editor iframe.
470 *
471 * WP 7.0+ blob: iframes send no Referer header for cross-origin
472 * requests — blob: is a "local scheme" per Fetch spec, so browsers
473 * strip it entirely. CDNs like Bunny.net reject these with 403.
474 *
475 * Since the blob: iframe is same-origin with the parent admin page,
476 * window.top is accessible. Replacing the iframe's XMLHttpRequest
477 * with window.top.XMLHttpRequest makes HLS.js send requests through
478 * the parent context, which has a proper HTTP Referer.
479 *
480 * Runs in any iframed editor canvas (post editor on WP 6.3+ when all
481 * blocks are apiVersion 3, site editor, widgets editor) — the injected
482 * script is only ever executed inside the iframe document, where
483 * window !== window.top is always true. Only the WP 7.0+ blob: iframe
484 * actually needs the fix; elsewhere the swap is a same-origin no-op.
485 * No-op on frontend due to is_admin() check.
486 *
487 * @param array<string, mixed> $settings The block editor settings.
488 * @return array<string, mixed> The filtered block editor settings.
489 */
490 public function iframeCdnFix( $settings ) {
491 if ( ! is_admin() ) {
492 return $settings;
493 }
494 // WARNING: private WP API (__unstableResolvedAssets) — re-verify on each WP major.
495 if ( isset( $settings['__unstableResolvedAssets']['scripts'] ) ) {
496 $settings['__unstableResolvedAssets']['scripts'] =
497 '<script>try{if(window!==window.top){window.XMLHttpRequest=window.top.XMLHttpRequest;}}catch(e){}</script>'
498 . $settings['__unstableResolvedAssets']['scripts'];
499 } elseif ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
500 // if WP renames the private key this fails silently and Bunny editor previews 403 again — log it.
501 error_log( 'Presto Player: __unstableResolvedAssets missing from editor settings, iframe CDN fix skipped.' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- WP_DEBUG-gated diagnostic for a private WP API dependency.
502 }
503 return $settings;
504 }
505
506 /**
507 * Print fallback scripts and styles.
508 *
509 * @return void
510 */
511 public function printFallbackScriptsAndStyles() {
512 /*
513 * This CSS is duplicated in 'packages/components/src/components/core/player/presto-player/presto-player.scss'.
514 */
515 echo '<style>.presto-iframe-fallback-container{position:relative;padding-bottom:56.25%;padding-top:30px;height:0;overflow:hidden}.presto-iframe-fallback-container embed,.presto-iframe-fallback-container iframe,.presto-iframe-fallback-container object{position:absolute;top:0;left:0;width:100%;height:100%}</style>';
516 echo '<script defer>
517 window.addEventListener("load", function(event) {
518 setTimeout(function() {
519 var deferVideo = document.getElementsByClassName("presto-fallback-iframe");
520 if (!deferVideo.length) return;
521 Array.from(deferVideo).forEach(function(video) {
522 video && video.setAttribute("src", video.getAttribute("data-src"));
523 });
524 }, 2000);
525 }, false);
526 </script>';
527 }
528
529 /**
530 * Enqueue custom template styles for single video pages.
531 *
532 * @return void
533 */
534 public function presto_player_custom_template_styles() {
535 if ( is_singular( 'pp_video_block' ) ) {
536 $assets = include trailingslashit( PRESTO_PLAYER_PLUGIN_DIR ) . 'dist/media-page.asset.php';
537 wp_enqueue_style(
538 'presto-player/media-page',
539 trailingslashit( PRESTO_PLAYER_PLUGIN_URL ) . 'dist/media-page.css',
540 array(),
541 $assets['version']
542 );
543 }
544 }
545
546 /**
547 * Enqueue the popup block script.
548 *
549 * @return void
550 */
551 public function registerPopupScript() {
552 $assets = include trailingslashit( PRESTO_PLAYER_PLUGIN_DIR ) . 'dist/presto-player-popup.asset.php';
553 wp_register_script_module(
554 'presto-player-popup',
555 trailingslashit( PRESTO_PLAYER_PLUGIN_URL ) . 'dist/presto-player-popup.js',
556 $assets['dependencies'],
557 $assets['version'],
558 array( 'in_footer' => true )
559 );
560 }
561 }
562