Files
2026-11-08 20:09:19 +00:00

288 lines
20 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Einstellungsseite (Einstellungen → DeskHub Tickets).
*/
if (!defined('ABSPATH')) {
exit;
}
class Deskhub_Tickets_Settings
{
const PAGE = 'deskhub-tickets';
const GROUP = 'deskhub_tickets';
public static function init(): void
{
add_action('admin_menu', [__CLASS__, 'menu']);
add_action('admin_init', [__CLASS__, 'register']);
add_action('admin_post_deskhub_tickets_clear_cache', [__CLASS__, 'handle_clear_cache']);
add_filter('plugin_action_links_' . plugin_basename(DESKHUB_TICKETS_FILE), [__CLASS__, 'action_links']);
}
public static function menu(): void
{
add_options_page(
__('DeskHub Tickets', 'deskhub-tickets'),
__('DeskHub Tickets', 'deskhub-tickets'),
'manage_options',
self::PAGE,
[__CLASS__, 'render']
);
}
public static function action_links(array $links): array
{
array_unshift($links, '<a href="' . esc_url(admin_url('options-general.php?page=' . self::PAGE)) . '">' . esc_html__('Einstellungen', 'deskhub-tickets') . '</a>');
return $links;
}
public static function register(): void
{
register_setting(self::GROUP, 'deskhub_tickets_options', [
'type' => 'array',
'sanitize_callback' => [__CLASS__, 'sanitize'],
'default' => [],
]);
}
/**
* Prüft und bereinigt die abgeschickten Einstellungen. Der API-Schlüssel bleibt erhalten, wenn das Feld leer ist
* (er wird nie wieder in die Seite geschrieben).
*/
public static function sanitize($input): array
{
$input = is_array($input) ? $input : [];
$old = get_option('deskhub_tickets_options', []);
$old = array_merge(deskhub_tickets_defaults(), is_array($old) ? $old : []);
$out = deskhub_tickets_defaults();
$url = trim((string) ($input['server_url'] ?? ''));
if ($url === '') {
$out['server_url'] = '';
} else {
$norm = Deskhub_Tickets_Client::normalize_url($url);
if (is_wp_error($norm)) {
add_settings_error('deskhub_tickets_options', 'deskhub_url', $norm->get_error_message());
$out['server_url'] = (string) $old['server_url'];
} else {
$out['server_url'] = $norm;
}
}
if (!empty($input['clear_key'])) {
$out['api_key'] = '';
} else {
$key = trim((string) ($input['api_key'] ?? ''));
$key = preg_replace('/[^\x21-\x7E]/', '', $key);
$out['api_key'] = $key !== '' ? $key : (string) $old['api_key'];
}
foreach (['department_id', 'topic_id', 'priority_id'] as $f) {
$out[$f] = absint($input[$f] ?? 0);
}
$out['consent_text'] = wp_kses((string) ($input['consent_text'] ?? ''), [
'a' => ['href' => [], 'target' => [], 'rel' => []],
'strong' => [],
'em' => [],
]);
$out['attachments'] = !empty($input['attachments']) ? 1 : 0;
$accent = sanitize_hex_color((string) ($input['accent_color'] ?? ''));
$out['accent_color'] = empty($input['accent_auto']) && $accent ? $accent : '';
$out['success_text'] = mb_substr(sanitize_text_field((string) ($input['success_text'] ?? '')), 0, 500);
$out['status_page_url'] = esc_url_raw((string) ($input['status_page_url'] ?? ''));
$out['min_seconds'] = max(0, min(60, absint($input['min_seconds'] ?? 3)));
$out['rate_limit_per_hour'] = max(0, min(100, absint($input['rate_limit_per_hour'] ?? 5)));
$out['turnstile_site'] = sanitize_text_field((string) ($input['turnstile_site'] ?? ''));
$secret = trim(sanitize_text_field((string) ($input['turnstile_secret'] ?? '')));
$out['turnstile_secret'] = !empty($input['clear_turnstile']) ? '' : ($secret !== '' ? $secret : (string) $old['turnstile_secret']);
// „Speichern und Verbindung testen“: prüft gleich die Werte, die gerade gespeichert werden (nicht erst die schon gespeicherten)
if (!empty($_POST['dht_test_after']) && current_user_can('manage_options')) {
$key = deskhub_tickets_key_from_config() ? (string) DESKHUB_TICKETS_API_KEY : (string) $out['api_key'];
$url = defined('DESKHUB_TICKETS_SERVER') && DESKHUB_TICKETS_SERVER !== '' ? (string) DESKHUB_TICKETS_SERVER : (string) $out['server_url'];
$norm = Deskhub_Tickets_Client::normalize_url($url);
$result = (is_wp_error($norm) || trim($key) === '')
? ['ok' => false, 'message' => __('Bitte Server-Adresse und API-Schlüssel eintragen.', 'deskhub-tickets'), 'canRead' => false]
: (new Deskhub_Tickets_Client($norm, trim($key)))->test_connection();
set_transient('deskhub_tickets_test_' . get_current_user_id(), $result, 120);
}
return $out;
}
/** „Formulare neu laden“: leert den Zwischenspeicher der Kundenformulare aus DeskHub. */
public static function handle_clear_cache(): void
{
if (!current_user_can('manage_options')) {
wp_die(esc_html__('Dafür fehlt die Berechtigung.', 'deskhub-tickets'), '', ['response' => 403]);
}
check_admin_referer('deskhub_tickets_clear_cache');
Deskhub_Tickets_Client::clear_form_cache();
set_transient('deskhub_tickets_test_' . get_current_user_id(), ['ok' => true, 'message' => __('Die Formulare werden beim nächsten Aufruf neu aus DeskHub geladen.', 'deskhub-tickets'), 'canRead' => true], 120);
wp_safe_redirect(admin_url('options-general.php?page=' . self::PAGE . '&dht_tested=1'));
exit;
}
public static function render(): void
{
if (!current_user_can('manage_options')) {
return;
} $o = deskhub_tickets_options();
$name = 'deskhub_tickets_options';
$keyFromConfig = deskhub_tickets_key_from_config();
$hasKey = trim((string) $o['api_key']) !== '';
$hasSecret = trim((string) $o['turnstile_secret']) !== '';
$topicList = [];
$cl = Deskhub_Tickets_Client::from_settings();
if ($cl) {
$tl = $cl->get_topics();
$topicList = is_array($tl) ? $tl : [];
}
$tk = 'deskhub_tickets_test_' . get_current_user_id();
$test = get_transient($tk); // Ergebnis von „Speichern und Verbindung testen“ bzw. „Formulare neu laden“ (wird nur einmal gezeigt)
delete_transient($tk);
?>
<div class="wrap">
<h1><?php echo esc_html__('DeskHub Tickets', 'deskhub-tickets'); ?></h1>
<p><?php echo esc_html__('Verbindet WordPress mit Ihrem DeskHub-Helpdesk: Besucher legen Tickets über ein Formular an und können den Stand abfragen.', 'deskhub-tickets'); ?></p>
<?php if (is_array($test)): ?>
<div class="notice <?php echo !empty($test['ok']) ? 'notice-success' : 'notice-error'; ?>"><p><?php echo esc_html((string) $test['message']); ?></p></div>
<?php endif; ?>
<?php settings_errors('deskhub_tickets_options'); ?>
<form method="post" action="options.php">
<?php settings_fields(self::GROUP); ?>
<h2><?php echo esc_html__('Verbindung', 'deskhub-tickets'); ?></h2>
<table class="form-table" role="presentation">
<tr>
<th scope="row"><label for="dht_server"><?php echo esc_html__('Adresse des DeskHub-Servers', 'deskhub-tickets'); ?></label></th>
<td>
<input type="text" id="dht_server" class="regular-text" name="<?php echo esc_attr($name); ?>[server_url]" value="<?php echo esc_attr((string) $o['server_url']); ?>" placeholder="https://support.example.de" autocomplete="off">
<p class="description"><?php echo esc_html__('Die Adresse, unter der Ihr DeskHub erreichbar ist. Nur https (http nur für lokale Tests).', 'deskhub-tickets'); ?></p>
</td>
</tr>
<tr>
<th scope="row"><label for="dht_key"><?php echo esc_html__('API-Schlüssel', 'deskhub-tickets'); ?></label></th>
<td>
<?php if ($keyFromConfig): ?>
<input type="text" class="regular-text" value="<?php echo esc_attr__('aus der wp-config.php', 'deskhub-tickets'); ?>" disabled>
<?php else: ?>
<input type="password" id="dht_key" class="regular-text" name="<?php echo esc_attr($name); ?>[api_key]" value="" autocomplete="new-password" placeholder="<?php echo $hasKey ? esc_attr__('gespeichert, zum Ändern neuen Schlüssel eintragen', 'deskhub-tickets') : 'dh_…'; ?>">
<?php if ($hasKey): ?>
<label style="margin-left:8px"><input type="checkbox" name="<?php echo esc_attr($name); ?>[clear_key]" value="1"> <?php echo esc_html__('Schlüssel entfernen', 'deskhub-tickets'); ?></label>
<?php endif; ?>
<?php endif; ?>
<p class="description"><?php echo wp_kses(
__('In DeskHub unter <strong>Verwalten → API-Schlüssel</strong> einen Schlüssel erstellen. Er braucht das Recht „Tickets anlegen“, für die Statusabfrage zusätzlich „Tickets lesen“. Sicherer: den Schlüssel in der <code>wp-config.php</code> eintragen: <code>define(\'DESKHUB_TICKETS_API_KEY\', \'dh_…\');</code>', 'deskhub-tickets'),
['strong' => [], 'code' => []]
); ?></p>
</td>
</tr>
</table>
<h2><?php echo esc_html__('Ticket-Voreinstellungen', 'deskhub-tickets'); ?></h2>
<table class="form-table" role="presentation">
<tr>
<th scope="row"><?php echo esc_html__('Nummern in DeskHub', 'deskhub-tickets'); ?></th>
<td>
<label><?php echo esc_html__('Abteilung', 'deskhub-tickets'); ?> <input type="number" min="0" class="small-text" name="<?php echo esc_attr($name); ?>[department_id]" value="<?php echo esc_attr((string) (int) $o['department_id']); ?>"></label>
<label style="margin-left:12px"><?php echo esc_html__('Hilfethema', 'deskhub-tickets'); ?> <?php if ($topicList): ?>
<select name="<?php echo esc_attr($name); ?>[topic_id]">
<option value="0"><?php echo esc_html__('DeskHub entscheidet', 'deskhub-tickets'); ?></option>
<?php foreach ($topicList as $tp): ?><option value="<?php echo (int) $tp['id']; ?>" <?php selected((int) $o['topic_id'], (int) $tp['id']); ?>><?php echo esc_html((string) $tp['path']); ?> (<?php echo (int) $tp['id']; ?>)</option><?php endforeach; ?>
</select>
<?php else: ?><input type="number" min="0" class="small-text" name="<?php echo esc_attr($name); ?>[topic_id]" value="<?php echo esc_attr((string) (int) $o['topic_id']); ?>"><?php endif; ?></label>
<label style="margin-left:12px"><?php echo esc_html__('Priorität', 'deskhub-tickets'); ?> <input type="number" min="0" class="small-text" name="<?php echo esc_attr($name); ?>[priority_id]" value="<?php echo esc_attr((string) (int) $o['priority_id']); ?>"></label>
<p class="description"><?php echo esc_html__('Die Nummern stehen in DeskHub bei der jeweiligen Abteilung, dem Hilfethema und der Priorität. 0 = DeskHub entscheidet (Standardabteilung, Regeln des Hilfethemas). Im Shortcode lassen sich die Werte je Formular überschreiben.', 'deskhub-tickets'); ?></p>
</td>
</tr>
</table>
<h2><?php echo esc_html__('Formular', 'deskhub-tickets'); ?></h2>
<table class="form-table" role="presentation">
<tr>
<th scope="row"><label for="dht_consent"><?php echo esc_html__('Einwilligung (Datenschutz)', 'deskhub-tickets'); ?></label></th>
<td>
<textarea id="dht_consent" class="large-text" rows="3" name="<?php echo esc_attr($name); ?>[consent_text]" placeholder="<?php echo esc_attr__('Ich habe die <a href="/datenschutz">Datenschutzerklärung</a> gelesen und bin mit der Verarbeitung meiner Angaben einverstanden.', 'deskhub-tickets'); ?>"><?php echo esc_textarea((string) $o['consent_text']); ?></textarea>
<p class="description"><?php echo esc_html__('Wenn ausgefüllt, muss der Besucher dieses Kästchen anhaken. Erlaubt sind Links (a), fett und kursiv.', 'deskhub-tickets'); ?></p>
</td>
</tr>
<tr>
<th scope="row"><?php echo esc_html__('Dateianhänge', 'deskhub-tickets'); ?></th>
<td>
<label><input type="checkbox" name="<?php echo esc_attr($name); ?>[attachments]" value="1" <?php checked(!empty($o['attachments'])); ?>> <?php echo esc_html__('Besucher dürfen Dateien anhängen', 'deskhub-tickets'); ?></label>
<p class="description"><?php echo esc_html__('Erlaubte Dateitypen und Größen bestimmt DeskHub (Einstellungen → Uploads): höchstens 5 Dateien, zusammen 10 MB. Braucht DeskHub 1.0.67 oder neuer, sonst bleibt das Feld unsichtbar.', 'deskhub-tickets'); ?></p>
</td>
</tr>
<tr>
<th scope="row"><label for="dht_accent"><?php echo esc_html__('Akzentfarbe', 'deskhub-tickets'); ?></label></th>
<td>
<input type="color" id="dht_accent" name="<?php echo esc_attr($name); ?>[accent_color]" value="<?php echo esc_attr((string) $o['accent_color'] !== '' ? (string) $o['accent_color'] : '#0f6f6a'); ?>">
<label><input type="checkbox" name="<?php echo esc_attr($name); ?>[accent_auto]" value="1" <?php checked((string) $o['accent_color'] === ''); ?>> <?php echo esc_html__('Automatisch vom Theme übernehmen', 'deskhub-tickets'); ?></label>
<p class="description"><?php echo esc_html__('Schrift, Hintergrund und Rahmen übernimmt das Formular immer vom Theme. Die Akzentfarbe (Knopf, Hervorhebung) wird automatisch aus Knöpfen und Links der Seite gelesen; hier lässt sie sich fest vorgeben.', 'deskhub-tickets'); ?></p>
</td>
</tr>
<tr>
<th scope="row"><label for="dht_success"><?php echo esc_html__('Text nach dem Absenden', 'deskhub-tickets'); ?></label></th>
<td>
<input type="text" id="dht_success" class="large-text" name="<?php echo esc_attr($name); ?>[success_text]" value="<?php echo esc_attr((string) $o['success_text']); ?>" placeholder="<?php echo esc_attr__('Vielen Dank! Wir melden uns so schnell wie möglich per E-Mail.', 'deskhub-tickets'); ?>">
<p class="description"><?php echo esc_html__('Die Ticketnummer wird automatisch darunter angezeigt.', 'deskhub-tickets'); ?></p>
</td>
</tr>
<tr>
<th scope="row"><label for="dht_status_url"><?php echo esc_html__('Seite mit der Statusabfrage', 'deskhub-tickets'); ?></label></th>
<td>
<input type="url" id="dht_status_url" class="regular-text" name="<?php echo esc_attr($name); ?>[status_page_url]" value="<?php echo esc_attr((string) $o['status_page_url']); ?>" placeholder="https://ihre-seite.de/ticket-status">
<p class="description"><?php echo esc_html__('Optional: Nach dem Absenden erscheint ein Link „Stand abfragen“ zu dieser Seite (dort steht der Shortcode [deskhub_status]).', 'deskhub-tickets'); ?></p>
</td>
</tr>
</table>
<h2><?php echo esc_html__('Spamschutz', 'deskhub-tickets'); ?></h2>
<table class="form-table" role="presentation">
<tr>
<th scope="row"><?php echo esc_html__('Eingebaut', 'deskhub-tickets'); ?></th>
<td>
<label><?php echo esc_html__('Mindestzeit bis zum Absenden', 'deskhub-tickets'); ?> <input type="number" min="0" max="60" class="small-text" name="<?php echo esc_attr($name); ?>[min_seconds]" value="<?php echo esc_attr((string) (int) $o['min_seconds']); ?>"> <?php echo esc_html__('Sekunden', 'deskhub-tickets'); ?></label><br>
<label><?php echo esc_html__('Höchstens', 'deskhub-tickets'); ?> <input type="number" min="0" max="100" class="small-text" name="<?php echo esc_attr($name); ?>[rate_limit_per_hour]" value="<?php echo esc_attr((string) (int) $o['rate_limit_per_hour']); ?>"> <?php echo esc_html__('Tickets je Besucher und Stunde (0 = unbegrenzt)', 'deskhub-tickets'); ?></label>
<p class="description"><?php echo esc_html__('Dazu kommt ein unsichtbares Feld, das nur Roboter ausfüllen. Das Formular funktioniert auch mit Seiten-Cache.', 'deskhub-tickets'); ?></p>
</td>
</tr>
<tr>
<th scope="row"><?php echo esc_html__('Cloudflare Turnstile (optional)', 'deskhub-tickets'); ?></th>
<td>
<input type="text" class="regular-text" name="<?php echo esc_attr($name); ?>[turnstile_site]" value="<?php echo esc_attr((string) $o['turnstile_site']); ?>" placeholder="<?php echo esc_attr__('Website-Schlüssel (Site Key)', 'deskhub-tickets'); ?>" autocomplete="off"><br>
<input type="password" class="regular-text" style="margin-top:6px" name="<?php echo esc_attr($name); ?>[turnstile_secret]" value="" placeholder="<?php echo $hasSecret ? esc_attr__('Geheimer Schlüssel gespeichert', 'deskhub-tickets') : esc_attr__('Geheimer Schlüssel (Secret Key)', 'deskhub-tickets'); ?>" autocomplete="new-password">
<?php if ($hasSecret): ?><label style="margin-left:8px"><input type="checkbox" name="<?php echo esc_attr($name); ?>[clear_turnstile]" value="1"> <?php echo esc_html__('entfernen', 'deskhub-tickets'); ?></label><?php endif; ?>
<p class="description"><?php echo esc_html__('Ein kostenloses Captcha ohne Rätsel. Beide Schlüssel eintragen, dann erscheint es im Formular. Dabei wird eine Verbindung zu Cloudflare aufgebaut: Das gehört in Ihre Datenschutzerklärung.', 'deskhub-tickets'); ?></p>
</td>
</tr>
</table>
<p class="submit">
<button type="submit" name="submit" class="button button-primary" value="1"><?php echo esc_html__('Speichern', 'deskhub-tickets'); ?></button>
<button type="submit" name="dht_test_after" class="button" value="1"><?php echo esc_html__('Speichern und Verbindung testen', 'deskhub-tickets'); ?></button>
<span class="description" style="margin-left:8px"><?php echo esc_html__('Der Test legt kein Ticket an.', 'deskhub-tickets'); ?></span>
</p>
</form>
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" style="margin:-8px 0 24px">
<input type="hidden" name="action" value="deskhub_tickets_clear_cache">
<?php wp_nonce_field('deskhub_tickets_clear_cache'); ?>
<button type="submit" class="button"><?php echo esc_html__('Formulare neu laden', 'deskhub-tickets'); ?></button>
<span class="description"><?php echo esc_html__('Eigene Felder und Texte kommen aus DeskHub und werden 5 Minuten gemerkt. Nach einer Änderung dort hier neu laden.', 'deskhub-tickets'); ?></span>
</form>
<h2><?php echo esc_html__('So binden Sie es ein', 'deskhub-tickets'); ?></h2>
<p><?php echo esc_html__('Die Shortcodes funktionieren in Seiten und Beiträgen (im Block-Editor mit dem Block „Shortcode“).', 'deskhub-tickets'); ?></p>
<ul style="list-style:disc;margin-left:22px">
<li><code>[deskhub_ticket]</code> – <?php echo esc_html__('Formular zum Anlegen eines Tickets', 'deskhub-tickets'); ?></li>
<li><code>[deskhub_ticket department="2" topic="5" priority="1"]</code> – <?php echo esc_html__('mit festen Voreinstellungen für dieses Formular', 'deskhub-tickets'); ?></li>
<li><code>[deskhub_ticket topics="Rechnung:3,Technik:4"]</code> – <?php echo esc_html__('Besucher wählen ein Thema aus (Bezeichnung:Nummer des Hilfethemas)', 'deskhub-tickets'); ?></li>
<li><code>[deskhub_status]</code> – <?php echo esc_html__('Statusabfrage mit Ticketnummer und E-Mail-Adresse', 'deskhub-tickets'); ?></li>
</ul>
</div>
<?php
}
}