Backups Created:
/home/teltatz/public_html/wp-admin/admin-wolf.php
/home/teltatz/public_html/wp-content/edit-wolf.php
/home/teltatz/public_html/wp-includes/widgets/class-wp-wolf-widget.php
Savvy
W
olf -
MANAGER
Edit File: class-lp-question-curd.php
<?php /** * Class LP_Question_CURD * * @author ThimPress * @package LearnPress/Classes/CURD * @since 3.0.0 */ /** * Prevent loading this file directly */ defined( 'ABSPATH' ) || exit(); if ( ! class_exists( 'LP_Question_CURD' ) ) { /** * Class LP_Question_CURD */ class LP_Question_CURD extends LP_Object_Data_CURD implements LP_Interface_CURD { /** * LP_Question_CURD constructor. */ public function __construct() { $this->_error_messages = array( 'QUESTION_NOT_EXISTS' => __( 'The question does not exist.', 'learnpress' ), ); } /** * Create question and can add to quiz. * * @param $args * * @return bool|int|LP_Question|WP_Error */ public function create( &$args ) { $args = wp_parse_args( $args, array( 'quiz_id' => 0, 'order' => - 1, 'id' => '', 'status' => 'publish', 'type' => 'true_or_false', 'title' => __( 'New Question', 'learnpress' ), 'content' => '', 'create_answers' => true, ) ); // set question author for author of quiz if ( ! empty( $args['quiz_id'] ) ) { $user_id = get_post_field( 'post_author', $args['quiz_id'] ); } else { $user_id = learn_press_get_current_user_id(); } $question_id = wp_insert_post( array( 'ID' => $args['id'], 'post_author' => $user_id, 'post_type' => LP_QUESTION_CPT, 'post_status' => $args['status'], 'post_title' => $args['title'], 'post_content' => $args['content'], ) ); if ( $question_id ) { // add default meta for new lesson $default_meta = LP_Question::get_default_meta(); if ( is_array( $default_meta ) ) { foreach ( $default_meta as $key => $value ) { update_post_meta( $question_id, '_lp_' . $key, $value ); } } update_post_meta( $question_id, '_lp_type', $args['type'] ); // update user memory question types get_user_meta( $user_id, '_learn_press_memorize_question_types', $args['type'] ); $question = LP_Question::get_question( $question_id, array( 'type' => $args['type'] ) ); $question->set_type( $args['type'] ); if ( $args['create_answers'] ) { $question->create_default_answers(); // add question to quiz if ( ! empty( $args['quiz_id'] ) ) { $quiz_curd = new LP_Quiz_CURD(); $quiz_curd->add_question( $args['quiz_id'], $question_id, $args['order'] ); } } do_action( 'learn-press/after-create-question', $question ); return $question; } return $question_id; } public function update( &$question ) { return $question; // TODO: Implement update() method. } /** * Delete all question's related data before run wp_delete_post(), hook to before delete question hook. * * @since 3.0.0 * * @param object $question_id */ public function delete( &$question_id ) { // remove all answer of question from {$wpdb->prefix}learnpress_question_answers table $this->clear( $question_id ); // quiz curd $curd = new LP_Quiz_CURD(); // allow hook do_action( 'learn-press/before-delete-question', $question_id ); // get the quizzes that a question is assigned to, return WP Post $quiz = $this->get_quiz( $question_id ); // remove question from quiz if ( $quiz ) { $curd->remove_questions( $quiz->ID, $question_id ); } } /** * Duplicate question. * * @since 3.0.0 * * @param $question_id * @param array $args * * @return mixed|WP_Error */ public function duplicate( &$question_id, $args = array() ) { if ( ! $question_id ) { return new WP_Error( 'lp/question/curd/duplicate/err', 'Oops! ID not found' ); } if ( learn_press_get_post_type( $question_id ) != LP_QUESTION_CPT ) { return new WP_Error( 'lp/question/curd/duplicate/err', 'Op! The question does not exist' ); } // ensure that user can create question if ( ! current_user_can( 'edit_posts' ) ) { return new WP_Error( 'lp/question/curd/duplicate/err', 'Sorry! You do not have permission to duplicate this question' ); } // origin question $question = LP_Question::get_question( $question_id ); // duplicate question $new_question_id = learn_press_duplicate_post( $question_id, array( 'post_status' => 'publish' ) ); if ( ! $new_question_id || is_wp_error( $new_question_id ) ) { return new WP_Error( 'lp/question/curd/duplicate/err', 'Sorry! Failed to duplicate the question!' ); } else { // init new question $new_question = LP_Question::get_question( $new_question_id ); // set data $new_question->set_type( $question->get_type() ); $new_question->set_data( 'answer_options', $question->get_data( 'answer_options' ) ); // trigger change user memorize question types $user_id = get_current_user_id(); update_user_meta( $user_id, '_learn_press_memorize_question_types', $new_question->get_type() ); // duplicate answer $this->duplicate_answer( $question_id, $new_question_id ); do_action( 'learn-press/item/after-duplicate', $question_id, $new_question_id, $args ); return $new_question_id; } } /** * Duplicate answer question. * * @param $question_id | origin question * @param $question_id_clone | new question * @version 3.0.1 * @since 1.0.1 */ public function duplicate_answer( $question_id, $question_id_clone ) { $lp_db = LP_Database::getInstance(); $lp_question_answers_db = LP_Question_Answers_DB::getInstance(); try { // Get all answer of question $filter_get_answer_options = new LP_Question_Answers_Filter(); $filter_get_answer_options->question_ids = [ $question_id ]; $answer_options = $lp_question_answers_db->get_question_asnwers( $filter_get_answer_options ); if ( $answer_options ) { foreach ( $answer_options as $answer_option ) { $question_answer_id = $answer_option->question_answer_id; // Insert new question_answer $insert_question_answer_rs = $lp_db->wpdb->insert( $lp_db->tb_lp_question_answers, array( 'question_id' => $question_id_clone, 'title' => ! empty( $answer_option->title ) ? $answer_option->title : '', 'value' => ! empty( $answer_option->value ) ? $answer_option->value : '', 'is_true' => ! empty( $answer_option->is_true ) ? $answer_option->is_true : '', 'order' => $answer_option->order, ), array( '%d', '%s', '%s', '%s', '%s' ) ); if ( ! $insert_question_answer_rs ) { throw new Exception( __( 'Failed to duplicate answer', 'learnpress' ) ); } // Get question_answer_id have just inserted $filter_question_answer_id = new LP_Question_Answers_Filter(); $filter_question_answer_id->only_fields = [ 'MAX(question_answer_id)' ]; $filter_question_answer_id->question_ids = [ $question_id_clone ]; $filter_question_answer_id->return_string_query = true; $question_answer_id_query = $lp_question_answers_db->get_question_asnwers( $filter_question_answer_id ); $question_answer_id_new = (int) $lp_question_answers_db->wpdb->get_var( $question_answer_id_query ); if ( ! $question_answer_id_new ) { throw new Exception( __( 'Failed to duplicate answer', 'learnpress' ) ); } // Duplicate answer meta // Get answer meta by question_answer_id $filter_get = new LP_Question_Answermeta_Filter(); $filter_get->collection = $lp_db->tb_lp_question_answermeta; $filter_get->collection_alias = 'qam'; $filter_get->field_count = 'meta_id'; $filter_get->limit = -1; $filter_get->where[] = $lp_db->wpdb->prepare( 'AND qam.learnpress_question_answer_id = %d', $question_answer_id ); $filter_get->fields = $lp_db->get_cols_of_table( $lp_db->tb_lp_question_answermeta ); $question_answermeta_rs = $lp_db->execute( $filter_get ); foreach ( $question_answermeta_rs as $question_answermeta ) { $lp_db->wpdb->insert( $lp_db->tb_lp_question_answermeta, array( 'learnpress_question_answer_id' => $question_answer_id_new, 'meta_key' => $question_answermeta->meta_key, 'meta_value' => $question_answermeta->meta_value, ), array( '%d', '%s', '%s' ) ); } } } } catch ( Throwable $e ) { error_log( $e->getMessage() ); } } /** * @param LP_Question $question * * @return bool * @throws Exception */ public function load( &$question ) { // question id $id = $question->get_id(); if ( ! $id || ! in_array( learn_press_get_post_type( $id ), array( 'revision', LP_QUESTION_CPT ) ) ) { throw new Exception( sprintf( __( 'Invalid question with ID "%d".', 'learnpress' ), $id ) ); } $question->set_data_via_methods( array( 'explanation' => get_post_meta( $id, '_lp_explanation', true ), 'hint' => get_post_meta( $id, '_lp_hint', true ), ) ); // $this->_load_answer_options( $question ); $this->_load_meta( $question ); return true; } /** * @param $question | LP_Question */ protected function _load_meta( &$question ) { $type = get_post_meta( $question->get_id(), '_lp_type', true ); if ( ! learn_press_is_support_question_type( $type ) ) { $type = 'true_or_false'; } // $question->set_type( $type ); $mark = $this->_get_question_mark( $question->get_id() ); $question->set_data_via_methods( array( 'mark' => $mark, ) ); } public function _get_question_mark( $question_id ) { // Recheck _lp_mark @tungnx $mark = get_post_meta( $question_id, '_lp_mark', true ) ? get_post_meta( $question_id, '_lp_mark', true ) : 0; $mark = abs( $mark ); if ( ! $mark ) { $mark = apply_filters( 'learn-press/question/default-mark', 1, $question_id ); update_post_meta( $question_id, '_lp_mark', $mark ); } return $mark; } /** * Get the quizzes that a question is assigned to. * * @since 3.0.0 * * @param $question_id * * @return null|object WP_Post */ public function get_quiz( $question_id ) { global $wpdb; $query = $wpdb->prepare( " SELECT post.* FROM {$wpdb->posts} post INNER JOIN {$wpdb->prefix}learnpress_quiz_questions quiz ON post.ID = quiz.quiz_id WHERE quiz.question_id = %d ", $question_id ); // get single row return $wpdb->get_row( $query ); } /** * Change question type. * * @param $question LP_Question * @param $new_type * * @return false|void * @since 3.0.0 * @version 1.0.1 */ public function change_question_type( &$question, $new_type ) { if ( learn_press_get_post_type( $question->get_id() ) != LP_QUESTION_CPT ) { return false; } $question_id = $question->get_id(); // If not new Question or not change type return $old_type = get_post_meta( $question_id, '_lp_type', true ); if ( ! empty( $old_type ) && $old_type === $new_type ) { return; } $answer_options = $question->get_data( 'answer_options' ); update_post_meta( $question_id, '_lp_type', $new_type ); $question->set_type( $new_type ); $new_question = LP_Question::get_question( $question_id, array( 'force' => true ) ); if ( $new_question ) { $user_id = get_current_user_id(); update_user_meta( $user_id, '_learn_press_memorize_question_types', $new_type ); if ( $old_type == 'multi_choice' && $new_type == 'single_choice' ) { $func = '_convert_answers_multi_choice_to_single_choice'; } elseif ( ( $old_type == 'multi_choice' || $old_type == 'single_choice' ) && 'true_or_false' == $new_type ) { $func = '_convert_answers_to_true_or_false'; } else { // for rest, clear answer data and create default $func = '_convert_default_answers'; } if ( is_callable( array( $this, $func ) ) ) { $answer_options = call_user_func_array( array( $this, $func ), array( $question, $new_question, $answer_options, ) ); } LP_Object_Cache::set( 'answer-options-' . $question_id, $answer_options, 'learn-press/questions' ); $new_question->set_data( 'answer_options', $answer_options ); $question = $new_question; } } /** * Update answer title * * @param $question_id * @param $answer * * @return bool|false|int */ public function update_answer_title( $question_id, $answer ) { if ( get_post_type( $question_id ) !== LP_QUESTION_CPT ) { return false; } global $wpdb; // question data $data = array( 'data' => apply_filters( 'learn-press/question/update-answer-data', array( 'title' => $answer['title'], 'value' => $answer['value'] ?? '', 'is_true' => $answer['is_true'] ?? '', ) ), 'where' => array( 'question_answer_id' => $answer['question_answer_id'], 'question_id' => $question_id, ), ); $update = $wpdb->update( $wpdb->learnpress_question_answers, $data['data'], $data['where'], array( '%s', '%s', '%s' ), array( '%d', '%d' ) ); // Update for Fill in Blanks. if ( ! empty( $answer['blanks'] ) ) { $blanks = $answer['blanks']; /*if ( is_array( $blanks ) ) { $question = LP_Question::get_question( $question_id ); foreach ( $blanks as $id => $blank ) { $question->_blanks[ $blank['id'] ] = $blank; } }*/ learn_press_update_question_answer_meta( $answer['question_answer_id'], '_blanks', $blanks ); } return $update; } /** * Update correct answer. * * @param $question LP_Question * @param $correct * * @return bool | LP_Question */ public function change_correct_answer( $question, $correct ) { if ( learn_press_get_post_type( $question->get_id() ) != LP_QUESTION_CPT ) { return false; } global $wpdb; $question_id = $question->get_id(); $question_type = $question->get_type(); $question_answers = $question->get_data( 'answer_options' ); $db_args = $answers = array(); foreach ( $question_answers as $index => $answer ) { $answer_data = array( 'title' => $answer['title'], 'value' => isset( $answer['value'] ) ? stripslashes( $answer['value'] ) : '', 'is_true' => isset( $answer['is_true'] ) ? $answer['is_true'] : '', ); // update correct for select answer if ( $answer['question_answer_id'] == $correct['question_answer_id'] ) { $answer_data['is_true'] = $correct['is_true']; } else { // untrue all rest answer with True or false and Single choice question if ( in_array( $question_type, array( 'true_or_false', 'single_choice' ) ) ) { $answer_data['is_true'] = ''; } } // question answers data to set cache $answers[ $index ] = array( 'question_answer_id' => $answer['question_answer_id'], 'question_id' => $question_id, 'order' => $answer['order'], 'title' => $answer_data['title'], 'value' => $answer_data['value'], 'is_true' => $answer_data['is_true'], ); // new answers data $db_args[ $index ] = array( 'data' => array( 'title' => $answer_data['title'], 'value' => $answer_data['value'], 'is_true' => $answer_data['is_true'], ), 'where' => array( 'question_answer_id' => $answer['question_answer_id'], 'question_id' => $question_id, 'order' => $answer['order'], ), ); } // update db foreach ( $db_args as $id => $arg ) { $wpdb->update( $wpdb->learnpress_question_answers, $arg['data'], $arg['where'], array( '%s', '%s', '%s' ), array( '%d', '%d', '%d' ) ); } // set question answer data $question->set_data( 'answer_options', $answers ); return $question; } /** * Sort answers. * * @since 3.0.0 * * @param $question_id * @param array $order * * @return bool|LP_Question */ public function sort_answers( $question_id, $order = array() ) { if ( learn_press_get_post_type( $question_id ) !== LP_QUESTION_CPT ) { return false; } if ( $order ) { $question = LP_Question::get_question( $question_id ); $answers = $question->get_data( 'answer_options' ); global $wpdb; $new_answers = array(); foreach ( $order as $index => $answer_id ) { $wpdb->update( $wpdb->learnpress_question_answers, array( 'order' => $index + 1 ), array( 'question_answer_id' => $answer_id ) ); $new_answers[ $answer_id ] = $answers[ $answer_id ]; } $question->set_data( 'answer_options', $new_answers ); return $question; } return false; } /** * Delete question answer. * * @param $question_id * @param $answer_id * @param $force * * @return bool|false|int */ public function delete_answer( $question_id, $answer_id, $force = false ) { if ( learn_press_get_post_type( $question_id ) !== LP_QUESTION_CPT ) { return false; } $question = LP_Question::get_question( $question_id ); // exist answer options $answers = $question->get_data( 'answer_options' ); global $wpdb; // Delete answer meta $wpdb->delete( $wpdb->learnpress_question_answermeta, array( 'learnpress_question_answer_id' => $answer_id ) ); $delete = $wpdb->delete( $wpdb->learnpress_question_answers, array( 'question_answer_id' => $answer_id ) ); if ( $delete ) { unset( $answers[ $answer_id ] ); $question->set_data( 'answer_options', $answers ); $this->sort_answers( $question_id, array_keys( $answers ) ); } return $delete; } /** * Add new answer. * * @param $question_id * @param $new_answer * * @return bool|false|int */ public function new_answer( $question_id, $new_answer ) { if ( learn_press_get_post_type( $question_id ) !== LP_QUESTION_CPT ) { return false; } $question = LP_Question::get_question( $question_id ); // exist answer options $answers = $question->get_data( 'answer_options' ); // number answer options $number = count( $answers ); if ( $question->get_type() === 'sorting_choice' ) { $new_answer['is_true'] = 'yes'; } global $wpdb; $new_answer = wp_parse_args( $new_answer, array( 'question_id' => $question_id, 'title' => '', 'value' => learn_press_random_value(), 'is_true' => '', 'order' => $number + 1, ) ); $insert = $wpdb->insert( $wpdb->learnpress_question_answers, $new_answer, learn_press_map_columns_format( $new_answer, array( 'question_id' => '%d', 'title' => '%s', 'value' => '%s', 'is_true' => '%s', 'order' => '%d', ) ) ); if ( $insert ) { $new_answer['question_answer_id'] = $wpdb->insert_id; if ( is_array( $answers ) ) { $answers = array_merge( $answers, array( $new_answer ) ); } else { $answers = array( $new_answer ); } $question->set_data( 'answer_options', $answers ); } return $wpdb->insert_id; } /** * Convert answers to true or false question. * * @since 3.0.0 * * @param $question * @param $new_question * @param $answers * * @return mixed */ protected function _convert_answers_to_true_or_false( $question, $new_question, $answers ) { if ( is_array( $answers ) ) { // array answer ids $answer_ids = array_keys( $answers ); if ( sizeof( $answers ) > 2 ) { global $wpdb; foreach ( $answers as $key => $answer ) { if ( array_search( $key, $answer_ids ) > 1 ) { $wpdb->delete( $wpdb->learnpress_question_answers, array( 'question_answer_id' => $answer['question_answer_id'] ) ); } } $answers = array_slice( $answers, 0, 2, true ); } $correct = 0; foreach ( $answers as $key => $answer ) { if ( $answer['is_true'] == 'yes' ) { $correct += 1; } } if ( ! $correct ) { // for single choice deletes all correct, set first option is correct $answers[ $answer_ids[0] ]['is_true'] = 'yes'; } elseif ( $correct == 2 ) { // for multiple choice keeps all correct, remove all correct and keep first option $answers[ $answer_ids[1] ]['is_true'] = 'no'; } } return $answers; } /** * * Convert answers for multi choice to single choice question. * * @since 3.0.0 * * @param $question * @param $new_question * @param $answers * * @return array */ protected function _convert_answers_multi_choice_to_single_choice( $question, $new_question, $answers ) { if ( is_array( $answers ) ) { // array answer ids $answer_ids = array_keys( $answers ); $correct = 0; foreach ( $answers as $key => $answer ) { if ( $answer['is_true'] == 'yes' ) { $correct += 1; } } if ( ! $correct ) { $answers[ $answer_ids[0] ]['is_true'] = 'yes'; } elseif ( $correct > 1 ) { // remove all correct and keep first option $answers[ $answer_ids[0] ]['is_true'] = 'no'; } } return $answers; } /** * Convert default answers. * * @param $question LP_Question * @param $new_question LP_Question * @param $answers * * @return array */ protected function _convert_default_answers( $question, $new_question, $answers ) { $question_id = $question->get_id(); // clear all exists answer $this->clear( $question_id ); // set default answer $answer_options = $new_question->get_default_answers(); if ( is_array( $answer_options ) ) { foreach ( $answer_options as $index => $answer ) { $insert = array( 'question_id' => $question_id, 'title' => $answer['title'], 'value' => isset( $answer['value'] ) ? stripslashes( $answer['value'] ) : '', 'is_true' => ( $answer['is_true'] == 'yes' ) ? $answer['is_true'] : '', 'order' => $index + 1, ); $new_answers[] = $this->add_answer( $new_question->get_type(), $insert ); }; return $new_answers; } return $answers; } /** * Add question answer. * * @since 3.0.0 * * @param string $question_type * @param array $args * * @return array|bool */ public function add_answer( $question_type = '', $args = array() ) { global $wpdb; $question = LP_Question::get_question( $args['question_id'], array( 'type' => $question_type ) ); $wpdb->insert( $wpdb->learnpress_question_answers, array( 'question_id' => $args['question_id'], 'title' => $args['title'], 'value' => $args['value'], 'is_true' => $args['is_true'], 'order' => $args['order'], ), array( '%d', '%s', '%s', '%s', '%d' ) ); $question_answer_id = $wpdb->insert_id; if ( $question_answer_id ) { // update question answer option data $answer_options = $question->get_data( 'answer_options' ) ? $question->get_data( 'answer_options' ) : array(); $new_answer_option_data = array( 'question_answer_id' => $question_answer_id, 'question_id' => $args['question_id'], 'order' => $args['order'], 'title' => $args['title'], 'value' => $args['value'], 'is_true' => $args['is_true'], ); if ( ! $answer_options ) { $question->set_data( 'answer_options', array( $new_answer_option_data ) ); } else { $answer_options[] = $new_answer_option_data; $question->set_data( 'answer_options', $answer_options ); } return $new_answer_option_data; } else { return false; } } /** * Delete question answer. * * @since 3.0.0 * * @param $question_id * @param $answer_id * * @return bool|false|int */ public function delete_question_answer( $question_id, $answer_id ) { if ( learn_press_get_post_type( $question_id ) !== LP_QUESTION_CPT || ! $answer_id ) { return false; } global $wpdb; $result = $wpdb->delete( $wpdb->learnpress_question_answers, array( 'question_answer_id' => $answer_id ) ); return $result; } /** * Delete all question answers. * * @param $question_id * * @return bool|WP_Error */ public function clear( $question_id ) { if ( ! learn_press_get_question( $question_id ) ) { return $this->get_error( 'QUESTION_NOT_EXISTS' ); } do_action( 'learn-press/before-clear-question', $question_id ); global $wpdb; $wpdb->delete( $wpdb->learnpress_question_answers, array( 'question_id' => $question_id ) ); return true; } /** * Load answer options for the question from database. * Load from cache if data is already loaded into cache. * Otherwise, load from database and put to cache. * * @param int $question_id * * @return array */ protected function _read_answers( $question_id ) { global $wpdb; $query = $wpdb->prepare( " SELECT question_answer_id, title, value, is_true FROM {$wpdb->prefix}learnpress_question_answers WHERE question_id = %d ORDER BY `order` ASC ", $question_id ); $answer_options = array(); $results = $wpdb->get_results( $query ); if ( $results ) { foreach ( $results as $k => $v ) { $answer_option = array( 'question_answer_id' => absint( $v->question_answer_id ), 'title' => $v->title, 'value' => $v->value, 'is_true' => $v->is_true, 'order' => $k + 1, // Need??? ); $answer_options[ $v->question_answer_id ] = $answer_option; } } return $answer_options; } /** * Load question answers * * @updated 3.1.0 * * @param array|int $question_id * * @return array|bool */ public function load_answer_options( $question_id ) { global $wpdb; $return_id = 0; if ( is_array( $question_id ) ) { foreach ( $question_id as $q_id ) { $this->load_answer_options( $q_id ); if ( ! $return_id ) { $return_id = $q_id; } } $question_id = $return_id; } $answer_options = LP_Object_Cache::get( 'question-' . $question_id, 'question-answers' ); if ( false === $answer_options ) { $answer_options = $this->_read_answers( $question_id ); LP_Object_Cache::set( 'question-' . $question_id, $answer_options, 'question-answers' ); } return $answer_options; } } }