PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.10
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.10
4.4.10 4.4.9.1 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 All 142 releases
learnpress / inc / TemplateHooks / Course / ListCoursesTemplate.php

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

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