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.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 -921 4.1.6.9 → 4.4.9 View file →
@@ -1,921 +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 $course_id
125 - * @param array $args
126 - *
127 - * @return mixed|WP_Error
128 - * @since 3.0.0
129 - */
130 - public function duplicate_bk( &$course_id, $args = array() ) {
131 -
132 - if ( ! $course_id ) {
133 - return new WP_Error( __( '<p>Op! ID not found</p>', 'learnpress' ) );
134 - }
135 -
136 - if ( learn_press_get_post_type( $course_id ) != LP_COURSE_CPT ) {
137 - return new WP_Error( __( '<p>Op! The course does not exist</p>', 'learnpress' ) );
138 - }
139 -
140 - // ensure that user can create course
141 - if ( ! current_user_can( 'edit_posts' ) ) {
142 - return new WP_Error(
143 - __(
144 - '<p>Sorry! You don\'t have permission to duplicate this course</p>',
145 - 'learnpress'
146 - )
147 - );
148 - }
149 - // duplicate course
150 - $new_course_id = learn_press_duplicate_post( $course_id, $args );
151 -
152 - if ( ! $new_course_id || is_wp_error( $new_course_id ) ) {
153 - return new WP_Error( __( '<p>Sorry! Failed to duplicate course!</p>', 'learnpress' ) );
154 - } else {
155 -
156 - // original course section curd
157 - $course = LP_Course::get_course( $course_id );
158 -
159 - // new course section curd
160 - $new_course_section_curd = new LP_Section_CURD( $new_course_id );
161 -
162 - // curriculum course
163 - // $course->load_curriculum();
164 - $curriculum = $course->get_curriculum_raw();
165 -
166 - // quiz curd
167 - $quiz_curd = new LP_Quiz_CURD();
168 -
169 - if ( is_array( $curriculum ) ) {
170 -
171 - foreach ( $curriculum as $section ) {
172 -
173 - $data = array(
174 - 'section_name' => $section['title'],
175 - 'section_course_id' => $new_course_id,
176 - 'section_order' => $section['order'],
177 - 'section_description' => $section['description'],
178 - );
179 -
180 - // clone sections to new course
181 - $new_section = $new_course_section_curd->create( $data );
182 -
183 - // get section items of original course
184 - $items = $section['items'];
185 -
186 - $new_items = array();
187 -
188 - // duplicate items
189 - if ( is_array( $items ) ) {
190 - foreach ( $items as $key => $item ) {
191 - // duplicate quiz
192 - if ( $item['type'] == LP_QUIZ_CPT ) {
193 - $new_item_id = $quiz_curd->duplicate(
194 - $item['id'],
195 - array( 'post_status' => 'publish' )
196 - );
197 - } else {
198 - // clone lesson
199 - $new_item_id = learn_press_duplicate_post(
200 - $item['id'],
201 - array( 'post_status' => 'publish' )
202 - );
203 - }
204 -
205 - // get new items data to add to section
206 - $new_items[ $key ] = array(
207 - 'id' => $new_item_id,
208 - 'type' => $item['type'],
209 - );
210 - }
211 -
212 - // add new clone items to section
213 - $new_course_section_curd->add_items_section( $new_section['section_id'], $new_items );
214 - }
215 - }
216 -
217 - do_action( 'learn-press/after-duplicate', $course_id, $new_course_id, $args );
218 -
219 - return $new_course_id;
220 - }
221 - }
222 -
223 - return false;
224 - }
225 -
226 - /**
227 - * Duplicate course.
228 - *
229 - * @param int $course_id
230 - * @param array $args
231 - *
232 - * @return int|WP_Error
233 - * @since 3.0.0
234 - * @version 1.0.2
235 - */
236 - public function duplicate( &$course_id, $args = array() ) {
237 - $course_id_new = 0;
238 -
239 - try {
240 - if ( ! current_user_can( 'edit_posts' ) ) {
241 - throw new Exception( 'Sorry! You don\'t have permission to duplicate this course' );
242 - }
243 -
244 - $course_origin = learn_press_get_course( $course_id );
245 - if ( ! $course_origin ) {
246 - throw new Exception( 'Course is invalid' );
247 - }
248 -
249 - $course_id_new = learn_press_duplicate_post( $course_id, $args );
250 -
251 - if ( is_wp_error( $course_id_new ) ) {
252 - return $course_id_new;
253 - }
254 -
255 - $this->duplicate_sections_and_items( $course_id_new, $course_origin );
256 -
257 - // Call save course duplicate
258 - //$course_post = get_post( $course_id_new );
259 - LP_Course_Post_Type::instance()->save( $course_id_new );
260 -
261 - do_action( 'learn-press/after-duplicate', $course_id, $course_id_new, $args );
262 - } catch ( Throwable $e ) {
263 - $course_id_new = new WP_Error( $e->getMessage() );
264 - }
265 -
266 - return $course_id_new;
267 - }
268 -
269 - /**
270 - * Duplicate sections and items of course
271 - * @param int $course_id_new
272 - * @param LP_Course $course_origin
273 - */
274 - public function duplicate_sections_and_items( $course_id_new, $course_origin ) {
275 - // curriculum course
276 - $curriculum = $course_origin->get_curriculum_raw();
277 -
278 - // quiz curd
279 - $quiz_curd = new LP_Quiz_CURD();
280 -
281 - if ( is_array( $curriculum ) ) {
282 - // new course section curd
283 - $new_course_section_curd = new LP_Section_CURD( $course_id_new );
284 - foreach ( $curriculum as $section ) {
285 - $data = array(
286 - 'section_name' => $section['title'],
287 - 'section_course_id' => $course_id_new,
288 - 'section_order' => $section['order'],
289 - 'section_description' => $section['description'],
290 - );
291 -
292 - // clone sections to new course
293 - $new_section = $new_course_section_curd->create( $data );
294 -
295 - // get section items of original course
296 - $items = $section['items'];
297 -
298 - $new_items = array();
299 -
300 - // duplicate items
301 - if ( ! empty( $items ) ) {
302 - foreach ( $items as $key => $item ) {
303 - // duplicate quiz
304 - if ( $item['type'] == LP_QUIZ_CPT ) {
305 - $new_item_id = $quiz_curd->duplicate(
306 - $item['id'],
307 - array( 'post_status' => 'publish' )
308 - );
309 - } else {
310 - // clone lesson
311 - $new_item_id = learn_press_duplicate_post(
312 - $item['id'],
313 - array( 'post_status' => 'publish' )
314 - );
315 - }
316 -
317 - // get new items data to add to section
318 - $new_items[ $key ] = array(
319 - 'id' => $new_item_id,
320 - 'type' => $item['type'],
321 - );
322 - }
323 -
324 - // add new clone items to section
325 - $new_course_section_curd->add_items_section( $new_section['section_id'], $new_items );
326 - }
327 - }
328 - }
329 - }
330 -
331 - /**
332 - * Load course data
333 - *
334 - * @param LP_Course|LP_Abstract_Course $course
335 - *
336 - * @return mixed
337 - */
338 - public function load( &$course ) {
339 - // $this->read_course_curriculum( $course->get_id() );
340 -
341 - return $course;
342 - }
343 -
344 - /**
345 - * Read all items in a course from database with an array in pair of
346 - * post ID and post type.
347 - *
348 - * @param int $course_id
349 - * @param bool $publish_only
350 - *
351 - * @return array
352 - * @depecated 4.1.6.9
353 - */
354 - /*public function read_course_items( $course_id, $publish_only = true, $section_ids = array() ) {
355 - global $wpdb;
356 - $where = '';
357 -
358 - if ( $publish_only ) {
359 - $where = $wpdb->prepare(
360 - '
361 - AND c.post_status = %s
362 - AND it.post_status = %s
363 - ',
364 - 'publish',
365 - 'publish'
366 - );
367 - }
368 -
369 - $types = learn_press_course_get_support_item_types( true );
370 - $where .= $wpdb->prepare(
371 - ' AND si.item_type IN(' . LP_Helper::db_format_array( $types, '%s' ) . ')',
372 - $types
373 - );
374 -
375 - if ( $section_ids ) {
376 - $where .= $wpdb->prepare(
377 - ' AND s.section_id IN(' . LP_Helper::db_format_array(
378 - $section_ids,
379 - '%d'
380 - ) . ')',
381 - $section_ids
382 - );
383 - }
384 -
385 - $query = $wpdb->prepare(
386 - "
387 - SELECT item_id id, it.post_type `type`, si.section_id
388 - FROM {$wpdb->learnpress_section_items} si
389 - INNER JOIN {$wpdb->learnpress_sections} s ON si.section_id = s.section_id
390 - INNER JOIN {$wpdb->posts} c ON c.ID = s.section_course_id
391 - INNER JOIN {$wpdb->posts} it ON it.ID = si.item_id
392 - WHERE c.ID = %d
393 - {$where}
394 - ORDER BY s.section_order, si.item_order, si.section_item_id ASC
395 - ",
396 - $course_id
397 - );
398 -
399 - $results = $wpdb->get_results( $query );
400 -
401 - return $results;
402 -
403 - //////////////////////////////////////////// Code new - tungnx
404 -
405 - $items = [];
406 -
407 - $course = learn_press_get_course( $course_id );
408 - if ( ! $course ) {
409 - return $items;
410 - }
411 -
412 - $sections_items = $course->get_full_sections_and_items_course();
413 - foreach ( $sections_items as $section_items ) {
414 - $section_id = $section_items->id;
415 -
416 - foreach ( $section_items->items as $item ) {
417 - $item->section_id = $section_id;
418 - $items[] = $item;
419 - }
420 - }
421 -
422 - return $items;
423 - }*/
424 -
425 - /**
426 - * Get all courses that contains an item by item id.
427 - * Data returned is an array of all courses found.
428 - *
429 - * @param int $item_id - ID of any item
430 - * @param bool $check_support - Optional. TRUE will check if course is support that item
431 - *
432 - * @return array|bool
433 - * @since 3.1.0
434 - */
435 - public function get_course_by_item( $item_id, $check_support = true ) {
436 - if ( $check_support && ! learn_press_is_support_course_item_type( get_post_type( $item_id ) ) ) {
437 - return false;
438 - }
439 -
440 - global $wpdb;
441 -
442 - $query = $wpdb->prepare(
443 - "
444 - SELECT c.ID
445 - FROM {$wpdb->posts} c
446 - INNER JOIN {$wpdb->learnpress_sections} s ON c.ID = s.section_course_id
447 - INNER JOIN {$wpdb->learnpress_section_items} si ON si.section_id = s.section_id
448 - WHERE si.item_id = %d
449 - ",
450 - $item_id
451 - );
452 -
453 - return $wpdb->get_col( $query );
454 - }
455 -
456 - /**
457 - * @depecated 4.1.6.9
458 - */
459 - /*public static function update_items_format( $item ) {
460 -
461 - if ( empty( $item['args']['course_id'] ) ) {
462 - return false;
463 - }
464 -
465 - $course_id = absint( $item['args']['course_id'] );
466 -
467 - delete_option( 'update_items_format_' . $course_id );
468 -
469 - global $wpdb;
470 -
471 - $course = learn_press_get_course( $course_id );
472 -
473 - if ( ! $course ) {
474 - return false;
475 - }
476 -
477 - $item_ids = $course->get_items();
478 -
479 - if ( ! $item_ids ) {
480 - return false;
481 - }
482 -
483 - $query = $wpdb->prepare(
484 - "
485 - SELECT object_id AS id, REPLACE(slug, 'post-format-', '') AS format
486 - FROM {$wpdb->terms} AS t
487 - INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id
488 - INNER JOIN {$wpdb->term_relationships} AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id
489 - WHERE tt.taxonomy IN (%s)
490 - AND tr.object_id IN (" . join( ',', $item_ids ) . ')
491 - ORDER BY t.name ASC
492 - ',
493 - 'post_format'
494 - );
495 -
496 - $terms = $wpdb->get_results( $query );
497 -
498 - if ( $terms ) {
499 - $updated = array();
500 - foreach ( $terms as $term ) {
501 - update_post_meta( $term->id, 'post_format', $term->format );
502 - $updated[] = $term->id;
503 - }
504 - $item_ids = array_diff( $item_ids, $updated );
505 - }
506 -
507 - if ( $item_ids ) {
508 - foreach ( $item_ids as $item_id ) {
509 - update_post_meta( $item_id, 'post_format', 'standard' );
510 - }
511 - }
512 -
513 - return false;
514 - }*/
515 -
516 - /**
517 - * Read curriculum of a course from db into cache.
518 - *
519 - * @param $course_id
520 - *
521 - * @return array|mixed
522 - */
523 - /*public function read_course_curriculum( $course_id ) {
524 -
525 - if ( learn_press_get_post_type( $course_id ) != LP_COURSE_CPT ) {
526 - return false;
527 - }
528 -
529 - if ( false !== LP_Course_Utils::get_course_items( $course_id ) ) {
530 - return false;
531 - }
532 -
533 - if ( $this->get_course_sections( $course_id, 'ids' ) ) {
534 - return $this->read_course_items( $course_id );
535 - }
536 -
537 - return false;
538 - }*/
539 -
540 - /**
541 - * Get sections of course
542 - *
543 - * @param int $course_id
544 - * @param string $return
545 - *
546 - * @return array
547 - * @version 4.0.0
548 - *
549 - */
550 - /*public function get_course_sections( $course_id, $return = '' ) {
551 - // if ( false === ( $sections = LP_Object_Cache::get( $course_id, 'learn-press/course-sections' ) ) ) {
552 - $sections = $this->read_course_sections( $course_id );
553 - // }
554 -
555 - // return $return === 'ids' ? LP_Object_Cache::get( $course_id, 'learn-press/course-sections-ids' ) : $sections;
556 - return $return === 'ids' ? LP_Course_Utils::get_cached_db_sections( $course_id, 'ids' ) : $sections;
557 - }*/
558 -
559 - /**
560 - * Retrieve total sections of a course.
561 - *
562 - * @param int $course_id
563 - *
564 - * @return int
565 - * @since 3.1.0
566 - */
567 - public function count_sections( $course_id ) {
568 - global $wpdb;
569 -
570 - $query = $wpdb->prepare(
571 - "
572 - SELECT COUNT(section_id)
573 - FROM {$wpdb->learnpress_sections}
574 - WHERE section_course_id = %d
575 - ",
576 - $course_id
577 - );
578 -
579 - return $wpdb->get_var( $query );
580 - }
581 -
582 - /**
583 - * Retrieve total items of a course.
584 - *
585 - * @param int $course_id
586 - *
587 - * @return array
588 - * @since 3.1.0
589 - * @editor tungnx
590 - * @modify 4.1.4.1 - comment - not use
591 - */
592 - /*public function count_items( $course_id, $context = 'view' ) {
593 - global $wpdb;
594 - $params = array( $course_id );
595 - $sql = "
596 - SELECT COUNT(it.ID) `count`, it.post_type
597 - FROM {$wpdb->learnpress_section_items} si
598 - INNER JOIN {$wpdb->learnpress_sections} s ON si.section_id = s.section_id
599 - INNER JOIN {$wpdb->posts} c ON c.ID = s.section_course_id
600 - INNER JOIN {$wpdb->posts} it ON it.ID = si.item_id
601 - WHERE s.section_course_id = %d";
602 - if ( $context == 'view' ) {
603 - $sql .= ' AND c.post_status = %s
604 - AND it.post_status = %s ';
605 - $params = array_merge( $params, array( 'publish', 'publish' ) );
606 - }
607 - $sql .= ' GROUP BY it.post_type ';
608 - $query = $wpdb->prepare( $sql, $params );
609 -
610 - $stats_object = array();
611 - if ( $results = $wpdb->get_results( $query ) ) {
612 - foreach ( $results as $result ) {
613 - $stats_object[ $result->post_type ] = $result->count;
614 - }
615 - }
616 -
617 - return $stats_object;
618 - }*/
619 -
620 - /**
621 - * Read sections of a bundle of courses by ids
622 - *
623 - * @param int|array $course_id
624 - *
625 - * @return mixed|array
626 - * @version 4.0.0
627 - * @depecated 4.1.6.9
628 - */
629 - /*public function read_course_sections( $course_id ) {
630 - global $wpdb;
631 -
632 - settype( $course_id, 'array' );
633 - $first_course_sections = false;
634 -
635 - foreach ( $course_id as $cid ) {
636 - $course_sections = LP_Course_Utils::get_cached_db_sections( $cid );
637 -
638 - if ( false === $course_sections ) {
639 - $query = $wpdb->prepare(
640 - "
641 - SELECT s.section_id, s.section_name, s.section_course_id, s.section_order, s.section_description, 'asd'
642 - FROM {$wpdb->posts} p
643 - INNER JOIN {$wpdb->learnpress_sections} s ON p.ID = s.section_course_id
644 - WHERE p.ID = %d
645 - ORDER BY p.ID, `section_order` ASC
646 - ",
647 - $cid
648 - );
649 -
650 - $course_sections = $wpdb->get_results( $query );
651 -
652 - if ( ! $course_sections ) {
653 - $course_sections = array();
654 - }
655 -
656 - if ( false === $first_course_sections ) {
657 - $first_course_sections = $course_sections;
658 - }
659 -
660 - LP_Course_Utils::set_cache_db_sections( $cid, $course_sections );
661 - }
662 - }
663 -
664 - return $first_course_sections;
665 - }*/
666 -
667 - /**
668 - * Remove lesson, quiz from course's curriculum.
669 - *
670 - * @param int $item_id
671 - * @param int $course_id - Optional. Added since 3.1.0
672 - *
673 - * @since 3.0.0
674 - */
675 - public function remove_item( $item_id, $course_id = 0 ) {
676 - $learnpress_user_item_db = LP_User_Items_DB::getInstance();
677 - global $wpdb;
678 - // allow hook
679 - do_action( 'learn-press/before-remove-section-item', $item_id, $course_id );
680 -
681 - if ( $course_id ) {
682 - if ( is_array( $course_id ) ) {
683 - $format = array_fill( 0, sizeof( $course_id ), '%d' );
684 - $where = $wpdb->prepare( 'AND s.section_course_id IN(' . join( ',', $format ) . ')', $course_id );
685 - } else {
686 - $where = $wpdb->prepare( 'AND s.section_course_id = %d', $course_id );
687 - }
688 - $query = $wpdb->prepare(
689 - "
690 - DELETE si
691 - FROM {$wpdb->learnpress_section_items} si
692 - INNER JOIN {$wpdb->learnpress_sections} s ON s.section_id = si.section_id
693 - WHERE item_id = %d
694 - {$where}
695 - ",
696 - $item_id
697 - );
698 - } else {
699 -
700 - $query = $wpdb->prepare(
701 - "
702 - SELECT s.section_course_id
703 - FROM {$wpdb->learnpress_sections} s
704 - INNER JOIN {$wpdb->learnpress_section_items} si ON s.section_id = si.section_id
705 - WHERE si.item_id = %d
706 - ",
707 - $item_id
708 - );
709 -
710 - $course_id = $wpdb->get_col( $query );
711 - $query = $wpdb->prepare( "DELETE FROM {$wpdb->learnpress_section_items} WHERE item_id = %d", $item_id );
712 - }
713 -
714 - // delete item from course's section
715 - $wpdb->query( $query );
716 -
717 - if ( $course_id ) {
718 - settype( $course_id, 'array' );
719 -
720 - foreach ( $course_id as $cid ) {
721 - do_action( 'learn-press/removed-item-from-section', $item_id, $cid );
722 - $learnpress_user_item_db->reset_course_current_item( $cid, $item_id );
723 - } // end foreach $course_id as $cid
724 - }
725 -
726 - learn_press_reset_auto_increment( 'learnpress_section_items' );
727 - }
728 -
729 - /**
730 - * Remove all course data from database, includes section and course's items
731 - *
732 - * @param $course_id
733 - * @editor tungnx
734 - * @modify 4.1.4.1 - comment - not use
735 - */
736 - /*public function remove_course( $course_id ) {
737 - global $wpdb;
738 -
739 - $section_ids = $wpdb->get_col(
740 - $wpdb->prepare(
741 - "SELECT section_id FROM {$wpdb->prefix}learnpress_sections WHERE section_course_id = %d",
742 - $course_id
743 - )
744 - );
745 - if ( $section_ids ) {
746 - $wpdb->query(
747 - $wpdb->prepare(
748 - "DELETE FROM {$wpdb->prefix}learnpress_section_items WHERE %d AND section_id IN(" . join(
749 - ',',
750 - $section_ids
751 - ) . ')',
752 - 1
753 - )
754 - );
755 - learn_press_reset_auto_increment( 'learnpress_section_items' );
756 - }
757 -
758 - // delete all sections
759 - $query = $wpdb->prepare(
760 - "
761 - DELETE FROM {$wpdb->prefix}learnpress_sections
762 - WHERE section_course_id = %d",
763 - $course_id
764 - );
765 - $wpdb->query( $query );
766 - learn_press_reset_auto_increment( 'learnpress_sections' );
767 - }*/
768 -
769 - /**
770 - * Get recent courses.
771 - *
772 - * @param array $args
773 - *
774 - * @return array
775 - */
776 - public function get_recent_courses( $args = array() ) {
777 - global $wpdb;
778 -
779 - $limit = ! empty( $args['limit'] ) ? $args['limit'] : - 1;
780 - $order = ! empty( $args['order'] ) ? $args['order'] : 'DESC';
781 -
782 - if ( $limit <= 0 ) {
783 - $limit = 0;
784 - }
785 -
786 - $query = apply_filters(
787 - 'learn-press/course-curd/query-recent-courses',
788 - $wpdb->prepare(
789 - "
790 - SELECT DISTINCT p.ID
791 - FROM $wpdb->posts AS p
792 - WHERE p.post_type = %s
793 - AND p.post_status = %s
794 - ORDER BY p.post_date {$order}
795 - LIMIT %d
796 - ",
797 - LP_COURSE_CPT,
798 - 'publish',
799 - $limit
800 - )
801 - );
802 -
803 - return $wpdb->get_col( $query );
804 - }
805 -
806 - /**
807 - * Get all ID of users enrolled course ID.
808 - *
809 - * @param int $course_id
810 - * @param int $limit
811 - *
812 - * @return array
813 - * @Todo tungnx from LP 4.1.3.1 use LP_Course_DB::get_user_ids_enrolled replace
814 - */
815 - public function get_user_enrolled( $course_id, $limit = - 1 ) {
816 - global $wpdb;
817 - if ( $limit < 0 ) {
818 - $limit = PHP_INT_MAX;
819 - }
820 - $query = $wpdb->prepare(
821 - "
822 - SELECT DISTINCT user.ID FROM {$wpdb->users} user
823 - INNER JOIN {$wpdb->learnpress_user_items} user_item ON user_item.user_id = user.ID
824 - WHERE user_item.item_id = %d
825 - AND user_item.item_type = %s
826 - LIMIT %d
827 - ",
828 - $course_id,
829 - LP_COURSE_CPT,
830 - $limit
831 - );
832 -
833 - return $wpdb->get_results( $query );
834 - }
835 -
836 - public function count_enrolled_users( $course_ids ) {
837 - global $wpdb;
838 -
839 - if ( ! $course_ids ) {
840 - return 0;
841 - }
842 -
843 - $results = LP_Object_Cache::get( 'enrolled-users', 'learn-press/course' );
844 -
845 - if ( $results && is_numeric( $course_ids ) && array_key_exists( $course_ids, $results ) ) {
846 - return $results[ $course_ids ];
847 - }
848 - settype( $course_ids, 'array' );
849 - $sql = $wpdb->prepare(
850 - "
851 - SELECT item_id cid, count(ID) `count`
852 - FROM(SELECT DISTINCT user.ID,user_item.item_id FROM {$wpdb->users} user
853 - INNER JOIN {$wpdb->learnpress_user_items} user_item ON user_item.user_id = user.ID
854 - WHERE user_item.item_id IN(" . join( ',', $course_ids ) . ')
855 - AND user_item.item_type = %s
856 - ) AS X GROUP BY item_id',
857 - LP_COURSE_CPT
858 - );
859 -
860 - $rows = $wpdb->get_results( $sql );
861 - if ( $rows ) {
862 - foreach ( $rows as $row ) {
863 - $results[ $row->cid ] = $row->count;
864 - }
865 - }
866 -
867 - $total = 0;
868 - foreach ( $course_ids as $course_id ) {
869 - if ( empty( $results[ $course_id ] ) ) {
870 - $results[ $course_id ] = 0;
871 - }
872 - $total += $results[ $course_id ];
873 - }
874 - LP_Object_Cache::set( 'enrolled-users', $results, 'learn-press/course' );
875 -
876 - return $total;
877 - }
878 -
879 - /**
880 - * Get feature courses.
881 - *
882 - * @param array $args
883 - *
884 - * @return array
885 - */
886 - public function get_featured_courses( $args = array() ) {
887 - global $wpdb;
888 -
889 - $limit = ! empty( $args['limit'] ) ? $args['limit'] : - 1;
890 - $order_by = ! empty( $args['order_by'] ) ? $args['order_by'] : 'post_date';
891 - $order = ! empty( $args['order'] ) ? $args['order'] : 'DESC';
892 -
893 - if ( $limit <= 0 ) {
894 - $limit = 0;
895 - }
896 -
897 - $query = apply_filters(
898 - 'learn-press/course-curd/query-featured-courses',
899 - $wpdb->prepare(
900 - "
901 - SELECT DISTINCT p.ID
902 - FROM {$wpdb->posts} p
903 - LEFT JOIN {$wpdb->postmeta} as pmeta ON p.ID=pmeta.post_id AND pmeta.meta_key = %s
904 - WHERE p.post_type = %s
905 - AND p.post_status = %s
906 - AND pmeta.meta_value = %s
907 - ORDER BY p.{$order_by} {$order}
908 - LIMIT %d
909 - ",
910 - '_lp_featured',
911 - LP_COURSE_CPT,
912 - 'publish',
913 - 'yes',
914 - $limit
915 - )
916 - );
917 -
918 - return $wpdb->get_col( $query );
919 - }
920 - }
921 -}
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 +}