From 48bf228f43799d1bd139a8e791d9a272c394d445 Mon Sep 17 00:00:00 2001 From: truongpn Date: Wed, 11 Dec 2024 17:38:56 +0700 Subject: [PATCH 001/225] single model --- .../Course/SingleCourseModelTemplate.php | 96 +++++++++++++++++++ learnpress.php | 2 + package.json | 8 +- templates/single-course.php | 8 +- 4 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 inc/TemplateHooks/Course/SingleCourseModelTemplate.php diff --git a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php new file mode 100644 index 000000000..46dae0d2a --- /dev/null +++ b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php @@ -0,0 +1,96 @@ +singleCourseTemplate = SingleCourseTemplate::instance(); + + add_action( + 'learn-press/single-course/model/layout', + [ $this, 'course_model_layout' ] + ); + } + + /** + * Single course layout + * + * @param $course + * + * @return void + */ + public function course_model_layout( $course ) { + + $sections = apply_filters( + 'learn-press/single-course/model/sections', + [ + 'wrapper_container' => '
', + 'wrapper' => '
', + 'section_header' => $this->header_sections( $course ), + // 'wrapper_main' => '
', + // 'section_left' => Template::combine_components( $section_left ), + // 'section_right' => Template::combine_components( $section_right ), + // 'wrapper_main_end' => '
', + // 'related_courses' => $html_courses_related, + 'wrapper_end' => '
', + 'wrapper_container_end' => '
', + ] + ); + + echo Template::combine_components( $sections ); + } + + public function header_sections( $course ): string { + + ob_start(); + learn_press_breadcrumb(); + $html_breadcrumb = ob_get_clean(); + + $html_categories = $this->singleCourseTemplate->html_categories( $course ); + if ( ! empty( $html_categories ) ) { + $html_categories = sprintf( + '
%s %s
', + sprintf( '', __( 'in', 'learnpress' ) ), + $html_categories + ); + } + + $html_instructor = $this->singleCourseTemplate->html_instructor( $course ); + + $header_sections = apply_filters( + 'learn-press/single-course/model/header/sections', + [ + 'wrapper_header' => '
', + 'breadcrumb' => $html_breadcrumb, + 'title' => $this->singleCourseTemplate->html_title( $course, 'h1' ), + 'wrapper_instructor_cate' => '
', + 'instructor' => sprintf( + '
%s %s
', + sprintf( '', __( 'by', 'learnpress' ) ), + $html_instructor + ), + 'category' => $html_categories, + 'wrapper_instructor_cate_end' => '
', + 'wrapper_header_end' => '
', + ] + ); + + return Template::combine_components( $header_sections ); + } +} \ No newline at end of file diff --git a/learnpress.php b/learnpress.php index 1cdfb642c..79b3d9579 100644 --- a/learnpress.php +++ b/learnpress.php @@ -27,6 +27,7 @@ use LearnPress\TemplateHooks\Course\ListCoursesRelatedTemplate; use LearnPress\TemplateHooks\Course\ListCoursesTemplate; use LearnPress\TemplateHooks\Course\SingleCourseOfflineTemplate; +use LearnPress\TemplateHooks\Course\SingleCourseModelTemplate; use LearnPress\TemplateHooks\Course\SingleCourseTemplate; use LearnPress\TemplateHooks\Instructor\ListInstructorsTemplate; use LearnPress\TemplateHooks\Instructor\SingleInstructorTemplate; @@ -305,6 +306,7 @@ private function include_files_global() { ListInstructorsTemplate::instance(); SingleCourseTemplate::instance(); SingleCourseOfflineTemplate::instance(); + SingleCourseModelTemplate::instance(); SingleInstructorTemplate::instance(); ProfileInstructorStatisticsTemplate::instance(); ProfileStudentStatisticsTemplate::instance(); diff --git a/package.json b/package.json index 915ec677a..4ac467c77 100644 --- a/package.json +++ b/package.json @@ -4,10 +4,10 @@ "description": "[![Stories in Ready](https://badge.waffle.io/LearnPress/LearnPress.svg?label=ready&title=Ready)](http://waffle.io/LearnPress/LearnPress)", "main": "index.js", "scripts": { - "dev": "cross-env NODE_OPTIONS=--openssl-legacy-provider wp-scripts start", - "build": "cross-env NODE_OPTIONS=--openssl-legacy-provider wp-scripts build", - "format-js": "cross-env NODE_OPTIONS=--openssl-legacy-provider wp-scripts format ./assets/src", - "dev-build": "cross-env NODE_OPTIONS=--openssl-legacy-provider npm run build && gulp styles && npm run dev", + "dev": "cross-env wp-scripts start", + "build": "cross-env wp-scripts build", + "format-js": "cross-env wp-scripts format ./assets/src", + "dev-build": "cross-env npm run build && gulp styles && npm run dev", "release": "npm run build && npm run makepot && gulp styles && gulp release", "makepot:js": "wp-babel-makepot \"./assets/src/**/*.{js,jsx,ts,tsx}\" --ignore \"**/node_modules/**,**/test/**,**/*.d.ts\" --base \"./\" --dir \"./languages/strings\" --output \"./languages/learnpress-js.pot\"", "makepot:cli": "wp i18n make-pot . languages/learnpress.pot --skip-audit --merge=languages/learnpress-js.pot --exclude=\"test,releases,build,dist,node_modules,vendor,wordpress\"", diff --git a/templates/single-course.php b/templates/single-course.php index 7f2087fa9..aeb692f4b 100644 --- a/templates/single-course.php +++ b/templates/single-course.php @@ -7,6 +7,8 @@ * @version 4.0.1 */ +use LearnPress\Models\CourseModel; + defined( 'ABSPATH' ) || exit; /** @@ -48,10 +50,12 @@ include $template_404; } } else { + $courseModel = CourseModel::find( $post->ID, true ); + // hook from @since 4.2.7.5 - do_action( 'learn-press/single-course/layout' ); + do_action( 'learn-press/single-course/model/layout', $courseModel ); - learn_press_get_template( 'content-single-course' ); + //learn_press_get_template( 'content-single-course' ); } } /*while ( have_posts() ) { From 386eea2d07bff6913db0471723f76ef0954cf94f Mon Sep 17 00:00:00 2001 From: truongpn Date: Thu, 12 Dec 2024 17:49:59 +0700 Subject: [PATCH 002/225] single course --- assets/src/scss/frontend/_course-single.scss | 187 +++++++++++++++ .../Course/SingleCourseModelTemplate.php | 221 +++++++++++++++++- 2 files changed, 397 insertions(+), 11 deletions(-) diff --git a/assets/src/scss/frontend/_course-single.scss b/assets/src/scss/frontend/_course-single.scss index 5de7b3931..43d9d3097 100644 --- a/assets/src/scss/frontend/_course-single.scss +++ b/assets/src/scss/frontend/_course-single.scss @@ -258,3 +258,190 @@ font-family: 'lp-icon'; } } + +.lp-single-course { + &__header { + background-color: #F1F2F8; + + &__inner { + max-width: var(--lp-container-max-width); + margin: 0 auto; + padding-right: var(--lp-cotainer-padding); + padding-left: var(--lp-cotainer-padding); + padding-top: 40px; + padding-bottom: 40px; + + > * { + @media (min-width: 992px) { + width: calc(100% - 440px); + } + } + } + + .learn-press-breadcrumb { + display: flex; + list-style: none; + gap: 4px; + flex-wrap: wrap; + margin-bottom: 8px; + } + + .course-title { + margin: 0 0 24px 0; + } + + .course-instructor-category { + display: flex; + padding: 0; + gap: 4px; + flex-wrap: wrap; + margin-bottom: 40px; + + > div > * { + display: inline; + vertical-align: middle; + } + + label { + font-size: inherit; + font-weight: inherit; + } + + a { + font-weight: 600; + text-decoration: none; + &:hover { + color: $color-primary; + } + } + + } + } + + .lp-single-course-main { + padding: 40px 0; + display: flex; + column-gap: 60px; + row-gap: 30px; + + &__left { + @media (min-width: 992px) { + width: calc(100% - 440px); + } + + > div { + margin-bottom: 40px; + + &:last-child { + margin-bottom: 0; + } + } + + .extra-box__title, + .course-faqs__title, + .course-material__title { + margin: 0 0 20px 0; + } + } + + &__right { + @media (min-width: 992px) { + width: 380px; + margin-top: -280px; + } + + &__inner { + position: sticky; + top: 0; + background-color: $color-white; + border: 1px solid $border-color; + padding: 20px; + border-radius: $border-radius-global; + + > div { + margin-bottom: 20px; + + &:last-child { + margin-bottom: 0; + } + } + } + + .info-metas { + margin-bottom: 30px; + + .info-meta-item { + display: flex; + gap: 4px; + margin-bottom: 12px; + + &:last-child { + margin-bottom: 0; + } + } + + .info-meta-left { + display: flex; + gap: 8px; + align-items: center; + } + + i { + color: $color-primary; + } + } + + .course-img { + margin-bottom: 20px; + overflow: hidden; + margin: -20px -20px 20px -20px; + border-radius: $border-radius-global $border-radius-global 0 0; + + img { + max-width: 100%; + } + } + + .course-price { + display: block; + margin-bottom: 30px; + font-size: $font-size-large; + font-weight: $heading-font-weight; + + .free { + color: #3AB500; + } + + .origin-price { + text-decoration: line-through; + opacity: 0.6; + font-size: $font-size-small; + margin-right: 4px; + } + } + + .course-buttons { + form, .lp-button { + width: 100%; + } + + .lp-button { + background-color: $color-primary; + border: $color-primary; + color: $color-white; + + &:hover { + background-color: var(--lp-secondary-color); + border-color: var(--lp-secondary-color); + } + } + } + } + } + + .lp-list-courses-related { + .section-title { + margin: 0 0 40px 0; + } + } +} diff --git a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php index 46dae0d2a..635721e8e 100644 --- a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php @@ -1,6 +1,6 @@ '
', 'wrapper' => '
', - 'section_header' => $this->header_sections( $course ), - // 'wrapper_main' => '
', - // 'section_left' => Template::combine_components( $section_left ), - // 'section_right' => Template::combine_components( $section_right ), - // 'wrapper_main_end' => '
', - // 'related_courses' => $html_courses_related, - 'wrapper_end' => '
', + 'section_header' => $this->header_sections( $course, $user ), + 'wrapper_container' => '
', + 'wrapper_main' => '
', + 'section_left' => $this->section_left( $course, $user ), + 'section_right' => $this->section_right( $course, $user ), + 'wrapper_main_end' => '
', + 'related_courses' => $html_courses_related, 'wrapper_container_end' => '
', + 'wrapper_end' => '
', ] ); echo Template::combine_components( $sections ); } - public function header_sections( $course ): string { + public function header_sections( $course, $user ): string { ob_start(); learn_press_breadcrumb(); @@ -73,10 +87,22 @@ public function header_sections( $course ): string { $html_instructor = $this->singleCourseTemplate->html_instructor( $course ); + $section_info_one = apply_filters( + 'learn-press/single-course/model/header/info-meta', + [ + 'wrapper' => '
', + 'last_update' => sprintf( '
%s: %s
', esc_html__( 'Last updated', 'learnpress' ), esc_attr( get_post_modified_time( get_option( 'date_format' ), true ))), + 'wrapper_end' => '
', + ], + $course, + $user + ); + $header_sections = apply_filters( 'learn-press/single-course/model/header/sections', [ 'wrapper_header' => '
', + 'wrapper_container' => '
', 'breadcrumb' => $html_breadcrumb, 'title' => $this->singleCourseTemplate->html_title( $course, 'h1' ), 'wrapper_instructor_cate' => '
', @@ -87,10 +113,183 @@ public function header_sections( $course ): string { ), 'category' => $html_categories, 'wrapper_instructor_cate_end' => '
', + 'info_one' => Template::combine_components( $section_info_one ), + 'wrapper_container_end' => '
', 'wrapper_header_end' => '
', - ] + ], ); return Template::combine_components( $header_sections ); } + + public function section_left( $course, $user ): string { + + $singleInstructorTemplate = SingleInstructorTemplate::instance(); + $author = $course->get_author_model(); + + // Instructor + $html_instructor = ''; + if ( $author ) { + $html_instructor_image = sprintf( + '%s', + $author->get_url_instructor(), + $author->get_display_name(), + $singleInstructorTemplate->html_avatar( $author ) + ); + $section_instructor_meta = [ + 'wrapper' => '
', + 'count_students' => sprintf( + '
%s
', + $singleInstructorTemplate->html_count_students( $author ) + ), + 'count_courses' => sprintf( + '
%s
', + $singleInstructorTemplate->html_count_courses( $author ) + ), + 'wrapper_end' => '
', + ]; + $html_instructor_meta = Template::combine_components( $section_instructor_meta ); + + $section_instructor_right = apply_filters( + 'learn-press/single-course/model/section-instructor/right', + [ + 'wrapper' => '
', + 'name' => sprintf( + '%s', + $author->get_url_instructor(), + $singleInstructorTemplate->html_display_name( $author ) + ), + 'meta' => $html_instructor_meta, + 'description' => $singleInstructorTemplate->html_description( $author ), + 'social' => $singleInstructorTemplate->html_social( $author ), + 'wrapper_end' => '
', + ], + $course, + $user + ); + $html_instructor_right = Template::combine_components( $section_instructor_right ); + $section_instructor = apply_filters( + 'learn-press/single-course/model/section-instructor', + [ + 'wrapper' => '
', + 'header' => sprintf( '

%s

', __( 'Instructor', 'learnpress' ) ), + 'wrapper_info' => '
', + 'image' => $html_instructor_image, + 'instructor_right' => $html_instructor_right, + 'wrapper_info_end' => '
', + 'wrapper_end' => '
', + ], + $course, + $user + ); + $html_instructor = Template::combine_components( $section_instructor ); + } + // End instructor + + $section_left = apply_filters( + 'learn-press/single-course/model/section_left', + [ + 'wrapper' => '
', + 'description' => $this->singleCourseTemplate->html_description( $course ), + 'features' => $this->singleCourseTemplate->html_features( $course ), + 'target' => $this->singleCourseTemplate->html_target( $course ), + 'requirements' => $this->singleCourseTemplate->html_requirements( $course ), + 'material' => $this->singleCourseTemplate->html_material( $course ), + 'faqs' => $this->singleCourseTemplate->html_faqs( $course ), + 'instructor' => $html_instructor, + 'wrapper_end' => '
', + ], + $course, + $user + ); + + return Template::combine_components( $section_left ); + } + + public function section_right( $course, $user ): string { + + $data_info_meta = [ + 'student' => [ + 'label' => sprintf( '%s', __( 'Student', 'learnpress' ) ), + 'value' => $this->singleCourseTemplate->html_count_student( $course ), + ], + 'lesson' => [ + 'label' => sprintf( '%s', __( 'Lesson', 'learnpress' ) ), + 'value' => $this->singleCourseTemplate->html_count_item( $course, LP_LESSON_CPT ), + ], + 'duration' => [ + 'label' => sprintf( '%s', __( 'Duration', 'learnpress' ) ), + 'value' => $this->singleCourseTemplate->html_duration( $course ), + ], + 'quiz' => [ + 'label' => sprintf( '%s', __( 'Quiz', 'learnpress' ) ), + 'value' => $this->singleCourseTemplate->html_count_item( $course, LP_QUIZ_CPT ), + ], + 'level' => [ + 'label' => sprintf( '%s', __( 'Level', 'learnpress' ) ), + 'value' => $this->singleCourseTemplate->html_level( $course ), + ], + ]; + + $data_info_meta = apply_filters( 'learn-press/single-course/model/info-meta', $data_info_meta, $course, $user ); + $html_info_meta = ''; + if ( ! empty( $data_info_meta ) ) { + foreach ( $data_info_meta as $info_meta ) { + $label = $info_meta['label']; + $value = $info_meta['value']; + $html_info_two_item = sprintf( + '
+ %s + %s +
', + $label, + $value + ); + $html_info_meta .= $html_info_two_item; + } + } + + $section_info_two = apply_filters( + 'learn-press/single-course/model/section-right/info-meta', + [ + 'wrapper' => '
', + 'meta' => $html_info_meta, + 'wrapper_end' => '
', + ], + $course, + $user + ); + + $section_buttons = apply_filters( + 'learn-press/single-course/model/section-right/info-meta/buttons', + [ + 'wrapper' => '
', + 'btn_contact' => $this->singleCourseTemplate->html_btn_external( $course, $user ), + 'btn_buy' => $this->singleCourseTemplate->html_btn_purchase_course( $course, $user ), + 'btn_enroll' => $this->singleCourseTemplate->html_btn_enroll_course( $course, $user ), + 'wrapper_end' => '
', + ], + $course, + $user + ); + + $section_right = apply_filters( + 'learn-press/single-course/model/section_right', + [ + 'wrapper' => '
', + 'wrapper_inner' => '
', + 'image' => $this->singleCourseTemplate->html_image( $course ), + 'price' => $this->singleCourseTemplate->html_price( $course ), + 'info_two' => Template::combine_components( $section_info_two ), + 'buttons' => Template::combine_components( $section_buttons ), + 'sidebar' => $this->singleCourseTemplate->html_sidebar( $course ), + 'wrapper_inner_end' => '
', + 'wrapper_end' => '
', + ], + $course, + $user + ); + + return Template::combine_components( $section_right ); + } } \ No newline at end of file From 1fc337efceaafe6152889e2d9a6a9ba5ba0e28bd Mon Sep 17 00:00:00 2001 From: truongpn Date: Fri, 13 Dec 2024 11:52:09 +0700 Subject: [PATCH 003/225] single course --- .../Course/SingleCourseModelTemplate.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php index 635721e8e..fd1da34d6 100644 --- a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php @@ -14,6 +14,7 @@ use LearnPress\Models\CoursePostModel; use LearnPress\Models\UserModel; use LearnPress\TemplateHooks\Instructor\SingleInstructorTemplate; +use LP_Course; class SingleCourseModelTemplate { use Singleton; @@ -194,6 +195,7 @@ public function section_left( $course, $user ): string { 'features' => $this->singleCourseTemplate->html_features( $course ), 'target' => $this->singleCourseTemplate->html_target( $course ), 'requirements' => $this->singleCourseTemplate->html_requirements( $course ), + //'curriculum' => $this->html_curriculum( $course, $user ), 'material' => $this->singleCourseTemplate->html_material( $course ), 'faqs' => $this->singleCourseTemplate->html_faqs( $course ), 'instructor' => $html_instructor, @@ -210,23 +212,23 @@ public function section_right( $course, $user ): string { $data_info_meta = [ 'student' => [ - 'label' => sprintf( '%s', __( 'Student', 'learnpress' ) ), + 'label' => sprintf( '%s:', __( 'Student', 'learnpress' ) ), 'value' => $this->singleCourseTemplate->html_count_student( $course ), ], 'lesson' => [ - 'label' => sprintf( '%s', __( 'Lesson', 'learnpress' ) ), + 'label' => sprintf( '%s:', __( 'Lesson', 'learnpress' ) ), 'value' => $this->singleCourseTemplate->html_count_item( $course, LP_LESSON_CPT ), ], 'duration' => [ - 'label' => sprintf( '%s', __( 'Duration', 'learnpress' ) ), + 'label' => sprintf( '%s:', __( 'Duration', 'learnpress' ) ), 'value' => $this->singleCourseTemplate->html_duration( $course ), ], 'quiz' => [ - 'label' => sprintf( '%s', __( 'Quiz', 'learnpress' ) ), + 'label' => sprintf( '%s:', __( 'Quiz', 'learnpress' ) ), 'value' => $this->singleCourseTemplate->html_count_item( $course, LP_QUIZ_CPT ), ], 'level' => [ - 'label' => sprintf( '%s', __( 'Level', 'learnpress' ) ), + 'label' => sprintf( '%s:', __( 'Level', 'learnpress' ) ), 'value' => $this->singleCourseTemplate->html_level( $course ), ], ]; @@ -282,6 +284,7 @@ public function section_right( $course, $user ): string { 'price' => $this->singleCourseTemplate->html_price( $course ), 'info_two' => Template::combine_components( $section_info_two ), 'buttons' => Template::combine_components( $section_buttons ), + 'featured_review' => $this->singleCourseTemplate->html_feature_review( $course ), 'sidebar' => $this->singleCourseTemplate->html_sidebar( $course ), 'wrapper_inner_end' => '', 'wrapper_end' => '', From 4366b0b8ffaf1b06af3ab27715d80ad80129716a Mon Sep 17 00:00:00 2001 From: truongpn Date: Fri, 13 Dec 2024 11:57:46 +0700 Subject: [PATCH 004/225] fix z index quiz nav --- assets/src/scss/frontend/_popup.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/src/scss/frontend/_popup.scss b/assets/src/scss/frontend/_popup.scss index 4f7ea77d3..f13e5aa18 100644 --- a/assets/src/scss/frontend/_popup.scss +++ b/assets/src/scss/frontend/_popup.scss @@ -1061,7 +1061,7 @@ body { &.fixed { position: fixed; - z-index: 99999; + z-index: 999991; bottom: 0; left: 50%; width: 100%; From 97f8a5d3b9ebaef43332967338998085512ae229 Mon Sep 17 00:00:00 2001 From: truongpn Date: Fri, 13 Dec 2024 14:44:20 +0700 Subject: [PATCH 005/225] classic layout --- .../Course/SingleCourseClassicTemplate.php | 68 +++++++++++++++++++ .../Course/SingleCourseModelTemplate.php | 2 +- inc/lp-deprecated.php | 2 +- 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 inc/TemplateHooks/Course/SingleCourseClassicTemplate.php diff --git a/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php b/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php new file mode 100644 index 000000000..93da08bba --- /dev/null +++ b/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php @@ -0,0 +1,68 @@ +singleCourseTemplate = SingleCourseTemplate::instance(); + + add_action( + 'learn-press/single-course/classic/layout', + [ $this, 'course_classic_layout' ] + ); + } + + /** + * Single course layout classic + * + * @param $course + * + * @return void + */ + public function course_classic_layout( $course ) { + if ( ! $course instanceof CourseModel ) { + return; + } + + $user = UserModel::find( get_current_user_id(), true ); + + ob_start(); + learn_press_breadcrumb(); + $html_breadcrumb = ob_get_clean(); + + $content = []; + + $sections = apply_filters( + 'learn-press/single-course/classic/sections', + [ + 'wrapper' => '
', + 'breadcrumb' => $html_breadcrumb, + 'course-summary' => '
', + 'content' => Template::combine_components( $content ), + 'course-summary_end' => '
', + 'wrapper_end' => '
', + ] + ); + + echo Template::combine_components( $sections ); + } +} \ No newline at end of file diff --git a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php index fd1da34d6..5876dabc5 100644 --- a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php @@ -34,7 +34,7 @@ public function init() { } /** - * Single course layout + * Single course layout model * * @param $course * diff --git a/inc/lp-deprecated.php b/inc/lp-deprecated.php index f2bf70362..1fa175297 100644 --- a/inc/lp-deprecated.php +++ b/inc/lp-deprecated.php @@ -851,7 +851,7 @@ function learn_press_breadcrumb( $args = array() ) { apply_filters( 'learn_press_breadcrumb_defaults', array( - 'delimiter' => ' / ', + 'delimiter' => '', 'wrap_before' => '', 'before' => '', From 00e98352f2436437c46a62792ef23160345e5f03 Mon Sep 17 00:00:00 2001 From: truongpn Date: Fri, 13 Dec 2024 15:16:51 +0700 Subject: [PATCH 006/225] format --- .../Course/SingleCourseModelTemplate.php | 131 ++++++++++-------- 1 file changed, 72 insertions(+), 59 deletions(-) diff --git a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php index 5876dabc5..50c026a5e 100644 --- a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php @@ -11,6 +11,8 @@ use LearnPress\Helpers\Singleton; use LearnPress\Helpers\Template; use LearnPress\Models\CourseModel; +use LearnPress\Models\UserItems\UserCourseModel; +use LearnPress\TemplateHooks\UserItem\UserCourseTemplate; use LearnPress\Models\CoursePostModel; use LearnPress\Models\UserModel; use LearnPress\TemplateHooks\Instructor\SingleInstructorTemplate; @@ -19,21 +21,21 @@ class SingleCourseModelTemplate { use Singleton; - /** + /** * @var SingleCourseTemplate */ public $singleCourseTemplate; public function init() { $this->singleCourseTemplate = SingleCourseTemplate::instance(); - + add_action( 'learn-press/single-course/model/layout', [ $this, 'course_model_layout' ] ); } - /** + /** * Single course layout model * * @param $course @@ -52,7 +54,7 @@ public function course_model_layout( $course ) { do_action( 'learn-press/single-course/courses-related/layout', $course, 4 ); $html_courses_related = ob_get_clean(); - $sections = apply_filters( + $sections = apply_filters( 'learn-press/single-course/model/sections', [ 'wrapper' => '
', @@ -69,59 +71,59 @@ public function course_model_layout( $course ) { ); echo Template::combine_components( $sections ); - } + } - public function header_sections( $course, $user ): string { + public function header_sections( $course, $user ): string { - ob_start(); + ob_start(); learn_press_breadcrumb(); $html_breadcrumb = ob_get_clean(); - $html_categories = $this->singleCourseTemplate->html_categories( $course ); - if ( ! empty( $html_categories ) ) { - $html_categories = sprintf( - '
%s %s
', - sprintf( '', __( 'in', 'learnpress' ) ), - $html_categories - ); - } + $html_categories = $this->singleCourseTemplate->html_categories( $course ); + if ( ! empty( $html_categories ) ) { + $html_categories = sprintf( + '
%s %s
', + sprintf( '', __( 'in', 'learnpress' ) ), + $html_categories + ); + } - $html_instructor = $this->singleCourseTemplate->html_instructor( $course ); + $html_instructor = $this->singleCourseTemplate->html_instructor( $course ); $section_info_one = apply_filters( 'learn-press/single-course/model/header/info-meta', [ 'wrapper' => '
', - 'last_update' => sprintf( '
%s: %s
', esc_html__( 'Last updated', 'learnpress' ), esc_attr( get_post_modified_time( get_option( 'date_format' ), true ))), + 'last_update' => sprintf( '
%s: %s
', esc_html__( 'Last updated', 'learnpress' ), esc_attr( get_post_modified_time( get_option( 'date_format' ), true ) ) ), 'wrapper_end' => '
', ], $course, $user ); - $header_sections = apply_filters( + $header_sections = apply_filters( 'learn-press/single-course/model/header/sections', [ - 'wrapper_header' => '
', - 'wrapper_container' => '
', - 'breadcrumb' => $html_breadcrumb, - 'title' => $this->singleCourseTemplate->html_title( $course, 'h1' ), - 'wrapper_instructor_cate' => '
', - 'instructor' => sprintf( - '
%s %s
', - sprintf( '', __( 'by', 'learnpress' ) ), - $html_instructor - ), - 'category' => $html_categories, - 'wrapper_instructor_cate_end' => '
', - 'info_one' => Template::combine_components( $section_info_one ), - 'wrapper_container_end' => '
', - 'wrapper_header_end' => '
', - ], - ); + 'wrapper_header' => '
', + 'wrapper_container' => '
', + 'breadcrumb' => $html_breadcrumb, + 'title' => $this->singleCourseTemplate->html_title( $course, 'h1' ), + 'wrapper_instructor_cate' => '
', + 'instructor' => sprintf( + '
%s %s
', + sprintf( '', __( 'by', 'learnpress' ) ), + $html_instructor + ), + 'category' => $html_categories, + 'wrapper_instructor_cate_end' => '
', + 'info_one' => Template::combine_components( $section_info_one ), + 'wrapper_container_end' => '
', + 'wrapper_header_end' => '
', + ], + ); - return Template::combine_components( $header_sections ); - } + return Template::combine_components( $header_sections ); + } public function section_left( $course, $user ): string { @@ -187,10 +189,10 @@ public function section_left( $course, $user ): string { } // End instructor - $section_left = apply_filters( + $section_left = apply_filters( 'learn-press/single-course/model/section_left', [ - 'wrapper' => '
', + 'wrapper' => '
', 'description' => $this->singleCourseTemplate->html_description( $course ), 'features' => $this->singleCourseTemplate->html_features( $course ), 'target' => $this->singleCourseTemplate->html_target( $course ), @@ -199,7 +201,7 @@ public function section_left( $course, $user ): string { 'material' => $this->singleCourseTemplate->html_material( $course ), 'faqs' => $this->singleCourseTemplate->html_faqs( $course ), 'instructor' => $html_instructor, - 'wrapper_end' => '
', + 'wrapper_end' => '
', ], $course, $user @@ -209,25 +211,24 @@ public function section_left( $course, $user ): string { } public function section_right( $course, $user ): string { - $data_info_meta = [ - 'student' => [ + 'student' => [ 'label' => sprintf( '%s:', __( 'Student', 'learnpress' ) ), 'value' => $this->singleCourseTemplate->html_count_student( $course ), ], - 'lesson' => [ + 'lesson' => [ 'label' => sprintf( '%s:', __( 'Lesson', 'learnpress' ) ), 'value' => $this->singleCourseTemplate->html_count_item( $course, LP_LESSON_CPT ), ], - 'duration' => [ + 'duration' => [ 'label' => sprintf( '%s:', __( 'Duration', 'learnpress' ) ), 'value' => $this->singleCourseTemplate->html_duration( $course ), ], - 'quiz' => [ + 'quiz' => [ 'label' => sprintf( '%s:', __( 'Quiz', 'learnpress' ) ), 'value' => $this->singleCourseTemplate->html_count_item( $course, LP_QUIZ_CPT ), ], - 'level' => [ + 'level' => [ 'label' => sprintf( '%s:', __( 'Level', 'learnpress' ) ), 'value' => $this->singleCourseTemplate->html_level( $course ), ], @@ -262,37 +263,49 @@ public function section_right( $course, $user ): string { $user ); + $userCourseModel = UserCourseModel::find( get_current_user_id(), $course->get_id(), true ); + $userCourseTemplate = UserCourseTemplate::instance(); + $btn_continue_and_finish = []; + + if ( $userCourseModel instanceof UserCourseModel ) { + $btn_continue_and_finish = [ + 'btn_continue' => $userCourseTemplate->html_btn_continue( $userCourseModel ), + 'btn_finish' => $userCourseTemplate->html_btn_finish( $userCourseModel ), + ]; + } + $section_buttons = apply_filters( 'learn-press/single-course/model/section-right/info-meta/buttons', [ - 'wrapper' => '
', - 'btn_contact' => $this->singleCourseTemplate->html_btn_external( $course, $user ), - 'btn_buy' => $this->singleCourseTemplate->html_btn_purchase_course( $course, $user ), - 'btn_enroll' => $this->singleCourseTemplate->html_btn_enroll_course( $course, $user ), - 'wrapper_end' => '
', + 'wrapper' => '
', + 'btn_contact' => $this->singleCourseTemplate->html_btn_external( $course, $user ), + 'btn_buy' => $this->singleCourseTemplate->html_btn_purchase_course( $course, $user ), + 'btn_enroll' => $this->singleCourseTemplate->html_btn_enroll_course( $course, $user ), + 'btn_continue_and_finish' => Template::combine_components( $btn_continue_and_finish ), + 'wrapper_end' => '
', ], $course, $user ); - $section_right = apply_filters( + $section_right = apply_filters( 'learn-press/single-course/model/section_right', [ - 'wrapper' => '
', + 'wrapper' => '
', 'wrapper_inner' => '
', - 'image' => $this->singleCourseTemplate->html_image( $course ), - 'price' => $this->singleCourseTemplate->html_price( $course ), + 'image' => $this->singleCourseTemplate->html_image( $course ), + 'price' => $this->singleCourseTemplate->html_price( $course ), 'info_two' => Template::combine_components( $section_info_two ), 'buttons' => Template::combine_components( $section_buttons ), 'featured_review' => $this->singleCourseTemplate->html_feature_review( $course ), - 'sidebar' => $this->singleCourseTemplate->html_sidebar( $course ), + 'sidebar' => $this->singleCourseTemplate->html_sidebar( $course ), 'wrapper_inner_end' => '
', - 'wrapper_end' => '
', + 'wrapper_end' => '
', ], $course, $user ); - + return Template::combine_components( $section_right ); } -} \ No newline at end of file +} From 0069724a6e6a8f2641c5334d5846d62c7af9bdd1 Mon Sep 17 00:00:00 2001 From: truongpn Date: Fri, 13 Dec 2024 17:26:50 +0700 Subject: [PATCH 007/225] layout classic single --- assets/src/scss/frontend/_course-offline.scss | 1 + assets/src/scss/frontend/_course-single.scss | 9 ++ .../Course/SingleCourseClassicTemplate.php | 129 +++++++++++++++--- inc/lp-deprecated.php | 4 +- learnpress.php | 2 + templates/single-course.php | 5 +- 6 files changed, 127 insertions(+), 23 deletions(-) diff --git a/assets/src/scss/frontend/_course-offline.scss b/assets/src/scss/frontend/_course-offline.scss index 17b24381e..3989d8ead 100644 --- a/assets/src/scss/frontend/_course-offline.scss +++ b/assets/src/scss/frontend/_course-offline.scss @@ -34,6 +34,7 @@ font-size: var(--lp-font-size-base); align-items: center; margin-bottom: 8px; + padding: 0; li{ list-style: none; padding: 0; diff --git a/assets/src/scss/frontend/_course-single.scss b/assets/src/scss/frontend/_course-single.scss index 43d9d3097..02a9a3c65 100644 --- a/assets/src/scss/frontend/_course-single.scss +++ b/assets/src/scss/frontend/_course-single.scss @@ -444,4 +444,13 @@ margin: 0 0 40px 0; } } + + .course-detail-info { + &__inner { + max-width: var(--lp-container-max-width); + margin: 0 auto; + padding-right: var(--lp-cotainer-padding); + padding-left: var(--lp-cotainer-padding); + } + } } diff --git a/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php b/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php index 93da08bba..ce91ff34c 100644 --- a/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php @@ -13,56 +13,145 @@ use LearnPress\Models\CourseModel; use LearnPress\Models\UserModel; use LearnPress\TemplateHooks\Instructor\SingleInstructorTemplate; +use LearnPress\TemplateHooks\UserTemplate; class SingleCourseClassicTemplate { use Singleton; - /** + /** * @var SingleCourseTemplate */ public $singleCourseTemplate; public function init() { $this->singleCourseTemplate = SingleCourseTemplate::instance(); - + add_action( 'learn-press/single-course/classic/layout', [ $this, 'course_classic_layout' ] ); } - /** + /** * Single course layout classic * * @param $course * * @return void */ - public function course_classic_layout( $course ) { - if ( ! $course instanceof CourseModel ) { + public function course_classic_layout( $course ) { + if ( ! $course instanceof CourseModel ) { return; } $user = UserModel::find( get_current_user_id(), true ); - ob_start(); + ob_start(); learn_press_breadcrumb(); $html_breadcrumb = ob_get_clean(); - $content = []; + $content = [ + 'wrapper' => '
', + 'section_header' => $this->header_sections( $course, $user ), + 'wrapper_end' => '
', + ]; - $sections = apply_filters( + $sections = apply_filters( 'learn-press/single-course/classic/sections', [ - 'wrapper' => '
', - 'breadcrumb' => $html_breadcrumb, - 'course-summary' => '
', - 'content' => Template::combine_components( $content ), - 'course-summary_end' => '
', - 'wrapper_end' => '
', - ] - ); - - echo Template::combine_components( $sections ); - } -} \ No newline at end of file + 'wrapper' => '
', + 'breadcrumb' => $html_breadcrumb, + 'course_summary' => '
', + 'content' => Template::combine_components( $content ), + 'course_summary_end' => '
', + 'wrapper_end' => '
', + ] + ); + + echo Template::combine_components( $sections ); + } + + public function header_sections( $course, $user ): string { + + $header_sections = apply_filters( + 'learn-press/single-course/classic/header/sections', + [ + 'wrapper' => '
', + 'wrapper_inner' => '
', + 'wrapper_instructor_cate' => '
', + 'instructor' => $this->html_instructor( $course ), + 'category' => $this->html_category( $course ), + 'wrapper_instructor_cate_end' => '
', + 'wrapper_inner_end' => '
', + 'wrapper_end' => '
', + ] + ); + + return Template::combine_components( $header_sections ); + } + + public function html_instructor( $course ): string { + $instructor = $course->get_author_model(); + if ( ! $instructor ) { + return ''; + } + + $singleInstructorTemplate = SingleInstructorTemplate::instance(); + + $html_instructor = apply_filters( + 'learn-press/course/instructor-html', + [ + 'wrapper' => '
', + 'avartar_instructor' => sprintf( '
%s
', UserTemplate::instance()->html_avatar( $instructor, [], 'instructor' ) ), + 'instructor' => '
', + 'label' => sprintf( '', esc_html__( 'Instructor', 'learnpress' ) ), + 'name' => sprintf( + '', + $instructor->get_url_instructor(), + $singleInstructorTemplate->html_display_name( $instructor ) + ), + 'instructor_end' => '
', + 'wrapper_end' => '
', + ], + $course, + $instructor, + ); + + return Template::combine_components( $html_instructor ); + } + + public function html_category( $course ): string { + $cats = $course->get_categories(); + if ( empty( $cats ) ) { + return ''; + } + + $cat_names = []; + array_map( + function ( $cat ) use ( &$cat_names ) { + $term = sprintf( '%s', get_term_link( $cat->term_id ), $cat->name ); + $cat_names[] = $term; + }, + $cats + ); + + $content = implode( ' | ', $cat_names ); + + $html_category = apply_filters( + 'learn-press/course/html-categories', + [ + 'wrapper' => '
', + 'category' => '
', + 'label' => sprintf( '', esc_html__( 'Category', 'learnpress' ) ), + 'content' => sprintf( '
%s
', $content ), + 'category_end' => '
', + 'wrapper_end' => '
', + ], + $course, + $cats, + $cat_names + ); + + return Template::combine_components( $html_category ); + } +} diff --git a/inc/lp-deprecated.php b/inc/lp-deprecated.php index 1fa175297..aafd8ad48 100644 --- a/inc/lp-deprecated.php +++ b/inc/lp-deprecated.php @@ -852,8 +852,8 @@ function learn_press_breadcrumb( $args = array() ) { 'learn_press_breadcrumb_defaults', array( 'delimiter' => '', - 'wrap_before' => '', + 'wrap_before' => '
    ', + 'wrap_after' => '
', 'before' => '', 'after' => '', 'home' => _x( 'Home', 'breadcrumb', 'learnpress' ), diff --git a/learnpress.php b/learnpress.php index 79b3d9579..70bffc877 100644 --- a/learnpress.php +++ b/learnpress.php @@ -28,6 +28,7 @@ use LearnPress\TemplateHooks\Course\ListCoursesTemplate; use LearnPress\TemplateHooks\Course\SingleCourseOfflineTemplate; use LearnPress\TemplateHooks\Course\SingleCourseModelTemplate; +use LearnPress\TemplateHooks\Course\SingleCourseClassicTemplate; use LearnPress\TemplateHooks\Course\SingleCourseTemplate; use LearnPress\TemplateHooks\Instructor\ListInstructorsTemplate; use LearnPress\TemplateHooks\Instructor\SingleInstructorTemplate; @@ -307,6 +308,7 @@ private function include_files_global() { SingleCourseTemplate::instance(); SingleCourseOfflineTemplate::instance(); SingleCourseModelTemplate::instance(); + SingleCourseClassicTemplate::instance(); SingleInstructorTemplate::instance(); ProfileInstructorStatisticsTemplate::instance(); ProfileStudentStatisticsTemplate::instance(); diff --git a/templates/single-course.php b/templates/single-course.php index aeb692f4b..916ca9f03 100644 --- a/templates/single-course.php +++ b/templates/single-course.php @@ -53,7 +53,10 @@ $courseModel = CourseModel::find( $post->ID, true ); // hook from @since 4.2.7.5 - do_action( 'learn-press/single-course/model/layout', $courseModel ); + //do_action( 'learn-press/single-course/model/layout', $courseModel ); + + // hook deprecated 4.2.7.4 + do_action( 'learn-press/single-course/classic/layout', $courseModel ); //learn_press_get_template( 'content-single-course' ); } From 88c7584988ce59a84bad1a7a5ae420d8aafdb1a4 Mon Sep 17 00:00:00 2001 From: truongpn Date: Mon, 16 Dec 2024 14:30:14 +0700 Subject: [PATCH 008/225] classic single course --- assets/src/scss/frontend/_course-single.scss | 58 ++++ .../Course/SingleCourseClassicTemplate.php | 313 +++++++++++++++++- 2 files changed, 360 insertions(+), 11 deletions(-) diff --git a/assets/src/scss/frontend/_course-single.scss b/assets/src/scss/frontend/_course-single.scss index 02a9a3c65..62eed50c6 100644 --- a/assets/src/scss/frontend/_course-single.scss +++ b/assets/src/scss/frontend/_course-single.scss @@ -452,5 +452,63 @@ padding-right: var(--lp-cotainer-padding); padding-left: var(--lp-cotainer-padding); } + + .course-meta { + gap: 16px; + } + + .course-meta__pull-left { + width: calc(100% - 340px); + max-width: 100%; + margin: 0; + } + } + .course-tabs { + .course-faqs__title { + display: none; + } + } + .course-summary-sidebar { + &__inner { + background-color: $color-white; + border: 1px solid $border-color; + padding: 20px; + border-radius: $border-radius-global; + } + + .course-summary-sidebar__inner > * { + padding: 0; + margin-bottom: 20px; + + &:last-child { + margin-bottom: 0; + } + } + + .course-img { + margin: -20px -20px 20px; + border-radius: $border-radius-global $border-radius-global 0 0; + + img { + max-width: 100%; + } + } + + .course-price { + display: block; + font-size: $font-size-large; + font-weight: $heading-font-weight; + + .free { + color: #3AB500; + } + + .origin-price { + text-decoration: line-through; + opacity: 0.6; + font-size: $font-size-small; + margin-right: 4px; + } + } } } diff --git a/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php b/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php index ce91ff34c..470d6ad4e 100644 --- a/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php @@ -12,6 +12,8 @@ use LearnPress\Helpers\Template; use LearnPress\Models\CourseModel; use LearnPress\Models\UserModel; +use LearnPress\Models\UserItems\UserCourseModel; +use LearnPress\TemplateHooks\UserItem\UserCourseTemplate; use LearnPress\TemplateHooks\Instructor\SingleInstructorTemplate; use LearnPress\TemplateHooks\UserTemplate; @@ -51,9 +53,10 @@ public function course_classic_layout( $course ) { $html_breadcrumb = ob_get_clean(); $content = [ - 'wrapper' => '
', - 'section_header' => $this->header_sections( $course, $user ), - 'wrapper_end' => '
', + 'wrapper' => '
', + 'section_header' => $this->header_sections( $course, $user ), + 'section_main' => $this->main_sections( $course, $user ), + 'wrapper_end' => '
', ]; $sections = apply_filters( @@ -73,23 +76,129 @@ public function course_classic_layout( $course ) { public function header_sections( $course, $user ): string { + $meta_primary = apply_filters( + 'learn-press/single-course/classic/meta-primary/sections', + [ + 'wrapper' => '
', + 'instructor' => $this->html_instructor( $course ), + 'category' => $this->html_category( $course ), + 'wrapper_end' => '
', + ] + ); + + $meta_secondary = apply_filters( + 'learn-press/single-course/classic/meta-secondary/sections', + [ + 'wrapper' => '
', + 'duration' => sprintf( + '
%s
', + $this->singleCourseTemplate->html_duration( $course ) + ), + 'level' => sprintf( + '
%s
', + $this->singleCourseTemplate->html_level( $course ) + ), + 'lesson' => sprintf( + '
%s
', + $this->singleCourseTemplate->html_count_item( $course, LP_LESSON_CPT ) + ), + 'quiz' => sprintf( + '
%s
', + $this->singleCourseTemplate->html_count_item( $course, LP_QUIZ_CPT ) + ), + 'student' => sprintf( + '
%s
', + $this->singleCourseTemplate->html_count_student( $course ) + ), + 'wrapper_end' => '
', + ] + ); + $header_sections = apply_filters( 'learn-press/single-course/classic/header/sections', [ - 'wrapper' => '
', - 'wrapper_inner' => '
', - 'wrapper_instructor_cate' => '
', - 'instructor' => $this->html_instructor( $course ), - 'category' => $this->html_category( $course ), - 'wrapper_instructor_cate_end' => '
', - 'wrapper_inner_end' => '
', - 'wrapper_end' => '
', + 'wrapper' => '
', + 'wrapper_inner' => '
', + 'wrapper_content' => '
', + 'meta_primary' => Template::combine_components( $meta_primary ), + 'title' => $this->singleCourseTemplate->html_title( $course, 'h1' ), + 'meta_secondary' => Template::combine_components( $meta_secondary ), + 'wrapper_content_end' => '
', + 'wrapper_inner_end' => '
', + 'wrapper_end' => '
', ] ); return Template::combine_components( $header_sections ); } + public function main_sections( $course, $user ): string { + + $content_left = apply_filters( + 'learn-press/single-course/classic/content-left/sections', + [ + 'wrapper' => '
', + 'course_tabs' => $this->html_course_tabs( $course, $user ), + 'features' => $this->singleCourseTemplate->html_features( $course ), + 'target' => $this->singleCourseTemplate->html_target( $course ), + 'requirements' => $this->singleCourseTemplate->html_requirements( $course ), + 'wrapper_end' => '
', + ] + ); + + $userCourseModel = UserCourseModel::find( get_current_user_id(), $course->get_id(), true ); + $userCourseTemplate = UserCourseTemplate::instance(); + $btn_continue_and_finish = []; + + if ( $userCourseModel instanceof UserCourseModel ) { + $btn_continue_and_finish = [ + 'btn_continue' => $userCourseTemplate->html_btn_continue( $userCourseModel ), + 'btn_finish' => $userCourseTemplate->html_btn_finish( $userCourseModel ), + ]; + } + + $section_buttons = apply_filters( + 'learn-press/single-course/model/section-right/info-meta/buttons', + [ + 'wrapper' => '
', + 'btn_contact' => $this->singleCourseTemplate->html_btn_external( $course, $user ), + 'btn_buy' => $this->singleCourseTemplate->html_btn_purchase_course( $course, $user ), + 'btn_enroll' => $this->singleCourseTemplate->html_btn_enroll_course( $course, $user ), + 'btn_continue_and_finish' => Template::combine_components( $btn_continue_and_finish ), + 'wrapper_end' => '
', + ], + $course, + $user + ); + + $summary_sidebar = apply_filters( + 'learn-press/single-course/classic/content-left/sections', + [ + 'wrapper' => '
', + 'wrapper_inner' => '
', + 'image' => $this->singleCourseTemplate->html_image( $course ), + 'price' => $this->singleCourseTemplate->html_price( $course ), + 'buttons' => Template::combine_components( $section_buttons ), + 'featured_review' => $this->singleCourseTemplate->html_feature_review( $course ), + 'sidebar' => $this->singleCourseTemplate->html_sidebar( $course ), + 'wrapper_inner_end' => '
', + 'wrapper_end' => '
', + ] + ); + + $main_sections = apply_filters( + 'learn-press/single-course/classic/main/sections', + [ + 'wrapper' => '
', + 'content_left' => Template::combine_components( $content_left ), + 'summary_sidebar' => Template::combine_components( $summary_sidebar ), + 'wrapper_end' => '
', + ] + ); + + return Template::combine_components( $main_sections ); + } + public function html_instructor( $course ): string { $instructor = $course->get_author_model(); if ( ! $instructor ) { @@ -154,4 +263,186 @@ function ( $cat ) use ( &$cat_names ) { return Template::combine_components( $html_category ); } + + public function html_course_tabs( $course, $user ): string { + + $tabs = apply_filters( + 'learn-press/single-course/classic/course-tabs', + [ + 'overview' => esc_html__( 'Overview', 'learnpress' ), + 'curriculum' => esc_html__( 'Curriculum', 'learnpress' ), + 'instructor' => esc_html__( 'Instructor', 'learnpress' ), + 'faqs' => esc_html__( 'FAQs', 'learnpress' ), + ] + ); + + $active_tab = 'overview'; + $lp_user = learn_press_get_current_user(); + + if ( $lp_user && ! $lp_user instanceof LP_User_Guest ) { + $can_view_course = $lp_user->can_view_content_course( get_the_ID() ); + + if ( ! $can_view_course->flag ) { + if ( LP_BLOCK_COURSE_FINISHED === $can_view_course->key ) { + learn_press_display_message( + esc_html__( 'You finished this course. This course has been blocked', 'learnpress' ), + 'warning' + ); + } elseif ( LP_BLOCK_COURSE_DURATION_EXPIRE === $can_view_course->key ) { + learn_press_display_message( + esc_html__( 'This course has been blocked for expiration', 'learnpress' ), + 'warning' + ); + } + } + } + + $html_tabs = []; + if ( $tabs ) { + ob_start(); + foreach ( $tabs as $key => $tab ) { + echo ''; + } + $html_input = ob_get_clean(); + + ob_start(); + foreach ( $tabs as $key => $tab ) { + $classes = array( 'course-nav course-nav-tab-' . esc_attr( $key ) ); + + if ( $active_tab === $key ) { + $classes[] = 'active'; + } + + echo '
  • '; + echo ''; + echo '
  • '; + } + $html_tabs_nav = ob_get_clean(); + + $tabs_nav = [ + 'wrapper' => '
    ', + 'nav_tabs' => '
      ', + 'content' => $html_tabs_nav, + 'nav_tabs_end' => '
    ', + 'wrapper_end' => '
    ', + ]; + + ob_start(); + + foreach ( $tabs as $key => $tab ) { + echo '
    '; + + switch ( $key ) { + case 'overview': + echo $this->singleCourseTemplate->html_description( $course ); + break; + // case 'curriculum': + // echo $this->singleCourseTemplate->html_curriculum( $course ); + // break; + case 'instructor': + echo $this->html_instructor_main( $course, $user ); + break; + case 'faqs': + echo $this->singleCourseTemplate->html_faqs( $course ); + break; + case 'materials': + echo $this->singleCourseTemplate->html_material( $course ); + break; + } + echo '
    '; + } + + $html_tabs_content = ob_get_clean(); + + $tabs_content = [ + 'wrapper' => '
    ', + 'content' => $html_tabs_content, + 'wrapper_end' => '
    ', + ]; + + $html_tabs = [ + 'input' => $html_input, + 'nav' => Template::combine_components( $tabs_nav ), + 'content' => Template::combine_components( $tabs_content ), + ]; + } + + $course_tabs = apply_filters( + 'learn-press/single-course/classic/main/course-tabs', + [ + 'wrapper' => '
    ', + 'tabs' => Template::combine_components( $html_tabs ), + 'wrapper_end' => '
    ', + ] + ); + + return Template::combine_components( $course_tabs ); + } + + public function html_instructor_main( $course, $user ): string { + + $singleInstructorTemplate = SingleInstructorTemplate::instance(); + $author = $course->get_author_model(); + + // Instructor + $html_instructor = ''; + if ( $author ) { + $html_instructor_image = sprintf( + '%s', + $author->get_url_instructor(), + $author->get_display_name(), + $singleInstructorTemplate->html_avatar( $author ) + ); + $section_instructor_meta = [ + 'wrapper' => '
    ', + 'count_students' => sprintf( + '
    %s
    ', + $singleInstructorTemplate->html_count_students( $author ) + ), + 'count_courses' => sprintf( + '
    %s
    ', + $singleInstructorTemplate->html_count_courses( $author ) + ), + 'wrapper_end' => '
    ', + ]; + $html_instructor_meta = Template::combine_components( $section_instructor_meta ); + + $section_instructor_right = apply_filters( + 'learn-press/single-course/model/section-instructor/right', + [ + 'wrapper' => '
    ', + 'name' => sprintf( + '%s', + $author->get_url_instructor(), + $singleInstructorTemplate->html_display_name( $author ) + ), + 'meta' => $html_instructor_meta, + 'description' => $singleInstructorTemplate->html_description( $author ), + 'social' => $singleInstructorTemplate->html_social( $author ), + 'wrapper_end' => '
    ', + ], + $course, + $user + ); + $html_instructor_right = Template::combine_components( $section_instructor_right ); + $section_instructor = apply_filters( + 'learn-press/single-course/model/section-instructor', + [ + 'wrapper' => '
    ', + 'wrapper_info' => '
    ', + 'image' => $html_instructor_image, + 'instructor_right' => $html_instructor_right, + 'wrapper_info_end' => '
    ', + 'wrapper_end' => '
    ', + ], + $course, + $user + ); + $html_instructor = Template::combine_components( $section_instructor ); + } + + return $html_instructor; + } } From b9dc8760c09e2a988963638148490f8a6ebe1761 Mon Sep 17 00:00:00 2001 From: truongpn Date: Mon, 16 Dec 2024 14:35:08 +0700 Subject: [PATCH 009/225] classic single course --- assets/src/scss/frontend/_course-single.scss | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/assets/src/scss/frontend/_course-single.scss b/assets/src/scss/frontend/_course-single.scss index 62eed50c6..9b59474f9 100644 --- a/assets/src/scss/frontend/_course-single.scss +++ b/assets/src/scss/frontend/_course-single.scss @@ -455,12 +455,15 @@ .course-meta { gap: 16px; + flex-wrap: wrap; } - .course-meta__pull-left { - width: calc(100% - 340px); - max-width: 100%; - margin: 0; + @media (min-width: 769px) { + .course-meta__pull-left { + width: calc(100% - 340px); + max-width: 100%; + margin: 0; + } } } .course-tabs { From 488bb007af631e751761aff9f8590136100c545a Mon Sep 17 00:00:00 2001 From: truongpn Date: Mon, 16 Dec 2024 14:58:36 +0700 Subject: [PATCH 010/225] classic single course --- assets/src/scss/frontend/_course-single.scss | 3 ++- inc/TemplateHooks/Course/SingleCourseClassicTemplate.php | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/assets/src/scss/frontend/_course-single.scss b/assets/src/scss/frontend/_course-single.scss index 9b59474f9..35854e521 100644 --- a/assets/src/scss/frontend/_course-single.scss +++ b/assets/src/scss/frontend/_course-single.scss @@ -467,7 +467,8 @@ } } .course-tabs { - .course-faqs__title { + .course-faqs__title, + .course-material__title { display: none; } } diff --git a/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php b/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php index 470d6ad4e..c5bbcb582 100644 --- a/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php @@ -272,6 +272,7 @@ public function html_course_tabs( $course, $user ): string { 'overview' => esc_html__( 'Overview', 'learnpress' ), 'curriculum' => esc_html__( 'Curriculum', 'learnpress' ), 'instructor' => esc_html__( 'Instructor', 'learnpress' ), + 'materials' => esc_html__( 'Materials', 'learnpress' ), 'faqs' => esc_html__( 'FAQs', 'learnpress' ), ] ); From 9a41d5f32cc89f2924169dc0833886e78174f857 Mon Sep 17 00:00:00 2001 From: truongpn Date: Mon, 16 Dec 2024 16:59:36 +0700 Subject: [PATCH 011/225] single course --- assets/src/scss/frontend/_course-single.scss | 145 ++++++++++++++++++ .../Course/SingleCourseClassicTemplate.php | 6 +- .../Course/SingleCourseModelTemplate.php | 40 +++++ templates/single-course.php | 4 +- 4 files changed, 190 insertions(+), 5 deletions(-) diff --git a/assets/src/scss/frontend/_course-single.scss b/assets/src/scss/frontend/_course-single.scss index 35854e521..f25b3994f 100644 --- a/assets/src/scss/frontend/_course-single.scss +++ b/assets/src/scss/frontend/_course-single.scss @@ -284,6 +284,7 @@ gap: 4px; flex-wrap: wrap; margin-bottom: 8px; + padding: 0; } .course-title { @@ -436,6 +437,150 @@ } } } + + .social-share-toggle { + position: relative; + text-align: right; + + .share-toggle-icon { + text-align: right; + cursor: pointer; + display: inline-block; + } + + .content-widget-social-share { + padding: 24px 16px; + background: #fff; + box-shadow: 0 1px 16px 0 rgba(0, 0, 0, 0.12); + + .title-share { + padding-bottom: 16px; + margin-bottom: 16px; + } + + .thim-social-media { + display: inline-flex; + + > li { + text-align: center; + list-style: none; + + > a { + display: block; + text-align: center; + margin: 0 auto; + } + } + } + + .btn-clipboard { + position: relative; + + .tooltip { + display: none; + position: absolute; + z-index: 2; + left: 50%; + right: auto; + bottom: 100%; + transform: translateX(-50%); + width: max-content; + color: #fff; + font-size: 0.825em; + padding: 5px 10px; + background: rgba(0, 0, 0, 0.72); + border-radius: 3px; + margin-bottom: 10px; + + &:before { + content: ""; + position: absolute; + z-index: 2; + left: 50%; + bottom: -5px; + margin-left: -3px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid rgba(0, 0, 0, 0.72); + } + } + + &:hover { + background-color: #eee; + + .tooltip { + display: block; + } + } + + //&.active { + // &:active, + // &:focus { + // outline: none; + // &:after { + // content: "Copied!"; + // } + // } + //} + } + + .clipboard-value { + border: 0; + padding: 0; + color: inherit; + background: transparent !important; + box-shadow: none; + + &:focus { + outline: none; + } + } + } + + .wrapper-content-widget { + visibility: hidden; + text-align: left; + opacity: 0; + -webkit-transition: all 0.27s ease; + -moz-transition: all 0.27s ease; + -o-transition: all 0.27s ease; + transition: all 0.27s ease; + position: absolute; + right: 0; + top: auto; + z-index: 9; + margin-top: 20px; + } + + &.social-share-toggle__open { + .wrapper-content-widget { + margin-top: 0; + visibility: visible; + opacity: 1; + } + } + + @media (max-width: 768px) { + .wrapper-content-widget { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.7); + + .content-widget-social-share { + position: relative; + z-index: 1; + max-width: fit-content; + top: 50%; + min-width: 320px; + transform: translateY(-50%); + margin: 0 auto; + } + } + } + } } } diff --git a/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php b/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php index c5bbcb582..2766c43b0 100644 --- a/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php @@ -137,12 +137,12 @@ public function main_sections( $course, $user ): string { $content_left = apply_filters( 'learn-press/single-course/classic/content-left/sections', [ - 'wrapper' => '
    ', - 'course_tabs' => $this->html_course_tabs( $course, $user ), + 'wrapper' => '
    ', + 'course_tabs' => $this->html_course_tabs( $course, $user ), 'features' => $this->singleCourseTemplate->html_features( $course ), 'target' => $this->singleCourseTemplate->html_target( $course ), 'requirements' => $this->singleCourseTemplate->html_requirements( $course ), - 'wrapper_end' => '
    ', + 'wrapper_end' => '
    ', ] ); diff --git a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php index 50c026a5e..a68321be7 100644 --- a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php @@ -297,6 +297,7 @@ public function section_right( $course, $user ): string { 'price' => $this->singleCourseTemplate->html_price( $course ), 'info_two' => Template::combine_components( $section_info_two ), 'buttons' => Template::combine_components( $section_buttons ), + 'share' => $this->html_share( $course ), 'featured_review' => $this->singleCourseTemplate->html_feature_review( $course ), 'sidebar' => $this->singleCourseTemplate->html_sidebar( $course ), 'wrapper_inner_end' => '
    ', @@ -308,4 +309,43 @@ public function section_right( $course, $user ): string { return Template::combine_components( $section_right ); } + + public function html_share( $course ): string { + + $social_media = apply_filters( + 'learn-press/single-course/social-share', + [] + ); + + $clipboard = [ + 'wrapper' => '
    ', + 'input' => sprintf( '', get_permalink() ), + 'button' => sprintf( + '', + esc_html__( 'Copied!', 'thim-elementor-kit' ), + esc_html__( 'Copy', 'thim-elementor-kit' ), + esc_html__( 'Copy to Clipboard', 'thim-elementor-kit' ) + ), + 'wrapper_end' => '
    ', + ]; + + $section_share = apply_filters( + 'learn-press/single-course/social-share/sections', + [ + 'wrapper' => '', + ] + ); + + return Template::combine_components( $section_share ); + } } diff --git a/templates/single-course.php b/templates/single-course.php index 916ca9f03..1d14cee2e 100644 --- a/templates/single-course.php +++ b/templates/single-course.php @@ -53,10 +53,10 @@ $courseModel = CourseModel::find( $post->ID, true ); // hook from @since 4.2.7.5 - //do_action( 'learn-press/single-course/model/layout', $courseModel ); + do_action( 'learn-press/single-course/model/layout', $courseModel ); // hook deprecated 4.2.7.4 - do_action( 'learn-press/single-course/classic/layout', $courseModel ); + //do_action( 'learn-press/single-course/classic/layout', $courseModel ); //learn_press_get_template( 'content-single-course' ); } From b9e5c8c465a77ecb43b5eda658e4def34b4a5f3b Mon Sep 17 00:00:00 2001 From: truongpn Date: Mon, 16 Dec 2024 18:11:37 +0700 Subject: [PATCH 012/225] add share --- assets/src/js/frontend/copy-to-clipboard.js | 21 ++++++ assets/src/js/frontend/widgets.js | 2 + assets/src/js/utils.js | 72 +++++++++++++++++++ .../Course/SingleCourseModelTemplate.php | 1 + 4 files changed, 96 insertions(+) create mode 100644 assets/src/js/frontend/copy-to-clipboard.js diff --git a/assets/src/js/frontend/copy-to-clipboard.js b/assets/src/js/frontend/copy-to-clipboard.js new file mode 100644 index 000000000..b52524c3b --- /dev/null +++ b/assets/src/js/frontend/copy-to-clipboard.js @@ -0,0 +1,21 @@ +import { LPClick } from '../utils'; + +export default function CopyToClipboard() { + LPClick( '.social-share-toggle', '.share-toggle-icon', '.content-widget-social-share' ); + + var copyTextareaBtn = document.querySelector( '.btn-clipboard' ); + if (copyTextareaBtn) { + copyTextareaBtn.addEventListener( 'click', function( event ) { + var copyTextarea = document.querySelector( '.clipboard-value' ); + copyTextarea.focus(); + copyTextarea.select(); + try { + var successful = document.execCommand( 'copy' ); + var msg = copyTextareaBtn.getAttribute( 'data-copied' ); + copyTextareaBtn.innerHTML = msg + '' + msg + ''; + } catch (err) { + + } + } ); + } +} diff --git a/assets/src/js/frontend/widgets.js b/assets/src/js/frontend/widgets.js index 30f73bd54..7a43e320d 100644 --- a/assets/src/js/frontend/widgets.js +++ b/assets/src/js/frontend/widgets.js @@ -1,5 +1,6 @@ import { lpFetchAPI } from '../utils'; import API from '../api'; +import LPCopyToClipboard from '../frontend/copy-to-clipboard'; function widgetRestAPI() { const widgets = document.querySelectorAll( '.learnpress-widget-wrapper:not(.loaded)' ); @@ -71,4 +72,5 @@ document.addEventListener( 'readystatechange', ( event ) => { // Case 3: DOMContentLoaded, find all elements with the class '.lp-load-ajax-element' not have class 'loaded' document.addEventListener( 'DOMContentLoaded', () => { widgetRestAPI(); + LPCopyToClipboard(); } ); diff --git a/assets/src/js/utils.js b/assets/src/js/utils.js index fb3174fe7..315c5c948 100644 --- a/assets/src/js/utils.js +++ b/assets/src/js/utils.js @@ -181,3 +181,75 @@ export { listenElementViewed, listenElementCreated, lpOnElementReady, lpAjaxParseJsonOld, lpShowHideEl, lpSetLoadingEl, }; + +export function LPClick( element, iconBtn, inner ) { + const wrapper = document.querySelector( element ), + clickBtn = wrapper && wrapper.querySelector( iconBtn ), + class_open = element.replace( '.', '' ) + '__open', + closeElement = wrapper && wrapper.querySelector( element + '__close' ); + + if (! wrapper) { + return; + } + + const isOpenElement = () => { + return wrapper.classList.contains( class_open ); + }; + + const showElement = () => { + if (isOpenElement()) { + return; + } + + wrapper.classList.add( class_open ); + }; + + const hideElement = () => { + if (! isOpenElement()) { + return; + } + + wrapper.classList.remove( class_open ); + }; + + const toggleElement = () => { + if (isOpenElement()) { + hideElement(); + } else { + showElement(); + } + }; + + const onKeyDown = ( e ) => { + if (e.keyCode === 27) { + hideElement(); + } + }; + clickBtn.onclick = function( e ) { + e.preventDefault(); + toggleElement(); + }; + + document.addEventListener( 'click', ( e ) => { + if (! isOpenElement()) { + return; + } + + const target = e.target; + + if (target.closest( inner ) || target.closest( iconBtn )) { + return; + } + + hideElement(); + } ); + + // Click close button. + closeElement && closeElement.addEventListener( 'click', ( e ) => { + e.preventDefault(); + + hideElement(); + } ); + + document.addEventListener( 'keydown', onKeyDown, false ); // click ESC button will hide popup +} \ No newline at end of file diff --git a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php index a68321be7..061be9aac 100644 --- a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php @@ -295,6 +295,7 @@ public function section_right( $course, $user ): string { 'wrapper_inner' => '
    ', 'image' => $this->singleCourseTemplate->html_image( $course ), 'price' => $this->singleCourseTemplate->html_price( $course ), + //'sale_discount' => $this->singleCourseTemplate->html_sale_discount( $course ), to do 'info_two' => Template::combine_components( $section_info_two ), 'buttons' => Template::combine_components( $section_buttons ), 'share' => $this->html_share( $course ), From e5ef583d00c6476e9bcfd415a56916cb6f20d472 Mon Sep 17 00:00:00 2001 From: truongpn Date: Tue, 17 Dec 2024 08:50:19 +0700 Subject: [PATCH 013/225] fix js share popup --- assets/src/apps/js/frontend/single-course.js | 2 ++ assets/src/js/frontend/copy-to-clipboard.js | 1 + assets/src/js/frontend/widgets.js | 2 -- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/assets/src/apps/js/frontend/single-course.js b/assets/src/apps/js/frontend/single-course.js index 3375c33bf..fb31e50e6 100644 --- a/assets/src/apps/js/frontend/single-course.js +++ b/assets/src/apps/js/frontend/single-course.js @@ -8,6 +8,7 @@ import TabsDragScroll from './tabs-scroll'; import { lpSetLoadingEl } from '../../../js/utils.js'; import Toastify from 'toastify-js'; import 'toastify-js/src/toastify.css'; +import LPCopyToClipboard from '../../../js/frontend/copy-to-clipboard.js'; export default SingleCourse; @@ -412,6 +413,7 @@ document.addEventListener( 'DOMContentLoaded', function() { lpMaterialsLoad(); //courseCurriculumSkeleton(); TabsDragScroll(); + LPCopyToClipboard(); } ); const detectedElCurriculum = setInterval( function() { diff --git a/assets/src/js/frontend/copy-to-clipboard.js b/assets/src/js/frontend/copy-to-clipboard.js index b52524c3b..d2252d3a5 100644 --- a/assets/src/js/frontend/copy-to-clipboard.js +++ b/assets/src/js/frontend/copy-to-clipboard.js @@ -4,6 +4,7 @@ export default function CopyToClipboard() { LPClick( '.social-share-toggle', '.share-toggle-icon', '.content-widget-social-share' ); var copyTextareaBtn = document.querySelector( '.btn-clipboard' ); + console.log('ádasdasdasd'); if (copyTextareaBtn) { copyTextareaBtn.addEventListener( 'click', function( event ) { var copyTextarea = document.querySelector( '.clipboard-value' ); diff --git a/assets/src/js/frontend/widgets.js b/assets/src/js/frontend/widgets.js index 7a43e320d..30f73bd54 100644 --- a/assets/src/js/frontend/widgets.js +++ b/assets/src/js/frontend/widgets.js @@ -1,6 +1,5 @@ import { lpFetchAPI } from '../utils'; import API from '../api'; -import LPCopyToClipboard from '../frontend/copy-to-clipboard'; function widgetRestAPI() { const widgets = document.querySelectorAll( '.learnpress-widget-wrapper:not(.loaded)' ); @@ -72,5 +71,4 @@ document.addEventListener( 'readystatechange', ( event ) => { // Case 3: DOMContentLoaded, find all elements with the class '.lp-load-ajax-element' not have class 'loaded' document.addEventListener( 'DOMContentLoaded', () => { widgetRestAPI(); - LPCopyToClipboard(); } ); From 0915d9ba9510dd15f2fc91ea0f3809f109c28c81 Mon Sep 17 00:00:00 2001 From: truongpn Date: Tue, 17 Dec 2024 08:51:02 +0700 Subject: [PATCH 014/225] fix js share popup --- assets/src/js/frontend/copy-to-clipboard.js | 1 - 1 file changed, 1 deletion(-) diff --git a/assets/src/js/frontend/copy-to-clipboard.js b/assets/src/js/frontend/copy-to-clipboard.js index d2252d3a5..b52524c3b 100644 --- a/assets/src/js/frontend/copy-to-clipboard.js +++ b/assets/src/js/frontend/copy-to-clipboard.js @@ -4,7 +4,6 @@ export default function CopyToClipboard() { LPClick( '.social-share-toggle', '.share-toggle-icon', '.content-widget-social-share' ); var copyTextareaBtn = document.querySelector( '.btn-clipboard' ); - console.log('ádasdasdasd'); if (copyTextareaBtn) { copyTextareaBtn.addEventListener( 'click', function( event ) { var copyTextarea = document.querySelector( '.clipboard-value' ); From 2973e3bcd32e5b750a07f3eed9f87a5820a99f0a Mon Sep 17 00:00:00 2001 From: truongpn Date: Tue, 17 Dec 2024 10:09:30 +0700 Subject: [PATCH 015/225] style popup share --- assets/src/scss/frontend/_course-offline.scss | 1 + assets/src/scss/frontend/_course-single.scss | 79 +++++++++++-------- .../Course/SingleCourseModelTemplate.php | 44 ++++++++++- 3 files changed, 89 insertions(+), 35 deletions(-) diff --git a/assets/src/scss/frontend/_course-offline.scss b/assets/src/scss/frontend/_course-offline.scss index 3989d8ead..ecd46d430 100644 --- a/assets/src/scss/frontend/_course-offline.scss +++ b/assets/src/scss/frontend/_course-offline.scss @@ -319,6 +319,7 @@ gap: 30px; margin-top: 30px; margin-bottom: 30px; + flex-wrap: wrap; .instructor-display-name { font-size: 1.4rem; diff --git a/assets/src/scss/frontend/_course-single.scss b/assets/src/scss/frontend/_course-single.scss index f25b3994f..9f00f5ae1 100644 --- a/assets/src/scss/frontend/_course-single.scss +++ b/assets/src/scss/frontend/_course-single.scss @@ -324,8 +324,10 @@ display: flex; column-gap: 60px; row-gap: 30px; + flex-wrap: wrap; &__left { + width: 100%; @media (min-width: 992px) { width: calc(100% - 440px); } @@ -346,6 +348,7 @@ } &__right { + width: 100%; @media (min-width: 992px) { width: 380px; margin-top: -280px; @@ -440,38 +443,64 @@ .social-share-toggle { position: relative; - text-align: right; .share-toggle-icon { - text-align: right; cursor: pointer; - display: inline-block; + display: flex; + align-items: center; + gap: 8px; + + .share-label { + margin: 0; + } } .content-widget-social-share { - padding: 24px 16px; + padding: 20px; background: #fff; box-shadow: 0 1px 16px 0 rgba(0, 0, 0, 0.12); - .title-share { - padding-bottom: 16px; - margin-bottom: 16px; - } - .thim-social-media { display: inline-flex; + padding: 0; + gap: 12px; > li { text-align: center; list-style: none; - - > a { - display: block; - text-align: center; - margin: 0 auto; + + span { + display: none; + } + + i { + width: 40px; + height: 40px; + display: inline-flex; + align-items: center; + justify-content: center; + border: 1px solid $border-color; + border-radius: 50%; + + &:hover { + background-color: $color-primary; + border-color: $color-primary; + color: $color-white; + } } } } + + .clipboard-post { + display: flex; + justify-content: space-between; + margin-bottom: 20px; + gap: 12px; + + @media (max-width: 600px) { + flex-wrap: wrap; + } + } .btn-clipboard { position: relative; @@ -512,27 +541,13 @@ display: block; } } - - //&.active { - // &:active, - // &:focus { - // outline: none; - // &:after { - // content: "Copied!"; - // } - // } - //} } .clipboard-value { - border: 0; - padding: 0; - color: inherit; - background: transparent !important; - box-shadow: none; - - &:focus { - outline: none; + border: 1px solid $border-color; + + @media (max-width: 600px) { + width: 100%; } } } diff --git a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php index 061be9aac..dd43e028c 100644 --- a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php @@ -313,11 +313,49 @@ public function section_right( $course, $user ): string { public function html_share( $course ): string { + $list_socials = [ + 'facebook' => esc_html__( 'Facebook', 'learnpress' ), + 'twitter' => esc_html__( 'Twitter', 'learnpress' ), + 'pinterest' => esc_html__( 'Pinterest', 'learnpress' ), + 'linkedin' => esc_html__( 'Linkedin', 'learnpress' ), + ]; + + ob_start(); + if ( $list_socials ) { + foreach ( $list_socials as $key => $social ) { + switch ( $key ) { + case 'facebook': + $link_share = 'https://www.facebook.com/sharer.php?u=' . urlencode( get_permalink() ); + $icon = ''; + break; + case'twitter': + $link_share = 'https://twitter.com/share?url=' . urlencode( get_permalink() ) . '&text=' . rawurlencode( esc_attr( get_the_title() ) ); + $icon = ''; + break; + case'pinterest': + $link_share = 'http://pinterest.com/pin/create/button/?url=' . urlencode( get_permalink() ) . '&description=' . rawurlencode( esc_attr( get_the_excerpt() ) ) . '&media=' . urlencode( wp_get_attachment_url( get_post_thumbnail_id() ) ) . ' onclick="window.open(this.href); return false;"'; + $icon = ''; + break; + case'linkedin': + $link_share = 'https://www.linkedin.com/shareArticle?mini=true&url=' . urlencode( get_permalink() ) . '&title=' . rawurlencode( esc_attr( get_the_title() ) ) . '&summary=&source=' . rawurlencode( esc_attr( get_the_excerpt() ) ); + $icon = ''; + break; + } + echo sprintf('
  • %s%s
  • ', $link_share, $social, $icon, $social); + } + } + + $html_social = ob_get_clean(); + $social_media = apply_filters( 'learn-press/single-course/social-share', - [] + [ + 'wrapper' => '', + ] ); - + $clipboard = [ 'wrapper' => '
    ', 'input' => sprintf( '', get_permalink() ), @@ -339,8 +377,8 @@ public function html_share( $course ): string { 'toggle_end' => '
    ', 'wrapper_content' => '
    ', 'wrapper_content_inner' => '', 'wrapper_content_end' => '
    ', 'wrapper_end' => '
    ', From 2d289a4d0a5a1509277d29567ee22c85e094b7d7 Mon Sep 17 00:00:00 2001 From: truongpn Date: Tue, 17 Dec 2024 14:41:18 +0700 Subject: [PATCH 016/225] single instructor --- assets/src/scss/frontend/_course-offline.scss | 5 +- assets/src/scss/frontend/_instructor.scss | 263 ++++++++++------ .../src/scss/frontend/_user_cover_image.scss | 2 +- .../Instructor/SingleInstructorTemplate.php | 294 ++++++------------ 4 files changed, 273 insertions(+), 291 deletions(-) diff --git a/assets/src/scss/frontend/_course-offline.scss b/assets/src/scss/frontend/_course-offline.scss index ecd46d430..301da8bdf 100644 --- a/assets/src/scss/frontend/_course-offline.scss +++ b/assets/src/scss/frontend/_course-offline.scss @@ -319,7 +319,10 @@ gap: 30px; margin-top: 30px; margin-bottom: 30px; - flex-wrap: wrap; + + @media (max-width: 600px) { + flex-wrap: wrap; + } .instructor-display-name { font-size: 1.4rem; diff --git a/assets/src/scss/frontend/_instructor.scss b/assets/src/scss/frontend/_instructor.scss index adfd87737..4844d62fa 100644 --- a/assets/src/scss/frontend/_instructor.scss +++ b/assets/src/scss/frontend/_instructor.scss @@ -6,6 +6,8 @@ */ // fix container for theme premium @import "variables"; +@import "user_cover_image"; + body { .entry-content { &.has-global-padding { @@ -50,42 +52,88 @@ body { } &__info { - border: 1px solid var(--lp-instructor-border-color); - margin-bottom: 50px; - padding: 16px; - display: flex; + margin-bottom: 40px; - .instructor-avatar { - margin-right: 30px; + &__wrapper { + display: flex; + align-items: center; + gap: 24px; + } + .instructor-avatar { img { - //border: 1px solid var(--lp-instructor-border-color); - //width: 100%; - //display: block; - //object-fit: cover; + max-width: 120px; + border-radius: 50%; } } &__right { flex: 1; + display: flex; + align-items: center; + justify-content: space-between; + gap: 20px; + + &__content { + display: flex; + flex-direction: column; + row-gap: 8px; + } .instructor-description:empty { margin: 0; } .instructor-social { - margin: $spacing-base-4x 0; display: flex; - gap: 25px; - font-size: $font-size-large; + gap: 12px; + font-size: $font-size-small; &:empty { margin: 0; } - svg { - width: 30px; - height: 30px; + i { + width: 40px; + height: 40px; + display: inline-flex; + align-items: center; + justify-content: center; + border: 1px solid $border-color; + border-radius: 50%; + + &:hover { + background-color: $color-primary; + border-color: $color-primary; + color: $color-white; + } + } + } + + .lp-instructor-meta { + display: flex; + column-gap: 20px; + + .instructor-item-meta { + display: inline-flex; + gap: 8px; + align-items: center; + + i { + color: $color-primary; + } + } + } + + @media (max-width: 991px) { + flex-wrap: wrap; + + .instructor-description { + display: none; + } + + .lp-instructor-meta { + flex-wrap: wrap; } } } @@ -106,8 +154,7 @@ body { .ul-instructor-courses { display: grid; - //grid-template-columns: repeat(4, 1fr); - gap: 16px; + gap: 30px; padding: 0!important; margin: 0 0 32px 0; list-style: none; @@ -122,94 +169,136 @@ body { color: var(--lp-primary-color); } - h2 { - font-size: 1.2em; - font-weight: bold; - margin-top: 0; - padding-bottom: var(--lp-instructor-item-padding); - border-bottom: 1px solid var(--lp-instructor-border-color); - margin-bottom: var(--lp-instructor-item-padding); - - a { - text-decoration: none; - } - } - - .course-img { - img { - width: 100%; - max-width: 100%; - height: auto; - aspect-ratio: 4/3; - object-fit: cover; + .course-item { + border: 1px solid $border-color; + border-radius: $border-radius-global; + &:hover { + box-shadow: 0 15px 20px 0 rgba(0, 0, 0, 0.2); } } - .price-categories { - margin: var(--lp-instructor-item-padding) 0; - //font-size: 0.8em; - .course-item-price { - .free { - color: green; - } - - .origin-price { - text-decoration: line-through; - margin-right: 5px; - opacity: 0.7; + .course-content { + padding: $spacing-base-5x; + flex-grow: 1; + .course-info { + flex-direction: column; + align-items: flex-start; + gap: $spacing-base-3x; + .course-readmore { + width: 100%; + text-align: center; } + } - .price { - color: var(--lp-primary-color); - } + .course-title { + font-size: $font-size-h4; } - .course-categories { - display: inline-block; + .course-excerpt, .course-short-description, .course-instructor-category { + display: none; + } + } - a { - text-decoration: none; + .course-thumbnail{ + border-radius:$border-radius-global $border-radius-global 0 0; + overflow: hidden; + } - &:not(:hover) { - color: inherit; - } + .course-wrap-meta { + display: flex; + padding: 0; + margin-bottom: $spacing-base-3x; + //font-size: $font-size-small; + gap: $spacing-base-5x; + flex-wrap: wrap; + row-gap: $spacing-base-2x; + + .meta-item { + text-transform: capitalize; + display: flex; + gap: $spacing-base-2x; + &::before { + color: var(--lp-primary-color); + font-family: 'lp-icon'; } - - &:not(:empty) { - &::before { - content: "|"; - display: inline-block; - padding: 0 10px; - } + & > div { + display: inline-block; } } + + .meta-item-level::before { + content: "\f012"; + } + + .meta-item-duration::before { + content: "\f017"; + } + + .meta-item-lesson::before { + content: "\f15b"; + } + + .meta-item-quiz::before { + content: "\f12e"; + } + + .meta-item-student::before { + content: "\f501"; + } + + .meta-item-address::before{ + content: "\e91b"; + } + + .meta-item-duration, .meta-item-level, .meta-item-quiz { + display: none; + } } - .course-count { - display: flex; - gap: 20px; - //font-size: 0.8em; - div { - display: flex; - align-items: center; - column-gap: 5px; - white-space: nowrap; + .course-price { + display: block; + margin: 0 0 $spacing-base-3x 0; + font-size: $font-size-large; + font-weight: $heading-font-weight; - .course-ico { - display: flex; + .free { + color: #3AB500; + } + + .origin-price { + text-decoration: line-through; + opacity: 0.6; + font-size: $font-size-small; + margin-right: 4px; + } + } - svg { - width: 20px; - height: 20px; - } + .course-title { + margin: 0 0 $spacing-base-3x 0; + padding: 0; + display: block; + + &:hover { + color: var(--lp-primary-color); + } + } + .course-readmore { + a { + padding: $spacing-base-2x $spacing-base-6x; + border-radius: $border-radius-global; + color: $text-color-base; + border: 1px solid $text-color-base; + transition: all 0.3s; + display: block; + background: transparent; + text-decoration: none; + &:hover { + background: $color-primary; + color: $color-white; + border-color: $color-primary; } } - } - - //@media (max-width: 900px) { - // grid-template-columns: repeat( auto-fit, minmax( 280px, 1fr ) ); - //} } } diff --git a/assets/src/scss/frontend/_user_cover_image.scss b/assets/src/scss/frontend/_user_cover_image.scss index 8e4e01253..0f828d3ac 100644 --- a/assets/src/scss/frontend/_user_cover_image.scss +++ b/assets/src/scss/frontend/_user_cover_image.scss @@ -12,7 +12,7 @@ right: 0; background: $bg-grey; padding: 12px 20px; - border-radius: $border-radius-global 0 0 0; + border-radius: $border-radius-global 0 $border-radius-global 0; text-transform: capitalize; cursor: pointer; color: $color-primary; diff --git a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php index 7cac81004..9f282c407 100644 --- a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php +++ b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php @@ -14,6 +14,8 @@ use LearnPress\Models\Courses; use LearnPress\Models\UserModel; use LearnPress\TemplateHooks\Course\SingleCourseTemplate; +use LearnPress\TemplateHooks\Profile\ProfileTemplate; +use LearnPress\TemplateHooks\Course\ListCoursesTemplate; use LearnPress\TemplateHooks\UserTemplate; use LP_Course; use LP_Course_Filter; @@ -29,10 +31,6 @@ public function init() { //add_action( 'wp_head', [ $this, 'add_internal_style_to_head' ] ); } - /*public function add_internal_style_to_head() { - echo ''; - }*/ - /** * Get display name html of instructor. * @@ -284,27 +282,20 @@ public function sections( array $data = [] ) { return; } - $html_wrapper = apply_filters( - 'learn-press/single-instructor/sections/wrapper', - [ - '
    ' => '
    ', - '
    ' => '
    ', - ], - $instructor - ); - $sections = apply_filters( - 'learn-press/single-instructor/sections/wrapper', + $sections = apply_filters( + 'learn-press/single-instructor/sections', [ - 'info' => [ 'text_html' => $this->info( $instructor ) ], - 'courses' => [ 'text_html' => $this->section_list_courses( $instructor ) ], + 'wrapper' => '
    ', + 'wrapper_inner' => '
    ', + 'info' => $this->info( $instructor ), + 'courses' => $this->section_list_courses( $instructor ), + 'wrapper_inner_end' => '
    ', + 'wrapper_end' => '
    ', ], $instructor ); - ob_start(); - Template::instance()->print_sections( $sections, compact( 'instructor' ) ); - $content = ob_get_clean(); - echo Template::instance()->nest_elements( $html_wrapper, $content ); + echo Template::combine_components( $sections ); } catch ( Throwable $e ) { ob_end_clean(); error_log( __METHOD__ . ': ' . $e->getMessage() ); @@ -344,166 +335,93 @@ public function detect_instructor_by_page() { * @return false|string */ public function info( LP_User $instructor ): string { - $content = ''; - try { - $html_wrapper = apply_filters( - 'learn-press/single-instructor/info/wrapper', - [ - '
    ' => '
    ', - ], - $instructor - ); + $html_cover = ''; - $sections = apply_filters( - 'learn-press/single-instructor/info/sections', - [ - 'image' => [ 'text_html' => $this->html_avatar( $instructor ) ], - 'info_right' => [ 'text_html' => $this->info_right( $instructor ) ], - ], - $instructor - ); + ob_start(); + $userModel = UserModel::find( $instructor->get_id(), true ); + // Display cover image + echo ProfileTemplate::instance()->html_cover_image( $userModel ); + $html_cover = ob_get_clean(); - ob_start(); - Template::instance()->print_sections( $sections, compact( 'instructor' ) ); - $content = ob_get_clean(); - $content = Template::instance()->nest_elements( $html_wrapper, $content ); - } catch ( Throwable $e ) { - ob_end_clean(); - error_log( __METHOD__ . ': ' . $e->getMessage() ); - } + $sections = apply_filters( + 'learn-press/single-instructor/info/sections', + [ + 'wrapper' => '
    ', + 'cover_img' => $html_cover, + 'wrapper_content' => '
    ', + 'image' => $this->html_avatar( $instructor ), + 'info_right' => $this->info_right( $instructor ), + 'wrapper_content_end' => '
    ', + 'wrapper_end' => '
    ', + ], + $instructor + ); - return $content; + return Template::combine_components( $sections ); } public function info_right( LP_User $instructor ): string { - $content = ''; - - try { - $html_wrapper = apply_filters( - 'learn-press/single-instructor/info-right/wrapper', - [ - '
    ' => '
    ', - ], - $instructor - ); - $count_course = sprintf( - '
    %s%s
    ', - ' ', + $section_instructor_meta = [ + 'wrapper' => '
    ', + 'count_courses' => sprintf( + '
    %s
    ', $this->html_count_courses( $instructor ) - ); - - $count_student = sprintf( - '
    %s%s
    ', - ' ', + ), + 'count_students' => sprintf( + '
    %s
    ', $this->html_count_students( $instructor ) - ); - - $sections = apply_filters( - 'learn-press/single-instructor/info-right/sections', - [ - 'title' => [ 'text_html' => "

    {$this->html_display_name( $instructor )}

    " ], - 'social' => [ 'text_html' => $this->html_social( $instructor ) ], - 'description' => [ 'text_html' => $this->html_description( $instructor ) ], - 'count_course' => [ 'text_html' => $count_course ], - 'count_student' => [ 'text_html' => $count_student ], - ], - $instructor - ); - - ob_start(); - Template::instance()->print_sections( $sections, compact( 'instructor' ) ); - $content = ob_get_clean(); - $content = Template::instance()->nest_elements( $html_wrapper, $content ); - } catch ( Throwable $e ) { - ob_end_clean(); - error_log( __METHOD__ . ': ' . $e->getMessage() ); - } - - return $content; - } - - public function section_list_courses( LP_User $instructor ): string { - $content = ''; - $html_wrapper = [ - '
    ' => '
    ', + ), + 'wrapper_end' => '
    ', ]; - try { - // Get option load courses of Instructor via ajax - $load_ajax = false; - - // Query courses of instructor - if ( ! $load_ajax ) { - $filter = new LP_Course_Filter(); - Courses::handle_params_for_query_courses( $filter, [] ); - $filter->post_author = $instructor->get_id(); - $filter->limit = \LP_Settings::get_option( 'archive_course_limit', 20 ); - $filter->page = $GLOBALS['wp_query']->get( 'paged', 1 ) ? $GLOBALS['wp_query']->get( 'paged', 1 ) : 1; - // $filter = apply_filters( 'lp/single-instructor/courses/query/filter', $filter, [] ); - - $total_courses = 0; - $courses = Courses::get_courses( $filter, $total_courses ); - - $sections = apply_filters( - 'learn-press/single-instructor/courses/sections', - [ - 'courses' => [ 'text_html' => $this->list_courses( $instructor, $courses ) ], - 'pagination' => [ 'text_html' => $this->courses_pagination( $filter->page, $filter->limit, $total_courses ) ], - ], - $courses, - $instructor - ); - - ob_start(); - Template::instance()->print_sections( $sections, compact( 'instructor', 'courses' ) ); - $content = ob_get_clean(); - } else { - ob_end_clean(); - $html_wrapper['
      '] = '
    '; - } - } catch ( Throwable $e ) { - error_log( __METHOD__ . ': ' . $e->getMessage() ); - } - - $html_wrapper = apply_filters( - 'learn-press/single-instructor/courses/wrapper', - $html_wrapper, + $sections = apply_filters( + 'learn-press/single-instructor/info-right/sections', + [ + 'wrapper' => '
    ', + 'wrapper_content' => '
    ', + 'title' => sprintf( '

    %s

    ', $this->html_display_name( $instructor ) ) , + 'meta' => Template::combine_components( $section_instructor_meta ), + 'description' => $this->html_description( $instructor ), + 'wrapper_content_end' => '
    ', + 'social' => $this->html_social( $instructor ), + 'wrapper_end' => '
    ', + ], $instructor ); - return Template::instance()->nest_elements( $html_wrapper, $content ); + return Template::combine_components( $sections ); } - /** - * Display list courses. - * - * @param $instructor - * @param $courses - * - * @return string - */ - public function list_courses( $instructor, $courses ): string { + public function section_list_courses( LP_User $instructor ): string { $content = ''; try { - $html_ul_wrapper = apply_filters( - 'learn-press/single-instructor/ul-courses/wrapper', + // Query courses of instructor + $filter = new LP_Course_Filter(); + Courses::handle_params_for_query_courses( $filter, [] ); + $filter->post_author = $instructor->get_id(); + $filter->limit = \LP_Settings::get_option( 'archive_course_limit', 20 ); + $filter->page = $GLOBALS['wp_query']->get( 'paged', 1 ) ? $GLOBALS['wp_query']->get( 'paged', 1 ) : 1; + // $filter = apply_filters( 'lp/single-instructor/courses/query/filter', $filter, [] ); + + $total_courses = 0; + $courses = Courses::get_courses( $filter, $total_courses ); + + $sections = apply_filters( + 'learn-press/single-instructor/courses/sections', [ - '
      ' => '
    ', + 'wrapper' => '
    ', + 'courses' => $this->list_courses( $instructor, $courses ), + 'pagination' => $this->courses_pagination( $filter->page, $filter->limit, $total_courses ), + 'wrapper_end' => '
    ', ], $courses, $instructor ); - // List courses - $ul_courses = ''; - foreach ( $courses as $course_obj ) { - $course = LP_Course::get_course( $course_obj->ID ); - $ul_courses .= $this->course_item( $course ); - } - $content = Template::instance()->nest_elements( $html_ul_wrapper, $ul_courses ); + $content = Template::combine_components( $sections ); } catch ( Throwable $e ) { error_log( __METHOD__ . ': ' . $e->getMessage() ); } @@ -512,65 +430,37 @@ public function list_courses( $instructor, $courses ): string { } /** - * Display item course. + * Display list courses. * - * @param LP_Course $course + * @param $instructor + * @param $courses * - * @return void + * @return string */ - public function course_item( LP_Course $course ): string { - $content = ''; - $html_wrapper = apply_filters( - 'learn-press/single-instructor/course_items/wrapper', - [ - '
  • ' => '
  • ', - ], - $course - ); + public function list_courses( $instructor, $courses ): string { + $content = ''; try { - $singleCourseTemplate = SingleCourseTemplate::instance(); + // List courses ob_start(); - $html_img = sprintf( - '%s', - $course->get_permalink(), - $singleCourseTemplate->html_image( $course ) - ); - $html_title = sprintf( - '

    %s

    ', - $course->get_permalink(), - $singleCourseTemplate->html_title( $course ) - ); - $html_price_categories = sprintf( - '
    %s %s
    ', - $course->get_course_price_html(), - $singleCourseTemplate->html_categories( $course ) - ); - - $count_lesson = $course->count_items( LP_LESSON_CPT ); - $count_student = $course->get_total_user_enrolled_or_purchased(); - $ico_lesson = ''; - $ico_student = ''; - $html_count = sprintf( - '
    %s %s
    ', - sprintf( '
    %s %d %s
    ', $ico_lesson, $count_lesson, _n( 'Lesson', 'Lessons', $count_lesson, 'learnpress' ) ), - sprintf( '
    %s %d %s
    ', $ico_student, $count_student, _n( 'Student', 'Students', $count_student, 'learnpress' ) ) - ); + foreach ( $courses as $course_obj ) { + $course = LP_Course::get_course( $course_obj->ID ); + echo ListCoursesTemplate::render_course( $course ); + } + $html_ul_wrapper = ob_get_clean(); $sections = apply_filters( - 'learn-press/single-instructor/course_items/sections', + 'learn-press/single-instructor/courses/sections', [ - 'img' => [ 'text_html' => $html_img ], - 'price-categories' => [ 'text_html' => $html_price_categories ], - 'title' => [ 'text_html' => $html_title ], - 'count' => [ 'text_html' => $html_count ], + 'wrapper' => '
      ', + 'list_course' => $html_ul_wrapper, + 'wrapper_end' => '
    ', ], - $course, - $singleCourseTemplate + $courses, + $instructor ); - Template::instance()->print_sections( $sections, compact( 'course' ) ); - $content = ob_get_clean(); - $content = Template::instance()->nest_elements( $html_wrapper, $content ); + + $content = Template::combine_components( $sections ); } catch ( Throwable $e ) { error_log( __METHOD__ . ': ' . $e->getMessage() ); } From aca17e76d9b8aa5144f1b5a037d4a9e55b2ef295 Mon Sep 17 00:00:00 2001 From: truongpn Date: Tue, 17 Dec 2024 15:46:57 +0700 Subject: [PATCH 017/225] single instructor --- .../Instructor/SingleInstructorTemplate.php | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php index 9f282c407..6c6f4f8ac 100644 --- a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php +++ b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php @@ -39,11 +39,13 @@ public function init() { * @return string */ public function html_display_name( $instructor ): string { - $html_wrapper = [ - '' => '', + $sections = [ + 'wrapper' => '', + 'content' => $instructor->get_display_name(), + 'wrapper_end' => '', ]; - return Template::instance()->nest_elements( $html_wrapper, $instructor->get_display_name() ); + return Template::combine_components( $sections ); } /** @@ -57,18 +59,21 @@ public function html_social( $instructor ): string { $content = ''; try { - $html_wrapper = [ - '
    ' => '
    ', - ]; - $socials = $instructor->get_profile_social( $instructor->get_id() ); + $socials = $instructor->get_profile_social( $instructor->get_id() ); ob_start(); foreach ( $socials as $k => $social ) { echo $social; } $content = ob_get_clean(); - $content = Template::instance()->nest_elements( $html_wrapper, $content ); + + $sections = [ + 'wrapper' => '
    ', + 'content' => $content, + 'wrapper_end' => '
    ', + ]; + + $content = Template::combine_components( $sections ); } catch ( Throwable $e ) { - ob_end_clean(); error_log( __METHOD__ . ': ' . $e->getMessage() ); } @@ -86,11 +91,13 @@ public function html_description( $instructor ): string { $content = ''; try { - $html_wrapper = [ - '
    ' => '
    ', + $sections = [ + 'wrapper' => '
    ', + 'content' => $instructor->get_description(), + 'wrapper_end' => '
    ', ]; - $content = Template::instance()->nest_elements( $html_wrapper, $instructor->get_description() ); + $content = Template::combine_components( $sections ); } catch ( Throwable $e ) { error_log( __METHOD__ . ': ' . $e->getMessage() ); } @@ -138,20 +145,19 @@ public function html_count_courses( $instructor ): string { $content = ''; try { - $html_wrapper = [ - '' => '', - ]; - $instructor_statistic = $instructor->get_instructor_statistic(); - $content = Template::instance()->nest_elements( - $html_wrapper, - sprintf( + $sections = [ + 'wrapper' => '', + 'content' => sprintf( '%d %s', $instructor_statistic['published_course'], _n( 'Course', 'Courses', $instructor_statistic['published_course'], 'learnpress' ) - ) - ); + ), + 'wrapper_end' => '', + ]; + + $content = Template::combine_components( $sections ); } catch ( Throwable $e ) { error_log( __METHOD__ . ': ' . $e->getMessage() ); } @@ -172,21 +178,19 @@ public function html_count_students( $instructor ): string { $content = ''; try { - $html_wrapper = [ - '' => '', - ]; - $instructor_statistic = $instructor->get_instructor_statistic(); - $content = Template::instance()->nest_elements( $html_wrapper, $instructor_statistic['total_student'] ); - $content = Template::instance()->nest_elements( - $html_wrapper, - sprintf( + $sections = [ + 'wrapper' => '', + 'content' => sprintf( '%d %s', $instructor_statistic['total_student'], _n( 'Student', 'Students', $instructor_statistic['total_student'], 'learnpress' ) - ) - ); + ), + 'wrapper_end' => '', + ]; + + $content = Template::combine_components( $sections ); } catch ( Throwable $e ) { error_log( __METHOD__ . ': ' . $e->getMessage() ); } From 3994dec81472c5cc8814fe02fd59df1fea40580c Mon Sep 17 00:00:00 2001 From: truongpn Date: Tue, 24 Dec 2024 09:57:00 +0700 Subject: [PATCH 018/225] remove font size --- assets/src/scss/frontend/_instructor.scss | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/assets/src/scss/frontend/_instructor.scss b/assets/src/scss/frontend/_instructor.scss index 4844d62fa..71da13903 100644 --- a/assets/src/scss/frontend/_instructor.scss +++ b/assets/src/scss/frontend/_instructor.scss @@ -156,9 +156,8 @@ body { display: grid; gap: 30px; padding: 0!important; - margin: 0 0 32px 0; + margin: 0 0 30px 0; list-style: none; - font-size: 1rem; grid-template-columns: repeat( auto-fill, minmax(var(--lp-instructor-minmax-column), 1fr) ); li { From aedfb1ac634faf89ea2ba40c638f4e6ef6f0d10b Mon Sep 17 00:00:00 2001 From: truongpn Date: Tue, 24 Dec 2024 14:08:47 +0700 Subject: [PATCH 019/225] update icon courses --- inc/TemplateHooks/Instructor/SingleInstructorTemplate.php | 4 ++-- package.json | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php index 6c6f4f8ac..9332888ff 100644 --- a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php +++ b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php @@ -148,7 +148,7 @@ public function html_count_courses( $instructor ): string { $instructor_statistic = $instructor->get_instructor_statistic(); $sections = [ - 'wrapper' => '', + 'wrapper' => '', 'content' => sprintf( '%d %s', $instructor_statistic['published_course'], @@ -370,7 +370,7 @@ public function info_right( LP_User $instructor ): string { $section_instructor_meta = [ 'wrapper' => '
    ', 'count_courses' => sprintf( - '
    %s
    ', + '
    %s
    ', $this->html_count_courses( $instructor ) ), 'count_students' => sprintf( diff --git a/package.json b/package.json index deae37489..fe37c2a67 100644 --- a/package.json +++ b/package.json @@ -4,10 +4,10 @@ "description": "[![Stories in Ready](https://badge.waffle.io/LearnPress/LearnPress.svg?label=ready&title=Ready)](http://waffle.io/LearnPress/LearnPress)", "main": "index.js", "scripts": { - "start": "cross-env NODE_OPTIONS=--openssl-legacy-provider wp-scripts start", - "build": "cross-env NODE_OPTIONS=--openssl-legacy-provider wp-scripts build", - "format-js": "cross-env NODE_OPTIONS=--openssl-legacy-provider wp-scripts format ./assets/src", - "dev-build": "cross-env NODE_OPTIONS=--openssl-legacy-provider npm run build && gulp styles && npm run dev", + "start": "cross-env wp-scripts start", + "build": "cross-env wp-scripts build", + "format-js": "cross-env wp-scripts format ./assets/src", + "dev-build": "cross-env npm run build && gulp styles && npm run dev", "makepot:js": "wp-babel-makepot \"./assets/src/**/*.{js,jsx,ts,tsx}\" --ignore \"**/node_modules/**,**/test/**,**/*.d.ts\" --base \"./\" --dir \"./languages/strings\" --output \"./languages/learnpress-js.pot\"", "makepot:cli": "wp i18n make-pot . languages/learnpress.pot --skip-audit --merge=languages/learnpress-js.pot --exclude=\"test,releases,build,dist,node_modules,vendor,wordpress\"", "makepot": "npm rum makepot:js && npm run makepot:cli && gulp updatePot", From 0fa8e1fac64ea094faabd5d2c5c159e6bac1b20a Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 24 Dec 2024 14:32:01 +0700 Subject: [PATCH 020/225] = 4.2.7.6 = ~ Tweak: SingleInstructorTemplate class. ~ Tweak: detect_instructor_id, detect_instructor_by_page methods. ~ Added: is_instructor method on UserModel class. --- .../SingleInstructorBaseElementor.php | 35 ++++++++----------- inc/Models/UserModel.php | 11 ++++++ .../Instructor/SingleInstructorTemplate.php | 33 ++++++++--------- .../views/meta-boxes/course/settings.php | 4 +-- 4 files changed, 43 insertions(+), 40 deletions(-) diff --git a/inc/ExternalPlugin/Elementor/Widgets/Instructor/SingleInstructorBaseElementor.php b/inc/ExternalPlugin/Elementor/Widgets/Instructor/SingleInstructorBaseElementor.php index 7d96eba4a..01627d1dd 100644 --- a/inc/ExternalPlugin/Elementor/Widgets/Instructor/SingleInstructorBaseElementor.php +++ b/inc/ExternalPlugin/Elementor/Widgets/Instructor/SingleInstructorBaseElementor.php @@ -15,6 +15,8 @@ use LearnPress\ExternalPlugin\Elementor\LPElementor; use LearnPress\ExternalPlugin\Elementor\LPElementorWidgetBase; use LearnPress\Helpers\Config; +use LearnPress\Models\UserModel; +use LearnPress\TemplateHooks\Instructor\SingleInstructorTemplate; use LP_User; class SingleInstructorBaseElementor extends LPElementorWidgetBase { @@ -31,43 +33,36 @@ public function get_categories() { * Detect instructor id if is single instructor page * * @param array $settings - * @param LP_User|null $instructor + * @param UserModel|false $instructor * @param string $label_default * + * @since 4.2.3 + * @version 1.0.1 * @return void * @throws Exception */ - protected function detect_instructor_id( array $settings, LP_User &$instructor = null, string $label_default = '' ) { + protected function detect_instructor_id( array $settings, &$instructor = null, string $label_default = '' ) { /** * Get instructor id * * If is page is single instructor, will be get instructor id from query var * Else will be get instructor id from widget */ - $instructor_id = 0; - if ( get_query_var( 'is_single_instructor' ) ) { - if ( get_query_var( 'instructor_name' ) && 'page' !== get_query_var( 'instructor_name' ) ) { - $user = get_user_by( 'slug', get_query_var( 'instructor_name' ) ); - if ( $user ) { - $instructor_id = $user->ID; - } - } else { - $instructor_id = get_current_user_id(); - } - } else { + $instructor = SingleInstructorTemplate::instance()->detect_instructor_by_page(); + if ( ! $instructor instanceof UserModel ) { $instructor_id = $settings['instructor_id'] ?? 0; + $instructor = UserModel::find( $instructor_id, true ); } - if ( ! $instructor_id && Plugin::$instance->editor->is_edit_mode() ) { - throw new Exception( $label_default ); - } - - $instructor = learn_press_get_user( $instructor_id ); if ( ! $instructor ) { - throw new Exception( __( 'Instructor not found!', 'learnpress' ) ); + if ( Plugin::$instance->editor->is_edit_mode() ) { + throw new Exception( $label_default ); + } else { + throw new Exception( __( 'Instructor not found!', 'learnpress' ) ); + } } - if ( ! $instructor->can_create_course() ) { + if ( ! $instructor->is_instructor() ) { throw new Exception( __( 'User is not Instructor!', 'learnpress' ) ); } } diff --git a/inc/Models/UserModel.php b/inc/Models/UserModel.php index b47a75082..b6feadf76 100644 --- a/inc/Models/UserModel.php +++ b/inc/Models/UserModel.php @@ -582,4 +582,15 @@ public function get_instructor_statistic( array $params = [] ): array { return apply_filters( 'lp/profile/instructor/statistic', $statistic, $this ); } + + /** + * Check user is instructor or not. + * + * @return bool + * @since 4.2.7.6 + * @version 1.0.0 + */ + public function is_instructor(): bool { + return user_can( $this->get_id(), LP_TEACHER_ROLE ) || user_can( $this->get_id(), 'administrator' ); + } } diff --git a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php index 9332888ff..5028caa8d 100644 --- a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php +++ b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php @@ -268,21 +268,16 @@ public function render_data( LP_User $instructor, string $data_content = '' ): s */ public function sections( array $data = [] ) { wp_enqueue_style( 'lp-instructor' ); - /** - * @var WP_Query $wp_query - */ - global $wp_query; - $instructor = false; try { if ( isset( $data['instructor_id'] ) ) { $instructor_id = $data['instructor_id']; - $instructor = learn_press_get_user( $instructor_id ); + $instructor = UserModel::find( $instructor_id, true ); } else { $instructor = $this->detect_instructor_by_page(); } - if ( ! $instructor || ! $instructor->can_create_course() ) { + if ( ! $instructor || ! $instructor->is_instructor() ) { return; } @@ -309,7 +304,9 @@ public function sections( array $data = [] ) { /** * Detected single instructor Page. * - * @return false|LP_User + * @return false|UserModel + * @since 4.2.3.4 + * @version 1.0.1 */ public function detect_instructor_by_page() { $instructor = false; @@ -320,32 +317,32 @@ public function detect_instructor_by_page() { if ( $instructor_name && 'page' !== $instructor_name ) { $user = get_user_by( 'slug', $instructor_name ); if ( $user ) { - $instructor = learn_press_get_user( $user->ID ); + $instructor = UserModel::find( $user->ID, true ); } } else { - $instructor = learn_press_get_user( get_current_user_id() ); + $instructor = UserModel::find( get_current_user_id(), true ); } } } catch ( Throwable $e ) { - + error_log( __METHOD__ . ': ' . $e->getMessage() ); } return $instructor; } /** - * @param LP_User $instructor + * @param UserModel $instructor * * @return false|string */ - public function info( LP_User $instructor ): string { + public function info( UserModel $instructor ): string { $html_cover = ''; ob_start(); - $userModel = UserModel::find( $instructor->get_id(), true ); - // Display cover image - echo ProfileTemplate::instance()->html_cover_image( $userModel ); + $userModel = UserModel::find( $instructor->get_id(), true ); + // Display cover image + echo ProfileTemplate::instance()->html_cover_image( $userModel ); $html_cover = ob_get_clean(); $sections = apply_filters( @@ -365,7 +362,7 @@ public function info( LP_User $instructor ): string { return Template::combine_components( $sections ); } - public function info_right( LP_User $instructor ): string { + public function info_right( UserModel $instructor ): string { $section_instructor_meta = [ 'wrapper' => '
    ', @@ -398,7 +395,7 @@ public function info_right( LP_User $instructor ): string { return Template::combine_components( $sections ); } - public function section_list_courses( LP_User $instructor ): string { + public function section_list_courses( UserModel $instructor ): string { $content = ''; try { diff --git a/inc/admin/views/meta-boxes/course/settings.php b/inc/admin/views/meta-boxes/course/settings.php index 1077cb9dc..80c7d2d83 100644 --- a/inc/admin/views/meta-boxes/course/settings.php +++ b/inc/admin/views/meta-boxes/course/settings.php @@ -347,7 +347,7 @@ public function lp_price( $post_id ): array { 'min' => '0', 'step' => '0.01', ), - 'style' => 'width: 100px;', + 'style' => 'width: 150px;', 'class' => 'lp_meta_box_regular_price', 'dependency' => [ 'name' => '_lp_no_required_enroll', @@ -365,7 +365,7 @@ public function lp_price( $post_id ): array { 'min' => '0', 'step' => '0.01', ), - 'style' => 'width: 100px;', + 'style' => 'width: 150px;', 'class' => 'lp_meta_box_sale_price', 'dependency' => [ 'name' => '_lp_no_required_enroll', From 0ca771b7bd3f65359f9251bf92cc77058a02eca3 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 24 Dec 2024 15:20:36 +0700 Subject: [PATCH 021/225] = 4.2.7.6 = ~ Added: url edit avatar. --- .../Instructor/SingleInstructorTemplate.php | 17 ++++------------- inc/TemplateHooks/UserTemplate.php | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php index 5028caa8d..5f25d310d 100644 --- a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php +++ b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php @@ -336,22 +336,13 @@ public function detect_instructor_by_page() { * @return false|string */ public function info( UserModel $instructor ): string { - - $html_cover = ''; - - ob_start(); - $userModel = UserModel::find( $instructor->get_id(), true ); - // Display cover image - echo ProfileTemplate::instance()->html_cover_image( $userModel ); - $html_cover = ob_get_clean(); - $sections = apply_filters( 'learn-press/single-instructor/info/sections', [ 'wrapper' => '
    ', - 'cover_img' => $html_cover, + 'cover_img' => ProfileTemplate::instance()->html_cover_image( $instructor ), 'wrapper_content' => '
    ', - 'image' => $this->html_avatar( $instructor ), + 'avatar' => $this->html_avatar( $instructor ), 'info_right' => $this->info_right( $instructor ), 'wrapper_content_end' => '
    ', 'wrapper_end' => '
    ', @@ -382,7 +373,7 @@ public function info_right( UserModel $instructor ): string { [ 'wrapper' => '
    ', 'wrapper_content' => '
    ', - 'title' => sprintf( '

    %s

    ', $this->html_display_name( $instructor ) ) , + 'title' => sprintf( '

    %s

    ', $this->html_display_name( $instructor ) ), 'meta' => Template::combine_components( $section_instructor_meta ), 'description' => $this->html_description( $instructor ), 'wrapper_content_end' => '
    ', @@ -445,7 +436,7 @@ public function list_courses( $instructor, $courses ): string { // List courses ob_start(); foreach ( $courses as $course_obj ) { - $course = LP_Course::get_course( $course_obj->ID ); + $course = CourseModel::find( $course_obj->ID, true ); echo ListCoursesTemplate::render_course( $course ); } $html_ul_wrapper = ob_get_clean(); diff --git a/inc/TemplateHooks/UserTemplate.php b/inc/TemplateHooks/UserTemplate.php index d10f1fce8..f7e93fba5 100644 --- a/inc/TemplateHooks/UserTemplate.php +++ b/inc/TemplateHooks/UserTemplate.php @@ -16,6 +16,7 @@ use LearnPress\TemplateHooks\Course\SingleCourseTemplate; use LP_Course; use LP_Course_Filter; +use LP_Profile; use LP_User; use Throwable; use WP_Query; @@ -35,7 +36,7 @@ public function init() { * * @return string * @since 4.2.7.2 - * @version 1.0.3 + * @version 1.0.4 */ public function html_avatar( UserModel $user, array $size_display = [], string $class_name = 'user' ): string { $html = ''; @@ -45,6 +46,7 @@ public function html_avatar( UserModel $user, array $size_display = [], string $ $size_display = learn_press_get_avatar_thumb_size(); } + $profile = LP_Profile::instance( $user->get_id() ); $width = $size_display; $height = $size_display; if ( is_array( $size_display ) ) { @@ -61,11 +63,22 @@ public function html_avatar( UserModel $user, array $size_display = [], string $ $height ); + $html_btn_to_edit_avatar = ''; + if ( $user->get_id() === get_current_user_id() ) { + $html_btn_to_edit_avatar = sprintf( + '+ %s', + $profile->get_tab_link( 'settings', 'avatar' ), + 'avatar', + __( 'edit avatar', 'learnpress' ) + ); + } + $section = apply_filters( 'learn-press/user/html-avatar', [ 'wrapper' => sprintf( '
    ', $class_name ), 'avatar' => $img_avatar, + 'btn_to_edit' => $html_btn_to_edit_avatar, 'wrapper_end' => '
    ', ], $user From 886de2903f3212bf5984c056479345acbc018f5e Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 24 Dec 2024 15:31:14 +0700 Subject: [PATCH 022/225] = 4.2.7.6 = --- inc/TemplateHooks/Instructor/SingleInstructorTemplate.php | 1 - inc/TemplateHooks/Profile/ProfileTemplate.php | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php index 5f25d310d..f4dde5b9c 100644 --- a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php +++ b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php @@ -296,7 +296,6 @@ public function sections( array $data = [] ) { echo Template::combine_components( $sections ); } catch ( Throwable $e ) { - ob_end_clean(); error_log( __METHOD__ . ': ' . $e->getMessage() ); } } diff --git a/inc/TemplateHooks/Profile/ProfileTemplate.php b/inc/TemplateHooks/Profile/ProfileTemplate.php index b6b6b92d8..6e2ffb912 100644 --- a/inc/TemplateHooks/Profile/ProfileTemplate.php +++ b/inc/TemplateHooks/Profile/ProfileTemplate.php @@ -34,17 +34,17 @@ public function init() { * @return string * @return string * @since 4.2.7.2 - * @version 1.0.0 + * @version 1.0.1 */ public function html_cover_image( UserModel $user ): string { $html = ''; try { $cover_image_url = $user->get_cover_image_url(); - $profile = LP_Profile::instance(); - $current_section = LP_Profile::instance()->get_current_section(); + $profile = LP_Profile::instance( $user->get_id() ); + $current_section = $profile->get_current_section(); $html_btn_to_edit_cover_image = ''; - $cover_image_dimensions = LP_Settings::get_option( + $cover_image_dimensions = LP_Settings::get_option( 'cover_image_dimensions', array( 'width' => 1290, From 9262821f361e56397615d9f70a4c907ba7d02289 Mon Sep 17 00:00:00 2001 From: truongpn Date: Tue, 24 Dec 2024 15:38:03 +0700 Subject: [PATCH 023/225] style edit avatar --- assets/src/scss/frontend/_instructor.scss | 42 +++++++++++++++++++ .../src/scss/frontend/_user_cover_image.scss | 12 ++++++ 2 files changed, 54 insertions(+) diff --git a/assets/src/scss/frontend/_instructor.scss b/assets/src/scss/frontend/_instructor.scss index 71da13903..6ec74e798 100644 --- a/assets/src/scss/frontend/_instructor.scss +++ b/assets/src/scss/frontend/_instructor.scss @@ -300,4 +300,46 @@ body { } } } + + .instructor-avatar { + position: relative; + + &:hover { + .lp-btn-to-edit-avatar { + opacity: 1; + visibility: visible; + } + } + + .lp-btn-to-edit-avatar { + position: absolute; + bottom: 0; + right: 0; + left: auto; + width: 36px; + height: 36px; + font-size: 0; + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + visibility: hidden; + cursor: pointer; + background-color: var(--lp-white-grey, #F7F7FB); + border-radius: 50%; + + @media (max-width: 767px) { + opacity: 1; + visibility: visible; + } + + &::before { + content: "\f044"; + font-size: 1.5rem; + font-family: "lp-icon"; + font-weight: normal; + color: var(--lp-primary-color); + } + } + } } diff --git a/assets/src/scss/frontend/_user_cover_image.scss b/assets/src/scss/frontend/_user_cover_image.scss index 0f828d3ac..bc82059f0 100644 --- a/assets/src/scss/frontend/_user_cover_image.scss +++ b/assets/src/scss/frontend/_user_cover_image.scss @@ -6,6 +6,13 @@ .lp-user-cover-image_background { position: relative; + &:hover { + .lp-btn-to-edit-cover-image { + opacity: 1; + visibility: visible; + } + } + .lp-btn-to-edit-cover-image { position: absolute; bottom: 0; @@ -17,9 +24,14 @@ cursor: pointer; color: $color-primary; text-decoration: none; + opacity: 0; + visibility: hidden; + @media (max-width: 767px) { font-size: 0; padding: 4px 12px; + opacity: 1; + visibility: visible; &:before{ font-family: 'lp-icon'; content: "\f044"; From 0b79ab89f5dfb0ef1ffa0dcc32e6e0bbf45bdec9 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 24 Dec 2024 15:43:52 +0700 Subject: [PATCH 024/225] = 4.2.7.6 = --- .../Widgets/Instructor/SingleInstructorBaseElementor.php | 4 ++-- inc/TemplateHooks/Instructor/SingleInstructorTemplate.php | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/inc/ExternalPlugin/Elementor/Widgets/Instructor/SingleInstructorBaseElementor.php b/inc/ExternalPlugin/Elementor/Widgets/Instructor/SingleInstructorBaseElementor.php index 01627d1dd..d24201fc2 100644 --- a/inc/ExternalPlugin/Elementor/Widgets/Instructor/SingleInstructorBaseElementor.php +++ b/inc/ExternalPlugin/Elementor/Widgets/Instructor/SingleInstructorBaseElementor.php @@ -50,8 +50,8 @@ protected function detect_instructor_id( array $settings, &$instructor = null, s */ $instructor = SingleInstructorTemplate::instance()->detect_instructor_by_page(); if ( ! $instructor instanceof UserModel ) { - $instructor_id = $settings['instructor_id'] ?? 0; - $instructor = UserModel::find( $instructor_id, true ); + $instructor_id = (int) $settings['instructor_id'] ?? 0; + $instructor = UserModel::find( $instructor_id, true ); } if ( ! $instructor ) { diff --git a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php index f4dde5b9c..5f5eedcd7 100644 --- a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php +++ b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php @@ -86,11 +86,18 @@ public function html_social( $instructor ): string { * @param LP_User|UserModel $instructor * * @return string + * @since 4.2.3.4 + * @version 1.0.0 */ public function html_description( $instructor ): string { $content = ''; try { + $description = $instructor->get_description(); + if ( empty( $description ) ) { + return $content; + } + $sections = [ 'wrapper' => '
    ', 'content' => $instructor->get_description(), From d4c4c8f4d70d461f41038e7a26e88fd76f63116b Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 24 Dec 2024 16:04:32 +0700 Subject: [PATCH 025/225] = 4.2.7.6 = ~ Tweak: display avatar on Profile. --- .../Instructor/SingleInstructorTemplate.php | 2 +- inc/TemplateHooks/UserTemplate.php | 4 ++-- inc/templates/class-lp-template-profile.php | 19 ++++++++++++++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php index 5f5eedcd7..e661252c1 100644 --- a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php +++ b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php @@ -278,7 +278,7 @@ public function sections( array $data = [] ) { try { if ( isset( $data['instructor_id'] ) ) { - $instructor_id = $data['instructor_id']; + $instructor_id = (int) $data['instructor_id']; $instructor = UserModel::find( $instructor_id, true ); } else { $instructor = $this->detect_instructor_by_page(); diff --git a/inc/TemplateHooks/UserTemplate.php b/inc/TemplateHooks/UserTemplate.php index f7e93fba5..19105e757 100644 --- a/inc/TemplateHooks/UserTemplate.php +++ b/inc/TemplateHooks/UserTemplate.php @@ -47,8 +47,8 @@ public function html_avatar( UserModel $user, array $size_display = [], string $ } $profile = LP_Profile::instance( $user->get_id() ); - $width = $size_display; - $height = $size_display; + $width = $size_display; + $height = $size_display; if ( is_array( $size_display ) ) { $width = $size_display['width']; $height = $size_display['height']; diff --git a/inc/templates/class-lp-template-profile.php b/inc/templates/class-lp-template-profile.php index 17583b439..b827a74fa 100644 --- a/inc/templates/class-lp-template-profile.php +++ b/inc/templates/class-lp-template-profile.php @@ -2,7 +2,9 @@ use LearnPress\Helpers\Template; use LearnPress\Models\UserModel; +use LearnPress\TemplateHooks\Instructor\SingleInstructorTemplate; use LearnPress\TemplateHooks\Profile\ProfileTemplate; +use LearnPress\TemplateHooks\UserTemplate; /** * Class LP_Profile_Template @@ -60,8 +62,23 @@ public function content( LP_Profile $profile ) { learn_press_get_template( 'profile/content.php', compact( 'user', 'profile_tab', 'tab_key', 'profile' ) ); } + /** + * Display avatar + * + * @since 3.x.x + * @version 1.0.1 + * @return void + */ public function avatar() { - learn_press_get_template( 'profile/avatar.php' ); + $lp_profile = LP_Profile::instance(); + $user = $lp_profile->get_user(); + $userModel = UserModel::find( $user->get_id(), true ); + if ( ! $userModel instanceof UserModel ) { + return; + } + + echo UserTemplate::instance()->html_avatar( $userModel ); + //learn_press_get_template( 'profile/avatar.php' ); } public function socials() { From a7ac35629c4418056555c04024342003712d50de Mon Sep 17 00:00:00 2001 From: truongpn Date: Tue, 24 Dec 2024 16:10:55 +0700 Subject: [PATCH 026/225] style edit avatar --- assets/src/scss/frontend/_instructor.scss | 13 +++--- assets/src/scss/frontend/_profile.scss | 46 +++++++++++++++++++ .../Instructor/SingleInstructorTemplate.php | 4 +- 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/assets/src/scss/frontend/_instructor.scss b/assets/src/scss/frontend/_instructor.scss index 6ec74e798..5aeed2659 100644 --- a/assets/src/scss/frontend/_instructor.scss +++ b/assets/src/scss/frontend/_instructor.scss @@ -56,7 +56,6 @@ body { &__wrapper { display: flex; - align-items: center; gap: 24px; } @@ -70,14 +69,14 @@ body { &__right { flex: 1; display: flex; - align-items: center; - justify-content: space-between; - gap: 20px; + flex-direction: column;; + gap: 8px; &__content { display: flex; - flex-direction: column; - row-gap: 8px; + align-items: center; + justify-content: space-between; + gap: 20px; } .instructor-description:empty { @@ -313,7 +312,7 @@ body { .lp-btn-to-edit-avatar { position: absolute; - bottom: 0; + top: 80px; right: 0; left: auto; width: 36px; diff --git a/assets/src/scss/frontend/_profile.scss b/assets/src/scss/frontend/_profile.scss index 5f08004be..6ce0de347 100644 --- a/assets/src/scss/frontend/_profile.scss +++ b/assets/src/scss/frontend/_profile.scss @@ -44,6 +44,52 @@ .lp-profile-left { min-width: 120px; max-width: 120px; + + .user-avatar { + position: relative; + + img { + border-radius: 50%; + } + + &:hover { + .lp-btn-to-edit-avatar { + opacity: 1; + visibility: visible; + } + } + + .lp-btn-to-edit-avatar { + position: absolute; + top: 80px; + right: 0; + left: auto; + width: 36px; + height: 36px; + font-size: 0; + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + visibility: hidden; + cursor: pointer; + background-color: var(--lp-white-grey, #F7F7FB); + border-radius: 50%; + + @media (max-width: 767px) { + opacity: 1; + visibility: visible; + } + + &::before { + content: "\f044"; + font-size: 1.5rem; + font-family: "lp-icon"; + font-weight: normal; + color: var(--lp-primary-color); + } + } + } } .lp-profile-right { diff --git a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php index e661252c1..80ccfddf0 100644 --- a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php +++ b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php @@ -380,10 +380,10 @@ public function info_right( UserModel $instructor ): string { 'wrapper' => '
    ', 'wrapper_content' => '
    ', 'title' => sprintf( '

    %s

    ', $this->html_display_name( $instructor ) ), + 'social' => $this->html_social( $instructor ), + 'wrapper_content_end' => '
    ', 'meta' => Template::combine_components( $section_instructor_meta ), 'description' => $this->html_description( $instructor ), - 'wrapper_content_end' => '
    ', - 'social' => $this->html_social( $instructor ), 'wrapper_end' => '
    ', ], $instructor From 59d442f2d0bed2526c9bda525196486cb407924f Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 24 Dec 2024 16:17:27 +0700 Subject: [PATCH 027/225] = 4.2.7.6 = --- .../Instructor/SingleInstructorTemplate.php | 4 +- .../class-lp-rest-instructor-controller.php | 3 +- inc/templates/class-lp-template-profile.php | 85 ++----------------- 3 files changed, 9 insertions(+), 83 deletions(-) diff --git a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php index 80ccfddf0..2668c6bd4 100644 --- a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php +++ b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php @@ -208,13 +208,13 @@ public function html_count_students( $instructor ): string { /** * Get button view instructor. * - * @param LP_User $instructor + * @param LP_User|UserModel|false $instructor * * @return string * @version 1.0.0 * @since 4.2.3 */ - public function html_button_view( LP_User $instructor ): string { + public function html_button_view( $instructor ): string { $btn_view = ''; try { diff --git a/inc/rest-api/v1/frontend/class-lp-rest-instructor-controller.php b/inc/rest-api/v1/frontend/class-lp-rest-instructor-controller.php index 65f28b684..89bbe6796 100644 --- a/inc/rest-api/v1/frontend/class-lp-rest-instructor-controller.php +++ b/inc/rest-api/v1/frontend/class-lp-rest-instructor-controller.php @@ -1,6 +1,7 @@ ID ); + $instructor = UserModel::find( $instructor_obj->ID, true ); echo $instructors_template->instructor_item( $instructor ); } diff --git a/inc/templates/class-lp-template-profile.php b/inc/templates/class-lp-template-profile.php index b827a74fa..8b860b55f 100644 --- a/inc/templates/class-lp-template-profile.php +++ b/inc/templates/class-lp-template-profile.php @@ -25,7 +25,7 @@ public function sidebar() { } if ( $profile->get_user_current()->is_guest() - && 'yes' !== LP_Profile::get_option_publish_profile() ) { + && 'yes' !== LP_Profile::get_option_publish_profile() ) { return; } @@ -65,14 +65,14 @@ public function content( LP_Profile $profile ) { /** * Display avatar * - * @since 3.x.x - * @version 1.0.1 * @return void + * @version 1.0.1 + * @since 3.x.x */ public function avatar() { $lp_profile = LP_Profile::instance(); - $user = $lp_profile->get_user(); - $userModel = UserModel::find( $user->get_id(), true ); + $user = $lp_profile->get_user(); + $userModel = UserModel::find( $user->get_id(), true ); if ( ! $userModel instanceof UserModel ) { return; } @@ -212,69 +212,6 @@ public static function tab_cover_image() { echo ProfileTemplate::instance()->html_upload_cover_image( $userModel ); } - /** - * @deprecated 4.2.6.2 - */ - public function dashboard_featured_courses() { - _deprecated_function( __METHOD__, '4.2.6.2' ); - die; - $profile_privacy = $this->get_user()->get_extra_data( - 'profile_privacy', - array( - 'courses' => 'no', - 'quizzes' => 'no', - ) - ); - - if ( $this->get_user()->get_id() !== get_current_user_id() && 'yes' !== $profile_privacy['courses'] ) { - return; - } - - $user = $this->get_user(); - $query = new LP_Course_Query( - array( - 'paginate' => true, - 'featured' => 'yes', - 'return' => 'ids', - 'author' => $user->get_id(), - ) - ); - - $data = $query->get_courses(); - - learn_press_get_template( 'profile/dashboard/featured-courses', (array) $data ); - } - - /** - * @deprecated 4.2.6.2 - */ - public function dashboard_latest_courses() { - _deprecated_function( __METHOD__, '4.2.6.2' ); - die; - $profile_privacy = $this->get_user()->get_extra_data( - 'profile_privacy', - array( - 'courses' => 'no', - 'quizzes' => 'no', - ) - ); - - if ( $this->get_user()->get_id() !== get_current_user_id() && 'yes' !== $profile_privacy['courses'] ) { - return; - } - - $user = $this->get_user(); - $query = new LP_Course_Query( - array( - 'paginate' => true, - 'return' => 'ids', - 'author' => $user->get_id(), - ) - ); - - learn_press_get_template( 'profile/dashboard/latest-courses', (array) $query->get_courses() ); - } - public function order_details() { $profile = LP_Profile::instance(); $order = $profile->get_view_order(); @@ -354,18 +291,6 @@ public function register_form() { learn_press_get_template( 'global/form-register.php' ); } - - /** - * @return bool|LP_User|mixed - * @deprecated 4.2.6.4 - */ - protected function get_user() { - _deprecated_function( __METHOD__, '4.2.6.4' ); - - return false; - - return LP_Profile::instance()->get_user(); - } } return new LP_Template_Profile(); From ca8c14f7dc27abf331fa84463e51d7520bc44f88 Mon Sep 17 00:00:00 2001 From: truongpn Date: Tue, 24 Dec 2024 16:19:38 +0700 Subject: [PATCH 028/225] style edit avatar --- assets/src/scss/frontend/_instructor.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/src/scss/frontend/_instructor.scss b/assets/src/scss/frontend/_instructor.scss index 5aeed2659..8c9447d7f 100644 --- a/assets/src/scss/frontend/_instructor.scss +++ b/assets/src/scss/frontend/_instructor.scss @@ -69,7 +69,7 @@ body { &__right { flex: 1; display: flex; - flex-direction: column;; + flex-direction: column; gap: 8px; &__content { From 2456934eb4ebce8303858ce282e2bc0c8fccd4c2 Mon Sep 17 00:00:00 2001 From: truongpn Date: Tue, 24 Dec 2024 16:23:45 +0700 Subject: [PATCH 029/225] style edit avatar --- assets/src/scss/frontend/_instructor.scss | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/assets/src/scss/frontend/_instructor.scss b/assets/src/scss/frontend/_instructor.scss index 8c9447d7f..02e50cb4a 100644 --- a/assets/src/scss/frontend/_instructor.scss +++ b/assets/src/scss/frontend/_instructor.scss @@ -76,7 +76,9 @@ body { display: flex; align-items: center; justify-content: space-between; - gap: 20px; + column-gap: 20px; + row-gap: 8px; + flex-wrap: wrap; } .instructor-description:empty { @@ -112,6 +114,7 @@ body { .lp-instructor-meta { display: flex; column-gap: 20px; + row-gap: 8px; .instructor-item-meta { display: inline-flex; From 13d76619d6380786f5db30e85b72babacef7ac11 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 24 Dec 2024 16:25:58 +0700 Subject: [PATCH 030/225] = 4.2.7.6 = --- .../Instructor/ListInstructorsTemplate.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/inc/TemplateHooks/Instructor/ListInstructorsTemplate.php b/inc/TemplateHooks/Instructor/ListInstructorsTemplate.php index 3a239c303..6a7e79879 100644 --- a/inc/TemplateHooks/Instructor/ListInstructorsTemplate.php +++ b/inc/TemplateHooks/Instructor/ListInstructorsTemplate.php @@ -3,12 +3,13 @@ * Template hooks List Instructors. * * @since 4.2.3 - * @version 1.0.0 + * @version 1.0.1 */ namespace LearnPress\TemplateHooks\Instructor; use LearnPress\Helpers\Template; +use LearnPress\Models\UserModel; use LP_Assets; use LP_Helper; use LP_Page_Controller; @@ -103,11 +104,11 @@ public function sections( array $data = [] ) { /** * Get instructor item. * - * @param LP_User $instructor + * @param UserModel $instructor * * @return false|string */ - public function instructor_item( LP_User $instructor ) { + public function instructor_item( $instructor ) { $content = ''; $html_wrapper = apply_filters( 'learn-press/list-instructors/instructor_item/wrapper', @@ -146,13 +147,13 @@ public function instructor_item( LP_User $instructor ) { /** * Get instructor info: total courses, total students. * - * @param LP_User $instructor + * @param UserModel $instructor * * @return false|string - * @version 1.0.0 + * @version 1.0.1 * @since 4.2.3 */ - public function instructor_item_info( LP_User $instructor ) { + public function instructor_item_info( $instructor ) { $content = ''; $html_wrapper = apply_filters( 'learn-press/list-instructors/instructor_item/info/wrapper', From ea972910c41dc6e70a98063dc7c5b491eaee7e4b Mon Sep 17 00:00:00 2001 From: truongpn Date: Tue, 24 Dec 2024 16:26:43 +0700 Subject: [PATCH 031/225] style edit avatar --- assets/src/scss/frontend/_instructor.scss | 5 +++++ assets/src/scss/frontend/_profile.scss | 1 + 2 files changed, 6 insertions(+) diff --git a/assets/src/scss/frontend/_instructor.scss b/assets/src/scss/frontend/_instructor.scss index 02e50cb4a..90d043179 100644 --- a/assets/src/scss/frontend/_instructor.scss +++ b/assets/src/scss/frontend/_instructor.scss @@ -63,6 +63,10 @@ body { img { max-width: 120px; border-radius: 50%; + + @media (max-width: 767px) { + max-width: 100px; + } } } @@ -332,6 +336,7 @@ body { @media (max-width: 767px) { opacity: 1; + top: 60px; visibility: visible; } diff --git a/assets/src/scss/frontend/_profile.scss b/assets/src/scss/frontend/_profile.scss index 6ce0de347..427c4c301 100644 --- a/assets/src/scss/frontend/_profile.scss +++ b/assets/src/scss/frontend/_profile.scss @@ -78,6 +78,7 @@ @media (max-width: 767px) { opacity: 1; + top: 60px; visibility: visible; } From 2ecec72b752e41311ff3e913155b2c1afe03bbeb Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 24 Dec 2024 16:45:21 +0700 Subject: [PATCH 032/225] = 4.2.7.6 = --- inc/TemplateHooks/UserTemplate.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/inc/TemplateHooks/UserTemplate.php b/inc/TemplateHooks/UserTemplate.php index 19105e757..fa831e635 100644 --- a/inc/TemplateHooks/UserTemplate.php +++ b/inc/TemplateHooks/UserTemplate.php @@ -66,9 +66,10 @@ public function html_avatar( UserModel $user, array $size_display = [], string $ $html_btn_to_edit_avatar = ''; if ( $user->get_id() === get_current_user_id() ) { $html_btn_to_edit_avatar = sprintf( - '+ %s', + '+ %s', $profile->get_tab_link( 'settings', 'avatar' ), 'avatar', + esc_attr__( 'Edit avatar', 'learnpress' ), __( 'edit avatar', 'learnpress' ) ); } From becceb319ee01b051ce71ca346c466ac15d37038 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 24 Dec 2024 17:13:16 +0700 Subject: [PATCH 033/225] = 4.2.7.6 = ~ Tweak: SingleInstructorTemplate class. --- .../Instructor/SingleInstructorTemplate.php | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php index 2668c6bd4..4b8bb9c86 100644 --- a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php +++ b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php @@ -3,7 +3,7 @@ * Template hooks Single Instructor. * * @since 4.2.3 - * @version 1.0.0 + * @version 1.0.1 */ namespace LearnPress\TemplateHooks\Instructor; @@ -13,15 +13,13 @@ use LearnPress\Models\CourseModel; use LearnPress\Models\Courses; use LearnPress\Models\UserModel; -use LearnPress\TemplateHooks\Course\SingleCourseTemplate; use LearnPress\TemplateHooks\Profile\ProfileTemplate; use LearnPress\TemplateHooks\Course\ListCoursesTemplate; use LearnPress\TemplateHooks\UserTemplate; -use LP_Course; use LP_Course_Filter; +use LP_Settings; use LP_User; use Throwable; -use WP_Query; class SingleInstructorTemplate { use Singleton; @@ -60,15 +58,13 @@ public function html_social( $instructor ): string { try { $socials = $instructor->get_profile_social( $instructor->get_id() ); - ob_start(); - foreach ( $socials as $k => $social ) { - echo $social; + if ( empty( $socials ) ) { + return $content; } - $content = ob_get_clean(); $sections = [ 'wrapper' => '
    ', - 'content' => $content, + 'content' => Template::combine_components( $socials ), 'wrapper_end' => '
    ', ]; @@ -400,7 +396,7 @@ public function section_list_courses( UserModel $instructor ): string { $filter = new LP_Course_Filter(); Courses::handle_params_for_query_courses( $filter, [] ); $filter->post_author = $instructor->get_id(); - $filter->limit = \LP_Settings::get_option( 'archive_course_limit', 20 ); + $filter->limit = LP_Settings::get_option( 'archive_course_limit', 20 ); $filter->page = $GLOBALS['wp_query']->get( 'paged', 1 ) ? $GLOBALS['wp_query']->get( 'paged', 1 ) : 1; // $filter = apply_filters( 'lp/single-instructor/courses/query/filter', $filter, [] ); @@ -447,16 +443,11 @@ public function list_courses( $instructor, $courses ): string { } $html_ul_wrapper = ob_get_clean(); - $sections = apply_filters( - 'learn-press/single-instructor/courses/sections', - [ - 'wrapper' => '
      ', - 'list_course' => $html_ul_wrapper, - 'wrapper_end' => '
    ', - ], - $courses, - $instructor - ); + $sections = [ + 'wrapper' => '
      ', + 'list_course' => $html_ul_wrapper, + 'wrapper_end' => '
    ', + ]; $content = Template::combine_components( $sections ); } catch ( Throwable $e ) { From da6713554a6ea072d45a31e0d79e0f908fc92cef Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 24 Dec 2024 17:17:00 +0700 Subject: [PATCH 034/225] = 4.2.7.6 = --- .../Instructor/SingleInstructorTemplate.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php index 4b8bb9c86..cf77d4cbe 100644 --- a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php +++ b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php @@ -435,17 +435,16 @@ public function list_courses( $instructor, $courses ): string { $content = ''; try { - // List courses - ob_start(); + // Li list courses + $html_li_item_course = ''; foreach ( $courses as $course_obj ) { - $course = CourseModel::find( $course_obj->ID, true ); - echo ListCoursesTemplate::render_course( $course ); + $course = CourseModel::find( $course_obj->ID, true ); + $html_li_item_course .= ListCoursesTemplate::render_course( $course ); } - $html_ul_wrapper = ob_get_clean(); $sections = [ 'wrapper' => '
      ', - 'list_course' => $html_ul_wrapper, + 'list_course' => $html_li_item_course, 'wrapper_end' => '
    ', ]; From 08ff6c61a9c82d64ca1149f3ce12f02a78da6e0d Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 24 Dec 2024 17:30:33 +0700 Subject: [PATCH 035/225] = 4.2.7.6 = --- inc/Helpers/Template.php | 25 +++++++++++++------ .../Instructor/SingleInstructorTemplate.php | 14 ++++++++++- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/inc/Helpers/Template.php b/inc/Helpers/Template.php index 6c5ebe749..0f034c0aa 100644 --- a/inc/Helpers/Template.php +++ b/inc/Helpers/Template.php @@ -22,13 +22,13 @@ protected function __construct() { * Set 1 for include file, 0 for not * Set 1 for separate template is block, 0 for not | use "wp_is_block_theme" function * - * @param bool $include + * @param bool $has_include * * @return self */ - public static function instance( bool $include = true ): Template { + public static function instance( bool $has_include = true ): Template { $self = new self(); - $self->include = $include; + $self->include = $has_include; return $self; } @@ -303,14 +303,19 @@ public static function insert_value_to_position_array( $old_array, $position, $k * * @param string $message * @param string $status 'success', 'warning', 'error, 'info' + * @param bool $print_mess since 4.2.7.6 * - * @return void + * @return void|string * @since 4.2.6.9.3 - * @version 1.0.1 + * @version 1.0.2 */ - public static function print_message( string $message, string $status = 'success' ) { + public static function print_message( string $message, string $status = 'success', bool $has_print = true ) { if ( empty( $message ) ) { - return; + if ( $has_print ) { + return; + } else { + return ''; + } } $section = [ @@ -319,6 +324,10 @@ public static function print_message( string $message, string $status = 'success 'wrapper_end' => '
    ', ]; - echo Template::combine_components( $section ); + if ( $has_print ) { + echo Template::combine_components( $section ); + } else { + return Template::combine_components( $section ); + } } } diff --git a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php index cf77d4cbe..9985cef3e 100644 --- a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php +++ b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php @@ -402,12 +402,24 @@ public function section_list_courses( UserModel $instructor ): string { $total_courses = 0; $courses = Courses::get_courses( $filter, $total_courses ); + if ( ! empty( $courses ) ) { + $html_courses = $this->list_courses( $instructor, $courses ); + } else { + $html_courses = Template::print_message( + sprintf( + __( '%s does not have any courses', 'learnpress' ), + $instructor->get_display_name() + ), + 'info', + false + ); + } $sections = apply_filters( 'learn-press/single-instructor/courses/sections', [ 'wrapper' => '
    ', - 'courses' => $this->list_courses( $instructor, $courses ), + 'courses' => $html_courses, 'pagination' => $this->courses_pagination( $filter->page, $filter->limit, $total_courses ), 'wrapper_end' => '
    ', ], From 9fdedb278717e87786997b03ffc0a0e78e04d6e5 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 24 Dec 2024 18:16:05 +0700 Subject: [PATCH 036/225] = 4.2.7.6 = --- .../Instructor/SingleInstructorTemplate.php | 22 ++++++++++++++++++- inc/TemplateHooks/UserTemplate.php | 12 ---------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php index 9985cef3e..371a43aca 100644 --- a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php +++ b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php @@ -17,6 +17,7 @@ use LearnPress\TemplateHooks\Course\ListCoursesTemplate; use LearnPress\TemplateHooks\UserTemplate; use LP_Course_Filter; +use LP_Profile; use LP_Settings; use LP_User; use Throwable; @@ -338,13 +339,32 @@ public function detect_instructor_by_page() { * @return false|string */ public function info( UserModel $instructor ): string { + $profile = LP_Profile::instance( $instructor->get_id() ); + $html_btn_to_edit_avatar = ''; + if ( $instructor->get_id() === get_current_user_id() ) { + $html_btn_to_edit_avatar = sprintf( + '+ %s', + $profile->get_tab_link( 'settings', 'avatar' ), + 'avatar', + esc_attr__( 'Edit avatar', 'learnpress' ), + __( 'edit avatar', 'learnpress' ) + ); + } + + $html_avatar = [ + 'start' => '
    ', + 'avatar' => $this->html_avatar( $instructor ), + 'btn_edit' => $html_btn_to_edit_avatar, + 'end' => '
    ', + ]; + $sections = apply_filters( 'learn-press/single-instructor/info/sections', [ 'wrapper' => '
    ', 'cover_img' => ProfileTemplate::instance()->html_cover_image( $instructor ), 'wrapper_content' => '
    ', - 'avatar' => $this->html_avatar( $instructor ), + 'avatar' => Template::combine_components( $html_avatar ), 'info_right' => $this->info_right( $instructor ), 'wrapper_content_end' => '
    ', 'wrapper_end' => '
    ', diff --git a/inc/TemplateHooks/UserTemplate.php b/inc/TemplateHooks/UserTemplate.php index fa831e635..2fa4514fb 100644 --- a/inc/TemplateHooks/UserTemplate.php +++ b/inc/TemplateHooks/UserTemplate.php @@ -63,23 +63,11 @@ public function html_avatar( UserModel $user, array $size_display = [], string $ $height ); - $html_btn_to_edit_avatar = ''; - if ( $user->get_id() === get_current_user_id() ) { - $html_btn_to_edit_avatar = sprintf( - '+ %s', - $profile->get_tab_link( 'settings', 'avatar' ), - 'avatar', - esc_attr__( 'Edit avatar', 'learnpress' ), - __( 'edit avatar', 'learnpress' ) - ); - } - $section = apply_filters( 'learn-press/user/html-avatar', [ 'wrapper' => sprintf( '
    ', $class_name ), 'avatar' => $img_avatar, - 'btn_to_edit' => $html_btn_to_edit_avatar, 'wrapper_end' => '
    ', ], $user From d557274bc75c220cb010a68419440df6f8526731 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 24 Dec 2024 18:36:27 +0700 Subject: [PATCH 037/225] = 4.2.7.6 = ~ Added: html_avatar_edit method. --- .../Instructor/SingleInstructorTemplate.php | 21 +----- inc/TemplateHooks/UserTemplate.php | 68 ++++++++++++++++++- inc/templates/class-lp-template-profile.php | 2 +- 3 files changed, 69 insertions(+), 22 deletions(-) diff --git a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php index 371a43aca..0060525fb 100644 --- a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php +++ b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php @@ -339,32 +339,13 @@ public function detect_instructor_by_page() { * @return false|string */ public function info( UserModel $instructor ): string { - $profile = LP_Profile::instance( $instructor->get_id() ); - $html_btn_to_edit_avatar = ''; - if ( $instructor->get_id() === get_current_user_id() ) { - $html_btn_to_edit_avatar = sprintf( - '+ %s', - $profile->get_tab_link( 'settings', 'avatar' ), - 'avatar', - esc_attr__( 'Edit avatar', 'learnpress' ), - __( 'edit avatar', 'learnpress' ) - ); - } - - $html_avatar = [ - 'start' => '
    ', - 'avatar' => $this->html_avatar( $instructor ), - 'btn_edit' => $html_btn_to_edit_avatar, - 'end' => '
    ', - ]; - $sections = apply_filters( 'learn-press/single-instructor/info/sections', [ 'wrapper' => '
    ', 'cover_img' => ProfileTemplate::instance()->html_cover_image( $instructor ), 'wrapper_content' => '
    ', - 'avatar' => Template::combine_components( $html_avatar ), + 'avatar' => UserTemplate::instance()->html_avatar_edit( $instructor, [], 'instructor' ), 'info_right' => $this->info_right( $instructor ), 'wrapper_content_end' => '
    ', 'wrapper_end' => '
    ', diff --git a/inc/TemplateHooks/UserTemplate.php b/inc/TemplateHooks/UserTemplate.php index 2fa4514fb..c36f47484 100644 --- a/inc/TemplateHooks/UserTemplate.php +++ b/inc/TemplateHooks/UserTemplate.php @@ -46,7 +46,6 @@ public function html_avatar( UserModel $user, array $size_display = [], string $ $size_display = learn_press_get_avatar_thumb_size(); } - $profile = LP_Profile::instance( $user->get_id() ); $width = $size_display; $height = $size_display; if ( is_array( $size_display ) ) { @@ -80,4 +79,71 @@ public function html_avatar( UserModel $user, array $size_display = [], string $ return $html; } + + /** + * Get html avatar of instructor with edit link. + * Don't wrapper this html with tag because has tag inside. + * + * @param UserModel $user + * @param array $size_display [ 'width' => 100, 'height' => 100 ] + * @param string $class_name + * + * @return string + * @since 4.2.7.6 + * @version 1.0.0 + */ + public function html_avatar_edit( UserModel $user, array $size_display = [], string $class_name = 'user' ): string { + $html = ''; + + try { + if ( empty( $size_display ) ) { + $size_display = learn_press_get_avatar_thumb_size(); + } + + $profile = LP_Profile::instance( $user->get_id() ); + $width = $size_display; + $height = $size_display; + if ( is_array( $size_display ) ) { + $width = $size_display['width']; + $height = $size_display['height']; + } + + $avatar_url = $user->get_avatar_url(); + $img_avatar = sprintf( + '%s', + esc_attr__( 'User Avatar', 'learnpress' ), + $avatar_url, + $width, + $height + ); + + $html_btn_to_edit_avatar = ''; + if ( $user->get_id() === get_current_user_id() ) { + $html_btn_to_edit_avatar = sprintf( + '+ %s', + $profile->get_tab_link( 'settings', 'avatar' ), + 'avatar', + esc_attr__( 'Edit avatar', 'learnpress' ), + __( 'edit avatar', 'learnpress' ) + ); + } + + $section = apply_filters( + 'learn-press/user/html-avatar-edit', + [ + 'wrapper' => sprintf( '
    ', $class_name ), + 'avatar' => $img_avatar, + 'btn_edit' => $html_btn_to_edit_avatar, + 'wrapper_end' => '
    ', + ], + $user + ); + + $html = Template::combine_components( $section ); + } catch ( Throwable $e ) { + error_log( __METHOD__ . ': ' . $e->getMessage() ); + } + + return $html; + } } diff --git a/inc/templates/class-lp-template-profile.php b/inc/templates/class-lp-template-profile.php index 8b860b55f..1bc80d877 100644 --- a/inc/templates/class-lp-template-profile.php +++ b/inc/templates/class-lp-template-profile.php @@ -77,7 +77,7 @@ public function avatar() { return; } - echo UserTemplate::instance()->html_avatar( $userModel ); + echo UserTemplate::instance()->html_avatar_edit( $userModel ); //learn_press_get_template( 'profile/avatar.php' ); } From a2059534616236b8f4d1732b17766f64688d9a5c Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 24 Dec 2024 19:00:54 +0700 Subject: [PATCH 038/225] = 4.2.7.6 = --- .../Course/SingleCourseClassicTemplate.php | 18 +++++++++--------- .../Course/SingleCourseTemplate.php | 9 +++++---- .../Instructor/SingleInstructorTemplate.php | 9 ++++++--- inc/TemplateHooks/UserTemplate.php | 17 +++++++++-------- inc/custom-post-types/abstract.php | 5 +++-- inc/templates/class-lp-template-profile.php | 3 ++- 6 files changed, 34 insertions(+), 27 deletions(-) diff --git a/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php b/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php index 2766c43b0..cda3d50f6 100644 --- a/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php @@ -210,17 +210,17 @@ public function html_instructor( $course ): string { $html_instructor = apply_filters( 'learn-press/course/instructor-html', [ - 'wrapper' => '
    ', - 'avartar_instructor' => sprintf( '
    %s
    ', UserTemplate::instance()->html_avatar( $instructor, [], 'instructor' ) ), - 'instructor' => '
    ', - 'label' => sprintf( '', esc_html__( 'Instructor', 'learnpress' ) ), - 'name' => sprintf( + 'wrapper' => '
    ', + 'avatar_instructor' => sprintf( '
    %s
    ', SingleInstructorTemplate::instance()->html_avatar( $instructor, [] ) ), + 'instructor' => '
    ', + 'label' => sprintf( '', esc_html__( 'Instructor', 'learnpress' ) ), + 'name' => sprintf( '', $instructor->get_url_instructor(), $singleInstructorTemplate->html_display_name( $instructor ) ), - 'instructor_end' => '
    ', - 'wrapper_end' => '
    ', + 'instructor_end' => '
    ', + 'wrapper_end' => '
    ', ], $course, $instructor, @@ -302,7 +302,7 @@ public function html_course_tabs( $course, $user ): string { if ( $tabs ) { ob_start(); foreach ( $tabs as $key => $tab ) { - echo ''; } $html_input = ob_get_clean(); @@ -316,7 +316,7 @@ public function html_course_tabs( $course, $user ): string { } echo '
  • '; - echo ''; + echo ''; echo '
  • '; } $html_tabs_nav = ob_get_clean(); diff --git a/inc/TemplateHooks/Course/SingleCourseTemplate.php b/inc/TemplateHooks/Course/SingleCourseTemplate.php index f71b7c370..46e87bfe7 100644 --- a/inc/TemplateHooks/Course/SingleCourseTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseTemplate.php @@ -264,11 +264,12 @@ public function html_instructor( $course, bool $with_avatar = false ): string { } $singleInstructorTemplate = SingleInstructorTemplate::instance(); + $userTemplate = new UserTemplate( 'instructor' ); $link_instructor = sprintf( '%s %s', $instructor->get_url_instructor(), - $with_avatar ? UserTemplate::instance()->html_avatar( $instructor, [], 'instructor' ) : '', + $with_avatar ? $userTemplate->html_avatar( $instructor ) : '', $singleInstructorTemplate->html_display_name( $instructor ) ); @@ -1219,13 +1220,13 @@ public function html_price_suffix( $course ): string { /** * Render string to data content * - * @param LP_Course $course + * @param CourseModel $course * @param string $data_content * * @return string */ - public function render_data( LP_Course $course, string $data_content = '' ): string { - $author_of_course = $course->get_author(); + public function render_data( CourseModel $course, string $data_content = '' ): string { + $author_of_course = $course->get_author_model(); $singleInstructorTemplate = SingleInstructorTemplate::instance(); // render count items diff --git a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php index 0060525fb..5ac14bd39 100644 --- a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php +++ b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php @@ -25,7 +25,10 @@ class SingleInstructorTemplate { use Singleton; + public static $userTemplate; + public function init() { + self::$userTemplate = new UserTemplate( 'instructor' ); add_action( 'learn-press/single-instructor/layout', [ $this, 'sections' ] ); //add_action( 'wp_head', [ $this, 'add_internal_style_to_head' ] ); } @@ -120,7 +123,7 @@ public function html_description( $instructor ): string { * @version 1.0.2 */ public function html_avatar( $instructor, array $size_display = [] ): string { - $userTemplate = UserTemplate::instance(); + $userTemplate = self::$userTemplate; $html = ''; if ( ! $instructor ) { return $html; @@ -133,7 +136,7 @@ public function html_avatar( $instructor, array $size_display = [] ): string { } } - return $userTemplate->html_avatar( $instructor, $size_display, 'instructor' ); + return $userTemplate->html_avatar( $instructor, $size_display ); } /** @@ -345,7 +348,7 @@ public function info( UserModel $instructor ): string { 'wrapper' => '
    ', 'cover_img' => ProfileTemplate::instance()->html_cover_image( $instructor ), 'wrapper_content' => '
    ', - 'avatar' => UserTemplate::instance()->html_avatar_edit( $instructor, [], 'instructor' ), + 'avatar' => self::$userTemplate->html_avatar_edit( $instructor, [], 'instructor' ), 'info_right' => $this->info_right( $instructor ), 'wrapper_content_end' => '
    ', 'wrapper_end' => '
    ', diff --git a/inc/TemplateHooks/UserTemplate.php b/inc/TemplateHooks/UserTemplate.php index c36f47484..eea405e5f 100644 --- a/inc/TemplateHooks/UserTemplate.php +++ b/inc/TemplateHooks/UserTemplate.php @@ -22,9 +22,10 @@ use WP_Query; class UserTemplate { - use Singleton; + public $class_name; - public function init() { + public function __construct( $class_name = 'user' ) { + $this->class_name = $class_name; } /** @@ -38,7 +39,7 @@ public function init() { * @since 4.2.7.2 * @version 1.0.4 */ - public function html_avatar( UserModel $user, array $size_display = [], string $class_name = 'user' ): string { + public function html_avatar( UserModel $user, array $size_display = [] ): string { $html = ''; try { @@ -46,8 +47,8 @@ public function html_avatar( UserModel $user, array $size_display = [], string $ $size_display = learn_press_get_avatar_thumb_size(); } - $width = $size_display; - $height = $size_display; + $width = $size_display; + $height = $size_display; if ( is_array( $size_display ) ) { $width = $size_display['width']; $height = $size_display['height']; @@ -65,7 +66,7 @@ public function html_avatar( UserModel $user, array $size_display = [], string $ $section = apply_filters( 'learn-press/user/html-avatar', [ - 'wrapper' => sprintf( '
    ', $class_name ), + 'wrapper' => sprintf( '
    ', $this->class_name ), 'avatar' => $img_avatar, 'wrapper_end' => '
    ', ], @@ -92,7 +93,7 @@ public function html_avatar( UserModel $user, array $size_display = [], string $ * @since 4.2.7.6 * @version 1.0.0 */ - public function html_avatar_edit( UserModel $user, array $size_display = [], string $class_name = 'user' ): string { + public function html_avatar_edit( UserModel $user, array $size_display = [] ): string { $html = ''; try { @@ -131,7 +132,7 @@ public function html_avatar_edit( UserModel $user, array $size_display = [], str $section = apply_filters( 'learn-press/user/html-avatar-edit', [ - 'wrapper' => sprintf( '
    ', $class_name ), + 'wrapper' => sprintf( '
    ', $this->class_name ), 'avatar' => $img_avatar, 'btn_edit' => $html_btn_to_edit_avatar, 'wrapper_end' => '
    ', diff --git a/inc/custom-post-types/abstract.php b/inc/custom-post-types/abstract.php index 0597d1cdf..66d3ab3e6 100644 --- a/inc/custom-post-types/abstract.php +++ b/inc/custom-post-types/abstract.php @@ -424,10 +424,11 @@ public function column_instructor( $post_id = 0 ) { 'author' => $user_id, ); - $author_link = esc_url_raw( add_query_arg( $args, 'edit.php' ) ); + $author_link = esc_url_raw( add_query_arg( $args, 'edit.php' ) ); + $userTemplate = new UserTemplate(); echo sprintf( '', - UserTemplate::instance()->html_avatar( + $userTemplate->html_avatar( $user, [ 'width' => 32, diff --git a/inc/templates/class-lp-template-profile.php b/inc/templates/class-lp-template-profile.php index 1bc80d877..13b43effe 100644 --- a/inc/templates/class-lp-template-profile.php +++ b/inc/templates/class-lp-template-profile.php @@ -77,7 +77,8 @@ public function avatar() { return; } - echo UserTemplate::instance()->html_avatar_edit( $userModel ); + $userTemplate = new UserTemplate(); + echo $userTemplate->html_avatar_edit( $userModel ); //learn_press_get_template( 'profile/avatar.php' ); } From 04a1118f6b6cad284de0a7bab62b035ffc1cbedc Mon Sep 17 00:00:00 2001 From: Tungnx Date: Wed, 25 Dec 2024 09:34:14 +0700 Subject: [PATCH 039/225] = 4.2.7.6 = ~ Tweak UserTemplate, SingleInstructorTemplate. --- composer.json | 2 +- .../Instructor/ListInstructorsElementor.php | 23 +-- inc/Models/UserModel.php | 8 +- .../Instructor/SingleInstructorTemplate.php | 133 +++--------------- inc/TemplateHooks/UserTemplate.php | 97 +++++++++++-- 5 files changed, 123 insertions(+), 140 deletions(-) diff --git a/composer.json b/composer.json index e6ade859d..aa08606f0 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "issues": "https://github.com/LearnPress/learnpress/issues" }, "require-dev": { - "squizlabs/php_codesniffer": "3.11.1", + "squizlabs/php_codesniffer": "3.11.2", "wp-coding-standards/wpcs": "3.1.0", "phpcompatibility/php-compatibility": "9.3.5" }, diff --git a/inc/ExternalPlugin/Elementor/Widgets/Instructor/ListInstructorsElementor.php b/inc/ExternalPlugin/Elementor/Widgets/Instructor/ListInstructorsElementor.php index 5cd954bea..758bf786e 100644 --- a/inc/ExternalPlugin/Elementor/Widgets/Instructor/ListInstructorsElementor.php +++ b/inc/ExternalPlugin/Elementor/Widgets/Instructor/ListInstructorsElementor.php @@ -11,6 +11,7 @@ use LearnPress\ExternalPlugin\Elementor\LPElementorWidgetBase; use LearnPress\Helpers\Config; use LearnPress\Helpers\Template; +use LearnPress\Models\UserModel; use LearnPress\TemplateHooks\Instructor\SingleInstructorTemplate; use WP_User_Query; @@ -87,31 +88,37 @@ protected function render() { $singleInstructorTemplate = SingleInstructorTemplate::instance(); echo '
      '; foreach ( $instructors as $instructor_id ) { - $instructor = learn_press_get_user( $instructor_id ); + $instructor = UserModel::find( $instructor_id, true ); if ( ! $instructor ) { continue; } ?>
    • - render_data( + render_data( $instructor, wp_kses_post( html_entity_decode( $item_layout['layout_html'] ) ) - ); ?> + ); + ?>
    • '; $content = ob_get_clean(); - $html_wrap = [ - '
      ' => '
      ', + $section = [ + 'wrapper' => sprintf( + '
      ', + 'elementor-repeater-item-' . esc_attr( $item_layout['_id'] ?? '' ) + ), + 'content' => $content, + 'wrapper_end' => '
      ', ]; - echo Template::instance()->nest_elements( $html_wrap, $content ); + + echo Template::combine_components( $section ); // End show list instructors } catch ( \Throwable $e ) { echo $e->getMessage(); } } - - } diff --git a/inc/Models/UserModel.php b/inc/Models/UserModel.php index b6feadf76..0b97ab13f 100644 --- a/inc/Models/UserModel.php +++ b/inc/Models/UserModel.php @@ -399,16 +399,14 @@ public function get_upload_avatar_src(): string { * Get links socials of use on Profile page * Icon is svg * - * @param int $user_id - * * @move from LP_Abstract_User * @return array * @since 4.2.3 - * @version 1.0.0 + * @version 1.0.1 */ - public function get_profile_social( int $user_id = 0 ): array { + public function get_profile_social(): array { $socials = array(); - $extra_info = learn_press_get_user_extra_profile_info( $user_id ); + $extra_info = learn_press_get_user_extra_profile_info( $this->get_id() ); if ( $extra_info ) { foreach ( $extra_info as $k => $v ) { diff --git a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php index 5ac14bd39..ff99ba8ff 100644 --- a/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php +++ b/inc/TemplateHooks/Instructor/SingleInstructorTemplate.php @@ -8,7 +8,6 @@ namespace LearnPress\TemplateHooks\Instructor; -use LearnPress\Helpers\Singleton; use LearnPress\Helpers\Template; use LearnPress\Models\CourseModel; use LearnPress\Models\Courses; @@ -17,126 +16,28 @@ use LearnPress\TemplateHooks\Course\ListCoursesTemplate; use LearnPress\TemplateHooks\UserTemplate; use LP_Course_Filter; -use LP_Profile; use LP_Settings; use LP_User; use Throwable; -class SingleInstructorTemplate { - use Singleton; - - public static $userTemplate; - - public function init() { - self::$userTemplate = new UserTemplate( 'instructor' ); - add_action( 'learn-press/single-instructor/layout', [ $this, 'sections' ] ); - //add_action( 'wp_head', [ $this, 'add_internal_style_to_head' ] ); - } - - /** - * Get display name html of instructor. - * - * @param LP_User|UserModel $instructor - * - * @return string - */ - public function html_display_name( $instructor ): string { - $sections = [ - 'wrapper' => '', - 'content' => $instructor->get_display_name(), - 'wrapper_end' => '', - ]; - - return Template::combine_components( $sections ); - } - - /** - * Get html social of instructor. - * - * @param LP_User|UserModel $instructor - * - * @return string - */ - public function html_social( $instructor ): string { - $content = ''; - - try { - $socials = $instructor->get_profile_social( $instructor->get_id() ); - if ( empty( $socials ) ) { - return $content; - } - - $sections = [ - 'wrapper' => '
      ', - 'content' => Template::combine_components( $socials ), - 'wrapper_end' => '
      ', - ]; - - $content = Template::combine_components( $sections ); - } catch ( Throwable $e ) { - error_log( __METHOD__ . ': ' . $e->getMessage() ); +class SingleInstructorTemplate extends UserTemplate { + public static function instance() { + static $instance = null; + if ( is_null( $instance ) ) { + $instance = new self(); } - return $content; + return $instance; } - /** - * Get html description of instructor. - * - * @param LP_User|UserModel $instructor - * - * @return string - * @since 4.2.3.4 - * @version 1.0.0 - */ - public function html_description( $instructor ): string { - $content = ''; - - try { - $description = $instructor->get_description(); - if ( empty( $description ) ) { - return $content; - } - - $sections = [ - 'wrapper' => '
      ', - 'content' => $instructor->get_description(), - 'wrapper_end' => '
      ', - ]; - - $content = Template::combine_components( $sections ); - } catch ( Throwable $e ) { - error_log( __METHOD__ . ': ' . $e->getMessage() ); - } - - return $content; + public function __construct( $class_name = 'instructor' ) { + parent::__construct( $class_name ); + $this->init(); } - /** - * Get html avatar of instructor. - * - * @param LP_User|UserModel $instructor - * @param array $size_display ['width' => 100, 'height' => 100] - * - * @return string - * @since 4.2.3 - * @version 1.0.2 - */ - public function html_avatar( $instructor, array $size_display = [] ): string { - $userTemplate = self::$userTemplate; - $html = ''; - if ( ! $instructor ) { - return $html; - } - - if ( $instructor instanceof LP_User ) { - $instructor = UserModel::find( $instructor->get_id(), true ); - if ( ! $instructor ) { - return $html; - } - } - - return $userTemplate->html_avatar( $instructor, $size_display ); + public function init() { + add_action( 'learn-press/single-instructor/layout', [ $this, 'sections' ] ); + //add_action( 'wp_head', [ $this, 'add_internal_style_to_head' ] ); } /** @@ -233,12 +134,16 @@ public function html_button_view( $instructor ): string { /** * Render string to data content * - * @param LP_User $instructor + * @param UserModel $instructor * @param string $data_content * * @return string */ - public function render_data( LP_User $instructor, string $data_content = '' ): string { + public function render_data( $instructor, string $data_content = '' ): string { + if ( $instructor instanceof LP_User ) { + $instructor = UserModel::find( $instructor->get_id(), true ); + } + $data_render = str_replace( [ '{{instructor_id}}', @@ -348,7 +253,7 @@ public function info( UserModel $instructor ): string { 'wrapper' => '
      ', 'cover_img' => ProfileTemplate::instance()->html_cover_image( $instructor ), 'wrapper_content' => '
      ', - 'avatar' => self::$userTemplate->html_avatar_edit( $instructor, [], 'instructor' ), + 'avatar' => $this->html_avatar_edit( $instructor ), 'info_right' => $this->info_right( $instructor ), 'wrapper_content_end' => '
      ', 'wrapper_end' => '
      ', diff --git a/inc/TemplateHooks/UserTemplate.php b/inc/TemplateHooks/UserTemplate.php index eea405e5f..36904acb8 100644 --- a/inc/TemplateHooks/UserTemplate.php +++ b/inc/TemplateHooks/UserTemplate.php @@ -3,23 +3,15 @@ * Template hooks User. * * @since 4.2.7.2 - * @version 1.0.0 + * @version 1.0.1 */ namespace LearnPress\TemplateHooks; -use LearnPress\Helpers\Singleton; use LearnPress\Helpers\Template; -use LearnPress\Models\CourseModel; -use LearnPress\Models\Courses; use LearnPress\Models\UserModel; -use LearnPress\TemplateHooks\Course\SingleCourseTemplate; -use LP_Course; -use LP_Course_Filter; use LP_Profile; -use LP_User; use Throwable; -use WP_Query; class UserTemplate { public $class_name; @@ -29,11 +21,63 @@ public function __construct( $class_name = 'user' ) { } /** - * Get html avatar of instructor. + * Get display name html of user. + * + * @param UserModel $userModel + * + * @return string + */ + public function html_display_name( UserModel $userModel ): string { + $sections = [ + 'wrapper' => sprintf( '', $this->class_name ), + 'content' => $userModel->get_display_name(), + 'wrapper_end' => '', + ]; + + return Template::combine_components( $sections ); + } + + /** + * Get html description of instructor. + * + * @param UserModel $userModel + * + * @return string + * @since 4.2.3.4 + * @version 1.0.0 + */ + public function html_description( $userModel ): string { + $content = ''; + + try { + $description = $userModel->get_description(); + if ( empty( $description ) ) { + return $content; + } + + $sections = apply_filters( + 'learn-press/user/html-description', + [ + 'wrapper' => sprintf( '
      ', $this->class_name ), + 'content' => $description, + 'wrapper_end' => '
      ', + ], + $userModel + ); + + $content = Template::combine_components( $sections ); + } catch ( Throwable $e ) { + error_log( __METHOD__ . ': ' . $e->getMessage() ); + } + + return $content; + } + + /** + * Get html avatar of user. * * @param UserModel $user * @param array $size_display [ 'width' => 100, 'height' => 100 ] - * @param string $class_name * * @return string * @since 4.2.7.2 @@ -87,7 +131,6 @@ public function html_avatar( UserModel $user, array $size_display = [] ): string * * @param UserModel $user * @param array $size_display [ 'width' => 100, 'height' => 100 ] - * @param string $class_name * * @return string * @since 4.2.7.6 @@ -147,4 +190,34 @@ public function html_avatar_edit( UserModel $user, array $size_display = [] ): s return $html; } + + /** + * Get html social of instructor. + * + * @param UserModel $userModel + * + * @return string + */ + public function html_social( $userModel ): string { + $content = ''; + + try { + $socials = $userModel->get_profile_social(); + if ( empty( $socials ) ) { + return $content; + } + + $sections = [ + 'wrapper' => sprintf( '
      ', $this->class_name ), + 'content' => Template::combine_components( $socials ), + 'wrapper_end' => '
      ', + ]; + + $content = Template::combine_components( $sections ); + } catch ( Throwable $e ) { + error_log( __METHOD__ . ': ' . $e->getMessage() ); + } + + return $content; + } } From d50899d0a1efb73e98e9e572e68db01bf051fa7e Mon Sep 17 00:00:00 2001 From: truongpn Date: Wed, 25 Dec 2024 09:38:05 +0700 Subject: [PATCH 040/225] =4.2.7.6= --- .../Instructor/ListInstructorsTemplate.php | 105 ++++++++++-------- 1 file changed, 56 insertions(+), 49 deletions(-) diff --git a/inc/TemplateHooks/Instructor/ListInstructorsTemplate.php b/inc/TemplateHooks/Instructor/ListInstructorsTemplate.php index 6a7e79879..e03bb2d22 100644 --- a/inc/TemplateHooks/Instructor/ListInstructorsTemplate.php +++ b/inc/TemplateHooks/Instructor/ListInstructorsTemplate.php @@ -78,25 +78,30 @@ public function sections( array $data = [] ) { */ global $wp_query; - ob_start(); try { - $html_wrapper = apply_filters( - 'learn-press/list-instructors/sections/wrapper', - [ - '
      ' => '
      ', - '
      ' => '
      ', - ], - $data - ); + ob_start(); ?>
      nest_elements( $html_wrapper, $content ); + $skeleton = ob_get_clean(); + + $sections = apply_filters( + 'learn-press/list-instructors/sections/wrapper', + [ + 'wrapper' => '
      ', + 'wrapper_inner' => '
      ', + 'skeleton' => $skeleton, + 'wrapper_inner_end' => '
      ', + 'wrapper_end' => '
      ', + ], + $data + ); + + echo Template::combine_components( $sections ); + } catch ( Throwable $e ) { - ob_end_clean(); error_log( __METHOD__ . ': ' . $e->getMessage() ); } } @@ -109,35 +114,36 @@ public function sections( array $data = [] ) { * @return false|string */ public function instructor_item( $instructor ) { - $content = ''; - $html_wrapper = apply_filters( - 'learn-press/list-instructors/instructor_item/wrapper', - [ - '
    • ' => '
    • ', - ], - $instructor - ); - - ob_start(); + $content = ''; + try { $singleInstructorTemplate = SingleInstructorTemplate::instance(); - $sections = apply_filters( + $items = apply_filters( 'learn-press/list-instructors/instructor_item/sections', [ - 'img' => [ 'text_html' => $singleInstructorTemplate->html_avatar( $instructor ) ], - 'name' => [ 'text_html' => $singleInstructorTemplate->html_display_name( $instructor ) ], - 'info' => [ 'text_html' => $this->instructor_item_info( $instructor ) ], - 'btn_view' => [ 'text_html' => $singleInstructorTemplate->html_button_view( $instructor ) ], + 'img' => $singleInstructorTemplate->html_avatar( $instructor ), + 'name' => $singleInstructorTemplate->html_display_name( $instructor ), + 'info' => $this->instructor_item_info( $instructor ), + 'btn_view' => $singleInstructorTemplate->html_button_view( $instructor ), ], $instructor, $singleInstructorTemplate ); - Template::instance()->print_sections( $sections, compact( 'instructor' ) ); - $content = ob_get_clean(); - $content = Template::instance()->nest_elements( $html_wrapper, $content ); + + $sections = apply_filters( + 'learn-press/list-instructors/instructor_item/wrapper', + [ + 'wrapper' => '
    • ', + 'content' => Template::combine_components( $items ), + 'wrapper_end' => '
    • ', + ], + $instructor + ); + + $content = Template::combine_components( $sections ); + } catch ( Throwable $e ) { - ob_end_clean(); error_log( __METHOD__ . ': ' . $e->getMessage() ); } @@ -154,16 +160,8 @@ public function instructor_item( $instructor ) { * @since 4.2.3 */ public function instructor_item_info( $instructor ) { - $content = ''; - $html_wrapper = apply_filters( - 'learn-press/list-instructors/instructor_item/info/wrapper', - [ - '
      ' => '
      ', - ], - $instructor - ); - - ob_start(); + $content = ''; + try { $singleInstructorTemplate = SingleInstructorTemplate::instance(); @@ -174,23 +172,32 @@ public function instructor_item_info( $instructor ) { $html_total_students = sprintf( '
      %s
      ', - $singleInstructorTemplate->html_count_students( $instructor ) + $singleInstructorTemplate->html_count_students( $instructor ) ); - $sections = apply_filters( + $items = apply_filters( 'learn-press/list-instructors/instructor_item/info/sections', [ - 'total_courses' => [ 'text_html' => $html_total_courses ], - 'total_students' => [ 'text_html' => $html_total_students ], + 'total_courses' => $html_total_courses, + 'total_students' => $html_total_students, ], $instructor, $singleInstructorTemplate ); - Template::instance()->print_sections( $sections, compact( 'instructor' ) ); - $content = ob_get_clean(); - $content = Template::instance()->nest_elements( $html_wrapper, $content ); + + $sections = apply_filters( + 'learn-press/list-instructors/instructor_item/wrapper', + [ + 'wrapper' => '
      ', + 'content' => Template::combine_components( $items ), + 'wrapper_end' => '
      ', + ], + $instructor + ); + + $content = Template::combine_components( $sections ); + } catch ( Throwable $e ) { - ob_end_clean(); error_log( __METHOD__ . ': ' . $e->getMessage() ); } From 198d84ec445a4655d40ccaf5dd9937ec7554f719 Mon Sep 17 00:00:00 2001 From: truongpn Date: Wed, 25 Dec 2024 10:20:28 +0700 Subject: [PATCH 041/225] =4.2.7.6= --- assets/src/scss/frontend/_instructors.scss | 15 +++++++++------ .../Instructor/ListInstructorsTemplate.php | 6 +++++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/assets/src/scss/frontend/_instructors.scss b/assets/src/scss/frontend/_instructors.scss index e62e73e8a..f76be463f 100644 --- a/assets/src/scss/frontend/_instructors.scss +++ b/assets/src/scss/frontend/_instructors.scss @@ -56,6 +56,7 @@ body { border: 1px solid var(--lp-instructor-border-color); padding: var(--lp-instructor-item-padding); list-style: none; + border-radius: $border-radius-global; .instructor-avatar{ margin-bottom: $spacing-base-3x; } @@ -70,15 +71,17 @@ body { .instructor-avatar img { width: 100%; + border-radius: $border-radius-global; } .instructor-info { display: flex; - column-gap: 10px; + column-gap: 16px; margin-bottom: $spacing-base-3x; + flex-wrap: wrap; + row-gap: 8px; + justify-content: center; > div { - flex: 1; - text-align: right; display: flex; align-items: center; column-gap: 10px; @@ -87,10 +90,10 @@ body { display: inline-flex; white-space: nowrap; } - } - .instructor-count-students { - justify-content: right; + .lp-ico { + color: $color-primary; + } } } diff --git a/inc/TemplateHooks/Instructor/ListInstructorsTemplate.php b/inc/TemplateHooks/Instructor/ListInstructorsTemplate.php index e03bb2d22..d7a65edc8 100644 --- a/inc/TemplateHooks/Instructor/ListInstructorsTemplate.php +++ b/inc/TemplateHooks/Instructor/ListInstructorsTemplate.php @@ -123,7 +123,11 @@ public function instructor_item( $instructor ) { 'learn-press/list-instructors/instructor_item/sections', [ 'img' => $singleInstructorTemplate->html_avatar( $instructor ), - 'name' => $singleInstructorTemplate->html_display_name( $instructor ), + 'name' => sprintf( + '%s', + $instructor->get_url_instructor(), + $singleInstructorTemplate->html_display_name( $instructor ) + ), 'info' => $this->instructor_item_info( $instructor ), 'btn_view' => $singleInstructorTemplate->html_button_view( $instructor ), ], From c4b8a099574f48b2d428737609cc00745d7d47a3 Mon Sep 17 00:00:00 2001 From: truongpn Date: Wed, 25 Dec 2024 10:51:27 +0700 Subject: [PATCH 042/225] =4.2.7.6= --- assets/src/scss/frontend/_instructors.scss | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/assets/src/scss/frontend/_instructors.scss b/assets/src/scss/frontend/_instructors.scss index f76be463f..4d8a11138 100644 --- a/assets/src/scss/frontend/_instructors.scss +++ b/assets/src/scss/frontend/_instructors.scss @@ -62,7 +62,6 @@ body { } .instructor-display-name { display: block; - text-align: center; margin-bottom: $spacing-base-3x; font-size: 1.2em; line-height: 1.3; @@ -80,7 +79,7 @@ body { margin-bottom: $spacing-base-3x; flex-wrap: wrap; row-gap: 8px; - justify-content: center; + > div { display: flex; align-items: center; From 3c62b7edf8164231671438c30c5a9a9ff4e548ca Mon Sep 17 00:00:00 2001 From: Tungnx Date: Wed, 25 Dec 2024 11:21:43 +0700 Subject: [PATCH 043/225] = 4.2.7.6 = ~ Tweak: render_courses. --- inc/TemplateHooks/Course/ListCoursesTemplate.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/inc/TemplateHooks/Course/ListCoursesTemplate.php b/inc/TemplateHooks/Course/ListCoursesTemplate.php index 1a8acd1e4..06aa473a0 100644 --- a/inc/TemplateHooks/Course/ListCoursesTemplate.php +++ b/inc/TemplateHooks/Course/ListCoursesTemplate.php @@ -81,7 +81,7 @@ public function layout_courses() { * * @return stdClass { content: string_html } * @since 4.2.5.7 - * @version 1.0.3 + * @version 1.0.4 */ public static function render_courses( array $settings = [] ): stdClass { $filter = new LP_Course_Filter(); @@ -93,12 +93,14 @@ public static function render_courses( array $settings = [] ): stdClass { elseif ( ! empty( $settings['page_tag_id_current'] ) && empty( $settings['tag_id'] ) ) { $filter->tag_ids[] = $settings['page_tag_id_current']; } - $total_rows = 0; - $courses = Courses::get_courses( $filter, $total_rows ); - $total_pages = LP_Database::get_total_pages( $filter->limit, $total_rows ); - $skin = $settings['skin'] ?? learn_press_get_courses_layout(); - $paged = $settings['paged'] ?? 1; - $listCoursesTemplate = self::instance(); + $total_rows = 0; + $courses = Courses::get_courses( $filter, $total_rows ); + $total_pages = LP_Database::get_total_pages( $filter->limit, $total_rows ); + $settings['total_pages'] = $total_pages; + $settings['courses_per_page'] = $filter->limit; + $skin = $settings['skin'] ?? learn_press_get_courses_layout(); + $paged = $settings['paged'] ?? 1; + $listCoursesTemplate = self::instance(); // HTML section courses. ob_start(); From c65f3acbfffa6596234a121a9f0ef433b885221b Mon Sep 17 00:00:00 2001 From: Tungnx Date: Wed, 25 Dec 2024 11:28:57 +0700 Subject: [PATCH 044/225] = 4.2.7.6 = --- .../Course/ListCoursesTemplate.php | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/inc/TemplateHooks/Course/ListCoursesTemplate.php b/inc/TemplateHooks/Course/ListCoursesTemplate.php index 06aa473a0..82be2cd81 100644 --- a/inc/TemplateHooks/Course/ListCoursesTemplate.php +++ b/inc/TemplateHooks/Course/ListCoursesTemplate.php @@ -97,9 +97,11 @@ public static function render_courses( array $settings = [] ): stdClass { $courses = Courses::get_courses( $filter, $total_rows ); $total_pages = LP_Database::get_total_pages( $filter->limit, $total_rows ); $settings['total_pages'] = $total_pages; + $settings['total_rows'] = $total_rows; $settings['courses_per_page'] = $filter->limit; $skin = $settings['skin'] ?? learn_press_get_courses_layout(); $paged = $settings['paged'] ?? 1; + $settings['paged'] = $paged; $listCoursesTemplate = self::instance(); // HTML section courses. @@ -498,7 +500,7 @@ public function html_layout_type( array $data = [] ): string { $content = '
        '; foreach ( $layouts as $k => $v ) { - $active = ( $data['courses_layout_default'] ?? '' ) === $k ? 'active' : ''; + $active = ( $data['courses_layout_default'] ?? '' ) === $k ? 'active' : ''; $content .= '
      • ' . $v . '
      • '; } $content .= '
      '; @@ -546,10 +548,10 @@ public function html_search_form( array $data = [] ) { ob_start(); ?>
      + action=""> + name="c_search" + value="">
      $value ) : ?> > + value="" + id="lp-switch-layout-btn-" > + title="" + for="lp-switch-layout-btn-">
    '
  • ', @@ -819,7 +821,7 @@ public static function fix_theme_course_old( $section, $course, $settings ) { break; } - ++$i; + ++ $i; } } From 0bf76557e22c40b5f1346cf3f43e2e280a2383d5 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Wed, 25 Dec 2024 13:42:42 +0700 Subject: [PATCH 045/225] = 4.2.7.6 = --- .../Instructor/ListInstructorsTemplate.php | 12 ++--- inc/TemplateHooks/UserTemplate.php | 49 +++++++++++++++++-- templates/single-course/meta/instructor.php | 11 +++-- 3 files changed, 56 insertions(+), 16 deletions(-) diff --git a/inc/TemplateHooks/Instructor/ListInstructorsTemplate.php b/inc/TemplateHooks/Instructor/ListInstructorsTemplate.php index d7a65edc8..b99d3d17e 100644 --- a/inc/TemplateHooks/Instructor/ListInstructorsTemplate.php +++ b/inc/TemplateHooks/Instructor/ListInstructorsTemplate.php @@ -88,7 +88,7 @@ public function sections( array $data = [] ) { $skeleton = ob_get_clean(); $sections = apply_filters( - 'learn-press/list-instructors/sections/wrapper', + 'learn-press/list-instructors/sections', [ 'wrapper' => '
    ', 'wrapper_inner' => '
    ', @@ -111,9 +111,9 @@ public function sections( array $data = [] ) { * * @param UserModel $instructor * - * @return false|string + * @return string */ - public function instructor_item( $instructor ) { + public function instructor_item( UserModel $instructor ): string { $content = ''; try { @@ -146,7 +146,6 @@ public function instructor_item( $instructor ) { ); $content = Template::combine_components( $sections ); - } catch ( Throwable $e ) { error_log( __METHOD__ . ': ' . $e->getMessage() ); } @@ -159,11 +158,11 @@ public function instructor_item( $instructor ) { * * @param UserModel $instructor * - * @return false|string + * @return string * @version 1.0.1 * @since 4.2.3 */ - public function instructor_item_info( $instructor ) { + public function instructor_item_info( UserModel $instructor ): string { $content = ''; try { @@ -200,7 +199,6 @@ public function instructor_item_info( $instructor ) { ); $content = Template::combine_components( $sections ); - } catch ( Throwable $e ) { error_log( __METHOD__ . ': ' . $e->getMessage() ); } diff --git a/inc/TemplateHooks/UserTemplate.php b/inc/TemplateHooks/UserTemplate.php index 36904acb8..d77995c65 100644 --- a/inc/TemplateHooks/UserTemplate.php +++ b/inc/TemplateHooks/UserTemplate.php @@ -11,6 +11,7 @@ use LearnPress\Helpers\Template; use LearnPress\Models\UserModel; use LP_Profile; +use LP_User; use Throwable; class UserTemplate { @@ -23,11 +24,19 @@ public function __construct( $class_name = 'user' ) { /** * Get display name html of user. * - * @param UserModel $userModel + * @param UserModel|LP_User $userModel * * @return string */ - public function html_display_name( UserModel $userModel ): string { + public function html_display_name( $userModel ): string { + if ( $userModel instanceof LP_User ) { + $userModel = UserModel::find( $userModel->get_id(), true ); + } + + if ( ! $userModel ) { + return ''; + } + $sections = [ 'wrapper' => sprintf( '', $this->class_name ), 'content' => $userModel->get_display_name(), @@ -40,7 +49,7 @@ public function html_display_name( UserModel $userModel ): string { /** * Get html description of instructor. * - * @param UserModel $userModel + * @param UserModel|LP_User $userModel * * @return string * @since 4.2.3.4 @@ -50,6 +59,14 @@ public function html_description( $userModel ): string { $content = ''; try { + if ( $userModel instanceof LP_User ) { + $userModel = UserModel::find( $userModel->get_id(), true ); + } + + if ( ! $userModel ) { + return $content; + } + $description = $userModel->get_description(); if ( empty( $description ) ) { return $content; @@ -87,6 +104,14 @@ public function html_avatar( UserModel $user, array $size_display = [] ): string $html = ''; try { + if ( $user instanceof LP_User ) { + $user = UserModel::find( $user->get_id(), true ); + } + + if ( ! $user ) { + return ''; + } + if ( empty( $size_display ) ) { $size_display = learn_press_get_avatar_thumb_size(); } @@ -140,6 +165,14 @@ public function html_avatar_edit( UserModel $user, array $size_display = [] ): s $html = ''; try { + if ( $user instanceof LP_User ) { + $user = UserModel::find( $user->get_id(), true ); + } + + if ( ! $user ) { + return ''; + } + if ( empty( $size_display ) ) { $size_display = learn_press_get_avatar_thumb_size(); } @@ -194,7 +227,7 @@ public function html_avatar_edit( UserModel $user, array $size_display = [] ): s /** * Get html social of instructor. * - * @param UserModel $userModel + * @param UserModel|LP_User $userModel * * @return string */ @@ -202,6 +235,14 @@ public function html_social( $userModel ): string { $content = ''; try { + if ( $userModel instanceof LP_User ) { + $userModel = UserModel::find( $userModel->get_id(), true ); + } + + if ( ! $userModel ) { + return ''; + } + $socials = $userModel->get_profile_social(); if ( empty( $socials ) ) { return $content; diff --git a/templates/single-course/meta/instructor.php b/templates/single-course/meta/instructor.php index 936a74ca2..f08c60743 100644 --- a/templates/single-course/meta/instructor.php +++ b/templates/single-course/meta/instructor.php @@ -2,21 +2,22 @@ /** * Template for displaying course instructor in primary-meta section. * - * @version 4.0.1 + * @version 4.0.2 * @author ThimPress * @package LearnPress/Templates */ +use LearnPress\Models\CourseModel; use LearnPress\TemplateHooks\Instructor\SingleInstructorTemplate; defined( 'ABSPATH' ) || exit; -$course = learn_press_get_course(); -if ( ! $course ) { +$courseModel = CourseModel::find( get_the_ID(), true ); +if ( ! $courseModel ) { return; } -$instructor = $course->get_instructor(); +$instructor = $courseModel->get_author_model(); if ( ! $instructor ) { return; } @@ -24,7 +25,7 @@
    - get_profile_picture() ); ?> + html_avatar( $instructor ) ); ?>
    From f7d7bce1c1ab4b2f5a8096a68fa62b959efc5f79 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Wed, 25 Dec 2024 15:06:58 +0700 Subject: [PATCH 046/225] = 4.2.7.6 = ~ Added: option chooice layout single course. ~ Handle layout single course with new install and old. --- config/settings/course.php | 15 ++ .../Course/SingleCourseClassicTemplate.php | 15 +- .../Course/SingleCourseModelTemplate.php | 6 +- .../Course/SingleCourseTemplate.php | 57 +------- inc/class-lp-page-controller.php | 132 +++++++++--------- templates/single-course-layout-classic.php | 33 +++++ templates/single-course-layout.php | 33 +++++ templates/single-course.php | 12 +- 8 files changed, 159 insertions(+), 144 deletions(-) create mode 100644 templates/single-course-layout-classic.php create mode 100644 templates/single-course-layout.php diff --git a/config/settings/course.php b/config/settings/course.php index 921cf4967..1912d867e 100644 --- a/config/settings/course.php +++ b/config/settings/course.php @@ -8,6 +8,10 @@ esc_html__( 'The site will be redirected to the URL added after clicking the finish course button.', 'learnpress' ), esc_html__( 'Set blank, the site will be redirected to the single course page', 'learnpress' ) ); +$layout_single_course_default = LP_Settings::get_option( 'layout_single_course', '' ); +if ( empty( $layout_single_course_default ) ) { + $layout_single_course_default = 'classic'; +} return apply_filters( 'learn-press/courses-settings-fields', @@ -19,6 +23,17 @@ 'title' => esc_html__( 'General', 'learnpress' ), 'type' => 'title', ), + array( + 'title' => esc_html__( 'Layout single course', 'learnpress' ), + 'desc' => esc_html__( 'Layout default display for single course.', 'learnpress' ), + 'id' => 'layout_single_course', + 'default' => $layout_single_course_default, + 'type' => 'select', + 'options' => array( + 'modern' => esc_html__( 'Modern', 'learnpress' ), + 'classic' => esc_html__( 'Classic', 'learnpress' ), + ), + ), array( 'title' => esc_html__( 'Review courses', 'learnpress' ), 'desc' => esc_html__( 'Courses created by instructors will be pending review first.', 'learnpress' ), diff --git a/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php b/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php index cda3d50f6..50bfc410d 100644 --- a/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseClassicTemplate.php @@ -21,31 +21,24 @@ class SingleCourseClassicTemplate { use Singleton; /** - * @var SingleCourseTemplate + * @var SingleCourseTemplate $singleCourseTemplate */ public $singleCourseTemplate; public function init() { $this->singleCourseTemplate = SingleCourseTemplate::instance(); - add_action( - 'learn-press/single-course/classic/layout', - [ $this, 'course_classic_layout' ] - ); + add_action( 'learn-press/single-course/layout/classic', [ $this, 'section' ] ); } /** * Single course layout classic * - * @param $course + * @param CourseModel $course * * @return void */ - public function course_classic_layout( $course ) { - if ( ! $course instanceof CourseModel ) { - return; - } - + public function section( CourseModel $course ) { $user = UserModel::find( get_current_user_id(), true ); ob_start(); diff --git a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php index dd43e028c..b5b97b5ea 100644 --- a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseModelTemplate.php @@ -30,7 +30,7 @@ public function init() { $this->singleCourseTemplate = SingleCourseTemplate::instance(); add_action( - 'learn-press/single-course/model/layout', + 'learn-press/single-course/layout', [ $this, 'course_model_layout' ] ); } @@ -351,11 +351,11 @@ public function html_share( $course ): string { 'learn-press/single-course/social-share', [ 'wrapper' => '', ] ); - + $clipboard = [ 'wrapper' => '
    ', 'input' => sprintf( '', get_permalink() ), diff --git a/inc/TemplateHooks/Course/SingleCourseTemplate.php b/inc/TemplateHooks/Course/SingleCourseTemplate.php index 46e87bfe7..d1c277000 100644 --- a/inc/TemplateHooks/Course/SingleCourseTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseTemplate.php @@ -3,7 +3,7 @@ * Template hooks Single Course. * * @since 4.2.3 - * @version 1.0.3 + * @version 1.0.4 */ namespace LearnPress\TemplateHooks\Course; @@ -264,7 +264,7 @@ public function html_instructor( $course, bool $with_avatar = false ): string { } $singleInstructorTemplate = SingleInstructorTemplate::instance(); - $userTemplate = new UserTemplate( 'instructor' ); + $userTemplate = new UserTemplate( 'instructor' ); $link_instructor = sprintf( '%s %s', @@ -363,29 +363,6 @@ public function html_price( $course ): string { return apply_filters( 'learn-press/course/html-price', $price_html, $course ); } - /** - * Get deliver type - * - * @param CourseModel $course - * - * @return string - * @deprecated 4.2.7.3 Move to SingleCourseOfflineTemplate - */ - public function html_deliver_type( CourseModel $course ): string { - return ''; - $content = ''; - - $html_wrapper = [ - '' => '', - ]; - - $deliver_type_options = Config::instance()->get( 'course-deliver-type' ); - $key = $course->get_meta_value_by_key( CoursePostModel::META_KEY_DELIVER, 'private_1_1' ); - $content = $deliver_type_options[ $key ] ?? ''; - - return Template::instance()->nest_elements( $html_wrapper, $content ); - } - /** * Get deliver type * @@ -607,36 +584,6 @@ public function html_feature_review( CourseModel $course ): string { return ob_get_clean(); } - /** - * Get html address of course offline - * - * @param CourseModel $course - * - * @return string - * @deprecated 4.2.7.3 Move to SingleCourseOfflineTemplate - */ - public function html_address( CourseModel $course ): string { - return ''; - $content = ''; - - try { - $address = $course->get_meta_value_by_key( CoursePostModel::META_KEY_ADDRESS, '' ); - if ( empty( $address ) ) { - return $content; - } - - $html_wrapper = [ - '' => '', - ]; - $content = Template::instance()->nest_elements( $html_wrapper, $address ); - apply_filters( 'learn-press/single-course/html-address', $content, $course ); - } catch ( Throwable $e ) { - error_log( __METHOD__ . ': ' . $e->getMessage() ); - } - - return $content; - } - /** * Get button external * diff --git a/inc/class-lp-page-controller.php b/inc/class-lp-page-controller.php index f1be8dee0..06667f621 100644 --- a/inc/class-lp-page-controller.php +++ b/inc/class-lp-page-controller.php @@ -1,5 +1,6 @@ ID ) ) { - - // Filter here to insert the shortcode - $auto_shortcodes = apply_filters( 'learn-press/auto-shortcode-pages', array() ); - - if ( ! empty( $auto_shortcodes[ $the_post->ID ] ) ) { - $shortcode_tag = $auto_shortcodes[ $the_post->ID ]; - - preg_match( '/\[' . $shortcode_tag . '\s?(.*)\]/', $the_post->post_content, $results ); - - if ( empty( $results ) ) { - $content = $the_post->post_content . "[$shortcode_tag]"; - $the_post->post_content = $content; - } - } - } - - return $template; - } - /** * Load data for item of course * @@ -404,6 +373,7 @@ public function remove_course_post_format( $qv ) { /** * @return bool + * @deprecated v4.2.7.6 */ protected function _is_archive() { return learn_press_is_courses() || learn_press_is_course_tag() || learn_press_is_course_category() || learn_press_is_search() || learn_press_is_course_tax(); @@ -411,6 +381,7 @@ protected function _is_archive() { /** * @return bool + * @deprecated v4.2.7.6 */ protected function _is_single() { return learn_press_is_course() && is_single(); @@ -464,23 +435,31 @@ public function template_loader( $template ) { */ private function get_page_template() { $page_template = ''; - $object = get_queried_object(); - - if ( is_singular( LP_COURSE_CPT ) ) { - $page_template = 'single-course.php'; - - if ( $this->_is_single() ) { - global $post; - setup_postdata( $post ); - - $course_item = LP_Global::course_item(); - if ( $course_item ) { - $page_template = 'content-single-item.php'; - } elseif ( $object ) { - $course = CourseModel::find( $object->ID, true ); - if ( $course && $course->is_offline() ) { - $page_template = 'single-course-offline.php'; - } + $object = get_queried_object(); + + if ( self::is_page_single_course() ) { + $page_template = 'single-course-layout.php'; + // Check condition to load single course layout classic or modern. + $is_override_single_course = Template::check_template_is_override( 'single-course.php' ); + $option_single_course_layout = LP_Settings::get_option( 'layout_single_course', '' ); + + if ( $is_override_single_course ) { // Old file template + $page_template = 'single-course.php'; + } elseif ( empty( $option_single_course_layout ) + || $option_single_course_layout === 'classic' ) { + $page_template = 'single-course-layout-classic.php'; + } + + global $post; + setup_postdata( $post ); + + $course_item = LP_Global::course_item(); + if ( $course_item ) { + $page_template = 'content-single-item.php'; + } elseif ( $object ) { + $course = CourseModel::find( $object->ID, true ); + if ( $course && $course->is_offline() ) { + $page_template = 'single-course-offline.php'; } } } elseif ( learn_press_is_course_taxonomy() ) { @@ -820,12 +799,15 @@ public function pre_get_posts( WP_Query $q ): WP_Query { * @since 3.2.7.5 */ public function set_link_item_course_default_wp_to_page_404( $q ) { - $post_type_apply_404 = apply_filters( 'lp/page-controller/', array( - LP_LESSON_CPT, - LP_QUIZ_CPT, - LP_QUESTION_CPT, - 'lp_assignment' - ) ); + $post_type_apply_404 = apply_filters( + 'lp/page-controller/', + array( + LP_LESSON_CPT, + LP_QUIZ_CPT, + LP_QUESTION_CPT, + 'lp_assignment', + ) + ); if ( ! isset( $q->query_vars['post_type'] ) || ! in_array( $q->query_vars['post_type'], $post_type_apply_404 ) ) { return $q; @@ -954,6 +936,28 @@ public static function page_is( string $name = '' ): bool { return false; } + /** + * Check is page is single course + * + * @since 4.2.7.6 + * @version 1.0.0 + * @return bool + */ + public static function is_page_single_course(): bool { + static $flag; + if ( ! is_null( $flag ) ) { + return $flag; + } + + try { + $flag = is_singular( LP_COURSE_CPT ); + } catch ( Throwable $e ) { + $flag = false; + } + + return $flag; + } + /** * Check is page courses * diff --git a/templates/single-course-layout-classic.php b/templates/single-course-layout-classic.php new file mode 100644 index 000000000..4e69d5c3d --- /dev/null +++ b/templates/single-course-layout-classic.php @@ -0,0 +1,33 @@ +ID, true ); - - // hook from @since 4.2.7.5 - do_action( 'learn-press/single-course/model/layout', $courseModel ); - - // hook deprecated 4.2.7.4 - //do_action( 'learn-press/single-course/classic/layout', $courseModel ); - - //learn_press_get_template( 'content-single-course' ); + learn_press_get_template( 'content-single-course' ); } } /*while ( have_posts() ) { From 49882c5c798765c388f5560d155ad6040e32272d Mon Sep 17 00:00:00 2001 From: Tungnx Date: Wed, 25 Dec 2024 15:08:15 +0700 Subject: [PATCH 047/225] = 4.2.7.6 = ~ Clean code. --- inc/lp-core-functions.php | 131 +++----------------------------------- 1 file changed, 9 insertions(+), 122 deletions(-) diff --git a/inc/lp-core-functions.php b/inc/lp-core-functions.php index 1d3e4acd0..b698aa221 100644 --- a/inc/lp-core-functions.php +++ b/inc/lp-core-functions.php @@ -335,19 +335,6 @@ function learn_press_get_current_url() { return $current_url; } -/** - * Compares an url with current URL user is viewing - * - * @param string $url - * - * @return bool - */ -function learn_press_is_current_url( $url ) { - $current_url = learn_press_get_current_url(); - - return ( $current_url && $url ) && strcmp( $current_url, learn_press_sanitize_url( $url ) ) == 0; -} - /** * Remove unneeded characters in an URL * @@ -364,7 +351,7 @@ function learn_press_sanitize_url( $url, $trailingslashit = true ) { $url = $matches[1] . $url_without_http; return ( $trailingslashit && - strpos( $url, '?' ) === false ) ? trailingslashit( $url ) : untrailingslashit( $url ); + strpos( $url, '?' ) === false ) ? trailingslashit( $url ) : untrailingslashit( $url ); } return $url; @@ -660,7 +647,7 @@ function learn_press_paging_nav( $args = array() ) { if ( $links ) { ?>
    - +
    maybe a bug :) -// * from => ( wp_2_posts.post_status = 'publish' OR wp_2_posts.post_status = 'private') OR wp_2_terms.name LIKE '%s%' -// * to => ( ( wp_2_posts.post_status = 'publish' OR wp_2_posts.post_status = 'private') OR wp_2_terms.name LIKE '%s%' ) -// */ -// $a = preg_match( '!(' . $wpdb->posts . '.post_status)!', $where ); -// $b = preg_match( '!(OR\s+' . $wpdb->terms . '.name LIKE \'%' . $wp_query->get( 's' ) . '%\')!', $where ); -// -// if ( $a && $b ) { -// // append ( to the start of the block -// $where = preg_replace( '!(' . $wpdb->posts . '.post_status)!', '( $1', $where, 1 ); -// -// // append ) to the end of the block -// $where = preg_replace( -// '!(OR\s+' . $wpdb->terms . '.name LIKE \'%' . $wp_query->get( 's' ) . '%\')!', -// '$1 )', -// $where -// ); -// } -// remove_filter( 'posts_where', 'learn_press_posts_where_statement_search', 99 ); -// -// return $where; -//} - -/** - * Filter post type for search function - * Only search lpr_course if see the param ref=course in request - * - * @param WP_Query $q - * @deprecated 4.1.7.2 - */ -/*function learn_press_filter_search( $q ) { - if ( $q->is_main_query() && $q->is_search() && ( ! empty( $_REQUEST['ref'] ) && sanitize_text_field( $_REQUEST['ref'] ) == 'course' ) ) { - $q->set( 'post_type', 'lp_course' ); - - add_filter( 'posts_where', 'learn_press_posts_where_statement_search', 99 ); - remove_filter( 'pre_get_posts', 'learn_press_filter_search', 99 ); - } -}*/ -//add_filter( 'pre_get_posts', 'learn_press_filter_search', 99 ); - if ( ! function_exists( 'learn_press_send_json' ) ) { function learn_press_send_json( $data ) { echo '<-- LP_AJAX_START -->'; @@ -1724,17 +1658,13 @@ function learn_press_is_course_tag( $term = '' ) { } if ( ! function_exists( 'learn_press_is_course' ) ) { - function learn_press_is_course() { - /** - * @var WP_Query $wp_query - */ - global $wp_query; - - if ( $wp_query->get_queried_object() ) { + function learn_press_is_course(): bool { + try { return is_singular( array( LP_COURSE_CPT ) ); - } else { - return false; + } catch ( Throwable $e ) { } + + return false; } } @@ -1902,49 +1832,6 @@ function learn_press_get_endpoint_url( $name, $value, $url ) { return apply_filters( 'learn_press_get_endpoint_url', esc_url_raw( $url ), $name, $value, $url ); } -/** - * Add all endpoints from settings to the pages. - * @deprecated 4.2.3 - * @use LP_Query::add_rewrite_endpoints instead - */ -//function learn_press_add_endpoints() { -// // Must LP_Profile::instance call on init, because it will add action hook to save data on Profile page -// // If rewrite save data on Profile page, can remove it. -// //LP_Profile::instance( get_current_user_id() ); -// -// $settings = LP_Settings::instance(); -// -// $endpoints = $settings->get_checkout_endpoints(); -// if ( $endpoints ) { -// foreach ( $endpoints as $endpoint => $value ) { -// LearnPress::instance()->query_vars[ $endpoint ] = $value; -// add_rewrite_endpoint( $value, EP_PAGES ); -// } -// } -// -// $endpoints = $settings->get_profile_endpoints(); -// if ( $endpoints ) { -// foreach ( $endpoints as $endpoint => $value ) { -// LearnPress::instance()->query_vars[ $endpoint ] = $value; -// add_rewrite_endpoint( $value, EP_PAGES ); -// } -// } -// -// $endpoints = $settings->get( 'quiz_endpoints' ); -// if ( $endpoints ) { -// foreach ( $endpoints as $endpoint => $value ) { -// $endpoint = preg_replace( '!_!', '-', $endpoint ); -// LearnPress::instance()->query_vars[ $endpoint ] = $value; -// add_rewrite_endpoint( -// $value, /*EP_ROOT | */ -// EP_PAGES -// ); -// } -// } -//} - -//add_action( 'init', 'learn_press_add_endpoints' ); - /** * @deprecated 4.2.3 */ @@ -3271,7 +3158,7 @@ function lp_add_shortcode_profile() { */ add_filter( 'elementor/theme/get_location_templates/template_id', - function( $theme_template_id ) { + function ( $theme_template_id ) { $elementor_template_type = get_post_meta( $theme_template_id, '_elementor_template_type', true ); if ( in_array( $elementor_template_type, array( 'archive' ) ) ) { From 468485f5d958125e0e71e634132e26985ed5b411 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Wed, 25 Dec 2024 15:08:56 +0700 Subject: [PATCH 048/225] = 4.2.7.6 = ~ Handle layout single course. --- learnpress.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/learnpress.php b/learnpress.php index a77eabe04..b96b75ee8 100644 --- a/learnpress.php +++ b/learnpress.php @@ -168,6 +168,11 @@ private function __construct() { if ( is_admin() ) { $learn_press_version = get_option( 'learnpress_version', '' ); if ( $learn_press_version !== $this->version ) { + if ( empty( $learn_press_version ) ) { // Case user install new + // Set using modern layout for new installation. + update_option( 'learn_press_layout_single_course', 'modern' ); + } + update_option( 'learnpress_version', $this->version ); } } From ef7b5905e0bce5321ed3b168636debfe54e3cc6e Mon Sep 17 00:00:00 2001 From: Tungnx Date: Wed, 25 Dec 2024 15:09:24 +0700 Subject: [PATCH 049/225] = 4.2.7.6 = ~ Tweak build release. --- build-release.js | 4 +++- package.json | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/build-release.js b/build-release.js index 3bd645d22..22a641232 100644 --- a/build-release.js +++ b/build-release.js @@ -12,6 +12,7 @@ console.log('Starting build...'); const buildJS = spawn('npm', ['run', 'start'], { stdio: 'inherit', shell: true, + env: { ...process.env, NODE_OPTIONS: '--openssl-legacy-provider' } }); buildJS.on('exit', () => { @@ -22,7 +23,8 @@ buildJS.on('spawn', () => { // Run command: npm run build-makepot-zip const releaseProcess = spawn('npm', ['run', 'build-makepot-zip'], { stdio: 'inherit', - shell: true + shell: true, + env: { ...process.env, NODE_OPTIONS: '--openssl-legacy-provider' } }); releaseProcess.on('exit', (code) => { diff --git a/package.json b/package.json index fe37c2a67..a9656dcf0 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "[![Stories in Ready](https://badge.waffle.io/LearnPress/LearnPress.svg?label=ready&title=Ready)](http://waffle.io/LearnPress/LearnPress)", "main": "index.js", "scripts": { - "start": "cross-env wp-scripts start", - "build": "cross-env wp-scripts build", + "start": "cross-env wp-scripts start", + "build": "cross-env wp-scripts build", "format-js": "cross-env wp-scripts format ./assets/src", "dev-build": "cross-env npm run build && gulp styles && npm run dev", "makepot:js": "wp-babel-makepot \"./assets/src/**/*.{js,jsx,ts,tsx}\" --ignore \"**/node_modules/**,**/test/**,**/*.d.ts\" --base \"./\" --dir \"./languages/strings\" --output \"./languages/learnpress-js.pot\"", From e6c09cf8617bdc9ae053ecec052a456e6aece726 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Thu, 26 Dec 2024 14:54:42 +0700 Subject: [PATCH 050/225] = 4.2.7.6 = ~ CourseModel: tweak get_image_url method. ~ CourseModel: added get_item_model method. --- inc/Models/CourseModel.php | 64 +++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/inc/Models/CourseModel.php b/inc/Models/CourseModel.php index 9784af6f6..005e2539c 100644 --- a/inc/Models/CourseModel.php +++ b/inc/Models/CourseModel.php @@ -22,6 +22,7 @@ use LP_Course_JSON_Filter; use LP_Datetime; use LP_Helper; +use LP_Lesson; use LP_Settings; use stdClass; use Throwable; @@ -152,13 +153,15 @@ public function get_title(): string { * * @return string * @throws Exception + * @since 4.2.6.9 + * @version 1.0.1 */ public function get_image_url(): string { $image_url = ''; - if ( ! empty( $this->image_url ) ) { + /*if ( ! empty( $this->image_url ) ) { return $this->image_url; - } + }*/ $post = new CoursePostModel( $this ); $image_url = $post->get_image_url(); @@ -503,10 +506,10 @@ public function get_final_quiz(): int { * * @return array * @since 4.1.6.9 - * @version 1.0.2 + * @version 1.0.3 * @author tungnx */ - public function get_sections_and_items_course_from_db_and_sort(): array { + private function get_sections_and_items_course_from_db_and_sort(): array { $sections_items = []; $course_id = $this->get_id(); $lp_course_db = LP_Course_DB::getInstance(); @@ -1053,6 +1056,59 @@ public function can_purchase( $user ) { return apply_filters( 'learn-press/user/can-purchase/course', $can_purchase, $this, $user ); } + /** + * Get item model assigned to this course + * + * @return mixed|false|null + * @since v4.2.7.6 + * @version 1.0.0 + */ + public function get_item_model( int $item_id, string $item_type ) { + try { + $item = false; + + $type = str_replace( 'lp_', '', $item_type ); + $findClassPostModel = ucfirst( $type ) . 'PostModel'; + $findClassModel = ucfirst( $type ) . 'Model'; // For feature, lesson, quiz, question has new table unique. + + if ( class_exists( $findClassModel ) ) { + if ( is_callable( [ $findClassModel, 'find' ] ) ) { + $item = call_user_func( [ $findClassModel, 'find' ], $item_id, true ); + } + } elseif ( class_exists( $findClassPostModel ) ) { + $item = call_user_func( [ $findClassPostModel, 'find' ], $item_id ); + } + + switch ( $item_type ) { + case LP_QUIZ_CPT: + $item = QuizPostModel::find( $item_id, true ); + break; + default: + $class_name = apply_filters( + 'learn-press/course/item-model', + $item_id, + $item_type + ); + + if ( class_exists( $class_name ) ) { + if ( is_callable( [ $class_name, 'find' ] ) ) { + $item = call_user_func( [ $class_name, 'find' ], $item_id, true ); + } + } + + break; + } + + if ( ! $item ) { + $item = get_post( $item_id ); + } + } catch ( Exception $e ) { + error_log( __METHOD__ . ': ' . $e->getMessage() ); + } + + return $item; + } + /** * Get item model if query success. * If not exists, return false. From 17eda4a0aa0df4e981b8b6d5b6161e171c23ef13 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Thu, 26 Dec 2024 18:43:00 +0700 Subject: [PATCH 051/225] = 4.2.7.6 = ~ Tweak clear cache lesson, quiz, question, course. --- inc/Databases/class-lp-course-db.php | 4 +- inc/Helpers/Template.php | 2 +- .../class-lp-background-single-course.php | 6 ++- inc/course/class-lp-course-item.php | 2 +- inc/course/lp-course-functions.php | 3 +- inc/custom-post-types/course.php | 11 ------ inc/custom-post-types/lesson.php | 19 ++++++++- inc/custom-post-types/question.php | 39 +++++++------------ inc/custom-post-types/quiz.php | 18 ++++++--- 9 files changed, 55 insertions(+), 49 deletions(-) diff --git a/inc/Databases/class-lp-course-db.php b/inc/Databases/class-lp-course-db.php index 73a236662..9f06b05e4 100644 --- a/inc/Databases/class-lp-course-db.php +++ b/inc/Databases/class-lp-course-db.php @@ -6,6 +6,8 @@ * @since 3.2.7.5 */ +use LearnPress\Models\CourseModel; + defined( 'ABSPATH' ) || exit(); class LP_Course_DB extends LP_Database { @@ -368,7 +370,7 @@ public function get_total_user_enrolled_or_purchased( int $course_id ): int { * @since 4.1.4.1 */ public function get_total_items( int $course_id = 0 ) { - $item_types = learn_press_get_course_item_types(); + $item_types = CourseModel::item_types_support(); $count_item_types = count( $item_types ); $i = 0; diff --git a/inc/Helpers/Template.php b/inc/Helpers/Template.php index 0f034c0aa..a36447c78 100644 --- a/inc/Helpers/Template.php +++ b/inc/Helpers/Template.php @@ -303,7 +303,7 @@ public static function insert_value_to_position_array( $old_array, $position, $k * * @param string $message * @param string $status 'success', 'warning', 'error, 'info' - * @param bool $print_mess since 4.2.7.6 + * @param bool $has_print since 4.2.7.6, true for print, false for return * * @return void|string * @since 4.2.6.9.3 diff --git a/inc/background-process/class-lp-background-single-course.php b/inc/background-process/class-lp-background-single-course.php index db1dfd792..c433511f7 100644 --- a/inc/background-process/class-lp-background-single-course.php +++ b/inc/background-process/class-lp-background-single-course.php @@ -114,6 +114,8 @@ protected function save_post() { $lp_courses_cache = new LP_Courses_Cache( true ); $lp_courses_cache->clear_cache_on_group( LP_Courses_Cache::KEYS_COUNT_COURSES_FREE ); // End + + $lp_courses_cache->clear_cache_on_group( LP_Courses_Cache::KEYS_QUERY_COURSES_APP ); } /** @@ -191,12 +193,12 @@ protected function save_price( CourseModel &$courseObj ) { $sale_price = $courseObj->get_sale_price(); if ( (float) $regular_price < 0 ) { $courseObj->meta_data->{CoursePostModel::META_KEY_REGULAR_PRICE} = ''; - $regular_price = $courseObj->get_regular_price(); + $regular_price = $courseObj->get_regular_price(); } if ( (float) $sale_price > (float) $regular_price ) { $courseObj->meta_data->{CoursePostModel::META_KEY_SALE_PRICE} = ''; - $sale_price = $courseObj->get_sale_price(); + $sale_price = $courseObj->get_sale_price(); } // Save sale regular price and sale price to table postmeta diff --git a/inc/course/class-lp-course-item.php b/inc/course/class-lp-course-item.php index c5bf30ca6..1c70f907c 100644 --- a/inc/course/class-lp-course-item.php +++ b/inc/course/class-lp-course-item.php @@ -424,7 +424,7 @@ public static function get_item( $item_id = 0, $course_id = 0 ) { } } - return apply_filters( 'learn-press/get-course-item', $item, $item_type, $item_id ); + return $item; } /** diff --git a/inc/course/lp-course-functions.php b/inc/course/lp-course-functions.php index 3ea02e006..12be56860 100644 --- a/inc/course/lp-course-functions.php +++ b/inc/course/lp-course-functions.php @@ -78,13 +78,14 @@ function learn_press_get_course( $the_course = 0 ) { * Get type of items are supported in course curriculum (post types). * Default: [lp_lesson, lp_quiz] * When all addon use hook 'learn-press/course/item-types-support', will deprecate this function - * @use CourseMoel::item_types_support + * @use CourseModel::item_types_support * * @return mixed * @since 3.0.0 * @editor tungnx * @version 1.0.1 * @return array + * @deprecated */ function learn_press_get_course_item_types( bool $return_only_value = true ): array { return apply_filters( diff --git a/inc/custom-post-types/course.php b/inc/custom-post-types/course.php index 0f16d6b92..01b4d5b22 100644 --- a/inc/custom-post-types/course.php +++ b/inc/custom-post-types/course.php @@ -37,7 +37,6 @@ public function __construct() { add_action( 'init', array( $this, 'register_taxonomy' ) ); add_filter( 'posts_where_paged', array( $this, '_posts_where_paged_course_items' ), 10 ); add_filter( 'posts_join_paged', array( $this, '_posts_join_paged_course_items' ), 10 ); - add_action( 'clean_post_cache', [ $this, 'clear_cache' ] ); } /** @@ -640,16 +639,6 @@ protected function save_price( CourseModel &$courseObj ) { $coursePost->save_meta_value_by_key( CoursePostModel::META_KEY_PRICE, $courseObj->price_to_sort ); } - /** - * Clear cache courses - * - * @return void - */ - public function clear_cache() { - $lp_cache_course = new LP_Courses_Cache( true ); - $lp_cache_course->clear_cache_on_group( LP_Courses_Cache::KEYS_QUERY_COURSES_APP ); - } - /** * Instance LP_Course_Post_Type. * diff --git a/inc/custom-post-types/lesson.php b/inc/custom-post-types/lesson.php index fe9ee8dcb..08b92ee77 100644 --- a/inc/custom-post-types/lesson.php +++ b/inc/custom-post-types/lesson.php @@ -43,6 +43,24 @@ public function __construct() { parent::__construct(); } + /** + * Handle when save post. + * + * @param int $post_id + * @param WP_Post|null $post + * @param bool $is_update + * + * @return void + * @since 4.2.7.6 + * @version 1.0.0 + */ + public function save_post( int $post_id, WP_Post $post = null, bool $is_update = false ) { + // Clear cache + $lpCache = new LP_Cache(); + $lpCache->clear( "lessonPostModel/find/{$post_id}" ); + $lpCache->clear( "lessonModel/find/{$post_id}" ); + } + /** * Filter items unassigned. * @@ -191,7 +209,6 @@ public function args_register_post_type(): array { 'with_front' => false, ), ); - } /** diff --git a/inc/custom-post-types/question.php b/inc/custom-post-types/question.php index 2d7531e67..85016061c 100644 --- a/inc/custom-post-types/question.php +++ b/inc/custom-post-types/question.php @@ -263,29 +263,21 @@ public function before_delete_question( int $question_id = 0 ) { } /** - * Add default answer when save new question action. + * Handle when save post. * - * @param int $post_id - * @param WP_Post $post - * @since 3.0.0 + * @param int $post_id + * @param WP_Post|null $post + * @param bool $is_update + * + * @return void + * @since 4.2.7.6 + * @version 1.0.0 */ - public function save( int $post_id, WP_Post $post ) { - /*$question_id = $post_id; - - $question_type = LP_Helper::sanitize_params_submitted( $_REQUEST['question-type'] ?? '' ); - - if ( empty( $question_type ) ) { - $types = array_keys( LP_Question::get_types() ); - $question_type = reset( $types ); - } - - update_post_meta( $question_id, '_lp_type', $question_type ); - - $question = LP_Question::get_question( $question_id ); - - if ( $question->is_support( 'answer-options' ) ) { - $question->create_default_answers(); - }*/ + public function save_post( int $post_id, WP_Post $post = null, bool $is_update = false ) { + // Clear cache get question by id + $lpCache = new LP_Cache(); + $lpCache->clear( "questionPostModel/find/{$post_id}" ); + $lpCache->clear( "questionModel/find/{$post_id}" ); } /** @@ -526,9 +518,4 @@ public static function instance() { } $question_post_type = LP_Question_Post_Type::instance(); - - // Todo: Nhamdv see to rewrite - // $question_post_type - // ->add_meta_box( 'lesson_assigned', esc_html__( 'Assigned', 'learnpress' ), 'question_assigned', 'side', 'high' ) - // ->add_meta_box( 'question-editor', esc_html__( 'Answer Options', 'learnpress' ), 'admin_editor', 'normal', 'high', 1 ); } diff --git a/inc/custom-post-types/quiz.php b/inc/custom-post-types/quiz.php index 9fcae8fbc..b18bb81e6 100644 --- a/inc/custom-post-types/quiz.php +++ b/inc/custom-post-types/quiz.php @@ -480,16 +480,24 @@ public static function instance() { } /** - * Save Post type Quiz + * Handle when save post. * - * @author tungnx + * @param int $post_id + * @param WP_Post|null $post + * @param bool $is_update + * + * @return void + * @since 4.2.7.6 * @version 1.0.0 - * @since 4.0.0 */ - public function save( int $post_id, WP_Post $post ) { - $lp_quiz_cache = LP_Quiz_Cache::instance(); + public function save_post( int $post_id, WP_Post $post = null, bool $is_update = false ) { + // Clear cache get quiz by id + $lpCache = new LP_Cache(); + $lpCache->clear( "quizPostModel/find/{$post_id}" ); + $lpCache->clear( "quizModel/find/{$post_id}" ); // Clear cache get question_ids of quiz + $lp_quiz_cache = LP_Quiz_Cache::instance(); $lp_quiz_cache->clear( "$post_id/question_ids" ); } } From 8dc0963821f1f48566eb0f7ff8b7d97e5faeeb17 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Thu, 26 Dec 2024 18:52:52 +0700 Subject: [PATCH 052/225] = 4.2.7.6 = ~ SingleCourseTemplate: added html_curriculum, render_html_section_item, render_html_course_item methods. ~ Tweak SingleCourseModernLayout class. ~ Tweak: CourseModel class. ~ UserItemModel: add constants. ~ UserCourseModel: tweak get_item_attend, calculate_course_results, evaluate_course_by_final_quiz ~ Added: LessonPostModel class. --- inc/Models/CourseModel.php | 44 +-- inc/Models/CoursePostModel.php | 1 + inc/Models/LessonPostModel.php | 78 +++++ inc/Models/UserItems/UserCourseModel.php | 111 +++--- inc/Models/UserItems/UserItemModel.php | 8 + inc/Models/UserItems/UserQuizModel.php | 4 - .../Course/ListCoursesTemplate.php | 27 +- ...plate.php => SingleCourseModernLayout.php} | 40 ++- .../Course/SingleCourseTemplate.php | 317 +++++++++++++++++- .../UserItem/UserCourseTemplate.php | 9 + .../UserItem/UserItemBaseTemplate.php | 23 +- learnpress.php | 4 +- 12 files changed, 512 insertions(+), 154 deletions(-) create mode 100644 inc/Models/LessonPostModel.php rename inc/TemplateHooks/Course/{SingleCourseModelTemplate.php => SingleCourseModernLayout.php} (91%) diff --git a/inc/Models/CourseModel.php b/inc/Models/CourseModel.php index 005e2539c..c71dec34d 100644 --- a/inc/Models/CourseModel.php +++ b/inc/Models/CourseModel.php @@ -7,7 +7,7 @@ * Another fields for query list courses faster * * @package LearnPress/Classes - * @version 1.0.2 + * @version 1.0.3 * @since 4.2.6.9 */ @@ -413,6 +413,19 @@ public function get_total_items() { return $this->total_items; } + /** + * Get total sections of course + * + * @return int + * @since 4.2.7.6 + * @version 1.0.0 + */ + public function get_total_sections(): int { + $section_items = $this->get_section_items(); + + return count( $section_items ); + } + /** * Get total items of course * @@ -1076,29 +1089,10 @@ public function get_item_model( int $item_id, string $item_type ) { $item = call_user_func( [ $findClassModel, 'find' ], $item_id, true ); } } elseif ( class_exists( $findClassPostModel ) ) { - $item = call_user_func( [ $findClassPostModel, 'find' ], $item_id ); - } - - switch ( $item_type ) { - case LP_QUIZ_CPT: - $item = QuizPostModel::find( $item_id, true ); - break; - default: - $class_name = apply_filters( - 'learn-press/course/item-model', - $item_id, - $item_type - ); - - if ( class_exists( $class_name ) ) { - if ( is_callable( [ $class_name, 'find' ] ) ) { - $item = call_user_func( [ $class_name, 'find' ], $item_id, true ); - } - } - - break; + $item = call_user_func( [ $findClassPostModel, 'find' ], $item_id, true ); } + // If not defined class, get post default if ( ! $item ) { $item = get_post( $item_id ); } @@ -1271,6 +1265,7 @@ public function clean_caches() { * * @return array * @since 4.2.7.4 + * @version 1.0.1 */ public static function item_types_support(): array { $item_types = [ @@ -1278,6 +1273,11 @@ public static function item_types_support(): array { LP_QUIZ_CPT, ]; + // Hook old + if ( has_filter( 'learn-press/course-item-type' ) ) { + $item_types = apply_filters( 'learn-press/course-item-type', $item_types ); + } + return apply_filters( 'learn-press/course/item-types-support', $item_types ); } } diff --git a/inc/Models/CoursePostModel.php b/inc/Models/CoursePostModel.php index 10bd4f111..441f2b3c1 100644 --- a/inc/Models/CoursePostModel.php +++ b/inc/Models/CoursePostModel.php @@ -62,6 +62,7 @@ class CoursePostModel extends PostModel { const META_KEY_FAQS = '_lp_faqs'; const META_KEY_PRICE_PREFIX = '_lp_price_prefix'; const META_KEY_PRICE_SUFFIX = '_lp_price_suffix'; + const META_KEY_FINAL_QUIZ = '_lp_final_quiz'; /** * Get the price of course. diff --git a/inc/Models/LessonPostModel.php b/inc/Models/LessonPostModel.php new file mode 100644 index 000000000..9e1367735 --- /dev/null +++ b/inc/Models/LessonPostModel.php @@ -0,0 +1,78 @@ +ID = $post_id; + $filter_post->post_type = LP_LESSON_CPT; + + $key_cache = "lessonPostModel/find/{$post_id}"; + $lpLessonCache = new LP_Cache(); + + // Check cache + if ( $check_cache ) { + $lessonPostModel = $lpLessonCache->get_cache( $key_cache ); + if ( $lessonPostModel instanceof self ) { + return $lessonPostModel; + } + } + + $lessonPostModel = self::get_item_model_from_db( $filter_post ); + // Set cache + if ( $lessonPostModel instanceof LessonPostModel ) { + $lpLessonCache->set_cache( $key_cache, $lessonPostModel ); + } + + return $lessonPostModel; + } + + /** + * Get duration lesson + * + * @return string + */ + public function get_duration(): string { + return $this->get_meta_value_by_key( self::META_KEY_DURATION, '0 minute' ); + } + + /** + * Check lesson enable preview + * + * @return bool + */ + public function has_preview(): bool { + return $this->get_meta_value_by_key( self::META_KEY_PREVIEW, 'no' ) === 'yes'; + } +} diff --git a/inc/Models/UserItems/UserCourseModel.php b/inc/Models/UserItems/UserCourseModel.php index 65a60e36f..01cf39b86 100644 --- a/inc/Models/UserItems/UserCourseModel.php +++ b/inc/Models/UserItems/UserCourseModel.php @@ -4,7 +4,7 @@ * Class UserItemModel * * @package LearnPress/Classes - * @version 1.0.0 + * @version 1.0.1 * @since 4.2.5 */ @@ -13,19 +13,18 @@ use Exception; use LearnPress\Models\CourseModel; use LearnPress\Models\CoursePostModel; -use LearnPress\Models\UserModel; +use LearnPress\Models\QuizPostModel; use LP_Cache; -use LP_Course; use LP_Course_Cache; use LP_Course_Item; use LP_Courses_Cache; use LP_Datetime; use LP_User; +use LP_User_Item_Course; use LP_User_Items_DB; use LP_User_Items_Filter; use LP_User_Items_Result_DB; use stdClass; -use Thim_Cache_DB; use Throwable; use WP_Error; @@ -108,14 +107,21 @@ public function get_item_attend( int $item_id, string $item_type = '' ) { $item = false; try { - $filter = new LP_User_Items_Filter(); - $filter->parent_id = $this->get_user_item_id(); - $filter->item_id = $item_id; - $filter->item_type = $item_type; - $filter->ref_type = $this->item_type; - $filter->ref_id = $this->item_id; - $filter->user_id = $this->user_id; - $item = UserItemModel::get_user_item_model_from_db( $filter ); +// $filter = new LP_User_Items_Filter(); +// $filter->parent_id = $this->get_user_item_id(); +// $filter->item_id = $item_id; +// $filter->item_type = $item_type; +// $filter->ref_type = $this->item_type; +// $filter->ref_id = $this->item_id; +// $filter->user_id = $this->user_id; + $item = UserItemModel::find_user_item( + $this->user_id, + $item_id, + $item_type, + $this->item_id, + $this->item_type, + true + ); if ( $item ) { switch ( $item_type ) { @@ -123,7 +129,6 @@ public function get_item_attend( int $item_id, string $item_type = '' ) { $item = new UserQuizModel( $item ); break; default: - $item = new UserItemModel( $item ); break; } @@ -224,7 +229,7 @@ public function is_finished(): bool { * * @move from class-lp-user-item-course.php * @since 4.1.4 - * @version 1.0.2 + * @version 1.0.3 */ public function calculate_course_results( bool $force_cache = false ) { $items = array(); @@ -278,7 +283,13 @@ public function calculate_course_results( bool $force_cache = false ) { $results_evaluate = $this->evaluate_course_by_question( $evaluate_type ); break; default: - $results_evaluate = apply_filters( 'learn-press/evaluate_passed_conditions', $results, $evaluate_type, $this ); + // Old Hook + if ( has_filter( 'learn-press/evaluate_passed_conditions' ) ) { + $user_course_old = new LP_User_Item_Course( $this ); + $results = apply_filters( 'learn-press/evaluate_passed_conditions', $results, $evaluate_type, $user_course_old ); + } + + $results_evaluate = apply_filters( 'learn-press/evaluate/calculate', $results, $evaluate_type, $this ); break; } @@ -293,7 +304,7 @@ public function calculate_course_results( bool $force_cache = false ) { $completed_items = intval( $count_items_completed->count_status ?? 0 ); - $item_types = learn_press_get_course_item_types(); + $item_types = CourseModel::item_types_support(); foreach ( $item_types as $item_type ) { $item_type_key = str_replace( 'lp_', '', $item_type ); @@ -449,18 +460,8 @@ public function count_items_completed() { $count_items_completed = new stdClass(); try { - $course = learn_press_get_course( $this->item_id ); - if ( ! $course ) { - throw new Exception( 'Course is invalid!' ); - } - - $user_course = $this->get_last_user_course(); - if ( ! $user_course ) { - throw new Exception( 'User course is invalid!' ); - } - $filter_count = new LP_User_Items_Filter(); - $filter_count->parent_id = $user_course->user_item_id; + $filter_count->parent_id = $this->get_user_item_id(); $filter_count->item_id = $this->item_id; $filter_count->user_id = $this->user_id; $filter_count->status = LP_ITEM_COMPLETED; @@ -473,27 +474,6 @@ public function count_items_completed() { return $count_items_completed; } - /** - * Get child item ids by type item - * - * @return object|null - */ - public function get_last_user_course() { - $lp_user_items_db = LP_User_Items_DB::getInstance(); - $user_course = null; - - try { - $filter_user_course = new LP_User_Items_Filter(); - $filter_user_course->item_id = $this->item_id; - $filter_user_course->user_id = $this->user_id; - $user_course = $lp_user_items_db->get_last_user_course( $filter_user_course ); - } catch ( Throwable $e ) { - error_log( __FUNCTION__ . ':' . $e->getMessage() ); - } - - return $user_course; - } - /** * Get graduation of course. * @@ -561,30 +541,27 @@ protected function evaluate_course_by_final_quiz(): array { ); try { - $quiz_final_id = get_post_meta( $this->get_course_model()->get_id(), '_lp_final_quiz', true ); - if ( ! $quiz_final_id ) { - throw new Exception( '' ); + $courseModel = $this->get_course_model(); + if ( ! $courseModel ) { + return $evaluate; } - $quiz_final = learn_press_get_quiz( $quiz_final_id ); - - if ( ! $quiz_final ) { - throw new Exception( 'Quiz final invalid' ); + $quiz_final_id = $courseModel->get_meta_value_by_key( CoursePostModel::META_KEY_FINAL_QUIZ, 0 ); + if ( ! $quiz_final_id ) { + return $evaluate; } - $user_course = $this->get_last_user_course(); - - if ( ! $user_course ) { - throw new Exception( 'User course not exists' ); + $quizPostModel = QuizPostModel::find( $quiz_final_id, true ); + if ( ! $quizPostModel ) { + return $evaluate; } $filter = new LP_User_Items_Filter(); $filter->query_type = 'get_row'; - $filter->parent_id = $user_course->user_item_id; + $filter->parent_id = $this->get_user_item_id(); $filter->item_type = LP_QUIZ_CPT; $filter->item_id = $quiz_final_id; $user_quiz = $lp_user_items_db->get_user_course_items_by_item_type( $filter ); - if ( ! $user_quiz ) { throw new Exception(); } @@ -599,7 +576,7 @@ protected function evaluate_course_by_final_quiz(): array { $evaluate['result'] = $quiz_result['result']; } - $passing_condition = floatval( $quiz_final->get_data( 'passing_grade', 0 ) ); + $passing_condition = $quizPostModel->get_passing_grade(); if ( $evaluate['result'] >= $passing_condition ) { $evaluate['pass'] = 1; } @@ -700,7 +677,7 @@ private function evaluate_course_by_mark( &$evaluate, $lp_quizzes, $total_mark_q * * @author tungnx * @since 4.1.4.1 - * @version 1.0.1 + * @version 1.0.2 */ protected function evaluate_course_by_question( string $evaluate_type ): array { $lp_user_items_db = LP_User_Items_DB::getInstance(); @@ -710,15 +687,9 @@ protected function evaluate_course_by_question( string $evaluate_type ): array { ); try { - $user_course = $this->get_last_user_course(); - - if ( ! $user_course ) { - throw new Exception( 'User course not exists!' ); - } - // get quiz_ids $filter_get_quiz_ids = new LP_User_Items_Filter(); - $filter_get_quiz_ids->parent_id = $user_course->user_item_id; + $filter_get_quiz_ids->parent_id = $this->get_user_item_id(); $filter_get_quiz_ids->item_type = LP_QUIZ_CPT; $lp_quizzes = $lp_user_items_db->get_user_course_items_by_item_type( $filter_get_quiz_ids ); diff --git a/inc/Models/UserItems/UserItemModel.php b/inc/Models/UserItems/UserItemModel.php index 040922929..01ab9dcb5 100644 --- a/inc/Models/UserItems/UserItemModel.php +++ b/inc/Models/UserItems/UserItemModel.php @@ -98,6 +98,14 @@ class UserItemModel { */ public $meta_data; + // Constants + const STATUS_COMPLETED = 'completed'; + const STATUS_FINISHED = 'finished'; + const STATUS_ENROLLED = 'enrolled'; + const STATUS_IN_PROGRESS = 'in-progress'; + const GRADUATION_PASSED = 'passed'; + const GRADUATION_FAILED = 'failed'; + /** * If data get from database, map to object. * Else create new object to save data to database. diff --git a/inc/Models/UserItems/UserQuizModel.php b/inc/Models/UserItems/UserQuizModel.php index f93cc6b33..84882e945 100644 --- a/inc/Models/UserItems/UserQuizModel.php +++ b/inc/Models/UserItems/UserQuizModel.php @@ -44,10 +44,6 @@ class UserQuizModel extends UserItemModel { public function __construct( $data = null ) { parent::__construct( $data ); - - if ( $data ) { - $this->get_quiz_post_model(); - } } /** diff --git a/inc/TemplateHooks/Course/ListCoursesTemplate.php b/inc/TemplateHooks/Course/ListCoursesTemplate.php index 82be2cd81..b2728218b 100644 --- a/inc/TemplateHooks/Course/ListCoursesTemplate.php +++ b/inc/TemplateHooks/Course/ListCoursesTemplate.php @@ -105,16 +105,15 @@ public static function render_courses( array $settings = [] ): stdClass { $listCoursesTemplate = self::instance(); // HTML section courses. - ob_start(); + $html_courses = ''; if ( empty( $courses ) ) { - Template::print_message( __( 'No courses found', 'learnpress' ), 'info' ); + $html_courses = Template::print_message( __( 'No courses found', 'learnpress' ), 'info', false ); } else { foreach ( $courses as $courseObj ) { - $course = CourseModel::find( $courseObj->ID, true ); - echo static::render_course( $course, $settings ); + $course = CourseModel::find( $courseObj->ID, true ); + $html_courses .= static::render_course( $course, $settings ); } } - $html_courses = ob_get_clean(); $section_courses = [ 'wrapper' => sprintf( '
      ', $skin ), @@ -500,7 +499,7 @@ public function html_layout_type( array $data = [] ): string { $content = '
        '; foreach ( $layouts as $k => $v ) { - $active = ( $data['courses_layout_default'] ?? '' ) === $k ? 'active' : ''; + $active = ( $data['courses_layout_default'] ?? '' ) === $k ? 'active' : ''; $content .= '
      • ' . $v . '
      • '; } $content .= '
      '; @@ -548,10 +547,10 @@ public function html_search_form( array $data = [] ) { ob_start(); ?>
      + action=""> + name="c_search" + value="">
      $value ) : ?> > + value="" + id="lp-switch-layout-btn-" > + title="" + for="lp-switch-layout-btn-">
    '
  • ', diff --git a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php b/inc/TemplateHooks/Course/SingleCourseModernLayout.php similarity index 91% rename from inc/TemplateHooks/Course/SingleCourseModelTemplate.php rename to inc/TemplateHooks/Course/SingleCourseModernLayout.php index b5b97b5ea..c1d9fb3cf 100644 --- a/inc/TemplateHooks/Course/SingleCourseModelTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseModernLayout.php @@ -13,12 +13,10 @@ use LearnPress\Models\CourseModel; use LearnPress\Models\UserItems\UserCourseModel; use LearnPress\TemplateHooks\UserItem\UserCourseTemplate; -use LearnPress\Models\CoursePostModel; use LearnPress\Models\UserModel; use LearnPress\TemplateHooks\Instructor\SingleInstructorTemplate; -use LP_Course; -class SingleCourseModelTemplate { +class SingleCourseModernLayout { use Singleton; /** @@ -120,6 +118,8 @@ public function header_sections( $course, $user ): string { 'wrapper_container_end' => '
  • ', 'wrapper_header_end' => '
    ', ], + $course, + $user ); return Template::combine_components( $header_sections ); @@ -197,7 +197,7 @@ public function section_left( $course, $user ): string { 'features' => $this->singleCourseTemplate->html_features( $course ), 'target' => $this->singleCourseTemplate->html_target( $course ), 'requirements' => $this->singleCourseTemplate->html_requirements( $course ), - //'curriculum' => $this->html_curriculum( $course, $user ), + 'curriculum' => $this->singleCourseTemplate->html_curriculum( $course, $user ), 'material' => $this->singleCourseTemplate->html_material( $course ), 'faqs' => $this->singleCourseTemplate->html_faqs( $course ), 'instructor' => $html_instructor, @@ -263,7 +263,11 @@ public function section_right( $course, $user ): string { $user ); - $userCourseModel = UserCourseModel::find( get_current_user_id(), $course->get_id(), true ); + $user_id = 0; + if ( $user instanceof UserModel ) { + $user_id = $user->get_id(); + } + $userCourseModel = UserCourseModel::find( $user_id, $course->get_id(), true ); $userCourseTemplate = UserCourseTemplate::instance(); $btn_continue_and_finish = []; @@ -295,7 +299,7 @@ public function section_right( $course, $user ): string { 'wrapper_inner' => '
    ', 'image' => $this->singleCourseTemplate->html_image( $course ), 'price' => $this->singleCourseTemplate->html_price( $course ), - //'sale_discount' => $this->singleCourseTemplate->html_sale_discount( $course ), to do + //'sale_discount' => $this->singleCourseTemplate->html_sale_discount( $course ), to do 'info_two' => Template::combine_components( $section_info_two ), 'buttons' => Template::combine_components( $section_buttons ), 'share' => $this->html_share( $course ), @@ -326,22 +330,26 @@ public function html_share( $course ): string { switch ( $key ) { case 'facebook': $link_share = 'https://www.facebook.com/sharer.php?u=' . urlencode( get_permalink() ); - $icon = ''; + $icon = ''; break; - case'twitter': + case 'twitter': $link_share = 'https://twitter.com/share?url=' . urlencode( get_permalink() ) . '&text=' . rawurlencode( esc_attr( get_the_title() ) ); - $icon = ''; + $icon = ''; break; - case'pinterest': - $link_share = 'http://pinterest.com/pin/create/button/?url=' . urlencode( get_permalink() ) . '&description=' . rawurlencode( esc_attr( get_the_excerpt() ) ) . '&media=' . urlencode( wp_get_attachment_url( get_post_thumbnail_id() ) ) . ' onclick="window.open(this.href); return false;"'; - $icon = ''; + case 'pinterest': + $link_share = 'https://pinterest.com/pin/create/button/?url=' . urlencode( get_permalink() ) . '&description=' . rawurlencode( esc_attr( get_the_excerpt() ) ) . '&media=' . urlencode( wp_get_attachment_url( get_post_thumbnail_id() ) ) . ' onclick="window.open(this.href); return false;"'; + $icon = ''; break; - case'linkedin': + case 'linkedin': $link_share = 'https://www.linkedin.com/shareArticle?mini=true&url=' . urlencode( get_permalink() ) . '&title=' . rawurlencode( esc_attr( get_the_title() ) ) . '&summary=&source=' . rawurlencode( esc_attr( get_the_excerpt() ) ); - $icon = ''; + $icon = ''; + break; + default: + $link_share = ''; + $icon = ''; break; } - echo sprintf('
  • %s%s
  • ', $link_share, $social, $icon, $social); + echo sprintf( '
  • %s%s
  • ', $link_share, $social, $icon, $social ); } } @@ -351,7 +359,7 @@ public function html_share( $course ): string { 'learn-press/single-course/social-share', [ 'wrapper' => '', ] ); diff --git a/inc/TemplateHooks/Course/SingleCourseTemplate.php b/inc/TemplateHooks/Course/SingleCourseTemplate.php index d1c277000..4f264cec2 100644 --- a/inc/TemplateHooks/Course/SingleCourseTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseTemplate.php @@ -14,14 +14,17 @@ use LearnPress\Models\CourseModel; use LearnPress\Models\CoursePostModel; use LearnPress\Models\UserItems\UserCourseModel; +use LearnPress\Models\UserItems\UserItemModel; use LearnPress\Models\UserModel; use LearnPress\TemplateHooks\Instructor\SingleInstructorTemplate; use LearnPress\TemplateHooks\UserTemplate; use LP_Checkout; use LP_Course; +use LP_Course_Item; use LP_Datetime; use LP_Material_Files_DB; use LP_Settings; +use stdClass; use Throwable; class SingleCourseTemplate { @@ -217,15 +220,19 @@ public function html_image( $course ): string { try { if ( $course instanceof LP_Course ) { - $content = $course->get_image(); - } elseif ( $course instanceof CourseModel ) { - $content = sprintf( - '%s', - esc_url_raw( $course->get_image_url() ), - _x( 'course thumbnail', 'no course thumbnail', 'learnpress' ) - ); + $course = CourseModel::find( $course->get_id(), true ); + } + + if ( ! $course instanceof CourseModel ) { + return ''; } + $content = sprintf( + '%s', + esc_url_raw( $course->get_image_url() ), + _x( 'course thumbnail', 'no course thumbnail', 'learnpress' ) + ); + $section = apply_filters( 'learn-press/course/html-image', [ @@ -637,9 +644,7 @@ public function html_btn_purchase_course( CourseModel $course, $user ): string { ); if ( in_array( $can_purchase->get_error_code(), $error_code_show ) && ! empty( $can_purchase->get_error_message() ) ) { - ob_start(); - Template::print_message( $can_purchase->get_error_message(), 'warning' ); - $html_btn = ob_get_clean(); + $html_btn = Template::print_message( $can_purchase->get_error_message(), 'warning', false ); } } else { $html_btn = sprintf( @@ -723,9 +728,7 @@ public function html_btn_enroll_course( CourseModel $course, $user ): string { ); if ( in_array( $can_enroll->get_error_code(), $error_code_show ) && ! empty( $can_enroll->get_error_message() ) ) { - ob_start(); - Template::print_message( $can_enroll->get_error_message(), 'warning' ); - $html_btn = ob_get_clean(); + $html_btn = Template::print_message( $can_enroll->get_error_message(), 'warning', false ); } } else { $html_btn = sprintf( @@ -1164,6 +1167,294 @@ public function html_price_suffix( $course ): string { return $html; } + /** + * Get HTML curriculum of course. + * + * @param CourseModel $course + * @param UserModel|false $user + * + * @return string + * @since 4.2.7.6 + * @version 1.0.0 + */ + public function html_curriculum( CourseModel $course, $user ): string { + $html = ''; + + try { + + $section_items = $course->get_section_items(); + $html = Template::print_message( esc_html__( 'Course has not any items.', 'learnpress' ), 'info', false ); + if ( empty( $section_items ) ) { + return $html; + } + + $li_section_items = ''; + foreach ( $section_items as $section_item ) { + $li_section_items .= $this->render_html_section_item( $course, $user, $section_item ); + } + + $section = [ + 'wrapper' => '
    ', + 'curriculum_info' => '
    ', + 'curriculum_info_left' => '
      ', + 'count_sections' => sprintf( + '
    • %s
    • ', + sprintf( + _n( '%d Section', '%d Sections', $course->get_total_sections(), 'learnpress' ), + $course->get_total_sections() + ) + ), + 'count_lesson' => sprintf( + '
    • %s
    • ', + sprintf( + _n( '%d Lesson', '%d Lessons', $course->count_items( LP_LESSON_CPT ), 'learnpress' ), + $course->get_total_sections() + ) + ), + 'duration' => sprintf( + '
    • %s
    • ', + $this->html_duration( $course ) + ), + 'curriculum_info_left_end' => '
    ', + 'curriculum_info_right' => '
    ', + 'expand_all' => sprintf( + '%s', + esc_html__( 'Expand all', 'learnpress' ) + ), + 'curriculum_info_right_end' => '
    ', + 'curriculum_info_end' => '
    ', + 'curriculum' => '
    ', + 'sections' => '
      ', + 'li_section_items' => $li_section_items, + 'sections_end' => '
    ', + 'curriculum_end' => '
    ', + 'wrapper_end' => '
    ', + ]; + + $html = Template::combine_components( $section ); + } catch ( Throwable $e ) { + + } + + return $html; + } + + /** + * Render HTML section item + * + * @param CourseModel $course + * @param UserModel|false $user + * @param $section_item object {section_id, section_name, section_description, items[{item_id, item_order, item_type, title, preview}]} + * + * @return string + * @since 4.2.7.6 + * @version 1.0.0 + */ + public function render_html_section_item( CourseModel $course, $user, $section_item ): string { + if ( ! $section_item instanceof stdClass ) { + return ''; + } + + $section_id = $section_item->section_id ?? 0; + $section_name = $section_item->section_name ?? ''; + $section_description = $section_item->section_description ?? ''; + $items = $section_item->items ?? []; + + $section_header = [ + 'start' => '
    ', + 'info' => '', + 'toggle' => ' + + + ', + 'end' => '
    ', + ]; + + $li_items = ''; + foreach ( $items as $item ) { + $li_items .= $this->render_html_course_item( $course, $user, $item ); + } + $section_items = [ + 'start' => '
      ', + 'li_items' => $li_items, + 'end' => '
    ', + ]; + + $section_item = apply_filters( + 'learn-press/course/html-curriculum-item', + [ + 'start' => sprintf( '
  • ', $section_id ), + 'header' => Template::combine_components( $section_header ), + 'items' => Template::combine_components( $section_items ), + 'end' => '
  • ', + ], + $course, + $user, + $section_item + ); + + return Template::combine_components( $section_item ); + } + + /** + * @param CourseModel $course + * @param UserModel|false $user + * @param $item + * + * @return string + * @since 4.2.7.6 + * @version 1.0.0 + */ + public function render_html_course_item( CourseModel $course, $user, $item ): string { + $html = ''; + + if ( ! $item instanceof stdClass ) { + return $html; + } + + $item_id = $item->item_id ?? 0; + $item_order = $item->item_order ?? 0; + $item_type = $item->item_type ?? ''; + $title = $item->title ?? ''; + $has_preview = $item->preview ?? ''; + + //LP_Course_Item::get_item( $item_id, $course->get_id() ); + $itemModel = $course->get_item_model( $item_id, $item_type ); + if ( empty( $itemModel ) ) { + return $html; + } + + $link_item = $course->get_item_link( $item_id ); + + $item_duration = ''; + $html_item_duration = ''; + if ( is_callable( [ $itemModel, 'get_duration' ] ) ) { + $item_duration = $itemModel->get_duration(); + } else { + $item_duration = get_post_meta( $item_id, '_lp_duration', true ); + } + + $duration_arr = explode( ' ', $item_duration ); + $duration_number = floatval( $duration_arr[0] ?? 0 ); + $duration_type = $duration_arr[1] ?? ''; + + $item_duration_plural = esc_html__( 'Unlimited', 'learnpress' ); + if ( $duration_number > 0 ) { + $item_duration_plural = LP_Datetime::get_string_plural_duration( $duration_number, $duration_type ); + } + $html_item_duration = sprintf( + '%s', + $item_duration_plural + ); + + $user_item_flag = ''; + if ( $user instanceof UserModel ) { + $userCourse = UserCourseModel::find( $user->get_id(), $course->get_id(), true ); + if ( $userCourse ) { + // Check status of item's course + $userCourseItem = $userCourse->get_item_attend( $item_id ); + if ( ! $userCourseItem instanceof UserItemModel ) { + $user_item_flag = UserItemModel::STATUS_IN_PROGRESS; + } else { + $user_item_flag = $userCourseItem->get_status(); + $user_item_graduation = $userCourseItem->get_graduation(); + if ( ! empty( $user_item_graduation ) ) { + $user_item_flag = $user_item_graduation; + } + } + } + } + + if ( empty( $user_item_flag ) ) { + $html_item_status = sprintf( + '%s', + esc_html__( 'Locked', 'learnpress' ) + ); + if ( $has_preview ) { + $html_item_status = sprintf( + '%s', + esc_html__( 'Preview', 'learnpress' ) + ); + } + } else { + switch ( $user_item_flag ) { + case UserItemModel::GRADUATION_PASSED: + $html_item_status = sprintf( + '%s', + esc_html__( 'Passed', 'learnpress' ) + ); + break; + case UserItemModel::GRADUATION_FAILED: + $html_item_status = sprintf( + '%s', + esc_html__( 'Failed', 'learnpress' ) + ); + break; + case UserItemModel::STATUS_COMPLETED: + $html_item_status = sprintf( + '%s', + esc_html__( 'Completed', 'learnpress' ) + ); + break; + case 'started': + $html_item_status = sprintf( + '%s', + esc_html__( 'Started', 'learnpress' ) + ); + break; + case 'locked': + default: + $html_item_status = sprintf( + '%s', + esc_html__( 'Locked', 'learnpress' ) + ); + break; + } + + $html_item_status = apply_filters( + 'learn-press/course/html-curriculum-item/status', + $html_item_status, + $user_item_flag, + $user, + $course, + $itemModel + ); + } + + $section_item = [ + 'start' => sprintf( + '
  • ', + $item_id, + $item_order, + $item_type + ), + 'link' => sprintf( + '', + esc_url_raw( $link_item ) + ), + 'item_left' => '
    ', + 'icon' => sprintf( + '', + esc_attr( $item_type ) + ), + 'title' => sprintf( '
    %s
    ', wp_kses_post( $title ) ), + 'item_left_end' => '
    ', + 'item_right' => '
    ', + 'duration' => $html_item_duration, + 'status' => $html_item_status, + 'item_right_end' => '
    ', + 'link_end' => '
    ', + 'end' => '
  • ', + ]; + + $html = Template::combine_components( $section_item ); + + return $html; + } + /** * Render string to data content * diff --git a/inc/TemplateHooks/UserItem/UserCourseTemplate.php b/inc/TemplateHooks/UserItem/UserCourseTemplate.php index f880b199b..5f528c61a 100644 --- a/inc/TemplateHooks/UserItem/UserCourseTemplate.php +++ b/inc/TemplateHooks/UserItem/UserCourseTemplate.php @@ -12,6 +12,15 @@ use LearnPress\Models\UserItems\UserCourseModel; class UserCourseTemplate extends UserItemBaseTemplate { + public static function instance() { + static $instance = null; + if ( is_null( $instance ) ) { + $instance = new self(); + } + + return $instance; + } + /** * HTML button continue course. * diff --git a/inc/TemplateHooks/UserItem/UserItemBaseTemplate.php b/inc/TemplateHooks/UserItem/UserItemBaseTemplate.php index f0180f4d4..fb54760cd 100644 --- a/inc/TemplateHooks/UserItem/UserItemBaseTemplate.php +++ b/inc/TemplateHooks/UserItem/UserItemBaseTemplate.php @@ -7,29 +7,24 @@ */ namespace LearnPress\TemplateHooks\UserItem; -use LearnPress\Helpers\Singleton; use LearnPress\Helpers\Template; +use LearnPress\Models\UserItems\UserItemModel; use LP_Datetime; use LP_User_Item; use Throwable; class UserItemBaseTemplate { - use Singleton; - - public function init() { - - } - /** * Get html start time html of user item. * - * @param LP_User_Item $user_item + * @param UserItemModel $user_item * @param bool $has_time + * * @return string * @since 4.2.3.5 * @version 1.0.0 */ - public function html_start_date_time( LP_User_Item $user_item, bool $has_time = true ): string { + public function html_start_date_time( UserItemModel $user_item, bool $has_time = true ): string { $content = ''; try { @@ -60,13 +55,14 @@ public function html_start_date_time( LP_User_Item $user_item, bool $has_time = /** * Get html end time html of user item. * - * @param LP_User_Item $user_item + * @param UserItemModel $user_item * @param bool $has_time + * * @return string * @since 4.2.3.5 * @version 1.0.0 */ - public function html_end_date_time( LP_User_Item $user_item, bool $has_time = true ): string { + public function html_end_date_time( UserItemModel $user_item, bool $has_time = true ): string { $content = ''; try { @@ -96,13 +92,14 @@ public function html_end_date_time( LP_User_Item $user_item, bool $has_time = tr /** * Get html expire time html of user item. * - * @param LP_User_Item $user_item + * @param UserItemModel $user_item * @param bool $has_time + * * @return string * @since 4.2.3.5 * @version 1.0.0 */ - public function html_expire_date_time( LP_User_Item $user_item, bool $has_time = true ): string { + public function html_expire_date_time( UserItemModel $user_item, bool $has_time = true ): string { $content = ''; try { diff --git a/learnpress.php b/learnpress.php index b96b75ee8..3f406198b 100644 --- a/learnpress.php +++ b/learnpress.php @@ -26,8 +26,8 @@ use LearnPress\TemplateHooks\Course\FilterCourseTemplate; use LearnPress\TemplateHooks\Course\ListCoursesRelatedTemplate; use LearnPress\TemplateHooks\Course\ListCoursesTemplate; +use LearnPress\TemplateHooks\Course\SingleCourseModernLayout; use LearnPress\TemplateHooks\Course\SingleCourseOfflineTemplate; -use LearnPress\TemplateHooks\Course\SingleCourseModelTemplate; use LearnPress\TemplateHooks\Course\SingleCourseClassicTemplate; use LearnPress\TemplateHooks\Course\SingleCourseTemplate; use LearnPress\TemplateHooks\Instructor\ListInstructorsTemplate; @@ -313,7 +313,7 @@ private function include_files_global() { ListInstructorsTemplate::instance(); SingleCourseTemplate::instance(); SingleCourseOfflineTemplate::instance(); - SingleCourseModelTemplate::instance(); + SingleCourseModernLayout::instance(); SingleCourseClassicTemplate::instance(); SingleInstructorTemplate::instance(); ProfileInstructorStatisticsTemplate::instance(); From 310555254a805b780eba54c34853f7e20846aa65 Mon Sep 17 00:00:00 2001 From: truongpn Date: Fri, 27 Dec 2024 14:33:41 +0700 Subject: [PATCH 053/225] fix text domain --- assets/src/scss/frontend/_course-single.scss | 192 +++++++++++------- .../Course/SingleCourseModernLayout.php | 8 +- 2 files changed, 120 insertions(+), 80 deletions(-) diff --git a/assets/src/scss/frontend/_course-single.scss b/assets/src/scss/frontend/_course-single.scss index 9f00f5ae1..4070dd54a 100644 --- a/assets/src/scss/frontend/_course-single.scss +++ b/assets/src/scss/frontend/_course-single.scss @@ -345,6 +345,46 @@ .course-material__title { margin: 0 0 20px 0; } + + .course-features, + .course-target, + .course-requirements { + ul { + margin: 0 0 0 20px; + } + } + + .instructor-social { + display: inline-flex; + padding: 0; + gap: 12px; + margin: 16px 0 0 0; + + > a { + text-align: center; + list-style: none; + + span { + display: none; + } + + i { + width: 40px; + height: 40px; + display: inline-flex; + align-items: center; + justify-content: center; + border: 1px solid $border-color; + border-radius: 50%; + + &:hover { + background-color: $color-primary; + border-color: $color-primary; + color: $color-white; + } + } + } + } } &__right { @@ -459,96 +499,96 @@ padding: 20px; background: #fff; box-shadow: 0 1px 16px 0 rgba(0, 0, 0, 0.12); - - .thim-social-media { - display: inline-flex; - padding: 0; - gap: 12px; - - > li { - text-align: center; - list-style: none; - - span { - display: none; - } + } - i { - width: 40px; - height: 40px; - display: inline-flex; - align-items: center; - justify-content: center; - border: 1px solid $border-color; - border-radius: 50%; - - &:hover { - background-color: $color-primary; - border-color: $color-primary; - color: $color-white; - } + .lp-social-media { + display: inline-flex; + padding: 0; + gap: 12px; + + > li { + text-align: center; + list-style: none; + + span { + display: none; + } + + i { + width: 40px; + height: 40px; + display: inline-flex; + align-items: center; + justify-content: center; + border: 1px solid $border-color; + border-radius: 50%; + + &:hover { + background-color: $color-primary; + border-color: $color-primary; + color: $color-white; } } } + } - .clipboard-post { - display: flex; - justify-content: space-between; - margin-bottom: 20px; - gap: 12px; + .clipboard-post { + display: flex; + justify-content: space-between; + margin-bottom: 20px; + gap: 12px; - @media (max-width: 600px) { - flex-wrap: wrap; - } + @media (max-width: 600px) { + flex-wrap: wrap; } - - .btn-clipboard { - position: relative; - - .tooltip { - display: none; + } + + .btn-clipboard { + position: relative; + + .tooltip { + display: none; + position: absolute; + z-index: 2; + left: 50%; + right: auto; + bottom: 100%; + transform: translateX(-50%); + width: max-content; + color: #fff; + font-size: 0.825em; + padding: 5px 10px; + background: rgba(0, 0, 0, 0.72); + border-radius: 3px; + margin-bottom: 10px; + + &:before { + content: ""; position: absolute; z-index: 2; left: 50%; - right: auto; - bottom: 100%; - transform: translateX(-50%); - width: max-content; - color: #fff; - font-size: 0.825em; - padding: 5px 10px; - background: rgba(0, 0, 0, 0.72); - border-radius: 3px; - margin-bottom: 10px; - - &:before { - content: ""; - position: absolute; - z-index: 2; - left: 50%; - bottom: -5px; - margin-left: -3px; - border-left: 5px solid transparent; - border-right: 5px solid transparent; - border-top: 5px solid rgba(0, 0, 0, 0.72); - } + bottom: -5px; + margin-left: -3px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid rgba(0, 0, 0, 0.72); } - - &:hover { - background-color: #eee; - - .tooltip { - display: block; - } + } + + &:hover { + background-color: #eee; + + .tooltip { + display: block; } } - - .clipboard-value { - border: 1px solid $border-color; + } + + .clipboard-value { + border: 1px solid $border-color; - @media (max-width: 600px) { - width: 100%; - } + @media (max-width: 600px) { + width: 100%; } } diff --git a/inc/TemplateHooks/Course/SingleCourseModernLayout.php b/inc/TemplateHooks/Course/SingleCourseModernLayout.php index c1d9fb3cf..acfaff612 100644 --- a/inc/TemplateHooks/Course/SingleCourseModernLayout.php +++ b/inc/TemplateHooks/Course/SingleCourseModernLayout.php @@ -358,7 +358,7 @@ public function html_share( $course ): string { $social_media = apply_filters( 'learn-press/single-course/social-share', [ - 'wrapper' => '
    ', ]; From 608b3c65a6101cc3cf93d4ea345188236208dbd9 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Fri, 27 Dec 2024 15:20:07 +0700 Subject: [PATCH 054/225] = 4.2.7.6 = ~ Tweak: UserItemBaseTemplate class. ~ Tweak file course-list.php. --- .../Course/SingleCourseTemplate.php | 2 +- .../UserItem/UserItemBaseTemplate.php | 90 +++++++++++-------- .../profile/tabs/courses/course-list.php | 28 +++--- 3 files changed, 71 insertions(+), 49 deletions(-) diff --git a/inc/TemplateHooks/Course/SingleCourseTemplate.php b/inc/TemplateHooks/Course/SingleCourseTemplate.php index 4f264cec2..530ea9b53 100644 --- a/inc/TemplateHooks/Course/SingleCourseTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseTemplate.php @@ -1219,7 +1219,7 @@ public function html_curriculum( CourseModel $course, $user ): string { 'curriculum_info_right' => '
    ', 'expand_all' => sprintf( '%s', - esc_html__( 'Expand all', 'learnpress' ) + esc_html__( 'Expand all sections', 'learnpress' ) ), 'curriculum_info_right_end' => '
    ', 'curriculum_info_end' => '
    ', diff --git a/inc/TemplateHooks/UserItem/UserItemBaseTemplate.php b/inc/TemplateHooks/UserItem/UserItemBaseTemplate.php index fb54760cd..f8c22b9b5 100644 --- a/inc/TemplateHooks/UserItem/UserItemBaseTemplate.php +++ b/inc/TemplateHooks/UserItem/UserItemBaseTemplate.php @@ -3,11 +3,11 @@ * Template hooks User Item Base. * * @since 4.2.3.5 - * @version 1.0.0 + * @version 1.0.1 */ + namespace LearnPress\TemplateHooks\UserItem; -use LearnPress\Helpers\Template; use LearnPress\Models\UserItems\UserItemModel; use LP_Datetime; use LP_User_Item; @@ -15,24 +15,28 @@ class UserItemBaseTemplate { /** - * Get html start time html of user item. + * Get html start time of user item. * - * @param UserItemModel $user_item + * @param UserItemModel|LP_User_Item $user_item * @param bool $has_time * * @return string * @since 4.2.3.5 - * @version 1.0.0 + * @version 1.0.1 */ - public function html_start_date_time( UserItemModel $user_item, bool $has_time = true ): string { - $content = ''; + public function html_start_date_time( $user_item, bool $has_time = true ): string { + $html = ''; try { - $html_wrapper = [ - '' => '', - ]; + if ( $user_item instanceof LP_User_Item ) { + $userItemModel = new UserItemModel( $user_item->get_data() ); + } elseif ( $user_item instanceof UserItemModel ) { + $userItemModel = $user_item; + } else { + return $html; + } - $start_time_from_db = $user_item->get_data( LP_User_Item::KEY_DATA_START_TIME ); + $start_time_from_db = $userItemModel->get_start_time(); if ( empty( $start_time_from_db ) ) { $start_date_str = ' - '; } else { @@ -44,33 +48,37 @@ public function html_start_date_time( UserItemModel $user_item, bool $has_time = } } - $content = Template::instance()->nest_elements( $html_wrapper, $start_date_str ); + $html = sprintf( '%s', $start_date_str ); } catch ( Throwable $e ) { error_log( __METHOD__ . ': ' . $e->getMessage() ); } - return $content; + return $html; } /** - * Get html end time html of user item. + * Get html end time of user item. * - * @param UserItemModel $user_item + * @param UserItemModel|LP_User_Item $user_item * @param bool $has_time * * @return string * @since 4.2.3.5 - * @version 1.0.0 + * @version 1.0.1 */ - public function html_end_date_time( UserItemModel $user_item, bool $has_time = true ): string { - $content = ''; + public function html_end_date_time( $user_item, bool $has_time = true ): string { + $html = ''; try { - $html_wrapper = [ - '' => '', - ]; + if ( $user_item instanceof LP_User_Item ) { + $userItemModel = new UserItemModel( $user_item->get_data() ); + } elseif ( $user_item instanceof UserItemModel ) { + $userItemModel = $user_item; + } else { + return $html; + } - $end_time_from_db = $user_item->get_data( LP_User_Item::KEY_DATA_END_TIME ); + $end_time_from_db = $userItemModel->get_end_time(); if ( empty( $end_time_from_db ) ) { $end_date_str = ' - '; } else { @@ -81,33 +89,38 @@ public function html_end_date_time( UserItemModel $user_item, bool $has_time = t $end_date_str = $end_date->format( LP_Datetime::I18N_FORMAT ); } } - $content = Template::instance()->nest_elements( $html_wrapper, $end_date_str ); + + $html = sprintf( '%s', $end_date_str ); } catch ( Throwable $e ) { error_log( __METHOD__ . ': ' . $e->getMessage() ); } - return $content; + return $html; } /** - * Get html expire time html of user item. + * Get html expire time of user item. * - * @param UserItemModel $user_item + * @param UserItemModel|LP_User_Item $user_item * @param bool $has_time * * @return string * @since 4.2.3.5 - * @version 1.0.0 + * @version 1.0.1 */ - public function html_expire_date_time( UserItemModel $user_item, bool $has_time = true ): string { - $content = ''; + public function html_expire_date_time( $user_item, bool $has_time = true ): string { + $html = ''; try { - $html_wrapper = [ - '' => '', - ]; + if ( $user_item instanceof LP_User_Item ) { + $userItemModel = new UserItemModel( $user_item->get_data() ); + } elseif ( $user_item instanceof UserItemModel ) { + $userItemModel = $user_item; + } else { + return $html; + } - $expire_date = $user_item->get_expiration_time(); + $expire_date = $userItemModel->get_expiration_time(); if ( empty( $expire_date ) ) { $expire_date_str = __( 'Never', 'learnpress' ); } else { @@ -118,12 +131,17 @@ public function html_expire_date_time( UserItemModel $user_item, bool $has_time } } - $content = Template::instance()->nest_elements( $html_wrapper, $expire_date_str ); - $content = apply_filters( 'learn-press/user-item/html-expire-date-time', $content, $user_item, $has_time ); + $html = sprintf( '%s', $expire_date_str ); + // Hook old + if ( has_filter( 'learn-press/user-item/html-expire-date-time' ) ) { + $html = apply_filters( 'learn-press/user-item/html-expire-date-time', $html, $user_item, $has_time ); + } + + $html = apply_filters( 'learn-press/user-item-model/html-expire-date-time', $html, $userItemModel, $has_time ); } catch ( Throwable $e ) { error_log( __METHOD__ . ': ' . $e->getMessage() ); } - return $content; + return $html; } } diff --git a/templates/profile/tabs/courses/course-list.php b/templates/profile/tabs/courses/course-list.php index 3d7a82934..55429404f 100644 --- a/templates/profile/tabs/courses/course-list.php +++ b/templates/profile/tabs/courses/course-list.php @@ -5,9 +5,11 @@ * * @author ThimPress * @package Learnpress/Templates - * @version 4.0.12 + * @version 4.0.13 */ +use LearnPress\Models\CourseModel; +use LearnPress\Models\UserItems\UserCourseModel; use LearnPress\TemplateHooks\Course\SingleCourseTemplate; use LearnPress\TemplateHooks\UserItem\UserCourseTemplate; @@ -36,33 +38,35 @@ get_course_data( $id ); - if ( ! $course_data ) { + $userCourseModel = UserCourseModel::find( $user->get_id(), $id, true ); + if ( ! $userCourseModel ) { continue; } - $course_result = $course_data->get_result(); + + $course_result = $userCourseModel->calculate_course_results(); ?> - - html_image( $course ) ); ?> + + html_image( $courseModel ) ); ?> - html_title( $course ) ); ?> + + html_title( $courseModel ) ); ?> % - html_expire_date_time( $course_data ); ?> + html_expire_date_time( $userCourseModel ); ?> - html_end_date_time( $course_data ); ?> + html_end_date_time( $userCourseModel ); ?> Date: Fri, 27 Dec 2024 17:22:35 +0700 Subject: [PATCH 055/225] = 4.2.7.6 = ~ Tweak: render_html_course_item. --- inc/Models/UserItems/UserCourseModel.php | 21 ++--- inc/Models/UserItems/UserItemModel.php | 12 +-- .../Course/SingleCourseTemplate.php | 89 +++++-------------- inc/class-lp-page-controller.php | 3 + 4 files changed, 41 insertions(+), 84 deletions(-) diff --git a/inc/Models/UserItems/UserCourseModel.php b/inc/Models/UserItems/UserCourseModel.php index 01cf39b86..e0099f6ca 100644 --- a/inc/Models/UserItems/UserCourseModel.php +++ b/inc/Models/UserItems/UserCourseModel.php @@ -97,24 +97,20 @@ public static function find( int $user_id, int $course_id, bool $check_cache = f } /** - * Get user_items is child of user course. + * Get user_item is child of user course. * * @param int $item_id * @param string $item_type - * @return false|UserItemModel + * + * @return false|UserItemModel|UserQuizModel|mixed + * @since 4.2.5 + * @version 1.0.1 */ public function get_item_attend( int $item_id, string $item_type = '' ) { $item = false; try { -// $filter = new LP_User_Items_Filter(); -// $filter->parent_id = $this->get_user_item_id(); -// $filter->item_id = $item_id; -// $filter->item_type = $item_type; -// $filter->ref_type = $this->item_type; -// $filter->ref_id = $this->item_id; -// $filter->user_id = $this->user_id; - $item = UserItemModel::find_user_item( + $item = UserItemModel::find_user_item( $this->user_id, $item_id, $item_type, @@ -129,13 +125,12 @@ public function get_item_attend( int $item_id, string $item_type = '' ) { $item = new UserQuizModel( $item ); break; default: + $item = apply_filters( 'learn-press/userCourseModel/get-item-attend', $item, $this, $item_id, $item_type ); break; } - - $item = apply_filters( 'learn-press/user-course-has-item-attend', $item, $item_type, $this ); } } catch ( Throwable $e ) { - error_log( $e->getMessage() ); + error_log( __METHOD__ . ': ' . $e->getMessage() ); } return $item; diff --git a/inc/Models/UserItems/UserItemModel.php b/inc/Models/UserItems/UserItemModel.php index 01ab9dcb5..c49eb7745 100644 --- a/inc/Models/UserItems/UserItemModel.php +++ b/inc/Models/UserItems/UserItemModel.php @@ -99,12 +99,12 @@ class UserItemModel { public $meta_data; // Constants - const STATUS_COMPLETED = 'completed'; - const STATUS_FINISHED = 'finished'; - const STATUS_ENROLLED = 'enrolled'; - const STATUS_IN_PROGRESS = 'in-progress'; - const GRADUATION_PASSED = 'passed'; - const GRADUATION_FAILED = 'failed'; + const STATUS_COMPLETED = 'completed'; + const STATUS_FINISHED = 'finished'; + const STATUS_ENROLLED = 'enrolled'; + const GRADUATION_IN_PROGRESS = 'in-progress'; + const GRADUATION_PASSED = 'passed'; + const GRADUATION_FAILED = 'failed'; /** * If data get from database, map to object. diff --git a/inc/TemplateHooks/Course/SingleCourseTemplate.php b/inc/TemplateHooks/Course/SingleCourseTemplate.php index 530ea9b53..50bc98879 100644 --- a/inc/TemplateHooks/Course/SingleCourseTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseTemplate.php @@ -1233,7 +1233,7 @@ public function html_curriculum( CourseModel $course, $user ): string { $html = Template::combine_components( $section ); } catch ( Throwable $e ) { - + error_log( __METHOD__ . ': ' . $e->getMessage() ); } return $html; @@ -1300,7 +1300,7 @@ public function render_html_section_item( CourseModel $course, $user, $section_i } /** - * @param CourseModel $course + * @param CourseModel $courseModel * @param UserModel|false $user * @param $item * @@ -1308,7 +1308,7 @@ public function render_html_section_item( CourseModel $course, $user, $section_i * @since 4.2.7.6 * @version 1.0.0 */ - public function render_html_course_item( CourseModel $course, $user, $item ): string { + public function render_html_course_item( CourseModel $courseModel, $user, $item ): string { $html = ''; if ( ! $item instanceof stdClass ) { @@ -1322,12 +1322,12 @@ public function render_html_course_item( CourseModel $course, $user, $item ): st $has_preview = $item->preview ?? ''; //LP_Course_Item::get_item( $item_id, $course->get_id() ); - $itemModel = $course->get_item_model( $item_id, $item_type ); + $itemModel = $courseModel->get_item_model( $item_id, $item_type ); if ( empty( $itemModel ) ) { return $html; } - $link_item = $course->get_item_link( $item_id ); + $link_item = $courseModel->get_item_link( $item_id ); $item_duration = ''; $html_item_duration = ''; @@ -1350,80 +1350,39 @@ public function render_html_course_item( CourseModel $course, $user, $item ): st $item_duration_plural ); - $user_item_flag = ''; + $user_item_status_ico_flag = 'locked'; + $user_attended_course = false; if ( $user instanceof UserModel ) { - $userCourse = UserCourseModel::find( $user->get_id(), $course->get_id(), true ); + $userCourse = UserCourseModel::find( $user->get_id(), $courseModel->get_id(), true ); if ( $userCourse ) { + $user_attended_course = true; // Check status of item's course - $userCourseItem = $userCourse->get_item_attend( $item_id ); + $userCourseItem = $userCourse->get_item_attend( $item_id, $item_type ); if ( ! $userCourseItem instanceof UserItemModel ) { - $user_item_flag = UserItemModel::STATUS_IN_PROGRESS; + $user_item_status_ico_flag = UserItemModel::GRADUATION_IN_PROGRESS; } else { - $user_item_flag = $userCourseItem->get_status(); - $user_item_graduation = $userCourseItem->get_graduation(); + $user_item_status_ico_flag = $userCourseItem->get_status(); + $user_item_graduation = $userCourseItem->get_graduation(); if ( ! empty( $user_item_graduation ) ) { - $user_item_flag = $user_item_graduation; + $user_item_status_ico_flag = $user_item_graduation; } } } } - if ( empty( $user_item_flag ) ) { - $html_item_status = sprintf( - '%s', - esc_html__( 'Locked', 'learnpress' ) - ); - if ( $has_preview ) { - $html_item_status = sprintf( - '%s', - esc_html__( 'Preview', 'learnpress' ) - ); - } - } else { - switch ( $user_item_flag ) { - case UserItemModel::GRADUATION_PASSED: - $html_item_status = sprintf( - '%s', - esc_html__( 'Passed', 'learnpress' ) - ); - break; - case UserItemModel::GRADUATION_FAILED: - $html_item_status = sprintf( - '%s', - esc_html__( 'Failed', 'learnpress' ) - ); - break; - case UserItemModel::STATUS_COMPLETED: - $html_item_status = sprintf( - '%s', - esc_html__( 'Completed', 'learnpress' ) - ); - break; - case 'started': - $html_item_status = sprintf( - '%s', - esc_html__( 'Started', 'learnpress' ) - ); - break; - case 'locked': - default: - $html_item_status = sprintf( - '%s', - esc_html__( 'Locked', 'learnpress' ) - ); - break; - } + if ( $has_preview && ! $user_attended_course ) { + $user_item_status_ico_flag = 'preview'; + } - $html_item_status = apply_filters( - 'learn-press/course/html-curriculum-item/status', - $html_item_status, - $user_item_flag, - $user, - $course, - $itemModel - ); + if ( $courseModel->has_no_enroll_requirement() ) { + $user_item_status_ico_flag = UserItemModel::GRADUATION_IN_PROGRESS; } + $html_item_status = sprintf( + '%1$s', + $user_item_status_ico_flag + ); + $section_item = [ 'start' => sprintf( '
  • ', diff --git a/inc/class-lp-page-controller.php b/inc/class-lp-page-controller.php index 06667f621..f60c32e4a 100644 --- a/inc/class-lp-page-controller.php +++ b/inc/class-lp-page-controller.php @@ -450,6 +450,9 @@ private function get_page_template() { $page_template = 'single-course-layout-classic.php'; } + // Old single course layout. + //$page_template = 'single-course.php'; + global $post; setup_postdata( $post ); From 202696b0fa79162aad3ad6e00323f3bb63aa5197 Mon Sep 17 00:00:00 2001 From: truongpn Date: Fri, 27 Dec 2024 18:02:23 +0700 Subject: [PATCH 056/225] style --- assets/src/scss/frontend/_curriculum.scss | 62 +++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/assets/src/scss/frontend/_curriculum.scss b/assets/src/scss/frontend/_curriculum.scss index 810318540..a159b3478 100644 --- a/assets/src/scss/frontend/_curriculum.scss +++ b/assets/src/scss/frontend/_curriculum.scss @@ -1101,3 +1101,65 @@ body.course-item-popup { } } + +// modern +.lp-course-curriculum { + ul { + list-style: none; + margin: 0; + padding: 0; + } + + .course-curriculum-info { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; + + &__left { + display: flex; + align-items: center; + flex-wrap: wrap; + column-gap: 20px; + row-gap: 8px; + } + } + + .course-curriculum { + .course-section { + margin-bottom: 8px; + border: 1px solid $border-color; + border-radius: $border-radius-global; + + &:last-child { + margin-bottom: 0; + } + + .course-section-header { + background-color: $bg-grey; + padding: 20px; + column-gap: 20px; + display: flex; + justify-content: space-between; + } + + &-title { + font-weight: bold; + } + + .course-item { + background-color: transparent; + border-bottom: 1px solid $border-color; + padding: 12px 20px; + + &:last-child { + border-bottom: none; + } + + &-left { + + } + } + } + } +} \ No newline at end of file From f1e0b5307cc45c8fb693c7165f2ba050d0ac3409 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Fri, 27 Dec 2024 18:36:21 +0700 Subject: [PATCH 057/225] = 4.2.7.6 = ~ Added: get_time_remaining to replace timestamp_remaining_duration method. ~ Tweak: render_html_course_item. --- inc/Models/UserItems/UserCourseModel.php | 53 +++++++++++++++++++ .../Course/SingleCourseTemplate.php | 31 ++++++----- 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/inc/Models/UserItems/UserCourseModel.php b/inc/Models/UserItems/UserCourseModel.php index e0099f6ca..622bcc46f 100644 --- a/inc/Models/UserItems/UserCourseModel.php +++ b/inc/Models/UserItems/UserCourseModel.php @@ -394,6 +394,7 @@ public function get_retaken_count(): int { * @since 4.0.0 * @author tungnx * @version 1.0.1 + * @depecated 4.2.7.6, instead of get_time_remaining */ public function timestamp_remaining_duration(): int { $timestamp_remaining = - 1; @@ -441,6 +442,58 @@ public function timestamp_remaining_duration(): int { return apply_filters( 'learnpress/course/block_duration_expire/timestamp_remaining', $timestamp_remaining ); } + /** + * Check time remaining course when enable duration expire + * Value: -1 is no limit (default) + * Value: 0 is block + * Administrator || (is instructor && is author course) will be not block. + * + * @return int second + * @since 4.2.7.6 + * @version 1.0.0 + */ + public function get_time_remaining(): int { + $timestamp_remaining = - 1; + $userModel = $this->get_user_model(); + $courseModel = $this->get_course_model(); + if ( ! $userModel || ! $courseModel ) { + return $timestamp_remaining; + } + + $author = $courseModel->get_author_model(); + if ( ! $author ) { + return $timestamp_remaining; + } + + $user_id = $userModel->get_id(); + $user_wp = new \WP_User( $userModel ); + if ( user_can( $user_wp, ADMIN_ROLE ) || + ( user_can( $user_wp, LP_TEACHER_ROLE ) && $author->get_id() === $user_id ) ) { + return $timestamp_remaining; + } + + if ( 0 === (int) $courseModel->get_duration() ) { + return $timestamp_remaining; + } + + if ( ! $courseModel->enable_block_when_expire() ) { + return $timestamp_remaining; + } + + $course_start_time = new LP_Datetime( $this->get_start_time() ); + $course_start_time = $course_start_time->get_raw_date(); + $duration = $courseModel->get_duration(); + $timestamp_expire = strtotime( $course_start_time . ' +' . $duration ); + $timestamp_current = time(); + $timestamp_remaining = $timestamp_expire - $timestamp_current; + + if ( $timestamp_remaining < 0 ) { + $timestamp_remaining = 0; + } + + return apply_filters( 'learnpress/course/block_duration_expire/timestamp_remaining', $timestamp_remaining ); + } + /** * Get completed items. * diff --git a/inc/TemplateHooks/Course/SingleCourseTemplate.php b/inc/TemplateHooks/Course/SingleCourseTemplate.php index 50bc98879..ff3535c7d 100644 --- a/inc/TemplateHooks/Course/SingleCourseTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseTemplate.php @@ -1301,14 +1301,14 @@ public function render_html_section_item( CourseModel $course, $user, $section_i /** * @param CourseModel $courseModel - * @param UserModel|false $user + * @param UserModel|false $userModel * @param $item * * @return string * @since 4.2.7.6 * @version 1.0.0 */ - public function render_html_course_item( CourseModel $courseModel, $user, $item ): string { + public function render_html_course_item( CourseModel $courseModel, $userModel, $item ): string { $html = ''; if ( ! $item instanceof stdClass ) { @@ -1352,19 +1352,24 @@ public function render_html_course_item( CourseModel $courseModel, $user, $item $user_item_status_ico_flag = 'locked'; $user_attended_course = false; - if ( $user instanceof UserModel ) { - $userCourse = UserCourseModel::find( $user->get_id(), $courseModel->get_id(), true ); - if ( $userCourse ) { + if ( $userModel instanceof UserModel ) { + $userCourseModel = UserCourseModel::find( $userModel->get_id(), $courseModel->get_id(), true ); + if ( $userCourseModel ) { $user_attended_course = true; - // Check status of item's course - $userCourseItem = $userCourse->get_item_attend( $item_id, $item_type ); - if ( ! $userCourseItem instanceof UserItemModel ) { - $user_item_status_ico_flag = UserItemModel::GRADUATION_IN_PROGRESS; + + if ( $userCourseModel->get_time_remaining() === 0 ) { + $user_item_status_ico_flag = 'expired'; } else { - $user_item_status_ico_flag = $userCourseItem->get_status(); - $user_item_graduation = $userCourseItem->get_graduation(); - if ( ! empty( $user_item_graduation ) ) { - $user_item_status_ico_flag = $user_item_graduation; + // Check status of item's course + $userCourseItem = $userCourseModel->get_item_attend( $item_id, $item_type ); + if ( ! $userCourseItem instanceof UserItemModel ) { + $user_item_status_ico_flag = UserItemModel::GRADUATION_IN_PROGRESS; + } else { + $user_item_status_ico_flag = $userCourseItem->get_status(); + $user_item_graduation = $userCourseItem->get_graduation(); + if ( ! empty( $user_item_graduation ) ) { + $user_item_status_ico_flag = $user_item_graduation; + } } } } From e0a90f29a409d1c24d8c34437e9d77e8c7d7e1a3 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Sat, 28 Dec 2024 13:48:47 +0700 Subject: [PATCH 058/225] = 4.2.7.6 = ~ Added: AjaxBase class. ~ Optimize flow handle main start on learnpress.php. --- config/settings/gateway/offline-payment.php | 2 +- inc/Ajax/AjaxBase.php | 31 ++ learnpress.php | 395 ++++++++------------ 3 files changed, 190 insertions(+), 238 deletions(-) create mode 100644 inc/Ajax/AjaxBase.php diff --git a/config/settings/gateway/offline-payment.php b/config/settings/gateway/offline-payment.php index d027d3d3c..35b6b4223 100644 --- a/config/settings/gateway/offline-payment.php +++ b/config/settings/gateway/offline-payment.php @@ -19,7 +19,7 @@ array( 'title' => __( 'Enable', 'learnpress' ), 'id' => '[enable]', - 'default' => 'no', + 'default' => 'yes', 'type' => 'checkbox', ), array( diff --git a/inc/Ajax/AjaxBase.php b/inc/Ajax/AjaxBase.php new file mode 100644 index 000000000..de2941350 --- /dev/null +++ b/inc/Ajax/AjaxBase.php @@ -0,0 +1,31 @@ +catch_lp_ajax(); + } + + public function catch_lp_ajax() { + if ( ! empty( $_REQUEST['lp-ajax'] ) ) { + $action = $_REQUEST['lp-ajax']; + $action = str_replace( '-', '_', $action ); + $action = 'lp_ajax_' . $action; + if ( is_callable( $action ) ) { + call_user_func( $action ); + } + wp_die( '0', 400 ); + } + } +} diff --git a/learnpress.php b/learnpress.php index 3f406198b..f417bf7f8 100644 --- a/learnpress.php +++ b/learnpress.php @@ -14,6 +14,7 @@ * @package LearnPress */ +use LearnPress\Ajax\AjaxBase; use LearnPress\ExternalPlugin\Elementor\LPElementor; use LearnPress\ExternalPlugin\YoastSeo\LPYoastSeo; use LearnPress\Models\UserModel; @@ -43,11 +44,6 @@ defined( 'ABSPATH' ) || exit(); -if ( ! defined( 'LP_PLUGIN_FILE' ) ) { - define( 'LP_PLUGIN_FILE', __FILE__ ); - include_once 'inc/lp-constants.php'; -} - if ( ! class_exists( 'LearnPress' ) ) { /** * Class LearnPress @@ -60,7 +56,7 @@ class LearnPress { * * @var string */ - public $version = LEARNPRESS_VERSION; + public $version = ''; /** * Version database require, use for this LP source * @@ -82,11 +78,6 @@ class LearnPress { */ public $session = null; - /** - * @var LP_Profile - */ - public $profile = null; - /** * @var LP_Cart object */ @@ -97,28 +88,11 @@ class LearnPress { */ public $settings = null; - /** - * @var null - */ - public $schedule = null; - /** * @var array */ public $query_vars = array(); - /** - * Table prefixes - * - * @var array - */ - protected $_table_prefixes = array(); - - /** - * @var null - */ - public $query = null; - /** * @var array */ @@ -144,13 +118,6 @@ class LearnPress { */ public $thim_core_version_require = '2.0.0'; - /** - * - */ - public $theme_support = null; - - public $gateways = null; - public static $time_limit_default_of_sever = 0; /** @@ -162,29 +129,14 @@ private function __construct() { }*/ try { - self::$time_limit_default_of_sever = ini_get( 'max_execution_time' ); - - // Update for case compare version of LP if LEARNPRESS_VERSION undefined - if ( is_admin() ) { - $learn_press_version = get_option( 'learnpress_version', '' ); - if ( $learn_press_version !== $this->version ) { - if ( empty( $learn_press_version ) ) { // Case user install new - // Set using modern layout for new installation. - update_option( 'learn_press_layout_single_course', 'modern' ); - } + $this->prepare_before_handle(); - update_option( 'learnpress_version', $this->version ); - } + if ( ! LP_Install::instance()->tables_install_done() ) { + return; } - // Define constant . - $this->plugin_defines(); - - // define table prefixes . - $this->define_tables(); - - // Include files . - $this->includes(); + // Must handle in hook init of WordPress, when loaded plugins, theme, user. + add_action( 'init', [ $this, 'lp_main_handle' ], - 1000 ); // hooks . $this->init_hooks(); @@ -193,10 +145,51 @@ private function __construct() { } } + /** + * Prepare before handle. + * 1.Load constants and includes files. + * 2.Get default time limit of server. + * 3.Update version of LP undefined. + * + * @return void + * @since 4.2.7.6 + * @version 1.0.0 + */ + public function prepare_before_handle() { + // Define constant . + $this->plugin_defines(); + + self::$time_limit_default_of_sever = ini_get( 'max_execution_time' ); + + // Update for case compare version of LP if LEARNPRESS_VERSION undefined + $this->version = LEARNPRESS_VERSION; + if ( is_admin() ) { + $learn_press_version = get_option( 'learnpress_version', '' ); + if ( $learn_press_version !== $this->version ) { + if ( empty( $learn_press_version ) ) { // Case user install new + // Set using modern layout for new installation. + update_option( 'learn_press_layout_single_course', 'modern' ); + } + + update_option( 'learnpress_version', $this->version ); + } + } + + // define table prefixes . + $this->define_tables(); + + // Include files . + $this->includes(); + } + /** * Define constant. */ protected function plugin_defines() { + if ( ! defined( 'LP_PLUGIN_FILE' ) ) { + define( 'LP_PLUGIN_FILE', __FILE__ ); + include_once 'inc/lp-constants.php'; + } } /** @@ -220,9 +213,7 @@ public function define_tables() { ); foreach ( $tables as $short_name ) { - $table_name = $wpdb->prefix . LP_TABLE_PREFIX . $short_name; - $this->_table_prefixes[ 'tbl_' . $short_name ] = $table_name; - + $table_name = $wpdb->prefix . LP_TABLE_PREFIX . $short_name; $backward_key = 'learnpress_' . $short_name; $wpdb->{$backward_key} = $table_name; } @@ -516,6 +507,115 @@ private function include_files_frontend() { include_once 'inc/class-lp-session-handler.php'; } + /** + * Main instance of LearnPress. + * 1. Load text domain. + * 2. Handle lp ajax. + * + * @return void + * @version 4.2.7.6 + * @version 1.0.0 + */ + public function lp_main_handle() { + // Load text domain. + $this->load_plugin_text_domain(); + // Handle lp ajax. + AjaxBase::instance(); + + // Polylang + if ( defined( 'POLYLANG_VERSION' ) ) { + include_once 'inc/ExternalPlugin/Polylang/class-lp-polylang.php'; + LP_Polylang::instance(); + } + + // For plugin Elementor + if ( defined( 'ELEMENTOR_VERSION' ) ) { + LPElementor::instance(); + } + + // For plugin WPSEO + if ( defined( 'WPSEO_FILE' ) ) { + LPYoastSeo::instance(); + } + + $this->api = new LP_Core_API(); + $this->admin_api = new LP_Admin_Core_API(); + $this->get_session(); + $this->settings = $this->settings(); + if ( $this->is_request( 'frontend' ) ) { + $this->get_cart(); + } + + // Init emails + LP_Emails::instance(); + // Email hook notify + include_once 'inc/emails/class-lp-email-hooks.php'; + + //LP_Gateways::instance(); + + if ( is_admin() ) { + $this->check_addons_version_valid(); + } + + // let third parties know that we're ready . + do_action( 'learn-press/ready' ); + + /** + * Fixed temporary for emails of Announcement v4.0.6, Assignment v4.1.1 addons. + * @since 4.2.7.4 + * When 2 addons update to new version, will remove this code. + */ + if ( class_exists( 'LP_Addon_Announcements_Preload' ) ) { + if ( version_compare( LP_ADDON_ANNOUNCEMENTS_VER, '4.0.6', '<=' ) ) { + $addon_announcement = LP_Addon_Announcements_Preload::$addon; + $addon_announcement->emails_setting(); + } + } + if ( class_exists( 'LP_Addon_Assignment_Preload' ) ) { + if ( version_compare( LP_ADDON_ASSIGNMENT_VER, '4.1.1', '<=' ) ) { + $addon_assignment = LP_Addon_Assignment_Preload::$addon; + $addon_assignment->emails_setting(); + } + } + } + + /** + * Check version addons valid version require. + * If not valid will be to deactivate. + * Reload page, so not affect to hook "learn-press/ready" + */ + public function check_addons_version_valid() { + $addons_valid = true; + $plugins = get_option( 'active_plugins' ); + + $list_lp_addon_activated = preg_grep( '/^learnpress-.*/i', $plugins ); + foreach ( $list_lp_addon_activated as $lp_addon ) { + $lp_addon_info = get_file_data( + WP_PLUGIN_DIR . '/' . $lp_addon, + array( + 'Require_LP_Version' => 'Require_LP_Version', + 'Version' => 'Version', + ) + ); + + $lp_addon_version = $lp_addon_info['Version']; + + $addon = new Lp_Addon(); + $addon->version = $lp_addon_version; + $addon->plugin_base = $lp_addon; + $addon->require_version = $lp_addon_info['Require_LP_Version']; + $addon_valid = $addon->check_require_version_addon(); + + if ( $addons_valid ) { + $addon_valid = $addon->check_require_version_lp(); + } + + if ( ! $addon_valid ) { + $addons_valid = false; + } + } + } + /** * Initial common hooks */ @@ -525,15 +625,7 @@ public function init_hooks() { register_activation_hook( LP_PLUGIN_FILE, array( $this, 'on_activate' ) ); register_deactivation_hook( LP_PLUGIN_FILE, array( $this, 'on_deactivate' ) ); - // add_action( 'deactivate_' . LP_PLUGIN_BASENAME, array( $this, 'on_deactivate' ) ); - if ( ! LP_Install::instance()->tables_install_done() ) { - return; - } - - //add_action( 'wp_loaded', array( $this, 'wp_loaded' ), 20 ); - //add_action( 'after_setup_theme', array( $this, 'setup_theme' ) ); - add_action( 'init', array( $this, 'plugins_loaded' ), - 10 ); add_action( 'plugin_loaded', function ( $plugin ) { @@ -628,149 +720,6 @@ public function on_deactivate() { do_action( 'learn-press/deactivate', $this ); } - /** - * Trigger WP loaded actions. - * - * @since 3.0.0 - * @deprecated 4.2.2 - */ - /*public function wp_loaded() { - _deprecated_function( __METHOD__, '4.2.2' ); - if ( $this->is_request( 'frontend' ) ) { - $this->gateways = LP_Gateways::instance()->get_available_payment_gateways(); - } - }*/ - - /** - * Setup courses thumbnail. - * - * @since 3.0.0 - * @deprecated 4.1.7.1 - */ - /*public function setup_theme() { - if ( ! current_theme_supports( 'post-thumbnails' ) ) { - add_theme_support( 'post-thumbnails' ); - } - add_post_type_support( LP_COURSE_CPT, 'thumbnail', 'author' ); - - $size = LP_Settings::get_option( - 'course_thumbnail_dimensions', - array( - 500, - 300, - ) - ); - - $size = array_values( (array) $size ); - - add_image_size( 'course_thumbnail', $size[0], $size[1], true ); - }*/ - - /** - * Trigger LearnPress loaded actions. - * - * @since 3.0.0 - * @version 1.0.4 - */ - public function plugins_loaded() { - try { - $this->load_plugin_text_domain(); - do_action( 'learnpress/hook/before-addons-call-hook-learnpress-ready' ); - - // Polylang - if ( defined( 'POLYLANG_VERSION' ) ) { - include_once 'inc/ExternalPlugin/Polylang/class-lp-polylang.php'; - LP_Polylang::instance(); - } - - // For plugin Elementor - if ( defined( 'ELEMENTOR_VERSION' ) ) { - LPElementor::instance(); - } - - // For plugin Elementor - if ( defined( 'WPSEO_FILE' ) ) { - LPYoastSeo::instance(); - } - - $this->init(); - - new LP_Gateways(); - - /** - * Check version addons valid version require. - * If not valid will be to deactivate. - * Reload page, so not affect to hook "learn-press/ready" - */ - $addons_valid = true; - $plugins = get_option( 'active_plugins' ); - - $list_lp_addon_activated = preg_grep( '/^learnpress-.*/i', $plugins ); - - // Remove hook deactivate addon assignments v3. - add_action( - 'deactivate_learnpress-assignments/learnpress-assignments.php', - array( $this, 'lp_assignment_install' ), - - 10 - ); - - foreach ( $list_lp_addon_activated as $lp_addon ) { - $lp_addon_info = get_file_data( - WP_PLUGIN_DIR . '/' . $lp_addon, - array( - 'Require_LP_Version' => 'Require_LP_Version', - 'Version' => 'Version', - ) - ); - - // $lp_addon_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $lp_addon ); - $lp_addon_version = $lp_addon_info['Version']; - - $addon = new Lp_Addon(); - $addon->version = $lp_addon_version; - $addon->plugin_base = $lp_addon; - $addon->require_version = $lp_addon_info['Require_LP_Version']; - $addon_valid = $addon->check_require_version_addon(); - - if ( $addons_valid ) { - $addon_valid = $addon->check_require_version_lp(); - } - - if ( ! $addon_valid ) { - $addons_valid = false; - } - } - // End check addons valid. - - if ( ! $addons_valid ) { - return; - } - - // let third parties know that we're ready . - do_action( 'learn-press/ready' ); - - /** - * Fixed temporary for emails of Announcement v4.0.6, Assignment v4.1.1 addons. - * @since 4.2.7.4 - * When 2 addons update to new version, will remove this code. - */ - if ( class_exists( 'LP_Addon_Announcements_Preload' ) ) { - if ( version_compare( LP_ADDON_ANNOUNCEMENTS_VER, '4.0.6', '<=' ) ) { - $addon_announcement = LP_Addon_Announcements_Preload::$addon; - $addon_announcement->emails_setting(); - } - } - if ( class_exists( 'LP_Addon_Assignment_Preload' ) ) { - if ( version_compare( LP_ADDON_ASSIGNMENT_VER, '4.1.1', '<=' ) ) { - $addon_assignment = LP_Addon_Assignment_Preload::$addon; - $addon_assignment->emails_setting(); - } - } - } catch ( Throwable $e ) { - error_log( __METHOD__ . ': ' . $e->getMessage() ); - } - } - /** * Handle load text domain for LearnPress. * @@ -789,13 +738,6 @@ public function load_plugin_text_domain() { load_plugin_textdomain( LP_TEXT_DOMAIN, false, LP_PLUGIN_FOLDER_NAME . '/languages' ); } - /** - * Remove hook deactivate addon assignments v3. - */ - public function lp_assignment_install() { - remove_action( 'deactivate_learnpress-assignments/learnpress-assignments.php', 'lp_assignment_remove' ); - } - /** * Get instance of class LP_Template. * @@ -813,27 +755,6 @@ public function template( $type = '' ) { return $templates[ $type ] ?? $this->template; } - /** - * Init LearnPress when WP initialises - */ - public function init() { - $this->api = new LP_Core_API(); - $this->admin_api = new LP_Admin_Core_API(); - - $this->get_session(); - - $this->settings = $this->settings(); - - if ( $this->is_request( 'frontend' ) ) { - $this->get_cart(); - } - - // Init emails - LP_Emails::instance(); - // Email hook notify - include_once 'inc/emails/class-lp-email-hooks.php'; - } - /** * Get session object instance. * From c413f4eb2be5528bc804fbbb4dbb54cef1f55a10 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Sat, 28 Dec 2024 14:11:29 +0700 Subject: [PATCH 059/225] = 4.2.7.6 = ~ Tweak: LP_Addon class. ~ Comment hook add_action( 'init', 'learn_press_setup_user' ) --- inc/abstracts/abstract-addon.php | 3 ++- inc/lp-template-functions.php | 2 +- learnpress.php | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/inc/abstracts/abstract-addon.php b/inc/abstracts/abstract-addon.php index ac892531a..e110c7d1c 100644 --- a/inc/abstracts/abstract-addon.php +++ b/inc/abstracts/abstract-addon.php @@ -90,7 +90,8 @@ public function __construct() { $this->_define_constants(); $this->_includes(); remove_action( 'plugins_loaded', array( 'LP_Addon_Announcements', 'instance' ) ); - add_action( 'init', array( $this, 'init' ) ); + //add_action( 'init', array( $this, 'init' ) ); + $this->init(); } /** diff --git a/inc/lp-template-functions.php b/inc/lp-template-functions.php index 07d408257..1cce23057 100644 --- a/inc/lp-template-functions.php +++ b/inc/lp-template-functions.php @@ -545,7 +545,7 @@ function learn_press_setup_user() { $GLOBALS['lp_user'] = learn_press_get_current_user(); } -add_action( 'init', 'learn_press_setup_user', 1000 ); +//add_action( 'init', 'learn_press_setup_user', 1000 ); /** * Display a message immediately with out push into queue diff --git a/learnpress.php b/learnpress.php index f417bf7f8..c19093855 100644 --- a/learnpress.php +++ b/learnpress.php @@ -509,6 +509,7 @@ private function include_files_frontend() { /** * Main instance of LearnPress. + * Must load on "init" hook of WordPress. * 1. Load text domain. * 2. Handle lp ajax. * From a3da9f564c893e1d453811cd6fc7c21ed1ba7c37 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Sat, 28 Dec 2024 17:55:17 +0700 Subject: [PATCH 060/225] = 4.2.7.6 = ~ Test call speed lp-ajax. --- assets/src/js/loadAJAX.js | 20 ++++++ inc/Ajax/AbstractAjax.php | 31 ++++++++++ inc/Ajax/AjaxBase.php | 31 ---------- inc/Ajax/LoadContentViaAjax.php | 78 ++++++++++++++++++++++++ inc/Models/UserItems/UserCourseModel.php | 4 +- inc/Shortcodes/AbstractShortcode.php | 1 - inc/class-lp-assets.php | 1 + inc/class-lp-helper.php | 2 +- inc/lp-ajax.php | 20 ++++++ package.json | 4 +- 10 files changed, 155 insertions(+), 37 deletions(-) create mode 100644 inc/Ajax/AbstractAjax.php delete mode 100644 inc/Ajax/AjaxBase.php create mode 100644 inc/Ajax/LoadContentViaAjax.php create mode 100644 inc/lp-ajax.php diff --git a/assets/src/js/loadAJAX.js b/assets/src/js/loadAJAX.js index 6f2b1315e..a74d6fb6b 100644 --- a/assets/src/js/loadAJAX.js +++ b/assets/src/js/loadAJAX.js @@ -89,6 +89,26 @@ const lpAJAX = ( () => { }; window.lpAJAXG.fetchAPI( url, dataSend, callBack ); + + // Test + const urlAjax = lpData.lpAjaxUrl; + const formData = new FormData(); + //formData.append( 'action', 'lp_load_content_via_ajax' ); + formData.append( 'nonce', lpData.nonce ); + formData.append( 'lp-load-ajax', 'load_content_via_ajax' ); + formData.append( 'data', JSON.stringify( dataObj ) ); + const dataSendX = { + method: 'POST', + headers: {}, + body: formData, + }; + + if ( 0 !== parseInt( lpData.user_id ) ) { + dataSendX.headers[ 'X-WP-Nonce' ] = lpSettings.nonce; + } + + lpFetchAPI( urlAjax, dataSendX, callBack ); + // End test. } ); } }, diff --git a/inc/Ajax/AbstractAjax.php b/inc/Ajax/AbstractAjax.php new file mode 100644 index 000000000..7f38f9ebb --- /dev/null +++ b/inc/Ajax/AbstractAjax.php @@ -0,0 +1,31 @@ +catch_lp_ajax(); - } - - public function catch_lp_ajax() { - if ( ! empty( $_REQUEST['lp-ajax'] ) ) { - $action = $_REQUEST['lp-ajax']; - $action = str_replace( '-', '_', $action ); - $action = 'lp_ajax_' . $action; - if ( is_callable( $action ) ) { - call_user_func( $action ); - } - wp_die( '0', 400 ); - } - } -} diff --git a/inc/Ajax/LoadContentViaAjax.php b/inc/Ajax/LoadContentViaAjax.php new file mode 100644 index 000000000..d4cf3e3dc --- /dev/null +++ b/inc/Ajax/LoadContentViaAjax.php @@ -0,0 +1,78 @@ +content ) ) { + throw new Exception( 'Error: data content invalid!' ); + } + + $response->status = 'success'; + $response->message = 'Success!'; + $response->data = $data; + } catch ( Throwable $e ) { + $response->status = 'error'; + $response->message = $e->getMessage(); + } + + wp_send_json( $response ); + } +} diff --git a/inc/Models/UserItems/UserCourseModel.php b/inc/Models/UserItems/UserCourseModel.php index 622bcc46f..7b18d931e 100644 --- a/inc/Models/UserItems/UserCourseModel.php +++ b/inc/Models/UserItems/UserCourseModel.php @@ -465,12 +465,12 @@ public function get_time_remaining(): int { return $timestamp_remaining; } - $user_id = $userModel->get_id(); + /*$user_id = $userModel->get_id(); $user_wp = new \WP_User( $userModel ); if ( user_can( $user_wp, ADMIN_ROLE ) || ( user_can( $user_wp, LP_TEACHER_ROLE ) && $author->get_id() === $user_id ) ) { return $timestamp_remaining; - } + }*/ if ( 0 === (int) $courseModel->get_duration() ) { return $timestamp_remaining; diff --git a/inc/Shortcodes/AbstractShortcode.php b/inc/Shortcodes/AbstractShortcode.php index 3ba6d3be3..64338a543 100644 --- a/inc/Shortcodes/AbstractShortcode.php +++ b/inc/Shortcodes/AbstractShortcode.php @@ -28,4 +28,3 @@ protected function init() { */ abstract public function render( $attrs ): string; } - diff --git a/inc/class-lp-assets.php b/inc/class-lp-assets.php index 4284d2288..6bc70a0fb 100644 --- a/inc/class-lp-assets.php +++ b/inc/class-lp-assets.php @@ -152,6 +152,7 @@ public function localize_data_global(): array { 'lp_version' => LearnPress::instance()->version, 'lp_rest_load_ajax' => get_rest_url( null, 'lp/v1/load_content_via_ajax/' ), 'ajaxUrl' => admin_url( 'admin-ajax.php' ), + 'lpAjaxUrl' => LP_PLUGIN_URL . 'inc/lp-ajax.php', 'coverImageRatio' => $aspectRatio, 'toast' => [ 'gravity' => 'bottom', diff --git a/inc/class-lp-helper.php b/inc/class-lp-helper.php index d81dddab8..94a7b49d6 100644 --- a/inc/class-lp-helper.php +++ b/inc/class-lp-helper.php @@ -585,7 +585,7 @@ public static function get_link_no_cache( string $link ): string { public static function json_decode( string $str, $associative = null ) { $obj = json_decode( $str, $associative ); if ( json_last_error() !== JSON_ERROR_NONE ) { - throw new Exception( json_last_error_msg() ); + throw new Exception( 'JSON decode: ' . json_last_error_msg() ); } return $obj; diff --git a/inc/lp-ajax.php b/inc/lp-ajax.php new file mode 100644 index 000000000..a32477817 --- /dev/null +++ b/inc/lp-ajax.php @@ -0,0 +1,20 @@ + Date: Mon, 30 Dec 2024 08:41:24 +0700 Subject: [PATCH 061/225] = 4.2.7.6 = ~ Tweak: handle Ajax on hook init with priority = 10. --- learnpress.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/learnpress.php b/learnpress.php index c19093855..b5c79ddee 100644 --- a/learnpress.php +++ b/learnpress.php @@ -14,7 +14,7 @@ * @package LearnPress */ -use LearnPress\Ajax\AjaxBase; +use LearnPress\Ajax\LoadContentViaAjax; use LearnPress\ExternalPlugin\Elementor\LPElementor; use LearnPress\ExternalPlugin\YoastSeo\LPYoastSeo; use LearnPress\Models\UserModel; @@ -138,6 +138,14 @@ private function __construct() { // Must handle in hook init of WordPress, when loaded plugins, theme, user. add_action( 'init', [ $this, 'lp_main_handle' ], - 1000 ); + add_action( + 'init', + function () { + // Handle lp ajax. + LoadContentViaAjax::catch_lp_ajax(); + } + ); + // hooks . $this->init_hooks(); } catch ( Throwable $e ) { @@ -520,8 +528,6 @@ private function include_files_frontend() { public function lp_main_handle() { // Load text domain. $this->load_plugin_text_domain(); - // Handle lp ajax. - AjaxBase::instance(); // Polylang if ( defined( 'POLYLANG_VERSION' ) ) { From a4ed2deabe6a522c9b7f841087a4e943eab8a75b Mon Sep 17 00:00:00 2001 From: truongpn Date: Mon, 30 Dec 2024 11:37:21 +0700 Subject: [PATCH 062/225] style curriculumn --- assets/src/scss/frontend/_course-single.scss | 1 + assets/src/scss/frontend/_curriculum.scss | 160 +++++++++++++++--- .../Course/SingleCourseTemplate.php | 26 +-- 3 files changed, 149 insertions(+), 38 deletions(-) diff --git a/assets/src/scss/frontend/_course-single.scss b/assets/src/scss/frontend/_course-single.scss index 4070dd54a..3540783ca 100644 --- a/assets/src/scss/frontend/_course-single.scss +++ b/assets/src/scss/frontend/_course-single.scss @@ -351,6 +351,7 @@ .course-requirements { ul { margin: 0 0 0 20px; + padding: 0; } } diff --git a/assets/src/scss/frontend/_curriculum.scss b/assets/src/scss/frontend/_curriculum.scss index a159b3478..7e7977ef1 100644 --- a/assets/src/scss/frontend/_curriculum.scss +++ b/assets/src/scss/frontend/_curriculum.scss @@ -1113,52 +1113,162 @@ body.course-item-popup { .course-curriculum-info { display: flex; justify-content: space-between; - align-items: center; + gap: 20px; margin-bottom: 20px; &__left { display: flex; align-items: center; flex-wrap: wrap; - column-gap: 20px; - row-gap: 8px; + gap: 8px; + + li { + display: inline-flex; + align-items: center; + gap: 8px; + + &::after { + content: ''; + width: 4px; + height: 4px; + background-color: $border-color; + display: inline-block; + } + + &:last-child { + &::after { + content: none; + } + } + } + } + + &__right { + font-weight: bold; + text-align: right; + text-transform: capitalize; } } - .course-curriculum { - .course-section { - margin-bottom: 8px; - border: 1px solid $border-color; - border-radius: $border-radius-global; - + .course-section { + margin-bottom: 8px; + border: 1px solid $border-color; + border-radius: $border-radius-global; + + &:last-child { + margin-bottom: 0; + } + + .course-section-header { + background-color: $bg-grey; + padding: 20px; + column-gap: 20px; + display: flex; + justify-content: space-between; + } + + &__title { + font-weight: bold; + font-size: $font-size-large; + margin: 0 0 8px 0; + } + + .section-toggle { + display: flex; + justify-content: center; + } + + .course-item { + background-color: transparent; + border-bottom: 1px solid $border-color; + padding: 12px 20px; + &:last-child { - margin-bottom: 0; + border-bottom: none; } - .course-section-header { - background-color: $bg-grey; - padding: 20px; - column-gap: 20px; + &__link { display: flex; justify-content: space-between; + width: 100%; + column-gap: 20px; + row-gap: 8; + flex-wrap: wrap; } - &-title { - font-weight: bold; + &__left { + display: flex; + column-gap: 16px; + row-gap: 8px; + align-items: center; + + &:hover { + color: $color-primary; + } } - .course-item { - background-color: transparent; - border-bottom: 1px solid $border-color; - padding: 12px 20px; + &__right { + display: flex; + column-gap: 12px; + row-gap: 8px; + align-items: center; + } + } - &:last-child { - border-bottom: none; - } + .course-item-ico { + &::before { + content: ''; + display: inline-block; + font-family: "lp-icon"; + font-weight: normal; + font-size: $font-size-large; + } - &-left { + &.lp_lesson::before { + content: "\f15b"; + } - } + &.lp_quiz::before { + content: "\f12e"; + } + + &.lp_assignment::before { + content: "\e929"; + } + + &.preview::before { + content: "\f06e"; + color: $input-color-placeholder; + } + + &.locked::before { + content: "\f023"; + color: $input-color-placeholder; + } + + &.passed::before { + content: "\f00c"; + color: #3bb54a; + } + + &.in-progress::before { + content: "\f00c"; + color: $input-color-placeholder; + } + + &.failed::before { + content: "\f00d"; + color: #f02425; + } + + &.started::before { + content: "\f00c"; + color: $input-color-placeholder; + } + + &.doing::before { + content: "\e921"; + color: $input-color-placeholder; } } } diff --git a/inc/TemplateHooks/Course/SingleCourseTemplate.php b/inc/TemplateHooks/Course/SingleCourseTemplate.php index ff3535c7d..91bdb4688 100644 --- a/inc/TemplateHooks/Course/SingleCourseTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseTemplate.php @@ -1195,8 +1195,8 @@ public function html_curriculum( CourseModel $course, $user ): string { $section = [ 'wrapper' => '
    ', - 'curriculum_info' => '
    ', - 'curriculum_info_left' => '
      ', + 'curriculum_info' => '
      ', + 'curriculum_info_left' => '
        ', 'count_sections' => sprintf( '
      • %s
      • ', sprintf( @@ -1205,7 +1205,7 @@ public function html_curriculum( CourseModel $course, $user ): string { ) ), 'count_lesson' => sprintf( - '
      • %s
      • ', + '
      • %s
      • ', sprintf( _n( '%d Lesson', '%d Lessons', $course->count_items( LP_LESSON_CPT ), 'learnpress' ), $course->get_total_sections() @@ -1216,7 +1216,7 @@ public function html_curriculum( CourseModel $course, $user ): string { $this->html_duration( $course ) ), 'curriculum_info_left_end' => '
      ', - 'curriculum_info_right' => '
      ', + 'curriculum_info_right' => '
      ', 'expand_all' => sprintf( '%s', esc_html__( 'Expand all sections', 'learnpress' ) @@ -1263,12 +1263,12 @@ public function render_html_section_item( CourseModel $course, $user, $section_i $section_header = [ 'start' => '
      ', 'info' => '', 'toggle' => ' - - + + ', 'end' => '
      ', ]; @@ -1278,7 +1278,7 @@ public function render_html_section_item( CourseModel $course, $user, $section_i $li_items .= $this->render_html_course_item( $course, $user, $item ); } $section_items = [ - 'start' => '
        ', + 'start' => '
          ', 'li_items' => $li_items, 'end' => '
        ', ]; @@ -1384,7 +1384,7 @@ public function render_html_course_item( CourseModel $courseModel, $userModel, $ } $html_item_status = sprintf( - '%1$s', + '', $user_item_status_ico_flag ); @@ -1396,17 +1396,17 @@ public function render_html_course_item( CourseModel $courseModel, $userModel, $ $item_type ), 'link' => sprintf( - '', + '', esc_url_raw( $link_item ) ), - 'item_left' => '
        ', + 'item_left' => '
        ', 'icon' => sprintf( '', esc_attr( $item_type ) ), 'title' => sprintf( '
        %s
        ', wp_kses_post( $title ) ), 'item_left_end' => '
        ', - 'item_right' => '
        ', + 'item_right' => '
        ', 'duration' => $html_item_duration, 'status' => $html_item_status, 'item_right_end' => '
        ', From 2b827f5f9392ef5ee74293f281531bf6a1a17fa5 Mon Sep 17 00:00:00 2001 From: truongpn Date: Mon, 30 Dec 2024 11:43:11 +0700 Subject: [PATCH 063/225] style curriculumn --- assets/src/scss/frontend/_course-single.scss | 4 +++- assets/src/scss/frontend/_curriculum.scss | 1 - inc/TemplateHooks/Course/SingleCourseTemplate.php | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/assets/src/scss/frontend/_course-single.scss b/assets/src/scss/frontend/_course-single.scss index 3540783ca..c7572da9d 100644 --- a/assets/src/scss/frontend/_course-single.scss +++ b/assets/src/scss/frontend/_course-single.scss @@ -342,8 +342,10 @@ .extra-box__title, .course-faqs__title, - .course-material__title { + .course-material__title, + .lp-course-curriculum__title { margin: 0 0 20px 0; + font-weight: bold; } .course-features, diff --git a/assets/src/scss/frontend/_curriculum.scss b/assets/src/scss/frontend/_curriculum.scss index 7e7977ef1..349e47653 100644 --- a/assets/src/scss/frontend/_curriculum.scss +++ b/assets/src/scss/frontend/_curriculum.scss @@ -1221,7 +1221,6 @@ body.course-item-popup { display: inline-block; font-family: "lp-icon"; font-weight: normal; - font-size: $font-size-large; } &.lp_lesson::before { diff --git a/inc/TemplateHooks/Course/SingleCourseTemplate.php b/inc/TemplateHooks/Course/SingleCourseTemplate.php index 91bdb4688..01dfa7d4c 100644 --- a/inc/TemplateHooks/Course/SingleCourseTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseTemplate.php @@ -1195,6 +1195,7 @@ public function html_curriculum( CourseModel $course, $user ): string { $section = [ 'wrapper' => '
        ', + 'title' => sprintf( '

        %s

        ', esc_html__( 'Curriculum', 'learnpress' ) ), 'curriculum_info' => '
        ', 'curriculum_info_left' => '
          ', 'count_sections' => sprintf( From b406a17cf9af23f98ac1f304b9d650702222e14a Mon Sep 17 00:00:00 2001 From: truongpn Date: Mon, 30 Dec 2024 11:53:25 +0700 Subject: [PATCH 064/225] style curriculumn --- inc/TemplateHooks/Course/SingleCourseTemplate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/TemplateHooks/Course/SingleCourseTemplate.php b/inc/TemplateHooks/Course/SingleCourseTemplate.php index 01dfa7d4c..bbcb58aeb 100644 --- a/inc/TemplateHooks/Course/SingleCourseTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseTemplate.php @@ -1342,7 +1342,7 @@ public function render_html_course_item( CourseModel $courseModel, $userModel, $ $duration_number = floatval( $duration_arr[0] ?? 0 ); $duration_type = $duration_arr[1] ?? ''; - $item_duration_plural = esc_html__( 'Unlimited', 'learnpress' ); + $item_duration_plural = ''; if ( $duration_number > 0 ) { $item_duration_plural = LP_Datetime::get_string_plural_duration( $duration_number, $duration_type ); } From f190cf2327b1ee50a6bd8803791a01f194577ace Mon Sep 17 00:00:00 2001 From: Tungnx Date: Mon, 30 Dec 2024 12:06:25 +0700 Subject: [PATCH 065/225] = 4.2.7.6 = --- inc/TemplateHooks/Course/SingleCourseTemplate.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/inc/TemplateHooks/Course/SingleCourseTemplate.php b/inc/TemplateHooks/Course/SingleCourseTemplate.php index ff3535c7d..2db2c9db6 100644 --- a/inc/TemplateHooks/Course/SingleCourseTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseTemplate.php @@ -1370,6 +1370,10 @@ public function render_html_course_item( CourseModel $courseModel, $userModel, $ if ( ! empty( $user_item_graduation ) ) { $user_item_status_ico_flag = $user_item_graduation; } + + if ( empty( $user_item_status_ico_flag ) ) { + $user_item_status_ico_flag = UserItemModel::GRADUATION_IN_PROGRESS; + } } } } From e24599d7e5f9e91355f24a1aac5f30504e329abb Mon Sep 17 00:00:00 2001 From: Tungnx Date: Mon, 30 Dec 2024 13:39:47 +0700 Subject: [PATCH 066/225] = 4.2.7.6 = ~ Added: exclude_from_search for lesson, quiz, order. --- inc/custom-post-types/lesson.php | 42 ++++++++++++------------------ inc/custom-post-types/order.php | 44 ++++++++++++++++---------------- inc/custom-post-types/quiz.php | 29 +++++++++++---------- 3 files changed, 54 insertions(+), 61 deletions(-) diff --git a/inc/custom-post-types/lesson.php b/inc/custom-post-types/lesson.php index 08b92ee77..45835bd35 100644 --- a/inc/custom-post-types/lesson.php +++ b/inc/custom-post-types/lesson.php @@ -170,7 +170,7 @@ public function views_pages( array $views ): array { public function args_register_post_type(): array { return array( - 'labels' => array( + 'labels' => array( 'name' => esc_html__( 'Lessons', 'learnpress' ), 'menu_name' => esc_html__( 'Lessons', 'learnpress' ), 'singular_name' => esc_html__( 'Lesson', 'learnpress' ), @@ -184,30 +184,31 @@ public function args_register_post_type(): array { 'not_found' => esc_html__( 'No lesson found', 'learnpress' ), 'not_found_in_trash' => esc_html__( 'There was no lesson found in the trash', 'learnpress' ), ), - 'public' => true, - 'query_var' => true, - 'taxonomies' => array( 'lesson_tag' ), - 'publicly_queryable' => true, - 'show_ui' => true, - 'has_archive' => false, - 'capability_type' => LP_LESSON_CPT, - 'map_meta_cap' => true, - 'show_in_menu' => 'learn_press', - 'show_in_admin_bar' => true, - 'show_in_nav_menus' => true, - 'show_in_rest' => learn_press_user_maybe_is_a_teacher(), - 'supports' => array( + 'public' => true, + 'query_var' => true, + 'taxonomies' => array( 'lesson_tag' ), + 'publicly_queryable' => true, + 'show_ui' => true, + 'has_archive' => false, + 'capability_type' => LP_LESSON_CPT, + 'map_meta_cap' => true, + 'show_in_menu' => 'learn_press', + 'show_in_admin_bar' => true, + 'show_in_nav_menus' => true, + 'show_in_rest' => learn_press_user_maybe_is_a_teacher(), + 'supports' => array( 'title', 'editor', 'revisions', 'comments', ), - 'hierarchical' => true, - 'rewrite' => array( + 'hierarchical' => true, + 'rewrite' => array( 'slug' => 'lessons', 'hierarchical' => true, 'with_front' => false, ), + 'exclude_from_search' => false, ); } @@ -304,15 +305,6 @@ public function sortable_columns( $columns ) { return $columns; } - /** - * Add admin params. - * - * @return array - */ - public function admin_params() { - return array( 'notice_empty_lesson' => '' ); - } - /** * Lesson assigned view. * diff --git a/inc/custom-post-types/order.php b/inc/custom-post-types/order.php index 2e567ea44..563627d2c 100644 --- a/inc/custom-post-types/order.php +++ b/inc/custom-post-types/order.php @@ -211,10 +211,10 @@ public function admin_footer() { */ public function posts_where_paged( $where ) { // Code temporary, when release about 1 week, will remove it. - $lp_filter_post = new LP_Post_Type_Filter(); - $lp_filter_post->post_type = LP_ORDER_CPT; + $lp_filter_post = new LP_Post_Type_Filter(); + $lp_filter_post->post_type = LP_ORDER_CPT; $lp_filter_post->post_status = [ 'lp-trash' ]; - $orders_trash = LP_Post_DB::getInstance()->get_posts( $lp_filter_post ); + $orders_trash = LP_Post_DB::getInstance()->get_posts( $lp_filter_post ); if ( $orders_trash ) { foreach ( $orders_trash as $order_trash ) { $order = learn_press_get_order( $order_trash->ID ); @@ -229,7 +229,7 @@ public function posts_where_paged( $where ) { global $wpdb, $wp_query; $lp_db = LP_Database::getInstance(); if ( is_admin() && $this->is_page_list_posts_on_backend() ) { - $where = " "; + $where = ' '; $where .= $wpdb->prepare( " AND {$lp_db->tb_posts}.post_type = %s", LP_ORDER_CPT ); } @@ -237,7 +237,6 @@ public function posts_where_paged( $where ) { if ( ! empty( $wp_query->get( 's' ) ) ) { $s = $wp_query->get( 's' ); - // Check search LP Order ID with format #000[ID] or 000[ID] $pattern = '/^#\d+$/'; if ( preg_match( $pattern, $s ) ) { @@ -252,18 +251,18 @@ public function posts_where_paged( $where ) { $s = trim( $s ); $where .= $wpdb->prepare( " AND {$lp_db->tb_posts}.ID = %d", $s ); - $where .= $wpdb->prepare( " OR lpori.order_item_name like %s", '%' . $wpdb->esc_like( $s ) . '%' ); + $where .= $wpdb->prepare( ' OR lpori.order_item_name like %s', '%' . $wpdb->esc_like( $s ) . '%' ); } // Search by author id if ( ! empty( $wp_query->get( 'author' ) ) ) { $user_id = absint( $wp_query->get( 'author' ) ); //$where .= $wpdb->prepare( ' AND uu.ID like %s ', $user_id ); - $where .= " AND ( pm1.meta_value like '%\"$user_id\"%' OR pm1.meta_value = $user_id ) "; + $where .= " AND ( pm1.meta_value like '%\"$user_id\"%' OR pm1.meta_value = $user_id ) "; } if ( ! empty( $wp_query->get( 'm' ) ) ) { - $month = $wp_query->get( 'm' ); + $month = $wp_query->get( 'm' ); $where .= " AND YEAR({$lp_db->tb_posts}.post_date)=" . substr( $month, 0, 4 ); if ( strlen( $month ) > 5 ) { $where .= " AND MONTH({$lp_db->tb_posts}.post_date)=" . substr( $month, 4, 2 ); @@ -350,8 +349,8 @@ public function posts_join_paged( $join ) { * @return mixed */ public function sortable_columns( $columns ) { - $columns['order_date'] = 'date'; - $columns['order_total'] = 'order_total'; + $columns['order_date'] = 'date'; + $columns['order_total'] = 'order_total'; return $columns; } @@ -591,7 +590,7 @@ private function _is_search() { */ public function args_register_post_type(): array { return array( - 'labels' => array( + 'labels' => array( 'name' => __( 'Orders', 'learnpress' ), 'menu_name' => __( 'Orders', 'learnpress' ), 'singular_name' => __( 'Order', 'learnpress' ), @@ -605,24 +604,25 @@ public function args_register_post_type(): array { 'not_found' => __( 'No order found', 'learnpress' ), 'not_found_in_trash' => __( 'There was no order found in the trash', 'learnpress' ), ), - 'public' => false, - 'show_ui' => true, - 'show_in_nav_menus' => false, - 'show_in_admin_bar' => false, - 'publicly_queryable' => false, - 'show_in_menu' => 'learn_press', - 'map_meta_cap' => true, - 'capability_type' => LP_ORDER_CPT, - 'hierarchical' => true, - 'rewrite' => array( + 'public' => false, + 'show_ui' => true, + 'show_in_nav_menus' => false, + 'show_in_admin_bar' => false, + 'publicly_queryable' => false, + 'show_in_menu' => 'learn_press', + 'map_meta_cap' => true, + 'capability_type' => LP_ORDER_CPT, + 'hierarchical' => true, + 'rewrite' => array( 'slug' => LP_ORDER_CPT, 'hierarchical' => true, 'with_front' => true, ), - 'supports' => array( + 'supports' => array( 'title', 'custom-fields', ), + 'exclude_from_search' => true, ); } diff --git a/inc/custom-post-types/quiz.php b/inc/custom-post-types/quiz.php index b18bb81e6..5c2cd4a77 100644 --- a/inc/custom-post-types/quiz.php +++ b/inc/custom-post-types/quiz.php @@ -81,7 +81,7 @@ public function args_register_post_type(): array { $args = apply_filters( 'lp_quiz_post_type_args', array( - 'labels' => array( + 'labels' => array( 'name' => esc_html__( 'Quizzes', 'learnpress' ), 'menu_name' => esc_html__( 'Quizzes', 'learnpress' ), 'singular_name' => esc_html__( 'Quiz', 'learnpress' ), @@ -95,27 +95,28 @@ public function args_register_post_type(): array { 'not_found' => sprintf( __( 'You haven\'t had any quizzes yet. Click Add new to start', 'learnpress' ), admin_url( 'post-new.php?post_type=lp_quiz' ) ), 'not_found_in_trash' => esc_html__( 'There was no quiz found in the trash', 'learnpress' ), ), - 'public' => true, - 'publicly_queryable' => true, - 'show_ui' => true, - 'has_archive' => false, - 'capability_type' => LP_LESSON_CPT, - 'map_meta_cap' => true, - 'show_in_menu' => 'learn_press', - 'show_in_rest' => true, - 'show_in_admin_bar' => true, - 'show_in_nav_menus' => true, - 'supports' => array( + 'public' => true, + 'publicly_queryable' => true, + 'show_ui' => true, + 'has_archive' => false, + 'capability_type' => LP_LESSON_CPT, + 'map_meta_cap' => true, + 'show_in_menu' => 'learn_press', + 'show_in_rest' => true, + 'show_in_admin_bar' => true, + 'show_in_nav_menus' => true, + 'supports' => array( 'title', 'editor', 'revisions', ), - 'hierarchical' => true, - 'rewrite' => array( + 'hierarchical' => true, + 'rewrite' => array( 'slug' => 'quizzes', 'hierarchical' => true, 'with_front' => false, ), + 'exclude_from_search' => true, ) ); From 9a92536d5670319f63941cfe93fa47e9423a2e31 Mon Sep 17 00:00:00 2001 From: truongpn Date: Mon, 30 Dec 2024 14:23:21 +0700 Subject: [PATCH 067/225] style curriculumn --- assets/src/scss/frontend/_curriculum.scss | 6 ++++++ inc/TemplateHooks/Course/SingleCourseTemplate.php | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/assets/src/scss/frontend/_curriculum.scss b/assets/src/scss/frontend/_curriculum.scss index 349e47653..e75818e9b 100644 --- a/assets/src/scss/frontend/_curriculum.scss +++ b/assets/src/scss/frontend/_curriculum.scss @@ -1212,6 +1212,12 @@ body.course-item-popup { column-gap: 12px; row-gap: 8px; align-items: center; + + .course-item-ico { + width: 24px; + display: flex; + justify-content: center; + } } } diff --git a/inc/TemplateHooks/Course/SingleCourseTemplate.php b/inc/TemplateHooks/Course/SingleCourseTemplate.php index aac2f4b03..43336de86 100644 --- a/inc/TemplateHooks/Course/SingleCourseTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseTemplate.php @@ -1347,7 +1347,7 @@ public function render_html_course_item( CourseModel $courseModel, $userModel, $ $item_duration_plural = LP_Datetime::get_string_plural_duration( $duration_number, $duration_type ); } $html_item_duration = sprintf( - '%s', + '%s', $item_duration_plural ); From 4591a020234aed94fb3de9654c7d54acd1647284 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Mon, 30 Dec 2024 14:38:17 +0700 Subject: [PATCH 068/225] = 4.2.7.6 = ~ Allow: html display on the Offline payment. --- .../offline-payment/class-lp-gateway-offline-payment.php | 2 +- templates/checkout/payment-method.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/inc/gateways/offline-payment/class-lp-gateway-offline-payment.php b/inc/gateways/offline-payment/class-lp-gateway-offline-payment.php index eb24a6459..8de439f63 100644 --- a/inc/gateways/offline-payment/class-lp-gateway-offline-payment.php +++ b/inc/gateways/offline-payment/class-lp-gateway-offline-payment.php @@ -88,7 +88,7 @@ public function get_settings(): array { * Payment form. */ public function get_payment_form() { - return esc_html( LP_Settings::instance()->get( $this->id . '.description', $this->description ) ); + return wp_kses_post( LP_Settings::instance()->get( $this->id . '.description', $this->description ) ); } /** diff --git a/templates/checkout/payment-method.php b/templates/checkout/payment-method.php index a6c806c11..ea056688f 100644 --- a/templates/checkout/payment-method.php +++ b/templates/checkout/payment-method.php @@ -6,7 +6,7 @@ * * @author ThimPress * @package Learnpress/Templates - * @version 4.0.1 + * @version 4.0.2 */ defined( 'ABSPATH' ) || exit(); @@ -34,11 +34,11 @@ class="lp-payment-method lp-payment-method-id ); get_payment_form(); $style = $gateway->is_selected ? 'display: block' : 'display: none'; - if ( $payment_form ) : + if ( ! empty( $payment_form ) ) : ?>
          - +
          From 62e426f6a9cc300492bb9789e3bf1c3f7b63feda Mon Sep 17 00:00:00 2001 From: Tungnx Date: Mon, 30 Dec 2024 14:49:42 +0700 Subject: [PATCH 069/225] = 4.2.7.6 = ~ Tweak: LP_Quiz_Post_Type class. --- inc/custom-post-types/abstract.php | 8 ++--- inc/custom-post-types/quiz.php | 52 +++++++++++------------------- 2 files changed, 20 insertions(+), 40 deletions(-) diff --git a/inc/custom-post-types/abstract.php b/inc/custom-post-types/abstract.php index 66d3ab3e6..cd5a64e30 100644 --- a/inc/custom-post-types/abstract.php +++ b/inc/custom-post-types/abstract.php @@ -407,12 +407,8 @@ public function trashed_post( int $post_id ) { } public function column_instructor( $post_id = 0 ) { - global $post; - - $user_id = get_the_author_meta( 'ID' ); - if ( ! $user_id ) { - return; - } + $post = get_post( $post_id ); + $user_id = $post->post_author; $user = UserModel::find( $user_id, true ); if ( ! $user ) { diff --git a/inc/custom-post-types/quiz.php b/inc/custom-post-types/quiz.php index 5c2cd4a77..08c909c1d 100644 --- a/inc/custom-post-types/quiz.php +++ b/inc/custom-post-types/quiz.php @@ -7,6 +7,8 @@ * @version 4.0.0 */ +use LearnPress\Models\QuizPostModel; + defined( 'ABSPATH' ) || exit(); if ( ! class_exists( 'LP_Quiz_Post_Type' ) ) { @@ -264,7 +266,10 @@ public function columns_head( $columns ) { * @param int $post_id */ public function columns_content( $name, $post_id = 0 ) { - global $post; + $quizPostModel = QuizPostModel::find( $post_id, true ); + if ( ! $quizPostModel ) { + return; + } switch ( $name ) { case 'instructor': @@ -274,48 +279,27 @@ public function columns_content( $name, $post_id = 0 ) { $this->_get_item_course( $post_id ); break; case 'num_of_question': - if ( property_exists( $post, 'question_count' ) ) { - $count = $post->question_count; - } else { - $quiz = LP_Quiz::get_quiz( $post_id ); - $count = $quiz->count_questions(); - } + $count = $quizPostModel->count_questions(); printf( - '%s', - ( $count ) ? sprintf( _n( '%d question', '%d questions', $count, 'learnpress' ), $count ) : __( 'This quiz has no questions', 'learnpress' ), + '%s', + ! $count ? 'disabled' : '', + $count ? + sprintf( _n( '%d question', '%d questions', $count, 'learnpress' ), $count ) : + __( 'This quiz has no questions', 'learnpress' ), $count ); break; case 'duration': - $duration_str = get_post_meta( $post_id, '_lp_duration', true ); - $duration = (int) $duration_str; + $duration_str = $quizPostModel->get_duration(); + $duration_arr = explode( ' ', $duration_str ); + $duration = $duration_arr[0]; + $duration_type = $duration_arr[1]; if ( $duration > 0 ) { - $duration_str .= 's'; - $duration_str_arr = explode( ' ', $duration_str ); - $type_time = ''; - - if ( is_array( $duration_str_arr ) && ! empty( $duration_str_arr ) && count( $duration_str_arr ) >= 2 ) { - switch ( $duration_str_arr[1] ) { - case 'hours': - $type_time = __( 'hours', 'learnpress' ); - break; - case 'minutes': - $type_time = __( 'minutes', 'learnpress' ); - break; - case 'days': - $type_time = __( 'days', 'learnpress' ); - break; - case 'weeks': - $type_time = __( 'weeks', 'learnpress' ); - break; - } - - $duration_str = sprintf( '%1$s %2$s', $duration_str_arr[0], $type_time ); - } + $duration_str = LP_Datetime::get_string_plural_duration( $duration, $duration_type ); } else { - $duration_str = '--'; + $duration_str = __( 'Unlimited', 'learnpress' ); } echo esc_html( $duration_str ); From efa31158dfc0d7c0a3bb617870e59d7393ca5139 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Mon, 30 Dec 2024 16:26:16 +0700 Subject: [PATCH 070/225] = 4.2.7.6 = ~ Code temporary query get lesson is preview when search via ?s= of WP. --- inc/Ajax/LoadContentViaAjax.php | 1 - inc/class-lp-page-controller.php | 39 +++++++++++++++++++++----------- inc/custom-post-types/lesson.php | 2 +- inc/order/lp-order-functions.php | 4 ++-- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/inc/Ajax/LoadContentViaAjax.php b/inc/Ajax/LoadContentViaAjax.php index d4cf3e3dc..9e32ec29b 100644 --- a/inc/Ajax/LoadContentViaAjax.php +++ b/inc/Ajax/LoadContentViaAjax.php @@ -8,7 +8,6 @@ namespace LearnPress\Ajax; -use Elementor\Thim_Ekit_Widget_Archive_Course; use Exception; use LP_Helper; use LP_REST_Response; diff --git a/inc/class-lp-page-controller.php b/inc/class-lp-page-controller.php index f60c32e4a..2973fc1bf 100644 --- a/inc/class-lp-page-controller.php +++ b/inc/class-lp-page-controller.php @@ -41,6 +41,32 @@ protected function __construct() { } else { //add_filter( 'post_type_archive_link', [ $this, 'link_archive_course' ], 10, 2 ); add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ), - 1 ); + // For debug mysql query post of WP. + /*add_filter( + 'posts_request', + function ( $request, $q ) { + LP_Debug::var_dump( $request ); + return $request; + }, + 10, + 2 + );*/ + /*add_filter( + 'posts_clauses_request', + function ( $clauses, $wp_query ) { + if ( ! $wp_query->is_search() ) { + return $clauses; + } + + $lp_db = LP_Database::getInstance(); + $clauses['where'] .= sprintf( " OR ( post_type = '%s' AND meta_key = '_lp_preview' AND meta_value = 'yes')", LP_LESSON_CPT ); + $clauses['join'] .= ' INNER JOIN ' . $lp_db->tb_postmeta . ' ON post_id = wp_posts.ID '; + + return $clauses; + }, + 10, + 2 + );*/ // For return result query course to cache. //add_action( 'posts_pre_query', [ $this, 'posts_pre_query' ], 10, 2 ); add_filter( 'template_include', array( $this, 'template_loader' ), 10 ); @@ -758,19 +784,6 @@ public function pre_get_posts( WP_Query $q ): WP_Query { // Exclude item not assign if ( $q->is_search() ) { - // Exclude item not assign any course - $course_item_types = learn_press_get_course_item_types(); - $list_ids_exclude = array(); - - foreach ( $course_item_types as $item_type ) { - $filter = new LP_Post_Type_Filter(); - $filter->post_type = $item_type; - $exclude_item = LP_Course_DB::getInstance()->get_item_ids_unassigned( $filter ); - $exclude_item = LP_Course_DB::get_values_by_key( $exclude_item ); - - $list_ids_exclude = array_merge( $list_ids_exclude, $exclude_item ); - } - return $q; } diff --git a/inc/custom-post-types/lesson.php b/inc/custom-post-types/lesson.php index 45835bd35..c60243a0a 100644 --- a/inc/custom-post-types/lesson.php +++ b/inc/custom-post-types/lesson.php @@ -208,7 +208,7 @@ public function args_register_post_type(): array { 'hierarchical' => true, 'with_front' => false, ), - 'exclude_from_search' => false, + 'exclude_from_search' => true, ); } diff --git a/inc/order/lp-order-functions.php b/inc/order/lp-order-functions.php index 2f2e1514e..487991e6f 100644 --- a/inc/order/lp-order-functions.php +++ b/inc/order/lp-order-functions.php @@ -690,7 +690,7 @@ function learn_press_get_register_order_statuses() { 'show_in_admin_status_list' => true, 'label_count' => _n_noop( 'Failed (%s)', 'Failed (%s)', 'learnpress' ), ); - $order_statues['trash'] = array( + $order_statues['trash'] = array( 'label' => _x( 'Trash', 'Order status', 'learnpress' ), 'public' => false, 'exclude_from_search' => false, @@ -737,7 +737,7 @@ function learn_press_get_order_status( $order_id ) { */ function learn_press_cancel_order_process() { if ( empty( $_REQUEST['cancel-order'] ) || empty( $_REQUEST['lp-nonce'] ) || - ! wp_verify_nonce( $_REQUEST['lp-nonce'], 'cancel-order' ) || is_admin() ) { + ! wp_verify_nonce( $_REQUEST['lp-nonce'], 'cancel-order' ) || is_admin() ) { return; } From 7b9fca5dcd009c95607d4cae2d801d6798aabced Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 31 Dec 2024 11:53:39 +0700 Subject: [PATCH 071/225] = 4.2.7.6 = ~ Tweak: loadAJAX.js, added: fetchAJAX function. ~ Replace window.lpAJAXG.fetchAPI instead of window.lpAJAXG.fetchAJAX --- assets/src/js/frontend/course-filter.js | 2 +- assets/src/js/frontend/courses-v2.js | 10 ++-- assets/src/js/loadAJAX.js | 49 +++++++++++-------- inc/Models/CourseModel.php | 6 +-- .../Course/ListCoursesTemplate.php | 1 + inc/admin/class-lp-admin-assets.php | 2 +- inc/lp-ajax.php | 2 + readme.txt | 4 ++ 8 files changed, 45 insertions(+), 31 deletions(-) diff --git a/assets/src/js/frontend/course-filter.js b/assets/src/js/frontend/course-filter.js index ba4271869..6fe29630e 100644 --- a/assets/src/js/frontend/course-filter.js +++ b/assets/src/js/frontend/course-filter.js @@ -321,7 +321,7 @@ window.lpCourseFilter = { }, }; - window.lpAJAXG.fetchAPI( urlFetch, dataSend, callBack ); + window.lpAJAXG.fetchAJAX( dataSend, callBack ); } else { const courseUrl = lpData.urlParams.page_term_url || lpData.courses_url || ''; const url = new URL( courseUrl ); diff --git a/assets/src/js/frontend/courses-v2.js b/assets/src/js/frontend/courses-v2.js index dcbd85ec4..aa0859774 100644 --- a/assets/src/js/frontend/courses-v2.js +++ b/assets/src/js/frontend/courses-v2.js @@ -114,7 +114,7 @@ window.lpCoursesList = ( () => { }, }; - window.lpAJAXG.fetchAPI( API.frontend.apiAJAX, dataSend, callBack ); + window.lpAJAXG.fetchAJAX( dataSend, callBack ); }, LoadMore: ( e, target ) => { const btnLoadMore = target.closest( `.${ classLoadMore + ':not(.disabled)' }` ); @@ -176,7 +176,7 @@ window.lpCoursesList = ( () => { }, }; - window.lpAJAXG.fetchAPI( API.frontend.apiAJAX, dataSend, callBack ); + window.lpAJAXG.fetchAJAX( dataSend, callBack ); }, LoadInfinite: () => { // When see element, will call API to load more items. @@ -233,7 +233,7 @@ window.lpCoursesList = ( () => { }, }; - window.lpAJAXG.fetchAPI( API.frontend.apiAJAX, dataSend, callBack ); + window.lpAJAXG.fetchAJAX( dataSend, callBack ); }; // Listen el courses load infinite have just created. @@ -301,7 +301,7 @@ window.lpCoursesList = ( () => { }, }; - window.lpAJAXG.fetchAPI( API.frontend.apiAJAX, dataSend, callBack ); + window.lpAJAXG.fetchAJAX( dataSend, callBack ); }, onChangeTypeLayout: ( e, target ) => { if ( 'lp-switch-layout-btn' !== target.getAttribute( 'name' ) ) { @@ -365,7 +365,7 @@ window.lpCoursesList = ( () => { }, }; - window.lpAJAXG.fetchAPI( API.frontend.apiAJAX, dataSend, callBack ); + window.lpAJAXG.fetchAJAX( dataSend, callBack ); }, 800 ); } }, diff --git a/assets/src/js/loadAJAX.js b/assets/src/js/loadAJAX.js index a74d6fb6b..32d0de795 100644 --- a/assets/src/js/loadAJAX.js +++ b/assets/src/js/loadAJAX.js @@ -2,7 +2,7 @@ * Load all you need via AJAX * * @since 4.2.5.7 - * @version 1.0.3 + * @version 1.0.4 */ import { lpAddQueryArgs, lpFetchAPI, listenElementCreated, lpOnElementReady } from './utils.js'; @@ -50,6 +50,29 @@ const lpAJAX = ( () => { lpFetchAPI( url, option, callBack ); }, + fetchAJAX: ( params, callBack ) => { + // Call via ajax. + let urlAjax = lpData.lpAjaxUrl; + if ( params.args.id_url ) { + urlAjax = lpAddQueryArgs( urlAjax, { id_url: params.args.id_url } ); + } + + const formData = new FormData(); + formData.append( 'nonce', lpData.nonce ); + formData.append( 'lp-load-ajax', 'load_content_via_ajax' ); + formData.append( 'data', JSON.stringify( params ) ); + const dataSend = { + method: 'POST', + headers: {}, + body: formData, + }; + + if ( 0 !== parseInt( lpData.user_id ) ) { + dataSend.headers[ 'X-WP-Nonce' ] = lpSettings.nonce; + } + + lpFetchAPI( urlAjax, dataSend, callBack ); + }, getElements: () => { // Finds all elements with the class '.lp-load-ajax-element' const elements = document.querySelectorAll( '.lp-load-ajax-element:not(.loaded)' ); @@ -88,27 +111,11 @@ const lpAJAX = ( () => { }, }; - window.lpAJAXG.fetchAPI( url, dataSend, callBack ); - - // Test - const urlAjax = lpData.lpAjaxUrl; - const formData = new FormData(); - //formData.append( 'action', 'lp_load_content_via_ajax' ); - formData.append( 'nonce', lpData.nonce ); - formData.append( 'lp-load-ajax', 'load_content_via_ajax' ); - formData.append( 'data', JSON.stringify( dataObj ) ); - const dataSendX = { - method: 'POST', - headers: {}, - body: formData, - }; - - if ( 0 !== parseInt( lpData.user_id ) ) { - dataSendX.headers[ 'X-WP-Nonce' ] = lpSettings.nonce; - } + // Call via API + //window.lpAJAXG.fetchAPI( url, dataSend, callBack ); - lpFetchAPI( urlAjax, dataSendX, callBack ); - // End test. + // Call via AJAX + window.lpAJAXG.fetchAJAX( dataSend, callBack ); } ); } }, diff --git a/inc/Models/CourseModel.php b/inc/Models/CourseModel.php index c71dec34d..a1d1b7494 100644 --- a/inc/Models/CourseModel.php +++ b/inc/Models/CourseModel.php @@ -82,7 +82,7 @@ class CourseModel { public $permalink = ''; public $categories; public $tags; - private $price = 0; // Not save in database, must auto reload calculate + private $price; // Not save in database, must auto reload calculate private $passing_condition = ''; public $post_excerpt = ''; /** @@ -240,9 +240,9 @@ public function get_tags(): array { * @return float */ public function get_price(): float { - if ( ! empty( $this->price ) ) { + /*if ( ! empty( $this->price ) ) { return $this->price; - } + }*/ if ( $this->has_sale_price() ) { $price = $this->get_sale_price(); diff --git a/inc/TemplateHooks/Course/ListCoursesTemplate.php b/inc/TemplateHooks/Course/ListCoursesTemplate.php index b2728218b..b28cb0523 100644 --- a/inc/TemplateHooks/Course/ListCoursesTemplate.php +++ b/inc/TemplateHooks/Course/ListCoursesTemplate.php @@ -59,6 +59,7 @@ public function layout_courses() { ]; $args = lp_archive_skeleton_get_args(); + $args['id_url'] = 'list-courses-default'; $args['courses_load_ajax'] = LP_Settings_Courses::is_ajax_load_courses() ? 1 : 0; $args['courses_first_no_ajax'] = LP_Settings_Courses::is_no_load_ajax_first_courses() ? 1 : 0; diff --git a/inc/admin/class-lp-admin-assets.php b/inc/admin/class-lp-admin-assets.php index 175c0d703..5714bc1c1 100644 --- a/inc/admin/class-lp-admin-assets.php +++ b/inc/admin/class-lp-admin-assets.php @@ -372,7 +372,7 @@ protected function _get_scripts(): array { [], 0, 0, - '1.0.2', + '1.0.4', [ 'strategy' => 'async' ] ), ) diff --git a/inc/lp-ajax.php b/inc/lp-ajax.php index a32477817..d4736f4a0 100644 --- a/inc/lp-ajax.php +++ b/inc/lp-ajax.php @@ -1,6 +1,8 @@ Date: Tue, 31 Dec 2024 12:05:17 +0700 Subject: [PATCH 072/225] = 4.2.7.6 = ~ Set offline payment default enable. --- .../class-lp-gateway-offline-payment.php | 32 ++----------------- .../paypal/class-lp-gateway-paypal.php | 2 -- 2 files changed, 2 insertions(+), 32 deletions(-) diff --git a/inc/gateways/offline-payment/class-lp-gateway-offline-payment.php b/inc/gateways/offline-payment/class-lp-gateway-offline-payment.php index 8de439f63..476012de6 100644 --- a/inc/gateways/offline-payment/class-lp-gateway-offline-payment.php +++ b/inc/gateways/offline-payment/class-lp-gateway-offline-payment.php @@ -45,35 +45,7 @@ public function __construct() { // Get settings $this->title = $this->settings->get( 'title', $this->method_title ); $this->description = $this->settings->get( 'description', $this->method_description ); - - if ( did_action( 'learn_press/offline-payment-add-on/loaded' ) ) { - return; - } - - /*add_filter( - 'learn-press/payment-gateway/' . $this->id . '/available', - array( - $this, - 'offline_payment_available', - ) - );*/ - - do_action( 'learn_press/offline-payment-add-on/loaded' ); - } - - /** - * Check gateway available. - * - * @return bool - */ - public function offline_payment_available(): bool { - _deprecated_function( __FUNCTION__, '4.2.3.5' ); - return LP_Settings::instance()->get( "{$this->id}.enable", 'no' ) === 'yes'; - } - - protected function _get( $name ) { - _deprecated_function( __FUNCTION__, '4.2.3.5' ); - return LP_Settings::instance()->get( $this->id . '.' . $name ); + $this->enabled = $this->settings->get( 'enable', 'yes' ); } /** @@ -104,7 +76,7 @@ public function process_payment( $order_id ) { $order = learn_press_get_order( $order_id ); // Mark as processing (payment won't be taken until delivery) - $default_status = 'processing'; + $default_status = LP_ORDER_PROCESSING; /** * If sandbox mode is turn on then the order diff --git a/inc/gateways/paypal/class-lp-gateway-paypal.php b/inc/gateways/paypal/class-lp-gateway-paypal.php index 72c626649..5ad241a72 100644 --- a/inc/gateways/paypal/class-lp-gateway-paypal.php +++ b/inc/gateways/paypal/class-lp-gateway-paypal.php @@ -84,8 +84,6 @@ class LP_Gateway_Paypal extends LP_Gateway_Abstract { * LP_Gateway_Paypal constructor. */ public function __construct() { - $this->id = 'paypal'; - $this->method_title = esc_html__( 'PayPal', 'learnpress' ); $this->method_description = esc_html__( 'Make a payment via Paypal.', 'learnpress' ); $this->icon = LP_PLUGIN_URL . 'assets/images/paypal-logo-preview.png'; From 167baf232565ca0e84408d8f21a1237b39328f87 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 31 Dec 2024 14:53:22 +0700 Subject: [PATCH 073/225] = 4.2.7.6 = --- inc/Ajax/AbstractAjax.php | 2 +- inc/Models/UserItems/UserItemModel.php | 1 + inc/TemplateHooks/Course/SingleCourseTemplate.php | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/inc/Ajax/AbstractAjax.php b/inc/Ajax/AbstractAjax.php index 7f38f9ebb..5c55ffa46 100644 --- a/inc/Ajax/AbstractAjax.php +++ b/inc/Ajax/AbstractAjax.php @@ -15,7 +15,7 @@ abstract class AbstractAjax { public static function catch_lp_ajax() { if ( ! empty( $_REQUEST['lp-load-ajax'] ) ) { $action = $_REQUEST['lp-load-ajax']; - $nonce = $_REQUEST['nonce']; + $nonce = $_REQUEST['nonce'] ?? ''; if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) { wp_die( 'Invalid request!', 400 ); } diff --git a/inc/Models/UserItems/UserItemModel.php b/inc/Models/UserItems/UserItemModel.php index c49eb7745..2a83f3b6b 100644 --- a/inc/Models/UserItems/UserItemModel.php +++ b/inc/Models/UserItems/UserItemModel.php @@ -102,6 +102,7 @@ class UserItemModel { const STATUS_COMPLETED = 'completed'; const STATUS_FINISHED = 'finished'; const STATUS_ENROLLED = 'enrolled'; + const STATUS_CANCEL = 'cancel'; const GRADUATION_IN_PROGRESS = 'in-progress'; const GRADUATION_PASSED = 'passed'; const GRADUATION_FAILED = 'failed'; diff --git a/inc/TemplateHooks/Course/SingleCourseTemplate.php b/inc/TemplateHooks/Course/SingleCourseTemplate.php index 43336de86..f93b8ffb9 100644 --- a/inc/TemplateHooks/Course/SingleCourseTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseTemplate.php @@ -1195,7 +1195,7 @@ public function html_curriculum( CourseModel $course, $user ): string { $section = [ 'wrapper' => '
          ', - 'title' => sprintf( '

          %s

          ', esc_html__( 'Curriculum', 'learnpress' ) ), + 'title' => sprintf( '

          %s

          ', esc_html__( 'Curriculum', 'learnpress' ) ), 'curriculum_info' => '
          ', 'curriculum_info_left' => '
            ', 'count_sections' => sprintf( @@ -1355,7 +1355,8 @@ public function render_html_course_item( CourseModel $courseModel, $userModel, $ $user_attended_course = false; if ( $userModel instanceof UserModel ) { $userCourseModel = UserCourseModel::find( $userModel->get_id(), $courseModel->get_id(), true ); - if ( $userCourseModel ) { + if ( $userCourseModel + && $userCourseModel->get_status() !== UserItemModel::STATUS_CANCEL ) { $user_attended_course = true; if ( $userCourseModel->get_time_remaining() === 0 ) { From 217583f5157ff53d611fbedaa90093990b623702 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 31 Dec 2024 15:27:09 +0700 Subject: [PATCH 074/225] = 4.2.7.6 = ~ Tweak: single course layout for block Theme. --- .../Course/SingleCourseTemplate.php | 2 +- .../class-block-template-single-course.php | 25 ++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/inc/TemplateHooks/Course/SingleCourseTemplate.php b/inc/TemplateHooks/Course/SingleCourseTemplate.php index f93b8ffb9..55be8469c 100644 --- a/inc/TemplateHooks/Course/SingleCourseTemplate.php +++ b/inc/TemplateHooks/Course/SingleCourseTemplate.php @@ -1209,7 +1209,7 @@ public function html_curriculum( CourseModel $course, $user ): string { '
          • %s
          • ', sprintf( _n( '%d Lesson', '%d Lessons', $course->count_items( LP_LESSON_CPT ), 'learnpress' ), - $course->get_total_sections() + $course->count_items( LP_LESSON_CPT ) ) ), 'duration' => sprintf( diff --git a/inc/block-template/class-block-template-single-course.php b/inc/block-template/class-block-template-single-course.php index fd14234a1..b0ee88fe2 100644 --- a/inc/block-template/class-block-template-single-course.php +++ b/inc/block-template/class-block-template-single-course.php @@ -1,5 +1,6 @@ query_vars; + $vars = $wp->query_vars; // Todo: For item course current display on post_type course // After when handle display item course on correct post_type item, remove this code. if ( ! empty( $vars['course-item'] ) ) { @@ -38,10 +39,28 @@ public function render_content_block_template( array $attributes ) { setup_postdata( $post ); $this->path_template_render_default = 'content-single-item.php'; } elseif ( $object ) { - $course = CourseModel::find( $object->ID, true ); + $page_template = 'single-course-layout.php'; + $course = CourseModel::find( $object->ID, true ); + + // Check condition to load single course layout classic or modern. + $is_override_single_course = Template::check_template_is_override( 'single-course.php' ); + $option_single_course_layout = LP_Settings::get_option( 'layout_single_course', '' ); + + if ( $is_override_single_course ) { // Old file template + $page_template = 'single-course.php'; + } elseif ( empty( $option_single_course_layout ) + || $option_single_course_layout === 'classic' ) { + $page_template = 'single-course-layout-classic.php'; + } + + // Old single course layout. + //$page_template = 'single-course.php'; + if ( $course && $course->is_offline() ) { - $this->path_template_render_default = 'single-course-offline.php'; + $page_template = 'single-course-offline.php'; } + + $this->path_template_render_default = $page_template; } return parent::render_content_block_template( $attributes ); From 8805dd67b78dcb29920f3eee1122fa6fe97d7871 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Tue, 31 Dec 2024 16:51:49 +0700 Subject: [PATCH 075/225] = 4.2.7.6 = ~ Tweak: abstract-addon.php. --- inc/abstracts/abstract-addon.php | 124 +++++++------------------------ 1 file changed, 25 insertions(+), 99 deletions(-) diff --git a/inc/abstracts/abstract-addon.php b/inc/abstracts/abstract-addon.php index e110c7d1c..2e4f3494b 100644 --- a/inc/abstracts/abstract-addon.php +++ b/inc/abstracts/abstract-addon.php @@ -89,9 +89,21 @@ public function __construct() { $this->plugin_folder_name = str_replace( array( '/', $this->plugin_base_name ), '', $this->plugin_base ); $this->_define_constants(); $this->_includes(); - remove_action( 'plugins_loaded', array( 'LP_Addon_Announcements', 'instance' ) ); - //add_action( 'init', array( $this, 'init' ) ); - $this->init(); + $this->load_text_domain(); + add_action( + 'init', + function () { + $this->_enqueue_assets(); + } + ); + add_filter( + "plugin_action_links_$this->plugin_base", + array( + $this, + '_plugin_links', + ) + ); + $this->_init_hooks(); } /** @@ -122,62 +134,31 @@ public function _plugin_links( $links ) { return $links; } - /** - * Init - */ - public function init() { - $this->load_text_domain(); - - add_filter( - "plugin_action_links_$this->plugin_base", - array( - $this, - '_plugin_links', - ) - ); - - $this->_init_hooks(); - $this->_enqueue_assets(); - } - /** * Define add-on constants. */ protected function _define_constants() { - } /** * Includes add-on files. */ protected function _includes() { - } /** * Init add-on hooks. */ protected function _init_hooks() { - } /** * Enqueue scripts. - */ - protected function _enqueue_assets() { - - } - - /** - * Get plugin slug from plugin file. + * @deprecated 4.2.7.6 * - * @return bool|string - * @deprecated 4.2.0 + * Need remove this function, use on the addons: wishlist, my-cred */ - public function get_plugin_slug() { - _deprecated_function( __METHOD__, '4.2.0' ); - - return $this->plugin_base; + protected function _enqueue_assets() { } /** @@ -268,7 +249,7 @@ public function admin_notice_require_addon_version() {

            LearnPress version %s require %s version %s or higher', 'learnpress' ) ), + wp_kses_post( __( 'LearnPress version %1$s require %2$s version %3$s or higher', 'learnpress' ) ), esc_html( LEARNPRESS_VERSION ), esc_html( $this->get_name() ), esc_html( $this->lp_require_addon_version ) @@ -288,10 +269,12 @@ public function admin_notice_require_lp_version() {

            %1$s add-on version %2$s requires LearnPress version %3$s or higher %4$s', - 'learnpress' - ) ), + wp_kses_post( + __( + '%1$s add-on version %2$s requires LearnPress version %3$s or higher %4$s', + 'learnpress' + ) + ), esc_html( $this->get_name() ), esc_html( $this->version ), esc_html( $this->require_version ), @@ -414,25 +397,6 @@ public function get_plugin_url( $sub = '/' ) { return plugins_url( $sub, $this->plugin_file ); } - /** - * Get template path. - * - * @return string - * @deprecated 4.2.0 - */ - public function get_template_path() { - _deprecated_function( __FUNCTION__, '4.2.0', 'LP_Addon::get_template' ); - if ( empty( $this->_template_path ) ) { - $this->_template_path = learn_press_template_path() . '/addons/' . preg_replace( - '!^learnpress-!', - '', - $this->plugin_folder_name - ); - } - - return $this->_template_path; - } - /** * Get content template of addon. * @@ -493,24 +457,6 @@ public function get_admin_template( string $template_name = '', $args = [] ) { Template::instance()->get_template( $template_path, $args ); } - /** - * Locate template of addon in theme or inside itself. - * - * @param string $template_name - * - * @return string - * @deprecated 4.2.0 - */ - public function locate_template( $template_name ) { - _deprecated_function( __FUNCTION__, '4.2.0', 'LP_Addon::get_template' ); - - return learn_press_locate_template( - $template_name, - $this->get_template_path(), - dirname( $this->plugin_file ) . '/templates/' - ); - } - /** * Output content of admin view file. * @@ -524,24 +470,6 @@ public function admin_view( $view, $args = array() ) { learn_press_admin_view( $view, $args ); } - /** - * Get content of admin view file. - * - * @param string $view - * @param array $args - * - * @return string - * @since x.x.x - * @deprecated 4.2.1 - */ - public function admin_view_content( $view, $args = array() ) { - _deprecated_function( __FUNCTION__, '4.2.1', 'LP_Addon::get_admin_template' ); - ob_start(); - $this->admin_view( $view, $args ); - - return ob_get_clean(); - } - /** * @return mixed * @deprecated 4.2.0 @@ -582,5 +510,3 @@ protected static function _get_called_class() { return $backtrace[2]['args'][0]; } } - -//add_action( 'admin_notices', array( 'LP_Addon', 'admin_errors' ) ); From 93a44aa15d7cf2b708e0dab6469ddf2b8e53c7d5 Mon Sep 17 00:00:00 2001 From: truongpn Date: Thu, 2 Jan 2025 14:16:48 +0700 Subject: [PATCH 076/225] style --- assets/src/scss/frontend/_course-offline.scss | 7 +++++++ assets/src/scss/frontend/_course-single.scss | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/assets/src/scss/frontend/_course-offline.scss b/assets/src/scss/frontend/_course-offline.scss index 301da8bdf..825f75a49 100644 --- a/assets/src/scss/frontend/_course-offline.scss +++ b/assets/src/scss/frontend/_course-offline.scss @@ -330,6 +330,13 @@ .lp-instructor-meta { margin-top: 16px; } + .instructor-description { + margin-top: 16px; + } + + img { + border-radius: $border-radius-global; + } } diff --git a/assets/src/scss/frontend/_course-single.scss b/assets/src/scss/frontend/_course-single.scss index c7572da9d..5dc60877e 100644 --- a/assets/src/scss/frontend/_course-single.scss +++ b/assets/src/scss/frontend/_course-single.scss @@ -639,6 +639,11 @@ } } } + + .featured-review__title { + font-weight: bold; + font-size: $font-size-large; + } } } From 7783fce431c859dce80cfb33b512838c3f89024f Mon Sep 17 00:00:00 2001 From: Tungnx Date: Thu, 2 Jan 2025 14:40:44 +0700 Subject: [PATCH 077/225] = 4.2.7.6 = ~ Tweak: install sample course --- assets/src/apps/js/admin/pages/tools.js | 1 + config/fields/edit-course.php | 11 +++ inc/Models/CourseModel.php | 3 +- inc/Models/CoursePostModel.php | 1 + inc/Models/Courses.php | 2 +- inc/admin/class-lp-install-sample-data.php | 96 ++++++++----------- .../views/meta-boxes/course/settings.php | 2 +- inc/admin/views/meta-boxes/fields/text.php | 2 +- .../tools/course/html-install-sample-data.php | 5 +- .../class-lp-background-single-course.php | 2 +- 10 files changed, 61 insertions(+), 64 deletions(-) create mode 100644 config/fields/edit-course.php diff --git a/assets/src/apps/js/admin/pages/tools.js b/assets/src/apps/js/admin/pages/tools.js index d15cd7ebb..a8b23c304 100644 --- a/assets/src/apps/js/admin/pages/tools.js +++ b/assets/src/apps/js/admin/pages/tools.js @@ -27,6 +27,7 @@ import resetData from './tools/reset-data'; isRunning = true; $.ajax( { + method: 'POST', url: $button.attr( 'href' ), data: $( '.lp-install-sample__options' ).serializeJSON(), success( response ) { diff --git a/config/fields/edit-course.php b/config/fields/edit-course.php new file mode 100644 index 000000000..8deede451 --- /dev/null +++ b/config/fields/edit-course.php @@ -0,0 +1,11 @@ +get_regular_price(); } - $this->price = (float) $price; + $this->price = (float) $price; + $this->meta_data->{CoursePostModel::META_KEY_PRICE} = (float) $price; return apply_filters( 'learnPress/course/price', (float) $price, $this->get_id() ); } diff --git a/inc/Models/CoursePostModel.php b/inc/Models/CoursePostModel.php index 441f2b3c1..0eccb066d 100644 --- a/inc/Models/CoursePostModel.php +++ b/inc/Models/CoursePostModel.php @@ -63,6 +63,7 @@ class CoursePostModel extends PostModel { const META_KEY_PRICE_PREFIX = '_lp_price_prefix'; const META_KEY_PRICE_SUFFIX = '_lp_price_suffix'; const META_KEY_FINAL_QUIZ = '_lp_final_quiz'; + const META_KEY_SAMPLE_DATA = '_lp_sample_data'; /** * Get the price of course. diff --git a/inc/Models/Courses.php b/inc/Models/Courses.php index 5e32c81e1..5f7e4e65c 100644 --- a/inc/Models/Courses.php +++ b/inc/Models/Courses.php @@ -144,7 +144,7 @@ public static function handle_params_for_query_courses( LP_Course_Filter &$filte // Sort by level $levels_str = LP_Helper::sanitize_params_submitted( urldecode( $param['c_level'] ?? '' ) ); if ( ! empty( $levels_str ) ) { - $levels_str = str_replace( 'all', '', $levels_str ); + //$levels_str = str_replace( 'all', '', $levels_str ); $levels = explode( ',', $levels_str ); $filter->levels = $levels; } diff --git a/inc/admin/class-lp-install-sample-data.php b/inc/admin/class-lp-install-sample-data.php index c99062bdc..4bc859ad3 100644 --- a/inc/admin/class-lp-install-sample-data.php +++ b/inc/admin/class-lp-install-sample-data.php @@ -54,7 +54,7 @@ public function __construct() { 'lp-uninstall-sample-data', ); - if ( ! in_array( LP_Request::get( 'page' ), $actions ) ) { + if ( ! in_array( LP_Request::get_param( 'page' ), $actions ) ) { return; } @@ -91,6 +91,14 @@ public function install() { return; } + if ( ! current_user_can( ADMIN_ROLE ) ) { + return; + } + + ini_set( 'max_execution_time', 0 ); + + $data = []; + $dummy_text = LP_WP_Filesystem::instance()->file_get_contents( LP_PLUGIN_PATH . '/dummy-data/dummy-text.txt' ); $this->dummy_text = preg_split( '!\s!', $dummy_text ); @@ -114,24 +122,11 @@ public function install() { self::$answer_range = $answer_range; } - try { - @ini_set( 'memory_limit', '2G' ); - - global $wp_filter; - - $keys = array_keys( $wp_filter ); - $ignore_keys = array( 'sanitize_title' ); - - foreach ( $keys as $key ) { - if ( in_array( $key, $ignore_keys ) ) { - continue; - } - - unset( $wp_filter[ $key ] ); - } + $data['price'] = LP_Request::get_param( 'course-price', 0, 'float' ); + $data['name'] = LP_Request::get_param( 'custom-name' ); - $name = LP_Request::get_param( 'custom-name' ); - $course_id = $this->create_course( $name ); + try { + $course_id = $this->create_course( $data ); if ( ! $course_id ) { throw new Exception( 'Create course failed.' ); @@ -139,27 +134,17 @@ public function install() { $this->create_sections( $course_id ); - $price = LP_Request::get_param( 'course-price', 0, 'float' ); - if ( $price ) { - update_post_meta( $course_id, '_lp_regular_price', $price ); - } - - /** - * Save info course in background. - */ - $coursePostModel = new CoursePostModel( get_post( $course_id ) ); - $coursePostModel->get_all_metadata(); - $courseModelNew = new CourseModel( $coursePostModel ); - $courseModelNew->get_price(); - $courseModelNew->save(); - $bg = LP_Background_Single_Course::instance(); - $bg->data( - array( - 'handle_name' => 'save_post', - 'course_id' => $course_id, - 'data' => [], - ) - )->dispatch(); + $courseModel = CourseModel::find( $course_id, true ); + // Unset value of keys for calculate again + unset( $courseModel->first_item_id ); + unset( $courseModel->total_items ); + unset( $courseModel->sections_items ); + unset( $courseModel->meta_data->_lp_final_quiz ); + $courseModel->get_first_item_id(); + $courseModel->get_total_items(); + $courseModel->get_section_items(); + $courseModel->get_final_quiz(); + $courseModel->save(); $link_course = get_the_permalink( $course_id ); $link_course = LP_Helper::handle_lp_permalink_structure( $link_course, get_post( $course_id ) ); @@ -179,6 +164,8 @@ public function install() { echo '

          '; } + ini_set( 'max_execution_time', LearnPress::$time_limit_default_of_sever ); + die(); } @@ -186,12 +173,10 @@ public function install() { * Un-install */ public function uninstall() { - if ( ! wp_verify_nonce( LP_Request::get_string( '_wpnonce' ), 'uninstall-sample-course' ) ) { + if ( ! wp_verify_nonce( LP_Request::get_param( '_wpnonce' ), 'uninstall-sample-course' ) ) { return; } - global $wpdb; - $posts = $this->get_sample_posts(); try { if ( ! $posts ) { @@ -355,33 +340,28 @@ protected function generate_title( $min = 10, $max = 15 ) { /** * Create course. * - * @param string $name + * @param array $data * * @return int|WP_Error */ - protected function create_course( $name = '' ) { + protected function create_course( array $data ) { + $title = $data['name'] ?? ''; - $data = array( - 'post_title' => strlen( $name ) ? $name : __( 'Sample course', 'learnpress' ), + $data_insert = array( + 'post_title' => ! empty( $title ) ? $title : __( 'Sample course', 'learnpress' ), 'post_type' => LP_COURSE_CPT, 'post_status' => 'publish', 'post_content' => $this->generate_content( 25, 40, 5 ), ); - $course_id = wp_insert_post( $data ); + $course_id = wp_insert_post( $data_insert ); if ( $course_id ) { - $metas = array( - '_lp_duration' => '10 week', - '_lp_max_students' => '0', - '_lp_students' => '0', - '_lp_retake_count' => '0', - '_lp_featured' => 'no', - '_lp_has_finish' => 'yes', - '_lp_course_result' => 'evaluate_lesson', - '_lp_passing_condition' => '80', - '_lp_sample_data' => 'yes', - ); + $metas = [ + CoursePostModel::META_KEY_DURATION => '10 week', + CoursePostModel::META_KEY_SAMPLE_DATA => 'yes', + CoursePostModel::META_KEY_LEVEL => 'all', + ]; foreach ( $metas as $key => $value ) { update_post_meta( $course_id, $key, $value ); } diff --git a/inc/admin/views/meta-boxes/course/settings.php b/inc/admin/views/meta-boxes/course/settings.php index 80c7d2d83..0cf89dcaa 100644 --- a/inc/admin/views/meta-boxes/course/settings.php +++ b/inc/admin/views/meta-boxes/course/settings.php @@ -129,7 +129,7 @@ public function general( $post_id ) { '_lp_duration' => new LP_Meta_Box_Duration_Field( esc_html__( 'Duration', 'learnpress' ), esc_html__( 'Set to 0 for the lifetime access.', 'learnpress' ), - '10', + '10 week', array( 'default_time' => 'week', 'custom_attributes' => array( diff --git a/inc/admin/views/meta-boxes/fields/text.php b/inc/admin/views/meta-boxes/fields/text.php index 7838445cd..a8b0713bd 100644 --- a/inc/admin/views/meta-boxes/fields/text.php +++ b/inc/admin/views/meta-boxes/fields/text.php @@ -91,7 +91,7 @@ public function output( $thepostid ) { public function save( $post_id ) { $type_input = $this->extra['type_input'] ?? 'text'; - $meta_value = LP_Request::get_param( $this->id, $this->default ?? '' ); + $meta_value = LP_Request::get_param( $this->id, $this->default ?? '', 'text', 'post' ); if ( $meta_value !== '' && $type_input === 'number' ) { $meta_value = (float) $meta_value; diff --git a/inc/admin/views/tools/course/html-install-sample-data.php b/inc/admin/views/tools/course/html-install-sample-data.php index 5f8371d09..0f91fdbe7 100644 --- a/inc/admin/views/tools/course/html-install-sample-data.php +++ b/inc/admin/views/tools/course/html-install-sample-data.php @@ -5,6 +5,8 @@ * @version 3.0.0 */ +use LearnPress\Models\CoursePostModel; + defined( 'ABSPATH' ) or die(); $section_range = LP_Install_Sample_Data::$section_range; @@ -46,7 +48,8 @@
        • - + +
        diff --git a/inc/background-process/class-lp-background-single-course.php b/inc/background-process/class-lp-background-single-course.php index c433511f7..233acc7ce 100644 --- a/inc/background-process/class-lp-background-single-course.php +++ b/inc/background-process/class-lp-background-single-course.php @@ -97,7 +97,7 @@ protected function save_post() { // Old hook, addon wpml and assignment is using do_action( 'lp/background/course/save', learn_press_get_course( $this->lp_course->get_id() ), $this->data ); // New hook from v4.2.6.9 - do_action( 'learnPress/background/course/save', $this->lp_course, $this->data ); + do_action( 'learnPress/background/course/save', $courseModel, $this->data ); /** * Clean cache courses From e4512052df26603d24a1f069562851f8f986e81c Mon Sep 17 00:00:00 2001 From: truongpn Date: Thu, 2 Jan 2025 16:57:35 +0700 Subject: [PATCH 078/225] fix js --- assets/src/js/utils.js | 74 +------------------- assets/src/scss/frontend/_course-single.scss | 4 ++ package.json | 4 +- 3 files changed, 7 insertions(+), 75 deletions(-) diff --git a/assets/src/js/utils.js b/assets/src/js/utils.js index 315c5c948..708f2edcf 100644 --- a/assets/src/js/utils.js +++ b/assets/src/js/utils.js @@ -180,76 +180,4 @@ export { lpFetchAPI, lpAddQueryArgs, lpGetCurrentURLNoParam, listenElementViewed, listenElementCreated, lpOnElementReady, lpAjaxParseJsonOld, lpShowHideEl, lpSetLoadingEl, -}; - -export function LPClick( element, iconBtn, inner ) { - const wrapper = document.querySelector( element ), - clickBtn = wrapper && wrapper.querySelector( iconBtn ), - class_open = element.replace( '.', '' ) + '__open', - closeElement = wrapper && wrapper.querySelector( element + '__close' ); - - if (! wrapper) { - return; - } - - const isOpenElement = () => { - return wrapper.classList.contains( class_open ); - }; - - const showElement = () => { - if (isOpenElement()) { - return; - } - - wrapper.classList.add( class_open ); - }; - - const hideElement = () => { - if (! isOpenElement()) { - return; - } - - wrapper.classList.remove( class_open ); - }; - - const toggleElement = () => { - if (isOpenElement()) { - hideElement(); - } else { - showElement(); - } - }; - - const onKeyDown = ( e ) => { - if (e.keyCode === 27) { - hideElement(); - } - }; - clickBtn.onclick = function( e ) { - e.preventDefault(); - toggleElement(); - }; - - document.addEventListener( 'click', ( e ) => { - if (! isOpenElement()) { - return; - } - - const target = e.target; - - if (target.closest( inner ) || target.closest( iconBtn )) { - return; - } - - hideElement(); - } ); - - // Click close button. - closeElement && closeElement.addEventListener( 'click', ( e ) => { - e.preventDefault(); - - hideElement(); - } ); - - document.addEventListener( 'keydown', onKeyDown, false ); // click ESC button will hide popup -} \ No newline at end of file +}; \ No newline at end of file diff --git a/assets/src/scss/frontend/_course-single.scss b/assets/src/scss/frontend/_course-single.scss index 5dc60877e..ba022d6bd 100644 --- a/assets/src/scss/frontend/_course-single.scss +++ b/assets/src/scss/frontend/_course-single.scss @@ -326,6 +326,10 @@ row-gap: 30px; flex-wrap: wrap; + @media (max-width: 991px) { + flex-direction: column-reverse; + } + &__left { width: 100%; @media (min-width: 992px) { diff --git a/package.json b/package.json index 53239bfa5..fe37c2a67 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "[![Stories in Ready](https://badge.waffle.io/LearnPress/LearnPress.svg?label=ready&title=Ready)](http://waffle.io/LearnPress/LearnPress)", "main": "index.js", "scripts": { - "start": "cross-env NODE_OPTIONS=--openssl-legacy-provider wp-scripts start", - "build": "cross-env NODE_OPTIONS=--openssl-legacy-provider wp-scripts build", + "start": "cross-env wp-scripts start", + "build": "cross-env wp-scripts build", "format-js": "cross-env wp-scripts format ./assets/src", "dev-build": "cross-env npm run build && gulp styles && npm run dev", "makepot:js": "wp-babel-makepot \"./assets/src/**/*.{js,jsx,ts,tsx}\" --ignore \"**/node_modules/**,**/test/**,**/*.d.ts\" --base \"./\" --dir \"./languages/strings\" --output \"./languages/learnpress-js.pot\"", From e95b06e65dcbd444ad2d9a0fe710dd63cee0eede Mon Sep 17 00:00:00 2001 From: truongpn Date: Thu, 2 Jan 2025 16:58:11 +0700 Subject: [PATCH 079/225] fix js --- assets/src/js/frontend/copy-to-clipboard.js | 72 ++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/assets/src/js/frontend/copy-to-clipboard.js b/assets/src/js/frontend/copy-to-clipboard.js index b52524c3b..fb2b48a84 100644 --- a/assets/src/js/frontend/copy-to-clipboard.js +++ b/assets/src/js/frontend/copy-to-clipboard.js @@ -1,4 +1,74 @@ -import { LPClick } from '../utils'; +function LPClick( element, iconBtn, inner ) { + const wrapper = document.querySelector( element ), + clickBtn = wrapper && wrapper.querySelector( iconBtn ), + class_open = element.replace( '.', '' ) + '__open', + closeElement = wrapper && wrapper.querySelector( element + '__close' ); + + if (! wrapper) { + return; + } + + const isOpenElement = () => { + return wrapper.classList.contains( class_open ); + }; + + const showElement = () => { + if (isOpenElement()) { + return; + } + + wrapper.classList.add( class_open ); + }; + + const hideElement = () => { + if (! isOpenElement()) { + return; + } + + wrapper.classList.remove( class_open ); + }; + + const toggleElement = () => { + if (isOpenElement()) { + hideElement(); + } else { + showElement(); + } + }; + + const onKeyDown = ( e ) => { + if (e.keyCode === 27) { + hideElement(); + } + }; + clickBtn.onclick = function( e ) { + e.preventDefault(); + toggleElement(); + }; + + document.addEventListener( 'click', ( e ) => { + if (! isOpenElement()) { + return; + } + + const target = e.target; + + if (target.closest( inner ) || target.closest( iconBtn )) { + return; + } + + hideElement(); + } ); + + // Click close button. + closeElement && closeElement.addEventListener( 'click', ( e ) => { + e.preventDefault(); + + hideElement(); + } ); + + document.addEventListener( 'keydown', onKeyDown, false ); // click ESC button will hide popup +} export default function CopyToClipboard() { LPClick( '.social-share-toggle', '.share-toggle-icon', '.content-widget-social-share' ); From ef2343e826e2c862e1d80ab465882ac98b30ea46 Mon Sep 17 00:00:00 2001 From: truongpn Date: Thu, 2 Jan 2025 17:02:11 +0700 Subject: [PATCH 080/225] back file package --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index fe37c2a67..53239bfa5 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "[![Stories in Ready](https://badge.waffle.io/LearnPress/LearnPress.svg?label=ready&title=Ready)](http://waffle.io/LearnPress/LearnPress)", "main": "index.js", "scripts": { - "start": "cross-env wp-scripts start", - "build": "cross-env wp-scripts build", + "start": "cross-env NODE_OPTIONS=--openssl-legacy-provider wp-scripts start", + "build": "cross-env NODE_OPTIONS=--openssl-legacy-provider wp-scripts build", "format-js": "cross-env wp-scripts format ./assets/src", "dev-build": "cross-env npm run build && gulp styles && npm run dev", "makepot:js": "wp-babel-makepot \"./assets/src/**/*.{js,jsx,ts,tsx}\" --ignore \"**/node_modules/**,**/test/**,**/*.d.ts\" --base \"./\" --dir \"./languages/strings\" --output \"./languages/learnpress-js.pot\"", From 7a7b4952a2f2758deb159cf07abaa482d6d9aeec Mon Sep 17 00:00:00 2001 From: truongpn Date: Thu, 2 Jan 2025 17:04:00 +0700 Subject: [PATCH 081/225] fix js --- assets/src/js/frontend/copy-to-clipboard.js | 140 ++++++++++---------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/assets/src/js/frontend/copy-to-clipboard.js b/assets/src/js/frontend/copy-to-clipboard.js index fb2b48a84..2cb04a218 100644 --- a/assets/src/js/frontend/copy-to-clipboard.js +++ b/assets/src/js/frontend/copy-to-clipboard.js @@ -1,73 +1,73 @@ -function LPClick( element, iconBtn, inner ) { - const wrapper = document.querySelector( element ), - clickBtn = wrapper && wrapper.querySelector( iconBtn ), - class_open = element.replace( '.', '' ) + '__open', - closeElement = wrapper && wrapper.querySelector( element + '__close' ); - - if (! wrapper) { - return; - } - - const isOpenElement = () => { - return wrapper.classList.contains( class_open ); - }; - - const showElement = () => { - if (isOpenElement()) { - return; - } - - wrapper.classList.add( class_open ); - }; - - const hideElement = () => { - if (! isOpenElement()) { - return; - } - - wrapper.classList.remove( class_open ); - }; - - const toggleElement = () => { - if (isOpenElement()) { - hideElement(); - } else { - showElement(); - } - }; - - const onKeyDown = ( e ) => { - if (e.keyCode === 27) { - hideElement(); - } - }; - clickBtn.onclick = function( e ) { - e.preventDefault(); - toggleElement(); - }; - - document.addEventListener( 'click', ( e ) => { - if (! isOpenElement()) { - return; - } - - const target = e.target; - - if (target.closest( inner ) || target.closest( iconBtn )) { - return; - } - - hideElement(); - } ); - - // Click close button. - closeElement && closeElement.addEventListener( 'click', ( e ) => { - e.preventDefault(); - - hideElement(); - } ); - - document.addEventListener( 'keydown', onKeyDown, false ); // click ESC button will hide popup +function LPClick(element, iconBtn, inner) { + const wrappers = document.querySelectorAll(element); + + if (!wrappers.length) { + return; + } + + wrappers.forEach((wrapper) => { + const clickBtn = wrapper.querySelector(iconBtn); + const class_open = element.replace('.', '') + '__open'; + const closeElement = wrapper.querySelector(element + '__close'); + + const isOpenElement = () => wrapper.classList.contains(class_open); + + const showElement = () => { + if (!isOpenElement()) { + wrapper.classList.add(class_open); + } + }; + + const hideElement = () => { + if (isOpenElement()) { + wrapper.classList.remove(class_open); + } + }; + + const toggleElement = () => { + if (isOpenElement()) { + hideElement(); + } else { + showElement(); + } + }; + + const onKeyDown = (e) => { + if (e.keyCode === 27) { + hideElement(); + } + }; + + if (clickBtn) { + clickBtn.onclick = function (e) { + e.preventDefault(); + toggleElement(); + }; + } + + document.addEventListener('click', (e) => { + if (!isOpenElement()) { + return; + } + + const target = e.target; + + if (target.closest(inner) || target.closest(iconBtn)) { + return; + } + + hideElement(); + }); + + if (closeElement) { + closeElement.addEventListener('click', (e) => { + e.preventDefault(); + hideElement(); + }); + } + + document.addEventListener('keydown', onKeyDown, false); + }); } export default function CopyToClipboard() { From dfe5c083729aa86f98bf4d7286902ede970fedb8 Mon Sep 17 00:00:00 2001 From: truongpn Date: Thu, 2 Jan 2025 17:05:16 +0700 Subject: [PATCH 082/225] fomat --- assets/src/js/frontend/copy-to-clipboard.js | 157 ++++++++++---------- 1 file changed, 80 insertions(+), 77 deletions(-) diff --git a/assets/src/js/frontend/copy-to-clipboard.js b/assets/src/js/frontend/copy-to-clipboard.js index 2cb04a218..9570ef0e5 100644 --- a/assets/src/js/frontend/copy-to-clipboard.js +++ b/assets/src/js/frontend/copy-to-clipboard.js @@ -1,91 +1,94 @@ -function LPClick(element, iconBtn, inner) { - const wrappers = document.querySelectorAll(element); - - if (!wrappers.length) { - return; - } - - wrappers.forEach((wrapper) => { - const clickBtn = wrapper.querySelector(iconBtn); - const class_open = element.replace('.', '') + '__open'; - const closeElement = wrapper.querySelector(element + '__close'); - - const isOpenElement = () => wrapper.classList.contains(class_open); - - const showElement = () => { - if (!isOpenElement()) { - wrapper.classList.add(class_open); - } - }; - - const hideElement = () => { - if (isOpenElement()) { - wrapper.classList.remove(class_open); - } - }; - - const toggleElement = () => { - if (isOpenElement()) { - hideElement(); - } else { - showElement(); - } - }; - - const onKeyDown = (e) => { - if (e.keyCode === 27) { - hideElement(); - } - }; - - if (clickBtn) { - clickBtn.onclick = function (e) { - e.preventDefault(); - toggleElement(); - }; - } - - document.addEventListener('click', (e) => { - if (!isOpenElement()) { - return; - } - - const target = e.target; - - if (target.closest(inner) || target.closest(iconBtn)) { - return; - } - - hideElement(); - }); - - if (closeElement) { - closeElement.addEventListener('click', (e) => { - e.preventDefault(); - hideElement(); - }); - } - - document.addEventListener('keydown', onKeyDown, false); - }); +function LPClick( element, iconBtn, inner ) { + const wrappers = document.querySelectorAll( element ); + + if ( ! wrappers.length ) { + return; + } + + wrappers.forEach( ( wrapper ) => { + const clickBtn = wrapper.querySelector( iconBtn ); + const class_open = element.replace( '.', '' ) + '__open'; + const closeElement = wrapper.querySelector( element + '__close' ); + + const isOpenElement = () => wrapper.classList.contains( class_open ); + + const showElement = () => { + if ( ! isOpenElement() ) { + wrapper.classList.add( class_open ); + } + }; + + const hideElement = () => { + if ( isOpenElement() ) { + wrapper.classList.remove( class_open ); + } + }; + + const toggleElement = () => { + if ( isOpenElement() ) { + hideElement(); + } else { + showElement(); + } + }; + + const onKeyDown = ( e ) => { + if ( e.keyCode === 27 ) { + hideElement(); + } + }; + + if ( clickBtn ) { + clickBtn.onclick = function ( e ) { + e.preventDefault(); + toggleElement(); + }; + } + + document.addEventListener( 'click', ( e ) => { + if ( ! isOpenElement() ) { + return; + } + + const target = e.target; + + if ( target.closest( inner ) || target.closest( iconBtn ) ) { + return; + } + + hideElement(); + } ); + + if ( closeElement ) { + closeElement.addEventListener( 'click', ( e ) => { + e.preventDefault(); + hideElement(); + } ); + } + + document.addEventListener( 'keydown', onKeyDown, false ); + } ); } export default function CopyToClipboard() { - LPClick( '.social-share-toggle', '.share-toggle-icon', '.content-widget-social-share' ); + LPClick( + '.social-share-toggle', + '.share-toggle-icon', + '.content-widget-social-share' + ); var copyTextareaBtn = document.querySelector( '.btn-clipboard' ); - if (copyTextareaBtn) { - copyTextareaBtn.addEventListener( 'click', function( event ) { + if ( copyTextareaBtn ) { + copyTextareaBtn.addEventListener( 'click', function ( event ) { var copyTextarea = document.querySelector( '.clipboard-value' ); copyTextarea.focus(); copyTextarea.select(); try { var successful = document.execCommand( 'copy' ); var msg = copyTextareaBtn.getAttribute( 'data-copied' ); - copyTextareaBtn.innerHTML = msg + '' + msg + ''; - } catch (err) { - - } + copyTextareaBtn.innerHTML = + msg + '' + msg + ''; + } catch ( err ) {} } ); } } From 1f470ac626fd2a85b00199ff1c289f64b965cdb3 Mon Sep 17 00:00:00 2001 From: Tungnx Date: Fri, 3 Jan 2025 11:33:35 +0700 Subject: [PATCH 083/225] = 4.2.7.6 = ~ Fixed: security. --- config/settings/gateway/offline-payment.php | 6 ------ inc/class-lp-assets.php | 6 +++--- inc/lp-core-functions.php | 6 +++--- inc/order/lp-order-functions.php | 12 ++++++++---- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/config/settings/gateway/offline-payment.php b/config/settings/gateway/offline-payment.php index 35b6b4223..8a5c87e11 100644 --- a/config/settings/gateway/offline-payment.php +++ b/config/settings/gateway/offline-payment.php @@ -29,12 +29,6 @@ 'type' => 'checkbox', 'desc' => __( 'Auto complete the order for testing purpose.' ), ), - array( - 'title' => __( 'Title', 'learnpress' ), - 'id' => '[title]', - 'default' => $lp_gateway_offline_payment->title, - 'type' => 'text', - ), array( 'title' => __( 'Instruction', 'learnpress' ), 'id' => '[description]', diff --git a/inc/class-lp-assets.php b/inc/class-lp-assets.php index 6bc70a0fb..ec8fcd973 100644 --- a/inc/class-lp-assets.php +++ b/inc/class-lp-assets.php @@ -430,10 +430,10 @@ public function load_scripts_on_head() { * @return void */ public function load_styles_on_head() { - $max_width = LP_Settings::get_option( 'width_container', '1290px' ); + $max_width = esc_html( LP_Settings::get_option( 'width_container', '1290px' ) ); $padding_container = apply_filters( 'learn-press/container-padding-width', '1rem' ); - $primary_color = LP_Settings::get_option( 'primary_color' ); - $secondary_color = LP_Settings::get_option( 'secondary_color' ); + $primary_color = esc_html( LP_Settings::get_option( 'primary_color' ) ); + $secondary_color = esc_html( LP_Settings::get_option( 'secondary_color' ) ); ?>