| 1 |
<?php |
| 2 |
|
| 3 |
/** |
| 4 |
* Class LP_Query |
| 5 |
* |
| 6 |
* @version 4.2.2.3 |
| 7 |
*/ |
| 8 |
|
| 9 |
use LearnPress\CourseBuilder\CourseBuilder; |
| 10 |
|
| 11 |
defined( 'ABSPATH' ) || exit; |
| 12 |
|
| 13 |
class LP_Query { |
| 14 |
/** |
| 15 |
* LP_Query constructor. |
| 16 |
*/ |
| 17 |
public function __construct() { |
| 18 |
// Not run in REST API LP, or heartbeat of WP |
| 19 |
if ( LP_Helper::isRestApiLP() || isset( $_POST['action'] ) && 'heartbeat' === $_POST['action'] ) { |
| 20 |
return; |
| 21 |
} |
| 22 |
|
| 23 |
add_action( 'init', array( $this, 'add_rewrite_tags' ) ); |
| 24 |
add_action( 'init', array( $this, 'add_rewrite_endpoints' ) ); |
| 25 |
add_filter( 'option_rewrite_rules', [ $this, 'update_option_rewrite_rules' ], 1 ); |
| 26 |
} |
| 27 |
|
| 28 |
/** |
| 29 |
* Parses request params and controls page |
| 30 |
* |
| 31 |
* @param WP_Query $q |
| 32 |
* |
| 33 |
* @return mixed |
| 34 |
*/ |
| 35 |
/*public function parse_request( $q ) { |
| 36 |
if ( did_action( 'learn_press_parse_query' ) ) { |
| 37 |
return $q; |
| 38 |
} |
| 39 |
|
| 40 |
do_action_ref_array( 'learn_press_parse_query', array( &$this ) ); |
| 41 |
|
| 42 |
return $q; |
| 43 |
}*/ |
| 44 |
|
| 45 |
/** |
| 46 |
* Add custom rewrite tags |
| 47 |
*/ |
| 48 |
public function add_rewrite_tags() { |
| 49 |
$tags = [ |
| 50 |
'%course-item%' => '([^&]+)', |
| 51 |
'%item-type%' => '([^&]+)', |
| 52 |
'%question%' => '([^&]+)', |
| 53 |
'%user%' => '([^/]*)', |
| 54 |
'%view%' => '([^/]*)', |
| 55 |
'%view_id%' => '(.*)', |
| 56 |
'%section%' => '(.*)', |
| 57 |
'%content-item-only%' => '(.*)', |
| 58 |
'%is_single_instructor%' => '(.*)', |
| 59 |
'%instructor_name%' => '(.*)', |
| 60 |
// For Course builder |
| 61 |
'%' . CourseBuilder::QUERY_VAR_MENU_SLUG . '%' => '([^/]*)', |
| 62 |
'%' . CourseBuilder::QUERY_VAR_ITEM_ID . '%' => '(.*)', |
| 63 |
'%' . CourseBuilder::QUERY_VAR_IS_COURSE_BUILDER . '%' => '(.*)', |
| 64 |
]; |
| 65 |
|
| 66 |
$tags = apply_filters( 'learn-press/rewrite/tags', $tags ); |
| 67 |
foreach ( $tags as $tag => $regex ) { |
| 68 |
add_rewrite_tag( $tag, $regex ); |
| 69 |
} |
| 70 |
} |
| 71 |
|
| 72 |
/** |
| 73 |
* Add custom rewrite endpoints |
| 74 |
*/ |
| 75 |
public function add_rewrite_endpoints() { |
| 76 |
$settings = LP_Settings::instance(); |
| 77 |
|
| 78 |
$endpoints = $settings->get_checkout_endpoints(); |
| 79 |
if ( $endpoints ) { |
| 80 |
foreach ( $endpoints as $endpoint => $value ) { |
| 81 |
LearnPress::instance()->query_vars[ $endpoint ] = $value; |
| 82 |
add_rewrite_endpoint( $value, EP_PAGES ); |
| 83 |
} |
| 84 |
} |
| 85 |
|
| 86 |
$endpoints = $settings->get_profile_endpoints(); |
| 87 |
if ( $endpoints ) { |
| 88 |
foreach ( $endpoints as $endpoint => $value ) { |
| 89 |
LearnPress::instance()->query_vars[ $endpoint ] = $value; |
| 90 |
add_rewrite_endpoint( $value, EP_PAGES ); |
| 91 |
} |
| 92 |
} |
| 93 |
|
| 94 |
$endpoints = $settings->get_course_builder_endpoints(); |
| 95 |
if ( $endpoints ) { |
| 96 |
foreach ( $endpoints as $endpoint => $value ) { |
| 97 |
LearnPress::instance()->query_vars[ $endpoint ] = $value; |
| 98 |
add_rewrite_endpoint( $value, EP_PAGES ); |
| 99 |
} |
| 100 |
} |
| 101 |
|
| 102 |
$endpoints = $settings->get( 'quiz_endpoints' ); |
| 103 |
if ( $endpoints ) { |
| 104 |
foreach ( $endpoints as $endpoint => $value ) { |
| 105 |
$endpoint = preg_replace( '!_!', '-', $endpoint ); |
| 106 |
LearnPress::instance()->query_vars[ $endpoint ] = $value; |
| 107 |
add_rewrite_endpoint( |
| 108 |
$value, /*EP_ROOT | */ |
| 109 |
EP_PAGES |
| 110 |
); |
| 111 |
} |
| 112 |
} |
| 113 |
|
| 114 |
add_rewrite_endpoint( 'lp-ajax-handle', EP_ROOT | EP_PAGES ); |
| 115 |
|
| 116 |
// Code temporary to fix 404 of order receiver page |
| 117 |
if ( LP_Page_Controller::is_page_checkout() ) { |
| 118 |
flush_rewrite_rules(); |
| 119 |
} |
| 120 |
} |
| 121 |
|
| 122 |
/** |
| 123 |
* Add lp rewrite rules |
| 124 |
* Format [key_parent][single_key] = [rule => match] |
| 125 |
* |
| 126 |
* link item course |
| 127 |
* link profile |
| 128 |
* @return array |
| 129 |
* @version 1.0.4 |
| 130 |
* @modify 4.2.2 |
| 131 |
* @since 3.0.0 |
| 132 |
*/ |
| 133 |
public function add_rewrite_rules(): array { |
| 134 |
$rules = array(); |
| 135 |
|
| 136 |
try { |
| 137 |
$course_item_slugs = LP_Settings::get_course_items_slug(); |
| 138 |
$course_slug = LP_Settings::get_permalink_single_course(); |
| 139 |
// For permalink has %course_category% |
| 140 |
if ( preg_match( '!%course_category%!', $course_slug ) ) { |
| 141 |
if ( ! preg_match( '!page!', LP_Helper::getUrlCurrent() ) ) { |
| 142 |
$course_slug = preg_replace( '!%course_category%!', '([^/]+)/([^/]+)', $course_slug ); |
| 143 |
|
| 144 |
// Rule single course |
| 145 |
$rules['single-course-with-cat'][] = [ |
| 146 |
"^{$course_slug}/?$" => |
| 147 |
'index.php?' . LP_COURSE_CPT . '=$matches[2]&course_category=$matches[1]', |
| 148 |
]; |
| 149 |
|
| 150 |
// Rule single item |
| 151 |
foreach ( $course_item_slugs as $post_type => $course_item_slug ) { |
| 152 |
$rules['course-with-cat-items'][ $post_type ] = [ |
| 153 |
"^{$course_slug}(?:/{$course_item_slug}/([^/]+))/?$" => |
| 154 |
'index.php?' . LP_COURSE_CPT . '=$matches[2]&course_category=$matches[1]&course-item=$matches[3]&item-type=' . $post_type, |
| 155 |
]; |
| 156 |
} |
| 157 |
} |
| 158 |
} else { |
| 159 |
// Rule single course |
| 160 |
$rules['single-course'][] = [ |
| 161 |
"^{$course_slug}/([^/]+)/?$" => |
| 162 |
'index.php?' . LP_COURSE_CPT . '=$matches[1]', |
| 163 |
]; |
| 164 |
|
| 165 |
// Rule single item |
| 166 |
foreach ( $course_item_slugs as $post_type => $course_item_slug ) { |
| 167 |
$rules['course-items'][ $post_type ] = [ |
| 168 |
"^{$course_slug}/([^/]+)(?:/{$course_item_slug}/([^/]+))/?$" => |
| 169 |
'index.php?' . LP_COURSE_CPT . '=$matches[1]&course-item=$matches[2]&item-type=' . $post_type, |
| 170 |
]; |
| 171 |
} |
| 172 |
} |
| 173 |
|
| 174 |
// Profile |
| 175 |
$this->add_rewrite_rules_profile( $rules ); |
| 176 |
|
| 177 |
// Instructor detail |
| 178 |
$single_instructor_page_id = learn_press_get_page_id( 'single_instructor' ); |
| 179 |
$instructor_slug = get_post_field( 'post_name', $single_instructor_page_id ); |
| 180 |
$rules['instructor']['has_name'] = [ |
| 181 |
"^{$instructor_slug}/([^/]+)/?(?:page/)?([^/][0-9]*)?/?$" => |
| 182 |
'index.php?page_id=' . $single_instructor_page_id . '&is_single_instructor=1&instructor_name=$matches[1]&paged=$matches[2]', |
| 183 |
]; |
| 184 |
$rules['instructor']['no_name'] = [ |
| 185 |
"^{$instructor_slug}/?$" => |
| 186 |
'index.php?page_id=' . $single_instructor_page_id . '&is_single_instructor=1&paged=$matches[2]', |
| 187 |
]; |
| 188 |
|
| 189 |
// For handle request lp-ajax |
| 190 |
$rules['lp-ajax'][] = [ |
| 191 |
'^lp-ajax-handle/?$' => 'index.php', |
| 192 |
]; |
| 193 |
|
| 194 |
// Course builder |
| 195 |
$this->add_rewrite_rules_course_builder( $rules ); |
| 196 |
|
| 197 |
$rules = apply_filters( 'learn-press/rewrite/rules', $rules ); |
| 198 |
} catch ( Throwable $e ) { |
| 199 |
error_log( $e->getMessage() ); |
| 200 |
} |
| 201 |
|
| 202 |
return $rules; |
| 203 |
} |
| 204 |
|
| 205 |
/** |
| 206 |
* Add rewrite rules for profile page. |
| 207 |
* |
| 208 |
* @param $rules |
| 209 |
* |
| 210 |
* @return void |
| 211 |
*/ |
| 212 |
public function add_rewrite_rules_profile( &$rules ) { |
| 213 |
// Profile |
| 214 |
$profile_id = learn_press_get_page_id( 'profile' ); |
| 215 |
if ( $profile_id ) { |
| 216 |
// Rule view profile of user (self or another) |
| 217 |
$page_profile_slug = urldecode( get_post_field( 'post_name', $profile_id ) ); |
| 218 |
$rules['profile']['user'] = [ |
| 219 |
"^{$page_profile_slug}/([^/]*)/?$" => |
| 220 |
"index.php?page_id={$profile_id}&user=" . '$matches[1]', |
| 221 |
]; |
| 222 |
|
| 223 |
// Rule view profile of user (self or another) with tab |
| 224 |
$tabs = LP_Profile::get_tabs_arr(); |
| 225 |
if ( $tabs ) { |
| 226 |
foreach ( $tabs as $tab_key => $args ) { |
| 227 |
$tab_slug = $args['slug'] ?? $tab_key; |
| 228 |
$rules['profile'][ $tab_key ] = [ |
| 229 |
"^{$page_profile_slug}/([^/]*)/({$tab_slug})/?([0-9]*)/?$" => |
| 230 |
'index.php?page_id=' . $profile_id . '&user=$matches[1]&view=$matches[2]&view_id=$matches[3]', |
| 231 |
]; |
| 232 |
|
| 233 |
if ( ! empty( $args['sections'] ) ) { |
| 234 |
foreach ( $args['sections'] as $section_key => $section ) { |
| 235 |
$section_slug = $section['slug'] ?? $section_key; |
| 236 |
$rules['profile'][ $section_key ] = [ |
| 237 |
"^{$page_profile_slug}/([^/]*)/({$tab_slug})/({$section_slug})/?([0-9]*)?$" => |
| 238 |
'index.php?page_id=' . $profile_id . '&user=$matches[1]&view=$matches[2]§ion=$matches[3]&view_id=$matches[4]', |
| 239 |
]; |
| 240 |
} |
| 241 |
} |
| 242 |
} |
| 243 |
} |
| 244 |
|
| 245 |
apply_filters( 'learn-press/rewrite-rules/profile', $rules['profile'], $profile_id ); |
| 246 |
} |
| 247 |
} |
| 248 |
|
| 249 |
/** |
| 250 |
* Add rewrite rules for profile page. |
| 251 |
* |
| 252 |
* @param $rules |
| 253 |
* |
| 254 |
* @return void |
| 255 |
*/ |
| 256 |
public function add_rewrite_rules_course_builder( &$rules ) { |
| 257 |
// Course Builder |
| 258 |
$page = LP_Settings::get_option( 'course_builder', 'course-builder' ); |
| 259 |
$menus = CourseBuilder::get_menus_arr(); |
| 260 |
$key_rule = 'course-builder'; |
| 261 |
|
| 262 |
if ( $menus ) { |
| 263 |
$rules[ $key_rule ]['home'] = [ |
| 264 |
"^{$page}/?$" => 'index.php?is_course_builder=1', |
| 265 |
]; |
| 266 |
|
| 267 |
foreach ( $menus as $menu_slug => $args ) { |
| 268 |
$rules[ $key_rule ][ $menu_slug . '_create' ] = [ |
| 269 |
"^{$page}/({$menu_slug})/(?:create)/?$" => |
| 270 |
sprintf( |
| 271 |
'index.php?%s=1&%s=%s&%s=new', |
| 272 |
CourseBuilder::QUERY_VAR_IS_COURSE_BUILDER, |
| 273 |
CourseBuilder::QUERY_VAR_MENU_SLUG, |
| 274 |
$menu_slug, |
| 275 |
CourseBuilder::QUERY_VAR_ITEM_ID |
| 276 |
), |
| 277 |
]; |
| 278 |
|
| 279 |
$rules[ $key_rule ][ $menu_slug . '_pagination' ] = [ |
| 280 |
"^{$page}/{$menu_slug}/(?:page)/?([0-9]*)/?$" => |
| 281 |
sprintf( |
| 282 |
'index.php?%s=1&%s=%s&paged=$matches[1]', |
| 283 |
CourseBuilder::QUERY_VAR_IS_COURSE_BUILDER, |
| 284 |
CourseBuilder::QUERY_VAR_MENU_SLUG, |
| 285 |
$menu_slug |
| 286 |
), |
| 287 |
]; |
| 288 |
|
| 289 |
$rules[ $key_rule ][ $menu_slug ] = [ |
| 290 |
"^{$page}/{$menu_slug}/?([0-9]*)/?$" => |
| 291 |
sprintf( |
| 292 |
'index.php?%s=1&%s=%s&%s=$matches[1]', |
| 293 |
CourseBuilder::QUERY_VAR_IS_COURSE_BUILDER, |
| 294 |
CourseBuilder::QUERY_VAR_MENU_SLUG, |
| 295 |
$menu_slug, |
| 296 |
CourseBuilder::QUERY_VAR_ITEM_ID |
| 297 |
), |
| 298 |
]; |
| 299 |
|
| 300 |
if ( empty( $args['sub_menu'] ) || ! is_array( $args['sub_menu'] ) ) { |
| 301 |
continue; |
| 302 |
} |
| 303 |
|
| 304 |
foreach ( $args['sub_menu'] as $sub_menu_slug => $sub_menu_args ) { |
| 305 |
if ( is_array( $sub_menu_args ) && ! empty( $sub_menu_args['slug'] ) ) { |
| 306 |
$sub_menu_slug = $sub_menu_args['slug']; |
| 307 |
} |
| 308 |
|
| 309 |
if ( ! is_string( $sub_menu_slug ) || '' === $sub_menu_slug ) { |
| 310 |
continue; |
| 311 |
} |
| 312 |
|
| 313 |
$rules[ $key_rule ][ $menu_slug . '_' . $sub_menu_slug ] = [ |
| 314 |
"^{$page}/{$menu_slug}/{$sub_menu_slug}/?$" => |
| 315 |
sprintf( |
| 316 |
'index.php?%s=1&%s=%s&%s=%s', |
| 317 |
CourseBuilder::QUERY_VAR_IS_COURSE_BUILDER, |
| 318 |
CourseBuilder::QUERY_VAR_MENU_SLUG, |
| 319 |
$menu_slug, |
| 320 |
CourseBuilder::QUERY_VAR_ITEM_ID, |
| 321 |
$sub_menu_slug |
| 322 |
), |
| 323 |
]; |
| 324 |
} |
| 325 |
} |
| 326 |
} |
| 327 |
|
| 328 |
apply_filters( 'learn-press/rewrite-rules/course-builder', $rules[ $key_rule ], $page ); |
| 329 |
} |
| 330 |
|
| 331 |
/** |
| 332 |
* @param string $join |
| 333 |
* |
| 334 |
* @return string |
| 335 |
* @deprecated 4.2.6.6 |
| 336 |
*/ |
| 337 |
/*public function join_term( $join ) { |
| 338 |
global $wp_query, $wpdb; |
| 339 |
|
| 340 |
if ( ! empty( $wp_query->query_vars['s'] ) && ! is_admin() ) { |
| 341 |
if ( ! preg_match( '/' . $wpdb->term_relationships . '/', $join ) ) { |
| 342 |
$join .= "LEFT JOIN $wpdb->term_relationships ON $wpdb->posts.ID = $wpdb->term_relationships.object_id "; |
| 343 |
} |
| 344 |
$join .= "LEFT JOIN $wpdb->term_taxonomy ON $wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id "; |
| 345 |
$join .= "LEFT JOIN $wpdb->terms ON $wpdb->term_taxonomy.term_id = $wpdb->terms.term_id "; |
| 346 |
} |
| 347 |
|
| 348 |
return $join; |
| 349 |
}*/ |
| 350 |
|
| 351 |
/** |
| 352 |
* @param string $where |
| 353 |
* |
| 354 |
* @return string |
| 355 |
* @deprecated 4.2.6.6 |
| 356 |
*/ |
| 357 |
/*public function add_tax_search( $where ) { |
| 358 |
global $wp_query, $wpdb; |
| 359 |
|
| 360 |
if ( ! empty( $wp_query->query_vars['s'] ) && ! is_admin() ) { |
| 361 |
$escaped_s = esc_sql( $wp_query->query_vars['s'] ); |
| 362 |
$where .= "OR $wpdb->terms.name LIKE '%{$escaped_s}%'"; |
| 363 |
} |
| 364 |
|
| 365 |
return $where; |
| 366 |
}*/ |
| 367 |
|
| 368 |
/** |
| 369 |
* @param string $groupby |
| 370 |
* |
| 371 |
* @return string |
| 372 |
* @deprecated 4.2.6.6 |
| 373 |
*/ |
| 374 |
/*public function tax_groupby( $groupby ) { |
| 375 |
global $wpdb; |
| 376 |
$groupby = "{$wpdb->posts}.ID"; |
| 377 |
|
| 378 |
$this->remove_query_tax(); |
| 379 |
|
| 380 |
return $groupby; |
| 381 |
}*/ |
| 382 |
|
| 383 |
/** |
| 384 |
* Remove filter query |
| 385 |
* @deprecated 4.2.6.6 |
| 386 |
*/ |
| 387 |
/*public function remove_query_tax() { |
| 388 |
remove_filter( 'posts_where', 'learn_press_add_tax_search' ); |
| 389 |
remove_filter( 'posts_join', 'learn_press_join_term' ); |
| 390 |
remove_filter( 'posts_groupby', 'learn_press_tax_groupby' ); |
| 391 |
}*/ |
| 392 |
|
| 393 |
/** |
| 394 |
* Clear cache rewrite rules when update option rewrite_rules |
| 395 |
* Fixed for case: addons Certificates (v4.0.5), FE(4.0.5), Live(4.0.2), Collections(4.0.2) not installed on site client. |
| 396 |
* Run only one time when reload page Frontend. |
| 397 |
* |
| 398 |
* @return mixed|array |
| 399 |
* @since 4.2.2 |
| 400 |
* @version 1.0.3 |
| 401 |
* @see get_option() hook in this function. |
| 402 |
*/ |
| 403 |
public function update_option_rewrite_rules( $wp_rules ) { |
| 404 |
// Check it is called from WP_Rewrite class |
| 405 |
$debug_backtrace = debug_backtrace(); |
| 406 |
|
| 407 |
// Find call from WP_Rewrite class |
| 408 |
$found = false; |
| 409 |
foreach ( $debug_backtrace as $trace ) { |
| 410 |
if ( isset( $trace['class'] ) && $trace['class'] == WP_Rewrite::class ) { |
| 411 |
$found = true; |
| 412 |
break; |
| 413 |
} |
| 414 |
} |
| 415 |
|
| 416 |
if ( ! $found ) { |
| 417 |
return $wp_rules; |
| 418 |
} |
| 419 |
|
| 420 |
/*static $handled = false; |
| 421 |
if ( $handled ) { |
| 422 |
return $wp_rules; |
| 423 |
} |
| 424 |
$handled = true;*/ |
| 425 |
|
| 426 |
if ( ! is_array( $wp_rules ) ) { |
| 427 |
return $wp_rules; |
| 428 |
} |
| 429 |
|
| 430 |
try { |
| 431 |
$lp_rules = $this->add_rewrite_rules(); |
| 432 |
foreach ( $lp_rules as $key_parent => $rules ) { |
| 433 |
foreach ( $rules as $key => $rule ) { |
| 434 |
if ( is_array( $rule ) ) { |
| 435 |
$wp_rules = array_merge( $rule, $wp_rules ); |
| 436 |
} |
| 437 |
} |
| 438 |
} |
| 439 |
} catch ( Throwable $e ) { |
| 440 |
error_log( sprintf( '%s:%s:%s', __FILE__, __LINE__, $e->getMessage() ) ); |
| 441 |
} |
| 442 |
|
| 443 |
return $wp_rules; |
| 444 |
} |
| 445 |
} |
| 446 |
|