PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.4
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.4
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 4.2.1 All 138 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.4.4, at inc/Databases/class-lp-course-db.php

863 lines 25.5 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 use LearnPress\Models\CourseModel;
10
11 defined( 'ABSPATH' ) || exit();
12
13 class LP_Course_DB extends LP_Database {
14 private static $_instance;
15
16 protected function __construct() {
17 parent::__construct();
18 }
19
20 public static function getInstance() {
21 if ( is_null( self::$_instance ) ) {
22 self::$_instance = new self();
23 }
24
25 return self::$_instance;
26 }
27
28 /**
29 * Get course_id of item
30 *
31 * item type lp_lesson, lp_quiz
32 *
33 * @param int $item_id
34 *
35 * @return int
36 * @throws Exception
37 */
38 public function get_course_by_item_id( $item_id = 0 ): int {
39 // Get cache
40 $lp_course_cache = LP_Course_Cache::instance();
41 $key_cache = "$item_id/course_id_of_item_id";
42 $course_id = $lp_course_cache->get_cache( $key_cache );
43
44 if ( ! $course_id ) {
45 $query = $this->wpdb->prepare(
46 "
47 SELECT section_course_id
48 FROM {$this->tb_lp_sections} AS s
49 INNER JOIN {$this->tb_lp_section_items} AS si
50 ON si.section_id = s.section_id
51 WHERE si.item_id = %d",
52 $item_id
53 );
54
55 $course_id = (int) $this->wpdb->get_var( $query );
56
57 $this->check_execute_has_error();
58
59 // Set cache
60 $lp_course_cache->set_cache( $key_cache, $course_id );
61 }
62
63 return $course_id;
64 }
65
66 /**
67 * Get all item ids' course
68 *
69 * @param int $course_id
70 *
71 * @return array|object|stdClass[]|null
72 * @throws Exception
73 * @since 4.1.6.9
74 * @version 1.0.0
75 */
76 public function get_full_sections_and_items_course( int $course_id = 0 ) {
77 $method_called_to = debug_backtrace()[1]['function'];
78
79 // Check accept call from function 'get_sections_and_items_course_from_db_and_sort'
80 if ( 'get_sections_and_items_course_from_db_and_sort' !== $method_called_to ) {
81 error_log( 'You can not call direct this function' );
82
83 return [];
84 }
85
86 $query = $this->wpdb->prepare(
87 "SELECT *
88 FROM {$this->tb_lp_section_items} AS si
89 INNER JOIN {$this->tb_lp_sections} AS s
90 ON si.section_id = s.section_id
91 INNER JOIN {$this->tb_posts} AS p
92 ON si.item_id = p.ID AND p.post_status = 'publish'
93 WHERE section_course_id = %d
94 ORDER BY s.section_order",
95 $course_id
96 );
97
98 $sections_items = $this->wpdb->get_results( $query );
99
100 $this->check_execute_has_error();
101
102 return $sections_items;
103 }
104
105 /**
106 * Get all sections' course
107 *
108 * @param int $course_id
109 *
110 * @return array|object|stdClass[]|null
111 * @throws Exception
112 * @since 4.1.6.9
113 * @version 1.0.0
114 */
115 public function get_sections( int $course_id = 0 ) {
116 $method_called_to = debug_backtrace()[1]['function'];
117
118 // Check accept call from function 'get_sections_and_items_course_from_db_and_sort'
119 if ( 'get_sections_and_items_course_from_db_and_sort' !== $method_called_to ) {
120 error_log( 'You can not call direct this function' );
121
122 return [];
123 }
124
125 $query = $this->wpdb->prepare(
126 "SELECT * FROM {$this->tb_lp_sections}
127 WHERE section_course_id = %d
128 ORDER BY section_order",
129 $course_id
130 );
131
132 $sections_items = $this->wpdb->get_results( $query, OBJECT_K );
133
134 $this->check_execute_has_error();
135
136 return $sections_items;
137 }
138
139 /**
140 * Get user_item_id by order_id, course_id, user_id
141 *
142 * @param int $order_id
143 * @param int $course_id
144 * @param int $user_id
145 *
146 * @return int
147 * @deprecated 4.2.6.6 not use anywhere
148 */
149 public function get_user_item_id( $order_id = 0, $course_id = 0, $user_id = 0 ): int {
150 _deprecated_function( __METHOD__, '4.2.6.6' );
151 $query = $this->wpdb->prepare(
152 "
153 SELECT user_item_id
154 FROM {$this->tb_lp_user_items}
155 WHERE ref_type = %s
156 AND ref_id = %d
157 AND item_type = %s
158 AND item_id = %d
159 AND user_id = %d
160 ",
161 LP_ORDER_CPT,
162 $order_id,
163 LP_COURSE_CPT,
164 $course_id,
165 $user_id
166 );
167
168 return (int) $this->wpdb->get_var( $query );
169 }
170
171 /**
172 * Get first item id of course
173 *
174 * @param int $course_id .
175 *
176 * @return int
177 * @throws Exception
178 * @since 4.0.0
179 * @version 1.0.4
180 * @modify 4.1.3
181 * @author tungnx
182 */
183 public function get_first_item_id( int $course_id = 0 ): int {
184 $query = $this->wpdb->prepare(
185 "
186 SELECT item_id FROM $this->tb_lp_section_items AS si
187 INNER JOIN $this->tb_lp_sections AS sections
188 ON si.section_id = sections.section_id
189 AND sections.section_course_id = %d
190 INNER JOIN $this->tb_posts AS p
191 ON si.item_id = p.ID
192 AND p.post_status = 'publish'
193 ORDER BY sections.section_order ASC, si.item_order ASC
194 LIMIT %d
195 ",
196 $course_id,
197 1
198 );
199
200 $first_item_id = (int) $this->wpdb->get_var( $query );
201
202 $this->check_execute_has_error();
203
204 return $first_item_id;
205 }
206
207 public function get_recent_courses( LP_Course_Filter $filter ): array {
208 global $wpdb;
209
210 $limit = $filter->limit ?? - 1;
211 $order = ! empty( $filter->order ) ? $filter->order : 'DESC';
212
213 if ( $limit <= 0 ) {
214 $limit = 0;
215 }
216
217 $query = apply_filters(
218 'learnpress/databases/widgets/recent_courses',
219 $wpdb->prepare(
220 "SELECT DISTINCT p.ID
221 FROM $wpdb->posts AS p
222 WHERE p.post_type = %s
223 AND p.post_status = %s
224 ORDER BY p.post_date {$order}
225 LIMIT %d",
226 LP_COURSE_CPT,
227 'publish',
228 $limit
229 )
230 );
231
232 return $wpdb->get_col( $query );
233 }
234
235 public function get_featured_courses( LP_Course_Filter $filter ): array {
236 global $wpdb;
237
238 $limit = ! empty( $filter->limit ) ? $filter->limit : - 1;
239 $order_by = ! empty( $filter->order_by ) ? $filter->order_by : 'post_date';
240 $order = ! empty( $filter->order ) ? $filter->order : 'DESC';
241
242 if ( $limit < 0 ) {
243 $limit = 0;
244 }
245
246 $query = apply_filters(
247 'learnpress/databases/widgets/featured_courses',
248 $wpdb->prepare(
249 "SELECT DISTINCT p.ID
250 FROM {$wpdb->posts} p
251 LEFT JOIN {$wpdb->postmeta} as pmeta ON p.ID=pmeta.post_id AND pmeta.meta_key = %s
252 WHERE p.post_type = %s
253 AND p.post_status = %s
254 AND pmeta.meta_value = %s
255 ORDER BY p.{$order_by} {$order}
256 LIMIT %d",
257 '_lp_featured',
258 LP_COURSE_CPT,
259 'publish',
260 'yes',
261 $limit
262 )
263 );
264
265 return $wpdb->get_col( $query );
266 }
267
268 /**
269 * Get list user ids enrolled by course
270 *
271 * @return array|object|null
272 * @throws Exception
273 * @version 1.0.0
274 * @author tungnx
275 * @since 4.1.3.1
276 */
277 public function get_user_ids_enrolled( int $course_id ) {
278 $query = $this->wpdb->prepare(
279 "
280 SELECT DISTINCT user_id FROM {$this->tb_lp_user_items}
281 WHERE item_id = %d
282 AND item_type = %s
283 AND (status = %s OR status = %s )
284 ",
285 $course_id,
286 LP_COURSE_CPT,
287 'enrolled',
288 'finished'
289 );
290
291 $result = $this->wpdb->get_results( $query, OBJECT_K );
292
293 $this->check_execute_has_error();
294
295 return $result;
296 }
297
298 /**
299 * Count total user enrolled by course
300 *
301 * @param int $course_id
302 *
303 * @return int
304 * @throws Exception
305 * @author tungnx
306 * @since 4.1.4
307 * @version 1.0.0
308 */
309 public function get_total_user_enrolled( int $course_id ): int {
310 $filter = new LP_User_Items_Filter();
311 $filter->only_fields = [ 'DISTINCT(user_id)' ];
312 $filter->item_id = $course_id;
313 $filter->item_type = LP_COURSE_CPT;
314 $filter->field_count = 'ui.user_id';
315 $filter->join[] = "INNER JOIN {$this->tb_users} AS u ON ui.user_id = u.ID";
316 $filter->where[] = 'AND ui.user_id > 0';
317 $filter->where[] = $this->wpdb->prepare( 'AND ( ui.status = %s OR ui.status = %s )', LP_COURSE_ENROLLED, LP_COURSE_FINISHED );
318 $filter->query_count = true;
319
320 $total = 0;
321 $lp_user_items_db = LP_User_Items_DB::getInstance();
322 $lp_user_items_db->get_user_items( $filter, $total );
323
324 return $total;
325 }
326
327 /**
328 * Count total user enrolled or purchase by course
329 *
330 * @param int $course_id
331 *
332 * @return int
333 * @throws Exception
334 * @author tungnx
335 * @since 4.1.4
336 * @version 1.0.2
337 */
338 public function get_total_user_enrolled_or_purchased( int $course_id ): int {
339 $filter = new LP_User_Items_Filter();
340 $filter->only_fields = [ 'DISTINCT(user_id) AS user_id' ];
341 $filter->item_id = $course_id;
342 $filter->item_type = LP_COURSE_CPT;
343 $filter->field_count = 'ui.user_id';
344 $filter->join[] = "INNER JOIN {$this->tb_users} AS u ON ui.user_id = u.ID";
345 $filter->where[] = 'AND ui.user_id > 0';
346 $filter->where[] = $this->wpdb->prepare(
347 'AND ( ui.status = %s OR ui.status = %s OR ui.status = %s )',
348 LP_COURSE_ENROLLED,
349 LP_COURSE_FINISHED,
350 LP_COURSE_PURCHASED
351 );
352 $filter->query_count = true;
353
354 $total = 0;
355 $lp_user_items_db = LP_User_Items_DB::getInstance();
356 $lp_user_items_db->get_user_items( $filter, $total );
357
358 return $total;
359 }
360
361 /**
362 * Get total items of course
363 *
364 * @param int $course_id
365 *
366 * @return null|object
367 * @throws Exception
368 * @version 1.0.1
369 * @author tungnx
370 * @since 4.1.4.1
371 */
372 public function get_total_items( int $course_id = 0 ) {
373 $item_types = CourseModel::item_types_support();
374 $count_item_types = count( $item_types );
375 $i = 0;
376
377 $query_count = $this->wpdb->prepare( 'SUM(s.section_course_id = %d) AS count_items,', $course_id );
378
379 foreach ( $item_types as $item_type ) {
380 ++ $i;
381 if ( $i == $count_item_types ) {
382 $query_count .= $this->wpdb->prepare( 'SUM(s.section_course_id = %d AND si.item_type = %s) AS %s', $course_id, $item_type, $item_type );
383 } else {
384 $query_count .= $this->wpdb->prepare( 'SUM(s.section_course_id = %d AND si.item_type = %s) AS %s,', $course_id, $item_type, $item_type );
385 }
386 }
387
388 $query = "
389 SELECT $query_count
390 FROM $this->tb_lp_section_items si
391 INNER JOIN $this->tb_lp_sections s ON s.section_id = si.section_id
392 INNER JOIN $this->tb_posts p ON si.item_id = p.ID
393 AND p.post_status = 'publish'
394 ";
395
396 $total_items = $this->wpdb->get_row( $query );
397
398 $this->check_execute_has_error();
399
400 return $total_items;
401 }
402
403 /**
404 * Count all item are unassigned to any courses.
405 *
406 * @param string $item_type (type item Lesson, Quiz, Assignment, H5P ...)
407 *
408 * @return int
409 * @throws Exception
410 * @author tungnx
411 * @version 1.0.1
412 * @since 4.1.4.1
413 */
414 public function get_total_item_unassigned( string $item_type ): int {
415 $filter = new LP_Post_Type_Filter();
416 $filter->post_type = $item_type;
417 $filter->query_count = true;
418 $filter->post_status = array();
419 $filter->field_count = 'p.ID';
420
421 return $this->get_item_ids_unassigned( $filter );
422 }
423
424 /**
425 * list id item are unassigned to any courses.
426 *
427 * @param LP_Post_Type_Filter|mixed $filter
428 *
429 * @return array|int|string|null
430 * @throws Exception
431 * @author tungnx
432 * @version 1.0.0
433 * @since 4.1.6
434 */
435 public function get_item_ids_unassigned( $filter = null ) {
436 if ( is_null( $filter ) ) {
437 $filter = new LP_Post_Type_Filter();
438 }
439
440 if ( ! $filter instanceof LP_Post_Type_Filter ) {
441 throw new Exception( 'Filter must be instance of LP_Post_Type_Filter' );
442 }
443
444 $filter_section_items = new LP_Section_Items_Filter();
445 $filter_section_items->return_string_query = true;
446 $filter_section_items->only_fields = array( 'si.item_id' );
447 $filter_section_items->where[] = $this->wpdb->prepare( 'AND si.item_type = %s', $filter->post_type );
448 $query_item_ids_assigned = LP_Section_Items_DB::getInstance()->get_section_items( $filter_section_items );
449
450 $filter->only_fields = array( 'p.ID' );
451 $filter->collection = $this->tb_posts;
452 $filter->collection_alias = 'p';
453 $filter->where[] = $this->wpdb->prepare( 'AND p.post_type = %s', $filter->post_type );
454 $filter->where[] = 'AND ID NOT IN(' . $query_item_ids_assigned . ')';
455 $filter->where[] = $this->wpdb->prepare( 'AND p.post_status not IN(%s, %s)', 'trash', 'auto-draft' );
456
457 return $this->execute( $filter );
458 }
459
460 /**
461 * Get Courses
462 *
463 * @param LP_Course_Filter $filter
464 * @param int $total_rows return total_rows
465 *
466 * @return array|object|null|int|string
467 * @throws Exception
468 * @author tungnx
469 * @version 1.0.2
470 * @since 4.1.5
471 */
472 public function get_courses( $filter, int &$total_rows = 0 ) {
473 $default_fields = $filter->all_fields;
474 $filter->fields = array_merge( $default_fields, $filter->fields );
475
476 if ( empty( $filter->collection ) ) {
477 $filter->collection = $this->tb_posts;
478 }
479
480 if ( empty( $filter->collection_alias ) ) {
481 $filter->collection_alias = 'p';
482 }
483
484 // Where
485 $filter->where[] = $this->wpdb->prepare( 'AND p.post_type = %s', $filter->post_type );
486
487 // Status
488 $filter->post_status = (array) $filter->post_status;
489 if ( ! empty( $filter->post_status ) ) {
490 $post_status_format = LP_Helper::db_format_array( $filter->post_status, '%s' );
491 $filter->where[] = $this->wpdb->prepare( 'AND p.post_status IN (' . $post_status_format . ')', $filter->post_status );
492 }
493
494 // Exclude status auto-draft, because Admin of WP not show auto-draft in list post, so all front-end and back-end of LP also not show auto-draft
495 if ( ! in_array( 'auto-draft', $filter->post_status, true ) ) {
496 $filter->where[] = $this->wpdb->prepare( 'AND p.post_status != %s', 'auto-draft' );
497 }
498
499 // Term ids
500 if ( ! empty( $filter->term_ids ) ) {
501 // Sanitize term ids
502 $filter->term_ids = array_map( 'absint', $filter->term_ids );
503 $filter->join[] = "INNER JOIN $this->tb_term_relationships AS r_term ON p.ID = r_term.object_id";
504 $filter->join[] = "INNER JOIN $this->tb_term_taxonomy AS tx ON r_term.term_taxonomy_id = tx.term_taxonomy_id";
505
506 if ( LP_Settings::get_option( 'get_courses_of_subcategory' ) !== 'yes' ) {
507 $term_ids_format = join( ',', $filter->term_ids );
508 $filter->where[] = "AND tx.term_id IN ($term_ids_format)";
509 } else {
510 $term_all = $this->recursion_sub_categories( $filter->term_ids );
511 $term_ids_format = join( ',', $term_all );
512 $filter->where[] = "AND tx.term_id IN ($term_ids_format)";
513 }
514 $filter->where[] = $this->wpdb->prepare( 'AND tx.taxonomy = %s', LP_COURSE_CATEGORY_TAX );
515 }
516
517 // Tag ids
518 if ( ! empty( $filter->tag_ids ) ) {
519 // Sanitize tag ids
520 $filter->tag_ids = array_map( 'absint', $filter->tag_ids );
521 $filter->join[] = "INNER JOIN $this->tb_term_relationships AS r_tag ON p.ID = r_tag.object_id";
522 $filter->join[] = "INNER JOIN $this->tb_term_taxonomy AS tag ON r_tag.term_taxonomy_id = tag.term_taxonomy_id";
523
524 $tag_ids_format = join( ',', $filter->tag_ids );
525 $filter->where[] = "AND tag.term_id IN ($tag_ids_format)";
526 $filter->where[] = $this->wpdb->prepare( 'AND tag.taxonomy = %s', LP_COURSE_TAXONOMY_TAG );
527 }
528
529 // Level
530 if ( ! empty( $filter->levels ) ) {
531 $filter->join[] = "INNER JOIN $this->tb_postmeta AS pml ON p.ID = pml.post_id";
532 $filter->where[] = $this->wpdb->prepare( 'AND pml.meta_key = %s', '_lp_level' );
533 $levels_format = LP_Helper::db_format_array( $filter->levels, '%s' );
534 $filter->where[] = $this->wpdb->prepare( 'AND pml.meta_value IN (' . $levels_format . ')', $filter->levels );
535 }
536
537 // Course type
538 if ( ! empty( $filter->type ) && $filter->type !== 'all' ) {
539 if ( $filter->type === 'offline' ) {
540 $filter->join[] = "INNER JOIN $this->tb_postmeta AS pm_off ON p.ID = pm_off.post_id";
541 $filter->where[] = $this->wpdb->prepare( 'AND pm_off.meta_key = %s', '_lp_offline_course' );
542 $filter->where[] = $this->wpdb->prepare( 'AND pm_off.meta_value = %s', 'yes' );
543 } else {
544 $filter->where[] = $this->wpdb->prepare(
545 "AND p.ID NOT IN
546 ( SELECT id FROM $this->tb_posts as p1
547 INNER JOIN $this->tb_postmeta as pm_ol on p1.ID = pm_ol.post_id
548 WHERE pm_ol.meta_key = %s AND pm_ol.meta_value = %s )",
549 '_lp_offline_course',
550 'yes'
551 );
552 }
553 }
554
555 // course ids
556 if ( ! empty( $filter->post_ids ) ) {
557 $list_ids_format = LP_Helper::db_format_array( $filter->post_ids, '%d' );
558 $filter->where[] = $this->wpdb->prepare( 'AND p.ID IN (' . $list_ids_format . ')', $filter->post_ids );
559 }
560
561 // Title, do not distinguish diacritics
562 if ( $filter->post_title ) {
563 //$filter->where[] = $this->wpdb->prepare( 'AND p.post_title COLLATE utf8mb4_unicode_ci LIKE %s', '%' . $filter->post_title . '%' );
564 $filter->where[] = $this->wpdb->prepare( 'AND p.post_title LIKE %s', '%' .$filter->post_title . '%' );
565 }
566
567 // Slug
568 if ( $filter->post_name ) {
569 $filter->where[] = $this->wpdb->prepare( 'AND p.post_name = %s', $filter->post_name );
570 }
571
572 // Author
573 if ( isset( $filter->post_author ) ) {
574 $filter->where[] = $this->wpdb->prepare( 'AND p.post_author = %d', $filter->post_author );
575 }
576 // Authors
577 if ( ! empty( $filter->post_authors ) ) {
578 $post_authors_format = LP_Helper::db_format_array( $filter->post_authors, '%d' );
579 $filter->where[] = $this->wpdb->prepare( 'AND p.post_author IN (' . $post_authors_format . ')', $filter->post_authors );
580 }
581
582 $filter = apply_filters( 'lp/course/query/filter', $filter );
583
584 return $this->execute( $filter, $total_rows );
585 }
586
587 /**
588 * Get list courses sort by price
589 *
590 * @param LP_Course_Filter $filter
591 *
592 * @return LP_Course_Filter
593 * @since 4.1.5
594 * @author tungnx
595 * @version 1.0.0
596 */
597 public function get_courses_order_by_price( LP_Course_Filter &$filter ): LP_Course_Filter {
598 $filter->join[] = "INNER JOIN $this->tb_postmeta AS pm ON p.ID = pm.post_id";
599 $filter->where[] = $this->wpdb->prepare( 'AND pm.meta_key = %s', '_lp_price' );
600 $filter->order_by = 'CAST( pm.meta_value AS UNSIGNED )';
601
602 return $filter;
603 }
604
605 /**
606 * Get list courses is on sale
607 *
608 * @param LP_Course_Filter $filter
609 *
610 * @return LP_Course_Filter
611 * @since 4.1.5
612 * @author tungnx
613 * @version 1.0.0
614 */
615 public function get_courses_sort_by_sale( LP_Course_Filter &$filter ): LP_Course_Filter {
616 $filter->join[] = "INNER JOIN $this->tb_postmeta AS pm ON p.ID = pm.post_id";
617 $filter->where[] = $this->wpdb->prepare( 'AND pm.meta_key = %s', '_lp_course_is_sale' );
618
619 return $filter;
620 }
621
622 /**
623 * Get list courses is Free
624 *
625 * @param LP_Course_Filter $filter
626 *
627 * @return LP_Course_Filter
628 * @throws Exception
629 * @version 1.0.0
630 * @since 4.2.3.2
631 */
632 public function get_courses_sort_by_free( LP_Course_Filter &$filter ): LP_Course_Filter {
633 $filter_course_price = new LP_Course_Filter();
634 $filter_course_price->only_fields = [ 'DISTINCT(ID)' ];
635 $filter_course_price = $this->get_courses_sort_by_paid( $filter_course_price );
636 $filter_course_price->return_string_query = true;
637 $courses_price = $this->get_courses( $filter_course_price );
638
639 $filter->join[] = "INNER JOIN $this->tb_postmeta AS pmfr ON p.ID = pmfr.post_id";
640 $filter->where[] = 'AND ID NOT IN( ' . $courses_price . ' )';
641
642 return $filter;
643 }
644
645 /**
646 * Get list courses has price
647 *
648 * @param LP_Course_Filter $filter
649 *
650 * @return LP_Course_Filter
651 * @version 1.0.0
652 * @since 4.2.3.2
653 */
654 public function get_courses_sort_by_paid( LP_Course_Filter $filter ): LP_Course_Filter {
655 $filter->join[] = "INNER JOIN $this->tb_postmeta AS pmp ON p.ID = pmp.post_id";
656 $filter->where[] = $this->wpdb->prepare( 'AND pmp.meta_key = %s AND pmp.meta_value > %d', '_lp_price', 0 );
657
658 return $filter;
659 }
660
661 /**
662 * Get list courses is on feature
663 *
664 * @param LP_Course_Filter $filter
665 *
666 * @return LP_Course_Filter
667 * @author tungnx
668 * @version 1.0.0
669 * @since 4.1.5
670 */
671 public function get_courses_sort_by_feature( LP_Course_Filter &$filter ): LP_Course_Filter {
672 $filter->join[] = "INNER JOIN $this->tb_postmeta AS pmf ON p.ID = pmf.post_id";
673 $filter->where[] = $this->wpdb->prepare( 'AND pmf.meta_key = %s', '_lp_featured' );
674 $filter->where[] = $this->wpdb->prepare( 'AND pmf.meta_value = %s', 'yes' );
675
676 return $filter;
677 }
678
679 /**
680 * Count total courses free on category
681 *
682 * @param LP_Course_Filter $filter
683 *
684 * @return int
685 * @since 4.2.5.4
686 * @version 1.0.1
687 */
688 public function count_course_free( LP_Course_Filter $filter ): int {
689 $count = 0;
690
691 try {
692 $filter->only_fields = [ 'COUNT( DISTINCT(ID) )' ];
693 $filter->order_by = ''; // Must set to empty to avoid error from param Request
694 $this->get_courses_sort_by_free( $filter );
695 $filter->return_string_query = true;
696 $query_count = $this->get_courses( $filter, $count );
697 $count = $this->wpdb->get_var( $query_count );
698 } catch ( Throwable $e ) {
699 LP_Debug::error_log( $e );
700 }
701
702 return (int) $count;
703 }
704
705 /**
706 * Get list courses is on popular
707 * Use "UNION" to merge 2 query
708 *
709 * @param LP_Course_Filter $filter
710 *
711 * @return LP_Course_Filter
712 * @throws Exception
713 * @version 1.0.1
714 * @since 4.1.6
715 * @author minhpd
716 */
717 public function get_courses_order_by_popular( LP_Course_Filter &$filter ): LP_Course_Filter {
718 // Set list name columns get
719 //$columns_table_posts = $this->get_cols_of_table( $this->tb_posts );
720 //$filter->fields = array_merge( $columns_table_posts, $filter->fields );
721
722 $filter_user_course = clone $filter;
723 $filter_course_not_attend = clone $filter;
724
725 // Query get users total attend courses
726 $fields_user_course_require = [ 'ID', 'COUNT(ID) AS total' ];
727 $filter_user_course->fields = array( 'ID', 'COUNT(ID) AS total' );
728 if ( ! empty( $filter_user_course->only_fields ) ) {
729 $pattern = '#ID.*#';
730 foreach ( $filter_user_course->only_fields as $k => $field ) {
731 if ( preg_match( $pattern, $field ) ) {
732 unset( $filter_user_course->only_fields[ $k ] );
733 }
734 }
735 $filter_user_course->only_fields = array_unique( array_merge( $filter_user_course->only_fields, $fields_user_course_require ) );
736 }
737
738 $filter_user_course->join[] = "INNER JOIN {$this->tb_lp_user_items} AS ui ON p.ID = ui.item_id";
739 $filter_user_course->where[] = $this->wpdb->prepare( 'AND ui.item_type = %s', LP_COURSE_CPT );
740 $filter_user_course->where[] = $this->wpdb->prepare(
741 'AND (status = %s OR status = %s OR status = %s)',
742 LP_COURSE_ENROLLED,
743 LP_COURSE_PURCHASED,
744 LP_COURSE_FINISHED
745 );
746 $filter_user_course->group_by = 'p.ID';
747 $filter_user_course->order_by = '';
748 $filter_user_course->return_string_query = true;
749 $query_user_course = LP_Course_DB::getInstance()->get_courses( $filter_user_course );
750
751 // Query get courses not attend
752 $filter_user_course_cl = clone $filter_user_course;
753 $filter_user_course_cl->only_fields = array( 'ID' );
754 $query_user_course_for_not_in = LP_Course_DB::getInstance()->get_courses( $filter_user_course_cl );
755
756 $fields_user_course_not_attend_require = [ 'ID', '0 AS total' ];
757 $filter_course_not_attend->fields = [ 'ID', '0 AS total' ];
758 if ( ! empty( $filter_course_not_attend->only_fields ) ) {
759 $pattern = '#ID.*#';
760 foreach ( $filter_course_not_attend->only_fields as $k => $field ) {
761 if ( preg_match( $pattern, $field ) ) {
762 unset( $filter_course_not_attend->only_fields[ $k ] );
763 }
764 }
765 $filter_course_not_attend->only_fields = array_unique( array_merge( $filter_course_not_attend->only_fields, $fields_user_course_not_attend_require ) );
766 }
767 $filter_course_not_attend->where[] = 'AND p.ID NOT IN(' . $query_user_course_for_not_in . ')';
768
769 $filter_course_not_attend->order_by = '';
770 $filter_course_not_attend->return_string_query = true;
771 $query_course_not_attend = LP_Course_DB::getInstance()->get_courses( $filter_course_not_attend );
772
773 $filter->union[] = $query_user_course;
774 $filter->union[] = $query_course_not_attend;
775 $filter->order_by = 'total';
776 $filter->order = 'DESC';
777
778 return $filter;
779 }
780
781 /**
782 * Get total courses of Author
783 *
784 * @param int $author_id
785 *
786 * @return LP_Course_Filter
787 * @throws Exception
788 * @version 1.0.0
789 * @since 4.1.6
790 * @deprecated 4.2.6.6 not use anywhere
791 */
792 public function count_courses_publish_of_author( int $author_id ): LP_Course_Filter {
793 _deprecated_function( __METHOD__, '4.2.6.6' );
794 $filter_course = new LP_Course_Filter();
795 $filter_course->only_fields = array( 'ID' );
796 $filter_course->post_author = $author_id;
797 $filter_course->post_status = 'publish';
798 $filter_course->field_count = 'ID';
799 $filter_course->query_count = true;
800
801 return apply_filters( 'lp/user/course/query/filter/count-users-attend-courses-of-author', $filter_course );
802 }
803
804 /**
805 * Get total courses of Author
806 *
807 * @param int $author_id
808 * @param array $status
809 *
810 * @return LP_Course_Filter
811 * @since 4.2.3
812 * @version 1.0.0
813 */
814 public function count_courses_of_author( int $author_id, array $status = [] ): LP_Course_Filter {
815 $filter_course = new LP_Course_Filter();
816 $filter_course->only_fields = array( 'ID' );
817 $filter_course->post_author = $author_id;
818 $filter_course->post_status = $status;
819 if ( empty( $status ) ) {
820 $filter_course->post_status = [];
821 }
822 $filter_course->field_count = 'ID';
823 $filter_course->query_count = true;
824
825 return apply_filters( 'lp/user/course/query/filter/count-courses-of-author', $filter_course );
826 }
827
828 /**
829 * Get child categories of category and add to query OR
830 *
831 * @param array $term_ids
832 *
833 * @return array
834 * @throws Exception
835 * @version 1.0.1
836 * @since 4.2.6.5
837 */
838 public function recursion_sub_categories( array $term_ids ): array {
839 $total_found = 0;
840 $term_ids_format = join( ',', $term_ids );
841 $filter_sub_category = new LP_Filter();
842 $filter_sub_category->collection = $this->tb_term_taxonomy;
843 $filter_sub_category->collection_alias = 'tx';
844 $filter_sub_category->field_count = 'tx.term_id';
845 $filter_sub_category->only_fields = [ 'term_id' ];
846 $filter_sub_category->where[] = "AND tx.parent IN ($term_ids_format)";
847 $filter_sub_category->limit = -1;
848 $query_sub_category = $this->execute( $filter_sub_category, $total_found );
849 $term_sub_ids = [];
850
851 if ( $total_found > 0 ) {
852 foreach ( $query_sub_category as $term_id ) {
853 $term_sub_ids[] = $term_id->term_id;
854 }
855
856 $term_sub_idss = $this->recursion_sub_categories( $term_sub_ids );
857 $term_sub_ids = array_merge( $term_sub_ids, $term_sub_idss );
858 }
859
860 return array_merge( $term_ids, $term_sub_ids );
861 }
862 }
863