PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 2.1.5
Tutor LMS – eLearning and online course solution v2.1.5
3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 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.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 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.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.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / models / CourseModel.php
tutor / models Last commit date
CourseModel.php 3 years ago LessonModel.php 3 years ago QuizModel.php 3 years ago WithdrawModel.php 3 years ago
CourseModel.php
381 lines
1 <?php
2 /**
3 * Course Model
4 *
5 * @package Tutor\Models
6 * @author Themeum <support@themeum.com>
7 * @link https://themeum.com
8 * @since 2.0.6
9 */
10
11 namespace Tutor\Models;
12
13 use Tutor\Helpers\QueryHelper;
14
15 /**
16 * CourseModel Class
17 *
18 * @since 2.0.6
19 */
20 class CourseModel {
21 /**
22 * WordPress course type name
23 *
24 * @var string
25 */
26 const POST_TYPE = 'courses';
27
28 const STATUS_PUBLISH = 'publish';
29 const STATUS_DRAFT = 'draft';
30 const STATUS_AUTO_DRAFT = 'auto-draft';
31 const STATUS_PENDING = 'pending';
32
33 /**
34 * Course record count
35 *
36 * @since 2.0.7
37 *
38 * @param string $status course status.
39 * @return int
40 */
41 public static function count( $status = self::STATUS_PUBLISH ) {
42 $count_obj = wp_count_posts( self::POST_TYPE );
43 if ( 'all' === $status ) {
44 return array_sum( (array) $count_obj );
45 }
46
47 return (int) $count_obj->{$status};
48 }
49
50 /**
51 * Get courses
52 *
53 * @since 1.0.0
54 *
55 * @param array $excludes exclude course ids.
56 * @param array $post_status post status array.
57 *
58 * @return array|null|object
59 */
60 public function get_courses( $excludes = array(), $post_status = array( 'publish' ) ) {
61 global $wpdb;
62
63 $excludes = (array) $excludes;
64 $exclude_query = '';
65
66 if ( count( $excludes ) ) {
67 $exclude_query = implode( "','", $excludes );
68 }
69
70 $post_status = array_map(
71 function ( $element ) {
72 return "'" . $element . "'";
73 },
74 $post_status
75 );
76
77 $post_status = implode( ',', $post_status );
78 $course_post_type = tutor()->course_post_type;
79
80 //phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
81 $query = $wpdb->get_results(
82 $wpdb->prepare(
83 "SELECT ID,
84 post_author,
85 post_title,
86 post_name,
87 post_status,
88 menu_order
89 FROM {$wpdb->posts}
90 WHERE post_status IN ({$post_status})
91 AND ID NOT IN('$exclude_query')
92 AND post_type = %s;
93 ",
94 $course_post_type
95 )
96 );
97 //phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
98
99 return $query;
100 }
101
102 /**
103 * Get courses for instructors
104 *
105 * @since 1.0.0
106 *
107 * @param int $instructor_id Instructor ID.
108 * @return array|null|object
109 */
110 public function get_courses_for_instructors( $instructor_id = 0 ) {
111 $instructor_id = tutor_utils()->get_user_id( $instructor_id );
112 $course_post_type = tutor()->course_post_type;
113
114 $courses = get_posts(
115 array(
116 'post_type' => $course_post_type,
117 'author' => $instructor_id,
118 'post_status' => array( 'publish', 'pending' ),
119 'posts_per_page' => 5,
120 )
121 );
122
123 return $courses;
124 }
125
126 /**
127 * Mark the course as completed
128 *
129 * @since 2.0.7
130 *
131 * @param int $course_id course id which is completed.
132 * @param int $user_id student id who completed the course.
133 *
134 * @return bool
135 */
136 public static function mark_course_as_completed( $course_id, $user_id ) {
137 if ( ! $course_id || ! $user_id ) {
138 return false;
139 }
140
141 do_action( 'tutor_course_complete_before', $course_id );
142
143 /**
144 * Marking course completed at Comment.
145 */
146 global $wpdb;
147
148 $date = date( 'Y-m-d H:i:s', tutor_time() );
149
150 // Making sure that, hash is unique.
151 do {
152 $hash = substr( md5( wp_generate_password( 32 ) . $date . $course_id . $user_id ), 0, 16 );
153 $has_hash = (int) $wpdb->get_var(
154 $wpdb->prepare(
155 "SELECT COUNT(comment_ID) from {$wpdb->comments}
156 WHERE comment_agent = 'TutorLMSPlugin' AND comment_type = 'course_completed' AND comment_content = %s ",
157 $hash
158 )
159 );
160
161 } while ( $has_hash > 0 );
162
163 $data = array(
164 'comment_post_ID' => $course_id,
165 'comment_author' => $user_id,
166 'comment_date' => $date,
167 'comment_date_gmt' => get_gmt_from_date( $date ),
168 'comment_content' => $hash, // Identification Hash.
169 'comment_approved' => 'approved',
170 'comment_agent' => 'TutorLMSPlugin',
171 'comment_type' => 'course_completed',
172 'user_id' => $user_id,
173 );
174
175 $wpdb->insert( $wpdb->comments, $data );
176
177 do_action( 'tutor_course_complete_after', $course_id, $user_id );
178
179 return true;
180 }
181
182 /**
183 * Delete a course by ID
184 *
185 * @since 2.0.9
186 *
187 * @param int $post_id course id that need to delete.
188 * @return bool
189 */
190 public static function delete_course( $post_id ) {
191 if ( get_post_type( $post_id ) !== tutor()->course_post_type ) {
192 return false;
193 }
194
195 wp_delete_post( $post_id, true );
196 return true;
197 }
198
199 /**
200 * Get post ids by post type and parent_id
201 *
202 * @since 1.6.6
203 *
204 * @param string $post_type post type.
205 * @param integer $post_parent post parent ID.
206 *
207 * @return array
208 */
209 private function get_post_ids( $post_type, $post_parent ) {
210 $args = array(
211 'fields' => 'ids',
212 'post_type' => $post_type,
213 'post_parent' => $post_parent,
214 'post_status' => 'any',
215 'posts_per_page' => -1,
216 );
217 return get_posts( $args );
218 }
219
220 /**
221 * Delete course data when permanently deleting a course.
222 *
223 * @since 1.6.6
224 * @since 2.0.9 updated
225 *
226 * @param integer $post_id post ID.
227 * @return bool
228 */
229 public function delete_course_data( $post_id ) {
230 $course_post_type = tutor()->course_post_type;
231 if ( get_post_type( $post_id ) !== $course_post_type ) {
232 return false;
233 }
234
235 global $wpdb;
236
237 $lesson_post_type = tutor()->lesson_post_type;
238 $assignment_post_type = tutor()->assignment_post_type;
239 $quiz_post_type = tutor()->quiz_post_type;
240
241 $topic_ids = $this->get_post_ids( 'topics', $post_id );
242
243 // Course > Topic > ( Lesson | Quiz | Assignment ).
244 if ( ! empty( $topic_ids ) ) {
245 foreach ( $topic_ids as $topic_id ) {
246 $content_post_type = array( $lesson_post_type, $assignment_post_type, $quiz_post_type );
247 $topic_content_ids = $this->get_post_ids( $content_post_type, $topic_id );
248
249 foreach ( $topic_content_ids as $content_id ) {
250 /**
251 * Delete Quiz data
252 */
253 if ( get_post_type( $content_id ) === 'tutor_quiz' ) {
254 $wpdb->delete( $wpdb->prefix . 'tutor_quiz_attempts', array( 'quiz_id' => $content_id ) );
255 $wpdb->delete( $wpdb->prefix . 'tutor_quiz_attempt_answers', array( 'quiz_id' => $content_id ) );
256
257 $questions_ids = $wpdb->get_col( $wpdb->prepare( "SELECT question_id FROM {$wpdb->prefix}tutor_quiz_questions WHERE quiz_id = %d ", $content_id ) );
258 if ( is_array( $questions_ids ) && count( $questions_ids ) ) {
259 $in_question_ids = "'" . implode( "','", $questions_ids ) . "'";
260 //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
261 $wpdb->query( "DELETE FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id IN({$in_question_ids}) " );
262 }
263 $wpdb->delete( $wpdb->prefix . 'tutor_quiz_questions', array( 'quiz_id' => $content_id ) );
264 }
265
266 /**
267 * Delete assignment data ( Assignments, Assignment Submit, Assignment Evalutation )
268 *
269 * @since 2.0.9
270 */
271 if ( get_post_type( $content_id ) === $assignment_post_type ) {
272 QueryHelper::delete_comment_with_meta(
273 array(
274 'comment_type' => 'tutor_assignment',
275 'comment_post_ID' => $content_id,
276 )
277 );
278 }
279
280 wp_delete_post( $content_id, true );
281
282 }
283
284 // Delete zoom meeting.
285 $wpdb->delete(
286 $wpdb->posts,
287 array(
288 'post_parent' => $topic_id,
289 'post_type' => 'tutor_zoom_meeting',
290 )
291 );
292
293 /**
294 * Delete Google Meet Record Related to Course Topic
295 *
296 * @since 2.1.0
297 */
298 $wpdb->delete(
299 $wpdb->posts,
300 array(
301 'post_parent' => $topic_id,
302 'post_type' => 'tutor-google-meet',
303 )
304 );
305
306 wp_delete_post( $topic_id, true );
307 }
308 }
309
310 $child_post_ids = $this->get_post_ids( array( 'tutor_announcements', 'tutor_enrolled', 'tutor_zoom_meeting', 'tutor-google-meet' ), $post_id );
311 if ( ! empty( $child_post_ids ) ) {
312 foreach ( $child_post_ids as $child_post_id ) {
313 wp_delete_post( $child_post_id, true );
314 }
315 }
316
317 /**
318 * Delete earning, gradebook result, course complete data
319 *
320 * @since 2.0.9
321 */
322 $wpdb->delete( $wpdb->prefix . 'tutor_earnings', array( 'course_id' => $post_id ) );
323 $wpdb->delete( $wpdb->prefix . 'tutor_gradebooks_results', array( 'course_id' => $post_id ) );
324 $wpdb->delete(
325 $wpdb->comments,
326 array(
327 'comment_type' => 'course_completed',
328 'comment_post_ID' => $post_id,
329 )
330 );
331
332 /**
333 * Delete onsite notification record & _tutor_instructor_course_id user meta
334 *
335 * @since 2.1.0
336 */
337 $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}tutor_notifications WHERE post_id=%d AND type IN ('Announcements','Q&A','Enrollments')", $post_id ) );
338 $wpdb->delete(
339 $wpdb->usermeta,
340 array(
341 'meta_key' => '_tutor_instructor_course_id',
342 'meta_value' => $post_id,
343 )
344 );
345
346 /**
347 * Delete Course rating and review
348 *
349 * @since 2.0.9
350 */
351 QueryHelper::delete_comment_with_meta(
352 array(
353 'comment_type' => 'tutor_course_rating',
354 'comment_post_ID' => $post_id,
355 )
356 );
357
358 /**
359 * Delete Q&A and its status ( read, replied etc )
360 *
361 * @since 2.0.9
362 */
363 QueryHelper::delete_comment_with_meta(
364 array(
365 'comment_type' => 'tutor_q_and_a',
366 'comment_post_ID' => $post_id,
367 )
368 );
369
370 /**
371 * Delete caches
372 */
373 $attempt_cache = new \Tutor\Cache\QuizAttempts();
374 if ( $attempt_cache->has_cache() ) {
375 $attempt_cache->delete_cache();
376 }
377
378 return true;
379 }
380 }
381