namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'validate_schema' ), 'permission_callback' => array( $this, 'validate_permissions_check' ), 'args' => array( 'schema_data' => array( 'description' => __( 'The schema data to validate (JSON object or string).', 'ai-schema-gen' ), 'type' => array( 'object', 'string' ), 'required' => true, ), ), ), ) ); // POST /validate/{id} - Validate existing schemas for a post. register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'validate_post_schema' ), 'permission_callback' => array( $this, 'validate_permissions_check' ), 'args' => array( 'id' => array( 'description' => __( 'Post ID whose schemas should be validated.', 'ai-schema-gen' ), 'type' => 'integer', 'required' => true, 'sanitize_callback' => 'absint', ), ), ), ) ); } /** * Validate provided schema data. * * Accepts a JSON schema payload and validates it against schema.org * requirements. * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object or error. */ public function validate_schema( $request ) { $schema_data = $request->get_param( 'schema_data' ); // Decode if it is a JSON string. if ( is_string( $schema_data ) ) { $schema_data = json_decode( $schema_data, true ); if ( null === $schema_data ) { return $this->error_response( 'schema_ai_invalid_json', __( 'Invalid JSON in schema_data.', 'ai-schema-gen' ), 400 ); } } if ( ! is_array( $schema_data ) || empty( $schema_data ) ) { return $this->error_response( 'schema_ai_empty_schema', __( 'Schema data cannot be empty.', 'ai-schema-gen' ), 400 ); } $validator = new Schema_AI_Schema_Validator(); $result = $validator->validate( $schema_data ); return $this->success_response( array( 'valid' => $result['valid'], 'errors' => $result['errors'], 'warnings' => $result['warnings'], 'score' => $result['score'], ) ); } /** * Validate all schemas stored for a specific post. * * Loads schemas from the database, validates each one, updates * the validation results in the database, and returns the results. * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object or error. */ public function validate_post_schema( $request ) { global $wpdb; $post_id = absint( $request->get_param( 'id' ) ); $valid = $this->validate_post_id( $post_id ); if ( is_wp_error( $valid ) ) { return $valid; } $table = esc_sql( $wpdb->prefix . 'schema_ai_schemas' ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Required for custom table; no WP API alternative exists. $schemas = $wpdb->get_results( $wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is sanitized via esc_sql() and not user input. "SELECT * FROM {$table} WHERE post_id = %d", $post_id ) ); if ( empty( $schemas ) ) { return $this->error_response( 'schema_ai_no_schemas', __( 'No schemas found for this post.', 'ai-schema-gen' ), 404 ); } $validator = new Schema_AI_Schema_Validator(); $results = array(); $now = current_time( 'mysql' ); foreach ( $schemas as $schema_row ) { $schema_data = json_decode( $schema_row->schema_data, true ); if ( ! is_array( $schema_data ) ) { $validation = array( 'valid' => false, 'errors' => array( __( 'Schema data is not valid JSON.', 'ai-schema-gen' ) ), 'warnings' => array(), 'score' => 0, ); } else { $validation = $validator->validate( $schema_data ); } // Determine validation status. $status = $validation['valid'] ? 'valid' : 'invalid'; // Update database with validation results. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Required for custom table; write operation (UPDATE), caching not applicable. $wpdb->update( $table, array( 'validation_status' => $status, 'validation_errors' => wp_json_encode( array( 'errors' => $validation['errors'], 'warnings' => $validation['warnings'], ) ), 'last_validated' => $now, 'updated_at' => $now, ), array( 'id' => $schema_row->id ), array( '%s', '%s', '%s', '%s' ), array( '%d' ) ); $results[] = array( 'schema_id' => (int) $schema_row->id, 'schema_type' => $schema_row->schema_type, 'valid' => $validation['valid'], 'errors' => $validation['errors'], 'warnings' => $validation['warnings'], 'score' => $validation['score'], ); } return $this->success_response( array( 'post_id' => $post_id, 'validations' => $results, 'total' => count( $results ), ) ); } /** * Permission check for validation endpoints. * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if allowed. */ public function validate_permissions_check( $request ) { if ( ! current_user_can( 'edit_posts' ) ) { return new WP_Error( 'schema_ai_forbidden', __( 'You do not have permission to validate schemas.', 'ai-schema-gen' ), array( 'status' => 403 ) ); } return true; } }