feat: Add Assessment Builder AJAX handler and initialization

This commit is contained in:
Ruben Ramirez 2025-04-03 22:07:16 -05:00
parent aa95d3f583
commit 4f136b3222
2 changed files with 154 additions and 0 deletions

View file

@ -190,6 +190,9 @@ function quiztech_init() {
// Initialize AJAX handler for assessment interactions
\Quiztech\AssessmentPlatform\Includes\Ajax\AssessmentAjaxHandler::init();
// Initialize AJAX handler for assessment builder interactions
new \Quiztech\AssessmentPlatform\Includes\Ajax\AssessmentBuilderAjaxHandler();
// Initialize Admin-specific features
if ( is_admin() ) {
$admin_list_tables = new \Quiztech\AssessmentPlatform\Admin\AdminListTables();

View file

@ -0,0 +1,151 @@
<?php
namespace Quiztech\AssessmentPlatform\Includes\Ajax;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles AJAX requests originating from the Assessment Builder frontend interface.
*/
class AssessmentBuilderAjaxHandler {
/**
* Constructor. Registers AJAX hooks.
*/
public function __construct() {
// AJAX action for logged-in users to fetch questions for the library
add_action( 'wp_ajax_quiztech_fetch_library_questions', [ $this, 'fetch_library_questions' ] );
// AJAX action for logged-in users to save/update an assessment
add_action( 'wp_ajax_quiztech_save_assessment', [ $this, 'save_assessment' ] );
// TODO: Add AJAX action for creating a new question directly from the builder?
}
/**
* AJAX handler to fetch questions for the library pane.
*
* Expects search/filter parameters via $_POST.
* Returns JSON containing question data or an error.
*/
public function fetch_library_questions() {
// 1. Verify Nonce (TODO: Add nonce check)
// check_ajax_referer( 'quiztech_assessment_builder_nonce', 'nonce' );
// 2. Check Capabilities
if ( ! current_user_can( 'manage_options' ) ) { // TODO: Use specific capability
wp_send_json_error( [ 'message' => esc_html__( 'Insufficient permissions.', 'quiztech' ) ], 403 );
}
// 3. Get Filters/Search (TODO: Implement filtering/pagination)
$search_term = isset( $_POST['search'] ) ? sanitize_text_field( wp_unslash( $_POST['search'] ) ) : '';
$page = isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
$posts_per_page = 10; // Or make configurable
// 4. Query Questions
$args = [
'post_type' => 'question',
'post_status' => 'publish', // Or allow selecting other statuses?
'posts_per_page' => $posts_per_page,
'paged' => $page,
's' => $search_term, // Basic search
// TODO: Add filtering by category (taxonomy) if needed
];
$query = new \WP_Query( $args );
$questions = [];
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
$question_id = get_the_ID();
// TODO: Get question type and credit cost from meta
$questions[] = [
'id' => $question_id,
'title' => get_the_title(),
'type' => get_post_meta( $question_id, '_quiztech_question_type', true ) ?: 'N/A', // Placeholder
'cost' => get_post_meta( $question_id, '_quiztech_question_credits', true ) ?: 0, // Placeholder
];
}
wp_reset_postdata();
}
// 5. Send Response
wp_send_json_success( [
'questions' => $questions,
'pagination' => [ // TODO: Add pagination details
'current_page' => $page,
'total_pages' => $query->max_num_pages,
'total_results' => $query->found_posts
]
] );
}
/**
* AJAX handler to save or update an assessment.
*
* Expects assessment data (title, question IDs) via $_POST.
* Returns JSON success or error message.
*/
public function save_assessment() {
// 1. Verify Nonce (TODO: Add nonce check)
// check_ajax_referer( 'quiztech_assessment_builder_nonce', 'nonce' );
// 2. Check Capabilities
if ( ! current_user_can( 'manage_options' ) ) { // TODO: Use specific capability
wp_send_json_error( [ 'message' => esc_html__( 'Insufficient permissions.', 'quiztech' ) ], 403 );
}
// 3. Sanitize Input
$assessment_id = isset( $_POST['assessment_id'] ) ? absint( $_POST['assessment_id'] ) : 0; // 0 for new assessment
$assessment_title = isset( $_POST['title'] ) ? sanitize_text_field( wp_unslash( $_POST['title'] ) ) : '';
$question_ids = isset( $_POST['question_ids'] ) && is_array( $_POST['question_ids'] )
? array_map( 'absint', $_POST['question_ids'] )
: [];
if ( empty( $assessment_title ) ) {
wp_send_json_error( [ 'message' => esc_html__( 'Assessment title cannot be empty.', 'quiztech' ) ], 400 );
}
// 4. Prepare Post Data
$post_data = [
'post_title' => $assessment_title,
'post_type' => 'assessment',
'post_status' => 'publish', // Or 'draft'?
'post_author' => get_current_user_id(),
];
if ( $assessment_id > 0 ) {
// Update existing assessment
$post_data['ID'] = $assessment_id;
// Optional: Check if post exists and belongs to user before updating
$existing_post = get_post( $assessment_id );
if ( ! $existing_post || $existing_post->post_type !== 'assessment' || $existing_post->post_author != get_current_user_id() ) {
wp_send_json_error( [ 'message' => esc_html__( 'Invalid assessment ID or permission denied.', 'quiztech' ) ], 403 );
}
$result = wp_update_post( $post_data, true );
} else {
// Insert new assessment
$result = wp_insert_post( $post_data, true );
}
// 5. Handle Result & Update Meta
if ( is_wp_error( $result ) ) {
wp_send_json_error( [ 'message' => $result->get_error_message() ], 500 );
} else {
$saved_assessment_id = $result;
// Update the list of associated question IDs in post meta
// Use a simple comma-separated list or serialized array. Serialized is more flexible.
update_post_meta( $saved_assessment_id, '_quiztech_assessment_questions', $question_ids ); // Using array directly
// TODO: Calculate and save total credit cost? Or calculate dynamically?
wp_send_json_success( [
'message' => esc_html__( 'Assessment saved successfully.', 'quiztech' ),
'assessment_id' => $saved_assessment_id
] );
}
}
}