Quiz
Source
File: classes/Quiz.php
class Quiz { public function __construct() { add_action( 'wp_ajax_load_quiz_editor', [ $this, 'load_quiz_editor' ] ); add_action( 'wp_ajax_dozent_save_quiz', [ $this, 'dozent_save_quiz' ] ); add_action( 'wp_ajax_sort_quiz_questions', [ $this, 'sort_quiz_questions' ] ); add_action( 'wp_ajax_quiz_load_edit', [ $this, 'quiz_load_edit' ] ); add_action( 'wp_ajax_dozent_quiz_add_question', [ $this, 'dozent_quiz_add_question' ] ); add_action( 'wp_ajax_load_edit_question_modal', [ $this, 'load_edit_question_modal' ] ); add_action( 'wp_ajax_dozent_quiz_update_question', [ $this, 'dozent_quiz_update_question' ] ); add_action( 'wp_ajax_quiz_question_delete', [ $this, 'quiz_question_delete' ] ); add_action( 'wp_ajax_question_option_delete', [ $this, 'question_option_delete' ] ); //Frontend Stuff add_dozent_action( 'start_quiz', [ $this, 'start_quiz' ] ); add_filter( 'dozent_curriculum_template', [ $this, 'quiz_attempting' ] ); add_filter( 'wp_ajax_dozent_quiz_submit_question', [ $this, 'submit_question' ] ); //Attempts Table Filter add_filter( 'dozent_html_table_quiz_attempts_column', [ $this, 'table_quiz_attempts_column' ], 10, 3 ); //View Attempt by Student page add_filter( 'dozent_curriculum_content_template', [ $this, 'attempt_view' ], 10, 2 ); /** * Table Column * Dashboard Attemtps Review */ add_filter( 'dozent_html_table_quiz_attempts_courses_column', [ $this, 'table_quiz_attempts_courses_column' ], 10, 3 ); add_filter( 'dozent_html_table_dozent_course_has_quizzes_column', [ $this, 'table_dozent_course_has_quizzes_column' ], 10, 3 ); add_filter( 'dozent_html_table_attempts_for_review_column', [ $this, 'table_attempts_for_review_column' ], 10, 3 ); /** * Review Quiz Attempt */ add_dozent_action( 'dozent_review_attempt', [ $this, 'review_attempt' ] ); } public function load_quiz_editor() { ob_start(); wp_editor( '', 'quiz_content', [ 'textarea_rows' => 4 ] ); $editor_html = ob_get_clean(); wp_send_json_success( [ 'editor_html' => $editor_html ] ); } /** * Add Lecture Action * * @since DozentLMS 1.0.0 */ public function dozent_save_quiz() { $course_id = (int) dozent_input_text( 'course_id' ); $item_id = (int) dozent_input_text( 'item_id' ); $title = dozent_input_text( 'title' ); $quiz_content = dozent_input_array_field( 'quiz_content' ); $section_id = dozent_input_array_field( 'section_id' ); $post_arr = [ 'post_type' => 'dozent_quiz', 'post_title' => $title, 'post_content' => $quiz_content, 'post_status' => 'publish', 'post_author' => get_current_user_id(), 'post_parent' => $section_id, ]; if ( $item_id ) { $item = get_post( $item_id ); $post_arr['ID'] = $item_id; $post_arr['menu_order'] = $item->menu_order; } else { $menu_order_id = dozent_get_next_curriculum_item_order_id( $course_id ); $post_arr['menu_order'] = $menu_order_id; } $quiz_id = wp_insert_post( $post_arr ); if ( $quiz_id ) { update_post_meta( $quiz_id, '_dozent_course_id', $course_id ); //Register Action Hooks do_action( 'dozent/quiz/saved', $quiz_id, $course_id, $post_arr ); if ( $item_id ) { do_action( 'dozent/quiz/updated', $quiz_id, $course_id, $post_arr ); } else { do_action( 'dozent/quiz/created', $quiz_id, $course_id, $post_arr ); } $quiz_options = dozent_input_array_field( 'quiz_option' ); update_post_meta( $quiz_id, '_quiz_option', $quiz_options ); } ob_start(); include DOZENT_ABSPATH . 'views/course_builder/curriculum.php'; $course_contents = ob_get_clean(); wp_send_json_success( [ 'quiz_id' => $quiz_id, 'curriculum' => $course_contents ] ); } /** * Sort quiz question */ public function sort_quiz_questions() { global $wpdb; $questions = dozent_input_array_field( 'questions' ); if ( dozent_count( $questions ) ) { foreach ( $questions as $short => $question ) { $wpdb->update( $wpdb->dozent_quiz_questions, [ 'sort_order' => $short ], [ 'question_id' => $question ] ); } } } /** * Load Quiz Edit Form * * * @since DozentLMS 1.0.0 * */ public function quiz_load_edit() { $item_id = (int) dozent_input_text( 'item_id' ); $item = get_post( $item_id ); ob_start(); include DOZENT_ABSPATH . 'views/course_builder/edit_quiz.php'; $html = ob_get_clean(); wp_send_json_success( [ 'html' => $html ] ); } /** * Quiz Add Question * * * @since DozentLMS 1.0.0 * * @see dozent_quiz_add_question(); * */ public function dozent_quiz_add_question() { global $wpdb; $question_type = dozent_input_text( 'question_type' ); $question_title = dozent_input_text( 'question_title' ); $quiz_id = dozent_input_text( 'quiz_id' ); $score = dozent_input_text( 'score' ); $image_id = dozent_input_text( 'image_id' ); //For the question type true false $is_true = dozent_input_text( 'question_type_is_true' ); if ( empty( $question_title ) ) { $error_text = __( 'The question title field is required.', 'dozent' ); $error_message = "<p class='dozent-text-danger'> <i class='dicon-notification'></i> {$error_text} </p>"; wp_send_json_error( [ 'message' => $error_message ] ); } $user_id = get_current_user_id(); $question_order = $wpdb->get_var( "SELECT MAX(sort_order) FROM {$wpdb->dozent_quiz_questions} WHERE quiz_id = {$quiz_id} " ); $question_order ++; $data = apply_filters( 'dozent/quiz/add_question/data', [ 'user_id' => $user_id, 'quiz_id' => $quiz_id, 'title' => $question_title, 'image_id' => $image_id, 'question_type' => $question_type, 'score' => $score, 'sort_order' => $question_order, ] ); if ( $question_type === 'true_false' ) { $data['mixed_value'] = $is_true; } do_action( 'dozent/quiz/add_question/before', $data ); $wpdb->insert( $wpdb->dozent_quiz_questions, $data ); $question_id = (int) $wpdb->insert_id; $question_options = (array) dozent_input_array_field( 'options' ); $question_options = dozent_array_except( $question_options, '{index}' ); if ( dozent_count( $question_options ) ) { $sort = 0; foreach ( $question_options as $option ) { $sort ++; $optionData = [ 'question_id' => $question_id, 'title' => dozent_array_get( 'title', $option ), 'image_id' => dozent_array_get( 'image_id', $option ), 'display_preference' => dozent_array_get( 'd_pref', $option ), 'is_correct' => (int) dozent_array_get( 'is_correct', $option ), 'sort_order' => $sort, ]; $wpdb->insert( $wpdb->dozent_quiz_question_options, $optionData ); } } do_action( 'dozent/quiz/add_question/after', $data, $question_id ); ob_start(); include DOZENT_ABSPATH . 'views/course_builder/quiz_questions.php'; $questions_html = ob_get_clean(); wp_send_json_success( [ 'questions_html' => $questions_html ] ); } public function load_edit_question_modal() { $question_id = (int) dozent_input_text( 'question_id' ); $question = dozent_get_question( $question_id ); ob_start(); include DOZENT_ABSPATH . 'views/course_builder/edit_question.php'; $course_contents = ob_get_clean(); wp_send_json_success( [ 'modal_html' => $course_contents ] ); } /** * Update quiz question * * * @since DozentLMS 1.0.0 * */ public function dozent_quiz_update_question() { global $wpdb; $question_id = dozent_input_text( 'question_id' ); $question = dozent_get_question( $question_id ); $question_title = dozent_input_text( 'question_title' ); $score = dozent_input_text( 'score' ); $image_id = dozent_input_text( 'image_id' ); //For the question type true false $is_true = dozent_input_text( 'question_type_is_true' ); if ( empty( $question_title ) ) { $error_text = __( 'The question title field is required.', 'dozent' ); $error_message = "<p class='dozent-text-danger'> <i class='dicon-notification'></i> {$error_text} </p>"; wp_send_json_error( [ 'message' => $error_message ] ); } $user_id = get_current_user_id(); $data = apply_filters( 'dozent/quiz/update_question/data', [ 'user_id' => $user_id, 'title' => $question_title, 'image_id' => $image_id, 'score' => $score, ] ); if ( $question->question_type === 'true_false' ) { $data['mixed_value'] = $is_true; } do_action( 'dozent/quiz/update_question/before', $data ); $wpdb->update( $wpdb->dozent_quiz_questions, $data, [ 'question_id' => $question_id ] ); $question_options = (array) dozent_input_array_field( 'options' ); $question_options = dozent_array_except( $question_options, '{index}' ); if ( dozent_count( $question_options ) ) { $sort = 0; foreach ( $question_options as $option ) { $sort ++; $option_id = (int) dozent_array_get( 'option_id', $option ); $optionData = [ 'question_id' => $question_id, 'title' => dozent_array_get( 'title', $option ), 'image_id' => dozent_array_get( 'image_id', $option ), 'display_preference' => dozent_array_get( 'd_pref', $option ), 'is_correct' => (int) dozent_array_get( 'is_correct', $option ), 'sort_order' => $sort, ]; if ( $option_id ) { $wpdb->update( $wpdb->dozent_quiz_question_options, $optionData, [ 'option_id' => $option_id ] ); } else { $wpdb->insert( $wpdb->dozent_quiz_question_options, $optionData ); } } } do_action( 'dozent/quiz/update_question/after', $data, $question_id ); ob_start(); $quiz_id = $question->quiz_id; include DOZENT_ABSPATH . 'views/course_builder/quiz_questions.php'; $questions_html = ob_get_clean(); wp_send_json_success( [ 'questions_html' => $questions_html ] ); } public function quiz_question_delete() { global $wpdb; $question_id = dozent_input_text( 'question_id' ); $wpdb->delete( $wpdb->dozent_quiz_questions, [ 'question_id' => $question_id ] ); $wpdb->delete( $wpdb->dozent_quiz_question_options, [ 'question_id' => $question_id ] ); wp_send_json_success(); } /** * Delete Quiz Question Option * * * @since DozentLMS 1.0.0 */ public function question_option_delete() { global $wpdb; $option_id = dozent_input_text( 'option_id' ); $wpdb->delete( $wpdb->dozent_quiz_question_options, [ 'option_id' => $option_id ] ); wp_send_json_success(); } /** * Start Quiz * * @since DozentLMS 1.0.0 */ public function start_quiz() { dozent_checking_nonce(); global $wpdb; $quiz_id = (int) dozent_input_text( 'quiz_id' ); $user_id = get_current_user_id(); $course_id = dozent_get_course_id_by_content( $quiz_id ); $has_started_attempt = dozent_get_attempts( [ 'quiz_id' => $quiz_id, 'user_id' => $user_id, 'status' => 'started', ] ); if ( ! $has_started_attempt->count ) { $quiz_option = dozent_get_quiz_option( $quiz_id ); $passing_percent = (int) dozent_array_get( 'passing_score', $quiz_option ); $attempt_data = [ 'course_id' => $course_id, 'quiz_id' => $quiz_id, 'user_id' => $user_id, 'questions_limit' => dozent_array_get( 'questions_limit', $quiz_option ), 'status' => 'started', 'quiz_gradable' => dozent_array_get( 'gradable', $quiz_option ), 'passing_percent' => $passing_percent, 'quiz_option' => json_encode( $quiz_option ), 'created_at' => dozent_mysql_time(), 'updated_at' => dozent_mysql_time(), ]; $wpdb->insert( $wpdb->dozent_quiz_attempts, $attempt_data ); } dozent_redirect( get_permalink( $quiz_id ) ); } /** * Check if user attempting to any question right now. * * @since DozentLMS 1.0.0 * * @param $template * * @return string */ public function quiz_attempting( $template ) { global $wpdb; if ( is_dozent_single_quiz() && is_user_logged_in() ) { $user_id = get_current_user_id(); $quiz_id = get_the_ID(); $has_started_attempt = dozent_get_attempts( [ 'quiz_id' => $quiz_id, 'user_id' => $user_id, 'status' => 'started', ], true ); if ( $has_started_attempt->count ) { $attempt = $has_started_attempt->results; $answered = dozent_get_quiz_answers( [ 'quiz_id' => $quiz_id, 'user_id' => $user_id, 'attempt_id' => $attempt->id ] ); $answered_question_ids = []; if ( dozent_count( $answered->results ) ) { $answered_question_ids = wp_list_pluck( $answered->results, 'question_id' ); } $questions = dozent_get_questions( [ 'quiz_id' => $quiz_id ] ); $questions_limit = (int) ( $questions->count >= $attempt->questions_limit ) ? $attempt->questions_limit : $questions->count; if ( $answered->count >= $questions_limit ) { //Finished Quiz $reviewRequired = dozent_get_quiz_answers( [ 'quiz_id' => $quiz_id, 'user_id' => $user_id, 'attempt_id' => $attempt->id, 'where_sql' => " AND (q_type = 'text' OR q_type = 'textarea') ", ] ); $total_scores = array_sum( array_map( function ( $item ) { return $item->q_score; }, $answered->results ) ); $earned_scores = array_sum( array_map( function ( $item ) { return $item->earned_scores; }, $answered->results ) ); $earned_percentage = ( $earned_scores > 0 && $total_scores > 0 ) ? ( number_format( ( $earned_scores * 100 ) / $total_scores ) ) : 0; $attempt_data = [ 'total_scores' => $total_scores, 'total_answered' => $answered->count, 'earned_scores' => $earned_scores, 'earned_percent' => $earned_percentage, ]; if ( $reviewRequired->count ) { $attempt_data['status'] = 'in_review'; } else { $attempt_data['status'] = 'finished'; } $attempt_data['ended_at'] = dozent_mysql_time(); $wpdb->update( $wpdb->dozent_quiz_attempts, $attempt_data, [ 'id' => $attempt->id ] ); dozent_complete_content( $quiz_id ); dozent_redirect( get_the_permalink( $quiz_id ) ); } $question_number = $answered->count + 1; $quiz_title = get_the_title( $quiz_id ); /** * Query single random question */ $question_query_args = [ 'quiz_id' => $quiz_id, 'order_by' => 'rand' ]; if ( dozent_count( $answered_question_ids ) ) { $question_query_args['not_in'] = [ 'question_id' => $answered_question_ids ]; } $question = dozent_get_questions( $question_query_args, true ); $attempt_option = apply_filters( 'dozent_quiz_attempt_options', [ 'started_at' => $attempt->created_at, 'date_time_now' => dozent_mysql_time(), 'quiz_option' => json_decode( $attempt->quiz_option, true ), ] ); global $question_data; $question_data = [ 'quiz_id' => $quiz_id, 'quiz_title' => $quiz_title, 'question_number' => $question_number, 'questions_limit' => $questions_limit, 'question' => $question, 'attempt' => $attempt, 'attempt_option' => $attempt_option, ]; $template = dozent_get_template_path( 'quiz-attempt' ); } } return $template; } public function submit_question() { global $wpdb; $user_id = get_current_user_id(); $questions = dozent_input_array_field( 'questions' ); $attempt_id = dozent_input_text( 'attempt_id' ); if ( dozent_count( $questions ) ) { foreach ( $questions as $question_id => $answer ) { $question = dozent_get_question( $question_id ); $answer = is_string( $answer ) ? $answer : json_encode( $answer ); $is_correct = 0; $r_score = 0; if ( $question->question_type === 'true_false' ) { if ( $question->mixed_value == $answer ) { $is_correct = 1; $r_score = $question->score; } } elseif ( $question->question_type === 'radio' ) { $option = dozent_get_question_correct_options( $question_id, true ); if ( $option && $option->option_id == $answer ) { $is_correct = 1; $r_score = $question->score; } } elseif ( $question->question_type === 'checkbox' ) { $options = (array) dozent_get_question_correct_options( $question_id ); $option_ids = wp_list_pluck( $options, 'option_id' ); if ( ! count( array_diff( $option_ids, json_decode( $answer, true ) ) ) ) { $is_correct = 1; $r_score = $question->score; } } $answerData = apply_filters( 'dozent_quiz_attempt_answer_data', [ 'quiz_id' => $question->quiz_id, 'question_id' => $question_id, 'user_id' => $user_id, 'attempt_id' => $attempt_id, 'answer' => $answer, 'q_type' => $question->question_type, 'q_score' => $question->score, 'earned_scores' => $r_score, 'is_correct' => $is_correct, ] ); $wpdb->insert( $wpdb->dozent_quiz_answers, $answerData ); } } wp_send_json_success( [ 'quiz_url' => get_the_permalink( $question->quiz_id ) ] ); } /** * Filter default column data for Quiz Attempts Table * * * @since DozentLMS 1.0.0 * * @param $cell_data * @param $column * @param $row_data * * @return string */ public function table_quiz_attempts_column( $cell_data, $column, $row_data ) { $attempt_id = dozent_array_get( 'id', $row_data ); $quiz_id = dozent_array_get( 'quiz_id', $row_data ); $course_id = dozent_array_get( 'course_id', $row_data ); if ( $column === 'info' ) { $output = ""; $quiz_title = "<a href=' " . get_the_permalink( $quiz_id ) . " '> " . get_the_title( $quiz_id ) . " </a>"; $course_title = "<a href=' " . get_the_permalink( $course_id ) . " '> " . get_the_title( $course_id ) . " </a>"; $output .= "<p> <strong> <i class='dicon-quiz'></i> " . __( 'Quiz', 'dozent' ) . " : </strong> " . $quiz_title . " </p>"; $output .= "<p> <strong> <i class='dicon-graduation-cap'></i> " . __( 'Quiz', 'dozent' ) . " : </strong> " . $course_title . " </p>"; return $output; } if ( $column === 'time' ) { $output = ""; $created_at = dozent_array_get( 'created_at', $row_data ); $ended_at = dozent_array_get( 'ended_at', $row_data ); $output .= "<p> " . __( 'Started at', 'dozent' ) . " : <span class='dozent-text-muted'> " . dozent_datetime_format( strtotime( $created_at ) ) . " </span> </p>"; $output .= "<p> " . __( 'Started at', 'dozent' ) . " : <span class='dozent-text-muted'> " . dozent_datetime_format( strtotime( $ended_at ) ) . " </span> </p>"; return $output; } if ( $column === 'stats' ) { $output = ""; $total_scores = dozent_array_get( 'total_scores', $row_data ); $earned_scores = dozent_array_get( 'earned_scores', $row_data ); $attempt_status = dozent_array_get( 'status', $row_data ); $passing_percent = dozent_array_get( 'passing_percent', $row_data ); $earned_percentage = $earned_scores > 0 ? ( number_format( ( $earned_scores * 100 ) / $total_scores ) ) : 0; $result = ''; if ( $attempt_status === 'in_review' ) { $result = '<span class="dozent-pill">' . __( 'Under Review', 'dozent' ) . '</span>'; } else { if ( $earned_percentage >= $passing_percent ) { $result = '<span class="dozent-pill dozent-pill-result-pass">' . __( 'Pass', 'dozent' ) . '</span>'; } else { $result = '<span class="dozent-pill dozent-pill-result-fail">' . __( 'Fail', 'dozent' ) . '</span>'; } } $output .= "<p> " . __( 'Total Scores', 'dozent' ) . " : <span class='dozent-text-muted'> " . $total_scores . " </span> </p>"; $output .= "<p> " . __( 'Earned Scores', 'dozent' ) . " : <span class='dozent-text-muted'> " . $earned_scores . " ({$earned_percentage}%)" . " </span> </p>"; $output .= "<p> " . __( 'Result', 'dozent' ) . " : {$result} </p>"; return $output; } if ( $column === 'status' ) { $status = dozent_array_get( $cell_data, dozent_attempt_statuses() ); $output = "<span class='dozent-pill dozent-pill-status-{$cell_data}'> {$status} </span>"; return $output; } if ( $column === 'actions' ) { $attempt_id = dozent_array_get( 'id', $row_data ); $url = add_query_arg( [ 'view_attempt_id' => $attempt_id ] ); $output = "<a href='{$url}'> " . __( 'View', 'dozent' ) . " </a>"; return $output; } return $cell_data; } /** * View attempt detail * * This page will see by student, when any student click to view attempt from the previous attempt list. * * * @since DozentLMS 1.0.0 * * * @param $template * @param $post_type * * @return mixed */ public function attempt_view( $template, $post_type ) { if ( $template === 'single/quiz/content' ) { $attempt_id = (int) dozent_input_text( 'view_attempt_id' ); if ( $attempt_id ) { return "single/quiz/attempt_view"; } } return $template; } public function table_quiz_attempts_courses_column( $cell_data, $column, $data ) { $course_id = dozent_array_get( 'ID', $data ); $post_statuses = get_post_statuses( $course_id ); $course_status = get_post_status( $course_id ); $course_status_text = dozent_array_get( $course_status, $post_statuses ); if ( $column === 'thumbnail' ) { return sprintf( '<div class="courses-thumbnail"> %s </div>', dozent_get_course_thumbnail( $course_id ) ); } if ( $column === 'course_info' ) { $quiz_count = dozent_get_total_quiz( $course_id ); $attempt_count = dozent_get_attempts_count_by_course( $course_id ); $quiz_count_text = sprintf( _n( '%s quiz', '%s quizzes', $quiz_count, 'dozent' ), number_format_i18n( $quiz_count ) ); $attempt_count_text = sprintf( _n( '%s attempt', '%s attempts', $attempt_count, 'dozent' ), number_format_i18n( $attempt_count ) ); $output = ''; $output .= "<p class='dozent-mb-2'> <a href='" . get_the_permalink( $course_id ) . "' target='_blank'><strong> " . get_the_title( $course_id ) . " </strong></a> <span class='dozent-pill dozent-pill-{$course_status}'> {$course_status_text} </span> </p>"; $output .= "<p class='dozent-text-muted dozent-small'> {$quiz_count_text}, {$attempt_count_text} </p>"; return $output; } if ( $column === 'buttons' ) { $quizzes_url = dozent_get_dashboard_permalink( 'quiz-attempts/quizzes' ); $quizzes_url = add_query_arg( [ 'course_id' => $course_id ], $quizzes_url ); return sprintf( "<a href='%s' class='dozent-btn dozent-btn-primary'> <i class='dicon-quiz'></i> " . __( 'Quizzes', 'dozent' ) . " </a>", $quizzes_url ); } return $cell_data; } public function table_dozent_course_has_quizzes_column( $cell_data, $column, $data ) { $quiz_id = dozent_array_get( 'ID', $data ); if ( $column === 'quiz_info' ) { $attempt_count = dozent_get_attempts_count_by_quiz( $quiz_id ); $attempt_count_text = sprintf( _n( '%s attempt', '%s attempts', $attempt_count, 'dozent' ), number_format_i18n( $attempt_count ) ); $output = ''; $output .= "<p class='dozent-mb-2'> <a href='" . get_the_permalink( $quiz_id ) . "' target='_blank'><strong> " . get_the_title( $quiz_id ) . " </strong></a> </p>"; $output .= "<p class='dozent-text-muted dozent-small'> {$attempt_count_text} </p>"; return $output; } if ( $column === 'buttons' ) { $quizzes_url = dozent_get_dashboard_permalink( 'quiz-attempts/attempts' ); $quizzes_url = add_query_arg( [ 'quiz_id' => $quiz_id ], $quizzes_url ); return sprintf( "<a href='%s' class='dozent-btn dozent-btn-primary'> <i class='dicon-quiz'></i> " . __( 'Attempts', 'dozent' ) . " </a>", $quizzes_url ); } return $cell_data; } public function table_attempts_for_review_column( $cell_data, $column, $data ) { $attempt_id = dozent_array_get( 'id', $data ); $user_id = dozent_array_get( 'user_id', $data ); if ( $column === 'attempt_info' ) { $user = get_userdata( $user_id ); $avatar = dozent_get_avatar( $user_id ); $profile_url = dozent_user_url( $user, false ); $total_scores = dozent_array_get( 'total_scores', $data ); $earned_scores = dozent_array_get( 'earned_scores', $data ); $attempt_status = dozent_array_get( 'status', $data ); $passing_percent = dozent_array_get( 'passing_percent', $data ); $created_at = dozent_array_get( 'created_at', $data ); $ended_at = dozent_array_get( 'ended_at', $data ); $earned_percentage = $earned_scores > 0 ? ( number_format( ( $earned_scores * 100 ) / $total_scores ) ) : 0; $takes_time = __( 'Time Takes', 'dozent' ) . ' - ' . dozent_datetime_diff( $created_at, $ended_at ); if ( $attempt_status === 'in_review' ) { $result = '<span class="dozent-pill">' . __( 'Under Review', 'dozent' ) . '</span>'; } else { if ( $earned_percentage >= $passing_percent ) { $result = '<span class="dozent-pill dozent-pill-result-pass">' . __( 'Pass', 'dozent' ) . '</span>'; } else { $result = '<span class="dozent-pill dozent-pill-result-fail">' . __( 'Fail', 'dozent' ) . '</span>'; } } $output = "<div class='student-name dozent-d-flex dozent-align-flex-start'> {$avatar} <strong class='flex-grow-1'> <a href='{$profile_url}' target='_blank'> {$user->display_name} </a> </strong> {$result} </div>"; $output .= "<p class='dozent-text-muted dozent-small'> {$takes_time} </p>"; return $output; } if ( $column === 'status' ) { $status = dozent_array_get( $cell_data, dozent_attempt_statuses() ); $output = "<span class='dozent-pill dozent-pill-status-{$cell_data}'> {$status} </span>"; return $output; } if ( $column === 'buttons' ) { $review_url = dozent_get_dashboard_permalink( 'quiz-attempts/attempt-review' ); $review_url = add_query_arg( [ 'attempt_id' => $attempt_id ], $review_url ); return sprintf( "<a href='%s' class='dozent-btn dozent-btn-primary'> <i class='dicon-check'></i> " . __( 'Review', 'dozent' ) . " </a>", $review_url ); } return $cell_data; } /** * Review Quiz Attempt * * * @since DozentLMS 1.0.0 */ public function review_attempt() { dozent_checking_nonce(); global $wpdb; $review_btn = dozent_input_text( 'review_btn' ); $attempt_id = (int) dozent_input_text( 'attempt_id' ); $attempt = dozent_get_attempts( [ 'id' => $attempt_id ], true )->results; if ( $review_btn === 'review' ) { //Review Attempt $answers = dozent_input_array_field( 'answers' ); $user_id = get_current_user_id(); if ( dozent_count( $answers ) ) { foreach ( $answers as $answer_id => $answer ) { $data = [ 'earned_scores' => dozent_array_get( 'review_score', $answer ), 'is_correct' => (int) dozent_array_get( 'is_correct', $answer ), ]; $wpdb->update( $wpdb->dozent_quiz_answers, $data, [ 'id' => $answer_id ] ); } /** * Update attempt data */ $total_scores = $attempt->total_scores; $earned_scores = $wpdb->get_var( "SELECT SUM(earned_scores) AS earned_scores FROM {$wpdb->dozent_quiz_answers} WHERE attempt_id = {$attempt_id} " ); $earned_percentage = ( $earned_scores > 0 && $total_scores > 0 ) ? ( ( $earned_scores * 100 ) / $total_scores ) : 0; $passed = $earned_percentage >= $attempt->passing_percent ? 1 : 0; $review_data = [ 'reviewer_id' => $user_id, 'earned_scores' => $earned_scores, 'earned_percent' => $earned_percentage, 'status' => 'finished', 'is_reviewed' => 1, 'reviewed_at' => dozent_mysql_time(), 'passed' => $passed, ]; $wpdb->update( $wpdb->dozent_quiz_attempts, $review_data, [ 'id' => $attempt_id ] ); /** * Fire action after quiz attempt review finished * * @since DozentLMS 1.0.0 * * @param int $attempt_id Attempt ID */ do_action( 'dozent_quiz_attempt_review_after', $attempt_id ); dozent_set_flash_message( __( 'Attempt has been reviewed', 'dozent' ) ); } } /** * Delete Review and sync with quiz. */ if ( $review_btn === 'delete' ) { $wpdb->delete( $wpdb->dozent_quiz_attempts, [ 'id' => $attempt_id ] ); $wpdb->delete( $wpdb->dozent_quiz_answers, [ 'attempt_id' => $attempt_id ] ); dozent_complete_content( $attempt->quiz_id, $attempt->user_id, 'delete' ); /** * Fire action after quiz attempt deleted * * @since DozentLMS 1.0.0 * * @param int $attempt_id Attempt ID */ do_action( 'dozent_quiz_attempt_deleted', $attempt_id ); dozent_set_flash_message( __( 'Attempt has been deleted', 'dozent' ) ); dozent_redirect( dozent_get_dashboard_permalink( "quiz-attempts/quizzes/?course_id={$attempt->course_id}" ) ); } dozent_redirect(); } }
Methods
- __construct
- attempt_view — View attempt detail
- dozent_quiz_add_question — Quiz Add Question
- dozent_quiz_update_question — Update quiz question
- dozent_save_quiz — Add Lecture Action
- load_edit_question_modal
- load_quiz_editor
- question_option_delete — Delete Quiz Question Option
- quiz_attempting — Check if user attempting to any question right now.
- quiz_load_edit — Load Quiz Edit Form
- quiz_question_delete
- review_attempt — Review Quiz Attempt
- sort_quiz_questions — Sort quiz question
- start_quiz — Start Quiz
- submit_question
- table_attempts_for_review_column
- table_dozent_course_has_quizzes_column
- table_quiz_attempts_column — Filter default column data for Quiz Attempts Table
- table_quiz_attempts_courses_column