From 6dc425104f4434c7cb7b1f0628f5d40e73d86440 Mon Sep 17 00:00:00 2001 From: b-l-i-n-d Date: Fri, 24 Apr 2026 16:01:15 +0600 Subject: [PATCH 1/3] feat: Filter v4 questions if learning mode is legacy --- classes/Utils.php | 70 +++++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/classes/Utils.php b/classes/Utils.php index 6b6a719aed..7c5745c643 100644 --- a/classes/Utils.php +++ b/classes/Utils.php @@ -5214,17 +5214,22 @@ public function get_quiz_option( $post_id = 0, $option_key = '', $default = fals */ public function get_questions_by_quiz( $quiz_id = 0 ) { $quiz_id = $this->get_post_id( $quiz_id ); - global $wpdb; - $questions = $wpdb->get_results( - $wpdb->prepare( - "SELECT * - FROM {$wpdb->prefix}tutor_quiz_questions - WHERE quiz_id = %d - ORDER BY question_order ASC - ", - $quiz_id - ) + $where = array( + 'quiz_id' => $quiz_id, + ); + + if ( $this->is_legacy_learning_mode() ) { + $types = array( 'scale', 'coordinates', 'draw_image', 'pin_image', 'puzzle' ); + $where['question_type'] = array( 'NOT IN', $types ); + } + + $questions = QueryHelper::get_all( + 'tutor_quiz_questions', + $where, + 'question_order', + -1, + 'ASC' ); $questions = apply_filters( 'tutor_get_questions_by_quiz', $questions, $quiz_id ); @@ -5583,32 +5588,37 @@ public function get_random_questions_by_quiz( $quiz_id = 0 ) { $questions_order = $this->get_quiz_option( get_the_ID(), 'questions_order', 'rand' ); - $order_by = ''; - if ( 'rand' === $questions_order ) { - $order_by = 'ORDER BY RAND()'; - } elseif ( 'asc' === $questions_order ) { - $order_by = 'ORDER BY question_id ASC'; + $order_by = 'RAND()'; + $order = ''; + + if ( 'asc' === $questions_order ) { + $order_by = 'question_id'; + $order = 'ASC'; } elseif ( 'desc' === $questions_order ) { - $order_by = 'ORDER BY question_id DESC'; + $order_by = 'question_id'; + $order = 'DESC'; } elseif ( 'sorting' === $questions_order ) { - $order_by = 'ORDER BY question_order ASC'; + $order_by = 'question_order'; + $order = 'ASC'; } - $limit = ''; - if ( $total_questions ) { - $limit = "LIMIT {$total_questions} "; + $where = array( + 'quiz_id' => $quiz_id, + ); + + if ( $this->is_legacy_learning_mode() ) { + $types = array( 'scale', 'coordinates', 'draw_image', 'pin_image', 'puzzle' ); + $where['question_type'] = array( 'NOT IN', $types ); } - $questions = $wpdb->get_results( - $wpdb->prepare( - "SELECT * - FROM {$wpdb->prefix}tutor_quiz_questions - WHERE quiz_id = %d - {$order_by} - {$limit} - ", - $quiz_id - ) + $limit = $total_questions ? $total_questions : -1; + + $questions = QueryHelper::get_all( + 'tutor_quiz_questions', + $where, + $order_by, + $limit, + $order ); return $questions; From 0a1338202245366b5768d49991a77faea77721b0 Mon Sep 17 00:00:00 2001 From: b-l-i-n-d Date: Sun, 3 May 2026 22:18:16 +0600 Subject: [PATCH 2/3] refactor: replace hardcoded quiz question exclusion with a filterable mechanism to safely merge query conditions --- classes/Utils.php | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/classes/Utils.php b/classes/Utils.php index 7c5745c643..ab9e45dd67 100644 --- a/classes/Utils.php +++ b/classes/Utils.php @@ -5219,9 +5219,20 @@ public function get_questions_by_quiz( $quiz_id = 0 ) { 'quiz_id' => $quiz_id, ); - if ( $this->is_legacy_learning_mode() ) { - $types = array( 'scale', 'coordinates', 'draw_image', 'pin_image', 'puzzle' ); - $where['question_type'] = array( 'NOT IN', $types ); + $exclude_types = apply_filters( 'tutor_filter_unsupported_quiz_question_types', array() ); + + /** + * Safely append excluded question types to the database query conditions. + * If a 'NOT IN' condition already exists for question types, it merges the new types + * to prevent overwriting previous exclusions. Otherwise, it creates a new condition. + */ + if ( count( $exclude_types ) ) { + $exclude_types = array_unique( $exclude_types ); + if ( isset( $where['question_type'] ) && is_array( $where['question_type'] ) && 'NOT IN' === $where['question_type'][0] ) { + $where['question_type'][1] = array_unique( array_merge( $where['question_type'][1], $exclude_types ) ); + } else { + $where['question_type'] = array( 'NOT IN', $exclude_types ); + } } $questions = QueryHelper::get_all( @@ -5606,9 +5617,20 @@ public function get_random_questions_by_quiz( $quiz_id = 0 ) { 'quiz_id' => $quiz_id, ); - if ( $this->is_legacy_learning_mode() ) { - $types = array( 'scale', 'coordinates', 'draw_image', 'pin_image', 'puzzle' ); - $where['question_type'] = array( 'NOT IN', $types ); + $exclude_types = apply_filters( 'tutor_filter_unsupported_quiz_question_types', array() ); + + /** + * Safely append excluded question types to the database query conditions. + * If a 'NOT IN' condition already exists for question types, it merges the new types + * to prevent overwriting previous exclusions. Otherwise, it creates a new condition. + */ + if ( count( $exclude_types ) ) { + $exclude_types = array_unique( $exclude_types ); + if ( isset( $where['question_type'] ) && is_array( $where['question_type'] ) && 'NOT IN' === $where['question_type'][0] ) { + $where['question_type'][1] = array_unique( array_merge( $where['question_type'][1], $exclude_types ) ); + } else { + $where['question_type'] = array( 'NOT IN', $exclude_types ); + } } $limit = $total_questions ? $total_questions : -1; From ca30d83801e47ef184c54c2c53da2394e7a57327 Mon Sep 17 00:00:00 2001 From: b-l-i-n-d Date: Tue, 5 May 2026 13:22:51 +0600 Subject: [PATCH 3/3] refactor: Refactor `get_questions_by_quiz` method --- classes/Utils.php | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/classes/Utils.php b/classes/Utils.php index ab9e45dd67..7d4d6ec14a 100644 --- a/classes/Utils.php +++ b/classes/Utils.php @@ -5219,20 +5219,16 @@ public function get_questions_by_quiz( $quiz_id = 0 ) { 'quiz_id' => $quiz_id, ); - $exclude_types = apply_filters( 'tutor_filter_unsupported_quiz_question_types', array() ); - /** - * Safely append excluded question types to the database query conditions. - * If a 'NOT IN' condition already exists for question types, it merges the new types - * to prevent overwriting previous exclusions. Otherwise, it creates a new condition. + * Filter to exclude quiz question types + * + * @since 4.0.0 */ - if ( count( $exclude_types ) ) { - $exclude_types = array_unique( $exclude_types ); - if ( isset( $where['question_type'] ) && is_array( $where['question_type'] ) && 'NOT IN' === $where['question_type'][0] ) { - $where['question_type'][1] = array_unique( array_merge( $where['question_type'][1], $exclude_types ) ); - } else { - $where['question_type'] = array( 'NOT IN', $exclude_types ); - } + $exclude_types = apply_filters( 'tutor_filter_unsupported_quiz_question_types', array() ); + + if ( tutor_utils()->count( $exclude_types ) ) { + $exclude_types = array_unique( $exclude_types ); + $where['question_type'] = array( 'NOT IN', $exclude_types ); } $questions = QueryHelper::get_all( @@ -5619,18 +5615,9 @@ public function get_random_questions_by_quiz( $quiz_id = 0 ) { $exclude_types = apply_filters( 'tutor_filter_unsupported_quiz_question_types', array() ); - /** - * Safely append excluded question types to the database query conditions. - * If a 'NOT IN' condition already exists for question types, it merges the new types - * to prevent overwriting previous exclusions. Otherwise, it creates a new condition. - */ - if ( count( $exclude_types ) ) { - $exclude_types = array_unique( $exclude_types ); - if ( isset( $where['question_type'] ) && is_array( $where['question_type'] ) && 'NOT IN' === $where['question_type'][0] ) { - $where['question_type'][1] = array_unique( array_merge( $where['question_type'][1], $exclude_types ) ); - } else { - $where['question_type'] = array( 'NOT IN', $exclude_types ); - } + if ( tutor_utils()->count( $exclude_types ) ) { + $exclude_types = array_unique( $exclude_types ); + $where['question_type'] = array( 'NOT IN', $exclude_types ); } $limit = $total_questions ? $total_questions : -1; @@ -6496,7 +6483,7 @@ public function get_earning_statements( $user_id = 0, $filter_data = array() ) { * @since 1.1.2 * @since 4.0.0 Condition added for different monetizations. * - * @param int $price price. + * @param int $price price. * * @return int|string */