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

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

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