diff --git a/quiztech-assessment-platform.php b/quiztech-assessment-platform.php
index 9f3565e..5dd9979 100644
--- a/quiztech-assessment-platform.php
+++ b/quiztech-assessment-platform.php
@@ -39,6 +39,17 @@ require_once QUIZTECH_PLUGIN_DIR . 'src/Includes/roles.php';
require_once QUIZTECH_PLUGIN_DIR . 'src/Includes/post-types.php';
require_once QUIZTECH_PLUGIN_DIR . 'src/Includes/taxonomies.php';
+// Use statements for Admin classes
+use Quiztech\AssessmentPlatform\Admin\AdminListTables;
+use Quiztech\AssessmentPlatform\Admin\SettingsPage;
+use Quiztech\AssessmentPlatform\Admin\JobMetaboxes;
+use Quiztech\AssessmentPlatform\Admin\QuestionMetaboxes;
+use Quiztech\AssessmentPlatform\Admin\AssessmentMetaboxes;
+use Quiztech\AssessmentPlatform\Includes\FrontendHandler;
+use Quiztech\AssessmentPlatform\Includes\Ajax\AssessmentAjaxHandler;
+use Quiztech\AssessmentPlatform\Includes\Ajax\AssessmentBuilderAjaxHandler;
+
+
/**
* Load plugin dependencies. (Now handled by autoloading)
*/
@@ -195,14 +206,20 @@ function quiztech_init() {
// Initialize Admin-specific features
if ( is_admin() ) {
- $admin_list_tables = new \Quiztech\AssessmentPlatform\Admin\AdminListTables();
+ $admin_list_tables = new AdminListTables();
$admin_list_tables->register_hooks();
- $settings_page = new \Quiztech\AssessmentPlatform\Admin\SettingsPage();
+ $settings_page = new SettingsPage();
$settings_page->register_hooks();
- $job_metaboxes = new \Quiztech\AssessmentPlatform\Admin\JobMetaboxes();
- $job_metaboxes->register_hooks();
+ $job_metaboxes = new JobMetaboxes();
+ $job_metaboxes->register_hooks();
+
+ $question_metaboxes = new QuestionMetaboxes();
+ $question_metaboxes->register_hooks();
+
+ $assessment_metaboxes = new AssessmentMetaboxes();
+ $assessment_metaboxes->register_hooks();
}
// Future core classes (e.g., Shortcode handlers) should be instantiated here.
diff --git a/src/Admin/AssessmentMetaboxes.php b/src/Admin/AssessmentMetaboxes.php
new file mode 100644
index 0000000..27216bd
--- /dev/null
+++ b/src/Admin/AssessmentMetaboxes.php
@@ -0,0 +1,109 @@
+ID, '_quiztech_linked_question_ids', true );
+ if ( ! is_array( $linked_question_ids ) ) {
+ $linked_question_ids = [];
+ }
+
+ $questions_query = new \WP_Query( [
+ 'post_type' => 'question',
+ 'posts_per_page' => -1,
+ 'post_status' => 'publish',
+ 'orderby' => 'title',
+ 'order' => 'ASC',
+ ] );
+
+ echo '
';
+ echo '
' . \esc_html__( 'Select the questions to include in this assessment:', 'quiztech' ) . '
';
+
+ if ( $questions_query->have_posts() ) {
+ echo '
';
+ \wp_reset_postdata();
+ } else {
+ echo '
' . \esc_html__( 'No questions found. Please create some questions first.', 'quiztech' ) . '
';
+ }
+ echo '
';
+ }
+
+ /**
+ * Saves the meta box data for the linked questions on an assessment.
+ *
+ * @param int $post_id The ID of the post being saved.
+ */
+ public function save_linked_questions_meta( $post_id ) {
+ // Basic checks (nonce, autosave, permissions)
+ if ( ! isset( $_POST['quiztech_linked_questions_nonce'] ) || ! \wp_verify_nonce( \sanitize_key( $_POST['quiztech_linked_questions_nonce'] ), 'quiztech_save_linked_questions_meta' ) ) { return; }
+ if ( \defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; }
+ if ( ! \current_user_can( 'edit_post', $post_id ) ) { return; }
+ // No need to check post type here, as the action is specific ('save_post_assessment')
+
+ // Process submitted IDs
+ $submitted_ids = [];
+ if ( isset( $_POST['quiztech_linked_questions_field'] ) && is_array( $_POST['quiztech_linked_questions_field'] ) ) {
+ $submitted_ids = array_map( 'absint', $_POST['quiztech_linked_questions_field'] );
+ $submitted_ids = array_filter( $submitted_ids ); // Remove zeros/invalid entries
+ }
+
+ // Update meta (even if empty array, to clear previous selections)
+ \update_post_meta( $post_id, '_quiztech_linked_question_ids', $submitted_ids );
+ }
+}
\ No newline at end of file
diff --git a/src/Admin/JobMetaboxes.php b/src/Admin/JobMetaboxes.php
index f4f4b80..e31ce22 100644
--- a/src/Admin/JobMetaboxes.php
+++ b/src/Admin/JobMetaboxes.php
@@ -13,13 +13,43 @@ class JobMetaboxes {
* Register hooks for the metaboxes.
*/
public function register_hooks() {
- add_action( 'add_meta_boxes', [ $this, 'add_send_invite_metabox' ] );
+ add_action( 'add_meta_boxes', [ $this, 'add_job_metaboxes' ] ); // Consolidated add_meta_boxes hook
+ add_action( 'save_post_job', [ $this, 'save_linked_assessment_meta' ] ); // Hook for saving linked assessment
add_action( 'wp_ajax_quiztech_send_job_invite', [ $this, 'handle_send_invite_ajax' ] );
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_scripts' ] );
}
/**
- * Adds the "Send Invite" metabox to the Job CPT.
+ * Adds all metaboxes for the Job CPT.
+ *
+ * @param string $post_type The current post type.
+ */
+ public function add_job_metaboxes( $post_type ) {
+ if ( 'job' === $post_type ) {
+ // Send Invite Metabox (Side)
+ add_meta_box(
+ 'quiztech_send_invite_metabox', // Metabox ID
+ __( 'Send Assessment Invite', 'quiztech' ), // Title
+ [ $this, 'render_send_invite_metabox' ], // Callback function
+ 'job', // Post type
+ 'side', // Context
+ 'high' // Priority
+ );
+
+ // Linked Assessment Metabox (Normal)
+ add_meta_box(
+ 'quiztech_linked_assessment_metabox',
+ __( 'Linked Assessment', 'quiztech' ),
+ [ $this, 'render_linked_assessment_metabox' ],
+ 'job',
+ 'normal', // Context below editor
+ 'default'
+ );
+ }
+ }
+
+ /**
+ * Adds the "Send Invite" metabox to the Job CPT. - DEPRECATED (consolidated into add_job_metaboxes)
*
* @param string $post_type The current post type.
*/
@@ -136,4 +166,67 @@ class JobMetaboxes {
]);
}
}
+
+ /**
+ * Renders the meta box content for selecting an assessment for a job.
+ *
+ * @param \WP_Post $post The post object.
+ */
+ public function render_linked_assessment_metabox( $post ) {
+ \wp_nonce_field( 'quiztech_save_linked_assessment_meta', 'quiztech_linked_assessment_nonce' );
+ $linked_assessment_id = \get_post_meta( $post->ID, '_quiztech_linked_assessment_id', true );
+
+ $assessments_query = new \WP_Query( [
+ 'post_type' => 'assessment',
+ 'posts_per_page' => -1,
+ 'post_status' => 'publish',
+ 'orderby' => 'title',
+ 'order' => 'ASC',
+ ] );
+
+ echo '<label for="quiztech_linked_assessment_field">';
+ \esc_html_e( 'Select the assessment for this job:', 'quiztech' );
+ echo '</label><br />';
+
+ if ( $assessments_query->have_posts() ) {
+ echo '<select name="quiztech_linked_assessment_field" id="quiztech_linked_assessment_field" class="widefat">';
+ echo '<option value="">' . \esc_html__( '-- None --', 'quiztech' ) . '</option>';
+ while ( $assessments_query->have_posts() ) {
+ $assessments_query->the_post();
+ $assessment_id = \get_the_ID();
+ $assessment_title = \get_the_title();
+ echo '<option value="' . \esc_attr( $assessment_id ) . '" ' . \selected( $linked_assessment_id, $assessment_id, false ) . '>' . \esc_html( $assessment_title ) . '</option>';
+ }
+ echo '</select>';
+ \wp_reset_postdata();
+ } else {
+ echo '<p>' . \esc_html__( 'No assessments found. Please create an assessment first.', 'quiztech' ) . '</p>';
+ }
+ }
+
+ /**
+ * Saves the meta box data for the linked assessment on a job.
+ *
+ * @param int $post_id The ID of the post being saved.
+ */
+ public function save_linked_assessment_meta( $post_id ) {
+ // Basic checks (nonce, autosave, permissions)
+ if ( ! isset( $_POST['quiztech_linked_assessment_nonce'] ) || ! \wp_verify_nonce( \sanitize_key( $_POST['quiztech_linked_assessment_nonce'] ), 'quiztech_save_linked_assessment_meta' ) ) { return; }
+ if ( \defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; }
+ if ( ! \current_user_can( 'edit_post', $post_id ) ) { return; }
+ // No need to check post type here, as the action is specific ('save_post_job')
+
+ // Field check and sanitize
+ if ( isset( $_POST['quiztech_linked_assessment_field'] ) ) {
+ $assessment_id = \sanitize_text_field( \wp_unslash( $_POST['quiztech_linked_assessment_field'] ) );
+ $assessment_id = '' === $assessment_id ? '' : \absint( $assessment_id );
+ \update_post_meta( $post_id, '_quiztech_linked_assessment_id', $assessment_id );
+ } else {
+ // If the field isn't submitted (e.g., if the metabox wasn't rendered for some reason),
+ // we might want to delete the meta key to ensure no stale data persists.
+ // However, typically, if the field exists and is submitted empty, the above logic handles it (sets to '').
+ // Let's delete it if it's not set in POST, assuming the metabox should always be present on save.
+ \delete_post_meta( $post_id, '_quiztech_linked_assessment_id' );
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Admin/QuestionMetaboxes.php b/src/Admin/QuestionMetaboxes.php
new file mode 100644
index 0000000..c4555e3
--- /dev/null
+++ b/src/Admin/QuestionMetaboxes.php
@@ -0,0 +1,232 @@
+ID, '_quiztech_question_type', true );
+ $question_types = [
+ 'text' => \__( 'Text (Single Line)', 'quiztech' ),
+ 'textarea' => \__( 'Text Area (Multi-line)', 'quiztech' ),
+ 'multiple-choice' => \__( 'Multiple Choice (Single Answer)', 'quiztech' ),
+ 'checkbox' => \__( 'Checkboxes (Multiple Answers)', 'quiztech' ),
+ 'numeric' => \__( 'Numeric', 'quiztech' ),
+ ];
+
+ echo ' ';
+ echo '';
+ }
+
+ /**
+ * Renders the meta box content for Correct Answer.
+ *
+ * @param \WP_Post $post The post object.
+ */
+ public function render_correct_answer_metabox( $post ) {
+ \wp_nonce_field( 'quiztech_save_correct_answer_meta', 'quiztech_correct_answer_nonce' );
+ $value = \get_post_meta( $post->ID, '_quiztech_correct_answer', true );
+
+ echo '
';
+ echo '';
+ echo '' . \esc_html__( 'Note: How this field is interpreted depends on the Question Type selected above.', 'quiztech' ) . '
';
+ }
+
+ /**
+ * Renders the meta box content for Credit Cost.
+ *
+ * @param \WP_Post $post The post object.
+ */
+ public function render_credit_cost_metabox( $post ) {
+ \wp_nonce_field( 'quiztech_save_credit_cost_meta', 'quiztech_credit_cost_nonce' );
+ $value = \get_post_meta( $post->ID, '_quiztech_credit_cost', true );
+ $value = $value ? \absint( $value ) : 0; // Ensure non-negative integer, default 0
+
+ echo '';
+ echo ' ';
+ echo '';
+ echo '
' . \esc_html__( 'Number of credits required to use this question.', 'quiztech' ) . '';
+ echo '
';
+ }
+
+ /**
+ * Renders the meta box content for Question Points.
+ *
+ * @param \WP_Post $post The post object.
+ */
+ public function render_question_points_metabox( $post ) {
+ \wp_nonce_field( 'quiztech_save_question_points_meta', 'quiztech_question_points_nonce' );
+ $value = \get_post_meta( $post->ID, '_quiztech_question_points', true );
+ $value = $value ? \absint( $value ) : 0; // Ensure non-negative integer, default 0
+
+ echo '';
+ echo ' ';
+ echo '';
+ echo '
' . \esc_html__( 'Points awarded for answering this question correctly.', 'quiztech' ) . '';
+ echo '
';
+ }
+
+ /**
+ * Saves the meta box data for Question Type.
+ *
+ * @param int $post_id The ID of the post being saved.
+ */
+ public function save_question_type_meta( $post_id ) {
+ // Basic checks (nonce, autosave, permissions)
+ if ( ! isset( $_POST['quiztech_question_type_nonce'] ) || ! \wp_verify_nonce( \sanitize_key( $_POST['quiztech_question_type_nonce'] ), 'quiztech_save_question_type_meta' ) ) { return; }
+ if ( \defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; }
+ if ( ! \current_user_can( 'edit_post', $post_id ) ) { return; }
+ // No need to check post type here, as the action is specific ('save_post_question')
+
+ // Field check and sanitize
+ if ( ! isset( $_POST['quiztech_question_type_field'] ) ) { return; }
+ $new_meta_value = \sanitize_text_field( \wp_unslash( $_POST['quiztech_question_type_field'] ) );
+
+ // Validation against allowed types
+ $allowed_types = ['text', 'textarea', 'multiple-choice', 'checkbox', 'numeric'];
+ if ( in_array( $new_meta_value, $allowed_types, true ) || '' === $new_meta_value ) {
+ \update_post_meta( $post_id, '_quiztech_question_type', $new_meta_value );
+ } else {
+ \delete_post_meta( $post_id, '_quiztech_question_type' );
+ }
+ }
+
+ /**
+ * Saves the meta box data for Correct Answer.
+ *
+ * @param int $post_id The ID of the post being saved.
+ */
+ public function save_correct_answer_meta( $post_id ) {
+ // Basic checks (nonce, autosave, permissions)
+ if ( ! isset( $_POST['quiztech_correct_answer_nonce'] ) || ! \wp_verify_nonce( \sanitize_key( $_POST['quiztech_correct_answer_nonce'] ), 'quiztech_save_correct_answer_meta' ) ) { return; }
+ if ( \defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; }
+ if ( ! \current_user_can( 'edit_post', $post_id ) ) { return; }
+
+ // Field check and sanitize
+ if ( isset( $_POST['quiztech_correct_answer_field'] ) ) {
+ $new_meta_value = \sanitize_textarea_field( \wp_unslash( $_POST['quiztech_correct_answer_field'] ) );
+ \update_post_meta( $post_id, '_quiztech_correct_answer', $new_meta_value );
+ } else {
+ // Delete if field is expected but not submitted
+ \delete_post_meta( $post_id, '_quiztech_correct_answer' );
+ }
+ }
+
+ /**
+ * Saves the meta box data for Credit Cost.
+ *
+ * @param int $post_id The ID of the post being saved.
+ */
+ public function save_credit_cost_meta( $post_id ) {
+ // Basic checks (nonce, autosave, permissions)
+ if ( ! isset( $_POST['quiztech_credit_cost_nonce'] ) || ! \wp_verify_nonce( \sanitize_key( $_POST['quiztech_credit_cost_nonce'] ), 'quiztech_save_credit_cost_meta' ) ) { return; }
+ if ( \defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; }
+ if ( ! \current_user_can( 'edit_post', $post_id ) ) { return; }
+
+ // Field check and sanitize
+ if ( isset( $_POST['quiztech_credit_cost_field'] ) ) {
+ // Use absint to ensure it's a non-negative integer.
+ $new_meta_value = \absint( \wp_unslash( $_POST['quiztech_credit_cost_field'] ) );
+ \update_post_meta( $post_id, '_quiztech_credit_cost', $new_meta_value );
+ }
+ }
+
+ /**
+ * Saves the meta box data for Question Points.
+ *
+ * @param int $post_id The ID of the post being saved.
+ */
+ public function save_question_points_meta( $post_id ) {
+ // Basic checks (nonce, autosave, permissions)
+ if ( ! isset( $_POST['quiztech_question_points_nonce'] ) || ! \wp_verify_nonce( \sanitize_key( $_POST['quiztech_question_points_nonce'] ), 'quiztech_save_question_points_meta' ) ) { return; }
+ if ( \defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; }
+ if ( ! \current_user_can( 'edit_post', $post_id ) ) { return; }
+
+ // Field check and sanitize
+ if ( isset( $_POST['quiztech_question_points_field'] ) ) {
+ // Use absint to ensure it's a non-negative integer.
+ $new_meta_value = \absint( \wp_unslash( $_POST['quiztech_question_points_field'] ) );
+ \update_post_meta( $post_id, '_quiztech_question_points', $new_meta_value );
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Includes/post-types.php b/src/Includes/post-types.php
index 95a7ee0..e44fb7f 100644
--- a/src/Includes/post-types.php
+++ b/src/Includes/post-types.php
@@ -169,288 +169,8 @@ function quiztech_register_post_types() {
}
\add_action( 'init', __NAMESPACE__ . '\quiztech_register_post_types' );
-
-// --- Meta Box Registration ---
-
-/**
- * Adds meta boxes for various CPTs.
- * Hooks into 'add_meta_boxes'.
- *
- * @param string $post_type The post type slug.
- */
-function quiztech_add_all_meta_boxes( $post_type ) {
- // Meta Boxes for 'question' CPT
- if ( 'question' === $post_type ) {
- \add_meta_box(
- 'quiztech_question_type_metabox',
- \__( 'Question Type', 'quiztech' ),
- __NAMESPACE__ . '\quiztech_render_question_type_metabox',
- 'question',
- 'normal', // Context below editor
- 'high'
- );
- \add_meta_box(
- 'quiztech_correct_answer_metabox',
- \__( 'Correct Answer(s)', 'quiztech' ),
- __NAMESPACE__ . '\quiztech_render_correct_answer_metabox',
- 'question',
- 'normal', // Context below editor
- 'high'
- );
- }
-
- // Meta Box for 'job' CPT
- if ( 'job' === $post_type ) {
- \add_meta_box(
- 'quiztech_linked_assessment_metabox',
- \__( 'Linked Assessment', 'quiztech' ),
- __NAMESPACE__ . '\quiztech_render_linked_assessment_metabox',
- 'job',
- 'normal', // Context below editor
- 'default'
- );
- }
-
- // Meta Box for 'assessment' CPT
- if ( 'assessment' === $post_type ) {
- \add_meta_box(
- 'quiztech_linked_questions_metabox',
- \__( 'Linked Questions', 'quiztech' ),
- __NAMESPACE__ . '\quiztech_render_linked_questions_metabox',
- 'assessment',
- 'normal', // Context below editor
- 'high'
- );
- }
-}
-\add_action( 'add_meta_boxes', __NAMESPACE__ . '\quiztech_add_all_meta_boxes' );
-
-
-// --- Meta Box Render Functions ---
-
-/**
- * Renders the meta box content for Question Type.
- *
- * @param \WP_Post $post The post object.
- */
-function quiztech_render_question_type_metabox( $post ) {
- \wp_nonce_field( 'quiztech_save_question_type_meta', 'quiztech_question_type_nonce' );
- $value = \get_post_meta( $post->ID, '_quiztech_question_type', true );
- $question_types = [
- 'text' => \__( 'Text (Single Line)', 'quiztech' ),
- 'textarea' => \__( 'Text Area (Multi-line)', 'quiztech' ),
- 'multiple-choice' => \__( 'Multiple Choice (Single Answer)', 'quiztech' ),
- 'checkbox' => \__( 'Checkboxes (Multiple Answers)', 'quiztech' ),
- 'numeric' => \__( 'Numeric', 'quiztech' ),
- ];
-
- echo ' ';
- echo '';
-}
-
-/**
- * Renders the meta box content for Correct Answer.
- *
- * @param \WP_Post $post The post object.
- */
-function quiztech_render_correct_answer_metabox( $post ) {
- \wp_nonce_field( 'quiztech_save_correct_answer_meta', 'quiztech_correct_answer_nonce' );
- $value = \get_post_meta( $post->ID, '_quiztech_correct_answer', true );
-
- echo '
';
- echo '';
- echo '' . \esc_html__( 'Note: How this field is interpreted depends on the Question Type selected above.', 'quiztech' ) . '
';
-}
-
-/**
- * Renders the meta box content for selecting an assessment for a job.
- *
- * @param \WP_Post $post The post object.
- */
-function quiztech_render_linked_assessment_metabox( $post ) {
- \wp_nonce_field( 'quiztech_save_linked_assessment_meta', 'quiztech_linked_assessment_nonce' );
- $linked_assessment_id = \get_post_meta( $post->ID, '_quiztech_linked_assessment_id', true );
-
- $assessments_query = new \WP_Query( [
- 'post_type' => 'assessment',
- 'posts_per_page' => -1,
- 'post_status' => 'publish',
- 'orderby' => 'title',
- 'order' => 'ASC',
- ] );
-
- echo '
';
-
- if ( $assessments_query->have_posts() ) {
- echo '';
- \wp_reset_postdata();
- } else {
- echo '' . \esc_html__( 'No assessments found. Please create an assessment first.', 'quiztech' ) . '
';
- }
-}
-
-/**
- * Renders the meta box content for selecting questions for an assessment.
- *
- * @param \WP_Post $post The post object.
- */
-function quiztech_render_linked_questions_metabox( $post ) {
- \wp_nonce_field( 'quiztech_save_linked_questions_meta', 'quiztech_linked_questions_nonce' );
- $linked_question_ids = \get_post_meta( $post->ID, '_quiztech_linked_question_ids', true );
- if ( ! is_array( $linked_question_ids ) ) {
- $linked_question_ids = [];
- }
-
- $questions_query = new \WP_Query( [
- 'post_type' => 'question',
- 'posts_per_page' => -1,
- 'post_status' => 'publish',
- 'orderby' => 'title',
- 'order' => 'ASC',
- ] );
-
- echo '';
- echo '
' . \esc_html__( 'Select the questions to include in this assessment:', 'quiztech' ) . '
';
-
- if ( $questions_query->have_posts() ) {
- echo '
';
- \wp_reset_postdata();
- } else {
- echo '
' . \esc_html__( 'No questions found. Please create some questions first.', 'quiztech' ) . '
';
- }
- echo '
';
-}
-
-
-// --- Meta Box Save Functions ---
-
-/**
- * Saves the meta box data for Question Type.
- * Hooks into 'save_post_question'.
- *
- * @param int $post_id The ID of the post being saved.
- */
-function quiztech_save_question_type_meta( $post_id ) {
- // Basic checks (nonce, autosave, permissions)
- if ( ! isset( $_POST['quiztech_question_type_nonce'] ) || ! \wp_verify_nonce( \sanitize_key( $_POST['quiztech_question_type_nonce'] ), 'quiztech_save_question_type_meta' ) ) { return; }
- if ( \defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; }
- if ( ! \current_user_can( 'edit_post', $post_id ) ) { return; }
-
- // Field check and sanitize
- if ( ! isset( $_POST['quiztech_question_type_field'] ) ) { return; }
- $new_meta_value = \sanitize_text_field( \wp_unslash( $_POST['quiztech_question_type_field'] ) );
-
- // Validation against allowed types
- $allowed_types = ['text', 'textarea', 'multiple-choice', 'checkbox', 'numeric'];
- if ( in_array( $new_meta_value, $allowed_types, true ) || '' === $new_meta_value ) {
- \update_post_meta( $post_id, '_quiztech_question_type', $new_meta_value );
- } else {
- \delete_post_meta( $post_id, '_quiztech_question_type' );
- }
-}
-\add_action( 'save_post_question', __NAMESPACE__ . '\quiztech_save_question_type_meta' );
-
-/**
- * Saves the meta box data for Correct Answer.
- * Hooks into 'save_post_question'.
- *
- * @param int $post_id The ID of the post being saved.
- */
-function quiztech_save_correct_answer_meta( $post_id ) {
- // Basic checks (nonce, autosave, permissions)
- if ( ! isset( $_POST['quiztech_correct_answer_nonce'] ) || ! \wp_verify_nonce( \sanitize_key( $_POST['quiztech_correct_answer_nonce'] ), 'quiztech_save_correct_answer_meta' ) ) { return; }
- if ( \defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; }
- if ( ! \current_user_can( 'edit_post', $post_id ) ) { return; }
-
- // Field check and sanitize
- if ( isset( $_POST['quiztech_correct_answer_field'] ) ) {
- $new_meta_value = \sanitize_textarea_field( \wp_unslash( $_POST['quiztech_correct_answer_field'] ) );
- \update_post_meta( $post_id, '_quiztech_correct_answer', $new_meta_value );
- } else {
- // Delete if field is expected but not submitted
- \delete_post_meta( $post_id, '_quiztech_correct_answer' );
- }
-}
-\add_action( 'save_post_question', __NAMESPACE__ . '\quiztech_save_correct_answer_meta' );
-
-/**
- * Saves the meta box data for the linked assessment on a job.
- * Hooks into 'save_post_job'.
- *
- * @param int $post_id The ID of the post being saved.
- */
-function quiztech_save_linked_assessment_meta( $post_id ) {
- // Basic checks (nonce, autosave, permissions)
- if ( ! isset( $_POST['quiztech_linked_assessment_nonce'] ) || ! \wp_verify_nonce( \sanitize_key( $_POST['quiztech_linked_assessment_nonce'] ), 'quiztech_save_linked_assessment_meta' ) ) { return; }
- if ( \defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; }
- if ( ! \current_user_can( 'edit_post', $post_id ) ) { return; }
-
- // Field check and sanitize
- if ( isset( $_POST['quiztech_linked_assessment_field'] ) ) {
- $assessment_id = \sanitize_text_field( \wp_unslash( $_POST['quiztech_linked_assessment_field'] ) );
- $assessment_id = '' === $assessment_id ? '' : \absint( $assessment_id );
- \update_post_meta( $post_id, '_quiztech_linked_assessment_id', $assessment_id );
- } else {
- \delete_post_meta( $post_id, '_quiztech_linked_assessment_id' );
- }
-}
-\add_action( 'save_post_job', __NAMESPACE__ . '\quiztech_save_linked_assessment_meta' );
-
-/**
- * Saves the meta box data for the linked questions on an assessment.
- * Hooks into 'save_post_assessment'.
- *
- * @param int $post_id The ID of the post being saved.
- */
-function quiztech_save_linked_questions_meta( $post_id ) {
- // Basic checks (nonce, autosave, permissions)
- if ( ! isset( $_POST['quiztech_linked_questions_nonce'] ) || ! \wp_verify_nonce( \sanitize_key( $_POST['quiztech_linked_questions_nonce'] ), 'quiztech_save_linked_questions_meta' ) ) { return; }
- if ( \defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; }
- if ( ! \current_user_can( 'edit_post', $post_id ) ) { return; }
-
- // Process submitted IDs
- $submitted_ids = [];
- if ( isset( $_POST['quiztech_linked_questions_field'] ) && is_array( $_POST['quiztech_linked_questions_field'] ) ) {
- $submitted_ids = array_map( 'absint', $_POST['quiztech_linked_questions_field'] );
- $submitted_ids = array_filter( $submitted_ids ); // Remove zeros/invalid entries
- }
-
- // Update meta (even if empty array, to clear previous selections)
- \update_post_meta( $post_id, '_quiztech_linked_question_ids', $submitted_ids );
-}
-\add_action( 'save_post_assessment', __NAMESPACE__ . '\quiztech_save_linked_questions_meta' );
+// Metabox registration, rendering, and saving are now handled in dedicated classes
+// within the src/Admin/ directory (e.g., QuestionMetaboxes.php, AssessmentMetaboxes.php, JobMetaboxes.php).
+// These classes are instantiated and their hooks registered in the main plugin file.
?>
\ No newline at end of file