sidebar.php
302 lines
| 1 | <?php |
| 2 | /** |
| 3 | * Tutor learning area sidebar. |
| 4 | * |
| 5 | * @package Tutor\Templates |
| 6 | * @author Themeum <support@themeum.com> |
| 7 | * @link https://themeum.com |
| 8 | * @since 4.0.0 |
| 9 | */ |
| 10 | |
| 11 | defined( 'ABSPATH' ) || exit; |
| 12 | |
| 13 | use Tutor\Components\Button; |
| 14 | use Tutor\Components\Constants\Size; |
| 15 | use Tutor\Components\Constants\Variant; |
| 16 | use Tutor\Components\ConfirmationModal; |
| 17 | use Tutor\Components\Popover; |
| 18 | use Tutor\Components\Progress; |
| 19 | use Tutor\Components\Tooltip; |
| 20 | use TUTOR\Icon; |
| 21 | use Tutor\Components\SvgIcon; |
| 22 | use Tutor\Components\Constants\Color; |
| 23 | use TUTOR\Course; |
| 24 | use TUTOR\Template; |
| 25 | |
| 26 | global $tutor_course, |
| 27 | $current_user_id, |
| 28 | $tutor_course_id, |
| 29 | $tutor_course_list_url, |
| 30 | $tutor_current_content_id, |
| 31 | $tutor_is_enrolled, |
| 32 | $tutor_is_public_course, |
| 33 | $tutor_is_course_instructor, |
| 34 | $tutor_current_post, |
| 35 | $tutor_course_progress, |
| 36 | $tutor_is_course_completed, |
| 37 | $tutor_can_complete_course, |
| 38 | $tutor_can_retake_course, |
| 39 | $course_complete_modal_id, |
| 40 | $course_retake_modal_id; |
| 41 | |
| 42 | $is_preview = get_post_meta( $tutor_current_post->ID, '_is_preview', true ); |
| 43 | $current_url = trailingslashit( $tutor_course_list_url ) . $tutor_course->post_name; |
| 44 | |
| 45 | $menu_items = Template::make_learning_area_sub_page_nav_items( $current_url ); |
| 46 | $active_menu = Template::learning_area_active_subpage(); |
| 47 | |
| 48 | $course_reset_progress = tutor_utils()->get_option( 'course_reset_progress', false ); |
| 49 | $reset_modal_id = 'tutor-course-reset-progress-modal'; |
| 50 | |
| 51 | ?> |
| 52 | <div |
| 53 | class="tutor-learning-sidebar" |
| 54 | x-data="tutorLearningSidebar({ courseId: <?php echo (int) $tutor_course->ID; ?>, resetModalId: '<?php echo esc_attr( $reset_modal_id ); ?>' })" |
| 55 | x-trap.noscroll="sidebarOpen" |
| 56 | :class="{ 'is-open': sidebarOpen }" |
| 57 | @click.outside="closeSidebar()" |
| 58 | @toggle-sidebar.window="toggleSidebar()" |
| 59 | > |
| 60 | <div class="tutor-hidden tutor-lg-flex tutor-items-center tutor-px-4"> |
| 61 | <h5 class="tutor-learning-header-title tutor-my-none"> |
| 62 | <?php echo esc_html( $tutor_course->post_title ); ?> |
| 63 | </h5> |
| 64 | <div class="tutor-learning-header-toggle-mobile"> |
| 65 | <?php |
| 66 | Button::make() |
| 67 | ->label( __( 'Close course sidebar', 'tutor' ) ) |
| 68 | ->variant( Variant::GHOST ) |
| 69 | ->size( Size::SMALL ) |
| 70 | ->icon( Icon::CROSS_2, 'left', 20 ) |
| 71 | ->icon_only() |
| 72 | ->attr( '@click.stop', '$dispatch(\'toggle-sidebar\')' ) |
| 73 | ->render(); |
| 74 | ?> |
| 75 | </div> |
| 76 | </div> |
| 77 | <div class="tutor-learning-sidebar-curriculum"> |
| 78 | <div class="tutor-learning-progress"> |
| 79 | <div class="tutor-learning-progress-content"> |
| 80 | <div class="tutor-learning-progress-text tutor-py-2"> |
| 81 | <?php |
| 82 | // translators: %s: course completed percentage. |
| 83 | printf( esc_html__( '%s Completed', 'tutor' ), '<span>' . esc_html( $tutor_course_progress ) . '%</span>' ); |
| 84 | ?> |
| 85 | </div> |
| 86 | <div class="tutor-flex"> |
| 87 | <?php |
| 88 | if ( $course_reset_progress && ! $tutor_is_course_completed ) { |
| 89 | Button::make() |
| 90 | ->label( __( 'Reset Progress', 'tutor' ) ) |
| 91 | ->variant( Variant::GHOST ) |
| 92 | ->size( Size::X_SMALL ) |
| 93 | ->icon( Icon::RELOAD_2, 'left', 16, Color::SECONDARY ) |
| 94 | ->icon_only() |
| 95 | ->attr( '@click', 'confirmReset()' ) |
| 96 | ->render(); |
| 97 | |
| 98 | ConfirmationModal::make() |
| 99 | ->id( $reset_modal_id ) |
| 100 | ->title( __( 'Reset Course Progress?', 'tutor' ) ) |
| 101 | ->message( __( 'This will remove your completed lessons, quizzes, and assignments. You will start the course from the beginning.', 'tutor' ) ) |
| 102 | ->cancel_text( __( 'No, Keep My Progress', 'tutor' ) ) |
| 103 | ->confirm_text( __( 'Yes, Reset Everything', 'tutor' ) ) |
| 104 | ->icon( tutor_utils()->get_themed_svg( 'images/illustrations/reset-course.svg' ), 80, 80, ConfirmationModal::ICON_TYPE_HTML ) |
| 105 | ->confirm_handler( 'resetProgress()' ) |
| 106 | ->mutation_state( 'resetProgressMutation' ) |
| 107 | ->render(); |
| 108 | } |
| 109 | ?> |
| 110 | </div> |
| 111 | </div> |
| 112 | <?php |
| 113 | Progress::make() |
| 114 | ->value( $tutor_course_progress ) |
| 115 | ->type( 'bar' ) |
| 116 | ->render(); |
| 117 | ?> |
| 118 | </div> |
| 119 | <div class="tutor-learning-nav" role="navigation"> |
| 120 | <?php |
| 121 | $topics = tutor_utils()->get_topics( $tutor_course->ID ); |
| 122 | if ( $topics->have_posts() ) { |
| 123 | while ( $topics->have_posts() ) { |
| 124 | $topics->the_post(); |
| 125 | $topic_id = get_the_ID(); |
| 126 | $topic_summery = get_the_content(); |
| 127 | $total_contents = tutor_utils()->count_completed_contents_by_topic( $topic_id ); |
| 128 | $course_contents = tutor_utils()->get_course_contents_by_topic( get_the_ID(), -1 ); |
| 129 | $is_topic_active = ! empty( |
| 130 | array_filter( |
| 131 | $course_contents->posts, |
| 132 | function ( $content ) use ( $tutor_current_post ) { |
| 133 | return $content->ID === $tutor_current_post->ID; |
| 134 | } |
| 135 | ) |
| 136 | ); |
| 137 | ?> |
| 138 | |
| 139 | <div |
| 140 | x-data="{ expanded: <?php echo esc_attr( ( $is_topic_active || ( 0 === $topics->current_post && ! empty( $active_menu ) ) ) ? 'true' : 'false' ); ?> }" |
| 141 | class="tutor-learning-nav-topic <?php echo esc_attr( $is_topic_active ? 'active' : '' ); ?>" |
| 142 | :class="{ 'expanded': expanded }" |
| 143 | > |
| 144 | <div |
| 145 | role="button" |
| 146 | tabindex="0" |
| 147 | @click="expanded = !expanded" |
| 148 | @keydown.enter.prevent="expanded = !expanded" |
| 149 | @keydown.space.prevent="expanded = !expanded" |
| 150 | :aria-expanded="expanded ? 'true' : 'false'" |
| 151 | class="tutor-learning-nav-header" |
| 152 | > |
| 153 | <div class="tutor-learning-nav-header-progress"> |
| 154 | <?php |
| 155 | Progress::make() |
| 156 | ->value( $total_contents['percentage'] ?? 0 ) |
| 157 | ->type( 'circle' ) |
| 158 | ->size( Size::X_SMALL ) |
| 159 | ->show_label( false ) |
| 160 | ->background( 'var(--tutor-actions-gray-empty)' ) |
| 161 | ->stroke_color( 'var(--tutor-border-hover)' ) |
| 162 | ->render(); |
| 163 | ?> |
| 164 | </div> |
| 165 | <div class="tutor-learning-nav-header-title" title="<?php the_title(); ?>"> |
| 166 | <?php the_title(); ?> |
| 167 | </div> |
| 168 | <div class="tutor-learning-nav-header-actions"> |
| 169 | <?php if ( ! empty( $topic_summery ) ) : ?> |
| 170 | <div class="tutor-learning-nav-header-summary"> |
| 171 | <?php |
| 172 | Tooltip::make() |
| 173 | ->content( $topic_summery ) |
| 174 | ->trigger_element( SvgIcon::make()->name( Icon::INFO_OCTAGON )->size( 16 )->color( Color::SECONDARY )->get() ) |
| 175 | ->size( Size::LARGE ) |
| 176 | ->arrow( Tooltip::ARROW_CENTER ) |
| 177 | ->render(); |
| 178 | ?> |
| 179 | </div> |
| 180 | <?php endif; ?> |
| 181 | <div class="tutor-learning-nav-header-arrow" :class="{ 'is-expanded': expanded }"> |
| 182 | <?php SvgIcon::make()->name( Icon::CHEVRON_DOWN_2 )->size( 20 )->render(); ?> |
| 183 | </div> |
| 184 | </div> |
| 185 | </div> |
| 186 | <div x-show="expanded" x-collapse x-cloak class="tutor-learning-nav-body"> |
| 187 | <?php |
| 188 | // Backward compatible hook. |
| 189 | do_action( 'tutor/lesson_list/before/topic', $topic_id ); |
| 190 | // Loop through lesson, quiz, assignment, zoom lesson. |
| 191 | while ( $course_contents->have_posts() ) { |
| 192 | $course_contents->the_post(); |
| 193 | |
| 194 | $topic_item = get_post(); |
| 195 | |
| 196 | $can_access = ! $is_preview || $tutor_is_enrolled || get_post_meta( $topic_item->ID, '_is_preview', true ) || $tutor_is_public_course || $tutor_is_course_instructor; |
| 197 | $can_access = apply_filters( 'tutor_course/single/content/show_permalink', $can_access, get_the_ID() ); |
| 198 | $can_access = null === $can_access ? true : $can_access; |
| 199 | |
| 200 | // Rendered the nav item using hook from their respective files. |
| 201 | do_action( 'tutor_learning_area_nav_item_' . $topic_item->post_type, $topic_item, $can_access ); |
| 202 | } |
| 203 | $course_contents->reset_postdata(); |
| 204 | do_action( 'tutor/lesson_list/after/topic', $topic_id ); // Backward compatible hook. |
| 205 | ?> |
| 206 | </div> |
| 207 | </div> |
| 208 | <?php |
| 209 | } |
| 210 | wp_reset_postdata(); |
| 211 | } |
| 212 | ?> |
| 213 | </div> |
| 214 | </div> |
| 215 | <div class="tutor-learning-sidebar-pages <?php echo ! empty( $active_menu ) ? 'expanded' : ''; ?>"> |
| 216 | <?php if ( ! empty( $active_menu ) ) : ?> |
| 217 | <div class="tutor-sidebar-resizer" @mousedown="startResizing($event)"></div> |
| 218 | <div class="tutor-sidebar-restore-dropdown"> |
| 219 | <button |
| 220 | :class="{ 'is-minimized': pagesHeight && pagesHeight <= 40 }" |
| 221 | @click="togglePagesHeight()" |
| 222 | :aria-expanded="pagesHeight > 40 ? 'true' : 'false'" |
| 223 | :aria-label="pagesHeight <= 40 ? '<?php echo esc_js( __( 'Expand panel', 'tutor' ) ); ?>' : '<?php echo esc_js( __( 'Collapse panel', 'tutor' ) ); ?>'" |
| 224 | > |
| 225 | <?php SvgIcon::make()->name( Icon::CHEVRON_DOWN_2 )->render(); ?> |
| 226 | </button> |
| 227 | </div> |
| 228 | <?php endif; ?> |
| 229 | <div class="tutor-learning-pages" x-ref="pagesList" :class="{ 'is-resizing': resizing }" <?php echo ! empty( $active_menu ) ? ':style="pagesHeight !== null ? { height: pagesHeight + \'px\' } : {}"' : ''; ?>> |
| 230 | <?php |
| 231 | ob_start(); |
| 232 | foreach ( $menu_items as $key => $item ) { |
| 233 | $active_class = ( $key === $active_menu ) ? 'active' : ''; |
| 234 | ?> |
| 235 | <a href="<?php echo esc_url( $item['url'] ); ?>" |
| 236 | class="tutor-learning-pages-item <?php echo esc_attr( $active_class ); ?>" |
| 237 | <?php if ( isset( $item['onclick'] ) ) : ?> |
| 238 | onclick="<?php echo esc_attr( $item['onclick'] ); ?>" |
| 239 | <?php endif; ?> |
| 240 | > |
| 241 | <?php if ( isset( $item['locked'] ) ) : ?> |
| 242 | <?php |
| 243 | SvgIcon::make() |
| 244 | ->name( Icon::LOCK_CIRCLE ) |
| 245 | ->size( 12 ) |
| 246 | ->attr( 'class', 'tutor-lock-icon' ) |
| 247 | ->render(); |
| 248 | ?> |
| 249 | <?php endif; ?> |
| 250 | <?php SvgIcon::make()->name( $item['icon'] )->size( 20 )->render(); ?> |
| 251 | <?php echo esc_html( $item['title'] ); ?> |
| 252 | </a> |
| 253 | <?php |
| 254 | } |
| 255 | $menu_html = ob_get_clean(); |
| 256 | ?> |
| 257 | |
| 258 | <?php if ( empty( $active_menu ) ) : ?> |
| 259 | <div> |
| 260 | <?php |
| 261 | $allowed_html = wp_kses_allowed_html( 'post' ); |
| 262 | if ( isset( $allowed_html['a'] ) ) { |
| 263 | $allowed_html['a']['onclick'] = true; |
| 264 | } |
| 265 | |
| 266 | Popover::make() |
| 267 | ->body( $menu_html, $allowed_html ) |
| 268 | ->trigger( |
| 269 | Button::make() |
| 270 | ->variant( Variant::GHOST ) |
| 271 | ->label( __( 'More', 'tutor' ) ) |
| 272 | ->icon( Icon::MORE, 'left', 20 ) |
| 273 | ->attr( 'class', 'tutor-learning-pages-item' ) |
| 274 | ->attr( 'x-ref', 'trigger' ) |
| 275 | ->attr( '@click', 'toggle()' ) |
| 276 | ->get() |
| 277 | ) |
| 278 | ->render(); |
| 279 | ?> |
| 280 | </div> |
| 281 | <?php else : ?> |
| 282 | <div class="tutor-learning-pages-nav"> |
| 283 | <?php echo $menu_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> |
| 284 | </div> |
| 285 | <?php endif; ?> |
| 286 | </div> |
| 287 | </div> |
| 288 | <?php if ( $tutor_is_enrolled ) : ?> |
| 289 | <div class="tutor-hidden tutor-md-flex tutor-flex-column tutor-gap-2"> |
| 290 | <?php |
| 291 | $incomplete_msg = Course::get_course_completion_restrict_msg( $tutor_course_id, $current_user_id ); |
| 292 | if ( $tutor_can_complete_course || $incomplete_msg ) { |
| 293 | Course::render_course_complete_btn( $course_complete_modal_id, $tutor_course_id, $tutor_course_progress, Size::MEDIUM, $incomplete_msg ?? '', true ); |
| 294 | } |
| 295 | if ( $tutor_can_retake_course ) { |
| 296 | Course::render_course_retake_btn( $course_retake_modal_id, Size::MEDIUM, true ); |
| 297 | } |
| 298 | ?> |
| 299 | </div> |
| 300 | <?php endif; ?> |
| 301 | </div> |
| 302 |