From 2a7042bb4e1dfac7f9aa05c63de26d4d9ba2c15b Mon Sep 17 00:00:00 2001 From: M_Viper Date: Tue, 15 Apr 2025 18:41:59 +0000 Subject: [PATCH] wp-multi.php aktualisiert --- wp-multi.php | 1529 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 968 insertions(+), 561 deletions(-) diff --git a/wp-multi.php b/wp-multi.php index e3139cb..62631d0 100644 --- a/wp-multi.php +++ b/wp-multi.php @@ -3,7 +3,7 @@ * Plugin Name: WP Multi * Plugin URI: https://git.viper.ipv64.net/M_Viper/wp-multi * Description: Erweiterter Anti-Spam-Schutz mit Honeypot, Keyword-Filter, Link-Limit und mehr. Jetzt mit Statistik im Dashboard und HappyForms-Integration. - * Version: 2.9 + * Version: 3.0 * Author: M_Viper * Author URI: https://m-viper.de * Requires at least: 6.7.2 @@ -60,10 +60,6 @@ if (wp_multi_check_dependency()) { } - - - - /* * Admin - Panel Banner */ @@ -421,14 +417,19 @@ add_action( 'wp_login', 'wp_multi_block_login_if_disabled', 10, 2 ); /* -* Auto Tag -*/ + * Verbessertes Auto-Tag-Plugin mit optimierter Sicherheit, Performance und Benutzerfreundlichkeit + */ +define('WP_MULTI_AUTO_TAGS_OPTION', 'wp_multi_custom_stopwords'); +define('WP_MULTI_AUTO_TAGS_QUEUE', 'wp_multi_auto_tags_queue'); +define('WP_MULTI_AUTO_TAGS_NONCE', 'wp_multi_auto_tags_nonce'); - -// Automatische Tags zu Beiträgen hinzufügen +/** + * Fügt automatische Tags zu einem Beitrag hinzu. + * + * @param int $post_id ID des Beitrags. + */ function wp_multi_auto_add_tags($post_id) { - // Prüfe nur den Post-Typ, da wp_is_post_revision redundant ist if (get_post_type($post_id) !== 'post') { return; } @@ -440,33 +441,19 @@ function wp_multi_auto_add_tags($post_id) { $post = get_post($post_id); if (!$post) { - return; // Sicherheitsprüfung, falls der Beitrag nicht existiert + error_log("WP Multi Auto Tags: Beitrag $post_id nicht gefunden."); + return; } $content = strip_tags($post->post_content); - $content = strtolower($content); + $content = mb_strtolower($content, 'UTF-8'); - // Stopwörter aus der Admin-Eingabe holen - $custom_stopwords = get_option('wp_multi_custom_stopwords', ''); - $custom_stopwords = array_filter(array_map('trim', explode(',', $custom_stopwords))); - - // Standard-Stopwörter - $default_stopwords = [ - 'und', 'oder', 'ein', 'eine', 'der', 'die', 'das', 'in', 'mit', 'auf', 'zu', 'von', - 'für', 'ist', 'es', 'im', 'an', 'am', 'bei', 'auch', 'aber', 'so', 'dass', 'kann', - 'wenn', 'wie', 'wir', 'man', 'nur', 'nicht', 'mehr', 'als', 'sein', 'wurde', 'werden', - 'hat', 'haben', 'schon', 'doch', 'denn', 'diese', 'dieser', 'dieses', 'nach', 'sehr', 'allgemein' - ]; - - // Alle Stopwörter kombinieren - $stopwords = array_merge($default_stopwords, $custom_stopwords); - - // Wörter mit mindestens 4 Buchstaben extrahieren - preg_match_all('/\b[a-zäöüß]{4,}\b/u', $content, $matches); - $words = array_unique(array_diff($matches[0], $stopwords)); + // Stopwörter laden + $stopwords = wp_multi_get_stopwords(); + $words = wp_multi_extract_words($content, $stopwords); if (empty($words)) { - return; // Keine Tags, wenn keine Wörter übrig sind + return; } $word_counts = array_count_values($words); @@ -474,11 +461,53 @@ function wp_multi_auto_add_tags($post_id) { $top_tags = array_slice(array_keys($word_counts), 0, 5); if (!empty($top_tags)) { - wp_set_post_tags($post_id, implode(',', $top_tags), true); + wp_set_post_tags($post_id, $top_tags, true); } } -// Menüeintrag für Automatische Tags +/** + * Extrahiert relevante Wörter aus dem Inhalt. + * + * @param string $content Der Inhalt des Beitrags. + * @param array $stopwords Liste der Stopwörter. + * @return array Liste der extrahierten Wörter. + */ +function wp_multi_extract_words($content, $stopwords) { + preg_match_all('/\b[a-zäöüß]{4,}\b/u', $content, $matches); + return array_unique(array_diff($matches[0], $stopwords)); +} + +/** + * Lädt die kombinierten Stopwörter (Standard + benutzerdefiniert). + * + * @return array Liste der Stopwörter. + */ +function wp_multi_get_stopwords() { + $cache_key = 'wp_multi_stopwords'; + $stopwords = get_transient($cache_key); + + if ($stopwords !== false) { + return $stopwords; + } + + $custom_stopwords = get_option(WP_MULTI_AUTO_TAGS_OPTION, ''); + $custom_stopwords = array_filter(array_map('trim', explode(',', sanitize_text_field($custom_stopwords)))); + + $default_stopwords = [ + 'und', 'oder', 'ein', 'eine', 'der', 'die', 'das', 'in', 'mit', 'auf', 'zu', 'von', + 'für', 'ist', 'es', 'im', 'an', 'am', 'bei', 'auch', 'aber', 'so', 'dass', 'kann', + 'wenn', 'wie', 'wir', 'man', 'nur', 'nicht', 'mehr', 'als', 'sein', 'wurde', 'werden', + 'hat', 'haben', 'schon', 'doch', 'denn', 'diese', 'dieser', 'dieses', 'nach', 'sehr', 'allgemein' + ]; + + $stopwords = array_merge($default_stopwords, $custom_stopwords); + set_transient($cache_key, $stopwords, DAY_IN_SECONDS); + return $stopwords; +} + +/** + * Fügt das Admin-Menü für automatische Tags hinzu. + */ function wp_multi_admin_menu() { add_submenu_page( 'edit.php', @@ -491,45 +520,47 @@ function wp_multi_admin_menu() { } add_action('admin_menu', 'wp_multi_admin_menu'); -// Menüseite mit Banner & schöner Progress Bar +/** + * Rendert die Admin-Seite für automatische Tags. + */ function wp_multi_auto_tags_page() { + if (!current_user_can('manage_options')) { + wp_die(__('Zugriff verweigert.', 'wp-multi')); + } + ?>
-
M_Viper Logo -

+

-

+

-
- +
+
- +

-

+

- - +
0%
-

admin_url('admin-ajax.php'), - 'nonce' => wp_create_nonce('wp_multi_auto_tags_nonce') + 'nonce' => wp_create_nonce(WP_MULTI_AUTO_TAGS_NONCE), + 'messages' => [ + 'processing' => __('Wird verarbeitet...', 'wp-multi'), + 'run' => __('Jetzt ausführen', 'wp-multi'), + 'loading' => __('Lade...', 'wp-multi'), + 'no_posts' => __('Keine Beiträge gefunden.', 'wp-multi'), + 'success' => __('Automatische Tags erfolgreich hinzugefügt!', 'wp-multi'), + 'error' => __('Fehler bei der Verarbeitung.', 'wp-multi'), + 'start_error' => __('Fehler beim Starten der Verarbeitung.', 'wp-multi'), + ], ]); ?> - - - - - - - - - - - - - - - $row) : ?> - - - - - - - - - - - - - - -
user_id); ?>action); ?> - post_id) { - $post_title = get_the_title($row->post_id); - echo esc_html($post_title ? $post_title : 'Kein Titel verfügbar'); - } else { - echo 'Kein Beitrag'; - } - ?> - post_id); ?>timestamp); ?>
- - get_results( + $wpdb->prepare( + "SELECT DATE(timestamp) AS date, action, post_id, COUNT(*) AS count, user_id, timestamp + FROM " . WP_MULTI_ANALYTICS_TABLE . " + WHERE timestamp >= %s + GROUP BY date, action, post_id, user_id, timestamp + ORDER BY date ASC", + date('Y-m-d H:i:s', strtotime($date_query)) + ) + ); } -// Funktion, um die Analytics-Daten zu holen (Datum und Anzahl der Aktivitäten) -function wp_multi_get_analytics_data() { - global $wpdb; - $table_name = $wpdb->prefix . 'wp_multi_user_analytics'; - - // Die letzten 7 Tage abrufen - $results = $wpdb->get_results(" - SELECT DATE(timestamp) AS date, action, post_id, COUNT(*) AS count, user_id, timestamp - FROM $table_name - WHERE timestamp >= CURDATE() - INTERVAL 7 DAY - GROUP BY date, action, post_id, user_id, timestamp - ORDER BY date ASC - "); - - // Daten für das Diagramm und die Tabelle organisieren - $dates = array(); - $comment_counts = array(); - $view_counts = array(); - $post_titles = array(); +/** + * Verarbeitet rohe Analytics-Daten für Diagramm und Tabelle. + * + * @param array $results Rohe Analytics-Daten. + * @return array Verarbeitete Daten. + */ +function wp_multi_process_analytics_data($results) { + $dates = []; + $comment_counts = []; + $view_counts = []; foreach ($results as $result) { - $dates[] = $result->date; - if ($result->action == 'comment') { - $comment_counts[$result->date] = $result->count; - } elseif ($result->action == 'view') { - $view_counts[$result->date] = $result->count; + $date = $result->date; + if (!in_array($date, $dates)) { + $dates[] = $date; } - - // Hinzufügen der Post-Titel für die Anzeige - if (!empty($result->post_id)) { - $post_titles[$result->post_id] = get_the_title($result->post_id); + if ($result->action === 'comment') { + $comment_counts[$date] = ($comment_counts[$date] ?? 0) + $result->count; + } elseif ($result->action === 'view') { + $view_counts[$date] = ($view_counts[$date] ?? 0) + $result->count; } } - // Sicherstellen, dass alle Daten für die letzten 7 Tage vorhanden sind - $unique_dates = array_unique($dates); - $all_dates = array(); - $datasets = array( - 'comments' => [], - 'views' => [] - ); + $all_dates = []; + $datasets = ['comments' => [], 'views' => []]; for ($i = 6; $i >= 0; $i--) { $date = date('Y-m-d', strtotime("-$i day")); $all_dates[] = $date; - $datasets['comments'][] = isset($comment_counts[$date]) ? $comment_counts[$date] : 0; - $datasets['views'][] = isset($view_counts[$date]) ? $view_counts[$date] : 0; + $datasets['comments'][] = $comment_counts[$date] ?? 0; + $datasets['views'][] = $view_counts[$date] ?? 0; } - // Rückgabe der Daten für das Diagramm und die Tabelle return [ 'dates' => array_reverse($all_dates), 'datasets' => [ [ - 'label' => 'Kommentare', + 'label' => __('Kommentare', 'wp-multi'), 'data' => array_reverse($datasets['comments']), 'borderColor' => 'rgba(75, 192, 192, 1)', 'borderWidth' => 1, 'fill' => false, ], [ - 'label' => 'Beitragsaufrufe', + 'label' => __('Beitragsaufrufe', 'wp-multi'), 'data' => array_reverse($datasets['views']), 'borderColor' => 'rgba(153, 102, 255, 1)', 'borderWidth' => 1, @@ -1796,66 +1859,211 @@ function wp_multi_get_analytics_data() { ]; } -// Hinzufügen der Analytics-Seite unter "Benutzer" im Admin-Menü +/** + * Ruft Analytics-Daten mit Caching ab. + * + * @param string $date_query Datum für die Abfrage. + * @return array Analytics-Daten. + */ +function wp_multi_get_analytics_data($date_query = 'CURDATE() - INTERVAL 7 DAY') { + $cache_key = 'wp_multi_analytics_data_' . md5($date_query); + $cached_data = get_transient($cache_key); + + if ($cached_data !== false) { + return $cached_data; + } + + $results = wp_multi_fetch_raw_analytics($date_query); + $data = wp_multi_process_analytics_data($results); + + set_transient($cache_key, $data, HOUR_IN_SECONDS); + return $data; +} + +/** + * Zeigt die Benutzer-Analytics-Seite im Admin-Bereich an. + */ +function wp_multi_display_user_analytics() { + global $wpdb; + + if (!$wpdb->get_var("SHOW TABLES LIKE '" . WP_MULTI_ANALYTICS_TABLE . "'")) { + echo '

' . esc_html__('Die Analytics-Tabelle existiert nicht. Bitte aktiviere das Plugin erneut.', 'wp-multi') . '

'; + return; + } + + $time_range = isset($_GET['time_range']) ? sanitize_text_field($_GET['time_range']) : '7days'; + $date_query = 'CURDATE() - INTERVAL 7 DAY'; + if ($time_range === '30days') { + $date_query = 'CURDATE() - INTERVAL 30 DAY'; + } elseif ($time_range === 'custom' && isset($_GET['start_date'], $_GET['end_date'])) { + $start_date = sanitize_text_field($_GET['start_date']); + $end_date = sanitize_text_field($_GET['end_date']); + $date_query = "$start_date AND $end_date"; + } + + $results = wp_multi_get_analytics_data($date_query); + + ?> +
+
+ Logo +

+
+ +
+ + + + + + + +
+ + +

+ + + + + + + + + + + + + + + + + $row) : ?> + + + + + + + + + +
user_id); ?>action); ?> + post_id) { + $post_title = get_the_title($row->post_id); + echo esc_html($post_title ?: __('Kein Titel verfügbar', 'wp-multi')); + } else { + echo esc_html__('Kein Beitrag', 'wp-multi'); + } + ?> + post_id ?: '-'); ?>timestamp); ?>
+ +
+ '1', + 'email' => '1', + 'url' => '1', + 'swear' => '1', + 'ip' => '1', + 'allowed_urls' => '', + 'allowed_words' => '', // Neue Option für erlaubte Wörter + 'filter_strength' => 'moderate', // Neue Option für Filterstärke + ]; - register_setting('wp_multi_filter_options_group', 'wp_multi_filter_phone'); - register_setting('wp_multi_filter_options_group', 'wp_multi_filter_email'); - register_setting('wp_multi_filter_options_group', 'wp_multi_filter_url'); - register_setting('wp_multi_filter_options_group', 'wp_multi_filter_swear'); - register_setting('wp_multi_filter_options_group', 'wp_multi_filter_ip'); - register_setting('wp_multi_filter_options_group', 'wp_multi_allowed_urls'); // NEU + foreach ($options as $key => $default) { + add_option(WP_MULTI_FILTER_OPTION_PREFIX . $key, $default); + register_setting('wp_multi_filter_options_group', WP_MULTI_FILTER_OPTION_PREFIX . $key, [ + 'sanitize_callback' => $key === 'allowed_urls' || $key === 'allowed_words' ? 'sanitize_textarea_field' : 'sanitize_text_field', + ]); + } } add_action('admin_init', 'wp_multi_register_comment_filter_settings'); -// Admin-Menü & Untermenü hinzufügen +/** + * Fügt das Admin-Menü für den Kommentar-Filter hinzu. + */ function wp_multi_create_menu() { add_submenu_page( 'users.php', - 'Benutzer sperren', - 'Benutzer sperren', - 'manage_options', - 'wp-multi-blocked-users', + __('Benutzer sperren', 'wp-multi'), + __('Benutzer sperren', 'wp-multi'), + 'manage_options', + 'wp-multi-blocked-users', 'wp_multi_blocked_users_page' ); add_submenu_page( 'edit-comments.php', - 'Kommentar-Filter Einstellungen', - 'Kommentar-Filter', - 'manage_options', - 'wp-multi-comment-filter-settings', + __('Kommentar-Filter Einstellungen', 'wp-multi'), + __('Kommentar-Filter', 'wp-multi'), + 'manage_options', + 'wp-multi-comment-filter-settings', 'wp_multi_comment_filter_settings_page' ); } add_action('admin_menu', 'wp_multi_create_menu'); -// Admin-Seite für Kommentar-Filter +/** + * Rendert die Admin-Seite für Kommentar-Filter-Einstellungen. + */ function wp_multi_comment_filter_settings_page() { ?>
@@ -1863,38 +2071,61 @@ function wp_multi_comment_filter_settings_page() {
-

Kommentar-Filter Einstellungen

- +

+
- - - - - - - - - - - - - - + + + - + + + + + + + + + + + + + + + + + + + + + + + + +
>
>
>
>
>
>
>
>
>
>
- -

Trenne mehrere URLs mit einem Komma. Es wird automatisch http:// und www. entfernt, bevor die URL überprüft wird.

+ +

+
+ +

+
+ +

- + 5]); + if (!is_wp_error($response)) { + $json_content = wp_remote_retrieve_body($response); + $decoded_data = json_decode($json_content, true); + if (json_last_error() === JSON_ERROR_NONE && isset($decoded_data['words']) && is_array($decoded_data['words'])) { + $swear_words = array_map('strtolower', $decoded_data['words']); + set_transient(WP_MULTI_SWEAR_WORDS_CACHE_KEY, $swear_words, DAY_IN_SECONDS); + } else { + error_log('WP Multi Filter: Fehler beim Dekodieren der Schimpfwort-JSON-Datei.'); + } + } else { + error_log('WP Multi Filter: Fehler beim Abrufen der Schimpfwort-Liste: ' . $response->get_error_message()); + } + + // Fallback: Standard-Schimpfwörter, falls die externe Liste nicht verfügbar ist + if (empty($swear_words)) { + $swear_words = ['beispielwort1', 'beispielwort2']; // Ersetze durch echte Fallback-Wörter + } + + return $swear_words; +} + +/** + * Filtert Schimpfwörter basierend auf der Filterstärke. + * + * @param string $content Kommentarinhalt. + * @param array $swear_words Schimpfwörter. + * @param array $allowed_words Erlaubte Wörter. + * @param string $strength Filterstärke. + * @return string Gefilterter Inhalt. + */ +function wp_multi_filter_swear_words($content, $swear_words, $allowed_words, $strength) { + if (empty($swear_words)) { + return $content; + } + + foreach ($swear_words as $word) { + if (in_array(strtolower($word), $allowed_words)) { + continue; + } + + $pattern = ($strength === 'loose') + ? '/\b' . preg_quote($word, '/') . '\b/iu' + : '/\b' . preg_quote($word, '/') . '[a-z0-9]*\b/iu'; + + if ($strength === 'moderate') { $pattern = '/\b' . preg_quote($word, '/') . '\b/iu'; - $replacement = str_repeat('*', mb_strlen($word)); - $comment_content = preg_replace($pattern, $replacement, $comment_content); } + + $replacement = str_repeat('*', mb_strlen($word)); + $content = preg_replace($pattern, $replacement, $content); } - if (get_option('wp_multi_filter_phone') == 1) { + return $content; +} + +/** + * Filtert Kommentarinhalte basierend auf den Einstellungen. + * + * @param string $comment_content Kommentarinhalt. + * @return string Gefilterter Inhalt. + */ +function wp_multi_filter_comment_content($comment_content) { + if (get_option(WP_MULTI_FILTER_OPTION_PREFIX . 'swear') == 1) { + $swear_words = wp_multi_load_swear_words(); + $allowed_words = array_map('strtolower', array_map('trim', explode(',', get_option(WP_MULTI_FILTER_OPTION_PREFIX . 'allowed_words', '')))); + $filter_strength = get_option(WP_MULTI_FILTER_OPTION_PREFIX . 'filter_strength', 'moderate'); + $comment_content = wp_multi_filter_swear_words($comment_content, $swear_words, $allowed_words, $filter_strength); + } + + if (get_option(WP_MULTI_FILTER_OPTION_PREFIX . 'phone') == 1) { $comment_content = preg_replace('/\b(\+?[0-9]{1,3}[-.\s]?)?(\(?\d{2,4}\)?[-.\s]?\d{2,4}[-.\s]?\d{2,4})\b/i', '**********', $comment_content); } - if (get_option('wp_multi_filter_email') == 1) { + if (get_option(WP_MULTI_FILTER_OPTION_PREFIX . 'email') == 1) { $comment_content = preg_replace('/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/i', '**********', $comment_content); } - if (get_option('wp_multi_filter_url') == 1) { - $allowed_urls = array_map('trim', explode(',', get_option('wp_multi_allowed_urls', ''))); - $comment_content = preg_replace_callback('/\b((https?:\/\/)?(www\.)?[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})(\/\S*)?\b/i', function($matches) use ($allowed_urls) { - // Entfernt "http://", "https://" und "www." - $url = strtolower(preg_replace(['/^https?:\/\//', '/^www\./'], '', $matches[0])); - return in_array($url, $allowed_urls) ? $matches[0] : '**************'; - }, $comment_content); + if (get_option(WP_MULTI_FILTER_OPTION_PREFIX . 'url') == 1) { + $allowed_urls = array_map('strtolower', array_map('trim', explode(',', get_option(WP_MULTI_FILTER_OPTION_PREFIX . 'allowed_urls', '')))); + $comment_content = preg_replace_callback( + '/\b((https?:\/\/)?(www\.)?[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})(\/\S*)?\b/i', + function ($matches) use ($allowed_urls) { + $url = strtolower(preg_replace(['/^https?:\/\//', '/^www\./'], '', $matches[0])); + return in_array($url, $allowed_urls) ? $matches[0] : '**************'; + }, + $comment_content + ); } - if (get_option('wp_multi_filter_ip') == 1) { + if (get_option(WP_MULTI_FILTER_OPTION_PREFIX . 'ip') == 1) { $comment_content = preg_replace('/\b(?:\d{1,3}\.){3}\d{1,3}\b/', '**********', $comment_content); } @@ -4220,185 +4512,332 @@ add_action('admin_menu', 'wp_stat_notice_add_reported_posts_menu'); /* -* Gast Lesezeichen -*/ + * Verbessertes Gast-Lesezeichen-Plugin mit erhöhter Sicherheit und Benutzerfreundlichkeit + */ -// Funktion zum Erstellen des benutzerdefinierten Post-Typs für Lesezeichen +define('STATISTIK_MANAGER_BOOKMARK_POST_TYPE', 'bookmark'); +define('STATISTIK_MANAGER_COOKIE_NAME', 'guest_token'); +define('STATISTIK_MANAGER_COOKIE_DURATION', 30 * DAY_IN_SECONDS); +define('STATISTIK_MANAGER_BOOKMARKS_CACHE_KEY', 'statistik_manager_bookmarks_'); + +/** + * Erstellt den benutzerdefinierten Post-Typ für Lesezeichen. + */ function statistik_manager_create_bookmark_post_type() { - register_post_type('bookmark', - array( - 'labels' => array( - 'name' => __('Lesezeichen', 'statistik-manager'), - 'singular_name' => __('Lesezeichen', 'statistik-manager') - ), - 'public' => false, // Privat, nur für Backend - 'show_ui' => false, // Nicht im Backend anzeigen - 'show_in_menu' => false, // Nicht im Menü anzeigen - 'supports' => array('title', 'custom-fields') - ) - ); + register_post_type(STATISTIK_MANAGER_BOOKMARK_POST_TYPE, [ + 'labels' => [ + 'name' => __('Lesezeichen', 'statistik-manager'), + 'singular_name' => __('Lesezeichen', 'statistik-manager'), + ], + 'public' => false, + 'show_ui' => false, + 'show_in_menu' => false, + 'supports' => ['title', 'custom-fields'], + ]); } add_action('init', 'statistik_manager_create_bookmark_post_type'); -// Funktion zum Speichern eines Lesezeichens für Gäste -function statistik_manager_save_bookmark($post_id) { - if (isset($_COOKIE['guest_token'])) { - update_post_meta($post_id, '_guest_token', $_COOKIE['guest_token']); - } -} - -// Funktion zum Abrufen der Lesezeichen eines Gastes -function statistik_manager_get_guest_bookmarks() { - $guest_token = isset($_COOKIE['guest_token']) ? $_COOKIE['guest_token'] : null; +/** + * Generiert oder holt den Gast-Token. + * + * @return string Der Gast-Token. + */ +function statistik_manager_get_guest_token() { + $guest_token = isset($_COOKIE[STATISTIK_MANAGER_COOKIE_NAME]) ? sanitize_text_field($_COOKIE[STATISTIK_MANAGER_COOKIE_NAME]) : null; if (!$guest_token) { - // Wenn der Gast noch kein Token hat, erstellen und speichern - $guest_token = wp_generate_uuid4(); // Ein zufälliger UUID-Token - setcookie('guest_token', $guest_token, time() + 3600 * 24 * 30, COOKIEPATH, COOKIE_DOMAIN); // Cookie für 30 Tage setzen + $guest_token = wp_generate_uuid4(); + setcookie( + STATISTIK_MANAGER_COOKIE_NAME, + $guest_token, + time() + STATISTIK_MANAGER_COOKIE_DURATION, + COOKIEPATH, + COOKIE_DOMAIN, + is_ssl(), // Secure + true // HttpOnly + ); } - // Abfrage der Lesezeichen für den aktuellen Gast - $args = array( - 'post_type' => 'bookmark', - 'meta_key' => '_guest_token', - 'meta_value' => $guest_token, - 'posts_per_page' => -1, - 'post_status' => 'publish' - ); - $bookmarks_query = new WP_Query($args); - - return $bookmarks_query->posts; + return $guest_token; } -// Funktion zum Löschen eines Lesezeichens (nur für den aktuellen Gast) -function statistik_manager_delete_bookmark() { - if (isset($_POST['bookmark_id']) && isset($_COOKIE['guest_token'])) { - $bookmark_id = intval($_POST['bookmark_id']); - $guest_token = $_COOKIE['guest_token']; +/** + * Speichert ein Lesezeichen für einen Gast. + * + * @param int $post_id Post-ID des Lesezeichens. + */ +function statistik_manager_save_bookmark($post_id) { + $guest_token = statistik_manager_get_guest_token(); + update_post_meta($post_id, '_guest_token', $guest_token); +} - // Überprüfen, ob das Lesezeichen diesem Gast gehört - $stored_token = get_post_meta($bookmark_id, '_guest_token', true); - if ($stored_token === $guest_token) { - wp_delete_post($bookmark_id, true); - echo 'Lesezeichen erfolgreich gelöscht!'; - } else { - echo 'Du kannst nur deine eigenen Lesezeichen löschen!'; - } +/** + * Ruft die Lesezeichen eines Gastes ab. + * + * @return array Liste der Lesezeichen. + */ +function statistik_manager_get_guest_bookmarks() { + $guest_token = statistik_manager_get_guest_token(); + $cache_key = STATISTIK_MANAGER_BOOKMARKS_CACHE_KEY . md5($guest_token); + $bookmarks = get_transient($cache_key); + + if ($bookmarks !== false) { + return $bookmarks; } - wp_die(); // Beende die Anfrage + + $args = [ + 'post_type' => STATISTIK_MANAGER_BOOKMARK_POST_TYPE, + 'meta_query' => [ + [ + 'key' => '_guest_token', + 'value' => $guest_token, + ], + ], + 'posts_per_page' => -1, + 'post_status' => 'publish', + 'orderby' => 'date', + 'order' => 'DESC', + ]; + + $bookmarks_query = new WP_Query($args); + $bookmarks = $bookmarks_query->posts; + + set_transient($cache_key, $bookmarks, HOUR_IN_SECONDS); + return $bookmarks; +} + +/** + * Löscht ein Lesezeichen via AJAX. + */ +function statistik_manager_delete_bookmark() { + check_ajax_referer('statistik_manager_bookmark_nonce', 'nonce'); + + if (!isset($_POST['bookmark_id']) || !isset($_COOKIE[STATISTIK_MANAGER_COOKIE_NAME])) { + wp_send_json_error(['message' => __('Ungültige Anfrage.', 'statistik-manager')]); + } + + $bookmark_id = absint($_POST['bookmark_id']); + $guest_token = sanitize_text_field($_COOKIE[STATISTIK_MANAGER_COOKIE_NAME]); + $stored_token = get_post_meta($bookmark_id, '_guest_token', true); + + if ($stored_token !== $guest_token) { + wp_send_json_error(['message' => __('Du kannst nur deine eigenen Lesezeichen löschen.', 'statistik-manager')]); + } + + wp_delete_post($bookmark_id, true); + delete_transient(STATISTIK_MANAGER_BOOKMARKS_CACHE_KEY . md5($guest_token)); + wp_send_json_success(['message' => __('Lesezeichen erfolgreich gelöscht.', 'statistik-manager')]); } add_action('wp_ajax_delete_bookmark', 'statistik_manager_delete_bookmark'); add_action('wp_ajax_nopriv_delete_bookmark', 'statistik_manager_delete_bookmark'); -// Funktion zum Anzeigen der Lesezeichen mit Löschen-Option -function statistik_manager_display_bookmarks() { - $bookmarks = statistik_manager_get_guest_bookmarks(); - - if (!empty($bookmarks)) { - $output = '
'; - $output .= '

' . __('Gespeicherte Lesezeichen', 'statistik-manager') . '

'; - $output .= ''; - $output .= '
'; - return $output; - } else { - return '

' . __('Keine Lesezeichen gefunden.', 'statistik-manager') . '

'; - } -} - -// Funktion zum Hinzufügen eines Lesezeichens via AJAX +/** + * Fügt ein Lesezeichen via AJAX hinzu. + */ function statistik_manager_add_bookmark_ajax() { - if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['bookmark_url']) && isset($_POST['bookmark_name'])) { - $bookmark_url = sanitize_text_field($_POST['bookmark_url']); - $bookmark_name = sanitize_text_field($_POST['bookmark_name']); // Name des Lesezeichens + check_ajax_referer('statistik_manager_bookmark_nonce', 'nonce'); - // Neues Lesezeichen erstellen - $post_id = wp_insert_post(array( - 'post_type' => 'bookmark', - 'post_title' => $bookmark_name, // Benutzerdefinierter Name für das Lesezeichen - 'post_status' => 'publish', - 'meta_input' => array( - '_bookmark_url' => $bookmark_url - ) - )); - - // Speichern des Gast-Token - if (isset($_COOKIE['guest_token'])) { - update_post_meta($post_id, '_guest_token', $_COOKIE['guest_token']); - } - - // Rückgabe des neuen Lesezeichens als HTML - $bookmark_html = '
  • '; - $bookmark_html .= ''; - $bookmark_html .= '' . esc_html($bookmark_name) . ''; - $bookmark_html .= '
  • '; - - echo $bookmark_html; + if (!isset($_POST['bookmark_url']) || !isset($_POST['bookmark_name'])) { + wp_send_json_error(['message' => __('Bitte alle Felder ausfüllen.', 'statistik-manager')]); } - wp_die(); // Beende die Anfrage + $bookmark_url = esc_url_raw($_POST['bookmark_url']); + $bookmark_name = sanitize_text_field($_POST['bookmark_name']); + + if (empty($bookmark_url) || empty($bookmark_name)) { + wp_send_json_error(['message' => __('Ungültige URL oder Name.', 'statistik-manager')]); + } + + // Prüfen, ob die URL bereits existiert + $guest_token = statistik_manager_get_guest_token(); + $args = [ + 'post_type' => STATISTIK_MANAGER_BOOKMARK_POST_TYPE, + 'meta_query' => [ + 'relation' => 'AND', + [ + 'key' => '_guest_token', + 'value' => $guest_token, + ], + [ + 'key' => '_bookmark_url', + 'value' => $bookmark_url, + ], + ], + 'posts_per_page' => 1, + ]; + + $existing = new WP_Query($args); + if ($existing->have_posts()) { + wp_send_json_error(['message' => __('Diese URL ist bereits ein Lesezeichen.', 'statistik-manager')]); + } + + // Neues Lesezeichen erstellen + $post_id = wp_insert_post([ + 'post_type' => STATISTIK_MANAGER_BOOKMARK_POST_TYPE, + 'post_title' => $bookmark_name, + 'post_status' => 'publish', + 'meta_input' => [ + '_bookmark_url' => $bookmark_url, + '_guest_token' => $guest_token, + ], + ]); + + if (is_wp_error($post_id)) { + wp_send_json_error(['message' => __('Fehler beim Hinzufügen des Lesezeichens.', 'statistik-manager')]); + } + + delete_transient(STATISTIK_MANAGER_BOOKMARKS_CACHE_KEY . md5($guest_token)); + wp_send_json_success([ + 'message' => __('Lesezeichen erfolgreich hinzugefügt.', 'statistik-manager'), + 'html' => '
  • ' . esc_html($bookmark_name) . '
  • ', + ]); } add_action('wp_ajax_add_bookmark', 'statistik_manager_add_bookmark_ajax'); add_action('wp_ajax_nopriv_add_bookmark', 'statistik_manager_add_bookmark_ajax'); -// JavaScript zum Hinzufügen des Lesezeichens ohne Seitenaktualisierung +/** + * Zeigt die Lesezeichen eines Gastes an. + * + * @return string HTML-Ausgabe der Lesezeichen. + */ +function statistik_manager_display_bookmarks() { + $bookmarks = statistik_manager_get_guest_bookmarks(); + + ob_start(); + ?> +
    +

    + +

    + + + +
    + +
    + +
    + + +
    +
    + + +
    +
    + +
    +
    +
    + +