LearnPress – WordPress LMS Plugin - Version 3.0.4

Version Description

~ Improved: action when clicking to close upgrade notice ~ Fixed: can not add course from other users to order ~ Fixed: lost quiz data after upgrading ~ Fixed: user can view lesson/quiz with single permalink ~ Fixed: can not view lesson ~ Fixed: notices in admin orders ~ Fixed: external buy this course redirect to home page ~ Fixed: remaining time message with course duration is zero ~ Fixed: hidden sections action ajax admin course editor ~ Fixed: admin can not add course to order from other users ~ More...

Download this release

Release Info

Developer tunnhn
Plugin Icon 128x128 LearnPress – WordPress LMS Plugin
Version 3.0.4
Comparing to
See all releases

Code changes from version 3.0.3 to 3.0.4

Files changed (41) hide show
  1. assets/css/learnpress.css +1 -1
  2. assets/js/admin/admin.js +1 -1
  3. assets/js/admin/modal-search-items.js +5 -1
  4. assets/js/frontend/course.js +9 -1
  5. assets/scss/frontend/_curriculum.scss +1 -2
  6. inc/admin/class-lp-modal-search-items.php +3 -1
  7. inc/admin/class-lp-updater.php +1 -1
  8. inc/admin/editor/class-lp-admin-editor-course.php +1 -1
  9. inc/admin/lp-admin-functions.php +28 -8
  10. inc/admin/views/html-admin-notice-templates.php +1 -1
  11. inc/admin/views/modal-search-items.php +1 -1
  12. inc/admin/views/updates/html-upgrade-message-3.0.0.php +2 -2
  13. inc/class-lp-ajax.php +21 -0
  14. inc/class-lp-install.php +3 -2
  15. inc/class-lp-page-controller.php +26 -11
  16. inc/class-lp-settings.php +10 -3
  17. inc/course/abstract-course.php +7 -3
  18. inc/curds/class-lp-course-curd.php +0 -6
  19. inc/curds/class-lp-order-curd.php +7 -8
  20. inc/curds/class-lp-question-curd.php +6 -2
  21. inc/custom-post-types/order.php +4 -3
  22. inc/lp-constants.php +1 -1
  23. inc/lp-core-functions.php +19 -0
  24. inc/lp-template-functions.php +2 -2
  25. inc/order/class-lp-order.php +53 -35
  26. inc/question/class-lp-question-answers.php +1 -1
  27. inc/updates/learnpress-update-2.1.1.php +4 -3
  28. inc/updates/learnpress-update-3.0.4.php +82 -0
  29. inc/user-item/class-lp-user-item-quiz.php +6 -3
  30. inc/user-item/class-lp-user-item.php +9 -8
  31. inc/user/abstract-lp-user.php +1 -0
  32. inc/user/class-lp-profile-tabs.php +1 -1
  33. inc/user/lp-user-functions.php +2 -0
  34. learnpress.php +1 -1
  35. readme.txt +14 -1
  36. templates/profile/tabs.php +13 -4
  37. templates/profile/tabs/orders/list.php +1 -1
  38. templates/profile/tabs/quizzes.php +1 -3
  39. templates/single-course/buttons/external-link.php +5 -2
  40. templates/single-course/remaining-time.php +6 -6
  41. templates/single-course/section/content-item.php +12 -4
assets/css/learnpress.css CHANGED
@@ -621,7 +621,7 @@
621
  clear: both;
622
  display: block;
623
  content: ''; }
624
- .lp-single-course .course-author .list-course-instructors {
625
  clear: both;
626
  padding-top: 20px; }
627
 
621
  clear: both;
622
  display: block;
623
  content: ''; }
624
+ .lp-single-course .course-author .course-instructor-item {
625
  clear: both;
626
  padding-top: 20px; }
627
 
assets/js/admin/admin.js CHANGED
@@ -289,13 +289,13 @@
289
  function hideUpgradeMessage(e) {
290
  e.preventDefault();
291
  var $btn = $(this);
 
292
  $.post({
293
  url: '',
294
  data: {
295
  'lp-hide-upgrade-message': 'yes'
296
  },
297
  success: function (res) {
298
- $btn.closest('.lp-upgrade-notice').fadeOut();
299
  }
300
  });
301
  }
289
  function hideUpgradeMessage(e) {
290
  e.preventDefault();
291
  var $btn = $(this);
292
+ $btn.closest('.lp-upgrade-notice').fadeOut();
293
  $.post({
294
  url: '',
295
  data: {
296
  'lp-hide-upgrade-message': 'yes'
297
  },
298
  success: function (res) {
 
299
  }
300
  });
301
  }
assets/js/admin/modal-search-items.js CHANGED
@@ -31,6 +31,7 @@
31
  },
32
  search: _.debounce(function (term) {
33
  var that = this;
 
34
  Vue.http.post(
35
  window.location.href, {
36
  type: this.postType,
@@ -111,13 +112,16 @@
111
  term: '',
112
  postType: '',
113
  callbacks: {},
114
- exclude: ''
 
115
  },
116
  methods: {
117
  open: function (options) {
 
118
  _.each(options.data, function (v, k) {
119
  this[k] = v;
120
  }, this);
 
121
  this.callbacks = options.callbacks;
122
  this.focusSearch();
123
  },
31
  },
32
  search: _.debounce(function (term) {
33
  var that = this;
34
+ console.log(this)
35
  Vue.http.post(
36
  window.location.href, {
37
  type: this.postType,
112
  term: '',
113
  postType: '',
114
  callbacks: {},
115
+ exclude: '',
116
+ context: ''
117
  },
118
  methods: {
119
  open: function (options) {
120
+ console.log(options)
121
  _.each(options.data, function (v, k) {
122
  this[k] = v;
123
  }, this);
124
+
125
  this.callbacks = options.callbacks;
126
  this.focusSearch();
127
  },
assets/js/frontend/course.js CHANGED
@@ -540,7 +540,15 @@
540
 
541
  $(document).ready(function () {
542
  $(document).ready(function () {
543
- new LP_Course({})
 
 
 
 
 
 
 
 
544
  });
545
  });
546
  })
540
 
541
  $(document).ready(function () {
542
  $(document).ready(function () {
543
+ new LP_Course({});
544
+
545
+ $(this).on('submit', 'form[name="course-external-link"]', function () {
546
+ var redirect = $(this).attr('action');
547
+ if (redirect) {
548
+ window.location.href = redirect;
549
+ return false;
550
+ }
551
+ })
552
  });
553
  });
554
  })
assets/scss/frontend/_curriculum.scss CHANGED
@@ -30,8 +30,7 @@
30
  &:after {
31
  @include clear-fix();
32
  }
33
-
34
- .list-course-instructors {
35
  clear: both;
36
  padding-top: 20px;
37
  }
30
  &:after {
31
  @include clear-fix();
32
  }
33
+ .course-instructor-item {
 
34
  clear: both;
35
  padding-top: 20px;
36
  }
inc/admin/class-lp-modal-search-items.php CHANGED
@@ -133,7 +133,9 @@ if ( ! class_exists( 'LP_Modal_Search_Items' ) ) {
133
  'offset' => ( $paged - 1 ) * $this->_options['limit']
134
  );
135
 
136
- $args['author'] = get_post_field( 'post_author', $context_id );
 
 
137
 
138
  if ( $term ) {
139
  $args['s'] = $term;
133
  'offset' => ( $paged - 1 ) * $this->_options['limit']
134
  );
135
 
136
+ if ( $context_id = apply_filters( 'learn-press/modal-search-items/context-id', $context_id, $context ) ) {
137
+ $args['author'] = get_post_field( 'post_author', $context_id );
138
+ }
139
 
140
  if ( $term ) {
141
  $args['s'] = $term;
inc/admin/class-lp-updater.php CHANGED
@@ -32,7 +32,7 @@ class LP_Updater {
32
  return;
33
  }
34
  echo '<div>';
35
- ob_start();
36
  try {
37
  LP_Debug::startTransaction();
38
  foreach ( $this->get_update_files() as $version => $file ) {
32
  return;
33
  }
34
  echo '<div>';
35
+ //ob_start();
36
  try {
37
  LP_Debug::startTransaction();
38
  foreach ( $this->get_update_files() as $version => $file ) {
inc/admin/editor/class-lp-admin-editor-course.php CHANGED
@@ -86,7 +86,7 @@ class LP_Admin_Editor_Course extends LP_Admin_Editor {
86
  /**
87
  * @param array $args
88
  */
89
- public function hide_sections( $args ) {
90
  // get hidden sections id
91
  $hidden = ! empty( $args['hidden'] ) ? $args['hidden'] : false;
92
  // update course post meta
86
  /**
87
  * @param array $args
88
  */
89
+ public function hidden_sections( $args ) {
90
  // get hidden sections id
91
  $hidden = ! empty( $args['hidden'] ) ? $args['hidden'] : false;
92
  // update course post meta
inc/admin/lp-admin-functions.php CHANGED
@@ -137,16 +137,16 @@ function learn_press_admin_view_content( $name, $args = array() ) {
137
  * Find a full path of a view and display the content in admin
138
  *
139
  * @param $name
140
- * @param array $args
141
  * @param bool|false $include_once
142
  * @param bool
143
  *
144
  * @return bool
145
  */
146
  function learn_press_admin_view( $name, $args = array(), $include_once = false, $return = false ) {
147
- $view = learn_press_get_admin_view( $name, ! empty( $args['plugin_file'] ) ? $args['plugin_file'] : null );
148
 
149
- if ( file_exists( $view ) ) {
150
  ob_start();
151
  // extract parameters as local variables if passed
152
  is_array( $args ) && extract( $args );
@@ -173,7 +173,7 @@ function learn_press_admin_view( $name, $args = array(), $include_once = false,
173
  *
174
  * @param $name
175
  * @param bool|false $selected
176
- * @param array $args
177
  *
178
  * @return mixed|string
179
  */
@@ -234,7 +234,7 @@ function learn_press_pages_dropdown( $name, $selected = false, $args = array() )
234
  $output = preg_replace( '!(<option class=".*" value="[0-9]+".*>.*</option>)!', $before_output . "\n$1", $output, 1 );
235
  }
236
 
237
- $output = str_replace('<option class="level-0" value="00000">#0 (no title)</option>', '', $output);
238
 
239
  if ( $selected && get_post_status( $selected ) !== 'publish' ) {
240
  $selected = 0;
@@ -1676,9 +1676,9 @@ if ( ! function_exists( 'learn_press_duplicate_post' ) ) {
1676
  *
1677
  * @since 3.0.0
1678
  *
1679
- * @param null $post_id
1680
  * @param array $args
1681
- * @param bool $meta
1682
  *
1683
  * @return bool|mixed
1684
  */
@@ -2180,4 +2180,24 @@ function learn_press_touch_time( $edit = 1, $for_post = 1, $tab_index = 0, $mult
2180
  $cur_timeunit = 'cur_' . $timeunit;
2181
  echo '<input type="hidden" id="' . $cur_timeunit . '" name="' . $cur_timeunit . '" value="' . $curr . '" />' . "\n";
2182
  }
2183
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  * Find a full path of a view and display the content in admin
138
  *
139
  * @param $name
140
+ * @param array $args
141
  * @param bool|false $include_once
142
  * @param bool
143
  *
144
  * @return bool
145
  */
146
  function learn_press_admin_view( $name, $args = array(), $include_once = false, $return = false ) {
147
+ $view = learn_press_get_admin_view( $name, ! empty( $args['plugin_file'] ) ? $args['plugin_file'] : null );
148
 
149
+ if ( file_exists( $view ) ) {
150
  ob_start();
151
  // extract parameters as local variables if passed
152
  is_array( $args ) && extract( $args );
173
  *
174
  * @param $name
175
  * @param bool|false $selected
176
+ * @param array $args
177
  *
178
  * @return mixed|string
179
  */
234
  $output = preg_replace( '!(<option class=".*" value="[0-9]+".*>.*</option>)!', $before_output . "\n$1", $output, 1 );
235
  }
236
 
237
+ $output = str_replace( '<option class="level-0" value="00000">#0 (no title)</option>', '', $output );
238
 
239
  if ( $selected && get_post_status( $selected ) !== 'publish' ) {
240
  $selected = 0;
1676
  *
1677
  * @since 3.0.0
1678
  *
1679
+ * @param null $post_id
1680
  * @param array $args
1681
+ * @param bool $meta
1682
  *
1683
  * @return bool|mixed
1684
  */
2180
  $cur_timeunit = 'cur_' . $timeunit;
2181
  echo '<input type="hidden" id="' . $cur_timeunit . '" name="' . $cur_timeunit . '" value="' . $curr . '" />' . "\n";
2182
  }
2183
+ }
2184
+
2185
+ /**
2186
+ * Filter to modal search items to void filter the posts by author.
2187
+ *
2188
+ * @since 3.0.4
2189
+ *
2190
+ * @param int|string $context_id
2191
+ * @param string $context
2192
+ *
2193
+ * @return bool|int|string
2194
+ */
2195
+ function learn_press_modal_search_items_context( $context_id, $context ) {
2196
+ if ( 'order-items' === $context ) {
2197
+ $context_id = false;
2198
+ }
2199
+
2200
+ return $context_id;
2201
+ }
2202
+
2203
+ add_filter( 'learn-press/modal-search-items/context-id', 'learn_press_modal_search_items_context', 10, 2 );
inc/admin/views/html-admin-notice-templates.php CHANGED
@@ -27,7 +27,7 @@ $theme_name = implode( ' & ', $theme_name );
27
 
28
  $readmore = 'https://thimpress.com/knowledge-base/outdated-template-fix/';
29
  ?>
30
- <div id="message" class="learn-press-message notice-warning">
31
  <p><?php printf( wp_kses( __( 'There is a new update of LearnPress. You may need to update your theme <strong>(%s)</strong> to avoid outdated template files.', 'learnpress' ), array( 'strong' => array() ) ), $theme_name ); ?></p>
32
  <p class="outdated-readmore-link"><?php echo sprintf( wp_kses( __( 'This is not a bug, don\'t worry. Read more about Outdated template files notice <a href="%s" target="_blank">here</a>.', 'learnpress' ), array(
33
  'a' => array(
27
 
28
  $readmore = 'https://thimpress.com/knowledge-base/outdated-template-fix/';
29
  ?>
30
+ <div id="message" class="learn-press-message notice-warning notice">
31
  <p><?php printf( wp_kses( __( 'There is a new update of LearnPress. You may need to update your theme <strong>(%s)</strong> to avoid outdated template files.', 'learnpress' ), array( 'strong' => array() ) ), $theme_name ); ?></p>
32
  <p class="outdated-readmore-link"><?php echo sprintf( wp_kses( __( 'This is not a bug, don\'t worry. Read more about Outdated template files notice <a href="%s" target="_blank">here</a>.', 'learnpress' ), array(
33
  'a' => array(
inc/admin/views/modal-search-items.php CHANGED
@@ -25,7 +25,7 @@
25
  </div>
26
  </script>
27
  <div id="vue-modal-search-items" style="position: relative;z-index: 10000;">
28
- <learn-press-modal-search-items v-if="show" :post-type="postType" :term="term" :contex="context"
29
  :context-id="contextId" :show="show" :callbacks="callbacks"
30
  :exclude="exclude"
31
  v-on:close="close">
25
  </div>
26
  </script>
27
  <div id="vue-modal-search-items" style="position: relative;z-index: 10000;">
28
+ <learn-press-modal-search-items v-if="show" :post-type="postType" :term="term" :context="context"
29
  :context-id="contextId" :show="show" :callbacks="callbacks"
30
  :exclude="exclude"
31
  v-on:close="close">
inc/admin/views/updates/html-upgrade-message-3.0.0.php CHANGED
@@ -11,7 +11,7 @@ defined( 'ABSPATH' ) or die();
11
 
12
  ?>
13
  <div class="notice notice-warning lp-notice lp-upgrade-notice">
14
- <h4><?php _e( 'Welcome to LearnPress 3.0.0', 'learnpress' ); ?></h4>
15
  <p><?php _e( 'This is a <strong>BIG UPDATE</strong> and it allows you to do so much more!', 'learnpress' ); ?></p>
16
  <p><?php _e( 'If there\'s any issue, please be sure to backup your site, update your theme, contact supporter.', 'learnpres' ); ?></p>
17
  <p>
@@ -21,5 +21,5 @@ defined( 'ABSPATH' ) or die();
21
  <a class="button" href="https://thimpress.com/help/"
22
  target="_blank"><?php _e( 'Get support now', 'learnpress' ); ?></a>
23
  </p>
24
- <a class="close-notice" href=""><?php _e('Got it!', 'learnpress');?></a>
25
  </div>
11
 
12
  ?>
13
  <div class="notice notice-warning lp-notice lp-upgrade-notice">
14
+ <h4><?php printf( __( 'Welcome to LearnPress %s', 'learnpress' ), LEARNPRESS_VERSION ); ?></h4>
15
  <p><?php _e( 'This is a <strong>BIG UPDATE</strong> and it allows you to do so much more!', 'learnpress' ); ?></p>
16
  <p><?php _e( 'If there\'s any issue, please be sure to backup your site, update your theme, contact supporter.', 'learnpres' ); ?></p>
17
  <p>
21
  <a class="button" href="https://thimpress.com/help/"
22
  target="_blank"><?php _e( 'Get support now', 'learnpress' ); ?></a>
23
  </p>
24
+ <a class="close-notice" href=""><?php _e( 'Got it!', 'learnpress' ); ?></a>
25
  </div>
inc/class-lp-ajax.php CHANGED
@@ -53,6 +53,7 @@ if ( ! class_exists( 'LP_AJAX' ) ) {
53
  'complete-lesson',
54
  'finish-course',
55
  'retake-course',
 
56
  //'register-user:nopriv',
57
  //'login-user:nopriv'
58
  );
@@ -82,6 +83,26 @@ if ( ! class_exists( 'LP_AJAX' ) ) {
82
  //LP_Request::register_ajax( 'recover-order', array( __CLASS__, 'recover_order' ) );
83
  }
84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  public static function register_user() {
86
 
87
  if ( ! get_option( 'users_can_register' ) ) {
53
  'complete-lesson',
54
  'finish-course',
55
  'retake-course',
56
+ 'external-link'
57
  //'register-user:nopriv',
58
  //'login-user:nopriv'
59
  );
83
  //LP_Request::register_ajax( 'recover-order', array( __CLASS__, 'recover_order' ) );
84
  }
85
 
86
+ public static function external_link() {
87
+ $nonce = LP_Request::get( 'nonce' );
88
+ $id = LP_Request::get( 'id' );
89
+
90
+ if ( ! $course = learn_press_get_course( $id ) ) {
91
+ return;
92
+ }
93
+
94
+ $link = $course->get_external_link();
95
+
96
+ if ( ! wp_verify_nonce( $nonce, 'external-link-' . $link ) ) {
97
+ return;
98
+ }
99
+
100
+ if ( apply_filters( 'learn-press/course-redirect-external-link', $id ) ) {
101
+ wp_redirect( $link );
102
+ exit();
103
+ }
104
+ }
105
+
106
  public static function register_user() {
107
 
108
  if ( ! get_option( 'users_can_register' ) ) {
inc/class-lp-install.php CHANGED
@@ -51,6 +51,7 @@ if ( ! function_exists( 'LP_Install' ) ) {
51
 
52
  //add_action( 'learn_press_activate', array( __CLASS__, 'install' ) );
53
 
 
54
  return;
55
  add_action( 'admin_init', array( __CLASS__, 'include_update' ), - 10 );
56
  add_action( 'admin_init', array( __CLASS__, 'update_from_09' ), 5 );
@@ -105,7 +106,7 @@ if ( ! function_exists( 'LP_Install' ) ) {
105
  $db_version = get_option( 'learnpress_db_version' );
106
 
107
  // Check latest version with the value updated in db
108
- if ( !$db_version || version_compare( $db_version, LEARNPRESS_VERSION, '=' ) ) {
109
  return;
110
  }
111
 
@@ -130,7 +131,7 @@ if ( ! function_exists( 'LP_Install' ) ) {
130
  self::_delete_transients();
131
  self::_create_log_path();
132
  ///self::_create_pages();
133
-
134
  $current_version = get_option( 'learnpress_version', null );
135
  $current_db_version = get_option( 'learnpress_db_version', null );
136
 
51
 
52
  //add_action( 'learn_press_activate', array( __CLASS__, 'install' ) );
53
 
54
+
55
  return;
56
  add_action( 'admin_init', array( __CLASS__, 'include_update' ), - 10 );
57
  add_action( 'admin_init', array( __CLASS__, 'update_from_09' ), 5 );
106
  $db_version = get_option( 'learnpress_db_version' );
107
 
108
  // Check latest version with the value updated in db
109
+ if ( !$db_version || version_compare( $db_version, LEARNPRESS_VERSION, '>=' ) ) {
110
  return;
111
  }
112
 
131
  self::_delete_transients();
132
  self::_create_log_path();
133
  ///self::_create_pages();
134
+ delete_transient( 'lp_upgraded_30' );
135
  $current_version = get_option( 'learnpress_version', null );
136
  $current_db_version = get_option( 'learnpress_db_version', null );
137
 
inc/class-lp-page-controller.php CHANGED
@@ -273,6 +273,7 @@ class LP_Page_Controller {
273
 
274
  if ( $file ) {
275
  $_template = locate_template( array_unique( $find ) );
 
276
  if ( ! $_template && ! in_array( $file, array( 'single-course.php', 'archive-course.php' ) ) ) {
277
  $_template = learn_press_plugin_path( 'templates/' ) . $file;
278
  }
@@ -477,7 +478,7 @@ class LP_Page_Controller {
477
  remove_filter( 'the_content', 'wpautop' );
478
  }
479
 
480
- $content = wpautop($content);
481
  $content = do_shortcode( $content );
482
 
483
  if ( $has_filter ) {
@@ -493,14 +494,14 @@ class LP_Page_Controller {
493
  $wp_query->post->post_title = single_term_title( '', false );
494
  }
495
 
496
- $wp_query->post->post_content = $content;
497
- $wp_query->posts = array( $wp_query->post );
498
 
499
- if( is_post_type_archive( LP_COURSE_CPT ) || LEARNPRESS_IS_CATEGORY ) {
500
- $wp_query->is_page = false;
501
- $wp_query->is_archive = true;
502
- $wp_query->is_category = true;
503
- $wp_query->is_single = false;
504
  } else {
505
  $wp_query->found_posts = 1;
506
  $wp_query->is_single = true;
@@ -530,6 +531,7 @@ class LP_Page_Controller {
530
  $wp_query->is_post_type_archive = false;
531
  }
532
  }
 
533
  return $template;
534
  }
535
 
@@ -546,9 +548,10 @@ class LP_Page_Controller {
546
  return $content;
547
  }
548
 
549
- if ( false !== ( $_content = wp_cache_get( 'course-' . get_the_ID(), 'course-content' ) ) ) {
550
- return $_content;
551
- }
 
552
 
553
  remove_filter( 'the_content', array( $this, 'single_content' ), $this->_filter_content_priority );
554
  add_filter( 'the_content', 'wpautop' );
@@ -590,6 +593,18 @@ class LP_Page_Controller {
590
  if ( ! $q->is_main_query() || is_admin() ) {
591
  return $q;
592
  }
 
 
 
 
 
 
 
 
 
 
 
 
593
  remove_action( 'pre_get_posts', array( $this, 'pre_get_posts' ), 10 );
594
 
595
  $this->_queried_object = ! empty( $q->queried_object_id ) ? $q->queried_object : false;
273
 
274
  if ( $file ) {
275
  $_template = locate_template( array_unique( $find ) );
276
+
277
  if ( ! $_template && ! in_array( $file, array( 'single-course.php', 'archive-course.php' ) ) ) {
278
  $_template = learn_press_plugin_path( 'templates/' ) . $file;
279
  }
478
  remove_filter( 'the_content', 'wpautop' );
479
  }
480
 
481
+ $content = wpautop( $content );
482
  $content = do_shortcode( $content );
483
 
484
  if ( $has_filter ) {
494
  $wp_query->post->post_title = single_term_title( '', false );
495
  }
496
 
497
+ $wp_query->post->post_content = $content;
498
+ $wp_query->posts = array( $wp_query->post );
499
 
500
+ if ( is_post_type_archive( LP_COURSE_CPT ) || LEARNPRESS_IS_CATEGORY ) {
501
+ $wp_query->is_page = false;
502
+ $wp_query->is_archive = true;
503
+ $wp_query->is_category = true;
504
+ $wp_query->is_single = false;
505
  } else {
506
  $wp_query->found_posts = 1;
507
  $wp_query->is_single = true;
531
  $wp_query->is_post_type_archive = false;
532
  }
533
  }
534
+
535
  return $template;
536
  }
537
 
548
  return $content;
549
  }
550
 
551
+ #@NOTE: make sure current page is not lesson or quiz before return cache content of single course page
552
+ // if ( function_exists( 'learn_press_content_single_course' ) && false !== ( $_content = wp_cache_get( 'course-' . get_the_ID(), 'course-content' ) ) ) {
553
+ // return $_content;
554
+ // }
555
 
556
  remove_filter( 'the_content', array( $this, 'single_content' ), $this->_filter_content_priority );
557
  add_filter( 'the_content', 'wpautop' );
593
  if ( ! $q->is_main_query() || is_admin() ) {
594
  return $q;
595
  }
596
+
597
+ // Handle 404 if user are viewing course item directly.
598
+ // Example: http://example.com/lesson/sample-lesson
599
+ $course_support_items = learn_press_get_course_item_types();
600
+
601
+ if ( isset($q->query_vars['post_type']) && in_array( $q->query_vars['post_type'], $course_support_items ) ) {
602
+ learn_press_404_page();
603
+ $q->set( 'post_type', '__unknown' );
604
+
605
+ return $q;
606
+ }
607
+
608
  remove_action( 'pre_get_posts', array( $this, 'pre_get_posts' ), 10 );
609
 
610
  $this->_queried_object = ! empty( $q->queried_object_id ) ? $q->queried_object : false;
inc/class-lp-settings.php CHANGED
@@ -51,6 +51,7 @@ class LP_Settings {
51
  settype( $data, 'array' );
52
  $this->_options = $data;
53
  }
 
54
  }
55
 
56
  /**
@@ -72,9 +73,11 @@ class LP_Settings {
72
  */
73
  protected function _load_options( $force = false ) {
74
  $_options = wp_load_alloptions();
75
- foreach ( $_options as $k => $v ) {
76
- $this->_options[ $k ] = maybe_unserialize( $v );
77
- }
 
 
78
 
79
  // if ( ( false === ( $_options = wp_cache_get( 'options', 'lp-options' ) ) ) || $force ) {
80
  // global $wpdb;
@@ -114,6 +117,7 @@ class LP_Settings {
114
  $current_var = array_shift( $var );
115
  if ( is_object( $obj ) ) {
116
  if ( isset( $obj->{$current_var} ) ) {
 
117
  if ( count( $var ) ) {
118
  $this->_set_option( $obj->{$current_var}, join( '.', $var ), $value );
119
  } else {
@@ -124,6 +128,7 @@ class LP_Settings {
124
  }
125
  } else {
126
  if ( isset( $obj[ $current_var ] ) ) {
 
127
  if ( count( $var ) ) {
128
  $this->_set_option( $obj[ $current_var ], join( '.', $var ), $value );
129
  } else {
@@ -172,6 +177,7 @@ class LP_Settings {
172
  $current_var = array_shift( $var );
173
  if ( is_object( $obj ) ) {
174
  if ( isset( $obj->{$current_var} ) ) {
 
175
  if ( count( $var ) ) {
176
  return $this->_get_option( $obj->{$current_var}, join( '.', $var ), $default );
177
  } else {
@@ -182,6 +188,7 @@ class LP_Settings {
182
  }
183
  } else {
184
  if ( isset( $obj[ $current_var ] ) ) {
 
185
  if ( count( $var ) ) {
186
  return $this->_get_option( $obj[ $current_var ], join( '.', $var ), $default );
187
  } else {
51
  settype( $data, 'array' );
52
  $this->_options = $data;
53
  }
54
+
55
  }
56
 
57
  /**
73
  */
74
  protected function _load_options( $force = false ) {
75
  $_options = wp_load_alloptions();
76
+ // foreach ( $_options as $k => $v ) {
77
+ // $this->_options[ $k ] = maybe_unserialize( $v );
78
+ // }
79
+
80
+ $this->_options = $_options;
81
 
82
  // if ( ( false === ( $_options = wp_cache_get( 'options', 'lp-options' ) ) ) || $force ) {
83
  // global $wpdb;
117
  $current_var = array_shift( $var );
118
  if ( is_object( $obj ) ) {
119
  if ( isset( $obj->{$current_var} ) ) {
120
+ $obj->{$current_var} = maybe_unserialize($obj->{$current_var});
121
  if ( count( $var ) ) {
122
  $this->_set_option( $obj->{$current_var}, join( '.', $var ), $value );
123
  } else {
128
  }
129
  } else {
130
  if ( isset( $obj[ $current_var ] ) ) {
131
+ $obj[ $current_var ] = maybe_unserialize($obj[ $current_var ]);
132
  if ( count( $var ) ) {
133
  $this->_set_option( $obj[ $current_var ], join( '.', $var ), $value );
134
  } else {
177
  $current_var = array_shift( $var );
178
  if ( is_object( $obj ) ) {
179
  if ( isset( $obj->{$current_var} ) ) {
180
+ $obj->{$current_var} = maybe_unserialize($obj->{$current_var});
181
  if ( count( $var ) ) {
182
  return $this->_get_option( $obj->{$current_var}, join( '.', $var ), $default );
183
  } else {
188
  }
189
  } else {
190
  if ( isset( $obj[ $current_var ] ) ) {
191
+ $obj[ $current_var ] = maybe_unserialize($obj[ $current_var ]);
192
  if ( count( $var ) ) {
193
  return $this->_get_option( $obj[ $current_var ], join( '.', $var ), $default );
194
  } else {
inc/course/abstract-course.php CHANGED
@@ -1659,9 +1659,11 @@ if ( ! function_exists( 'LP_Abstract_Course' ) ) {
1659
  $course_info = $user->get_course_info( $this->get_id() );
1660
  $start_time = array_key_exists( 'start_time', $args ) ? $args['start_time'] : ( is_array( $course_info ) && array_key_exists( 'start', $course_info ) ? intval( strtotime( $course_info['start'] ) ) : 0 );
1661
  if ( $duration == 0 ) {
1662
- $duration = DAY_IN_SECONDS * 365 * 100;
 
 
 
1663
  }
1664
- $expired = $start_time + $duration;
1665
 
1666
  return apply_filters( 'learn_press_user_course_expired_time', $expired, $user_id, $this->get_id() );
1667
  }
@@ -1680,7 +1682,9 @@ if ( ! function_exists( 'LP_Abstract_Course' ) ) {
1680
  $user_id = get_current_user_id();
1681
  }
1682
 
1683
- return apply_filters( 'learn_press_user_course_expired', $this->get_user_expired_time( $user_id, $args ) - current_time( 'timestamp' ) );
 
 
1684
  }
1685
 
1686
  /**
1659
  $course_info = $user->get_course_info( $this->get_id() );
1660
  $start_time = array_key_exists( 'start_time', $args ) ? $args['start_time'] : ( is_array( $course_info ) && array_key_exists( 'start', $course_info ) ? intval( strtotime( $course_info['start'] ) ) : 0 );
1661
  if ( $duration == 0 ) {
1662
+ //$duration = DAY_IN_SECONDS * 365 * 100;
1663
+ $expired = false;
1664
+ } else {
1665
+ $expired = $start_time + $duration;
1666
  }
 
1667
 
1668
  return apply_filters( 'learn_press_user_course_expired_time', $expired, $user_id, $this->get_id() );
1669
  }
1682
  $user_id = get_current_user_id();
1683
  }
1684
 
1685
+ $expired = $this->get_user_expired_time( $user_id, $args );
1686
+
1687
+ return apply_filters( 'learn_press_user_course_expired', $expired !== false ? ( $expired - current_time( 'timestamp' ) ) : false );
1688
  }
1689
 
1690
  /**
inc/curds/class-lp-course-curd.php CHANGED
@@ -216,11 +216,8 @@ if ( ! class_exists( 'LP_Course_CURD' ) ) {
216
  */
217
  public function read_course_curriculum( $course_id ) {
218
  global $wpdb;
219
- LP_Debug::log_function( __CLASS__ . '::' . __FUNCTION__ );
220
 
221
  if ( get_post_type( $course_id ) != LP_COURSE_CPT ) {
222
- LP_Debug::log_function( __CLASS__ . '::' . __FUNCTION__ );
223
-
224
  return false;
225
  }
226
 
@@ -229,8 +226,6 @@ if ( ! class_exists( 'LP_Course_CURD' ) ) {
229
  * then ignore that course.
230
  */
231
  if ( wp_cache_get( 'course-' . $course_id, 'lp-course-curriculum' ) ) {
232
- LP_Debug::log_function( __CLASS__ . '::' . __FUNCTION__ );
233
-
234
  return false;
235
  }
236
 
@@ -357,7 +352,6 @@ if ( ! class_exists( 'LP_Course_CURD' ) ) {
357
  $quiz_factory = new LP_Quiz_CURD();
358
  $quiz_factory->load_questions( $quiz_ids );
359
  }
360
- LP_Debug::log_function( __CLASS__ . '::' . __FUNCTION__ );
361
 
362
  return true;
363
  }
216
  */
217
  public function read_course_curriculum( $course_id ) {
218
  global $wpdb;
 
219
 
220
  if ( get_post_type( $course_id ) != LP_COURSE_CPT ) {
 
 
221
  return false;
222
  }
223
 
226
  * then ignore that course.
227
  */
228
  if ( wp_cache_get( 'course-' . $course_id, 'lp-course-curriculum' ) ) {
 
 
229
  return false;
230
  }
231
 
352
  $quiz_factory = new LP_Quiz_CURD();
353
  $quiz_factory->load_questions( $quiz_ids );
354
  }
 
355
 
356
  return true;
357
  }
inc/curds/class-lp-order-curd.php CHANGED
@@ -25,7 +25,7 @@ class LP_Order_CURD extends LP_Object_Data_CURD implements LP_Interface_CURD {
25
  public function create( &$order ) {
26
 
27
  $order->set_order_date( current_time( 'timestamp' ) );
28
- $order->set_order_key( learn_press_generate_order_key() );
29
 
30
  $order_data = array(
31
  'post_author' => '1',
@@ -34,8 +34,8 @@ class LP_Order_CURD extends LP_Object_Data_CURD implements LP_Interface_CURD {
34
  'post_status' => $order->get_order_status(),
35
  'ping_status' => 'closed',
36
  'post_title' => $order->get_title(),
37
- 'post_date' => $order->get_order_date()->toSql( true ),
38
- 'post_date_gmt' => $order->get_order_date()->toSql( false ),
39
  'post_excerpt' => $order->get_customer_note()
40
  );
41
 
@@ -153,8 +153,8 @@ class LP_Order_CURD extends LP_Object_Data_CURD implements LP_Interface_CURD {
153
  }
154
 
155
  $post_data = array(
156
- 'post_date' => $order->get_order_date()->toSql(),
157
- 'post_date_gmt' => $order->get_order_date()->toSql( false ),
158
  'post_status' => 'lp-' . $status,
159
  'post_parent' => $order->get_parent_id(),
160
  //'post_excerpt' => $this->get_post_excerpt( $order ),
@@ -471,7 +471,7 @@ class LP_Order_CURD extends LP_Object_Data_CURD implements LP_Interface_CURD {
471
  * Recover an order checked out by Guest for an user.
472
  *
473
  * @param string $order_key
474
- * @param int $user_id
475
  *
476
  * @return bool|LP_Order|WP_Error
477
  */
@@ -502,8 +502,7 @@ class LP_Order_CURD extends LP_Object_Data_CURD implements LP_Interface_CURD {
502
 
503
  // Trigger action
504
  do_action( 'learn-press/order/recovered-successful', $order->get_id(), $user_id );
505
- }
506
- catch ( Exception $ex ) {
507
  return new WP_Error( $ex->getCode(), $ex->getMessage() );
508
  }
509
 
25
  public function create( &$order ) {
26
 
27
  $order->set_order_date( current_time( 'timestamp' ) );
28
+ $order->set_order_key( learn_press_generate_order_key() );
29
 
30
  $order_data = array(
31
  'post_author' => '1',
34
  'post_status' => $order->get_order_status(),
35
  'ping_status' => 'closed',
36
  'post_title' => $order->get_title(),
37
+ 'post_date' => $order->get_order_date( 'edit' )->toSql( true ),
38
+ 'post_date_gmt' => $order->get_order_date( 'edit' )->toSql( false ),
39
  'post_excerpt' => $order->get_customer_note()
40
  );
41
 
153
  }
154
 
155
  $post_data = array(
156
+ 'post_date' => $order->get_order_date( 'edit' )->toSql(),
157
+ 'post_date_gmt' => $order->get_order_date( 'edit' )->toSql( false ),
158
  'post_status' => 'lp-' . $status,
159
  'post_parent' => $order->get_parent_id(),
160
  //'post_excerpt' => $this->get_post_excerpt( $order ),
471
  * Recover an order checked out by Guest for an user.
472
  *
473
  * @param string $order_key
474
+ * @param int $user_id
475
  *
476
  * @return bool|LP_Order|WP_Error
477
  */
502
 
503
  // Trigger action
504
  do_action( 'learn-press/order/recovered-successful', $order->get_id(), $user_id );
505
+ } catch ( Exception $ex ) {
 
506
  return new WP_Error( $ex->getCode(), $ex->getMessage() );
507
  }
508
 
inc/curds/class-lp-question-curd.php CHANGED
@@ -201,7 +201,7 @@ if ( ! class_exists( 'LP_Question_CURD' ) ) {
201
  /**
202
  * Duplicate answer question.
203
  *
204
- * @param $question_id | origin question
205
  * @param $new_question_id | new question
206
  */
207
  public function duplicate_answer( $question_id, $new_question_id ) {
@@ -754,7 +754,7 @@ if ( ! class_exists( 'LP_Question_CURD' ) ) {
754
  * @since 3.0.0
755
  *
756
  * @param string $question_type
757
- * @param array $args
758
  *
759
  * @return array|bool
760
  */
@@ -839,8 +839,12 @@ if ( ! class_exists( 'LP_Question_CURD' ) ) {
839
  return $this->get_error( 'QUESTION_NOT_EXISTS' );
840
  }
841
 
 
 
842
  global $wpdb;
843
  $wpdb->delete( $wpdb->learnpress_question_answers, array( 'question_id' => $question_id ) );
 
 
844
  }
845
 
846
  /**
201
  /**
202
  * Duplicate answer question.
203
  *
204
+ * @param $question_id | origin question
205
  * @param $new_question_id | new question
206
  */
207
  public function duplicate_answer( $question_id, $new_question_id ) {
754
  * @since 3.0.0
755
  *
756
  * @param string $question_type
757
+ * @param array $args
758
  *
759
  * @return array|bool
760
  */
839
  return $this->get_error( 'QUESTION_NOT_EXISTS' );
840
  }
841
 
842
+ do_action( 'learn-press/before-clear-question', $question_id );
843
+
844
  global $wpdb;
845
  $wpdb->delete( $wpdb->learnpress_question_answers, array( 'question_id' => $question_id ) );
846
+
847
+ return true;
848
  }
849
 
850
  /**
inc/custom-post-types/order.php CHANGED
@@ -739,8 +739,7 @@ if ( ! class_exists( 'LP_Order_Post_Type' ) ) {
739
  $the_order = learn_press_get_order( $post->ID );
740
  switch ( $column ) {
741
  case 'order_student':
742
- if ( $user_ids = $the_order->get_data( 'user_id' ) ) {
743
- settype( $user_ids, 'array' );
744
  $outputs = array();
745
  foreach ( $user_ids as $user_id ) {
746
  if ( get_user_by( 'id', $user_id ) ) {
@@ -753,7 +752,9 @@ if ( ! class_exists( 'LP_Order_Post_Type' ) ) {
753
  $user->get_data( 'user_email' )
754
  );
755
  } else {
756
- $outputs[] = $the_order->get_customer_name();
 
 
757
  }
758
  }
759
  echo join( ', ', $outputs );
739
  $the_order = learn_press_get_order( $post->ID );
740
  switch ( $column ) {
741
  case 'order_student':
742
+ if ( $user_ids = $the_order->get_users() ) {
 
743
  $outputs = array();
744
  foreach ( $user_ids as $user_id ) {
745
  if ( get_user_by( 'id', $user_id ) ) {
752
  $user->get_data( 'user_email' )
753
  );
754
  } else {
755
+ if ( sizeof( $user_ids ) == 1 ) {
756
+ $outputs[] = $the_order->get_customer_name();
757
+ }
758
  }
759
  }
760
  echo join( ', ', $outputs );
inc/lp-constants.php CHANGED
@@ -4,7 +4,7 @@
4
  */
5
  $upload_dir = wp_upload_dir();
6
  // version
7
- define( 'LEARNPRESS_VERSION', '3.0.3' );
8
 
9
  define( 'LP_WP_CONTENT', basename( WP_CONTENT_DIR ) );
10
 
4
  */
5
  $upload_dir = wp_upload_dir();
6
  // version
7
+ define( 'LEARNPRESS_VERSION', '3.0.4' );
8
 
9
  define( 'LP_WP_CONTENT', basename( WP_CONTENT_DIR ) );
10
 
inc/lp-core-functions.php CHANGED
@@ -3109,4 +3109,23 @@ function learn_press_sort_list_by_priority_callback( $a, $b ) {
3109
  }
3110
 
3111
  return ( $a_priority < $b_priority ) ? - 1 : 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3112
  }
3109
  }
3110
 
3111
  return ( $a_priority < $b_priority ) ? - 1 : 1;
3112
+ }
3113
+
3114
+ /**
3115
+ * Localize date with custom format.
3116
+ *
3117
+ * @since 3.0.0
3118
+ *
3119
+ * @param string $timestamp
3120
+ * @param string $format
3121
+ * @param bool $gmt
3122
+ *
3123
+ * @return string
3124
+ */
3125
+ function learn_press_date_i18n( $timestamp = '', $format = '', $gmt = false ) {
3126
+ if ( ! $format ) {
3127
+ $format = get_option( 'date_format' );
3128
+ }
3129
+
3130
+ return date_i18n( $format, $timestamp, $gmt );
3131
  }
inc/lp-template-functions.php CHANGED
@@ -151,7 +151,7 @@ if ( ! function_exists( 'learn_press_course_continue_button' ) ) {
151
  $user = LP_Global::user();
152
  $course = LP_Global::course();
153
 
154
- if (! learn_press_current_user_enrolled_course() && $course->get_external_link() ) {
155
  return;
156
  }
157
 
@@ -185,7 +185,7 @@ if ( ! function_exists( 'learn_press_course_finish_button' ) ) {
185
  $user = LP_Global::user();
186
  $course = LP_Global::course();
187
 
188
- if (! learn_press_current_user_enrolled_course() && $course->get_external_link() ) {
189
  return;
190
  }
191
 
151
  $user = LP_Global::user();
152
  $course = LP_Global::course();
153
 
154
+ if ( ! learn_press_current_user_enrolled_course() && $course->get_external_link() ) {
155
  return;
156
  }
157
 
185
  $user = LP_Global::user();
186
  $course = LP_Global::course();
187
 
188
+ if ( ! learn_press_current_user_enrolled_course() && $course->get_external_link() ) {
189
  return;
190
  }
191
 
inc/order/class-lp-order.php CHANGED
@@ -136,33 +136,35 @@ if ( ! class_exists( 'LP_Order' ) ) {
136
  /**
137
  * Get date of this order.
138
  *
139
- * @param string $format
140
  *
141
  * @return string|LP_Datetime
142
  */
143
- public function get_order_date( $format = '' ) {
144
  $date = $this->get_data( 'order_date' );
145
 
146
- $strtime = strtotime( $date->toSql() );
147
-
148
- switch ( $format ) {
149
- case 'd':
150
- $return = date_i18n( 'Y-m-d', $strtime );
151
- break;
152
- case 'h':
153
- $return = date_i18n( 'H', $strtime );
154
- break;
155
- case 'm':
156
- $return = date_i18n( 'i', $strtime );
157
- break;
158
- case 'timestamp':
159
- $return = $strtime;
160
- break;
161
- default:
162
- $return = $format ? date_i18n( $format, $strtime ) : $date;
 
 
163
  }
164
 
165
- return $return;
166
  }
167
 
168
  /**
@@ -462,21 +464,29 @@ if ( ! class_exists( 'LP_Order' ) ) {
462
  $customer = false;
463
  if ( 'auto-draft' === get_post_status( $this->get_id() ) ) {
464
  } else {
465
- $customer = learn_press_get_user( $this->get_data( 'user_id' ) );
466
- }
467
- if ( $customer ) {
468
- if ( ! $customer->is_exists() ) {
469
- $customer_name = $this->get_guest_customer_name();
470
- } else {
471
- if ( $customer->get_data( 'display_name' ) ) {
472
- $customer_name = $customer->get_data( 'display_name' );
473
- } elseif ( $customer->get_data( 'user_nicename' ) ) {
474
- $customer_name = $customer->get_data( 'user_nicename' );
475
- } elseif ( $customer->get_data( 'user_login' ) ) {
476
- $customer_name = $customer->get_data( 'user_login' );
 
 
 
 
477
  }
 
 
478
  }
479
- } else {
 
 
480
  $customer_name = $this->get_guest_customer_name();
481
  }
482
 
@@ -764,7 +774,10 @@ if ( ! class_exists( 'LP_Order' ) ) {
764
  */
765
  public function get_user( $field = '' ) {
766
 
767
- if ( false === ( $user = learn_press_get_user( $this->get_data( 'user_id' ) ) ) ) {
 
 
 
768
  return false;
769
  }
770
 
@@ -785,7 +798,12 @@ if ( ! class_exists( 'LP_Order' ) ) {
785
  * @return array
786
  */
787
  public function get_users() {
788
- $users = (array) $this->get_data( 'user_id' );
 
 
 
 
 
789
 
790
  return $users;
791
  }
136
  /**
137
  * Get date of this order.
138
  *
139
+ * @param string $context
140
  *
141
  * @return string|LP_Datetime
142
  */
143
+ public function get_order_date( $context = '' ) {
144
  $date = $this->get_data( 'order_date' );
145
 
146
+ if ( 'edit' !== $context ) {
147
+ $strtime = strtotime( $date->toSql() );
148
+
149
+ switch ( $context ) {
150
+ case 'd':
151
+ $date = date_i18n( 'Y-m-d', $strtime );
152
+ break;
153
+ case 'h':
154
+ $date = date_i18n( 'H', $strtime );
155
+ break;
156
+ case 'm':
157
+ $date = date_i18n( 'i', $strtime );
158
+ break;
159
+ case 'timestamp':
160
+ $date = $strtime;
161
+ break;
162
+ default:
163
+ $date = learn_press_date_i18n( $strtime );
164
+ }
165
  }
166
 
167
+ return $date;
168
  }
169
 
170
  /**
464
  $customer = false;
465
  if ( 'auto-draft' === get_post_status( $this->get_id() ) ) {
466
  } else {
467
+ if ( $user_id = $this->get_data( 'user_id' ) ) {
468
+ settype( $user_id, 'array' );
469
+ $customer_name = array();
470
+ foreach ( $user_id as $uid ) {
471
+ $customer = learn_press_get_user( $uid );
472
+ if ( $customer && $customer->is_exists() ) {
473
+ if ( $customer->get_data( 'display_name' ) ) {
474
+ $customer_name[] = $customer->get_data( 'display_name' );
475
+ } elseif ( $customer->get_data( 'user_nicename' ) ) {
476
+ $customer_name[] = $customer->get_data( 'user_nicename' );
477
+ } elseif ( $customer->get_data( 'user_login' ) ) {
478
+ $customer_name[] = $customer->get_data( 'user_login' );
479
+ }
480
+ } else {
481
+ $customer_name[] = $this->get_guest_customer_name();
482
+ }
483
  }
484
+
485
+ $customer_name = join( ', ', $customer_name );
486
  }
487
+ }
488
+
489
+ if ( ! $customer_name ) {
490
  $customer_name = $this->get_guest_customer_name();
491
  }
492
 
774
  */
775
  public function get_user( $field = '' ) {
776
 
777
+ $users = $this->get_users();
778
+ $uid = reset($users);
779
+
780
+ if ( false === ( $user = learn_press_get_user( $uid ) ) ) {
781
  return false;
782
  }
783
 
798
  * @return array
799
  */
800
  public function get_users() {
801
+ if ( $users = $this->get_data( 'user_id' ) ) {
802
+ settype( $users, 'array' );
803
+ $users = array_unique( $users );
804
+ } else {
805
+ $users = array();
806
+ }
807
 
808
  return $users;
809
  }
inc/question/class-lp-question-answers.php CHANGED
@@ -91,7 +91,7 @@ if ( ! class_exists( 'LP_Question_Answers' ) ) {
91
  }
92
 
93
  foreach ( $raw as $data ) {
94
- $key = $data['question_answer_id'];
95
  $answer = new LP_Question_Answer_Option( $this->_question, $data );
96
  $this->_answers[ $key ] = $answer;
97
  }
91
  }
92
 
93
  foreach ( $raw as $data ) {
94
+ $key = isset( $data['question_answer_id'] ) ? $data['question_answer_id'] : 0;
95
  $answer = new LP_Question_Answer_Option( $this->_question, $data );
96
  $this->_answers[ $key ] = $answer;
97
  }
inc/updates/learnpress-update-2.1.1.php CHANGED
@@ -2,12 +2,13 @@
2
  /**
3
  * Upgrade user profile picture used for avatar
4
  */
5
- $user = learn_press_get_current_user();
6
- if ( !empty( $user->get_id() ) && $user->profile_picture_type == 'picture' ) {
 
7
  $thumb = $user->profile_picture_thumbnail_url;
8
  $origin = $user->profile_picture_url;
9
  $wp_upload = wp_upload_dir();
10
- $thumb = preg_replace( '!' . untrailingslashit( $wp_upload['baseurl'] ) . '/!', '', $thumb );
11
  if ( file_exists( $wp_upload['basedir'] . '/' . $thumb ) ) {
12
  // Update new user meta key value and remove unused meta data
13
  update_user_meta( $user->get_id(), '_lp_profile_picture', $thumb );
2
  /**
3
  * Upgrade user profile picture used for avatar
4
  */
5
+ $user = learn_press_get_current_user();
6
+ $user_id = $user->get_id();
7
+ if ( ! empty( $user_id ) && $user->profile_picture_type == 'picture' ) {
8
  $thumb = $user->profile_picture_thumbnail_url;
9
  $origin = $user->profile_picture_url;
10
  $wp_upload = wp_upload_dir();
11
+ $thumb = preg_replace( '!' . untrailingslashit( $wp_upload['baseurl'] ) . '/!', '', $thumb );
12
  if ( file_exists( $wp_upload['basedir'] . '/' . $thumb ) ) {
13
  // Update new user meta key value and remove unused meta data
14
  update_user_meta( $user->get_id(), '_lp_profile_picture', $thumb );
inc/updates/learnpress-update-3.0.4.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Todo: update emails
4
+ */
5
+
6
+
7
+ /**
8
+ * Class LP_Update_304
9
+ *
10
+ * Helper class for updating database to 3.0.4
11
+ */
12
+ class LP_Update_304 {
13
+
14
+ /**
15
+ * Entry point
16
+ */
17
+ public static function update() {
18
+ LP_Debug::startTransaction();
19
+ try {
20
+ self::update_item_meta();
21
+
22
+ LP_Install::update_db_version();
23
+ LP_Install::update_version();
24
+
25
+ set_transient( 'lp_upgraded_30', 'yes', DAY_IN_SECONDS );
26
+ LP_Debug::commitTransaction();
27
+ }
28
+ catch ( Exception $exception ) {
29
+ LP_Debug::rollbackTransaction();
30
+ }
31
+ }
32
+
33
+ public static function update_item_meta(){
34
+
35
+ }
36
+
37
+ protected static function _update_item_meta() {
38
+ global $wpdb;
39
+ $query = $wpdb->prepare( "
40
+ SELECT pm1.learnpress_user_item_id, pm1.meta_value AS question_answers, pm2.meta_value AS _question_answers
41
+ FROM {$wpdb->learnpress_user_itemmeta} pm1
42
+ LEFT JOIN {$wpdb->learnpress_user_itemmeta} pm2 ON pm1.learnpress_user_item_id = pm2.learnpress_user_item_id AND pm2.meta_key = %s
43
+ WHERE pm1.meta_key = %s
44
+ HAVING _question_answers IS NULL
45
+ LIMIT 0, 100
46
+ ", '_question_answers', 'question_answers' );
47
+
48
+ if ( ! $rows = $wpdb->get_results( $query ) ) {
49
+ return false;
50
+ }
51
+
52
+ $sqlUpdate = $wpdb->prepare( "
53
+ INSERT INTO {$wpdb->learnpress_user_itemmeta}(learnpress_user_item_id, meta_key, meta_value)
54
+ VALUES
55
+ " );
56
+
57
+ $updateRows = array();
58
+ $count = 0;
59
+ $total = sizeof( $rows );
60
+
61
+ foreach ( $rows as $k => $row ) {
62
+
63
+ if ( $row->_question_answers ) {
64
+ continue;
65
+ }
66
+
67
+ $updateRows[] = $wpdb->prepare( "(%d, %s, %s)", $row->learnpress_user_item_id, '_question_answers', $row->question_answers );
68
+ $count ++;
69
+
70
+ if ( ( $count == 10 ) || ( $k == $total - 1 ) ) {
71
+ $query = $sqlUpdate . join( ',', $updateRows );
72
+ $wpdb->query( $query );
73
+ $count = 0;
74
+ $updateRows = array();
75
+ }
76
+ }
77
+
78
+ return true;
79
+ }
80
+ }
81
+
82
+ //LP_Update_304::update();
inc/user-item/class-lp-user-item-quiz.php CHANGED
@@ -25,8 +25,11 @@ class LP_User_Item_Quiz extends LP_User_Item {
25
  *
26
  */
27
  protected function _parse_answers() {
28
- if ( $answers = learn_press_get_user_item_meta( $this->get_user_item_id(), '_question_answers', true ) ) {
29
- $this->_answers = $answers;
 
 
 
30
  }
31
  }
32
 
@@ -135,7 +138,7 @@ class LP_User_Item_Quiz extends LP_User_Item {
135
  $question = LP_Question::get_question( $question_id );
136
  $answered = $this->get_question_answer( $question_id );
137
 
138
- $check = apply_filters( 'learn-press/quiz/check-question-result', $question->check( $answered ), $question_id, $this );
139
 
140
  $check['type'] = $question->get_type();
141
  $check['answered'] = $answered !== false;
25
  *
26
  */
27
  protected function _parse_answers() {
28
+ foreach ( array( '_question_answers', 'question_answers' ) as $k ) {
29
+ if ( $answers = learn_press_get_user_item_meta( $this->get_user_item_id(), $k, true ) ) {
30
+ $this->_answers = $answers;
31
+ break;
32
+ }
33
  }
34
  }
35
 
138
  $question = LP_Question::get_question( $question_id );
139
  $answered = $this->get_question_answer( $question_id );
140
 
141
+ $check = apply_filters( 'learn-press/quiz/check-question-result', $question->check( $answered ), $question_id, $this );
142
 
143
  $check['type'] = $question->get_type();
144
  $check['answered'] = $answered !== false;
inc/user-item/class-lp-user-item.php CHANGED
@@ -77,7 +77,7 @@ class LP_User_Item extends LP_Abstract_Object_Data {
77
  $date = new LP_Datetime( $time );
78
 
79
  if ( $format ) {
80
- return $date->format( $format );
81
  }
82
 
83
  return $date;
@@ -90,7 +90,7 @@ class LP_User_Item extends LP_Abstract_Object_Data {
90
  public function get_start_time_gmt( $format = '' ) {
91
  $date = new LP_Datetime( $this->get_data( 'start_time_gmt' ) );
92
  if ( $format ) {
93
- return $date->format( $format );
94
  }
95
 
96
  return $date;
@@ -115,7 +115,7 @@ class LP_User_Item extends LP_Abstract_Object_Data {
115
  public function get_end_time( $format = '' ) {
116
  $date = new LP_Datetime( $this->get_data( 'end_time' ) );
117
  if ( $format ) {
118
- return $date->format( $format );
119
  }
120
 
121
  return $date;
@@ -140,7 +140,7 @@ class LP_User_Item extends LP_Abstract_Object_Data {
140
  public function get_end_time_gmt( $format = '' ) {
141
  $date = new LP_Datetime( $this->get_data( 'end_time_gmt' ) );
142
  if ( $format ) {
143
- return $date->format( $format );
144
  }
145
 
146
  return $date;
@@ -414,10 +414,11 @@ class LP_User_Item extends LP_Abstract_Object_Data {
414
  * @return float|int
415
  */
416
  public function is_exceeded() {
417
- $time = new LP_Datetime();
418
- $current = $time->getTimestamp();
 
419
 
420
- return $this->get_exceeded_time() - $current;
421
  }
422
 
423
  /**
@@ -434,7 +435,7 @@ class LP_User_Item extends LP_Abstract_Object_Data {
434
  $duration = 100 * DAY_IN_SECONDS * 360;
435
  }
436
 
437
- return $format ? date( $format, $start_time + $duration ) : $start_time + $duration;
438
  }
439
 
440
  /**
77
  $date = new LP_Datetime( $time );
78
 
79
  if ( $format ) {
80
+ return $format = 'i18n' ? learn_press_date_i18n( $date->getTimestamp() ) : $date->format( $format );
81
  }
82
 
83
  return $date;
90
  public function get_start_time_gmt( $format = '' ) {
91
  $date = new LP_Datetime( $this->get_data( 'start_time_gmt' ) );
92
  if ( $format ) {
93
+ return $format = 'i18n' ? learn_press_date_i18n( $date->getTimestamp() ) : $date->format( $format );
94
  }
95
 
96
  return $date;
115
  public function get_end_time( $format = '' ) {
116
  $date = new LP_Datetime( $this->get_data( 'end_time' ) );
117
  if ( $format ) {
118
+ return $format = 'i18n' ? learn_press_date_i18n( $date->getTimestamp() ) : $date->format( $format );
119
  }
120
 
121
  return $date;
140
  public function get_end_time_gmt( $format = '' ) {
141
  $date = new LP_Datetime( $this->get_data( 'end_time_gmt' ) );
142
  if ( $format ) {
143
+ return $format = 'i18n' ? learn_press_date_i18n( $date->getTimestamp() ) : $date->format( $format );
144
  }
145
 
146
  return $date;
414
  * @return float|int
415
  */
416
  public function is_exceeded() {
417
+ $time = new LP_Datetime();
418
+ $current = $time->getTimestamp();
419
+ $exceeded = $this->get_exceeded_time();
420
 
421
+ return false !== $exceeded ? $exceeded - $current : false;
422
  }
423
 
424
  /**
435
  $duration = 100 * DAY_IN_SECONDS * 360;
436
  }
437
 
438
+ return $duration !== false ? $format ? date( $format, $start_time + $duration ) : $start_time + $duration : false;
439
  }
440
 
441
  /**
inc/user/abstract-lp-user.php CHANGED
@@ -2547,6 +2547,7 @@ if ( ! class_exists( 'LP_Abstract_User' ) ) {
2547
  public function get_course_remaining_time( $course_id ) {
2548
  $course = learn_press_get_course( $course_id );
2549
  $remain = false;
 
2550
  if ( $course && $course->get_id() ) {
2551
  if ( $course_data = $this->get_course_data( $course_id, true ) ) {
2552
  $remain = $course_data->is_exceeded();
2547
  public function get_course_remaining_time( $course_id ) {
2548
  $course = learn_press_get_course( $course_id );
2549
  $remain = false;
2550
+
2551
  if ( $course && $course->get_id() ) {
2552
  if ( $course_data = $this->get_course_data( $course_id, true ) ) {
2553
  $remain = $course_data->is_exceeded();
inc/user/class-lp-profile-tabs.php CHANGED
@@ -76,7 +76,7 @@ class LP_Profile_Tabs extends LP_Array_Access {
76
 
77
  uasort( $tabs, array( $this, '_sort_tabs' ) );
78
 
79
- $key = md5( serialize( $tabs ) );
80
  if ( $key !== get_option( '_lp_tabs_data' ) ) {
81
  flush_rewrite_rules();
82
  update_option( '_lp_tabs_data', $key, false );
76
 
77
  uasort( $tabs, array( $this, '_sort_tabs' ) );
78
 
79
+ $key = md5( serialize( array_keys( $tabs ) ) );
80
  if ( $key !== get_option( '_lp_tabs_data' ) ) {
81
  flush_rewrite_rules();
82
  update_option( '_lp_tabs_data', $key, false );
inc/user/lp-user-functions.php CHANGED
@@ -129,6 +129,8 @@ if ( ! function_exists( 'learn_press_get_user' ) ) {
129
  return false;
130
  }
131
 
 
 
132
  if ( $force_new || empty( LP_Global::$users[ $user_id ] ) ) {
133
  LP_Global::$users[ $user_id ] = isset( $is_guest ) ? new LP_User_Guest( $user_id ) : new LP_User( $user_id );
134
  }
129
  return false;
130
  }
131
 
132
+
133
+
134
  if ( $force_new || empty( LP_Global::$users[ $user_id ] ) ) {
135
  LP_Global::$users[ $user_id ] = isset( $is_guest ) ? new LP_User_Guest( $user_id ) : new LP_User( $user_id );
136
  }
learnpress.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: LearnPress
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: 3.0.3
8
  Author URI: http://thimpress.com
9
  Requires at least: 3.8
10
  Tested up to: 4.9.4
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: 3.0.4
8
  Author URI: http://thimpress.com
9
  Requires at least: 3.8
10
  Tested up to: 4.9.4
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link:
4
  Tags: WordPress LMS, LMS, eLearning, e-Learning, Learning Management System, LMS WordPress, Course, Courses, Quiz, Quizzes, Training, Guru, Sell Courses
5
  Requires at least: 3.8
6
  Tested up to: 4.9.4
7
- Stable tag: 3.0.3
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -198,6 +198,19 @@ https://www.transifex.com/projects/p/learnpress/
198
  8. Add-ons of LearnPress.
199
 
200
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  = 3.0.3 =
202
  ~ Fixed quiz auto finish with duration is zero
203
  ~ Fixed pagination with quizzes in user profile
4
  Tags: WordPress LMS, LMS, eLearning, e-Learning, Learning Management System, LMS WordPress, Course, Courses, Quiz, Quizzes, Training, Guru, Sell Courses
5
  Requires at least: 3.8
6
  Tested up to: 4.9.4
7
+ Stable tag: 3.0.4
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
198
  8. Add-ons of LearnPress.
199
 
200
  == Changelog ==
201
+ = 3.0.4 =
202
+ ~ Improved: action when clicking to close upgrade notice
203
+ ~ Fixed: can not add course from other users to order
204
+ ~ Fixed: lost quiz data after upgrading
205
+ ~ Fixed: user can view lesson/quiz with single permalink
206
+ ~ Fixed: can not view lesson
207
+ ~ Fixed: notices in admin orders
208
+ ~ Fixed: external buy this course redirect to home page
209
+ ~ Fixed: remaining time message with course duration is zero
210
+ ~ Fixed: hidden sections action ajax admin course editor
211
+ ~ Fixed: admin can not add course to order from other users
212
+ ~ More...
213
+
214
  = 3.0.3 =
215
  ~ Fixed quiz auto finish with duration is zero
216
  ~ Fixed pagination with quizzes in user profile
templates/profile/tabs.php CHANGED
@@ -26,6 +26,9 @@ $profile = LP_Profile::instance();
26
  <?php
27
  foreach ( $profile->get_tabs()->tabs() as $tab_key => $tab_data ) {
28
 
 
 
 
29
  if ( $tab_data->is_hidden() || ! $tab_data->user_can_view() ) {
30
  continue;
31
  }
@@ -33,12 +36,18 @@ $profile = LP_Profile::instance();
33
  $slug = $profile->get_slug( $tab_data, $tab_key );
34
  $link = $profile->get_tab_link( $tab_key, true );
35
  $tab_classes = array( esc_attr( $tab_key ) );
 
 
 
 
36
 
37
- if ( $profile->is_current_tab( $tab_key ) ) {
38
- $tab_classes[] = 'active';
39
  }
40
 
41
- ?>
 
 
42
 
43
  <li class="<?php echo join( ' ', $tab_classes ) ?>">
44
  <!--tabs-->
@@ -47,7 +56,7 @@ $profile = LP_Profile::instance();
47
  </a>
48
  <!--section-->
49
 
50
- <?php if ( ( $sections = $tab_data->sections() ) && sizeof( $sections ) > 1 ) { ?>
51
 
52
  <ul class="profile-tab-sections">
53
  <?php foreach ( $sections as $section_key => $section_data ) {
26
  <?php
27
  foreach ( $profile->get_tabs()->tabs() as $tab_key => $tab_data ) {
28
 
29
+ /**
30
+ * @var $tab_data LP_Profile_Tab
31
+ */
32
  if ( $tab_data->is_hidden() || ! $tab_data->user_can_view() ) {
33
  continue;
34
  }
36
  $slug = $profile->get_slug( $tab_data, $tab_key );
37
  $link = $profile->get_tab_link( $tab_key, true );
38
  $tab_classes = array( esc_attr( $tab_key ) );
39
+ /**
40
+ * @var $tab_data LP_Profile_Tab
41
+ */
42
+ $sections = $tab_data->sections();
43
 
44
+ if ( $sections && sizeof( $sections ) > 1 ) {
45
+ $tab_classes[] = 'has-child';
46
  }
47
 
48
+ if ( $profile->is_current_tab( $tab_key ) ) {
49
+ $tab_classes[] = 'active';
50
+ } ?>
51
 
52
  <li class="<?php echo join( ' ', $tab_classes ) ?>">
53
  <!--tabs-->
56
  </a>
57
  <!--section-->
58
 
59
+ <?php if ( $sections && sizeof( $sections ) > 1 ) { ?>
60
 
61
  <ul class="profile-tab-sections">
62
  <?php foreach ( $sections as $section_key => $section_data ) {
templates/profile/tabs/orders/list.php CHANGED
@@ -42,7 +42,7 @@ if ( ! $query_orders['items'] ) {
42
  $order = learn_press_get_order( $order_id ); ?>
43
  <tr class="order-row">
44
  <td class="column-order-number"><?php echo $order->get_order_number(); ?></td>
45
- <td class="column-order-date"><?php echo $order->get_order_date( get_option( 'date_format' ) ); ?></td>
46
  <td class="column-order-status">
47
  <span class="lp-label label-<?php echo esc_attr( $order->get_status() ); ?>"><?php echo $order->get_order_status_html(); ?></span>
48
  </td>
42
  $order = learn_press_get_order( $order_id ); ?>
43
  <tr class="order-row">
44
  <td class="column-order-number"><?php echo $order->get_order_number(); ?></td>
45
+ <td class="column-order-date"><?php echo $order->get_order_date(); ?></td>
46
  <td class="column-order-status">
47
  <span class="lp-label label-<?php echo esc_attr( $order->get_status() ); ?>"><?php echo $order->get_order_status_html(); ?></span>
48
  </td>
templates/profile/tabs/quizzes.php CHANGED
@@ -57,9 +57,7 @@ $query = $profile->query_quizzes( array( 'status' => $filter_status ) );
57
 
58
  </td>
59
  <td class="column-date"><?php
60
- // echo $user_quiz->get_start_time( 'd M Y' );
61
- $start_time = $user_quiz->get_start_time();
62
- echo date_i18n( get_option( 'date_format' ), $start_time->getTimestamp() ); ?></td>
63
  <td class="column-status">
64
  <span class="result-percent"><?php echo $user_quiz->get_percent_result(); ?></span>
65
  <span class="lp-label label-<?php echo esc_attr( $user_quiz->get_results( 'status' ) ); ?>">
57
 
58
  </td>
59
  <td class="column-date"><?php
60
+ echo $user_quiz->get_start_time( 'i18n' ); ?></td>
 
 
61
  <td class="column-status">
62
  <span class="result-percent"><?php echo $user_quiz->get_percent_result(); ?></span>
63
  <span class="lp-label label-<?php echo esc_attr( $user_quiz->get_results( 'status' ) ); ?>">
templates/single-course/buttons/external-link.php CHANGED
@@ -17,9 +17,12 @@ defined( 'ABSPATH' ) || exit();
17
  $course = LP_Global::course();
18
  ?>
19
 
20
- <form name="course-external-link" class="course-external-link form-button lp-form" method="get"
21
- action="<?php echo esc_url( $course->get_external_link() ); ?>">
22
 
 
 
 
 
23
  <button type="submit" class="lp-button button"><?php echo esc_html( $course->get_external_link_text() ); ?></button>
24
 
25
  </form>
17
  $course = LP_Global::course();
18
  ?>
19
 
20
+ <form name="course-external-link" class="course-external-link form-button lp-form" method="post">
 
21
 
22
+ <input type="hidden" name="lp-ajax" value="external-link">
23
+ <input type="hidden" name="id" value="<?php echo $course->get_id(); ?>">
24
+ <input type="hidden" name="nonce"
25
+ value="<?php echo wp_create_nonce( 'external-link-' . $course->get_external_link() ); ?>">
26
  <button type="submit" class="lp-button button"><?php echo esc_html( $course->get_external_link_text() ); ?></button>
27
 
28
  </form>
templates/single-course/remaining-time.php CHANGED
@@ -4,19 +4,19 @@
4
  *
5
  * @author ThimPress
6
  * @package LearnPress/Templates
7
- * @version 3.0.0
8
  */
9
 
10
  defined( 'ABSPATH' ) or die();
11
 
12
- if ( ! isset( $remaining_time ) ) {
13
- return;
14
- }
15
-
16
  ?>
17
  <div class="course-remaining-time">
18
  <p>
19
  <?php learn_press_label_html( __( 'Enrolled', 'learnpress' ), 'enrolled' ); ?>
20
- <?php echo sprintf( __( 'You have %s remaining for the course', 'learnpress' ), $remaining_time ); ?>
 
 
 
21
  </p>
22
  </div>
4
  *
5
  * @author ThimPress
6
  * @package LearnPress/Templates
7
+ * @version 3.0.4
8
  */
9
 
10
  defined( 'ABSPATH' ) or die();
11
 
12
+ $course = LP_Global::course();
 
 
 
13
  ?>
14
  <div class="course-remaining-time">
15
  <p>
16
  <?php learn_press_label_html( __( 'Enrolled', 'learnpress' ), 'enrolled' ); ?>
17
+ <?php
18
+ if ( isset( $remaining_time ) && $course->get_duration() ) {
19
+ echo sprintf( __( 'You have %s remaining for the course', 'learnpress' ), $remaining_time );
20
+ } ?>
21
  </p>
22
  </div>
templates/single-course/section/content-item.php CHANGED
@@ -1,10 +1,18 @@
1
  <?php
2
  /**
3
- * Created by PhpStorm.
4
- * User: tu
5
- * Date: 12/14/17
6
- * Time: 2:56 PM
 
 
 
 
 
 
 
7
  */
 
8
 
9
  $args = array( 'item' => $item, 'section' => $section );
10
 
1
  <?php
2
  /**
3
+ * Template for displaying content item in single course.
4
+ *
5
+ * This template can be overridden by copying it to yourtheme/learnpress/single-course/section/content-item.php.
6
+ *
7
+ * @author ThimPress
8
+ * @package Learnpress/Templates
9
+ * @version 3.0.0
10
+ */
11
+
12
+ /**
13
+ * Prevent loading this file directly
14
  */
15
+ defined( 'ABSPATH' ) || exit();
16
 
17
  $args = array( 'item' => $item, 'section' => $section );
18