PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 2.1.6
Tutor LMS – eLearning and online course solution v2.1.6
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
402 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 * Check a user is main instructor of a course
128 *
129 * @since 2.1.6
130 *
131 * @param integer $course_id course id.
132 * @param integer $user_id instructor id ( optional ) default: current user id.
133 *
134 * @return boolean
135 */
136 public static function is_main_instructor( $course_id, $user_id = 0 ) {
137 $course = get_post( $course_id );
138 $user_id = tutor_utils()->get_user_id( $user_id );
139
140 if ( ! $course || self::POST_TYPE !== $course->post_type || $user_id !== (int) $course->post_author ) {
141 return false;
142 }
143
144 return true;
145 }
146
147 /**
148 * Mark the course as completed
149 *
150 * @since 2.0.7
151 *
152 * @param int $course_id course id which is completed.
153 * @param int $user_id student id who completed the course.
154 *
155 * @return bool
156 */
157 public static function mark_course_as_completed( $course_id, $user_id ) {
158 if ( ! $course_id || ! $user_id ) {
159 return false;
160 }
161
162 do_action( 'tutor_course_complete_before', $course_id );
163
164 /**
165 * Marking course completed at Comment.
166 */
167 global $wpdb;
168
169 $date = date( 'Y-m-d H:i:s', tutor_time() );
170
171 // Making sure that, hash is unique.
172 do {
173 $hash = substr( md5( wp_generate_password( 32 ) . $date . $course_id . $user_id ), 0, 16 );
174 $has_hash = (int) $wpdb->get_var(
175 $wpdb->prepare(
176 "SELECT COUNT(comment_ID) from {$wpdb->comments}
177 WHERE comment_agent = 'TutorLMSPlugin' AND comment_type = 'course_completed' AND comment_content = %s ",
178 $hash
179 )
180 );
181
182 } while ( $has_hash > 0 );
183
184 $data = array(
185 'comment_post_ID' => $course_id,
186 'comment_author' => $user_id,
187 'comment_date' => $date,
188 'comment_date_gmt' => get_gmt_from_date( $date ),
189 'comment_content' => $hash, // Identification Hash.
190 'comment_approved' => 'approved',
191 'comment_agent' => 'TutorLMSPlugin',
192 'comment_type' => 'course_completed',
193 'user_id' => $user_id,
194 );
195
196 $wpdb->insert( $wpdb->comments, $data );
197
198 do_action( 'tutor_course_complete_after', $course_id, $user_id );
199
200 return true;
201 }
202
203 /**
204 * Delete a course by ID
205 *
206 * @since 2.0.9
207 *
208 * @param int $post_id course id that need to delete.
209 * @return bool
210 */
211 public static function delete_course( $post_id ) {
212 if ( get_post_type( $post_id ) !== tutor()->course_post_type ) {
213 return false;
214 }
215
216 wp_delete_post( $post_id, true );
217 return true;
218 }
219
220 /**
221 * Get post ids by post type and parent_id
222 *
223 * @since 1.6.6
224 *
225 * @param string $post_type post type.
226 * @param integer $post_parent post parent ID.
227 *
228 * @return array
229 */
230 private function get_post_ids( $post_type, $post_parent ) {
231 $args = array(
232 'fields' => 'ids',
233 'post_type' => $post_type,
234 'post_parent' => $post_parent,
235 'post_status' => 'any',
236 'posts_per_page' => -1,
237 );
238 return get_posts( $args );
239 }
240
241 /**
242 * Delete course data when permanently deleting a course.
243 *
244 * @since 1.6.6
245 * @since 2.0.9 updated
246 *
247 * @param integer $post_id post ID.
248 * @return bool
249 */
250 public function delete_course_data( $post_id ) {
251 $course_post_type = tutor()->course_post_type;
252 if ( get_post_type( $post_id ) !== $course_post_type ) {
253 return false;
254 }
255
256 global $wpdb;
257
258 $lesson_post_type = tutor()->lesson_post_type;
259 $assignment_post_type = tutor()->assignment_post_type;
260 $quiz_post_type = tutor()->quiz_post_type;
261
262 $topic_ids = $this->get_post_ids( 'topics', $post_id );
263
264 // Course > Topic > ( Lesson | Quiz | Assignment ).
265 if ( ! empty( $topic_ids ) ) {
266 foreach ( $topic_ids as $topic_id ) {
267 $content_post_type = array( $lesson_post_type, $assignment_post_type, $quiz_post_type );
268 $topic_content_ids = $this->get_post_ids( $content_post_type, $topic_id );
269
270 foreach ( $topic_content_ids as $content_id ) {
271 /**
272 * Delete Quiz data
273 */
274 if ( get_post_type( $content_id ) === 'tutor_quiz' ) {
275 $wpdb->delete( $wpdb->prefix . 'tutor_quiz_attempts', array( 'quiz_id' => $content_id ) );
276 $wpdb->delete( $wpdb->prefix . 'tutor_quiz_attempt_answers', array( 'quiz_id' => $content_id ) );
277
278 $questions_ids = $wpdb->get_col( $wpdb->prepare( "SELECT question_id FROM {$wpdb->prefix}tutor_quiz_questions WHERE quiz_id = %d ", $content_id ) );
279 if ( is_array( $questions_ids ) && count( $questions_ids ) ) {
280 $in_question_ids = "'" . implode( "','", $questions_ids ) . "'";
281 //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
282 $wpdb->query( "DELETE FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id IN({$in_question_ids}) " );
283 }
284 $wpdb->delete( $wpdb->prefix . 'tutor_quiz_questions', array( 'quiz_id' => $content_id ) );
285 }
286
287 /**
288 * Delete assignment data ( Assignments, Assignment Submit, Assignment Evalutation )
289 *
290 * @since 2.0.9
291 */
292 if ( get_post_type( $content_id ) === $assignment_post_type ) {
293 QueryHelper::delete_comment_with_meta(
294 array(
295 'comment_type' => 'tutor_assignment',
296 'comment_post_ID' => $content_id,
297 )
298 );
299 }
300
301 wp_delete_post( $content_id, true );
302
303 }
304
305 // Delete zoom meeting.
306 $wpdb->delete(
307 $wpdb->posts,
308 array(
309 'post_parent' => $topic_id,
310 'post_type' => 'tutor_zoom_meeting',
311 )
312 );
313
314 /**
315 * Delete Google Meet Record Related to Course Topic
316 *
317 * @since 2.1.0
318 */
319 $wpdb->delete(
320 $wpdb->posts,
321 array(
322 'post_parent' => $topic_id,
323 'post_type' => 'tutor-google-meet',
324 )
325 );
326
327 wp_delete_post( $topic_id, true );
328 }
329 }
330
331 $child_post_ids = $this->get_post_ids( array( 'tutor_announcements', 'tutor_enrolled', 'tutor_zoom_meeting', 'tutor-google-meet' ), $post_id );
332 if ( ! empty( $child_post_ids ) ) {
333 foreach ( $child_post_ids as $child_post_id ) {
334 wp_delete_post( $child_post_id, true );
335 }
336 }
337
338 /**
339 * Delete earning, gradebook result, course complete data
340 *
341 * @since 2.0.9
342 */
343 $wpdb->delete( $wpdb->prefix . 'tutor_earnings', array( 'course_id' => $post_id ) );
344 $wpdb->delete( $wpdb->prefix . 'tutor_gradebooks_results', array( 'course_id' => $post_id ) );
345 $wpdb->delete(
346 $wpdb->comments,
347 array(
348 'comment_type' => 'course_completed',
349 'comment_post_ID' => $post_id,
350 )
351 );
352
353 /**
354 * Delete onsite notification record & _tutor_instructor_course_id user meta
355 *
356 * @since 2.1.0
357 */
358 $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}tutor_notifications WHERE post_id=%d AND type IN ('Announcements','Q&A','Enrollments')", $post_id ) );
359 $wpdb->delete(
360 $wpdb->usermeta,
361 array(
362 'meta_key' => '_tutor_instructor_course_id',
363 'meta_value' => $post_id,
364 )
365 );
366
367 /**
368 * Delete Course rating and review
369 *
370 * @since 2.0.9
371 */
372 QueryHelper::delete_comment_with_meta(
373 array(
374 'comment_type' => 'tutor_course_rating',
375 'comment_post_ID' => $post_id,
376 )
377 );
378
379 /**
380 * Delete Q&A and its status ( read, replied etc )
381 *
382 * @since 2.0.9
383 */
384 QueryHelper::delete_comment_with_meta(
385 array(
386 'comment_type' => 'tutor_q_and_a',
387 'comment_post_ID' => $post_id,
388 )
389 );
390
391 /**
392 * Delete caches
393 */
394 $attempt_cache = new \Tutor\Cache\QuizAttempts();
395 if ( $attempt_cache->has_cache() ) {
396 $attempt_cache->delete_cache();
397 }
398
399 return true;
400 }
401 }
402