Files
WP-Multi-Formular/inc/classes/class-admin.php
2026-04-13 18:52:46 +02:00

349 lines
18 KiB
PHP

<?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">&larr; 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;
}
}