PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.8
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.8
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
← All changes | inc/class-lp-page-controller.php +1325 -1325 4.3.9.14.4.8 View file →
@@ -1,1325 +1,1325 @@
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 -}
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 +}