Upload folder via GUI - inc
This commit is contained in:
348
inc/classes/class-admin.php
Normal file
348
inc/classes/class-admin.php
Normal file
@@ -0,0 +1,348 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
class WMF_Admin {
|
||||
private static $instance=null;
|
||||
public static function instance() {
|
||||
if(is_null(self::$instance)){self::$instance=new self();self::$instance->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 ? ' <span class="awaiting-mod update-plugins count-'.intval($new_count).'"><span class="pending-count">'.intval($new_count).'</span></span>' : '';
|
||||
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);
|
||||
?>
|
||||
<div class="wrap wmf-admin-wrap">
|
||||
<h1 class="wmf-page-title">
|
||||
Einreichung #<?php echo intval($sid); ?>
|
||||
<span style="font-size:14px;font-weight:normal;color:#646970;margin-left:8px;">
|
||||
aus: <?php echo esc_html($form ? $form->post_title : ''); ?>
|
||||
</span>
|
||||
</h1>
|
||||
<?php WMF_Submissions_List::render_single($sid, $form_id); ?>
|
||||
</div>
|
||||
<?php
|
||||
return;
|
||||
}
|
||||
|
||||
// Einreichungen eines Formulars anzeigen
|
||||
if(!empty($_GET['form_id'])) {
|
||||
$form_id = intval($_GET['form_id']);
|
||||
$form = get_post($form_id);
|
||||
WMF_Submissions_List::maybe_export($form_id);
|
||||
?>
|
||||
<div class="wrap wmf-admin-wrap">
|
||||
<h1 class="wmf-page-title">
|
||||
Einreichungen:
|
||||
<span style="color:#646970;"><?php echo esc_html($form ? $form->post_title : ''); ?></span>
|
||||
<a href="<?php echo esc_url(admin_url('admin.php?page=wmf-submissions')); ?>"
|
||||
class="page-title-action">← Alle Formulare</a>
|
||||
</h1>
|
||||
<?php WMF_Submissions_List::render($form_id); ?>
|
||||
</div>
|
||||
<?php
|
||||
return;
|
||||
}
|
||||
|
||||
// Übersicht aller Formulare mit Einreichungszahlen
|
||||
?>
|
||||
<div class="wrap wmf-admin-wrap">
|
||||
<h1>Einreichungen</h1>
|
||||
<?php
|
||||
$forms = get_posts(array(
|
||||
'post_type' => 'wmf-form',
|
||||
'post_status' => 'publish',
|
||||
'numberposts' => -1,
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
));
|
||||
|
||||
if(empty($forms)): ?>
|
||||
<div class="wmf-empty-state">
|
||||
<span class="dashicons dashicons-email-alt wmf-empty-icon"></span>
|
||||
<h2>Noch keine Formulare vorhanden</h2>
|
||||
<p>Erstellen Sie zuerst ein Formular und binden Sie es auf einer Seite ein.</p>
|
||||
<a href="<?php echo esc_url(admin_url('admin.php?page=wmf-new-form')); ?>"
|
||||
class="button button-primary button-hero">Formular erstellen</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<table class="wp-list-table widefat fixed striped wmf-submissions-overview">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Formular</th>
|
||||
<th style="width:100px;text-align:center;">Gesamt</th>
|
||||
<th style="width:80px;text-align:center;">Neu</th>
|
||||
<th style="width:100px;text-align:center;">Gelesen</th>
|
||||
<th style="width:110px;text-align:center;">Archiviert</th>
|
||||
<th style="width:130px;text-align:center;">Letzte Einreichung</th>
|
||||
<th style="width:120px;">Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($forms as $form):
|
||||
$total = wmf_count_submissions($form->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);
|
||||
?>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>
|
||||
<a href="<?php echo esc_url($view_url); ?>">
|
||||
<?php echo esc_html($form->post_title); ?>
|
||||
</a>
|
||||
</strong>
|
||||
<div style="font-size:11px;color:#646970;margin-top:2px;">
|
||||
<?php echo esc_html(wmf_get_shortcode($form->ID)); ?>
|
||||
</div>
|
||||
</td>
|
||||
<td style="text-align:center;">
|
||||
<a href="<?php echo esc_url($view_url); ?>" style="font-size:18px;font-weight:700;color:#2271b1;text-decoration:none;">
|
||||
<?php echo intval($total); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td style="text-align:center;">
|
||||
<?php if($count_new > 0): ?>
|
||||
<a href="<?php echo esc_url(add_query_arg('sub_status','neu',$view_url)); ?>"
|
||||
style="display:inline-block;background:#2271b1;color:#fff;border-radius:10px;padding:2px 9px;font-size:12px;font-weight:700;text-decoration:none;">
|
||||
<?php echo intval($count_new); ?>
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<span style="color:#a7aaad;">0</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td style="text-align:center;color:#646970;"><?php echo intval($count_read); ?></td>
|
||||
<td style="text-align:center;color:#a7aaad;"><?php echo intval($count_arch); ?></td>
|
||||
<td style="text-align:center;font-size:12px;color:#646970;">
|
||||
<?php echo $last ? esc_html(date_i18n('d.m.Y H:i', strtotime($last))) : '—'; ?>
|
||||
</td>
|
||||
<td>
|
||||
<a href="<?php echo esc_url($view_url); ?>" class="button button-small">Anzeigen</a>
|
||||
<?php if($total > 0): ?>
|
||||
<a href="<?php echo esc_url($export_url); ?>" class="button button-small">CSV</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
/**
|
||||
* Sicherer Redirect: funktioniert auch wenn bereits Output gesendet wurde
|
||||
* (z.B. durch andere Plugins wie wp-multi-ticket)
|
||||
*/
|
||||
private function safe_redirect($url) {
|
||||
$url = esc_url_raw($url);
|
||||
if(!headers_sent()) {
|
||||
wp_redirect($url);
|
||||
exit;
|
||||
}
|
||||
// Fallback: JavaScript-Redirect wenn Header bereits gesendet
|
||||
echo '<script>window.location.href=' . wp_json_encode($url) . ';</script>';
|
||||
echo '<noscript><meta http-equiv="refresh" content="0;url=' . esc_attr($url) . '"></noscript>';
|
||||
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('<div class="notice notice-%s is-dismissible"><p>%s</p></div>',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;
|
||||
}
|
||||
}
|
||||
44
inc/classes/class-builder.php
Normal file
44
inc/classes/class-builder.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Builder {
|
||||
private static $instance=null;
|
||||
public static function instance() {
|
||||
if(is_null(self::$instance)){self::$instance=new self();self::$instance->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 '<div class="wmf-preview-wrap">';
|
||||
foreach($fields as $field) {
|
||||
$obj=wmf_get_field($field['type']??'');
|
||||
if(!$obj) continue;
|
||||
echo '<div class="wmf-field-wrap">';
|
||||
$obj->render($field,'');
|
||||
echo '</div>';
|
||||
}
|
||||
echo '<div class="wmf-submit-wrap"><button type="button" class="wmf-submit-button" disabled>'.esc_html($meta['submit_label']?:'Absenden').'</button></div>';
|
||||
echo '</div>';
|
||||
$html=ob_get_clean();
|
||||
wp_send_json_success(array('html'=>$html));
|
||||
}
|
||||
}
|
||||
21
inc/classes/class-field-registry.php
Normal file
21
inc/classes/class-field-registry.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_Registry {
|
||||
private static $instance=null;
|
||||
private $fields=array();
|
||||
public static function instance() {
|
||||
if(is_null(self::$instance)){self::$instance=new self();self::$instance->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; }
|
||||
}
|
||||
105
inc/classes/class-form-processor.php
Normal file
105
inc/classes/class-form-processor.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
class WMF_Form_Processor {
|
||||
private static $instance=null;
|
||||
public static function instance() {
|
||||
if(is_null(self::$instance)){self::$instance=new self();self::$instance->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'];
|
||||
}
|
||||
}
|
||||
145
inc/classes/class-form-renderer.php
Normal file
145
inc/classes/class-form-renderer.php
Normal file
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
class WMF_Form_Renderer {
|
||||
|
||||
public static function render($form_id,$args=array()) {
|
||||
$form=get_post($form_id);
|
||||
if(!$form||$form->post_type!=='wmf-form'||$form->post_status!=='publish')
|
||||
return '<p class="wmf-error">Formular nicht gefunden.</p>';
|
||||
|
||||
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 '<div class="wmf-notice wmf-notice-success" role="alert">'.esc_html($meta['success_message']).'</div>';
|
||||
if(empty($args['always_show'])) return ob_get_clean();
|
||||
}
|
||||
if(!empty($errors['_global']))
|
||||
echo '<div class="wmf-notice wmf-notice-error" role="alert">'.esc_html($errors['_global']).'</div>';
|
||||
|
||||
$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);
|
||||
?>
|
||||
<div class="wmf-form-wrap" id="wmf-wrap-<?php echo intval($form_id); ?>">
|
||||
|
||||
<?php if($multi_step&&!empty($meta['show_progress'])&&$meta['show_progress']==='1'): ?>
|
||||
<div class="wmf-progress-bar" data-steps="<?php echo $total_steps; ?>">
|
||||
<?php $step_labels=$meta['step_labels']??array();
|
||||
foreach(array_keys($steps) as $si=>$snum): $lbl=$step_labels[$si]??'Schritt '.($si+1); ?>
|
||||
<div class="wmf-step-indicator <?php echo $si===0?'active':''; ?>" data-step="<?php echo $si; ?>">
|
||||
<span class="wmf-step-num"><?php echo $si+1; ?></span>
|
||||
<span class="wmf-step-lbl"><?php echo esc_html($lbl); ?></span>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form class="<?php echo $form_cls; ?>"
|
||||
id="wmf-form-<?php echo intval($form_id); ?>"
|
||||
method="post"
|
||||
enctype="multipart/form-data"
|
||||
novalidate
|
||||
data-form-id="<?php echo intval($form_id); ?>"
|
||||
data-multi-step="<?php echo $multi_step?'1':'0'; ?>"
|
||||
data-total-steps="<?php echo $total_steps; ?>"
|
||||
data-fields='<?php echo esc_attr($field_json); ?>'>
|
||||
|
||||
<?php wp_nonce_field('wmf_submit_'.$form_id,'wmf_nonce'); ?>
|
||||
<input type="hidden" name="wmf_form_id" value="<?php echo intval($form_id); ?>">
|
||||
<input type="hidden" name="wmf_action" value="submit">
|
||||
|
||||
<?php // Honeypot
|
||||
if(!empty($meta['honeypot_enabled'])&&$meta['honeypot_enabled']==='1'):
|
||||
$hp_name='wmf_hp_'.md5($form_id); ?>
|
||||
<div class="wmf-hp-field" aria-hidden="true" style="position:absolute;left:-9999px;opacity:0;pointer-events:none;">
|
||||
<label for="<?php echo esc_attr($hp_name); ?>">Bitte leer lassen</label>
|
||||
<input type="text" id="<?php echo esc_attr($hp_name); ?>" name="<?php echo esc_attr($hp_name); ?>" value="" tabindex="-1" autocomplete="off">
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if($multi_step): ?>
|
||||
<?php foreach(array_values($steps) as $si=>$step_fields): ?>
|
||||
<div class="wmf-step" data-step="<?php echo $si; ?>" <?php echo $si>0?'style="display:none;"':''; ?>>
|
||||
<div class="wmf-fields">
|
||||
<?php self::render_fields($step_fields,$errors,$saved_values); ?>
|
||||
</div>
|
||||
<div class="wmf-step-nav">
|
||||
<?php if($si>0): ?><button type="button" class="wmf-prev-step button button-secondary">← Zurück</button><?php endif; ?>
|
||||
<?php if($si<$total_steps-1): ?>
|
||||
<button type="button" class="wmf-next-step button button-primary">Weiter →</button>
|
||||
<?php else: ?>
|
||||
<?php self::render_submit($meta,$form_id); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<div class="wmf-fields">
|
||||
<?php self::render_fields($fields,$errors,$saved_values); ?>
|
||||
</div>
|
||||
<?php self::render_submit($meta,$form_id); ?>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
private static function render_fields($fields,$errors,$saved_values) {
|
||||
foreach($fields as $field) {
|
||||
$obj=wmf_get_field($field['type']??'');
|
||||
if(!$obj) continue;
|
||||
$value=$saved_values[$field['id']]??'';
|
||||
$err=$errors[$field['id']]??'';
|
||||
$wrap_cls='wmf-field-wrap'.($err?' wmf-has-error':'');
|
||||
echo '<div class="'.esc_attr($wrap_cls).'">';
|
||||
$obj->render($field,$value);
|
||||
if($err) echo '<p class="wmf-field-error">'.esc_html($err).'</p>';
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
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 '<input type="hidden" name="wmf_recaptcha_token" id="wmf-rctoken-'.intval($form_id).'">';
|
||||
echo '<script>if(typeof grecaptcha!=="undefined"){grecaptcha.ready(function(){grecaptcha.execute("'.esc_js($creds['site_key']).'",{action:"submit"}).then(function(t){document.getElementById("wmf-rctoken-'.intval($form_id).'").value=t;});});}</script>';
|
||||
} elseif($rv2&&$rv2->is_connected()) {
|
||||
$creds=$rv2->get_credentials();
|
||||
echo '<div class="wmf-recaptcha g-recaptcha" data-sitekey="'.esc_attr($creds['site_key']).'"></div>';
|
||||
echo '<script async defer src="https://www.google.com/recaptcha/api.js"></script>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div class="wmf-submit-wrap">
|
||||
<button type="submit" class="wmf-submit-button">
|
||||
<?php echo esc_html($meta['submit_label']?:'Absenden'); ?>
|
||||
</button>
|
||||
<span class="wmf-spinner" aria-hidden="true"></span>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
102
inc/classes/class-mailer.php
Normal file
102
inc/classes/class-mailer.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class WMF_Mailer {
|
||||
|
||||
/**
|
||||
* Admin-Benachrichtigung
|
||||
*/
|
||||
public static function notify_admin($form_id, $meta, $fields, $values, $file_values = array()) {
|
||||
$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'));
|
||||
$to = !empty($meta['admin_email']) ? $meta['admin_email'] : get_option('admin_email');
|
||||
$subject = !empty($meta['admin_subject']) ? $meta['admin_subject'] : 'Neue Formulareinreichung';
|
||||
|
||||
$headers = array(
|
||||
'Content-Type: text/html; charset=UTF-8',
|
||||
'From: ' . $from_name . ' <' . $from_email . '>',
|
||||
);
|
||||
|
||||
// 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 = '<html><body style="font-family:sans-serif;color:#1d2327;max-width:600px;margin:0 auto;">'
|
||||
. wpautop(esc_html($meta['sender_message'] ?? ''))
|
||||
. '<p style="color:#888;font-size:12px;margin-top:24px;">Gesendet ueber ' . get_bloginfo('name') . '</p>'
|
||||
. '</body></html>';
|
||||
|
||||
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 = '<img src="' . esc_attr($val) . '" style="max-width:300px;border:1px solid #ddd;">';
|
||||
if(isset($file_values[$f['id']])) {
|
||||
$links = array_map(
|
||||
fn($u) => '<a href="' . esc_url($u['url']) . '">' . esc_html($u['name']) . '</a>',
|
||||
$file_values[$f['id']]
|
||||
);
|
||||
$val = implode('<br>', $links);
|
||||
}
|
||||
$rows .= '<tr>'
|
||||
. '<th style="text-align:left;padding:8px 14px;background:#f6f7f7;border-bottom:1px solid #eee;white-space:nowrap;font-weight:600;">' . esc_html($lbl) . '</th>'
|
||||
. '<td style="padding:8px 14px;border-bottom:1px solid #eee;">' . $val . '</td>'
|
||||
. '</tr>';
|
||||
}
|
||||
|
||||
return '<html><body style="font-family:Arial,sans-serif;color:#1d2327;max-width:600px;margin:0 auto;">'
|
||||
. '<div style="background:#2271b1;padding:20px 24px;border-radius:4px 4px 0 0;">'
|
||||
. '<h2 style="color:#fff;margin:0;font-size:18px;">Neue Formulareinreichung</h2>'
|
||||
. '<p style="color:rgba(255,255,255,.8);margin:4px 0 0;font-size:13px;">' . get_bloginfo('name') . ' · ' . current_time('d.m.Y H:i') . '</p>'
|
||||
. '</div>'
|
||||
. '<div style="border:1px solid #dcdcde;border-top:none;border-radius:0 0 4px 4px;padding:0;">'
|
||||
. '<table style="border-collapse:collapse;width:100%;">' . $rows . '</table>'
|
||||
. '</div>'
|
||||
. '<p style="color:#888;font-size:11px;margin-top:16px;text-align:center;">Diese E-Mail wurde automatisch gesendet von WP Multi Formular</p>'
|
||||
. '</body></html>';
|
||||
}
|
||||
}
|
||||
43
inc/classes/class-post-type.php
Normal file
43
inc/classes/class-post-type.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) exit;
|
||||
|
||||
class WMF_Post_Type {
|
||||
private static $instance = null;
|
||||
public static function instance() {
|
||||
if ( is_null( self::$instance ) ) { self::$instance = new self(); self::$instance->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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
inc/classes/class-shortcode.php
Normal file
36
inc/classes/class-shortcode.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Shortcode {
|
||||
private static $instance=null;
|
||||
public static function instance() {
|
||||
if(is_null(self::$instance)){self::$instance=new self();self::$instance->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 '<p class="wmf-error">Bitte geben Sie eine Formular-ID an.</p>';
|
||||
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',
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
54
inc/classes/class-smtp.php
Normal file
54
inc/classes/class-smtp.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class WMF_SMTP {
|
||||
|
||||
private static $instance = null;
|
||||
|
||||
public static function instance() {
|
||||
if(is_null(self::$instance)) {
|
||||
self::$instance = new self();
|
||||
self::$instance->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,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
18
inc/classes/class-submission.php
Normal file
18
inc/classes/class-submission.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Submission {
|
||||
public static function save($form_id,$values) {
|
||||
global $wpdb;
|
||||
$wpdb->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'));
|
||||
}
|
||||
}
|
||||
481
inc/classes/class-submissions-list.php
Normal file
481
inc/classes/class-submissions-list.php
Normal file
@@ -0,0 +1,481 @@
|
||||
<?php
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class WMF_Submissions_List {
|
||||
|
||||
/* ================================================================
|
||||
LISTE ALLER EINREICHUNGEN EINES FORMULARS
|
||||
================================================================ */
|
||||
public static function render($form_id) {
|
||||
$meta = wmf_get_form_meta($form_id);
|
||||
$fields = self::get_display_fields($meta);
|
||||
$per_page = 25;
|
||||
$current_page= max(1, intval($_GET['paged'] ?? 1));
|
||||
$offset = ($current_page - 1) * $per_page;
|
||||
$status_filter = sanitize_text_field($_GET['sub_status'] ?? '');
|
||||
$search = sanitize_text_field($_GET['sub_search'] ?? '');
|
||||
|
||||
$submissions = wmf_get_submissions($form_id, array(
|
||||
'limit' => $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'));
|
||||
?>
|
||||
|
||||
<div class="wmf-submissions-wrap">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="wmf-subs-header">
|
||||
<h2 class="wmf-subs-title">
|
||||
Einreichungen
|
||||
<span class="wmf-subs-count"><?php echo intval($total); ?></span>
|
||||
</h2>
|
||||
<div class="wmf-subs-actions">
|
||||
<?php if($submissions): ?>
|
||||
<a href="<?php echo esc_url(self::export_url($form_id)); ?>"
|
||||
class="button">⬇ CSV exportieren</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filter-Leiste -->
|
||||
<div class="wmf-subs-filter-bar">
|
||||
<form method="get" action="<?php echo esc_url(admin_url('admin.php')); ?>">
|
||||
<input type="hidden" name="page" value="wp-multi-formular">
|
||||
<input type="hidden" name="view_submissions" value="<?php echo intval($form_id); ?>">
|
||||
|
||||
<!-- Status-Tabs -->
|
||||
<div class="wmf-status-tabs">
|
||||
<?php
|
||||
$statuses = array('' => 'Alle', 'neu' => 'Neu', 'gelesen' => 'Gelesen', 'archiviert' => 'Archiviert');
|
||||
foreach($statuses as $s_key => $s_label):
|
||||
$cnt = ($s_key === '') ? wmf_count_submissions($form_id) : wmf_count_submissions($form_id, $s_key);
|
||||
$active = ($status_filter === $s_key) ? 'current' : '';
|
||||
?>
|
||||
<a href="<?php echo esc_url(add_query_arg(array('sub_status'=>$s_key,'paged'=>1), $base_url)); ?>"
|
||||
class="wmf-status-tab <?php echo $active; ?>">
|
||||
<?php echo esc_html($s_label); ?>
|
||||
<span class="count">(<?php echo intval($cnt); ?>)</span>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<!-- Suche -->
|
||||
<div class="wmf-subs-search">
|
||||
<input type="search" name="sub_search" value="<?php echo esc_attr($search); ?>"
|
||||
placeholder="Einreichungen durchsuchen …" class="wmf-search-input">
|
||||
<button type="submit" class="button">Suchen</button>
|
||||
<?php if($search): ?>
|
||||
<a href="<?php echo esc_url($base_url); ?>" class="button">✕ Zurücksetzen</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php if(empty($submissions)): ?>
|
||||
<div class="wmf-empty-submissions">
|
||||
<span class="dashicons dashicons-email-alt" style="font-size:48px;width:48px;height:48px;color:#c3c4c7;margin-bottom:12px;display:block;"></span>
|
||||
<?php if($search||$status_filter): ?>
|
||||
<p>Keine Einreichungen gefunden.</p>
|
||||
<a href="<?php echo esc_url($base_url); ?>" class="button">Filter zurücksetzen</a>
|
||||
<?php else: ?>
|
||||
<p>Noch keine Einreichungen vorhanden.</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
|
||||
<!-- Tabelle -->
|
||||
<div class="wmf-table-wrap">
|
||||
<table class="wp-list-table widefat fixed striped wmf-submissions-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="wmf-col-id">#</th>
|
||||
<th class="wmf-col-date">Datum</th>
|
||||
<?php foreach(array_slice($fields, 0, 4) as $f): ?>
|
||||
<th><?php echo esc_html($f['label']); ?></th>
|
||||
<?php endforeach; ?>
|
||||
<th class="wmf-col-status">Status</th>
|
||||
<th class="wmf-col-actions">Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($submissions as $row):
|
||||
$data = json_decode($row->data, true) ?? array();
|
||||
$view_url = add_query_arg(array(
|
||||
'page' => 'wp-multi-formular',
|
||||
'view_submission' => $row->id,
|
||||
'form_id' => $form_id,
|
||||
), admin_url('admin.php'));
|
||||
?>
|
||||
<tr class="wmf-sub-row <?php echo $row->status === 'neu' ? 'wmf-sub-new' : ''; ?>">
|
||||
<td class="wmf-col-id">
|
||||
<a href="<?php echo esc_url($view_url); ?>" class="wmf-sub-id-link">
|
||||
#<?php echo intval($row->id); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td class="wmf-col-date">
|
||||
<a href="<?php echo esc_url($view_url); ?>">
|
||||
<?php echo esc_html(date_i18n('d.m.Y', strtotime($row->created_at))); ?>
|
||||
<span class="wmf-time"><?php echo esc_html(date_i18n('H:i', strtotime($row->created_at))); ?></span>
|
||||
</a>
|
||||
</td>
|
||||
<?php foreach(array_slice($fields, 0, 4) as $f):
|
||||
$v = $data[$f['id']] ?? '';
|
||||
if(is_array($v)) $v = implode(', ', $v);
|
||||
if(($f['type']??'') === 'signature') $v = '(Unterschrift)';
|
||||
$v_short = mb_strlen($v) > 60 ? mb_substr($v, 0, 60).'…' : $v;
|
||||
?>
|
||||
<td>
|
||||
<a href="<?php echo esc_url($view_url); ?>" title="<?php echo esc_attr($v); ?>">
|
||||
<?php echo esc_html($v_short); ?>
|
||||
</a>
|
||||
</td>
|
||||
<?php endforeach; ?>
|
||||
<td class="wmf-col-status">
|
||||
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" class="wmf-status-form">
|
||||
<?php wp_nonce_field('wmf_update_status'); ?>
|
||||
<input type="hidden" name="action" value="wmf_update_submission_status">
|
||||
<input type="hidden" name="submission_id" value="<?php echo intval($row->id); ?>">
|
||||
<input type="hidden" name="form_id" value="<?php echo intval($form_id); ?>">
|
||||
<input type="hidden" name="redirect_url" value="<?php echo esc_attr(add_query_arg(array('page'=>'wp-multi-formular','view_submissions'=>$form_id,'paged'=>$current_page,'sub_status'=>$status_filter), admin_url('admin.php'))); ?>">
|
||||
<select name="status" class="wmf-status-select wmf-status-<?php echo esc_attr($row->status); ?>" onchange="this.form.submit()">
|
||||
<option value="neu" <?php selected($row->status,'neu'); ?>>Neu</option>
|
||||
<option value="gelesen" <?php selected($row->status,'gelesen'); ?>>Gelesen</option>
|
||||
<option value="archiviert" <?php selected($row->status,'archiviert'); ?>>Archiviert</option>
|
||||
</select>
|
||||
</form>
|
||||
</td>
|
||||
<td class="wmf-col-actions">
|
||||
<a href="<?php echo esc_url($view_url); ?>" class="button button-small">
|
||||
👁 Ansehen
|
||||
</a>
|
||||
<a href="<?php echo esc_url(wp_nonce_url(
|
||||
add_query_arg(array('wmf_action'=>'delete_submission','submission_id'=>$row->id,'form_id'=>$form_id,'page'=>'wp-multi-formular'), admin_url('admin.php')),
|
||||
'wmf_delete_submission'
|
||||
)); ?>"
|
||||
class="button button-small wmf-btn-delete"
|
||||
onclick="return confirm('Einreichung #<?php echo intval($row->id); ?> wirklich löschen?')">
|
||||
🗑 Löschen
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<?php if($total_pages > 1): ?>
|
||||
<div class="wmf-pagination">
|
||||
<?php if($current_page > 1): ?>
|
||||
<a href="<?php echo esc_url(add_query_arg('paged', $current_page-1, $base_url)); ?>" class="button">« Zurück</a>
|
||||
<?php endif; ?>
|
||||
<span class="wmf-page-info">
|
||||
Seite <?php echo $current_page; ?> von <?php echo $total_pages; ?>
|
||||
</span>
|
||||
<?php if($current_page < $total_pages): ?>
|
||||
<a href="<?php echo esc_url(add_query_arg('paged', $current_page+1, $base_url)); ?>" class="button">Weiter »</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
DETAILANSICHT EINER EINZELNEN EINREICHUNG
|
||||
================================================================ */
|
||||
public static function render_single($submission_id, $form_id) {
|
||||
global $wpdb;
|
||||
$row = $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT * FROM {$wpdb->prefix}wmf_submissions WHERE id = %d AND form_id = %d",
|
||||
$submission_id, $form_id
|
||||
));
|
||||
|
||||
if(!$row) {
|
||||
echo '<div class="notice notice-error"><p>Einreichung nicht gefunden.</p></div>';
|
||||
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');
|
||||
?>
|
||||
|
||||
<div class="wmf-submission-detail">
|
||||
|
||||
<!-- Navigation -->
|
||||
<div class="wmf-detail-nav">
|
||||
<a href="<?php echo esc_url($back_url); ?>" class="button">
|
||||
← Alle Einreichungen
|
||||
</a>
|
||||
<div class="wmf-detail-nav-arrows">
|
||||
<?php if($prev_url): ?>
|
||||
<a href="<?php echo esc_url($prev_url); ?>" class="button" title="Vorherige Einreichung">« Vorherige</a>
|
||||
<?php else: ?>
|
||||
<button class="button" disabled>« Vorherige</button>
|
||||
<?php endif; ?>
|
||||
<?php if($next_url): ?>
|
||||
<a href="<?php echo esc_url($next_url); ?>" class="button" title="Nächste Einreichung">Nächste »</a>
|
||||
<?php else: ?>
|
||||
<button class="button" disabled>Nächste »</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Meta-Karte -->
|
||||
<div class="wmf-detail-meta-card">
|
||||
<div class="wmf-detail-meta-item">
|
||||
<span class="wmf-detail-meta-label">Einreichung</span>
|
||||
<span class="wmf-detail-meta-value">#<?php echo intval($row->id); ?></span>
|
||||
</div>
|
||||
<div class="wmf-detail-meta-item">
|
||||
<span class="wmf-detail-meta-label">Formular</span>
|
||||
<span class="wmf-detail-meta-value"><?php echo esc_html($form ? $form->post_title : 'Unbekannt'); ?></span>
|
||||
</div>
|
||||
<div class="wmf-detail-meta-item">
|
||||
<span class="wmf-detail-meta-label">Datum</span>
|
||||
<span class="wmf-detail-meta-value"><?php echo esc_html(date_i18n('d.m.Y H:i', strtotime($row->created_at))); ?></span>
|
||||
</div>
|
||||
<div class="wmf-detail-meta-item">
|
||||
<span class="wmf-detail-meta-label">IP-Adresse</span>
|
||||
<span class="wmf-detail-meta-value"><?php echo esc_html($row->ip ?: '—'); ?></span>
|
||||
</div>
|
||||
<div class="wmf-detail-meta-item">
|
||||
<span class="wmf-detail-meta-label">Status</span>
|
||||
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" style="display:inline;">
|
||||
<?php wp_nonce_field('wmf_update_status'); ?>
|
||||
<input type="hidden" name="action" value="wmf_update_submission_status">
|
||||
<input type="hidden" name="submission_id" value="<?php echo intval($row->id); ?>">
|
||||
<input type="hidden" name="form_id" value="<?php echo intval($form_id); ?>">
|
||||
<input type="hidden" name="redirect_url" value="<?php echo esc_attr(add_query_arg(array('page'=>'wp-multi-formular','view_submission'=>$row->id,'form_id'=>$form_id), admin_url('admin.php'))); ?>">
|
||||
<select name="status" class="wmf-status-select wmf-status-<?php echo esc_attr($row->status); ?>" onchange="this.form.submit()">
|
||||
<option value="neu" <?php selected($row->status,'neu'); ?>>Neu</option>
|
||||
<option value="gelesen" <?php selected($row->status,'gelesen'); ?>>Gelesen</option>
|
||||
<option value="archiviert" <?php selected($row->status,'archiviert'); ?>>Archiviert</option>
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
<div class="wmf-detail-meta-item wmf-detail-meta-actions">
|
||||
<a href="<?php echo esc_url(wp_nonce_url(
|
||||
add_query_arg(array('wmf_action'=>'delete_submission','submission_id'=>$row->id,'form_id'=>$form_id,'page'=>'wp-multi-formular'), admin_url('admin.php')),
|
||||
'wmf_delete_submission'
|
||||
)); ?>"
|
||||
class="button wmf-btn-delete"
|
||||
onclick="return confirm('Einreichung #<?php echo intval($row->id); ?> wirklich löschen?')">
|
||||
🗑 Löschen
|
||||
</a>
|
||||
<button onclick="window.print()" class="button">🖶 Drucken</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Felder-Inhalt -->
|
||||
<div class="wmf-detail-fields">
|
||||
<h3 class="wmf-detail-section-title">Eingereichte Daten</h3>
|
||||
<div class="wmf-detail-fields-grid">
|
||||
<?php foreach($fields as $field):
|
||||
$val = $data[$field['id']] ?? '';
|
||||
$type = $field['type'] ?? 'text';
|
||||
?>
|
||||
<div class="wmf-detail-field <?php echo 'wmf-detail-field-' . esc_attr($type); ?>">
|
||||
<div class="wmf-detail-field-label">
|
||||
<?php echo esc_html($field['label']); ?>
|
||||
<span class="wmf-detail-field-type"><?php echo esc_html($type); ?></span>
|
||||
</div>
|
||||
<div class="wmf-detail-field-value">
|
||||
<?php self::render_field_value($val, $field); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Technische Infos (aufklappbar) -->
|
||||
<details class="wmf-detail-technical">
|
||||
<summary>Technische Informationen</summary>
|
||||
<table class="widefat" style="margin-top:12px;">
|
||||
<tr><th>User-Agent</th><td><?php echo esc_html($row->user_agent ?: '—'); ?></td></tr>
|
||||
<tr><th>Erstellt am</th><td><?php echo esc_html($row->created_at); ?></td></tr>
|
||||
<tr><th>Datenbank-ID</th><td><?php echo intval($row->id); ?></td></tr>
|
||||
</table>
|
||||
</details>
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@media print {
|
||||
#adminmenumain,#wpadminbar,.wmf-detail-nav,.wmf-detail-meta-actions,
|
||||
#screen-meta,#wpfooter,.notice { display:none!important; }
|
||||
.wmf-submission-detail { margin:0; padding:0; }
|
||||
.wmf-detail-fields { border:none; }
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
FELDINHALTE RENDERN (je nach Typ)
|
||||
================================================================ */
|
||||
private static function render_field_value($val, $field) {
|
||||
$type = $field['type'] ?? 'text';
|
||||
|
||||
if($val === '' || $val === null || $val === array()) {
|
||||
echo '<span class="wmf-empty-value">—</span>';
|
||||
return;
|
||||
}
|
||||
|
||||
switch($type) {
|
||||
case 'checkbox':
|
||||
$vals = is_array($val) ? $val : explode(', ', $val);
|
||||
echo '<ul class="wmf-val-list">';
|
||||
foreach($vals as $v) echo '<li>' . esc_html($v) . '</li>';
|
||||
echo '</ul>';
|
||||
break;
|
||||
|
||||
case 'gdpr':
|
||||
$icon = $val === '1' ? '✅' : '❌';
|
||||
echo $icon . ' ' . ($val === '1' ? 'Zugestimmt' : 'Nicht zugestimmt');
|
||||
break;
|
||||
|
||||
case 'signature':
|
||||
if(strpos($val, 'data:image') === 0) {
|
||||
echo '<img src="' . esc_attr($val) . '" style="max-width:300px;border:1px solid #dcdcde;border-radius:4px;background:#fff;">';
|
||||
} else {
|
||||
echo '<span class="wmf-empty-value">Keine Unterschrift</span>';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'file':
|
||||
$urls = is_array($val) ? $val : explode(', ', $val);
|
||||
echo '<div class="wmf-val-files">';
|
||||
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 '<div class="wmf-val-file-img"><a href="' . esc_url($url) . '" target="_blank">';
|
||||
echo '<img src="' . esc_url($url) . '" style="max-width:200px;max-height:150px;border-radius:4px;"></a></div>';
|
||||
} else {
|
||||
echo '<a href="' . esc_url($url) . '" target="_blank" class="wmf-val-file-link">📎 ' . esc_html($filename) . '</a>';
|
||||
}
|
||||
}
|
||||
echo '</div>';
|
||||
break;
|
||||
|
||||
case 'rating':
|
||||
$stars = intval($val);
|
||||
$max = intval($field['max_stars'] ?? 5);
|
||||
echo '<div class="wmf-val-stars">';
|
||||
for($i = 1; $i <= $max; $i++) {
|
||||
echo '<span style="color:' . ($i <= $stars ? '#f0b429' : '#ddd') . ';font-size:20px;">★</span>';
|
||||
}
|
||||
echo ' <span style="color:#646970;font-size:13px;">' . $stars . '/' . $max . '</span></div>';
|
||||
break;
|
||||
|
||||
case 'url':
|
||||
echo '<a href="' . esc_url($val) . '" target="_blank">' . esc_html($val) . '</a>';
|
||||
break;
|
||||
|
||||
case 'email':
|
||||
echo '<a href="mailto:' . esc_attr($val) . '">' . esc_html($val) . '</a>';
|
||||
break;
|
||||
|
||||
case 'textarea':
|
||||
echo '<div class="wmf-val-textarea">' . nl2br(esc_html($val)) . '</div>';
|
||||
break;
|
||||
|
||||
default:
|
||||
if(is_array($val)) {
|
||||
echo '<ul class="wmf-val-list">';
|
||||
foreach($val as $v) echo '<li>' . esc_html($v) . '</li>';
|
||||
echo '</ul>';
|
||||
} else {
|
||||
echo '<span class="wmf-val-text">' . esc_html($val) . '</span>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
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;
|
||||
}
|
||||
}
|
||||
158
inc/fields/class-field-base.php
Normal file
158
inc/fields/class-field-base.php
Normal file
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) exit;
|
||||
|
||||
abstract class WMF_Field_Base {
|
||||
public $type = '';
|
||||
public $label = '';
|
||||
public $icon = 'dashicons-edit';
|
||||
public $category = 'standard';
|
||||
|
||||
public function defaults() {
|
||||
return array(
|
||||
'id' => '',
|
||||
'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 ) {
|
||||
?>
|
||||
<div class="wmf-field-setting">
|
||||
<label>Bezeichnung</label>
|
||||
<input type="text" data-setting="label" value="<?php echo esc_attr($field['label']??''); ?>" class="widefat">
|
||||
</div>
|
||||
<div class="wmf-field-setting">
|
||||
<label>Feldname <span class="wmf-hint">(intern, nur a-z, 0-9, _)</span></label>
|
||||
<input type="text" data-setting="name" value="<?php echo esc_attr($field['name']??''); ?>" class="widefat wmf-slug-input">
|
||||
</div>
|
||||
<div class="wmf-field-setting">
|
||||
<label>Platzhaltertext</label>
|
||||
<input type="text" data-setting="placeholder" value="<?php echo esc_attr($field['placeholder']??''); ?>" class="widefat">
|
||||
</div>
|
||||
<div class="wmf-field-setting">
|
||||
<label>Hilfetext (unter dem Feld)</label>
|
||||
<input type="text" data-setting="description" value="<?php echo esc_attr($field['description']??''); ?>" class="widefat">
|
||||
</div>
|
||||
<div class="wmf-field-setting wmf-field-inline">
|
||||
<label><input type="checkbox" data-setting="required" value="1" <?php checked($field['required']??'0','1'); ?>> Pflichtfeld</label>
|
||||
</div>
|
||||
<div class="wmf-field-setting">
|
||||
<label>Breite</label>
|
||||
<select data-setting="width" class="widefat">
|
||||
<option value="full" <?php selected($field['width']??'full','full'); ?>>Volle Breite</option>
|
||||
<option value="half" <?php selected($field['width']??'full','half'); ?>>½ Breite</option>
|
||||
<option value="third" <?php selected($field['width']??'full','third'); ?>>⅓ Breite</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="wmf-field-setting">
|
||||
<label>CSS-Klasse</label>
|
||||
<input type="text" data-setting="css_class" value="<?php echo esc_attr($field['css_class']??''); ?>" class="widefat">
|
||||
</div>
|
||||
<hr class="wmf-settings-sep">
|
||||
<div class="wmf-field-setting">
|
||||
<label>Bedingte Logik</label>
|
||||
<select data-setting="conditional_logic" class="widefat wmf-conditional-toggle">
|
||||
<option value="0" <?php selected($field['conditional_logic']??'0','0'); ?>>Deaktiviert</option>
|
||||
<option value="1" <?php selected($field['conditional_logic']??'0','1'); ?>>Aktiviert</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="wmf-conditional-rules" style="<?php echo ($field['conditional_logic']??'0')==='1'?'':'display:none'; ?>">
|
||||
<div class="wmf-field-setting">
|
||||
<label>Dieses Feld</label>
|
||||
<select data-setting="conditional_action" class="widefat">
|
||||
<option value="show" <?php selected($field['conditional_action']??'show','show'); ?>>anzeigen</option>
|
||||
<option value="hide" <?php selected($field['conditional_action']??'show','hide'); ?>>ausblenden</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="wmf-field-setting">
|
||||
<label>wenn</label>
|
||||
<select data-setting="conditional_match" class="widefat">
|
||||
<option value="all" <?php selected($field['conditional_match']??'all','all'); ?>>alle Bedingungen erfüllt sind</option>
|
||||
<option value="any" <?php selected($field['conditional_match']??'all','any'); ?>>eine Bedingung erfüllt ist</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="wmf-conditional-rule-list" data-field-id="<?php echo esc_attr($field['id']??''); ?>">
|
||||
<?php
|
||||
$rules = $field['conditional_rules'] ?? array();
|
||||
if (empty($rules)) $rules = array(array('field'=>'','operator'=>'=','value'=>''));
|
||||
foreach($rules as $rule): ?>
|
||||
<div class="wmf-rule-row">
|
||||
<select class="wmf-rule-field" data-setting-rule="field">
|
||||
<option value="">— Feld —</option>
|
||||
</select>
|
||||
<select class="wmf-rule-op" data-setting-rule="operator">
|
||||
<option value="=" <?php selected($rule['operator']??'=','='); ?>>ist</option>
|
||||
<option value="!=" <?php selected($rule['operator']??'=','!='); ?>>ist nicht</option>
|
||||
<option value="contains" <?php selected($rule['operator']??'=','contains'); ?>>enthält</option>
|
||||
<option value="not_empty" <?php selected($rule['operator']??'=','not_empty'); ?>>ist ausgefüllt</option>
|
||||
</select>
|
||||
<input type="text" class="wmf-rule-value" data-setting-rule="value" value="<?php echo esc_attr($rule['value']??''); ?>" placeholder="Wert">
|
||||
<button type="button" class="wmf-rule-remove">✕</button>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<button type="button" class="button wmf-add-rule">+ Bedingung hinzufügen</button>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
protected function wrapper_classes( $field ) {
|
||||
$cls = array( 'wmf-field', 'wmf-field-' . $this->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') ? ' <span class="wmf-required-mark" aria-hidden="true">*</span>' : '';
|
||||
printf( '<label for="%s" class="wmf-label">%s%s</label>', esc_attr($field['id']), esc_html($field['label']), $req );
|
||||
}
|
||||
|
||||
protected function render_description( $field ) {
|
||||
if ( empty($field['description']) ) return;
|
||||
printf( '<p class="wmf-description">%s</p>', 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()))
|
||||
);
|
||||
}
|
||||
}
|
||||
23
inc/fields/class-field-checkbox.php
Normal file
23
inc/fields/class-field-checkbox.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_Checkbox extends WMF_Field_Base {
|
||||
public $type='checkbox'; public $label='Kontrollkästchen'; public $icon='dashicons-yes-alt'; public $category='auswahl';
|
||||
public function defaults() { return array_merge(parent::defaults(),array('options'=>array(array('label'=>'Option 1','value'=>'option_1')),'layout'=>'vertical')); }
|
||||
public function render($field,$value='') {
|
||||
$checked=is_array($value)?$value:($value?array($value):array()); ?>
|
||||
<div class="<?php echo esc_attr($this->wrapper_classes($field)); ?>"<?php echo $this->conditional_attrs($field); ?> data-field-id="<?php echo esc_attr($field['id']); ?>">
|
||||
<?php $this->render_label($field); ?>
|
||||
<div class="wmf-checkbox-group wmf-layout-<?php echo esc_attr($field['layout']??'vertical'); ?>">
|
||||
<?php foreach($field['options']??array() as $opt): ?>
|
||||
<label class="wmf-checkbox-label">
|
||||
<input type="checkbox" name="wmf_fields[<?php echo esc_attr($field['id']); ?>][]" value="<?php echo esc_attr($opt['value']); ?>" <?php echo in_array($opt['value'],$checked)?'checked':''; ?>>
|
||||
<span><?php echo esc_html($opt['label']); ?></span>
|
||||
</label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php $this->render_description($field); ?>
|
||||
<span class="wmf-field-error-msg"></span>
|
||||
</div><?php
|
||||
}
|
||||
public function sanitize($v,$f) { return is_array($v)?array_map('sanitize_text_field',$v):array(); }
|
||||
}
|
||||
14
inc/fields/class-field-date.php
Normal file
14
inc/fields/class-field-date.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_Date extends WMF_Field_Base {
|
||||
public $type='date'; public $label='Datum'; public $icon='dashicons-calendar-alt';
|
||||
public function defaults() { return array_merge(parent::defaults(),array('min_date'=>'','max_date'=>'')); }
|
||||
public function render($field,$value='') { ?>
|
||||
<div class="<?php echo esc_attr($this->wrapper_classes($field)); ?>"<?php echo $this->conditional_attrs($field); ?> data-field-id="<?php echo esc_attr($field['id']); ?>">
|
||||
<?php $this->render_label($field); ?>
|
||||
<input type="date" id="<?php echo esc_attr($field['id']); ?>" name="wmf_fields[<?php echo esc_attr($field['id']); ?>]" value="<?php echo esc_attr($value); ?>" <?php echo!empty($field['min_date'])?'min="'.esc_attr($field['min_date']).'"':''; ?> <?php echo!empty($field['max_date'])?'max="'.esc_attr($field['max_date']).'"':''; ?> <?php echo(!empty($field['required'])&&$field['required']==='1')?'required':''; ?> class="wmf-input">
|
||||
<?php $this->render_description($field); ?>
|
||||
<span class="wmf-field-error-msg"></span>
|
||||
</div><?php
|
||||
}
|
||||
}
|
||||
13
inc/fields/class-field-divider.php
Normal file
13
inc/fields/class-field-divider.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_Divider extends WMF_Field_Base {
|
||||
public $type='divider'; public $label='Trennlinie / Abschnitt'; public $icon='dashicons-minus'; public $category='layout';
|
||||
public function render($field,$value='') { ?>
|
||||
<div class="<?php echo esc_attr($this->wrapper_classes($field)); ?>"<?php echo $this->conditional_attrs($field); ?>>
|
||||
<?php if(!empty($field['label'])): ?><h4 class="wmf-section-title"><?php echo esc_html($field['label']); ?></h4><?php else: ?><hr class="wmf-divider"><?php endif; ?>
|
||||
<?php $this->render_description($field); ?>
|
||||
</div><?php
|
||||
}
|
||||
public function validate($v,$f) { return true; }
|
||||
public function sanitize($v,$f) { return ''; }
|
||||
}
|
||||
19
inc/fields/class-field-email.php
Normal file
19
inc/fields/class-field-email.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_Email extends WMF_Field_Base {
|
||||
public $type='email'; public $label='E-Mail'; public $icon='dashicons-email-alt';
|
||||
public function render($field,$value='') { ?>
|
||||
<div class="<?php echo esc_attr($this->wrapper_classes($field)); ?>"<?php echo $this->conditional_attrs($field); ?> data-field-id="<?php echo esc_attr($field['id']); ?>">
|
||||
<?php $this->render_label($field); ?>
|
||||
<input type="email" id="<?php echo esc_attr($field['id']); ?>" name="wmf_fields[<?php echo esc_attr($field['id']); ?>]" value="<?php echo esc_attr($value); ?>" placeholder="<?php echo esc_attr($field['placeholder']??''); ?>" <?php echo(!empty($field['required'])&&$field['required']==='1')?'required':''; ?> class="wmf-input" autocomplete="email">
|
||||
<?php $this->render_description($field); ?>
|
||||
<span class="wmf-field-error-msg"></span>
|
||||
</div><?php
|
||||
}
|
||||
public function validate($value,$field) {
|
||||
$base=parent::validate($value,$field); if($base!==true) return $base;
|
||||
if($value!==''&&!is_email($value)) return sprintf('Bitte geben Sie eine gültige E-Mail-Adresse für „%s" ein.',$field['label']);
|
||||
return true;
|
||||
}
|
||||
public function sanitize($value,$field) { return sanitize_email($value); }
|
||||
}
|
||||
64
inc/fields/class-field-file.php
Normal file
64
inc/fields/class-field-file.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_File extends WMF_Field_Base {
|
||||
public $type='file'; public $label='Datei-Upload'; public $icon='dashicons-upload';
|
||||
public function defaults() { return array_merge(parent::defaults(),array('allowed_types'=>'jpg,jpeg,png,pdf,doc,docx','max_size_mb'=>'5','multiple'=>'0','save_to_media'=>'1')); }
|
||||
public function render($field,$value='') { ?>
|
||||
<div class="<?php echo esc_attr($this->wrapper_classes($field)); ?>"<?php echo $this->conditional_attrs($field); ?> data-field-id="<?php echo esc_attr($field['id']); ?>">
|
||||
<?php $this->render_label($field); ?>
|
||||
<input type="file" id="<?php echo esc_attr($field['id']); ?>" name="wmf_files[<?php echo esc_attr($field['id']); ?>]<?php echo(!empty($field['multiple'])&&$field['multiple']==='1')?'[]':''; ?>" accept="<?php echo esc_attr($this->accept_attr($field)); ?>" <?php echo(!empty($field['multiple'])&&$field['multiple']==='1')?'multiple':''; ?> <?php echo(!empty($field['required'])&&$field['required']==='1')?'required':''; ?> class="wmf-input wmf-file-input">
|
||||
<p class="wmf-description">Erlaubt: <?php echo esc_html($field['allowed_types']??''); ?> — Max. <?php echo esc_html($field['max_size_mb']??5); ?> MB</p>
|
||||
<?php $this->render_description($field); ?>
|
||||
<span class="wmf-field-error-msg"></span>
|
||||
</div><?php
|
||||
}
|
||||
private function accept_attr($field) {
|
||||
$types=array_map('trim',explode(',',$field['allowed_types']??''));
|
||||
return implode(',',array_map(fn($t)=>'.'.$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;
|
||||
}
|
||||
}
|
||||
34
inc/fields/class-field-gdpr.php
Normal file
34
inc/fields/class-field-gdpr.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_GDPR extends WMF_Field_Base {
|
||||
public $type='gdpr'; public $label='DSGVO-Zustimmung'; public $icon='dashicons-shield'; public $category='auswahl';
|
||||
public function defaults() {
|
||||
return array_merge(parent::defaults(),array(
|
||||
'required' => '1',
|
||||
'gdpr_text' => 'Ich stimme der <a href="/datenschutz" target="_blank">Datenschutzerklärung</a> zu.',
|
||||
'error_message' => 'Bitte stimmen Sie der Datenschutzerklärung zu.',
|
||||
));
|
||||
}
|
||||
public function render($field,$value='') { ?>
|
||||
<div class="<?php echo esc_attr($this->wrapper_classes($field)); ?> wmf-gdpr-wrap"<?php echo $this->conditional_attrs($field); ?> data-field-id="<?php echo esc_attr($field['id']); ?>">
|
||||
<label class="wmf-gdpr-label">
|
||||
<input type="checkbox" name="wmf_fields[<?php echo esc_attr($field['id']); ?>]" value="1" <?php checked($value,'1'); ?> <?php echo(!empty($field['required'])&&$field['required']==='1')?'required':''; ?> class="wmf-gdpr-checkbox">
|
||||
<span class="wmf-gdpr-text"><?php echo wp_kses_post($field['gdpr_text']??''); ?></span>
|
||||
</label>
|
||||
<span class="wmf-field-error-msg"></span>
|
||||
</div><?php
|
||||
}
|
||||
public function validate($value,$field) {
|
||||
if(!empty($field['required'])&&$field['required']==='1'&&$value!=='1') {
|
||||
return $field['error_message']??'Bitte stimmen Sie der Datenschutzerklärung zu.';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public function sanitize($v,$f) { return $v==='1'?'1':'0'; }
|
||||
public function settings_panel($field) {
|
||||
parent::settings_panel($field); ?>
|
||||
<div class="wmf-field-setting"><label>DSGVO-Text (HTML erlaubt)</label><textarea data-setting="gdpr_text" class="widefat" rows="3"><?php echo esc_textarea($field['gdpr_text']??''); ?></textarea></div>
|
||||
<div class="wmf-field-setting"><label>Fehlermeldung</label><input type="text" data-setting="error_message" value="<?php echo esc_attr($field['error_message']??''); ?>" class="widefat"></div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
15
inc/fields/class-field-hidden.php
Normal file
15
inc/fields/class-field-hidden.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_Hidden extends WMF_Field_Base {
|
||||
public $type='hidden'; public $label='Verstecktes Feld'; public $icon='dashicons-hidden'; public $category='layout';
|
||||
public function defaults() { return array_merge(parent::defaults(),array('default_value'=>'')); }
|
||||
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('<input type="hidden" name="wmf_fields[%s]" value="%s">',esc_attr($field['id']),esc_attr($v));
|
||||
}
|
||||
public function validate($v,$f) { return true; }
|
||||
}
|
||||
13
inc/fields/class-field-html.php
Normal file
13
inc/fields/class-field-html.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_HTML extends WMF_Field_Base {
|
||||
public $type='html'; public $label='HTML-Block'; public $icon='dashicons-editor-code'; public $category='layout';
|
||||
public function defaults() { return array_merge(parent::defaults(),array('content'=>'')); }
|
||||
public function render($field,$value='') { ?>
|
||||
<div class="<?php echo esc_attr($this->wrapper_classes($field)); ?>"<?php echo $this->conditional_attrs($field); ?>>
|
||||
<?php echo wp_kses_post($field['content']??''); ?>
|
||||
</div><?php
|
||||
}
|
||||
public function validate($v,$f) { return true; }
|
||||
public function sanitize($v,$f) { return ''; }
|
||||
}
|
||||
15
inc/fields/class-field-number.php
Normal file
15
inc/fields/class-field-number.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_Number extends WMF_Field_Base {
|
||||
public $type='number'; public $label='Zahl'; public $icon='dashicons-calculator';
|
||||
public function defaults() { return array_merge(parent::defaults(),array('min'=>'','max'=>'','step'=>'1')); }
|
||||
public function render($field,$value='') { ?>
|
||||
<div class="<?php echo esc_attr($this->wrapper_classes($field)); ?>"<?php echo $this->conditional_attrs($field); ?> data-field-id="<?php echo esc_attr($field['id']); ?>">
|
||||
<?php $this->render_label($field); ?>
|
||||
<input type="number" id="<?php echo esc_attr($field['id']); ?>" name="wmf_fields[<?php echo esc_attr($field['id']); ?>]" value="<?php echo esc_attr($value); ?>" placeholder="<?php echo esc_attr($field['placeholder']??''); ?>" <?php echo!empty($field['min'])?'min="'.esc_attr($field['min']).'"':''; ?> <?php echo!empty($field['max'])?'max="'.esc_attr($field['max']).'"':''; ?> step="<?php echo esc_attr($field['step']??1); ?>" <?php echo(!empty($field['required'])&&$field['required']==='1')?'required':''; ?> class="wmf-input">
|
||||
<?php $this->render_description($field); ?>
|
||||
<span class="wmf-field-error-msg"></span>
|
||||
</div><?php
|
||||
}
|
||||
public function sanitize($v,$f) { return is_numeric($v)?$v+0:''; }
|
||||
}
|
||||
13
inc/fields/class-field-phone.php
Normal file
13
inc/fields/class-field-phone.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_Phone extends WMF_Field_Base {
|
||||
public $type='phone'; public $label='Telefon'; public $icon='dashicons-phone';
|
||||
public function render($field,$value='') { ?>
|
||||
<div class="<?php echo esc_attr($this->wrapper_classes($field)); ?>"<?php echo $this->conditional_attrs($field); ?> data-field-id="<?php echo esc_attr($field['id']); ?>">
|
||||
<?php $this->render_label($field); ?>
|
||||
<input type="tel" id="<?php echo esc_attr($field['id']); ?>" name="wmf_fields[<?php echo esc_attr($field['id']); ?>]" value="<?php echo esc_attr($value); ?>" placeholder="<?php echo esc_attr($field['placeholder']??''); ?>" <?php echo(!empty($field['required'])&&$field['required']==='1')?'required':''; ?> class="wmf-input" autocomplete="tel">
|
||||
<?php $this->render_description($field); ?>
|
||||
<span class="wmf-field-error-msg"></span>
|
||||
</div><?php
|
||||
}
|
||||
}
|
||||
21
inc/fields/class-field-radio.php
Normal file
21
inc/fields/class-field-radio.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_Radio extends WMF_Field_Base {
|
||||
public $type='radio'; public $label='Radio-Buttons'; public $icon='dashicons-marker'; public $category='auswahl';
|
||||
public function defaults() { return array_merge(parent::defaults(),array('options'=>array(array('label'=>'Option 1','value'=>'option_1')),'layout'=>'vertical')); }
|
||||
public function render($field,$value='') { ?>
|
||||
<div class="<?php echo esc_attr($this->wrapper_classes($field)); ?>"<?php echo $this->conditional_attrs($field); ?> data-field-id="<?php echo esc_attr($field['id']); ?>">
|
||||
<?php $this->render_label($field); ?>
|
||||
<div class="wmf-radio-group wmf-layout-<?php echo esc_attr($field['layout']??'vertical'); ?>">
|
||||
<?php foreach($field['options']??array() as $opt): ?>
|
||||
<label class="wmf-radio-label">
|
||||
<input type="radio" name="wmf_fields[<?php echo esc_attr($field['id']); ?>]" value="<?php echo esc_attr($opt['value']); ?>" <?php checked($value,$opt['value']); ?> <?php echo(!empty($field['required'])&&$field['required']==='1')?'required':''; ?>>
|
||||
<span><?php echo esc_html($opt['label']); ?></span>
|
||||
</label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php $this->render_description($field); ?>
|
||||
<span class="wmf-field-error-msg"></span>
|
||||
</div><?php
|
||||
}
|
||||
}
|
||||
20
inc/fields/class-field-range.php
Normal file
20
inc/fields/class-field-range.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_Range extends WMF_Field_Base {
|
||||
public $type='range'; public $label='Schieberegler'; public $icon='dashicons-leftright'; public $category='auswahl';
|
||||
public function defaults() { return array_merge(parent::defaults(),array('min'=>'0','max'=>'100','step'=>'1','show_value'=>'1')); }
|
||||
public function render($field,$value='') {
|
||||
$val=$value!==''?$value:($field['min']??0); ?>
|
||||
<div class="<?php echo esc_attr($this->wrapper_classes($field)); ?>"<?php echo $this->conditional_attrs($field); ?> data-field-id="<?php echo esc_attr($field['id']); ?>">
|
||||
<?php $this->render_label($field); ?>
|
||||
<div class="wmf-range-wrap">
|
||||
<input type="range" id="<?php echo esc_attr($field['id']); ?>" name="wmf_fields[<?php echo esc_attr($field['id']); ?>]" value="<?php echo esc_attr($val); ?>" min="<?php echo esc_attr($field['min']??0); ?>" max="<?php echo esc_attr($field['max']??100); ?>" step="<?php echo esc_attr($field['step']??1); ?>" class="wmf-range-input">
|
||||
<?php if(!empty($field['show_value'])&&$field['show_value']==='1'): ?>
|
||||
<span class="wmf-range-value"><?php echo esc_html($val); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php $this->render_description($field); ?>
|
||||
</div><?php
|
||||
}
|
||||
public function sanitize($v,$f) { return is_numeric($v)?$v+0:$f['min']??0; }
|
||||
}
|
||||
21
inc/fields/class-field-rating.php
Normal file
21
inc/fields/class-field-rating.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_Rating extends WMF_Field_Base {
|
||||
public $type='rating'; public $label='Bewertung (Sterne)'; public $icon='dashicons-star-filled'; public $category='auswahl';
|
||||
public function defaults() { return array_merge(parent::defaults(),array('max_stars'=>'5','icon'=>'star')); }
|
||||
public function render($field,$value='') {
|
||||
$max=intval($field['max_stars']??5); ?>
|
||||
<div class="<?php echo esc_attr($this->wrapper_classes($field)); ?>"<?php echo $this->conditional_attrs($field); ?> data-field-id="<?php echo esc_attr($field['id']); ?>">
|
||||
<?php $this->render_label($field); ?>
|
||||
<div class="wmf-rating" data-max="<?php echo $max; ?>">
|
||||
<?php for($i=1;$i<=$max;$i++): ?>
|
||||
<button type="button" class="wmf-star <?php echo $i<=intval($value)?'active':''; ?>" data-value="<?php echo $i; ?>" aria-label="<?php echo $i; ?> Stern">★</button>
|
||||
<?php endfor; ?>
|
||||
<input type="hidden" name="wmf_fields[<?php echo esc_attr($field['id']); ?>]" value="<?php echo esc_attr($value); ?>" class="wmf-rating-value">
|
||||
</div>
|
||||
<?php $this->render_description($field); ?>
|
||||
<span class="wmf-field-error-msg"></span>
|
||||
</div><?php
|
||||
}
|
||||
public function sanitize($v,$f) { return max(0,min(intval($f['max_stars']??5),intval($v))); }
|
||||
}
|
||||
23
inc/fields/class-field-select.php
Normal file
23
inc/fields/class-field-select.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_Select extends WMF_Field_Base {
|
||||
public $type='select'; public $label='Auswahlliste'; public $icon='dashicons-list-view'; public $category='auswahl';
|
||||
public function defaults() { return array_merge(parent::defaults(),array('options'=>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?'[]':''); ?>
|
||||
<div class="<?php echo esc_attr($this->wrapper_classes($field)); ?>"<?php echo $this->conditional_attrs($field); ?> data-field-id="<?php echo esc_attr($field['id']); ?>">
|
||||
<?php $this->render_label($field); ?>
|
||||
<select id="<?php echo esc_attr($field['id']); ?>" name="<?php echo $name; ?>" class="wmf-input wmf-select" <?php echo $multi?'multiple':''; ?> <?php echo(!empty($field['required'])&&$field['required']==='1')?'required':''; ?>>
|
||||
<?php if(!$multi): ?><option value=""><?php echo esc_html($field['placeholder']?:'— Bitte wählen —'); ?></option><?php endif; ?>
|
||||
<?php foreach($field['options']??array() as $opt):
|
||||
$sel=is_array($value)?in_array($opt['value'],$value):$value===$opt['value']; ?>
|
||||
<option value="<?php echo esc_attr($opt['value']); ?>" <?php echo $sel?'selected':''; ?>><?php echo esc_html($opt['label']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<?php $this->render_description($field); ?>
|
||||
<span class="wmf-field-error-msg"></span>
|
||||
</div><?php
|
||||
}
|
||||
public function sanitize($v,$f) { return is_array($v)?array_map('sanitize_text_field',$v):sanitize_text_field($v); }
|
||||
}
|
||||
28
inc/fields/class-field-signature.php
Normal file
28
inc/fields/class-field-signature.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_Signature extends WMF_Field_Base {
|
||||
public $type='signature'; public $label='Unterschrift'; public $icon='dashicons-edit-page'; public $category='auswahl';
|
||||
public function render($field,$value='') { ?>
|
||||
<div class="<?php echo esc_attr($this->wrapper_classes($field)); ?>"<?php echo $this->conditional_attrs($field); ?> data-field-id="<?php echo esc_attr($field['id']); ?>">
|
||||
<?php $this->render_label($field); ?>
|
||||
<div class="wmf-signature-wrap">
|
||||
<canvas class="wmf-signature-canvas" id="sig_<?php echo esc_attr($field['id']); ?>" width="400" height="150"></canvas>
|
||||
<div class="wmf-signature-controls">
|
||||
<button type="button" class="wmf-sig-clear button">Löschen</button>
|
||||
</div>
|
||||
<input type="hidden" name="wmf_fields[<?php echo esc_attr($field['id']); ?>]" value="<?php echo esc_attr($value); ?>" class="wmf-signature-data">
|
||||
</div>
|
||||
<?php $this->render_description($field); ?>
|
||||
<span class="wmf-field-error-msg"></span>
|
||||
</div><?php
|
||||
}
|
||||
public function validate($value,$field) {
|
||||
if(!empty($field['required'])&&$field['required']==='1'&&empty($value)) return sprintf('Bitte unterschreiben Sie im Feld „%s".',$field['label']);
|
||||
return true;
|
||||
}
|
||||
public function sanitize($v,$f) {
|
||||
// Base64 PNG-Daten erlaubt, sonst leer
|
||||
if(strpos($v,'data:image/png;base64,')===0) return sanitize_text_field($v);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
13
inc/fields/class-field-text.php
Normal file
13
inc/fields/class-field-text.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_Text extends WMF_Field_Base {
|
||||
public $type='text'; public $label='Textfeld'; public $icon='dashicons-editor-textcolor';
|
||||
public function render($field,$value='') { ?>
|
||||
<div class="<?php echo esc_attr($this->wrapper_classes($field)); ?>"<?php echo $this->conditional_attrs($field); ?> data-field-id="<?php echo esc_attr($field['id']); ?>">
|
||||
<?php $this->render_label($field); ?>
|
||||
<input type="text" id="<?php echo esc_attr($field['id']); ?>" name="wmf_fields[<?php echo esc_attr($field['id']); ?>]" value="<?php echo esc_attr($value); ?>" placeholder="<?php echo esc_attr($field['placeholder']??''); ?>" <?php echo(!empty($field['required'])&&$field['required']==='1')?'required':''; ?> class="wmf-input" autocomplete="on">
|
||||
<?php $this->render_description($field); ?>
|
||||
<span class="wmf-field-error-msg"></span>
|
||||
</div><?php
|
||||
}
|
||||
}
|
||||
22
inc/fields/class-field-textarea.php
Normal file
22
inc/fields/class-field-textarea.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_Textarea extends WMF_Field_Base {
|
||||
public $type='textarea'; public $label='Textbereich'; public $icon='dashicons-text';
|
||||
public function defaults() { return array_merge(parent::defaults(),array('rows'=>'5','max_chars'=>'')); }
|
||||
public function render($field,$value='') { ?>
|
||||
<div class="<?php echo esc_attr($this->wrapper_classes($field)); ?>"<?php echo $this->conditional_attrs($field); ?> data-field-id="<?php echo esc_attr($field['id']); ?>">
|
||||
<?php $this->render_label($field); ?>
|
||||
<textarea id="<?php echo esc_attr($field['id']); ?>" name="wmf_fields[<?php echo esc_attr($field['id']); ?>]" placeholder="<?php echo esc_attr($field['placeholder']??''); ?>" rows="<?php echo intval($field['rows']??5); ?>" <?php echo(!empty($field['required'])&&$field['required']==='1')?'required':''; ?> <?php echo(!empty($field['max_chars']))?'maxlength="'.intval($field['max_chars']).'"':''; ?> class="wmf-input wmf-textarea"><?php echo esc_textarea($value); ?></textarea>
|
||||
<?php if(!empty($field['max_chars'])): ?><div class="wmf-char-count"><span class="wmf-chars-used">0</span>/<?php echo intval($field['max_chars']); ?></div><?php endif; ?>
|
||||
<?php $this->render_description($field); ?>
|
||||
<span class="wmf-field-error-msg"></span>
|
||||
</div><?php
|
||||
}
|
||||
public function sanitize($v,$f) { return sanitize_textarea_field($v); }
|
||||
public function settings_panel($field) {
|
||||
parent::settings_panel($field); ?>
|
||||
<div class="wmf-field-setting"><label>Zeilen</label><input type="number" min="2" max="30" data-setting="rows" value="<?php echo esc_attr($field['rows']??5); ?>" class="small-text"></div>
|
||||
<div class="wmf-field-setting"><label>Max. Zeichen (0 = unbegrenzt)</label><input type="number" min="0" data-setting="max_chars" value="<?php echo esc_attr($field['max_chars']??''); ?>" class="small-text"></div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
14
inc/fields/class-field-url.php
Normal file
14
inc/fields/class-field-url.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
if (!defined('ABSPATH')) exit;
|
||||
class WMF_Field_URL extends WMF_Field_Base {
|
||||
public $type='url'; public $label='Website-URL'; public $icon='dashicons-admin-site';
|
||||
public function render($field,$value='') { ?>
|
||||
<div class="<?php echo esc_attr($this->wrapper_classes($field)); ?>"<?php echo $this->conditional_attrs($field); ?> data-field-id="<?php echo esc_attr($field['id']); ?>">
|
||||
<?php $this->render_label($field); ?>
|
||||
<input type="url" id="<?php echo esc_attr($field['id']); ?>" name="wmf_fields[<?php echo esc_attr($field['id']); ?>]" value="<?php echo esc_attr($value); ?>" placeholder="<?php echo esc_attr($field['placeholder']??'https://'); ?>" <?php echo(!empty($field['required'])&&$field['required']==='1')?'required':''; ?> class="wmf-input">
|
||||
<?php $this->render_description($field); ?>
|
||||
<span class="wmf-field-error-msg"></span>
|
||||
</div><?php
|
||||
}
|
||||
public function sanitize($v,$f) { return esc_url_raw($v); }
|
||||
}
|
||||
118
inc/helpers/helper-functions.php
Normal file
118
inc/helpers/helper-functions.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) exit;
|
||||
|
||||
function wmf_create_submissions_table() {
|
||||
global $wpdb;
|
||||
$table = $wpdb->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 '<script>window.location.href=' . wp_json_encode( $url ) . ';</script>';
|
||||
echo '<noscript><meta http-equiv="refresh" content="0;url=' . esc_attr( $url ) . '"></noscript>';
|
||||
exit;
|
||||
}
|
||||
Reference in New Issue
Block a user