LearnPress – WordPress LMS Plugin - Version 4.1.6.9.2

Version Description

(2022-08-09) = ~ Fixed: show wrong special character (Ex: ) on Section title, description. ~ Fixed: error on duplicate course, item function not same content old course, item. ~ Fixed: button sidebar toggle not show on default theme WP. ~ Fixed: ESC make error with payment gateway.

Download this release

Release Info

Developer ThimPress
Plugin Icon 128x128 LearnPress – WordPress LMS Plugin
Version 4.1.6.9.2
Comparing to
See all releases

Code changes from version 4.1.6.9.1 to 4.1.6.9.2

inc/abstracts/abstract-post-data.php CHANGED
@@ -133,35 +133,21 @@ if ( ! class_exists( 'LP_Abstract_Post_Data' ) ) {
133
 
134
  // Post not preview
135
  if ( ! isset( $_REQUEST['preview'] ) ) {
136
- $posts = apply_filters_ref_array(
137
- 'the_posts',
138
- array(
139
- array( get_post( $this->get_id() ) ),
140
- &$wp_query,
141
- )
142
- );
143
-
144
  // Fix style, js if content is WP Bakery
145
  if ( class_exists( 'WPBMap' ) && method_exists( 'WPBMap', 'addAllMappedShortcodes' ) ) {
146
  WPBMap::addAllMappedShortcodes();
147
  }
148
 
149
- if ( $posts ) {
150
- $post = $posts[0];
151
- }
152
 
153
  setup_postdata( $post );
154
- $content_post = get_the_content();
155
- $content_post = apply_filters( 'the_content', $content_post );
156
- $content_post = str_replace( ']]>', ']]>', $content_post );
157
- $this->_content = $content_post;
158
- wp_reset_postdata();
159
- } else { // Post is previewd
160
- $content_post = get_the_content();
161
- $content_post = apply_filters( 'the_content', $content_post );
162
- $content_post = str_replace( ']]>', ']]>', $content_post );
163
- $this->_content = $content_post;
164
  }
 
 
 
 
 
 
165
  }
166
  } else {
167
  $content = get_post_field( 'post_content', $this->get_id() );
133
 
134
  // Post not preview
135
  if ( ! isset( $_REQUEST['preview'] ) ) {
 
 
 
 
 
 
 
 
136
  // Fix style, js if content is WP Bakery
137
  if ( class_exists( 'WPBMap' ) && method_exists( 'WPBMap', 'addAllMappedShortcodes' ) ) {
138
  WPBMap::addAllMappedShortcodes();
139
  }
140
 
141
+ $post = get_post( $this->get_id() );
 
 
142
 
143
  setup_postdata( $post );
 
 
 
 
 
 
 
 
 
 
144
  }
145
+
146
+ $content_post = get_the_content();
147
+ /*$content_post = apply_filters( 'the_content', $content_post );
148
+ $content_post = str_replace( ']]>', ']]>', $content_post );*/
149
+ $this->_content = $content_post;
150
+ wp_reset_postdata();
151
  }
152
  } else {
153
  $content = get_post_field( 'post_content', $this->get_id() );
inc/admin/lp-admin-functions.php CHANGED
@@ -1888,53 +1888,35 @@ if ( ! function_exists( 'learn_press_duplicate_post' ) ) {
1888
  }
1889
 
1890
  /**
 
 
1891
  * @editor tungnx
1892
- * @modify 4.1.4 - fix sanitize query
 
1893
  */
1894
  if ( ! function_exists( 'learn_press_duplicate_post_meta' ) ) {
1895
  function learn_press_duplicate_post_meta( $old_post_id, $new_post_id, $excerpt = array() ) {
1896
- global $wpdb;
1897
-
1898
- $post_meta_infos = $wpdb->get_results(
1899
- $wpdb->prepare(
1900
- "SELECT meta_key, meta_value FROM $wpdb->postmeta
1901
- WHERE post_id = %d",
 
 
 
 
 
 
 
1902
  $old_post_id
1903
- )
1904
- );
1905
-
1906
- if ( count( $post_meta_infos ) != 0 ) {
1907
- $excerpt = array_merge( array( '_edit_lock', '_edit_last' ), $excerpt );
1908
- $excerpt = apply_filters(
1909
- 'learn_press_excerpt_duplicate_post_meta',
1910
- $excerpt,
1911
- $old_post_id,
1912
- $new_post_id
1913
  );
1914
- $sql_query = "INSERT INTO $wpdb->postmeta (post_id, meta_key, meta_value) ";
1915
- $sql_query_sel = array();
1916
 
1917
- foreach ( $post_meta_infos as $meta ) {
1918
- if ( in_array( $meta->meta_key, $excerpt ) ) {
1919
- continue;
1920
- }
1921
-
1922
- if ( $meta->meta_key === '_lp_course_author' ) {
1923
- $meta->meta_value = get_current_user_id();
1924
- }
1925
-
1926
- $meta_key = $meta->meta_key;
1927
- $meta_value = addslashes( $meta->meta_value );
1928
- $sql_query_sel[] = $wpdb->prepare(
1929
- 'SELECT %d, %s, %s',
1930
- $new_post_id,
1931
- $meta_key,
1932
- $meta_value
1933
- );
1934
- }
1935
 
1936
- $sql_query .= implode( ' UNION ALL ', $sql_query_sel );
1937
- $wpdb->query( $sql_query );
 
1938
  }
1939
  }
1940
  }
1888
  }
1889
 
1890
  /**
1891
+ * Duplicate post meta.
1892
+ *
1893
  * @editor tungnx
1894
+ * @sicne 3.0.0
1895
+ * @version 4.0.1
1896
  */
1897
  if ( ! function_exists( 'learn_press_duplicate_post_meta' ) ) {
1898
  function learn_press_duplicate_post_meta( $old_post_id, $new_post_id, $excerpt = array() ) {
1899
+ $lp_db = LP_Database::getInstance();
1900
+
1901
+ try {
1902
+ $excerpt = array_merge( array( '_edit_lock', '_edit_last' ), $excerpt );
1903
+ $excerpt_name_keys = implode( "','", $excerpt );
1904
+ $sql_query = $lp_db->wpdb->prepare(
1905
+ "INSERT INTO $lp_db->tb_postmeta (post_id, meta_key, meta_value)
1906
+ SELECT %d, pmc.meta_key, pmc.meta_value
1907
+ FROM $lp_db->tb_postmeta AS pmc
1908
+ WHERE post_id = %d
1909
+ AND meta_key not in ('{$excerpt_name_keys}')
1910
+ ",
1911
+ $new_post_id,
1912
  $old_post_id
 
 
 
 
 
 
 
 
 
 
1913
  );
 
 
1914
 
1915
+ $lp_db->check_execute_has_error();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1916
 
1917
+ $lp_db->wpdb->query( $sql_query );
1918
+ } catch ( Throwable $e ) {
1919
+ error_log( $e->getMessage() );
1920
  }
1921
  }
1922
  }
inc/admin/views/meta-boxes/fields/duration.php CHANGED
@@ -91,7 +91,7 @@ class LP_Meta_Box_Duration_Field extends LP_Meta_Box_Field {
91
  $duration_keys = array_keys( $duration );
92
  $default_time = ! empty( $this->extra['default_time'] ) ? $this->extra['default_time'] : end( $duration_keys );
93
 
94
- $duration = isset( $_POST[ $this->id ][0] ) && $_POST[ $this->id ][0] !== '' ? implode( ' ', wp_unslash( $_POST[ $this->id ] ) ) : absint( $this->default ) . ' ' . trim( $default_time );
95
 
96
  update_post_meta( $post_id, $this->id, $duration );
97
  }
91
  $duration_keys = array_keys( $duration );
92
  $default_time = ! empty( $this->extra['default_time'] ) ? $this->extra['default_time'] : end( $duration_keys );
93
 
94
+ $duration = isset( $_POST[ $this->id ][0] ) && $_POST[ $this->id ][0] !== '' ? absint( wp_unslash( $_POST[ $this->id ][0] ) ) . ' ' . trim( wp_unslash( $_POST[ $this->id ][1] ) ) : absint( $this->default ) . ' ' . trim( $default_time );
95
 
96
  update_post_meta( $post_id, $this->id, $duration );
97
  }
inc/class-lp-page-controller.php CHANGED
@@ -4,10 +4,7 @@
4
  * Class LP_Page_Controller
5
  */
6
  class LP_Page_Controller {
7
- protected static $_instance = null;
8
- protected $_shortcode_exists = false;
9
- protected $_shortcode_tag = '[learn_press_archive_course]';
10
- protected $_archive_contents = null;
11
 
12
  /**
13
  * Store the object has queried by WP.
@@ -49,7 +46,6 @@ class LP_Page_Controller {
49
 
50
  // edit link item course when form search default wp
51
  add_filter( 'post_type_link', array( $this, 'post_type_link' ), 10, 2 );
52
- // add_action( 'the_post', array( $this, 'learn_press_setup_object_data' ) );
53
 
54
  // Set link profile to admin menu
55
  add_action( 'admin_bar_menu', array( $this, 'learn_press_edit_admin_bar' ) );
@@ -72,39 +68,6 @@ class LP_Page_Controller {
72
  }
73
  }
74
 
75
- /**
76
- * When the_post is called, put course data into a global.
77
- *
78
- * Todo: after replace code LP::course()
79
- *
80
- * @param mixed $post
81
- *
82
- * @return LP_Course
83
- */
84
- /*public function learn_press_setup_object_data( $post ) {
85
- $object = null;
86
-
87
- if ( is_int( $post ) ) {
88
- $post = get_post( $post );
89
- }
90
-
91
- if ( ! $post ) {
92
- return $object;
93
- }
94
-
95
- if ( LP_COURSE_CPT === $post->post_type ) {
96
- if ( isset( $GLOBALS['course'] ) ) {
97
- unset( $GLOBALS['course'] );
98
- }
99
-
100
- $object = learn_press_get_course( $post->ID );
101
-
102
- LP()->global['course'] = $GLOBALS['course'] = $GLOBALS['lp_course'] = $object;
103
- }
104
-
105
- return $object;
106
- }*/
107
-
108
  /**
109
  * Set link item course when form search default wp
110
  *
@@ -649,61 +612,19 @@ class LP_Page_Controller {
649
  *
650
  * @return array
651
  * @since 3.x.x
 
652
  */
653
- public function page_template_hierarchy( $templates ) {
654
  $templates = array_merge( $templates, array( 'singular.php' ) );
655
 
656
  return $templates;
657
- }
658
 
659
  /**
660
- * @return bool
661
- * @editor tungnx - comment 4.1.6.6
 
662
  */
663
- // protected function _maybe_redirect_courses_page() {
664
- // /**
665
- // * If is archive course page and a static page is used for displaying courses
666
- // * we need to redirect it to the right page
667
- // */
668
- // if ( ! is_post_type_archive( LP_COURSE_CPT ) ) {
669
- // return false;
670
- // }
671
- //
672
- // /**
673
- // * @var WP_Query $wp_query
674
- // * @var WP_Rewrite $wp_rewrite
675
- // */
676
- // global $wp_query, $wp_rewrite;
677
- //
678
- // $page_id = learn_press_get_page_id( 'courses' );
679
- //
680
- // if ( $page_id && ( empty( $wp_query->queried_object_id ) || ! empty( $wp_query->queried_object_id ) && $page_id != $wp_query->queried_object_id ) ) {
681
- // $redirect = trailingslashit( learn_press_get_page_link( 'courses' ) );
682
- //
683
- // if ( ! empty( $wp_query->query['paged'] ) ) {
684
- // if ( $wp_rewrite->using_permalinks() ) {
685
- // $redirect = $redirect . 'page/' . $wp_query->query['paged'] . '/';
686
- // } else {
687
- // $redirect = add_query_arg( 'paged', $wp_query->query['paged'], $redirect );
688
- // }
689
- // }
690
- //
691
- // if ( isset( $_GET ) ) {
692
- // $_GET = array_map( 'stripslashes_deep', $_GET );
693
- // foreach ( $_GET as $k => $v ) {
694
- // $redirect = add_query_arg( $k, urlencode( $v ), $redirect );
695
- // }
696
- // }
697
- //
698
- // if ( $page_id != get_option( 'page_on_front' ) && ! learn_press_is_current_url( $redirect ) ) {
699
- // wp_redirect( $redirect );
700
- // exit();
701
- // }
702
- // }
703
- //
704
- // return false;
705
- // }
706
-
707
  public function archive_content() {
708
  ob_start();
709
  learn_press_get_template( 'content-archive-course.php' );
@@ -725,162 +646,6 @@ class LP_Page_Controller {
725
  return $title;
726
  }
727
 
728
- /**
729
- * Load archive courses content.
730
- *
731
- * @param string $template
732
- *
733
- * @return string
734
- */
735
- public function _load_archive_courses( $template ) {
736
-
737
- if ( ! defined( 'LEARNPRESS_IS_COURSES' ) ) {
738
- define( 'LEARNPRESS_IS_COURSES', learn_press_is_courses() );
739
- }
740
-
741
- if ( ! defined( 'LEARNPRESS_IS_TAG' ) ) {
742
- define( 'LEARNPRESS_IS_TAG', learn_press_is_course_tag() );
743
- }
744
-
745
- if ( ! defined( 'LEARNPRESS_IS_CATEGORY' ) ) {
746
- define( 'LEARNPRESS_IS_CATEGORY', learn_press_is_course_category() );
747
- }
748
-
749
- if ( ! defined( 'LEARNPRESS_IS_TAX' ) ) {
750
- define( 'LEARNPRESS_IS_TAX', learn_press_is_course_tax() );
751
- }
752
-
753
- if ( ! defined( 'LEARNPRESS_IS_SEARCH' ) ) {
754
- define( 'LEARNPRESS_IS_SEARCH', learn_press_is_search() );
755
- }
756
-
757
- if ( LEARNPRESS_IS_COURSES || LEARNPRESS_IS_TAG || LEARNPRESS_IS_CATEGORY || LEARNPRESS_IS_SEARCH || LEARNPRESS_IS_TAX ) {
758
- global $wp_query;
759
- // PHP 7
760
- LP()->wp_query = clone $wp_query;
761
-
762
- $template = get_page_template();
763
-
764
- /**
765
- * Fix in case a static page is used for archive course page and
766
- * it's slug is the same with course archive slug (courses).
767
- * In this case, WP know it as a course archive page not a
768
- * single page.
769
- */
770
- $course_page_id = learn_press_get_page_id( 'courses' );
771
- $course_page_slug = get_post_field( 'post_name', $course_page_id );
772
- if ( ! LEARNPRESS_IS_CATEGORY && $course_page_id && $course_page_slug ) {
773
- if ( $course_page_slug == 'courses' ) {
774
- $wp_query->queried_object_id = $course_page_id;
775
- $this->queried_object = $wp_query->queried_object = get_post( $course_page_id );
776
- add_filter( 'document_title_parts', array( $this, 'page_title' ) );
777
- }
778
- }
779
-
780
- $wp_query->posts_per_page = 1;
781
- $wp_query->nopaging = true;
782
- $wp_query->post_count = 1;
783
-
784
- // If we don't have a post, load an empty one
785
- if ( ! empty( $this->_queried_object ) ) {
786
- $wp_query->post = $this->_queried_object;
787
- } elseif ( empty( $wp_query->post ) || learn_press_is_courses() /* -> Fixed: archive course page displays name of first course */ ) {
788
- $wp_query->post = new WP_Post( new stdClass() );
789
- } elseif ( $wp_query->post->post_type != 'page' ) {
790
- // Do not show content of post if it is not a page
791
- $wp_query->post->post_content = '';
792
- }
793
- $content = $wp_query->post->post_content;
794
-
795
- preg_match( '/\[learn_press_archive_course\s?(.*)\]/', $content, $results );
796
- $this->_shortcode_exists = ! empty( $results );
797
-
798
- if ( empty( $results ) ) {
799
- $content = wpautop( $content ) . $this->_shortcode_tag;
800
- } else {
801
- $this->_shortcode_tag = $results[0];
802
- }
803
-
804
- $has_filter = false;
805
- if ( has_filter( 'the_content', 'wpautop' ) ) {
806
- $has_filter = true;
807
- remove_filter( 'the_content', 'wpautop' );
808
- }
809
-
810
- // $content = do_shortcode( $content );
811
-
812
- if ( $has_filter ) {
813
- // add_filter( 'the_content', 'wpautop' );
814
- }
815
-
816
- $this->_archive_contents = do_shortcode( $this->_shortcode_tag );
817
- if ( class_exists( 'SiteOrigin_Panels' ) ) {
818
- if ( class_exists( 'SiteOrigin_Panels' ) &&
819
- has_filter( 'the_content', array( SiteOrigin_Panels::single(), 'generate_post_content' ) )
820
- ) {
821
- remove_shortcode( 'learn_press_archive_course' );
822
- add_filter(
823
- 'the_content',
824
- array(
825
- $this,
826
- 'the_content_callback',
827
- ),
828
- $this->_filter_content_priority
829
- );
830
- }
831
- } else {
832
- $content = do_shortcode( $content );
833
- }
834
-
835
- if ( empty( $wp_query->post->ID ) || LEARNPRESS_IS_CATEGORY ) {
836
- $wp_query->post->ID = 0;
837
- }
838
-
839
- $wp_query->post->filter = 'raw';
840
- if ( learn_press_is_course_category() ) {
841
- $wp_query->post->post_title = single_term_title( '', false );
842
- }
843
-
844
- $wp_query->post->post_content = $content;
845
- $wp_query->posts = array( $wp_query->post );
846
-
847
- if ( is_post_type_archive( LP_COURSE_CPT ) || LEARNPRESS_IS_CATEGORY ) {
848
- $wp_query->is_page = false;
849
- $wp_query->is_archive = true;
850
- $wp_query->is_single = false;
851
- } else {
852
- $wp_query->found_posts = 1;
853
- $wp_query->is_single = true;
854
- $wp_query->is_preview = false;
855
- $wp_query->is_archive = false;
856
- $wp_query->is_date = false;
857
- $wp_query->is_year = false;
858
- $wp_query->is_month = false;
859
- $wp_query->is_day = false;
860
- $wp_query->is_time = false;
861
- $wp_query->is_author = false;
862
- $wp_query->is_category = false;
863
- $wp_query->is_tag = false;
864
- $wp_query->is_tax = false;
865
- $wp_query->is_search = false;
866
- $wp_query->is_feed = false;
867
- $wp_query->is_comment_feed = false;
868
- $wp_query->is_trackback = false;
869
- $wp_query->is_home = false;
870
- $wp_query->is_404 = false;
871
- $wp_query->is_comments_popup = false;
872
- $wp_query->is_paged = false;
873
- $wp_query->is_admin = false;
874
- $wp_query->is_attachment = false;
875
- $wp_query->is_singular = false;
876
- $wp_query->is_posts_page = false;
877
- $wp_query->is_post_type_archive = false;
878
- }
879
- }
880
-
881
- return $template;
882
- }
883
-
884
  /**
885
  * Query courses if page is archive courses
886
  *
@@ -1144,7 +909,10 @@ class LP_Page_Controller {
1144
  return $q;
1145
  }
1146
 
1147
- public function the_content_callback( $content ) {
 
 
 
1148
  if ( $this->_archive_contents ) {
1149
  preg_match( '/\[learn_press_archive_course\s?(.*)\]/', $content, $results );
1150
  $this->_shortcode_exists = ! empty( $results );
@@ -1157,7 +925,7 @@ class LP_Page_Controller {
1157
  }
1158
 
1159
  return $content;
1160
- }
1161
 
1162
  /**
1163
  * Check is page Become a teacher
4
  * Class LP_Page_Controller
5
  */
6
  class LP_Page_Controller {
7
+ protected static $_instance = null;
 
 
 
8
 
9
  /**
10
  * Store the object has queried by WP.
46
 
47
  // edit link item course when form search default wp
48
  add_filter( 'post_type_link', array( $this, 'post_type_link' ), 10, 2 );
 
49
 
50
  // Set link profile to admin menu
51
  add_action( 'admin_bar_menu', array( $this, 'learn_press_edit_admin_bar' ) );
68
  }
69
  }
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  /**
72
  * Set link item course when form search default wp
73
  *
612
  *
613
  * @return array
614
  * @since 3.x.x
615
+ * @depecated 4.1.6.9.2
616
  */
617
+ /*public function page_template_hierarchy( $templates ) {
618
  $templates = array_merge( $templates, array( 'singular.php' ) );
619
 
620
  return $templates;
621
+ }*/
622
 
623
  /**
624
+ * Archive course content.
625
+ *
626
+ * @return false|string
627
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
628
  public function archive_content() {
629
  ob_start();
630
  learn_press_get_template( 'content-archive-course.php' );
646
  return $title;
647
  }
648
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
649
  /**
650
  * Query courses if page is archive courses
651
  *
909
  return $q;
910
  }
911
 
912
+ /**
913
+ * @depecated 4.1.6.9.2
914
+ */
915
+ /*public function the_content_callback( $content ) {
916
  if ( $this->_archive_contents ) {
917
  preg_match( '/\[learn_press_archive_course\s?(.*)\]/', $content, $results );
918
  $this->_shortcode_exists = ! empty( $results );
925
  }
926
 
927
  return $content;
928
+ }*/
929
 
930
  /**
931
  * Check is page Become a teacher
inc/course/class-lp-course.php CHANGED
@@ -337,7 +337,7 @@ if ( ! class_exists( 'LP_Course' ) ) {
337
  */
338
  public function set_info_extra_for_fast_query( LP_Course_Extra_Info_Fast_Query_Model $data_object ) {
339
  try {
340
- $extra_info_json = json_encode( $data_object );
341
 
342
  if ( JSON_ERROR_NONE !== json_last_error() ) {
343
  throw new Exception( 'Error encode on ' . __METHOD__ );
@@ -640,8 +640,8 @@ if ( ! class_exists( 'LP_Course' ) ) {
640
  $sections_items[ $section_new ] = new stdClass();
641
  $sections_items[ $section_new ]->id = $section_new;
642
  $sections_items[ $section_new ]->order = $section_order;
643
- $sections_items[ $section_new ]->title = $sections_item->section_name;
644
- $sections_items[ $section_new ]->description = $sections_item->section_description;
645
  $sections_items[ $section_new ]->items = [];
646
 
647
  // Sort item by item_order
@@ -679,8 +679,8 @@ if ( ! class_exists( 'LP_Course' ) ) {
679
  $section_obj = new stdClass();
680
  $section_obj->id = $section_id;
681
  $section_obj->order = $section->section_order;
682
- $section_obj->title = $section->section_name;
683
- $section_obj->description = $section->section_description;
684
  $section_obj->items = [];
685
  $sections_items[ $section_id ] = $section_obj;
686
  }
337
  */
338
  public function set_info_extra_for_fast_query( LP_Course_Extra_Info_Fast_Query_Model $data_object ) {
339
  try {
340
+ $extra_info_json = json_encode( $data_object, JSON_UNESCAPED_UNICODE );
341
 
342
  if ( JSON_ERROR_NONE !== json_last_error() ) {
343
  throw new Exception( 'Error encode on ' . __METHOD__ );
640
  $sections_items[ $section_new ] = new stdClass();
641
  $sections_items[ $section_new ]->id = $section_new;
642
  $sections_items[ $section_new ]->order = $section_order;
643
+ $sections_items[ $section_new ]->title = html_entity_decode( $sections_item->section_name );
644
+ $sections_items[ $section_new ]->description = html_entity_decode( $sections_item->section_description );
645
  $sections_items[ $section_new ]->items = [];
646
 
647
  // Sort item by item_order
679
  $section_obj = new stdClass();
680
  $section_obj->id = $section_id;
681
  $section_obj->order = $section->section_order;
682
+ $section_obj->title = html_entity_decode( $section->section_name );
683
+ $section_obj->description = html_entity_decode( $section->section_description );
684
  $section_obj->items = [];
685
  $sections_items[ $section_id ] = $section_obj;
686
  }
inc/curds/class-lp-lesson-curd.php CHANGED
@@ -96,30 +96,29 @@ if ( ! class_exists( 'LP_Lesson_CURD' ) ) {
96
  * @return mixed|WP_Error
97
  */
98
  public function duplicate( &$lesson_id, $args = array() ) {
99
-
100
  if ( ! $lesson_id ) {
101
- return new WP_Error( __( '<p>Op! ID not found</p>', 'learnpress' ) );
102
  }
103
 
104
  if ( get_post_type( $lesson_id ) != LP_LESSON_CPT ) {
105
- return new WP_Error( __( '<p>Op! The lesson does not exist</p>', 'learnpress' ) );
106
  }
107
 
108
  $user_id = $args['meta_input']['_lp_user'] ?? get_current_user_id();
109
  // ensure that user can create lesson
110
  if ( ! user_can( $user_id, 'edit_posts' ) ) {
111
- return new WP_Error( __( '<p>Sorry! You don\'t have permission to duplicate this lesson</p>', 'learnpress' ) );
112
  }
113
 
114
  // duplicate lesson
115
  $new_lesson_id = learn_press_duplicate_post( $lesson_id, $args );
116
 
117
  if ( ! $new_lesson_id || is_wp_error( $new_lesson_id ) ) {
118
- return new WP_Error( __( '<p>Sorry! Failed to duplicate lesson!</p>', 'learnpress' ) );
119
- } else {
120
- do_action( 'learn-press/after-duplicate', $lesson_id, $new_lesson_id, $args );
121
- return $new_lesson_id;
122
  }
 
 
 
123
  }
124
 
125
  /**
96
  * @return mixed|WP_Error
97
  */
98
  public function duplicate( &$lesson_id, $args = array() ) {
 
99
  if ( ! $lesson_id ) {
100
+ return new WP_Error( '0', 'Op! ID not found' );
101
  }
102
 
103
  if ( get_post_type( $lesson_id ) != LP_LESSON_CPT ) {
104
+ return new WP_Error( '1', 'Op! The lesson does not exist' );
105
  }
106
 
107
  $user_id = $args['meta_input']['_lp_user'] ?? get_current_user_id();
108
  // ensure that user can create lesson
109
  if ( ! user_can( $user_id, 'edit_posts' ) ) {
110
+ return new WP_Error( '2', 'Sorry! You don\'t have permission to duplicate this lesson' );
111
  }
112
 
113
  // duplicate lesson
114
  $new_lesson_id = learn_press_duplicate_post( $lesson_id, $args );
115
 
116
  if ( ! $new_lesson_id || is_wp_error( $new_lesson_id ) ) {
117
+ return new WP_Error( '3', 'Sorry! Failed to duplicate lesson!' );
 
 
 
118
  }
119
+
120
+ do_action( 'learn-press/after-duplicate', $lesson_id, $new_lesson_id, $args );
121
+ return $new_lesson_id;
122
  }
123
 
124
  /**
inc/curds/class-lp-user-curd.php CHANGED
@@ -2118,10 +2118,6 @@ ORDER BY MAX(user_item_id) DESC";
2118
  return $order_id;
2119
  }
2120
 
2121
- public function evaluate_course_results() {
2122
-
2123
- }
2124
-
2125
  public function duplicate( &$user, $args = array() ) {
2126
  // TODO: Implement duplicate() method.
2127
  }
2118
  return $order_id;
2119
  }
2120
 
 
 
 
 
2121
  public function duplicate( &$user, $args = array() ) {
2122
  // TODO: Implement duplicate() method.
2123
  }
inc/emails/types/class-lp-email-type-finished-course.php CHANGED
@@ -121,7 +121,6 @@ class LP_Email_Type_Finished_Course extends LP_Email {
121
  }
122
 
123
  $user_course_data = $user->get_course_data( $this->course_id );
124
- $user_course_data->get_results();
125
 
126
  $variables = apply_filters(
127
  'lp/email/type-finished-course/variables-mapper',
121
  }
122
 
123
  $user_course_data = $user->get_course_data( $this->course_id );
 
124
 
125
  $variables = apply_filters(
126
  'lp/email/type-finished-course/variables-mapper',
inc/jwt/responsive.http ADDED
@@ -0,0 +1,263 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ###
2
+ POST http://learnpress4.local/wp-json/learnpress/v1/token
3
+ Content-Type: application/json
4
+
5
+ {
6
+ "username": "admin",
7
+ "password": "admin"
8
+ }
9
+
10
+ ###
11
+ POST http://learnpress4.local/wp-json/learnpress/v1/token
12
+ Content-Type: application/json
13
+
14
+ {
15
+ "username": "student",
16
+ "password": "student"
17
+ }
18
+
19
+ ###
20
+ POST http://learnpress4.local/wp-json/learnpress/v1/token/register
21
+ Content-Type: application/json
22
+
23
+ {
24
+ "username": "student4",
25
+ "password": "student4",
26
+ "confirm_password": "student4",
27
+ "email": "student4@gmail.com"
28
+ }
29
+
30
+ ###
31
+ POST http://learnpress4.local/wp-json/learnpress/v1/token/validate
32
+ Content-Type: application/json
33
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTYyNDU4NzE3MiwibmJmIjoxNjI0NTg3MTcyLCJleHAiOjE2MjUxOTE5NzIsImRhdGEiOnsidXNlciI6eyJpZCI6IjEifX19.czBrKpTMrlUt5nGc5DXbNsAhkhg2od1xnlSHcgzBG6U
34
+
35
+ ## Get list Course learned by user, if not learned will get all course
36
+ ## add param: learned, course_filter: in-progress, passed, failed.
37
+ ###
38
+ GET http://lp/wp-json/learnpress/v1/courses?on_sale=true
39
+ Content-Type: application/json
40
+
41
+ ## Get list Course learned by user, if not learned will get all course
42
+ ## add param: learned, course_filter: in-progress, passed, failed.
43
+ ###
44
+ GET http://learnpress4.local/wp-json/learnpress/v1/courses?learned=true&per_page=1&order=desc&course_filter=in-progress
45
+ Content-Type: application/json
46
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTY0MTg3MTM3NSwibmJmIjoxNjQxODcxMzc1LCJleHAiOjE2NDI0NzYxNzUsImRhdGEiOnsidXNlciI6eyJpZCI6IjEifX19.NvKdO6v4ylCjLNc06Q7S6T9GIdNL5i4YAyPC0p776lE
47
+
48
+ ###
49
+ GET http://learnpress4.local/wp-json/learnpress/v1/courses/86?v=123213
50
+ Content-Type: application/json
51
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTY0NDgyOTQxOSwibmJmIjoxNjQ0ODI5NDE5LCJleHAiOjE2NDU0MzQyMTksImRhdGEiOnsidXNlciI6eyJpZCI6IjEifX19.jllFuVONx23EL_614lSK2OVFiIMDfajeFVWtg4maJOc
52
+
53
+ ### Get content Course
54
+ ## If have token will show course_data for this user: course_data: graduation, status....
55
+ GET http://learnpress4.local/wp-json/learnpress/v1/courses/196
56
+ Content-Type: application/json
57
+
58
+
59
+ ## Enroll course.
60
+ ###
61
+ POST http://learnpress4.local/wp-json/learnpress/v1/courses/enroll
62
+ Content-Type: application/json
63
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTYyNjIzNDYxMiwibmJmIjoxNjI2MjM0NjEyLCJleHAiOjE2MjY4Mzk0MTIsImRhdGEiOnsidXNlciI6eyJpZCI6IjIifX19.qxB0-uGPBk52QyjVAAoqceizynMp8BUt3eOrBB3MF2c
64
+
65
+ {
66
+ "id": "196"
67
+ }
68
+
69
+ ## Finish course.
70
+ ###
71
+ POST http://learnpress4.local/wp-json/learnpress/v1/courses/finish
72
+ Content-Type: application/json
73
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTYyNjIzNDYxMiwibmJmIjoxNjI2MjM0NjEyLCJleHAiOjE2MjY4Mzk0MTIsImRhdGEiOnsidXNlciI6eyJpZCI6IjIifX19.qxB0-uGPBk52QyjVAAoqceizynMp8BUt3eOrBB3MF2c
74
+
75
+ {
76
+ "id": "196"
77
+ }
78
+
79
+ ## Retake course.
80
+ ###
81
+ POST http://learnpress4.local/wp-json/learnpress/v1/courses/retake
82
+ Content-Type: application/json
83
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTYyNjIzNDYxMiwibmJmIjoxNjI2MjM0NjEyLCJleHAiOjE2MjY4Mzk0MTIsImRhdGEiOnsidXNlciI6eyJpZCI6IjIifX19.qxB0-uGPBk52QyjVAAoqceizynMp8BUt3eOrBB3MF2c
84
+
85
+
86
+ {
87
+ "id": "196"
88
+ }
89
+
90
+ ## Get All lesson: is administration, student cannot get list.
91
+ ###
92
+ GET http://learnpress4.local/wp-json/learnpress/v1/lessons
93
+ Content-Type: application/json
94
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTY0NDgzNjQ0NSwibmJmIjoxNjQ0ODM2NDQ1LCJleHAiOjE2NDU0NDEyNDUsImRhdGEiOnsidXNlciI6eyJpZCI6IjEifX19.e_tX-kD-51vLUMdt0TBSzZ1rt6Zea9QzOdat5N6K6bY
95
+
96
+ ## In student: You can get lesson by course is enrolled
97
+ ###
98
+ GET http://learnpress4.local/wp-json/learnpress/v1/lessons/545
99
+ Content-Type: application/json
100
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTYzNTEzNjYxMCwibmJmIjoxNjM1MTM2NjEwLCJleHAiOjE2MzU3NDE0MTAsImRhdGEiOnsidXNlciI6eyJpZCI6IjEifX19._eGVoYIw1YHxH9qB6IhIYiPUwJnMFi-lPtjBVASzTBc
101
+
102
+ ## Action Complete Lesson.
103
+ ###
104
+ POST http://learnpress4.local/wp-json/learnpress/v1/lessons/finish
105
+ Content-Type: application/json
106
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTYyNTgwMDYxMywibmJmIjoxNjI1ODAwNjEzLCJleHAiOjE2MjY0MDU0MTMsImRhdGEiOnsidXNlciI6eyJpZCI6IjIifX19.4IQCUUcgZG5KH335evg8ZkDADVC0KCte8zFfENtQ0FA
107
+
108
+ {
109
+ "id": "545"
110
+ }
111
+
112
+ ## In student: You can get quiz by course is enrolled
113
+ ###
114
+ GET http://learnpress4.local/wp-json/learnpress/v1/quiz/197
115
+ Content-Type: application/json
116
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTYzNTEzNjYxMCwibmJmIjoxNjM1MTM2NjEwLCJleHAiOjE2MzU3NDE0MTAsImRhdGEiOnsidXNlciI6eyJpZCI6IjEifX19._eGVoYIw1YHxH9qB6IhIYiPUwJnMFi-lPtjBVASzTBc
117
+
118
+ ## Start Quiz.
119
+ ###
120
+ POST http://learnpress4.local/wp-json/learnpress/v1/quiz/start
121
+ Content-Type: application/json
122
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTY0NDgwNDUyMiwibmJmIjoxNjQ0ODA0NTIyLCJleHAiOjE2NDU0MDkzMjIsImRhdGEiOnsidXNlciI6eyJpZCI6IjEifX19.zWvrzrAiMdd7oyU9P2E-vTNWxlvcQ3IZjlswXWpyPgk
123
+
124
+ {
125
+ "id": "11"
126
+ }
127
+
128
+ ## Check Answer Quiz.
129
+ ###
130
+ POST http://learnpress4.local/wp-json/learnpress/v1/quiz/check_answer
131
+ Content-Type: application/json
132
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTYyNTgwMDYxMywibmJmIjoxNjI1ODAwNjEzLCJleHAiOjE2MjY0MDU0MTMsImRhdGEiOnsidXNlciI6eyJpZCI6IjIifX19.4IQCUUcgZG5KH335evg8ZkDADVC0KCte8zFfENtQ0FA
133
+
134
+ {
135
+ "id": "197",
136
+ "question_id": "198",
137
+ "answered": "5f2674eb"
138
+ }
139
+
140
+ ## Finish Quiz.
141
+ ###
142
+ POST http://learnpress4.local/wp-json/learnpress/v1/quiz/finish
143
+ Content-Type: application/json
144
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTY0NDgzNTY1NywibmJmIjoxNjQ0ODM1NjU3LCJleHAiOjE2NDU0NDA0NTcsImRhdGEiOnsidXNlciI6eyJpZCI6IjEifX19.Zm_-2CyEYeuiEiTkbxX4q4dKYGBFYFna77XKUGYTAEk
145
+
146
+ {
147
+ "id": 11,
148
+ "answered": {
149
+ "12": "eaf33d04"
150
+ }
151
+ }
152
+
153
+ ###
154
+ GET http://learnpress4.local/wp-json/wp/v2/categories
155
+ Content-Type: application/json
156
+
157
+ ### END.
158
+
159
+ ###
160
+ GET http://learnpress4.local/wp-json/learnpress/v1/quiz?per_page=2
161
+ Content-Type: application/json
162
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTYyNTE5NDUzMCwibmJmIjoxNjI1MTk0NTMwLCJleHAiOjE2MjU3OTkzMzAsImRhdGEiOnsidXNlciI6eyJpZCI6IjEifX19.GXI49miNfrGgatf9EjcFiciJHdB8jvmIr_jtedBnWQ4
163
+
164
+
165
+ ###
166
+ GET http://learnpress4.local/wp-json/learnpress/v1/questions
167
+ Content-Type: application/json
168
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTYyNDU4NzE3MiwibmJmIjoxNjI0NTg3MTcyLCJleHAiOjE2MjUxOTE5NzIsImRhdGEiOnsidXNlciI6eyJpZCI6IjEifX19.czBrKpTMrlUt5nGc5DXbNsAhkhg2od1xnlSHcgzBG6U
169
+
170
+
171
+ ###
172
+ GET http://learnpress4.local/wp-json/wp/v2/users
173
+ Content-Type: application/json
174
+
175
+ ###
176
+ GET http://learnpress4.local/wp-json/learnpress/v1/users/?roles[]=lp_teacher&roles[]=administrator
177
+ Content-Type: application/json
178
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTYzNTIxNzM5MiwibmJmIjoxNjM1MjE3MzkyLCJleHAiOjE2MzU4MjIxOTIsImRhdGEiOnsidXNlciI6eyJpZCI6IjEifX19.d68sBM5k8dYqWb-3MBs1fBzdgldCfCG-rh_ZbdAYP2U
179
+
180
+ ###
181
+ GET http://learnpress4.local/wp-json/learnpress/v1/users/1
182
+ Content-Type: application/json
183
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTY0NDgwNDUyMiwibmJmIjoxNjQ0ODA0NTIyLCJleHAiOjE2NDU0MDkzMjIsImRhdGEiOnsidXNlciI6eyJpZCI6IjEifX19.zWvrzrAiMdd7oyU9P2E-vTNWxlvcQ3IZjlswXWpyPgk
184
+
185
+ ### Change Password
186
+ POST http://learnpress4.local/wp-json/learnpress/v1/users/change-password/
187
+ Content-Type: application/json
188
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTY0NDgwNDUyMiwibmJmIjoxNjQ0ODA0NTIyLCJleHAiOjE2NDU0MDkzMjIsImRhdGEiOnsidXNlciI6eyJpZCI6IjEifX19.zWvrzrAiMdd7oyU9P2E-vTNWxlvcQ3IZjlswXWpyPgk
189
+
190
+ {
191
+ "old_password": "123456",
192
+ "new_password": "admin"
193
+ }
194
+
195
+ ###
196
+ POST http://learnpress4.local/wp-json/learnpress/v1/users/1/
197
+ Content-Type: application/json
198
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTY0NDgwNDUyMiwibmJmIjoxNjQ0ODA0NTIyLCJleHAiOjE2NDU0MDkzMjIsImRhdGEiOnsidXNlciI6eyJpZCI6IjEifX19.zWvrzrAiMdd7oyU9P2E-vTNWxlvcQ3IZjlswXWpyPgk
199
+
200
+ {
201
+ "first_name": "dao",
202
+ "last_name": "nham",
203
+ "nickname": "admin",
204
+ "email": "admin@g.com",
205
+ "description": "Hello Bio admin",
206
+ "avatar_url": "data:image/jpeg;base64,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"
207
+ }
208
+
209
+ ###
210
+ GET http://learnpress4.local/wp-json/learnpress/v1/users/2
211
+ Content-Type: application/json
212
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTYyMzI5MTgzNiwibmJmIjoxNjIzMjkxODM2LCJleHAiOjE2MjM4OTY2MzYsImRhdGEiOnsidXNlciI6eyJpZCI6IjIifX19.Ls7Q3EiFE5ZHn78Exe6CdnfZJ2JZaPcuJBI0wQHdvzk
213
+
214
+ ###
215
+ POST http://learnpress4.local/wp-json/learnpress/v1/users/2
216
+ Content-Type: application/json
217
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTYyNTQ2MDU4MSwibmJmIjoxNjI1NDYwNTgxLCJleHAiOjE2MjYwNjUzODEsImRhdGEiOnsidXNlciI6eyJpZCI6IjIifX19.-vPZer6A5impVQ_pHa2tUmvWmEDdQXL166pKHGlOv6U
218
+
219
+ {
220
+ "first_name": "nham",
221
+ "last_name": "kin",
222
+ "email": "studentsss@gmail.com",
223
+ "password": "student"
224
+ }
225
+
226
+ ####
227
+ GET http://learnpress4.local/wp-json/wp/v2/users/
228
+ Content-Type: application/json
229
+
230
+ ###
231
+ POST http://learnpress4.local/wp-json/learnpress/v1/users/reset-password
232
+ Content-Type: application/json
233
+
234
+ {
235
+ "user_login" : "daonham95@gmail.com"
236
+ }
237
+
238
+ ###
239
+ POST https://test.thimpress.com/wp-json/learnpress/v1/token?v=asdasdsdd
240
+ Content-Type: application/json
241
+
242
+ {
243
+ "username": "pensive-tesla",
244
+ "password": "FXIOajZUlYoOrhT6kd"
245
+ }
246
+
247
+ ###
248
+ GET https://test.thimpress.com/wp-json/wp/v2/posts?v=qweqwedsfdsfds
249
+ Content-Type: application/json
250
+
251
+ ###
252
+ GET http://learnpress4.local/wp-json/learnpress/v1/sections/sections-by-course-id/205
253
+ Content-Type: application/json
254
+
255
+ ###
256
+ GET http://learnpress4.local/wp-json/learnpress/v1/section-items/items/8
257
+ Content-Type: application/json
258
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9sZWFybnByZXNzNC5sb2NhbCIsImlhdCI6MTY0MDkyMTQ5OCwibmJmIjoxNjQwOTIxNDk4LCJleHAiOjE2NDE1MjYyOTgsImRhdGEiOnsidXNlciI6eyJpZCI6IjEifX19.nv7SgzB0JDQLSipszofbamoXyQHPPhx8IuO7-ISAGVU
259
+
260
+ ###
261
+ GET https://test.thimpress.com/wp-json/learnpress/v1/courses?learned=true&per_page=1&order=desc&course_filter=in-progress?v=ddsadsadios
262
+ Content-Type: application/json
263
+ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvdGVzdC50aGltcHJlc3MuY29tIiwiaWF0IjoxNjQyMDY4NTk0LCJuYmYiOjE2NDIwNjg1OTQsImV4cCI6MTY0MjY3MzM5NCwiZGF0YSI6eyJ1c2VyIjp7ImlkIjoiMSJ9fX0.rRRLon3MJel4MFjm6O5XqwdDqfr3s0xlNjVIeghW2Js
inc/lp-template-hooks.php CHANGED
@@ -376,7 +376,7 @@ add_action(
376
  */
377
  add_action(
378
  'learn-press/single-button-toggle-sidebar',
379
- LP()->template( 'course' )->text( '<input type="checkbox" id="sidebar-toggle" />', 'single-button-toggle-sidebar' ),
380
  5
381
  );
382
 
376
  */
377
  add_action(
378
  'learn-press/single-button-toggle-sidebar',
379
+ LP()->template( 'course' )->text( '<input type="checkbox" id="sidebar-toggle" />' ),
380
  5
381
  );
382
 
inc/templates/abstract-template.php CHANGED
@@ -259,7 +259,7 @@ class LP_Template_Callback {
259
  }
260
 
261
  public function text() {
262
- echo wp_kses_post( $this->template );
263
  }
264
 
265
  public function get_args() {
259
  }
260
 
261
  public function text() {
262
+ learn_press_echo_vuejs_write_on_php( $this->template );
263
  }
264
 
265
  public function get_args() {
inc/user-item/class-lp-user-item-course.php CHANGED
@@ -191,15 +191,16 @@ class LP_User_Item_Course extends LP_User_Item implements ArrayAccess {
191
 
192
  /**
193
  * @return LP_User_Item|bool
 
194
  */
195
- public function get_viewing_item() {
196
  $item = LP_Global::course_item();
197
  if ( $item ) {
198
  return $this[ $item->get_id() ];
199
  }
200
 
201
  return false;
202
- }
203
 
204
  public function get_course( $return = '' ) {
205
  $cid = $this->get_data( 'item_id' );
@@ -257,13 +258,7 @@ class LP_User_Item_Course extends LP_User_Item implements ArrayAccess {
257
  );
258
 
259
  if ( $results === false ) {
260
- // $course_result = $course->get_evaluation_results_method();
261
-
262
- // $results = LP_User_Items_Result_DB::instance()->get_result( $this->get_user_item_id() );
263
-
264
- // if ( is_array( $results ) && array_key_exists( 'result', $results ) ) {
265
  $results = $this->calculate_course_results();
266
- // }
267
 
268
  LP_Object_Cache::set(
269
  'course-' . $this->get_item_id() . '-' . $this->get_user_id(),
@@ -286,6 +281,7 @@ class LP_User_Item_Course extends LP_User_Item implements ArrayAccess {
286
  'items' => array(),
287
  'evaluate_type' => '',
288
  'pass' => 0,
 
289
  );
290
 
291
  try {
@@ -329,6 +325,7 @@ class LP_User_Item_Course extends LP_User_Item implements ArrayAccess {
329
  break;
330
  default:
331
  $results_evaluate = apply_filters( 'learn-press/evaluate_passed_conditions', $results, $evaluate_type, $this );
 
332
  }
333
 
334
  if ( ! is_array( $results_evaluate ) ) {
@@ -358,13 +355,6 @@ class LP_User_Item_Course extends LP_User_Item implements ArrayAccess {
358
  compact( 'count_items', 'completed_items', 'items', 'evaluate_type' )
359
  );
360
 
361
- /*
362
- $graduation = '';
363
-
364
- if ( ! $this->is_purchased() ) {
365
- $graduation = $this->is_finished() ? $this->_is_passed( $results['result'] ) : 'in-progress';
366
- }*/
367
-
368
  $results = apply_filters(
369
  'learn-press/update-course-results',
370
  $results,
@@ -707,40 +697,9 @@ class LP_User_Item_Course extends LP_User_Item implements ArrayAccess {
707
  }
708
 
709
  /**
710
- * Evaluate course result by final quiz.
711
- *
712
- * @return array
713
  */
714
- protected function _evaluate_course_by_final_quiz() {
715
- $cache_key = 'user-course-' . $this->get_user_id() . '-' . $this->get_id();
716
- $cached_data = LP_Object_Cache::get( $cache_key, 'learn-press/course-results' );
717
-
718
- if ( false === $cached_data || ! array_key_exists( 'final-quiz', $cached_data ) ) {
719
- $course = $this->get_course();
720
- $final_quiz = $course->get_final_quiz();
721
- $user_quiz = $this->get_item( $final_quiz );
722
- $result = false;
723
-
724
- if ( $user_quiz ) {
725
- $result = $user_quiz->get_results( false );
726
- }
727
-
728
- $percent = $result ? $result['result'] : 0;
729
- $data = array(
730
- 'result' => $percent,
731
- 'status' => $this->get_status(),
732
- );
733
-
734
- settype( $cached_data, 'array' );
735
- $cached_data['final-quiz'] = $data;
736
-
737
- LP_Object_Cache::set( $cache_key, $cached_data, 'learn-press/course-results' );
738
- }
739
-
740
- return isset( $cached_data['final-quiz'] ) ? $cached_data['final-quiz'] : array();
741
- }
742
-
743
- protected function _is_passed( $result ) {
744
  $is_passed = LP_COURSE_GRADUATION_FAILED;
745
  $result = round( $result, 2 );
746
 
@@ -749,7 +708,7 @@ class LP_User_Item_Course extends LP_User_Item implements ArrayAccess {
749
  }
750
 
751
  return apply_filters( 'learnpress/user/course/is-passed', $is_passed, $result );
752
- }
753
 
754
  /**
755
  * Get completed items.
@@ -941,10 +900,11 @@ class LP_User_Item_Course extends LP_User_Item implements ArrayAccess {
941
 
942
  /**
943
  * @return bool
 
944
  */
945
- public function can_graduated() {
946
  return $this->get_results( 'result' ) >= $this->get_passing_condition();
947
- }
948
 
949
  function __destruct() {
950
  // TODO: Implement __unset() method.
191
 
192
  /**
193
  * @return LP_User_Item|bool
194
+ * @depecated 4.1.6.9.2
195
  */
196
+ /*public function get_viewing_item() {
197
  $item = LP_Global::course_item();
198
  if ( $item ) {
199
  return $this[ $item->get_id() ];
200
  }
201
 
202
  return false;
203
+ }*/
204
 
205
  public function get_course( $return = '' ) {
206
  $cid = $this->get_data( 'item_id' );
258
  );
259
 
260
  if ( $results === false ) {
 
 
 
 
 
261
  $results = $this->calculate_course_results();
 
262
 
263
  LP_Object_Cache::set(
264
  'course-' . $this->get_item_id() . '-' . $this->get_user_id(),
281
  'items' => array(),
282
  'evaluate_type' => '',
283
  'pass' => 0,
284
+ 'result' => 0,
285
  );
286
 
287
  try {
325
  break;
326
  default:
327
  $results_evaluate = apply_filters( 'learn-press/evaluate_passed_conditions', $results, $evaluate_type, $this );
328
+ break;
329
  }
330
 
331
  if ( ! is_array( $results_evaluate ) ) {
355
  compact( 'count_items', 'completed_items', 'items', 'evaluate_type' )
356
  );
357
 
 
 
 
 
 
 
 
358
  $results = apply_filters(
359
  'learn-press/update-course-results',
360
  $results,
697
  }
698
 
699
  /**
700
+ * @depecated 4.1.6.9.2
 
 
701
  */
702
+ /*protected function _is_passed( $result ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
703
  $is_passed = LP_COURSE_GRADUATION_FAILED;
704
  $result = round( $result, 2 );
705
 
708
  }
709
 
710
  return apply_filters( 'learnpress/user/course/is-passed', $is_passed, $result );
711
+ }*/
712
 
713
  /**
714
  * Get completed items.
900
 
901
  /**
902
  * @return bool
903
+ * @depecated 4.1.6.9.2
904
  */
905
+ /*public function can_graduated() {
906
  return $this->get_results( 'result' ) >= $this->get_passing_condition();
907
+ }*/
908
 
909
  function __destruct() {
910
  // TODO: Implement __unset() method.
inc/user/abstract-lp-user.php CHANGED
@@ -2121,11 +2121,14 @@ if ( ! class_exists( 'LP_Abstract_User' ) ) {
2121
  return apply_filters( 'learn_press_user_can_do_quiz', $can, $quiz_id, $this->get_id(), $course_id );
2122
  }
2123
 
2124
- public function evaluate_course_results( $course_id ) {
 
 
 
2125
  $user_course = $this->get_course_data( $course_id );
2126
 
2127
  return isset( $user_course ) ? $user_course->get_results( 'result' ) : 0;
2128
- }
2129
 
2130
  /**
2131
  * @editor tungnx
2121
  return apply_filters( 'learn_press_user_can_do_quiz', $can, $quiz_id, $this->get_id(), $course_id );
2122
  }
2123
 
2124
+ /**
2125
+ * @depecated 4.1.6.9.2
2126
+ */
2127
+ /*public function evaluate_course_results( $course_id ) {
2128
  $user_course = $this->get_course_data( $course_id );
2129
 
2130
  return isset( $user_course ) ? $user_course->get_results( 'result' ) : 0;
2131
+ }*/
2132
 
2133
  /**
2134
  * @editor tungnx
learnpress.php CHANGED
@@ -4,7 +4,7 @@
4
  * Plugin URI: http://thimpress.com/learnpress
5
  * Description: LearnPress is a WordPress complete solution for creating a Learning Management System (LMS). It can help you to create courses, lessons and quizzes.
6
  * Author: ThimPress
7
- * Version: 4.1.6.9.1
8
  * Author URI: http://thimpress.com
9
  * Requires at least: 5.6
10
  * Tested up to: 6.0
4
  * Plugin URI: http://thimpress.com/learnpress
5
  * Description: LearnPress is a WordPress complete solution for creating a Learning Management System (LMS). It can help you to create courses, lessons and quizzes.
6
  * Author: ThimPress
7
+ * Version: 4.1.6.9.2
8
  * Author URI: http://thimpress.com
9
  * Requires at least: 5.6
10
  * Tested up to: 6.0
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: elearning, education, course, lms, learning management system
5
  Requires at least: 5.6
6
  Tested up to: 6.0
7
  Requires PHP: 7.0
8
- Stable tag: 4.1.6.9.1
9
  License: GPLv2 or later
10
  License URI: https://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -203,6 +203,12 @@ https://www.transifex.com/projects/p/learnpress/
203
 
204
  == Changelog ==
205
 
 
 
 
 
 
 
206
  = 4.1.6.9.1 (2022-08-04) =
207
  ~ Fixed: error ESC content of course, items' course make iframe, embed not working.
208
  ~ Fixed: error complete lesson, do quiz on API for App mobile.
5
  Requires at least: 5.6
6
  Tested up to: 6.0
7
  Requires PHP: 7.0
8
+ Stable tag: 4.1.6.9.2
9
  License: GPLv2 or later
10
  License URI: https://www.gnu.org/licenses/gpl-2.0.html
11
 
203
 
204
  == Changelog ==
205
 
206
+ = 4.1.6.9.2 (2022-08-09) =
207
+ ~ Fixed: show wrong special character (Ex: ü) on Section title, description.
208
+ ~ Fixed: error on duplicate course, item function not same content old course, item.
209
+ ~ Fixed: button sidebar toggle not show on default theme WP.
210
+ ~ Fixed: ESC make error with payment gateway.
211
+
212
  = 4.1.6.9.1 (2022-08-04) =
213
  ~ Fixed: error ESC content of course, items' course make iframe, embed not working.
214
  ~ Fixed: error complete lesson, do quiz on API for App mobile.
templates/content-lesson/content.php CHANGED
@@ -34,7 +34,8 @@ if ( ! $content ) {
34
 
35
  <div class="content-item-description lesson-description">
36
  <?php
37
- $content = apply_filters( 'the_content', $content );
38
- echo str_replace( ']]>', ']]&gt;', $content );
 
39
  ?>
40
  </div>
34
 
35
  <div class="content-item-description lesson-description">
36
  <?php
37
+ /*$content = apply_filters( 'the_content', $content );
38
+ echo str_replace( ']]>', ']]&gt;', $content );*/
39
+ learn_press_echo_vuejs_write_on_php( $content );
40
  ?>
41
  </div>
templates/content-lesson/title.php CHANGED
@@ -9,6 +9,10 @@
9
 
10
  defined( 'ABSPATH' ) || exit();
11
 
 
 
 
 
12
  $title = $lesson->get_title( 'display' );
13
 
14
  if ( ! $title ) {
@@ -16,4 +20,4 @@ if ( ! $title ) {
16
  }
17
  ?>
18
 
19
- <h3 class="course-item-title question-title"><?php echo esc_html( $title ); ?></h3>
9
 
10
  defined( 'ABSPATH' ) || exit();
11
 
12
+ if ( ! isset( $lesson ) ) {
13
+ return;
14
+ }
15
+
16
  $title = $lesson->get_title( 'display' );
17
 
18
  if ( ! $title ) {
20
  }
21
  ?>
22
 
23
+ <h3 class="course-item-title lesson-title"><?php echo esc_html( $title ); ?></h3>
templates/single-course/tabs/overview.php CHANGED
@@ -36,8 +36,9 @@ if ( ! $course ) {
36
  */
37
  do_action( 'learn-press/before-single-course-description' );
38
 
39
- $content = apply_filters( 'the_content', $course->get_content() );
40
- echo str_replace( ']]>', ']]&gt;', $content );
 
41
 
42
  /**
43
  * @since 3.0.0
36
  */
37
  do_action( 'learn-press/before-single-course-description' );
38
 
39
+ /*$content = apply_filters( 'the_content', $course->get_content() );
40
+ echo str_replace( ']]>', ']]&gt;', $content );*/
41
+ learn_press_echo_vuejs_write_on_php( $course->get_content() );
42
 
43
  /**
44
  * @since 3.0.0