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