PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.8
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.8
4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 All 139 releases
learnpress / inc / curds / class-lp-course-curd.php

class-lp-course-curd.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.8, at inc/curds/class-lp-course-curd.php

613 lines 15.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class LP_Course_CURD
4 *
5 * @author ThimPress
6 * @package LearnPress/Classes/CURD
7 * @since 3.0.0
8 */
9
10 /**
11 * Prevent loading this file directly
12 */
13 defined( 'ABSPATH' ) || exit();
14
15 if ( ! class_exists( 'LP_Course_CURD' ) ) {
16
17 /**
18 * Class LP_Course_CURD
19 */
20 class LP_Course_CURD extends LP_Object_Data_CURD implements LP_Interface_CURD {
21
22 /**
23 * LP_Course_CURD constructor.
24 */
25 public function __construct() {
26 $this->_error_messages = array(
27 'COURSE_NOT_EXISTS' => __( 'The course does not exist.', 'learnpress' ),
28 );
29 }
30
31 /**
32 * Create course, with default meta.
33 *
34 * @param $args
35 *
36 * @return int|WP_Error
37 * @since 3.0.0
38 */
39 public function create( &$args ) {
40
41 $args = wp_parse_args(
42 $args,
43 array(
44 'id' => '',
45 'status' => 'publish',
46 'title' => __( 'New Course', 'learnpress' ),
47 'content' => '',
48 'author' => learn_press_get_current_user_id(),
49 )
50 );
51
52 $course_id = wp_insert_post(
53 array(
54 'ID' => $args['id'],
55 'post_type' => LP_COURSE_CPT,
56 'post_status' => $args['status'],
57 'post_title' => $args['title'],
58 'post_content' => $args['content'],
59 'post_author' => $args['author'],
60 )
61 );
62
63 if ( $course_id ) {
64 // add default meta for new course
65 $default_meta = LP_Course::get_default_meta();
66
67 if ( is_array( $default_meta ) ) {
68 foreach ( $default_meta as $key => $value ) {
69 update_post_meta( $course_id, '_lp_' . $key, $value );
70 }
71 }
72 }
73
74 return $course_id;
75 }
76
77 public function update( &$course ) {
78 // TODO: Implement update() method.
79 }
80
81 /**
82 * Delete course.
83 *
84 * @param object $course_id
85 *
86 * @since 3.0.0
87 * @editor tungnx
88 * @modify 4.1.4.1
89 */
90 public function delete( &$course_id ) {
91 // section curd
92 // $curd = new LP_Section_CURD( $course_id );
93 // clear course items
94 // $curd->clear();
95 }
96
97 /**
98 * Delete course itself and sections.
99 *
100 * @param int|object $course_id
101 * @param bool $delete_item - Optional. TRUE will delete all items assigned to course
102 */
103 public function delete_course( $course_id, $delete_item = false ) {
104 if ( $delete_item ) {
105 $course = learn_press_get_course( $course_id );
106
107 if ( $course ) {
108 $items = $course->get_items();
109
110 if ( $items ) {
111 foreach ( $items as $item ) {
112 wp_delete_post( $item );
113 }
114 }
115 }
116 }
117
118 wp_delete_post( $course_id );
119 }
120
121 /**
122 * Duplicate course.
123 *
124 * @param int $course_id
125 * @param array $args
126 *
127 * @return int|WP_Error
128 * @since 3.0.0
129 * @version 1.0.2
130 */
131 public function duplicate( &$course_id, $args = array() ) {
132 $course_id_new = 0;
133
134 try {
135 if ( ! current_user_can( 'edit_posts' ) ) {
136 throw new Exception( 'Sorry! You don\'t have permission to duplicate this course' );
137 }
138
139 $course_origin = learn_press_get_course( $course_id );
140 if ( ! $course_origin ) {
141 throw new Exception( 'The course is invalid!' );
142 }
143
144 $course_id_new = learn_press_duplicate_post( $course_id, $args );
145
146 if ( is_wp_error( $course_id_new ) ) {
147 return $course_id_new;
148 }
149
150 $this->duplicate_sections( $course_id_new, $course_origin );
151
152 // Call save course duplicate
153 LP_Course_Post_Type::instance()->save_post( $course_id_new );
154
155 do_action( 'learn-press/item/after-duplicate', $course_id, $course_id_new, $args );
156 } catch ( Throwable $e ) {
157 $course_id_new = new WP_Error( $e->getMessage() );
158 }
159
160 return $course_id_new;
161 }
162
163 /**
164 * Duplicate sections and items of course
165 *
166 * @param int $course_id_new
167 * @param LP_Course $course_origin
168 */
169 public function duplicate_sections( int $course_id_new, LP_Course $course_origin ) {
170 try {
171 $curriculum = $course_origin->get_curriculum_raw();
172
173 // new course section curd
174 $section_curd_new = new LP_Section_CURD( $course_id_new );
175 foreach ( $curriculum as $section_origin ) {
176 $data = array(
177 'section_id' => $section_origin['id'],
178 'section_name' => $section_origin['title'],
179 'section_course_id' => $course_id_new,
180 'section_order' => $section_origin['order'],
181 'section_description' => $section_origin['description'],
182 );
183
184 // Hook before clone section.
185 $can_clone = true;
186 $can_clone = apply_filters( 'lp/section/can-clone', $can_clone, $course_id_new, $course_origin, $section_origin );
187 if ( ! $can_clone ) {
188 continue;
189 }
190
191 // Clone section
192 $section_new = $section_curd_new->create( $data );
193 // Clone items of section
194 if ( isset( $section_new['section_id'] ) ) {
195 $this->duplicate_section_items( $section_new['section_id'], $section_curd_new, $section_origin );
196 $args = compact( 'section_new', 'section_origin', 'course_id_new', 'course_origin' );
197 do_action( 'lp/section/clone/success', $args );
198 }
199 }
200 } catch ( Throwable $e ) {
201 error_log( $e->getMessage() );
202 }
203 }
204
205 /**
206 * Duplicate items of section.
207 *
208 * @param int $section_id_new
209 * @param LP_Section_CURD $section_curd_new
210 * @param array $section_origin
211 *
212 * @version 3.0.1
213 * @since 3.0.0
214 * @return void
215 */
216 public function duplicate_section_items( int $section_id_new, LP_Section_CURD $section_curd_new, array $section_origin ) {
217 try {
218 $item_origins = $section_origin['items'] ?? array();
219 $new_items = array();
220
221 foreach ( $item_origins as $key => $item_origin ) {
222 if ( ! isset( $item_origin['type'] ) ) {
223 continue;
224 }
225
226 // Get class CURD of item.
227 $class_item_curd_str = ucwords( $item_origin['type'], '_' ) . '_CURD';
228 /**
229 * @var LP_Object_Data_CURD $class_item_curd_str
230 */
231 if ( class_exists( $class_item_curd_str ) ) {
232 $can_clone = true;
233 $args = compact( 'item_origin', 'section_id_new', 'section_curd_new', 'section_origin' );
234 $can_clone = apply_filters( 'lp/section/item/can-clone', $can_clone, $args );
235
236 if ( ! $can_clone ) {
237 continue;
238 }
239
240 $class_item_curd = new $class_item_curd_str();
241 $new_item_id = $class_item_curd->duplicate(
242 $item_origin['id'],
243 array( 'post_status' => 'publish' )
244 );
245
246 // Prepare data to assign item to section.
247 $new_item = array(
248 'item_id' => $new_item_id,
249 'item_type' => $item_origin['type'],
250 'item_order' => $item_origin['order'],
251 );
252
253 $section_curd_new->assign_item_section( $section_id_new, $new_item );
254 }
255 }
256 } catch ( Throwable $e ) {
257 error_log( $e->getMessage() );
258 }
259 }
260
261 /**
262 * Load course data
263 *
264 * @param LP_Course|LP_Abstract_Course $course
265 *
266 * @return mixed
267 */
268 public function load( &$course ) {
269 // $this->read_course_curriculum( $course->get_id() );
270
271 return $course;
272 }
273
274 /**
275 * Get all courses that contains an item by item id.
276 * Data returned is an array of all courses found.
277 *
278 * @param int $item_id - ID of any item
279 * @param bool $check_support - Optional. TRUE will check if course is support that item
280 *
281 * @return array|bool
282 * @since 3.1.0
283 */
284 public function get_course_by_item( $item_id, $check_support = true ) {
285 if ( $check_support && ! learn_press_is_support_course_item_type( get_post_type( $item_id ) ) ) {
286 return false;
287 }
288
289 global $wpdb;
290
291 $query = $wpdb->prepare(
292 "
293 SELECT c.ID
294 FROM {$wpdb->posts} c
295 INNER JOIN {$wpdb->learnpress_sections} s ON c.ID = s.section_course_id
296 INNER JOIN {$wpdb->learnpress_section_items} si ON si.section_id = s.section_id
297 WHERE si.item_id = %d
298 ",
299 $item_id
300 );
301
302 return $wpdb->get_col( $query );
303 }
304
305 /**
306 * Retrieve total sections of a course.
307 *
308 * @param int $course_id
309 *
310 * @return int
311 * @since 3.1.0
312 */
313 public function count_sections( $course_id ) {
314 global $wpdb;
315
316 $query = $wpdb->prepare(
317 "
318 SELECT COUNT(section_id)
319 FROM {$wpdb->learnpress_sections}
320 WHERE section_course_id = %d
321 ",
322 $course_id
323 );
324
325 return $wpdb->get_var( $query );
326 }
327
328 /**
329 * Read sections of a bundle of courses by ids
330 *
331 * @param int|array $course_id
332 *
333 * @return mixed|array
334 * @version 4.0.0
335 * @deprecated 4.1.6.9
336 * Use in addon co-instructor 4.0.2
337 */
338 /*public function read_course_sections( $course_id ) {
339 _deprecated_function( __FUNCTION__, '4.1.6.9 call from ' . debug_backtrace()[0]['function'] );
340 return false;
341 global $wpdb;
342
343 settype( $course_id, 'array' );
344 $first_course_sections = false;
345
346 foreach ( $course_id as $cid ) {
347 $course_sections = LP_Course_Utils::get_cached_db_sections( $cid );
348
349 if ( false === $course_sections ) {
350 $query = $wpdb->prepare(
351 "
352 SELECT s.section_id, s.section_name, s.section_course_id, s.section_order, s.section_description, 'asd'
353 FROM {$wpdb->posts} p
354 INNER JOIN {$wpdb->learnpress_sections} s ON p.ID = s.section_course_id
355 WHERE p.ID = %d
356 ORDER BY p.ID, `section_order` ASC
357 ",
358 $cid
359 );
360
361 $course_sections = $wpdb->get_results( $query );
362
363 if ( ! $course_sections ) {
364 $course_sections = array();
365 }
366
367 if ( false === $first_course_sections ) {
368 $first_course_sections = $course_sections;
369 }
370
371 LP_Course_Utils::set_cache_db_sections( $cid, $course_sections );
372 }
373 }
374
375 return $first_course_sections;
376 }*/
377
378 /**
379 * Remove lesson, quiz from course's curriculum.
380 *
381 * @param int $item_id
382 * @param int $course_id - Optional. Added since 3.1.0
383 *
384 * @since 3.0.0
385 */
386 public function remove_item( $item_id, $course_id = 0 ) {
387 $learnpress_user_item_db = LP_User_Items_DB::getInstance();
388 global $wpdb;
389 // allow hook
390 do_action( 'learn-press/before-remove-section-item', $item_id, $course_id );
391
392 if ( $course_id ) {
393 if ( is_array( $course_id ) ) {
394 $format = array_fill( 0, sizeof( $course_id ), '%d' );
395 $where = $wpdb->prepare( 'AND s.section_course_id IN(' . join( ',', $format ) . ')', $course_id );
396 } else {
397 $where = $wpdb->prepare( 'AND s.section_course_id = %d', $course_id );
398 }
399 $query = $wpdb->prepare(
400 "
401 DELETE si
402 FROM {$wpdb->learnpress_section_items} si
403 INNER JOIN {$wpdb->learnpress_sections} s ON s.section_id = si.section_id
404 WHERE item_id = %d
405 {$where}
406 ",
407 $item_id
408 );
409 } else {
410
411 $query = $wpdb->prepare(
412 "
413 SELECT s.section_course_id
414 FROM {$wpdb->learnpress_sections} s
415 INNER JOIN {$wpdb->learnpress_section_items} si ON s.section_id = si.section_id
416 WHERE si.item_id = %d
417 ",
418 $item_id
419 );
420
421 $course_id = $wpdb->get_col( $query );
422 $query = $wpdb->prepare( "DELETE FROM {$wpdb->learnpress_section_items} WHERE item_id = %d", $item_id );
423 }
424
425 // delete item from course's section
426 $wpdb->query( $query );
427
428 if ( $course_id ) {
429 settype( $course_id, 'array' );
430
431 foreach ( $course_id as $cid ) {
432 do_action( 'learn-press/removed-item-from-section', $item_id, $cid );
433 $learnpress_user_item_db->reset_course_current_item( $cid, $item_id );
434 } // end foreach $course_id as $cid
435 }
436
437 learn_press_reset_auto_increment( 'learnpress_section_items' );
438 }
439
440 /**
441 * Get recent courses.
442 *
443 * @param array $args
444 *
445 * @return array
446 * @since 3.0.0
447 * @version 1.0.2
448 */
449 public function get_recent_courses( $args = array() ) {
450 global $wpdb;
451
452 $limit = absint( $args['limit'] ?? 5 );
453 $order = $args['order'] ?? 'DESC';
454 if ( ! in_array( $order, array( 'ASC', 'DESC' ) ) ) {
455 $order = 'DESC';
456 }
457
458 $query = apply_filters(
459 'learn-press/course-curd/query-recent-courses',
460 $wpdb->prepare(
461 "
462 SELECT DISTINCT p.ID
463 FROM $wpdb->posts AS p
464 WHERE p.post_type = %s
465 AND p.post_status = %s
466 ORDER BY p.post_date {$order}
467 LIMIT %d
468 ",
469 LP_COURSE_CPT,
470 'publish',
471 $limit
472 )
473 );
474
475 return $wpdb->get_col( $query );
476 }
477
478 /**
479 * Get all ID of users enrolled course ID.
480 *
481 * @param int $course_id
482 * @param int $limit
483 *
484 * @return array
485 * @Todo tungnx from LP 4.1.3.1 use LP_Course_DB::get_user_ids_enrolled replace
486 * Addon Student List still use
487 */
488 public function get_user_enrolled( $course_id, $limit = - 1 ) {
489 global $wpdb;
490 if ( $limit < 0 ) {
491 $limit = PHP_INT_MAX;
492 }
493 $query = $wpdb->prepare(
494 "
495 SELECT DISTINCT user.ID FROM {$wpdb->users} user
496 INNER JOIN {$wpdb->learnpress_user_items} user_item ON user_item.user_id = user.ID
497 WHERE user_item.item_id = %d
498 AND user_item.item_type = %s
499 LIMIT %d
500 ",
501 $course_id,
502 LP_COURSE_CPT,
503 $limit
504 );
505
506 return $wpdb->get_results( $query );
507 }
508
509 public function count_enrolled_users( $course_ids ) {
510 global $wpdb;
511
512 if ( ! $course_ids ) {
513 return 0;
514 }
515
516 $results = LP_Object_Cache::get( 'enrolled-users', 'learn-press/course' );
517
518 if ( $results && is_numeric( $course_ids ) && array_key_exists( $course_ids, $results ) ) {
519 return $results[ $course_ids ];
520 }
521 settype( $course_ids, 'array' );
522 $sql = $wpdb->prepare(
523 "
524 SELECT item_id cid, count(ID) `count`
525 FROM(SELECT DISTINCT user.ID,user_item.item_id FROM {$wpdb->users} user
526 INNER JOIN {$wpdb->learnpress_user_items} user_item ON user_item.user_id = user.ID
527 WHERE user_item.item_id IN(" . join( ',', $course_ids ) . ')
528 AND user_item.item_type = %s
529 ) AS X GROUP BY item_id',
530 LP_COURSE_CPT
531 );
532
533 $rows = $wpdb->get_results( $sql );
534 if ( $rows ) {
535 foreach ( $rows as $row ) {
536 $results[ $row->cid ] = $row->count;
537 }
538 }
539
540 $total = 0;
541 foreach ( $course_ids as $course_id ) {
542 if ( empty( $results[ $course_id ] ) ) {
543 $results[ $course_id ] = 0;
544 }
545 $total += $results[ $course_id ];
546 }
547 LP_Object_Cache::set( 'enrolled-users', $results, 'learn-press/course' );
548
549 return $total;
550 }
551
552 /**
553 * Get feature courses.
554 *
555 * @param array $args
556 *
557 * @return array
558 * @version 1.0.1
559 * @since 3.0.0
560 * @Todo: should call LP_Course_DB
561 */
562 public function get_featured_courses( $args = array() ) {
563 global $wpdb;
564 $lp_course_db = LP_Course_DB::getInstance();
565 $courses = [];
566
567 try {
568 $limit = absint( $args['limit'] ?? 5 );
569 $order = $args['order'] ?? 'DESC';
570 $order = strtoupper( $order );
571 if ( ! in_array( $order, [ 'DESC', 'ASC' ] ) ) {
572 $order = 'DESC';
573 }
574 $order_by = esc_sql( $args['order_by'] ?? 'post_date' );
575 $filter = new LP_Course_Filter();
576 $cols = $filter->all_fields;
577 $order_by = in_array( $order_by, $cols ) ? $order_by : 'post_date'; // For security
578
579 if ( $limit <= 0 ) {
580 $limit = 0;
581 }
582
583 $query = apply_filters(
584 'learn-press/course-curd/query-featured-courses',
585 $wpdb->prepare(
586 "
587 SELECT DISTINCT p.ID
588 FROM {$wpdb->posts} p
589 LEFT JOIN {$wpdb->postmeta} as pmeta ON p.ID=pmeta.post_id AND pmeta.meta_key = %s
590 WHERE p.post_type = %s
591 AND p.post_status = %s
592 AND pmeta.meta_value = %s
593 ORDER BY p.{$order_by} {$order}
594 LIMIT %d
595 ",
596 '_lp_featured',
597 LP_COURSE_CPT,
598 'publish',
599 'yes',
600 $limit
601 )
602 );
603
604 $courses = $wpdb->get_col( $query );
605 } catch ( Throwable $e ) {
606 error_log( $e->getMessage() );
607 }
608
609 return $courses;
610 }
611 }
612 }
613