PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.10
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.10
4.4.10 4.4.9.1 4.4.9 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 All 142 releases
← All changes | inc/curds/class-lp-course-curd.php +612 -868 4.1.6.9.4 → 4.4.10 View file →
@@ -1,868 +1,612 @@
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' => __( '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( '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( $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_items[ $key ] = array(
248 - 'id' => $new_item_id,
249 - 'type' => $item_origin['type'],
250 - 'order' => $item_origin['order'],
251 - );
252 - }
253 -
254 - // duplicate quiz
255 - /*if ( $item_origin['type'] === LP_QUIZ_CPT ) {
256 - $new_item_id = $quiz_curd->duplicate(
257 - $item_origin['id'],
258 - array( 'post_status' => 'publish' )
259 - );
260 - } else {
261 - // clone item
262 - $new_item_id = learn_press_duplicate_post(
263 - $item_origin['id'],
264 - array( 'post_status' => 'publish' )
265 - );
266 - }*/
267 - }
268 -
269 - // add new clone items to section
270 - if ( ! empty( $new_items ) ) {
271 - $section_curd_new->add_items_section( $section_id_new, $new_items );
272 - }
273 - } catch ( Throwable $e ) {
274 - error_log( $e->getMessage() );
275 - }
276 - }
277 -
278 - /**
279 - * Load course data
280 - *
281 - * @param LP_Course|LP_Abstract_Course $course
282 - *
283 - * @return mixed
284 - */
285 - public function load( &$course ) {
286 - // $this->read_course_curriculum( $course->get_id() );
287 -
288 - return $course;
289 - }
290 -
291 - /**
292 - * Read all items in a course from database with an array in pair of
293 - * post ID and post type.
294 - *
295 - * @param int $course_id
296 - * @param bool $publish_only
297 - *
298 - * @return array
299 - * @depecated 4.1.6.9
300 - */
301 - /*public function read_course_items( $course_id, $publish_only = true, $section_ids = array() ) {
302 - global $wpdb;
303 - $where = '';
304 -
305 - if ( $publish_only ) {
306 - $where = $wpdb->prepare(
307 - '
308 - AND c.post_status = %s
309 - AND it.post_status = %s
310 - ',
311 - 'publish',
312 - 'publish'
313 - );
314 - }
315 -
316 - $types = learn_press_course_get_support_item_types( true );
317 - $where .= $wpdb->prepare(
318 - ' AND si.item_type IN(' . LP_Helper::db_format_array( $types, '%s' ) . ')',
319 - $types
320 - );
321 -
322 - if ( $section_ids ) {
323 - $where .= $wpdb->prepare(
324 - ' AND s.section_id IN(' . LP_Helper::db_format_array(
325 - $section_ids,
326 - '%d'
327 - ) . ')',
328 - $section_ids
329 - );
330 - }
331 -
332 - $query = $wpdb->prepare(
333 - "
334 - SELECT item_id id, it.post_type `type`, si.section_id
335 - FROM {$wpdb->learnpress_section_items} si
336 - INNER JOIN {$wpdb->learnpress_sections} s ON si.section_id = s.section_id
337 - INNER JOIN {$wpdb->posts} c ON c.ID = s.section_course_id
338 - INNER JOIN {$wpdb->posts} it ON it.ID = si.item_id
339 - WHERE c.ID = %d
340 - {$where}
341 - ORDER BY s.section_order, si.item_order, si.section_item_id ASC
342 - ",
343 - $course_id
344 - );
345 -
346 - $results = $wpdb->get_results( $query );
347 -
348 - return $results;
349 -
350 - //////////////////////////////////////////// Code new - tungnx
351 -
352 - $items = [];
353 -
354 - $course = learn_press_get_course( $course_id );
355 - if ( ! $course ) {
356 - return $items;
357 - }
358 -
359 - $sections_items = $course->get_full_sections_and_items_course();
360 - foreach ( $sections_items as $section_items ) {
361 - $section_id = $section_items->id;
362 -
363 - foreach ( $section_items->items as $item ) {
364 - $item->section_id = $section_id;
365 - $items[] = $item;
366 - }
367 - }
368 -
369 - return $items;
370 - }*/
371 -
372 - /**
373 - * Get all courses that contains an item by item id.
374 - * Data returned is an array of all courses found.
375 - *
376 - * @param int $item_id - ID of any item
377 - * @param bool $check_support - Optional. TRUE will check if course is support that item
378 - *
379 - * @return array|bool
380 - * @since 3.1.0
381 - */
382 - public function get_course_by_item( $item_id, $check_support = true ) {
383 - if ( $check_support && ! learn_press_is_support_course_item_type( get_post_type( $item_id ) ) ) {
384 - return false;
385 - }
386 -
387 - global $wpdb;
388 -
389 - $query = $wpdb->prepare(
390 - "
391 - SELECT c.ID
392 - FROM {$wpdb->posts} c
393 - INNER JOIN {$wpdb->learnpress_sections} s ON c.ID = s.section_course_id
394 - INNER JOIN {$wpdb->learnpress_section_items} si ON si.section_id = s.section_id
395 - WHERE si.item_id = %d
396 - ",
397 - $item_id
398 - );
399 -
400 - return $wpdb->get_col( $query );
401 - }
402 -
403 - /**
404 - * @depecated 4.1.6.9
405 - */
406 - /*public static function update_items_format( $item ) {
407 -
408 - if ( empty( $item['args']['course_id'] ) ) {
409 - return false;
410 - }
411 -
412 - $course_id = absint( $item['args']['course_id'] );
413 -
414 - delete_option( 'update_items_format_' . $course_id );
415 -
416 - global $wpdb;
417 -
418 - $course = learn_press_get_course( $course_id );
419 -
420 - if ( ! $course ) {
421 - return false;
422 - }
423 -
424 - $item_ids = $course->get_items();
425 -
426 - if ( ! $item_ids ) {
427 - return false;
428 - }
429 -
430 - $query = $wpdb->prepare(
431 - "
432 - SELECT object_id AS id, REPLACE(slug, 'post-format-', '') AS format
433 - FROM {$wpdb->terms} AS t
434 - INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id
435 - INNER JOIN {$wpdb->term_relationships} AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id
436 - WHERE tt.taxonomy IN (%s)
437 - AND tr.object_id IN (" . join( ',', $item_ids ) . ')
438 - ORDER BY t.name ASC
439 - ',
440 - 'post_format'
441 - );
442 -
443 - $terms = $wpdb->get_results( $query );
444 -
445 - if ( $terms ) {
446 - $updated = array();
447 - foreach ( $terms as $term ) {
448 - update_post_meta( $term->id, 'post_format', $term->format );
449 - $updated[] = $term->id;
450 - }
451 - $item_ids = array_diff( $item_ids, $updated );
452 - }
453 -
454 - if ( $item_ids ) {
455 - foreach ( $item_ids as $item_id ) {
456 - update_post_meta( $item_id, 'post_format', 'standard' );
457 - }
458 - }
459 -
460 - return false;
461 - }*/
462 -
463 - /**
464 - * Read curriculum of a course from db into cache.
465 - *
466 - * @param $course_id
467 - *
468 - * @return array|mixed
469 - */
470 - /*public function read_course_curriculum( $course_id ) {
471 -
472 - if ( learn_press_get_post_type( $course_id ) != LP_COURSE_CPT ) {
473 - return false;
474 - }
475 -
476 - if ( false !== LP_Course_Utils::get_course_items( $course_id ) ) {
477 - return false;
478 - }
479 -
480 - if ( $this->get_course_sections( $course_id, 'ids' ) ) {
481 - return $this->read_course_items( $course_id );
482 - }
483 -
484 - return false;
485 - }*/
486 -
487 - /**
488 - * Get sections of course
489 - *
490 - * @param int $course_id
491 - * @param string $return
492 - *
493 - * @return array
494 - * @version 4.0.0
495 - *
496 - */
497 - /*public function get_course_sections( $course_id, $return = '' ) {
498 - // if ( false === ( $sections = LP_Object_Cache::get( $course_id, 'learn-press/course-sections' ) ) ) {
499 - $sections = $this->read_course_sections( $course_id );
500 - // }
501 -
502 - // return $return === 'ids' ? LP_Object_Cache::get( $course_id, 'learn-press/course-sections-ids' ) : $sections;
503 - return $return === 'ids' ? LP_Course_Utils::get_cached_db_sections( $course_id, 'ids' ) : $sections;
504 - }*/
505 -
506 - /**
507 - * Retrieve total sections of a course.
508 - *
509 - * @param int $course_id
510 - *
511 - * @return int
512 - * @since 3.1.0
513 - */
514 - public function count_sections( $course_id ) {
515 - global $wpdb;
516 -
517 - $query = $wpdb->prepare(
518 - "
519 - SELECT COUNT(section_id)
520 - FROM {$wpdb->learnpress_sections}
521 - WHERE section_course_id = %d
522 - ",
523 - $course_id
524 - );
525 -
526 - return $wpdb->get_var( $query );
527 - }
528 -
529 - /**
530 - * Retrieve total items of a course.
531 - *
532 - * @param int $course_id
533 - *
534 - * @return array
535 - * @since 3.1.0
536 - * @editor tungnx
537 - * @modify 4.1.4.1 - comment - not use
538 - */
539 - /*public function count_items( $course_id, $context = 'view' ) {
540 - global $wpdb;
541 - $params = array( $course_id );
542 - $sql = "
543 - SELECT COUNT(it.ID) `count`, it.post_type
544 - FROM {$wpdb->learnpress_section_items} si
545 - INNER JOIN {$wpdb->learnpress_sections} s ON si.section_id = s.section_id
546 - INNER JOIN {$wpdb->posts} c ON c.ID = s.section_course_id
547 - INNER JOIN {$wpdb->posts} it ON it.ID = si.item_id
548 - WHERE s.section_course_id = %d";
549 - if ( $context == 'view' ) {
550 - $sql .= ' AND c.post_status = %s
551 - AND it.post_status = %s ';
552 - $params = array_merge( $params, array( 'publish', 'publish' ) );
553 - }
554 - $sql .= ' GROUP BY it.post_type ';
555 - $query = $wpdb->prepare( $sql, $params );
556 -
557 - $stats_object = array();
558 - if ( $results = $wpdb->get_results( $query ) ) {
559 - foreach ( $results as $result ) {
560 - $stats_object[ $result->post_type ] = $result->count;
561 - }
562 - }
563 -
564 - return $stats_object;
565 - }*/
566 -
567 - /**
568 - * Read sections of a bundle of courses by ids
569 - *
570 - * @param int|array $course_id
571 - *
572 - * @return mixed|array
573 - * @version 4.0.0
574 - * @depecated 4.1.6.9
575 - */
576 - /*public function read_course_sections( $course_id ) {
577 - global $wpdb;
578 -
579 - settype( $course_id, 'array' );
580 - $first_course_sections = false;
581 -
582 - foreach ( $course_id as $cid ) {
583 - $course_sections = LP_Course_Utils::get_cached_db_sections( $cid );
584 -
585 - if ( false === $course_sections ) {
586 - $query = $wpdb->prepare(
587 - "
588 - SELECT s.section_id, s.section_name, s.section_course_id, s.section_order, s.section_description, 'asd'
589 - FROM {$wpdb->posts} p
590 - INNER JOIN {$wpdb->learnpress_sections} s ON p.ID = s.section_course_id
591 - WHERE p.ID = %d
592 - ORDER BY p.ID, `section_order` ASC
593 - ",
594 - $cid
595 - );
596 -
597 - $course_sections = $wpdb->get_results( $query );
598 -
599 - if ( ! $course_sections ) {
600 - $course_sections = array();
601 - }
602 -
603 - if ( false === $first_course_sections ) {
604 - $first_course_sections = $course_sections;
605 - }
606 -
607 - LP_Course_Utils::set_cache_db_sections( $cid, $course_sections );
608 - }
609 - }
610 -
611 - return $first_course_sections;
612 - }*/
613 -
614 - /**
615 - * Remove lesson, quiz from course's curriculum.
616 - *
617 - * @param int $item_id
618 - * @param int $course_id - Optional. Added since 3.1.0
619 - *
620 - * @since 3.0.0
621 - */
622 - public function remove_item( $item_id, $course_id = 0 ) {
623 - $learnpress_user_item_db = LP_User_Items_DB::getInstance();
624 - global $wpdb;
625 - // allow hook
626 - do_action( 'learn-press/before-remove-section-item', $item_id, $course_id );
627 -
628 - if ( $course_id ) {
629 - if ( is_array( $course_id ) ) {
630 - $format = array_fill( 0, sizeof( $course_id ), '%d' );
631 - $where = $wpdb->prepare( 'AND s.section_course_id IN(' . join( ',', $format ) . ')', $course_id );
632 - } else {
633 - $where = $wpdb->prepare( 'AND s.section_course_id = %d', $course_id );
634 - }
635 - $query = $wpdb->prepare(
636 - "
637 - DELETE si
638 - FROM {$wpdb->learnpress_section_items} si
639 - INNER JOIN {$wpdb->learnpress_sections} s ON s.section_id = si.section_id
640 - WHERE item_id = %d
641 - {$where}
642 - ",
643 - $item_id
644 - );
645 - } else {
646 -
647 - $query = $wpdb->prepare(
648 - "
649 - SELECT s.section_course_id
650 - FROM {$wpdb->learnpress_sections} s
651 - INNER JOIN {$wpdb->learnpress_section_items} si ON s.section_id = si.section_id
652 - WHERE si.item_id = %d
653 - ",
654 - $item_id
655 - );
656 -
657 - $course_id = $wpdb->get_col( $query );
658 - $query = $wpdb->prepare( "DELETE FROM {$wpdb->learnpress_section_items} WHERE item_id = %d", $item_id );
659 - }
660 -
661 - // delete item from course's section
662 - $wpdb->query( $query );
663 -
664 - if ( $course_id ) {
665 - settype( $course_id, 'array' );
666 -
667 - foreach ( $course_id as $cid ) {
668 - do_action( 'learn-press/removed-item-from-section', $item_id, $cid );
669 - $learnpress_user_item_db->reset_course_current_item( $cid, $item_id );
670 - } // end foreach $course_id as $cid
671 - }
672 -
673 - learn_press_reset_auto_increment( 'learnpress_section_items' );
674 - }
675 -
676 - /**
677 - * Remove all course data from database, includes section and course's items
678 - *
679 - * @param $course_id
680 - * @editor tungnx
681 - * @modify 4.1.4.1 - comment - not use
682 - */
683 - /*public function remove_course( $course_id ) {
684 - global $wpdb;
685 -
686 - $section_ids = $wpdb->get_col(
687 - $wpdb->prepare(
688 - "SELECT section_id FROM {$wpdb->prefix}learnpress_sections WHERE section_course_id = %d",
689 - $course_id
690 - )
691 - );
692 - if ( $section_ids ) {
693 - $wpdb->query(
694 - $wpdb->prepare(
695 - "DELETE FROM {$wpdb->prefix}learnpress_section_items WHERE %d AND section_id IN(" . join(
696 - ',',
697 - $section_ids
698 - ) . ')',
699 - 1
700 - )
701 - );
702 - learn_press_reset_auto_increment( 'learnpress_section_items' );
703 - }
704 -
705 - // delete all sections
706 - $query = $wpdb->prepare(
707 - "
708 - DELETE FROM {$wpdb->prefix}learnpress_sections
709 - WHERE section_course_id = %d",
710 - $course_id
711 - );
712 - $wpdb->query( $query );
713 - learn_press_reset_auto_increment( 'learnpress_sections' );
714 - }*/
715 -
716 - /**
717 - * Get recent courses.
718 - *
719 - * @param array $args
720 - *
721 - * @return array
722 - */
723 - public function get_recent_courses( $args = array() ) {
724 - global $wpdb;
725 -
726 - $limit = ! empty( $args['limit'] ) ? $args['limit'] : - 1;
727 - $order = ! empty( $args['order'] ) ? $args['order'] : 'DESC';
728 -
729 - if ( $limit <= 0 ) {
730 - $limit = 0;
731 - }
732 -
733 - $query = apply_filters(
734 - 'learn-press/course-curd/query-recent-courses',
735 - $wpdb->prepare(
736 - "
737 - SELECT DISTINCT p.ID
738 - FROM $wpdb->posts AS p
739 - WHERE p.post_type = %s
740 - AND p.post_status = %s
741 - ORDER BY p.post_date {$order}
742 - LIMIT %d
743 - ",
744 - LP_COURSE_CPT,
745 - 'publish',
746 - $limit
747 - )
748 - );
749 -
750 - return $wpdb->get_col( $query );
751 - }
752 -
753 - /**
754 - * Get all ID of users enrolled course ID.
755 - *
756 - * @param int $course_id
757 - * @param int $limit
758 - *
759 - * @return array
760 - * @Todo tungnx from LP 4.1.3.1 use LP_Course_DB::get_user_ids_enrolled replace
761 - */
762 - public function get_user_enrolled( $course_id, $limit = - 1 ) {
763 - global $wpdb;
764 - if ( $limit < 0 ) {
765 - $limit = PHP_INT_MAX;
766 - }
767 - $query = $wpdb->prepare(
768 - "
769 - SELECT DISTINCT user.ID FROM {$wpdb->users} user
770 - INNER JOIN {$wpdb->learnpress_user_items} user_item ON user_item.user_id = user.ID
771 - WHERE user_item.item_id = %d
772 - AND user_item.item_type = %s
773 - LIMIT %d
774 - ",
775 - $course_id,
776 - LP_COURSE_CPT,
777 - $limit
778 - );
779 -
780 - return $wpdb->get_results( $query );
781 - }
782 -
783 - public function count_enrolled_users( $course_ids ) {
784 - global $wpdb;
785 -
786 - if ( ! $course_ids ) {
787 - return 0;
788 - }
789 -
790 - $results = LP_Object_Cache::get( 'enrolled-users', 'learn-press/course' );
791 -
792 - if ( $results && is_numeric( $course_ids ) && array_key_exists( $course_ids, $results ) ) {
793 - return $results[ $course_ids ];
794 - }
795 - settype( $course_ids, 'array' );
796 - $sql = $wpdb->prepare(
797 - "
798 - SELECT item_id cid, count(ID) `count`
799 - FROM(SELECT DISTINCT user.ID,user_item.item_id FROM {$wpdb->users} user
800 - INNER JOIN {$wpdb->learnpress_user_items} user_item ON user_item.user_id = user.ID
801 - WHERE user_item.item_id IN(" . join( ',', $course_ids ) . ')
802 - AND user_item.item_type = %s
803 - ) AS X GROUP BY item_id',
804 - LP_COURSE_CPT
805 - );
806 -
807 - $rows = $wpdb->get_results( $sql );
808 - if ( $rows ) {
809 - foreach ( $rows as $row ) {
810 - $results[ $row->cid ] = $row->count;
811 - }
812 - }
813 -
814 - $total = 0;
815 - foreach ( $course_ids as $course_id ) {
816 - if ( empty( $results[ $course_id ] ) ) {
817 - $results[ $course_id ] = 0;
818 - }
819 - $total += $results[ $course_id ];
820 - }
821 - LP_Object_Cache::set( 'enrolled-users', $results, 'learn-press/course' );
822 -
823 - return $total;
824 - }
825 -
826 - /**
827 - * Get feature courses.
828 - *
829 - * @param array $args
830 - *
831 - * @return array
832 - */
833 - public function get_featured_courses( $args = array() ) {
834 - global $wpdb;
835 -
836 - $limit = ! empty( $args['limit'] ) ? $args['limit'] : - 1;
837 - $order_by = ! empty( $args['order_by'] ) ? $args['order_by'] : 'post_date';
838 - $order = ! empty( $args['order'] ) ? $args['order'] : 'DESC';
839 -
840 - if ( $limit <= 0 ) {
841 - $limit = 0;
842 - }
843 -
844 - $query = apply_filters(
845 - 'learn-press/course-curd/query-featured-courses',
846 - $wpdb->prepare(
847 - "
848 - SELECT DISTINCT p.ID
849 - FROM {$wpdb->posts} p
850 - LEFT JOIN {$wpdb->postmeta} as pmeta ON p.ID=pmeta.post_id AND pmeta.meta_key = %s
851 - WHERE p.post_type = %s
852 - AND p.post_status = %s
853 - AND pmeta.meta_value = %s
854 - ORDER BY p.{$order_by} {$order}
855 - LIMIT %d
856 - ",
857 - '_lp_featured',
858 - LP_COURSE_CPT,
859 - 'publish',
860 - 'yes',
861 - $limit
862 - )
863 - );
864 -
865 - return $wpdb->get_col( $query );
866 - }
867 - }
868 -}
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 +}