Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added functionality for link multiple question with broadcating channel #2693

Merged
merged 2 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions css/qsm-admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,93 @@ td.scheduled_time_start {
margin: 0 10px;
width: auto;
}


#post-body-content .qsm-popup-upgrade-warning img {
width: auto;
height: 15px;
margin-right: 8px;
}

.qsm-linked-list-div-block {
padding: 4px;
margin: 5px 0;
margin-top: -20px;
width: max-content;
background-color: #ffe684;
border-radius: 2px;
}

span.qsm-linked-list-view-button {
cursor: pointer;
color: #135e96;
text-decoration: underline;
font-weight: 500;
}

span.qsm-linked-list-item {
margin: 0 0 5px 0;
padding: 5px;
background: #f0f0f1;
}

div.qsm-linked-list-inside span.qsm-unlink-the-question {
color: #DC3232;
font-weight: 500;
max-width: 60px;
cursor: pointer;
}

.qsm-linked-list-div-block p {
margin: 0;
font-size: 13px;
color: #856404;
}

.qsm-linked-list-container {
position: absolute;
}

.qsm-linked-list-div-block .qsm-linked-list-inside {
position: relative;
right: -155px;
top: 20px;
z-index: 999;
width: 350px;
padding: 10px;
box-sizing: border-box;
border-radius: 4px;
background: #ffffff;
border: 1px solid #dfd4d4;
box-shadow: 0 0 6px 2px #ddd;
display: grid;
grid-template-columns: 1fr;
}

.qsm-linked-list-div-block .qsm-linked-list-inside:before {
content: " ";
position: absolute;
top: -24px;
left: 28%;
margin-left: -12px;
border-width: 12px;
border-style: solid;
border-color: transparent transparent #ffffff transparent;
z-index: 1;
}

.qsm-linked-list-div-block .qsm-linked-list-inside:after {
content: " ";
position: absolute;
top: -26px;
left: 28%;
margin-left: -12px;
border-width: 12px;
border-style: solid;
border-color: transparent transparent #dfd4d4 transparent;
z-index: 0;
}

/** * Text Tab design */
.qsm-text-main-wrap {
display: inline-block;
Expand Down
268 changes: 264 additions & 4 deletions js/qsm-admin.js

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions mlw_quizmaster2.php
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,11 @@ public function qsm_admin_scripts_style( $hook ) {
'question_created' => __('Question created!', 'quiz-master-next'),
'new_question' => __('Your new question!', 'quiz-master-next'),
'creating_question' => __('Creating question...', 'quiz-master-next'),
'unlink_question' => __('Unlink', 'quiz-master-next'),
'duplicating_question' => __('Duplicating question...', 'quiz-master-next'),
'linking_question' => __('Linking...', 'quiz-master-next'),
'link_question' => __('Link', 'quiz-master-next'),
'creating_question' => __('Creating question...', 'quiz-master-next'),
'saving_question' => __('Saving question...', 'quiz-master-next'),
'question_saved' => __('Question was saved!', 'quiz-master-next'),
'load_more_quetions' => __('Load more questions', 'quiz-master-next'),
Expand Down
220 changes: 212 additions & 8 deletions php/admin/options-page-questions-tab.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,14 @@ function qsm_options_questions_tab_content() {
$json_data = array(
'quizID' => $quiz_id,
'answerText' => __( 'Answer', 'quiz-master-next' ),
'linked_view' => __( 'View', 'quiz-master-next' ),
'linked_close' => __( 'Close', 'quiz-master-next' ),
'nonce' => wp_create_nonce( 'wp_rest' ),
'pages' => $pages,
'qpages' => $qpages,
'qsm_user_ve' => get_user_meta( $user_id, 'rich_editing', true ),
'saveNonce' => wp_create_nonce( 'ajax-nonce-sandy-page' ),
'unlinkNonce' => wp_create_nonce( 'ajax-nonce-unlink-question' ),
'categories' => $question_categories,
'form_type' => $form_type,
'quiz_system' => $quiz_system,
Expand Down Expand Up @@ -280,6 +283,12 @@ class="save-page-button button button-primary"><?php esc_html_e( 'Save Questions
<div id="poststuff">
<div id="post-body" class="metabox-holder columns-2">
<div id="post-body-content" style="position: relative;">
<div class="qsm-linked-list-div-block">
<p><?php esc_attr_e( 'This question is linked with other quizzes ', 'quiz-master-next' ); ?> <span class="qsm-linked-list-view-button"><?php esc_attr_e( 'View', 'quiz-master-next' ); ?></span></p>
<div class="qsm-linked-list-container">
<div class="qsm-linked-list-inside"></div>
</div>
</div>
<div class="qsm-row">
<input type="text" id="question_title" class="question-title" name="question-title" value="" placeholder="<?php esc_attr_e( 'Type your question here', 'quiz-master-next' ); ?>">
</div>
Expand Down Expand Up @@ -876,6 +885,80 @@ class="save-page-button button button-primary"><?php esc_html_e( 'Save Questions
<?php
}

/**
* Unlinks a question from all quizzes it is associated with.
* This function checks for a valid nonce, retrieves the question ID from the request.
*
* @since 9.1.3
* @return void
*/
function qsm_ajax_unlink_question_from_list() {
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'ajax-nonce-unlink-question' ) ) {
wp_send_json_error( array(
'message' => __(
'Nonce verification failed.',
'quiz-master-next'
),
));
}
$question_id = isset( $_POST['question_id'] ) ? intval( $_POST['question_id'] ) : 0;
if ( $question_id > 0 ) {
qsm_process_unlink_question_from_list_by_question_id($question_id);
wp_send_json_success( array(
'message' => __(
'Question is unlinked from all quizzes.',
'quiz-master-next'
),
));
} else {
wp_send_json_error( array(
'message' => __(
'Invalid question ID.',
'quiz-master-next'
),
));
}
}
add_action( 'wp_ajax_qsm_unlink_question_from_list', 'qsm_ajax_unlink_question_from_list' );

/**
* Unlinks a question from all quizzes it is associated with.
* @since 9.1.3
* @param int $question_id The ID of the question to unlink.
* @return void
*/
function qsm_process_unlink_question_from_list_by_question_id( $question_id ) {
global $wpdb;
$current_linked_questions = $wpdb->get_var( $wpdb->prepare(
"SELECT linked_question FROM {$wpdb->prefix}mlw_questions WHERE question_id = %d",
$question_id
) );

if ( $current_linked_questions ) {
$current_links = explode(',', $current_linked_questions);
$current_links = array_map('trim', $current_links);
$current_links = array_diff($current_links, [ $question_id ]);
$updated_linked_list = implode(',', array_filter($current_links));
$linked_ids = explode(',', $updated_linked_list);
foreach ( $linked_ids as $linked_id ) {
$wpdb->update(
$wpdb->prefix . 'mlw_questions',
array( 'linked_question' => $updated_linked_list ),
array( 'question_id' => intval($linked_id) ),
array( '%s' ),
array( '%d' )
);
}
$wpdb->update(
$wpdb->prefix . 'mlw_questions',
array( 'linked_question' => '' ),
array( 'question_id' => intval($question_id) ),
array( '%s' ),
array( '%d' )
);
}
}

add_action( 'wp_ajax_qsm_save_pages', 'qsm_ajax_save_pages' );

/**
Expand Down Expand Up @@ -1093,11 +1176,38 @@ function qsm_delete_question_from_database() {
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'delete_question_from_database' ) ) {
wp_send_json_error( __( 'Nonce verification failed.', 'quiz-master-next' ) );
}
$question_id = isset( $_POST['question_id'] ) ? intval( $_POST['question_id'] ) : 0;
$base_question_id = $question_id = isset( $_POST['question_id'] ) ? intval( $_POST['question_id'] ) : 0;
if ( $question_id ) {

global $wpdb, $mlwQuizMasterNext;
$results = $wpdb->delete( $wpdb->prefix . 'mlw_questions', array( 'question_id' => $question_id ) );
$update_qpages_after_delete = array();
$connected_question_ids = qsm_get_unique_linked_question_ids_to_remove( [ $question_id ] );
$question_ids_to_delete = array_merge($connected_question_ids, [ $question_id ]);
$question_ids_to_delete = array_unique( $question_ids_to_delete );
$placeholders = array_fill( 0, count( $question_ids_to_delete ), '%d' );

if ( ! empty($connected_question_ids) ) {
$connected_question_ids = array_diff($connected_question_ids, [ $base_question_id ] );
$update_qpages_after_delete = qsm_process_to_update_qpages_after_unlink($connected_question_ids);
}

// Construct the query with placeholders
$query = sprintf(
"DELETE FROM {$wpdb->prefix}mlw_questions WHERE question_id IN (%s)",
implode( ', ', $placeholders )
);

// Prepare the query
$query = $wpdb->prepare( $query, $question_ids_to_delete );
$results = $wpdb->query( $query );
if ( $results ) {
if ( ! empty($update_qpages_after_delete) ) {
foreach ( $update_qpages_after_delete as $quiz_id => $aftervalue ) {
$mlwQuizMasterNext->pluginHelper->prepare_quiz( $quiz_id );
$mlwQuizMasterNext->pluginHelper->update_quiz_setting( 'qpages', $aftervalue['qpages'] );
$mlwQuizMasterNext->pluginHelper->update_quiz_setting( 'pages', $aftervalue['pages'] );
}
}
wp_send_json_success( __( 'Question removed Successfully.', 'quiz-master-next' ) );
}else {
wp_send_json_error( __( 'Question delete failed!', 'quiz-master-next' ) );
Expand Down Expand Up @@ -1136,11 +1246,19 @@ function qsm_bulk_delete_question_from_database() {
} );

// Sanitize and validate the IDs
$question_id = array_map( 'intval', $question_id );

$base_question_ids = $question_id = array_map( 'intval', $question_id );
if ( ! empty( $question_id ) ) {
// Generate placeholders for each ID
$placeholders = array_fill( 0, count( $question_id ), '%d' );

$update_qpages_after_delete = array();
$connected_question_ids = qsm_get_unique_linked_question_ids_to_remove($question_id);
$question_ids_to_delete = array_merge($connected_question_ids, $question_id);
$question_ids_to_delete = array_unique( $question_ids_to_delete );
$placeholders = array_fill( 0, count( $question_ids_to_delete ), '%d' );
if ( ! empty($connected_question_ids) ) {
$connected_question_ids = array_diff($connected_question_ids, $base_question_ids );
$update_qpages_after_delete = qsm_process_to_update_qpages_after_unlink($connected_question_ids);
}

// Construct the query with placeholders
$query = sprintf(
Expand All @@ -1149,10 +1267,17 @@ function qsm_bulk_delete_question_from_database() {
);

// Prepare the query
$query = $wpdb->prepare( $query, $question_id );
$query = $wpdb->prepare( $query, $question_ids_to_delete );

$results = $wpdb->query( $query );
if ( $results ) {
if ( ! empty($update_qpages_after_delete) ) {
foreach ( $update_qpages_after_delete as $quiz_id => $aftervalue ) {
$mlwQuizMasterNext->pluginHelper->prepare_quiz( $quiz_id );
$mlwQuizMasterNext->pluginHelper->update_quiz_setting( 'qpages', $aftervalue['qpages'] );
$mlwQuizMasterNext->pluginHelper->update_quiz_setting( 'pages', $aftervalue['pages'] );
}
}
wp_send_json_success( __( 'Questions removed Successfully.', 'quiz-master-next' ) );
}else {
$mlwQuizMasterNext->log_manager->add( __('Error 0001 delete questions failed - question IDs:', 'quiz-master-next') . $question_id, '<br><b>Error:</b>' . $wpdb->last_error . ' from ' . $wpdb->last_query, 0, 'error' );
Expand All @@ -1164,6 +1289,82 @@ function qsm_bulk_delete_question_from_database() {
}
add_action( 'wp_ajax_qsm_bulk_delete_question_from_database', 'qsm_bulk_delete_question_from_database' );

/**
* returns pages and qpages for dependent question ids for update after deleting questions
*
* @param array $connected_question_ids An array of question IDs.
* @since 9.1.3
*/
function qsm_process_to_update_qpages_after_unlink( $connected_question_ids ) {
$comma_seprated_ids = implode( ',', array_unique($connected_question_ids) );
$qpages_array = array();
if ( ! empty($comma_seprated_ids) ) {
global $wpdb, $mlwQuizMasterNext;
$quiz_results = $wpdb->get_results( "SELECT `quiz_id`, `question_id` FROM `{$wpdb->prefix}mlw_questions` WHERE `question_id` IN (" .$comma_seprated_ids. ")" );
if ( ! empty($quiz_results) ) {
foreach ( $quiz_results as $single_quiz ) {
$quiz_id = $single_quiz->quiz_id;
$mlwQuizMasterNext->pluginHelper->prepare_quiz( $quiz_id );
$pages = $mlwQuizMasterNext->pluginHelper->get_quiz_setting( 'pages', array() );
$clone_qpages = $qpages = $mlwQuizMasterNext->pluginHelper->get_quiz_setting( 'qpages', array() );
if ( ! empty($clone_qpages) ) {
foreach ( $clone_qpages as $clonekey => $clonevalue ) {
if ( ! empty($clonevalue['questions']) && in_array($single_quiz->question_id, $clonevalue['questions']) ) {
$clone_qpages[ $clonekey ]['questions'] = array_diff($clonevalue['questions'], [ $single_quiz->question_id ]);
$pages[ $clonekey ] = array_diff($pages[ $clonekey ], [ $single_quiz->question_id ]);
}
}
$qpages = $clone_qpages;
}
//merge duplicate questions
$all_questions = array();
foreach ( $pages as $page_key => $questions ) {
$page_questions = array();
$questions = array_unique( $questions );
foreach ( $questions as $id ) {
if ( ! in_array( $id, $all_questions, true ) ) {
$page_questions[] = $id;
}
}
$all_questions = array_merge( $all_questions, $questions );
$pages[ $page_key ] = $page_questions;
if ( isset( $qpages[ $page_key ] ) ) {
$qpages[ $page_key ]['questions'] = $page_questions;
}
}
$qpages_array[ $quiz_id ] = array(
'pages' => $pages,
'qpages' => $qpages,
);
}
}
}
return $qpages_array;
}

/**
* Get Unique Linked Question IDs
*
* @param array $question_ids An array of question IDs to query for linked questions.
* @return array $unique_ids An array of unique question IDs extracted from the linked questions.
* @since 9.1.3
*/
function qsm_get_unique_linked_question_ids_to_remove( $question_ids ) {
global $wpdb;
$all_ids = array();
foreach ( $question_ids as $id ) {
$sql = $wpdb->prepare(
"SELECT linked_question FROM {$wpdb->prefix}mlw_questions WHERE question_id = %d",
$id
);
$linked_question = $wpdb->get_var($sql);
if ( ! empty($linked_question) ) {
$all_ids = array_merge($all_ids, explode(',', $linked_question));
}
}
return $all_ids;
}

add_action( 'wp_ajax_save_new_category', 'qsm_save_new_category' );
function qsm_save_new_category() {
$category = isset( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : '';
Expand Down Expand Up @@ -1243,7 +1444,10 @@ function qsm_options_questions_tab_template() {
<input type="checkbox" name="qsm-question-checkbox[]" class="qsm-question-checkbox" />
</div>
<div><p>{{{data.question}}}</p><p style="font-size: 12px;color: gray;font-style: italic;"><b>Quiz Name:</b> {{data.quiz_name}} <# if ( data.category != '' ) { #> <b>Category:</b> {{data.category}} <# } #></p></div>
<div><a href="javascript:void(0)" class="button import-button" data-question-id="{{data.id}}"><?php esc_html_e( 'Add Question', 'quiz-master-next' ); ?></a></div>
<div>
<a href="javascript:void(0)" class="button import-button" data-question-id="{{data.id}}"><?php esc_html_e( 'Add', 'quiz-master-next' ); ?></a>
<a href="javascript:void(0)" data-questions="{{data.linked_question}}" class="button link-question" data-question-id="{{data.id}}"><?php esc_html_e( 'Link', 'quiz-master-next' ); ?></a>
</div>
</div>
</script>

Expand Down
Loading