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