Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changelogs/3092.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
significance: patch
type: fixed
links:
- "#3058"
attributions:
- "@faisalahammad"
entry: Show "Mark Complete" button when quiz requirements are already met.
33 changes: 29 additions & 4 deletions includes/functions/llms-functions-progression.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,48 @@ function llms_allow_lesson_completion( $user_id, $lesson_id, $trigger = '', $arg
/**
* Determines whether or not a "Mark Complete" button should be displayed for a given lesson
*
* @param obj $lesson LLMS_Lesson.
* @return boolean
* @since 3.29.0
* @version 3.29.0
* If the lesson has a quiz, the button will only be shown if the current user has
* already met the quiz requirements (passed the quiz, or completed at least one attempt
* if passing is not required).
*
* @since 3.29.0
* @since [version] Show button when quiz requirements are already met. Fixes issue #3058.
*
* @param LLMS_Lesson $lesson LLMS_Lesson instance.
* @return boolean
*/
function llms_show_mark_complete_button( $lesson ) {

$show = true;

// If a quiz button should be shown, check if user already met quiz requirements.
if ( llms_show_take_quiz_button( $lesson ) ) {
$show = false;

// Check if current user has already met quiz requirements.
$user_id = get_current_user_id();
if ( $user_id && $lesson->is_quiz_enabled() ) {
$student = llms_get_student( $user_id );
if ( $student ) {
$quiz_id = $lesson->get( 'quiz' );
$attempt = $student->quizzes()->get_best_attempt( $quiz_id );

if ( $attempt ) {
$passing_required = llms_parse_bool( $lesson->get( 'require_passing_grade' ) );
// Show button if: passing not required, OR attempt is passing.
if ( ! $passing_required || $attempt->is_passing() ) {
$show = true;
}
}
}
}
}

return apply_filters( 'llms_show_mark_complete_button', $show, $lesson );

}


/**
* Determines whether or not a "Take Quiz" button should be displayed for a given lesson.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,144 @@ public function test_llms_show_mark_complete_button() {

}

/**
* Test llms_show_mark_complete_button() when quiz has not been attempted.
*
* @since [version]
*
* @return void
*/
public function test_llms_show_mark_complete_button_quiz_not_attempted() {

$course = $this->factory->course->create_and_get( array( 'sections' => 1, 'lessons' => 1, 'quizzes' => 1 ) );
$lesson = $course->get_lessons()[0];
$student = $this->factory->student->create_and_get();

wp_set_current_user( $student->get( 'id' ) );
$student->enroll( $course->get( 'id' ) );

// Quiz exists but no attempts - should not show mark complete.
$this->assertFalse( llms_show_mark_complete_button( $lesson ) );

}

/**
* Test llms_show_mark_complete_button() when quiz has been passed.
*
* @since [version]
*
* @return void
*/
public function test_llms_show_mark_complete_button_quiz_passed() {

$course = $this->factory->course->create_and_get( array( 'sections' => 1, 'lessons' => 1, 'quizzes' => 1 ) );
$lesson = $course->get_lessons()[0];
$quiz = $lesson->get_quiz();
$student = $this->factory->student->create_and_get();

wp_set_current_user( $student->get( 'id' ) );
$student->enroll( $course->get( 'id' ) );

// Set passing grade requirement.
$lesson->set( 'require_passing_grade', 'yes' );
$quiz->set( 'passing_percent', 50 );

// Simulate a passing quiz attempt.
$attempt = LLMS_Quiz_Attempt::init( $quiz->get( 'id' ), $lesson->get( 'id' ), $student->get( 'id' ) );
$attempt->start();

// Get all questions and answer them correctly (100% score).
$questions = $attempt->get_questions();
foreach ( $questions as $key => $question ) {
$questions[ $key ]['answer'] = 'correct_answer';
$questions[ $key ]['earned'] = $questions[ $key ]['points'];
}
$attempt->set_questions( $questions, true );
$attempt->end();

// Quiz passed - should show mark complete button.
$this->assertTrue( llms_show_mark_complete_button( $lesson ) );

}

/**
* Test llms_show_mark_complete_button() when quiz failed and passing is required.
*
* @since [version]
*
* @return void
*/
public function test_llms_show_mark_complete_button_quiz_failed_passing_required() {

$course = $this->factory->course->create_and_get( array( 'sections' => 1, 'lessons' => 1, 'quizzes' => 1 ) );
$lesson = $course->get_lessons()[0];
$quiz = $lesson->get_quiz();
$student = $this->factory->student->create_and_get();

wp_set_current_user( $student->get( 'id' ) );
$student->enroll( $course->get( 'id' ) );

// Set passing grade requirement.
$lesson->set( 'require_passing_grade', 'yes' );
$quiz->set( 'passing_percent', 80 );

// Simulate a failing quiz attempt (0% score).
$attempt = LLMS_Quiz_Attempt::init( $quiz->get( 'id' ), $lesson->get( 'id' ), $student->get( 'id' ) );
$attempt->start();

// Get all questions and answer them incorrectly (0% score).
$questions = $attempt->get_questions();
foreach ( $questions as $key => $question ) {
$questions[ $key ]['answer'] = 'wrong_answer';
$questions[ $key ]['earned'] = 0;
}
$attempt->set_questions( $questions, true );
$attempt->end();

// Quiz failed and passing required - should NOT show mark complete button.
$this->assertFalse( llms_show_mark_complete_button( $lesson ) );

}

/**
* Test llms_show_mark_complete_button() when quiz failed but passing is NOT required.
*
* @since [version]
*
* @return void
*/
public function test_llms_show_mark_complete_button_quiz_failed_passing_not_required() {

$course = $this->factory->course->create_and_get( array( 'sections' => 1, 'lessons' => 1, 'quizzes' => 1 ) );
$lesson = $course->get_lessons()[0];
$quiz = $lesson->get_quiz();
$student = $this->factory->student->create_and_get();

wp_set_current_user( $student->get( 'id' ) );
$student->enroll( $course->get( 'id' ) );

// Passing grade is NOT required.
$lesson->set( 'require_passing_grade', 'no' );
$quiz->set( 'passing_percent', 80 );

// Simulate a failing quiz attempt (0% score).
$attempt = LLMS_Quiz_Attempt::init( $quiz->get( 'id' ), $lesson->get( 'id' ), $student->get( 'id' ) );
$attempt->start();

// Get all questions and answer them incorrectly (0% score).
$questions = $attempt->get_questions();
foreach ( $questions as $key => $question ) {
$questions[ $key ]['answer'] = 'wrong_answer';
$questions[ $key ]['earned'] = 0;
}
$attempt->set_questions( $questions, true );
$attempt->end();

// Quiz failed but passing NOT required - should show mark complete button.
$this->assertTrue( llms_show_mark_complete_button( $lesson ) );

}

/**
* Test the llms_show_take_quiz_button()
* @return void
Expand Down