PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.3.9
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.3.9
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 4.2.1 All 138 releases
learnpress / inc / TemplateHooks / Course / ListCoursesTemplate.php

ListCoursesTemplate.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.3.9, at inc/TemplateHooks/Course/ListCoursesTemplate.php

922 lines 27.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Template hooks List Courses.
4 *
5 * @since 4.2.3.2
6 * @version 1.0.3
7 */
8
9 namespace LearnPress\TemplateHooks\Course;
10
11 use LearnPress\Helpers\Singleton;
12 use LearnPress\Helpers\Template;
13 use LearnPress\Models\CourseModel;
14 use LearnPress\Models\Courses;
15 use LearnPress\Models\UserItems\UserCourseModel;
16 use LearnPress\TemplateHooks\TemplateAJAX;
17 use LP_Course;
18 use LP_Course_Filter;
19 use LP_Database;
20 use LP_Settings;
21 use LP_Settings_Courses;
22 use LP_User_Items_DB;
23 use LP_User_Items_Filter;
24 use LP_WP_Filesystem;
25 use stdClass;
26 use Throwable;
27 use WP_Term;
28
29 class ListCoursesTemplate {
30 use Singleton;
31
32 public function init() {
33 add_action( 'learn-press/list-courses/layout', [ $this, 'layout_courses' ] );
34 add_action( 'learn-press/rest-api/courses/suggest/layout', [ $this, 'sections_course_suggest' ] );
35 add_action( 'learn-press/archive-course/sidebar', [ $this, 'sidebar' ] );
36 add_filter( 'lp/rest/ajax/allow_callback', [ $this, 'allow_callback' ] );
37 }
38
39 public function allow_callback( $callbacks ) {
40 /**
41 * @uses self::render_courses()
42 */
43 $callbacks[] = get_class( $this ) . ':render_courses';
44
45 return $callbacks;
46 }
47
48 /**
49 * Layout default list courses.
50 *
51 * @return void
52 * @since 4.2.5.8
53 * @version 1.0.1
54 */
55 public function layout_courses() {
56 $html_wrapper = [
57 '<div class="lp-list-courses-default">' => '</div>',
58 ];
59
60 $callback = [
61 'class' => get_class( $this ),
62 'method' => 'render_courses',
63 ];
64
65 $args = lp_archive_skeleton_get_args();
66 $args['id_url'] = 'list-courses-default';
67 $args['courses_load_ajax'] = LP_Settings_Courses::is_ajax_load_courses() ? 1 : 0;
68 $args['courses_first_no_ajax'] = LP_Settings_Courses::is_no_load_ajax_first_courses() ? 1 : 0;
69
70 // Load list courses via AJAX.
71 if ( LP_Settings_Courses::is_ajax_load_courses() && ! LP_Settings_Courses::is_no_load_ajax_first_courses() ) {
72 $content = TemplateAJAX::load_content_via_ajax( $args, $callback );
73 } else { // Load courses first not AJAX, or for filter.
74 $content_obj = static::render_courses( $args );
75 $args['html_no_load_ajax_first'] = $content_obj->content;
76 $content = TemplateAJAX::load_content_via_ajax( $args, $callback );
77 }
78
79 echo Template::instance()->nest_elements( $html_wrapper, $content );
80 }
81
82 /**
83 * Render template list courses with settings param.
84 *
85 * @param array $settings
86 *
87 * @return stdClass { content: string_html }
88 * @since 4.2.5.7
89 * @version 1.0.5
90 */
91 public static function render_courses( array $settings = [] ): stdClass {
92 $filter = new LP_Course_Filter();
93 Courses::handle_params_for_query_courses( $filter, $settings );
94
95 $total_rows = 0;
96 $courses = Courses::get_courses( $filter, $total_rows );
97 $total_pages = LP_Database::get_total_pages( $filter->limit, $total_rows );
98 $settings['total_pages'] = $total_pages;
99 $settings['total_rows'] = $total_rows;
100 $settings['courses_per_page'] = $filter->limit;
101 $skin = $settings['skin'] ?? ( wp_is_mobile() ? 'grid' : learn_press_get_courses_layout() );
102 $paged = $settings['paged'] ?? 1;
103 $settings['paged'] = $paged;
104 $listCoursesTemplate = self::instance();
105
106 // HTML section courses.
107 $html_courses = '';
108 if ( empty( $courses ) ) {
109 $html_courses = Template::print_message( __( 'No courses found', 'learnpress' ), 'info', false );
110 } else {
111 foreach ( $courses as $courseObj ) {
112 $course = CourseModel::find( $courseObj->ID, true );
113 $html_courses .= static::render_course( $course, $settings );
114 }
115 }
116
117 $section_courses = apply_filters(
118 'learn-press/layout/list-courses/section/courses',
119 [
120 'wrap' => sprintf(
121 '<ul class="learn-press-courses lp-list-courses-no-css %1$s" data-layout="%1$s">',
122 $skin
123 ),
124 'courses' => $html_courses,
125 'wrap_end' => '</ul>',
126 ],
127 $courses,
128 $settings
129 );
130
131 $section_top = apply_filters(
132 'learn-press/layout/list-courses/section/top',
133 [
134 'wrapper' => '<div class="lp-courses-bar">',
135 'search' => $listCoursesTemplate->html_search_form( $settings ),
136 'order_by' => $listCoursesTemplate->html_order_by( $settings['order_by'] ?? 'post_date' ),
137 'switch_layout' => $listCoursesTemplate->switch_layout(),
138 'btn_filter_courses_mobile' => FilterCourseTemplate::instance()->html_btn_filter_mobile( $settings ),
139 'wrapper_end' => '</div>',
140 ],
141 $courses,
142 $settings
143 );
144
145 // For old themes use old hook.
146 $section_top = self::fix_theme_cb_hook_courses( $section_top, $courses, $settings );
147 //$section= self::fix_theme_el_hook_old_render_courses( $section, $courses, $settings );
148 // End.
149
150 // Pagination html
151 $data_pagination_type = LP_Settings::get_option( 'course_pagination_type', 'number' );
152 if ( empty( $settings['courses_load_ajax'] ) ) {
153 $data_pagination_type = 'number';
154 }
155 $data_pagination = [
156 'total_pages' => $total_pages,
157 'type' => $data_pagination_type,
158 'base' => add_query_arg( 'paged', '%#%', $settings['url_current'] ?? '' ),
159 'paged' => $settings['paged'] ?? 1,
160 ];
161 $html_pagination = static::instance()->html_pagination( $data_pagination );
162
163 $section = apply_filters(
164 'learn-press/layout/list-courses/section',
165 [
166 'top' => Template::combine_components( $section_top ),
167 'courses' => Template::combine_components( $section_courses ),
168 'pagination' => $html_pagination,
169 ],
170 $courses,
171 $settings
172 );
173
174 $content = new stdClass();
175 $content->content = Template::combine_components( $section );
176 $content->total_pages = $total_pages;
177 $content->paged = $paged;
178
179 return $content;
180 }
181
182 /**
183 * Render single item course
184 *
185 * @param CourseModel|LP_Course $course
186 * @param array $settings
187 *
188 * @return string
189 * @since 4.2.5.8
190 * @version 1.0.4
191 */
192 public static function render_course( $course, array $settings = [] ): string {
193 if ( ! $course instanceof CourseModel ) {
194 $course = CourseModel::find( $course->get_id(), true );
195 }
196 $singleCourseTemplate = SingleCourseTemplate::instance();
197 $show_view_students = ! empty( $settings['show_view_students'] );
198
199 try {
200 // New layout course item.
201
202 // HTML top section, show image.
203 $section_top = apply_filters(
204 'learn-press/layout/list-courses/item/section-top',
205 [
206 'wrapper' => '<div class="course-thumbnail">',
207 'img' => sprintf(
208 '<a href="%s">%s</a>',
209 $course->get_permalink(),
210 $singleCourseTemplate->html_image( $course )
211 ),
212 'wrapper_end' => '</div>',
213 ],
214 $course,
215 $settings
216 );
217
218 // HTML meta section.
219 $meta_data = apply_filters(
220 'learn-press/layout/list-courses/item/meta-data',
221 [
222 'duration' => $singleCourseTemplate->html_duration( $course ),
223 'level' => $singleCourseTemplate->html_level( $course ),
224 'lesson' => $singleCourseTemplate->html_count_item( $course, LP_LESSON_CPT ),
225 'quiz' => $singleCourseTemplate->html_count_item( $course, LP_QUIZ_CPT ),
226 'student' => $singleCourseTemplate->html_count_student( $course ),
227 ],
228 $course,
229 $settings
230 );
231
232 if ( $course->is_offline() ) {
233 $singleCourseOfflineTemplate = SingleCourseOfflineTemplate::instance();
234 unset( $meta_data['quiz'] );
235 unset( $meta_data['student'] );
236 if ( ! empty( $meta_data['lesson'] ) ) {
237 $meta_data['lesson'] = $singleCourseOfflineTemplate->html_lesson_info( $course, true );
238 }
239
240 // Add address for offline course.
241 $html_address = $singleCourseOfflineTemplate->html_address( $course );
242 if ( ! empty( $html_address ) ) {
243 $meta_data['address'] = $singleCourseOfflineTemplate->html_address( $course );
244 }
245 }
246
247 $html_meta_data = '';
248 if ( ! empty( $meta_data ) ) {
249 foreach ( $meta_data as $k => $v ) {
250 $html_meta_data .= sprintf( '<div class="meta-item meta-item-%s">%s</div>', $k, $v );
251 }
252
253 $html_meta_data = sprintf( '<div class="course-wrap-meta">%s</div>', $html_meta_data );
254 }
255
256 $btn_read_more_text = SingleCourseTemplate::text_button_course( $course );
257
258 // HTML bottom section end.
259 $section_bottom_end = apply_filters(
260 'learn-press/layout/list-courses/item/section/bottom/end',
261 [
262 'short_des' => $singleCourseTemplate->html_short_description( $course ),
263 'wrapper' => '<div class="course-info">',
264 //'clearfix' => '<div class="clearfix"></div>',
265 //'course_footer' => '<div class="course-footer">',
266 'price' => $singleCourseTemplate->html_price( $course ),
267 'btn_read_more' => sprintf(
268 '<div class="course-readmore"><a href="%s">%s</a></div>',
269 $course->get_permalink(),
270 $btn_read_more_text
271 ),
272 'btn_view_list' => $show_view_students ? sprintf(
273 '<div class="lp-wrap-btn-view-course-students">
274 <button type="button" class="lp-button lp-btn-view-students" data-course-id="%d" data-course-title="%s">%s</button>
275 </div>',
276 $course->get_id(),
277 esc_attr( $course->get_title() ),
278 esc_html__( 'View List Students', 'learnpress' )
279 ) : '',
280 //'course_footer_end' => '</div>',
281 'wrapper_end' => '</div>',
282 ],
283 $course,
284 $settings
285 );
286
287 // HTML bottom section.
288 $html_categories = $singleCourseTemplate->html_categories( $course );
289 if ( ! empty( $html_categories ) ) {
290 $html_categories = sprintf(
291 '<div>%s %s</div>',
292 sprintf( '<label>%s</label>', __( 'in', 'learnpress' ) ),
293 $html_categories
294 );
295 }
296 $section_bottom = apply_filters(
297 'learn-press/layout/list-courses/item/section/bottom',
298 [
299 'wrapper' => '<div class="course-content">',
300 'title' => sprintf(
301 '<h3 class="wap-course-title"><a class="course-permalink" href="%s">%s</a></h3>',
302 $course->get_permalink(),
303 $singleCourseTemplate->html_title( $course )
304 ),
305 'featured' => $singleCourseTemplate->html_featured( $course ),
306 'wrapper_instructor_cate' => '<div class="course-instructor-category">',
307 'instructor' => sprintf(
308 '<div>%s %s</div>',
309 sprintf( '<label>%s</label>', __( 'by', 'learnpress' ) ),
310 $singleCourseTemplate->html_instructor( $course )
311 ),
312 'category' => $html_categories,
313 'wrapper_instructor_cate_end' => '</div>',
314 'meta' => $html_meta_data,
315 'info' => Template::combine_components( $section_bottom_end ),
316 'wrapper_end' => '</div>',
317 ],
318 $course,
319 $settings
320 );
321
322 $section = apply_filters(
323 'learn-press/layout/list-courses/item-li',
324 [
325 'wrapper_li' => '<li class="course">',
326 'wrapper_div' => sprintf( '<div class="course-item" data-id="%s">', esc_attr( $course->get_id() ) ),
327 'top' => Template::combine_components( $section_top ),
328 'bottom' => Template::combine_components( $section_bottom ),
329 'wrapper_div_end' => '</div>',
330 'wrapper_li_end' => '</li>',
331 ],
332 $course,
333 $settings
334 );
335
336 // For old themes use old hook.
337 $section = self::fix_theme_course_old( $section, $course, $settings );
338 // End.
339
340 $html_item = Template::combine_components( $section );
341 // End new layout course item.
342 } catch ( Throwable $e ) {
343 $html_item = $e->getMessage();
344 }
345
346 return $html_item;
347 }
348
349 /**
350 * Button Load more
351 *
352 * @return string
353 * @since 4.2.3.3
354 * @version 1.0.0
355 */
356 public function html_pagination_load_more(): string {
357 $html_wrapper = [
358 '<button class="courses-btn-load-more learn-press-pagination lp-button courses-btn-load-more-no-css">' => '</button>',
359 ];
360 $content = sprintf(
361 '%s<span class="lp-loading-circle lp-loading-no-css hide"></span>',
362 __( 'Load more', 'learnpress' )
363 );
364
365 return Template::instance()->nest_elements( $html_wrapper, $content );
366 }
367
368 /**
369 * Button infinite
370 *
371 * @return string
372 * @since 4.2.3.3
373 * @version 1.0.0
374 */
375 public function html_pagination_infinite(): string {
376 $html_wrapper = [
377 '<div class="courses-load-infinite-no-css courses-load-infinite learn-press-pagination">' => '</div>',
378 ];
379 $content = '<span class="lp-loading-circle lp-loading-no-css hide"></span>';
380
381 return Template::instance()->nest_elements( $html_wrapper, $content );
382 }
383
384 /**
385 * Pagination number
386 *
387 * @param array $data
388 *
389 * @return string
390 * @since 4.2.3.3
391 * @version 1.0.0
392 */
393 public function html_pagination_number( array $data = [] ): string {
394 if ( empty( $data['total_pages'] ) || $data['total_pages'] <= 1 ) {
395 return '';
396 }
397
398 $html_wrapper = $data['wrapper'] ?? [
399 '<nav class="learn-press-pagination navigation pagination">' => '</nav>',
400 ];
401
402 $pagination = paginate_links(
403 apply_filters(
404 'learn_press_pagination_args',
405 array(
406 'base' => $data['base'] ?? '',
407 'format' => '',
408 'add_args' => '',
409 'current' => max( 1, $data['paged'] ?? 1 ),
410 'total' => $data[ 'total_pages' ?? 1 ],
411 'prev_text' => '<i class="lp-icon-arrow-left"></i>',
412 'next_text' => '<i class="lp-icon-arrow-right"></i>',
413 'type' => 'list',
414 'end_size' => 3,
415 'mid_size' => 3,
416 )
417 )
418 );
419
420 return Template::instance()->nest_elements( $html_wrapper, $pagination );
421 }
422
423 /**
424 * Pagination
425 *
426 * @param array $data
427 *
428 * @return string
429 * @since 4.2.3.3
430 * @version 1.0.0
431 */
432 public function html_pagination( array $data = [] ): string {
433 if ( empty( $data['total_pages'] ) || $data['total_pages'] <= 1 ) {
434 return '';
435 }
436
437 $pagination_type = $data['type'] ?? 'number';
438 switch ( $pagination_type ) {
439 case 'load-more':
440 if ( $data['paged'] >= $data['total_pages'] ) {
441 return '';
442 }
443
444 return $this->html_pagination_load_more();
445 case 'infinite':
446 if ( $data['paged'] >= $data['total_pages'] ) {
447 return '';
448 }
449
450 return $this->html_pagination_infinite();
451 default:
452 return $this->html_pagination_number( $data );
453 }
454 }
455
456 /**
457 * Pagination
458 *
459 * @param array $data
460 *
461 * @return string
462 * @since 4.2.3.3
463 * @version 1.0.1
464 */
465 public function html_courses_page_result( array $data = [] ): string {
466 $html = '';
467
468 try {
469 $total_rows = $data['total_rows'] ?? 0;
470 $paged = $data['paged'] ?? 1;
471 $course_per_page = $data['courses_per_page'] ?? 8;
472 $pagination_type = $data['pagination_type'] ?? 'number';
473
474 $from = 1 + ( $paged - 1 ) * $course_per_page;
475 $to = ( $paged * $course_per_page > $total_rows ) ? $total_rows : $paged * $course_per_page;
476
477 $content = '';
478 if ( 0 === $total_rows ) {
479
480 } elseif ( 1 === $total_rows ) {
481 $content = esc_html__( 'Showing only one result', 'learnpress' );
482 } else {
483 $from_to = $from . '-' . $to;
484 // For pagination type is load-more or infinite.
485 if ( $pagination_type !== 'number' ) {
486 $from_to = '1 - ' . $to;
487 }
488 $content = sprintf( esc_html__( 'Showing %1$s of %2$s results', 'learnpress' ), $from_to, $total_rows );
489 }
490
491 if ( ! empty( $content ) ) {
492 $html = '<span class="courses-page-result">' . $content . '</span>';
493 }
494 } catch ( Throwable $e ) {
495 error_log( $e->getMessage() );
496 }
497
498 return $html;
499 }
500
501 /**
502 * Layouts type
503 *
504 * @param array $data
505 *
506 * @return string
507 * @since 4.2.3.3
508 * @version 1.0.0
509 */
510 public function html_layout_type( array $data = [] ): string {
511 $html_wrapper = [
512 '<div class="courses-layouts-display">' => '</div>',
513 ];
514
515 $ico_grid_default = LP_WP_Filesystem::get_icon_svg( 'ico-grid.svg' );
516 $ico_list_default = LP_WP_Filesystem::get_icon_svg( 'ico-list.svg' );
517
518 $layouts = [
519 'list' => $data['courses_ico_list'] ?? $ico_list_default,
520 'grid' => $data['courses_ico_grid'] ?? $ico_grid_default,
521 ];
522
523 $content = '<ul class="courses-layouts-display-list">';
524 foreach ( $layouts as $k => $v ) {
525 $active = ( $data['courses_layout_default'] ?? '' ) === $k ? 'active' : '';
526 $content .= '<li class="courses-layout ' . $active . '" data-layout="' . $k . '">' . $v . '</li>';
527 }
528 $content .= '</ul>';
529
530 return Template::instance()->nest_elements( $html_wrapper, $content );
531 }
532
533 /**
534 * Order by
535 *
536 * @param string $default_value
537 *
538 * @return string
539 * @since 4.2.3.2
540 * @version 1.0.1
541 */
542 public function html_order_by( string $default_value = 'post_date' ): string {
543 $html_wrapper = [
544 '<div class="courses-order-by-wrapper">' => '</div>',
545 ];
546
547 $values = apply_filters(
548 'learn-press/courses/order-by/values',
549 [
550 'post_date' => esc_html__( 'Newly published', 'learnpress' ),
551 'post_title' => esc_html__( 'Title a-z', 'learnpress' ),
552 'post_title_desc' => esc_html__( 'Title z-a', 'learnpress' ),
553 'price' => esc_html__( 'Price high to low', 'learnpress' ),
554 'price_low' => esc_html__( 'Price low to high', 'learnpress' ),
555 'popular' => esc_html__( 'Popular', 'learnpress' ),
556 ]
557 );
558
559 $content = '<select name="order_by" class="courses-order-by">';
560 foreach ( $values as $k => $v ) {
561 $content .= '<option value="' . $k . '" ' . selected( $default_value, $k, false ) . '>' . $v . '</option>';
562 }
563 $content .= '</select>';
564
565 return Template::instance()->nest_elements( $html_wrapper, $content );
566 }
567
568 public function html_search_form( array $data = [] ) {
569 $s = $data['c_search'] ?? '';
570 $class = $data['class'] ?? 'search-courses';
571 ob_start();
572 ?>
573 <form class="<?php echo esc_attr( $class ); ?>" method="get"
574 action="<?php echo esc_url_raw( learn_press_get_page_link( 'courses' ) ); ?>">
575 <input type="search" placeholder="<?php esc_attr_e( 'Search courses...', 'learnpress' ); ?>"
576 name="c_search"
577 value="<?php echo esc_attr( $s ); ?>">
578 <button type="submit" name="lp-btn-search-courses"><i class="lp-icon-search"></i></button>
579 </form>
580 <?php
581 return ob_get_clean();
582 }
583
584 /**
585 * Html switch layout.
586 *
587 * @return string
588 */
589 public function switch_layout(): string {
590 $layouts = learn_press_courses_layouts();
591 $active = learn_press_get_courses_layout();
592
593 $html_layouts = '';
594 foreach ( $layouts as $layout => $value ) {
595 $html_layouts .= sprintf(
596 '<input type="radio" name="lp-switch-layout-btn" value="%s" id="lp-switch-layout-btn-%s" %s>
597 <label class="switch-btn %s" title="%s" for="lp-switch-layout-btn-%s"></label>',
598 esc_attr( $layout ),
599 esc_attr( $layout ),
600 checked( $layout, $active, false ),
601 esc_attr( $layout ),
602 sprintf( esc_attr__( 'Switch to %s', 'learnpress' ), $value ),
603 esc_attr( $layout )
604 );
605 }
606
607 $section = apply_filters(
608 'learn-press/layout/list-courses/section/switch-layout',
609 [
610 'wrapper' => '<div class="switch-layout">',
611 'layouts' => $html_layouts,
612 'wrapper_end' => '</div>',
613 ]
614 );
615
616 return Template::combine_components( $section );
617 }
618
619 /**
620 * Layout course search suggest result.
621 *
622 * @param array $data
623 *
624 * @return void
625 * @since 4.2.3.2
626 * @version 1.0.1
627 */
628 public function sections_course_suggest( array $data = [] ) {
629 $content = '';
630 $singleCourseTemplate = SingleCourseTemplate::instance();
631
632 ob_start();
633 try {
634 $courses = $data['courses'] ?? [];
635 $key_search = $data['keyword'] ?? '';
636 $total_courses = $data['total_course'] ?? 0;
637
638 // HTML section list courses.
639 $html_list_course = '';
640 foreach ( $courses as $courseObj ) {
641 if ( ! is_object( $courseObj ) ) {
642 continue;
643 }
644 $course_id = $courseObj->ID;
645 $courseModel = CourseModel::find( $course_id, true );
646 if ( ! $courseModel ) {
647 continue;
648 }
649
650 $section_item = apply_filters(
651 'learn-press/course-suggest/item/sections',
652 [
653 'wrapper' => '<li class="item-course-suggest">',
654 'course_image' => $singleCourseTemplate->html_image( $courseModel ),
655 'course_title' => sprintf(
656 '<a href="%s">%s</a>',
657 esc_url_raw( $courseModel->get_permalink() ),
658 $singleCourseTemplate->html_title( $courseModel )
659 ),
660 'wrapper_end' => '</li>',
661 ],
662 $courseModel,
663 $key_search,
664 $data
665 );
666 $html_list_course .= Template::combine_components( $section_item );
667 }
668
669 $count_courses = sprintf(
670 '%s %s',
671 $total_courses,
672 _n( 'Course Found', 'Courses Found', $total_courses, 'learnpress' )
673 );
674 $view_all = sprintf(
675 '<a href="%s">%s</a>',
676 add_query_arg( 'c_search', $key_search, learn_press_get_page_link( 'courses' ) ),
677 __( 'View All', 'learnpress' )
678 );
679
680 // Section.
681 $section = [
682 'wrapper' => '<ul class="lp-courses-suggest-list">',
683 'courses' => $html_list_course,
684 'wrapper_end' => '</ul>',
685 'wrapper_info' => '<div class="lp-courses-suggest-info">',
686 'count' => $count_courses,
687 'view_all' => $view_all,
688 'wrapper_info_end' => '</div>',
689 ];
690 $content = Template::combine_components( $section );
691 echo $content;
692 } catch ( Throwable $e ) {
693 Template::print_message( $e->getMessage(), 'error' );
694 }
695 }
696
697 /**
698 * Sidebar
699 *
700 * @return void
701 * @version 1.0.0
702 * @since 4.2.3.2
703 */
704 public function sidebar() {
705 try {
706 if ( is_active_sidebar( 'archive-courses-sidebar' ) ) {
707 $html_wrapper = [
708 '<div class="lp-archive-courses-sidebar">' => '</div>',
709 ];
710
711 ob_start();
712 dynamic_sidebar( 'archive-courses-sidebar' );
713 echo Template::instance()->nest_elements( $html_wrapper, ob_get_clean() );
714 }
715 } catch ( Throwable $e ) {
716 error_log( $e->getMessage() );
717 }
718 }
719
720 /**
721 * Show total course free by Category.
722 * @return string
723 * @version 1.0.0
724 *
725 * @since 4.2.5.4
726 */
727 public function html_count_course_free(): string {
728 $html_wrapper = [
729 '<div class="courses-count-free">' => '</div>',
730 ];
731
732 $category_current = 0;
733 $category_current_slug = get_query_var( 'term' );
734 if ( ! empty( $category_current_slug ) ) {
735 $category_current_obj = get_term_by( 'slug', $category_current_slug, LP_COURSE_CATEGORY_TAX );
736 if ( $category_current_obj instanceof WP_Term ) {
737 $category_current = $category_current_obj->term_id;
738 }
739 }
740
741 $filter = new LP_Course_Filter();
742 if ( ! empty( $category_current ) ) {
743 $filter->term_ids = [ $category_current ];
744 }
745
746 $count = Courses::count_course_free( $filter );
747 $content = sprintf(
748 '<span class="courses-count-free-number">%1$s</span> %2$s',
749 $count,
750 _n( 'Free Course', 'Free Courses', $count, 'learnpress' )
751 );
752
753 return Template::instance()->nest_elements( $html_wrapper, $content );
754 }
755
756 /**
757 * Show total students on Course Category.
758 *
759 * @return string
760 * @since 4.2.5.4
761 * @version 1.0.0
762 */
763 public function html_count_students(): string {
764 $html_wrapper = [
765 '<div class="courses-count-students">' => '</div>',
766 ];
767
768 $category_current = 0;
769 $category_current_slug = get_query_var( 'term' );
770 if ( ! empty( $category_current_slug ) ) {
771 $category_current_obj = get_term_by( 'slug', $category_current_slug, LP_COURSE_CATEGORY_TAX );
772 if ( $category_current_obj instanceof WP_Term ) {
773 $category_current = $category_current_obj->term_id;
774 }
775 }
776
777 $lp_user_items_db = LP_User_Items_DB::getInstance();
778 $filter = new LP_User_Items_Filter();
779
780 // If page is course category, get total students of this category.
781 if ( ! empty( $category_current ) ) {
782 $filter->join[] = "INNER JOIN {$lp_user_items_db->tb_posts} AS p ON ui.item_id = p.ID";
783 $filter->join[] = "INNER JOIN {$lp_user_items_db->tb_term_relationships} AS r_term ON ui.item_id = r_term.object_id";
784 $filter->where[] = $lp_user_items_db->wpdb->prepare( 'AND r_term.term_taxonomy_id = %d', $category_current );
785 }
786
787 $count = UserCourseModel::count_students( $filter );
788 $content = sprintf(
789 '<span class="courses-count-students-number">%1$s</span> %2$s',
790 $count,
791 _n( 'Student', 'Students', $count, 'learnpress' )
792 );
793
794 return Template::instance()->nest_elements( $html_wrapper, $content );
795 }
796
797 /************************** Hook old *****************************/
798
799 /**
800 * Fix theme course-builder use old hook.
801 *
802 * @param array $section
803 *
804 * @return array
805 */
806 public static function fix_theme_cb_hook_courses( $section, $courses, $settings ) {
807 /*$theme_name = wp_get_theme()->get( 'Name' );
808 if ( 'Course Builder' !== $theme_name ) {
809 return $section;
810 }*/
811
812 $section_top = apply_filters(
813 'learn-press/list-courses/layout/section/top',
814 [],
815 $courses,
816 $settings
817 );
818
819 $section_new = [];
820 if ( ! empty( $section_top ) ) {
821 foreach ( $section_top as $k => $v ) {
822 $section_new[ $k ] = $v['text_html'] ?? '';
823 }
824
825 return $section_new;
826 }
827
828 return $section;
829 }
830
831 /**
832 * Fix theme course-builder use old hook.
833 *
834 * @param array $section
835 *
836 * @return array
837 */
838 public static function fix_theme_course_old( $section, $course, $settings ) {
839 /*$theme_name = wp_get_theme()->get( 'Name' );
840 if ( 'Course Builder' !== $theme_name ) {
841 return $section;
842 }*/
843
844 $course = learn_press_get_course( $course->get_id() );
845
846 $wrapper = apply_filters(
847 'learn-press/list-courses/layout/item/wrapper',
848 [],
849 $course,
850 $settings
851 );
852 if ( ! empty( $wrapper ) ) {
853 $i = 0;
854 foreach ( $wrapper as $k => $v ) {
855 if ( $i === 0 ) {
856 $section['wrapper_li'] = $k;
857 $section['wrapper_li_end'] = $v;
858 } elseif ( $i === 1 ) {
859 $section['wrapper_div'] = $k;
860 $section['wrapper_div_end'] = $v;
861 break;
862 }
863
864 ++$i;
865 }
866 }
867
868 $section_item = apply_filters(
869 'learn-press/list-courses/layout/item/section',
870 [],
871 $course,
872 $settings
873 );
874 if ( ! empty( $section_item ) ) {
875 $section['top'] = $section_item['thim_top']['text_html'] ?? '';
876 }
877
878 $section_bottom = apply_filters(
879 'learn-press/list-courses/layout/item/section/bottom',
880 [],
881 $course,
882 $settings
883 );
884 $section_bottom_new = [];
885 if ( ! empty( $section_bottom ) ) {
886 foreach ( $section_bottom as $k => $v ) {
887 $section_bottom_new[ $k ] = $v['text_html'] ?? '';
888 }
889
890 $section['bottom'] = Template::combine_components( $section_bottom_new );
891 }
892
893 return $section;
894 }
895
896 /**
897 * Render string to data content
898 *
899 * @param array $data
900 * @param string $data_content
901 *
902 * @return string
903 */
904 public function render_data( array $data, string $data_content ): string {
905 return str_replace(
906 [
907 '{{courses_order_by}}',
908 '{{courses_layout_type}}',
909 '{{courses_pagination}}',
910 '{{courses_page_result}}',
911 ],
912 [
913 $this->html_order_by( $data['order_by'] ?? '' ),
914 $this->html_layout_type( $data ),
915 $this->html_pagination( $data['pagination'] ?? [] ),
916 $this->html_courses_page_result( $data ),
917 ],
918 $data_content
919 );
920 }
921 }
922