PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 4.0.3
Tutor LMS – eLearning and online course solution v4.0.3
4.0.3 4.0.2 4.0.1 4.0.0 3.9.15 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 / EnrollmentModel.php
tutor / models Last commit date
BaseModel.php 10 months ago BillingModel.php 6 days ago CartItemModel.php 10 months ago CartModel.php 3 weeks ago CouponModel.php 3 weeks ago CourseModel.php 6 days ago EnrollmentModel.php 6 days ago LessonModel.php 10 months ago OrderActivitiesModel.php 1 year ago OrderItemMetaModel.php 10 months ago OrderItemModel.php 10 months ago OrderMetaModel.php 1 year ago OrderModel.php 3 weeks ago QuizModel.php 6 days ago UserModel.php 1 year ago WithdrawModel.php 3 weeks ago
EnrollmentModel.php
375 lines
1 <?php
2 /**
3 * Enrollment Model
4 *
5 * @package Tutor\Models
6 * @author Themeum <support@themeum.com>
7 * @link https://themeum.com
8 * @since 4.0.0
9 */
10
11 namespace Tutor\Models;
12
13 use Tutor\Cache\TutorCache;
14 use TUTOR\Course;
15 use Tutor\Helpers\QueryHelper;
16 use TUTOR\User;
17
18 /**
19 * Class EnrollmentModel
20 *
21 * @since 4.0.0
22 */
23 class EnrollmentModel {
24 /**
25 * Enrollment status constants
26 *
27 * @since 4.0.0
28 *
29 * @var string
30 */
31 const STATUS_COMPLETED = 'completed';
32 const STATUS_PENDING = 'pending';
33 const STATUS_CANCEL = 'cancel';
34
35 /**
36 * Enrollment post type
37 *
38 * @since 4.0.0
39 *
40 * @var string
41 */
42 const POST_TYPE = 'tutor_enrolled';
43
44
45 /**
46 * Enrollment meta
47 *
48 * @since 4.0.0
49 */
50 const ENROLLMENT_ORDER_ID_META = '_tutor_enrolled_by_order_id';
51 const ENROLLMENT_PRODUCT_ID_META = '_tutor_enrolled_by_product_id';
52
53 /**
54 * Saving enroll information to posts table
55 * post_author = enrolled_student_id (wp_users id)
56 * post_parent = enrolled course id
57 *
58 * @since 1.0.0
59 * @since 2.6.0 Return enrolled id
60 * @since 3.3.0 Added $fire_hook parameter.
61 *
62 * @param int $course_id course id.
63 * @param int $order_id order id.
64 * @param int $user_id user id.
65 * @param bool $fire_hook fire hook.
66 *
67 * @return int enrolled id
68 */
69 public static function do_enroll( $course_id = 0, $order_id = 0, $user_id = 0, $fire_hook = true ) {
70 $enrolled_id = 0;
71 if ( ! CourseModel::is_course_accessible( $course_id ) ) {
72 return $enrolled_id;
73 }
74
75 $can_enroll = apply_filters( 'tutor_allow_course_enrollment', true, $course_id );
76 if ( is_wp_error( $can_enroll ) ) {
77 return $enrolled_id;
78 }
79
80 $fire_hook ? do_action( 'tutor_before_enroll', $course_id ) : null;
81 $user_id = tutor_utils()->get_user_id( $user_id );
82 $title = __( 'Course Enrolled', 'tutor' ) . ' &ndash; ' . gmdate( get_option( 'date_format' ) ) . ' @ ' . gmdate( get_option( 'time_format' ) );
83
84 if ( $course_id && $user_id ) {
85 $enrolled_info = self::is_enrolled( $course_id, $user_id );
86 if ( $enrolled_info ) {
87 return $enrolled_info->ID;
88 }
89 }
90
91 $enrolment_status = self::STATUS_COMPLETED;
92
93 if ( tutor_utils()->is_course_purchasable( $course_id ) ) {
94 $enrolment_status = self::STATUS_PENDING;
95 }
96
97 $enroll_data = apply_filters(
98 'tutor_enroll_data',
99 array(
100 'post_type' => self::POST_TYPE,
101 'post_title' => $title,
102 'post_status' => $enrolment_status,
103 'post_author' => $user_id,
104 'post_parent' => $course_id,
105 'post_date_gmt' => current_time( 'mysql', true ),
106 )
107 );
108
109 // Insert the post into the database.
110 $is_enrolled = wp_insert_post( $enroll_data );
111 if ( $is_enrolled ) {
112
113 // Run this hook for both of pending and completed enrollment.
114 $fire_hook ? do_action( 'tutor_after_enroll', $course_id, $is_enrolled ) : null;
115
116 // Mark Current User as Students with user meta data.
117 update_user_meta( $user_id, User::TUTOR_STUDENT_META, tutor_time() );
118
119 if ( $order_id ) {
120 // Mark order for course and user.
121 $product_id = tutor_utils()->get_course_product_id( $course_id );
122 update_post_meta( $is_enrolled, self::ENROLLMENT_ORDER_ID_META, $order_id );
123 update_post_meta( $is_enrolled, self::ENROLLMENT_PRODUCT_ID_META, $product_id );
124
125 $monetize_by = tutor_utils()->get_option( 'monetize_by' );
126 if ( 'wc' === $monetize_by ) {
127 $order = wc_get_order( $order_id );
128 $order->update_meta_data( Course::IS_TUTOR_ORDER_FOR_COURSE_META, tutor_time() );
129 $order->update_meta_data( Course::TUTOR_ORDER_FOR_COURSE_ID_META . $course_id, $is_enrolled );
130 $order->save();
131 } elseif ( 'edd' === $monetize_by ) {
132 $payment = new \EDD_Payment( $order_id );
133 $payment->update_meta( Course::IS_TUTOR_ORDER_FOR_COURSE_META, tutor_time() );
134 $payment->update_meta( Course::TUTOR_ORDER_FOR_COURSE_ID_META . $course_id, $is_enrolled );
135 $payment->save();
136 } else {
137 update_post_meta( $order_id, Course::IS_TUTOR_ORDER_FOR_COURSE_META, tutor_time() );
138 update_post_meta( $order_id, Course::TUTOR_ORDER_FOR_COURSE_ID_META . $course_id, $is_enrolled );
139 }
140 }
141
142 $enrolled_id = $is_enrolled;
143
144 // Run this hook for completed enrollment regardless of payment provider and free/paid mode.
145 if ( $fire_hook && self::STATUS_COMPLETED === $enroll_data['post_status'] ) {
146 do_action( 'tutor_after_enrolled', $course_id, $user_id, $enrolled_id );
147 }
148 }
149
150 return $enrolled_id;
151 }
152
153 /**
154 * Check if current user has been enrolled or not
155 *
156 * @since 1.0.0
157 *
158 * @since 3.0.0 $is_complete parameter added to check with completed status
159 * Default value set true for backward compatibility. It set
160 * false then it will just check record.
161 *
162 * @since 3.3.0 param $is_complete added to cache key.
163 * @since 4.0.0 enrollment order_id and product_id added to enrollment info.
164 *
165 * @param int $course_id course id.
166 * @param int $user_id user id.
167 * @param bool $is_complete Whether to enrollment completed or not.
168 *
169 * @return array|bool|null|object
170 */
171 public static function is_enrolled( $course_id = 0, $user_id = 0, bool $is_complete = true ) {
172 global $wpdb;
173 $course_id = tutor_utils()->get_post_id( $course_id );
174 $user_id = tutor_utils()->get_user_id( $user_id );
175
176 $cache_key = "tutor_is_enrolled_{$course_id}_{$user_id}_{$is_complete}";
177 $cached = TutorCache::get( $cache_key );
178
179 if ( false !== $cached ) {
180 return $cached;
181 }
182
183 do_action( 'tutor_is_enrolled_before', $course_id, $user_id );
184
185 $status_clause = '';
186 if ( $is_complete ) {
187 $status_clause = $wpdb->prepare( 'AND post_status = %s ', self::STATUS_COMPLETED );
188 }
189
190 //phpcs:disable
191 $get_enrolled_info = $wpdb->get_row(
192 $wpdb->prepare(
193 "SELECT ID,
194 post_author,
195 post_date,
196 post_date_gmt,
197 post_title
198 FROM {$wpdb->posts}
199 WHERE post_author > 0
200 AND post_parent > 0
201 AND post_type = %s
202 AND post_parent = %d
203 AND post_author = %d
204 {$status_clause};
205 ",
206 self::POST_TYPE,
207 $course_id,
208 $user_id
209 )
210 );
211 //phpcs:enable
212
213 if ( $get_enrolled_info ) {
214 $get_enrolled_info->order_id = (int) get_post_meta( $get_enrolled_info->ID, self::ENROLLMENT_ORDER_ID_META, true );
215 $get_enrolled_info->product_id = (int) get_post_meta( $get_enrolled_info->ID, self::ENROLLMENT_PRODUCT_ID_META, true );
216 }
217
218 TutorCache::set( $cache_key, $get_enrolled_info );
219
220 if ( $get_enrolled_info ) {
221 return apply_filters( 'tutor_is_enrolled', $get_enrolled_info, $course_id, $user_id );
222 }
223
224 return false;
225 }
226
227 /**
228 * Get enrollment by enrol_id
229 *
230 * @since 1.6.9
231 *
232 * @param int $enrol_id enrol id.
233 *
234 * @return array|object
235 */
236 public static function get_enrolment_by_enrol_id( $enrol_id = 0 ) {
237 global $wpdb;
238
239 $enrolment = $wpdb->get_row(
240 $wpdb->prepare(
241 "SELECT enrol.id AS enrol_id,
242 enrol.post_author AS student_id,
243 enrol.post_date AS enrol_date,
244 enrol.post_title AS enrol_title,
245 enrol.post_status AS status,
246 enrol.post_parent AS course_id,
247 course.post_title AS course_title,
248 student.user_nicename,
249 student.user_email,
250 student.display_name,
251 student.ID
252 FROM {$wpdb->posts} enrol
253 INNER JOIN {$wpdb->posts} course
254 ON enrol.post_parent = course.id
255 INNER JOIN {$wpdb->users} student
256 ON enrol.post_author = student.id
257 WHERE enrol.id = %d;
258 ",
259 $enrol_id
260 )
261 );
262
263 if ( $enrolment ) {
264 return $enrolment;
265 }
266
267 return false;
268 }
269
270 /**
271 * Get single or list of enrolled course data by a user
272 *
273 * @since 2.0.5
274 * @since 4.0.0 param $status added.
275 *
276 * @param integer $user_id user id.
277 * @param integer $course_id course id.
278 * @param string $status the status of enrollment.
279 *
280 * @return object|mixed
281 */
282 public static function get_enrolled_data( $user_id = 0, $course_id = 0, $status = self::STATUS_COMPLETED ) {
283 global $wpdb;
284 $status_clause = $status ? $wpdb->prepare( 'AND post_status = %s ', $status ) : '';
285 // If course ID provided, it will return single row data.
286 if ( $course_id > 0 ) {
287 return $wpdb->get_row(
288 $wpdb->prepare(
289 "SELECT * FROM {$wpdb->posts}
290 WHERE post_type = %s
291 AND post_parent = %d
292 {$status_clause}
293 AND post_author = %d;",
294 self::POST_TYPE,
295 $course_id,
296 $user_id
297 )
298 );
299 } else {
300 // Return all enrolled data by user ID.
301 return $wpdb->get_results(
302 $wpdb->prepare(
303 "SELECT * FROM {$wpdb->posts}
304 WHERE post_type = %s
305 {$status_clause}
306 AND post_author = %d;",
307 self::POST_TYPE,
308 $user_id
309 )
310 );
311 }
312 }
313
314 /**
315 * Execute bulk action for enrollment list ex: complete | cancel
316 *
317 * @since 2.0.3
318 * @since 3.2.0 $trigger_hook param added.
319 *
320 * @param string $status hold status for updating.
321 * @param array $enrollment_ids ids that need to update.
322 * @param bool $trigger_hook optional - trigger hook or not.
323 *
324 * @return bool
325 */
326 public static function update_enrollments( string $status, array $enrollment_ids, bool $trigger_hook = true ): bool {
327 global $wpdb;
328 $enrollment_ids_in = QueryHelper::prepare_in_clause( $enrollment_ids );
329 $status = 'complete' === $status ? 'completed' : $status;
330 $post_table = $wpdb->posts;
331
332 //phpcs:disable
333 $wpdb->query(
334 $wpdb->prepare(
335 "UPDATE {$post_table}
336 SET post_status = %s
337 WHERE ID IN ($enrollment_ids_in)
338 ",
339 $status
340 )
341 );
342 //phpcs:enable
343
344 if ( $trigger_hook ) {
345 // Run action hook.
346 foreach ( $enrollment_ids as $id ) {
347 do_action( 'tutor_enrollment/after/' . $status, $id );
348 }
349 }
350
351 return true;
352 }
353
354 /**
355 * Delete enrollment record by providing the student and course id
356 *
357 * @since 3.4.0
358 *
359 * @param int $student_id Student id.
360 * @param int $course_id Course id.
361 *
362 * @return bool
363 */
364 public static function delete_enrollment_record( int $student_id, int $course_id ): bool {
365 return QueryHelper::delete(
366 'posts',
367 array(
368 'post_author' => $student_id,
369 'post_parent' => $course_id,
370 'post_type' => self::POST_TYPE,
371 )
372 );
373 }
374 }
375