Quiz And Survey Master (Formerly Quiz Master Next) - Version 7.2.2

Version Description

(July 14, 2021) = * Feature: Implemented multiple fill in the blanks support. * Feature: Implemented new template variable %TIMER_SECONDS% to show left over seconds. * Feature: Implemented new option to limit number of questions per category. * Bug: Fixed issue with template variable %AMOUNT_INCORRECT%. * Bug: Fixed issue of undefined index notice of facebook app id. * Bug: Fixed issue with saving conditions in email and results tab. * Bug: Fixed issue of wordpress database error notice on fresh installation. * Bug: Fixed issue with validation on retake quiz

Download this release

Release Info

Developer expresstech
Plugin Icon 128x128 Quiz And Survey Master (Formerly Quiz Master Next)
Version 7.2.2
Comparing to
See all releases

Code changes from version 7.2.1 to 7.2.2

css/qsm-admin-question.css CHANGED
@@ -15,53 +15,62 @@
15
  margin-left: 5px;
16
  }
17
 
18
- #modal-7 {
 
19
  max-width: 500px;
20
  }
21
 
22
- #modal-7 hr {
 
23
  margin: 0 -30px;
24
  }
25
 
26
- #modal-7 header {
 
27
  margin: -10px 0 10px 0;
28
  }
29
 
30
- #modal-7 .qsm-popup__close {
 
31
  margin: -10px -10px 0 0;
32
  font-size: 20px;
33
  }
34
 
35
- #modal-7-title {
 
36
  color: gray;
37
  opacity: 70%;
38
  }
39
 
40
- #modal-7 footer .dashicons {
 
41
  font-size: 20px;
42
  margin-right: 3px;
43
  vertical-align: middle;
44
  margin-left: -10px;
45
  }
46
 
47
- #modal-7 .qsm-popup__container {
 
48
  max-width: 560px;
49
  padding-bottom: 20px;
50
  }
51
 
52
- .modal-7-table {
 
53
  font-size: 16px;
54
  }
55
 
56
- #modal-7 footer {
 
57
  margin-top: 15px;
58
  }
59
 
60
- .modal-7-table tr td {
 
61
  vertical-align: top;
62
  padding: 0 10px 5px 0
63
  }
64
-
65
  @media screen and (min-width:700px) {
66
  .question-controls {
67
  flex-direction: row;
15
  margin-left: 5px;
16
  }
17
 
18
+ #modal-7,
19
+ #modal-8 {
20
  max-width: 500px;
21
  }
22
 
23
+ #modal-7 hr,
24
+ #modal-8 hr {
25
  margin: 0 -30px;
26
  }
27
 
28
+ #modal-7 header,
29
+ #modal-8 header {
30
  margin: -10px 0 10px 0;
31
  }
32
 
33
+ #modal-7 .qsm-popup__close,
34
+ #modal-8 .qsm-popup__close {
35
  margin: -10px -10px 0 0;
36
  font-size: 20px;
37
  }
38
 
39
+ #modal-7-title,
40
+ #modal-8-title {
41
  color: gray;
42
  opacity: 70%;
43
  }
44
 
45
+ #modal-7 footer .dashicons,
46
+ #modal-8 footer .dashicons {
47
  font-size: 20px;
48
  margin-right: 3px;
49
  vertical-align: middle;
50
  margin-left: -10px;
51
  }
52
 
53
+ #modal-7 .qsm-popup__container,
54
+ #modal-8 .qsm-popup__container {
55
  max-width: 560px;
56
  padding-bottom: 20px;
57
  }
58
 
59
+ .modal-7-table,
60
+ .modal-8-table {
61
  font-size: 16px;
62
  }
63
 
64
+ #modal-7 footer,
65
+ #modal-8 footer {
66
  margin-top: 15px;
67
  }
68
 
69
+ .modal-7-table tr td,
70
+ .modal-8-table tr td {
71
  vertical-align: top;
72
  padding: 0 10px 5px 0
73
  }
 
74
  @media screen and (min-width:700px) {
75
  .question-controls {
76
  flex-direction: row;
css/qsm-admin.css CHANGED
@@ -325,10 +325,11 @@ span.qsm-quiz-name {
325
  border-bottom: 0;
326
  margin-top: 20px;
327
  background: #fff;
328
- padding: 16px;
329
  color: #007cba;
330
  font-weight: bold;
331
  position: relative;
 
332
  }
333
 
334
  .qsm-addon-news-ads .qsm-news-ads-title:before,
@@ -390,6 +391,15 @@ span.qsm-quiz-name {
390
  box-shadow: 0px 0px 5px 1px rgb(0 0 0 / 16%);
391
  }
392
 
 
 
 
 
 
 
 
 
 
393
  .qsm-addon-news-ads .qsm-info-widget:nth-child(2) .bundle-icon {
394
  background: #00b592;
395
  }
@@ -1935,7 +1945,8 @@ td.scheduled_time_start {
1935
  }
1936
 
1937
  .qsm-quiz-email-tab .qsm-show-all-variable-text,
1938
- .qsm-quiz-result-tab .qsm-show-all-variable-text {
 
1939
  position: fixed;
1940
  bottom: 20px;
1941
  right: 25px;
325
  border-bottom: 0;
326
  margin-top: 20px;
327
  background: #fff;
328
+ padding: 16px 24px;
329
  color: #007cba;
330
  font-weight: bold;
331
  position: relative;
332
+ font-size: 14px;
333
  }
334
 
335
  .qsm-addon-news-ads .qsm-news-ads-title:before,
391
  box-shadow: 0px 0px 5px 1px rgb(0 0 0 / 16%);
392
  }
393
 
394
+ .qsm-addon-news-ads .qsm-info-widget .bundle-icon img {
395
+ max-width: 40px;
396
+ max-height: 40px;
397
+ }
398
+
399
+ .qsm-addon-news-ads .qsm-info-widget:nth-child(4) .bundle-icon {
400
+ background: #2271b1;
401
+ }
402
+
403
  .qsm-addon-news-ads .qsm-info-widget:nth-child(2) .bundle-icon {
404
  background: #00b592;
405
  }
1945
  }
1946
 
1947
  .qsm-quiz-email-tab .qsm-show-all-variable-text,
1948
+ .qsm-quiz-result-tab .qsm-show-all-variable-text,
1949
+ #slack-integration .qsm-show-all-variable-text {
1950
  position: fixed;
1951
  bottom: 20px;
1952
  right: 25px;
js/qsm-admin-question.js CHANGED
@@ -391,6 +391,7 @@ var import_button;
391
  var featureImageID = $('.qsm-feature-image-id').val();
392
  var featureImageSrc = $('.qsm-feature-image-src').val();
393
  var answerType = $('#change-answer-editor').val();
 
394
 
395
  var answers = [];
396
  var $answers = jQuery('.answers-single');
@@ -454,6 +455,7 @@ var import_button;
454
  featureImageSrc: featureImageSrc,
455
  answers: answers,
456
  answerEditor: answerType,
 
457
  other_settings: advanced_option
458
  },
459
  {
@@ -674,6 +676,9 @@ var import_button;
674
  $('#' + index).val(value);
675
  }
676
  }
 
 
 
677
  });
678
  }
679
  CurrentElement.parents('.question').next('.questionElements').slideDown('slow');
@@ -839,6 +844,26 @@ var import_button;
839
  alert('Text/HTML Section cannot be empty');
840
  return false;
841
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
842
  }
843
  $('#save-edit-question-spinner').addClass('is-active');
844
  var model_html = $('#modal-1-content').html();
391
  var featureImageID = $('.qsm-feature-image-id').val();
392
  var featureImageSrc = $('.qsm-feature-image-src').val();
393
  var answerType = $('#change-answer-editor').val();
394
+ var matchAnswer = $('#match-answer').val();
395
 
396
  var answers = [];
397
  var $answers = jQuery('.answers-single');
455
  featureImageSrc: featureImageSrc,
456
  answers: answers,
457
  answerEditor: answerType,
458
+ matchAnswer: matchAnswer,
459
  other_settings: advanced_option
460
  },
461
  {
676
  $('#' + index).val(value);
677
  }
678
  }
679
+ if (index == 'matchAnswer') {
680
+ $('#match-answer').val(value);
681
+ }
682
  });
683
  }
684
  CurrentElement.parents('.question').next('.questionElements').slideDown('slow');
844
  alert('Text/HTML Section cannot be empty');
845
  return false;
846
  }
847
+ }
848
+ if (14 == questionElements.find('#question_type').val()) {
849
+ question_description = wp.editor.getContent('question-text').trim();
850
+ blanks = question_description.match(/%BLANK%/g);
851
+ options_length = $('.answer-text-div').length
852
+ if ($('#match-answer').val() == 'sequence') {
853
+ if (blanks == null || blanks.length != options_length) {
854
+ $('.modal-8-table').html('Number of <strong>%BLANK%</strong> should be equal to options for sequential matching');
855
+ MicroModal.show('modal-8');
856
+ return false;
857
+ }
858
+ } else {
859
+ if (blanks == null || options_length === 0) {
860
+ $('.modal-8-table').html('Atleast one <strong>%BLANK%</strong> and one option is required.');
861
+ MicroModal.show('modal-8');
862
+ return false;
863
+ }
864
+ }
865
+
866
+
867
  }
868
  $('#save-edit-question-spinner').addClass('is-active');
869
  var model_html = $('#modal-1-content').html();
js/qsm-quiz.js CHANGED
@@ -630,30 +630,7 @@ var QSMPageTimer;
630
 
631
  // On load code
632
  $(function () {
633
-
634
- // Legacy init.
635
- qmnInit();
636
-
637
- // Call main initialization.
638
- qsminstance = QSM.init();
639
-
640
- jQuery(".qsm-quiz-container").on("click", ".mlw_next", function () {
641
- if (quizType == 'paginated') {
642
- timer_ms = jQuery("input[name='timer_ms']").val();
643
- if (timer_ms == 0) {
644
- qsmTimerInterval = setInterval(qmnTimeTakenTimer, 1000);
645
- jQuery("input[name='timer_ms']").each(function () {
646
- var timems = qsmTimeInMS();
647
- jQuery(this).val(timems);
648
- });
649
- }
650
- }
651
- });
652
- });
653
-
654
- jQuery("input[name='timer_ms']").each(function () {
655
- var timems = qsmTimeInMS();
656
- jQuery(this).val(timems);
657
  });
658
  }(jQuery));
659
 
@@ -692,6 +669,27 @@ function qsmCheckMR(event, limit) {
692
  }
693
  }
694
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
695
  function qmnTimeTakenTimer() {
696
  var x = +jQuery('#timer').val();
697
  if (NaN === x) {
@@ -1237,14 +1235,8 @@ jQuery(function () {
1237
  success: function (response) {
1238
  parent_div.replaceWith(response);
1239
  //Reload the timer and pagination
1240
- QSM.init();
1241
- qmnInit();
1242
- QSM.initTimer(quiz_id);
1243
- jQuery("input[name='timer_ms']").each(function () {
1244
- var timems = qsmTimeInMS();
1245
- jQuery(this).val(timems);
1246
- });
1247
- setInterval(qmnTimeTakenTimer, 1000);
1248
  MathJax.Hub.queue.Push(["Typeset", MathJax.Hub]);
1249
 
1250
  // trigger fired on successfull retake quiz
630
 
631
  // On load code
632
  $(function () {
633
+ qmnDoInit();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
634
  });
635
  }(jQuery));
636
 
669
  }
670
  }
671
 
672
+ function qmnDoInit() {
673
+ // Legacy init.
674
+ qmnInit();
675
+
676
+ // Call main initialization.
677
+ qsminstance = QSM.init();
678
+
679
+ jQuery(".qsm-quiz-container").on("click", ".mlw_next", function () {
680
+ if (quizType == 'paginated') {
681
+ timer_ms = jQuery("input[name='timer_ms']").val();
682
+ if (timer_ms == 0) {
683
+ qsmTimerInterval = setInterval(qmnTimeTakenTimer, 1000);
684
+ jQuery("input[name='timer_ms']").each(function () {
685
+ var timems = qsmTimeInMS();
686
+ jQuery(this).val(timems);
687
+ });
688
+ }
689
+ }
690
+ });
691
+ }
692
+
693
  function qmnTimeTakenTimer() {
694
  var x = +jQuery('#timer').val();
695
  if (NaN === x) {
1235
  success: function (response) {
1236
  parent_div.replaceWith(response);
1237
  //Reload the timer and pagination
1238
+ qmnDoInit();
1239
+
 
 
 
 
 
 
1240
  MathJax.Hub.queue.Push(["Typeset", MathJax.Hub]);
1241
 
1242
  // trigger fired on successfull retake quiz
mlw_quizmaster2.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * Plugin Name: Quiz And Survey Master
4
  * Description: Easily and quickly add quizzes and surveys to your website.
5
- * Version: 7.2.1
6
  * Author: ExpressTech
7
  * Author URI: https://quizandsurveymaster.com/
8
  * Plugin URI: https://expresstech.io/
9
  * Text Domain: quiz-master-next
10
  *
11
  * @author QSM Team
12
- * @version 7.2.1
13
  * @package QSM
14
  */
15
 
@@ -41,7 +41,7 @@ class MLWQuizMasterNext {
41
  * @var string
42
  * @since 4.0.0
43
  */
44
- public $version = '7.2.1';
45
 
46
  /**
47
  * QSM Alert Manager Object
@@ -356,12 +356,24 @@ class MLWQuizMasterNext {
356
  */
357
  public function qsm_overide_old_setting_options() {
358
  $settings = (array) get_option( 'qmn-settings' );
 
 
 
359
  $facebook_app_id = $settings['facebook_app_id'];
 
360
  if ( $facebook_app_id == '483815031724529' ) {
361
  $settings['facebook_app_id'] = '594986844960937';
362
  update_option( 'qmn-settings', $settings );
363
  }
 
 
 
 
 
 
 
364
  }
 
365
  }
366
 
367
  global $mlwQuizMasterNext;
2
  /**
3
  * Plugin Name: Quiz And Survey Master
4
  * Description: Easily and quickly add quizzes and surveys to your website.
5
+ * Version: 7.2.2
6
  * Author: ExpressTech
7
  * Author URI: https://quizandsurveymaster.com/
8
  * Plugin URI: https://expresstech.io/
9
  * Text Domain: quiz-master-next
10
  *
11
  * @author QSM Team
12
+ * @version 7.2.2
13
  * @package QSM
14
  */
15
 
41
  * @var string
42
  * @since 4.0.0
43
  */
44
+ public $version = '7.2.2';
45
 
46
  /**
47
  * QSM Alert Manager Object
356
  */
357
  public function qsm_overide_old_setting_options() {
358
  $settings = (array) get_option( 'qmn-settings' );
359
+
360
+ if (isset($settings['facebook_app_id'])) {
361
+
362
  $facebook_app_id = $settings['facebook_app_id'];
363
+
364
  if ( $facebook_app_id == '483815031724529' ) {
365
  $settings['facebook_app_id'] = '594986844960937';
366
  update_option( 'qmn-settings', $settings );
367
  }
368
+ }
369
+ else{
370
+ $settings['facebook_app_id'] = '594986844960937';
371
+ update_option( 'qmn-settings', $settings );
372
+ }
373
+
374
+
375
  }
376
+
377
  }
378
 
379
  global $mlwQuizMasterNext;
php/admin/admin-results-page.php CHANGED
@@ -88,7 +88,7 @@ function qsm_results_overview_tab_content() {
88
  // Variables from delete result form.
89
  $mlw_delete_results_id = intval( $_POST['result_id'] );
90
  $mlw_delete_results_name = sanitize_text_field( $_POST['delete_quiz_name'] );
91
-
92
  // Updates table to mark results as deleted.
93
  $results = $wpdb->update(
94
  $wpdb->prefix . 'mlw_results',
@@ -154,6 +154,8 @@ function qsm_results_overview_tab_content() {
154
  // Prepares the SQL to retrieve the results.
155
  $table_limit = 40;
156
  $search_phrase_sql = '';
 
 
157
  $order_by_sql = 'ORDER BY result_id DESC';
158
  if ( isset( $_GET['qsm_search_phrase'] ) && ! empty( $_GET['qsm_search_phrase'] ) ) {
159
  // Sanitizes the search phrase and then uses $wpdb->prepare to properly escape the queries after using $wpdb->esc_like.
@@ -163,9 +165,9 @@ function qsm_results_overview_tab_content() {
163
  }
164
  if ( isset( $_GET['quiz_id'] ) && ! empty( $_GET['quiz_id'] ) ) {
165
  $quiz_id = intval( $_GET['quiz_id'] );
166
- $qsm_results_count = $wpdb->get_var( "SELECT COUNT(result_id) FROM {$wpdb->prefix}mlw_results WHERE deleted=0 AND quiz_id='{$quiz_id}' {$search_phrase_sql}" );
167
  } else {
168
- $qsm_results_count = $wpdb->get_var( "SELECT COUNT(result_id) FROM {$wpdb->prefix}mlw_results WHERE deleted=0 {$search_phrase_sql}" );
169
  }
170
 
171
  // Gets the order by arg. Uses switch to create SQL to prevent SQL injection.
@@ -203,9 +205,9 @@ function qsm_results_overview_tab_content() {
203
  $results_left = $qsm_results_count - ( $result_page * $table_limit );
204
  if ( isset( $_GET['quiz_id'] ) && ! empty( $_GET['quiz_id'] ) ) {
205
  $quiz_id = intval( $_GET['quiz_id'] );
206
- $mlw_quiz_data = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}mlw_results WHERE deleted=0 AND quiz_id = %d $search_phrase_sql $order_by_sql LIMIT %d, %d", $quiz_id, $result_begin, $table_limit ) );
207
  } else {
208
- $mlw_quiz_data = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}mlw_results WHERE deleted=0 $search_phrase_sql $order_by_sql LIMIT %d, %d", $result_begin, $table_limit ) );
209
  }
210
 
211
  wp_enqueue_script( 'jquery' );
@@ -272,7 +274,7 @@ function deleteResults(id, quizName) {
272
  ?>
273
  <a class="prev-page button"
274
  href="<?php echo esc_url_raw( "?page=mlw_quiz_results&&qsm_results_page=$mlw_qmn_previous_page$url_query_string" ); ?>">
275
- << /a>
276
  <span class="paging-input"><?php echo esc_html( $mlw_current_page ); ?> of
277
  <?php echo esc_html( $mlw_total_pages ); ?></span>
278
  <?php
88
  // Variables from delete result form.
89
  $mlw_delete_results_id = intval( $_POST['result_id'] );
90
  $mlw_delete_results_name = sanitize_text_field( $_POST['delete_quiz_name'] );
91
+ do_action('qsm_before_delete_result' , $mlw_delete_results_id);
92
  // Updates table to mark results as deleted.
93
  $results = $wpdb->update(
94
  $wpdb->prefix . 'mlw_results',
154
  // Prepares the SQL to retrieve the results.
155
  $table_limit = 40;
156
  $search_phrase_sql = '';
157
+ $delete = 'deleted=0';
158
+ $delete = apply_filters( 'qsm_results_delete_clause', $delete );
159
  $order_by_sql = 'ORDER BY result_id DESC';
160
  if ( isset( $_GET['qsm_search_phrase'] ) && ! empty( $_GET['qsm_search_phrase'] ) ) {
161
  // Sanitizes the search phrase and then uses $wpdb->prepare to properly escape the queries after using $wpdb->esc_like.
165
  }
166
  if ( isset( $_GET['quiz_id'] ) && ! empty( $_GET['quiz_id'] ) ) {
167
  $quiz_id = intval( $_GET['quiz_id'] );
168
+ $qsm_results_count = $wpdb->get_var( "SELECT COUNT(result_id) FROM {$wpdb->prefix}mlw_results WHERE {$delete} AND quiz_id='{$quiz_id}' {$search_phrase_sql}" );
169
  } else {
170
+ $qsm_results_count = $wpdb->get_var( "SELECT COUNT(result_id) FROM {$wpdb->prefix}mlw_results WHERE {$delete} {$search_phrase_sql}" );
171
  }
172
 
173
  // Gets the order by arg. Uses switch to create SQL to prevent SQL injection.
205
  $results_left = $qsm_results_count - ( $result_page * $table_limit );
206
  if ( isset( $_GET['quiz_id'] ) && ! empty( $_GET['quiz_id'] ) ) {
207
  $quiz_id = intval( $_GET['quiz_id'] );
208
+ $mlw_quiz_data = $wpdb->get_results(stripslashes( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}mlw_results WHERE $delete AND quiz_id = %d $search_phrase_sql $order_by_sql LIMIT %d, %d", $quiz_id, $result_begin, $table_limit ) ) );
209
  } else {
210
+ $mlw_quiz_data = $wpdb->get_results(stripslashes( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}mlw_results WHERE $delete $search_phrase_sql $order_by_sql LIMIT %d, %d", $result_begin, $table_limit ) ) );
211
  }
212
 
213
  wp_enqueue_script( 'jquery' );
274
  ?>
275
  <a class="prev-page button"
276
  href="<?php echo esc_url_raw( "?page=mlw_quiz_results&&qsm_results_page=$mlw_qmn_previous_page$url_query_string" ); ?>">
277
+ <</a>
278
  <span class="paging-input"><?php echo esc_html( $mlw_current_page ); ?> of
279
  <?php echo esc_html( $mlw_total_pages ); ?></span>
280
  <?php
php/admin/functions.php CHANGED
@@ -642,7 +642,8 @@ function qsm_text_template_variable_list() {
642
  '%QUESTIONS_ANSWERS%' => __( 'Shows the question, the answer the user provided, and the correct answer', 'quiz-master-next' ),
643
  '%COMMENT_SECTION%' => __( 'The comments the user entered into comment box if enabled', 'quiz-master-next' ),
644
  '%TIMER%' => __( 'The amount of time user spent on quiz in seconds', 'quiz-master-next' ),
645
- '%TIMER_MINUTES%' => __( 'The amount of time user spent on quiz in minutes', 'quiz-master-next' ),
 
646
  '%CATEGORY_POINTS_X%' => __( 'X: Category name - The amount of points a specific category earned.', 'quiz-master-next' ),
647
  '%CATEGORY_SCORE_X%' => __( 'X: Category name - The score a specific category earned.', 'quiz-master-next' ),
648
  '%CATEGORY_AVERAGE_POINTS%' => __( 'The average points from all categories.', 'quiz-master-next' ),
642
  '%QUESTIONS_ANSWERS%' => __( 'Shows the question, the answer the user provided, and the correct answer', 'quiz-master-next' ),
643
  '%COMMENT_SECTION%' => __( 'The comments the user entered into comment box if enabled', 'quiz-master-next' ),
644
  '%TIMER%' => __( 'The amount of time user spent on quiz in seconds', 'quiz-master-next' ),
645
+ '%TIMER_MINUTES%' => __( 'The amount of time user spent on quiz in minutes i.e. If total time is 3 minutes 38 seconds. This will output 3', 'quiz-master-next' ),
646
+ '%TIMER_SECONDS%' => __( 'The left over seconds user spent on quiz. i.e. If total time is 3 minutes 38 seconds. This will output 38', 'quiz-master-next' ),
647
  '%CATEGORY_POINTS_X%' => __( 'X: Category name - The amount of points a specific category earned.', 'quiz-master-next' ),
648
  '%CATEGORY_SCORE_X%' => __( 'X: Category name - The score a specific category earned.', 'quiz-master-next' ),
649
  '%CATEGORY_AVERAGE_POINTS%' => __( 'The average points from all categories.', 'quiz-master-next' ),
php/admin/options-page-email-tab.php CHANGED
@@ -82,6 +82,7 @@ function qsm_options_emails_tab_content() {
82
  <p><?php esc_html_e('Create the email that should be sent when the conditions are met.', 'quiz-master-next'); ?></p>
83
  </div>
84
  <label><?php esc_html_e('Who to send the email to? Put %USER_EMAIL% to send to user', 'quiz-master-next'); ?></label>
 
85
  <input type="email" class="to-email" value="{{ data.to }}">
86
  <label><?php esc_html_e('Email Subject', 'quiz-master-next'); ?></label>
87
  <input type="text" class="subject" value="{{ data.subject }}">
82
  <p><?php esc_html_e('Create the email that should be sent when the conditions are met.', 'quiz-master-next'); ?></p>
83
  </div>
84
  <label><?php esc_html_e('Who to send the email to? Put %USER_EMAIL% to send to user', 'quiz-master-next'); ?></label>
85
+ <?php do_action('qsm_after_send_email_label'); ?>
86
  <input type="email" class="to-email" value="{{ data.to }}">
87
  <label><?php esc_html_e('Email Subject', 'quiz-master-next'); ?></label>
88
  <input type="text" class="subject" value="{{ data.subject }}">
php/admin/options-page-questions-tab.php CHANGED
@@ -373,6 +373,17 @@ function qsm_options_questions_tab_content() {
373
  ),
374
  'default' => '0',
375
  ),
 
 
 
 
 
 
 
 
 
 
 
376
  );
377
  $simple_question_option = apply_filters( 'qsm_question_format_option', $simple_question_option );
378
  $keys = array_column( $simple_question_option, 'priority' );
@@ -692,6 +703,28 @@ function qsm_options_questions_tab_content() {
692
  </div>
693
  </div>
694
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
695
  <?php
696
  }
697
 
373
  ),
374
  'default' => '0',
375
  ),
376
+ 'match-answer' => array(
377
+ 'label' => __( 'Match Answer', 'quiz-master-next' ),
378
+ 'type' => 'select',
379
+ 'priority' => '3',
380
+ 'options' => array(
381
+ 'random' => __( 'Randomly', 'quiz-master-next' ),
382
+ 'sequence' => __( 'Sequentially', 'quiz-master-next' ),
383
+ ),
384
+ 'default' => 'random',
385
+ 'show' => '14',
386
+ ),
387
  );
388
  $simple_question_option = apply_filters( 'qsm_question_format_option', $simple_question_option );
389
  $keys = array_column( $simple_question_option, 'priority' );
703
  </div>
704
  </div>
705
 
706
+ <div class="qsm-popup qsm-popup-slide" id="modal-8" aria-hidden="false">
707
+ <div class="qsm-popup__overlay" tabindex="-1" data-micromodal-close="">
708
+ <div class="qsm-popup__container" role="dialog" aria-modal="true" aria-labelledby="modal-8-title">
709
+ <header class="qsm-popup__header">
710
+ <h3 class="qsm-popup__title" id="modal-8-title"><?php _e( 'Alert', 'quiz-master-next' ); ?>
711
+ </h3>
712
+ <a class="qsm-popup__close" aria-label="Close modal" data-micromodal-close=""></a>
713
+ </header>
714
+ <hr />
715
+ <main class="qsm-popup__content" id="modal-8-content">
716
+ <div class="modal-8-table">
717
+ </div>
718
+ </main>
719
+ <hr />
720
+ <footer class="qsm-popup__footer">
721
+ <button id="cancel-button" class="qsm-popup__btn" data-micromodal-close=""
722
+ aria-label="Close this dialog window"><?php _e( 'Cancel', 'quiz-master-next' ); ?></button>
723
+ </footer>
724
+ </div>
725
+ </div>
726
+ </div>
727
+
728
  <?php
729
  }
730
 
php/admin/quizzes-page.php CHANGED
@@ -36,6 +36,7 @@ function qsm_generate_quizzes_surveys_page() {
36
  // Delete quiz.
37
  if ( isset( $_POST['qsm_delete_quiz_nonce'] ) && wp_verify_nonce( $_POST['qsm_delete_quiz_nonce'], 'qsm_delete_quiz' ) ) {
38
  $quiz_id = intval( $_POST['delete_quiz_id'] );
 
39
  $quiz_name = sanitize_text_field( $_POST['delete_quiz_name'] );
40
  $mlwQuizMasterNext->quizCreator->delete_quiz( $quiz_id, $quiz_name );
41
  }
@@ -136,7 +137,8 @@ window.location = "?page=mlw_quiz_list&paged=1&s=" + s + "&action=" + action;
136
  $num_of_pages = ceil( $total / $limit );
137
  } else {
138
  $condition = ' WHERE deleted=0';
139
- $total = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(`quiz_id`) FROM {$wpdb->prefix}mlw_quizzes %1s", $condition ) );
 
140
  $num_of_pages = ceil( $total / $limit );
141
  }
142
 
@@ -176,6 +178,7 @@ window.location = "?page=mlw_quiz_list&paged=1&s=" + s + "&action=" + action;
176
  if ( isset( $_POST['btnSearchQuiz'] ) && $_POST['s'] != '' ) {
177
  $search_quiz = htmlspecialchars( $_POST['s'], ENT_QUOTES );
178
  $condition = " WHERE deleted=0 AND quiz_name LIKE '%$search_quiz%'";
 
179
  $qry = stripslashes( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}mlw_quizzes%1s", $condition ) );
180
  $quizzes = $wpdb->get_results( $qry );
181
 
36
  // Delete quiz.
37
  if ( isset( $_POST['qsm_delete_quiz_nonce'] ) && wp_verify_nonce( $_POST['qsm_delete_quiz_nonce'], 'qsm_delete_quiz' ) ) {
38
  $quiz_id = intval( $_POST['delete_quiz_id'] );
39
+ do_action('qsm_before_delete_quiz' , $quiz_id);
40
  $quiz_name = sanitize_text_field( $_POST['delete_quiz_name'] );
41
  $mlwQuizMasterNext->quizCreator->delete_quiz( $quiz_id, $quiz_name );
42
  }
137
  $num_of_pages = ceil( $total / $limit );
138
  } else {
139
  $condition = ' WHERE deleted=0';
140
+ $condition = apply_filters( 'quiz_query_condition_clause', $condition );
141
+ $total = $wpdb->get_var( stripslashes($wpdb->prepare( "SELECT COUNT(`quiz_id`) FROM {$wpdb->prefix}mlw_quizzes %1s", $condition ) ));
142
  $num_of_pages = ceil( $total / $limit );
143
  }
144
 
178
  if ( isset( $_POST['btnSearchQuiz'] ) && $_POST['s'] != '' ) {
179
  $search_quiz = htmlspecialchars( $_POST['s'], ENT_QUOTES );
180
  $condition = " WHERE deleted=0 AND quiz_name LIKE '%$search_quiz%'";
181
+ $condition = apply_filters( 'quiz_query_condition_clause', $condition );
182
  $qry = stripslashes( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}mlw_quizzes%1s", $condition ) );
183
  $quizzes = $wpdb->get_results( $qry );
184
 
php/classes/class-qmn-plugin-helper.php CHANGED
@@ -176,6 +176,7 @@ class QMNPluginHelper
176
  $limit = ' limit ' . $offset . ', ' . $limit;
177
  }
178
  // Get quizzes and return them
 
179
  $quizzes = $wpdb->get_results(stripslashes($wpdb->prepare("SELECT * FROM {$wpdb->prefix}mlw_quizzes %1s %2s %3s ORDER BY %4s %5s %6s", $delete, $user_str, $where_str, $order_field, $order_direction, $limit)));
180
  return $quizzes;
181
  }
@@ -656,6 +657,6 @@ class QMNPluginHelper
656
  */
657
  public function get_settings_tabs()
658
  {
659
- return $this->settings_tabs;
660
  }
661
  }
176
  $limit = ' limit ' . $offset . ', ' . $limit;
177
  }
178
  // Get quizzes and return them
179
+ $delete = apply_filters( 'quiz_query_delete_clause', $delete );
180
  $quizzes = $wpdb->get_results(stripslashes($wpdb->prepare("SELECT * FROM {$wpdb->prefix}mlw_quizzes %1s %2s %3s ORDER BY %4s %5s %6s", $delete, $user_str, $where_str, $order_field, $order_direction, $limit)));
181
  return $quizzes;
182
  }
657
  */
658
  public function get_settings_tabs()
659
  {
660
+ return apply_filters('qmn_quiz_setting_tabs' , $this->settings_tabs);
661
  }
662
  }
php/classes/class-qmn-quiz-creator.php CHANGED
@@ -108,7 +108,7 @@ class QMNQuizCreator
108
  'user_phone' => 2,
109
  'admin_email' => get_option('admin_email', 'Enter email'),
110
  'comment_section' => 1,
111
- 'question_from_total' => 0,
112
  'total_user_tries' => 0,
113
  'total_user_tries_text' => __('You have utilized all of your attempts to pass this quiz.', 'quiz-master-next'),
114
  'certificate_template' => '',
@@ -377,7 +377,7 @@ class QMNQuizCreator
377
  'user_phone' => $mlw_qmn_duplicate_data->user_phone,
378
  'admin_email' => get_option('admin_email', 'Enter email'),
379
  'comment_section' => $mlw_qmn_duplicate_data->comment_section,
380
- 'question_from_total' => $mlw_qmn_duplicate_data->question_from_total,
381
  'total_user_tries' => $mlw_qmn_duplicate_data->total_user_tries,
382
  'total_user_tries_text' => $mlw_qmn_duplicate_data->total_user_tries_text,
383
  'certificate_template' => $mlw_qmn_duplicate_data->certificate_template,
108
  'user_phone' => 2,
109
  'admin_email' => get_option('admin_email', 'Enter email'),
110
  'comment_section' => 1,
111
+ 'question_from_total' => 0,
112
  'total_user_tries' => 0,
113
  'total_user_tries_text' => __('You have utilized all of your attempts to pass this quiz.', 'quiz-master-next'),
114
  'certificate_template' => '',
377
  'user_phone' => $mlw_qmn_duplicate_data->user_phone,
378
  'admin_email' => get_option('admin_email', 'Enter email'),
379
  'comment_section' => $mlw_qmn_duplicate_data->comment_section,
380
+ 'question_from_total' => $mlw_qmn_duplicate_data->question_from_total,
381
  'total_user_tries' => $mlw_qmn_duplicate_data->total_user_tries,
382
  'total_user_tries_text' => $mlw_qmn_duplicate_data->total_user_tries_text,
383
  'certificate_template' => $mlw_qmn_duplicate_data->certificate_template,
php/classes/class-qmn-quiz-manager.php CHANGED
@@ -448,7 +448,7 @@ class QMNQuizManager {
448
  * @return array The questions for the quiz
449
  * @deprecated 5.2.0 Use new class: QSM_Questions instead
450
  */
451
- public function load_questions( $quiz_id, $quiz_options, $is_quiz_page, $question_amount = 0 ) {
452
 
453
  // Prepare variables.
454
  global $wpdb;
@@ -456,11 +456,12 @@ class QMNQuizManager {
456
  $questions = array();
457
  $order_by_sql = 'ORDER BY question_order ASC';
458
  $limit_sql = '';
 
459
 
460
  // Checks if the questions should be randomized.
461
  $cat_query = '';
462
  if ( 1 == $quiz_options->randomness_order || 2 == $quiz_options->randomness_order ) {
463
- $order_by_sql = 'ORDER BY rand()';
464
  $categories = isset( $quiz_options->randon_category ) ? $quiz_options->randon_category : '';
465
  if ( $categories ) {
466
  $exploded_arr = explode( ',', $quiz_options->randon_category );
@@ -470,7 +471,7 @@ class QMNQuizManager {
470
  }
471
 
472
  // Check if we should load all questions or only a selcted amount.
473
- if ( $is_quiz_page && ( 0 != $quiz_options->question_from_total || 0 !== $question_amount ) ) {
474
  if ( 0 !== $question_amount ) {
475
  $limit_sql = " LIMIT $question_amount";
476
  } else {
@@ -490,13 +491,83 @@ class QMNQuizManager {
490
  }
491
  $question_ids = apply_filters( 'qsm_load_questions_ids', $question_ids, $quiz_id, $quiz_options );
492
  $question_sql = implode( ', ', $question_ids );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
493
  $query = $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}mlw_questions WHERE question_id IN (%1s) %2s %3s %4s", $question_sql, $cat_query, $order_by_sql, $limit_sql );
494
  $questions = $wpdb->get_results( stripslashes( $query ) );
 
 
495
 
496
  // If we are not using randomization, we need to put the questions in the order of the new question editor.
497
  // If a user has saved the pages in the question editor but still uses the older pagination options
498
  // Then they will make it here. So, we need to order the questions based on the new editor.
499
- if ( 1 != $quiz_options->randomness_order && 2 != $quiz_options->randomness_order ) {
 
500
  $ordered_questions = array();
501
  foreach ( $questions as $question ) {
502
  $key = array_search( $question->question_id, $question_ids );
@@ -519,6 +590,7 @@ class QMNQuizManager {
519
  $questions = apply_filters( 'qsm_load_questions_filter', $questions, $quiz_id, $quiz_options );
520
  // Returns an array of all the loaded questions.
521
  return $questions;
 
522
  }
523
 
524
  /**
448
  * @return array The questions for the quiz
449
  * @deprecated 5.2.0 Use new class: QSM_Questions instead
450
  */
451
+ public function load_questions( $quiz_id, $quiz_options, $is_quiz_page, $question_amount = 0 ) {
452
 
453
  // Prepare variables.
454
  global $wpdb;
456
  $questions = array();
457
  $order_by_sql = 'ORDER BY question_order ASC';
458
  $limit_sql = '';
459
+ $big_array = array();
460
 
461
  // Checks if the questions should be randomized.
462
  $cat_query = '';
463
  if ( 1 == $quiz_options->randomness_order || 2 == $quiz_options->randomness_order ) {
464
+ $order_by_sql = 'ORDER BY rand()';
465
  $categories = isset( $quiz_options->randon_category ) ? $quiz_options->randon_category : '';
466
  if ( $categories ) {
467
  $exploded_arr = explode( ',', $quiz_options->randon_category );
471
  }
472
 
473
  // Check if we should load all questions or only a selcted amount.
474
+ if ( $is_quiz_page && ( 0 != $quiz_options->question_from_total || 0 !== $question_amount ) ) {
475
  if ( 0 !== $question_amount ) {
476
  $limit_sql = " LIMIT $question_amount";
477
  } else {
491
  }
492
  $question_ids = apply_filters( 'qsm_load_questions_ids', $question_ids, $quiz_id, $quiz_options );
493
  $question_sql = implode( ', ', $question_ids );
494
+
495
+ //check If we should load a specific number of question
496
+ if( $quiz_options->question_per_category != 0 && $is_quiz_page ){
497
+
498
+
499
+ //processing Categories checking. removing commas and making them arrays
500
+ $cat_sql = $wpdb->get_results( $wpdb->prepare("SELECT category FROM {$wpdb->prefix}mlw_questions WHERE quiz_id = %d ", $quiz_id), );
501
+ $all_cat = array();
502
+ foreach($cat_sql as $cat){
503
+ array_push($all_cat, $cat->category);
504
+ }
505
+ //processing the categories
506
+ $all_cat = array_unique($all_cat);
507
+
508
+ $all_cat = array_values($all_cat);
509
+
510
+
511
+ $categories = $quiz_options->randon_category != '' ? $quiz_options->randon_category : $all_cat;
512
+
513
+ if($quiz_options->randon_category != ''){
514
+
515
+ $categories = explode(",",$categories);
516
+
517
+ $categories = str_replace(',', '', $categories) ;
518
+ }
519
+ //Running a loop for each category and getting a limited number of questions
520
+ for ($i=0; $i < count($categories) ; $i++) {
521
+ $catSQL = isset( $quiz_options->randon_category )&& !empty( $quiz_options->randon_category) ? : '';
522
+ $piece1 = $wpdb->prepare("SELECT * FROM {$wpdb->prefix}mlw_questions WHERE question_id IN (%1s) AND category IN (%s) LIMIT %d",
523
+ $question_sql,$categories[$i],
524
+ $quiz_options->question_per_category );
525
+
526
+ $piece_res = $wpdb->get_results( stripslashes( $piece1 ) );
527
+ //add them to the big_array
528
+ $big_array = array_merge($big_array, $piece_res);
529
+
530
+
531
+ }
532
+
533
+ // Check If the no category Question is less or equal to the question limit
534
+
535
+ if (count($big_array) <= $quiz_options->question_from_total )
536
+ {
537
+ $big_range = range(0, count($big_array) - 1);
538
+ $quiz_options->randomness_order == 1 || $quiz_options->randomness_order == 2 ? shuffle($big_range) : $big_range;
539
+ for ($i=0; $i < count($big_array) ; $i++) {
540
+
541
+ array_push($questions, $big_array[$big_range[$i]]);
542
+ }
543
+
544
+ }
545
+ //If Category Question are more then run array_rand to get random entries
546
+ else{
547
+
548
+ $range = range(0, $quiz_options->question_from_total);
549
+
550
+ $quiz_options->randomness_order == 1 || $quiz_options->randomness_order == 2 ? shuffle($range) : $range;
551
+ for ($i=0; $i < $quiz_options->question_from_total ; $i++) {
552
+
553
+ array_push($questions, $big_array[$range[$i]]);
554
+ }
555
+
556
+ }
557
+
558
+ }
559
+ else{
560
+
561
  $query = $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}mlw_questions WHERE question_id IN (%1s) %2s %3s %4s", $question_sql, $cat_query, $order_by_sql, $limit_sql );
562
  $questions = $wpdb->get_results( stripslashes( $query ) );
563
+
564
+ }
565
 
566
  // If we are not using randomization, we need to put the questions in the order of the new question editor.
567
  // If a user has saved the pages in the question editor but still uses the older pagination options
568
  // Then they will make it here. So, we need to order the questions based on the new editor.
569
+
570
+ if ( 1 != $quiz_options->randomness_order && 2 != $quiz_options->randomness_order && $quiz_options->question_per_category == 0 ) {
571
  $ordered_questions = array();
572
  foreach ( $questions as $question ) {
573
  $key = array_search( $question->question_id, $question_ids );
590
  $questions = apply_filters( 'qsm_load_questions_filter', $questions, $quiz_id, $quiz_options );
591
  // Returns an array of all the loaded questions.
592
  return $questions;
593
+
594
  }
595
 
596
  /**
php/classes/class-qsm-contact-manager.php CHANGED
@@ -157,6 +157,7 @@ class QSM_Contact_Manager {
157
  break;
158
 
159
  default:
 
160
  break;
161
  }
162
  ?>
157
  break;
158
 
159
  default:
160
+ do_action('qsm_extra_contact_filed' ,$fields, $options);
161
  break;
162
  }
163
  ?>
php/classes/class-qsm-install.php CHANGED
@@ -247,6 +247,22 @@ class QSM_Install {
247
  'help' => __('Leave 0 to load all questions','quiz-master-next'),
248
  'tooltip' => __('Show only limited number of questions from your quiz.','quiz-master-next')
249
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
250
  $mlwQuizMasterNext->pluginHelper->register_quiz_setting( $field_array, 'quiz_options' );
251
 
252
  // Registers scheduled_time_start setting
@@ -310,7 +326,7 @@ class QSM_Install {
310
  // Registers category setting
311
  $field_array = array(
312
  'id' => 'randon_category',
313
- 'label' => __('Random Questions Categories', 'quiz-master-next'),
314
  'type' => 'category',
315
  'default' => '',
316
  'help' => __('Questions will load only from selected categories', 'quiz-master-next')
@@ -1829,7 +1845,7 @@ class QSM_Install {
1829
  $results = $wpdb->query( $update_sql );
1830
  }
1831
  //Update 7.1.11
1832
- if($wpdb->get_var("select data_type from information_schema.columns where table_name = ".$wpdb->prefix . "mlw_results and column_name = 'point_score'") != 'FLOAT' )
1833
  {
1834
  $results = $wpdb->query( "ALTER TABLE ".$wpdb->prefix . "mlw_results MODIFY point_score FLOAT NOT NULL;" );
1835
  }
@@ -1896,4 +1912,4 @@ class QSM_Install {
1896
 
1897
  $qsm_install = new QSM_Install();
1898
 
1899
- ?>
247
  'help' => __('Leave 0 to load all questions','quiz-master-next'),
248
  'tooltip' => __('Show only limited number of questions from your quiz.','quiz-master-next')
249
  );
250
+
251
+ $mlwQuizMasterNext->pluginHelper->register_quiz_setting( $field_array, 'quiz_options' );
252
+
253
+
254
+ // Registers question_per_category setting
255
+ $field_array = array(
256
+ 'id' => 'question_per_category',
257
+ 'label' => __('Limit number of Questions Per Category ', 'quiz-master-next'),
258
+ 'type' => 'number',
259
+ 'options' => array(
260
+
261
+ ),
262
+ 'default' => 0,
263
+ 'help' => __('Leave 0 to load all questions. You also need to set Limit Number of questions, as well as select Question Categories','quiz-master-next'),
264
+ 'tooltip' => __('Show only limited number of category questions from your quiz.You also need to set Limit Number of questions.','quiz-master-next')
265
+ );
266
  $mlwQuizMasterNext->pluginHelper->register_quiz_setting( $field_array, 'quiz_options' );
267
 
268
  // Registers scheduled_time_start setting
326
  // Registers category setting
327
  $field_array = array(
328
  'id' => 'randon_category',
329
+ 'label' => __('Questions Categories', 'quiz-master-next'),
330
  'type' => 'category',
331
  'default' => '',
332
  'help' => __('Questions will load only from selected categories', 'quiz-master-next')
1845
  $results = $wpdb->query( $update_sql );
1846
  }
1847
  //Update 7.1.11
1848
+ if($wpdb->get_var("select data_type from information_schema.columns where table_name = '".$wpdb->prefix . "mlw_results' and column_name = 'point_score'") != 'FLOAT' )
1849
  {
1850
  $results = $wpdb->query( "ALTER TABLE ".$wpdb->prefix . "mlw_results MODIFY point_score FLOAT NOT NULL;" );
1851
  }
1912
 
1913
  $qsm_install = new QSM_Install();
1914
 
1915
+ ?>
php/classes/class-qsm-settings.php CHANGED
@@ -298,6 +298,7 @@ class QSM_Quiz_Settings {
298
  'comment_section' => $quiz_options->comment_section,
299
  'randomness_order' => $quiz_options->randomness_order,
300
  'question_from_total' => $quiz_options->question_from_total,
 
301
  'total_user_tries' => $quiz_options->total_user_tries,
302
  'social_media' => $quiz_options->social_media,
303
  'pagination' => $quiz_options->pagination,
298
  'comment_section' => $quiz_options->comment_section,
299
  'randomness_order' => $quiz_options->randomness_order,
300
  'question_from_total' => $quiz_options->question_from_total,
301
+ 'question_per_category' => $quiz_options->question_per_category,
302
  'total_user_tries' => $quiz_options->total_user_tries,
303
  'social_media' => $quiz_options->social_media,
304
  'pagination' => $quiz_options->pagination,
php/question-types.php CHANGED
@@ -1162,7 +1162,7 @@ function qmn_fill_blank_display( $id, $question, $answers ) {
1162
  $mlw_requireClass = 'mlwRequiredText';
1163
  } else {
1164
  $mlw_requireClass = '';}
1165
- $input_text = '<input ' . $autofill_att . $limit_text_att . " type='text' class='qmn_fill_blank $mlw_requireClass' name='question" . $id . "' />";
1166
  if ( strpos( $question, '%BLANK%' ) !== false ) {
1167
  $question = str_replace( '%BLANK%', $input_text, do_shortcode( htmlspecialchars_decode( $question, ENT_QUOTES ) ) );
1168
  }
@@ -1182,31 +1182,79 @@ function qmn_fill_blank_display( $id, $question, $answers ) {
1182
  * @since 4.4.0
1183
  */
1184
  function qmn_fill_blank_review( $id, $question, $answers ) {
 
 
1185
  $return_array = array(
1186
- 'points' => 0,
1187
- 'correct' => 'incorrect',
1188
- 'user_text' => '',
1189
- 'correct_text' => '',
 
1190
  );
1191
  if ( strpos( $question, '%BLANK%' ) !== false || strpos( $question, '%blank%' ) !== false ) {
1192
  $return_array['question_text'] = str_replace( array( '%BLANK%', '%blank%' ), array( '__________', '__________' ), do_shortcode( htmlspecialchars_decode( $question, ENT_QUOTES ) ) );
1193
  }
1194
- if ( isset( $_POST[ 'question' . $id ] ) ) {
1195
- $decode_user_answer = sanitize_textarea_field( strval( stripslashes( htmlspecialchars_decode( $_POST[ 'question' . $id ], ENT_QUOTES ) ) ) );
1196
- $mlw_user_answer = trim( preg_replace( '/\s\s+/', ' ', str_replace( "\n", ' ', $decode_user_answer ) ) );
1197
- } else {
1198
- $mlw_user_answer = ' ';
 
 
 
1199
  }
1200
- $return_array['user_text'] = $mlw_user_answer;
1201
- foreach ( $answers as $answer ) {
1202
- $decode_correct_text = strval( htmlspecialchars_decode( $answer[0], ENT_QUOTES ) );
1203
- $return_array['correct_text'] = trim( preg_replace( '/\s\s+/', ' ', str_replace( "\n", ' ', $decode_correct_text ) ) );
1204
- if ( mb_strtoupper( $return_array['user_text'] ) == mb_strtoupper( $return_array['correct_text'] ) ) {
1205
- $return_array['correct'] = 'correct';
1206
- $return_array['points'] = $answer[1];
1207
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1208
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1209
  }
 
1210
  /**
1211
  * Hook to filter answers array
1212
  */
1162
  $mlw_requireClass = 'mlwRequiredText';
1163
  } else {
1164
  $mlw_requireClass = '';}
1165
+ $input_text = '<input ' . $autofill_att . $limit_text_att . " type='text' class='qmn_fill_blank $mlw_requireClass' name='question" . $id . "[]' />";
1166
  if ( strpos( $question, '%BLANK%' ) !== false ) {
1167
  $question = str_replace( '%BLANK%', $input_text, do_shortcode( htmlspecialchars_decode( $question, ENT_QUOTES ) ) );
1168
  }
1182
  * @since 4.4.0
1183
  */
1184
  function qmn_fill_blank_review( $id, $question, $answers ) {
1185
+ global $mlwQuizMasterNext;
1186
+ $match_answer = $mlwQuizMasterNext->pluginHelper->get_question_setting( $id, 'matchAnswer' );
1187
  $return_array = array(
1188
+ 'points' => 0,
1189
+ 'correct' => 'incorrect',
1190
+ 'user_text' => '',
1191
+ 'correct_text' => '',
1192
+ 'user_compare_text' => '',
1193
  );
1194
  if ( strpos( $question, '%BLANK%' ) !== false || strpos( $question, '%blank%' ) !== false ) {
1195
  $return_array['question_text'] = str_replace( array( '%BLANK%', '%blank%' ), array( '__________', '__________' ), do_shortcode( htmlspecialchars_decode( $question, ENT_QUOTES ) ) );
1196
  }
1197
+ $user_input = $user_text = array();
1198
+ if ( isset( $_POST[ 'question' . $id ] ) && ! empty( $_POST[ 'question' . $id ] ) ) {
1199
+ foreach ( $_POST[ 'question' . $id ] as $input ) {
1200
+ $decode_user_answer = sanitize_textarea_field( strval( stripslashes( htmlspecialchars_decode( $input, ENT_QUOTES ) ) ) );
1201
+ $mlw_user_answer = trim( preg_replace( '/\s\s+/', ' ', str_replace( "\n", ' ', $decode_user_answer ) ) );
1202
+ $user_input[] = mb_strtoupper( $mlw_user_answer );
1203
+ $user_text[] = $mlw_user_answer;
1204
+ }
1205
  }
1206
+
1207
+ $total_correct = $user_correct = 0;
1208
+ if ( $match_answer == 'sequence' ) {
1209
+ foreach ( $answers as $key => $answer ) {
1210
+ $decode_user_text = strval( htmlspecialchars_decode( $answer[0], ENT_QUOTES ) );
1211
+ $decode_user_text = trim( preg_replace( '/\s\s+/', ' ', str_replace( "\n", ' ', $decode_user_text ) ) );
1212
+ if ( mb_strtoupper( $decode_user_text ) == $user_input[ $key ] ) {
1213
+ $return_array['points'] += $answer[1];
1214
+ $user_correct += 1;
1215
+ }
1216
+ $total_correct++;
1217
+ }
1218
+ $return_array['user_text'] = implode( '.', $user_text );
1219
+ $return_array['user_compare_text'] = implode( '=====', $user_text );
1220
+ if($total_correct == $user_correct){
1221
+ $return_array['correct'] = 'correct';
1222
+ }
1223
+ } else {
1224
+ $answers_array = array();
1225
+ $correct = true;
1226
+ foreach($answers as $answer){
1227
+ $decode_user_text = strval( htmlspecialchars_decode( $answer[0], ENT_QUOTES ) );
1228
+ $decode_user_text = trim( preg_replace( '/\s\s+/', ' ', str_replace( "\n", ' ', $decode_user_text ) ) );
1229
+ $answers_array[] = mb_strtoupper( $decode_user_text );
1230
  }
1231
+ $total_user_input = sizeof($user_input);
1232
+ $total_option = sizeof($answers);
1233
+ if($total_user_input < $total_option){
1234
+ foreach($user_input as $k => $input){
1235
+ $key = array_search( $input, $answers_array );
1236
+ if($key !== false){
1237
+ $return_array['points'] += $answers[$key][1];
1238
+ } else {
1239
+ $correct = false;
1240
+ }
1241
+ }
1242
+ } else {
1243
+ foreach($answers_array as $k => $answer){
1244
+ $key = array_search( $answer, $user_input );
1245
+ if($key !== false){
1246
+ $return_array['points'] += $answers[$k][1];
1247
+ } else {
1248
+ $correct = false;
1249
+ }
1250
+ }
1251
+ }
1252
+ if($correct){
1253
+ $return_array['correct'] = 'correct';
1254
+ }
1255
+ $return_array['user_compare_text'] = implode( '=====', $user_text );
1256
  }
1257
+
1258
  /**
1259
  * Hook to filter answers array
1260
  */
php/rest-api.php CHANGED
@@ -596,6 +596,7 @@ function qsm_rest_save_question( WP_REST_Request $request ) {
596
  $settings['question_title'] = sanitize_text_field( $request['question_title'] );
597
  $settings['featureImageID'] = sanitize_text_field( $request['featureImageID'] );
598
  $settings['featureImageSrc'] = sanitize_text_field( $request['featureImageSrc'] );
 
599
  if ( isset( $request['other_settings'] ) && is_array( $request['other_settings'] ) ) {
600
  foreach ( $request['other_settings'] as $setting_key => $setting_value ) {
601
  $settings[ $setting_key ] = $setting_value;
596
  $settings['question_title'] = sanitize_text_field( $request['question_title'] );
597
  $settings['featureImageID'] = sanitize_text_field( $request['featureImageID'] );
598
  $settings['featureImageSrc'] = sanitize_text_field( $request['featureImageSrc'] );
599
+ $settings['matchAnswer'] = sanitize_text_field( $request['matchAnswer'] );
600
  if ( isset( $request['other_settings'] ) && is_array( $request['other_settings'] ) ) {
601
  foreach ( $request['other_settings'] as $setting_key => $setting_value ) {
602
  $settings[ $setting_key ] = $setting_value;
php/template-variables.php CHANGED
@@ -56,6 +56,7 @@ add_filter( 'mlw_qmn_template_variable_results_page', 'mlw_qmn_variable_question
56
  add_filter( 'mlw_qmn_template_variable_results_page', 'mlw_qmn_variable_comments', 10, 2 );
57
  add_filter( 'mlw_qmn_template_variable_results_page', 'mlw_qmn_variable_timer', 10, 2 );
58
  add_filter( 'mlw_qmn_template_variable_results_page', 'mlw_qmn_variable_timer_minutes', 10, 2 );
 
59
  add_filter( 'mlw_qmn_template_variable_results_page', 'mlw_qmn_variable_date', 10, 2 );
60
  add_filter( 'mlw_qmn_template_variable_results_page', 'mlw_qmn_variable_date_taken', 10, 2 );
61
  add_filter( 'mlw_qmn_template_variable_results_page', 'mlw_qmn_variable_social_share', 10, 2 );
@@ -313,10 +314,10 @@ function mlw_qmn_variable_amount_correct( $content, $mlw_quiz_array ) {
313
  */
314
  function mlw_qmn_variable_amount_incorrect( $content, $mlw_quiz_array ) {
315
  if ( false !== strpos( $content, '%AMOUNT_INCORRECT%' ) ) {
316
- $total_question = $mlw_quiz_array['total_questions'];
317
- $total_correct = $mlw_quiz_array['total_correct'];
318
- $total_incorrect = $total_question - $total_correct;
319
- $content = str_replace( '%AMOUNT_INCORRECT%', max( $total_incorrect, 0 ), $content );
320
  }
321
  return $content;
322
  }
@@ -500,11 +501,17 @@ function mlw_qmn_variable_timer( $content, $mlw_quiz_array ) {
500
  }
501
 
502
  function mlw_qmn_variable_timer_minutes( $content, $mlw_quiz_array ) {
503
- $mlw_minutes = ( isset( $mlw_quiz_array['timer'] ) ? round( $mlw_quiz_array['timer'] / 60, 2 ) : '' );
504
  $content = str_replace( '%TIMER_MINUTES%', $mlw_minutes, $content );
505
  return $content;
506
  }
507
 
 
 
 
 
 
 
508
  /**
509
  * Replaces the variable %CURRENT_DATE% and displays the current date
510
  *
@@ -886,10 +893,10 @@ function qsm_questions_answers_shortcode_to_text( $mlw_quiz_array, $qmn_question
886
  12,
887
  5,
888
  7,
889
- 14,
890
  );
891
- $form_type = isset( $mlw_quiz_array['form_type'] ) ? $mlw_quiz_array['form_type'] : 0;
892
- $quiz_system = isset( $mlw_quiz_array['quiz_system'] ) ? $mlw_quiz_array['quiz_system'] : 0;
893
  if ( isset( $answer['id'] ) && isset( $questions[ $answer['id'] ] ) && ! empty( $questions[ $answer['id'] ] ) ) {
894
  $total_answers = isset( $questions[ $answer['id'] ]['answers'] ) ? $questions[ $answer['id'] ]['answers'] : array();
895
  if ( $total_answers ) {
@@ -939,6 +946,64 @@ function qsm_questions_answers_shortcode_to_text( $mlw_quiz_array, $qmn_question
939
  } else {
940
  $question_with_answer_text .= "<span class='$user_answer_class'>" . trim( htmlspecialchars_decode( $answer[1], ENT_QUOTES ) ) . '</span>';
941
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
942
  } else {
943
  if ( $form_type == 0 && ( $quiz_system == 0 || $quiz_system == 3 ) ) {
944
  if ( isset( $answer['question_type'] ) && ( $answer['question_type'] == 4 || $answer['question_type'] == 10 ) ) {
56
  add_filter( 'mlw_qmn_template_variable_results_page', 'mlw_qmn_variable_comments', 10, 2 );
57
  add_filter( 'mlw_qmn_template_variable_results_page', 'mlw_qmn_variable_timer', 10, 2 );
58
  add_filter( 'mlw_qmn_template_variable_results_page', 'mlw_qmn_variable_timer_minutes', 10, 2 );
59
+ add_filter( 'mlw_qmn_template_variable_results_page', 'mlw_qmn_variable_timer_seconds', 10, 2 );
60
  add_filter( 'mlw_qmn_template_variable_results_page', 'mlw_qmn_variable_date', 10, 2 );
61
  add_filter( 'mlw_qmn_template_variable_results_page', 'mlw_qmn_variable_date_taken', 10, 2 );
62
  add_filter( 'mlw_qmn_template_variable_results_page', 'mlw_qmn_variable_social_share', 10, 2 );
314
  */
315
  function mlw_qmn_variable_amount_incorrect( $content, $mlw_quiz_array ) {
316
  if ( false !== strpos( $content, '%AMOUNT_INCORRECT%' ) ) {
317
+ $total_attempted_question = $mlw_quiz_array['total_attempted_questions'];
318
+ $total_correct = $mlw_quiz_array['total_correct'];
319
+ $total_incorrect = $total_attempted_question - $total_correct;
320
+ $content = str_replace( '%AMOUNT_INCORRECT%', max( $total_incorrect, 0 ), $content );
321
  }
322
  return $content;
323
  }
501
  }
502
 
503
  function mlw_qmn_variable_timer_minutes( $content, $mlw_quiz_array ) {
504
+ $mlw_minutes = ( isset( $mlw_quiz_array['timer'] ) ? floor( $mlw_quiz_array['timer'] / 60 ) : '' );
505
  $content = str_replace( '%TIMER_MINUTES%', $mlw_minutes, $content );
506
  return $content;
507
  }
508
 
509
+ function mlw_qmn_variable_timer_seconds( $content, $mlw_quiz_array ) {
510
+ $mlw_minutes = ( isset( $mlw_quiz_array['timer'] ) ? (int) ( $mlw_quiz_array['timer'] % 60 ) : '' );
511
+ $content = str_replace( '%TIMER_SECONDS%', $mlw_minutes, $content );
512
+ return $content;
513
+ }
514
+
515
  /**
516
  * Replaces the variable %CURRENT_DATE% and displays the current date
517
  *
893
  12,
894
  5,
895
  7,
896
+ // 14,
897
  );
898
+ $form_type = isset( $mlw_quiz_array['form_type'] ) ? $mlw_quiz_array['form_type'] : 0;
899
+ $quiz_system = isset( $mlw_quiz_array['quiz_system'] ) ? $mlw_quiz_array['quiz_system'] : 0;
900
  if ( isset( $answer['id'] ) && isset( $questions[ $answer['id'] ] ) && ! empty( $questions[ $answer['id'] ] ) ) {
901
  $total_answers = isset( $questions[ $answer['id'] ]['answers'] ) ? $questions[ $answer['id'] ]['answers'] : array();
902
  if ( $total_answers ) {
946
  } else {
947
  $question_with_answer_text .= "<span class='$user_answer_class'>" . trim( htmlspecialchars_decode( $answer[1], ENT_QUOTES ) ) . '</span>';
948
  }
949
+ } elseif ( isset( $answer['question_type'] ) && $answer['question_type'] == 14 ) {
950
+ $match_answer = $mlwQuizMasterNext->pluginHelper->get_question_setting( $answer['id'], 'matchAnswer' );
951
+ $new_array_user_answer = isset( $answer['user_compare_text'] ) ? explode( '=====', $answer['user_compare_text'] ) : array();
952
+ if($match_answer == 'sequence'){
953
+ foreach ( $total_answers as $key => $single_answer ) {
954
+ $show_user_answer = $new_array_user_answer[ $key ];
955
+ $is_answer_correct = false;
956
+ if ( mb_strtoupper( $show_user_answer ) == mb_strtoupper( $single_answer[0] ) ) {
957
+ $is_answer_correct = true;
958
+ }
959
+ $index = $key +1;
960
+ if ( $is_answer_correct ) {
961
+ $question_with_answer_text .= '<span class="qsm-text-correct-option qsm-text-user-correct-answer">(' . $index. ') ' . $show_user_answer . '</span>';
962
+ } else {
963
+ if($show_user_answer == '') {
964
+ $show_user_answer = 'No answer provided';
965
+ }
966
+ $question_with_answer_text .= '<span class="qsm-text-wrong-option">(' . $index . ') ' . $show_user_answer . '</span>';
967
+ $question_with_answer_text .= '<span class="qsm-text-correct-option">(' . $index . ') ' . $single_answer[0] . '</span>';
968
+ }
969
+ }
970
+ } else {
971
+ $options = array();
972
+ foreach($total_answers as $key => $single_answer){
973
+ $options[] = mb_strtoupper($single_answer[0]);
974
+ }
975
+ if(sizeof($new_array_user_answer) < sizeof($total_answers)){
976
+ foreach($new_array_user_answer as $show_user_answer){
977
+ $key = array_search( mb_strtoupper($show_user_answer), $options );
978
+ if($key !== false){
979
+ $question_with_answer_text .= '<span class="qsm-text-correct-option qsm-text-user-correct-answer">' . $show_user_answer . '</span>';
980
+ } else {
981
+ if($show_user_answer == '') {
982
+ $show_user_answer = 'No answer provided';
983
+ }
984
+ $question_with_answer_text .= '<span class="qsm-text-wrong-option">' . $show_user_answer . '</span>';
985
+ }
986
+ }
987
+ } else {
988
+ foreach($new_array_user_answer as $show_user_answer){
989
+ $key = array_search( mb_strtoupper($show_user_answer), $options );
990
+ if($key !== false){
991
+ $question_with_answer_text .= '<span class="qsm-text-correct-option qsm-text-user-correct-answer">' . $show_user_answer . '</span>';
992
+ } else {
993
+ if($show_user_answer == '') {
994
+ $show_user_answer = 'No answer provided';
995
+ }
996
+ if($answer['correct'] == 'correct'){
997
+ $question_with_answer_text .= '<span class="qsm-text-simple-option">' . $show_user_answer . '</span>';
998
+ } else {
999
+ $question_with_answer_text .= '<span class="qsm-text-wrong-option">' . $show_user_answer . '</span>';
1000
+ }
1001
+
1002
+ }
1003
+ }
1004
+ }
1005
+ }
1006
+
1007
  } else {
1008
  if ( $form_type == 0 && ( $quiz_system == 0 || $quiz_system == 3 ) ) {
1009
  if ( isset( $answer['question_type'] ) && ( $answer['question_type'] == 4 || $answer['question_type'] == 10 ) ) {
readme.txt CHANGED
@@ -4,7 +4,7 @@ Tags: quiz, survey, lead, test, score, exam, questionnaire, question,wordpress q
4
  Requires at least: 4.9
5
  Tested up to: 5.7
6
  Requires PHP: 5.4
7
- Stable tag: 7.2.1
8
  License: GPLv2
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -132,20 +132,36 @@ This is usually a theme conflict. You can [checkout out our common conflict solu
132
  == Screenshots ==
133
 
134
  1. Dashboard
135
- 2. Create New Quiz or Survey
136
- 3. Question Type
137
  4. Questions
138
  5. All Quizzes & Surveys
139
  6. Contact Field
140
- 7. Frontend View
141
- 8. Frontend View with Answer
142
- 9. Answer
143
- 10. Database
144
- 11. Stats
145
- 12. Reporting and analysis result
 
 
 
 
 
 
146
 
147
  == Changelog ==
148
 
 
 
 
 
 
 
 
 
 
 
149
  = 7.2.1 (June 25, 2021) =
150
  * Bug: Fixed layout issues with rtl languages.
151
  * Bug: Fixed issue of user comments not appearing on admin result page.
4
  Requires at least: 4.9
5
  Tested up to: 5.7
6
  Requires PHP: 5.4
7
+ Stable tag: 7.2.2
8
  License: GPLv2
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
132
  == Screenshots ==
133
 
134
  1. Dashboard
135
+ 2. Create New Quiz Or Survey
136
+ 3. Adding Questions / Answers
137
  4. Questions
138
  5. All Quizzes & Surveys
139
  6. Contact Field
140
+ 7. Style Tab
141
+ 8. Featured Image
142
+ 9. Frontend View with Answer
143
+ 10. Answer
144
+ 11. Database
145
+ 12. Stats
146
+ 13. Reporting and analysis result
147
+ 14. Customizing Themes
148
+ 15. QSM Breeze Theme
149
+ 16. QSM Fragrance Theme
150
+ 17. QSM Ivory Theme
151
+ 18. QSM Pool Theme
152
 
153
  == Changelog ==
154
 
155
+ = 7.2.2 (July 14, 2021) =
156
+ * Feature: Implemented multiple fill in the blanks support.
157
+ * Feature: Implemented new template variable %TIMER_SECONDS% to show left over seconds.
158
+ * Feature: Implemented new option to limit number of questions per category.
159
+ * Bug: Fixed issue with template variable %AMOUNT_INCORRECT%.
160
+ * Bug: Fixed issue of undefined index notice of facebook app id.
161
+ * Bug: Fixed issue with saving conditions in email and results tab.
162
+ * Bug: Fixed issue of wordpress database error notice on fresh installation.
163
+ * Bug: Fixed issue with validation on retake quiz
164
+
165
  = 7.2.1 (June 25, 2021) =
166
  * Bug: Fixed layout issues with rtl languages.
167
  * Bug: Fixed issue of user comments not appearing on admin result page.