482 lines
25 KiB
PHP
482 lines
25 KiB
PHP
<?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;
|
|
}
|
|
}
|