LearnPress – WordPress LMS Plugin - Version 3.0.1

Version Description

~ Improved 'External link' button if user has enrolled course ~ Fixed category does not display courses (SO) ~ Fixed callback issue when sorting array|object ~ Fixed course auto finish if duration is 0 ~ Fixed warning message when counting enrolled users ~ Fixed error when calling a method from object + Added position counter to course section + Update some default settings + Fixed some bugs...

Download this release

Release Info

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

Code changes from version 3.0.0 to 3.0.1

assets/js/admin/quiz-editor.js CHANGED
@@ -310,8 +310,11 @@ var LP_List_Quiz_Questions_Store = (function (Vue, helpers, data, $) {
310
  'ADD_NEW_QUESTION': function (state, question) {
311
  state.questions.push(question);
312
 
313
- var _offset = $('.lp-list-questions .main > div:last-child').offset().top;
314
- $('html,body').animate({scrollTop: _offset});
 
 
 
315
  },
316
  'CHANGE_QUESTION_TYPE': function (state, data) {
317
  state.questions = state.questions.map(function (question) {
310
  'ADD_NEW_QUESTION': function (state, question) {
311
  state.questions.push(question);
312
 
313
+ var _last_child = $('.lp-list-questions .main > div:last-child');
314
+ if (_last_child.length) {
315
+ var _offset = _last_child.offset().top;
316
+ $('html,body').animate({scrollTop: _offset});
317
+ }
318
  },
319
  'CHANGE_QUESTION_TYPE': function (state, data) {
320
  state.questions = state.questions.map(function (question) {
inc/abstracts/abstract-object-data.php CHANGED
@@ -284,13 +284,17 @@ if ( ! class_exists( 'LP_Abstract_Object_Data' ) ) {
284
  * @param $value
285
  */
286
  public function set_data_date( $key, $value ) {
287
- if ( ! $value instanceof LP_Datetime ) {
288
  $value = new LP_Datetime( $value );
289
  }
290
 
291
  $this->_set_data( $key, $value );
292
  }
293
 
 
 
 
 
294
  /**
295
  * Set data via methods in array
296
  *
284
  * @param $value
285
  */
286
  public function set_data_date( $key, $value ) {
287
+ if ( LP_Datetime::getSqlNullDate() !== $value && ! $value instanceof LP_Datetime ) {
288
  $value = new LP_Datetime( $value );
289
  }
290
 
291
  $this->_set_data( $key, $value );
292
  }
293
 
294
+ public function set_data_null_date( $key ) {
295
+ $this->_set_data( $key, LP_Datetime::getSqlNullDate() );
296
+ }
297
+
298
  /**
299
  * Set data via methods in array
300
  *
inc/admin/class-lp-admin-menu.php CHANGED
@@ -108,7 +108,8 @@ class LP_Admin_Menu {
108
  $menu_items = apply_filters( 'learn-press/admin/menu-items', $menu_items );
109
 
110
  // Sort menu items by it's priority
111
- uasort( $menu_items, array( $this, 'sort_menu_items' ) );
 
112
 
113
  if ( $menu_items ) {
114
  foreach ( $menu_items as $item ) {
108
  $menu_items = apply_filters( 'learn-press/admin/menu-items', $menu_items );
109
 
110
  // Sort menu items by it's priority
111
+ //uasort( $menu_items, array( $this, 'sort_menu_items' ) );
112
+ uasort( $menu_items, 'learn_press_sort_list_by_priority_callback' );
113
 
114
  if ( $menu_items ) {
115
  foreach ( $menu_items as $item ) {
inc/admin/settings/class-lp-settings-general.php CHANGED
@@ -30,7 +30,7 @@ class LP_Settings_General extends LP_Abstract_Settings_Page {
30
  $currencies = learn_press_currencies();
31
  foreach ( $currencies as $code => $name ) {
32
  $s = learn_press_get_currency_symbol( $code );
33
- $currencies[ $code ] = sprintf( '%s (%s)', $name, $s ? $s : 'XXXXXX' );
34
  }
35
 
36
  $settings = apply_filters(
30
  $currencies = learn_press_currencies();
31
  foreach ( $currencies as $code => $name ) {
32
  $s = learn_press_get_currency_symbol( $code );
33
+ $currencies[ $code ] = sprintf( '%s (%s)', $name, $s );
34
  }
35
 
36
  $settings = apply_filters(
inc/background-process/class-lp-background-schedule-items.php CHANGED
@@ -80,7 +80,7 @@ if ( ! class_exists( 'LP_Background_Schedule_Items' ) ) {
80
  }
81
  }
82
 
83
- if ( ( $exceeded = $item_course->is_exceeded() ) <= 0 && ( $item_course->get_status() === 'enrolled' ) ) {
84
  $item_course->finish();
85
 
86
  $start_time = $item_course->get_start_time()->getTimestamp();
@@ -109,7 +109,7 @@ if ( ! class_exists( 'LP_Background_Schedule_Items' ) ) {
109
  $exclude_items = $queued_course_ids ? "AND user_item_id NOT IN(" . join( ',', $queued_course_ids ) . ")" : '';
110
 
111
  $null_time = '0000-00-00 00:00:00';
112
- $query = $wpdb->prepare( "
113
  SELECT user_item_id, user_id
114
  FROM {$wpdb->learnpress_user_items}
115
  WHERE item_type = %s
80
  }
81
  }
82
 
83
+ if ( ( ( $exceeded = $item_course->is_exceeded() ) <= 0 ) && ( $item_course->get_status() === 'enrolled' ) ) {
84
  $item_course->finish();
85
 
86
  $start_time = $item_course->get_start_time()->getTimestamp();
109
  $exclude_items = $queued_course_ids ? "AND user_item_id NOT IN(" . join( ',', $queued_course_ids ) . ")" : '';
110
 
111
  $null_time = '0000-00-00 00:00:00';
112
+ $query = $wpdb->prepare( "
113
  SELECT user_item_id, user_id
114
  FROM {$wpdb->learnpress_user_items}
115
  WHERE item_type = %s
inc/class-lp-page-controller.php CHANGED
@@ -60,7 +60,7 @@ class LP_Page_Controller {
60
  }
61
  }
62
 
63
- if (LP_Global::quiz_question() && ! $user->has_started_quiz( $quiz->get_id(), $course->get_id() ) ) {
64
  $redirect = $course->get_item_link( $quiz->get_id() );
65
  }
66
 
@@ -416,7 +416,9 @@ class LP_Page_Controller {
416
  /**
417
  * Load archive courses content.
418
  *
419
- * @param $template
 
 
420
  */
421
  public function _load_archive_courses( $template ) {
422
  define( 'LEARNPRESS_IS_COURSES', learn_press_is_courses() );
@@ -425,93 +427,110 @@ class LP_Page_Controller {
425
  define( 'LEARNPRESS_IS_TAX', learn_press_is_course_tax() );
426
  define( 'LEARNPRESS_IS_SEARCH', learn_press_is_search() );
427
 
 
 
 
 
 
 
 
 
428
 
429
- global $wp_query;
430
- if ( is_callable( 'clone' ) ) {
431
- LP()->wp_query = clone( $wp_query );
432
- } else {
433
- // PHP 7
434
- LP()->wp_query = clone $wp_query;
435
- }
436
 
437
- /**
438
- * Fix in case a static page is used for archive course page and
439
- * it's slug is the same with course archive slug (courses).
440
- * In this case, WP know it as a course archive page not a
441
- * single page.
442
- */
443
- if ( ( $course_page_id = learn_press_get_page_id( 'courses' ) ) && ( $course_page_slug = get_post_field( 'post_name', $course_page_id ) ) ) {
444
- if ( $course_page_slug == 'courses' ) {
445
- $wp_query->queried_object_id = $course_page_id;
446
- $this->_queried_object = $wp_query->queried_object = get_post( $course_page_id );
447
- add_filter( 'document_title_parts', array( $this, 'page_title' ) );
 
448
  }
449
- }
450
 
451
- $wp_query->posts_per_page = 1;
452
- $wp_query->nopaging = true;
453
- $wp_query->post_count = 1;
454
-
455
- // If we don't have a post, load an empty one
456
- if ( ! empty( $this->_queried_object ) ) {
457
- $wp_query->post = $this->_queried_object;
458
- } elseif ( empty( $wp_query->post ) ) {
459
- $wp_query->post = new WP_Post( new stdClass() );
460
- } elseif ( $wp_query->post->post_type != 'page' ) {
461
- // Do not show content of post if it is not a page
462
- $wp_query->post->post_content = '';
463
- }
464
- $content = $wp_query->post->post_content;
465
-
466
- if ( ! preg_match( '/\[learn_press_archive_course\s?(.*)\]/', $content ) ) {
467
- $content = $content . '[learn_press_archive_course]';
468
- }
469
-
470
- $has_filter = false;
471
- if ( has_filter( 'the_content', 'wpautop' ) ) {
472
- $has_filter = true;
473
- remove_filter( 'the_content', 'wpautop' );
474
- }
475
- $content = do_shortcode( $content );
476
- if ( $has_filter ) {
477
- has_filter( 'the_content', 'wpautop' );
478
- }
479
- //$wp_query->post->ID = 10;
480
- $wp_query->post->filter = 'raw';
481
- if ( learn_press_is_course_category() ) {
482
- $wp_query->post->post_title = single_term_title( '', false );
483
- }
484
-
485
- $wp_query->post->post_content = $content;
486
- $wp_query->posts = array( $wp_query->post );
487
- $wp_query->found_posts = 1;
488
- $wp_query->is_single = false;
489
- $wp_query->is_preview = false;
490
- $wp_query->is_page = false;
491
- $wp_query->is_archive = false;
492
- $wp_query->is_date = false;
493
- $wp_query->is_year = false;
494
- $wp_query->is_month = false;
495
- $wp_query->is_day = false;
496
- $wp_query->is_time = false;
497
- $wp_query->is_author = false;
498
- $wp_query->is_category = false;
499
- $wp_query->is_tag = false;
500
- $wp_query->is_tax = false;
501
- $wp_query->is_search = false;
502
- $wp_query->is_feed = false;
503
- $wp_query->is_comment_feed = false;
504
- $wp_query->is_trackback = false;
505
- $wp_query->is_home = false;
506
- $wp_query->is_404 = false;
507
- $wp_query->is_comments_popup = false;
508
- $wp_query->is_paged = false;
509
- $wp_query->is_admin = false;
510
- $wp_query->is_attachment = false;
511
- $wp_query->is_singular = false;
512
- $wp_query->is_posts_page = false;
513
- $wp_query->is_post_type_archive = false;
514
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
515
  }
516
 
517
  /**
60
  }
61
  }
62
 
63
+ if ( LP_Global::quiz_question() && ! $user->has_started_quiz( $quiz->get_id(), $course->get_id() ) ) {
64
  $redirect = $course->get_item_link( $quiz->get_id() );
65
  }
66
 
416
  /**
417
  * Load archive courses content.
418
  *
419
+ * @param string $template
420
+ *
421
+ * @return string
422
  */
423
  public function _load_archive_courses( $template ) {
424
  define( 'LEARNPRESS_IS_COURSES', learn_press_is_courses() );
427
  define( 'LEARNPRESS_IS_TAX', learn_press_is_course_tax() );
428
  define( 'LEARNPRESS_IS_SEARCH', learn_press_is_search() );
429
 
430
+ if ( LEARNPRESS_IS_COURSES || LEARNPRESS_IS_TAG || LEARNPRESS_IS_CATEGORY || LEARNPRESS_IS_SEARCH || LEARNPRESS_IS_TAX ) {
431
+ global $wp_query;
432
+ if ( is_callable( 'clone' ) ) {
433
+ LP()->wp_query = clone( $wp_query );
434
+ } else {
435
+ // PHP 7
436
+ LP()->wp_query = clone $wp_query;
437
+ }
438
 
439
+ $template = get_page_template();
 
 
 
 
 
 
440
 
441
+ /**
442
+ * Fix in case a static page is used for archive course page and
443
+ * it's slug is the same with course archive slug (courses).
444
+ * In this case, WP know it as a course archive page not a
445
+ * single page.
446
+ */
447
+ if ( ( $course_page_id = learn_press_get_page_id( 'courses' ) ) && ( $course_page_slug = get_post_field( 'post_name', $course_page_id ) ) ) {
448
+ if ( $course_page_slug == 'courses' ) {
449
+ $wp_query->queried_object_id = $course_page_id;
450
+ $this->_queried_object = $wp_query->queried_object = get_post( $course_page_id );
451
+ add_filter( 'document_title_parts', array( $this, 'page_title' ) );
452
+ }
453
  }
 
454
 
455
+ $wp_query->posts_per_page = 1;
456
+ $wp_query->nopaging = true;
457
+ $wp_query->post_count = 1;
458
+
459
+ // If we don't have a post, load an empty one
460
+ if ( ! empty( $this->_queried_object ) ) {
461
+ $wp_query->post = $this->_queried_object;
462
+ } elseif ( empty( $wp_query->post ) ) {
463
+ $wp_query->post = new WP_Post( new stdClass() );
464
+ } elseif ( $wp_query->post->post_type != 'page' ) {
465
+ // Do not show content of post if it is not a page
466
+ $wp_query->post->post_content = '';
467
+ }
468
+ $content = $wp_query->post->post_content;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
469
 
470
+ if ( ! preg_match( '/\[learn_press_archive_course\s?(.*)\]/', $content ) ) {
471
+ $content = $content . '[learn_press_archive_course]';
472
+ }
473
+
474
+ $has_filter = false;
475
+ if ( has_filter( 'the_content', 'wpautop' ) ) {
476
+ $has_filter = true;
477
+ remove_filter( 'the_content', 'wpautop' );
478
+ }
479
+
480
+ $content = wpautop($content);
481
+ $content = do_shortcode( $content );
482
+
483
+ if ( $has_filter ) {
484
+ //add_filter( 'the_content', 'wpautop' );
485
+ }
486
+
487
+ if ( empty( $wp_query->post->ID ) || LEARNPRESS_IS_CATEGORY ) {
488
+ $wp_query->post->ID = 0;
489
+ }
490
+
491
+ $wp_query->post->filter = 'raw';
492
+ if ( learn_press_is_course_category() ) {
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;
507
+ $wp_query->is_preview = false;
508
+ $wp_query->is_archive = false;
509
+ $wp_query->is_date = false;
510
+ $wp_query->is_year = false;
511
+ $wp_query->is_month = false;
512
+ $wp_query->is_day = false;
513
+ $wp_query->is_time = false;
514
+ $wp_query->is_author = false;
515
+ $wp_query->is_category = false;
516
+ $wp_query->is_tag = false;
517
+ $wp_query->is_tax = false;
518
+ $wp_query->is_search = false;
519
+ $wp_query->is_feed = false;
520
+ $wp_query->is_comment_feed = false;
521
+ $wp_query->is_trackback = false;
522
+ $wp_query->is_home = false;
523
+ $wp_query->is_404 = false;
524
+ $wp_query->is_comments_popup = false;
525
+ $wp_query->is_paged = false;
526
+ $wp_query->is_admin = false;
527
+ $wp_query->is_attachment = false;
528
+ $wp_query->is_singular = false;
529
+ $wp_query->is_posts_page = false;
530
+ $wp_query->is_post_type_archive = false;
531
+ }
532
+ }
533
+ return $template;
534
  }
535
 
536
  /**
inc/course/abstract-course.php CHANGED
@@ -853,7 +853,7 @@ if ( ! function_exists( 'LP_Abstract_Course' ) ) {
853
  $append_students = LP()->settings()->get( 'enrolled_students_number' );// get_post_meta( $this->get_id(), '_lp_append_students', true );
854
 
855
  if ( ( 'yes' == $append_students ) || ! in_array( $append_students, array( 'yes', 'no' ) ) ) {
856
- $count_in_order += $this->get_fake_students();
857
  }
858
 
859
  return $count_in_order;
853
  $append_students = LP()->settings()->get( 'enrolled_students_number' );// get_post_meta( $this->get_id(), '_lp_append_students', true );
854
 
855
  if ( ( 'yes' == $append_students ) || ! in_array( $append_students, array( 'yes', 'no' ) ) ) {
856
+ $count_in_order += intval($this->get_fake_students());
857
  }
858
 
859
  return $count_in_order;
inc/course/class-lp-course-section.php CHANGED
@@ -5,7 +5,7 @@
5
  *
6
  * @since 3.0.0
7
  */
8
- class LP_Course_Section {
9
 
10
  /**
11
  * Store section data
@@ -20,6 +20,7 @@ class LP_Course_Section {
20
  * @param $data
21
  */
22
  public function __construct( $data ) {
 
23
  $data = wp_parse_args(
24
  $data,
25
  array(
@@ -28,6 +29,7 @@ class LP_Course_Section {
28
  'section_course_id' => 0,
29
  'section_order' => 1,
30
  'section_description' => '',
 
31
  'items' => array()
32
  )
33
  );
@@ -158,7 +160,7 @@ class LP_Course_Section {
158
  * Get items in this section.
159
  *
160
  * @param string|array $type
161
- * @param bool $preview
162
  *
163
  * @return array
164
  */
@@ -231,7 +233,7 @@ class LP_Course_Section {
231
  * Count number of items in section.
232
  *
233
  * @param string $type
234
- * @param bool $preview
235
  *
236
  * @return int
237
  */
@@ -275,4 +277,12 @@ class LP_Course_Section {
275
 
276
  return $output;
277
  }
 
 
 
 
 
 
 
 
278
  }
5
  *
6
  * @since 3.0.0
7
  */
8
+ class LP_Course_Section extends LP_Abstract_Object_Data {
9
 
10
  /**
11
  * Store section data
20
  * @param $data
21
  */
22
  public function __construct( $data ) {
23
+ parent::__construct( $data );
24
  $data = wp_parse_args(
25
  $data,
26
  array(
29
  'section_course_id' => 0,
30
  'section_order' => 1,
31
  'section_description' => '',
32
+ 'position' => 0,
33
  'items' => array()
34
  )
35
  );
160
  * Get items in this section.
161
  *
162
  * @param string|array $type
163
+ * @param bool $preview
164
  *
165
  * @return array
166
  */
233
  * Count number of items in section.
234
  *
235
  * @param string $type
236
+ * @param bool $preview
237
  *
238
  * @return int
239
  */
277
 
278
  return $output;
279
  }
280
+
281
+ public function set_position( $position ) {
282
+ $this->data['position'] = $position;
283
+ }
284
+
285
+ public function get_position() {
286
+ return ! empty( $this->data['position'] ) ? absint( $this->data['position'] ) : 0;
287
+ }
288
  }
inc/curds/class-lp-course-curd.php CHANGED
@@ -33,11 +33,11 @@ if ( ! class_exists( 'LP_Course_CURD' ) ) {
33
  *
34
  * @since 3.0.0
35
  *
36
- * @param array $args
37
  *
38
  * @return int|WP_Error
39
  */
40
- public function create( &$args = array() ) {
41
 
42
  $args = wp_parse_args( $args, array(
43
  'id' => '',
@@ -377,8 +377,11 @@ if ( ! class_exists( 'LP_Course_CURD' ) ) {
377
  if ( false === ( $curriculum = wp_cache_get( 'course-' . $course_id, 'lp-course-curriculum-sections' ) ) ) {
378
 
379
  if ( $sections = wp_cache_get( 'course-' . $course_id, 'lp-course-sections' ) ) {
 
380
  foreach ( $sections as $k => $section ) {
381
- $curriculum[ $section->section_id ] = new LP_Course_Section( $section );
 
 
382
  }
383
 
384
  // Update post meta
@@ -690,7 +693,7 @@ if ( ! class_exists( 'LP_Course_CURD' ) ) {
690
  }
691
 
692
  /**
693
- * @param int $course_id
694
  * @param string|array $statuses
695
  *
696
  * @return int
33
  *
34
  * @since 3.0.0
35
  *
36
+ * @param $args
37
  *
38
  * @return int|WP_Error
39
  */
40
+ public function create( &$args ) {
41
 
42
  $args = wp_parse_args( $args, array(
43
  'id' => '',
377
  if ( false === ( $curriculum = wp_cache_get( 'course-' . $course_id, 'lp-course-curriculum-sections' ) ) ) {
378
 
379
  if ( $sections = wp_cache_get( 'course-' . $course_id, 'lp-course-sections' ) ) {
380
+ $position = 0;
381
  foreach ( $sections as $k => $section ) {
382
+ $_section = new LP_Course_Section( $section );
383
+ $_section->set_position( ++ $position );
384
+ $curriculum[ $section->section_id ] = $_section;
385
  }
386
 
387
  // Update post meta
693
  }
694
 
695
  /**
696
+ * @param int $course_id
697
  * @param string|array $statuses
698
  *
699
  * @return int
inc/curds/class-lp-lesson-curd.php CHANGED
@@ -22,11 +22,11 @@ if ( ! class_exists( 'LP_Lesson_CURD' ) ) {
22
  /**
23
  * Create lesson, with default meta.
24
  *
25
- * @param array $args
26
  *
27
  * @return int|WP_Error
28
  */
29
- public function create( &$args = array() ) {
30
 
31
  $args = wp_parse_args( $args, array(
32
  'id' => '',
22
  /**
23
  * Create lesson, with default meta.
24
  *
25
+ * @param $args
26
  *
27
  * @return int|WP_Error
28
  */
29
+ public function create( &$args ) {
30
 
31
  $args = wp_parse_args( $args, array(
32
  'id' => '',
inc/curds/class-lp-question-curd.php CHANGED
@@ -32,11 +32,11 @@ if ( ! class_exists( 'LP_Question_CURD' ) ) {
32
  /**
33
  * Create question and can add to quiz.
34
  *
35
- * @param array $args
36
  *
37
  * @return bool|int|LP_Question|WP_Error
38
  */
39
- public function create( &$args = array() ) {
40
  $args = wp_parse_args( $args, array(
41
  'quiz_id' => 0,
42
  'order' => - 1,
@@ -45,7 +45,7 @@ if ( ! class_exists( 'LP_Question_CURD' ) ) {
45
  'type' => 'true_or_false',
46
  'title' => __( 'New Question', 'learnpress' ),
47
  'content' => '',
48
- 'create_answers' => true // some cases does not need create answers for new question
49
  )
50
  );
51
 
@@ -65,7 +65,6 @@ if ( ! class_exists( 'LP_Question_CURD' ) ) {
65
  'post_content' => $args['content'],
66
  ) );
67
 
68
-
69
  if ( $question_id ) {
70
 
71
  // add default meta for new lesson
@@ -84,7 +83,6 @@ if ( ! class_exists( 'LP_Question_CURD' ) ) {
84
 
85
  if ( $args['create_answers'] ) {
86
  $answers = $question->get_default_answers();
87
-
88
  // insert answers data in new question
89
  foreach ( $answers as $index => $answer ) {
90
  $insert = array(
@@ -107,6 +105,9 @@ if ( ! class_exists( 'LP_Question_CURD' ) ) {
107
  }
108
  }
109
 
 
 
 
110
  return $question;
111
  }
112
 
32
  /**
33
  * Create question and can add to quiz.
34
  *
35
+ * @param $args
36
  *
37
  * @return bool|int|LP_Question|WP_Error
38
  */
39
+ public function create( &$args ) {
40
  $args = wp_parse_args( $args, array(
41
  'quiz_id' => 0,
42
  'order' => - 1,
45
  'type' => 'true_or_false',
46
  'title' => __( 'New Question', 'learnpress' ),
47
  'content' => '',
48
+ 'create_answers' => true // some cases do not need create answers for new question
49
  )
50
  );
51
 
65
  'post_content' => $args['content'],
66
  ) );
67
 
 
68
  if ( $question_id ) {
69
 
70
  // add default meta for new lesson
83
 
84
  if ( $args['create_answers'] ) {
85
  $answers = $question->get_default_answers();
 
86
  // insert answers data in new question
87
  foreach ( $answers as $index => $answer ) {
88
  $insert = array(
105
  }
106
  }
107
 
108
+ // hook
109
+ do_action( 'learn-press/after-create-question', $question );
110
+
111
  return $question;
112
  }
113
 
inc/curds/class-lp-quiz-curd.php CHANGED
@@ -68,11 +68,11 @@ if ( ! function_exists( 'LP_Quiz_CURD' ) ) {
68
  /**
69
  * Create quiz, with default meta.
70
  *
71
- * @param array $args
72
  *
73
  * @return int|WP_Error
74
  */
75
- public function create( &$args = array() ) {
76
 
77
  $args = wp_parse_args( $args, array(
78
  'id' => '',
@@ -318,7 +318,7 @@ if ( ! function_exists( 'LP_Quiz_CURD' ) ) {
318
  * Reorder question by indexed number.
319
  *
320
  * @param LP_Quiz|WP_Post|int $the_quiz
321
- * @param mixed $questions
322
  *
323
  * @return mixed
324
  */
@@ -388,7 +388,7 @@ if ( ! function_exists( 'LP_Quiz_CURD' ) ) {
388
  *
389
  * @param LP_Quiz|int $the_quiz
390
  * @param $question_id
391
- * @param array $args
392
  *
393
  * @return mixed false on failed
394
  */
@@ -448,7 +448,7 @@ if ( ! function_exists( 'LP_Quiz_CURD' ) ) {
448
  /**
449
  * Check if a question (or batch of questions) is already added to quiz.
450
  *
451
- * @param int $the_id
452
  * @param int|array $ids
453
  *
454
  * @return array|bool|null|object
68
  /**
69
  * Create quiz, with default meta.
70
  *
71
+ * @param $args
72
  *
73
  * @return int|WP_Error
74
  */
75
+ public function create( &$args ) {
76
 
77
  $args = wp_parse_args( $args, array(
78
  'id' => '',
318
  * Reorder question by indexed number.
319
  *
320
  * @param LP_Quiz|WP_Post|int $the_quiz
321
+ * @param mixed $questions
322
  *
323
  * @return mixed
324
  */
388
  *
389
  * @param LP_Quiz|int $the_quiz
390
  * @param $question_id
391
+ * @param array $args
392
  *
393
  * @return mixed false on failed
394
  */
448
  /**
449
  * Check if a question (or batch of questions) is already added to quiz.
450
  *
451
+ * @param int $the_id
452
  * @param int|array $ids
453
  *
454
  * @return array|bool|null|object
inc/lp-core-functions.php CHANGED
@@ -3030,14 +3030,22 @@ function learn_press_sort_list_by_priority_callback( $a, $b ) {
3030
 
3031
  if ( is_array( $a ) && array_key_exists( 'priority', $a ) ) {
3032
  $a_priority = $a['priority'];
3033
- } elseif ( is_object( $a ) && property_exists( $a, 'priority' ) ) {
3034
- $a_priority = $a->priority;
 
 
 
 
3035
  }
3036
 
3037
  if ( is_array( $b ) && array_key_exists( 'priority', $b ) ) {
3038
  $b_priority = $b['priority'];
3039
- } elseif ( is_object( $b ) && property_exists( $b, 'priority' ) ) {
3040
- $b_priority = $b->priority;
 
 
 
 
3041
  }
3042
 
3043
  if ( $a_priority === $b_priority ) {
3030
 
3031
  if ( is_array( $a ) && array_key_exists( 'priority', $a ) ) {
3032
  $a_priority = $a['priority'];
3033
+ } elseif ( is_object( $a ) ) {
3034
+ if ( is_callable( array( $a, 'get_priority' ) ) ) {
3035
+ $a_priority = $a->get_priority();
3036
+ } elseif ( property_exists( $a, 'priority' ) ) {
3037
+ $a_priority = $a->priority;
3038
+ }
3039
  }
3040
 
3041
  if ( is_array( $b ) && array_key_exists( 'priority', $b ) ) {
3042
  $b_priority = $b['priority'];
3043
+ } elseif ( is_object( $b ) ) {
3044
+ if ( is_callable( array( $b, 'get_priority' ) ) ) {
3045
+ $b_priority = $b->get_priority();
3046
+ } elseif ( property_exists( $b, 'priority' ) ) {
3047
+ $b_priority = $b->priority;
3048
+ }
3049
  }
3050
 
3051
  if ( $a_priority === $b_priority ) {
inc/lp-template-functions.php CHANGED
@@ -21,7 +21,7 @@ if ( ! function_exists( 'learn_press_course_purchase_button' ) ) {
21
  $course = LP_Global::course();
22
  $user = LP_Global::user();
23
 
24
- if ( $course->get_external_link() ) {
25
  return;
26
  }
27
 
@@ -72,7 +72,7 @@ if ( ! function_exists( 'learn_press_course_enroll_button' ) ) {
72
  $user = LP_Global::user();
73
  $course = LP_Global::course();
74
 
75
- if ( $course->get_external_link() ) {
76
  return;
77
  }
78
 
@@ -126,7 +126,7 @@ if ( ! function_exists( 'learn_press_course_retake_button' ) ) {
126
  $course = learn_press_get_course();
127
  }
128
 
129
- if ( $course->get_external_link() ) {
130
  return;
131
  }
132
 
@@ -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 ( $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 ( $course->get_external_link() ) {
189
  return;
190
  }
191
 
@@ -213,13 +213,17 @@ if ( ! function_exists( 'learn_press_course_external_button' ) ) {
213
  return;
214
  }
215
 
216
- remove_action( 'learn-press/course-buttons', 'learn_press_course_purchase_button', 10 );
217
- remove_action( 'learn-press/course-buttons', 'learn_press_course_enroll_button', 15 );
218
- remove_action( 'learn-press/course-buttons', 'learn_press_course_retake_button', 20 );
219
- remove_action( 'learn-press/course-buttons', 'learn_press_course_continue_button', 25 );
220
- remove_action( 'learn-press/course-buttons', 'learn_press_course_finish_button', 30 );
 
 
 
221
 
222
- learn_press_get_template( 'single-course/buttons/external-link.php' );
 
223
  }
224
  }
225
 
@@ -847,7 +851,11 @@ if ( ! function_exists( 'learn_press_quiz_start_button' ) ) {
847
  $user = LP_Global::user();
848
  $quiz = LP_Global::course_item_quiz();
849
 
850
- if ( $user->has_quiz_status( array( 'started', 'completed' ), $quiz->get_id(), $course->get_id() ) ) {
 
 
 
 
851
  return;
852
  }
853
  learn_press_get_template( 'content-quiz/buttons/start.php' );
@@ -880,7 +888,7 @@ if ( ! function_exists( 'learn_press_quiz_complete_button' ) ) {
880
  $user = LP_Global::user();
881
  $quiz = LP_Global::course_item_quiz();
882
 
883
- if ( ! $user->has_quiz_status( 'started', $quiz->get_id(), $course->get_id() ) ) {
884
  return;
885
  }
886
  learn_press_get_template( 'content-quiz/buttons/complete.php' );
@@ -898,7 +906,7 @@ if ( ! function_exists( 'learn_press_quiz_redo_button' ) ) {
898
  return;
899
  }
900
 
901
- if ( ! $user->can_retake_quiz( $quiz->get_id(), $course->get_id() ) ) {
902
  return;
903
  }
904
 
@@ -963,7 +971,7 @@ if ( ! function_exists( 'learn_press_quiz_check_button' ) ) {
963
  return;
964
  }
965
 
966
- if ( ! $user->has_quiz_status( 'started', $quiz->get_id(), $course->get_id() ) ) {
967
  return;
968
  }
969
 
@@ -1091,7 +1099,8 @@ if ( ! function_exists( 'learn_press_content_item_edit_links' ) ) {
1091
  }
1092
 
1093
  if ( is_learnpress() && $post && $post->ID === 0 ) {
1094
- $wp_admin_bar->remove_node( 'edit' );
 
1095
  }
1096
 
1097
  if ( ! is_user_member_of_blog() && ! is_super_admin() ) {
@@ -3592,4 +3601,22 @@ function learn_press_redirect_search() {
3592
  exit();
3593
  }
3594
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3595
  }
21
  $course = LP_Global::course();
22
  $user = LP_Global::user();
23
 
24
+ if ( ! learn_press_current_user_enrolled_course() && $course->get_external_link() ) {
25
  return;
26
  }
27
 
72
  $user = LP_Global::user();
73
  $course = LP_Global::course();
74
 
75
+ if ( ! learn_press_current_user_enrolled_course() && $course->get_external_link() ) {
76
  return;
77
  }
78
 
126
  $course = learn_press_get_course();
127
  }
128
 
129
+ if ( ! learn_press_current_user_enrolled_course() && $course->get_external_link() ) {
130
  return;
131
  }
132
 
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
 
213
  return;
214
  }
215
 
216
+ $user = learn_press_get_current_user();
217
+
218
+ if ( ! $user->has_enrolled_course( $course->get_id() ) ) {
219
+ remove_action( 'learn-press/course-buttons', 'learn_press_course_purchase_button', 10 );
220
+ remove_action( 'learn-press/course-buttons', 'learn_press_course_enroll_button', 15 );
221
+ remove_action( 'learn-press/course-buttons', 'learn_press_course_retake_button', 20 );
222
+ remove_action( 'learn-press/course-buttons', 'learn_press_course_continue_button', 25 );
223
+ remove_action( 'learn-press/course-buttons', 'learn_press_course_finish_button', 30 );
224
 
225
+ learn_press_get_template( 'single-course/buttons/external-link.php' );
226
+ }
227
  }
228
  }
229
 
851
  $user = LP_Global::user();
852
  $quiz = LP_Global::course_item_quiz();
853
 
854
+ if ( $user->has_course_status( $course->get_id(), array( 'finished' ) ) || $user->has_quiz_status( array(
855
+ 'started',
856
+ 'completed'
857
+ ), $quiz->get_id(), $course->get_id() )
858
+ ) {
859
  return;
860
  }
861
  learn_press_get_template( 'content-quiz/buttons/start.php' );
888
  $user = LP_Global::user();
889
  $quiz = LP_Global::course_item_quiz();
890
 
891
+ if ( $user->has_course_status( $course->get_id(), array( 'finished' ) ) || ! $user->has_quiz_status( 'started', $quiz->get_id(), $course->get_id() ) ) {
892
  return;
893
  }
894
  learn_press_get_template( 'content-quiz/buttons/complete.php' );
906
  return;
907
  }
908
 
909
+ if ( $user->has_course_status( $course->get_id(), array( 'finished' ) ) || ! $user->can_retake_quiz( $quiz->get_id(), $course->get_id() ) ) {
910
  return;
911
  }
912
 
971
  return;
972
  }
973
 
974
+ if ( $user->has_course_status( $course->get_id(), array( 'finished' ) ) || ! $user->has_quiz_status( 'started', $quiz->get_id(), $course->get_id() ) ) {
975
  return;
976
  }
977
 
1099
  }
1100
 
1101
  if ( is_learnpress() && $post && $post->ID === 0 ) {
1102
+ // This also remove the 'Edit Category' link when viewing course category!!!
1103
+ //$wp_admin_bar->remove_node( 'edit' );
1104
  }
1105
 
1106
  if ( ! is_user_member_of_blog() && ! is_super_admin() ) {
3601
  exit();
3602
  }
3603
  }
3604
+ }
3605
+
3606
+ /**
3607
+ * Return TRUE if current user has already enroll course in single view.
3608
+ *
3609
+ * @since 3.0.0
3610
+ *
3611
+ * @return bool
3612
+ */
3613
+ function learn_press_current_user_enrolled_course() {
3614
+ $user = learn_press_get_current_user();
3615
+ $course = LP_Global::course();
3616
+
3617
+ if ( ! $course ) {
3618
+ return false;
3619
+ }
3620
+
3621
+ return $user->has_enrolled_course( $course->get_id() );
3622
  }
inc/user-item/class-lp-user-item-course.php CHANGED
@@ -87,10 +87,10 @@ class LP_User_Item_Course extends LP_User_Item implements ArrayAccess {
87
  $default_data
88
  );
89
  }
90
- $course_item = apply_filters( 'learn-press/user-course-item', LP_User_Item::get_item_object( $data ), $data, $this );
91
-
92
- $this->_items[ $item_id ] = $course_item;
93
- $this->_items_by_item_ids[ $course_item->get_user_item_id() ] = $item_id;
94
  }
95
  }
96
  }
@@ -98,6 +98,21 @@ class LP_User_Item_Course extends LP_User_Item implements ArrayAccess {
98
 
99
  }
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  /**
102
  * Read item meta.
103
  *
@@ -454,9 +469,9 @@ class LP_User_Item_Course extends LP_User_Item implements ArrayAccess {
454
  /**
455
  * Get completed items.
456
  *
457
- * @param string $type - Optional. Filter by type (such lp_quiz, lp_lesson) if passed
458
- * @param bool $with_total - Optional. Include total if TRUE
459
- * @param int $section_id - Optional. Get in specific section
460
  *
461
  * @return array|bool|mixed
462
  */
@@ -510,8 +525,8 @@ class LP_User_Item_Course extends LP_User_Item implements ArrayAccess {
510
  /**
511
  * Get items completed by percentage.
512
  *
513
- * @param string $type - Optional. Filter by type or not
514
- * @param int $section_id - Optional. Get in specific section
515
  *
516
  * @return float|int
517
  */
87
  $default_data
88
  );
89
  }
90
+ if ( $course_item = apply_filters( 'learn-press/user-course-item', LP_User_Item::get_item_object( $data ), $data, $this ) ) {
91
+ $this->_items[ $item_id ] = $course_item;
92
+ $this->_items_by_item_ids[ $course_item->get_user_item_id() ] = $item_id;
93
+ }
94
  }
95
  }
96
  }
98
 
99
  }
100
 
101
+ public function is_exceeded() {
102
+ $exceeded = DAY_IN_SECONDS * 360 * 100;
103
+
104
+ if ( ! $course = $this->get_course() ) {
105
+ return $exceeded;
106
+ }
107
+
108
+ if ( ! $course->get_duration() ) {
109
+ return $exceeded;
110
+ }
111
+
112
+
113
+ return parent::is_exceeded();
114
+ }
115
+
116
  /**
117
  * Read item meta.
118
  *
469
  /**
470
  * Get completed items.
471
  *
472
+ * @param string $type - Optional. Filter by type (such lp_quiz, lp_lesson) if passed
473
+ * @param bool $with_total - Optional. Include total if TRUE
474
+ * @param int $section_id - Optional. Get in specific section
475
  *
476
  * @return array|bool|mixed
477
  */
525
  /**
526
  * Get items completed by percentage.
527
  *
528
+ * @param string $type - Optional. Filter by type or not
529
+ * @param int $section_id - Optional. Get in specific section
530
  *
531
  * @return float|int
532
  */
inc/user-item/class-lp-user-item.php CHANGED
@@ -83,6 +83,19 @@ class LP_User_Item extends LP_Abstract_Object_Data {
83
  return $date;
84
  }
85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  /**
87
  * Get end-time.
88
  *
@@ -283,12 +296,18 @@ class LP_User_Item extends LP_Abstract_Object_Data {
283
  $v = is_a( $v, 'LP_Datetime' ) ? $v->toSql() : $v;
284
  break;
285
  case 'start_time_gmt':
286
- $v = new LP_Datetime( $this->_data['start_time'] );
287
- $v = $v->toSql( false );
 
 
 
288
  break;
289
  case 'end_time_gmt':
290
- $v = new LP_Datetime( $this->_data['end_time'] );
291
- $v = $v->toSql( false );
 
 
 
292
  break;
293
  }
294
  $columns[ $k ] = $v;
@@ -394,7 +413,8 @@ class LP_User_Item extends LP_Abstract_Object_Data {
394
  * @return float|int
395
  */
396
  public function is_exceeded() {
397
- $current = ( new LP_Datetime() )->getTimestamp();
 
398
 
399
  return $this->get_exceeded_time() - $current;
400
  }
@@ -460,6 +480,34 @@ class LP_User_Item extends LP_Abstract_Object_Data {
460
  learn_press_update_user_item_meta( $this->get_user_item_id(), 'grade', $result['grade'] );
461
  }
462
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
463
  /**
464
  * Get post type of item.
465
  *
83
  return $date;
84
  }
85
 
86
+ public function set_start_time_gmt( $time ) {
87
+ $this->set_data_date( 'start_time_gmt', $time );
88
+ }
89
+
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;
97
+ }
98
+
99
  /**
100
  * Get end-time.
101
  *
296
  $v = is_a( $v, 'LP_Datetime' ) ? $v->toSql() : $v;
297
  break;
298
  case 'start_time_gmt':
299
+ if ( ! $this->_data['start_time_gmt'] ) {
300
+ $v = new LP_Datetime( $this->_data['start_time'] );
301
+ }
302
+
303
+ $v = is_a( $v, 'LP_Datetime' ) ? $v->toSql() : $v;
304
  break;
305
  case 'end_time_gmt':
306
+ if ( ! $this->_data['end_time_gmt'] ) {
307
+ $v = new LP_Datetime( $this->_data['end_time'] );
308
+ }
309
+
310
+ $v = is_a( $v, 'LP_Datetime' ) ? $v->toSql() : $v;
311
  break;
312
  }
313
  $columns[ $k ] = $v;
413
  * @return float|int
414
  */
415
  public function is_exceeded() {
416
+ $time = new LP_Datetime();
417
+ $current = $time->getTimestamp();
418
 
419
  return $this->get_exceeded_time() - $current;
420
  }
480
  learn_press_update_user_item_meta( $this->get_user_item_id(), 'grade', $result['grade'] );
481
  }
482
 
483
+ public function delete_meta_data( $include = '', $exclude = '' ) {
484
+ global $wpdb;
485
+
486
+ $where = '';
487
+ if ( $include ) {
488
+ settype( $include, 'array' );
489
+ $format = array_fill( 0, sizeof( $include ), '%s' );
490
+ $where .= $wpdb->prepare( " AND meta_key IN(" . join( ',', $format ) . ")", $include );
491
+ }
492
+
493
+ if ( $exclude ) {
494
+ settype( $exclude, 'array' );
495
+ $format = array_fill( 0, sizeof( $exclude ), '%s' );
496
+ $where .= $wpdb->prepare( " AND meta_key IN(" . join( ',', $format ) . ")", $exclude );
497
+ }
498
+
499
+ $query = $wpdb->prepare( "
500
+ DELETE FROM {$wpdb->learnpress_user_itemmeta}
501
+ WHERE learnpress_user_item_id = %d
502
+ {$where}
503
+ ", $this->get_user_item_id() );
504
+
505
+ $wpdb->query( $query );
506
+
507
+ $this->_meta_data = array();
508
+ update_meta_cache( 'learnpress_user_item', $this->get_user_item_id() );
509
+ }
510
+
511
  /**
512
  * Get post type of item.
513
  *
inc/user/abstract-lp-user.php CHANGED
@@ -2030,13 +2030,8 @@ if ( ! class_exists( 'LP_Abstract_User' ) ) {
2030
  */
2031
  public function has_started_quiz( $quiz_id, $course_id = 0 ) {
2032
  $course_id = $this->_get_course( $course_id );
2033
-
2034
  $started = false;
2035
- $quiz_info = $this->get_quiz_results( $quiz_id, $course_id );
2036
- if ( $quiz_info ) {
2037
- $started = in_array( $quiz_info->status, array( 'started', 'completed' ) ) ? $quiz_info->status : false;
2038
- }
2039
- $started = $this->has_quiz_status( array( 'started', 'completed' ), $quiz_id, $course_id );
2040
 
2041
  return apply_filters( 'learn_press_user_started_quiz', $started, $quiz_id, $course_id, $this->get_id() );
2042
  }
@@ -2156,12 +2151,17 @@ if ( ! class_exists( 'LP_Abstract_User' ) ) {
2156
  }
2157
 
2158
  if ( $course_data = $this->get_course_data( $course_id ) ) {
 
 
2159
  $course_data->set_status( 'enrolled' );
 
 
 
2160
  $course_data->set_end_time( LP_Datetime::getSqlNullDate() );
2161
  $course_data->set_end_time_gmt( LP_Datetime::getSqlNullDate() );
2162
 
2163
- if ( $result = $course_data->update() ) {
2164
 
 
2165
  $course_data->increase_retake_count();
2166
 
2167
  /*
2030
  */
2031
  public function has_started_quiz( $quiz_id, $course_id = 0 ) {
2032
  $course_id = $this->_get_course( $course_id );
 
2033
  $started = false;
2034
+ $started = $this->has_quiz_status( array( 'started', 'completed' ), $quiz_id, $course_id );
 
 
 
 
2035
 
2036
  return apply_filters( 'learn_press_user_started_quiz', $started, $quiz_id, $course_id, $this->get_id() );
2037
  }
2151
  }
2152
 
2153
  if ( $course_data = $this->get_course_data( $course_id ) ) {
2154
+ $course_data->delete_meta_data( array( 'grade', 'via', 'exceeded' ) );
2155
+
2156
  $course_data->set_status( 'enrolled' );
2157
+ $start_time = new LP_Datetime( current_time( 'mysql' ) );
2158
+ $course_data->set_start_time( $start_time->toSql() );
2159
+ $course_data->set_start_time_gmt( $start_time->toSql( false ) );
2160
  $course_data->set_end_time( LP_Datetime::getSqlNullDate() );
2161
  $course_data->set_end_time_gmt( LP_Datetime::getSqlNullDate() );
2162
 
 
2163
 
2164
+ if ( $result = $course_data->update() ) {
2165
  $course_data->increase_retake_count();
2166
 
2167
  /*
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.0
8
  Author URI: http://thimpress.com
9
  Requires at least: 3.8
10
  Tested up to: 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: 3.0.1
8
  Author URI: http://thimpress.com
9
  Requires at least: 3.8
10
  Tested up to: 4.7
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.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -198,6 +198,17 @@ https://www.transifex.com/projects/p/learnpress/
198
  8. Add-ons of LearnPress.
199
 
200
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
201
  = 3.0.0 =
202
  + Reset courses data for an user has enrolled course
203
  + Reset course data for users has enrolled course
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.1
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.1 =
202
+ ~ Improved 'External link' button if user has enrolled course
203
+ ~ Fixed category does not display courses (SO)
204
+ ~ Fixed callback issue when sorting array|object
205
+ ~ Fixed course auto finish if duration is 0
206
+ ~ Fixed warning message when counting enrolled users
207
+ ~ Fixed error when calling a method from object
208
+ + Added position counter to course section
209
+ + Update some default settings
210
+ + Fixed some bugs...
211
+
212
  = 3.0.0 =
213
  + Reset courses data for an user has enrolled course
214
  + Reset course data for users has enrolled course
templates/content-quiz/buttons/nav.php CHANGED
@@ -63,7 +63,7 @@ $course_id = get_the_ID();
63
 
64
  <?php do_action( 'learn-press/quiz/before-skip-question-button' ); ?>
65
 
66
- <form name="skip-question" class="skip-question form-button" method="post"
67
  action="<?php echo $quiz->get_question_link( $next_id ); ?>">
68
 
69
  <?php do_action( 'learn-press/quiz/begin-skip-question-button' ); ?>
63
 
64
  <?php do_action( 'learn-press/quiz/before-skip-question-button' ); ?>
65
 
66
+ <form name="skip-question" class="skip-question form-button lp-form" method="post"
67
  action="<?php echo $quiz->get_question_link( $next_id ); ?>">
68
 
69
  <?php do_action( 'learn-press/quiz/begin-skip-question-button' ); ?>
templates/single-course/section/item-meta.php CHANGED
@@ -29,5 +29,4 @@ defined( 'ABSPATH' ) || exit();
29
  <?php } ?>
30
 
31
  <?php do_action( 'learn-press/course-section-item/after-' . $item->get_item_type() . '-meta', $item ); ?>
32
-
33
  </div>
29
  <?php } ?>
30
 
31
  <?php do_action( 'learn-press/course-section-item/after-' . $item->get_item_type() . '-meta', $item ); ?>
 
32
  </div>