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