PluginProbe ʕ •ᴥ•ʔ
Presto Player / 4.3.3
Presto Player v4.3.3
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 / Integrations / LearnDash / LearnDash.php
presto-player / inc / Integrations / LearnDash Last commit date
LearnDash.php 5 days ago
LearnDash.php
406 lines
1 <?php
2 /**
3 * LearnDash integration for Presto Player.
4 *
5 * @package PrestoPlayer
6 */
7
8 namespace PrestoPlayer\Integrations\LearnDash;
9
10 use PrestoPlayer\Models\Post;
11 use PrestoPlayer\Support\Utility;
12 use PrestoPlayer\Contracts\Service;
13
14 /**
15 * Integrates Presto Player video progression with LearnDash.
16 */
17 class LearnDash implements Service {
18
19 /**
20 * Register the integration hooks.
21 *
22 * @return void
23 */
24 public function register() {
25 add_action(
26 'plugins_loaded',
27 function () {
28 if ( ! self::isEnabled() ) {
29 return;
30 }
31
32 add_filter( 'learndash_settings_fields', array( $this, 'settingsFields' ), 10, 2 );
33 add_filter( 'ld_video_provider', array( $this, 'addProvider' ), 10, 2 );
34 add_filter( 'presto-settings-block-js-options', array( $this, 'jsOptions' ) );
35 add_filter( 'get_post_metadata', array( $this, 'filterVideoURL' ), 10, 3 );
36
37 add_filter( 'presto_player/block/default_attributes', array( $this, 'addVideoAttributes' ) );
38 add_filter( 'presto_player/templates/player_tag', array( $this, 'addPlayerTags' ) );
39 }
40 );
41 }
42
43 /**
44 * Add tags to player
45 *
46 * @param array $data Player data containing cookie key and video progress.
47 * @return void
48 */
49 public function addPlayerTags( $data ) {
50 if ( empty( $data['cookieKey'] ) || empty( $data['videoProgress'] ) ) {
51 return;
52 }
53
54 ob_start();
55 ?>
56 data-video-cookie-key="<?php echo esc_attr( $data['cookieKey'] ); ?>"
57 data-video-progression="<?php echo esc_attr( $data['videoProgress'] ); ?>"
58 data-video-provider="presto"
59 <?php
60 echo ob_get_clean(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output composed of the esc_attr() escaped data attributes above.
61 }
62
63 /**
64 * Add attributes to video for video progression
65 *
66 * @param array $attributes Block attributes.
67 * @return array
68 */
69 public function addVideoAttributes( $attributes ) {
70 global $post;
71
72 // Bail if not a learndash post type.
73 if ( ! self::isLearnDashPost( $post ) ) {
74 return $attributes;
75 }
76
77 $logic_video = true;
78 $video_id = ! empty( $attributes['id'] ) ? '(presto-' . $attributes['id'] . ')' : '(presto)';
79 $video_completed = $this->stepIsCompleted( $post->ID );
80
81 if ( $video_completed ) {
82 $logic_video = false;
83 } else {
84 // Get lesson settings.
85 $step_settings = learndash_get_setting( $post );
86
87 if ( 'BEFORE' === ( $step_settings['lesson_video_shown'] ?? '' ) ) {
88 $logic_video = true;
89
90 $topics = learndash_get_topic_list( $post->ID );
91 if ( ! empty( $topics ) ) {
92 $progress = learndash_get_course_progress( null, $topics[0]->ID );
93 if ( ! empty( $progress ) ) {
94 $topics_completed = 0;
95 foreach ( $progress['posts'] as $topic ) {
96 if ( (int) 1 === (int) $topic->completed ) {
97 ++$topics_completed;
98 break;
99 }
100 }
101
102 if ( ! empty( $topics_completed ) ) {
103 $logic_video = false;
104 }
105 }
106 }
107 }
108 }
109
110 if ( true === $logic_video ) {
111 $logic_video_str = 'true';
112 } else {
113 $logic_video_str = 'false';
114 }
115
116 $attributes['cookieKey'] = $this->buildVideoCookieKey( $video_id );
117 $attributes['videoProgress'] = $logic_video_str;
118
119 return $attributes;
120 }
121
122 /**
123 * Build unique video progress cookie key. This is used to track the video state
124 * in the user's browser.
125 *
126 * @param integer $attach_id Attachment ID of the video.
127 *
128 * @return string $cookie_key.
129 */
130 public function buildVideoCookieKey( $attach_id = '' ) {
131 $cookie_key = '';
132 $cookie_key = $this->getNonceSlug();
133
134 if ( ( isset( $attach_id ) ) && ( ! empty( $attach_id ) ) ) {
135 $lesson_video_url = trim( $attach_id );
136 $lesson_video_url = html_entity_decode( $lesson_video_url );
137
138 $cookie_key .= '_' . $lesson_video_url;
139 }
140 $cookie_key = 'learndash-video-progress-' . md5( $cookie_key );
141
142 return $cookie_key;
143 }
144
145 /**
146 * Utility function to get the nonce slug.
147 *
148 * @since 3.2.3
149 */
150 protected function getNonceSlug() {
151 $post_id = get_the_ID();
152 $step_id = $post_id;
153 $course_id = learndash_get_course_id( $post_id );
154 $user_id = (int) get_current_user_id();
155
156 return 'learndash_video_' . $user_id . '_' . $course_id . '_' . $step_id;
157 }
158
159 /**
160 * Dynamically replace (presto) with (presto-$video_id)
161 *
162 * @param mixed $value The meta value being filtered.
163 * @param integer $object_id The post ID the meta belongs to.
164 * @param string $meta_key The meta key being requested.
165 *
166 * @return mixed
167 */
168 public function filterVideoURL( $value, $object_id, $meta_key ) {
169 // Prevent recursion.
170 remove_filter( current_filter(), __FUNCTION__ );
171
172 // Only learndash meta.
173 if ( ! in_array( $meta_key, array( '_sfwd-topic', '_sfwd-lessons' ) ) ) {
174 return $value;
175 }
176
177 // Get meta.
178 $meta_cache = wp_cache_get( $object_id, 'post_meta' );
179 if ( ! $meta_cache ) {
180 $meta_cache = update_meta_cache( 'post', array( $object_id ) );
181 if ( isset( $meta_cache[ $object_id ] ) ) {
182 $meta_cache = $meta_cache[ $object_id ];
183 } else {
184 $meta_cache = null;
185 }
186 }
187 if ( ! $meta_key ) {
188 return $meta_cache;
189 }
190
191 if ( isset( $meta_cache[ $meta_key ] ) ) {
192 $saved = maybe_unserialize( $meta_cache[ $meta_key ][0] );
193
194 if ( is_array( $saved ) ) {
195 $key = array_key_exists( 'sfwd-lessons_lesson_video_url', $saved ) ? 'sfwd-lessons_lesson_video_url' : '';
196 $key = array_key_exists( 'sfwd-topic_lesson_video_url', $saved ) ? 'sfwd-topic_lesson_video_url' : $key;
197 }
198
199 if ( ! $key ) {
200 return $value;
201 }
202
203 if ( strpos( $saved[ $key ], '(presto' ) === false ) {
204 return $value;
205 }
206
207 $post = get_post( $object_id );
208 if ( ! $post instanceof \WP_Post ) {
209 return $value;
210 }
211
212 $post_model = new Post( $post );
213 $video_id = $post_model->findVideoId();
214 $saved[ $key ] = "(presto-$video_id)";
215 $meta_cache[ $meta_key ][0] = $saved;
216 return $meta_cache[ $meta_key ];
217 }
218
219 return $value;
220 }
221
222 /**
223 * Pass javascript options to presto player
224 *
225 * @param array $options Javascript options passed to the player.
226 * @return array
227 */
228 public function jsOptions( $options ) {
229 if ( self::isEnabled() ) {
230 global $post;
231 $settings = learndash_get_setting( $post );
232
233 if ( ! empty( $settings['lesson_video_auto_complete_delay'] ) ) {
234 $post_type_obj = get_post_type_object( $post->post_type );
235 $settings['videos_auto_complete_delay_message'] = sprintf(
236 // translators: placeholders: 1. Lesson or Topic label, 2. span for counter.
237 wp_kses_post( _x( '<p class="ld-video-delay-message">%1$s will auto complete in %2$s seconds</p>', 'placeholders: 1. Lesson or Topic label, 2. span for counter', 'presto-player' ) ),
238 $post_type_obj->labels->singular_name,
239 '<span class="time-countdown">' . $settings['lesson_video_auto_complete_delay'] . '</span>'
240 );
241 }
242
243 $options['learndash'] = $settings;
244 }
245
246 return $options;
247 }
248
249 /**
250 * Is LearnDash enabled?
251 *
252 * @return boolean
253 */
254 public static function isEnabled() {
255 return defined( 'LEARNDASH_VERSION' );
256 }
257
258 /**
259 * Should the video load on the learndash page
260 *
261 * @return boolean
262 */
263 public static function shouldVideoLoad() {
264 global $post;
265
266 // Bail if not a learndash post type.
267 if ( ! self::isLearnDashPost( $post ) ) {
268 return true;
269 }
270
271 // Step is completed, load video.
272 if ( self::stepIsCompleted( $post ) ) {
273 return true;
274 }
275
276 // Check if lesson steps are complete.
277 return self::areStepsComplete( $post );
278 }
279
280 /**
281 * Is this a learndash post?
282 *
283 * @param \WP_Post $post The post to check.
284 * @return boolean
285 */
286 public static function isLearnDashPost( $post ) {
287 if ( ! $post ) {
288 return false;
289 }
290
291 return in_array( $post->post_type, array( 'sfwd-lessons', 'sfwd-topic' ) );
292 }
293
294 /**
295 * Is the learndash step completed
296 *
297 * @param \WP_Post $post The post to check.
298 * @return bool
299 */
300 public static function stepIsCompleted( $post ) {
301 if ( ! function_exists( 'learndash_get_course_progress' ) ) {
302 return true;
303 }
304
305 global $post;
306 $progress = learndash_get_course_progress( null, $post->ID );
307 return ( ! empty( $progress['this'] ) ) && ( $progress['this'] instanceof \WP_Post ) && ( true === (bool) $progress['this']->completed );
308 }
309
310 /**
311 * Are lesson/topic steps complete?
312 *
313 * @param \WP_Post $post The post to check.
314 * @return boolean
315 */
316 public static function areStepsComplete( \WP_Post $post ) {
317 // Get lesson settings.
318 $lesson_settings = learndash_get_setting( $post );
319
320 // We're only concerned with "AFTER".
321 if ( 'AFTER' !== ( $lesson_settings['lesson_video_shown'] ?? '' ) ) {
322 return true;
323 }
324
325 // If this is a lesson, check if topics are completed.
326 if ( 'sfwd-lessons' === $post->post_type ) {
327 if ( ! learndash_lesson_topics_completed( $post->ID ) ) {
328 return false;
329 }
330 }
331
332 // Quizes must also be completed.
333 return self::areQuizzesCompleted( $post );
334 }
335
336 /**
337 * Are quizzes completed?
338 *
339 * @param \WP_Post $post The post to check.
340 * @return boolean
341 */
342 public static function areQuizzesCompleted( \WP_Post $post ) {
343 // Quizes must also be completed.
344 $quizzes_completed = true;
345 $lesson_quizzes_list = learndash_get_lesson_quiz_list( $post->ID );
346 if ( ! empty( $lesson_quizzes_list ) ) {
347 foreach ( $lesson_quizzes_list as $quiz ) {
348 if ( 'completed' !== $quiz['status'] ) {
349 $quizzes_completed = false;
350 break;
351 }
352 }
353 }
354 return (bool) $quizzes_completed;
355 }
356
357 /**
358 * Add our video provider to learndash
359 *
360 * @param array $video_data The current video provider data.
361 * @param array $step_settings The LearnDash step settings.
362 * @return array
363 */
364 public function addProvider( $video_data, $step_settings ) {
365 if ( strpos( $step_settings['lesson_video_url'], '(presto' ) !== false ) {
366 return 'presto';
367 }
368 return $video_data;
369 }
370
371 /**
372 * Adds our setting to the lesson settings page
373 *
374 * @param array $settings The current settings fields.
375 * @param string $meta_box_key The settings meta box key.
376 * @return array
377 */
378 public function settingsFields( $settings, $meta_box_key ) {
379 // If it's not one of these settings pages, bail.
380 if ( ! in_array( $meta_box_key, array( 'learndash-lesson-display-content-settings', 'learndash-topic-display-content-settings' ) ) ) {
381 return $settings;
382 }
383
384 $setting = array(
385 'lesson_use_presto_video' => array(
386 'name' => 'lesson_use_presto_video',
387 'label' => esc_html__( 'Use Presto Video', 'presto-player' ),
388 'type' => 'checkbox-switch',
389 'value' => ! empty( $settings['use_presto_video'] ) ? $settings['use_presto_video'] : '',
390 'help_text' => esc_html__( 'Use the Presto Player video in your post content for video progression.', 'presto-player' ),
391 'default' => '',
392 'options' => array(
393 'on' => esc_html__( 'The presto video in this post will be used for video progression.', 'presto-player' ),
394 '' => '',
395 ),
396 'parent_setting' => 'lesson_video_enabled',
397 ),
398 );
399
400 // Insert before video url.
401 $settings = Utility::arrayInsert( $settings, $setting, 'lesson_video_url', 'before' );
402
403 return $settings;
404 }
405 }
406