← All changes
|
Modules/Course/Http/Controllers/CourseAdminController.php
+47
-8
2.9.0
→
2.11.0
View file →
| @@ -85,9 +85,9 @@ | ||
| 85 | 85 | $courseData = [ |
| 86 | 86 | 'parent_id' => $request->get('parent_id') ?: null, // phpcs:ignore Universal.Operators.DisallowShortTernary.Found |
| 87 | 87 | 'title' => $request->getSafe('title', 'sanitize_text_field'), |
| 88 | 88 | 'privacy' => $request->get('privacy'), |
| 89 | - 'description' => wp_kses_post($request->get('description')), | |
| 89 | + 'description' => wp_kses_post((string) $request->get('description', '')), | |
| 90 | 90 | 'status' => $request->get('status', 'draft'), |
| 91 | 91 | 'settings' => [ |
| 92 | 92 | 'course_type' => $request->get('course_type'), |
| 93 | 93 | 'emoji' => CustomSanitizer::sanitizeEmoji($request->get('settings.emoji', '')), |
| @@ -94,9 +94,9 @@ | ||
| 94 | 94 | 'shape_svg' => CustomSanitizer::sanitizeSvg($request->get('settings.shape_svg', '')), |
| 95 | 95 | 'disable_comments' => $request->get('settings.disable_comments') === 'yes' ? 'yes' : 'no', |
| 96 | 96 | 'hide_members_count' => $request->get('settings.hide_members_count') === 'yes' ? 'yes' : 'no', |
| 97 | 97 | 'course_layout' => $request->get('settings.course_layout') === 'modern' ? 'modern' : 'classic', |
| 98 | - 'course_details' => CustomSanitizer::unslashMarkdown(trim($request->get('settings.course_details'))), | |
| 98 | + 'course_details' => CustomSanitizer::unslashMarkdown(trim((string) $request->get('settings.course_details', ''))), | |
| 99 | 99 | 'hide_instructor_view' => $request->get('settings.hide_instructor_view') === 'yes' ? 'yes' : 'no', |
| 100 | 100 | 'show_instructor_students_count' => $request->get('settings.show_instructor_students_count') === 'yes' ? 'yes' : 'no', |
| 101 | 101 | 'sequential_lesson_order' => $request->get('settings.sequential_lesson_order') === 'yes' ? 'yes' : 'no', |
| 102 | 102 | ], |
| @@ -229,9 +229,9 @@ | ||
| 229 | 229 | |
| 230 | 230 | $courseData = [ |
| 231 | 231 | 'title' => $request->getSafe('title', 'sanitize_text_field'), |
| 232 | 232 | 'privacy' => $request->get('privacy'), |
| 233 | - 'description' => wp_kses_post($request->get('description')), | |
| 233 | + 'description' => wp_kses_post((string) $request->get('description', '')), | |
| 234 | 234 | 'status' => $request->get('status'), |
| 235 | 235 | 'cover_photo' => $request->getSafe('cover_photo', 'sanitize_url'), |
| 236 | 236 | 'parent_id' => $request->get('parent_id') ?: null, // phpcs:ignore Universal.Operators.DisallowShortTernary.Found |
| 237 | 237 | ]; |
| @@ -303,9 +303,9 @@ | ||
| 303 | 303 | $existingSettings['show_instructor_students_count'] = $request->get('settings.show_instructor_students_count') === 'yes' ? 'yes' : 'no'; |
| 304 | 304 | $existingSettings['show_paywalls'] = $request->get('settings.show_paywalls') === 'yes' ? 'yes' : 'no'; |
| 305 | 305 | $existingSettings['show_welcome_banner'] = $request->get('settings.show_welcome_banner') === 'yes' ? 'yes' : 'no'; |
| 306 | 306 | $existingSettings['course_layout'] = $request->get('settings.course_layout') === 'modern' ? 'modern' : 'classic'; |
| 307 | - $existingSettings['course_details'] = CustomSanitizer::unslashMarkdown(trim($request->get('settings.course_details'))); | |
| 307 | + $existingSettings['course_details'] = CustomSanitizer::unslashMarkdown(trim((string) $request->get('settings.course_details', ''))); | |
| 308 | 308 | $existingSettings['sequential_lesson_order'] = $request->get('settings.sequential_lesson_order') === 'yes' ? 'yes' : 'no'; |
| 309 | 309 | |
| 310 | 310 | if ($request->get('privacy') == 'public' && $existingSettings['course_type'] == 'self_paced') { |
| 311 | 311 | $existingSettings['public_lesson_view'] = $request->get('settings.public_lesson_view') == 'yes' ? 'yes' : 'no'; |
| @@ -383,8 +383,10 @@ | ||
| 383 | 383 | $newTopic = $topic->replicate(); |
| 384 | 384 | $newTopic->space_id = $newCourse->id; |
| 385 | 385 | $newTopic->save(); |
| 386 | 386 | |
| 387 | + do_action('fluent_community/section/created', $newTopic, $newCourse); | |
| 388 | + | |
| 387 | 389 | foreach ($topic->lessons as $lesson) { |
| 388 | 390 | /** @var CourseLesson $lesson */ |
| 389 | 391 | $newLesson = $lesson->replicate(); |
| 390 | 392 | $newLesson->space_id = $newCourse->id; |
| @@ -390,8 +392,10 @@ | ||
| 390 | 392 | $newLesson->space_id = $newCourse->id; |
| 391 | 393 | $newLesson->parent_id = $newTopic->id; |
| 392 | 394 | $newLesson->save(); |
| 393 | 395 | CourseHelper::copyLessonDocuments($lesson, $newLesson); |
| 396 | + | |
| 397 | + do_action('fluent_community/lesson/created', $newLesson, $newTopic); | |
| 394 | 398 | } |
| 395 | 399 | } |
| 396 | 400 | |
| 397 | 401 | do_action('fluent_community/course/created', $newCourse); |
| @@ -603,9 +607,13 @@ | ||
| 603 | 607 | 'message' => __('This student is not enrolled in this course.', 'fluent-community'), |
| 604 | 608 | ]); |
| 605 | 609 | } |
| 606 | 610 | |
| 607 | - CourseHelper::resetCourseProgress($courseId, (int) $studentId); | |
| 611 | + if (!CourseHelper::resetCourseProgress($courseId, (int) $studentId)) { | |
| 612 | + return $this->sendError([ | |
| 613 | + 'message' => __("Student's progress could not be reset. Please try again.", 'fluent-community'), | |
| 614 | + ]); | |
| 615 | + } | |
| 608 | 616 | |
| 609 | 617 | return [ |
| 610 | 618 | 'message' => __("Student's progress has been reset.", 'fluent-community'), |
| 611 | 619 | ]; |
| @@ -735,9 +743,9 @@ | ||
| 735 | 743 | 'space_id' => $courseId, |
| 736 | 744 | 'status' => 'published', |
| 737 | 745 | ]; |
| 738 | 746 | |
| 739 | - Course::findOrFail($courseId); | |
| 747 | + $course = Course::findOrFail($courseId); | |
| 740 | 748 | |
| 741 | 749 | $latestPriority = CourseTopic::where('type', 'course_section')->where('space_id', $courseId)->max('priority'); |
| 742 | 750 | |
| 743 | 751 | $sectionData['priority'] = (int) $latestPriority + 1; |
| @@ -745,8 +753,10 @@ | ||
| 745 | 753 | $section = CourseTopic::create($sectionData); |
| 746 | 754 | |
| 747 | 755 | $section->load('lessons'); |
| 748 | 756 | |
| 757 | + do_action('fluent_community/section/created', $section, $course); | |
| 758 | + | |
| 749 | 759 | return [ |
| 750 | 760 | 'message' => __('Section has been created successfully.', 'fluent-community'), |
| 751 | 761 | 'section' => $section, |
| 752 | 762 | ]; |
| @@ -868,8 +878,10 @@ | ||
| 868 | 878 | $newSection->space_id = $toCourse->id; |
| 869 | 879 | $newSection->priority = (int) $latestPriority + 1; |
| 870 | 880 | $newSection->save(); |
| 871 | 881 | |
| 882 | + do_action('fluent_community/section/created', $newSection, $toCourse); | |
| 883 | + | |
| 872 | 884 | $originalLessons = CourseLesson::where('parent_id', $originalSection->id)->get(); |
| 873 | 885 | foreach ($originalLessons as $lesson) { |
| 874 | 886 | /** @var CourseLesson $lesson */ |
| 875 | 887 | $newLesson = $lesson->replicate(); |
| @@ -876,8 +888,10 @@ | ||
| 876 | 888 | $newLesson->space_id = $toCourse->id; |
| 877 | 889 | $newLesson->parent_id = $newSection->id; |
| 878 | 890 | $newLesson->save(); |
| 879 | 891 | CourseHelper::copyLessonDocuments($lesson, $newLesson); |
| 892 | + | |
| 893 | + do_action('fluent_community/lesson/created', $newLesson, $newSection); | |
| 880 | 894 | } |
| 881 | 895 | |
| 882 | 896 | $newSection->load('lessons'); |
| 883 | 897 | |
| @@ -989,8 +1003,10 @@ | ||
| 989 | 1003 | $lesson = CourseLesson::create($lessonData); |
| 990 | 1004 | |
| 991 | 1005 | $lesson = CourseLesson::findOrFail($lesson->id); |
| 992 | 1006 | |
| 1007 | + do_action('fluent_community/lesson/created', $lesson, $topic); | |
| 1008 | + | |
| 993 | 1009 | return [ |
| 994 | 1010 | 'message' => __('Lesson has been created successfully.', 'fluent-community'), |
| 995 | 1011 | 'lesson' => $lesson, |
| 996 | 1012 | ]; |
| @@ -1068,8 +1084,12 @@ | ||
| 1068 | 1084 | if ($dirtyFields) { |
| 1069 | 1085 | $lesson->save(); |
| 1070 | 1086 | $isNewlyPublished = $lesson->status === 'published' && $previousStatus !== 'published'; |
| 1071 | 1087 | do_action('fluent_community/lesson/updated', $lesson, $dirtyFields, $isNewlyPublished); |
| 1088 | + | |
| 1089 | + if ($isNewlyPublished) { | |
| 1090 | + do_action('fluent_community/lesson/published', $lesson); | |
| 1091 | + } | |
| 1072 | 1092 | } |
| 1073 | 1093 | |
| 1074 | 1094 | do_action('fluent_community/lesson/additional_media_updated', $request->all(), $lesson, $updateData); |
| 1075 | 1095 | |
| @@ -1086,8 +1106,10 @@ | ||
| 1086 | 1106 | }) |
| 1087 | 1107 | ->where('id', $lessionId) |
| 1088 | 1108 | ->firstOrFail(); |
| 1089 | 1109 | |
| 1110 | + $previousStatus = $lesson->status; | |
| 1111 | + | |
| 1090 | 1112 | $acceptedFields = [ 'title', 'status', 'slug' ]; |
| 1091 | 1113 | |
| 1092 | 1114 | // empty title/slug/status must not overwrite, but a literal "0" is a valid value |
| 1093 | 1115 | // Request::only() is a plain array pick with no sanitization, so each field is |
| @@ -1101,9 +1123,16 @@ | ||
| 1101 | 1123 | $lessonData['title'] = sanitize_text_field($lessonData['title']); |
| 1102 | 1124 | } |
| 1103 | 1125 | |
| 1104 | 1126 | if (isset($lessonData['slug'])) { |
| 1105 | - $lessonData['slug'] = sanitize_title($lessonData['slug']); | |
| 1127 | + // sanitize_title() alone let an author set a slug already taken by a | |
| 1128 | + // sibling lesson, which getLessonBySlug() then resolves arbitrarily. | |
| 1129 | + $lessonData['slug'] = CourseLesson::uniqueSlug( | |
| 1130 | + $lessonData['slug'], | |
| 1131 | + $lesson->space_id, | |
| 1132 | + $lesson->id, | |
| 1133 | + Arr::get($lessonData, 'title', $lesson->title) | |
| 1134 | + ); | |
| 1106 | 1135 | } |
| 1107 | 1136 | |
| 1108 | 1137 | if (isset($lessonData['status']) && !in_array($lessonData['status'], ['draft', 'published', 'archived'], true)) { |
| 1109 | 1138 | unset($lessonData['status']); |
| @@ -1121,10 +1150,19 @@ | ||
| 1121 | 1150 | } |
| 1122 | 1151 | |
| 1123 | 1152 | if (!empty($lessonData)) { |
| 1124 | 1153 | $lesson->fill($lessonData); |
| 1125 | - if ($lesson->isDirty()) { | |
| 1154 | + $dirtyFields = $lesson->getDirty(); | |
| 1155 | + | |
| 1156 | + if ($dirtyFields) { | |
| 1126 | 1157 | $lesson->save(); |
| 1158 | + | |
| 1159 | + $isNewlyPublished = $lesson->status === 'published' && $previousStatus !== 'published'; | |
| 1160 | + do_action('fluent_community/lesson/updated', $lesson, $dirtyFields, $isNewlyPublished); | |
| 1161 | + | |
| 1162 | + if ($isNewlyPublished) { | |
| 1163 | + do_action('fluent_community/lesson/published', $lesson); | |
| 1164 | + } | |
| 1127 | 1165 | } |
| 1128 | 1166 | } |
| 1129 | 1167 | |
| 1130 | 1168 | return [ |
| @@ -1199,8 +1237,9 @@ | ||
| 1199 | 1237 | $newLesson = CourseLesson::findOrFail($newLesson->id); |
| 1200 | 1238 | |
| 1201 | 1239 | CourseHelper::copyLessonDocuments($lesson, $newLesson); |
| 1202 | 1240 | |
| 1241 | + do_action('fluent_community/lesson/created', $newLesson, $newLesson->topic); | |
| 1203 | 1242 | do_action('fluent_community/lesson/duplicated', $newLesson, $lesson); |
| 1204 | 1243 | |
| 1205 | 1244 | return [ |
| 1206 | 1245 | 'message' => __('Lesson has been duplicated successfully.', 'fluent-community'), |