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

class-lp-course-db.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.1.7.3, at inc/databases/class-lp-course-db.php

650 lines 17.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class LP_Course_DB
4 *
5 * @author tungnx
6 * @since 3.2.7.5
7 */
8
9 defined( 'ABSPATH' ) || exit();
10
11 class LP_Course_DB extends LP_Database {
12 private static $_instance;
13
14 protected function __construct() {
15 parent::__construct();
16 }
17
18 public static function getInstance() {
19 if ( is_null( self::$_instance ) ) {
20 self::$_instance = new self();
21 }
22
23 return self::$_instance;
24 }
25
26 /**
27 * Get course_id of item
28 *
29 * item type lp_lesson, lp_quiz
30 *
31 * @param int $item_id
32 *
33 * @return int
34 * @throws Exception
35 */
36 public function get_course_by_item_id( $item_id = 0 ): int {
37 // Get cache
38 $lp_course_cache = LP_Course_Cache::instance();
39 $key_cache = "$item_id/course_id_of_item_id";
40 $course_id = $lp_course_cache->get_cache( $key_cache );
41
42 if ( ! $course_id ) {
43 $query = $this->wpdb->prepare(
44 "
45 SELECT section_course_id
46 FROM {$this->tb_lp_sections} AS s
47 INNER JOIN {$this->tb_lp_section_items} AS si
48 ON si.section_id = s.section_id
49 WHERE si.item_id = %d",
50 $item_id
51 );
52
53 $course_id = (int) $this->wpdb->get_var( $query );
54
55 $this->check_execute_has_error();
56
57 // Set cache
58 $lp_course_cache->set_cache( $key_cache, $course_id );
59 }
60
61 return $course_id;
62 }
63
64 /**
65 * Get all item ids' course
66 *
67 * @param int $course_id
68 *
69 * @return array|object|stdClass[]|null
70 * @throws Exception
71 * @since 4.1.6.9
72 * @version 1.0.0
73 */
74 public function get_full_sections_and_items_course( int $course_id = 0 ) {
75 $method_called_to = debug_backtrace()[1]['function'];
76
77 // Check accept call from function 'get_sections_and_items_course_from_db_and_sort'
78 if ( 'get_sections_and_items_course_from_db_and_sort' !== $method_called_to ) {
79 error_log( 'You can not call direct this function' );
80 return [];
81 }
82
83 $query = $this->wpdb->prepare(
84 "SELECT *
85 FROM {$this->tb_lp_section_items} AS si
86 INNER JOIN {$this->tb_lp_sections} AS s
87 ON si.section_id = s.section_id
88 WHERE section_course_id = %d
89 ORDER BY s.section_order",
90 $course_id
91 );
92
93 $sections_items = $this->wpdb->get_results( $query );
94
95 $this->check_execute_has_error();
96
97 return $sections_items;
98 }
99
100 /**
101 * Get all sections' course
102 *
103 * @param int $course_id
104 *
105 * @return array|object|stdClass[]|null
106 * @throws Exception
107 * @since 4.1.6.9
108 * @version 1.0.0
109 */
110 public function get_sections( int $course_id = 0 ) {
111 $method_called_to = debug_backtrace()[1]['function'];
112
113 // Check accept call from function 'get_sections_and_items_course_from_db_and_sort'
114 if ( 'get_sections_and_items_course_from_db_and_sort' !== $method_called_to ) {
115 error_log( 'You can not call direct this function' );
116 return [];
117 }
118
119 $query = $this->wpdb->prepare(
120 "SELECT * FROM {$this->tb_lp_sections}
121 WHERE section_course_id = %d
122 ORDER BY section_order",
123 $course_id
124 );
125
126 $sections_items = $this->wpdb->get_results( $query, OBJECT_K );
127
128 $this->check_execute_has_error();
129
130 return $sections_items;
131 }
132
133 /**
134 * Get user_item_id by order_id, course_id, user_id
135 *
136 * @param int $order_id
137 * @param int $course_id
138 * @param int $user_id
139 *
140 * @return int
141 */
142 public function get_user_item_id( $order_id = 0, $course_id = 0, $user_id = 0 ): int {
143 $query = $this->wpdb->prepare(
144 "
145 SELECT user_item_id
146 FROM {$this->tb_lp_user_items}
147 WHERE ref_type = %s
148 AND ref_id = %d
149 AND item_type = %s
150 AND item_id = %d
151 AND user_id = %d
152 ",
153 LP_ORDER_CPT,
154 $order_id,
155 LP_COURSE_CPT,
156 $course_id,
157 $user_id
158 );
159
160 return (int) $this->wpdb->get_var( $query );
161 }
162
163 /**
164 * Get first item id of course
165 *
166 * @param int $course_id .
167 *
168 * @return int
169 * @throws Exception
170 * @since 4.0.0
171 * @version 1.0.2
172 * @modify 4.1.3
173 * @author tungnx
174 */
175 public function get_first_item_id( int $course_id = 0 ): int {
176 // Get cache
177 $lp_course_cache = LP_Course_Cache::instance();
178 $key_cache = "$course_id/first_item_id";
179 $first_item_id = $lp_course_cache->get_cache( $key_cache );
180
181 if ( ! $first_item_id ) {
182 $query = $this->wpdb->prepare(
183 "
184 SELECT item_id FROM $this->tb_lp_section_items AS items
185 INNER JOIN $this->tb_lp_sections AS sections
186 ON items.section_id = sections.section_id
187 AND sections.section_course_id = %d
188 ORDER BY items.item_order ASC, sections.section_order ASC
189 LIMIT %d
190 ",
191 $course_id,
192 1
193 );
194
195 $first_item_id = (int) $this->wpdb->get_var( $query );
196
197 $this->check_execute_has_error();
198
199 // Set cache
200 $lp_course_cache->set_cache( $key_cache, $first_item_id );
201 }
202
203 return $first_item_id;
204 }
205
206 public function get_recent_courses( LP_Course_Filter $filter ) : array {
207 global $wpdb;
208
209 $limit = $filter->limit ?? - 1;
210 $order = ! empty( $filter->order ) ? $filter->order : 'DESC';
211
212 if ( $limit <= 0 ) {
213 $limit = 0;
214 }
215
216 $query = apply_filters(
217 'learnpress/databases/widgets/recent_courses',
218 $wpdb->prepare(
219 "SELECT DISTINCT p.ID
220 FROM $wpdb->posts AS p
221 WHERE p.post_type = %s
222 AND p.post_status = %s
223 ORDER BY p.post_date {$order}
224 LIMIT %d",
225 LP_COURSE_CPT,
226 'publish',
227 $limit
228 )
229 );
230
231 return $wpdb->get_col( $query );
232 }
233
234 public function get_featured_courses( LP_Course_Filter $filter ) : array {
235 global $wpdb;
236
237 $limit = ! empty( $filter->limit ) ? $filter->limit : -1;
238 $order_by = ! empty( $filter->order_by ) ? $filter->order_by : 'post_date';
239 $order = ! empty( $filter->order ) ? $filter->order : 'DESC';
240
241 if ( $limit <= 0 ) {
242 $limit = 0;
243 }
244
245 $query = apply_filters(
246 'learnpress/databases/widgets/featured_courses',
247 $wpdb->prepare(
248 "SELECT DISTINCT p.ID
249 FROM {$wpdb->posts} p
250 LEFT JOIN {$wpdb->postmeta} as pmeta ON p.ID=pmeta.post_id AND pmeta.meta_key = %s
251 WHERE p.post_type = %s
252 AND p.post_status = %s
253 AND pmeta.meta_value = %s
254 ORDER BY p.{$order_by} {$order}
255 LIMIT %d",
256 '_lp_featured',
257 LP_COURSE_CPT,
258 'publish',
259 'yes',
260 $limit
261 )
262 );
263
264 return $wpdb->get_col( $query );
265 }
266
267 /**
268 * Get list user ids enrolled by course
269 *
270 * @return array|object|null
271 * @throws Exception
272 * @version 1.0.0
273 * @author tungnx
274 * @since 4.1.3.1
275 */
276 public function get_user_ids_enrolled( int $course_id ) {
277 $query = $this->wpdb->prepare(
278 "
279 SELECT DISTINCT user_id FROM {$this->tb_lp_user_items}
280 WHERE item_id = %d
281 AND item_type = %s
282 AND (status = %s OR status = %s )
283 ",
284 $course_id,
285 LP_COURSE_CPT,
286 'enrolled',
287 'finished'
288 );
289
290 $result = $this->wpdb->get_results( $query, OBJECT_K );
291
292 $this->check_execute_has_error();
293
294 return $result;
295 }
296
297 /**
298 * Count total user enrolled by course
299 *
300 * @param int $course_id
301 *
302 * @return int
303 * @version 1.0.0
304 * @author tungnx
305 * @since 4.1.4
306 */
307 public function get_total_user_enrolled( int $course_id ): int {
308 $query = $this->wpdb->prepare(
309 "
310 SELECT COUNT(DISTINCT user_id) AS total FROM {$this->tb_lp_user_items}
311 WHERE item_id = %d
312 AND item_type = %s
313 AND (status = %s OR status = %s )
314 ",
315 $course_id,
316 LP_COURSE_CPT,
317 LP_COURSE_ENROLLED,
318 LP_COURSE_FINISHED
319 );
320
321 return (int) $this->wpdb->get_var( $query );
322 }
323
324 /**
325 * Count total user enrolled or purchase by course
326 *
327 * @param int $course_id
328 *
329 * @return int
330 * @version 1.0.0
331 * @author tungnx
332 * @since 4.1.4
333 */
334 public function get_total_user_enrolled_or_purchased( int $course_id ): int {
335 $query = $this->wpdb->prepare(
336 "
337 SELECT COUNT(DISTINCT user_id) AS total FROM {$this->tb_lp_user_items}
338 WHERE item_id = %d
339 AND item_type = %s
340 AND (status = %s OR status = %s OR status = %s )
341 ",
342 $course_id,
343 LP_COURSE_CPT,
344 LP_COURSE_ENROLLED,
345 LP_COURSE_FINISHED,
346 LP_COURSE_PURCHASED
347 );
348
349 return (int) $this->wpdb->get_var( $query );
350 }
351
352 /**
353 * Get total items of course
354 *
355 * @param int $course_id
356 * @author tungnx
357 * @since 4.1.4.1
358 * @version 1.0.0
359 * @return null|object
360 */
361 public function get_total_items( int $course_id = 0 ) {
362 // Get cache
363 $lp_course_cache = LP_Course_Cache::instance();
364 $key_cache = "$course_id/total_items";
365 $total_items = $lp_course_cache->get_cache( $key_cache );
366
367 if ( ! $total_items ) {
368 $item_types = learn_press_get_course_item_types();
369 $count_item_types = count( $item_types );
370 $i = 0;
371
372 $query_count = $this->wpdb->prepare( 'SUM(s.section_course_id = %d) AS count_items,', $course_id );
373
374 foreach ( $item_types as $item_type ) {
375 $i++;
376 if ( $i == $count_item_types ) {
377 $query_count .= $this->wpdb->prepare( 'SUM(s.section_course_id = %d AND si.item_type = %s) AS %s', $course_id, $item_type, $item_type );
378 } else {
379 $query_count .= $this->wpdb->prepare( 'SUM(s.section_course_id = %d AND si.item_type = %s) AS %s,', $course_id, $item_type, $item_type );
380 }
381 }
382
383 $query = "
384 SELECT $query_count
385 FROM $this->tb_lp_section_items si
386 INNER JOIN $this->tb_lp_sections s ON s.section_id = si.section_id
387 ";
388
389 $total_items = $this->wpdb->get_row( $query );
390
391 // Set cache
392 $lp_course_cache->set_cache( $key_cache, $total_items );
393 }
394
395 return $total_items;
396 }
397
398 /**
399 * Count all item are unassigned to any courses.
400 *
401 * @param string $item_type (type item Lesson, Quiz, Assignment, H5P ...)
402 *
403 * @return int
404 * @throws Exception
405 * @author tungnx
406 * @version 1.0.1
407 * @since 4.1.4.1
408 */
409 public function get_total_item_unassigned( string $item_type ): int {
410 $filter = new LP_Post_Type_Filter();
411 $filter->post_type = $item_type;
412 $filter->query_count = true;
413 $filter->post_status = array();
414 $filter->field_count = 'p.ID';
415
416 return $this->get_item_ids_unassigned( $filter );
417 }
418
419 /**
420 * list id item are unassigned to any courses.
421 *
422 * @param LP_Post_Type_Filter $filter
423 *
424 * @return array|int|string|null
425 * @throws Exception
426 * @author tungnx
427 * @version 1.0.0
428 * @since 4.1.6
429 */
430 public function get_item_ids_unassigned( LP_Post_Type_Filter $filter = null ) {
431 if ( is_null( $filter ) ) {
432 $filter = new LP_Post_Type_Filter();
433 }
434
435 $filter_section_items = new LP_Section_Items_Filter();
436 $filter_section_items->return_string_query = true;
437 $filter_section_items->only_fields = array( 'si.item_id' );
438 $filter_section_items->where[] = $this->wpdb->prepare( 'AND si.item_type = %s', $filter->post_type );
439 $query_item_ids_assigned = LP_Section_Items_DB::getInstance()->get_section_items( $filter_section_items );
440
441 $filter->only_fields = array( 'p.ID' );
442 $filter->collection = $this->tb_posts;
443 $filter->collection_alias = 'p';
444 $filter->where[] = $this->wpdb->prepare( 'AND p.post_type = %s', $filter->post_type );
445 $filter->where[] = 'AND ID NOT IN(' . $query_item_ids_assigned . ')';
446 $filter->where[] = $this->wpdb->prepare( 'AND p.post_status not IN(%s, %s)', 'trash', 'auto-draft' );
447
448 return $this->execute( $filter );
449 }
450
451 /**
452 * Get Courses
453 *
454 * @param LP_Course_Filter $filter
455 * @param int $total_rows return total_rows
456 *
457 * @return array|null|int|string
458 * @throws Exception
459 * @author tungnx
460 * @version 1.0.1
461 * @since 4.1.5
462 */
463 public function get_courses( LP_Course_Filter $filter, int &$total_rows = 0 ) {
464 $default_fields = $this->get_cols_of_table( $this->tb_posts );
465 $filter->fields = array_merge( $default_fields, $filter->fields );
466
467 if ( empty( $filter->collection ) ) {
468 $filter->collection = $this->tb_posts;
469 }
470
471 if ( empty( $filter->collection_alias ) ) {
472 $filter->collection_alias = 'p';
473 }
474
475 // Where
476 $filter->where[] = $this->wpdb->prepare( 'AND p.post_type = %s', $filter->post_type );
477
478 // Status
479 $filter->post_status = (array) $filter->post_status;
480 if ( ! empty( $filter->post_status ) ) {
481 $post_status_format = LP_Helper::db_format_array( $filter->post_status, '%s' );
482 $filter->where[] = $this->wpdb->prepare( 'AND p.post_status IN (' . $post_status_format . ')', $filter->post_status );
483 }
484
485 // Term ids
486 if ( ! empty( $filter->term_ids ) ) {
487 $filter->join[] = "INNER JOIN $this->tb_term_relationships AS r_term ON p.ID = r_term.object_id";
488
489 $term_ids_format = LP_Helper::db_format_array( $filter->term_ids, '%d' );
490 $filter->where[] = $this->wpdb->prepare( 'AND r_term.term_taxonomy_id IN (' . $term_ids_format . ')', $filter->term_ids );
491 }
492
493 // course ids
494 if ( ! empty( $filter->post_ids ) ) {
495 $list_ids_format = LP_Helper::db_format_array( $filter->post_ids, '%d' );
496 $filter->where[] = $this->wpdb->prepare( 'AND p.ID IN (' . $list_ids_format . ')', $filter->post_ids );
497 }
498
499 // Title
500 if ( $filter->post_title ) {
501 $filter->where[] = $this->wpdb->prepare( 'AND p.post_title LIKE %s', '%' . $filter->post_title . '%' );
502 }
503
504 // Author
505 if ( $filter->post_author ) {
506 $filter->where[] = $this->wpdb->prepare( 'AND p.post_author = %d', $filter->post_author );
507 }
508 // Authors
509 if ( ! empty( $filter->post_authors ) ) {
510 $post_authors_format = LP_Helper::db_format_array( $filter->post_authors, '%d' );
511 $filter->where[] = $this->wpdb->prepare( 'AND p.post_author IN (' . $post_authors_format . ')', $filter->post_authors );
512 }
513
514 $filter = apply_filters( 'lp/course/query/filter', $filter );
515
516 return $this->execute( $filter, $total_rows );
517 }
518
519 /**
520 * Get list courses sort by price
521 *
522 * @param LP_Course_Filter $filter
523 *
524 * @return LP_Course_Filter
525 * @since 4.1.5
526 * @author tungnx
527 * @version 1.0.0
528 */
529 public function get_courses_order_by_price( LP_Course_Filter $filter ): LP_Course_Filter {
530 $filter->join[] = "INNER JOIN $this->tb_postmeta AS pm ON p.ID = pm.post_id";
531 $filter->where[] = $this->wpdb->prepare( 'AND pm.meta_key = %s', '_lp_price' );
532 $filter->order_by = 'CAST( pm.meta_value AS UNSIGNED )';
533
534 return $filter;
535 }
536
537 /**
538 * Get list courses is on sale
539 *
540 * @param LP_Course_Filter $filter
541 *
542 * @return LP_Course_Filter
543 * @since 4.1.5
544 * @author tungnx
545 * @version 1.0.0
546 */
547 public function get_courses_sort_by_sale( LP_Course_Filter $filter ): LP_Course_Filter {
548 $filter->join[] = "INNER JOIN $this->tb_postmeta AS pm ON p.ID = pm.post_id";
549 $filter->where[] = $this->wpdb->prepare( 'AND pm.meta_key = %s', '_lp_course_is_sale' );
550
551 return $filter;
552 }
553
554 /**
555 * Get list courses is on feature
556 *
557 * @param LP_Course_Filter $filter
558 *
559 * @return LP_Course_Filter
560 * @author tungnx
561 * @version 1.0.0
562 * @since 4.1.5
563 */
564 public function get_courses_sort_by_feature( LP_Course_Filter $filter ): LP_Course_Filter {
565 $filter->join[] = "INNER JOIN $this->tb_postmeta AS pm ON p.ID = pm.post_id";
566 $filter->where[] = $this->wpdb->prepare( 'AND pm.meta_key = %s', '_lp_featured' );
567 $filter->where[] = $this->wpdb->prepare( 'AND pm.meta_value = %s', 'yes' );
568
569 return $filter;
570 }
571
572 /**
573 * Get list courses is on popular
574 * Use "UNION" to merge 2 query
575 * @param LP_Course_Filter $filter
576 *
577 * @return LP_Course_Filter
578 * @throws Exception
579 * @version 1.0.0
580 * @since 4.1.6
581 * @author minhpd
582 */
583 public function get_courses_order_by_popular( LP_Course_Filter &$filter ): LP_Course_Filter {
584 // Set list name columns get
585 $columns_table_posts = $this->get_cols_of_table( $this->tb_posts );
586 $filter->fields = array_merge( $columns_table_posts, $filter->fields );
587
588 $filter_user_course = clone $filter;
589 $filter_course_not_attend = clone $filter;
590
591 // Query get users total attend courses
592 $filter_user_course->fields = array( 'ID', 'COUNT(ID) AS total' );
593 $filter_user_course->only_fields = [];
594 $filter_user_course->join[] = "INNER JOIN {$this->tb_lp_user_items} AS ui ON p.ID = ui.item_id";
595 $filter_user_course->where[] = $this->wpdb->prepare( 'AND ui.item_type = %s', LP_COURSE_CPT );
596 $filter_user_course->where[] = $this->wpdb->prepare(
597 'AND (status = %s OR status = %s OR status = %s)',
598 LP_COURSE_ENROLLED,
599 LP_COURSE_PURCHASED,
600 LP_COURSE_FINISHED
601 );
602 $filter_user_course->group_by = 'p.ID';
603 $filter_user_course->return_string_query = true;
604 $query_user_course = LP_Course_DB::getInstance()->get_courses( $filter_user_course );
605
606 // Query get courses not attend
607 $filter_user_course_cl = clone $filter_user_course;
608 $filter_user_course_cl->only_fields = array( 'ID' );
609 $query_user_course_for_not_in = LP_Course_DB::getInstance()->get_courses( $filter_user_course_cl );
610
611 $filter_course_not_attend->fields = [ 'ID', '0 AS total' ];
612 $filter_course_not_attend->only_fields = [];
613 $filter_course_not_attend->where[] = 'AND p.ID NOT IN(' . $query_user_course_for_not_in . ')';
614
615 $filter_course_not_attend->return_string_query = true;
616 $query_course_not_attend = LP_Course_DB::getInstance()->get_courses( $filter_course_not_attend );
617
618 $filter->union[] = $query_user_course;
619 $filter->union[] = $query_course_not_attend;
620 $filter->order_by = 'total';
621 $filter->order = 'DESC';
622
623 return $filter;
624 }
625
626 /**
627 * Get total courses of Author
628 *
629 * @param int $author_id
630 *
631 * @return LP_Course_Filter
632 * @since 4.1.6
633 * @version 1.0.0
634 * @throws Exception
635 */
636 public function count_courses_publish_of_author( int $author_id ): LP_Course_Filter {
637 $filter_course = new LP_Course_Filter();
638 $filter_course->only_fields = array( 'ID' );
639 $filter_course->post_author = $author_id;
640 $filter_course->post_status = 'publish';
641 $filter_course->field_count = 'ID';
642 $filter_course->query_count = true;
643
644 return apply_filters( 'lp/user/course/query/filter/count-users-attend-courses-of-author', $filter_course );
645 }
646 }
647
648 LP_Course_DB::getInstance();
649
650