diff --git a/assets/Premium Bundle.png b/assets/Premium Bundle.png deleted file mode 100644 index 7ee627438..000000000 Binary files a/assets/Premium Bundle.png and /dev/null differ diff --git a/assets/Starter Bundle.png b/assets/Starter Bundle.png deleted file mode 100644 index 9e5a54fd6..000000000 Binary files a/assets/Starter Bundle.png and /dev/null differ diff --git a/css/qsm-admin-question.css b/css/qsm-admin-question.css index b5e9e5e09..0e0bfe9ed 100644 --- a/css/qsm-admin-question.css +++ b/css/qsm-admin-question.css @@ -453,11 +453,11 @@ input#image_size-width { .change-answer-editor-label>#change-answer-editor { width: auto; } -a.import-button.button.disable_import { +a.import-button.button.disable_import, a.link-question.button.disable_import { position: relative; z-index: 0; } -a.import-button.button.disable_import::before { +a.import-button.button.disable_import::before, a.link-question.button.disable_import::before { content: ''; background: rgba(255, 255, 255, 0.5); width: 100%; diff --git a/css/qsm-admin.css b/css/qsm-admin.css index 63a049e03..f15f72b61 100644 --- a/css/qsm-admin.css +++ b/css/qsm-admin.css @@ -1378,7 +1378,7 @@ tr .qsm-opt-desc { #quiz_settings_wrapper .qsm-opt-desc { display: none !important; } -.form-table td fieldset label { +.qsm_tab_content .form-table td fieldset label { margin-right: 20px !important; width: 100%; } @@ -1458,6 +1458,8 @@ td.scheduled_time_start { background: #fff; box-sizing: border-box; } + + .qsm-text-main-wrap #postbox-container-1 { position: relative; background: #fff; diff --git a/js/qsm-admin.js b/js/qsm-admin.js index 603dbe52d..277e3378e 100644 --- a/js/qsm-admin.js +++ b/js/qsm-admin.js @@ -2240,10 +2240,14 @@ var import_button; QSMQuestion.addQuestionToPage(model); QSMQuestion.savePages(); - $('.import-button').removeClass('disable_import'); + $('.import-button, .link-question').removeClass('disable_import'); QSMQuestion.countTotal(); - import_button.html('').html(qsm_admin_messages.add_question); - import_button.attr("onclick", "return confirm(" + qsm_admin_messages.confirm_message + "' '" + qsm_admin_messages.import_question_again + ")"); + if(import_button){ + import_button.html(qsm_admin_messages.add_question); + } + if(import_button){ + import_button.attr("onclick", "return confirm('" + qsm_admin_messages.confirm_message + " " + qsm_admin_messages.import_question_again + "');"); + } QSMQuestion.openEditPopup(model.id, $('.question[data-question-id=' + model.id + ']').find('.edit-question-button')); // $('#save-popup-button').trigger('click'); }, @@ -3256,7 +3260,7 @@ var import_button; $(document).on('click', '.qsm-popup-bank .import-button', function (event) { event.preventDefault(); - $(this).text('').text(qsm_admin_messages.adding_question); + $(this).text(qsm_admin_messages.adding_question); import_button = $(this); $('.import-button').addClass('disable_import'); QSMQuestion.addQuestionFromQuestionBank($(this).data('question-id')); @@ -3773,6 +3777,7 @@ var import_button; }) .done(function (results) { if (results.status) { + jQuery(document).trigger('qsm_after_save_results'); QSMAdmin.displayAlert(qsm_admin_messages.results_page_saved, 'success'); } else { QSMAdmin.displayAlert( qsm_admin_messages.results_page_save_error + ' ' + qsm_admin_messages.results_page_saved, 'error'); diff --git a/js/qsm-quiz.js b/js/qsm-quiz.js index 89c3611eb..bbd87c641 100644 --- a/js/qsm-quiz.js +++ b/js/qsm-quiz.js @@ -132,7 +132,7 @@ var qsmTimerInterval = []; // Calculates starting time. var timerTotal = parseFloat(qmn_quiz_data[quizID].timer_limit) * 60; var timerStarted = localStorage.getItem('mlw_started_quiz' + quizID); - var timerConsumed = parseInt(localStorage.getItem('mlw_time_consumed_quiz' + quizID)); + var timerConsumed = parseInt(localStorage.getItem('mlw_time_consumed_quiz' + quizID)) || 1; var timerRemaning = timerTotal - timerConsumed; if ('yes' == timerStarted && 0 < timerRemaning) { seconds = parseInt(timerRemaning); @@ -162,6 +162,7 @@ var qsmTimerInterval = []; * @param int quizID The ID of the quiz. */ timer: function (quizID) { + jQuery(document).trigger('qmn_timer_consumed_seconds', [quizID, qmn_quiz_data, qsm_timer_consumed_obj]); qmn_quiz_data[quizID].timerRemaning -= 1; qmn_quiz_data[quizID].timerConsumed += 1; if (0 > qmn_quiz_data[quizID].timerRemaning) { @@ -169,6 +170,7 @@ var qsmTimerInterval = []; } var secondsRemaining = qmn_quiz_data[quizID].timerRemaning; var secondsConsumed = qmn_quiz_data[quizID].timerConsumed; + jQuery(document).trigger('qmn_timer_consumed_seconds', [quizID, qmn_quiz_data, qsm_timer_consumed_obj]); if (localStorage.getItem('mlw_time_quiz' + quizID) != null ) { secondsRemaining = (parseFloat(qmn_quiz_data[quizID].timer_limit) * 60) - secondsConsumed + 1; if(secondsRemaining < 0) { @@ -176,6 +178,9 @@ var qsmTimerInterval = []; } } var display = QSM.secondsToTimer(secondsRemaining); + if(qsm_timer_consumed_obj.qmn_count_upward_status){ + display = QSM.secondsToTimer(secondsConsumed); + } var systemTime = new Date().getTime() / 1000; systemTime = Math.round(systemTime); if ('1' === qmn_quiz_data[quizID].not_allow_after_expired_time && systemTime > qmn_quiz_data[quizID].scheduled_time_end) { @@ -357,7 +362,7 @@ var qsmTimerInterval = []; // Calculates starting time. let timerStarted = localStorage.getItem('mlw_started_quiz' + quizID); - let timerConsumed = parseInt(localStorage.getItem('mlw_time_consumed_quiz' + quizID)); + let timerConsumed = parseInt(localStorage.getItem('mlw_time_consumed_quiz' + quizID)) || 1; let seconds = parseFloat(qmn_quiz_data[quizID].timer_limit) * 60; let timerRemaning = seconds - timerConsumed; if ('yes' == timerStarted && 0 < timerRemaning) { @@ -2079,4 +2084,7 @@ jQuery(document).keydown(function(event) { } jQuery(document).trigger('qsm_keyboard_quiz_action_end', event); } -}); \ No newline at end of file +}); +const qsm_timer_consumed_obj = { + qmn_count_upward_status : false +} \ No newline at end of file diff --git a/mlw_quizmaster2.php b/mlw_quizmaster2.php index b65eb8b09..ce63fc21e 100644 --- a/mlw_quizmaster2.php +++ b/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: 9.1.3 + * Version: 9.2.0 * Author: ExpressTech * Author URI: https://quizandsurveymaster.com/ * Plugin URI: https://expresstech.io/ @@ -43,7 +43,7 @@ class MLWQuizMasterNext { * @var string * @since 4.0.0 */ - public $version = '9.1.3'; + public $version = '9.2.0'; /** * QSM Alert Manager Object @@ -345,6 +345,7 @@ private function load_dependencies() { * @return void */ private function add_hooks() { + add_action( 'admin_menu', array( $this, 'qsm_add_user_capabilities' ) ); add_action( 'admin_menu', array( $this, 'setup_admin_menu' ) ); add_action( 'admin_head', array( $this, 'admin_head' ), 900 ); add_action( 'init', array( $this, 'register_quiz_post_types' ) ); @@ -524,10 +525,8 @@ public function qsm_admin_scripts_style( $hook ) { 'results_page_saved' => __('Results pages were saved!', 'quiz-master-next'), 'results_page_save_error' => __('There was an error when saving the results pages.', 'quiz-master-next'), 'all_categories' => __('All Categories', 'quiz-master-next'), - 'add_question' => __('Add Question', 'quiz-master-next'), 'question_created' => __('Question created!', 'quiz-master-next'), 'new_question' => __('Your new question!', 'quiz-master-next'), - 'adding_question' => __('Adding question...', 'quiz-master-next'), 'creating_question' => __('Creating question...', 'quiz-master-next'), 'duplicating_question' => __('Duplicating question...', 'quiz-master-next'), 'saving_question' => __('Saving question...', 'quiz-master-next'), @@ -652,6 +651,26 @@ public function register_quiz_post_types() { 'rewrite' => array( 'slug' => $cpt_slug ), 'has_archive' => $has_archive, 'supports' => array( 'title', 'author', 'comments', 'thumbnail' ), + 'capability_type' => array( 'qsm_quiz', 'qsm_quizzes' ), + 'map_meta_cap' => true, + ); + $quiz_args['capabilities'] = array( + 'edit_post' => 'edit_qsm_quiz', + 'edit_post' => 'duplicate_qsm_quiz', + 'read_post' => 'read_qsm_quiz', + 'delete_post' => 'delete_qsm_quiz', + 'edit_posts' => 'edit_qsm_quizzes', + 'edit_others_posts' => 'edit_others_qsm_quizzes', + 'publish_posts' => 'publish_qsm_quizzes', + 'read_private_posts' => 'read_private_qsm_quizzes', + 'delete_posts' => 'delete_qsm_quizzes', + 'delete_private_posts' => 'delete_private_qsm_quizzes', + 'delete_published_posts' => 'delete_published_qsm_quizzes', + 'delete_others_posts' => 'delete_others_qsm_quizzes', + 'edit_private_posts' => 'edit_private_qsm_quizzes', + 'edit_published_posts' => 'edit_published_qsm_quizzes', + 'create_posts' => 'create_qsm_quizzes', + 'moderate_comments' => 'view_qsm_quiz_result', ); // Registers post type. @@ -682,10 +701,88 @@ public function register_quiz_post_types() { 'show_in_rest' => true, 'show_tagcloud' => false, 'rewrite' => false, + 'capabilities' => array( + 'manage_terms' => 'manage_qsm_quiz_categories', + 'edit_terms' => 'edit_qsm_quiz_categories', + 'delete_terms' => 'delete_qsm_quiz_categories', + 'assign_terms' => 'assign_qsm_quiz_categories', + ), ); register_taxonomy( 'qsm_category', array( 'qsm-taxonomy' ), $taxonomy_args ); } + public function qsm_add_user_capabilities() { + $administrator_capabilities = array( + 'duplicate_qsm_quiz', + 'delete_qsm_quiz', + 'edit_others_qsm_quizzes', + 'publish_qsm_quizzes', + 'read_private_qsm_quizzes', + 'delete_qsm_quizzes', + 'delete_private_qsm_quizzes', + 'delete_published_qsm_quizzes', + 'delete_others_qsm_quizzes', + 'edit_private_qsm_quizzes', + 'edit_published_qsm_quizzes', + 'manage_qsm_quiz_categories', + 'manage_qsm_quiz_answer_label', + 'view_qsm_quiz_result', + 'edit_qsm_quiz_categories', + 'assign_qsm_quiz_categories', + 'delete_qsm_quiz_categories', + ); + $editor_capabilities = array( + 'publish_qsm_quizzes', + 'edit_published_qsm_quizzes', + 'edit_others_qsm_quizzes', + 'delete_published_qsm_quizzes', + 'delete_qsm_quiz', + 'delete_qsm_quizzes', + 'manage_qsm_quiz_categories', + 'manage_qsm_quiz_answer_label', + 'view_qsm_quiz_result', + 'edit_qsm_quiz_categories', + 'assign_qsm_quiz_categories', + ); + $author_capabilities = array( + 'edit_published_qsm_quizzes', + 'publish_qsm_quizzes', + ); + $contributor_capabilities = array( + 'read_qsm_quiz', + 'edit_qsm_quiz', + 'edit_qsm_quizzes', + 'create_qsm_quizzes', + ); + + $user = wp_get_current_user(); + $roles = (array) $user->roles; + $rolename = $roles[0]; + + $role = get_role( $rolename ); + + // Remove all capabilities first. + foreach ( $administrator_capabilities as $cap ) { + if ( $role->has_cap( $cap ) ) { + $role->remove_cap( $cap ); + } + } + + // 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 ) ) : [], + $user + ); + + if ( isset( $capabilities_to_add ) ) { + foreach ( $capabilities_to_add as $cap ) { + $role->add_cap( $cap ); + } + } + } + public function parent_file( $file_name ) { global $menu, $submenu, $parent_file, $submenu_file; if ( 'edit-tags.php?taxonomy=qsm_category' === $submenu_file ) { @@ -729,44 +826,45 @@ public function setup_admin_menu() { $enabled = get_option( 'qsm_multiple_category_enabled' ); $menu_position = self::get_free_menu_position(26.1, 0.3); $settings = (array) get_option( 'qmn-settings' ); - if ( ! class_exists('QSM_Ultimate') ) { - $user = wp_get_current_user(); - if ( in_array( 'subscriber', (array) $user->roles, true ) ) { - $role_capabilities = get_role( 'subscriber' ); - $role_capabilities->remove_cap('edit_posts'); - $role_capabilities->remove_cap('moderate_comments'); - } - } - else { - apply_filters('qsm_user_role_menu_for_subcriber',true); - } - $qsm_dashboard_page = add_menu_page( 'Quiz And Survey Master', __( 'QSM', 'quiz-master-next' ), 'edit_posts', 'qsm_dashboard', 'qsm_generate_dashboard_page', 'dashicons-feedback', $menu_position ); - add_submenu_page( 'qsm_dashboard', __( 'Dashboard', 'quiz-master-next' ), __( 'Dashboard', 'quiz-master-next' ), 'edit_posts', 'qsm_dashboard', 'qsm_generate_dashboard_page', 0 ); + + apply_filters('qsm_user_role_menu_for_subscriber', true); + + $capabilities = array( + 'delete_published_qsm_quizzes', + 'create_qsm_quizzes', + 'delete_others_qsm_quizzes', + 'manage_qsm_quiz_categories', + 'manage_qsm_quiz_answer_label', + 'view_qsm_quiz_result', + ); + + add_menu_page( 'Quiz And Survey Master', __( 'QSM', 'quiz-master-next' ), $capabilities[1], 'qsm_dashboard', 'qsm_generate_dashboard_page', 'dashicons-feedback', $menu_position ); + add_submenu_page( 'qsm_dashboard', __( 'Dashboard', 'quiz-master-next' ), __( 'Dashboard', 'quiz-master-next' ), $capabilities[2], 'qsm_dashboard', 'qsm_generate_dashboard_page', 0 ); if ( $enabled && 'cancelled' !== $enabled ) { - $qsm_taxonomy_menu_hook = add_submenu_page( 'qsm_dashboard', __( 'Question Categories', 'quiz-master-next' ), __( 'Question Categories', 'quiz-master-next' ), 'edit_posts', 'edit-tags.php?taxonomy=qsm_category' ); + add_submenu_page( 'qsm_dashboard', __( 'Question Categories', 'quiz-master-next' ), __( 'Question Categories', 'quiz-master-next' ), $capabilities[3], 'edit-tags.php?taxonomy=qsm_category' ); } if ( ! class_exists( 'QSM_Advanced_Assessment' ) ) { - add_submenu_page( 'qsm_dashboard', __( 'Answer Labels', 'quiz-master-next' ), __( 'Answer Labels', 'quiz-master-next' ), 'manage_options', 'qsm-answer-label', 'qsm_advanced_assessment_quiz_page_content', 3 ); + add_submenu_page( 'qsm_dashboard', __( 'Answer Labels', 'quiz-master-next' ), __( 'Answer Labels', 'quiz-master-next' ), $capabilities[4], 'qsm-answer-label', 'qsm_advanced_assessment_quiz_page_content', 3 ); } - add_submenu_page( 'options.php', __( 'Settings', 'quiz-master-next' ), __( 'Settings', 'quiz-master-next' ), 'edit_posts', 'mlw_quiz_options', 'qsm_generate_quiz_options' ); - add_submenu_page( 'qsm_dashboard', __( 'Results', 'quiz-master-next' ), __( 'Results', 'quiz-master-next' ), 'moderate_comments', 'mlw_quiz_results', 'qsm_generate_admin_results_page' ); + add_submenu_page( 'options.php', __( 'Settings', 'quiz-master-next' ), __( 'Settings', 'quiz-master-next' ), $capabilities[1], 'mlw_quiz_options', 'qsm_generate_quiz_options' ); + add_submenu_page( 'qsm_dashboard', __( 'Results', 'quiz-master-next' ), __( 'Results', 'quiz-master-next' ), $capabilities[5], 'mlw_quiz_results', 'qsm_generate_admin_results_page' ); // Failed Submission. if ( ! empty( $settings['enable_qsm_log'] ) && $settings['enable_qsm_log'] ) { - add_submenu_page( 'qsm_dashboard', __( 'Failed Submission', 'quiz-master-next' ), __( 'Failed Submission', 'quiz-master-next' ), 'moderate_comments', 'qsm-quiz-failed-submission', array( $this, 'admin_failed_submission_page' ) ); + add_submenu_page( 'qsm_dashboard', __( 'Failed Submission', 'quiz-master-next' ), __( 'Failed Submission', 'quiz-master-next' ), $capabilities[2], 'qsm-quiz-failed-submission', array( $this, 'admin_failed_submission_page' ) ); } // Failed DB Query if ( ! empty( $settings['enable_qsm_log'] ) && $settings['enable_qsm_log'] && $this->get_failed_alter_table_queries() ) { - add_submenu_page( 'qsm_dashboard', __( 'Failed DB Queries', 'quiz-master-next' ), __( 'Failed Database Queries', 'quiz-master-next' ), 'moderate_comments', 'qsm-database-failed-queries', array( $this, 'qsm_database_failed_queries' ) ); + add_submenu_page( 'qsm_dashboard', __( 'Failed DB Queries', 'quiz-master-next' ), __( 'Failed Database Queries', 'quiz-master-next' ), $capabilities[2], 'qsm-database-failed-queries', array( $this, 'qsm_database_failed_queries' ) ); } - add_submenu_page( 'options.php', __( 'Result Details', 'quiz-master-next' ), __( 'Result Details', 'quiz-master-next' ), 'moderate_comments', 'qsm_quiz_result_details', 'qsm_generate_result_details' ); - add_submenu_page( 'qsm_dashboard', __( 'Settings', 'quiz-master-next' ), __( 'Settings', 'quiz-master-next' ), 'manage_options', 'qmn_global_settings', array( 'QMNGlobalSettingsPage', 'display_page' ) ); - add_submenu_page( 'qsm_dashboard', __( 'Tools', 'quiz-master-next' ), __( 'Tools', 'quiz-master-next' ), 'manage_options', 'qsm_quiz_tools', 'qsm_generate_quiz_tools' ); - add_submenu_page( 'qsm_dashboard', __( 'Stats', 'quiz-master-next' ), __( 'Stats', 'quiz-master-next' ), 'moderate_comments', 'qmn_stats', 'qmn_generate_stats_page' ); - add_submenu_page( 'qsm_dashboard', __( 'About', 'quiz-master-next' ), __( 'About', 'quiz-master-next' ), 'moderate_comments', 'qsm_quiz_about', 'qsm_generate_about_page' ); - - add_submenu_page( 'qsm_dashboard', __( 'Extensions Settings', 'quiz-master-next' ), '' . __( 'Extensions', 'quiz-master-next' ) . '', 'moderate_comments', 'qmn_addons', 'qmn_addons_page', 34 ); - add_submenu_page( 'qsm_dashboard', __( 'Free Add-ons', 'quiz-master-next' ), '' . esc_html__( 'Free Add-ons', 'quiz-master-next' ) . '', 'moderate_comments', 'qsm-free-addon', 'qsm_display_optin_page', 90 ); + add_submenu_page( 'options.php', __( 'Result Details', 'quiz-master-next' ), __( 'Result Details', 'quiz-master-next' ), $capabilities[5], 'qsm_quiz_result_details', 'qsm_generate_result_details' ); + add_submenu_page( 'qsm_dashboard', __( 'Settings', 'quiz-master-next' ), __( 'Settings', 'quiz-master-next' ), $capabilities[2], 'qmn_global_settings', array( 'QMNGlobalSettingsPage', 'display_page' ) ); + 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', __( 'Extensions Settings', 'quiz-master-next' ), '' . __( 'Extensions', 'quiz-master-next' ) . '', $capabilities[2], 'qmn_addons', 'qmn_addons_page', 34 ); + add_submenu_page( 'qsm_dashboard', __( 'Free Add-ons', 'quiz-master-next' ), '' . esc_html__( 'Free Add-ons', 'quiz-master-next' ) . '', $capabilities[2], 'qsm-free-addon', 'qsm_display_optin_page', 90 ); // Register screen option for dashboard page add_action( 'screen_settings', 'qsm_dashboard_screen_options', 10, 2 ); } diff --git a/php/admin/admin-results-details-page.php b/php/admin/admin-results-details-page.php index 7bbe45feb..59825ee2b 100644 --- a/php/admin/admin-results-details-page.php +++ b/php/admin/admin-results-details-page.php @@ -8,7 +8,7 @@ * @since 4.4.0 */ function qsm_generate_result_details() { - if ( ! current_user_can( 'moderate_comments' ) ) { + if ( ! current_user_can( 'view_qsm_quiz_result' ) ) { return; } global $mlwQuizMasterNext; @@ -69,6 +69,12 @@ function qsm_generate_results_details_tab() { $quiz_id = intval( $results_data->quiz_id ); $mlwQuizMasterNext->pluginHelper->prepare_quiz( $quiz_id ); + $quiz_post_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'quiz_id' AND meta_value = %d", $quiz_id ) ); + $post_author = get_post_field( 'post_author', $quiz_post_id, true ); + if ( ( ! current_user_can( 'view_qsm_quiz_result' ) || intval($post_author) != get_current_user_id()) && ! current_user_can( 'delete_others_qsm_quizzes' ) ) { + return; + } + //Get the data for comments $quiz_options = $mlwQuizMasterNext->quiz_settings->get_setting( 'quiz_options'); $comments_enabled = $quiz_options['comment_section']; diff --git a/php/admin/admin-results-page.php b/php/admin/admin-results-page.php index 3653acd1a..7647e67d3 100644 --- a/php/admin/admin-results-page.php +++ b/php/admin/admin-results-page.php @@ -12,7 +12,7 @@ function qsm_generate_admin_results_page() { // Makes sure user has the right privledges. - if ( ! current_user_can( 'moderate_comments' ) ) { + if ( ! current_user_can( 'view_qsm_quiz_result' ) ) { return; } @@ -524,7 +524,20 @@ function qsm_results_overview_tab_content() { ?>