PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 4.0.0
Tutor LMS – eLearning and online course solution v4.0.0
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 1 year ago CartItemModel.php 10 months ago CartModel.php 2 days ago CouponModel.php 2 days ago CourseModel.php 2 days ago EnrollmentModel.php 2 days ago LessonModel.php 9 months ago OrderActivitiesModel.php 1 year ago OrderItemMetaModel.php 10 months ago OrderItemModel.php 10 months ago OrderMetaModel.php 1 year ago OrderModel.php 2 days ago QuizModel.php 2 days ago UserModel.php 1 year ago WithdrawModel.php 2 days ago
EnrollmentModel.php
374 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 *
275 * @param integer $user_id user id.
276 * @param integer $course_id cousrs id.
277 *
278 * @return object|mixed
279 */
280 public static function get_enrolled_data( $user_id = 0, $course_id = 0 ) {
281 global $wpdb;
282 // If course ID provided, it will return single row data.
283 if ( $course_id > 0 ) {
284 return $wpdb->get_row(
285 $wpdb->prepare(
286 "SELECT * FROM {$wpdb->posts}
287 WHERE post_type = %s
288 AND post_parent = %d
289 AND post_status = %s
290 AND post_author = %d;",
291 self::POST_TYPE,
292 $course_id,
293 self::STATUS_COMPLETED,
294 $user_id
295 )
296 );
297 } else {
298 // Return all enrolled data by user ID.
299 return $wpdb->get_results(
300 $wpdb->prepare(
301 "SELECT * FROM {$wpdb->posts}
302 WHERE post_type = %s
303 AND post_status = %s
304 AND post_author = %d;",
305 self::POST_TYPE,
306 self::STATUS_COMPLETED,
307 $user_id
308 )
309 );
310 }
311 }
312
313 /**
314 * Execute bulk action for enrollment list ex: complete | cancel
315 *
316 * @since 2.0.3
317 * @since 3.2.0 $trigger_hook param added.
318 *
319 * @param string $status hold status for updating.
320 * @param array $enrollment_ids ids that need to update.
321 * @param bool $trigger_hook optional - trigger hook or not.
322 *
323 * @return bool
324 */
325 public static function update_enrollments( string $status, array $enrollment_ids, bool $trigger_hook = true ): bool {
326 global $wpdb;
327 $enrollment_ids_in = QueryHelper::prepare_in_clause( $enrollment_ids );
328 $status = 'complete' === $status ? 'completed' : $status;
329 $post_table = $wpdb->posts;
330
331 //phpcs:disable
332 $wpdb->query(
333 $wpdb->prepare(
334 "UPDATE {$post_table}
335 SET post_status = %s
336 WHERE ID IN ($enrollment_ids_in)
337 ",
338 $status
339 )
340 );
341 //phpcs:enable
342
343 if ( $trigger_hook ) {
344 // Run action hook.
345 foreach ( $enrollment_ids as $id ) {
346 do_action( 'tutor_enrollment/after/' . $status, $id );
347 }
348 }
349
350 return true;
351 }
352
353 /**
354 * Delete enrollment record by providing the student and course id
355 *
356 * @since 3.4.0
357 *
358 * @param int $student_id Student id.
359 * @param int $course_id Course id.
360 *
361 * @return bool
362 */
363 public static function delete_enrollment_record( int $student_id, int $course_id ): bool {
364 return QueryHelper::delete(
365 'posts',
366 array(
367 'post_author' => $student_id,
368 'post_parent' => $course_id,
369 'post_type' => self::POST_TYPE,
370 )
371 );
372 }
373 }
374