PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.4
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.4
1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 trunk 1.2.0 All 47 releases
fluent-cart / app / Modules / FluentPlayer / FluentPlayerBridge.php

FluentPlayerBridge.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.6.4, at app/Modules/FluentPlayer/FluentPlayerBridge.php

217 lines 7.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\App\Modules\FluentPlayer;
4
5 use FluentCart\Framework\Support\Arr;
6
7 /**
8 * Single seam to the FluentPlayer plugin. Every call is feature-detected so
9 * a missing or older FluentPlayer degrades to "no video" instead of a fatal.
10 */
11 class FluentPlayerBridge
12 {
13 const REST_NAMESPACE = 'fluent-player/v2';
14
15 const MEDIA_POST_TYPE = 'fluent_player_media';
16
17 const DEFAULT_AUTHORING_CAP = 'edit_others_posts';
18
19 const DEFAULT_PRESET_SLUG = 'course';
20
21 public static function isActive(): bool
22 {
23 $active = defined('FLUENT_PLAYER')
24 && class_exists('\FluentPlayer\App\Services\MediaRenderer')
25 && class_exists('\FluentPlayer\App\Models\Media');
26
27 if (function_exists('apply_filters')) {
28 $active = (bool) apply_filters('fluent_cart/fluent_player/is_active', $active);
29 }
30
31 return $active;
32 }
33
34 /**
35 * True when the FluentPlayer plugin files are present but not (yet) active.
36 */
37 public static function isInstalled(): bool
38 {
39 if (self::isActive()) {
40 return true;
41 }
42
43 if (!function_exists('get_plugins')) {
44 require_once ABSPATH . 'wp-admin/includes/plugin.php';
45 }
46
47 return array_key_exists('fluent-player/fluent-player.php', get_plugins());
48 }
49
50 public static function hasPro(): bool
51 {
52 return self::isActive() && defined('FLUENT_PLAYER_PRO_VERSION');
53 }
54
55 public static function authoringCapability(): string
56 {
57 if (self::isActive() && method_exists('\FluentPlayer\App\Helpers\Helper', 'authoringCapability')) {
58 $capability = \FluentPlayer\App\Helpers\Helper::authoringCapability();
59 if (is_string($capability) && $capability !== '') {
60 return $capability;
61 }
62 }
63
64 return self::DEFAULT_AUTHORING_CAP;
65 }
66
67 public static function defaultPresetSlug(): string
68 {
69 if (self::isActive() && method_exists('\FluentPlayer\App\Services\PresetService', 'getDefaultSlug')) {
70 $slug = \FluentPlayer\App\Services\PresetService::getDefaultSlug();
71 if (is_string($slug) && $slug !== '') {
72 return $slug;
73 }
74 }
75
76 return self::DEFAULT_PRESET_SLUG;
77 }
78
79 public static function adminAppConfig(): array
80 {
81 if (!self::isActive()) {
82 $installed = self::isInstalled();
83
84 // Mirrors the capability AddonsController::installAndActivate() enforces,
85 // so the tab does not offer a button whose request would come back 403:
86 // the endpoint always activates, and also downloads when the addon is
87 // absent.
88 $canInstall = current_user_can('activate_plugins')
89 && ($installed || current_user_can('install_plugins'));
90
91 return [
92 'active' => false,
93 'installed' => $installed,
94 'canInstall' => $canInstall,
95 ];
96 }
97
98 return [
99 'active' => true,
100 'hasPro' => self::hasPro(),
101 'canAuthor' => current_user_can(self::authoringCapability()),
102 'restUrl' => rtrim(rest_url(self::REST_NAMESPACE), '/'),
103 'editUrlBase' => admin_url('post.php?action=edit&post='),
104 'defaultPresetSlug' => self::defaultPresetSlug(),
105 ];
106 }
107
108 /**
109 * @return object|null Media the current visitor may see (FluentPlayer's
110 * Media::findVisible: read_post + its can_view_media filter).
111 */
112 public static function findVisibleMedia(int $mediaId): ?object
113 {
114 if (!self::isActive() || $mediaId <= 0) {
115 return null;
116 }
117
118 try {
119 $media = \FluentPlayer\App\Models\Media::findVisible($mediaId);
120 } catch (\Throwable $e) {
121 self::reportFailure('find', $mediaId, $e);
122 return null;
123 }
124
125 return $media ?: null;
126 }
127
128 /**
129 * @return array|null ['id', 'title', 'poster', 'provider', 'src'], null when not visible.
130 */
131 public static function getMediaSummary(int $mediaId): ?array
132 {
133 $media = self::findVisibleMedia($mediaId);
134
135 return $media ? self::summarize($media) : null;
136 }
137
138 /**
139 * @param object $media A FluentPlayer media model (or anything exposing ID, post_title, settings).
140 */
141 public static function summarize($media): array
142 {
143 $settings = is_array($media->settings) ? $media->settings : [];
144
145 return [
146 'id' => (int) $media->ID,
147 'title' => (string) $media->post_title,
148 'poster' => self::resolvePoster($settings),
149 'provider' => (string) Arr::get($settings, 'provider', ''),
150 'src' => (string) Arr::get($settings, 'src', ''),
151 ];
152 }
153
154 /**
155 * Saved posterSrc, else the YouTube thumbnail FluentPlayer itself falls back to.
156 */
157 public static function resolvePoster(array $settings): string
158 {
159 $poster = trim((string) Arr::get($settings, 'posterSrc', ''));
160 if ($poster !== '') {
161 return $poster;
162 }
163
164 $src = (string) Arr::get($settings, 'src', '');
165 if ($src === '' || !method_exists('\FluentPlayer\App\Helpers\Helper', 'extractYouTubeVideoId')) {
166 return '';
167 }
168
169 $videoId = \FluentPlayer\App\Helpers\Helper::extractYouTubeVideoId($src);
170 if (!is_string($videoId) || $videoId === '') {
171 return '';
172 }
173
174 if (method_exists('\FluentPlayer\App\Helpers\Helper', 'getYouTubeFallbackPosterUrl')) {
175 $poster = \FluentPlayer\App\Helpers\Helper::getYouTubeFallbackPosterUrl($videoId);
176 if (is_string($poster) && $poster !== '') {
177 return $poster;
178 }
179 }
180
181 return 'https://i.ytimg.com/vi/' . rawurlencode($videoId) . '/hqdefault.jpg';
182 }
183
184 /**
185 * Rendering also enqueues FluentPlayer's runtime and localizes the player
186 * config. Password-protected media renders FluentPlayer's unlock form.
187 */
188 public static function renderPlayer(int $mediaId, string $extraClasses = ''): string
189 {
190 if (!self::findVisibleMedia($mediaId)) {
191 return '';
192 }
193
194 try {
195 $html = \FluentPlayer\App\Services\MediaRenderer::render($mediaId, $extraClasses);
196 } catch (\Throwable $e) {
197 self::reportFailure('render', $mediaId, $e);
198 return '';
199 }
200
201 return is_string($html) ? $html : '';
202 }
203
204 /**
205 * A FluentPlayer failure must never break the product page, but it must not
206 * vanish either: it is logged under WP_DEBUG and exposed as an action.
207 */
208 protected static function reportFailure(string $stage, int $mediaId, \Throwable $e): void
209 {
210 if (defined('WP_DEBUG') && WP_DEBUG) {
211 error_log(sprintf('[FluentCart] FluentPlayer %s failed for media #%d: %s', $stage, $mediaId, $e->getMessage()));
212 }
213
214 do_action('fluent_cart/fluent_player/failed', $stage, $mediaId, $e);
215 }
216 }
217