Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/quiz-master-next/blocks/block.php
+++ b/quiz-master-next/blocks/block.php
@@ -35,7 +35,6 @@
add_action( 'enqueue_block_editor_assets', array( $this, 'register_block_scripts' ) );
add_action( 'rest_api_init', array( $this, 'register_editor_rest_routes' ) );
-
}
/**
@@ -64,7 +63,6 @@
)
);
}
-
}
/**
@@ -108,7 +106,7 @@
* Get hierarchical qsm_category
*/
private function hierarchical_qsm_category( $cat = 0 ) {
- $category = [];
+ $category = array();
$next = get_categories( array(
'taxonomy' => 'qsm_category',
'hide_empty' => false,
@@ -364,7 +362,6 @@
);
//save pages and question order inside page : qsm_ajax_save_pages()
-
}
/**
@@ -661,9 +658,7 @@
'status' => 'success',
'msg' => __( 'Quiz saved successfully', 'quiz-master-next' ),
);
-
}
-
}
QSMBlock::get_instance();
--- a/quiz-master-next/mlw_quizmaster2.php
+++ b/quiz-master-next/mlw_quizmaster2.php
@@ -2,7 +2,7 @@
/**
* Plugin Name: Quiz And Survey Master
* Description: Easily and quickly add quizzes and surveys to your website.
- * Version: 10.1.0
+ * Version: 11.1.1
* Author: ExpressTech
* Author URI: https://quizandsurveymaster.com/
* Plugin URI: https://expresstech.io/
@@ -43,7 +43,7 @@
* @var string
* @since 4.0.0
*/
- public $version = '10.1.0';
+ public $version = '11.1.1';
/**
* QSM Alert Manager Object
@@ -126,6 +126,14 @@
public $qsm_api;
/**
+ * QSM Abilities Object
+ *
+ * @var object
+ * @since 9.1.0
+ */
+ public $abilities;
+
+ /**
* Holds quiz_data
*
* @var object
@@ -284,6 +292,7 @@
include_once 'php/admin/admin-results-page.php';
include_once 'php/admin/admin-results-details-page.php';
include_once 'php/admin/tools-page.php';
+ include_once 'php/admin/question-bank-page.php';
include_once 'php/classes/class-qsm-changelog-generator.php';
include_once 'php/admin/about-page.php';
include_once 'php/admin/dashboard-widgets.php';
@@ -306,6 +315,10 @@
include_once 'php/classes/class-qsm-emails.php';
include_once 'php/classes/class-qmn-quiz-manager.php';
+ // Load new rendering system files
+ include_once 'renderer/frontend/template-loader.php';
+ include_once 'renderer/frontend/class-qsm-render-pagination.php';
+ include_once 'renderer/frontend/class-qsm-new-renderer.php';
include_once 'php/template-variables.php';
include_once 'php/adverts-generate.php';
include_once 'php/question-types.php';
@@ -335,6 +348,10 @@
include_once 'php/rest-api.php';
include_once 'php/classes/class-qsm-quiz-api.php';
$this->qsm_api = new QSMQuizApi();
+
+ include_once 'php/admin/class-qsm-embed.php';
+ include_once 'php/classes/class-qsm-abilities.php';
+ $this->abilities = new QSM_Abilities();
}
/**
@@ -359,6 +376,48 @@
add_action( 'admin_init', array( $this, 'qsm_overide_old_setting_options' ) );
add_action( 'admin_notices', array( $this, 'qsm_admin_notices' ) );
add_filter( 'manage_edit-qsm_category_columns', array( $this, 'modify_qsm_category_columns' ) );
+ add_action( 'wp_ajax_qsm_mark_setup_wizard_completed', array( $this, 'qsm_mark_setup_wizard_completed' ) );
+ add_action( 'wp_ajax_qsm_reset_setup_wizard_completed', array( $this, 'qsm_reset_setup_wizard_completed' ) );
+ }
+
+ /**
+ * Marks setup wizard as completed for current user.
+ *
+ * @since 0.0.0
+ * @return void
+ */
+ public function qsm_mark_setup_wizard_completed() {
+ if ( ! function_exists( 'is_admin' ) || ! is_admin() || ! current_user_can( 'edit_posts' ) ) {
+ wp_send_json_error(
+ array(
+ 'message' => __( 'Unauthorized!', 'quiz-master-next' ),
+ )
+ );
+ }
+ check_ajax_referer( 'qsm_setup_wizard_nonce', 'nonce' );
+ $user_id = get_current_user_id();
+ update_user_meta( $user_id, 'qsm_setup_wizard_completed', 1 );
+ wp_send_json_success( array( 'completed' => 1 ) );
+ }
+
+ /**
+ * Resets setup wizard completion for current user.
+ *
+ * @since 0.0.0
+ * @return void
+ */
+ public function qsm_reset_setup_wizard_completed() {
+ if ( ! function_exists( 'is_admin' ) || ! is_admin() || ! current_user_can( 'edit_posts' ) ) {
+ wp_send_json_error(
+ array(
+ 'message' => __( 'Unauthorized!', 'quiz-master-next' ),
+ )
+ );
+ }
+ check_ajax_referer( 'qsm_setup_wizard_nonce', 'nonce' );
+ $user_id = get_current_user_id();
+ delete_user_meta( $user_id, 'qsm_setup_wizard_completed' );
+ wp_send_json_success( array( 'completed' => 0 ) );
}
/**
@@ -437,7 +496,7 @@
wp_enqueue_script( 'ChartJS', QSM_PLUGIN_JS_URL . '/chart.min.js', array(), '3.6.0', true );
}
// quiz option pages
- if ( 'admin_page_mlw_quiz_options' === $hook ) {
+ if ( 'admin_page_mlw_quiz_options' === $hook || 'qsm_page_qmn_global_settings' === $hook ) {
wp_enqueue_script( 'wp-tinymce' );
wp_enqueue_script( 'micromodal_script', plugins_url( 'js/micromodal.min.js', __FILE__ ), array( 'jquery', 'qsm_admin_js' ), $this->version, true );
$current_tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : 'questions';
@@ -451,6 +510,16 @@
wp_add_inline_script( 'math_jax', self::$default_MathJax_script, 'before' );
wp_enqueue_editor();
wp_enqueue_media();
+ wp_enqueue_style( 'wp-pointer' );
+ wp_enqueue_script( 'wp-pointer' );
+ wp_enqueue_script( 'qsm_admin_tour_js', plugins_url( 'js/qsm-admin-tour.js', __FILE__ ), array( 'jquery', 'wp-pointer' ), $this->version, true );
+ wp_localize_script(
+ 'qsm_admin_tour_js',
+ 'qsmAdminTourData',
+ array(
+ 'quiz_id' => isset( $_GET['quiz_id'] ) ? intval( $_GET['quiz_id'] ) : 0,
+ )
+ );
break;
case 'style':
wp_enqueue_style( 'wp-color-picker' );
@@ -473,6 +542,7 @@
break;
case 'results-pages':
case 'emails':
+ case 'quiz-default-template':
wp_enqueue_script( 'select2-js', QSM_PLUGIN_JS_URL.'/jquery.select2.min.js', array( 'jquery' ), $this->version,true);
wp_enqueue_style( 'select2-css', QSM_PLUGIN_CSS_URL . '/jquery.select2.min.css', array(), $this->version );
wp_enqueue_editor();
@@ -484,15 +554,35 @@
break;
}
}
+
+ if ( ! wp_script_is( 'select2-js', 'registered' ) ) {
+ wp_register_script( 'select2-js', QSM_PLUGIN_JS_URL . '/jquery.select2.min.js', array( 'jquery' ), $this->version, true );
+ }
+ if ( ! wp_style_is( 'select2-css', 'registered' ) ) {
+ wp_register_style( 'select2-css', QSM_PLUGIN_CSS_URL . '/jquery.select2.min.css', array(), $this->version );
+ }
// load admin JS after all dependencies are loaded
/** Fixed wpApiSettings is not defined js error by using 'wp-api-request' core script to allow the use of localized version of wpApiSettings. **/
- wp_enqueue_script( 'qsm_admin_js', plugins_url( 'js/qsm-admin.js', __FILE__ ), array( 'jquery', 'backbone', 'underscore', 'wp-util', 'jquery-ui-sortable', 'jquery-touch-punch', 'qsm-jquery-multiselect-js', 'wp-api-request' ), $this->version, true );
+ wp_enqueue_script( 'qsm_admin_js', plugins_url( 'js/qsm-admin.js', __FILE__ ), array( 'jquery', 'backbone', 'underscore', 'wp-util', 'jquery-ui-sortable', 'jquery-touch-punch', 'qsm-jquery-multiselect-js', 'wp-api-request', 'select2-js' ), $this->version, true );
wp_enqueue_style( 'jquer-multiselect-css', QSM_PLUGIN_CSS_URL . '/jquery.multiselect.min.css', array(), $this->version );
wp_enqueue_script( 'qsm-jquery-multiselect-js', QSM_PLUGIN_JS_URL . '/jquery.multiselect.min.js', array( 'jquery' ), $this->version, true );
wp_enqueue_script( 'micromodal_script', plugins_url( 'js/micromodal.min.js', __FILE__ ), array( 'jquery', 'qsm_admin_js' ), $this->version, true );
$qsm_variables = function_exists( 'qsm_text_template_variable_list' ) ? qsm_text_template_variable_list() : array();
$qsm_variables_name = array();
$qsm_quizzes = $wpdb->get_results("SELECT quiz_id, quiz_name FROM {$wpdb->prefix}mlw_quizzes");
+ $current_quiz_id = isset( $_GET['quiz_id'] ) ? intval( $_GET['quiz_id'] ) : 0;
+ $other_quizzes_count = 0;
+ if ( is_array( $qsm_quizzes ) ) {
+ foreach ( $qsm_quizzes as $quiz_obj ) {
+ if ( ! isset( $quiz_obj->quiz_id ) ) {
+ continue;
+ }
+ if ( $current_quiz_id && intval( $quiz_obj->quiz_id ) === $current_quiz_id ) {
+ continue;
+ }
+ $other_quizzes_count++;
+ }
+ }
foreach ( $qsm_variables as $key => $value ) {
// Iterate over each key of the nested object
if ( is_array( $value ) && ! empty($value) ) {
@@ -593,6 +683,7 @@
'insert_variable' => __("Insert QSM variables", 'quiz-master-next'),
'select_all' => __("Select All", 'quiz-master-next'),
'select' => __("Select", 'quiz-master-next'),
+ 'quiz_count' => $other_quizzes_count,
'qsmQuizzesObject' => $qsm_quizzes,
'arrow_up_image' => esc_url(QSM_PLUGIN_URL . 'assets/arrow-up-s-line.svg'),
'arrow_down_image' => esc_url(QSM_PLUGIN_URL . 'assets/arrow-down-s-line.svg'),
@@ -615,10 +706,58 @@
'success_icon' => esc_url(QSM_PLUGIN_URL . 'assets/success-message.png'),
'warning_icon' => esc_url(QSM_PLUGIN_URL . 'assets/warning-message.png'),
'info_icon' => esc_url(QSM_PLUGIN_URL . 'assets/info-message.png'),
+ 'question_shuffle' => __('Question shuffled successfully!', 'quiz-master-next'),
+ 'is_migration_done' => get_option( 'qsm_migration_results_processed', 0 ),
+ 'guided_wizard' => array(
+ 'storage_key' => 'qsm_setup_wizard_completed',
+ 'completed' => (int) get_user_meta( get_current_user_id(), 'qsm_setup_wizard_completed', true ),
+ 'nonce' => wp_create_nonce( 'qsm_setup_wizard_nonce' ),
+ 'guided_wizard' => __('Guided Wizard', 'quiz-master-next'),
+ 'answer_limit_area' => __('Set how many answers users can select.', 'quiz-master-next'),
+ 'grading_mode_area' => __('Choose how this question should be graded.', 'quiz-master-next'),
+ 'add_poll_type_area' => __('Turn this into a poll to show how others responded.', 'quiz-master-next'),
+ 'correct_answer_info_area' => __('Add an explanation to support the correct answer.', 'quiz-master-next'),
+ 'comments_area' => __('Allow users to add comments for this question.', 'quiz-master-next'),
+ 'hint_area' => __('Provide a hint to guide users before answering.', 'quiz-master-next'),
+ 'first_question' => __('Create your first question', 'quiz-master-next'),
+ 'question_type' => __('Choose your question type.', 'quiz-master-next'),
+ 'question_title' => __('Question Title', 'quiz-master-next'),
+ 'question_title_desc' => __('Write the question you want to ask your users.', 'quiz-master-next'),
+ 'add_answer' => __('Add Answers', 'quiz-master-next'),
+ 'add_answer_text' => __('Add all possible answers for this question.', 'quiz-master-next'),
+ 'add_answer_desc1' => __('Use the', 'quiz-master-next'),
+ 'add_answer_desc2' => __('buttons to add or remove answers.', 'quiz-master-next'),
+ 'add_answer_desc3' => __('Assign', 'quiz-master-next'),
+ 'add_answer_desc4' => __('points', 'quiz-master-next'),
+ 'add_answer_desc5' => __('and mark the', 'quiz-master-next'),
+ 'add_answer_desc6' => __('correct answer', 'quiz-master-next'),
+ 'add_answer_desc7' => __('Select the appropriate', 'quiz-master-next'),
+ 'add_answer_desc8' => __('label', 'quiz-master-next'),
+ 'add_answer_desc9' => __('(Optional).', 'quiz-master-next'),
+ 'save_question' => __('Save Question', 'quiz-master-next'),
+ 'save_question_desc' => __('Click <strong>Save Question</strong> to save your first question.', 'quiz-master-next'),
+ 'feature_image' => __( 'Featured Image (Optional)', 'quiz-master-next'),
+ 'feature_image_desc' => __( 'Add an image to visually enhance this question.', 'quiz-master-next'),
+ 'category' => __( 'Category (Optional)', 'quiz-master-next'),
+ 'category_desc' => __( 'Assign this question to one or more categories to organize, filter, and reuse it across quizzes.', 'quiz-master-next'),
+ 'question_status' => __( 'Published / Draft', 'quiz-master-next'),
+ 'question_status_desc1' => __( 'Use the toggle to switch between Draft and Published.', 'quiz-master-next'),
+ 'question_status_desc2' => __( 'Set it to Published to make the question available in quizzes, or keep it as Draft to continue editing.', 'quiz-master-next'),
+ 'advance_setting' => __( 'Advanced Settings', 'quiz-master-next'),
+ 'advance_setting_desc1' => __( 'Here you can configure advanced settings for this question.', 'quiz-master-next'),
+ 'advance_setting_desc2' => __( 'Use this section to control evaluation and learner feedback.', 'quiz-master-next'),
+ 'save_updates' => __( 'Save your updates', 'quiz-master-next'),
+ 'save_updates_desc' => __( 'Click “Save Question” to apply your changes and complete the setup', 'quiz-master-next'),
+ 'congrats2' => __( 'Congratulations!', 'quiz-master-next'),
+ 'congrats2_desc1' => __( 'Your advanced settings have been saved successfully.', 'quiz-master-next'),
+ 'congrats2_desc2' => __( 'The question logic and behavior are now updated.', 'quiz-master-next'),
+ 'congrats1' => __( 'Great start!', 'quiz-master-next'),
+ 'congrats1_desc1' => __( 'Your question is ready with basic settings.', 'quiz-master-next'),
+ 'congrats1_desc2' => __( 'Now you can customize logic and behavior to unlock its full potential.', 'quiz-master-next'),
+ ),
);
$qsm_admin_messages = apply_filters( 'qsm_admin_messages_after', $qsm_admin_messages );
wp_localize_script( 'qsm_admin_js', 'qsm_admin_messages', $qsm_admin_messages );
-
}
/**
@@ -797,17 +936,19 @@
return;
}
$roles = (array) $user->roles;
+ if ( empty( $roles ) || ! isset($roles[0]) || ! is_string($roles[0]) ) {
+ return;
+ }
$rolename = $roles[0];
$role = get_role( $rolename );
if ( ! $role ) {
return;
}
-
// Dynamically determine the capabilities to add based on the current user role.
$capabilities_to_add = isset(${$rolename . '_capabilities'}) ? ${$rolename . '_capabilities'} : array();
$capabilities_to_add = apply_filters(
'qsm_default_user_capabilities',
- isset(${$rolename . '_capabilities'}) ? array_unique( array_merge( $capabilities_to_add, $contributor_capabilities ) ) : [],
+ isset(${$rolename . '_capabilities'}) ? array_unique( array_merge( $capabilities_to_add, $contributor_capabilities ) ) : array(),
$user
);
@@ -898,6 +1039,7 @@
add_submenu_page( 'qsm_dashboard', __( 'Tools', 'quiz-master-next' ), __( 'Tools', 'quiz-master-next' ), $capabilities[2], 'qsm_quiz_tools', 'qsm_generate_quiz_tools' );
add_submenu_page( 'qsm_dashboard', __( 'Stats', 'quiz-master-next' ), __( 'Stats', 'quiz-master-next' ), $capabilities[2], 'qmn_stats', 'qmn_generate_stats_page' );
add_submenu_page( 'qsm_dashboard', __( 'About', 'quiz-master-next' ), __( 'About', 'quiz-master-next' ), $capabilities[2], 'qsm_quiz_about', 'qsm_generate_about_page' );
+ add_submenu_page( 'qsm_dashboard', __( 'Question Bank', 'quiz-master-next' ), __( 'Question Bank', 'quiz-master-next' ), $capabilities[6], 'qsm_question_bank', 'qsm_render_question_bank_page', 2 );
add_submenu_page( 'qsm_dashboard', __( 'Extensions Settings', 'quiz-master-next' ), '<span style="color:#f39c12;">' . __( 'Extensions', 'quiz-master-next' ) . '</span>', $capabilities[2], 'qmn_addons', 'qmn_addons_page', 34 );
add_submenu_page( 'qsm_dashboard', __( 'Free Add-ons', 'quiz-master-next' ), '<span style="color:#f39c12;">' . esc_html__( 'Free Add-ons', 'quiz-master-next' ) . '</span>', $capabilities[2], 'qsm-free-addon', 'qsm_display_optin_page', 90 );
@@ -943,8 +1085,8 @@
$question_terms_table_name = $wpdb->prefix . 'mlw_question_terms';
// List of tables and their columns
- $tables = [
- $quiz_table_name => [
+ $tables = array(
+ $quiz_table_name => array(
'quiz_id',
'quiz_name',
'message_before',
@@ -1001,8 +1143,8 @@
'quiz_taken',
'deleted',
'quiz_author_id',
- ],
- $question_table_name => [
+ ),
+ $question_table_name => array(
'question_id',
'quiz_id',
'question_name',
@@ -1030,8 +1172,8 @@
'category',
'deleted',
'deleted_question_bank',
- ],
- $results_table_name => [
+ ),
+ $results_table_name => array(
'result_id',
'quiz_id',
'quiz_name',
@@ -1054,8 +1196,8 @@
'form_type',
'page_name',
'page_url',
- ],
- $audit_table_name => [
+ ),
+ $audit_table_name => array(
'trail_id',
'action_user',
'action',
@@ -1063,32 +1205,32 @@
'quiz_name',
'form_data',
'time',
- ],
- $themes_table_name => [
+ ),
+ $themes_table_name => array(
'id',
'theme',
'theme_name',
'default_settings',
'theme_active',
- ],
- $quiz_themes_settings_table_name => [
+ ),
+ $quiz_themes_settings_table_name => array(
'id',
'theme_id',
'quiz_id',
'quiz_theme_settings',
'active_theme',
- ],
- $question_terms_table_name => [
+ ),
+ $question_terms_table_name => array(
'id',
'question_id',
'quiz_id',
'term_id',
'taxonomy',
- ],
- ];
+ ),
+ );
$response['message'] = "";
// Check all tables
- $errors = [];
+ $errors = array();
foreach ( $tables as $table_name => $columns ) {
$error = $this->qsm_check_table_structure($table_name, $columns);
if ( $error ) {
@@ -1129,7 +1271,7 @@
return esc_html__("Table ", "quiz-master-next") . $table_name . esc_html__(" does not exist.", "quiz-master-next");
}
$existing_columns = array_column($columns, 'Field');
- $missing_columns = [];
+ $missing_columns = array();
foreach ( $expected_columns as $column ) {
if ( ! in_array($column, $existing_columns, true) ) {
$missing_columns[] = $column;
@@ -1223,14 +1365,19 @@
}
/**
- * Displays QSM Admin notices
+ * Admin notices.
*
- * @return void
* @since 7.3.0
+ * @return void
*/
public function qsm_admin_notices() {
+ if ( ! is_user_logged_in() || ! current_user_can( 'manage_options' ) ) {
+ return;
+ }
+
$multiple_categories = get_option( 'qsm_multiple_category_enabled' );
if ( ! $multiple_categories ) {
+ $nonce = wp_create_nonce( 'qsm_enable_multiple_categories' );
?>
<div class="notice notice-info multiple-category-notice" style="display:none;">
<h3><?php esc_html_e( 'Database update required', 'quiz-master-next' ); ?></h3>
@@ -1239,19 +1386,19 @@
<?php esc_html_e( 'We need to upgrade your database so that you can enjoy the latest features.', 'quiz-master-next' ); ?><br>
<?php
/* translators: %s: HTML tag */
- echo sprintf( esc_html__( 'Please note that this action %1$s can not be %2$s rolled back. We recommend you to take a backup of your current site before proceeding.', 'quiz-master-next' ), '<b>', '</b>' );
+ printf( esc_html__( 'Please note that this action %1$s can not be %2$s rolled back. We recommend you to take a backup of your current site before proceeding.', 'quiz-master-next' ), '<b>', '</b>' );
?>
</p>
<p class="category-action">
- <a href="javascrip:void(0)" class="button cancel-multiple-category"><?php esc_html_e( 'Cancel', 'quiz-master-next' ); ?></a>
- <a href="javascript:void(0)" class="button button-primary enable-multiple-category"><?php esc_html_e( 'Update Database', 'quiz-master-next' ); ?></a>
+ <a href="javascrip:void(0)" class="button cancel-multiple-category" data-qsm-mc-nonce="<?php echo esc_attr( $nonce ); ?>"><?php esc_html_e( 'Cancel', 'quiz-master-next' ); ?></a>
+ <a href="javascript:void(0)" class="button button-primary enable-multiple-category" data-qsm-mc-nonce="<?php echo esc_attr( $nonce ); ?>"><?php esc_html_e( 'Update Database', 'quiz-master-next' ); ?></a>
</p>
</div>
<?php
}
- $settings = (array) get_option( 'qmn-settings' );
- $background_quiz_email_process = isset( $settings['background_quiz_email_process'] ) ? $settings['background_quiz_email_process'] : 1;
+ $settings = (array) get_option( 'qmn-settings' );
+ $background_quiz_email_process = isset( $settings['background_quiz_email_process'] ) ? $settings['background_quiz_email_process'] : 1;
if ( 1 == $background_quiz_email_process && is_plugin_active( 'wpml-string-translation/plugin.php' ) ) {
?>
<div class="notice notice-warning">
@@ -1265,6 +1412,8 @@
global $mlwQuizMasterNext;
$mlwQuizMasterNext = new MLWQuizMasterNext();
register_activation_hook( __FILE__, array( 'QSM_Install', 'install' ) );
+register_activation_hook( __FILE__, array( 'QSM_Embed', 'on_activation' ) );
+register_deactivation_hook( __FILE__, array( 'QSM_Embed', 'on_deactivation' ) );
/**
* Displays QSM Admin bar menu
--- a/quiz-master-next/php/admin/about-page.php
+++ b/quiz-master-next/php/admin/about-page.php
@@ -21,20 +21,20 @@
if ( ! current_user_can( 'delete_others_qsm_quizzes' ) ) {
return;
}
- $tab_array = [
- [
+ $tab_array = array(
+ array(
'slug' => 'about',
'title' => 'About',
- ],
- [
+ ),
+ array(
'slug' => 'help',
'title' => 'Help',
- ],
- [
+ ),
+ array(
'slug' => 'system_info',
'title' => 'System Info',
- ],
- ];
+ ),
+ );
$active_tab = isset($_GET['tab']) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : 'about';
// Creates the widgets.
@@ -138,7 +138,7 @@
*/
function qsm_documentation_meta_box_content() {
global $mlwQuizMasterNext;
- wp_enqueue_style( 'qsm_result_page_style', plugins_url( '../css/qsm-admin.css', __FILE__ ), array(), $mlwQuizMasterNext->version );
+ wp_enqueue_style( 'qsm_result_page_style', QSM_PLUGIN_CSS_URL.'/qsm-admin.css', array(), $mlwQuizMasterNext->version );
?>
<div class="help-slide">
<div>
@@ -155,9 +155,9 @@
</div>
<div>
<img src="<?php echo esc_url( QSM_PLUGIN_URL . 'assets/services.png' )?> " alt="services">
- <h3><?php esc_html_e( 'Need Customization Service?', 'quiz-master-next' ); ?></h3>
+ <h3><?php esc_html_e( 'See All Services', 'quiz-master-next' ); ?></h3>
<p><?php esc_html_e( 'Tailor Quiz and Survey Master to your specific needs with our professional customization services for unique functionality.', 'quiz-master-next' ); ?></p>
- <a href="<?php echo esc_url( qsm_get_plugin_link( 'docs', 'qsm', 'help', 'about_help_documentation' ) );?>" rel="noopener" target="_blank"><?php esc_html_e( 'Documentation', 'quiz-master-next' ); ?></a>
+ <a href="<?php echo esc_url( qsm_get_utm_link( 'https://justhyre.com/customize-qsm/', 'qsm', 'help', 'see_all_services' ) ); ?>" rel="noopener" target="_blank"><?php esc_html_e( 'See All Services', 'quiz-master-next' ); ?></a>
</div>
</div>
<?php
--- a/quiz-master-next/php/admin/addons-page.php
+++ b/quiz-master-next/php/admin/addons-page.php
@@ -180,7 +180,7 @@
</a>
</div>
</div>
- <?php $count++;
+ <?php ++$count;
} ?>
</div>
<?php } ?>
@@ -200,7 +200,7 @@
$mlwQuizMasterNext->pluginHelper->register_addon_settings_tab( __( 'Featured Addons', 'quiz-master-next' ), 'qsm_generate_featured_addons' );
}
-add_action( 'plugins_loaded', 'qsm_featured_addons_tab' );
+add_action( 'init', 'qsm_featured_addons_tab' );
/**
* @version 3.2.0
--- a/quiz-master-next/php/admin/admin-dashboard.php
+++ b/quiz-master-next/php/admin/admin-dashboard.php
@@ -13,12 +13,12 @@
* @since 7.3.5
* @return array $blog_data
*/
-function qsm_get_blog_data_rss(){
- include_once( ABSPATH . WPINC . '/feed.php' );
+function qsm_get_blog_data_rss() {
+ include_once ABSPATH . WPINC . '/feed.php';
$blog_data_obj = fetch_feed( 'https://quizandsurveymaster.com/feed/' );
- $maxitems = 0;
+ $maxitems = 0;
if ( ! is_wp_error( $blog_data_obj ) ) {
- $maxitems = $blog_data_obj->get_item_quantity( 2 );
+ $maxitems = $blog_data_obj->get_item_quantity( 2 );
$blog_data_items = $blog_data_obj->get_items( 0, $maxitems );
}
$blog_data = array();
@@ -55,31 +55,33 @@
function qsm_check_plugins_compatibility() {
global $mlwQuizMasterNext;
- if ( class_exists('QSM_Installer') ) {
+ if ( class_exists( 'QSM_Installer' ) ) {
$plugin_path = WP_PLUGIN_DIR . '/qsm-installer/qsm-installer.php';
- $plugin_data = get_plugin_data( $plugin_path );
+ $plugin_data = get_plugin_data( $plugin_path );
- // Check if the plugin version is below 2.0.0
- if ( isset( $plugin_data['Version'] ) && version_compare( $plugin_data['Version'], '2.0.0', '<' ) ) {
+ // Check if the plugin version is below 2.0.0
+ if ( isset( $plugin_data['Version'] ) && version_compare( $plugin_data['Version'], '2.0.0', '<' ) ) {
$account_url = esc_url( qsm_get_utm_link( 'https://quizandsurveymaster.com/account', 'dashboard', 'useful_links', 'qsm_installer_update' ) );
?>
<div class="qsm-dashboard-help-center qsm-dashboard-warning-container">
<div class="qsm-dashboard-error-content">
- <h3><?php esc_html_e('Update Available', 'quiz-master-next'); ?></h3>
- <p><?php esc_html_e('We recommend downloading the latest version of the QSM Installer for a seamless quiz and survey creation experience.', 'quiz-master-next'); ?></p>
- <a href="<?php echo esc_url($account_url); ?>" class="qsm-dashboard-error-btn" target="_blank">
- <?php esc_html_e('Get Latest QSM Installer', 'quiz-master-next'); ?>
+ <h3><?php esc_html_e( 'Update Available', 'quiz-master-next' ); ?></h3>
+ <p><?php esc_html_e( 'We recommend downloading the latest version of the QSM Installer for a seamless quiz and survey creation experience.', 'quiz-master-next' ); ?></p>
+ <a href="<?php echo esc_url( $account_url ); ?>" class="qsm-dashboard-error-btn" target="_blank">
+ <?php esc_html_e( 'Get Latest QSM Installer', 'quiz-master-next' ); ?>
</a>
</div>
</div>
- <?php
+ <?php
}
}
+
+ do_action( 'qsm_admin_dashboard_compatibility_after' );
}
-function qsm_dashboard_display_change_log_section(){
+function qsm_dashboard_display_change_log_section() {
global $wp_filesystem, $mlwQuizMasterNext;
- require_once ( ABSPATH . '/wp-admin/includes/file.php' );
+ require_once ABSPATH . '/wp-admin/includes/file.php';
WP_Filesystem();
$change_log = array();
$readme_file = QSM_PLUGIN_PATH . 'readme.txt';
@@ -88,9 +90,9 @@
if ( $file_content ) {
$parts = explode( '== Changelog ==', $file_content, 2 );
if ( isset( $parts[1] ) ) {
- preg_match_all('/* (.+)/', $parts[1], $matches);
- if ( ! empty($matches[1]) ) {
- $change_log = array_slice($matches[1], 0, 5);
+ preg_match_all( '/* (.+)/', $parts[1], $matches );
+ if ( ! empty( $matches[1] ) ) {
+ $change_log = array_slice( $matches[1], 0, 5 );
}
}
}
@@ -122,7 +124,7 @@
<p><?php echo wp_kses_post( $cl_str ); ?></p>
</li>
<?php
- $i ++;
+ ++$i;
}
}
?>
@@ -137,56 +139,56 @@
<?php
}
-function qsm_dashboard_display_need_help_section(){
+function qsm_dashboard_display_need_help_section() {
// Define sections
- $sections = [
- [
- 'title' => __('Documentation', 'quiz-master-next'),
- 'description' => __('Find detailed guides and step-by-step instructions to help you explore and utilize all the features of the QSM plugin effectively.', 'quiz-master-next'),
+ $sections = array(
+ array(
+ 'title' => __( 'Documentation', 'quiz-master-next' ),
+ 'description' => __( 'Find detailed guides and step-by-step instructions to help you explore and utilize all the features of the QSM plugin effectively.', 'quiz-master-next' ),
'image' => QSM_PLUGIN_URL . 'assets/contact.png',
'alt' => 'contact.png',
- 'link' => qsm_get_plugin_link('docs', 'dashboard', 'next_steps', 'dashboard_read_document'),
- ],
- [
- 'title' => __('Demos', 'quiz-master-next'),
- 'description' => __('Explore live examples of quizzes and surveys built with QSM to see its features in action.', 'quiz-master-next'),
+ 'link' => qsm_get_plugin_link( 'docs', 'dashboard', 'next_steps', 'dashboard_read_document' ),
+ ),
+ array(
+ 'title' => __( 'Demos', 'quiz-master-next' ),
+ 'description' => __( 'Explore live examples of quizzes and surveys built with QSM to see its features in action.', 'quiz-master-next' ),
'image' => QSM_PLUGIN_URL . 'assets/camera.png',
'alt' => 'camera.png',
- 'link' => qsm_get_utm_link('https://demo.quizandsurveymaster.com/', 'demos', 'dashboard', 'useful_links', 'dashboard_demos'),
+ 'link' => qsm_get_utm_link( 'https://demo.quizandsurveymaster.com/', 'demos', 'dashboard', 'useful_links', 'dashboard_demos' ),
- ],
- [
- 'title' => __('FAQ', 'quiz-master-next'),
- 'description' => __('Get quick answers to commonly asked questions about QSM, covering troubleshooting, setup, and best practices.', 'quiz-master-next'),
+ ),
+ array(
+ 'title' => __( 'FAQ', 'quiz-master-next' ),
+ 'description' => __( 'Get quick answers to commonly asked questions about QSM, covering troubleshooting, setup, and best practices.', 'quiz-master-next' ),
'image' => QSM_PLUGIN_URL . 'assets/faq.png',
'alt' => 'faq.png',
'link' => 'https://quizandsurveymaster.com/#:~:text=Frequently%20asked%20questions',
- ],
- [
- 'title' => __('Contact Support', 'quiz-master-next'),
- 'description' => __('Need further assistance? Reach out to our support team for personalized help with any issues or queries related to QSM.', 'quiz-master-next'),
+ ),
+ array(
+ 'title' => __( 'Contact Support', 'quiz-master-next' ),
+ 'description' => __( 'Need further assistance? Reach out to our support team for personalized help with any issues or queries related to QSM.', 'quiz-master-next' ),
'image' => QSM_PLUGIN_URL . 'assets/dashboard-support.png',
'alt' => 'dashboard-support.png',
- 'link' => qsm_get_plugin_link('contact-support', 'dashboard', 'useful_links', 'dashboard_support'),
- ],
- ];
+ 'link' => qsm_get_plugin_link( 'contact-support', 'dashboard', 'useful_links', 'dashboard_support' ),
+ ),
+ );
?>
<div class="qsm-dashboard-help-center">
- <h3 class="qsm-dashboard-help-center-title"><?php echo esc_html__('Need Help?', 'quiz-master-next'); ?></h3>
+ <h3 class="qsm-dashboard-help-center-title"><?php echo esc_html__( 'Need Help?', 'quiz-master-next' ); ?></h3>
<div class="qsm-dashboard-help-center-grid qsm-dashboard-page-common-style">
<?php foreach ( $sections as $section ) : ?>
<div class="qsm-dashboard-help-center-card">
<div class="qsm-dashboard-help-center-card-icon">
<div class="qsm-dashboard-help-icon-wrap">
- <img class="qsm-dashboard-help-image" src="<?php echo esc_url($section['image']); ?>" alt="<?php echo esc_attr($section['alt']); ?>"/>
+ <img class="qsm-dashboard-help-image" src="<?php echo esc_url( $section['image'] ); ?>" alt="<?php echo esc_attr( $section['alt'] ); ?>"/>
</div>
</div>
<h3 class="qsm-dashboard-help-center-card-title">
- <a target="_blank" rel="noopener" href="<?php echo esc_url( $section['link'] )?>" class="welcome-icon"><?php echo esc_html($section['title']); ?></a>
+ <a target="_blank" rel="noopener" href="<?php echo esc_url( $section['link'] ); ?>" class="welcome-icon"><?php echo esc_html( $section['title'] ); ?></a>
</h3>
<p class="qsm-dashboard-help-center-card-description">
- <?php echo esc_html($section['description']); ?>
+ <?php echo esc_html( $section['description'] ); ?>
</p>
</div>
<?php endforeach; ?>
@@ -196,8 +198,8 @@
}
function qsm_dashboard_display_popular_addon_section( $popular_addons ) {
- $desiredOrder = [ 572582, 591230, 567900, 3437 ];
- $sortedAddons = [];
+ $desiredOrder = array( 572582, 591230, 567900, 3437 );
+ $sortedAddons = array();
foreach ( $desiredOrder as $id ) {
foreach ( $popular_addons as $addon ) {
if ( $addon['id'] == $id ) {
@@ -207,11 +209,12 @@
}
?>
<div class="qsm-dashboard-help-center">
- <h3 class="qsm-dashboard-help-center-title"><?php echo esc_html__('Explore Addons', 'quiz-master-next'); ?></h3>
+ <h3 class="qsm-dashboard-help-center-title"><?php echo esc_html__( 'Explore Addons', 'quiz-master-next' ); ?></h3>
<div class="qsm-dashboard-help-center-grid qsm-dashboard-page-common-style">
- <?php foreach ( array_slice($sortedAddons, 0, 4) as $addon ) :
+ <?php
+ foreach ( array_slice( $sortedAddons, 0, 4 ) as $addon ) :
$addon_link = qsm_get_utm_link( $addon['link'], 'addon_setting', 'popular_addon', 'addon-settings_' . sanitize_title( $addon['name'] ) );
- $addon_icon = isset($addon['icon']) && "" != $addon['icon'] ? $addon['icon'] : QSM_PLUGIN_URL . 'assets/chat-smile.png';
+ $addon_icon = isset( $addon['icon'] ) && '' != $addon['icon'] ? $addon['icon'] : QSM_PLUGIN_URL . 'assets/chat-smile.png';
?>
<div class="qsm-dashboard-help-center-card">
<div class="qsm-dashboard-help-center-card-icon">
@@ -220,12 +223,13 @@
</div>
</div>
<h3 class="qsm-dashboard-help-center-card-title">
- <a target="_blank" rel="noopener" href="<?php echo esc_url($addon_link); ?>"><?php echo esc_html($addon['name']); ?></a>
+ <a target="_blank" rel="noopener" href="<?php echo esc_url( $addon_link ); ?>"><?php echo esc_html( $addon['name'] ); ?></a>
</h3>
<p class="qsm-dashboard-help-center-card-description">
- <?php $display_text = mb_strlen($addon['description']) > 110 ? mb_substr($addon['description'], 0, 110) . '...' : $addon['description'];
- echo esc_html($display_text);
- ?>
+ <?php
+ $display_text = mb_strlen( $addon['description'] ) > 110 ? mb_substr( $addon['description'], 0, 110 ) . '...' : $addon['description'];
+ echo esc_html( $display_text );
+ ?>
</p>
</div>
<?php endforeach; ?>
@@ -236,8 +240,8 @@
function qsm_dashboard_display_popular_theme_section( $themes ) {
- $desiredOrder = [ 547794, 557086, 551027, 302299 ];
- $sortedThemes = [];
+ $desiredOrder = array( 547794, 557086, 551027, 302299 );
+ $sortedThemes = array();
foreach ( $desiredOrder as $id ) {
foreach ( $themes as $theme ) {
if ( $theme['id'] == $id ) {
@@ -247,25 +251,148 @@
}
?>
<div class="qsm-dashboard-help-center">
- <h3 class="qsm-dashboard-help-center-title"><?php echo esc_html__('Popular Themes', 'quiz-master-next'); ?></h3>
+ <h3 class="qsm-dashboard-help-center-title"><?php echo esc_html__( 'Popular Themes', 'quiz-master-next' ); ?></h3>
<div class="qsm-dashboard-themes-container qsm-dashboard-page-common-style">
- <?php foreach ( $sortedThemes as $single_theme ) {
- $theme_demo = qsm_get_utm_link( $single_theme['demo'], 'new_quiz', 'themes', 'quizsurvey_preview_' . sanitize_title( $single_theme['name'] ) );
+ <?php
+ foreach ( $sortedThemes as $single_theme ) {
+ $theme_demo = qsm_get_utm_link( $single_theme['demo'], 'new_quiz', 'themes', 'quizsurvey_preview_' . sanitize_title( $single_theme['name'] ) );
?>
<div class="qsm-dashboard-themes-card">
<div class="qsm-dashboard-themes-image-wrapper">
- <img src="<?php echo esc_url($single_theme['img']); ?>" alt="<?php echo esc_attr($single_theme['name']); ?>">
+ <img src="<?php echo esc_url( $single_theme['img'] ); ?>" alt="<?php echo esc_attr( $single_theme['name'] ); ?>">
</div>
<div class="qsm-dashboard-themes-details-wrapper">
- <h3><?php echo esc_html($single_theme['name']); ?></h3>
- <a class="button button-secondary" target="_blank" href="<?php echo esc_url($theme_demo); ?>" class="qsm-dashboard-themes-button"><?php echo esc_html__('Demo', 'quiz-master-next'); ?></a>
+ <h3><?php echo esc_html( $single_theme['name'] ); ?></h3>
+ <a class="button button-secondary" target="_blank" href="<?php echo esc_url( $theme_demo ); ?>" class="qsm-dashboard-themes-button"><?php echo esc_html__( 'Demo', 'quiz-master-next' ); ?></a>
</div>
</div>
<?php } ?>
</div>
</div>
-<?php
+ <?php
}
+
+/**
+ * Display recently quiz taken section on dashboard
+ *
+ * @since 10.2.7
+ */
+
+function qsm_dashboard_recent_taken_quiz() {
+ global $wpdb, $mlwQuizMasterNext;
+ $mlw_result_data = $wpdb->get_row( "SELECT DISTINCT COUNT(result_id) as total_result FROM {$wpdb->prefix}mlw_results WHERE deleted=0", ARRAY_A );
+ if ( 0 != $mlw_result_data['total_result'] ) {
+ ?>
+ <div class="qsm-dashboard-help-center">
+ <h3 class="qsm-dashboard-help-center-title"><?php esc_html_e( 'Recent Activity', 'quiz-master-next' ); ?></h3>
+ <div class="qsm-dashboard-recently-taken-quiz qsm-dashboard-page-common-style">
+ <a href="admin.php?page=mlw_quiz_results" style="color: #fff;" class="button button-primary qsm-dashboard-view-all-results">
+ <?php
+ echo esc_html__( 'See All Results ', 'quiz-master-next' );
+ echo isset( $mlw_result_data['total_result'] ) ? ' (' . wp_kses_post( $mlw_result_data['total_result'] ) . ')' : '';
+ ?>
+ </a>
+ <ul class="recently-taken-quiz-ul">
+ <?php
+ $mlw_result_data = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}mlw_results WHERE deleted=0 ORDER BY result_id DESC LIMIT 2", ARRAY_A );
+ if ( $mlw_result_data ) {
+ foreach ( $mlw_result_data as $key => $single_result_arr ) {
+ ?>
+ <li>
+ <?php
+ if ( isset( $single_result_arr['user'] ) && '' !== $single_result_arr['user'] ) {
+ echo '<img src="' . esc_url( get_avatar_url( $single_result_arr['user'] ) ) . '" class="avatar avatar-50 photo" alt="User Avatar">';
+ } else {
+ echo '<img src="' . esc_url( QSM_PLUGIN_URL . '/assets/default_image.png' ) . '" class="avatar avatar-50 photo" alt="Default Image">';
+ }
+ ?>
+ <div class="rtq-main-wrapper">
+ <span class="rtq_user_info">
+ <?php
+ if ( isset( $single_result_arr['user'] ) && 0 !== intval( $single_result_arr['user'] ) ) {
+ $edit_link = get_edit_profile_url( $single_result_arr['user'] );
+ $actual_user = get_userdata( $single_result_arr['user'] );
+ $user_name = 'None' === $single_result_arr['name'] ? $actual_user->data->display_name : $single_result_arr['name'];
+ echo '<a href="' . esc_url( $edit_link ) . '">' . esc_html( $user_name ) . '</a>';
+ } else {
+ esc_html_e( 'Guest', 'quiz-master-next' );
+ }
+ esc_html_e( ' took quiz ', 'quiz-master-next' );
+ echo '<a href="admin.php?page=mlw_quiz_options&quiz_id=' . esc_attr( $single_result_arr['quiz_id'] ) . '">' . esc_html( $single_result_arr['quiz_name'] ) . '</a>';
+ ?>
+ </span>
+ <span class="rtq-result-info">
+ <?php
+ $quotes_list = '';
+ $form_type = isset( $single_result_arr['form_type'] ) ? $single_result_arr['form_type'] : 0;
+ if ( 1 === intval( $form_type ) || 2 === intval( $form_type ) ) {
+ $quotes_list .= __( 'Not Graded', 'quiz-master-next' );
+ } else {
+ if ( 0 === intval( $single_result_arr['quiz_system'] ) ) {
+ $quotes_list .= $single_result_arr['correct'] . ' out of ' . $single_result_arr['total'] . ' or ' . $single_result_arr['correct_score'] . '%';
+ }
+ if ( 1 === intval( $single_result_arr['quiz_system'] ) ) {
+ $quotes_list .= $single_result_arr['point_score'] . ' Points';
+ }
+ if ( 3 === intval( $single_result_arr['quiz_system'] ) ) {
+ $quotes_list .= $single_result_arr['correct'] . ' out of ' . $single_result_arr['total'] . ' or ' . $single_result_arr['correct_score'] . '%<br/>';
+ $quotes_list .= $single_result_arr['point_score'] . ' Points';
+ }
+ }
+ echo wp_kses_post( $quotes_list );
+ ?>
+ |
+ <?php
+ $mlw_complete_time = '';
+ $is_new_format = $mlwQuizMasterNext->pluginHelper->is_new_format_result( $single_result_arr );
+ if ( $is_new_format ) {
+ // Load new format result structure
+ $mlw_qmn_results_array = $mlwQuizMasterNext->pluginHelper->get_formated_result_data( $single_result_arr['result_id'] );
+ } else {
+ $mlw_qmn_results_array = maybe_unserialize( $single_result_arr['quiz_results'] );
+ }
+ if ( is_array( $mlw_qmn_results_array ) ) {
+ $mlw_complete_hours = floor( $mlw_qmn_results_array[0] / 3600 );
+ if ( $mlw_complete_hours > 0 ) {
+ $mlw_complete_time .= "$mlw_complete_hours hours ";
+ }
+ $mlw_complete_minutes = floor( ( $mlw_qmn_results_array[0] % 3600 ) / 60 );
+ if ( $mlw_complete_minutes > 0 ) {
+ $mlw_complete_time .= "$mlw_complete_minutes minutes ";
+ }
+ $mlw_complete_seconds = $mlw_qmn_results_array[0] % 60;
+ $mlw_complete_time .= "$mlw_complete_seconds seconds";
+ }
+ esc_html_e( ' Time to complete ', 'quiz-master-next' );
+ echo wp_kses_post( $mlw_complete_time );
+ ?>
+ </span>
+ <span class="rtq-time-taken"><?php echo esc_html( date_i18n( get_option( 'date_format' ), strtotime( $single_result_arr['time_taken'] ) ) ); ?></span>
+ <?php if ( current_user_can( 'view_qsm_quiz_result' ) || current_user_can( 'administrator' ) ) { ?>
+ <p class="row-actions-c">
+ <a href="admin.php?page=qsm_quiz_result_details&result_id=<?php echo esc_attr( $single_result_arr['result_id'] ); ?>"><?php esc_html_e( 'View', 'quiz-master-next' ); ?></a>
+ <?php if ( current_user_can( 'administrator' ) ) { ?>
+ | <a href="javascript:void(0)" data-result_id="<?php echo esc_attr( $single_result_arr['result_id'] ); ?>"
+ class="trash rtq-delete-result"><?php esc_html_e( 'Delete', 'quiz-master-next' ); ?></a>
+ <?php } ?>
+ </p>
+ <?php } ?>
+ </div>
+ <?php
+ }
+ } else {
+ ?>
+ <li><?php esc_html_e( 'No recent activity found.', 'quiz-master-next' ); ?></li>
+ <?php
+ }
+ ?>
+ </ul>
+ </div>
+ </div>
+ <?php
+ }
+}
+
/**
* @since 7.0
* @return HTMl Dashboard for QSM
@@ -277,7 +404,7 @@
}
global $mlwQuizMasterNext;
qsm_display_header_section_links();
-?>
+ ?>
<div class="wrap">
<div class="qsm-dashboard-wrapper">
<div class="qsm-dashboard-container">
@@ -287,20 +414,23 @@
<p class="qsm-dashboard-card-description"><?php esc_html_e( 'Design quizzes and surveys tailored to your needs.', 'quiz-master-next' ); ?></p>
</div>
<div class="">
- <a class="button button-primary qsm-dashboard-section-create-quiz" href="<?php echo esc_url(admin_url('admin.php?page=qsm_create_quiz_page')); ?>" ><?php esc_html_e( 'Get Started', 'quiz-master-next' ) ?><img class="qsm-dashboard-help-image" src="<?php echo esc_url(QSM_PLUGIN_URL . 'assets/right-arrow.png'); ?>" alt="right-arrow.png"/></a>
+ <a class="button button-primary qsm-dashboard-section-create-quiz" href="<?php echo esc_url( admin_url( 'admin.php?page=qsm_create_quiz_page' ) ); ?>" ><?php esc_html_e( 'Get Started', 'quiz-master-next' ); ?><img class="qsm-dashboard-help-image" src="<?php echo esc_url( QSM_PLUGIN_URL . 'assets/right-arrow.png' ); ?>" alt="right-arrow.png"/></a>
</div>
</div>
<?php
+ qsm_display_migration_tools_redirect_button();
+
$qsm_admin_dd = qsm_get_parsing_script_data();
if ( $qsm_admin_dd ) {
- $popular_addons = isset($qsm_admin_dd['popular_products']) ? $qsm_admin_dd['popular_products'] : [];
- $themes = isset($qsm_admin_dd['themes']) ? $qsm_admin_dd['themes'] : [];
+ $popular_addons = isset( $qsm_admin_dd['popular_products'] ) ? $qsm_admin_dd['popular_products'] : array();
+ $themes = isset( $qsm_admin_dd['themes'] ) ? $qsm_admin_dd['themes'] : array();
qsm_check_plugins_compatibility();
- qsm_dashboard_display_need_help_section();
- qsm_dashboard_display_popular_addon_section($popular_addons);
- qsm_dashboard_display_popular_theme_section($themes);
+ qsm_dashboard_recent_taken_quiz();
+ qsm_dashboard_display_popular_theme_section( $themes );
+ qsm_dashboard_display_popular_addon_section( $popular_addons );
qsm_dashboard_display_change_log_section();
+ qsm_dashboard_display_need_help_section();
} else {
qsm_display_fullscreen_error();
}
@@ -309,7 +439,7 @@
</div>
<?php qsm_display_promotion_links_section(); ?>
</div>
-<?php
+ <?php
}
/**
* @since 7.0
@@ -347,33 +477,33 @@
<ul class="what-new-ul">
<li>
<a href="https://app.productstash.io/qsm#/roadmap"
- target="_blank" rel="noopener"> <?php esc_html_e( "Roadmap", "quiz-master-next"); ?>
+ target="_blank" rel="noopener"> <?php esc_html_e( 'Roadmap', 'quiz-master-next' ); ?>
</a>
<div class="post-description">
- <?php esc_html_e( "Visit out public Roadmap to checkout what's in the development pipepline of QSM.", "quiz-master-next"); ?>
+ <?php esc_html_e( "Visit out public Roadmap to checkout what's in the development pipepline of QSM.", 'quiz-master-next' ); ?>
</div>
</li>
<li>
<a href="https://app.productstash.io/qsm#/updates"
- target="_blank" rel="noopener"><?php esc_html_e( "Recent Updates", "quiz-master-next"); ?>
+ target="_blank" rel="noopener"><?php esc_html_e( 'Recent Updates', 'quiz-master-next' ); ?>
</a>
<div class="post-description">
- <?php esc_html_e( "Checkout our updates page to know more about our recent releases", "quiz-master-next"); ?>
+ <?php esc_html_e( 'Checkout our updates page to know more about our recent releases', 'quiz-master-next' ); ?>
</div>
</li>
<li>
<a href="https://app.productstash.io/qsm#/ideas"
- target="_blank" rel="noopener"><?php esc_html_e( "Submit your ideas", "quiz-master-next"); ?>
+ target="_blank" rel="noopener"><?php esc_html_e( 'Submit your ideas', 'quiz-master-next' ); ?>
</a>
<div class="post-description">
- <?php esc_html_e( "We are open your suggestions on how to improve QSM. Please visit our ideas page to share your thoughts.", "quiz-master-next"); ?>
+ <?php esc_html_e( 'We are open your suggestions on how to improve QSM. Please visit our ideas page to share your thoughts.', 'quiz-master-next' ); ?>
</div>
</li>
</ul>
</div>
</div>
</div>
-<?php
+ <?php
}
/**
@@ -382,11 +512,11 @@
*/
function qsm_create_new_quiz_from_wizard() {
// Create new quiz.
- if ( isset( $_POST['qsm_new_quiz_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash($_POST['qsm_new_quiz_nonce'] ) ), 'qsm_new_quiz' ) ) {
+ if ( isset( $_POST['qsm_new_quiz_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['qsm_new_quiz_nonce'] ) ), 'qsm_new_quiz' ) ) {
global $mlwQuizMasterNext;
$quiz_name = isset( $_POST['quiz_name'] ) ? sanitize_text_field( wp_unslash( $_POST['quiz_name'] ) ) : '';
$quiz_name = htmlspecialchars( $quiz_name, ENT_QUOTES );
- $theme_id = isset( $_POST['quiz_theme_id'] ) ? intval( $_POST['quiz_theme_id'] ) : 0;
+ $theme_id = isset( $_POST['quiz_theme_id'] ) ? intval( $_POST['quiz_theme_id'] ) : 0;
unset( $_POST['qsm_new_quiz_nonce'] );
unset( $_POST['_wp_http_referer'] );
unset( $_POST['quiz_theme_id'] );
@@ -414,26 +544,78 @@
/**
* Prepare Contact Fields
*/
- $contact_form = array();
+ $contact_form = array();
if ( isset( $_POST['enable_contact_form'] ) && 1 == sanitize_text_field( wp_unslash( $_POST['enable_contact_form'] ) ) ) {
- $cf_fields = QSM_Contact_Manager::default_fields();
+ $cf_fields = QSM_Contact_Manager::default_fields();
if ( isset( $cf_fields['name'] ) ) {
$cf_fields['name']['enable'] = 'true';
$contact_form[] = $cf_fields['name'];
}
if ( isset( $cf_fields['email'] ) ) {
- $cf_fields['email']['enable'] = 'true';
- $contact_form[] = $cf_fields['email'];
+ $cf_fields['email']['enable'] = 'true';
+ $contact_form[] = $cf_fields['email'];
}
}
/**
* Prepare Quiz Options
*/
$quiz_options = apply_filters( 'qsm_quiz_wizard_settings_option_save', $quiz_options );
- $mlwQuizMasterNext->quizCreator->create_quiz( $quiz_name, $theme_id, array(
- 'quiz_options' => $quiz_options,
- 'contact_form' => $contact_form,
- ) );
+ $mlwQuizMasterNext->quizCreator->create_quiz(
+ $quiz_name,
+ $theme_id,
+ array(
+ 'quiz_options' => $quiz_options,
+ 'contact_form' => $contact_form,
+ )
+ );
}
}
-add_action( 'admin_init', 'qsm_create_new_quiz_from_wizard' );
No newline at end of file
+
+add_action( 'admin_init', 'qsm_create_new_quiz_from_wizard' );
+
+/**
+ * Displays a redirect button to the migration tools page on the dashboard.
+ *
+ * This function outputs a styled section on the dashboard that encourages users
+ * to perform a database migration. It includes a heading, a brief description,
+ * and a button that links to the migration tools page.
+ *
+ * @since 11.0.0
+ * @return void
+ */
+function qsm_display_migration_tools_redirect_button() {
+ // Only show this section if the migration has not been completed.
+ if ( 1 == get_option( 'qsm_migration_results_processed' ) ) {
+ return;
+ }
+ ?>
+ <div class="qsm-dashboard-migration-section qsm-dashboard-page-common-style">
+ <div class="qsm-dashboard-page-header">
+ <h3 class="qsm-dashboard-card-title"><?php esc_html_e( 'Database Migration', 'quiz-master-next' ); ?></h3>
+ </div>
+ <div class="qsm-db-migration-container">
+ <div class="qsm-migration-notice qsm-migration-info">
+ <div class="qsm-migration-notice-header">
+ <strong><?php esc_html_e( 'You’ve updated to QSM 11', 'quiz-master-next' ); ?></strong>
+ </div>
+ <p><?php esc_html_e( 'Complete a one-time database migration to ensure your quizzes and results work smoothly with the new version and its improved rendering experience.', 'quiz-master-next' ); ?></p>
+ </div>
+ <div class="qsm-migration-notice qsm-migration-warning">
+ <div class="qsm-migration-notice-header">
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M10 0C4.48 0 0 4.48 0 10C0 15.52 4.48 20 10 20C15.52 20 20 15.52 20 10C20 4.48 15.52 0 10 0ZM11 15H9V13H11V15ZM11 11H9V5H11V11Z" fill="#F59E0B"/>
+ </svg>
+ <strong><?php esc_html_e( 'Important', 'quiz-master-next' ); ?></strong>
+ </div>
+ <p><?php esc_html_e( 'After migration, new quiz results will not be compatible with older versions of QSM. If you downgrade later, these results may not be accessible.', 'quiz-master-next' ); ?></p>
+ </div>
+ <div class="qsm-migration-action">
+ <a class="button button-primary qsm-dashboard-section-migration" href="<?php echo esc_url( admin_url( 'admin.php?page=qsm_quiz_tools&tab=qsm_tools_page_migration' ) ); ?>">
+ <?php esc_html_e( 'Go To Migration', 'quiz-master-next' ); ?>
+ </a>
+ <p class="qsm-migration-note"><?php esc_html_e( 'Your data will remain safe during migration', 'quiz-master-next' ); ?></p>
+ </div>
+ </div>
+ </div>
+ <?php
+}
No newline at end of file
--- a/quiz-master-next/php/admin/admin-results-details-page.php
+++ b/quiz-master-next/php/admin/admin-results-details-page.php
@@ -30,9 +30,16 @@
if ( $active_tab === $tab['slug'] ) {
$active_class = ' nav-tab-active';
}
- $result_id = isset( $_GET["result_id"] ) ? intval( $_GET["result_id"] ) : '';
+ $result_id = isset( $_GET['result_id'] ) ? sanitize_text_field( wp_unslash( $_GET['result_id'] ) ) : '';
+ $link = esc_url(add_query_arg(array(
+ 'page' => 'qsm_quiz_result_details',
+ 'result_id' => $result_id,
+ 'tab' => isset($tab['slug']) ? $tab['slug'] : '',
+ ), admin_url('admin.php')));
- echo '<a href="?page=qsm_quiz_result_details&result_id='.esc_attr( $result_id ).'&tab='.esc_attr( $tab['slug'] ).'" class="nav-tab '.esc_attr( $active_class ).'">' . esc_html( $tab['title'] ) . '</a>';
+ $link = apply_filters( 'qsm_admin_before_results_details_page_link', $link, $tab['slug'] );
+
+ echo '<a href="'.esc_url($link).'" class="nav-tab '.esc_attr( $active_class ).'">' . esc_html( $tab['title'] ) . '</a>';
}
?>
</h2>
@@ -65,6 +72,22 @@
$result_id = isset( $_GET["result_id"] ) ? intval( $_GET["result_id"] ) : 0;
$results_data = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}mlw_results WHERE result_id = %d", $result_id ) );
$results_data = apply_filters( 'qsm_admin_result_page_before', $results_data );
+
+ if ( empty($results_data) ) {
+ $resultpage_link = admin_url('admin.php?page=mlw_quiz_results');
+ ?>
+ <div id="qsm-dashboard-error-container">
+ <div class="qsm-dashboard-error-content">
+ <h3><?php esc_html_e('Quiz Result Not Available', 'quiz-master-next'); ?></h3>
+ <p><?php esc_html_e('The quiz result you are trying to view could not be found. Please return to the results page.', 'quiz-master-next'); ?></p>
+ <a href="<?php echo esc_url($resultpage_link); ?>" class="qsm-dashboard-error-btn">
+ <?php esc_html_e('Back to All Results', 'quiz-master-next'); ?>
+ </a>
+ </div>
+ </div>
+ <?php
+ return;
+ }
// Prepare plugin helper.
$quiz_id = intval( $results_data->quiz_id );
$mlwQuizMasterNext->pluginHelper->prepare_quiz( $quiz_id );
@@ -106,7 +129,13 @@
// Prepare responses array.
$total_hidden_questions = 0;
- $results = maybe_unserialize( $results_data->quiz_results );
+ $is_new_format = $mlwQuizMasterNext->pluginHelper->is_new_format_result( $results_data );
+ if ( $is_new_format ) {
+ // Load new format result structure
+ $mlw_qmn_results_array = $results = $mlwQuizMasterNext->pluginHelper->get_formated_result_data( $results_data->result_id );
+ } else {
+ $mlw_qmn_results_array = $results = maybe_unserialize( $results_data->quiz_results );
+ }
if ( is_array( $results ) ) {
$total_hidden_questions = ! empty( $results['hidden_questions'] ) && is_array( $results['hidden_questions'] ) ? count( $results['hidden_questions'] ) : 0;
if ( ! isset( $results["contact"] ) ) {
@@ -156,7 +185,6 @@
}
if ( 1 === intval( $new_template_result_detail ) ) {
$template = '';
- $mlw_qmn_results_array = maybe_unserialize( $results_data->quiz_results );
if ( is_array( $mlw_qmn_results_array ) ) {
$span_start = '<span class="result-candidate-span"><label>';
$span_end = '</label><span>';
@@ -283,7 +311,7 @@
}
}
- if ( ! is_array( maybe_unserialize( $results_data->quiz_results ) ) ) {
+ if ( ! is_array( maybe_unserialize( $results_data->quiz_results ) ) && '' != $results_data->quiz_results ) {
$template = str_replace( "%QUESTIONS_ANSWERS%" , $results_data->quiz_results, $template );
$template = str_replace( "%TIMER%" , '', $template );
$template = str_replace( "%COMMENT_SECTION%" , '', $template );
--- a/quiz-master-next/php/admin/admin-results-page.php
+++ b/quiz-master-next/php/admin/admin-results-page.php
@@ -30,6 +30,9 @@
<?php } ?>
</h2>
</div>
+ <?php
+ qsm_show_results_migration_warning();
+ ?>
<?php $mlwQuizMasterNext->alertManager->showAlerts(); ?>
<?php qsm_show_adverts(); ?>
<h2 class="nav-tab-wrapper">
@@ -81,7 +84,7 @@
}
}
-add_action( 'plugins_loaded', 'qsm_results_overview_tab' );
+add_action( 'init', 'qsm_results_overview_tab' );
/**
* Generates HTML For Overview Tab
@@ -90,10 +93,17 @@
* @return void
*/
function qsm_delete_results_attachments( $rows_before_update ) {
+ global $mlwQuizMasterNext;
// Loop through each row in the results
foreach ( $rows_before_update as $row ) {
// Unserialize the quiz results
- $mlw_qmn_results_array = maybe_unserialize( $row->quiz_results );
+ $is_new_format = $mlwQuizMasterNext->pluginHelper->is_new_format_result( $row );
+ if ( $is_new_format ) {
+ // Load new format result structure
+ $mlw_qmn_results_array = $mlwQuizMasterNext->pluginHelper->get_formated_result_data( $row->result_id );
+ } else {
+ $mlw_qmn_results_array = maybe_unserialize( $row->quiz_results );
+ }
// Ensure the results array exists and has the expected structure
foreach ( $mlw_qmn_results_array[1] as $key => $value ) {
// Check if the question type is 11 and user answer is not empty
@@ -106,12 +116,17 @@
}
}
function qsm_results_overview_tab_content() {
+ $get_subtabs = apply_filters( 'qsm_ultimate_get_subtabs_options', array() );
+ $current_subtab = isset( $_GET['subtab'] ) ? sanitize_key( $_GET['subtab'] ) : '';
+ do_action('qsm_before_admin_show_results_list', $get_subtabs, $current_subtab);
+
+ if ( empty( $get_subtabs ) || '' === $current_subtab ) {
global $wpdb;
global $mlwQuizMasterNext;
// If nonce is correct, delete results.
- if ( isset( $_POST['delete_results_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['delete_results_nonce'] ) ), 'delete_results' ) ) {
+ if ( isset( $_POST['delete_results_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['delete_results_nonce'] ) ), 'delete_results' ) && current_user_can( 'administrator' ) ) {
$mlw_delete_results_id = isset( $_POST['result_id'] ) ? intval( $_POST['result_id'] ) : 0;
$mlw_delete_results_name = isset( $_POST['delete_quiz_name'] ) ? sanitize_text_field( wp_unslash( $_POST['delete_quiz_name'] ) ) : '';
@@ -135,9 +150,9 @@
$mlwQuizMasterNext->alertManager->newAlert( sprintf( __( 'There was an error when deleting this result. Error from WordPress: %s', 'quiz-master-next' ), $error ), 'error' );
$mlwQuizMasterNext->log_manager->add( 'Error deleting result', "Tried {$wpdb->last_query} but got $error.", 0, 'error' );
} else {
- qsm_delete_results_attachments($row_before_update);
+ qsm_delete_results_attachments( $row_before_update );
$mlwQuizMasterNext->alertManager->newAlert( __( 'Your results has been deleted successfully.', 'quiz-master-next' ), 'success' );
- $mlwQuizMasterNext->audit_manager->new_audit( "Results Has Been Deleted From:", $mlw_delete_results_name, "" );
+ $mlwQuizMasterNext->audit_manager->new_audit( 'Results Has Been Deleted From:', $mlw_delete_results_name, '' );
}
}
@@ -148,11 +163,11 @@