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

1,326 lines 34.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 use LearnPress\CourseBuilder\CourseBuilder;
4 use LearnPress\Helpers\Template;
5 use LearnPress\Models\CourseModel;
6 use LearnPress\Models\Courses;
7 use LearnPress\Models\UserModel;
8
9 /**
10 * Class LP_Page_Controller
11 */
12 class LP_Page_Controller {
13 protected static $_instance = null;
14
15 /**
16 * Store the object has queried by WP.
17 *
18 * @var int
19 */
20 //protected $_queried_object = 0;
21
22 /**
23 * @var int
24 */
25 //protected $_filter_content_priority = 10000;
26
27 /**
28 * Flag for 404 content.
29 *
30 * @var bool
31 */
32 protected $_is_404 = false;
33
34 /**
35 * LP_Page_Controller constructor.
36 */
37 protected function __construct() {
38 // Set link course, item course.
39 add_filter( 'post_type_link', array( $this, 'post_type_link' ), 10, 2 );
40
41 if ( LP_Page_Controller::is_page_lp_ajax() ) {
42 if ( ! isset( $_REQUEST['lp-load-ajax'] ) ) {
43 wp_die( 'Invalid request!', 400 );
44 }
45 }
46
47 if ( is_admin() ) {
48 add_action( 'admin_init', [ $this, 'redirect_admin_to_course_builder' ] );
49 } else {
50 //add_filter( 'post_type_archive_link', [ $this, 'link_archive_course' ], 10, 2 );
51 add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ), - 1 );
52 // For debug mysql query post of WP.
53 /*add_filter(
54 'posts_request',
55 function ( $request, $q ) {
56 LP_Debug::var_dump( $request );
57 return $request;
58 },
59 10,
60 2
61 );*/
62 /*add_filter(
63 'posts_clauses_request',
64 function ( $clauses, $wp_query ) {
65 if ( ! $wp_query->is_search() ) {
66 return $clauses;
67 }
68
69 $lp_db = LP_Database::getInstance();
70 $clauses['where'] .= sprintf( " OR ( post_type = '%s' AND meta_key = '_lp_preview' AND meta_value = 'yes')", LP_LESSON_CPT );
71 $clauses['join'] .= ' INNER JOIN ' . $lp_db->tb_postmeta . ' ON post_id = wp_posts.ID ';
72
73 return $clauses;
74 },
75 10,
76 2
77 );*/
78 // For return result query course to cache.
79 //add_action( 'posts_pre_query', [ $this, 'posts_pre_query' ], 10, 2 );
80 add_filter( 'template_include', array( $this, 'template_loader' ), 10 );
81 add_filter( 'template_include', array( $this, 'logout' ), 30 );
82 add_action( 'template_redirect', array( $this, 'template_redirect' ), -1 );
83
84 add_filter( 'the_post', array( $this, 'setup_data_for_item_course' ) );
85 add_filter( 'request', array( $this, 'remove_course_post_format' ), 1 );
86
87 //add_shortcode( 'learn_press_archive_course', array( $this, 'archive_content' ) );
88 add_filter( 'pre_get_document_title', array( $this, 'set_title_pages' ), 10, 1 );
89
90 // Yoast seo
91 add_filter( 'wpseo_opengraph_desc', array( $this, 'lp_desc_item_yoast_seo' ), 11, 1 );
92 add_filter( 'wpseo_metadesc', array( $this, 'lp_desc_item_yoast_seo' ), 11, 1 );
93
94 // Set link profile to admin menu
95 //add_action( 'admin_bar_menu', array( $this, 'learn_press_edit_admin_bar' ) );
96
97 // Set again x-wp-nonce on header when has cache with not login.
98 add_filter( 'rest_send_nocache_headers', array( $this, 'check_x_wp_nonce_cache' ) );
99
100 // Rewrite lesson comment links
101 add_filter( 'get_comment_link', array( $this, 'edit_lesson_comment_links' ), 10, 2 );
102 // Active menu
103 add_filter( 'wp_nav_menu_objects', [ $this, 'menu_active' ], 10, 1 );
104 // Canonical
105 add_filter(
106 'get_canonical_url',
107 function ( $canonical_url ) {
108 if ( LP_Page_Controller::is_page_instructor() ) {
109 $canonical_url = LP_Helper::getUrlCurrent();
110 }
111
112 return $canonical_url;
113 }
114 );
115 }
116
117 // Disable create sitemap for items type of Course.
118 add_filter(
119 'wp_sitemaps_post_types',
120 function ( $post_types ) {
121 $item_types = CourseModel::item_types_support();
122 $item_types[] = LP_QUESTION_CPT;
123 foreach ( $item_types as $item_type ) {
124 if ( isset( $post_types[ $item_type ] ) ) {
125 unset( $post_types[ $item_type ] );
126 }
127 }
128
129 return $post_types;
130 }
131 );
132
133 /**
134 * Disable create sitemap for YoastSEO, Rank Math, but can affect to all logic, ex: it makes link edit of items course lose.
135 *
136 * @var WP_Post_Type $post_type
137 */
138 /*add_filter(
139 'is_post_type_viewable',
140 function ( $is_viewable, $post_type ) {
141 $item_types = CourseModel::item_types_support();
142 $item_types[] = LP_QUESTION_CPT;
143 if ( in_array( $post_type->name, $item_types ) ) {
144 $is_viewable = false;
145 }
146
147 return $is_viewable;
148 },
149 10,
150 2
151 );*/
152 }
153
154 /**
155 * Set link archive course.
156 *
157 * @param string $link
158 * @param string $post_type
159 *
160 * @return string
161 */
162 public function link_archive_course( string $link, string $post_type ): string {
163 if ( $post_type == LP_COURSE_CPT && learn_press_get_page_id( 'courses' ) ) {
164 $link = learn_press_get_page_link( 'courses' );
165 }
166
167 return $link;
168 }
169
170 /**
171 * Set link course, item course
172 *
173 * @param string $post_link
174 * @param object $post
175 */
176 public function post_type_link( $post_link, $post ) {
177 // Set item's course permalink
178 $course_item_types = CourseModel::item_types_support();
179 $item_id = $post->ID;
180
181 // Link item course on search page of WP.
182 if ( in_array( $post->post_type, $course_item_types ) && is_search() ) {
183 $section_id = LP_Section_DB::getInstance()->get_section_id_by_item_id( $item_id );
184 if ( ! $section_id ) {
185 return $post_link;
186 }
187
188 $course_id = LP_Section_DB::getInstance()->get_course_id_by_section( $section_id );
189 if ( ! $course_id ) {
190 return $post_link;
191 }
192
193 $course = learn_press_get_course( $course_id );
194 if ( ! $course ) {
195 return $post_link;
196 }
197
198 $post_link = $course->get_item_link( $item_id );
199 } elseif ( LP_COURSE_CPT === $post->post_type ) {
200 // Link single course (with %course_category%).
201 $post_link = LP_Helper::handle_lp_permalink_structure( $post_link, $post );
202 }
203
204 return $post_link;
205 }
206
207 /**
208 * Set title of pages
209 *
210 * 1. Title course archive page
211 * 2. Title item of course
212 * 3. Title page Profile
213 *
214 * @param string $title
215 *
216 * @return string
217 * @throws Exception
218 * @since 3.2.7.7
219 * @version 1.0.2
220 * @author tungnx
221 */
222 public function set_title_pages( $title = '' ): string {
223 $flag_title_course = false;
224 $user_id = get_current_user_id();
225
226 $course_archive_page_id = LP_Settings::get_option( 'courses_page_id', 0 );
227
228 // Set title single course.
229 if ( learn_press_is_course() ) {
230 $item = LP_Global::course_item();
231 if ( $item ) {
232 $title = apply_filters( 'learn-press/document-course-title-parts', get_the_title() . ' &rarr; ' . $item->get_title(), $item );
233
234 $flag_title_course = true;
235 }
236 } elseif ( LP_Page_Controller::is_page_courses() ) { // Set title course archive page.
237 if ( isset( $_GET['c_search'] ) ) {
238 $title = __( 'Course Search Results', 'learnpress' );
239 } elseif ( is_tax( LP_COURSE_CATEGORY_TAX ) || is_tax( LP_COURSE_TAXONOMY_TAG ) ) {
240 /**
241 * @var WP_Query $wp_query
242 */
243 global $wp_query;
244 if ( $wp_query->queried_object ) {
245 $title = $wp_query->queried_object->name;
246 }
247 } else {
248 $title = $course_archive_page_id ? get_the_title( $course_archive_page_id ) : __( 'Courses', 'learnpress' );
249 }
250
251 $flag_title_course = true;
252 } elseif ( LP_Page_Controller::is_page_profile() ) {
253 $userModel = UserModel::find( get_current_user_id(), true );
254 $profile = LP_Profile::instance( $user_id );
255 $page_id = learn_press_get_page_id( 'profile' );
256 $tab = false;
257 if ( $userModel ) {
258 $tab_slug = $profile->get_current_tab();
259 $tab = $profile->get_tab_at( $tab_slug );
260 }
261
262 if ( $page_id ) {
263 $page_title = get_the_title( $page_id );
264 } else {
265 $page_title = '';
266 }
267
268 if ( $tab instanceof LP_Profile_Tab ) {
269 $title = join(
270 ' ',
271 apply_filters(
272 'learn-press/document-profile-title-parts',
273 array(
274 $page_title,
275 '&rarr;',
276 $tab->get( 'title' ),
277 )
278 )
279 );
280 } else {
281 $title = $page_title;
282 }
283
284 $flag_title_course = true;
285 }
286
287 if ( $flag_title_course ) {
288 $title .= ' - ' . get_bloginfo( 'name', 'display' );
289 }
290
291 if ( ! is_string( $title ) ) {
292 $title = get_bloginfo( 'name', 'display' );
293 }
294
295 return apply_filters( 'learn-press/title-page', $title );
296 }
297
298 /**
299 * Set description of course's item for yoast seo
300 *
301 * @param $desc
302 *
303 * @return mixed
304 * @author tungnx
305 * @since 3.2.7.9
306 */
307 public function lp_desc_item_yoast_seo( $desc ) {
308 if ( learn_press_is_course() ) {
309
310 $item = LP_Global::course_item();
311
312 if ( empty( $item ) ) {
313 return $desc;
314 }
315
316 $desc = get_post_meta( $item->get_id(), '_yoast_wpseo_metadesc', true );
317 }
318
319 return $desc;
320 }
321
322 /**
323 * Handle logout
324 */
325 public function logout( $template ) {
326 global $wp_query;
327
328 $logout_slug = learn_press_profile_logout_slug();
329
330 if ( $logout_slug && ( $wp_query->get( 'view' ) === $logout_slug ) ) {
331 wp_safe_redirect( str_replace( '&amp;', '&', wp_logout_url( learn_press_get_page_link( 'profile' ) ) ) );
332 exit;
333 }
334
335 return $template;
336 }
337
338 /**
339 * Load data for item of course
340 *
341 * @param $post
342 *
343 * @return mixed
344 * @editor tungnx
345 * Todo: should remove this function when load true type post's item
346 */
347 public function setup_data_for_item_course( $post ): WP_Post {
348 /**
349 * @var WP $wp
350 * @var WP_Query $wp_query
351 * @var LP_Course $lp_course
352 * @var LP_Course_Item|LP_Quiz|LP_Lesson $lp_course_item
353 */
354 global $wp, $wp_query, $lp_course_item;
355 $vars = $wp->query_vars;
356 if ( empty( $vars['course-item'] ) ) {
357 return $post;
358 }
359
360 if ( LP_COURSE_CPT !== $post->post_type ) {
361 return $post;
362 }
363
364 $course = learn_press_get_course();
365 if ( ! $course ) {
366 return $post;
367 }
368
369 /**
370 * Use for case not load course via send params, use global instead.
371 * Not recommended for use
372 * This method is only purpose instead get_the_ID(), on file item of course.
373 * When all file write by standard callback send param courseModel, this method will be removed.
374 *
375 * @return false|CourseModel
376 * @since 4.2.7.4
377 */
378 global $lpCourseModel;
379 $lpCourseModel = CourseModel::find( $course->get_id(), true );
380
381 /**
382 * @deprecated v4.1.6.1 LearnPress::instance()->global['course'], $GLOBALS['course']
383 * Some theme still use: global $course; LearnPress::instance()->global['course']
384 */
385 //LearnPress::instance()->global['course'] = $GLOBALS['course'] = $GLOBALS['lp_course'] = $course;
386 LearnPress::instance()->global['course'] = $GLOBALS['course'] = $course;
387
388 if ( wp_verify_nonce( LP_Request::get_param( 'preview' ), 'preview-' . $post->ID ) ) {
389 $GLOBALS['preview_course'] = $post->ID;
390 }
391
392 if ( ! $wp_query->is_main_query() ) {
393 return $post;
394 }
395
396 try {
397 $user = learn_press_get_current_user();
398
399 // If item name is set in query vars
400 $item_type = $vars['item-type'];
401 $post_item = learn_press_get_post_by_name( $vars['course-item'], $item_type );
402
403 if ( ! $post_item ) {
404 return $post;
405 }
406
407 $lp_course_item = apply_filters( 'learn-press/single-course-request-item', $course->get_item( $post_item->ID ) );
408
409 if ( ! $lp_course_item ) {
410 return $post;
411 }
412
413 // Set item viewing
414 $user->set_viewing_item( $lp_course_item );
415 } catch ( Throwable $e ) {
416 error_log( $e->getMessage() );
417 }
418
419 return $post;
420 }
421
422 public function is_404() {
423 return apply_filters( 'learn-press/query/404', $this->_is_404 );
424 }
425
426 /**
427 * In preview mode, if there is a 'post_format' in query var
428 * wp check and replace our post-type to post. This make preview
429 * course item become 404
430 *
431 * @param $qv
432 *
433 * @return mixed
434 */
435 public function remove_course_post_format( $qv ) {
436 if ( ! empty( $qv['post_type'] ) && LP_COURSE_CPT === $qv['post_type'] ) {
437 if ( ! empty( $qv['post_format'] ) ) {
438 unset( $qv['post_format'] );
439 }
440 }
441
442 return $qv;
443 }
444
445 /**
446 * @return bool
447 * @deprecated v4.2.7.6
448 */
449 protected function _is_archive() {
450 _deprecated_function( __METHOD__, '4.1.7.3' );
451 return false;
452 return learn_press_is_courses() || learn_press_is_course_tag() || learn_press_is_course_category() || learn_press_is_search() || learn_press_is_course_tax();
453 }
454
455 /**
456 * @return bool
457 * @deprecated v4.2.7.6
458 */
459 protected function _is_single() {
460 _deprecated_function( __METHOD__, '4.1.7.3' );
461 return false;
462 return learn_press_is_course() && is_single();
463 }
464
465 /**
466 * Load content of course depending on query.
467 *
468 * @param string $template
469 *
470 * @return bool|string
471 */
472 public function template_loader( $template ) {
473 if ( wp_is_block_theme() ) {
474 return $template;
475 }
476
477 if ( is_embed() ) {
478 return $template;
479 }
480
481 // $this->_maybe_redirect_courses_page();
482
483 $default_template = $this->get_page_template();
484
485 if ( $default_template ) {
486 $templates = $this->get_page_templates( $default_template );
487
488 /**
489 * Disable override templates in theme by default since LP 4.0.0
490 */
491 if ( learn_press_override_templates() ) {
492 $new_template = locate_template( $templates );
493 }
494
495 if ( ! isset( $new_template ) || ! $new_template ) {
496 $new_template = LP_TEMPLATE_PATH . $default_template;
497 }
498
499 $template = $new_template;
500 }
501
502 return $template;
503 }
504
505 /**
506 * Check if current page is Course Builder
507 */
508 public function template_redirect() {
509 if ( LP_Page_Controller::is_page_course_builder() ) {
510 include LP_TEMPLATE_PATH . 'pages/course-builder.php';
511 die;
512 }
513 }
514
515 /**
516 * Get the default filename for a template.
517 *
518 * @return string
519 * @since 4.0.0
520 */
521 private function get_page_template() {
522 $page_template = '';
523 $object = get_queried_object();
524
525 if ( self::is_page_single_course() ) {
526 $page_template = 'single-course-layout.php';
527 // Check condition to load single course layout classic or modern.
528 $is_override_single_course = Template::check_template_is_override( 'single-course.php' )
529 || Template::check_template_is_override( 'content-course.php' )
530 || Template::check_template_is_override( 'content-single-course.php' )
531 || Template::check_template_is_override( 'loop/single-course/loop-section.php' )
532 || Template::check_template_is_override( 'single-course/loop-section.php' )
533 || Template::check_template_is_override( 'single-course/tabs/curriculum.php' )
534 || Template::check_template_is_override( 'single-course/tabs/curriculum-v2.php' );
535 $option_single_course_layout = LP_Settings::get_option( 'layout_single_course', '' );
536
537 if ( $is_override_single_course ) { // Old file template
538 $page_template = 'single-course.php';
539 } elseif ( empty( $option_single_course_layout )
540 || $option_single_course_layout === 'classic' ) {
541 $page_template = 'single-course-layout-classic.php';
542 // Set temporary old single course layout.
543 $page_template = 'single-course.php';
544 }
545
546 // Old single course layout.
547 //$page_template = 'single-course.php';
548
549 global $post;
550 setup_postdata( $post );
551
552 $course_item = LP_Global::course_item();
553 if ( $course_item ) {
554 $page_template = 'content-single-item.php';
555 } elseif ( $object ) {
556 $course = CourseModel::find( $object->ID, true );
557 if ( $course && $course->is_offline() ) {
558 $page_template = 'single-course-offline.php';
559 }
560 }
561 } elseif ( learn_press_is_course_taxonomy() ) {
562 if ( is_tax( 'course_category' ) || is_tax( 'course_tag' ) ) {
563 $page_template = 'taxonomy-' . $object->taxonomy . '.php';
564
565 if ( ! file_exists( learn_press_locate_template( $page_template ) ) ) {
566 $page_template = 'archive-course.php';
567 }
568 } else {
569 $page_template = 'archive-course.php';
570 }
571 } elseif ( self::is_page_courses() ) {
572 $page_template = 'archive-course.php';
573 } elseif ( learn_press_is_checkout() ) {
574 $page_template = 'pages/checkout.php';
575 }
576
577 return apply_filters( 'learn-press/page-template', $page_template );
578 }
579
580 private function get_page_templates( $default_template ) {
581 $templates = apply_filters( 'learn-press/page-templates', array(), $default_template );
582
583 if ( is_page_template() ) {
584 $page_template = get_page_template_slug();
585
586 if ( $page_template ) {
587 $validated_file = validate_file( $page_template );
588 if ( 0 === $validated_file ) {
589 $templates[] = $page_template;
590 } else {
591 error_log( "LearnPress: Unable to validate template path: \"$page_template\". Error Code: $validated_file." );
592 }
593 }
594 }
595
596 /*if ( is_singular( LP_COURSE_CPT ) ) {
597 $object = get_queried_object();
598 $name_decoded = urldecode( $object->post_name );
599
600 if ( $name_decoded !== $object->post_name ) {
601 $templates[] = "single-course-$name_decoded.php";
602 }
603
604 $templates[] = "single-product-$object->post_name.php";
605 }*/
606
607 if ( learn_press_is_course_taxonomy() ) {
608 $object = get_queried_object();
609 $templates[] = 'taxonomy-' . $object->taxonomy . '-' . $object->slug . '.php';
610 $templates[] = learn_press_template_path() . '/taxonomy-' . $object->taxonomy . '-' . $object->slug . '.php';
611 $templates[] = 'taxonomy-' . $object->taxonomy . '.php';
612 $templates[] = learn_press_template_path() . '/taxonomy-' . $object->taxonomy . '.php';
613 }
614
615 $templates[] = $default_template;
616 $templates[] = learn_press_template_path() . '/' . $default_template;
617
618 return array_unique( $templates );
619 }
620
621 /**
622 * @param $title
623 *
624 * @return mixed
625 */
626 public function page_title( $title ) {
627 global $wp_query;
628 if ( ! empty( $wp_query->queried_object_id ) ) {
629 $title['title'] = get_the_title( $wp_query->queried_object_id );
630 }
631
632 return $title;
633 }
634
635 /**
636 * Query courses if page is archive courses
637 *
638 * @param $q WP_Query
639 *
640 * @return WP_Query
641 * @editor tungnx
642 * @throws Exception
643 * @version 4.1.3
644 * @since 3.0.0
645 */
646 public function pre_get_posts( WP_Query $q ): WP_Query {
647 // Affect only the main query and not in admin
648 if ( ! $q->is_main_query() && ! is_admin() ) {
649 return $q;
650 }
651
652 try {
653 if ( LP_Page_Controller::is_page_courses() ) {
654 if ( LP_Settings_Courses::is_ajax_load_courses() && ! LP_Settings_Courses::is_no_load_ajax_first_courses()
655 && ! LP_Settings::theme_no_support_load_courses_ajax() ) {
656 /**
657 * If page is archive course - query set posts_per_page = 1
658 * For fastest - because when page loaded - call API to load list courses
659 *
660 * Current, apply only for LP, not apply for theme Thimpress, because theme override
661 */
662 $q->set( 'posts_per_page', 1 );
663 $q->set( 'suppress_filters', true );
664 //$q->set( 'posts_per_archive_page', 1 );
665 //$q->set( 'nopaging', true );
666 } else {
667 $filter = new LP_Course_Filter();
668 $filter->only_fields = [ 'ID' ];
669 $filter->limit = - 1;
670 $is_need_check_in_arr = false;
671 $limit = LP_Settings::get_option( 'archive_course_limit', 6 );
672
673 if ( LP_Settings_Courses::is_ajax_load_courses() &&
674 LP_Settings_Courses::get_type_pagination() != 'number' &&
675 ! LP_Settings::theme_no_support_load_courses_ajax() ) {
676 $q->set( 'paged', 1 );
677 }
678
679 $q->set( 'posts_per_page', $limit );
680 // $q->set( 'cache_results', true ); // it default true
681
682 // Search courses by keyword
683 if ( ! empty( $_REQUEST['c_search'] ) ) {
684 $filter->post_title = LP_Helper::sanitize_params_submitted( $_REQUEST['c_search'] );
685 $is_need_check_in_arr = true;
686 }
687
688 $author_ids_str = LP_Helper::sanitize_params_submitted( $_REQUEST['c_authors'] ?? 0 );
689 if ( ! empty( $author_ids_str ) ) {
690 $q->set( 'author', $author_ids_str );
691 }
692
693 // Search course has price/free
694 $meta_query = [];
695 if ( isset( $_REQUEST['sort_by'] ) ) {
696 $sort_by = LP_Helper::sanitize_params_submitted( $_REQUEST['sort_by'] );
697 if ( 'on_paid' === $sort_by ) {
698 $meta_query[] = array(
699 'key' => '_lp_price',
700 'value' => 0,
701 'compare' => '>',
702 );
703 }
704
705 if ( 'on_free' === $sort_by ) {
706 $meta_query[] = array(
707 'relation' => 'OR',
708 [
709 'key' => '_lp_price',
710 'value' => 0,
711 'compare' => '=',
712 ],
713 [
714 'key' => '_lp_price',
715 'value' => '',
716 'compare' => '=',
717 ],
718 [
719 'key' => '_lp_price',
720 'compare' => 'NOT EXISTS',
721 ],
722 );
723 }
724 }
725
726 // Search by level
727 $c_level = LP_Helper::sanitize_params_submitted( urldecode( $_REQUEST['c_level'] ?? '' ) );
728 if ( ! empty( $c_level ) ) {
729 $c_level = str_replace( 'all', '', $c_level );
730 $c_level = explode( ',', $c_level );
731 $meta_query[] = array(
732 'key' => '_lp_level',
733 'value' => $c_level,
734 'compare' => 'IN',
735 );
736 }
737
738 $q->set( 'meta_query', $meta_query );
739 // End Meta query
740
741 // Search on Category
742 $args_cat = lp_archive_skeleton_get_args();
743 $tax_query = [];
744 $term_ids_str = LP_Helper::sanitize_params_submitted(
745 urldecode( $_REQUEST['term_id'] ?? $args_cat['page_term_id_current'] ?? '' )
746 );
747 if ( ! empty( $term_ids_str ) ) {
748 $term_ids = explode( ',', $term_ids_str );
749
750 $tax_query[] = array(
751 'taxonomy' => 'course_category',
752 'field' => 'term_id',
753 'terms' => $term_ids,
754 'operator' => 'IN',
755 'include_children' => false,
756 );
757 }
758
759 // Tag query
760 $tag_ids_str = LP_Helper::sanitize_params_submitted( urldecode( $_REQUEST['tag_id'] ?? '' ) );
761 if ( ! empty( $tag_ids_str ) ) {
762 $term_ids = explode( ',', $tag_ids_str );
763
764 $tax_query[] = array(
765 'taxonomy' => 'course_tag',
766 'field' => 'term_id',
767 'terms' => $term_ids,
768 'operator' => 'IN',
769 );
770 }
771
772 $q->set( 'tax_query', $tax_query );
773 // End Tax query
774
775 // Author query
776 if ( isset( $_REQUEST['c_author'] ) ) {
777 $author_ids = LP_Helper::sanitize_params_submitted( $_REQUEST['c_author'] );
778 $q->set( 'author__in', $author_ids );
779 }
780 // End Author query
781
782 // Order query
783 if ( isset( $_REQUEST['order_by'] ) ) {
784 $order_by = LP_Helper::sanitize_params_submitted( $_REQUEST['order_by'] );
785 $order = 'DESC';
786
787 switch ( $order_by ) {
788 case 'post_title':
789 $order_by = 'title';
790 $order = 'ASC';
791 break;
792 case 'popular':
793 $filter->order_by = 'popular';
794 $order_by = 'post__in';
795 $is_need_check_in_arr = true;
796 break;
797 default:
798 $order_by = 'date';
799 break;
800 }
801
802 $q->set( 'orderby', $order_by );
803 $q->set( 'order', $order );
804 }
805
806 if ( $is_need_check_in_arr ) {
807 $posts_in = Courses::get_courses( $filter );
808 if ( ! empty( $posts_in ) ) {
809 $posts_in = LP_Database::get_values_by_key( $posts_in );
810 $q->set( 'post__in', $posts_in );
811 } else {
812 $q->set( 'post__in', 0 );
813 }
814 }
815
816 $q = apply_filters( 'lp/page-courses/query/legacy', $q );
817 }
818
819 return $q;
820 }
821
822 // Exclude item not assign
823 if ( $q->is_search() ) {
824 return $q;
825 }
826
827 // Handle 404 if user are viewing course item directly.
828 $this->set_link_item_course_default_wp_to_page_404( $q );
829
830 // set 404 if viewing single instructor but not logged
831 $slug_instructor = get_query_var( 'instructor_name' );
832 if ( get_query_var( 'is_single_instructor' ) ) {
833 if ( empty( $slug_instructor ) && ! is_user_logged_in() ) {
834 self::set_page_404();
835 }
836 }
837 } catch ( Throwable $e ) {
838 error_log( $e->getMessage() );
839 }
840
841 return $q;
842 }
843
844 /**
845 * Handle 404 if user are viewing course item directly.
846 * Example: http://example.com/lesson/slug-lesson
847 * Apply for user not admin, instructor, co-instructor
848 *
849 * @param WP_Query $q
850 *
851 * @editor tungnx
852 * @since 3.2.7.5
853 */
854 public function set_link_item_course_default_wp_to_page_404( $q ) {
855 $post_type_apply_404 = apply_filters(
856 'lp/page-controller/',
857 array(
858 LP_LESSON_CPT,
859 LP_QUIZ_CPT,
860 LP_QUESTION_CPT,
861 'lp_assignment',
862 )
863 );
864
865 if ( ! isset( $q->query_vars['post_type'] ) || ! in_array( $q->query_vars['post_type'], $post_type_apply_404 ) ) {
866 return;
867 }
868
869 try {
870 $flag_load_404 = true;
871 $user = wp_get_current_user();
872 $post_author = 0;
873
874 if ( $user ) {
875 if ( isset( $_GET['preview_id'] ) ) {
876 $post_id = absint( $_GET['preview_id'] );
877 $post = get_post( $post_id );
878 $post_author = $post->post_author;
879 } elseif ( isset( $_GET['preview'] ) && isset( $_GET['p'] ) ) {
880 $post_id = absint( $_GET['p'] );
881 $post = get_post( $post_id );
882 $post_author = $post->post_author;
883 } else {
884 $post_author = LP_Database::getInstance()->getPostAuthorByTypeAndSlug( $q->query_vars['post_type'] ?? '', $q->query_vars['name'] ?? '' );
885 }
886
887 if ( $user->has_cap( 'administrator' ) ) {
888 $flag_load_404 = false;
889 } elseif ( $user->has_cap( LP_TEACHER_ROLE ) && $post_author == $user->ID ) {
890 $flag_load_404 = false;
891 }
892 }
893
894 $flag_load_404 = apply_filters( 'learnpress/page/set-link-item-course-404', $flag_load_404, $post_author, $user );
895
896 if ( $flag_load_404 ) {
897 self::set_page_404();
898 }
899 } catch ( Throwable $e ) {
900 error_log( $e->getMessage() );
901 }
902 }
903
904 /**
905 * Get page current on frontend
906 *
907 * @return string
908 * @since 3.2.8
909 * @author tungnx
910 */
911 public static function page_current(): string {
912 /**
913 * @var WP_Query $wp_query
914 */
915 global $wp_query;
916
917 // Course Builder page detection
918 if ( self::is_page_course_builder() ) {
919 return LP_PAGE_COURSE_BUILDER;
920 }
921
922 if ( ! is_object( $wp_query ) || ! $wp_query->get_queried_object() ) {
923 return '';
924 }
925
926 if ( self::is_page_checkout() ) {
927 return LP_PAGE_CHECKOUT;
928 } elseif ( LP_Global::course_item_quiz() ) {
929 return LP_PAGE_QUIZ;
930 } elseif ( learn_press_is_course() && LP_Global::course_item() ) {
931 return LP_PAGE_SINGLE_COURSE_CURRICULUM;
932 } elseif ( self::is_page_courses() ) {
933 return LP_PAGE_COURSES;
934 } elseif ( learn_press_is_course() ) {
935 return LP_PAGE_SINGLE_COURSE;
936 } elseif ( self::is_page_become_a_teacher() ) {
937 return LP_PAGE_BECOME_A_TEACHER;
938 } elseif ( self::is_page_profile() ) {
939 return LP_PAGE_PROFILE;
940 } elseif ( learn_press_is_instructors() ) {
941 return LP_PAGE_INSTRUCTORS;
942 } elseif ( self::is_page_instructor() ) {
943 return LP_PAGE_INSTRUCTOR;
944 } else {
945 return apply_filters( 'learnpress/page/current', '' );
946 }
947 }
948
949 /**
950 * Check is page viewing
951 *
952 * @param string $name
953 *
954 * @return bool
955 */
956 public static function page_is( string $name = '' ): bool {
957 $page_id = learn_press_get_page_id( $name );
958 if ( ! $page_id || 'page' !== get_post_type( $page_id ) ) {
959 return false;
960 }
961
962 // If pages of LP set to homepage will return false
963 $link_page = urldecode( get_the_permalink( $page_id ) );
964 $home_url = home_url( '/' );
965 if ( $home_url === $link_page ) {
966 return false;
967 }
968
969 $page_profile_option = untrailingslashit( $link_page );
970 $page_profile_option = str_replace( '/', '\/', $page_profile_option );
971 $pattern = "/^$page_profile_option/";
972 if ( preg_match( $pattern, LP_Helper::getUrlCurrent() ) ) {
973 return true;
974 }
975
976 return false;
977 }
978
979 /**
980 * Check is page is single course
981 *
982 * @since 4.2.7.6
983 * @version 1.0.0
984 * @return bool
985 */
986 public static function is_page_single_course(): bool {
987 static $flag;
988 if ( ! is_null( $flag ) ) {
989 return $flag;
990 }
991
992 try {
993 $flag = is_singular( LP_COURSE_CPT );
994 } catch ( Throwable $e ) {
995 $flag = false;
996 }
997
998 return $flag;
999 }
1000
1001 /**
1002 * Check is page courses
1003 *
1004 * @return bool
1005 */
1006 public static function is_page_courses(): bool {
1007 static $flag;
1008 if ( ! is_null( $flag ) ) {
1009 return $flag;
1010 }
1011
1012 $is_tag = is_tax( LP_COURSE_TAXONOMY_TAG );
1013 $is_category = is_tax( LP_COURSE_CATEGORY_TAX );
1014
1015 if ( $is_category || $is_tag || is_post_type_archive( 'lp_course' ) ) {
1016 $flag = true;
1017 } else {
1018 $page_courses_id = learn_press_get_page_id( 'courses' );
1019 $page_courses_url = untrailingslashit( get_the_permalink( $page_courses_id ) );
1020 if ( empty( $page_courses_url ) ) {
1021 $page_courses_url = home_url( 'courses' );
1022 }
1023
1024 $page_courses_regex = str_replace( '/', '\/', $page_courses_url );
1025 $pattern = '/' . $page_courses_regex . '\/?(page\/[0-9]*)?$/';
1026 if ( preg_match( $pattern, LP_Helper::getUrlCurrent() ) ) {
1027 $flag = true;
1028 } else {
1029 $flag = false;
1030 }
1031 }
1032
1033 return $flag;
1034 }
1035
1036 /**
1037 * Check is page profile
1038 *
1039 * @return bool
1040 */
1041 public static function is_page_profile(): bool {
1042 static $flag;
1043 if ( ! is_null( $flag ) ) {
1044 return $flag;
1045 }
1046
1047 $flag = self::page_is( 'profile' );
1048
1049 return $flag;
1050 }
1051
1052 /**
1053 * Check is page instructor
1054 *
1055 * @return bool
1056 */
1057 public static function is_page_instructors(): bool {
1058 static $flag;
1059 if ( ! is_null( $flag ) ) {
1060 return $flag;
1061 }
1062
1063 $flag = self::page_is( 'instructors' );
1064
1065 return $flag;
1066 }
1067
1068 /**
1069 * Check is page instructor
1070 *
1071 * @return bool
1072 */
1073 public static function is_page_instructor(): bool {
1074 global $wp_query;
1075 static $flag;
1076 if ( ! is_null( $flag ) ) {
1077 return $flag;
1078 }
1079
1080 $flag = false;
1081 if ( $wp_query->get( 'is_single_instructor' ) ) {
1082 $flag = true;
1083 }
1084
1085 return $flag;
1086 }
1087
1088 /**
1089 * Check is page profile
1090 *
1091 * @return bool
1092 */
1093 public static function is_page_checkout(): bool {
1094 return self::page_is( 'checkout' );
1095 }
1096
1097 /**
1098 * Check is page Become a teacher
1099 *
1100 * @return bool
1101 * @since 3.2.8
1102 * @author tungnx
1103 */
1104 public static function is_page_become_a_teacher(): bool {
1105 return self::page_is( 'become_a_teacher' );
1106 }
1107
1108 /**
1109 * Check page is LP Ajax
1110 *
1111 * @return bool
1112 * @since 4.2.7.7
1113 */
1114 public static function is_page_lp_ajax(): bool {
1115 // If pages of LP set to homepage will return false
1116 $pattern = '/lp-ajax-handle/';
1117 if ( preg_match( $pattern, LP_Helper::getUrlCurrent() ) ) {
1118 return true;
1119 }
1120
1121 return false;
1122 }
1123
1124 /**
1125 * Redirect admin to course builder if hide instructor access admin screen
1126 *
1127 * @since 4.3.6
1128 * @version 1.0.0
1129 */
1130 public function redirect_admin_to_course_builder() {
1131 // Skip AJAX requests
1132 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1133 return;
1134 }
1135
1136 // Check hide instructor access admin screen
1137 $hide_instructor_access_admin_screen = LP_Settings::is_hide_instructor_access_admin_screen();
1138 if ( $hide_instructor_access_admin_screen
1139 && current_user_can( UserModel::ROLE_INSTRUCTOR ) ) {
1140 $cb_url = CourseBuilder::get_link_course_builder();
1141
1142 // Avoid infinite redirect
1143 if ( strpos( LP_Helper::getUrlCurrent(), $cb_url ) !== false ) {
1144 return;
1145 }
1146
1147 wp_redirect( $cb_url );
1148 exit;
1149 }
1150 }
1151
1152 public static function is_page_course_builder(): bool {
1153 /** @var WP_Query $wp_query */
1154 global $wp_query;
1155 return $wp_query->get( 'is_course_builder' );
1156 }
1157
1158 /**
1159 * Get link page by name
1160 *
1161 * @param string $page_name
1162 * @param array $args
1163 * @param bool $no_cache
1164 *
1165 * @return string
1166 * @since 4.2.7.8
1167 * @version 1.0.0
1168 */
1169 public static function get_link_page( string $page_name, array $args = [], bool $no_cache = false ): string {
1170 $page_link = learn_press_get_page_link( $page_name );
1171
1172 if ( ! empty( $args ) ) {
1173 $page_link = add_query_arg( $args, $page_link );
1174 }
1175
1176 if ( $no_cache ) {
1177 $page_link = LP_Helper::get_link_no_cache( $page_link );
1178 }
1179
1180 return $page_link;
1181 }
1182
1183 public static function instance() {
1184 if ( ! self::$_instance ) {
1185 self::$_instance = new self();
1186 }
1187
1188 return self::$_instance;
1189 }
1190
1191 /**
1192 * Add user profile link into admin bar
1193 *
1194 * @editor tungnx
1195 * @version 1.0.1
1196 * @since 3.0.0
1197 * @deprecated 4.1.7.3
1198 */
1199 public function learn_press_edit_admin_bar() {
1200 _deprecated_function( __METHOD__, '4.1.7.3' );
1201 return;
1202
1203 global $wp_admin_bar;
1204
1205 $current_user = wp_get_current_user();
1206
1207 if ( ! in_array( LP_TEACHER_ROLE, $current_user->roles ) && ! in_array( 'administrator', $current_user->roles ) ) {
1208 return;
1209 }
1210
1211 $page_profile_id = learn_press_get_page_id( 'profile' );
1212 if ( $page_profile_id && get_post_status( $page_profile_id ) != 'trash' ) {
1213 $user_id = $current_user->ID;
1214 $profile = LP_Profile::instance( $user_id );
1215
1216 $wp_admin_bar->add_menu(
1217 array(
1218 'id' => 'course_profile',
1219 'parent' => 'user-actions',
1220 'title' => get_the_title( $page_profile_id ),
1221 'href' => $profile->get_tab_link(),
1222 )
1223 );
1224 }
1225 }
1226
1227 /**
1228 * Set again HTTP_X_WP_NONCE when cache make 403 error.
1229 *
1230 * @param $send_no_cache_headers
1231 *
1232 * @return mixed
1233 * @since 4.1.7
1234 * @version 1.0.0
1235 */
1236 public function check_x_wp_nonce_cache( $send_no_cache_headers ) {
1237 if ( ! $send_no_cache_headers && ! is_admin() && $_SERVER['REQUEST_METHOD'] == 'GET' && LP_Helper::isRestApiLP() ) {
1238 $nonce = wp_create_nonce( 'wp_rest' );
1239 $_SERVER['HTTP_X_WP_NONCE'] = $nonce;
1240 }
1241
1242 return $send_no_cache_headers;
1243 }
1244
1245 /**
1246 * Override lesson comment permalink.
1247 *
1248 * @param string $link The comment permalink with '#comment-$id' appended.
1249 * @param WP_Comment $comment The current comment object.
1250 *
1251 * @return string $link The comment permalink with '#comment-$id' appended.
1252 * @since 4.2.3
1253 * @version 1.0.0
1254 */
1255 public function edit_lesson_comment_links( $link, $comment ): string {
1256 try {
1257 $comment = get_comment( $comment );
1258 if ( get_post_type( $comment->comment_post_ID ) == LP_LESSON_CPT ) {
1259 $link = wp_get_referer() . '#comment-' . $comment->comment_ID;
1260 }
1261
1262 return $link;
1263 } catch ( Throwable $e ) {
1264 error_log( $e->getMessage() );
1265 }
1266
1267 return $link;
1268 }
1269
1270 /**
1271 * Set menu active for page courses.
1272 *
1273 * @param $menu_items
1274 *
1275 * @return mixed
1276 */
1277 public function menu_active( $menu_items ) {
1278 $course_page = learn_press_get_page_id( 'courses' );
1279 $page_for_posts = (int) get_option( 'page_for_posts' );
1280
1281 if ( is_array( $menu_items ) && ! empty( $menu_items ) ) {
1282 foreach ( $menu_items as $key => $menu_item ) {
1283 $classes = (array) $menu_item->classes;
1284 $menu_id = (int) $menu_item->object_id;
1285
1286 // Unset active class for blog page.
1287 if ( $page_for_posts === $menu_id ) {
1288 $menu_item->current = false;
1289
1290 if ( in_array( 'current_page_parent', $classes, true ) ) {
1291 unset( $classes[ array_search( 'current_page_parent', $classes, true ) ] );
1292 }
1293
1294 if ( in_array( 'current-menu-item', $classes, true ) ) {
1295 unset( $classes[ array_search( 'current-menu-item', $classes, true ) ] );
1296 }
1297 } elseif ( ( is_post_type_archive( 'lp_course' ) || is_page( $course_page ) ) && $course_page === $menu_id && 'page' === $menu_item->object ) {
1298 // Set active state if this is the shop page link.
1299 $menu_item->current = true;
1300 $classes[] = 'current-menu-item';
1301 $classes[] = 'current_page_item';
1302 } elseif ( is_singular( 'lp_course' ) && $course_page === $menu_id ) {
1303 // Set parent state if this is a product page.
1304 $classes[] = 'current_page_parent';
1305 }
1306
1307 $menu_item->classes = array_unique( $classes );
1308 $menu_items[ $key ] = $menu_item;
1309 }
1310 }
1311
1312 return $menu_items;
1313 }
1314
1315 /**
1316 * Set Page viewing to 404
1317 *
1318 * @return void
1319 */
1320 public static function set_page_404() {
1321 global $wp_query;
1322 $wp_query->set_404();
1323 status_header( 404 );
1324 }
1325 }
1326