PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.9
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.9
4.4.9 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 All 140 releases
← All changes | inc/admin/class-lp-admin.php +312 -185 4.1.7.3.2 → 4.4.9 View file →
@@ -1,14 +1,20 @@
1 1 <?php
2 2 /**
3 3 * @author ThimPress
4 4 * @package LearnPress/Admin/Classes
5 - * @version 1.0.1
5 + * @version 1.0.2
6 6 */
7 -if ( ! defined( 'ABSPATH' ) ) {
8 - exit; // Exit if accessed directly
9 -}
10 7
8 +use LearnPress\Background\LPBackgroundAjax;
9 +use LearnPress\Helpers\Template;
10 +use LearnPress\Models\CourseModel;
11 +use LearnPress\TemplateHooks\Admin\Notices\AdminNotesTemplate;
12 +use LearnPress\TemplateHooks\TemplateAJAX;
13 +use LearnPress\TemplateHooks\CourseBuilder\Course\BuilderCourseTemplate;
14 +
15 +defined( 'ABSPATH' ) || exit;
16 +
11 17 if ( ! class_exists( 'LP_Admin' ) ) {
12 18 /**
13 19 * Class LP_Admin
14 20 */
@@ -14,27 +20,31 @@
14 20 */
15 21 class LP_Admin {
16 22 protected static $instance;
17 23
18 - /**
19 - * @var array
20 - */
21 - protected $_static_pages = false;
24 + protected $pages = [];
22 25
23 26 /**
24 27 * Constructor
25 28 */
26 29 protected function __construct() {
30 + $this->pages = [
31 + 'courses' => __( 'Courses', 'learnpress' ),
32 + 'instructors' => __( 'Instructors', 'learnpress' ),
33 + 'single_instructor' => __( 'Single Instructors', 'learnpress' ),
34 + 'profile' => __( 'Profile', 'learnpress' ),
35 + 'checkout' => __( 'Checkout', 'learnpress' ),
36 + 'become_a_teacher' => __( 'Become an Instructor', 'learnpress' ),
37 + ];
27 38 $this->includes();
28 39 add_action( 'delete_user', array( $this, 'delete_user_data' ) );
29 - add_action( 'delete_user_form', array( $this, 'delete_user_form' ) );
30 - add_action( 'wp_ajax_learn_press_rated', array( $this, 'rated' ) );
31 - add_action( 'admin_notices', array( $this, 'admin_notices' ) );
40 + //add_action( 'delete_user_form', array( $this, 'delete_user_form' ) );
41 + add_action( 'admin_footer', array( $this, 'admin_notices' ) );
32 42 add_action( 'admin_enqueue_scripts', array( $this, 'load_modal' ) );
33 43 add_filter( 'admin_body_class', array( $this, 'body_class' ) );
34 - add_filter( 'manage_users_custom_column', array( $this, 'users_custom_column' ), 10, 3 );
35 - add_filter( 'manage_pages_columns', array( $this, 'page_columns_head' ) );
36 - add_filter( 'manage_pages_custom_column', array( $this, 'page_columns_content' ), 10, 2 );
44 + //add_filter( 'manage_users_custom_column', array( $this, 'users_custom_column' ), 10, 3 );
45 + //add_filter( 'manage_pages_columns', array( $this, 'page_columns_head' ) );
46 + //add_filter( 'manage_pages_custom_column', array( $this, 'page_columns_content' ), 10, 2 );
37 47 add_filter( 'views_edit-page', array( $this, 'views_pages' ), 10 );
38 48 add_filter( 'views_users', array( $this, 'views_users' ), 10, 1 );
39 49 add_filter( 'user_row_actions', array( $this, 'user_row_actions' ), 10, 2 );
40 50 add_filter( 'get_pages', array( $this, 'add_empty_page' ), 1000, 2 );
@@ -44,9 +54,9 @@
44 54 LP_Request::register( 'lp-action', array( $this, 'filter_users' ) );
45 55
46 56 add_filter( 'learn-press/modal-search-items-args', array( $this, 'filter_modal_search' ) );
47 57
48 - add_filter(
58 + /*add_filter(
49 59 'learn-press/dismissed-notice-response',
50 60 array(
51 61 $this,
52 62 'on_dismissed_notice_response',
@@ -52,9 +62,9 @@
52 62 'on_dismissed_notice_response',
53 63 ),
54 64 10,
55 65 2
56 - );
66 + );*/
57 67
58 68 // get list items course of user | tungnx
59 69 add_action( 'pre_get_posts', array( $this, 'get_course_items_of_user_backend' ), 10 );
60 70 add_action( 'pre_get_posts', array( $this, 'get_pages_of_lp' ), 10 );
@@ -60,8 +70,28 @@
60 70 add_action( 'pre_get_posts', array( $this, 'get_pages_of_lp' ), 10 );
61 71
62 72 // Set link item course when edit on Backend | tungnx
63 73 add_filter( 'get_sample_permalink_html', array( $this, 'lp_course_set_link_item_backend' ), 10, 5 );
74 +
75 + // Add "Edit with Course Builder" button below title area for courses
76 + add_action( 'edit_form_after_title', array( $this, 'add_course_builder_button' ) );
77 +
78 + /*add_action(
79 + 'admin_init',
80 + function () {
81 + // From LP v4.2.3 temporary run create pages to add page instructors, single instructor for client upgrade LP.
82 + // After a long time, will remove this code.
83 + if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
84 + LP_Install::create_pages();
85 + }
86 + }
87 + );*/
88 +
89 + add_filter( 'users_list_table_query_args', [ $this, 'exclude_temp_users' ] );
90 +
91 + // Show label 'LearnPress Page' for page of LearnPress.
92 + //add_filter('post_states_html');
93 + add_filter( 'display_post_states', [ $this, 'show_label_page_type' ], 10, 2 );
64 94 }
65 95
66 96 /**
67 97 * @since 3.2.6
@@ -66,15 +96,16 @@
66 96 /**
67 97 * @since 3.2.6
68 98 */
69 99 public function load_modal() {
70 - if ( in_array( get_post_type(), array( LP_COURSE_CPT, LP_QUIZ_CPT, LP_QUESTION_CPT, LP_ORDER_CPT ) ) ) {
100 + // Now only add item(s) when create new Order is using.
101 + if ( in_array( get_post_type(), array( LP_ORDER_CPT ) ) ) {
71 102 LP_Modal_Search_Items::instance();
72 103 }
73 104
74 - if ( in_array( get_post_type(), array( LP_ORDER_CPT ) ) ) {
105 + /*if ( in_array( get_post_type(), array( LP_ORDER_CPT ) ) ) {
75 106 LP_Modal_Search_Users::instance();
76 - }
107 + }*/
77 108 }
78 109
79 110 /**
80 111 * @param $options
@@ -116,9 +147,9 @@
116 147 if ( $active_plugins ) {
117 148 if ( $search ) {
118 149 foreach ( $search as $k => $v ) {
119 150 if ( in_array( $k, $active_plugins ) ) {
120 - $count_activated ++;
151 + ++ $count_activated;
121 152 }
122 153 }
123 154 }
124 155 }
@@ -174,9 +205,9 @@
174 205 * @param int $id
175 206 *
176 207 * @return bool
177 208 */
178 - protected function _is_wc_page( $id ) {
209 + /*protected function _is_wc_page( $id ) {
179 210 if ( class_exists( 'WooCommerce' ) ) {
180 211 if ( ! class_exists( 'WC_Admin_Post_Types' ) ) {
181 212 include_once dirname( WC_PLUGIN_FILE ) . '/includes/admin/class-wc-admin-post-types.php';
182 213 }
@@ -201,11 +232,11 @@
201 232 }
202 233 }
203 234
204 235 return false;
205 - }
236 + }*/
206 237
207 - public function wc_add_display_post_states( $post_states, $post ) {
238 + /*public function wc_add_display_post_states( $post_states, $post ) {
208 239 if ( wc_get_page_id( 'shop' ) === $post->ID ) {
209 240 $post_states['wc_page_for_shop'] = __( 'Shop Page', 'learnpress' );
210 241 }
211 242
@@ -225,9 +256,9 @@
225 256 $post_states['wc_page_for_terms'] = __( 'Terms and Conditions Page', 'learnpress' );
226 257 }
227 258
228 259 return $post_states;
229 - }
260 + }*/
230 261
231 262 /**
232 263 * Check if a page is set for Paid Membership Pro.
233 264 *
@@ -234,9 +265,9 @@
234 265 * @param int $id
235 266 *
236 267 * @return bool|mixed
237 268 */
238 - protected function _is_pmpro_page( $id ) {
269 + /*protected function _is_pmpro_page( $id ) {
239 270 global $pmpro_pages;
240 271 if ( $pmpro_pages ) {
241 272 $pages = array(
242 273 'account' => __( 'Account', 'learnpress' ),
@@ -255,9 +286,9 @@
255 286 }
256 287 }
257 288
258 289 return false;
259 - }
290 + }*/
260 291
261 292 /**
262 293 * Check if a page is set for Paid Membership Pro.
263 294 *
@@ -264,9 +295,9 @@
264 295 * @param int $id
265 296 *
266 297 * @return bool|mixed
267 298 */
268 - protected function _is_bp_page( $id ) {
299 + /*protected function _is_bp_page( $id ) {
269 300 if ( function_exists( 'buddypress' ) ) {
270 301 $bp_pages = get_option( 'bp-pages' );
271 302 if ( ! $bp_pages ) {
272 303 return false;
@@ -286,56 +317,56 @@
286 317 }
287 318 }
288 319
289 320 return false;
290 - }
321 + }*/
291 322
292 323 /**
293 - * @param string $plugin
324 + * Get pages is publish set by LearnPress.
294 325 *
295 - * @return array|bool
326 + * @return array
296 327 */
297 - protected function _get_static_pages( $plugin = '' ) {
298 - if ( false === $this->_static_pages ) {
299 - $this->_static_pages = array(
300 - 'learnpress' => array(),
301 - 'WooCommerce' => array(),
302 - 'Paid Membership Pro' => array(),
303 - 'BuddyPress' => array(),
304 - );
328 + protected function _get_static_pages(): array {
329 + $static_pages = [];
330 + foreach ( $this->pages as $name => $title ) {
331 + $page_id = learn_press_get_page_id( $name );
305 332
306 - $all_pages = array(
307 - 'courses' => __( 'Courses', 'learnpress' ),
308 - 'profile' => __( 'Profile', 'learnpress' ),
309 - 'checkout' => __( 'Checkout', 'learnpress' ),
310 - 'become_a_teacher' => __( 'Become a Teacher', 'learnpress' ),
311 - );
333 + if ( $page_id && 'publish' === get_post_status( $page_id ) ) {
334 + $static_pages[ $page_id ] = $title;
335 + }
336 + }
312 337
313 - foreach ( $all_pages as $name => $title ) {
314 - $page_id = learn_press_get_page_id( $name );
338 + return $static_pages;
339 + }
315 340
316 - if ( $page_id && 'publish' === get_post_status( $page_id ) ) {
317 - $this->_static_pages['learnpress'][ $page_id ] = $title;
341 + /**
342 + * Show label LearnPress Page for pages set by LearnPress.
343 + *
344 + * @param array $post_states
345 + * @param WP_Post $post
346 + *
347 + * @return array
348 + * @since 4.3.2.6
349 + * @version 1.0.0
350 + */
351 + public function show_label_page_type( $post_states, $post ) {
352 + $post_type = get_post_type( $post );
353 + if ( $post_type !== 'page' ) {
354 + return $post_states;
355 + }
318 356
319 - $for_page = $this->_is_wc_page( $page_id );
320 - if ( $for_page ) {
321 - $this->_static_pages['WooCommerce'][ $page_id ] = $for_page;
322 - }
323 -
324 - $for_page = $this->_is_pmpro_page( $page_id );
325 - if ( $for_page ) {
326 - $this->_static_pages['Paid Membership Pro'][ $page_id ] = $for_page;
327 - }
328 -
329 - $for_page = $this->_is_bp_page( $page_id );
330 - if ( $for_page ) {
331 - $this->_static_pages['BuddyPress'][ $page_id ] = $for_page;
332 - }
333 - }
357 + $page_id_compare = $post->ID;
358 + foreach ( $this->_get_static_pages() as $page_id => $title ) {
359 + if ( $page_id == $page_id_compare ) {
360 + $post_states['lp_page'] = sprintf(
361 + '<span class="is-lp-page">%s</span>',
362 + 'LearnPress ' . $title . ' Page'
363 + );
364 + break;
334 365 }
335 366 }
336 367
337 - return $plugin ? ( ! empty( $this->_static_pages[ $plugin ] ) ? $this->_static_pages[ $plugin ] : false ) : $this->_static_pages;
368 + return $post_states;
338 369 }
339 370
340 371 /**
341 372 * Add new column to WP Pages manage to show what page is assigned to.
@@ -343,9 +374,9 @@
343 374 * @param array $columns
344 375 *
345 376 * @return array
346 377 */
347 - public function page_columns_head( $columns ) {
378 + /*public function page_columns_head( $columns ) {
348 379
349 380 $_columns = $columns;
350 381 $columns = array();
351 382
@@ -356,17 +387,17 @@
356 387 $columns[ $name ] = $text;
357 388 }
358 389
359 390 return $columns;
360 - }
391 + }*/
361 392
362 393 /**
363 394 * Display the page is assigned to LP Page.
364 395 *
365 396 * @param string $column_name
366 - * @param int $post
397 + * @param int $post
367 398 */
368 - public function page_columns_content( $column_name, $post ) {
399 + /*public function page_columns_content( $column_name, $post ) {
369 400 $pages = $this->_get_static_pages();
370 401 switch ( $column_name ) {
371 402 case 'lp-page':
372 403 if ( ! empty( $pages['learnpress'][ $post ] ) ) {
@@ -386,9 +417,9 @@
386 417 );
387 418 }
388 419 }
389 420 }
390 - }
421 + }*/
391 422
392 423 /**
393 424 * @param $actions
394 425 *
@@ -394,15 +425,13 @@
394 425 *
395 426 * @return mixed
396 427 */
397 428 public function views_pages( $actions ) {
398 - $this->_get_static_pages();
429 + $pages = $this->_get_static_pages();
399 430
400 - $pages = $this->_get_static_pages( 'learnpress' );
401 -
402 431 if ( $pages ) {
403 432 $text = sprintf( __( 'LearnPress Pages (%d)', 'learnpress' ), sizeof( $pages ) );
404 - if ( 'yes' !== LP_Request::get( 'lp-page' ) ) {
433 + if ( 'yes' !== LP_Request::get_param( 'lp-page' ) ) {
405 434 $actions['lp-page'] = sprintf(
406 435 '<a href="%s">%s</a>',
407 436 admin_url( 'edit.php?post_type=page&lp-page=yes' ),
408 437 $text
@@ -422,11 +451,15 @@
422 451 *
423 452 * @return mixed
424 453 */
425 454 public function get_pages_of_lp( $q ) {
426 - if ( 'page' == LP_Request::get( 'post_type' ) && 'yes' == LP_Request::get( 'lp-page' ) ) {
427 - $ids = $this->_get_static_pages( 'learnpress' );
455 + if ( ! is_admin() || ! $q->is_main_query() ) {
456 + return $q;
457 + }
428 458
459 + if ( 'page' == LP_Request::get_param( 'post_type' ) && 'yes' == LP_Request::get_param( 'lp-page' ) ) {
460 + $ids = $this->_get_static_pages();
461 +
429 462 if ( ! empty( $ids ) ) {
430 463 $ids = array_keys( $ids );
431 464 $q->set( 'post__in', $ids );
432 465 }
@@ -437,24 +470,27 @@
437 470
438 471 /**
439 472 * Add actions to users list
440 473 *
441 - * @param array $actions
474 + * @param array $actions
442 475 * @param WP_User $user
443 476 *
444 477 * @return mixed
445 478 */
446 479 public function user_row_actions( $actions, $user ) {
447 - $pending_request = LP_User_Factory::get_pending_requests();
448 - if ( LP_Request::get_string( 'lp-action' ) == 'pending-request' && $pending_request ) {
480 + $pending_request = self::get_pending_requests();
481 + if ( LP_Request::get_param( 'lp-action' ) == 'pending-request' && $pending_request ) {
449 482 $actions = array();
483 + $nonce = 'nonce=' . wp_create_nonce( 'lp-action-permit-role-teacher' );
450 484 if ( in_array( $user->ID, $pending_request ) ) {
451 485 $actions['accept'] = sprintf(
452 - '<a href="' . admin_url( 'users.php?lp-action=accept-request&user_id=' . $user->ID ) . '">%s</a>',
486 + '<a href="%s">%s</a>',
487 + admin_url( "users.php?lp-action=accept-request&user_id={$user->ID}&{$nonce}" ),
453 488 _x( 'Accept', 'pending-request', 'learnpress' )
454 489 );
455 490 $actions['delete deny'] = sprintf(
456 - '<a class="submitdelete" href="' . admin_url( 'users.php?lp-action=deny-request&user_id=' . $user->ID ) . '">%s</a>',
491 + '<a class="submitdelete" href="%s">%s</a>',
492 + admin_url( "users.php?lp-action=deny-request&user_id={$user->ID}&{$nonce}" ),
457 493 _x( 'Deny', 'pending-request', 'learnpress' )
458 494 );
459 495 }
460 496 }
@@ -461,9 +497,38 @@
461 497
462 498 return $actions;
463 499 }
464 500
501 + public function exclude_temp_users( $args ) {
502 + if ( LP_Request::get_param( 'lp-action' ) == 'pending-request' ) {
503 + $args['include'] = self::get_pending_requests();
504 + }
505 +
506 + return $args;
507 + }
508 +
465 509 /**
510 + * Get pending requests be come a Teacher.
511 + *
512 + * @return array
513 + */
514 + public static function get_pending_requests() {
515 + global $wpdb;
516 + $query = $wpdb->prepare(
517 + "
518 + SELECT ID
519 + FROM {$wpdb->users} u
520 + INNER JOIN {$wpdb->usermeta} um ON um.user_id = u.ID AND um.meta_key = %s
521 + WHERE um.meta_value = %s
522 + ",
523 + '_requested_become_teacher',
524 + 'yes'
525 + );
526 +
527 + return $wpdb->get_col( $query );
528 + }
529 +
530 + /**
466 531 * Filter user by custom param
467 532 *
468 533 * @param string $action
469 534 */
@@ -471,38 +536,59 @@
471 536 if ( ! current_user_can( 'administrator' ) ) {
472 537 return;
473 538 }
474 539
475 - $user_id = LP_Request::get_int( 'user_id' );
540 + $user_id = LP_Request::get_param( 'user_id', 'int' );
541 + if ( ! $user_id || ! get_user_by( 'id', $user_id ) ) {
542 + return;
543 + }
476 544
477 - if ( ! $user_id || ! get_user_by( 'id', $user_id ) ) {
545 + $nonce = LP_Request::get_param( 'nonce' );
546 + if ( ! wp_verify_nonce( $nonce, 'lp-action-permit-role-teacher' ) ) {
478 547 return;
479 548 }
480 549
481 550 $user_data = get_userdata( $user_id );
551 + if ( in_array( $action, array( 'accept-request', 'deny-request' ) ) ) {
552 + delete_user_meta( $user_id, '_requested_become_teacher' );
553 + }
482 554
483 - if ( in_array( $action, array( 'accept-request', 'deny-request' ) ) ) {
555 + switch ( $action ) {
556 + case 'accept-request':
557 + $be_teacher = new WP_User( $user_id );
558 + $be_teacher->set_role( LP_TEACHER_ROLE );
484 559
485 - delete_user_meta( $user_id, '_requested_become_teacher' );
560 + /**
561 + * Send email to user when admin accept user become a teacher
562 + * @use SendEmailAjax::send_mail_become_a_teacher_accept
563 + */
564 + $data_send = [
565 + 'params' => [ $user_data->user_email ],
566 + 'lp-load-ajax' => 'send_mail_become_a_teacher_accept',
567 + ];
568 + LPBackgroundAjax::handle( $data_send );
486 569
487 - switch ( $action ) {
488 - case 'accept-request':
489 - $be_teacher = new WP_User( $user_id );
490 - $be_teacher->set_role( LP_TEACHER_ROLE );
570 + do_action( 'learn-press/user-become-a-teacher-accept', $user_data->user_email );
571 + wp_redirect( admin_url( 'users.php?lp-action=accepted-request&user_id=' . $user_id ) );
572 + exit();
573 + case 'deny-request':
574 + /**
575 + * Send email to user when admin accept user become a teacher
576 + * @use SendEmailAjax::send_mail_become_a_teacher_deny
577 + */
578 + $data_send = [
579 + 'params' => [ $user_data->user_email ],
580 + 'lp-load-ajax' => 'send_mail_become_a_teacher_deny',
581 + ];
582 + LPBackgroundAjax::handle( $data_send );
491 583
492 - do_action( 'learn-press/user-become-a-teacher-accept', $user_data->user_email );
493 - wp_redirect( admin_url( 'users.php?lp-action=accepted-request&user_id=' . $user_id ) );
494 - exit();
495 - case 'deny-request':
496 - do_action( 'learn-press/user-become-a-teacher-deny', $user_data->user_email );
497 - wp_redirect( admin_url( 'users.php?lp-action=denied-request&user_id=' . $user_id ) );
498 - exit();
499 - }
584 + do_action( 'learn-press/user-become-a-teacher-deny', $user_data->user_email );
585 + wp_redirect( admin_url( 'users.php?lp-action=denied-request&user_id=' . $user_id ) );
586 + exit();
500 587 }
501 588 }
502 589
503 590 public function users_custom_column( $content, $column_name, $user_id ) {
504 -
505 591 }
506 592
507 593 /**
508 594 * Add new view to users views for filtering user by "pending request" of "become a teacher".
@@ -511,12 +597,12 @@
511 597 *
512 598 * @return mixed
513 599 */
514 600 public function views_users( $views ) {
515 - $pending_request = LP_User_Factory::get_pending_requests();
601 + $pending_request = self::get_pending_requests();
516 602
517 603 if ( $pending_request ) {
518 - if ( LP_Request::get_string( 'lp-action' ) == 'pending-request' ) {
604 + if ( LP_Request::get_param( 'lp-action' ) == 'pending-request' ) {
519 605 $class = ' class="current"';
520 606 foreach ( $views as $k => $view ) {
521 607 $views[ $k ] = preg_replace( '!class="current"!', '', $view );
522 608 }
@@ -564,14 +650,13 @@
564 650 /**
565 651 * Display notices on Backend.
566 652 */
567 653 public function admin_notices() {
568 - // Show template file templates override.
569 - $page = LP_Request::get_param( 'page' );
570 - $tab = LP_Request::get_param( 'tab' );
571 - if ( $page == 'learn-press-tools' && $tab == 'templates' ) {
572 - if ( LP_Outdated_Template_Helper::detect_outdated_template() ) {
573 - learn_press_admin_view( 'html-admin-notice-templates' );
654 + if ( function_exists( 'get_current_screen' ) ) {
655 + $wp_screen = get_current_screen();
656 + // Not run on course edit screen, it slows, can affect performance edit course.
657 + if ( $wp_screen->id === LP_COURSE_CPT ) {
658 + return;
574 659 }
575 660 }
576 661
577 662 // Request accept/denied user can become a teacher.
@@ -592,17 +677,30 @@
592 677 </div>
593 678 <?php
594 679 }
595 680
596 - learn_press_admin_view( 'admin-notices.php', [], true );
597 - }
681 + // Load Ajax notes here
682 + /** @use AdminNotesTemplate::render_notices */
683 + $html_notices = TemplateAJAX::load_content_via_ajax(
684 + [
685 + 'method_request' => 'GET',
686 + 'id_url' => 'admin-notices',
687 + 'html_loading_before_show_content' => '',
688 + ],
689 + [
690 + 'class' => AdminNotesTemplate::class,
691 + 'method' => 'render_notices',
692 + ]
693 + );
598 694
599 - /**
600 - * Update option data user rated.
601 - */
602 - public function rated() {
603 - update_option( 'learn_press_message_user_rated', 'yes' );
604 - die();
695 + wp_enqueue_script( 'lp-admin-notices' );
696 +
697 + echo Template::instance()->nest_elements(
698 + [
699 + '<div class="learn-press-admin-notices notice">' => '</div>',
700 + ],
701 + $html_notices
702 + );
605 703 }
606 704
607 705 /**
608 706 * Admin footer add review.
@@ -630,30 +728,8 @@
630 728 'learnpress'
631 729 ) . '">',
632 730 '</a>'
633 731 );
634 -
635 - ob_start();
636 - ?>
637 -
638 - <script>
639 - jQuery(function ($) {
640 - var $ratingLink = $('a.lp-rating-link').click(function (e) {
641 - $.ajax({
642 - url: '<?php echo admin_url( 'admin-ajax.php' ); ?>',
643 - data: {
644 - action: 'learn_press_rated'
645 - },
646 - success: function () {
647 - $ratingLink.parent().html($ratingLink.data('rated'))
648 - }
649 - })
650 - })
651 - })
652 - </script>
653 -
654 - <?php
655 - echo ob_get_clean();
656 732 }
657 733 }
658 734
659 735 return $footer_text;
@@ -658,11 +734,11 @@
658 734
659 735 return $footer_text;
660 736 }
661 737
662 - function delete_user_form() {
738 + /*function delete_user_form() {
663 739 // What should be displayed here?
664 - }
740 + }*/
665 741
666 742 /**
667 743 * Delete records related user being deleted in other tables
668 744 *
@@ -674,15 +750,16 @@
674 750
675 751 /**
676 752 * Send data to join newsletter or dismiss.
677 753 *
678 - * @param array $data
754 + * @param array $data
679 755 * @param string $notice
680 756 *
681 757 * @return array
682 758 * @since 3.0.10
759 + * @deprecated 4.2.3.1
683 760 */
684 - public function on_dismissed_notice_response( $data, $notice ) {
761 + /*public function on_dismissed_notice_response( $data, $notice ) {
685 762 switch ( $notice ) {
686 763 case 'skip-setup-wizard':
687 764 delete_option( 'learn_press_install' );
688 765 break;
@@ -729,9 +806,9 @@
729 806 }
730 807 }
731 808
732 809 return $data;
733 - }
810 + }*/
734 811
735 812 /**
736 813 * Include all classes and functions used for admin
737 814 */
@@ -738,10 +815,18 @@
738 815 public function includes() {
739 816 // Common function used in admin
740 817 include_once 'lp-admin-functions.php';
741 818 include_once 'lp-admin-actions.php';
742 - require_once LP_PLUGIN_PATH . 'inc/background-process/class-lp-background-query-items.php';
743 819 include_once 'class-lp-admin-assets.php';
820 + LP_Admin_Assets::instance();
821 + // For MCP
822 + if ( learn_press_is_mcp_available() ) {
823 + include_once 'class-lp-admin-mcp-api-keys.php';
824 + LP_Admin_MCP_API_Keys::instance();
825 + }
826 + // End MCP
827 + include_once 'class-lp-admin-webhooks.php';
828 + LP_Admin_Webhooks::instance();
744 829 include_once 'class-lp-admin-dashboard.php';
745 830 // include_once 'class-lp-admin-tools.php';
746 831 include_once 'class-lp-admin-ajax.php';
747 832 include_once 'editor/class-lp-admin-editor.php';
@@ -746,19 +831,19 @@
746 831 include_once 'class-lp-admin-ajax.php';
747 832 include_once 'editor/class-lp-admin-editor.php';
748 833 include_once 'class-lp-admin-menu.php';
749 834 include_once 'helpers/class-lp-outdated-template-helper.php';
750 - include_once 'helpers/class-lp-plugins-helper.php';
751 835 include_once 'class-lp-modal-search-items.php';
752 - include_once 'class-lp-modal-search-users.php';
836 + //include_once 'class-lp-modal-search-users.php';
753 837 include_once 'class-lp-setup-wizard.php';
754 838 // include_once 'class-lp-updater.php';
755 - include_once 'class-lp-install-sample-data.php';
756 - include_once 'class-lp-reset-data.php';
839 + // include_once 'class-lp-install-sample-data.php'; // Replaced by LearnPress\Ajax\SampleDataAJAX.
840 + // include_once 'class-lp-reset-data.php'; // Deprecated: replaced by CourseToolsAjax::reset_progress_items_course.
757 841 include_once LP_PLUGIN_PATH . 'inc/admin/views/meta-boxes/course/settings.php';
842 + include_once LP_PLUGIN_PATH . 'inc/admin/views/meta-boxes/course/class-lp-meta-box-course-offline.php';
758 843 include_once LP_PLUGIN_PATH . 'inc/admin/views/meta-boxes/quiz/settings.php';
759 844 include_once LP_PLUGIN_PATH . 'inc/admin/views/meta-boxes/lesson/settings.php';
760 - include_once LP_PLUGIN_PATH . 'inc/admin/views/meta-boxes/question/settings.php';
845 + //include_once LP_PLUGIN_PATH . 'inc/admin/views/meta-boxes/question/settings.php';
761 846 }
762 847
763 848 /**
764 849 * Get courses, item's courses on Backend page post_type
@@ -769,9 +854,9 @@
769 854 if ( ! $query->is_main_query() ) {
770 855 return;
771 856 }
772 857
773 - global $post_type, $pagenow;
858 + /*global $post_type, $pagenow;
774 859
775 860 if ( current_user_can( ADMIN_ROLE ) ) {
776 861 return;
777 862 }
@@ -786,25 +871,26 @@
786 871 );
787 872
788 873 if ( ! in_array( $post_type, $post_type_valid ) ) {
789 874 return;
790 - }
875 + }*/
791 876
792 877 // $query->set( 'author', get_current_user_id() );
793 878
794 - $query = apply_filters( 'learnpress/get-post-type-lp-on-backend', $query );
879 + // Hook only Co-instructor using.
880 + return apply_filters( 'learnpress/get-post-type-lp-on-backend', $query );
795 881
796 882 //add_filter( 'views_edit-' . $post_type . '', '_learn_press_restrict_view_items', 10 );
797 - remove_filter( 'pre_get_posts', array( $this, 'get_course_items_of_user_backend' ), 10 );
883 + //remove_filter( 'pre_get_posts', array( $this, 'get_course_items_of_user_backend' ), 10 );
798 884 }
799 885
800 886 /**
801 887 * Set link item of course when edit item on Backend
802 888 *
803 - * @param string $post_link
804 - * @param int $post_id
805 - * @param string $new_title
806 - * @param string $new_slug
889 + * @param string $post_link
890 + * @param int $post_id
891 + * @param string $new_title
892 + * @param string $new_slug
807 893 * @param WP_Post|null $post
808 894 *
809 895 * @return string
810 896 * @author tungnx
@@ -811,45 +897,47 @@
811 897 * @since 3.2.7.5
812 898 * @version 4.0.1
813 899 */
814 900 public function lp_course_set_link_item_backend( $post_link = '', $post_id = 0, $new_title = '', $new_slug = '', $post = null ) {
815 - if ( ! in_array( $post->post_type, learn_press_get_course_item_types() ) ) {
816 - return $post_link;
817 - }
818 -
819 901 try {
820 - $course_id_of_item = LP_Course_DB::getInstance()->get_course_by_item_id( $post->ID );
902 + if ( in_array( $post->post_type, CourseModel::item_types_support() ) ) {
903 + $course_id_of_item = LP_Course_DB::getInstance()->get_course_by_item_id( $post->ID );
904 + if ( $course_id_of_item ) {
905 + $course = learn_press_get_course( $course_id_of_item );
906 + if ( $course ) {
907 + $link_item = urldecode( $course->get_item_link( $post->ID ) );
908 + $post_slug = $post->post_name;
909 + $link_item_edit_slug = preg_replace( '/' . $post_slug . '$/', '', $link_item );
821 910
822 - if ( $course_id_of_item ) {
823 - $course = learn_press_get_course( $course_id_of_item );
911 + // For update new slug
912 + if ( $new_slug ) {
913 + $post_slug = $new_slug;
914 + }
915 + $post_slug = urldecode( $post_slug );
824 916
825 - if ( $course ) {
826 - $link_item = $course->get_item_link( $post->ID );
917 + $slug_arr = explode( '/', $link_item_edit_slug );
918 + $count_slug = count( $slug_arr );
919 + unset( $slug_arr[ $count_slug - 2 ] );
920 + $link_item_edit_slug = implode( '/', $slug_arr );
827 921
828 - $post_slug = $post->post_name;
829 - $link_item_edit_slug = preg_replace( '/' . $post_slug . '$/', '', $link_item );
830 -
831 - // For update new slug
832 - if ( $new_slug ) {
833 - $post_slug = $new_slug;
922 + $post_link = '<strong>Permalink: </strong>';
923 + $post_link .= '<span id="sample-permalink">';
924 + $post_link .= '<a href="' . $link_item . '">' . $link_item_edit_slug . '<span id="editable-post-name">' . $post_slug . '</span>/</a>';
925 + $post_link .= '</span>';
926 + $post_link .= '&lrm;<span id="edit-slug-buttons">';
927 + $post_link .= '<button type="button" class="edit-slug button button-small hide-if-no-js" aria-label="Edit permalink">Edit</button>';
928 + $post_link .= '</span>';
929 + $post_link .= '<span id="editable-post-name-full">' . $post_slug . '</span>';
834 930 }
835 -
836 - $post_link = '<strong>Permalink: </strong>';
837 - $post_link .= '<span id="sample-permalink">';
838 - $post_link .= '<a href="' . $link_item . '">' . $link_item_edit_slug . '<span id="editable-post-name">' . $post_slug . '</span>/</a>';
839 - $post_link .= '</span>';
840 - $post_link .= '&lrm;<span id="edit-slug-buttons">';
841 - $post_link .= '<button type="button" class="edit-slug button button-small hide-if-no-js" aria-label="Edit permalink">Edit</button>';
842 - $post_link .= '</span>';
843 - $post_link .= '<span id="editable-post-name-full">' . $post_slug . '</span>';
931 + } else {
932 + $post_link_message = '<span>' . __(
933 + 'Permalink is only available if the item is already assigned to a course.',
934 + 'learnpress'
935 + ) . '</span>';
936 + $post_link = sprintf( '<div id="learn-press-box-edit-slug">%s</div>', $post_link_message );
844 937 }
845 - } else {
846 - // $post_link_preview = sprintf( '<a class="button" href="%s" target="_blank">%s</a>', learn_press_get_preview_url( $post_id ), __( 'Preview', 'learnpress' ) );
847 - $post_link_message = '<span>' . __(
848 - 'Permalink is only available if the item is already assigned to a course.',
849 - 'learnpress'
850 - ) . '</span>';
851 - $post_link = sprintf( '<div id="learn-press-box-edit-slug">%s</div>', $post_link_message );
938 + } elseif ( LP_COURSE_CPT === get_post_type( $post ) ) {
939 + $post_link = LP_Helper::handle_lp_permalink_structure( $post_link, $post );
852 940 }
853 941 } catch ( Throwable $e ) {
854 942 error_log( $e->getMessage() );
855 943 }
@@ -854,8 +942,47 @@
854 942 error_log( $e->getMessage() );
855 943 }
856 944
857 945 return $post_link;
946 + }
947 +
948 + /**
949 + * Add "Edit with Course Builder" button below title area for courses
950 + *
951 + * @param WP_Post $post
952 + *
953 + * @since 4.3.0
954 + */
955 + public function add_course_builder_button( $post ) {
956 + if ( ! $post || LP_COURSE_CPT !== $post->post_type ) {
957 + return;
958 + }
959 +
960 + // Only show for existing courses (not new)
961 + if ( 'auto-draft' === $post->post_status ) {
962 + return;
963 + }
964 +
965 + $course_builder_url = BuilderCourseTemplate::instance()->get_link_edit( $post->ID ) ?? '';
966 + ?>
967 + <div class="lp-edit-with-course-builder" style="margin: 10px 0 20px 0;">
968 + <a href="<?php echo esc_url( $course_builder_url ); ?>" class="button button-primary button-large" style="background: #7067ED; border-color: #7067ED; display: inline-flex; align-items: center; gap: 6px; padding: 0 16px; font-size: 14px; border-radius: 3px; line-height: 3;">
969 + <svg width="26" height="18" viewBox="0 0 69 48" fill="none" xmlns="http://www.w3.org/2000/svg">
970 + <path d="M50.9291 24.84L50.2591 21.69C50.5491 21.47 50.7391 21.11 50.7391 20.71C50.7391 20.03 50.1891 19.48 49.4991 19.48C48.8091 19.48 48.2591 20.03 48.2591 20.71C48.2591 21.11 48.4491 21.46 48.7391 21.69L48.0691 24.84C47.9891 25.21 48.1791 25.56 48.4791 25.56H50.5091C50.8091 25.56 50.9991 25.21 50.9191 24.84H50.9291Z" fill="white"></path>
971 + <path d="M50.8892 13.24H50.0092V20.92H48.9892V13.21L46.2992 13.18C43.3992 8.47 38.1692 5.34 32.2192 5.34C30.8292 5.34 29.4792 5.51 28.1892 5.83L24.9492 2.53C24.7992 2.38 24.8892 2.14 25.0992 2.11L40.7292 0L48.5492 9.68L49.7592 11.17L51.0992 12.83C51.2292 12.99 51.1092 13.24 50.8992 13.23L50.8892 13.24Z" fill="white"></path>
972 + <path d="M44.7392 13.1701L43.1392 17.1401C40.7292 13.1101 36.3092 10.4101 31.2592 10.4101C29.9992 10.4101 28.7892 10.5801 27.6292 10.8901L29.2292 6.93014C30.1992 6.74014 31.1992 6.64014 32.2192 6.64014C37.4092 6.64014 41.9892 9.22014 44.7392 13.1701Z" fill="white"></path>
973 + <path d="M25.4692 23.6899V23.8499C25.4692 23.9599 25.4592 24.0699 25.4592 24.1899C25.4592 24.0199 25.4592 23.8499 25.4692 23.6899Z" fill="white"></path>
974 + <path d="M43.3692 24.2601C43.3692 25.2901 43.2392 26.2901 42.9892 27.2501C42.3892 29.5401 41.1192 31.5601 39.4092 33.1001C37.9992 34.3601 36.2892 35.2901 34.3892 35.7701C33.4492 36.0101 32.4592 36.1401 31.4392 36.1401H27.9692V35.8001C27.9692 35.6601 27.9792 35.5301 27.9992 35.3901C28.2092 33.2201 29.5592 31.3901 31.4492 30.4901C31.6092 30.4101 31.7692 30.3401 31.9292 30.2801C32.1692 30.1901 32.4192 30.1201 32.6692 30.0601C32.7292 30.0501 32.7992 30.0301 32.8592 30.0201C35.4892 29.4101 37.4492 27.0601 37.4492 24.2501C37.4492 21.2701 35.2392 18.8001 32.3592 18.3901C32.0792 18.3501 31.7892 18.3301 31.4992 18.3301C31.2392 18.3301 30.9992 18.3501 30.7492 18.3801C28.2992 18.6901 26.2592 20.4801 25.6492 22.8201C25.5292 23.2901 25.4792 23.7701 25.4792 24.2401V42.7601C25.1492 45.6001 22.8092 47.8301 19.9092 47.9901H19.5592H16.4792C18.3092 46.6501 19.5092 44.5001 19.5092 42.0701V23.7001C19.5092 23.5601 19.5192 23.4301 19.5392 23.3001C19.6292 22.2301 19.8492 21.1901 20.2092 20.2201C20.4592 19.5401 20.7692 18.8801 21.1292 18.2501C21.7592 17.1801 22.5492 16.2201 23.4692 15.4001C24.6192 14.3701 25.9792 13.5601 27.4692 13.0401C28.7092 12.6001 30.0492 12.3701 31.4392 12.3701C32.4792 12.3701 33.4792 12.5001 34.4392 12.7501C36.6892 13.3301 38.6792 14.5401 40.2092 16.1901C40.2592 16.2401 40.3092 16.3001 40.3592 16.3501C40.3592 16.3501 40.3592 16.3501 40.3692 16.3601C41.9592 18.1401 43.0192 20.4101 43.2992 22.9001C43.3293 23.1701 43.3492 23.4501 43.3692 23.7201C43.3692 23.8901 43.3692 24.0601 43.3692 24.2401V24.2601Z" fill="white"></path>
975 + <path d="M25.4692 23.6899V23.8499C25.4692 23.9599 25.4592 24.0699 25.4592 24.1899C25.4592 24.0199 25.4592 23.8499 25.4692 23.6899Z" fill="white"></path>
976 + <path d="M6.13917 42.0799H18.0692C18.0592 45.3499 15.3792 47.9999 12.0892 47.9999H6.11917C2.83917 47.9999 0.16917 45.3499 0.14917 42.0799V12.3799H0.18917C3.46917 12.3799 6.13917 15.0299 6.13917 18.2999V42.0799Z" fill="white"></path>
977 + <path d="M67.6736 23.2845L63.9566 19.5676C63.1998 18.8108 61.9757 18.8108 61.219 19.5676L59.0266 21.7599L65.4812 28.2145L67.6736 26.0222C68.4303 25.2654 68.4303 24.0413 67.6736 23.2845Z" fill="white"></path>
978 + <path d="M45.4722 45.0411L46.3513 45.9203L42.078 46.7883C42.078 46.7883 42.0557 46.3432 41.477 45.7534C40.8983 45.1747 40.442 45.1524 40.442 45.1524L41.3101 40.879L42.1892 41.7582L59.817 24.1305L58.2256 22.5391L40.5979 40.1668L39.2513 46.7883C39.1066 47.4894 39.7298 48.1126 40.4309 47.968L47.0525 46.6214L64.6802 28.9937L63.0888 27.4023L45.4611 45.03L45.4722 45.0411Z" fill="white"></path>
979 + <path d="M60.6182 24.9316L42.9905 42.5594L44.6932 44.2621L62.3209 26.6343L60.6182 24.9316Z" fill="white"></path>
980 + </svg>
981 + <?php esc_html_e( 'Edit with Course Builder', 'learnpress' ); ?>
982 + </a>
983 + </div>
984 + <?php
858 985 }
859 986
860 987 /**
861 988 * @return false|string