PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.3.7
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.3.7
4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 All 139 releases
learnpress / inc / TemplateHooks / CourseBuilder / CourseBuilderTemplate.php

CourseBuilderTemplate.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.3.7, at inc/TemplateHooks/CourseBuilder/CourseBuilderTemplate.php

629 lines 17.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Template hooks Course Builder.
4 *
5 * @since 4.3.x
6 * @version 1.0.0
7 */
8
9 namespace LearnPress\TemplateHooks\CourseBuilder;
10
11 use Exception;
12 use LearnPress\CourseBuilder\CourseBuilder;
13 use LearnPress\Helpers\Singleton;
14 use LearnPress\Helpers\Template;
15 use LearnPress\Models\UserModel;
16 use LearnPress\TemplateHooks\CourseBuilder\Course\BuilderCourseTemplate;
17 use LearnPress\TemplateHooks\TemplateAJAX;
18 use LP_Profile;
19 use LP_Settings;
20 use LP_WP_Filesystem;
21 use Throwable;
22 use WP_User;
23
24 class CourseBuilderTemplate {
25 use Singleton;
26
27 const MENU_COURSES = 'courses';
28 const MENU_LESSONS = 'lessons';
29 const MENU_QUIZZES = 'quizzes';
30 const MENU_QUESTIONS = 'questions';
31 const MENU_SETTINGS = 'settings';
32
33 public function init() {
34 //add_filter( 'lp/rest/ajax/allow_callback', [ $this, 'allow_callback' ] );
35 add_action( 'learn-press/course-builder/layout', [ $this, 'layout' ] );
36 // Show link to Course Builder in admin bar
37 add_action( 'admin_bar_menu', array( $this, 'add_admin_bar_menu' ), 80 );
38 // Hide admin bar for instructor (not admin)
39 add_filter( 'show_admin_bar', [ $this, 'hide_admin_bar_for_instructor' ] );
40 // Dequeue theme styles on Course Builder page (must run during wp_head, not after)
41 //add_action( 'wp_enqueue_scripts', [ $this, 'dequeue_theme_styles' ], 9999 );
42 }
43
44 /**
45 * Hide admin bar for instructor users (not administrators).
46 *
47 * @param bool $show_admin_bar
48 *
49 * @return bool
50 * @since 4.3.0
51 */
52 public function hide_admin_bar_for_instructor( bool $show_admin_bar ): bool {
53 // Check enable hide admin bar for instructor
54 if ( ! LP_Settings::get_option( 'hide_admin_bar_for_instructor', 'no' ) ) {
55 return $show_admin_bar;
56 }
57
58 return $show_admin_bar;
59 }
60
61 /**
62 * Allow callback for AJAX.
63 * @use self::render_html_comments
64 *
65 * @param array $callbacks
66 *
67 * @return array
68 */
69 /*public function allow_callback( array $callbacks ): array {
70 $callbacks[] = get_class( $this ) . ':sidebar';
71
72 return $callbacks;
73 }*/
74
75 /**
76 * Layout for Course Builder.
77 *
78 * @since 4.3.6
79 * @version 1.0.0
80 */
81 public function layout() {
82 try {
83 // Enqueue assets(js,css) for Course Builder
84 //$this->enqueue_assets();
85
86 // Check permission
87 $user_id = get_current_user_id();
88 $userModel = UserModel::find( $user_id, true );
89 if ( ! $userModel || ! $userModel->is_instructor() ) {
90 throw new Exception( __( "Sorry, you don't have permission to access Course Builder", 'learnpress' ) );
91 }
92
93 $data = [
94 'userModel' => $userModel,
95 ];
96
97 $layout = [
98 'wrapper' => '<div class="learn-press-course-builder">',
99 'header' => $this->html_header( $data ),
100 'body' => '<div class="lp-cb-body">',
101 'sidebar' => $this->html_sidebar( $data ),
102 'content' => $this->html_content( $data ),
103 'body_end' => '</div>',
104 'wrapper_end' => '</div>',
105 ];
106
107 echo Template::combine_components( $layout );
108 } catch ( Throwable $e ) {
109 Template::print_message(
110 wp_kses_post( $e->getMessage() ),
111 'error'
112 );
113 }
114 }
115
116 /**
117 * Enqueue scripts, styles and localize data for Course Builder.
118 *
119 * @since 4.3.x
120 * @version 1.0.0
121 */
122 protected function enqueue_assets() {}
123
124 /**
125 * Auto-detect and dequeue all theme/child-theme stylesheets.
126 * Prevents theme CSS from interfering with Course Builder styles.
127 *
128 * Hooked to `wp_enqueue_scripts` at priority 9999 so it runs DURING wp_head(),
129 * after themes have enqueued their styles but before they are printed.
130 *
131 * Only removes styles whose source URL is within the theme or child-theme directory.
132 * WP core styles, plugin styles, and other assets remain untouched.
133 *
134 * @since 4.3.0
135 * @version 1.0.0
136 */
137 /*public function dequeue_theme_styles() {
138 global $wp_styles, $wp_scripts;
139
140 if ( ! LP_Page_Controller::is_page_course_builder() ) {
141 return;
142 }
143
144 $allowed_styles = apply_filters(
145 'learn-press/course-builder/allowed-styles',
146 [
147 'dashicons',
148 'admin-bar',
149 'buttons',
150 'media-views',
151 'wp-components',
152 'wp-block-library',
153 'wp-editor',
154 'wp-edit-post',
155 'wp-block-editor',
156 'wp-components',
157 'wp-editor',
158 'wp-nux',
159 'wp-notices',
160 ]
161 );
162
163 $allowed_scripts = apply_filters(
164 'learn-press/course-builder/allowed-scripts',
165 [
166 'jquery',
167 'jquery-core',
168 'jquery-migrate',
169 'jquery-ui-core',
170 'jquery-ui-widget',
171 'wp-api-fetch',
172 'wp-i18n',
173 'wp-components',
174 'wp-element',
175 'react',
176 'react-dom',
177 'wp-polyfill',
178 'wp-hooks',
179 'lodash',
180 'moment',
181 'heartbeat',
182 'wp-data',
183 'wp-core-data',
184 'wp-url',
185 'wp-api',
186 'wp-block-editor',
187 'wp-blocks',
188 'wp-media-utils',
189 'wp-compose',
190 'regenerator-runtime',
191 'wp-a11y',
192 ]
193 );
194
195 if ( ! empty( $wp_styles->queue ) ) {
196 foreach ( $wp_styles->queue as $handle ) {
197 if ( ! in_array( $handle, $allowed_styles ) && strpos( $handle, 'lp-' ) !== 0 && strpos( $handle, 'learn-press' ) !== 0 && strpos( $handle, 'learnpress' ) !== 0 ) {
198 wp_dequeue_style( $handle );
199 }
200 }
201 }
202
203 if ( ! empty( $wp_scripts->queue ) ) {
204 foreach ( $wp_scripts->queue as $handle ) {
205 if ( ! in_array( $handle, $allowed_scripts ) && strpos( $handle, 'lp-' ) !== 0 && strpos( $handle, 'learn-press' ) !== 0 && strpos( $handle, 'learnpress' ) !== 0 ) {
206 wp_dequeue_script( $handle );
207 }
208 }
209 }
210 }*/
211
212 /**
213 * Header with logo and user profile
214 *
215 * @param array $data
216 *
217 * @return string
218 * @throws Exception
219 * @version 1.0.0
220 * @since 4.3.6
221 */
222 protected function html_header( array $data = [] ): string {
223 /** @var UserModel $userModel */
224 $userModel = $data['userModel'] ?? false;
225 if ( ! $userModel ) {
226 return '';
227 }
228
229 $avatar = $userModel->get_avatar_url();
230 $display_name = $userModel->get_display_name();
231 $profile = LP_Profile::instance( $userModel->get_id() );
232 $profile_url = $profile->get_tab_link();
233 $logout_url = wp_logout_url( home_url() );
234 $logo_id = absint( LP_Settings::get_option( 'course_builder_logo_id', 0 ) );
235
236 if ( $logo_id ) {
237 $custom_logo = wp_get_attachment_image(
238 $logo_id,
239 'full',
240 false,
241 [
242 'class' => 'lp-cb-top-header__logo-image',
243 'alt' => __( 'Course Builder', 'learnpress' ),
244 'loading' => 'eager',
245 'decoding' => 'async',
246 ]
247 );
248 }
249
250 $header = [
251 'wrapper' => '<header class="lp-cb-top-header">',
252 'logo' => sprintf(
253 '<div class="lp-cb-top-header__logo">
254 <a href="%s">%s</a>
255 </div>',
256 esc_url( CourseBuilder::get_link_course_builder() ),
257 $custom_logo ?? LP_WP_Filesystem::get_icon_svg( 'ico-logo-course-builder.svg' ),
258 ),
259 'user' => sprintf(
260 '<div class="lp-cb-top-header__user">
261 <div class="lp-cb-top-header__user-avatar">
262 <img src="%s" class="lp-cb-top-header__user-avatar-image">
263 <span class="lp-cb-top-header__online-dot"></span>
264 </div>
265 <div class="lp-cb-top-header__user-info">
266 <span class="lp-cb-top-header__user-name">%s</span>
267 <a href="%s" class="lp-cb-top-header__user-link" target="_blank">%s</a>
268 </div>
269 <a href="%s" class="lp-cb-top-header__logout" title="%s">
270 %s
271 </a>
272 </div>',
273 $avatar,
274 esc_html( $display_name ),
275 esc_url( $profile_url ),
276 __( 'View Profile', 'learnpress' ),
277 esc_url( $logout_url ),
278 __( 'Logout', 'learnpress' ),
279 LP_WP_Filesystem::get_icon_svg( 'ico-logout.svg' ),
280 ),
281 'wrapper_end' => '</header>',
282 ];
283
284 return Template::combine_components( $header );
285 }
286
287 /**
288 * HTML Sidebar
289 *
290 * @param array $data
291 *
292 * @return string
293 */
294 public function html_sidebar( array $data = [] ): string {
295 $userModel = $data['userModel'] ?? false;
296 if ( ! $userModel ) {
297 return '';
298 }
299
300 $tabs = CourseBuilder::get_menus_arr();
301 $nav_content = '';
302 $is_admin = current_user_can( ADMIN_ROLE );
303
304 $tabs = array_filter(
305 $tabs,
306 static function ( array $tab ) use ( $is_admin ): bool {
307 if ( ! empty( $tab['admin_only'] ) && ! $is_admin ) {
308 return false;
309 }
310
311 return true;
312 }
313 );
314
315 usort(
316 $tabs,
317 static function ( array $a, array $b ): int {
318 $a_priority = isset( $a['priority'] ) && is_numeric( $a['priority'] ) ? (int) $a['priority'] : PHP_INT_MAX;
319 $b_priority = isset( $b['priority'] ) && is_numeric( $b['priority'] ) ? (int) $b['priority'] : PHP_INT_MAX;
320
321 return $a_priority <=> $b_priority;
322 }
323 );
324
325 foreach ( $tabs as $tab ) {
326 $slug = $tab['slug'];
327 $nav_item = $this->html_nav_item_main( $slug, $tab );
328 $nav_content .= $nav_item;
329 }
330
331 $nav = [
332 'wrapper' => '<ul class="lp-cb-sidebar__nav">',
333 'content' => $nav_content,
334 'wrapper_end' => '</ul>',
335 ];
336
337 $sidebar_toggle_icon = LP_WP_Filesystem::get_icon_svg( 'ico-cb-sidebar-toggle.svg' );
338 $toggle = sprintf(
339 '<button type="button" class="lp-cb-sidebar__toggle" aria-label="%s" title="%s">
340 %s
341 </button>',
342 esc_attr__( 'Toggle Sidebar', 'learnpress' ),
343 esc_attr__( 'Toggle Sidebar', 'learnpress' ),
344 $sidebar_toggle_icon
345 );
346
347 $sidebar = [
348 'wrapper' => '<aside id="lp-course-builder-sidebar" class="lp-cb-sidebar">',
349 'nav' => Template::combine_components( $nav ),
350 'toggle' => $toggle,
351 'footer' => $this->sidebar_footer( $data ),
352 'wrapper_end' => '</aside>',
353 ];
354
355 return Template::combine_components( $sidebar );
356 }
357
358 /**
359 * HTML main content area
360 *
361 * @param array $data
362 *
363 * @return string
364 * @throws Exception
365 * @version 1.0.1
366 * @since 4.3.6
367 */
368 public function html_content( array $data = [] ): string {
369 $userModel = $data['userModel'] ?? false;
370 if ( ! $userModel ) {
371 return '';
372 }
373
374 $menu_current = CourseBuilder::get_menu_current();
375
376 //Switch layout display by menu, via model, @since 4.3.7
377 switch ( $menu_current ) {
378 case self::MENU_COURSES:
379 $content = BuilderCourseTemplate::instance()->layout( $data );
380 break;
381 default:
382 if ( has_action( "learn-press/course-builder/{$menu_current}/layout" ) ) {
383 // Hook old @since 4.3.6.
384 ob_start();
385 do_action( "learn-press/course-builder/{$menu_current}/layout", $data );
386 $content = ob_get_clean();
387 } else {
388 // Hook new @since 4.3.7.
389 $content = apply_filters( 'learn-press/course-builder/content/layout', '', $menu_current, $data );
390 }
391 break;
392 }
393
394 $output = [
395 'wrapper' => '<div id="lp-course-builder-content" class="lp-cb-main">',
396 'content' => $content,
397 'wrapper_end' => '</div>',
398 ];
399
400 return Template::combine_components( $output );
401 }
402
403 /**
404 * Sidebar footer with "Back to Dashboard" link
405 *
406 * @param array $data
407 *
408 * @return string
409 * @since 4.3.0
410 */
411 protected function sidebar_footer( array $data = [] ): string {
412 $userModel = $data['userModel'] ?? false;
413 if ( ! $userModel instanceof UserModel ) {
414 return '';
415 }
416
417 $hide_instructor_access_admin_screen = LP_Settings::is_hide_instructor_access_admin_screen();
418 $wp_user = new WP_User( $userModel );
419 $is_instructor = user_can( $wp_user, UserModel::ROLE_INSTRUCTOR );
420 $dashboard_url = admin_url();
421
422 $footer = [
423 'wrapper' => '<div class="lp-cb-sidebar__footer">',
424 ];
425
426 // Hide "Back to WordPress" for instructors when CB admin mode is on
427 // Admins always see this link
428 $hide_back_link = $hide_instructor_access_admin_screen && $is_instructor;
429
430 if ( ! $hide_back_link ) {
431 $back_to_wp_text = __( 'Back to WordPress', 'learnpress' );
432
433 $footer['back'] = sprintf(
434 '<a href="%s" class="lp-cb-sidebar__item lp-cb-sidebar__back" title="%s" aria-label="%s">
435 <span class="dashicons dashicons-wordpress"></span>
436 <span class="lp-cb-sidebar__item-title">%s</span>
437 </a>',
438 esc_url( $dashboard_url ),
439 esc_attr( $back_to_wp_text ),
440 esc_attr( $back_to_wp_text ),
441 esc_html( $back_to_wp_text )
442 );
443 }
444
445 $footer['wrapper_end'] = '</div>';
446
447 return Template::combine_components( $footer );
448 }
449
450 /**
451 * Render main navigation item (persistent sidebar)
452 *
453 * @param string $slug
454 * @param array $tab_data
455 *
456 * @return string
457 * @since 4..0
458 */
459 protected function html_nav_item_main( $slug, $tab_data ) {
460 $tab_current = CourseBuilder::get_menu_current();
461 $is_active = $slug === $tab_current;
462 $classes = [ 'lp-cb-sidebar__item', $slug ];
463
464 if ( $is_active ) {
465 $classes[] = 'is-active';
466 }
467
468 $icon = isset( $tab_data['icon'] ) ? $tab_data['icon'] : '';
469 $title = $tab_data['title'];
470 $link = CourseBuilder::get_tab_link( $slug );
471
472 $item = [
473 'wrapper' => sprintf( '<li class="%s">', implode( ' ', $classes ) ),
474 'content' => sprintf(
475 '<a href="%s" title="%s" aria-label="%s">
476 %s
477 <span class="lp-cb-sidebar__item-title">%s</span>
478 </a>',
479 esc_url( $link ),
480 esc_attr( $title ),
481 esc_attr( $title ),
482 $icon,
483 esc_html( $title )
484 ),
485 'wrapper_end' => '</li>',
486 ];
487
488 return Template::combine_components( $item );
489 }
490
491 public function html_btn_add_new() {
492 $tab_current = CourseBuilder::get_menu_current();
493 $map_title = [
494 'courses' => __( 'Course', 'learnpress' ),
495 'lessons' => __( 'Lesson', 'learnpress' ),
496 'quizzes' => __( 'Quiz', 'learnpress' ),
497 'questions' => __( 'Question', 'learnpress' ),
498 ];
499
500 $map_type = [
501 'lessons' => 'lesson',
502 'quizzes' => 'quiz',
503 'questions' => 'question',
504 ];
505
506 $title = isset( $map_title[ $tab_current ] ) ? $map_title[ $tab_current ] : '';
507 $type = isset( $map_type[ $tab_current ] ) ? $map_type[ $tab_current ] : '';
508 $add_new = 'data-add-new-' . esc_attr( $type );
509 $template_html = '';
510 $template_attr = '';
511
512 $btn_add_new = sprintf( '<button %s class="lp-button cb-btn-add-new">', $add_new );
513 $btn_close = '</button>';
514
515 if ( 'lessons' === $tab_current ) {
516 $template_id = 'lp-tmpl-builder-popup-lesson-tab-new';
517 $template_attr = sprintf(
518 ' data-template="#%1$s" data-popup-type="lesson" data-popup-id="0"',
519 esc_attr( $template_id )
520 );
521 $template_html = sprintf(
522 '<script type="text/template" id="%1$s"><div class="lp-builder-popup-overlay"></div><div class="lp-builder-popup lp-builder-popup--loading">%2$s</div></script>',
523 esc_attr( $template_id ),
524 TemplateAJAX::load_content_via_ajax(
525 [
526 'id_url' => 'builder-popup-lesson-tab-new',
527 'lesson_id' => 0,
528 'html_no_load_ajax_first' => sprintf(
529 '<div class="lp-builder-popup__loader"><div class="lp-loading-circle"></div><span>%s</span></div>',
530 esc_html__( 'Loading...', 'learnpress' )
531 ),
532 ],
533 [
534 'class' => BuilderPopupTemplate::class,
535 'method' => 'render_lesson_popup',
536 ]
537 )
538 );
539 }
540
541 if ( 'courses' === $tab_current ) {
542 $btn_add_new = sprintf(
543 '<a href="%s" class="lp-button cb-btn-add-new">',
544 esc_url( CourseBuilder::get_link_add_new( 'courses' ) )
545 );
546 $btn_close = '</a>';
547 }
548
549 if ( 'quizzes' === $tab_current ) {
550 $btn_add_new = sprintf(
551 '<a href="%s" class="lp-button cb-btn-add-new">',
552 esc_url( CourseBuilder::get_link_add_new( 'quizzes' ) )
553 );
554 $btn_close = '</a>';
555 }
556
557 if ( 'questions' === $tab_current ) {
558 $btn_add_new = sprintf(
559 '<a href="%s" class="lp-button cb-btn-add-new">',
560 esc_url( CourseBuilder::get_link_add_new( 'questions' ) )
561 );
562 $btn_close = '</a>';
563 }
564
565 $btn = [
566 'wrapper' => str_replace( '>', $template_attr . '>', $btn_add_new ),
567 'content' => sprintf( '%s %s', __( 'Add New', 'learnpress' ), $title ),
568 'wrapper_end' => $btn_close,
569 'template' => $template_html,
570 ];
571 $btn = apply_filters( 'learn-press/course-builder/button-add-new', $btn, $tab_current, $type );
572
573 return Template::combine_components( $btn );
574 }
575
576 /**
577 * Show link to Course Builder in admin bar
578 */
579 public function add_admin_bar_menu( $wp_admin_bar ) {
580 $href = CourseBuilder::get_link_course_builder();
581 $title = esc_html__( 'Course Builder', 'learnpress' );
582
583 // Check if on frontend single course page
584 if ( is_singular( LP_COURSE_CPT ) && get_the_ID() ) {
585 $title = esc_html__( 'Edit with Course Builder', 'learnpress' );
586 $href = BuilderCourseTemplate::instance()->get_link_edit( get_the_ID() );
587 }
588
589 // Check if on admin edit course page (post.php or post-new.php)
590 if ( is_admin() ) {
591 global $post, $pagenow;
592 if ( in_array( $pagenow, array( 'post.php', 'post-new.php' ), true ) ) {
593 $post_type = '';
594 if ( isset( $_GET['post_type'] ) ) {
595 $post_type = sanitize_text_field( wp_unslash( $_GET['post_type'] ) );
596 } elseif ( isset( $_GET['post'] ) ) {
597 $post_id = absint( $_GET['post'] );
598 $post_type = get_post_type( $post_id );
599 } elseif ( $post && isset( $post->post_type ) ) {
600 $post_type = $post->post_type;
601 }
602
603 if ( LP_COURSE_CPT === $post_type ) {
604 $title = esc_html__( 'Edit with Course Builder', 'learnpress' );
605 if ( isset( $_GET['post'] ) ) {
606 $href = BuilderCourseTemplate::instance()->get_link_edit( $_GET['post'] );
607 } else {
608 $href = CourseBuilder::get_link_add_new( 'courses' );
609 }
610 }
611 }
612 }
613
614 $admin_bar_icon = LP_WP_Filesystem::get_icon_svg( 'ico-cb-admin-bar.svg' );
615
616 $wp_admin_bar->add_node(
617 array(
618 'id' => 'lp-course-builder',
619 'title' => sprintf(
620 '<span class="lp-cb-admin-bar-icon">%1$s</span><span class="ab-label">%2$s</span>',
621 $admin_bar_icon,
622 $title
623 ),
624 'href' => $href,
625 )
626 );
627 }
628 }
629