| 1 |
<?php |
| 2 |
|
| 3 |
namespace FluentCommunity\App\Hooks\Handlers; |
| 4 |
|
| 5 |
use FluentCommunity\App\Services\Helper; |
| 6 |
use FluentCommunity\Framework\Support\Arr; |
| 7 |
use FluentCommunity\Modules\Course\Services\LessonVideoGateService; |
| 8 |
|
| 9 |
/** |
| 10 |
* Hook wiring for video-gated lesson completion. |
| 11 |
* The gate/watched-state logic lives in LessonVideoGateService. |
| 12 |
*/ |
| 13 |
class LessonVideoGateHandler |
| 14 |
{ |
| 15 |
public function register() |
| 16 |
{ |
| 17 |
add_filter('fluent_community/is_allowed_to_complete_lesson', [$this, 'gateLessonCompletion'], 11, 3); |
| 18 |
|
| 19 |
add_filter('fluent_community/lesson/get_public_meta', [$this, 'appendPublicMeta'], 10, 2); |
| 20 |
|
| 21 |
add_filter('fluent_community/portal_data_vars', [$this, 'injectPortalAssets'], 11); |
| 22 |
|
| 23 |
// A progress reset means the student starts pristine — watched videos included |
| 24 |
add_action('fluent_community/course/progress_reset', [$this, 'resetWatchedRecords'], 10, 2); |
| 25 |
|
| 26 |
// Un-completing a gated lesson requires re-watching the video |
| 27 |
add_action('fluent_community/course/lesson_marked_incomplete', [$this, 'resetLessonWatchedRecord'], 10, 2); |
| 28 |
|
| 29 |
// Deleting a lesson removes every student's watched record with it |
| 30 |
add_action('fluent_community/lesson/before_deleted', [$this, 'deleteLessonWatchedRecords']); |
| 31 |
} |
| 32 |
|
| 33 |
public function gateLessonCompletion($isAllowed, $lesson, $state = '') |
| 34 |
{ |
| 35 |
// Un-completing a lesson is never gated |
| 36 |
if (!$isAllowed || $state == 'incomplete') { |
| 37 |
return $isAllowed; |
| 38 |
} |
| 39 |
|
| 40 |
return !LessonVideoGateService::isCompletionBlockedFor($lesson, Helper::getCurrentUser()); |
| 41 |
} |
| 42 |
|
| 43 |
public function appendPublicMeta($meta, $lesson) |
| 44 |
{ |
| 45 |
$isGated = LessonVideoGateService::isGatedLesson($lesson); |
| 46 |
|
| 47 |
$meta['require_video_completion'] = Arr::get($meta, 'require_video_completion') == 'yes' ? 'yes' : 'no'; |
| 48 |
$meta['video_completion_threshold'] = LessonVideoGateService::getThreshold($lesson); |
| 49 |
$meta['is_video_gated'] = $isGated; |
| 50 |
$meta['video_auto_complete'] = LessonVideoGateService::isAutoCompleteEnabled($lesson); |
| 51 |
$meta['video_watched'] = $isGated && LessonVideoGateService::hasWatched($lesson, get_current_user_id()); |
| 52 |
|
| 53 |
return $meta; |
| 54 |
} |
| 55 |
|
| 56 |
public function injectPortalAssets($data) |
| 57 |
{ |
| 58 |
// The portal tracker is only useful when FluentPlayer can render |
| 59 |
if (!LessonVideoGateService::isFluentPlayerActive()) { |
| 60 |
return $data; |
| 61 |
} |
| 62 |
|
| 63 |
$data['js_files']['fcom_lesson_video_gate'] = [ |
| 64 |
'url' => FLUENT_COMMUNITY_PLUGIN_URL . 'Modules/Course/js/lesson-video-gate.js', |
| 65 |
'deps' => [] |
| 66 |
]; |
| 67 |
|
| 68 |
if (!isset($data['js_vars'])) { |
| 69 |
$data['js_vars'] = []; |
| 70 |
} |
| 71 |
|
| 72 |
$data['js_vars']['fcomLessonVideoGate'] = [ |
| 73 |
'rest_url' => rest_url('fluent-community/v2'), |
| 74 |
'nonce' => wp_create_nonce('wp_rest'), |
| 75 |
'default_threshold' => LessonVideoGateService::getDefaultThreshold(), |
| 76 |
'auto_complete_delay' => LessonVideoGateService::getAutoCompleteDelay(), |
| 77 |
'i18n' => [ |
| 78 |
/* translators: %d is the watched percentage required to complete the lesson */ |
| 79 |
'watch_notice' => __('Watch at least %d%% of this video to be able to complete this lesson.', 'fluent-community'), |
| 80 |
'watch_to_end' => __('Watch this video to the end to be able to complete this lesson.', 'fluent-community'), |
| 81 |
'watched_done' => __('Video watched — you can now complete this lesson.', 'fluent-community'), |
| 82 |
'watch_failed' => __('Could not record your watch progress. Please reload the page and try again.', 'fluent-community') |
| 83 |
] |
| 84 |
]; |
| 85 |
|
| 86 |
return $data; |
| 87 |
} |
| 88 |
|
| 89 |
public function resetWatchedRecords($course, $userId) |
| 90 |
{ |
| 91 |
LessonVideoGateService::resetWatchedForCourse($course->id, $userId); |
| 92 |
} |
| 93 |
|
| 94 |
public function resetLessonWatchedRecord($lesson, $userId) |
| 95 |
{ |
| 96 |
if (!LessonVideoGateService::isGatedLesson($lesson)) { |
| 97 |
return; |
| 98 |
} |
| 99 |
|
| 100 |
LessonVideoGateService::resetWatchedForLesson($lesson, $userId); |
| 101 |
} |
| 102 |
|
| 103 |
public function deleteLessonWatchedRecords($lesson) |
| 104 |
{ |
| 105 |
LessonVideoGateService::deleteWatchedForLesson($lesson->id); |
| 106 |
} |
| 107 |
|
| 108 |
} |
| 109 |
|