PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.1.7.1
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.1.7.1
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 / class-lp-page-controller.php

class-lp-page-controller.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.1.7.1, at inc/class-lp-page-controller.php

1,041 lines 28.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Class LP_Page_Controller
5 */
6 class LP_Page_Controller {
7 protected static $_instance = null;
8
9 /**
10 * Store the object has queried by WP.
11 *
12 * @var int
13 */
14 //protected $_queried_object = 0;
15
16 /**
17 * @var int
18 */
19 //protected $_filter_content_priority = 10000;
20
21 /**
22 * Flag for 404 content.
23 *
24 * @var bool
25 */
26 protected $_is_404 = false;
27
28 /**
29 * LP_Page_Controller constructor.
30 */
31 protected function __construct() {
32 add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ), -1 );
33 add_filter( 'template_include', array( $this, 'template_loader' ), 10 );
34 add_filter( 'template_include', array( $this, 'check_pages' ), 30 );
35 add_filter( 'template_include', array( $this, 'auto_shortcode' ), 50 );
36
37 add_filter( 'the_post', array( $this, 'setup_data_for_item_course' ) );
38 add_filter( 'request', array( $this, 'remove_course_post_format' ), 1 );
39
40 add_shortcode( 'learn_press_archive_course', array( $this, 'archive_content' ) );
41 add_filter( 'pre_get_document_title', array( $this, 'set_title_pages' ), 20, 1 );
42
43 // Yoast seo
44 add_filter( 'wpseo_opengraph_desc', array( $this, 'lp_desc_item_yoast_seo' ), 11, 1 );
45 add_filter( 'wpseo_metadesc', array( $this, 'lp_desc_item_yoast_seo' ), 11, 1 );
46
47 // edit link item course when form search default wp
48 add_filter( 'post_type_link', array( $this, 'post_type_link' ), 10, 2 );
49
50 // Set link profile to admin menu
51 add_action( 'admin_bar_menu', array( $this, 'learn_press_edit_admin_bar' ) );
52
53 // Web hook detected PayPal request.
54 add_action( 'init', [ $this, 'check_webhook_paypal_ipn' ] );
55 // Set again x-wp-nonce on header when has cache with not login.
56 add_filter( 'rest_send_nocache_headers', array( $this, 'check_x_wp_nonce_cache' ) );
57 }
58
59 /**
60 * Check notify papal call when done.
61 *
62 * Set in param notify_url on @see LP_Gateway_Paypal::get_paypal_args()
63 */
64 public function check_webhook_paypal_ipn() {
65 //error_log( 'xxx:' . json_encode( $_POST, JSON_UNESCAPED_UNICODE ) );
66
67 // Paypal payment done
68 if ( ! isset( $_GET['paypal_notify'] ) ) {
69 return;
70 }
71
72 if ( ! isset( $_POST['ipn_track_id'] ) ) {
73 return;
74 }
75
76 try {
77 $paypal = new LP_Gateway_Paypal();
78 $verify = $paypal->validate_ipn();
79
80 if ( $verify ) {
81 if ( isset( $_POST['custom'] ) ) {
82 $data_order = json_decode( LP_Helper::sanitize_params_submitted( $_POST['custom'] ) );
83
84 if ( json_last_error() === JSON_ERROR_NONE ) {
85 $order_id = $data_order->order_id;
86
87 $lp_order = learn_press_get_order( $order_id );
88 $lp_order->set_status( 'completed' );
89 $lp_order->save();
90 }
91 }
92 }
93 } catch ( Throwable $e ) {
94 error_log( $e->getMessage() );
95 }
96 }
97
98 /**
99 * Set link item course when form search default wp
100 *
101 * @param string $post_link
102 * @param object $post
103 */
104 public function post_type_link( $post_link, $post ) {
105 // Set item's course permalink
106 $course_item_types = learn_press_get_course_item_types();
107 $item_id = $post->ID;
108
109 if ( in_array( $post->post_type, $course_item_types ) ) {
110 $section_id = LP_Section_DB::getInstance()->get_section_id_by_item_id( $item_id );
111
112 if ( ! $section_id ) {
113 return $post_link;
114 }
115
116 $course_id = LP_Section_DB::getInstance()->get_course_id_by_section( $section_id );
117
118 if ( ! $course_id ) {
119 return $post_link;
120 }
121
122 $course = learn_press_get_course( $course_id );
123 if ( ! $course ) {
124 return $post_link;
125 }
126
127 $post_link = $course->get_item_link( $item_id );
128 } elseif ( LP_COURSE_CPT === $post->post_type ) {
129 // Abort early if the placeholder rewrite tag isn't in the generated URL
130 if ( false === strpos( $post_link, '%' ) ) {
131 return $post_link;
132 }
133
134 // Get the custom taxonomy terms in use by this post
135 $terms = get_the_terms( $post->ID, 'course_category' );
136
137 if ( ! empty( $terms ) ) {
138 $terms = _learn_press_usort_terms_by_ID( $terms ); // order by ID
139 $category_object = apply_filters(
140 'learn_press_course_post_type_link_course_category',
141 $terms[0],
142 $terms,
143 $post
144 );
145 $category_object = get_term( $category_object, 'course_category' );
146 $course_category = $category_object->slug;
147
148 $parent = $category_object->parent;
149 if ( $parent ) {
150 $ancestors = get_ancestors( $category_object->term_id, 'course_category' );
151 foreach ( $ancestors as $ancestor ) {
152 $ancestor_object = get_term( $ancestor, 'course_category' );
153 $course_category = $ancestor_object->slug . '/' . $course_category;
154 }
155 }
156 } else {
157 // If no terms are assigned to this post, use a string instead (can't leave the placeholder there)
158 $course_category = _x( 'uncategorized', 'slug', 'learnpress' );
159 }
160
161 $find = array(
162 '%year%',
163 '%monthnum%',
164 '%day%',
165 '%hour%',
166 '%minute%',
167 '%second%',
168 '%post_id%',
169 '%category%',
170 '%course_category%',
171 );
172
173 $replace = array(
174 date_i18n( 'Y', strtotime( $post->post_date ) ),
175 date_i18n( 'm', strtotime( $post->post_date ) ),
176 date_i18n( 'd', strtotime( $post->post_date ) ),
177 date_i18n( 'H', strtotime( $post->post_date ) ),
178 date_i18n( 'i', strtotime( $post->post_date ) ),
179 date_i18n( 's', strtotime( $post->post_date ) ),
180 $post->ID,
181 $course_category,
182 $course_category,
183 );
184
185 $post_link = str_replace( $find, $replace, $post_link );
186 }
187
188 return $post_link;
189 }
190
191 private function has_block_template( $template_name ) {
192 if ( ! $template_name ) {
193 return false;
194 }
195
196 $has_template = false;
197 $template_name = str_replace( 'course', LP_COURSE_CPT, $template_name );
198 $template_filename = $template_name . '.html';
199 // Since Gutenberg 12.1.0, the conventions for block templates directories have changed,
200 // we should check both these possible directories for backwards-compatibility.
201 $possible_templates_dirs = array( 'templates', 'block-templates' );
202
203 // Combine the possible root directory names with either the template directory
204 // or the stylesheet directory for child themes, getting all possible block templates
205 // locations combinations.
206 $filepath = DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR . $template_filename;
207 $legacy_filepath = DIRECTORY_SEPARATOR . 'block-templates' . DIRECTORY_SEPARATOR . $template_filename;
208 $possible_paths = array(
209 get_stylesheet_directory() . $filepath,
210 get_stylesheet_directory() . $legacy_filepath,
211 get_template_directory() . $filepath,
212 get_template_directory() . $legacy_filepath,
213 );
214
215 // Check the first matching one.
216 foreach ( $possible_paths as $path ) {
217 if ( is_readable( $path ) ) {
218 $has_template = true;
219 break;
220 }
221 }
222
223 /**
224 * Filters the value of the result of the block template check.
225 *
226 * @since x.x.x
227 *
228 * @param boolean $has_template value to be filtered.
229 * @param string $template_name The name of the template.
230 */
231 return (bool) apply_filters( 'learnpress_has_block_template', $has_template, $template_name );
232 }
233
234 /**
235 * Set title of pages
236 *
237 * 1. Title course archive page
238 * 2. Title item of course
239 * 3. Title page Profile
240 *
241 * @param string $title
242 *
243 * @return string
244 * @author tungnx
245 * @since 3.2.7.7
246 */
247 public function set_title_pages( string $title = '' ): string {
248 global $wp_query;
249 $flag_title_course = false;
250
251 $course_archive_page_id = LP_Settings::instance()->get( 'courses_page_id', 0 );
252
253 // Set title course archive page
254 if ( ! empty( $course_archive_page_id ) && $wp_query->post &&
255 $course_archive_page_id == $wp_query->post->ID ) {
256 $title = get_the_title( $course_archive_page_id );
257 $flag_title_course = true;
258 } elseif ( learn_press_is_course() ) {
259 $item = LP_Global::course_item();
260 if ( $item ) {
261 $title = apply_filters( 'learn-press/document-course-title-parts', get_the_title() . ' &rarr; ' . $item->get_title(), $item );
262
263 $flag_title_course = true;
264 }
265 } elseif ( learn_press_is_courses() ) {
266 if ( learn_press_is_search() ) {
267 $title = __( 'Course Search Results', 'learnpress' );
268 } else {
269 $title = __( 'Courses', 'learnpress' );
270 }
271
272 $flag_title_course = true;
273 } elseif ( learn_press_is_profile() ) {
274 $profile = LP_Profile::instance();
275 $tab_slug = $profile->get_current_tab();
276 $tab = $profile->get_tab_at( $tab_slug );
277 $page_id = learn_press_get_page_id( 'profile' );
278
279 if ( $page_id ) {
280 $page_title = get_the_title( $page_id );
281 } else {
282 $page_title = '';
283 }
284 if ( $tab ) {
285 $title = join(
286 ' ',
287 apply_filters(
288 'learn-press/document-profile-title-parts',
289 array(
290 $page_title,
291 '&rarr;',
292 $tab['title'],
293 )
294 )
295 );
296 }
297
298 $flag_title_course = true;
299 }
300
301 if ( $flag_title_course ) {
302 $title .= ' - ' . get_bloginfo( 'name', 'display' );
303 }
304
305 return apply_filters( 'learn-press/title-page', $title );
306 }
307
308 /**
309 * Set description of course's item for yoast seo
310 *
311 * @param $desc
312 *
313 * @return mixed
314 * @author tungnx
315 * @since 3.2.7.9
316 */
317 public function lp_desc_item_yoast_seo( $desc ) {
318 if ( learn_press_is_course() ) {
319
320 $item = LP_Global::course_item();
321
322 if ( empty( $item ) ) {
323 return $desc;
324 }
325
326 $desc = get_post_meta( $item->get_id(), '_yoast_wpseo_metadesc', true );
327 }
328
329 return $desc;
330 }
331
332 public function check_pages( $template ) {
333 if ( learn_press_is_checkout() ) {
334 $available_gateways = LP_Gateways::instance()->get_available_payment_gateways();
335
336 if ( ! $available_gateways ) {
337 learn_press_add_message( __( 'No payment method is available.', 'learnpress' ), 'error' );
338 }
339 } else {
340 global $wp_query;
341
342 $logout_slug = learn_press_profile_logout_slug();
343
344 if ( $logout_slug && ( $wp_query->get( 'view' ) === $logout_slug ) ) {
345 wp_safe_redirect( str_replace( '&amp;', '&', wp_logout_url( learn_press_get_page_link( 'profile' ) ) ) );
346 exit;
347 }
348 }
349
350 return $template;
351 }
352
353 /**
354 * Auto inserting a registered shortcode to a specific page
355 * if that page is viewing in single mode.
356 *
357 * @param string $template
358 *
359 * @return string;
360 * @since 3.3.0
361 */
362 public function auto_shortcode( $template ) {
363 global $post;
364 $the_post = $post;
365 if ( $the_post && is_page( $the_post->ID ) ) {
366
367 // Filter here to insert the shortcode
368 $auto_shortcodes = apply_filters( 'learn-press/auto-shortcode-pages', array() );
369
370 if ( ! empty( $auto_shortcodes[ $the_post->ID ] ) ) {
371 $shortcode_tag = $auto_shortcodes[ $the_post->ID ];
372
373 preg_match( '/\[' . $shortcode_tag . '\s?(.*)\]/', $the_post->post_content, $results );
374
375 if ( empty( $results ) ) {
376 $content = $the_post->post_content . "[$shortcode_tag]";
377 $the_post->post_content = $content;
378 }
379 }
380 }
381
382 return $template;
383 }
384
385 /**
386 * Load data for item of course
387 *
388 * @param $post
389 *
390 * @return mixed
391 * @editor tungnx
392 * Todo: should remove this function when load true type post's item
393 */
394 public function setup_data_for_item_course( $post ): WP_Post {
395 /**
396 * @var WP $wp
397 * @var WP_Query $wp_query
398 * @var LP_Course $lp_course
399 * @var LP_Course_Item|LP_Quiz|LP_Lesson $lp_course_item
400 */
401 global $wp, $wp_query, $lp_course_item;
402
403 if ( LP_COURSE_CPT !== $post->post_type ) {
404 return $post;
405 }
406
407 $course = learn_press_get_course();
408 if ( ! $course ) {
409 return $post;
410 }
411
412 /**
413 * @deprecated v4.1.6.1 LP()->global['course'], $GLOBALS['course']
414 * Some theme still use: global $course; LP()->global['course']
415 */
416 //LP()->global['course'] = $GLOBALS['course'] = $GLOBALS['lp_course'] = $course;
417 LP()->global['course'] = $GLOBALS['course'] = $course;
418
419 if ( wp_verify_nonce( LP_Request::get( 'preview' ), 'preview-' . $post->ID ) ) {
420 $GLOBALS['preview_course'] = $post->ID;
421 }
422
423 $vars = $wp->query_vars;
424
425 if ( empty( $vars['course-item'] ) ) {
426 return $post;
427 }
428
429 if ( ! $wp_query->is_main_query() ) {
430 return $post;
431 }
432
433 try {
434 $user = learn_press_get_current_user();
435
436 // If item name is set in query vars
437 if ( ! is_numeric( $vars['course-item'] ) ) {
438 $item_type = $vars['item-type'];
439 $post_item = learn_press_get_post_by_name( $vars['course-item'], $item_type );
440 } else {
441 $post_item = get_post( absint( $vars['course-item'] ) );
442 }
443
444 if ( ! $post_item ) {
445 return $post;
446 }
447
448 $lp_course_item = apply_filters( 'learn-press/single-course-request-item', $course->get_item( $post_item->ID ) );
449
450 if ( ! $lp_course_item ) {
451 return $post;
452 }
453
454 // Set item viewing
455 $user->set_viewing_item( $lp_course_item );
456 } catch ( Exception $ex ) {
457 learn_press_add_message( $ex->getMessage(), 'error' );
458 }
459
460 return $post;
461 }
462
463 /**
464 * Set page 404
465 *
466 * @return mixed
467 * @editor tungnx
468 * @reason not use
469 * @deprecated 4.0.0
470 */
471 /*
472 public function set_404( $is_404 ) {
473 global $wp_query;
474 $wp_query->is_404 = $this->_is_404 = (bool) $is_404;
475 }*/
476
477 public function is_404() {
478 return apply_filters( 'learn-press/query/404', $this->_is_404 );
479 }
480
481 /**
482 * In preview mode, if there is a 'post_format' in query var
483 * wp check and replace our post-type to post. This make preview
484 * course item become 404
485 *
486 * @param $qv
487 *
488 * @return mixed
489 */
490 public function remove_course_post_format( $qv ) {
491 if ( ! empty( $qv['post_type'] ) && LP_COURSE_CPT === $qv['post_type'] ) {
492 if ( ! empty( $qv['post_format'] ) ) {
493 unset( $qv['post_format'] );
494 }
495 }
496
497 return $qv;
498 }
499
500 /**
501 * @return bool
502 */
503 protected function _is_archive() {
504 return learn_press_is_courses() || learn_press_is_course_tag() || learn_press_is_course_category() || learn_press_is_search() || learn_press_is_course_tax();
505 }
506
507 /**
508 * @return bool
509 */
510 protected function _is_single() {
511 return learn_press_is_course() && is_single();
512 }
513
514 /**
515 * Load content of course depending on query.
516 *
517 * @param string $template
518 *
519 * @return bool|string
520 */
521 public function template_loader( $template ) {
522
523 if ( is_embed() ) {
524 return $template;
525 }
526
527 // $this->_maybe_redirect_courses_page();
528
529 $default_template = $this->get_page_template();
530
531 if ( $default_template ) {
532 $templates = $this->get_page_templates( $default_template );
533
534 /**
535 * Disable override templates in theme by default since LP 4.0.0
536 */
537 if ( learn_press_override_templates() ) {
538 $new_template = locate_template( $templates );
539 }
540
541 if ( ! isset( $new_template ) || ! $new_template ) {
542 $new_template = LP_TEMPLATE_PATH . $default_template;
543 }
544
545 $template = $new_template;
546 }
547
548 return $template;
549 }
550
551 /**
552 * Get the default filename for a template.
553 *
554 * @return string
555 * @since 4.0.0
556 */
557 private function get_page_template() {
558 $page_template = '';
559
560 if ( is_singular( LP_COURSE_CPT ) ) {
561 if ( ! self::has_block_template( 'single-course' ) ) {
562 $page_template = 'single-course.php';
563 }
564
565 if ( $this->_is_single() ) {
566 global $post;
567 setup_postdata( $post );
568
569 $course_item = LP_Global::course_item();
570 if ( $course_item && ! self::has_block_template( 'content-single-course-item' ) ) {
571 $page_template = 'content-single-item.php';
572 }
573 }
574 } elseif ( learn_press_is_course_taxonomy() ) {
575 $object = get_queried_object();
576
577 if ( is_tax( 'course_category' ) || is_tax( 'course_tag' ) ) {
578 $page_template = 'taxonomy-' . $object->taxonomy . '.php';
579
580 if ( self::has_block_template( 'taxonomy-' . $object->taxonomy ) ) {
581 $page_template = '';
582 } elseif ( ! file_exists( learn_press_locate_template( $page_template ) ) && ! self::has_block_template( 'archive-course' ) ) {
583 $page_template = 'archive-course.php';
584 }
585 } elseif ( ! self::has_block_template( 'archive-course' ) ) {
586 $page_template = 'archive-course.php';
587 }
588 } elseif ( ( is_post_type_archive( LP_COURSE_CPT ) || ( ! empty( learn_press_get_page_id( 'courses' ) ) && is_page( learn_press_get_page_id( 'courses' ) ) ) ) && ! self::has_block_template( 'archive-course' ) ) {
589 $page_template = 'archive-course.php';
590 } elseif ( learn_press_is_checkout() && ! self::has_block_template( 'page-lp_checkout' ) ) {
591 $page_template = 'pages/checkout.php';
592 }
593
594 return apply_filters( 'learn-press/page-template', $page_template );
595 }
596
597 private function get_page_templates( $default_template ) {
598 $templates = apply_filters( 'learn-press/page-templates', array(), $default_template );
599
600 if ( is_page_template() ) {
601 $page_template = get_page_template_slug();
602
603 if ( $page_template ) {
604 $validated_file = validate_file( $page_template );
605 if ( 0 === $validated_file ) {
606 $templates[] = $page_template;
607 } else {
608 error_log( "LearnPress: Unable to validate template path: \"$page_template\". Error Code: $validated_file." );
609 }
610 }
611 }
612
613 if ( is_singular( LP_COURSE_CPT ) ) {
614 $object = get_queried_object();
615 $name_decoded = urldecode( $object->post_name );
616
617 if ( $name_decoded !== $object->post_name ) {
618 $templates[] = "single-course-$name_decoded.php";
619 }
620
621 $templates[] = "single-product-$object->post_name.php";
622 }
623
624 if ( learn_press_is_course_taxonomy() ) {
625 $object = get_queried_object();
626 $templates[] = 'taxonomy-' . $object->taxonomy . '-' . $object->slug . '.php';
627 $templates[] = learn_press_template_path( true ) . 'taxonomy-' . $object->taxonomy . '-' . $object->slug . '.php';
628 $templates[] = 'taxonomy-' . $object->taxonomy . '.php';
629 $templates[] = learn_press_template_path( true ) . 'taxonomy-' . $object->taxonomy . '.php';
630 }
631
632 $templates[] = $default_template;
633 $templates[] = learn_press_template_path( true ) . $default_template;
634
635 return array_unique( $templates );
636 }
637
638 /**
639 * Filter to allow search more templates in theme for wp page template hierarchy.
640 * Theme twentytwenty used 'singular.php' instead of 'page.php'
641 *
642 * @param array $templates
643 *
644 * @return array
645 * @since 3.x.x
646 * @depecated 4.1.6.9.2
647 */
648 /*public function page_template_hierarchy( $templates ) {
649 $templates = array_merge( $templates, array( 'singular.php' ) );
650
651 return $templates;
652 }*/
653
654 /**
655 * Archive course content.
656 *
657 * @return false|string
658 */
659 public function archive_content() {
660 ob_start();
661 learn_press_get_template( 'content-archive-course.php' );
662
663 return ob_get_clean();
664 }
665
666 /**
667 * @param $title
668 *
669 * @return mixed
670 */
671 public function page_title( $title ) {
672 global $wp_query;
673 if ( ! empty( $wp_query->queried_object_id ) ) {
674 $title['title'] = get_the_title( $wp_query->queried_object_id );
675 }
676
677 return $title;
678 }
679
680 /**
681 * Query courses if page is archive courses
682 *
683 * @param $q WP_Query
684 *
685 * @return WP_Query
686 * @editor tungnx
687 * @since 3.0.0
688 * @version 4.1.3
689 * @throws Exception
690 */
691 public function pre_get_posts( WP_Query $q ): WP_Query {
692 // Affect only the main query and not in admin
693 if ( ! $q->is_main_query() && ! is_admin() ) {
694 return $q;
695 }
696
697 try {
698 if ( LP_Page_Controller::page_current() === LP_PAGE_COURSES ) {
699 if ( ( LP_Settings_Courses::is_ajax_load_courses() && ! LP_Settings_Courses::is_no_load_ajax_first_courses() ) ) {
700 LP()->template( 'course' )->remove_callback( 'learn-press/after-courses-loop', 'loop/course/pagination.php', 10 );
701 /**
702 * If page is archive course - query set posts_per_page = 1
703 * For fastest - because when page loaded - call API to load list courses
704 *
705 * Current, apply only for LP, not apply for theme Thimpress, because theme override
706 */
707 $q->set( 'posts_per_page', 1 );
708 $q->set( 'posts_per_archive_page', 1 );
709 $q->set( 'nopaging', true );
710 } else {
711 $filter = new LP_Course_Filter();
712 $filter->only_fields = [ 'ID' ];
713 $filter->limit = -1;
714 $is_need_check_in_arr = false;
715 $limit = LP_Settings::get_option( 'archive_course_limit', 6 );
716
717 $q->set( 'posts_per_page', $limit );
718 // $q->set( 'cache_results', true ); // it default true
719
720 // Search courses by keyword
721 // $q->set( 's', $_REQUEST['c_search'] ?? '' );
722 if ( ! empty( $_REQUEST['c_search'] ) ) {
723 $filter->post_title = LP_Helper::sanitize_params_submitted( $_REQUEST['c_search'] );
724 $is_need_check_in_arr = true;
725 }
726
727 $author_ids_str = LP_Helper::sanitize_params_submitted( $_REQUEST['c_authors'] ?? 0 );
728 if ( ! empty( $author_ids_str ) ) {
729 $q->set( 'author', $author_ids_str );
730 }
731
732 // Meta query
733 $meta_query = [];
734 if ( isset( $_REQUEST['sort_by'] ) ) {
735 $sort_by = LP_Helper::sanitize_params_submitted( $_REQUEST['sort_by'] );
736 if ( 'on_paid' === $sort_by ) {
737 $meta_query[] = array(
738 'key' => '_lp_price',
739 'value' => 0,
740 'compare' => '>',
741 );
742 }
743
744 if ( 'on_free' === $sort_by ) {
745 $meta_query[] = array(
746 'key' => '_lp_price',
747 'value' => 0,
748 'compare' => '=',
749 );
750 }
751 }
752 $q->set( 'meta_query', $meta_query );
753 // End Meta query
754
755 // Tax query
756 $tax_query = [];
757 $term_ids_str = LP_Helper::sanitize_params_submitted( urldecode( $_REQUEST['term_id'] ?? '' ) );
758 if ( ! empty( $term_ids_str ) ) {
759 $term_ids = explode( ',', $term_ids_str );
760
761 $tax_query[] = array(
762 'taxonomy' => 'course_category',
763 'field' => 'term_id',
764 'terms' => $term_ids,
765 'operator' => 'IN',
766 );
767 }
768
769 $q->set( 'tax_query', $tax_query );
770 // End Tax query
771
772 // Author query
773 if ( isset( $_REQUEST['c_author'] ) ) {
774 $author_ids = LP_Helper::sanitize_params_submitted( $_REQUEST['c_author'] );
775 $q->set( 'author__in', $author_ids );
776 }
777 // End Author query
778
779 // Order query
780 if ( isset( $_REQUEST['order_by'] ) ) {
781 $order_by = LP_Helper::sanitize_params_submitted( $_REQUEST['order_by'] );
782 $order = 'DESC';
783
784 switch ( $order_by ) {
785 case 'post_title':
786 $order_by = 'title';
787 $order = 'ASC';
788 break;
789 case 'popular':
790 $filter->order_by = 'popular';
791 $order_by = 'post__in';
792 $is_need_check_in_arr = true;
793 break;
794 default:
795 $order_by = 'date';
796 break;
797 }
798
799 $q->set( 'orderby', $order_by );
800 $q->set( 'order', $order );
801 }
802
803 if ( $is_need_check_in_arr ) {
804 $posts_in = LP_Course::get_courses( $filter );
805 if ( ! empty( $posts_in ) ) {
806 $posts_in = LP_Database::get_values_by_key( $posts_in );
807 $q->set( 'post__in', $posts_in );
808 } else {
809 $q->set( 'post__in', 0 );
810 }
811 }
812
813 $q = apply_filters( 'lp/page-courses/query/legacy', $q );
814 }
815
816 return $q;
817 }
818
819 // Exclude item not assign
820 if ( $q->is_search() ) {
821 // Exclude item not assign any course
822 $course_item_types = learn_press_get_course_item_types();
823 $list_ids_exclude = array();
824
825 foreach ( $course_item_types as $item_type ) {
826 $filter = new LP_Post_Type_Filter();
827 $filter->post_type = $item_type;
828 $exclude_item = LP_Course_DB::getInstance()->get_item_ids_unassigned( $filter );
829 $exclude_item = LP_Course_DB::get_values_by_key( $exclude_item );
830
831 $list_ids_exclude = array_merge( $list_ids_exclude, $exclude_item );
832 }
833
834 // Exclude question not assign any quiz
835 $question_ids = LP_Question_DB::getInstance()->get_questions_not_assign_quiz();
836 $question_ids = LP_Course_DB::get_values_by_key( $question_ids );
837 $list_ids_exclude = array_merge( $list_ids_exclude, $question_ids );
838
839 if ( ! empty( $list_ids_exclude ) ) {
840 $q->set( 'post__not_in', $list_ids_exclude );
841 }
842
843 return $q;
844 }
845
846 // Handle 404 if user are viewing course item directly.
847 $this->set_link_item_course_default_wp_to_page_404( $q );
848 } catch ( Throwable $e ) {
849 error_log( $e->getMessage() );
850 }
851
852 return $q;
853 }
854
855 /**
856 * Handle 404 if user are viewing course item directly.
857 * Example: http://example.com/lesson/slug-lesson
858 * Apply for user not admin, instructor, co-instructor
859 *
860 * @param WP_Query $q
861 * @editor tungnx
862 * @since 3.2.7.5
863 */
864 public function set_link_item_course_default_wp_to_page_404( $q ) {
865 $post_type_apply_404 = apply_filters( 'lp/page-controller/', array( LP_LESSON_CPT, LP_QUIZ_CPT, LP_QUESTION_CPT, 'lp_assignment' ) );
866
867 if ( ! isset( $q->query_vars['post_type'] ) || ! in_array( $q->query_vars['post_type'], $post_type_apply_404 ) ) {
868 return $q;
869 }
870
871 try {
872 $flag_load_404 = true;
873 $user = wp_get_current_user();
874 $post_author = 0;
875
876 if ( $user ) {
877 if ( isset( $_GET['preview_id'] ) ) {
878 $post_id = absint( $_GET['preview_id'] );
879 $post = get_post( $post_id );
880 $post_author = $post->post_author;
881 } elseif ( isset( $_GET['preview'] ) && isset( $_GET['p'] ) ) {
882 $post_id = absint( $_GET['p'] );
883 $post = get_post( $post_id );
884 $post_author = $post->post_author;
885 } else {
886 $post_author = LP_Database::getInstance()->getPostAuthorByTypeAndSlug( $q->query_vars['post_type'] ?? '', $q->query_vars['name'] ?? '' );
887 }
888
889 if ( $user->has_cap( 'administrator' ) ) {
890 $flag_load_404 = false;
891 } elseif ( $user->has_cap( LP_TEACHER_ROLE ) && $post_author == $user->ID ) {
892 $flag_load_404 = false;
893 }
894 }
895
896 $flag_load_404 = apply_filters( 'learnpress/page/set-link-item-course-404', $flag_load_404, $post_author, $user );
897
898 if ( $flag_load_404 ) {
899 learn_press_404_page();
900 }
901 } catch ( Throwable $e ) {
902 error_log( $e->getMessage() );
903 }
904 }
905
906 /**
907 * @depecated 4.1.6.9.2
908 */
909 /*public function the_content_callback( $content ) {
910 if ( $this->_archive_contents ) {
911 preg_match( '/\[learn_press_archive_course\s?(.*)\]/', $content, $results );
912 $this->_shortcode_exists = ! empty( $results );
913 if ( $this->_shortcode_exists ) {
914 $this->_shortcode_tag = $results[0];
915 $content = str_replace( $this->_shortcode_tag, $this->_archive_contents, $content );
916 } else {
917 $content .= $this->_archive_contents;
918 }
919 }
920
921 return $content;
922 }*/
923
924 /**
925 * Check is page Become a teacher
926 *
927 * @return bool|mixed|void
928 * @since 3.2.8
929 * @author tungnx
930 */
931 public static function is_page_become_a_teacher() {
932 $page_id = learn_press_get_page_id( 'become_a_teacher' );
933
934 if ( $page_id && is_page( $page_id ) ) {
935 return true;
936 }
937
938 return apply_filters( 'learnpress/is-page/become-a-teacher', false );
939 }
940
941 /**
942 * Get page current on frontend
943 *
944 * @return string
945 * @since 3.2.8
946 * @author tungnx
947 */
948 public static function page_current(): string {
949 /**
950 * @var WP_Query $wp_query
951 */
952 global $wp_query;
953
954 if ( ! is_object( $wp_query ) || ! $wp_query->get_queried_object() ) {
955 return '';
956 }
957
958 if ( learn_press_is_checkout() ) {
959 return LP_PAGE_CHECKOUT;
960 } elseif ( LP_Global::course_item_quiz() ) {
961 return LP_PAGE_QUIZ;
962 } elseif ( learn_press_is_course() && LP_Global::course_item() ) {
963 return LP_PAGE_SINGLE_COURSE_CURRICULUM;
964 } elseif ( learn_press_is_courses() ) {
965 return LP_PAGE_COURSES;
966 } elseif ( learn_press_is_course() ) {
967 return LP_PAGE_SINGLE_COURSE;
968 } elseif ( self::is_page_become_a_teacher() ) {
969 return LP_PAGE_BECOME_A_TEACHER;
970 } elseif ( learn_press_is_profile() ) {
971 return LP_PAGE_PROFILE;
972 } else {
973 return apply_filters( 'learnpress/page/current', '' );
974 }
975 }
976
977 public static function instance() {
978 if ( is_admin() ) {
979 return null;
980 }
981
982 if ( ! self::$_instance ) {
983 self::$_instance = new self();
984 }
985
986 return self::$_instance;
987 }
988
989 /**
990 * Add user profile link into admin bar
991 *
992 * @editor tungnx
993 * @version 1.0.1
994 * @since 3.0.0
995 */
996 public function learn_press_edit_admin_bar() {
997 global $wp_admin_bar;
998
999 $current_user = wp_get_current_user();
1000
1001 if ( ! in_array( LP_TEACHER_ROLE, $current_user->roles ) && ! in_array( 'administrator', $current_user->roles ) ) {
1002 return;
1003 }
1004
1005 $page_profile_id = learn_press_get_page_id( 'profile' );
1006
1007 if ( $page_profile_id && get_post_status( $page_profile_id ) != 'trash' ) {
1008 $user_id = $current_user->ID;
1009
1010 $wp_admin_bar->add_menu(
1011 array(
1012 'id' => 'course_profile',
1013 'parent' => 'user-actions',
1014 'title' => get_the_title( $page_profile_id ),
1015 'href' => learn_press_user_profile_link( $user_id, false ),
1016 )
1017 );
1018 }
1019 }
1020
1021 /**
1022 * Set again HTTP_X_WP_NONCE when cache make 403 error.
1023 *
1024 * @param $send_no_cache_headers
1025 *
1026 * @return mixed
1027 * @since 4.1.7
1028 * @version 1.0.0
1029 */
1030 public function check_x_wp_nonce_cache( $send_no_cache_headers ) {
1031 if ( ! $send_no_cache_headers && ! is_admin() && $_SERVER['REQUEST_METHOD'] == 'GET' && LP_Helper::isRestApiLP() ) {
1032 $nonce = wp_create_nonce( 'wp_rest' );
1033 $_SERVER['HTTP_X_WP_NONCE'] = $nonce;
1034 }
1035
1036 return $send_no_cache_headers;
1037 }
1038 }
1039
1040 return LP_Page_Controller::instance();
1041