diff --git a/includes/class-form-handler.php b/includes/class-form-handler.php
new file mode 100644
index 0000000..365fe5c
--- /dev/null
+++ b/includes/class-form-handler.php
@@ -0,0 +1,352 @@
+is_enabled() ) {
+ $verified = $captcha->verify_response( $_POST );
+ if ( ! $verified ) {
+ $captcha_error = array(
+ 'messages' => array( 'Captcha-Verifizierung fehlgeschlagen. Bitte versuchen Sie es erneut.' ),
+ 'fields' => array(),
+ );
+ set_transient( 'umzugsliste_errors_' . session_id(), $captcha_error, 300 );
+ wp_safe_redirect( wp_get_referer() );
+ exit;
+ }
+ }
+
+ // Validate submission
+ $validation_errors = $this->validate_submission( $_POST );
+ if ( ! empty( $validation_errors ) ) {
+ // Store errors in transient for display
+ set_transient( 'umzugsliste_errors_' . session_id(), $validation_errors, 300 );
+ // Redirect back to form
+ wp_safe_redirect( wp_get_referer() );
+ exit;
+ }
+
+ // Sanitize data
+ $data = $this->sanitize_submission( $_POST );
+
+ // Save to CPT
+ $entry_id = $this->save_to_cpt( $data );
+
+ if ( ! $entry_id ) {
+ // Log error but continue
+ error_log( 'Umzugsliste: Failed to save CPT entry' );
+ }
+
+ // Send email
+ $email_sent = $this->send_email( $entry_id, $data );
+
+ if ( ! $email_sent ) {
+ // Email failed - update CPT and show error
+ if ( $entry_id ) {
+ update_post_meta( $entry_id, '_umzugsliste_email_sent', false );
+ }
+
+ // Show error message
+ wp_die(
+ '
E-Mail konnte nicht versendet werden
+ Ihre Anfrage wurde gespeichert, aber die E-Mail konnte nicht versendet werden.
+ Bitte kontaktieren Sie uns telefonisch:
+ Wiesbaden: (06 11) 2 20 20
+ Mainz: (0 61 31) 22 21 41
+ Zurück zur Startseite
',
+ 'E-Mail-Fehler'
+ );
+ }
+
+ // Redirect to thank you page
+ $this->redirect_to_thank_you( $entry_id );
+ }
+
+ /**
+ * Validate submission data
+ *
+ * @param array $data POST data
+ * @return array Validation errors (empty if valid)
+ */
+ private function validate_submission( $data ) {
+ $errors = array();
+
+ // Required fields
+ $required_fields = array(
+ 'bName' => 'Name (Beladeadresse)',
+ 'bStrasse' => 'Straße (Beladeadresse)',
+ 'bort' => 'PLZ/Ort (Beladeadresse)',
+ 'bTelefon' => 'Telefon (Beladeadresse)',
+ 'eName' => 'Name (Entladeadresse)',
+ 'eStrasse' => 'Straße (Entladeadresse)',
+ 'eort' => 'PLZ/Ort (Entladeadresse)',
+ );
+
+ foreach ( $required_fields as $field => $label ) {
+ if ( empty( $data[ $field ] ) ) {
+ $errors[] = 'Pflichtfeld fehlt: ' . $label;
+ }
+ }
+
+ // Validate email if provided
+ if ( ! empty( $data['info']['eE-Mail'] ) && ! is_email( $data['info']['eE-Mail'] ) ) {
+ $errors[] = 'Ungültige E-Mail-Adresse';
+ }
+
+ // Validate date
+ if ( empty( $data['day'] ) || empty( $data['month'] ) || empty( $data['year'] ) ) {
+ $errors[] = 'Umzugstermin fehlt';
+ }
+
+ // Check if at least one furniture item has quantity
+ $has_items = false;
+ $rooms = Umzugsliste_Furniture_Data::get_rooms();
+
+ foreach ( $rooms as $room_key => $room_label ) {
+ $post_array_name = ucfirst( $room_key );
+ if ( 'kueche_esszimmer' === $room_key ) {
+ $post_array_name = 'Kueche_Esszimmer';
+ }
+
+ if ( ! empty( $data[ $post_array_name ] ) ) {
+ foreach ( $data[ $post_array_name ] as $key => $value ) {
+ if ( substr( $key, 0, 1 ) === 'v' && ! empty( $value ) && floatval( $value ) > 0 ) {
+ $has_items = true;
+ break 2;
+ }
+ }
+ }
+ }
+
+ if ( ! $has_items ) {
+ $errors[] = 'Bitte geben Sie mindestens eine Möbelmenge ein';
+ }
+
+ return $errors;
+ }
+
+ /**
+ * Sanitize submission data
+ *
+ * @param array $data POST data
+ * @return array Sanitized data
+ */
+ private function sanitize_submission( $data ) {
+ $sanitized = array();
+
+ // Sanitize simple text fields
+ $text_fields = array( 'bName', 'eName', 'bStrasse', 'eStrasse', 'bort', 'eort', 'bTelefon', 'eTelefon', 'day', 'month', 'year' );
+
+ foreach ( $text_fields as $field ) {
+ $sanitized[ $field ] = isset( $data[ $field ] ) ? sanitize_text_field( $data[ $field ] ) : '';
+ }
+
+ // Sanitize info array
+ if ( ! empty( $data['info'] ) && is_array( $data['info'] ) ) {
+ $sanitized['info'] = array();
+ foreach ( $data['info'] as $key => $value ) {
+ if ( 'eE-Mail' === $key ) {
+ $sanitized['info'][ $key ] = sanitize_email( $value );
+ } else {
+ $sanitized['info'][ $key ] = sanitize_text_field( $value );
+ }
+ }
+ }
+
+ // Sanitize room arrays
+ $rooms = Umzugsliste_Furniture_Data::get_rooms();
+
+ foreach ( $rooms as $room_key => $room_label ) {
+ $post_array_name = ucfirst( $room_key );
+ if ( 'kueche_esszimmer' === $room_key ) {
+ $post_array_name = 'Kueche_Esszimmer';
+ }
+
+ if ( ! empty( $data[ $post_array_name ] ) && is_array( $data[ $post_array_name ] ) ) {
+ $sanitized[ $post_array_name ] = array();
+ foreach ( $data[ $post_array_name ] as $key => $value ) {
+ $sanitized[ $post_array_name ][ $key ] = sanitize_text_field( $value );
+ }
+ }
+ }
+
+ return $sanitized;
+ }
+
+ /**
+ * Save submission to CPT
+ *
+ * @param array $data Sanitized form data
+ * @return int|false Post ID on success, false on failure
+ */
+ private function save_to_cpt( $data ) {
+ $customer_name = $data['bName'] ?? 'Unbekannt';
+ $date_string = ( $data['day'] ?? '' ) . '.' . ( $data['month'] ?? '' ) . '.' . ( $data['year'] ?? '' );
+
+ // Calculate total CBM
+ $total_cbm = 0;
+ $rooms = Umzugsliste_Furniture_Data::get_rooms();
+
+ foreach ( $rooms as $room_key => $room_label ) {
+ $post_array_name = ucfirst( $room_key );
+ if ( 'kueche_esszimmer' === $room_key ) {
+ $post_array_name = 'Kueche_Esszimmer';
+ }
+
+ $room_data = $data[ $post_array_name ] ?? array();
+
+ foreach ( $room_data as $key => $value ) {
+ if ( substr( $key, 0, 1 ) === 'v' && ! empty( $value ) && floatval( $value ) > 0 ) {
+ $item_name = substr( $key, 1 );
+ $quantity = floatval( str_replace( ',', '.', trim( $value ) ) );
+ $cbm = isset( $room_data[ 'q' . $item_name ] ) ? floatval( $room_data[ 'q' . $item_name ] ) : 0;
+ $total_cbm += ( $quantity * $cbm );
+ }
+ }
+ }
+
+ // Create post
+ $post_id = wp_insert_post(
+ array(
+ 'post_title' => 'Anfrage vom ' . $date_string . ' - ' . $customer_name,
+ 'post_content' => wp_json_encode( $data ),
+ 'post_status' => 'publish',
+ 'post_type' => 'umzugsliste_entry',
+ )
+ );
+
+ if ( ! is_wp_error( $post_id ) && $post_id ) {
+ // Add meta data
+ update_post_meta( $post_id, '_umzugsliste_customer_name', $customer_name );
+ update_post_meta( $post_id, '_umzugsliste_customer_email', $data['info']['eE-Mail'] ?? '' );
+ update_post_meta( $post_id, '_umzugsliste_moving_date', $date_string );
+ update_post_meta( $post_id, '_umzugsliste_total_cbm', number_format( $total_cbm, 2, '.', '' ) );
+ update_post_meta( $post_id, '_umzugsliste_submission_ip', $_SERVER['REMOTE_ADDR'] ?? '' );
+
+ return $post_id;
+ }
+
+ return false;
+ }
+
+ /**
+ * Send email via wp_mail()
+ *
+ * @param int $entry_id CPT entry ID
+ * @param array $data Form data
+ * @return bool True on success
+ */
+ private function send_email( $entry_id, $data ) {
+ // Generate email HTML
+ $email_html = Umzugsliste_Email_Generator::generate( $data );
+
+ // Get receiver email from settings
+ $to = get_option( 'umzugsliste_receiver_email', get_option( 'admin_email' ) );
+
+ // Subject
+ $subject = 'Internetanfrage - Anfrage vom ' . date( 'd.m.Y H:i' );
+
+ // Headers
+ $headers = array( 'Content-Type: text/html; charset=UTF-8' );
+
+ // Add Reply-To if customer email provided
+ $customer_email = $data['info']['eE-Mail'] ?? '';
+ if ( ! empty( $customer_email ) && is_email( $customer_email ) ) {
+ $customer_name = $data['bName'] ?? 'Kunde';
+ $headers[] = 'Reply-To: ' . $customer_name . ' <' . $customer_email . '>';
+ }
+
+ // Send email
+ $sent = wp_mail( $to, $subject, $email_html, $headers );
+
+ // Update CPT meta
+ if ( $entry_id ) {
+ update_post_meta( $entry_id, '_umzugsliste_email_sent', $sent );
+ if ( $sent ) {
+ update_post_meta( $entry_id, '_umzugsliste_email_sent_at', current_time( 'mysql' ) );
+ }
+ }
+
+ return $sent;
+ }
+
+ /**
+ * Redirect to thank you page
+ *
+ * @param int $entry_id CPT entry ID
+ */
+ private function redirect_to_thank_you( $entry_id ) {
+ $thank_you_url = get_option( 'umzugsliste_thankyou_url', home_url() );
+
+ // Add query parameters
+ $redirect_url = add_query_arg(
+ array(
+ 'umzugsliste' => 'success',
+ 'entry' => $entry_id,
+ ),
+ $thank_you_url
+ );
+
+ wp_safe_redirect( $redirect_url );
+ exit;
+ }
+}