diff --git a/inc/classes/class-admin.php b/inc/classes/class-admin.php
new file mode 100644
index 0000000..3890fae
--- /dev/null
+++ b/inc/classes/class-admin.php
@@ -0,0 +1,348 @@
+hook();}
+ return self::$instance;
+ }
+ public function hook() {
+ add_action('admin_menu', array($this,'register_menu'));
+ add_action('admin_enqueue_scripts', array($this,'enqueue_assets'));
+ add_action('admin_init', array($this,'handle_actions'));
+ add_action('admin_notices', array($this,'admin_notices'));
+ }
+ public function register_menu() {
+ add_menu_page('WP Multi Formular','Formulare','manage_options','wp-multi-formular',
+ array($this,'page_router'),'dashicons-feedback',25);
+ add_submenu_page('wp-multi-formular','Alle Formulare','Alle Formulare','manage_options','wp-multi-formular',array($this,'page_router'));
+ add_submenu_page('wp-multi-formular','Neues Formular','+ Neues Formular','manage_options','wmf-new-form',array($this,'page_builder'));
+ // Neue Einreichungen zaehlen fuer Badge
+ $new_count = 0;
+ $forms = get_posts(array('post_type'=>'wmf-form','post_status'=>'publish','numberposts'=>-1,'fields'=>'ids'));
+ foreach($forms as $fid) $new_count += wmf_count_submissions($fid,'neu');
+ $badge = $new_count > 0 ? ' '.intval($new_count).'' : '';
+ add_submenu_page('wp-multi-formular','Einreichungen','Einreichungen'.$badge,'manage_options','wmf-submissions',array($this,'page_submissions'));
+ }
+ public function page_router() {
+ // Einzelne Einreichung anzeigen
+ if(!empty($_GET['view_submission']) && !empty($_GET['form_id'])) {
+ $sid = intval($_GET['view_submission']);
+ $form_id = intval($_GET['form_id']);
+ require WMF_TPL.'admin/page-submission-detail.php';
+ return;
+ }
+ // Einreichung löschen
+ if(!empty($_GET['wmf_action'])&&$_GET['wmf_action']==='delete_submission'&&!empty($_GET['submission_id'])) {
+ if(wp_verify_nonce($_GET['_wpnonce']??'','wmf_delete_submission')) {
+ WMF_Submission::delete(intval($_GET['submission_id']));
+ $this->safe_redirect(add_query_arg('wmf_notice','deleted',admin_url('admin.php?page=wmf-submissions')));
+ }
+ }
+ // CSV Export
+ if(!empty($_GET['wmf_action'])&&$_GET['wmf_action']==='export_csv'&&!empty($_GET['form_id'])) {
+ WMF_Submissions_List::maybe_export(intval($_GET['form_id']));
+ }
+ // Einreichungen anzeigen
+ if(!empty($_GET['view_submissions'])) {
+ $form_id=intval($_GET['view_submissions']);
+ require WMF_TPL.'admin/page-submissions.php'; return;
+ }
+ // Builder (Bearbeiten)
+ if(!empty($_GET['edit'])) {
+ require WMF_TPL.'admin/page-builder.php'; return;
+ }
+ require WMF_TPL.'admin/page-forms-list.php';
+ }
+ public function page_builder() {
+ require WMF_TPL.'admin/page-builder.php';
+ }
+
+ public function page_submissions() {
+ // Einzelne Einreichung anzeigen
+ if(!empty($_GET['view_submission']) && !empty($_GET['form_id'])) {
+ $sid = intval($_GET['view_submission']);
+ $form_id = intval($_GET['form_id']);
+ $form = get_post($form_id);
+ ?>
+
+
+ Einreichung #
+
+ aus: post_title : ''); ?>
+
+
+
+
+
+
+
+
+
Einreichungen
+ 'wmf-form',
+ 'post_status' => 'publish',
+ 'numberposts' => -1,
+ 'orderby' => 'date',
+ 'order' => 'DESC',
+ ));
+
+ if(empty($forms)): ?>
+
+
+
Noch keine Formulare vorhanden
+
Erstellen Sie zuerst ein Formular und binden Sie es auf einer Seite ein.
+
Formular erstellen
+
+
+
+
+
+ | Formular |
+ Gesamt |
+ Neu |
+ Gelesen |
+ Archiviert |
+ Letzte Einreichung |
+ Aktionen |
+
+
+
+ ID);
+ $count_new = wmf_count_submissions($form->ID, 'neu');
+ $count_read = wmf_count_submissions($form->ID, 'gelesen');
+ $count_arch = wmf_count_submissions($form->ID, 'archiviert');
+ global $wpdb;
+ $last = $wpdb->get_var($wpdb->prepare(
+ "SELECT created_at FROM {$wpdb->prefix}wmf_submissions WHERE form_id=%d ORDER BY created_at DESC LIMIT 1",
+ $form->ID
+ ));
+ $view_url = add_query_arg(array('page'=>'wmf-submissions','form_id'=>$form->ID), admin_url('admin.php'));
+ $export_url = WMF_Submissions_List::export_url($form->ID);
+ ?>
+
+ |
+
+
+ post_title); ?>
+
+
+
+ ID)); ?>
+
+ |
+
+
+
+
+ |
+
+ 0): ?>
+
+
+
+
+ 0
+
+ |
+ |
+ |
+
+
+ |
+
+ Anzeigen
+ 0): ?>
+ CSV
+
+ |
+
+
+
+
+
+
+ window.location.href=' . wp_json_encode($url) . ';';
+ echo '';
+ exit;
+ }
+
+ public function handle_actions() {
+ // Globale Einstellungen speichern (via admin-post.php)
+ add_action('admin_post_wmf_save_global_settings', array($this, 'save_global_settings'));
+ add_action('admin_post_wmf_update_submission_status', array($this, 'update_submission_status'));
+
+ if(empty($_POST['wmf_admin_action'])||!current_user_can('manage_options')) return;
+ if($_POST['wmf_admin_action']==='save_form') {
+ check_admin_referer('wmf_save_form'); $this->save_form();
+ }
+ if($_POST['wmf_admin_action']==='delete_form'&&!empty($_POST['form_id'])) {
+ check_admin_referer('wmf_delete_form_'.intval($_POST['form_id']));
+ wp_delete_post(intval($_POST['form_id']),true);
+ $this->safe_redirect(add_query_arg('wmf_notice','form_deleted',admin_url('admin.php?page=wp-multi-formular')));
+ }
+ }
+ private function save_form() {
+ $form_id=intval($_POST['form_id']??0);
+ $title=sanitize_text_field($_POST['form_title']??'Neues Formular');
+ $fields_raw=stripslashes($_POST['wmf_form_fields']??'[]');
+ $fields=json_decode($fields_raw,true);
+ if(!is_array($fields)) $fields=array();
+
+ // Felder bereinigen
+ $clean_fields=array();
+ foreach($fields as $f) {
+ if(empty($f['id'])||empty($f['type'])) continue;
+ $f['name']=sanitize_key($f['name']??$f['id']);
+ $f['label']=sanitize_text_field($f['label']??'');
+ $f['placeholder']=sanitize_text_field($f['placeholder']??'');
+ $f['description']=sanitize_text_field($f['description']??'');
+ $f['required']=in_array($f['required']??'0',array('0','1'))?$f['required']:'0';
+ $f['width']=in_array($f['width']??'full',array('full','half','third'))?$f['width']:'full';
+ $clean_fields[]=$f;
+ }
+
+ $step_labels=array();
+ if(!empty($_POST['step_labels'])&&is_array($_POST['step_labels'])) {
+ $step_labels=array_map('sanitize_text_field',$_POST['step_labels']);
+ }
+
+ $data=array(
+ 'fields' => $clean_fields,
+ 'submit_label' => sanitize_text_field($_POST['submit_label']??'Absenden'),
+ 'success_message' => sanitize_textarea_field($_POST['success_message']??''),
+ 'error_message' => sanitize_textarea_field($_POST['error_message']??''),
+ 'notify_admin' => !empty($_POST['notify_admin'])?'1':'0',
+ 'admin_email' => sanitize_email($_POST['admin_email']??''),
+ 'admin_subject' => sanitize_text_field($_POST['admin_subject']??''),
+ 'admin_reply_to' => !empty($_POST['admin_reply_to'])?'1':'0',
+ 'notify_sender' => !empty($_POST['notify_sender'])?'1':'0',
+ 'sender_subject' => sanitize_text_field($_POST['sender_subject']??''),
+ 'sender_message' => sanitize_textarea_field($_POST['sender_message']??''),
+ 'from_name' => sanitize_text_field($_POST['from_name']??''),
+ 'from_email' => sanitize_email($_POST['from_email']??''),
+ 'save_submissions' => !empty($_POST['save_submissions'])?'1':'0',
+ 'recaptcha_enabled' => !empty($_POST['recaptcha_enabled'])?'1':'0',
+ 'honeypot_enabled' => !empty($_POST['honeypot_enabled'])?'1':'0',
+ 'redirect_url' => esc_url_raw($_POST['redirect_url']??''),
+ 'css_class' => sanitize_html_class($_POST['css_class']??''),
+ 'multi_step' => !empty($_POST['multi_step'])?'1':'0',
+ 'step_labels' => $step_labels,
+ 'show_progress' => !empty($_POST['show_progress'])?'1':'0',
+ );
+
+ if($form_id) {
+ wp_update_post(array('ID'=>$form_id,'post_title'=>$title,'post_status'=>'publish'));
+ } else {
+ $form_id=wp_insert_post(array('post_type'=>'wmf-form','post_title'=>$title,'post_status'=>'publish'));
+ }
+ wmf_save_form_meta($form_id,$data);
+ $this->safe_redirect(add_query_arg(array('page'=>'wp-multi-formular','edit'=>$form_id,'wmf_notice'=>'saved'),admin_url('admin.php')));
+ }
+ public function admin_notices() {
+ $n=$_GET['wmf_notice']??'';
+ $msgs=array('saved'=>array('success','Formular gespeichert.'),'deleted'=>array('success','Einreichung gelöscht.'),'form_deleted'=>array('success','Formular gelöscht.'),'global_saved'=>array('success','Globale E-Mail-Einstellungen gespeichert.'));
+ if(isset($msgs[$n])) printf('',esc_attr($msgs[$n][0]),esc_html($msgs[$n][1]));
+ }
+ public function enqueue_assets($hook) {
+ $page=$_GET['page']??'';
+ if(!in_array($page,array('wp-multi-formular','wmf-new-form','wmf-integrations'))&&strpos($hook,'wmf')=== false) return;
+ wp_enqueue_style('wmf-admin',WMF_URL.'assets/css/admin.css',array(),WMF_VERSION);
+ wp_enqueue_script('wmf-admin',WMF_URL.'assets/js/admin.js',array('jquery','jquery-ui-sortable','jquery-ui-draggable'),WMF_VERSION,true);
+ wp_enqueue_style('dashicons');
+ wp_localize_script('wmf-admin','WMF',array(
+ 'ajax_url' => admin_url('admin-ajax.php'),
+ 'nonce' => wp_create_nonce('wmf_admin'),
+ 'fields' => $this->fields_for_js(),
+ 'i18n' => array(
+ 'confirm_delete' => 'Feld wirklich löschen?',
+ 'confirm_delete_form' => 'Formular und alle Einreichungen wirklich löschen?',
+ 'no_label' => '(kein Titel)',
+ 'loading' => 'Lade …',
+ 'preview' => 'Vorschau',
+ 'close_preview' => 'Vorschau schließen',
+ ),
+ ));
+ }
+ public function update_submission_status() {
+ if(!wp_verify_nonce($_POST['_wpnonce'] ?? '', 'wmf_update_status') || !current_user_can('manage_options')) wp_die('Fehler.');
+ $sid = intval($_POST['submission_id'] ?? 0);
+ $status = sanitize_text_field($_POST['status'] ?? 'neu');
+ $form_id = intval($_POST['form_id'] ?? 0);
+ $redirect = esc_url_raw($_POST['redirect_url'] ?? admin_url('admin.php?page=wp-multi-formular'));
+ if($sid && in_array($status, array('neu','gelesen','archiviert'))) {
+ WMF_Submission::update_status($sid, $status);
+ }
+ $this->safe_redirect($redirect);
+ }
+
+ public function save_global_settings() {
+ if(!wp_verify_nonce($_POST['wmf_global_nonce'] ?? '', 'wmf_global_settings_save')) {
+ wp_die('Sicherheitsfehler.');
+ }
+ if(!current_user_can('manage_options')) wp_die('Keine Berechtigung.');
+
+ $settings = array(
+ 'from_name' => sanitize_text_field($_POST['wmf_from_name'] ?? ''),
+ 'from_email' => sanitize_email( $_POST['wmf_from_email'] ?? ''),
+ 'smtp_enabled' => !empty($_POST['wmf_smtp_enabled']) ? '1' : '0',
+ 'smtp_host' => sanitize_text_field($_POST['wmf_smtp_host'] ?? ''),
+ 'smtp_port' => intval( $_POST['wmf_smtp_port'] ?? 587),
+ 'smtp_enc' => sanitize_text_field($_POST['wmf_smtp_enc'] ?? 'tls'),
+ 'smtp_user' => sanitize_text_field($_POST['wmf_smtp_user'] ?? ''),
+ 'smtp_pass' => $_POST['wmf_smtp_pass'] ?? '', // Passwort nicht strippen
+ );
+
+ update_option('wmf_global_settings', $settings);
+
+ $this->safe_redirect(add_query_arg(array('page'=>'wmf-integrations','wmf_notice'=>'global_saved'), admin_url('admin.php')));
+ }
+
+ private function fields_for_js() {
+ $r=array();
+ foreach(wmf_get_fields() as $type=>$f) {
+ $r[]=array('type'=>$type,'label'=>$f->label,'icon'=>$f->icon,'category'=>$f->category,'defaults'=>$f->defaults());
+ }
+ return $r;
+ }
+}
diff --git a/inc/classes/class-builder.php b/inc/classes/class-builder.php
new file mode 100644
index 0000000..ad1db91
--- /dev/null
+++ b/inc/classes/class-builder.php
@@ -0,0 +1,44 @@
+hook();}
+ return self::$instance;
+ }
+ public function hook() {
+ add_action('wp_ajax_wmf_get_field_settings',array($this,'ajax_field_settings'));
+ add_action('wp_ajax_wmf_preview_form', array($this,'ajax_preview'));
+ }
+ public function ajax_field_settings() {
+ check_ajax_referer('wmf_admin','nonce');
+ if(!current_user_can('manage_options')) wp_die();
+ $type=sanitize_text_field($_POST['field_type']??'');
+ $field=json_decode(stripslashes($_POST['field_data']??'{}'),true);
+ $obj=wmf_get_field($type);
+ if(!$obj) wp_send_json_error('Unbekannter Feldtyp: '.$type);
+ ob_start(); $obj->settings_panel($field); $html=ob_get_clean();
+ wp_send_json_success(array('html'=>$html));
+ }
+ public function ajax_preview() {
+ check_ajax_referer('wmf_admin','nonce');
+ if(!current_user_can('manage_options')) wp_die();
+ $form_id=intval($_POST['form_id']??0);
+ $fields=json_decode(stripslashes($_POST['fields']??'[]'),true);
+ $meta=wmf_get_form_meta($form_id);
+ $meta['fields']=$fields;
+ ob_start();
+ echo '';
+ foreach($fields as $field) {
+ $obj=wmf_get_field($field['type']??'');
+ if(!$obj) continue;
+ echo '
';
+ $obj->render($field,'');
+ echo '
';
+ }
+ echo '
';
+ echo '
';
+ $html=ob_get_clean();
+ wp_send_json_success(array('html'=>$html));
+ }
+}
diff --git a/inc/classes/class-field-registry.php b/inc/classes/class-field-registry.php
new file mode 100644
index 0000000..9d7e367
--- /dev/null
+++ b/inc/classes/class-field-registry.php
@@ -0,0 +1,21 @@
+register_defaults();}
+ return self::$instance;
+ }
+ private function register_defaults() {
+ foreach(array('WMF_Field_Text','WMF_Field_Email','WMF_Field_Textarea','WMF_Field_Select',
+ 'WMF_Field_Checkbox','WMF_Field_Radio','WMF_Field_Number','WMF_Field_Phone',
+ 'WMF_Field_URL','WMF_Field_Date','WMF_Field_File','WMF_Field_Rating',
+ 'WMF_Field_Range','WMF_Field_GDPR','WMF_Field_Signature',
+ 'WMF_Field_Hidden','WMF_Field_HTML','WMF_Field_Divider') as $cls) {
+ $f=new $cls(); $this->fields[$f->type]=$f;
+ }
+ }
+ public function get_fields() { return $this->fields; }
+ public function get_field($type) { return $this->fields[$type]??null; }
+}
diff --git a/inc/classes/class-form-processor.php b/inc/classes/class-form-processor.php
new file mode 100644
index 0000000..2632b71
--- /dev/null
+++ b/inc/classes/class-form-processor.php
@@ -0,0 +1,105 @@
+hook();}
+ return self::$instance;
+ }
+ public function hook() {
+ add_action('init',array($this,'maybe_process'),20);
+ }
+ public function maybe_process() {
+ if(empty($_POST['wmf_action'])||$_POST['wmf_action']!=='submit') return;
+ if(empty($_POST['wmf_form_id'])) return;
+ if(!session_id()) session_start();
+
+ $form_id=intval($_POST['wmf_form_id']);
+ if(!wp_verify_nonce($_POST['wmf_nonce']??'','wmf_submit_'.$form_id)) {
+ $this->fail($form_id,'Sicherheitsüberprüfung fehlgeschlagen.'); return;
+ }
+ $form=get_post($form_id);
+ if(!$form||$form->post_type!=='wmf-form') return;
+
+ $meta = wmf_get_form_meta($form_id);
+ $fields = $meta['fields']??array();
+
+ // Honeypot prüfen
+ if(!empty($meta['honeypot_enabled'])&&$meta['honeypot_enabled']==='1') {
+ if(!empty($_POST['wmf_hp_'.md5($form_id)])) { $this->ok($form_id,$meta); return; } // stille Ablehnung
+ }
+
+ // Werte sammeln + validieren
+ $values=array(); $errors=array();
+ foreach($fields as $field) {
+ $type=$field['type']??'';
+ $obj=wmf_get_field($type);
+ if(!$obj) continue;
+ if(in_array($type,array('html','divider'))) continue;
+
+ $raw=$_POST['wmf_fields'][$field['id']]??'';
+ $val=$obj->sanitize($raw,$field);
+ $valid=$obj->validate($val,$field);
+ $values[$field['id']]=$val;
+ if($valid!==true) $errors[$field['id']]=$valid;
+ }
+
+ // Datei-Uploads
+ $file_values=array();
+ if(!empty($_FILES['wmf_files'])) {
+ foreach($fields as $field) {
+ if(($field['type']??'')!=='file') continue;
+ $uploaded=WMF_Field_File::handle_upload($field,$form_id);
+ if(!empty($uploaded)) $file_values[$field['id']]=$uploaded;
+ // Validierung nochmal mit Upload-Ergebnis
+ $valid=wmf_get_field('file')->validate('',$field);
+ if($valid!==true&&!isset($errors[$field['id']])) $errors[$field['id']]=$valid;
+ }
+ }
+
+ if(!empty($errors)) {
+ $_SESSION['wmf_values_'.$form_id]=$values;
+ $_SESSION['wmf_errors_'.$form_id]=$errors;
+ wp_redirect($this->current_url()); exit;
+ }
+
+ // Datei-URLs in Werte mergen
+ foreach($file_values as $fid=>$uploads) {
+ $urls=array_map(fn($u)=>$u['url'],$uploads);
+ $values[$fid]=implode(', ',$urls);
+ }
+
+ // Speichern
+ $submission_id=null;
+ if(!empty($meta['save_submissions'])&&$meta['save_submissions']==='1') {
+ $submission_id=WMF_Submission::save($form_id,$values);
+ }
+
+ // E-Mails
+ if(!empty($meta['notify_admin'])&&$meta['notify_admin']==='1') {
+ WMF_Mailer::notify_admin($form_id,$meta,$fields,$values,$file_values);
+ }
+ if(!empty($meta['notify_sender'])&&$meta['notify_sender']==='1') {
+ WMF_Mailer::notify_sender($form_id,$meta,$fields,$values);
+ }
+
+ do_action('wmf_form_submitted',$form_id,$meta,$fields,$values,$submission_id);
+ $this->ok($form_id,$meta);
+ }
+
+ private function ok($form_id,$meta) {
+ if(!empty($meta['redirect_url'])) { wp_redirect(esc_url_raw($meta['redirect_url'])); exit; }
+ if(!session_id()) session_start();
+ $_SESSION['wmf_success_'.$form_id]=true;
+ wp_redirect($this->current_url()); exit;
+ }
+ private function fail($form_id,$msg) {
+ if(!session_id()) session_start();
+ $_SESSION['wmf_errors_'.$form_id]=array('_global'=>$msg);
+ wp_redirect($this->current_url()); exit;
+ }
+ private function current_url() {
+ return (is_ssl()?'https':'http').'://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
+ }
+}
diff --git a/inc/classes/class-form-renderer.php b/inc/classes/class-form-renderer.php
new file mode 100644
index 0000000..39d91e9
--- /dev/null
+++ b/inc/classes/class-form-renderer.php
@@ -0,0 +1,145 @@
+post_type!=='wmf-form'||$form->post_status!=='publish')
+ return 'Formular nicht gefunden.
';
+
+ if(!session_id()) session_start();
+
+ $meta = wmf_get_form_meta($form_id);
+ $fields = $meta['fields']??array();
+ $saved_values = $_SESSION['wmf_values_'.$form_id]??array();
+ $errors = $_SESSION['wmf_errors_'.$form_id]??array();
+ $success = $_SESSION['wmf_success_'.$form_id]??false;
+
+ unset($_SESSION['wmf_values_'.$form_id],$_SESSION['wmf_errors_'.$form_id],$_SESSION['wmf_success_'.$form_id]);
+
+ ob_start();
+
+ if($success) {
+ echo ''.esc_html($meta['success_message']).'
';
+ if(empty($args['always_show'])) return ob_get_clean();
+ }
+ if(!empty($errors['_global']))
+ echo ''.esc_html($errors['_global']).'
';
+
+ $multi_step=!empty($meta['multi_step'])&&$meta['multi_step']==='1';
+ // Schritte ermitteln
+ $steps=array();
+ foreach($fields as $f) { $s=intval($f['step']??0); if(!isset($steps[$s])) $steps[$s]=array(); $steps[$s][]=$f; }
+ ksort($steps);
+ $total_steps=count($steps);
+ if($total_steps<2) $multi_step=false;
+
+ $form_cls='wmf-form'.(!empty($meta['css_class'])?' '.esc_attr($meta['css_class']):'');
+ $field_json=wp_json_encode($fields);
+ ?>
+
+ ';
+ $obj->render($field,$value);
+ if($err) echo ''.esc_html($err).'
';
+ echo '';
+ }
+ }
+
+ private static function render_submit($meta,$form_id) {
+ // reCAPTCHA
+ $integrations=wmf_get_integrations();
+ if(!empty($meta['recaptcha_enabled'])&&$meta['recaptcha_enabled']==='1') {
+ $rv3=$integrations->get_service('recaptchav3');
+ $rv2=$integrations->get_service('recaptcha');
+ if($rv3&&$rv3->is_connected()) {
+ $creds=$rv3->get_credentials();
+ echo '';
+ echo '';
+ } elseif($rv2&&$rv2->is_connected()) {
+ $creds=$rv2->get_credentials();
+ echo '';
+ echo '';
+ }
+ }
+ ?>
+
+
+
+
+ ',
+ );
+
+ // Reply-To auf Absender-E-Mail-Feld setzen
+ if(!empty($meta['admin_reply_to']) && $meta['admin_reply_to'] === '1') {
+ foreach($fields as $f) {
+ if(($f['type'] ?? '') === 'email' && !empty($values[$f['id']]) && is_email($values[$f['id']])) {
+ $headers[] = 'Reply-To: ' . $values[$f['id']];
+ break;
+ }
+ }
+ }
+
+ wp_mail($to, $subject, self::build_body($fields, $values, $file_values), $headers);
+ }
+
+ /**
+ * Absender-Bestaetigung
+ */
+ public static function notify_sender($form_id, $meta, $fields, $values) {
+ $global = get_option('wmf_global_settings', array());
+ $from_name = !empty($meta['from_name']) ? $meta['from_name'] : ($global['from_name'] ?? get_bloginfo('name'));
+ $from_email = !empty($meta['from_email']) ? $meta['from_email'] : ($global['from_email'] ?? get_option('admin_email'));
+
+ $email = '';
+ foreach($fields as $f) {
+ if(($f['type'] ?? '') === 'email' && !empty($values[$f['id']]) && is_email($values[$f['id']])) {
+ $email = $values[$f['id']];
+ break;
+ }
+ }
+ if(!$email) return;
+
+ $headers = array(
+ 'Content-Type: text/html; charset=UTF-8',
+ 'From: ' . $from_name . ' <' . $from_email . '>',
+ );
+
+ $body = ''
+ . wpautop(esc_html($meta['sender_message'] ?? ''))
+ . 'Gesendet ueber ' . get_bloginfo('name') . '
'
+ . '';
+
+ wp_mail($email, $meta['sender_subject'] ?? 'Ihre Nachricht wurde empfangen', $body, $headers);
+ }
+
+ /**
+ * E-Mail-Body aufbauen
+ */
+ private static function build_body($fields, $values, $file_values) {
+ $rows = '';
+ foreach($fields as $f) {
+ if(in_array($f['type'] ?? '', array('html','divider','hidden'))) continue;
+ $lbl = $f['label'] ?? $f['id'];
+ $val = $values[$f['id']] ?? '';
+ if(is_array($val)) $val = implode(', ', $val);
+ if(($f['type'] ?? '') === 'gdpr')
+ $val = ($val === '1') ? '✓ Zugestimmt' : '✗ Nicht zugestimmt';
+ if(($f['type'] ?? '') === 'signature' && !empty($val))
+ $val = '
';
+ if(isset($file_values[$f['id']])) {
+ $links = array_map(
+ fn($u) => '' . esc_html($u['name']) . '',
+ $file_values[$f['id']]
+ );
+ $val = implode('
', $links);
+ }
+ $rows .= ''
+ . '| ' . esc_html($lbl) . ' | '
+ . '' . $val . ' | '
+ . '
';
+ }
+
+ return ''
+ . ''
+ . '
Neue Formulareinreichung
'
+ . '
' . get_bloginfo('name') . ' · ' . current_time('d.m.Y H:i') . '
'
+ . '
'
+ . ''
+ . 'Diese E-Mail wurde automatisch gesendet von WP Multi Formular
'
+ . '';
+ }
+}
diff --git a/inc/classes/class-post-type.php b/inc/classes/class-post-type.php
new file mode 100644
index 0000000..e6989af
--- /dev/null
+++ b/inc/classes/class-post-type.php
@@ -0,0 +1,43 @@
+hook(); }
+ return self::$instance;
+ }
+ public function hook() {
+ add_action( 'init', array( $this, 'register' ) );
+ add_action( 'admin_init', array( $this, 'redirect_cpt' ) );
+ }
+ public static function register() {
+ register_post_type( 'wmf-form', array(
+ 'labels' => array(
+ 'name' => 'Formulare',
+ 'singular_name' => 'Formular',
+ 'not_found' => 'Keine Formulare gefunden.',
+ ),
+ 'public' => false,
+ 'show_ui' => true,
+ 'show_in_menu' => false,
+ 'supports' => array( 'title' ),
+ 'capability_type' => 'post',
+ 'has_archive' => false,
+ 'rewrite' => false,
+ ) );
+ }
+ public function redirect_cpt() {
+ if ( ! is_admin() ) return;
+ $pt = $_GET['post_type'] ?? '';
+ if ( $pt === 'wmf-form' && basename( $_SERVER['PHP_SELF'] ) === 'edit.php' ) {
+ wp_redirect( admin_url( 'admin.php?page=wp-multi-formular' ) ); exit;
+ }
+ if ( isset( $_GET['post'], $_GET['action'] ) && $_GET['action'] === 'edit' ) {
+ $p = get_post( intval( $_GET['post'] ) );
+ if ( $p && $p->post_type === 'wmf-form' ) {
+ wp_redirect( admin_url( 'admin.php?page=wp-multi-formular&edit=' . $p->ID ) ); exit;
+ }
+ }
+ }
+}
diff --git a/inc/classes/class-shortcode.php b/inc/classes/class-shortcode.php
new file mode 100644
index 0000000..a3c9224
--- /dev/null
+++ b/inc/classes/class-shortcode.php
@@ -0,0 +1,36 @@
+hook();}
+ return self::$instance;
+ }
+ public function hook() {
+ add_shortcode('wp_multi_formular',array($this,'render'));
+ add_action('wp_enqueue_scripts',array($this,'enqueue_assets'));
+ add_action('init',array($this,'start_session'),1);
+ }
+ public function start_session() { if(!session_id()&&!headers_sent()) session_start(); }
+ public function render($atts) {
+ $atts=shortcode_atts(array('id'=>0),$atts,'wp_multi_formular');
+ $id=intval($atts['id']);
+ if(!$id) return 'Bitte geben Sie eine Formular-ID an.
';
+ return WMF_Form_Renderer::render($id);
+ }
+ public function enqueue_assets() {
+ wp_enqueue_style('wp-multi-formular',WMF_URL.'assets/css/frontend.css',array(),WMF_VERSION);
+ wp_enqueue_script('wp-multi-formular',WMF_URL.'assets/js/frontend.js',array('jquery'),WMF_VERSION,true);
+ wp_localize_script('wp-multi-formular','WMF_Frontend',array(
+ 'ajax_url'=>admin_url('admin-ajax.php'),
+ 'i18n'=>array(
+ 'required' =>'Dieses Feld ist ein Pflichtfeld.',
+ 'email' =>'Bitte geben Sie eine gültige E-Mail-Adresse ein.',
+ 'url' =>'Bitte geben Sie eine gültige URL ein.',
+ 'step_of' =>'Schritt %1 von %2',
+ 'next' =>'Weiter',
+ 'prev' =>'Zurück',
+ ),
+ ));
+ }
+}
diff --git a/inc/classes/class-smtp.php b/inc/classes/class-smtp.php
new file mode 100644
index 0000000..6556877
--- /dev/null
+++ b/inc/classes/class-smtp.php
@@ -0,0 +1,54 @@
+hook();
+ }
+ return self::$instance;
+ }
+
+ public function hook() {
+ $opts = get_option('wmf_global_settings', array());
+ if(!empty($opts['smtp_enabled']) && $opts['smtp_enabled'] === '1' && !empty($opts['smtp_host'])) {
+ add_action('phpmailer_init', array($this, 'configure_smtp'));
+ }
+ }
+
+ public function configure_smtp($phpmailer) {
+ $opts = get_option('wmf_global_settings', array());
+ if(empty($opts['smtp_host'])) return;
+
+ $phpmailer->isSMTP();
+ $phpmailer->Host = $opts['smtp_host'];
+ $phpmailer->Port = intval($opts['smtp_port'] ?? 587);
+ $phpmailer->SMTPSecure = $opts['smtp_enc'] ?? 'tls';
+
+ if(!empty($opts['smtp_user'])) {
+ $phpmailer->SMTPAuth = true;
+ $phpmailer->Username = $opts['smtp_user'];
+ $phpmailer->Password = $opts['smtp_pass'] ?? '';
+ } else {
+ $phpmailer->SMTPAuth = false;
+ }
+
+ // From-Adresse global setzen falls nicht per Mail-Header gesetzt
+ if(!empty($opts['from_email'])) {
+ $phpmailer->From = $opts['from_email'];
+ $phpmailer->FromName = $opts['from_name'] ?? get_bloginfo('name');
+ }
+
+ $phpmailer->SMTPOptions = array(
+ 'ssl' => array(
+ 'verify_peer' => false,
+ 'verify_peer_name' => false,
+ 'allow_self_signed' => true,
+ )
+ );
+ }
+}
diff --git a/inc/classes/class-submission.php b/inc/classes/class-submission.php
new file mode 100644
index 0000000..d2a9f8c
--- /dev/null
+++ b/inc/classes/class-submission.php
@@ -0,0 +1,18 @@
+insert($wpdb->prefix.'wmf_submissions',array(
+ 'form_id'=>$form_id,'data'=>wp_json_encode($values),
+ 'ip'=>wmf_get_client_ip(),'user_agent'=>$_SERVER['HTTP_USER_AGENT']??'',
+ 'status'=>'neu','created_at'=>current_time('mysql'),
+ ),array('%d','%s','%s','%s','%s','%s'));
+ return $wpdb->insert_id;
+ }
+ public static function delete($id) { global $wpdb; $wpdb->delete($wpdb->prefix.'wmf_submissions',array('id'=>$id),array('%d')); }
+ public static function update_status($id,$status) {
+ global $wpdb;
+ $wpdb->update($wpdb->prefix.'wmf_submissions',array('status'=>sanitize_text_field($status)),array('id'=>$id),array('%s'),array('%d'));
+ }
+}
diff --git a/inc/classes/class-submissions-list.php b/inc/classes/class-submissions-list.php
new file mode 100644
index 0000000..ab63f46
--- /dev/null
+++ b/inc/classes/class-submissions-list.php
@@ -0,0 +1,481 @@
+ $per_page,
+ 'offset' => $offset,
+ 'status' => $status_filter,
+ 'search' => $search,
+ ));
+ $total = wmf_count_submissions($form_id, $status_filter, $search);
+ $total_pages = ceil($total / $per_page);
+
+ $base_url = add_query_arg(array(
+ 'page' => 'wp-multi-formular',
+ 'view_submissions' => $form_id,
+ ), admin_url('admin.php'));
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Keine Einreichungen gefunden.
+
Filter zurücksetzen
+
+
Noch keine Einreichungen vorhanden.
+
+
+
+
+
+
+
+
+ 1): ?>
+
+
+
+
+
+ get_row($wpdb->prepare(
+ "SELECT * FROM {$wpdb->prefix}wmf_submissions WHERE id = %d AND form_id = %d",
+ $submission_id, $form_id
+ ));
+
+ if(!$row) {
+ echo 'Einreichung nicht gefunden.
';
+ return;
+ }
+
+ // Als gelesen markieren
+ if($row->status === 'neu') {
+ WMF_Submission::update_status($submission_id, 'gelesen');
+ $row->status = 'gelesen';
+ }
+
+ $data = json_decode($row->data, true) ?? array();
+ $meta = wmf_get_form_meta($form_id);
+ $fields = self::get_display_fields($meta);
+ $form = get_post($form_id);
+
+ $back_url = add_query_arg(array(
+ 'page' => 'wp-multi-formular',
+ 'view_submissions' => $form_id,
+ ), admin_url('admin.php'));
+
+ $prev_url = self::get_adjacent_url($submission_id, $form_id, 'prev');
+ $next_url = self::get_adjacent_url($submission_id, $form_id, 'next');
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Technische Informationen
+
+ | User-Agent | user_agent ?: '—'); ?> |
+ | Erstellt am | created_at); ?> |
+ | Datenbank-ID | id); ?> |
+
+
+
+
+
+
+ —';
+ return;
+ }
+
+ switch($type) {
+ case 'checkbox':
+ $vals = is_array($val) ? $val : explode(', ', $val);
+ echo '';
+ foreach($vals as $v) echo '- ' . esc_html($v) . '
';
+ echo '
';
+ break;
+
+ case 'gdpr':
+ $icon = $val === '1' ? '✅' : '❌';
+ echo $icon . ' ' . ($val === '1' ? 'Zugestimmt' : 'Nicht zugestimmt');
+ break;
+
+ case 'signature':
+ if(strpos($val, 'data:image') === 0) {
+ echo '
';
+ } else {
+ echo 'Keine Unterschrift';
+ }
+ break;
+
+ case 'file':
+ $urls = is_array($val) ? $val : explode(', ', $val);
+ echo '';
+ foreach($urls as $url) {
+ $url = trim($url);
+ if(!$url) continue;
+ $filename = basename(parse_url($url, PHP_URL_PATH));
+ $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+ $is_image = in_array($ext, array('jpg','jpeg','png','gif','webp'));
+ if($is_image) {
+ echo '
';
+ } else {
+ echo '
📎 ' . esc_html($filename) . '';
+ }
+ }
+ echo '
';
+ break;
+
+ case 'rating':
+ $stars = intval($val);
+ $max = intval($field['max_stars'] ?? 5);
+ echo '';
+ for($i = 1; $i <= $max; $i++) {
+ echo '★';
+ }
+ echo ' ' . $stars . '/' . $max . '
';
+ break;
+
+ case 'url':
+ echo '' . esc_html($val) . '';
+ break;
+
+ case 'email':
+ echo '' . esc_html($val) . '';
+ break;
+
+ case 'textarea':
+ echo '' . nl2br(esc_html($val)) . '
';
+ break;
+
+ default:
+ if(is_array($val)) {
+ echo '';
+ foreach($val as $v) echo '- ' . esc_html($v) . '
';
+ echo '
';
+ } else {
+ echo '' . esc_html($val) . '';
+ }
+ }
+ }
+
+ /* ================================================================
+ HILFSFUNKTIONEN
+ ================================================================ */
+ private static function get_display_fields($meta) {
+ return array_values(array_filter($meta['fields'] ?? array(), function($f) {
+ return !in_array($f['type'] ?? '', array('html','divider','hidden'));
+ }));
+ }
+
+ private static function get_adjacent_url($submission_id, $form_id, $direction) {
+ global $wpdb;
+ $op = $direction === 'prev' ? '>' : '<';
+ $order = $direction === 'prev' ? 'ASC' : 'DESC';
+ $adj = $wpdb->get_var($wpdb->prepare(
+ "SELECT id FROM {$wpdb->prefix}wmf_submissions WHERE form_id = %d AND id {$op} %d ORDER BY id {$order} LIMIT 1",
+ $form_id, $submission_id
+ ));
+ if(!$adj) return null;
+ return add_query_arg(array('page'=>'wp-multi-formular','view_submission'=>$adj,'form_id'=>$form_id), admin_url('admin.php'));
+ }
+
+ public static function status_label($s) {
+ return array('neu'=>'Neu','gelesen'=>'Gelesen','archiviert'=>'Archiviert')[$s] ?? $s;
+ }
+
+ public static function export_url($form_id) {
+ return wp_nonce_url(add_query_arg(array('wmf_action'=>'export_csv','form_id'=>$form_id,'page'=>'wp-multi-formular'), admin_url('admin.php')), 'wmf_export_csv');
+ }
+
+ public static function maybe_export($form_id) {
+ if(empty($_GET['wmf_action']) || $_GET['wmf_action'] !== 'export_csv') return;
+ if(!wp_verify_nonce($_GET['_wpnonce'] ?? '', 'wmf_export_csv')) return;
+ $meta = wmf_get_form_meta($form_id);
+ $fields = self::get_display_fields($meta);
+ $rows = wmf_get_submissions($form_id, array('limit'=>9999));
+ header('Content-Type: text/csv; charset=utf-8');
+ header('Content-Disposition: attachment; filename="formular-' . $form_id . '-einreichungen.csv"');
+ $out = fopen('php://output', 'w');
+ fprintf($out, chr(0xEF).chr(0xBB).chr(0xBF));
+ $header = array('ID','Datum','Status','IP');
+ foreach($fields as $f) $header[] = $f['label'];
+ fputcsv($out, $header, ';');
+ foreach($rows as $row) {
+ $data = json_decode($row->data, true) ?? array();
+ $line = array($row->id, date_i18n('d.m.Y H:i', strtotime($row->created_at)), self::status_label($row->status), $row->ip);
+ foreach($fields as $f) {
+ $v = $data[$f['id']] ?? '';
+ if(is_array($v)) $v = implode(', ', $v);
+ if(($f['type']??'') === 'signature') $v = '(Unterschrift)';
+ $line[] = $v;
+ }
+ fputcsv($out, $line, ';');
+ }
+ fclose($out);
+ exit;
+ }
+}
diff --git a/inc/fields/class-field-base.php b/inc/fields/class-field-base.php
new file mode 100644
index 0000000..d22eda6
--- /dev/null
+++ b/inc/fields/class-field-base.php
@@ -0,0 +1,158 @@
+ '',
+ 'type' => $this->type,
+ 'label' => $this->label,
+ 'name' => '',
+ 'placeholder' => '',
+ 'description' => '',
+ 'required' => '0',
+ 'css_class' => '',
+ 'width' => 'full',
+ // Bedingte Logik
+ 'conditional_logic' => '0',
+ 'conditional_action' => 'show', // show|hide
+ 'conditional_rules' => array(), // [{field,operator,value}]
+ 'conditional_match' => 'all', // all|any
+ // Schritt (mehrstufige Formulare)
+ 'step' => 0,
+ );
+ }
+
+ abstract public function render( $field, $value = '' );
+
+ public function validate( $value, $field ) {
+ if ( ! empty( $field['required'] ) && $field['required'] === '1' ) {
+ $empty = ( $value === '' || $value === null || $value === array() );
+ if ( $empty ) return sprintf( 'Das Feld „%s" ist ein Pflichtfeld.', $field['label'] );
+ }
+ return true;
+ }
+
+ public function sanitize( $value, $field ) {
+ return sanitize_text_field( (string) $value );
+ }
+
+ /* Einstellungs-Panel im Builder */
+ public function settings_panel( $field ) {
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ '','operator'=>'=','value'=>''));
+ foreach($rules as $rule): ?>
+
+
+
+
+
+
+
+
+
+
+ type );
+ $w = $field['width'] ?? 'full';
+ if ( $w !== 'full' ) $cls[] = 'wmf-field-width-' . $w;
+ if ( ! empty($field['css_class']) ) $cls[] = $field['css_class'];
+ if ( !empty($field['required']) && $field['required']==='1' ) $cls[] = 'wmf-required';
+ if ( !empty($field['conditional_logic']) && $field['conditional_logic']==='1' ) $cls[] = 'wmf-has-condition';
+ return implode(' ', $cls);
+ }
+
+ protected function render_label( $field ) {
+ if ( empty($field['label']) ) return;
+ $req = (!empty($field['required']) && $field['required']==='1') ? ' *' : '';
+ printf( '', esc_attr($field['id']), esc_html($field['label']), $req );
+ }
+
+ protected function render_description( $field ) {
+ if ( empty($field['description']) ) return;
+ printf( '%s
', esc_html($field['description']) );
+ }
+
+ protected function conditional_attrs( $field ) {
+ if ( empty($field['conditional_logic']) || $field['conditional_logic'] !== '1' ) return '';
+ return sprintf(
+ ' data-condition="%s" data-condition-action="%s" data-condition-match="%s" data-condition-rules="%s"',
+ '1',
+ esc_attr($field['conditional_action'] ?? 'show'),
+ esc_attr($field['conditional_match'] ?? 'all'),
+ esc_attr(wp_json_encode($field['conditional_rules'] ?? array()))
+ );
+ }
+}
diff --git a/inc/fields/class-field-checkbox.php b/inc/fields/class-field-checkbox.php
new file mode 100644
index 0000000..4a6dea5
--- /dev/null
+++ b/inc/fields/class-field-checkbox.php
@@ -0,0 +1,23 @@
+array(array('label'=>'Option 1','value'=>'option_1')),'layout'=>'vertical')); }
+ public function render($field,$value='') {
+ $checked=is_array($value)?$value:($value?array($value):array()); ?>
+ conditional_attrs($field); ?> data-field-id="">
+ render_label($field); ?>
+
+
+
+
+
+ render_description($field); ?>
+
+
'','max_date'=>'')); }
+ public function render($field,$value='') { ?>
+ conditional_attrs($field); ?> data-field-id="">
+ render_label($field); ?>
+ class="wmf-input">
+ render_description($field); ?>
+
+
+ conditional_attrs($field); ?>>
+
+ render_description($field); ?>
+
+ conditional_attrs($field); ?> data-field-id="">
+ render_label($field); ?>
+ class="wmf-input" autocomplete="email">
+ render_description($field); ?>
+
+
'jpg,jpeg,png,pdf,doc,docx','max_size_mb'=>'5','multiple'=>'0','save_to_media'=>'1')); }
+ public function render($field,$value='') { ?>
+ conditional_attrs($field); ?> data-field-id="">
+ render_label($field); ?>
+
class="wmf-input wmf-file-input">
+
Erlaubt: — Max. MB
+ render_description($field); ?>
+
+
'.'.$t,$types));
+ }
+ public function validate($value,$field) {
+ $key=$field['id'];
+ if(!isset($_FILES['wmf_files']['error'][$key])) return true;
+ $err=$_FILES['wmf_files']['error'][$key];
+ if(is_array($err)) $err=array_filter($err,fn($e)=>$e!==UPLOAD_ERR_NO_FILE);
+ if(empty($err)||$err===UPLOAD_ERR_NO_FILE) {
+ if(!empty($field['required'])&&$field['required']==='1') return sprintf('Bitte laden Sie eine Datei für „%s" hoch.',$field['label']);
+ return true;
+ }
+ $max=intval($field['max_size_mb']??5)*1024*1024;
+ $sizes=$_FILES['wmf_files']['size'][$key];
+ if(is_array($sizes)) { foreach($sizes as $s) if($s>$max) return sprintf('Max. %s MB erlaubt.',$field['max_size_mb']??5); }
+ elseif($sizes>$max) return sprintf('Max. %s MB erlaubt.',$field['max_size_mb']??5);
+ return true;
+ }
+ public function sanitize($v,$f) { return $v; }
+
+ public static function handle_upload($field,$form_id) {
+ $key=$field['id'];
+ if(!isset($_FILES['wmf_files']['tmp_name'][$key])) return array();
+ require_once ABSPATH.'wp-admin/includes/image.php';
+ require_once ABSPATH.'wp-admin/includes/file.php';
+ require_once ABSPATH.'wp-admin/includes/media.php';
+ $tmp=$_FILES['wmf_files']['tmp_name'][$key];
+ $names=$_FILES['wmf_files']['name'][$key];
+ $results=array();
+ if(!is_array($tmp)) { $tmp=array($tmp); $names=array($names); }
+ foreach($tmp as $i=>$t) {
+ if(empty($t)||!is_uploaded_file($t)) continue;
+ $upload=wp_handle_upload(array(
+ 'tmp_name'=>$t,'name'=>$names[$i],'type'=>mime_content_type($t),'error'=>0,'size'=>filesize($t)
+ ),array('test_form'=>false));
+ if(isset($upload['url'])) {
+ if(!empty($field['save_to_media'])&&$field['save_to_media']==='1') {
+ $att=array('post_mime_type'=>$upload['type'],'post_title'=>sanitize_file_name($names[$i]),'post_content'=>'','post_status'=>'inherit');
+ $att_id=wp_insert_attachment($att,$upload['file']);
+ wp_update_attachment_metadata($att_id,wp_generate_attachment_metadata($att_id,$upload['file']));
+ $results[]=array('url'=>$upload['url'],'attachment_id'=>$att_id,'name'=>$names[$i]);
+ } else {
+ $results[]=array('url'=>$upload['url'],'name'=>$names[$i]);
+ }
+ }
+ }
+ return $results;
+ }
+}
diff --git a/inc/fields/class-field-gdpr.php b/inc/fields/class-field-gdpr.php
new file mode 100644
index 0000000..1395ddf
--- /dev/null
+++ b/inc/fields/class-field-gdpr.php
@@ -0,0 +1,34 @@
+ '1',
+ 'gdpr_text' => 'Ich stimme der Datenschutzerklärung zu.',
+ 'error_message' => 'Bitte stimmen Sie der Datenschutzerklärung zu.',
+ ));
+ }
+ public function render($field,$value='') { ?>
+ conditional_attrs($field); ?> data-field-id="">
+
+
+
+
+
+ '')); }
+ public function render($field,$value='') {
+ $v=$value?:($field['default_value']??'');
+ // Dynamic values
+ if($v==='{{user_ip}}') $v=wmf_get_client_ip();
+ if($v==='{{page_url}}') $v=home_url(add_query_arg(array()));
+ if($v==='{{date}}') $v=date('Y-m-d');
+ printf('',esc_attr($field['id']),esc_attr($v));
+ }
+ public function validate($v,$f) { return true; }
+}
diff --git a/inc/fields/class-field-html.php b/inc/fields/class-field-html.php
new file mode 100644
index 0000000..ceb50cb
--- /dev/null
+++ b/inc/fields/class-field-html.php
@@ -0,0 +1,13 @@
+'')); }
+ public function render($field,$value='') { ?>
+ conditional_attrs($field); ?>>
+
+
'','max'=>'','step'=>'1')); }
+ public function render($field,$value='') { ?>
+ conditional_attrs($field); ?> data-field-id="">
+ render_label($field); ?>
+ step="" class="wmf-input">
+ render_description($field); ?>
+
+
+ conditional_attrs($field); ?> data-field-id="">
+ render_label($field); ?>
+ class="wmf-input" autocomplete="tel">
+ render_description($field); ?>
+
+
array(array('label'=>'Option 1','value'=>'option_1')),'layout'=>'vertical')); }
+ public function render($field,$value='') { ?>
+ conditional_attrs($field); ?> data-field-id="">
+ render_label($field); ?>
+
+
+
+
+
+ render_description($field); ?>
+
+
'0','max'=>'100','step'=>'1','show_value'=>'1')); }
+ public function render($field,$value='') {
+ $val=$value!==''?$value:($field['min']??0); ?>
+ conditional_attrs($field); ?> data-field-id="">
+ render_label($field); ?>
+
+
+
+
+
+
+ render_description($field); ?>
+
'5','icon'=>'star')); }
+ public function render($field,$value='') {
+ $max=intval($field['max_stars']??5); ?>
+ conditional_attrs($field); ?> data-field-id="">
+ render_label($field); ?>
+
+
+
+
+
+
+ render_description($field); ?>
+
+
array(array('label'=>'Option 1','value'=>'option_1')),'multiple'=>'0')); }
+ public function render($field,$value='') {
+ $multi=!empty($field['multiple'])&&$field['multiple']==='1';
+ $name='wmf_fields['.esc_attr($field['id']).']'.($multi?'[]':''); ?>
+ conditional_attrs($field); ?> data-field-id="">
+ render_label($field); ?>
+
+ render_description($field); ?>
+
+
+ conditional_attrs($field); ?> data-field-id="">
+ render_label($field); ?>
+
+ render_description($field); ?>
+
+
+ conditional_attrs($field); ?> data-field-id="">
+ render_label($field); ?>
+ class="wmf-input" autocomplete="on">
+ render_description($field); ?>
+
+
'5','max_chars'=>'')); }
+ public function render($field,$value='') { ?>
+ conditional_attrs($field); ?> data-field-id="">
+ render_label($field); ?>
+
+
0/
+ render_description($field); ?>
+
+
+
+
+
+ conditional_attrs($field); ?> data-field-id="">
+ render_label($field); ?>
+ class="wmf-input">
+ render_description($field); ?>
+
+
prefix . 'wmf_submissions';
+ $charset = $wpdb->get_charset_collate();
+ $sql = "CREATE TABLE IF NOT EXISTS {$table} (
+ id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+ form_id BIGINT(20) UNSIGNED NOT NULL,
+ data LONGTEXT NOT NULL,
+ ip VARCHAR(45) DEFAULT '',
+ user_agent TEXT DEFAULT '',
+ status VARCHAR(20) DEFAULT 'neu',
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY (id),
+ KEY form_id (form_id)
+ ) {$charset};";
+ require_once ABSPATH . 'wp-admin/includes/upgrade.php';
+ dbDelta( $sql );
+ update_option( 'wmf_db_version', '2.0' );
+}
+
+function wmf_get_fields() { return WMF_Field_Registry::instance()->get_fields(); }
+function wmf_get_field( $type ) { return WMF_Field_Registry::instance()->get_field( $type ); }
+function wmf_get_shortcode( $id ) { return '[wp_multi_formular id="' . intval($id) . '"]'; }
+function wmf_unique_id() { return 'field_' . substr( md5( uniqid( '', true ) ), 0, 8 ); }
+
+function wmf_get_form_meta( $form_id ) {
+ $defaults = array(
+ 'fields' => array(),
+ 'submit_label' => 'Absenden',
+ 'success_message' => 'Vielen Dank! Ihre Nachricht wurde gesendet.',
+ 'error_message' => 'Es ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.',
+ 'notify_admin' => '1',
+ 'admin_email' => get_option('admin_email'),
+ 'admin_subject' => 'Neue Formulareinreichung',
+ 'admin_reply_to' => '1',
+ 'notify_sender' => '0',
+ 'sender_subject' => 'Ihre Nachricht wurde empfangen',
+ 'sender_message' => 'Vielen Dank für Ihre Nachricht. Wir melden uns bald.',
+ 'from_name' => get_bloginfo('name'),
+ 'from_email' => get_option('admin_email'),
+ 'save_submissions' => '1',
+ 'recaptcha_enabled' => '0',
+ 'honeypot_enabled' => '1',
+ 'active_email_service' => '',
+ 'email_list_field' => '',
+ 'redirect_url' => '',
+ 'css_class' => '',
+ 'multi_step' => '0',
+ 'step_labels' => array(),
+ 'show_progress' => '1',
+ );
+ $meta = get_post_meta( $form_id, '_wmf_form_data', true );
+ if ( ! is_array( $meta ) ) $meta = array();
+ return wp_parse_args( $meta, $defaults );
+}
+
+function wmf_save_form_meta( $form_id, $data ) {
+ update_post_meta( $form_id, '_wmf_form_data', $data );
+}
+
+function wmf_get_submissions( $form_id, $args = array() ) {
+ global $wpdb;
+ $table = $wpdb->prefix . 'wmf_submissions';
+ $defaults = array( 'limit' => 50, 'offset' => 0, 'status' => '', 'search' => '' );
+ $args = wp_parse_args( $args, $defaults );
+
+ $where = $wpdb->prepare( 'WHERE form_id = %d', $form_id );
+ if ( $args['status'] )
+ $where .= $wpdb->prepare( ' AND status = %s', $args['status'] );
+ if ( $args['search'] )
+ $where .= $wpdb->prepare( ' AND data LIKE %s', '%' . $wpdb->esc_like( $args['search'] ) . '%' );
+
+ return $wpdb->get_results(
+ $wpdb->prepare(
+ "SELECT * FROM {$table} {$where} ORDER BY created_at DESC LIMIT %d OFFSET %d",
+ $args['limit'], $args['offset']
+ )
+ );
+}
+
+function wmf_count_submissions( $form_id, $status = '', $search = '' ) {
+ global $wpdb;
+ $where = $wpdb->prepare( 'WHERE form_id = %d', $form_id );
+ if ( $status )
+ $where .= $wpdb->prepare( ' AND status = %s', $status );
+ if ( $search )
+ $where .= $wpdb->prepare( ' AND data LIKE %s', '%' . $wpdb->esc_like( $search ) . '%' );
+ return (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}wmf_submissions {$where}" );
+}
+
+function wmf_get_client_ip() {
+ foreach ( array('HTTP_CLIENT_IP','HTTP_X_FORWARDED_FOR','REMOTE_ADDR') as $k ) {
+ if ( ! empty( $_SERVER[$k] ) ) {
+ $ip = trim( explode(',', $_SERVER[$k])[0] );
+ if ( filter_var($ip, FILTER_VALIDATE_IP) ) return $ip;
+ }
+ }
+ return '';
+}
+
+/**
+ * Sicherer Redirect - funktioniert auch wenn Header bereits gesendet wurden
+ * (z.B. durch Plugins die Output vor wp_redirect() ausgeben)
+ */
+function wmf_safe_redirect( $url ) {
+ $url = esc_url_raw( $url );
+ if ( ! headers_sent() ) {
+ wp_redirect( $url );
+ exit;
+ }
+ // JavaScript-Fallback
+ echo '';
+ echo '';
+ exit;
+}