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 / class-lp-page-controller.php

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

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