PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.8
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.8
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
← All changes | inc/TemplateHooks/Course/SingleCourseTemplate.php +1951 -1951 4.3.94.4.8 View file →
@@ -1,1951 +1,1951 @@
1 -<?php
2 -/**
3 - * Template hooks Single Course.
4 - *
5 - * @since 4.2.3
6 - * @version 1.0.5
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\CoursePostModel;
15 -use LearnPress\Models\LessonPostModel;
16 -use LearnPress\Models\PostModel;
17 -use LearnPress\Models\QuizPostModel;
18 -use LearnPress\Models\UserItems\UserCourseModel;
19 -use LearnPress\Models\UserItems\UserItemModel;
20 -use LearnPress\Models\UserModel;
21 -use LearnPress\TemplateHooks\Instructor\SingleInstructorTemplate;
22 -use LearnPress\TemplateHooks\TemplateAJAX;
23 -use LearnPress\TemplateHooks\UserTemplate;
24 -use LearnPressAssignment\Models\AssignmentPostModel;
25 -use LP_Checkout;
26 -use LP_Course;
27 -use LP_Course_Item;
28 -use LP_Datetime;
29 -use LP_Debug;
30 -use LP_Global;
31 -use LP_Material_Files_DB;
32 -use LP_Settings;
33 -use stdClass;
34 -use Throwable;
35 -
36 -class SingleCourseTemplate {
37 - use Singleton;
38 -
39 - /**
40 - * @var false|LessonPostModel|QuizPostModel|PostModel|mixed $currentItemModel
41 - */
42 - public $currentItemModel = false;
43 -
44 - public function init() {
45 - add_filter( 'lp/rest/ajax/allow_callback', [ $this, 'allow_callback' ] );
46 - }
47 -
48 - /**
49 - * Allow callback for AJAX.
50 - * @use self::render_html_comments
51 - *
52 - * @param array $callbacks
53 - *
54 - * @return array
55 - */
56 - public function allow_callback( array $callbacks ): array {
57 - $callbacks[] = get_class( $this ) . ':render_html_comments';
58 -
59 - return $callbacks;
60 - }
61 -
62 - /**
63 - * Get display title course.
64 - *
65 - * @param LP_Course|CourseModel $course
66 - * @param string $tag_html
67 - *
68 - * @return string
69 - */
70 - public function html_title( $course, string $tag_html = 'span' ): string {
71 - $tag_html = esc_attr( sanitize_key( $tag_html ) );
72 - $html_wrapper = apply_filters(
73 - 'learn-press/single-course/html-title',
74 - [
75 - "<{$tag_html} class='course-title'>" => "</{$tag_html}>",
76 - ],
77 - $course
78 - );
79 -
80 - return Template::instance()->nest_elements( $html_wrapper, $course->get_title() );
81 - }
82 -
83 - /**
84 - * Get short description course.
85 - *
86 - * @param LP_Course|CourseModel $course
87 - * @param int $number_words
88 - *
89 - * @return string
90 - */
91 - public function html_short_description( $course, int $number_words = 0 ): string {
92 - $html_wrapper = [
93 - '<p class="course-short-description">' => '</p>',
94 - ];
95 -
96 - if ( $course instanceof LP_Course ) {
97 - $course = CourseModel::find( $course->get_id(), true );
98 - }
99 -
100 - $short_description = $course->get_short_description();
101 - if ( empty( $short_description ) ) {
102 - return '';
103 - }
104 -
105 - if ( $number_words > 0 ) {
106 - $short_description = wp_trim_words( $short_description, $number_words, '...' );
107 - }
108 -
109 - return Template::instance()->nest_elements( $html_wrapper, $short_description );
110 - }
111 -
112 - /**
113 - * Get description course.
114 - *
115 - * @param LP_Course|CourseModel $course
116 - *
117 - * @return string
118 - */
119 - public function html_description( $course ): string {
120 - $content = '';
121 -
122 - if ( $course instanceof LP_Course ) {
123 - $content = $course->get_data( 'description' );
124 - } elseif ( $course instanceof CourseModel ) {
125 - $content = $course->get_description();
126 - }
127 -
128 - $section = apply_filters(
129 - 'learn-press/course/html-description',
130 - [
131 - 'wrapper' => '<div class="lp-course-description">',
132 - 'content' => $content,
133 - 'wrapper_end' => '</div>',
134 - ],
135 - $course
136 - );
137 -
138 - return Template::combine_components( $section );
139 - }
140 -
141 - /**
142 - * Get display categories course.
143 - *
144 - * @param LP_Course|CourseModel $course
145 - * @param array $setting
146 - *
147 - * @return string
148 - * @since 4.2.6
149 - * @version 1.0.3
150 - */
151 - public function html_categories( $course, array $setting = [] ): string {
152 - $html = '';
153 -
154 - try {
155 - if ( $course instanceof LP_Course ) {
156 - $course = CourseModel::find( $course->get_id(), true );
157 - }
158 -
159 - if ( empty( $course ) ) {
160 - return '';
161 - }
162 -
163 - $cats = $course->get_categories();
164 - if ( empty( $cats ) ) {
165 - return '';
166 - }
167 -
168 - $is_link = $setting['is_link'] ?? true;
169 - $attribute_target = ! empty( $setting['new_tab'] ) ? 'target="_blank"' : '';
170 - $cat_names = [];
171 - foreach ( $cats as $cat ) {
172 - if ( $is_link ) {
173 - $term = sprintf(
174 - '<a href="%s" %s>%s</a>',
175 - get_term_link( $cat ),
176 - $attribute_target,
177 - $cat->name
178 - );
179 - } else {
180 - $term = $cat->name;
181 - }
182 -
183 - $cat_names[] = $term;
184 - }
185 -
186 - $content = implode( ', ', $cat_names );
187 -
188 - $section = apply_filters(
189 - 'learn-press/course/html-categories',
190 - [
191 - 'wrapper' => '<div class="course-categories">',
192 - 'content' => $content,
193 - 'wrapper_end' => '</div>',
194 - ],
195 - $course,
196 - $cats,
197 - $cat_names
198 - );
199 -
200 - $html = Template::combine_components( $section );
201 - } catch ( Throwable $e ) {
202 - error_log( __METHOD__ . ': ' . $e->getMessage() );
203 - }
204 -
205 - return $html;
206 - }
207 -
208 - /**
209 - * Get display tags course.
210 - *
211 - * @param LP_Course|CourseModel $course
212 - *
213 - * @return string
214 - * @since 4.2.6
215 - * @version 1.0.2
216 - */
217 - public function html_tags( $course ): string {
218 - $html = '';
219 -
220 - try {
221 - if ( $course instanceof LP_Course ) {
222 - $course = CourseModel::find( $course->get_id(), true );
223 - }
224 -
225 - if ( empty( $course ) ) {
226 - return '';
227 - }
228 -
229 - $tags = $course->get_tags();
230 - if ( empty( $tags ) ) {
231 - return '';
232 - }
233 -
234 - $tag_names = [];
235 - foreach ( $tags as $tag ) {
236 - $term = sprintf(
237 - '<a href="%s">%s</a>',
238 - get_term_link( $tag ),
239 - $tag->name
240 - );
241 - $tag_names[] = $term;
242 - }
243 -
244 - $content = implode( ', ', $tag_names );
245 -
246 - $section = apply_filters(
247 - 'learn-press/course/html-tags',
248 - [
249 - 'wrapper' => '<div class="course-tags">',
250 - 'content' => $content,
251 - 'wrapper_end' => '</div>',
252 - ],
253 - $course,
254 - $tags,
255 - $tag_names
256 - );
257 -
258 - $html = Template::combine_components( $section );
259 - } catch ( Throwable $e ) {
260 - error_log( __METHOD__ . ': ' . $e->getMessage() );
261 - }
262 -
263 - return $html;
264 - }
265 -
266 - /**
267 - * Get display image course.
268 - *
269 - * @param LP_Course|CourseModel $course
270 - * @param array $data ['size'] Size of image to get, Ex: [500, 300] or string 'thumbnail', 'medium', 'large', 'full' etc.
271 - *
272 - * @return string
273 - * @since 4.2.3.2
274 - * @version 1.0.3
275 - */
276 - public function html_image( $course, array $data = [] ): string {
277 - $content = '';
278 -
279 - try {
280 - $courseModel = $course;
281 - if ( $course instanceof LP_Course ) {
282 - $courseModel = CourseModel::find( $course->get_id(), true );
283 - }
284 -
285 - if ( ! $courseModel instanceof CourseModel ) {
286 - return '';
287 - }
288 -
289 - if ( ! empty( $data['size'] ) ) {
290 - $size_img_send = $data['size'];
291 -
292 - // If custom size, data size is type int[], like [500, 300], not [ width => 500, height => 300 ]
293 - // Convert if data is [ width => 500, height => 300 ]
294 - if ( is_array( $size_img_send ) && array_key_exists( 'width', $size_img_send ) ) {
295 - $size_img_send = [
296 - $size_img_send['width'] ?? 500,
297 - $size_img_send['height'] ?? 300,
298 - ];
299 - }
300 - } else {
301 - $size_img_setting = LP_Settings::get_option( 'course_thumbnail_dimensions', [] );
302 - $size_img_send = [
303 - $size_img_setting['width'] ?? 500,
304 - $size_img_setting['height'] ?? 300,
305 - ];
306 - }
307 -
308 - // Check cache before get image url
309 - $cache = new \LP_Course_Cache();
310 - $key_cache = 'image_url/' . $courseModel->get_id();
311 - if ( is_array( $size_img_send ) && count( $size_img_send ) === 2 ) {
312 - $key_cache .= '/' . implode( 'x', $size_img_send );
313 - } elseif ( is_string( $size_img_send ) ) {
314 - $key_cache .= '/' . $size_img_send;
315 - }
316 -
317 - // Set cache for image url
318 - $course_img_url = $cache->get_cache( $key_cache );
319 - if ( false === $course_img_url ) {
320 - $course_img_url = $courseModel->get_image_url( $size_img_send );
321 - $cache->set_cache( $key_cache, $course_img_url );
322 - $cache->save_cache_keys( sprintf( 'image_urls/%s', $courseModel->get_id() ), $key_cache );
323 - }
324 -
325 - $content = sprintf(
326 - '<img src="%s" alt="%s">',
327 - esc_url_raw( $course_img_url ),
328 - _x( 'course thumbnail', 'no course thumbnail', 'learnpress' )
329 - );
330 -
331 - $section = apply_filters(
332 - 'learn-press/course/html-image',
333 - [
334 - 'wrapper' => '<div class="course-img">',
335 - 'content' => $content,
336 - 'wrapper_end' => '</div>',
337 - ],
338 - $courseModel
339 - );
340 -
341 - $content = Template::combine_components( $section );
342 - } catch ( Throwable $e ) {
343 - error_log( __METHOD__ . ': ' . $e->getMessage() );
344 - }
345 -
346 - return $content;
347 - }
348 -
349 - /**
350 - * Get display instructor course.
351 - *
352 - * @param CourseModel $course
353 - * @param bool $with_avatar
354 - *
355 - * @return string
356 - * @since 4.2.5.8
357 - * @version 1.0.2
358 - */
359 - public function html_instructor( $course, bool $with_avatar = false, $setting = [] ): string {
360 - $content = '';
361 -
362 - try {
363 - $instructor = $course->get_author_model();
364 - if ( ! $instructor ) {
365 - return '';
366 - }
367 -
368 - $singleInstructorTemplate = SingleInstructorTemplate::instance();
369 - $userTemplate = new UserTemplate( 'instructor' );
370 - $is_link = $setting['is_link'] ?? true;
371 - if ( $is_link ) {
372 - $attribute_target = ! empty( $setting['new_tab'] ) ? 'target="_blank"' : '';
373 - $link_instructor = sprintf(
374 - '<a href="%s" %s >%s %s</a>',
375 - $instructor->get_url_instructor(),
376 - $attribute_target,
377 - $with_avatar ? $userTemplate->html_avatar( $instructor ) : '',
378 - $singleInstructorTemplate->html_display_name( $instructor )
379 - );
380 - } else {
381 - $link_instructor = sprintf(
382 - '%s %s',
383 - $with_avatar ? $userTemplate->html_avatar( $instructor ) : '',
384 - $singleInstructorTemplate->html_display_name( $instructor )
385 - );
386 - }
387 -
388 - $section = apply_filters(
389 - 'learn-press/course/instructor-html',
390 - [
391 - 'wrapper' => '<div class="course-instructor">',
392 - 'content' => $link_instructor,
393 - 'wrapper_end' => '</div>',
394 - ],
395 - $course,
396 - $instructor,
397 - $with_avatar
398 - );
399 -
400 - $content = Template::combine_components( $section );
401 - } catch ( Throwable $e ) {
402 - error_log( __METHOD__ . ': ' . $e->getMessage() );
403 - }
404 -
405 - return $content;
406 - }
407 -
408 - /**
409 - * Get html regular price
410 - *
411 - * @param CourseModel $course
412 - *
413 - * @return string
414 - */
415 - public function html_regular_price( CourseModel $course ): string {
416 - $price = learn_press_format_price( $course->get_regular_price() );
417 - $price = apply_filters( 'learn-press/course/regular-price-html', $price, $course, $this );
418 -
419 - return sprintf( '<span class="origin-price">%s</span>', $price );
420 - }
421 -
422 - /**
423 - * Get display price course.
424 - *
425 - * @param LP_Course|CourseModel $course
426 - *
427 - * @return string
428 - */
429 - public function html_price( $course ): string {
430 - $price_html = '';
431 -
432 - if ( $course instanceof LP_Course ) {
433 - $course = CourseModel::find( $course->get_id(), true );
434 - }
435 -
436 - if ( ! $course ) {
437 - return $price_html;
438 - }
439 -
440 - if ( $course->is_free() ) {
441 - if ( '' != $course->get_sale_price() ) {
442 - $price_html .= $this->html_regular_price( $course );
443 - }
444 -
445 - $price_html .= sprintf( '<span class="free">%s</span>', esc_html__( 'Free', 'learnpress' ) );
446 - $price_html = apply_filters( 'learn_press_course_price_html_free', $price_html, $this );
447 - } elseif ( $course->has_no_enroll_requirement() ) {
448 - $price_html .= '';
449 - } else {
450 - if ( $course->has_sale_price() ) {
451 - $price_html .= $this->html_regular_price( $course );
452 - }
453 -
454 - $price_html .= sprintf(
455 - '<span class="price">%s</span>',
456 - learn_press_format_price( $course->get_price(), true )
457 - );
458 - $price_html = sprintf(
459 - '%1$s %2$s %3$s',
460 - $this->html_price_prefix( $course ),
461 - $price_html,
462 - $this->html_price_suffix( $course )
463 - );
464 - $price_html = apply_filters(
465 - 'learn_press_course_price_html',
466 - $price_html,
467 - $course->has_sale_price(),
468 - $course->get_id()
469 - );
470 - }
471 -
472 - // @since 4.2.7
473 - $price_html = sprintf( '<span class="course-price"><span class="course-item-price">%s</span></span>', $price_html );
474 -
475 - return apply_filters( 'learn-press/course/html-price', $price_html, $course );
476 - }
477 -
478 - /**
479 - * Get deliver type
480 - *
481 - * @param CourseModel $course
482 - *
483 - * @return string
484 - */
485 - public function html_capacity( CourseModel $course ): string {
486 - $content = '';
487 -
488 - $html_wrapper = [
489 - '<span class="course-capacity">' => '</span>',
490 - ];
491 - $capacity = $course->get_meta_value_by_key( CoursePostModel::META_KEY_MAX_STUDENTS, 0 );
492 -
493 - if ( $capacity == 0 ) {
494 - $content = __( 'Unlimited', 'learnpress' );
495 - } else {
496 - $content = sprintf( '%d %s', $capacity, _n( 'Student', 'Students', $capacity, 'learnpress' ) );
497 - }
498 -
499 - return Template::instance()->nest_elements( $html_wrapper, $content );
500 - }
501 -
502 - /**
503 - * Get display total student's course.
504 - *
505 - * @param LP_Course|CourseModel $course
506 - *
507 - * @return string
508 - * @since 4.2.3.4
509 - * @version 1.0.2
510 - */
511 - public function html_count_student( $course ): string {
512 - if ( $course instanceof LP_Course ) {
513 - $course = CourseModel::find( $course->get_id(), true );
514 - }
515 -
516 - if ( empty( $course ) ) {
517 - return '';
518 - }
519 -
520 - $count_student = $course->get_total_user_enrolled_or_purchased();
521 - $count_student += $course->get_fake_students();
522 - $content = sprintf( '%d %s', $count_student, _n( 'Student', 'Students', $count_student, 'learnpress' ) );
523 - $html_wrapper = [
524 - '<div class="course-count-student">' => '</div>',
525 - ];
526 -
527 - return Template::instance()->nest_elements( $html_wrapper, $content );
528 - }
529 -
530 - /**
531 - * Get display total lesson's course.
532 - *
533 - * @param LP_Course|CourseModel $course
534 - * @param string $item_type custom post type item
535 - * @param bool $show_only_number
536 - *
537 - * @return string
538 - */
539 - public function html_count_item( $course, string $item_type, bool $show_only_number = false ): string {
540 - if ( $course instanceof LP_Course ) {
541 - $course = CourseModel::find( $course->get_id(), true );
542 - }
543 -
544 - if ( empty( $course ) ) {
545 - return '';
546 - }
547 -
548 - $info_total_items = $course->get_total_items();
549 - if ( empty( $info_total_items ) ) {
550 - return '';
551 - }
552 -
553 - $count_item = $info_total_items->{$item_type} ?? 0;
554 -
555 - if ( $show_only_number ) {
556 - $content = $count_item;
557 - } else {
558 - switch ( $item_type ) {
559 - case LP_LESSON_CPT:
560 - $content = sprintf( '%d %s', $count_item, _n( 'Lesson', 'Lessons', $count_item, 'learnpress' ) );
561 - break;
562 - case LP_QUIZ_CPT:
563 - $content = sprintf( '%d %s', $count_item, _n( 'Quiz', 'Quizzes', $count_item, 'learnpress' ) );
564 - break;
565 - case 'lp_assignment':
566 - $content = sprintf( '%d %s', $count_item, _n( 'Assignment', 'Assignments', $count_item, 'learnpress' ) );
567 - break;
568 - case 'lp_h5p':
569 - $content = sprintf( '%d %s', $count_item, _n( 'H5P', 'H5Ps', $count_item, 'learnpress' ) );
570 - break;
571 - default:
572 - $content = apply_filters( 'learn-press/single-course/i18n/count-item', $count_item, $course, $item_type );
573 - break;
574 - }
575 - }
576 -
577 - $section = apply_filters(
578 - 'learn-press/single-course/html-count-item',
579 - [
580 - 'wrapper' => sprintf( '<div class="course-count-item %s">', $item_type ),
581 - 'content' => $content,
582 - 'wrapper_end' => '</div>',
583 - ],
584 - $course,
585 - $item_type,
586 - $count_item
587 - );
588 -
589 - return Template::combine_components( $section );
590 - }
591 -
592 - /**
593 - * Get html level course.
594 - *
595 - * @param LP_Course|CourseModel $course
596 - *
597 - * @return string
598 - * @since 4.2.3.5
599 - * @version 1.0.1
600 - */
601 - public function html_level( $course ): string {
602 - $content = '';
603 -
604 - try {
605 - if ( $course instanceof LP_Course ) {
606 - $course = CourseModel::find( $course->get_id(), true );
607 - }
608 -
609 - $level = $course->get_meta_value_by_key( CoursePostModel::META_KEY_LEVEL, '' );
610 - if ( empty( $level ) ) {
611 - $level = 'all';
612 - }
613 -
614 - $levels = lp_course_level();
615 - $level = $levels[ $level ] ?? $levels['all'];
616 -
617 - $html_wrapper = [
618 - '<span class="course-level">' => '</span>',
619 - ];
620 - $content = Template::instance()->nest_elements( $html_wrapper, $level );
621 - } catch ( Throwable $e ) {
622 - error_log( __METHOD__ . ': ' . $e->getMessage() );
623 - }
624 -
625 - return $content;
626 - }
627 -
628 - /**
629 - * Get html duration course.
630 - *
631 - * @param LP_Course|CourseModel $course
632 - *
633 - * @return string
634 - * @since 4.2.3.5
635 - * @version 1.0.0
636 - */
637 - public function html_duration( $course ): string {
638 - $content = '';
639 -
640 - try {
641 - if ( $course instanceof LP_Course ) {
642 - $course = CourseModel::find( $course->get_id(), true );
643 - }
644 -
645 - $duration = $course->get_meta_value_by_key( CoursePostModel::META_KEY_DURATION, '' );
646 - $duration_arr = explode( ' ', $duration );
647 - $duration_number = floatval( $duration_arr[0] ?? 0 );
648 - $duration_type = $duration_arr[1] ?? '';
649 - if ( empty( $duration_number ) ) {
650 - $duration_str = __( 'Lifetime', 'learnpress' );
651 - } else {
652 - $duration_str = LP_Datetime::get_string_plural_duration( $duration_number, $duration_type );
653 - }
654 -
655 - $html_wrapper = [
656 - '<span class="course-duration">' => '</span>',
657 - ];
658 - $content = Template::instance()->nest_elements( $html_wrapper, $duration_str );
659 - } catch ( Throwable $e ) {
660 - error_log( __METHOD__ . ': ' . $e->getMessage() );
661 - }
662 -
663 - return $content;
664 - }
665 -
666 - /**
667 - * Get feature review
668 - *
669 - * @param CourseModel $course
670 - * @param UserModel|false $userModel
671 - * @param array $data
672 - *
673 - * @return string
674 - * @since 4.2.7
675 - * @version 1.0.2
676 - */
677 - public function html_feature_review( CourseModel $course, $userModel = false, array $data = [] ): string {
678 - $feature_review = $course->get_meta_value_by_key( CoursePostModel::META_KEY_FEATURED_REVIEW, '' );
679 - if ( empty( $feature_review ) ) {
680 - return '';
681 - }
682 -
683 - if ( $userModel instanceof UserModel ) {
684 - $userCourseModel = UserCourseModel::find( $userModel->get_id(), $course->get_id(), true );
685 - if ( $userCourseModel ) {
686 - return '';
687 - }
688 - }
689 -
690 - $stars = '';
691 - foreach ( range( 1, 5 ) as $star ) {
692 - $stars .= '<i class="lp-icon-star"></i>';
693 - }
694 -
695 - $section = [
696 - 'wrapper' => sprintf(
697 - '<div class="course-featured-review %s">',
698 - esc_attr( $data['lp_display_on'] ?? '' )
699 - ),
700 - 'title' => sprintf(
701 - '<div class="featured-review__title">%s</div>',
702 - esc_html__( 'Featured Review', 'learnpress' )
703 - ),
704 - 'stars' => sprintf(
705 - '<div class="featured-review__stars">%s</div>',
706 - $stars
707 - ),
708 - 'content' => sprintf(
709 - '<div class="featured-review__content">%s</div>',
710 - wp_kses_post( wpautop( $feature_review ) )
711 - ),
712 - 'wrapper_end' => '</div>',
713 - ];
714 -
715 - return Template::combine_components( $section );
716 - }
717 -
718 - /**
719 - * Get button external
720 - *
721 - * @param CourseModel $courseModel
722 - * @param UserModel|false $userModel
723 - *
724 - * @return string
725 - * @since 4.2.7
726 - * @version 1.0.3
727 - */
728 - public function html_btn_external( CourseModel $courseModel, $userModel ): string {
729 - $external_link = $courseModel->get_meta_value_by_key( CoursePostModel::META_KEY_EXTERNAL_LINK_BY_COURSE, '' );
730 - if ( empty( $external_link ) ) {
731 - return '';
732 - }
733 -
734 - // Check user has enrolled, finished or purchased course
735 - if ( $userModel instanceof UserModel ) {
736 - $userCourse = UserCourseModel::find( $userModel->get_id(), $courseModel->get_id(), true );
737 - if ( $userCourse && ( $userCourse->has_enrolled_or_finished() || $userCourse->has_purchased() ) ) {
738 - return '';
739 - }
740 - }
741 -
742 - $content = sprintf(
743 - '<a href="%s" class="lp-button course-btn-extra" target="_blank">%s</a>',
744 - esc_url_raw( $external_link ),
745 - __( 'Contact To Request', 'learnpress' )
746 - );
747 -
748 - return apply_filters( 'learn-press/course/html-button-external', $content, $courseModel, $userModel );
749 - }
750 -
751 - /**
752 - * HTML button purchase course
753 - *
754 - * @param CourseModel $courseModel
755 - * @param false|UserModel $userModel
756 - *
757 - * @return string
758 - * @since 4.2.7.2
759 - * @version 1.0.2
760 - */
761 - public function html_btn_purchase_course( CourseModel $courseModel, $userModel ): string {
762 - $html_btn = '';
763 - $can_purchase = $courseModel->can_purchase( $userModel );
764 - if ( is_wp_error( $can_purchase ) ) {
765 - $error_code_show = apply_filters(
766 - 'learn-press/course/html-button-purchase/show-messages',
767 - []
768 - );
769 - if ( in_array( $can_purchase->get_error_code(), $error_code_show )
770 - && ! empty( $can_purchase->get_error_message() ) ) {
771 - $html_btn = Template::print_message( $can_purchase->get_error_message(), 'warning', false );
772 - }
773 - } else {
774 - $html_btn = sprintf(
775 - '<button class="lp-button button-purchase-course">%s</button>',
776 - __( 'Buy Now', 'learnpress' )
777 - );
778 - }
779 -
780 - if ( empty( $html_btn ) ) {
781 - return apply_filters(
782 - 'learn-press/course/html-button-purchase/empty',
783 - $html_btn,
784 - $courseModel,
785 - $userModel
786 - );
787 - }
788 -
789 - $class_guest_checkout = LP_Checkout::instance()->is_enable_guest_checkout() ? 'guest_checkout' : '';
790 -
791 - // Hook action old
792 - $html_hook_old = '';
793 - if ( has_action( 'learn-press/after-purchase-button' ) ) {
794 - ob_start();
795 - do_action( 'learn-press/after-purchase-button' );
796 - $html_hook_old = ob_get_clean();
797 - }
798 -
799 - if ( has_filter( 'learnpress/course/template/button-purchase/can-show' ) ) {
800 - $user_id = 0;
801 - if ( $userModel instanceof UserModel ) {
802 - $user_id = $userModel->get_id();
803 - }
804 - $user_old = learn_press_get_user( $user_id );
805 - $course_old = learn_press_get_course( $courseModel->get_id() );
806 - $can_show = apply_filters( 'learnpress/course/template/button-purchase/can-show', true, $user_old, $course_old );
807 - if ( ! $can_show ) {
808 - return '';
809 - }
810 - }
811 - // End hook action old
812 -
813 - $section = apply_filters(
814 - 'learn-press/course/html-button-purchase',
815 - [
816 - 'form' => sprintf(
817 - '<form name="purchase-course" class="purchase-course %s" method="post">',
818 - esc_attr( $class_guest_checkout )
819 - ),
820 - 'input' => sprintf(
821 - '<input type="hidden" name="purchase-course" value="%d"/>',
822 - esc_attr( $courseModel->get_id() )
823 - ),
824 - 'btn' => $html_btn,
825 - 'hook_old' => $html_hook_old,
826 - 'form_end' => '</form>',
827 - ],
828 - $courseModel,
829 - $userModel
830 - );
831 -
832 - return Template::combine_components( $section );
833 - }
834 -
835 - /**
836 - * HTML button enroll course
837 - *
838 - * @param CourseModel $courseModel
839 - * @param false|UserModel $userModel
840 - *
841 - * @return string
842 - * @since 4.2.7.3
843 - * @version 1.0.0
844 - */
845 - public function html_btn_enroll_course( CourseModel $courseModel, $userModel ): string {
846 - $html_btn = '';
847 - $can_enroll = $courseModel->can_enroll( $userModel );
848 - if ( is_wp_error( $can_enroll ) ) {
849 - $error_code_show = apply_filters(
850 - 'learn-press/course/html-button-enroll/show-messages',
851 - [ 'course_is_no_required_enroll_not_login', 'course_out_of_stock' ]
852 - );
853 - if ( in_array( $can_enroll->get_error_code(), $error_code_show )
854 - && ! empty( $can_enroll->get_error_message() ) ) {
855 - $html_btn = Template::print_message( $can_enroll->get_error_message(), 'warning', false );
856 - }
857 - } else {
858 - $html_btn = sprintf(
859 - '<button type="submit" class="lp-button button-enroll-course">%s</button>',
860 - __( 'Start Now', 'learnpress' )
861 - );
862 - }
863 -
864 - if ( empty( $html_btn ) ) {
865 - return $html_btn;
866 - }
867 -
868 - // Hook old
869 - $html_hook_before_old = '';
870 - if ( has_action( 'learn-press/before-enroll-button' ) ) {
871 - ob_start();
872 - do_action( 'learn-press/before-enroll-button' );
873 - $html_hook_before_old = ob_get_clean();
874 - }
875 -
876 - $html_hook_after_old = '';
877 - if ( has_action( 'learn-press/after-enroll-button' ) ) {
878 - ob_start();
879 - do_action( 'learn-press/after-enroll-button' );
880 - $html_hook_after_old = ob_get_clean();
881 - }
882 -
883 - if ( has_filter( 'learnpress/course/template/button-enroll/can-show' ) ) {
884 - $user_id = 0;
885 - if ( $userModel instanceof UserModel ) {
886 - $user_id = $userModel->get_id();
887 - }
888 - $user_old = learn_press_get_user( $user_id );
889 - $course_old = learn_press_get_course( $courseModel->get_id() );
890 - $can_show = apply_filters( 'learnpress/course/template/button-enroll/can-show', true, $user_old, $course_old );
891 - if ( ! $can_show ) {
892 - return '';
893 - }
894 - }
895 - // End hook old
896 -
897 - $section = apply_filters(
898 - 'learn-press/course/html-button-enroll',
899 - [
900 - 'form' => '<form name="enroll-course" class="enroll-course" method="post">',
901 - 'hook_before_old' => $html_hook_before_old,
902 - 'input' => sprintf(
903 - '<input type="hidden" name="enroll-course" value="%s"/>',
904 - esc_attr( $courseModel->get_id() )
905 - ),
906 - 'btn' => $html_btn,
907 - 'hook_after_old' => $html_hook_after_old,
908 - 'form_end' => '</form>',
909 - ],
910 - $courseModel,
911 - $userModel
912 - );
913 -
914 - return Template::combine_components( $section );
915 - }
916 -
917 - /**
918 - * Sidebar
919 - *
920 - * @param CourseModel $courseModel
921 - * @param array $data
922 - *
923 - * @return void
924 - * @version 1.0.1
925 - * @since 4.2.7
926 - */
927 - public function html_sidebar( CourseModel $courseModel, array $data = [] ): string {
928 - $html = '';
929 -
930 - try {
931 - if ( is_active_sidebar( 'course-sidebar' ) ) {
932 - ob_start();
933 - dynamic_sidebar( 'course-sidebar' );
934 - $sidebar_content = ob_get_clean();
935 -
936 - $section = apply_filters(
937 - 'learn-press/course/html-sidebar',
938 - [
939 - 'wrapper' => sprintf(
940 - '<div class="lp-single-course-sidebar %s">',
941 - esc_attr( $data['lp_display_on'] ?? '' )
942 - ),
943 - 'content' => $sidebar_content,
944 - 'wrapper_end' => '</div>',
945 - ],
946 - $courseModel
947 - );
948 -
949 - $html = Template::combine_components( $section );
950 - }
951 - } catch ( Throwable $e ) {
952 - error_log( $e->getMessage() );
953 - }
954 -
955 - return $html;
956 - }
957 -
958 - /**
959 - * HTML meta faqs
960 - *
961 - * @param CourseModel $courseModel
962 - * @param array $data
963 - *
964 - * @return string
965 - * @since 4.2.7.2
966 - * @version 1.0.1
967 - */
968 - public function html_faqs( CourseModel $courseModel, array $data = [] ): string {
969 - $html = '';
970 -
971 - try {
972 - $show_heading = $data['show_heading'] ?? true;
973 - $faqs = $courseModel->get_meta_value_by_key( CoursePostModel::META_KEY_FAQS, [] );
974 - if ( ! is_array( $faqs ) && ! is_object( $faqs ) ) {
975 - return '';
976 - }
977 - if ( empty( $faqs ) ) {
978 - return '';
979 - }
980 -
981 - foreach ( $faqs as $faq ) {
982 - $title = $faq[0];
983 - $description = $faq[1];
984 - if ( empty( $title ) || empty( $description ) ) {
985 - continue;
986 - }
987 -
988 - $key = uniqid();
989 - $section_item = [
990 - 'input_checkbox' => sprintf(
991 - '<input type="checkbox" name="course-faqs-box-ratio" id="course-faqs-box-ratio-%s">',
992 - $key
993 - ),
994 - 'wrapper' => '<div class="course-faqs-box">',
995 - 'title' => sprintf(
996 - '<label class="course-faqs-box__title" for="course-faqs-box-ratio-%s">%s</label>',
997 - $key,
998 - $title
999 - ),
1000 - 'content' => '<div class="course-faqs-box__content">',
1001 - 'content_inner' => '<div class="course-faqs-box__content-inner">',
1002 - 'content_main' => wp_kses_post( $description ),
1003 - 'content_inner_end' => '</div>',
1004 - 'content_end' => '</div>',
1005 - 'wrapper_end' => '</div>',
1006 - ];
1007 - $html .= Template::combine_components( $section_item );
1008 - }
1009 -
1010 - $section = apply_filters(
1011 - 'learn-press/course/html-faqs',
1012 - [
1013 - 'wrapper' => '<div class="course-faqs course-tab-panel-faqs">',
1014 - 'title' => $show_heading ? sprintf(
1015 - '<h3 class="course-faqs__title">%s</h3>',
1016 - __( 'FAQs', 'learnpress' )
1017 - ) : '',
1018 - 'content' => $html,
1019 - 'wrapper_end' => '</div>',
1020 - ],
1021 - $courseModel
1022 - );
1023 - $html = Template::combine_components( $section );
1024 - } catch ( Throwable $e ) {
1025 - error_log( $e->getMessage() );
1026 - }
1027 -
1028 - return $html;
1029 - }
1030 -
1031 - /**
1032 - * HTML struct course box extra
1033 - *
1034 - * @param CourseModel $courseModel
1035 - * @param $title
1036 - * @param string $html_list
1037 - *
1038 - * @return string
1039 - * @since 4.2.7.2
1040 - * @version 1.0.0
1041 - */
1042 - public function html_course_box_extra( CourseModel $courseModel, $title, string $html_list ): string {
1043 - if ( empty( $html_list ) ) {
1044 - return '';
1045 - }
1046 -
1047 - $section = apply_filters(
1048 - 'learn-press/course/html-course-box-extra',
1049 - [
1050 - 'wrapper' => '<div class="course-extra-box">',
1051 - 'title' => sprintf( '<h3 class="course-extra-box__title">%s</h3>', $title ),
1052 - 'content' => '<div class="course-extra-box__content">',
1053 - 'content_inner' => '<div class="course-extra-box__content-inner">',
1054 - 'list' => $html_list,
1055 - 'content_inner_end' => '</div>',
1056 - 'content_end' => '</div>',
1057 - 'wrapper_end' => '</div>',
1058 - ],
1059 - $courseModel
1060 - );
1061 -
1062 - return Template::combine_components( $section );
1063 - }
1064 -
1065 - /**
1066 - * HTML meta requirements
1067 - *
1068 - * @param CourseModel $courseModel
1069 - *
1070 - * @return string
1071 - * @since 4.2.7.2
1072 - * @version 1.0.0
1073 - */
1074 - public function html_requirements( CourseModel $courseModel ): string {
1075 - $html = '';
1076 -
1077 - try {
1078 - $requirements = $courseModel->get_meta_value_by_key( CoursePostModel::META_KEY_REQUIREMENTS, [] );
1079 - if ( ! is_array( $requirements ) && ! is_object( $requirements ) ) {
1080 - return '';
1081 - }
1082 - if ( empty( $requirements ) ) {
1083 - return '';
1084 - }
1085 -
1086 - $html_lis = '';
1087 - foreach ( $requirements as $requirement ) {
1088 - $html_lis .= sprintf( '<li>%s</li>', $requirement );
1089 - }
1090 -
1091 - $section_list = [
1092 - 'wrapper' => '<ul>',
1093 - 'content' => $html_lis,
1094 - 'wrapper_end' => '</ul>',
1095 - ];
1096 -
1097 - $section = apply_filters(
1098 - 'learn-press/course/html-requirements',
1099 - [
1100 - 'wrapper' => '<div class="course-requirements extra-box">',
1101 - 'title' => sprintf( '<h3 class="extra-box__title">%s</h3>', __( 'Requirements', 'learnpress' ) ),
1102 - 'content' => Template::combine_components( $section_list ),
1103 - 'wrapper_end' => '</div>',
1104 - ],
1105 - $courseModel,
1106 - $requirements
1107 - );
1108 - $html = Template::combine_components( $section );
1109 - } catch ( Throwable $e ) {
1110 - error_log( $e->getMessage() );
1111 - }
1112 -
1113 - return $html;
1114 - }
1115 -
1116 - /**
1117 - * HTML meta features
1118 - *
1119 - * @param CourseModel $courseModel
1120 - *
1121 - * @return string
1122 - * @since 4.2.7.2
1123 - * @version 1.0.0
1124 - */
1125 - public function html_features( CourseModel $courseModel ): string {
1126 - $html = '';
1127 -
1128 - try {
1129 - $features = $courseModel->get_meta_value_by_key( CoursePostModel::META_KEY_FEATURES, [] );
1130 - if ( ! is_array( $features ) && ! is_object( $features ) ) {
1131 - return '';
1132 - }
1133 - if ( empty( $features ) ) {
1134 - return '';
1135 - }
1136 -
1137 - $html_lis = '';
1138 - foreach ( $features as $feature ) {
1139 - $html_lis .= sprintf( '<li>%s</li>', $feature );
1140 - }
1141 -
1142 - $section_list = [
1143 - 'wrapper' => '<ul>',
1144 - 'content' => $html_lis,
1145 - 'wrapper_end' => '</ul>',
1146 - ];
1147 -
1148 - $section = apply_filters(
1149 - 'learn-press/course/html-features',
1150 - [
1151 - 'wrapper' => '<div class="course-features extra-box">',
1152 - 'title' => sprintf( '<h3 class="extra-box__title">%s</h3>', __( 'Features', 'learnpress' ) ),
1153 - 'content' => Template::combine_components( $section_list ),
1154 - 'wrapper_end' => '</div>',
1155 - ],
1156 - $courseModel,
1157 - $features
1158 - );
1159 - $html = Template::combine_components( $section );
1160 - } catch ( Throwable $e ) {
1161 - error_log( $e->getMessage() );
1162 - }
1163 -
1164 - return $html;
1165 - }
1166 -
1167 - /**
1168 - * HTML meta target
1169 - *
1170 - * @param CourseModel $courseModel
1171 - *
1172 - * @return string
1173 - * @since 4.2.7.2
1174 - * @version 1.0.0
1175 - */
1176 - public function html_target( CourseModel $courseModel ): string {
1177 - $html = '';
1178 -
1179 - try {
1180 - $targets = $courseModel->get_meta_value_by_key( CoursePostModel::META_KEY_TARGET, [] );
1181 - if ( ! is_array( $targets ) && ! is_object( $targets ) ) {
1182 - return '';
1183 - }
1184 - if ( empty( $targets ) ) {
1185 - return '';
1186 - }
1187 -
1188 - $html_lis = '';
1189 - foreach ( $targets as $target ) {
1190 - $html_lis .= sprintf( '<li>%s</li>', $target );
1191 - }
1192 -
1193 - $section_list = [
1194 - 'wrapper' => '<ul>',
1195 - 'content' => $html_lis,
1196 - 'wrapper_end' => '</ul>',
1197 - ];
1198 -
1199 - $section = apply_filters(
1200 - 'learn-press/course/html-target',
1201 - [
1202 - 'wrapper' => '<div class="course-target extra-box">',
1203 - 'title' => sprintf( '<h3 class="extra-box__title">%s</h3>', __( 'Target audiences', 'learnpress' ) ),
1204 - 'content' => Template::combine_components( $section_list ),
1205 - 'wrapper_end' => '</div>',
1206 - ],
1207 - $courseModel,
1208 - $targets
1209 - );
1210 - $html = Template::combine_components( $section );
1211 - } catch ( Throwable $e ) {
1212 - error_log( $e->getMessage() );
1213 - }
1214 -
1215 - return $html;
1216 - }
1217 -
1218 - /**
1219 - * HTML material
1220 - *
1221 - * @param CourseModel $courseModel
1222 - * @param UserModel|false $userModel
1223 - * @param array $data
1224 - *
1225 - * @return string
1226 - * @since 4.2.7.2
1227 - * @version 1.0.4
1228 - */
1229 - public function html_material( CourseModel $courseModel, $userModel = false, array $data = [] ): string {
1230 - $html = '';
1231 -
1232 - try {
1233 - $show_heading = $data['show_heading'] ?? true;
1234 - $can_show = false;
1235 -
1236 - if ( $userModel instanceof UserModel ) {
1237 - if ( $courseModel->check_user_is_author( $userModel )
1238 - || user_can( $userModel->get_id(), ADMIN_ROLE ) ) {
1239 - $can_show = true;
1240 - } else {
1241 - $userCourseModel = UserCourseModel::find( $userModel->get_id(), $courseModel->get_id(), true );
1242 - if ( $userCourseModel &&
1243 - ( $userCourseModel->has_enrolled_or_finished()
1244 - || $userCourseModel->has_purchased() ) ) {
1245 - $can_show = true;
1246 - }
1247 - }
1248 - } elseif ( $courseModel->has_no_enroll_requirement() ) {
1249 - $can_show = true;
1250 - }
1251 -
1252 - $can_show = apply_filters( 'learn-press/course-material/can-show', $can_show, $courseModel, $userModel );
1253 -
1254 - $file_per_page = LP_Settings::get_option( 'material_file_per_page', - 1 );
1255 - $count_files = LP_Material_Files_DB::getInstance()->get_total( $courseModel->get_id() );
1256 - if ( ! $can_show || $file_per_page == 0 || $count_files <= 0 ) {
1257 - return $html;
1258 - }
1259 -
1260 - ob_start();
1261 - do_action( 'learn-press/course-material/layout', [] );
1262 - $html_content = ob_get_clean();
1263 -
1264 - $section = [
1265 - 'wrapper' => '<div class="course-material">',
1266 - 'title' => $show_heading ? sprintf(
1267 - '<h3 class="course-material__title">%s</h3>',
1268 - __( 'Course Material', 'learnpress' )
1269 - ) : '',
1270 - 'content' => $html_content,
1271 - 'wrapper_end' => '</div>',
1272 - ];
1273 -
1274 - $html = Template::combine_components( $section );
1275 - } catch ( Throwable $e ) {
1276 - error_log( __METHOD__ . ': ' . $e->getMessage() );
1277 - }
1278 -
1279 - return $html;
1280 - }
1281 -
1282 - /**
1283 - * Get html level course.
1284 - *
1285 - * @param LP_Course|CourseModel $course
1286 - *
1287 - * @return string
1288 - * @since 4.2.7.5
1289 - * @version 1.0.1
1290 - */
1291 - public function html_price_prefix( $course ): string {
1292 - $html = '';
1293 -
1294 - try {
1295 - if ( $course instanceof LP_Course ) {
1296 - $course = CourseModel::find( $course->get_id(), true );
1297 - if ( ! $course instanceof CourseModel ) {
1298 - return $html;
1299 - }
1300 - }
1301 -
1302 - $price_prefix_str = $course->get_meta_value_by_key( CoursePostModel::META_KEY_PRICE_PREFIX, '' );
1303 - if ( empty( $price_prefix_str ) ) {
1304 - return $html;
1305 - }
1306 -
1307 - $html = sprintf( '<span class="course-price-prefix">%s</span>', $price_prefix_str );
1308 - } catch ( Throwable $e ) {
1309 - error_log( __METHOD__ . ': ' . $e->getMessage() );
1310 - }
1311 -
1312 - return $html;
1313 - }
1314 -
1315 - /**
1316 - * Get html level course.
1317 - *
1318 - * @param LP_Course|CourseModel $course
1319 - *
1320 - * @return string
1321 - * @since 4.2.7.5
1322 - * @version 1.0.0
1323 - */
1324 - public function html_price_suffix( $course ): string {
1325 - $html = '';
1326 -
1327 - try {
1328 - $price_suffix_str = $course->get_meta_value_by_key( CoursePostModel::META_KEY_PRICE_SUFFIX, '' );
1329 - if ( empty( $price_suffix_str ) ) {
1330 - return $html;
1331 - }
1332 -
1333 - $html = sprintf( '<span class="course-price-suffix">%s</span>', $price_suffix_str );
1334 - } catch ( Throwable $e ) {
1335 - error_log( __METHOD__ . ': ' . $e->getMessage() );
1336 - }
1337 -
1338 - return $html;
1339 - }
1340 -
1341 - /**
1342 - * Get html featured course.
1343 - *
1344 - * @param CourseModel $courseModel
1345 - *
1346 - * @return string
1347 - * @since 4.2.9
1348 - * @version 1.0.0
1349 - */
1350 - public function html_featured( CourseModel $courseModel ): string {
1351 - $html = '';
1352 -
1353 - try {
1354 - $is_featured = $courseModel->get_meta_value_by_key( CoursePostModel::META_KEY_FEATURED, 'no' );
1355 - if ( $is_featured !== 'yes' ) {
1356 - return $html;
1357 - }
1358 -
1359 - $html = sprintf( '<span class="course-featured">%s</span>', __( 'Featured', 'learnpress' ) );
1360 - } catch ( Throwable $e ) {
1361 - LP_Debug::error_log( $e );
1362 - }
1363 -
1364 - return $html;
1365 - }
1366 -
1367 - /**
1368 - * GET HTML comment default of WP
1369 - *
1370 - * @param CourseModel $courseModel
1371 - * @param false|UserModel $userModel
1372 - *
1373 - * @return string
1374 - * @since 4.2.7.6
1375 - * @version 1.0.0
1376 - */
1377 - public function html_comment( CourseModel $courseModel, $userModel = false ): string {
1378 - $args = [
1379 - 'id_url' => 'course-comments',
1380 - 'course_id' => $courseModel->get_id(),
1381 - 'user_id' => $userModel instanceof UserModel ? $userModel->get_id() : 0,
1382 - ];
1383 - $callBack = [
1384 - 'class' => __CLASS__,
1385 - 'method' => 'render_html_comments',
1386 - ];
1387 - $html = TemplateAJAX::load_content_via_ajax( $args, $callBack );
1388 -
1389 - $section_comment = apply_filters(
1390 - 'learn-press/single-course/html-comment',
1391 - [
1392 - 'wrapper' => '<div class="lp-course-comment">',
1393 - 'content' => $html,
1394 - 'wrapper_end' => '</div>',
1395 - ],
1396 - $courseModel,
1397 - $userModel
1398 - );
1399 -
1400 - return Template::combine_components( $section_comment );
1401 - }
1402 -
1403 - /**
1404 - * Render HTML comments of course.
1405 - *
1406 - * @param array $data ['course_id']
1407 - *
1408 - * @return stdClass
1409 - * @since 4.2.7.6
1410 - * @version 1.0.0
1411 - */
1412 - public static function render_html_comments( array $data ): stdClass {
1413 - $response = new stdClass();
1414 - $response->content = '';
1415 -
1416 - try {
1417 - $course_id = $data['course_id'] ?? 0;
1418 - $user_id = $data['user_id'] ?? 0;
1419 - if ( empty( $course_id ) ) {
1420 - return $response;
1421 - }
1422 -
1423 - global $withcomments, $post;
1424 -
1425 - $post = get_post( $course_id );
1426 - if ( $post->comment_status !== 'open' ) {
1427 - return $response;
1428 - } else {
1429 - $withcomments = true;
1430 - }
1431 -
1432 - $withcomments = apply_filters(
1433 - 'learn-press/single-course/render-html-comment/is-show',
1434 - $withcomments,
1435 - $post,
1436 - $user_id
1437 - );
1438 -
1439 - //$post->comment_count = 0;
1440 -
1441 - ob_start();
1442 - add_filter( 'deprecated_file_trigger_error', '__return_false' );
1443 - comments_template();
1444 - remove_filter( 'deprecated_file_trigger_error', '__return_false' );
1445 - $html = ob_get_clean();
1446 - $response->content = $html;
1447 - } catch ( Throwable $e ) {
1448 - $response->content = Template::print_message( $e->getMessage(), 'error', false );
1449 - }
1450 -
1451 - return $response;
1452 - }
1453 -
1454 - /**
1455 - * Get HTML curriculum of course.
1456 - *
1457 - * @param CourseModel $courseModel
1458 - * @param UserModel|false $userModel
1459 - * @param LessonPostModel|QuizPostModel|PostModel|mixed $itemModelCurrent
1460 - *
1461 - * @return string
1462 - * @since 4.2.7.6
1463 - * @version 1.0.3
1464 - */
1465 - public function html_curriculum( CourseModel $courseModel, $userModel, $itemModelCurrent = false ): string {
1466 - $html = '';
1467 -
1468 - try {
1469 - // Get current item viewing
1470 - /**
1471 - * @var $lp_course_item LP_Course_Item
1472 - * @var $post \WP_Post
1473 - */
1474 - global $lp_course_item, $post;
1475 - /**
1476 - * @var $itemModelCurrent LessonPostModel|QuizPostModel|AssignmentPostModel|PostModel...
1477 - */
1478 - $itemModelCurrent = $courseModel->get_item_model( $post->ID, $post->post_type );
1479 - if ( $lp_course_item ) {
1480 - $itemModelCurrent = $courseModel->get_item_model( $lp_course_item->get_id(), $lp_course_item->get_item_type() );
1481 - }
1482 -
1483 - if ( $itemModelCurrent ) {
1484 - $item_types = CourseModel::item_types_support();
1485 - // Check item type is support
1486 - if ( in_array( $itemModelCurrent->post_type, $item_types ) ) {
1487 - $this->currentItemModel = $itemModelCurrent;
1488 - }
1489 - }
1490 - // End get current item viewing
1491 -
1492 - $section_items = $courseModel->get_section_items();
1493 - $html = Template::print_message(
1494 - esc_html__( 'There are no items in the curriculum yet.', 'learnpress' ),
1495 - 'info',
1496 - false
1497 - );
1498 - if ( empty( $section_items ) ) {
1499 - return $html;
1500 - }
1501 -
1502 - wp_enqueue_script( 'lp-curriculum' );
1503 - $li_section_items = '';
1504 - foreach ( $section_items as $section_item ) {
1505 - $li_section_items .= $this->render_html_section_item( $courseModel, $userModel, $section_item );
1506 - }
1507 -
1508 - $section = apply_filters(
1509 - 'learn-press/course/html-curriculum',
1510 - [
1511 - 'wrapper' => '<div class="lp-course-curriculum">',
1512 - 'title' => sprintf(
1513 - '<h3 class="lp-course-curriculum__title">%s</h3>',
1514 - esc_html__( 'Curriculum', 'learnpress' )
1515 - ),
1516 - 'curriculum_info' => '<div class="course-curriculum-info">',
1517 - 'curriculum_info_left' => '<ul class="course-curriculum-info__left">',
1518 - 'count_sections' => sprintf(
1519 - '<li class="course-count-section">%s</li>',
1520 - sprintf(
1521 - _n( '%d Section', '%d Sections', $courseModel->get_total_sections(), 'learnpress' ),
1522 - $courseModel->get_total_sections()
1523 - )
1524 - ),
1525 - 'count_lesson' => sprintf(
1526 - '<li class="course-count-lesson">%s</li>',
1527 - sprintf(
1528 - _n( '%d Lesson', '%d Lessons', $courseModel->count_items( LP_LESSON_CPT ), 'learnpress' ),
1529 - $courseModel->count_items( LP_LESSON_CPT )
1530 - )
1531 - ),
1532 - 'duration' => sprintf(
1533 - '<li class="course-duration">%s</li>',
1534 - $this->html_duration( $courseModel )
1535 - ),
1536 - 'curriculum_info_left_end' => '</ul>',
1537 - 'curriculum_info_right' => '<div class="course-curriculum-info__right">',
1538 - 'expand_all' => sprintf(
1539 - '<span class="course-toggle-all-sections">%s</span>',
1540 - esc_html__( 'Expand all sections', 'learnpress' )
1541 - ),
1542 - 'collapse_all' => sprintf(
1543 - '<span class="course-toggle-all-sections lp-collapse lp-hidden">%s</span>',
1544 - esc_html__( 'Collapse all sections', 'learnpress' )
1545 - ),
1546 - 'curriculum_info_right_end' => '</div>',
1547 - 'curriculum_info_end' => '</div>',
1548 - 'curriculum' => '<div class="course-curriculum">',
1549 - 'sections' => '<ul class="course-sections">',
1550 - 'li_section_items' => $li_section_items,
1551 - 'sections_end' => '</ul>',
1552 - 'curriculum_end' => '</div>',
1553 - 'wrapper_end' => '</div>',
1554 - ],
1555 - $courseModel,
1556 - $userModel,
1557 - $itemModelCurrent
1558 - );
1559 -
1560 - $html = Template::combine_components( $section );
1561 - } catch ( Throwable $e ) {
1562 - error_log( __METHOD__ . ': ' . $e->getMessage() );
1563 - }
1564 -
1565 - return $html;
1566 - }
1567 -
1568 - /**
1569 - * Render HTML section item
1570 - *
1571 - * @param CourseModel $courseModel
1572 - * @param UserModel|false $userModel
1573 - * @param $section_item object {section_id, section_name, section_description, items[{item_id, item_order, item_type, title, preview}]}
1574 - *
1575 - * @return string
1576 - * @since 4.2.7.6
1577 - * @version 1.0.1
1578 - */
1579 - public function render_html_section_item( CourseModel $courseModel, $userModel, $section_item ): string {
1580 - if ( ! $section_item instanceof stdClass ) {
1581 - return '';
1582 - }
1583 -
1584 - $section_id = $section_item->section_id ?? 0;
1585 - $section_name = $section_item->section_name ?? '';
1586 - $section_description = $section_item->section_description ?? '';
1587 - $section_order = $section_item->section_order ?? 1;
1588 - $items = $section_item->items ?? [];
1589 - $html_section_description = '';
1590 - if ( ! empty( $section_description ) ) {
1591 - $html_section_description = sprintf(
1592 - '<div class="course-section__description">%s</div>',
1593 - wp_kses_post( $section_description )
1594 - );
1595 - }
1596 -
1597 - $section_header = [
1598 - 'start' => '<div class="course-section-header">',
1599 - 'toggle' => '<div class="section-toggle">
1600 - <i class="lp-icon-angle-down"></i>
1601 - <i class="lp-icon-angle-up"></i>
1602 - </div>',
1603 - 'info' => '<div class="course-section-info">',
1604 - 'title' => sprintf( '<div class="course-section__title">%s</div>', wp_kses_post( $section_name ) ),
1605 - 'description' => $html_section_description,
1606 - 'info_end' => '</div>',
1607 - 'count_items' => sprintf(
1608 - '<div class="section-count-items">%d</div>',
1609 - count( $items )
1610 - ),
1611 - 'end' => '</div>',
1612 - ];
1613 -
1614 - $li_items = '';
1615 - foreach ( $items as $item ) {
1616 - $li_items .= $this->render_html_course_item( $courseModel, $userModel, $item, $section_item );
1617 - }
1618 - $section_items = [
1619 - 'start' => '<ul class="course-section__items">',
1620 - 'li_items' => $li_items,
1621 - 'end' => '</ul>',
1622 - ];
1623 -
1624 - $curriculum_display_setting = LP_Settings::get_option( 'curriculum_display', 'expand_first_section' );
1625 - $class_section_toggle = '';
1626 -
1627 - if ( $this->currentItemModel ) {
1628 - $current_section = $courseModel->get_section_of_item( $this->currentItemModel->get_id() );
1629 - if ( $current_section != $section_id ) {
1630 - $class_section_toggle = 'lp-collapse';
1631 - }
1632 - } else {
1633 - if ( $curriculum_display_setting === 'collapse_all' ) {
1634 - $class_section_toggle = 'lp-collapse';
1635 - } elseif ( $curriculum_display_setting === 'expand_first_section' ) {
1636 - if ( $section_order > 1 ) {
1637 - $class_section_toggle = 'lp-collapse';
1638 - }
1639 - }
1640 - }
1641 -
1642 - $class_section_toggle = apply_filters(
1643 - 'learn-press/course/html-section-item/class-section-toggle',
1644 - $class_section_toggle,
1645 - $courseModel,
1646 - $userModel,
1647 - $section_item
1648 - );
1649 -
1650 - $section_item = apply_filters(
1651 - 'learn-press/course/html-section-item',
1652 - [
1653 - 'start' => sprintf(
1654 - '<li class="course-section %s" data-section-id="%s">',
1655 - $class_section_toggle,
1656 - $section_id
1657 - ),
1658 - 'header' => Template::combine_components( $section_header ),
1659 - 'items' => Template::combine_components( $section_items ),
1660 - 'end' => '</li>',
1661 - ],
1662 - $courseModel,
1663 - $userModel,
1664 - $section_item
1665 - );
1666 -
1667 - return Template::combine_components( $section_item );
1668 - }
1669 -
1670 - /**
1671 - * @param CourseModel $courseModel
1672 - * @param UserModel|false $userModel
1673 - * @param $item stdClass {item_id, item_order, item_type, title, preview}
1674 - * @param $section_item stdClass {section_id, section_name, section_description, items[{item_id, item_order, item_type, title, preview}]}
1675 - *
1676 - * @return string
1677 - * @since 4.2.7.6
1678 - * @version 1.0.2
1679 - */
1680 - public function render_html_course_item( CourseModel $courseModel, $userModel, $item, $section_item ): string {
1681 - $html = '';
1682 -
1683 - if ( ! $item instanceof stdClass ) {
1684 - return $html;
1685 - }
1686 -
1687 - $item_id = (int) ( $item->item_id ?? $item->id ?? 0 );
1688 - $item_order = $item->item_order ?? $item->order ?? 0;
1689 - $item_type = $item->item_type ?? $item->type ?? '';
1690 - $title = $item->title ?? '';
1691 - $has_preview = $item->preview ?? '';
1692 - $class_current = '';
1693 - if ( $this->currentItemModel ) {
1694 - $current_item_id = $this->currentItemModel->get_id();
1695 - if ( $current_item_id == $item_id ) {
1696 - $class_current = 'current';
1697 - }
1698 - }
1699 -
1700 - //LP_Course_Item::get_item( $item_id, $course->get_id() );
1701 - $itemModel = $courseModel->get_item_model( $item_id, $item_type );
1702 - if ( empty( $itemModel ) ) {
1703 - return $html;
1704 - }
1705 -
1706 - $link_item = $courseModel->get_item_link( $item_id, $item_type );
1707 -
1708 - $item_duration = '';
1709 - $html_item_duration = '';
1710 - if ( is_callable( [ $itemModel, 'get_duration' ] ) ) {
1711 - $item_duration = $itemModel->get_duration();
1712 - } else {
1713 - $item_duration = get_post_meta( $item_id, '_lp_duration', true );
1714 - }
1715 -
1716 - $duration_arr = explode( ' ', $item_duration );
1717 - $duration_number = floatval( $duration_arr[0] ?? 0 );
1718 - $duration_type = $duration_arr[1] ?? '';
1719 -
1720 - if ( $duration_number > 0 ) {
1721 - $item_duration_plural = LP_Datetime::get_string_plural_duration( $duration_number, $duration_type );
1722 -
1723 - $html_item_duration = sprintf(
1724 - '<span class="duration">%s</span>',
1725 - $item_duration_plural
1726 - );
1727 - }
1728 -
1729 - // Count question of quiz
1730 - $html_item_count_questions = '';
1731 - if ( $item_type === LP_QUIZ_CPT ) {
1732 - $quizPostModel = QuizPostModel::find( $item_id, true );
1733 - if ( $quizPostModel instanceof QuizPostModel ) {
1734 - $question_count = $quizPostModel->count_questions();
1735 - $html_item_duration .= sprintf(
1736 - '<span class="question-count">%s</span>',
1737 - sprintf(
1738 - _n( '%d Question', '%d Questions', $question_count, 'learnpress' ),
1739 - $question_count
1740 - )
1741 - );
1742 - }
1743 - }
1744 -
1745 - $user_item_status_ico_flag = 'locked';
1746 - $user_attended_course = false;
1747 - if ( $userModel instanceof UserModel ) {
1748 - $userCourseModel = UserCourseModel::find( $userModel->get_id(), $courseModel->get_id(), true );
1749 - if ( $userCourseModel
1750 - && $userCourseModel->get_status() !== UserItemModel::STATUS_CANCEL
1751 - && $userCourseModel->get_status() !== UserCourseModel::STATUS_PURCHASED ) {
1752 - $user_attended_course = true;
1753 -
1754 - // Check status of item's course
1755 - $userCourseItem = $userCourseModel->get_item_attend( $item_id, $item_type );
1756 - if ( ! $userCourseItem instanceof UserItemModel ) {
1757 - $user_item_status_ico_flag = UserItemModel::GRADUATION_IN_PROGRESS;
1758 - } else {
1759 - $user_item_status_ico_flag = $userCourseItem->get_status();
1760 - $user_item_graduation = $userCourseItem->get_graduation();
1761 - if ( ! empty( $user_item_graduation ) ) {
1762 - $user_item_status_ico_flag = $user_item_graduation . ' completed';
1763 - }
1764 -
1765 - if ( empty( $user_item_status_ico_flag ) ) {
1766 - $user_item_status_ico_flag = UserItemModel::GRADUATION_IN_PROGRESS;
1767 - }
1768 - }
1769 -
1770 - if ( $user_item_status_ico_flag === UserItemModel::GRADUATION_IN_PROGRESS ) {
1771 - if ( $userCourseModel->get_time_remaining() === 0 ) {
1772 - $user_item_status_ico_flag = 'locked';
1773 - } elseif ( $userCourseModel->get_status() === UserItemModel::STATUS_FINISHED
1774 - && $courseModel->enable_block_when_finished() ) {
1775 - $user_item_status_ico_flag = 'locked';
1776 - }
1777 - }
1778 - }
1779 - }
1780 -
1781 - if ( $has_preview && ! $user_attended_course ) {
1782 - $user_item_status_ico_flag = 'preview';
1783 - }
1784 -
1785 - if ( $courseModel->has_no_enroll_requirement()
1786 - && ! $user_attended_course && ! $userModel ) {
1787 - $user_item_status_ico_flag = UserItemModel::GRADUATION_IN_PROGRESS;
1788 - }
1789 -
1790 - $user_item_status_ico_flag = apply_filters(
1791 - 'learn-press/course/item/status-ico-flag',
1792 - $user_item_status_ico_flag,
1793 - $courseModel,
1794 - $userModel,
1795 - $item,
1796 - $section_item
1797 - );
1798 -
1799 - $html_item_status = sprintf(
1800 - '<div class="course-item__status"><span class="course-item-ico %1$s"></span></div>',
1801 - $user_item_status_ico_flag
1802 - );
1803 -
1804 - $html_item_right = [];
1805 - if ( $html_item_count_questions != '' || $html_item_duration != '' ) {
1806 - $html_item_right = [
1807 - 'item_right' => '<div class="course-item__right">',
1808 - 'question_count' => $html_item_count_questions,
1809 - 'duration' => $html_item_duration,
1810 - 'item_right_end' => '</div>',
1811 - ];
1812 - }
1813 -
1814 - $section_item = apply_filters(
1815 - 'learn-press/course/html-course-item',
1816 - [
1817 - 'start' => sprintf(
1818 - '<li class="course-item %s" data-item-id="%s" data-item-order="%s" data-item-type="%s">',
1819 - $class_current,
1820 - $item_id,
1821 - $item_order,
1822 - $item_type
1823 - ),
1824 - 'link' => sprintf(
1825 - '<a href="%s" class="course-item__link">',
1826 - esc_url_raw( $link_item )
1827 - ),
1828 - 'item_info' => '<div class="course-item__info">',
1829 - 'icon' => sprintf(
1830 - '<span class="course-item-ico %s"></span>',
1831 - esc_attr( $item_type )
1832 - ),
1833 - 'item_order' => sprintf(
1834 - '<span class="course-item-order lp-hidden">%s.%s</span>',
1835 - $section_item->section_order,
1836 - $item_order
1837 - ),
1838 - 'item_info_end' => '</div>',
1839 - 'item_content' => '<div class="course-item__content">',
1840 - 'item_left' => '<div class="course-item__left">',
1841 - 'title' => sprintf( '<div class="course-item-title">%s</div>', wp_kses_post( $title ) ),
1842 - 'item_left_end' => '</div>',
1843 - 'item_right' => Template::combine_components( $html_item_right ),
1844 - 'item_content_end' => '</div>',
1845 - 'status' => $html_item_status,
1846 - 'link_end' => '</a>',
1847 - 'end' => '</li>',
1848 - ],
1849 - $courseModel,
1850 - $userModel,
1851 - $item,
1852 - $section_item
1853 - );
1854 -
1855 - return Template::combine_components( $section_item );
1856 - }
1857 -
1858 - /**
1859 - * Render string to data content
1860 - *
1861 - * @param CourseModel $course
1862 - * @param string $data_content
1863 - *
1864 - * @return string
1865 - */
1866 - public function render_data( CourseModel $course, string $data_content = '' ): string {
1867 - $author_of_course = $course->get_author_model();
1868 - $singleInstructorTemplate = SingleInstructorTemplate::instance();
1869 -
1870 - // render count items
1871 - $pattern_count_items = '/{{course_count_.*?}}/';
1872 - preg_match_all( $pattern_count_items, $data_content, $matches_count_items );
1873 - if ( ! empty( $matches_count_items ) ) {
1874 - $items = $matches_count_items[0];
1875 - foreach ( $items as $item ) {
1876 - $method = str_replace( [ '{{', '}}' ], '', $item );
1877 - $post_type_item = str_replace( 'course_count_', '', $method );
1878 - $data_content = str_replace( $item, $this->html_count_item( $course, $post_type_item ), $data_content );
1879 - }
1880 - }
1881 -
1882 - return str_replace(
1883 - [
1884 - '{{course_id}}',
1885 - '{{course_title}}',
1886 - '{{course_image}}',
1887 - '{{course_url}}',
1888 - '{{course_short_description}}',
1889 - '{{course_price}}',
1890 - '{{course_categories}}',
1891 - '{{course_count_student}}',
1892 - '{{course_author_display_name}}',
1893 - '{{course_author_url}}',
1894 - '{{course_author_avatar}}',
1895 - ],
1896 - [
1897 - $course->get_id(),
1898 - $this->html_title( $course ),
1899 - $this->html_image( $course ),
1900 - $course->get_permalink(),
1901 - $this->html_short_description( $course ),
1902 - $this->html_price( $course ),
1903 - $this->html_categories( $course ),
1904 - $this->html_count_student( $course ),
1905 - $singleInstructorTemplate->html_display_name( $author_of_course ),
1906 - $author_of_course->get_url_instructor(),
1907 - $singleInstructorTemplate->html_avatar( $author_of_course ),
1908 - ],
1909 - $data_content
1910 - );
1911 - }
1912 -
1913 - /**
1914 - * Get text button read more of course on list courses.
1915 - *
1916 - * @param CourseModel $courseModel
1917 - *
1918 - * @return string
1919 - * @since 4.3.4
1920 - * @version 1.0.0
1921 - */
1922 - public static function text_button_course( CourseModel $courseModel ): string {
1923 - $btn_text = __( 'Enroll Now', 'learnpress' );
1924 - $userModel = UserModel::find( get_current_user_id(), true );
1925 -
1926 - $userCourseModel = null;
1927 - if ( $userModel instanceof UserModel ) {
1928 - $userCourseModel = UserCourseModel::find( $userModel->get_id(), $courseModel->get_id(), true );
1929 - }
1930 -
1931 - if ( $userCourseModel instanceof UserCourseModel ) {
1932 - if ( $userCourseModel->has_enrolled() ) {
1933 - $btn_text = __( 'Continue Learning', 'learnpress' );
1934 - } elseif ( $userCourseModel->has_purchased() ) {
1935 - $btn_text = __( 'Start Learning', 'learnpress' );
1936 - } else {
1937 - $btn_text = __( 'View Detail', 'learnpress' );
1938 - }
1939 - } else {
1940 - if ( $courseModel->has_no_enroll_requirement() ) {
1941 - $btn_text = __( 'Start Learning', 'learnpress' );
1942 - } elseif ( ! $courseModel->is_free() ) {
1943 - $btn_text = __( 'Buy Now', 'learnpress' );
1944 - } elseif ( ! empty( $courseModel->get_external_link() ) ) {
1945 - $btn_text = __( 'View Detail', 'learnpress' );
1946 - }
1947 - }
1948 -
1949 - return $btn_text;
1950 - }
1951 -}
1 +<?php
2 +/**
3 + * Template hooks Single Course.
4 + *
5 + * @since 4.2.3
6 + * @version 1.0.5
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\CoursePostModel;
15 +use LearnPress\Models\LessonPostModel;
16 +use LearnPress\Models\PostModel;
17 +use LearnPress\Models\QuizPostModel;
18 +use LearnPress\Models\UserItems\UserCourseModel;
19 +use LearnPress\Models\UserItems\UserItemModel;
20 +use LearnPress\Models\UserModel;
21 +use LearnPress\TemplateHooks\Instructor\SingleInstructorTemplate;
22 +use LearnPress\TemplateHooks\TemplateAJAX;
23 +use LearnPress\TemplateHooks\UserTemplate;
24 +use LearnPressAssignment\Models\AssignmentPostModel;
25 +use LP_Checkout;
26 +use LP_Course;
27 +use LP_Course_Item;
28 +use LP_Datetime;
29 +use LP_Debug;
30 +use LP_Global;
31 +use LP_Material_Files_DB;
32 +use LP_Settings;
33 +use stdClass;
34 +use Throwable;
35 +
36 +class SingleCourseTemplate {
37 + use Singleton;
38 +
39 + /**
40 + * @var false|LessonPostModel|QuizPostModel|PostModel|mixed $currentItemModel
41 + */
42 + public $currentItemModel = false;
43 +
44 + public function init() {
45 + add_filter( 'lp/rest/ajax/allow_callback', [ $this, 'allow_callback' ] );
46 + }
47 +
48 + /**
49 + * Allow callback for AJAX.
50 + * @use self::render_html_comments
51 + *
52 + * @param array $callbacks
53 + *
54 + * @return array
55 + */
56 + public function allow_callback( array $callbacks ): array {
57 + $callbacks[] = get_class( $this ) . ':render_html_comments';
58 +
59 + return $callbacks;
60 + }
61 +
62 + /**
63 + * Get display title course.
64 + *
65 + * @param LP_Course|CourseModel $course
66 + * @param string $tag_html
67 + *
68 + * @return string
69 + */
70 + public function html_title( $course, string $tag_html = 'span' ): string {
71 + $tag_html = esc_attr( sanitize_key( $tag_html ) );
72 + $html_wrapper = apply_filters(
73 + 'learn-press/single-course/html-title',
74 + [
75 + "<{$tag_html} class='course-title'>" => "</{$tag_html}>",
76 + ],
77 + $course
78 + );
79 +
80 + return Template::instance()->nest_elements( $html_wrapper, $course->get_title() );
81 + }
82 +
83 + /**
84 + * Get short description course.
85 + *
86 + * @param LP_Course|CourseModel $course
87 + * @param int $number_words
88 + *
89 + * @return string
90 + */
91 + public function html_short_description( $course, int $number_words = 0 ): string {
92 + $html_wrapper = [
93 + '<p class="course-short-description">' => '</p>',
94 + ];
95 +
96 + if ( $course instanceof LP_Course ) {
97 + $course = CourseModel::find( $course->get_id(), true );
98 + }
99 +
100 + $short_description = $course->get_short_description();
101 + if ( empty( $short_description ) ) {
102 + return '';
103 + }
104 +
105 + if ( $number_words > 0 ) {
106 + $short_description = wp_trim_words( $short_description, $number_words, '...' );
107 + }
108 +
109 + return Template::instance()->nest_elements( $html_wrapper, $short_description );
110 + }
111 +
112 + /**
113 + * Get description course.
114 + *
115 + * @param LP_Course|CourseModel $course
116 + *
117 + * @return string
118 + */
119 + public function html_description( $course ): string {
120 + $content = '';
121 +
122 + if ( $course instanceof LP_Course ) {
123 + $content = $course->get_data( 'description' );
124 + } elseif ( $course instanceof CourseModel ) {
125 + $content = $course->get_description();
126 + }
127 +
128 + $section = apply_filters(
129 + 'learn-press/course/html-description',
130 + [
131 + 'wrapper' => '<div class="lp-course-description">',
132 + 'content' => $content,
133 + 'wrapper_end' => '</div>',
134 + ],
135 + $course
136 + );
137 +
138 + return Template::combine_components( $section );
139 + }
140 +
141 + /**
142 + * Get display categories course.
143 + *
144 + * @param LP_Course|CourseModel $course
145 + * @param array $setting
146 + *
147 + * @return string
148 + * @since 4.2.6
149 + * @version 1.0.3
150 + */
151 + public function html_categories( $course, array $setting = [] ): string {
152 + $html = '';
153 +
154 + try {
155 + if ( $course instanceof LP_Course ) {
156 + $course = CourseModel::find( $course->get_id(), true );
157 + }
158 +
159 + if ( empty( $course ) ) {
160 + return '';
161 + }
162 +
163 + $cats = $course->get_categories();
164 + if ( empty( $cats ) ) {
165 + return '';
166 + }
167 +
168 + $is_link = $setting['is_link'] ?? true;
169 + $attribute_target = ! empty( $setting['new_tab'] ) ? 'target="_blank"' : '';
170 + $cat_names = [];
171 + foreach ( $cats as $cat ) {
172 + if ( $is_link ) {
173 + $term = sprintf(
174 + '<a href="%s" %s>%s</a>',
175 + get_term_link( $cat ),
176 + $attribute_target,
177 + $cat->name
178 + );
179 + } else {
180 + $term = $cat->name;
181 + }
182 +
183 + $cat_names[] = $term;
184 + }
185 +
186 + $content = implode( ', ', $cat_names );
187 +
188 + $section = apply_filters(
189 + 'learn-press/course/html-categories',
190 + [
191 + 'wrapper' => '<div class="course-categories">',
192 + 'content' => $content,
193 + 'wrapper_end' => '</div>',
194 + ],
195 + $course,
196 + $cats,
197 + $cat_names
198 + );
199 +
200 + $html = Template::combine_components( $section );
201 + } catch ( Throwable $e ) {
202 + error_log( __METHOD__ . ': ' . $e->getMessage() );
203 + }
204 +
205 + return $html;
206 + }
207 +
208 + /**
209 + * Get display tags course.
210 + *
211 + * @param LP_Course|CourseModel $course
212 + *
213 + * @return string
214 + * @since 4.2.6
215 + * @version 1.0.2
216 + */
217 + public function html_tags( $course ): string {
218 + $html = '';
219 +
220 + try {
221 + if ( $course instanceof LP_Course ) {
222 + $course = CourseModel::find( $course->get_id(), true );
223 + }
224 +
225 + if ( empty( $course ) ) {
226 + return '';
227 + }
228 +
229 + $tags = $course->get_tags();
230 + if ( empty( $tags ) ) {
231 + return '';
232 + }
233 +
234 + $tag_names = [];
235 + foreach ( $tags as $tag ) {
236 + $term = sprintf(
237 + '<a href="%s">%s</a>',
238 + get_term_link( $tag ),
239 + $tag->name
240 + );
241 + $tag_names[] = $term;
242 + }
243 +
244 + $content = implode( ', ', $tag_names );
245 +
246 + $section = apply_filters(
247 + 'learn-press/course/html-tags',
248 + [
249 + 'wrapper' => '<div class="course-tags">',
250 + 'content' => $content,
251 + 'wrapper_end' => '</div>',
252 + ],
253 + $course,
254 + $tags,
255 + $tag_names
256 + );
257 +
258 + $html = Template::combine_components( $section );
259 + } catch ( Throwable $e ) {
260 + error_log( __METHOD__ . ': ' . $e->getMessage() );
261 + }
262 +
263 + return $html;
264 + }
265 +
266 + /**
267 + * Get display image course.
268 + *
269 + * @param LP_Course|CourseModel $course
270 + * @param array $data ['size'] Size of image to get, Ex: [500, 300] or string 'thumbnail', 'medium', 'large', 'full' etc.
271 + *
272 + * @return string
273 + * @since 4.2.3.2
274 + * @version 1.0.3
275 + */
276 + public function html_image( $course, array $data = [] ): string {
277 + $content = '';
278 +
279 + try {
280 + $courseModel = $course;
281 + if ( $course instanceof LP_Course ) {
282 + $courseModel = CourseModel::find( $course->get_id(), true );
283 + }
284 +
285 + if ( ! $courseModel instanceof CourseModel ) {
286 + return '';
287 + }
288 +
289 + if ( ! empty( $data['size'] ) ) {
290 + $size_img_send = $data['size'];
291 +
292 + // If custom size, data size is type int[], like [500, 300], not [ width => 500, height => 300 ]
293 + // Convert if data is [ width => 500, height => 300 ]
294 + if ( is_array( $size_img_send ) && array_key_exists( 'width', $size_img_send ) ) {
295 + $size_img_send = [
296 + $size_img_send['width'] ?? 500,
297 + $size_img_send['height'] ?? 300,
298 + ];
299 + }
300 + } else {
301 + $size_img_setting = LP_Settings::get_option( 'course_thumbnail_dimensions', [] );
302 + $size_img_send = [
303 + $size_img_setting['width'] ?? 500,
304 + $size_img_setting['height'] ?? 300,
305 + ];
306 + }
307 +
308 + // Check cache before get image url
309 + $cache = new \LP_Course_Cache();
310 + $key_cache = 'image_url/' . $courseModel->get_id();
311 + if ( is_array( $size_img_send ) && count( $size_img_send ) === 2 ) {
312 + $key_cache .= '/' . implode( 'x', $size_img_send );
313 + } elseif ( is_string( $size_img_send ) ) {
314 + $key_cache .= '/' . $size_img_send;
315 + }
316 +
317 + // Set cache for image url
318 + $course_img_url = $cache->get_cache( $key_cache );
319 + if ( false === $course_img_url ) {
320 + $course_img_url = $courseModel->get_image_url( $size_img_send );
321 + $cache->set_cache( $key_cache, $course_img_url );
322 + $cache->save_cache_keys( sprintf( 'image_urls/%s', $courseModel->get_id() ), $key_cache );
323 + }
324 +
325 + $content = sprintf(
326 + '<img src="%s" alt="%s">',
327 + esc_url_raw( $course_img_url ),
328 + _x( 'course thumbnail', 'no course thumbnail', 'learnpress' )
329 + );
330 +
331 + $section = apply_filters(
332 + 'learn-press/course/html-image',
333 + [
334 + 'wrapper' => '<div class="course-img">',
335 + 'content' => $content,
336 + 'wrapper_end' => '</div>',
337 + ],
338 + $courseModel
339 + );
340 +
341 + $content = Template::combine_components( $section );
342 + } catch ( Throwable $e ) {
343 + error_log( __METHOD__ . ': ' . $e->getMessage() );
344 + }
345 +
346 + return $content;
347 + }
348 +
349 + /**
350 + * Get display instructor course.
351 + *
352 + * @param CourseModel $course
353 + * @param bool $with_avatar
354 + *
355 + * @return string
356 + * @since 4.2.5.8
357 + * @version 1.0.2
358 + */
359 + public function html_instructor( $course, bool $with_avatar = false, $setting = [] ): string {
360 + $content = '';
361 +
362 + try {
363 + $instructor = $course->get_author_model();
364 + if ( ! $instructor ) {
365 + return '';
366 + }
367 +
368 + $singleInstructorTemplate = SingleInstructorTemplate::instance();
369 + $userTemplate = new UserTemplate( 'instructor' );
370 + $is_link = $setting['is_link'] ?? true;
371 + if ( $is_link ) {
372 + $attribute_target = ! empty( $setting['new_tab'] ) ? 'target="_blank"' : '';
373 + $link_instructor = sprintf(
374 + '<a href="%s" %s >%s %s</a>',
375 + $instructor->get_url_instructor(),
376 + $attribute_target,
377 + $with_avatar ? $userTemplate->html_avatar( $instructor ) : '',
378 + $singleInstructorTemplate->html_display_name( $instructor )
379 + );
380 + } else {
381 + $link_instructor = sprintf(
382 + '%s %s',
383 + $with_avatar ? $userTemplate->html_avatar( $instructor ) : '',
384 + $singleInstructorTemplate->html_display_name( $instructor )
385 + );
386 + }
387 +
388 + $section = apply_filters(
389 + 'learn-press/course/instructor-html',
390 + [
391 + 'wrapper' => '<div class="course-instructor">',
392 + 'content' => $link_instructor,
393 + 'wrapper_end' => '</div>',
394 + ],
395 + $course,
396 + $instructor,
397 + $with_avatar
398 + );
399 +
400 + $content = Template::combine_components( $section );
401 + } catch ( Throwable $e ) {
402 + error_log( __METHOD__ . ': ' . $e->getMessage() );
403 + }
404 +
405 + return $content;
406 + }
407 +
408 + /**
409 + * Get html regular price
410 + *
411 + * @param CourseModel $course
412 + *
413 + * @return string
414 + */
415 + public function html_regular_price( CourseModel $course ): string {
416 + $price = learn_press_format_price( $course->get_regular_price() );
417 + $price = apply_filters( 'learn-press/course/regular-price-html', $price, $course, $this );
418 +
419 + return sprintf( '<span class="origin-price">%s</span>', $price );
420 + }
421 +
422 + /**
423 + * Get display price course.
424 + *
425 + * @param LP_Course|CourseModel $course
426 + *
427 + * @return string
428 + */
429 + public function html_price( $course ): string {
430 + $price_html = '';
431 +
432 + if ( $course instanceof LP_Course ) {
433 + $course = CourseModel::find( $course->get_id(), true );
434 + }
435 +
436 + if ( ! $course ) {
437 + return $price_html;
438 + }
439 +
440 + if ( $course->is_free() ) {
441 + if ( '' != $course->get_sale_price() ) {
442 + $price_html .= $this->html_regular_price( $course );
443 + }
444 +
445 + $price_html .= sprintf( '<span class="free">%s</span>', esc_html__( 'Free', 'learnpress' ) );
446 + $price_html = apply_filters( 'learn_press_course_price_html_free', $price_html, $this );
447 + } elseif ( $course->has_no_enroll_requirement() ) {
448 + $price_html .= '';
449 + } else {
450 + if ( $course->has_sale_price() ) {
451 + $price_html .= $this->html_regular_price( $course );
452 + }
453 +
454 + $price_html .= sprintf(
455 + '<span class="price">%s</span>',
456 + learn_press_format_price( $course->get_price(), true )
457 + );
458 + $price_html = sprintf(
459 + '%1$s %2$s %3$s',
460 + $this->html_price_prefix( $course ),
461 + $price_html,
462 + $this->html_price_suffix( $course )
463 + );
464 + $price_html = apply_filters(
465 + 'learn_press_course_price_html',
466 + $price_html,
467 + $course->has_sale_price(),
468 + $course->get_id()
469 + );
470 + }
471 +
472 + // @since 4.2.7
473 + $price_html = sprintf( '<span class="course-price"><span class="course-item-price">%s</span></span>', $price_html );
474 +
475 + return apply_filters( 'learn-press/course/html-price', $price_html, $course );
476 + }
477 +
478 + /**
479 + * Get deliver type
480 + *
481 + * @param CourseModel $course
482 + *
483 + * @return string
484 + */
485 + public function html_capacity( CourseModel $course ): string {
486 + $content = '';
487 +
488 + $html_wrapper = [
489 + '<span class="course-capacity">' => '</span>',
490 + ];
491 + $capacity = $course->get_meta_value_by_key( CoursePostModel::META_KEY_MAX_STUDENTS, 0 );
492 +
493 + if ( $capacity == 0 ) {
494 + $content = __( 'Unlimited', 'learnpress' );
495 + } else {
496 + $content = sprintf( '%d %s', $capacity, _n( 'Student', 'Students', $capacity, 'learnpress' ) );
497 + }
498 +
499 + return Template::instance()->nest_elements( $html_wrapper, $content );
500 + }
501 +
502 + /**
503 + * Get display total student's course.
504 + *
505 + * @param LP_Course|CourseModel $course
506 + *
507 + * @return string
508 + * @since 4.2.3.4
509 + * @version 1.0.2
510 + */
511 + public function html_count_student( $course ): string {
512 + if ( $course instanceof LP_Course ) {
513 + $course = CourseModel::find( $course->get_id(), true );
514 + }
515 +
516 + if ( empty( $course ) ) {
517 + return '';
518 + }
519 +
520 + $count_student = $course->get_total_user_enrolled_or_purchased();
521 + $count_student += $course->get_fake_students();
522 + $content = sprintf( '%d %s', $count_student, _n( 'Student', 'Students', $count_student, 'learnpress' ) );
523 + $html_wrapper = [
524 + '<div class="course-count-student">' => '</div>',
525 + ];
526 +
527 + return Template::instance()->nest_elements( $html_wrapper, $content );
528 + }
529 +
530 + /**
531 + * Get display total lesson's course.
532 + *
533 + * @param LP_Course|CourseModel $course
534 + * @param string $item_type custom post type item
535 + * @param bool $show_only_number
536 + *
537 + * @return string
538 + */
539 + public function html_count_item( $course, string $item_type, bool $show_only_number = false ): string {
540 + if ( $course instanceof LP_Course ) {
541 + $course = CourseModel::find( $course->get_id(), true );
542 + }
543 +
544 + if ( empty( $course ) ) {
545 + return '';
546 + }
547 +
548 + $info_total_items = $course->get_total_items();
549 + if ( empty( $info_total_items ) ) {
550 + return '';
551 + }
552 +
553 + $count_item = $info_total_items->{$item_type} ?? 0;
554 +
555 + if ( $show_only_number ) {
556 + $content = $count_item;
557 + } else {
558 + switch ( $item_type ) {
559 + case LP_LESSON_CPT:
560 + $content = sprintf( '%d %s', $count_item, _n( 'Lesson', 'Lessons', $count_item, 'learnpress' ) );
561 + break;
562 + case LP_QUIZ_CPT:
563 + $content = sprintf( '%d %s', $count_item, _n( 'Quiz', 'Quizzes', $count_item, 'learnpress' ) );
564 + break;
565 + case 'lp_assignment':
566 + $content = sprintf( '%d %s', $count_item, _n( 'Assignment', 'Assignments', $count_item, 'learnpress' ) );
567 + break;
568 + case 'lp_h5p':
569 + $content = sprintf( '%d %s', $count_item, _n( 'H5P', 'H5Ps', $count_item, 'learnpress' ) );
570 + break;
571 + default:
572 + $content = apply_filters( 'learn-press/single-course/i18n/count-item', $count_item, $course, $item_type );
573 + break;
574 + }
575 + }
576 +
577 + $section = apply_filters(
578 + 'learn-press/single-course/html-count-item',
579 + [
580 + 'wrapper' => sprintf( '<div class="course-count-item %s">', $item_type ),
581 + 'content' => $content,
582 + 'wrapper_end' => '</div>',
583 + ],
584 + $course,
585 + $item_type,
586 + $count_item
587 + );
588 +
589 + return Template::combine_components( $section );
590 + }
591 +
592 + /**
593 + * Get html level course.
594 + *
595 + * @param LP_Course|CourseModel $course
596 + *
597 + * @return string
598 + * @since 4.2.3.5
599 + * @version 1.0.1
600 + */
601 + public function html_level( $course ): string {
602 + $content = '';
603 +
604 + try {
605 + if ( $course instanceof LP_Course ) {
606 + $course = CourseModel::find( $course->get_id(), true );
607 + }
608 +
609 + $level = $course->get_meta_value_by_key( CoursePostModel::META_KEY_LEVEL, '' );
610 + if ( empty( $level ) ) {
611 + $level = 'all';
612 + }
613 +
614 + $levels = lp_course_level();
615 + $level = $levels[ $level ] ?? $levels['all'];
616 +
617 + $html_wrapper = [
618 + '<span class="course-level">' => '</span>',
619 + ];
620 + $content = Template::instance()->nest_elements( $html_wrapper, $level );
621 + } catch ( Throwable $e ) {
622 + error_log( __METHOD__ . ': ' . $e->getMessage() );
623 + }
624 +
625 + return $content;
626 + }
627 +
628 + /**
629 + * Get html duration course.
630 + *
631 + * @param LP_Course|CourseModel $course
632 + *
633 + * @return string
634 + * @since 4.2.3.5
635 + * @version 1.0.0
636 + */
637 + public function html_duration( $course ): string {
638 + $content = '';
639 +
640 + try {
641 + if ( $course instanceof LP_Course ) {
642 + $course = CourseModel::find( $course->get_id(), true );
643 + }
644 +
645 + $duration = $course->get_meta_value_by_key( CoursePostModel::META_KEY_DURATION, '' );
646 + $duration_arr = explode( ' ', $duration );
647 + $duration_number = floatval( $duration_arr[0] ?? 0 );
648 + $duration_type = $duration_arr[1] ?? '';
649 + if ( empty( $duration_number ) ) {
650 + $duration_str = __( 'Lifetime', 'learnpress' );
651 + } else {
652 + $duration_str = LP_Datetime::get_string_plural_duration( $duration_number, $duration_type );
653 + }
654 +
655 + $html_wrapper = [
656 + '<span class="course-duration">' => '</span>',
657 + ];
658 + $content = Template::instance()->nest_elements( $html_wrapper, $duration_str );
659 + } catch ( Throwable $e ) {
660 + error_log( __METHOD__ . ': ' . $e->getMessage() );
661 + }
662 +
663 + return $content;
664 + }
665 +
666 + /**
667 + * Get feature review
668 + *
669 + * @param CourseModel $course
670 + * @param UserModel|false $userModel
671 + * @param array $data
672 + *
673 + * @return string
674 + * @since 4.2.7
675 + * @version 1.0.2
676 + */
677 + public function html_feature_review( CourseModel $course, $userModel = false, array $data = [] ): string {
678 + $feature_review = $course->get_meta_value_by_key( CoursePostModel::META_KEY_FEATURED_REVIEW, '' );
679 + if ( empty( $feature_review ) ) {
680 + return '';
681 + }
682 +
683 + if ( $userModel instanceof UserModel ) {
684 + $userCourseModel = UserCourseModel::find( $userModel->get_id(), $course->get_id(), true );
685 + if ( $userCourseModel ) {
686 + return '';
687 + }
688 + }
689 +
690 + $stars = '';
691 + foreach ( range( 1, 5 ) as $star ) {
692 + $stars .= '<i class="lp-icon-star"></i>';
693 + }
694 +
695 + $section = [
696 + 'wrapper' => sprintf(
697 + '<div class="course-featured-review %s">',
698 + esc_attr( $data['lp_display_on'] ?? '' )
699 + ),
700 + 'title' => sprintf(
701 + '<div class="featured-review__title">%s</div>',
702 + esc_html__( 'Featured Review', 'learnpress' )
703 + ),
704 + 'stars' => sprintf(
705 + '<div class="featured-review__stars">%s</div>',
706 + $stars
707 + ),
708 + 'content' => sprintf(
709 + '<div class="featured-review__content">%s</div>',
710 + wp_kses_post( wpautop( $feature_review ) )
711 + ),
712 + 'wrapper_end' => '</div>',
713 + ];
714 +
715 + return Template::combine_components( $section );
716 + }
717 +
718 + /**
719 + * Get button external
720 + *
721 + * @param CourseModel $courseModel
722 + * @param UserModel|false $userModel
723 + *
724 + * @return string
725 + * @since 4.2.7
726 + * @version 1.0.3
727 + */
728 + public function html_btn_external( CourseModel $courseModel, $userModel ): string {
729 + $external_link = $courseModel->get_meta_value_by_key( CoursePostModel::META_KEY_EXTERNAL_LINK_BY_COURSE, '' );
730 + if ( empty( $external_link ) ) {
731 + return '';
732 + }
733 +
734 + // Check user has enrolled, finished or purchased course
735 + if ( $userModel instanceof UserModel ) {
736 + $userCourse = UserCourseModel::find( $userModel->get_id(), $courseModel->get_id(), true );
737 + if ( $userCourse && ( $userCourse->has_enrolled_or_finished() || $userCourse->has_purchased() ) ) {
738 + return '';
739 + }
740 + }
741 +
742 + $content = sprintf(
743 + '<a href="%s" class="lp-button course-btn-extra" target="_blank">%s</a>',
744 + esc_url_raw( $external_link ),
745 + __( 'Contact To Request', 'learnpress' )
746 + );
747 +
748 + return apply_filters( 'learn-press/course/html-button-external', $content, $courseModel, $userModel );
749 + }
750 +
751 + /**
752 + * HTML button purchase course
753 + *
754 + * @param CourseModel $courseModel
755 + * @param false|UserModel $userModel
756 + *
757 + * @return string
758 + * @since 4.2.7.2
759 + * @version 1.0.2
760 + */
761 + public function html_btn_purchase_course( CourseModel $courseModel, $userModel ): string {
762 + $html_btn = '';
763 + $can_purchase = $courseModel->can_purchase( $userModel );
764 + if ( is_wp_error( $can_purchase ) ) {
765 + $error_code_show = apply_filters(
766 + 'learn-press/course/html-button-purchase/show-messages',
767 + []
768 + );
769 + if ( in_array( $can_purchase->get_error_code(), $error_code_show )
770 + && ! empty( $can_purchase->get_error_message() ) ) {
771 + $html_btn = Template::print_message( $can_purchase->get_error_message(), 'warning', false );
772 + }
773 + } else {
774 + $html_btn = sprintf(
775 + '<button class="lp-button button-purchase-course">%s</button>',
776 + __( 'Buy Now', 'learnpress' )
777 + );
778 + }
779 +
780 + if ( empty( $html_btn ) ) {
781 + return apply_filters(
782 + 'learn-press/course/html-button-purchase/empty',
783 + $html_btn,
784 + $courseModel,
785 + $userModel
786 + );
787 + }
788 +
789 + $class_guest_checkout = LP_Checkout::instance()->is_enable_guest_checkout() ? 'guest_checkout' : '';
790 +
791 + // Hook action old
792 + $html_hook_old = '';
793 + if ( has_action( 'learn-press/after-purchase-button' ) ) {
794 + ob_start();
795 + do_action( 'learn-press/after-purchase-button' );
796 + $html_hook_old = ob_get_clean();
797 + }
798 +
799 + if ( has_filter( 'learnpress/course/template/button-purchase/can-show' ) ) {
800 + $user_id = 0;
801 + if ( $userModel instanceof UserModel ) {
802 + $user_id = $userModel->get_id();
803 + }
804 + $user_old = learn_press_get_user( $user_id );
805 + $course_old = learn_press_get_course( $courseModel->get_id() );
806 + $can_show = apply_filters( 'learnpress/course/template/button-purchase/can-show', true, $user_old, $course_old );
807 + if ( ! $can_show ) {
808 + return '';
809 + }
810 + }
811 + // End hook action old
812 +
813 + $section = apply_filters(
814 + 'learn-press/course/html-button-purchase',
815 + [
816 + 'form' => sprintf(
817 + '<form name="purchase-course" class="purchase-course %s" method="post">',
818 + esc_attr( $class_guest_checkout )
819 + ),
820 + 'input' => sprintf(
821 + '<input type="hidden" name="purchase-course" value="%d"/>',
822 + esc_attr( $courseModel->get_id() )
823 + ),
824 + 'btn' => $html_btn,
825 + 'hook_old' => $html_hook_old,
826 + 'form_end' => '</form>',
827 + ],
828 + $courseModel,
829 + $userModel
830 + );
831 +
832 + return Template::combine_components( $section );
833 + }
834 +
835 + /**
836 + * HTML button enroll course
837 + *
838 + * @param CourseModel $courseModel
839 + * @param false|UserModel $userModel
840 + *
841 + * @return string
842 + * @since 4.2.7.3
843 + * @version 1.0.0
844 + */
845 + public function html_btn_enroll_course( CourseModel $courseModel, $userModel ): string {
846 + $html_btn = '';
847 + $can_enroll = $courseModel->can_enroll( $userModel );
848 + if ( is_wp_error( $can_enroll ) ) {
849 + $error_code_show = apply_filters(
850 + 'learn-press/course/html-button-enroll/show-messages',
851 + [ 'course_is_no_required_enroll_not_login', 'course_out_of_stock' ]
852 + );
853 + if ( in_array( $can_enroll->get_error_code(), $error_code_show )
854 + && ! empty( $can_enroll->get_error_message() ) ) {
855 + $html_btn = Template::print_message( $can_enroll->get_error_message(), 'warning', false );
856 + }
857 + } else {
858 + $html_btn = sprintf(
859 + '<button type="submit" class="lp-button button-enroll-course">%s</button>',
860 + __( 'Start Now', 'learnpress' )
861 + );
862 + }
863 +
864 + if ( empty( $html_btn ) ) {
865 + return $html_btn;
866 + }
867 +
868 + // Hook old
869 + $html_hook_before_old = '';
870 + if ( has_action( 'learn-press/before-enroll-button' ) ) {
871 + ob_start();
872 + do_action( 'learn-press/before-enroll-button' );
873 + $html_hook_before_old = ob_get_clean();
874 + }
875 +
876 + $html_hook_after_old = '';
877 + if ( has_action( 'learn-press/after-enroll-button' ) ) {
878 + ob_start();
879 + do_action( 'learn-press/after-enroll-button' );
880 + $html_hook_after_old = ob_get_clean();
881 + }
882 +
883 + if ( has_filter( 'learnpress/course/template/button-enroll/can-show' ) ) {
884 + $user_id = 0;
885 + if ( $userModel instanceof UserModel ) {
886 + $user_id = $userModel->get_id();
887 + }
888 + $user_old = learn_press_get_user( $user_id );
889 + $course_old = learn_press_get_course( $courseModel->get_id() );
890 + $can_show = apply_filters( 'learnpress/course/template/button-enroll/can-show', true, $user_old, $course_old );
891 + if ( ! $can_show ) {
892 + return '';
893 + }
894 + }
895 + // End hook old
896 +
897 + $section = apply_filters(
898 + 'learn-press/course/html-button-enroll',
899 + [
900 + 'form' => '<form name="enroll-course" class="enroll-course" method="post">',
901 + 'hook_before_old' => $html_hook_before_old,
902 + 'input' => sprintf(
903 + '<input type="hidden" name="enroll-course" value="%s"/>',
904 + esc_attr( $courseModel->get_id() )
905 + ),
906 + 'btn' => $html_btn,
907 + 'hook_after_old' => $html_hook_after_old,
908 + 'form_end' => '</form>',
909 + ],
910 + $courseModel,
911 + $userModel
912 + );
913 +
914 + return Template::combine_components( $section );
915 + }
916 +
917 + /**
918 + * Sidebar
919 + *
920 + * @param CourseModel $courseModel
921 + * @param array $data
922 + *
923 + * @return void
924 + * @version 1.0.1
925 + * @since 4.2.7
926 + */
927 + public function html_sidebar( CourseModel $courseModel, array $data = [] ): string {
928 + $html = '';
929 +
930 + try {
931 + if ( is_active_sidebar( 'course-sidebar' ) ) {
932 + ob_start();
933 + dynamic_sidebar( 'course-sidebar' );
934 + $sidebar_content = ob_get_clean();
935 +
936 + $section = apply_filters(
937 + 'learn-press/course/html-sidebar',
938 + [
939 + 'wrapper' => sprintf(
940 + '<div class="lp-single-course-sidebar %s">',
941 + esc_attr( $data['lp_display_on'] ?? '' )
942 + ),
943 + 'content' => $sidebar_content,
944 + 'wrapper_end' => '</div>',
945 + ],
946 + $courseModel
947 + );
948 +
949 + $html = Template::combine_components( $section );
950 + }
951 + } catch ( Throwable $e ) {
952 + error_log( $e->getMessage() );
953 + }
954 +
955 + return $html;
956 + }
957 +
958 + /**
959 + * HTML meta faqs
960 + *
961 + * @param CourseModel $courseModel
962 + * @param array $data
963 + *
964 + * @return string
965 + * @since 4.2.7.2
966 + * @version 1.0.1
967 + */
968 + public function html_faqs( CourseModel $courseModel, array $data = [] ): string {
969 + $html = '';
970 +
971 + try {
972 + $show_heading = $data['show_heading'] ?? true;
973 + $faqs = $courseModel->get_meta_value_by_key( CoursePostModel::META_KEY_FAQS, [] );
974 + if ( ! is_array( $faqs ) && ! is_object( $faqs ) ) {
975 + return '';
976 + }
977 + if ( empty( $faqs ) ) {
978 + return '';
979 + }
980 +
981 + foreach ( $faqs as $faq ) {
982 + $title = $faq[0];
983 + $description = $faq[1];
984 + if ( empty( $title ) || empty( $description ) ) {
985 + continue;
986 + }
987 +
988 + $key = uniqid();
989 + $section_item = [
990 + 'input_checkbox' => sprintf(
991 + '<input type="checkbox" name="course-faqs-box-ratio" id="course-faqs-box-ratio-%s">',
992 + $key
993 + ),
994 + 'wrapper' => '<div class="course-faqs-box">',
995 + 'title' => sprintf(
996 + '<label class="course-faqs-box__title" for="course-faqs-box-ratio-%s">%s</label>',
997 + $key,
998 + $title
999 + ),
1000 + 'content' => '<div class="course-faqs-box__content">',
1001 + 'content_inner' => '<div class="course-faqs-box__content-inner">',
1002 + 'content_main' => wp_kses_post( $description ),
1003 + 'content_inner_end' => '</div>',
1004 + 'content_end' => '</div>',
1005 + 'wrapper_end' => '</div>',
1006 + ];
1007 + $html .= Template::combine_components( $section_item );
1008 + }
1009 +
1010 + $section = apply_filters(
1011 + 'learn-press/course/html-faqs',
1012 + [
1013 + 'wrapper' => '<div class="course-faqs course-tab-panel-faqs">',
1014 + 'title' => $show_heading ? sprintf(
1015 + '<h3 class="course-faqs__title">%s</h3>',
1016 + __( 'FAQs', 'learnpress' )
1017 + ) : '',
1018 + 'content' => $html,
1019 + 'wrapper_end' => '</div>',
1020 + ],
1021 + $courseModel
1022 + );
1023 + $html = Template::combine_components( $section );
1024 + } catch ( Throwable $e ) {
1025 + error_log( $e->getMessage() );
1026 + }
1027 +
1028 + return $html;
1029 + }
1030 +
1031 + /**
1032 + * HTML struct course box extra
1033 + *
1034 + * @param CourseModel $courseModel
1035 + * @param $title
1036 + * @param string $html_list
1037 + *
1038 + * @return string
1039 + * @since 4.2.7.2
1040 + * @version 1.0.0
1041 + */
1042 + public function html_course_box_extra( CourseModel $courseModel, $title, string $html_list ): string {
1043 + if ( empty( $html_list ) ) {
1044 + return '';
1045 + }
1046 +
1047 + $section = apply_filters(
1048 + 'learn-press/course/html-course-box-extra',
1049 + [
1050 + 'wrapper' => '<div class="course-extra-box">',
1051 + 'title' => sprintf( '<h3 class="course-extra-box__title">%s</h3>', $title ),
1052 + 'content' => '<div class="course-extra-box__content">',
1053 + 'content_inner' => '<div class="course-extra-box__content-inner">',
1054 + 'list' => $html_list,
1055 + 'content_inner_end' => '</div>',
1056 + 'content_end' => '</div>',
1057 + 'wrapper_end' => '</div>',
1058 + ],
1059 + $courseModel
1060 + );
1061 +
1062 + return Template::combine_components( $section );
1063 + }
1064 +
1065 + /**
1066 + * HTML meta requirements
1067 + *
1068 + * @param CourseModel $courseModel
1069 + *
1070 + * @return string
1071 + * @since 4.2.7.2
1072 + * @version 1.0.0
1073 + */
1074 + public function html_requirements( CourseModel $courseModel ): string {
1075 + $html = '';
1076 +
1077 + try {
1078 + $requirements = $courseModel->get_meta_value_by_key( CoursePostModel::META_KEY_REQUIREMENTS, [] );
1079 + if ( ! is_array( $requirements ) && ! is_object( $requirements ) ) {
1080 + return '';
1081 + }
1082 + if ( empty( $requirements ) ) {
1083 + return '';
1084 + }
1085 +
1086 + $html_lis = '';
1087 + foreach ( $requirements as $requirement ) {
1088 + $html_lis .= sprintf( '<li>%s</li>', $requirement );
1089 + }
1090 +
1091 + $section_list = [
1092 + 'wrapper' => '<ul>',
1093 + 'content' => $html_lis,
1094 + 'wrapper_end' => '</ul>',
1095 + ];
1096 +
1097 + $section = apply_filters(
1098 + 'learn-press/course/html-requirements',
1099 + [
1100 + 'wrapper' => '<div class="course-requirements extra-box">',
1101 + 'title' => sprintf( '<h3 class="extra-box__title">%s</h3>', __( 'Requirements', 'learnpress' ) ),
1102 + 'content' => Template::combine_components( $section_list ),
1103 + 'wrapper_end' => '</div>',
1104 + ],
1105 + $courseModel,
1106 + $requirements
1107 + );
1108 + $html = Template::combine_components( $section );
1109 + } catch ( Throwable $e ) {
1110 + error_log( $e->getMessage() );
1111 + }
1112 +
1113 + return $html;
1114 + }
1115 +
1116 + /**
1117 + * HTML meta features
1118 + *
1119 + * @param CourseModel $courseModel
1120 + *
1121 + * @return string
1122 + * @since 4.2.7.2
1123 + * @version 1.0.0
1124 + */
1125 + public function html_features( CourseModel $courseModel ): string {
1126 + $html = '';
1127 +
1128 + try {
1129 + $features = $courseModel->get_meta_value_by_key( CoursePostModel::META_KEY_FEATURES, [] );
1130 + if ( ! is_array( $features ) && ! is_object( $features ) ) {
1131 + return '';
1132 + }
1133 + if ( empty( $features ) ) {
1134 + return '';
1135 + }
1136 +
1137 + $html_lis = '';
1138 + foreach ( $features as $feature ) {
1139 + $html_lis .= sprintf( '<li>%s</li>', $feature );
1140 + }
1141 +
1142 + $section_list = [
1143 + 'wrapper' => '<ul>',
1144 + 'content' => $html_lis,
1145 + 'wrapper_end' => '</ul>',
1146 + ];
1147 +
1148 + $section = apply_filters(
1149 + 'learn-press/course/html-features',
1150 + [
1151 + 'wrapper' => '<div class="course-features extra-box">',
1152 + 'title' => sprintf( '<h3 class="extra-box__title">%s</h3>', __( 'Features', 'learnpress' ) ),
1153 + 'content' => Template::combine_components( $section_list ),
1154 + 'wrapper_end' => '</div>',
1155 + ],
1156 + $courseModel,
1157 + $features
1158 + );
1159 + $html = Template::combine_components( $section );
1160 + } catch ( Throwable $e ) {
1161 + error_log( $e->getMessage() );
1162 + }
1163 +
1164 + return $html;
1165 + }
1166 +
1167 + /**
1168 + * HTML meta target
1169 + *
1170 + * @param CourseModel $courseModel
1171 + *
1172 + * @return string
1173 + * @since 4.2.7.2
1174 + * @version 1.0.0
1175 + */
1176 + public function html_target( CourseModel $courseModel ): string {
1177 + $html = '';
1178 +
1179 + try {
1180 + $targets = $courseModel->get_meta_value_by_key( CoursePostModel::META_KEY_TARGET, [] );
1181 + if ( ! is_array( $targets ) && ! is_object( $targets ) ) {
1182 + return '';
1183 + }
1184 + if ( empty( $targets ) ) {
1185 + return '';
1186 + }
1187 +
1188 + $html_lis = '';
1189 + foreach ( $targets as $target ) {
1190 + $html_lis .= sprintf( '<li>%s</li>', $target );
1191 + }
1192 +
1193 + $section_list = [
1194 + 'wrapper' => '<ul>',
1195 + 'content' => $html_lis,
1196 + 'wrapper_end' => '</ul>',
1197 + ];
1198 +
1199 + $section = apply_filters(
1200 + 'learn-press/course/html-target',
1201 + [
1202 + 'wrapper' => '<div class="course-target extra-box">',
1203 + 'title' => sprintf( '<h3 class="extra-box__title">%s</h3>', __( 'Target audiences', 'learnpress' ) ),
1204 + 'content' => Template::combine_components( $section_list ),
1205 + 'wrapper_end' => '</div>',
1206 + ],
1207 + $courseModel,
1208 + $targets
1209 + );
1210 + $html = Template::combine_components( $section );
1211 + } catch ( Throwable $e ) {
1212 + error_log( $e->getMessage() );
1213 + }
1214 +
1215 + return $html;
1216 + }
1217 +
1218 + /**
1219 + * HTML material
1220 + *
1221 + * @param CourseModel $courseModel
1222 + * @param UserModel|false $userModel
1223 + * @param array $data
1224 + *
1225 + * @return string
1226 + * @since 4.2.7.2
1227 + * @version 1.0.4
1228 + */
1229 + public function html_material( CourseModel $courseModel, $userModel = false, array $data = [] ): string {
1230 + $html = '';
1231 +
1232 + try {
1233 + $show_heading = $data['show_heading'] ?? true;
1234 + $can_show = false;
1235 +
1236 + if ( $userModel instanceof UserModel ) {
1237 + if ( $courseModel->check_user_is_author( $userModel )
1238 + || user_can( $userModel->get_id(), ADMIN_ROLE ) ) {
1239 + $can_show = true;
1240 + } else {
1241 + $userCourseModel = UserCourseModel::find( $userModel->get_id(), $courseModel->get_id(), true );
1242 + if ( $userCourseModel &&
1243 + ( $userCourseModel->has_enrolled_or_finished()
1244 + || $userCourseModel->has_purchased() ) ) {
1245 + $can_show = true;
1246 + }
1247 + }
1248 + } elseif ( $courseModel->has_no_enroll_requirement() ) {
1249 + $can_show = true;
1250 + }
1251 +
1252 + $can_show = apply_filters( 'learn-press/course-material/can-show', $can_show, $courseModel, $userModel );
1253 +
1254 + $file_per_page = LP_Settings::get_option( 'material_file_per_page', - 1 );
1255 + $count_files = LP_Material_Files_DB::getInstance()->get_total( $courseModel->get_id() );
1256 + if ( ! $can_show || $file_per_page == 0 || $count_files <= 0 ) {
1257 + return $html;
1258 + }
1259 +
1260 + ob_start();
1261 + do_action( 'learn-press/course-material/layout', [] );
1262 + $html_content = ob_get_clean();
1263 +
1264 + $section = [
1265 + 'wrapper' => '<div class="course-material">',
1266 + 'title' => $show_heading ? sprintf(
1267 + '<h3 class="course-material__title">%s</h3>',
1268 + __( 'Course Material', 'learnpress' )
1269 + ) : '',
1270 + 'content' => $html_content,
1271 + 'wrapper_end' => '</div>',
1272 + ];
1273 +
1274 + $html = Template::combine_components( $section );
1275 + } catch ( Throwable $e ) {
1276 + error_log( __METHOD__ . ': ' . $e->getMessage() );
1277 + }
1278 +
1279 + return $html;
1280 + }
1281 +
1282 + /**
1283 + * Get html level course.
1284 + *
1285 + * @param LP_Course|CourseModel $course
1286 + *
1287 + * @return string
1288 + * @since 4.2.7.5
1289 + * @version 1.0.1
1290 + */
1291 + public function html_price_prefix( $course ): string {
1292 + $html = '';
1293 +
1294 + try {
1295 + if ( $course instanceof LP_Course ) {
1296 + $course = CourseModel::find( $course->get_id(), true );
1297 + if ( ! $course instanceof CourseModel ) {
1298 + return $html;
1299 + }
1300 + }
1301 +
1302 + $price_prefix_str = $course->get_meta_value_by_key( CoursePostModel::META_KEY_PRICE_PREFIX, '' );
1303 + if ( empty( $price_prefix_str ) ) {
1304 + return $html;
1305 + }
1306 +
1307 + $html = sprintf( '<span class="course-price-prefix">%s</span>', $price_prefix_str );
1308 + } catch ( Throwable $e ) {
1309 + error_log( __METHOD__ . ': ' . $e->getMessage() );
1310 + }
1311 +
1312 + return $html;
1313 + }
1314 +
1315 + /**
1316 + * Get html level course.
1317 + *
1318 + * @param LP_Course|CourseModel $course
1319 + *
1320 + * @return string
1321 + * @since 4.2.7.5
1322 + * @version 1.0.0
1323 + */
1324 + public function html_price_suffix( $course ): string {
1325 + $html = '';
1326 +
1327 + try {
1328 + $price_suffix_str = $course->get_meta_value_by_key( CoursePostModel::META_KEY_PRICE_SUFFIX, '' );
1329 + if ( empty( $price_suffix_str ) ) {
1330 + return $html;
1331 + }
1332 +
1333 + $html = sprintf( '<span class="course-price-suffix">%s</span>', $price_suffix_str );
1334 + } catch ( Throwable $e ) {
1335 + error_log( __METHOD__ . ': ' . $e->getMessage() );
1336 + }
1337 +
1338 + return $html;
1339 + }
1340 +
1341 + /**
1342 + * Get html featured course.
1343 + *
1344 + * @param CourseModel $courseModel
1345 + *
1346 + * @return string
1347 + * @since 4.2.9
1348 + * @version 1.0.0
1349 + */
1350 + public function html_featured( CourseModel $courseModel ): string {
1351 + $html = '';
1352 +
1353 + try {
1354 + $is_featured = $courseModel->get_meta_value_by_key( CoursePostModel::META_KEY_FEATURED, 'no' );
1355 + if ( $is_featured !== 'yes' ) {
1356 + return $html;
1357 + }
1358 +
1359 + $html = sprintf( '<span class="course-featured">%s</span>', __( 'Featured', 'learnpress' ) );
1360 + } catch ( Throwable $e ) {
1361 + LP_Debug::error_log( $e );
1362 + }
1363 +
1364 + return $html;
1365 + }
1366 +
1367 + /**
1368 + * GET HTML comment default of WP
1369 + *
1370 + * @param CourseModel $courseModel
1371 + * @param false|UserModel $userModel
1372 + *
1373 + * @return string
1374 + * @since 4.2.7.6
1375 + * @version 1.0.0
1376 + */
1377 + public function html_comment( CourseModel $courseModel, $userModel = false ): string {
1378 + $args = [
1379 + 'id_url' => 'course-comments',
1380 + 'course_id' => $courseModel->get_id(),
1381 + 'user_id' => $userModel instanceof UserModel ? $userModel->get_id() : 0,
1382 + ];
1383 + $callBack = [
1384 + 'class' => __CLASS__,
1385 + 'method' => 'render_html_comments',
1386 + ];
1387 + $html = TemplateAJAX::load_content_via_ajax( $args, $callBack );
1388 +
1389 + $section_comment = apply_filters(
1390 + 'learn-press/single-course/html-comment',
1391 + [
1392 + 'wrapper' => '<div class="lp-course-comment">',
1393 + 'content' => $html,
1394 + 'wrapper_end' => '</div>',
1395 + ],
1396 + $courseModel,
1397 + $userModel
1398 + );
1399 +
1400 + return Template::combine_components( $section_comment );
1401 + }
1402 +
1403 + /**
1404 + * Render HTML comments of course.
1405 + *
1406 + * @param array $data ['course_id']
1407 + *
1408 + * @return stdClass
1409 + * @since 4.2.7.6
1410 + * @version 1.0.0
1411 + */
1412 + public static function render_html_comments( array $data ): stdClass {
1413 + $response = new stdClass();
1414 + $response->content = '';
1415 +
1416 + try {
1417 + $course_id = $data['course_id'] ?? 0;
1418 + $user_id = $data['user_id'] ?? 0;
1419 + if ( empty( $course_id ) ) {
1420 + return $response;
1421 + }
1422 +
1423 + global $withcomments, $post;
1424 +
1425 + $post = get_post( $course_id );
1426 + if ( $post->comment_status !== 'open' ) {
1427 + return $response;
1428 + } else {
1429 + $withcomments = true;
1430 + }
1431 +
1432 + $withcomments = apply_filters(
1433 + 'learn-press/single-course/render-html-comment/is-show',
1434 + $withcomments,
1435 + $post,
1436 + $user_id
1437 + );
1438 +
1439 + //$post->comment_count = 0;
1440 +
1441 + ob_start();
1442 + add_filter( 'deprecated_file_trigger_error', '__return_false' );
1443 + comments_template();
1444 + remove_filter( 'deprecated_file_trigger_error', '__return_false' );
1445 + $html = ob_get_clean();
1446 + $response->content = $html;
1447 + } catch ( Throwable $e ) {
1448 + $response->content = Template::print_message( $e->getMessage(), 'error', false );
1449 + }
1450 +
1451 + return $response;
1452 + }
1453 +
1454 + /**
1455 + * Get HTML curriculum of course.
1456 + *
1457 + * @param CourseModel $courseModel
1458 + * @param UserModel|false $userModel
1459 + * @param LessonPostModel|QuizPostModel|PostModel|mixed $itemModelCurrent
1460 + *
1461 + * @return string
1462 + * @since 4.2.7.6
1463 + * @version 1.0.3
1464 + */
1465 + public function html_curriculum( CourseModel $courseModel, $userModel, $itemModelCurrent = false ): string {
1466 + $html = '';
1467 +
1468 + try {
1469 + // Get current item viewing
1470 + /**
1471 + * @var $lp_course_item LP_Course_Item
1472 + * @var $post \WP_Post
1473 + */
1474 + global $lp_course_item, $post;
1475 + /**
1476 + * @var $itemModelCurrent LessonPostModel|QuizPostModel|AssignmentPostModel|PostModel...
1477 + */
1478 + $itemModelCurrent = $courseModel->get_item_model( $post->ID, $post->post_type );
1479 + if ( $lp_course_item ) {
1480 + $itemModelCurrent = $courseModel->get_item_model( $lp_course_item->get_id(), $lp_course_item->get_item_type() );
1481 + }
1482 +
1483 + if ( $itemModelCurrent ) {
1484 + $item_types = CourseModel::item_types_support();
1485 + // Check item type is support
1486 + if ( in_array( $itemModelCurrent->post_type, $item_types ) ) {
1487 + $this->currentItemModel = $itemModelCurrent;
1488 + }
1489 + }
1490 + // End get current item viewing
1491 +
1492 + $section_items = $courseModel->get_section_items();
1493 + $html = Template::print_message(
1494 + esc_html__( 'There are no items in the curriculum yet.', 'learnpress' ),
1495 + 'info',
1496 + false
1497 + );
1498 + if ( empty( $section_items ) ) {
1499 + return $html;
1500 + }
1501 +
1502 + wp_enqueue_script( 'lp-curriculum' );
1503 + $li_section_items = '';
1504 + foreach ( $section_items as $section_item ) {
1505 + $li_section_items .= $this->render_html_section_item( $courseModel, $userModel, $section_item );
1506 + }
1507 +
1508 + $section = apply_filters(
1509 + 'learn-press/course/html-curriculum',
1510 + [
1511 + 'wrapper' => '<div class="lp-course-curriculum">',
1512 + 'title' => sprintf(
1513 + '<h3 class="lp-course-curriculum__title">%s</h3>',
1514 + esc_html__( 'Curriculum', 'learnpress' )
1515 + ),
1516 + 'curriculum_info' => '<div class="course-curriculum-info">',
1517 + 'curriculum_info_left' => '<ul class="course-curriculum-info__left">',
1518 + 'count_sections' => sprintf(
1519 + '<li class="course-count-section">%s</li>',
1520 + sprintf(
1521 + _n( '%d Section', '%d Sections', $courseModel->get_total_sections(), 'learnpress' ),
1522 + $courseModel->get_total_sections()
1523 + )
1524 + ),
1525 + 'count_lesson' => sprintf(
1526 + '<li class="course-count-lesson">%s</li>',
1527 + sprintf(
1528 + _n( '%d Lesson', '%d Lessons', $courseModel->count_items( LP_LESSON_CPT ), 'learnpress' ),
1529 + $courseModel->count_items( LP_LESSON_CPT )
1530 + )
1531 + ),
1532 + 'duration' => sprintf(
1533 + '<li class="course-duration">%s</li>',
1534 + $this->html_duration( $courseModel )
1535 + ),
1536 + 'curriculum_info_left_end' => '</ul>',
1537 + 'curriculum_info_right' => '<div class="course-curriculum-info__right">',
1538 + 'expand_all' => sprintf(
1539 + '<span class="course-toggle-all-sections">%s</span>',
1540 + esc_html__( 'Expand all sections', 'learnpress' )
1541 + ),
1542 + 'collapse_all' => sprintf(
1543 + '<span class="course-toggle-all-sections lp-collapse lp-hidden">%s</span>',
1544 + esc_html__( 'Collapse all sections', 'learnpress' )
1545 + ),
1546 + 'curriculum_info_right_end' => '</div>',
1547 + 'curriculum_info_end' => '</div>',
1548 + 'curriculum' => '<div class="course-curriculum">',
1549 + 'sections' => '<ul class="course-sections">',
1550 + 'li_section_items' => $li_section_items,
1551 + 'sections_end' => '</ul>',
1552 + 'curriculum_end' => '</div>',
1553 + 'wrapper_end' => '</div>',
1554 + ],
1555 + $courseModel,
1556 + $userModel,
1557 + $itemModelCurrent
1558 + );
1559 +
1560 + $html = Template::combine_components( $section );
1561 + } catch ( Throwable $e ) {
1562 + error_log( __METHOD__ . ': ' . $e->getMessage() );
1563 + }
1564 +
1565 + return $html;
1566 + }
1567 +
1568 + /**
1569 + * Render HTML section item
1570 + *
1571 + * @param CourseModel $courseModel
1572 + * @param UserModel|false $userModel
1573 + * @param $section_item object {section_id, section_name, section_description, items[{item_id, item_order, item_type, title, preview}]}
1574 + *
1575 + * @return string
1576 + * @since 4.2.7.6
1577 + * @version 1.0.1
1578 + */
1579 + public function render_html_section_item( CourseModel $courseModel, $userModel, $section_item ): string {
1580 + if ( ! $section_item instanceof stdClass ) {
1581 + return '';
1582 + }
1583 +
1584 + $section_id = $section_item->section_id ?? 0;
1585 + $section_name = $section_item->section_name ?? '';
1586 + $section_description = $section_item->section_description ?? '';
1587 + $section_order = $section_item->section_order ?? 1;
1588 + $items = $section_item->items ?? [];
1589 + $html_section_description = '';
1590 + if ( ! empty( $section_description ) ) {
1591 + $html_section_description = sprintf(
1592 + '<div class="course-section__description">%s</div>',
1593 + wp_kses_post( $section_description )
1594 + );
1595 + }
1596 +
1597 + $section_header = [
1598 + 'start' => '<div class="course-section-header">',
1599 + 'toggle' => '<div class="section-toggle">
1600 + <i class="lp-icon-angle-down"></i>
1601 + <i class="lp-icon-angle-up"></i>
1602 + </div>',
1603 + 'info' => '<div class="course-section-info">',
1604 + 'title' => sprintf( '<div class="course-section__title">%s</div>', wp_kses_post( $section_name ) ),
1605 + 'description' => $html_section_description,
1606 + 'info_end' => '</div>',
1607 + 'count_items' => sprintf(
1608 + '<div class="section-count-items">%d</div>',
1609 + count( $items )
1610 + ),
1611 + 'end' => '</div>',
1612 + ];
1613 +
1614 + $li_items = '';
1615 + foreach ( $items as $item ) {
1616 + $li_items .= $this->render_html_course_item( $courseModel, $userModel, $item, $section_item );
1617 + }
1618 + $section_items = [
1619 + 'start' => '<ul class="course-section__items">',
1620 + 'li_items' => $li_items,
1621 + 'end' => '</ul>',
1622 + ];
1623 +
1624 + $curriculum_display_setting = LP_Settings::get_option( 'curriculum_display', 'expand_first_section' );
1625 + $class_section_toggle = '';
1626 +
1627 + if ( $this->currentItemModel ) {
1628 + $current_section = $courseModel->get_section_of_item( $this->currentItemModel->get_id() );
1629 + if ( $current_section != $section_id ) {
1630 + $class_section_toggle = 'lp-collapse';
1631 + }
1632 + } else {
1633 + if ( $curriculum_display_setting === 'collapse_all' ) {
1634 + $class_section_toggle = 'lp-collapse';
1635 + } elseif ( $curriculum_display_setting === 'expand_first_section' ) {
1636 + if ( $section_order > 1 ) {
1637 + $class_section_toggle = 'lp-collapse';
1638 + }
1639 + }
1640 + }
1641 +
1642 + $class_section_toggle = apply_filters(
1643 + 'learn-press/course/html-section-item/class-section-toggle',
1644 + $class_section_toggle,
1645 + $courseModel,
1646 + $userModel,
1647 + $section_item
1648 + );
1649 +
1650 + $section_item = apply_filters(
1651 + 'learn-press/course/html-section-item',
1652 + [
1653 + 'start' => sprintf(
1654 + '<li class="course-section %s" data-section-id="%s">',
1655 + $class_section_toggle,
1656 + $section_id
1657 + ),
1658 + 'header' => Template::combine_components( $section_header ),
1659 + 'items' => Template::combine_components( $section_items ),
1660 + 'end' => '</li>',
1661 + ],
1662 + $courseModel,
1663 + $userModel,
1664 + $section_item
1665 + );
1666 +
1667 + return Template::combine_components( $section_item );
1668 + }
1669 +
1670 + /**
1671 + * @param CourseModel $courseModel
1672 + * @param UserModel|false $userModel
1673 + * @param $item stdClass {item_id, item_order, item_type, title, preview}
1674 + * @param $section_item stdClass {section_id, section_name, section_description, items[{item_id, item_order, item_type, title, preview}]}
1675 + *
1676 + * @return string
1677 + * @since 4.2.7.6
1678 + * @version 1.0.2
1679 + */
1680 + public function render_html_course_item( CourseModel $courseModel, $userModel, $item, $section_item ): string {
1681 + $html = '';
1682 +
1683 + if ( ! $item instanceof stdClass ) {
1684 + return $html;
1685 + }
1686 +
1687 + $item_id = (int) ( $item->item_id ?? $item->id ?? 0 );
1688 + $item_order = $item->item_order ?? $item->order ?? 0;
1689 + $item_type = $item->item_type ?? $item->type ?? '';
1690 + $title = $item->title ?? '';
1691 + $has_preview = $item->preview ?? '';
1692 + $class_current = '';
1693 + if ( $this->currentItemModel ) {
1694 + $current_item_id = $this->currentItemModel->get_id();
1695 + if ( $current_item_id == $item_id ) {
1696 + $class_current = 'current';
1697 + }
1698 + }
1699 +
1700 + //LP_Course_Item::get_item( $item_id, $course->get_id() );
1701 + $itemModel = $courseModel->get_item_model( $item_id, $item_type );
1702 + if ( empty( $itemModel ) ) {
1703 + return $html;
1704 + }
1705 +
1706 + $link_item = $courseModel->get_item_link( $item_id, $item_type );
1707 +
1708 + $item_duration = '';
1709 + $html_item_duration = '';
1710 + if ( is_callable( [ $itemModel, 'get_duration' ] ) ) {
1711 + $item_duration = $itemModel->get_duration();
1712 + } else {
1713 + $item_duration = get_post_meta( $item_id, '_lp_duration', true );
1714 + }
1715 +
1716 + $duration_arr = explode( ' ', $item_duration );
1717 + $duration_number = floatval( $duration_arr[0] ?? 0 );
1718 + $duration_type = $duration_arr[1] ?? '';
1719 +
1720 + if ( $duration_number > 0 ) {
1721 + $item_duration_plural = LP_Datetime::get_string_plural_duration( $duration_number, $duration_type );
1722 +
1723 + $html_item_duration = sprintf(
1724 + '<span class="duration">%s</span>',
1725 + $item_duration_plural
1726 + );
1727 + }
1728 +
1729 + // Count question of quiz
1730 + $html_item_count_questions = '';
1731 + if ( $item_type === LP_QUIZ_CPT ) {
1732 + $quizPostModel = QuizPostModel::find( $item_id, true );
1733 + if ( $quizPostModel instanceof QuizPostModel ) {
1734 + $question_count = $quizPostModel->count_questions();
1735 + $html_item_duration .= sprintf(
1736 + '<span class="question-count">%s</span>',
1737 + sprintf(
1738 + _n( '%d Question', '%d Questions', $question_count, 'learnpress' ),
1739 + $question_count
1740 + )
1741 + );
1742 + }
1743 + }
1744 +
1745 + $user_item_status_ico_flag = 'locked';
1746 + $user_attended_course = false;
1747 + if ( $userModel instanceof UserModel ) {
1748 + $userCourseModel = UserCourseModel::find( $userModel->get_id(), $courseModel->get_id(), true );
1749 + if ( $userCourseModel
1750 + && $userCourseModel->get_status() !== UserItemModel::STATUS_CANCEL
1751 + && $userCourseModel->get_status() !== UserCourseModel::STATUS_PURCHASED ) {
1752 + $user_attended_course = true;
1753 +
1754 + // Check status of item's course
1755 + $userCourseItem = $userCourseModel->get_item_attend( $item_id, $item_type );
1756 + if ( ! $userCourseItem instanceof UserItemModel ) {
1757 + $user_item_status_ico_flag = UserItemModel::GRADUATION_IN_PROGRESS;
1758 + } else {
1759 + $user_item_status_ico_flag = $userCourseItem->get_status();
1760 + $user_item_graduation = $userCourseItem->get_graduation();
1761 + if ( ! empty( $user_item_graduation ) ) {
1762 + $user_item_status_ico_flag = $user_item_graduation . ' completed';
1763 + }
1764 +
1765 + if ( empty( $user_item_status_ico_flag ) ) {
1766 + $user_item_status_ico_flag = UserItemModel::GRADUATION_IN_PROGRESS;
1767 + }
1768 + }
1769 +
1770 + if ( $user_item_status_ico_flag === UserItemModel::GRADUATION_IN_PROGRESS ) {
1771 + if ( $userCourseModel->get_time_remaining() === 0 ) {
1772 + $user_item_status_ico_flag = 'locked';
1773 + } elseif ( $userCourseModel->get_status() === UserItemModel::STATUS_FINISHED
1774 + && $courseModel->enable_block_when_finished() ) {
1775 + $user_item_status_ico_flag = 'locked';
1776 + }
1777 + }
1778 + }
1779 + }
1780 +
1781 + if ( $has_preview && ! $user_attended_course ) {
1782 + $user_item_status_ico_flag = 'preview';
1783 + }
1784 +
1785 + if ( $courseModel->has_no_enroll_requirement()
1786 + && ! $user_attended_course && ! $userModel ) {
1787 + $user_item_status_ico_flag = UserItemModel::GRADUATION_IN_PROGRESS;
1788 + }
1789 +
1790 + $user_item_status_ico_flag = apply_filters(
1791 + 'learn-press/course/item/status-ico-flag',
1792 + $user_item_status_ico_flag,
1793 + $courseModel,
1794 + $userModel,
1795 + $item,
1796 + $section_item
1797 + );
1798 +
1799 + $html_item_status = sprintf(
1800 + '<div class="course-item__status"><span class="course-item-ico %1$s"></span></div>',
1801 + $user_item_status_ico_flag
1802 + );
1803 +
1804 + $html_item_right = [];
1805 + if ( $html_item_count_questions != '' || $html_item_duration != '' ) {
1806 + $html_item_right = [
1807 + 'item_right' => '<div class="course-item__right">',
1808 + 'question_count' => $html_item_count_questions,
1809 + 'duration' => $html_item_duration,
1810 + 'item_right_end' => '</div>',
1811 + ];
1812 + }
1813 +
1814 + $section_item = apply_filters(
1815 + 'learn-press/course/html-course-item',
1816 + [
1817 + 'start' => sprintf(
1818 + '<li class="course-item %s" data-item-id="%s" data-item-order="%s" data-item-type="%s">',
1819 + $class_current,
1820 + $item_id,
1821 + $item_order,
1822 + $item_type
1823 + ),
1824 + 'link' => sprintf(
1825 + '<a href="%s" class="course-item__link">',
1826 + esc_url_raw( $link_item )
1827 + ),
1828 + 'item_info' => '<div class="course-item__info">',
1829 + 'icon' => sprintf(
1830 + '<span class="course-item-ico %s"></span>',
1831 + esc_attr( $item_type )
1832 + ),
1833 + 'item_order' => sprintf(
1834 + '<span class="course-item-order lp-hidden">%s.%s</span>',
1835 + $section_item->section_order,
1836 + $item_order
1837 + ),
1838 + 'item_info_end' => '</div>',
1839 + 'item_content' => '<div class="course-item__content">',
1840 + 'item_left' => '<div class="course-item__left">',
1841 + 'title' => sprintf( '<div class="course-item-title">%s</div>', wp_kses_post( $title ) ),
1842 + 'item_left_end' => '</div>',
1843 + 'item_right' => Template::combine_components( $html_item_right ),
1844 + 'item_content_end' => '</div>',
1845 + 'status' => $html_item_status,
1846 + 'link_end' => '</a>',
1847 + 'end' => '</li>',
1848 + ],
1849 + $courseModel,
1850 + $userModel,
1851 + $item,
1852 + $section_item
1853 + );
1854 +
1855 + return Template::combine_components( $section_item );
1856 + }
1857 +
1858 + /**
1859 + * Render string to data content
1860 + *
1861 + * @param CourseModel $course
1862 + * @param string $data_content
1863 + *
1864 + * @return string
1865 + */
1866 + public function render_data( CourseModel $course, string $data_content = '' ): string {
1867 + $author_of_course = $course->get_author_model();
1868 + $singleInstructorTemplate = SingleInstructorTemplate::instance();
1869 +
1870 + // render count items
1871 + $pattern_count_items = '/{{course_count_.*?}}/';
1872 + preg_match_all( $pattern_count_items, $data_content, $matches_count_items );
1873 + if ( ! empty( $matches_count_items ) ) {
1874 + $items = $matches_count_items[0];
1875 + foreach ( $items as $item ) {
1876 + $method = str_replace( [ '{{', '}}' ], '', $item );
1877 + $post_type_item = str_replace( 'course_count_', '', $method );
1878 + $data_content = str_replace( $item, $this->html_count_item( $course, $post_type_item ), $data_content );
1879 + }
1880 + }
1881 +
1882 + return str_replace(
1883 + [
1884 + '{{course_id}}',
1885 + '{{course_title}}',
1886 + '{{course_image}}',
1887 + '{{course_url}}',
1888 + '{{course_short_description}}',
1889 + '{{course_price}}',
1890 + '{{course_categories}}',
1891 + '{{course_count_student}}',
1892 + '{{course_author_display_name}}',
1893 + '{{course_author_url}}',
1894 + '{{course_author_avatar}}',
1895 + ],
1896 + [
1897 + $course->get_id(),
1898 + $this->html_title( $course ),
1899 + $this->html_image( $course ),
1900 + $course->get_permalink(),
1901 + $this->html_short_description( $course ),
1902 + $this->html_price( $course ),
1903 + $this->html_categories( $course ),
1904 + $this->html_count_student( $course ),
1905 + $singleInstructorTemplate->html_display_name( $author_of_course ),
1906 + $author_of_course->get_url_instructor(),
1907 + $singleInstructorTemplate->html_avatar( $author_of_course ),
1908 + ],
1909 + $data_content
1910 + );
1911 + }
1912 +
1913 + /**
1914 + * Get text button read more of course on list courses.
1915 + *
1916 + * @param CourseModel $courseModel
1917 + *
1918 + * @return string
1919 + * @since 4.3.4
1920 + * @version 1.0.0
1921 + */
1922 + public static function text_button_course( CourseModel $courseModel ): string {
1923 + $btn_text = __( 'Enroll Now', 'learnpress' );
1924 + $userModel = UserModel::find( get_current_user_id(), true );
1925 +
1926 + $userCourseModel = null;
1927 + if ( $userModel instanceof UserModel ) {
1928 + $userCourseModel = UserCourseModel::find( $userModel->get_id(), $courseModel->get_id(), true );
1929 + }
1930 +
1931 + if ( $userCourseModel instanceof UserCourseModel ) {
1932 + if ( $userCourseModel->has_enrolled() ) {
1933 + $btn_text = __( 'Continue Learning', 'learnpress' );
1934 + } elseif ( $userCourseModel->has_purchased() ) {
1935 + $btn_text = __( 'Start Learning', 'learnpress' );
1936 + } else {
1937 + $btn_text = __( 'View Detail', 'learnpress' );
1938 + }
1939 + } else {
1940 + if ( $courseModel->has_no_enroll_requirement() ) {
1941 + $btn_text = __( 'Start Learning', 'learnpress' );
1942 + } elseif ( ! $courseModel->is_free() ) {
1943 + $btn_text = __( 'Buy Now', 'learnpress' );
1944 + } elseif ( ! empty( $courseModel->get_external_link() ) ) {
1945 + $btn_text = __( 'View Detail', 'learnpress' );
1946 + }
1947 + }
1948 +
1949 + return $btn_text;
1950 + }
1951 +}