Jake Vanderwerf
2026-01-22 58e8ae0759ccfa97c478ccae4e0778bdce70966f
inc/rest/routes/FormRoutes.php
@@ -142,7 +142,6 @@
   {
      // Get form configuration
      $form_config = FormBlock::getForm($form_type);
      if (!$form_config) {
         return new WP_Error('invalid_form', 'Form configuration not found.');
      }
@@ -178,7 +177,6 @@
      try {
         $email_sent = $this->sendEmailNotification($form_type, $form_config, $processed_data, $files);
      } catch (\Exception $e) {
         ;
         return new WP_Error('email_failed', 'Email error: ' . $e->getMessage());
      }
@@ -226,7 +224,7 @@
         $value = $normalized_form_data[$field_name] ?? '';
         if (in_array($field_config['type'], ['checkbox', 'set'])) {
            $value = jvbCommaList((is_array($value)) ? $value : explode(',',$value));
            $value = is_array($value) ? implode(',', $value) : $value;
         }
         // Check required fields
@@ -267,9 +265,6 @@
   /**
    * Send email notification
    */
   /**
    * Send email notification
    */
   protected function sendEmailNotification(string $form_type, array $form_config, array $form_data, array $files = []): bool
   {
      $admin_email = apply_filters('jvb_form_email_to', $form_config['email_to'], $form_type, $form_data);
@@ -286,6 +281,17 @@
         $submitter_name = $form_data['name'];
      }
      if (!array_key_exists('preheader', $form_config)) {
         $preheader = $form_config['preheader'];
      } else {
         $preheader = sprintf(
            'New %s submission from %s',
            $form_config['title'],
            $submitter_name ?: ($submitter_name ?: 'website visitor')
         );
      }
      // Email headers
      $headers = [];
@@ -319,23 +325,36 @@
         );
      }
      // Build form data array for table
      // Build form data array for table - using similar logic to JS
      $skip_fields = array_merge(
         ['sendAll', 'action', 'form_id', 'form_type', 'timestamp', '_wpnonce', '_wp_http_referer', 'cf-turnstile-response'],
         $form_config['ignore'] ?? []
      );
      $form = [];
      foreach ($form_config['fields'] as $field_name => $config) {
         // Skip file upload fields
         if ($config['type'] == 'upload') {
         // Skip ignored fields
         if (in_array($field_name, $skip_fields)) {
            continue;
         }
         // Skip upload fields (handled separately)
         if ($config['type'] === 'upload') {
            continue;
         }
         $value = $form_data[$field_name] ?? '';
         // Skip empty fields
         if (empty($value)) {
         if ($this->isEmptyValue($value)) {
            continue;
         }
         // Get label - check for summaryTitle first, then label (similar to JS checking legend then label)
         $label = $config['summaryTitle'] ?? $config['label'] ?? ucfirst(str_replace('_', ' ', $field_name));
         $form[] = [
            'label' => $config['summaryTitle'] ?? $config['label'],
            'label' => $label,
            'value' => $this->formatFieldValueForEmail($field_name, $value, $config)
         ];
      }
@@ -359,17 +378,34 @@
         $subject,
         $body,
         '',
         $preheader,
         $headers,
         $attachments
      );
   }
   /**
    * Check if value is empty (similar to JS isEmptyValue)
    */
   protected function isEmptyValue($value): bool
   {
      if ($value === null || $value === '' || $value === false) {
         return true;
      }
      if (is_array($value) && empty($value)) {
         return true;
      }
      return false;
   }
   /**
    * Format field value for email display
    */
   protected function formatFieldValueForEmail(string $field_name, mixed $value, array $field_config): string
   {
      if (empty($value)) {
      if ($this->isEmptyValue($value)) {
         return '';
      }
@@ -377,9 +413,17 @@
      $type = $field_config['subType'] ?? $type;
      switch ($type) {
         case 'repeater':
            return $this->formatRepeaterForEmail($value, $field_config);
         case 'tag-list':
            return $this->formatTagListForEmail($value);
         case 'location':
            return $this->formatLocationForEmail($value);
         case 'phone':
         case 'tel':
            // Format phone number as xxx-xxx-xxxx
            $cleaned = preg_replace('/\D/', '', $value);
            if (strlen($cleaned) === 10) {
               return substr($cleaned, 0, 3) . '-' . substr($cleaned, 3, 3) . '-' . substr($cleaned, 6);
@@ -388,51 +432,101 @@
         case 'checkbox':
         case 'set':
            // Convert array of values to comma-separated labels
            if (!is_array($value)) {
               $value = explode(',', $value);
            }
            $labels = [];
            foreach ($value as $val) {
            $values = explode(',', $value);
            $labels = array_map(function($val) use ($field_config) {
               $val = trim($val);
               if (isset($field_config['options'][$val])) {
                  $labels[] = $field_config['options'][$val];
               } else {
                  $labels[] = $val; // Fallback to value if no label found
               }
            }
               return $field_config['options'][$val] ?? ucfirst(str_replace('_', ' ', $val));
            }, $values);
            return implode(', ', $labels);
         case 'radio':
         case 'select':
            // Return label instead of value
            if (isset($field_config['options'][$value])) {
               return $field_config['options'][$value];
            }
            return $value;
         case 'textarea':
         case 'wysiwyg':
            // Keep line breaks for email display
            return $value; // nl2br is already applied in the email body
            // Fallback: capitalize the value
            return ucfirst(str_replace('_', ' ', $value));
         case 'true_false':
            $true_text = $field_config['true_text'] ?? 'Yes';
            $false_text = $field_config['false_text'] ?? 'No';
            return ($value === '1' || $value === 1 || $value === true) ? $true_text : $false_text;
         case 'email':
            return $value; // Will be clickable in email client
         case 'url':
            return $value; // Will be clickable in email client
         default:
            return is_array($value) ? implode(', ', $value) : $value;
      }
   }
   /**
    * Format repeater field for email
    */
   protected function formatRepeaterForEmail(array $rows, array $field_config): string
   {
      $output = '';
      foreach ($rows as $index => $row) {
         $output .= '<strong>Entry ' . ($index + 1) . ':</strong><br>';
         foreach ($row as $sub_field => $sub_value) {
            if ($this->isEmptyValue($sub_value)) {
               continue;
            }
            // Get sub-field label if available
            $sub_config = $field_config['sub_fields'][$sub_field] ?? [];
            $label = $sub_config['label'] ?? ucfirst(str_replace('_', ' ', $sub_field));
            $output .= '&nbsp;&nbsp;' . esc_html($label) . ': ' . esc_html($sub_value) . '<br>';
         }
         $output .= '<br>';
      }
      return $output;
   }
   /**
    * Format tag-list field for email
    */
   protected function formatTagListForEmail(array $tags): string
   {
      $items = [];
      foreach ($tags as $tag) {
         // Get first non-empty value as display
         $display = '';
         foreach ($tag as $field => $value) {
            if (!$this->isEmptyValue($value)) {
               $display = $value;
               break;
            }
         }
         if ($display) {
            $items[] = $display;
         }
      }
      return implode(', ', $items);
   }
   /**
    * Format location field for email
    */
   protected function formatLocationForEmail(array $location): string
   {
      $parts = [];
      if (!empty($location['street'])) $parts[] = $location['street'];
      if (!empty($location['city'])) $parts[] = $location['city'];
      if (!empty($location['province'])) $parts[] = $location['province'];
      if (!empty($location['postal_code'])) $parts[] = $location['postal_code'];
      if (!empty($location['country'])) $parts[] = $location['country'];
      return !empty($parts) ? implode(', ', $parts) : ($location['address'] ?? '');
   }
   /**
    * Process uploaded files for email attachments
    * Files are in PHP's tmp directory and will be automatically cleaned up after request
    */