From 8822dad5835341c07355d128cccf9eff545b9e86 Mon Sep 17 00:00:00 2001 From: M_Viper Date: Mon, 7 Apr 2025 22:18:26 +0000 Subject: [PATCH] wp-multi.php aktualisiert --- wp-multi.php | 1303 ++++++++++++++++++++++++++------------------------ 1 file changed, 667 insertions(+), 636 deletions(-) diff --git a/wp-multi.php b/wp-multi.php index bc70ad8..194e17e 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.6 + * Version: 2.7 * Author: M_Viper * Author URI: https://m-viper.de * Requires at least: 6.7.2 @@ -12,41 +12,270 @@ * License URI: https://www.gnu.org/licenses/gpl-2.0.html * Text Domain: wp-multi * Tags: anti-spam, security, honeypot, comment-protection, statistics, happyforms - * Support: [Microsoft Teams Support](https://teams.live.com/l/community/FEAzokphpZTJ2u6OgI) + * Support: [Microsoft Teams Support](https://teams.live.com/l/community/FEAzokphpZTJ2u6OgI) * Support: [Telegram Support](https://t.me/M_Viper04) */ -if (!defined('ABSPATH')) exit; + if (!defined('ABSPATH')) exit; /* -* Admin - Panel Banner -*/ + * Admin - Panel Banner + */ -// Admin-Banner als Notice mit Blauem Hintergrund (#0073aa) -function wp_multi_add_warning_banner() { - echo ' -
-

Danke, dass du WP Multi verwendest! Dein Feedback hilft uns, das Plugin ständig zu verbessern. Wenn du Fehler entdeckst oder Verbesserungsvorschläge hast, besuche bitte unsere Gitea-Seite und teile uns deine Ideen mit!

-

Support: Bei Fragen oder Supportanfragen kannst du uns über Microsoft Teams oder Telegram erreichen.

-
'; + // Admin-Banner als Notice mit Blauem Hintergrund (#0073aa) + function wp_multi_add_warning_banner() { + // Verwende printf für bessere Lesbarkeit und Übersetzbarkeit + printf( + '
+

%s %s %s %s

+

%s: %s %s %s %s %s

+
', + esc_html__('Danke, dass du WP Multi verwendest!', 'wp-multi'), + esc_html__('Dein Feedback hilft uns, das Plugin ständig zu verbessern. Wenn du Fehler entdeckst oder Verbesserungsvorschläge hast, besuche bitte unsere', 'wp-multi'), + 'https://git.viper.ipv64.net/M_Viper/wp-multi', + esc_html__('Gitea-Seite', 'wp-multi'), + esc_html__('und teile uns deine Ideen mit!', 'wp-multi'), + esc_html__('Support', 'wp-multi'), + esc_html__('Bei Fragen oder Supportanfragen kannst du uns über', 'wp-multi'), + 'https://teams.live.com/l/community/FEAzokphpZTJ2u6OgI', + esc_html__('Microsoft Teams', 'wp-multi'), + esc_html__('oder', 'wp-multi'), + 'https://t.me/M_Viper04', + esc_html__('Telegram', 'wp-multi'), + esc_html__('erreichen.', 'wp-multi') + ); + } + add_action('admin_notices', 'wp_multi_add_warning_banner'); + + // Support-Links in der Plugin-Übersicht anzeigen + function wp_multi_plugin_row_meta($links, $file) { + if ($file === plugin_basename(__FILE__)) { + $new_links = array( + 'support_teams' => sprintf( + '%s', + esc_url('https://teams.live.com/l/community/FEAzokphpZTJ2u6OgI'), + esc_html__('Microsoft Teams Support', 'wp-multi') + ), + 'support_telegram' => sprintf( + '%s', + esc_url('https://t.me/M_Viper04'), + esc_html__('Telegram Support', 'wp-multi') + ), + ); + $links = array_merge($links, $new_links); + } + return $links; + } + add_filter('plugin_row_meta', 'wp_multi_plugin_row_meta', 10, 2); + + +/* + * Update Widget + */ + +// Widget zum Admin-Dashboard hinzufügen +function wp_multi_update_dashboard_widget() { + wp_add_dashboard_widget( + 'wp_multi_update_widget', + __('Verfügbare Updates für WP Multi', 'wp-multi'), + 'wp_multi_update_dashboard_widget_content' + ); } -add_action('admin_notices', 'wp_multi_add_warning_banner'); +add_action('wp_dashboard_setup', 'wp_multi_update_dashboard_widget'); -// Support-Links in der Plugin-Übersicht anzeigen -function wp_multi_plugin_row_meta($links, $file) { - if ($file == plugin_basename(__FILE__)) { - $new_links = array( - 'support_teams' => 'Microsoft Teams Support', - 'support_telegram' => 'Telegram Support', - ); - // Links an die Plugin-Übersicht anhängen - $links = array_merge($links, $new_links); +// Benutzerdefiniertes Cron-Intervall hinzufügen +add_filter('cron_schedules', function ($schedules) { + $schedules['hourly'] = array( + 'interval' => 3600, // 1 Stunde in Sekunden + 'display' => __('Stündlich', 'wp-multi'), + ); + return $schedules; +}); + +// Cron-Job registrieren +function wp_multi_update_schedule_check() { + if (!wp_next_scheduled('wp_multi_update_check_event')) { + wp_schedule_event(time(), 'hourly', 'wp_multi_update_check_event'); } - return $links; } -add_filter('plugin_row_meta', 'wp_multi_plugin_row_meta', 10, 2); +add_action('wp', 'wp_multi_update_schedule_check'); + +// Hilfsfunktion zur Wiederverwendung der Gitea-API-Abfrage +function wp_multi_fetch_latest_release($show_prereleases = false) { + $api_url = 'https://git.viper.ipv64.net/api/v1/repos/M_Viper/wp-multi/releases'; + $response = wp_remote_get($api_url, array('timeout' => 10)); + + if (is_wp_error($response)) { + error_log('WP Multi Update Check Fehler: ' . $response->get_error_message()); + return false; + } + + $body = wp_remote_retrieve_body($response); + $data = json_decode($body, true); + + if (!is_array($data)) { + error_log('WP Multi Update Check: Ungültige API-Antwort'); + return false; + } + + foreach ($data as $release) { + if (!$show_prereleases && isset($release['prerelease']) && $release['prerelease']) { + continue; + } + if (!empty($release['tag_name'])) { + return $release; + } + } + return null; +} + +// Cron-Job für Update-Überprüfung +function wp_multi_update_check() { + $plugin_data = get_plugin_data(__FILE__); + $installed_version = $plugin_data['Version']; + $show_prereleases = get_option('wp_multi_update_show_prereleases', false); + + $valid_release = wp_multi_fetch_latest_release($show_prereleases); + + if ($valid_release) { + $latest_version = $valid_release['tag_name']; + $release_notes = isset($valid_release['body']) ? $valid_release['body'] : ''; + $is_prerelease = isset($valid_release['prerelease']) && $valid_release['prerelease']; + + update_option('wp_multi_update_latest_version', $latest_version); + update_option('wp_multi_update_release_notes', $release_notes); + update_option('wp_multi_update_is_prerelease', $is_prerelease); + } +} +add_action('wp_multi_update_check_event', 'wp_multi_update_check'); + +// Callback-Funktion für das Widget +function wp_multi_update_dashboard_widget_content() { + $plugin_data = get_plugin_data(__FILE__); + $installed_version = $plugin_data['Version']; + $show_prereleases = get_option('wp_multi_update_show_prereleases', false); + + $valid_release = wp_multi_fetch_latest_release($show_prereleases); + + if ($valid_release === false) { + printf('

%s

', esc_html__('Fehler beim Abrufen der Versionsinformationen von Gitea.', 'wp-multi')); + return; + } + + if ($valid_release) { + $latest_version = $valid_release['tag_name']; + $release_notes = isset($valid_release['body']) ? $valid_release['body'] : ''; + $is_prerelease = isset($valid_release['prerelease']) && $valid_release['prerelease']; + + if (version_compare($installed_version, $latest_version, '>=')) { + printf( + '

%s

', + sprintf( + __('Ihre Version ist aktuell. Version %s ist die neueste Version.', 'wp-multi'), + esc_html($installed_version) + ) + ); + } else { + printf( + '

%s

', + sprintf( + __('Es ist eine neue Version von WP Multi verfügbar! Version %s ist jetzt verfügbar.', 'wp-multi'), + esc_html($latest_version) + ) + ); + printf( + '

%s: %s

', + __('Aktuell installierte Version', 'wp-multi'), + esc_html($installed_version) + ); + printf( + '

%s: %s

', + __('Neue Version auf Gitea', 'wp-multi'), + esc_html($latest_version) + ); + + if ($is_prerelease && $show_prereleases) { + printf('

%s

', __('Dieses Update ist ein PreRelease.', 'wp-multi')); + } + + if (!empty($release_notes)) { + printf( + '

%s:

%s

', + __('Information zum Update', 'wp-multi'), + nl2br(esc_html($release_notes)) + ); + } + + $button_text = $is_prerelease ? __('PreRelease herunterladen', 'wp-multi') : __('Update herunterladen', 'wp-multi'); + $download_url = isset($valid_release['assets'][0]['browser_download_url']) ? $valid_release['assets'][0]['browser_download_url'] : '#'; + printf( + '

%s

', + esc_url($download_url), + esc_html($button_text) + ); + } + } else { + printf('

%s

', esc_html__('Keine Versionsinformationen gefunden.', 'wp-multi')); + } +} + +// Füge die Checkbox zu den allgemeinen Einstellungen hinzu +function wp_multi_update_general_settings() { + // Füge die Option für Pre-Releases unter "Allgemein" hinzu + add_settings_section( + 'wp_multi_update_section', + __('WP Multi Update Einstellungen', 'wp-multi'), + null, + 'general' + ); + + add_settings_field( + 'wp_multi_update_show_prereleases', + __('Pre-Releases anzeigen', 'wp-multi'), + 'wp_multi_update_show_prereleases_callback', + 'general', + 'wp_multi_update_section' + ); + + register_setting('general', 'wp_multi_update_show_prereleases', array( + 'type' => 'boolean', + 'description' => __('Aktivieren, um Pre-Releases im Dashboard und in den Versionsinformationen anzuzeigen.', 'wp-multi'), + 'default' => 0, + )); +} +add_action('admin_init', 'wp_multi_update_general_settings'); + +// Callback-Funktion für das Anzeigen der Checkbox +function wp_multi_update_show_prereleases_callback() { + $checked = get_option('wp_multi_update_show_prereleases', false); + echo ''; + // Hinweistext unter der Checkbox in Rot + echo '

' . __('Achtung: Pre-Releases sind Beta-Versionen und können Fehler enthalten. Verwenden Sie sie nur, wenn Sie Fehlerberichterstattung oder Tests durchführen möchten.', 'wp-multi') . '

'; +} + + + + + + + + + + + + + + + + + + + + + + /* * Index Verzeichnis [alphabetical_index] @@ -357,33 +586,50 @@ add_action( 'wp_login', 'wp_multi_block_login_if_disabled', 10, 2 ); */ + // Automatische Tags zu Beiträgen hinzufügen function wp_multi_auto_add_tags($post_id) { - if (get_post_type($post_id) !== 'post' || wp_is_post_revision($post_id)) return; + // Prüfe nur den Post-Typ, da wp_is_post_revision redundant ist + if (get_post_type($post_id) !== 'post') { + return; + } $existing_tags = wp_get_post_tags($post_id, ['fields' => 'names']); - if (!empty($existing_tags)) return; + if (!empty($existing_tags)) { + return; + } $post = get_post($post_id); + if (!$post) { + return; // Sicherheitsprüfung, falls der Beitrag nicht existiert + } + $content = strip_tags($post->post_content); $content = strtolower($content); // Stopwörter aus der Admin-Eingabe holen $custom_stopwords = get_option('wp_multi_custom_stopwords', ''); - $custom_stopwords = array_map('trim', explode(',', $custom_stopwords)); // In ein Array umwandeln + $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']; + $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 (standard und benutzerdefiniert) + // 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)); + if (empty($words)) { + return; // Keine Tags, wenn keine Wörter übrig sind + } + $word_counts = array_count_values($words); arsort($word_counts); @@ -397,8 +643,8 @@ function wp_multi_auto_add_tags($post_id) { function wp_multi_admin_menu() { add_submenu_page( 'edit.php', - 'Automatische Tags', - 'Automatische Tags', + __('Automatische Tags', 'wp-multi'), + __('Automatische Tags', 'wp-multi'), 'manage_options', 'wp-multi-auto-tags', 'wp_multi_auto_tags_page' @@ -413,26 +659,27 @@ function wp_multi_auto_tags_page() {
M_Viper Logo -

Automatische Tags

+

-

Diese Funktion fügt automatisch Tag zu Beiträgen hinzu, die noch keine haben.

+

-
+

- Trenne die Wörter durch Kommas, z. B. "wird, auch, aber". +

-

+

- +
0%
@@ -441,167 +688,101 @@ function wp_multi_auto_tags_page() {

- - + admin_url('admin-ajax.php'), + 'nonce' => wp_create_nonce('wp_multi_auto_tags_nonce') + ]); + ?> @@ -610,38 +791,52 @@ function wp_multi_auto_tags_page() { // Einstellungen registrieren function wp_multi_auto_tags_settings_init() { - register_setting('wp_multi_auto_tags_options', 'wp_multi_custom_stopwords'); + register_setting('wp_multi_auto_tags_options', 'wp_multi_custom_stopwords', [ + 'sanitize_callback' => 'sanitize_text_field' + ]); } add_action('admin_init', 'wp_multi_auto_tags_settings_init'); // AJAX-Aufrufe für schnelle Verarbeitung add_action('wp_ajax_wp_multi_process_auto_tags', 'wp_multi_process_auto_tags'); function wp_multi_process_auto_tags() { - $args = ['post_type' => 'post', 'posts_per_page' => -1, 'fields' => 'ids']; + check_ajax_referer('wp_multi_auto_tags_nonce', 'nonce'); + + $args = [ + 'post_type' => 'post', + 'posts_per_page' => 100, // Begrenze auf 100 für bessere Performance + 'fields' => 'ids', + 'paged' => 1 // Erste Seite, erweiterbar für Pagination + ]; $posts = get_posts($args); - + + if (empty($posts)) { + wp_send_json(['total' => 0]); + } + set_transient('wp_multi_auto_tags_queue', $posts, 300); - wp_send_json(['total' => count($posts)]); } add_action('wp_ajax_wp_multi_process_auto_tags_step', 'wp_multi_process_auto_tags_step'); function wp_multi_process_auto_tags_step() { + check_ajax_referer('wp_multi_auto_tags_nonce', 'nonce'); + $queue = get_transient('wp_multi_auto_tags_queue'); $batchSize = isset($_POST['batchSize']) ? intval($_POST['batchSize']) : 10; + $batchSize = max(1, min($batchSize, 50)); // Begrenze zwischen 1 und 50 if (!$queue || empty($queue)) { wp_send_json(['done' => false]); } $posts_to_process = array_splice($queue, 0, $batchSize); - + foreach ($posts_to_process as $post_id) { wp_multi_auto_add_tags($post_id); } set_transient('wp_multi_auto_tags_queue', $queue, 300); - wp_send_json(['done' => true]); } @@ -956,139 +1151,154 @@ function wp_multi_blocked_ips_callback() { // Funktion zur Erfassung der echten IP-Adresse des Benutzers function get_user_ip() { - if (!empty($_SERVER['HTTP_CLIENT_IP'])) { + // Priorität: HTTP_CLIENT_IP > HTTP_X_FORWARDED_FOR > REMOTE_ADDR + if (!empty($_SERVER['HTTP_CLIENT_IP']) && filter_var($_SERVER['HTTP_CLIENT_IP'], FILTER_VALIDATE_IP)) { return $_SERVER['HTTP_CLIENT_IP']; } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { - return $_SERVER['HTTP_X_FORWARDED_FOR']; - } else { - return $_SERVER['REMOTE_ADDR']; + // HTTP_X_FORWARDED_FOR kann mehrere IPs enthalten (Comma-separated) + $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); + $ip = trim($ips[0]); + return filter_var($ip, FILTER_VALIDATE_IP) ? $ip : $_SERVER['REMOTE_ADDR']; } + return filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0'; } // Funktion zur Verfolgung von fehlgeschlagenen Anmeldeversuchen function wp_multi_log_failed_login($username) { global $wpdb; - // Holen der IP-Adresse $ip = get_user_ip(); - $table_name = $wpdb->prefix . 'blocked_ips'; // Tabelle für blockierte IPs - $user = get_user_by('login', $username); // Benutzerinformationen basierend auf dem Anmeldenamen - - // Überprüfen, ob die IP bereits in der Tabelle existiert + if ($ip === '0.0.0.0') { + return; // Ungültige IP, keine Aktion erforderlich + } + + $table_name = $wpdb->prefix . 'blocked_ips'; + $user = get_user_by('login', $username); + $max_attempts = 3; // Maximale Anzahl an E-Mails + $block_threshold = 5; // Schwelle für Sperrung + + // Prüfen, ob die IP bereits existiert $row = $wpdb->get_row($wpdb->prepare("SELECT * FROM $table_name WHERE ip = %s", $ip)); if ($row) { - // Wenn die IP existiert, erhöhen wir die Anzahl der fehlgeschlagenen Versuche $wpdb->update( $table_name, - array('attempts' => $row->attempts + 1, 'last_attempt' => current_time('mysql')), - array('ip' => $ip) + array( + 'attempts' => $row->attempts + 1, + 'last_attempt' => current_time('mysql'), + ), + array('ip' => $ip), + array('%d', '%s'), + array('%s') ); + $attempts = $row->attempts + 1; } else { - // Wenn die IP nicht existiert, fügen wir sie hinzu $wpdb->insert( $table_name, - array('ip' => $ip, 'attempts' => 1, 'last_attempt' => current_time('mysql')) // Die `last_attempt` sollte ebenfalls beim Einfügen gesetzt werden + array( + 'ip' => $ip, + 'attempts' => 1, + 'last_attempt' => current_time('mysql'), + ), + array('%s', '%d', '%s') ); + $attempts = 1; } - // Zähler für E-Mails und Versuche (maximal 3 E-Mails) - $max_attempts = 3; - - // Wenn die Anzahl der Versuche größer oder gleich 5 ist, blockiere die IP und sende E-Mails - if ($row && $row->attempts >= 5) { - // Prüfen, ob bereits mehr als 3 E-Mails versendet wurden - $email_sent = get_option('failed_login_email_sent_' . $ip, 0); + // Sperrung und E-Mail-Benachrichtigung bei Überschreitung der Schwelle + if ($attempts >= $block_threshold) { + $email_sent = (int) get_option('failed_login_email_sent_' . $ip, 0); if ($email_sent < $max_attempts) { - // E-Mail an den betroffenen Benutzer senden (falls der Benutzer existiert) + // E-Mail an Benutzer (falls vorhanden) if ($user) { wp_mail( $user->user_email, - 'Deine IP-Adresse wurde gesperrt', - 'Hallo ' . $user->user_login . ',\n\nDeine IP-Adresse wurde aufgrund zu vieler fehlgeschlagener Anmeldeversuche gesperrt. Bitte kontaktiere den Administrator, falls du Unterstützung benötigst.', + __('Deine IP-Adresse wurde gesperrt', 'wp-multi'), + sprintf( + __("Hallo %s,\n\nDeine IP-Adresse wurde aufgrund zu vieler fehlgeschlagener Anmeldeversuche gesperrt. Bitte kontaktiere den Administrator.", 'wp-multi'), + $user->user_login + ), array('Content-Type: text/plain; charset=UTF-8') ); - // Zähler erhöhen - update_option('failed_login_email_sent_' . $ip, $email_sent + 1); } - // E-Mail an den Administrator senden + // E-Mail an Admin $admin_email = get_option('admin_email'); wp_mail( $admin_email, - 'Brute-Force-Angriff erkannt', - 'Es wurde ein Brute-Force-Angriff auf deine WordPress-Seite erkannt. Die IP-Adresse ' . $ip . ' wurde nach mehreren fehlgeschlagenen Anmeldeversuchen blockiert.', + __('Brute-Force-Angriff erkannt', 'wp-multi'), + sprintf( + __("Ein Brute-Force-Angriff wurde erkannt. Die IP-Adresse %s wurde nach %d fehlgeschlagenen Versuchen blockiert.", 'wp-multi'), + $ip, + $attempts + ), array('Content-Type: text/plain; charset=UTF-8') ); + // Zähler erhöhen update_option('failed_login_email_sent_' . $ip, $email_sent + 1); } - // Benutzer sperren und eine Fehlermeldung anzeigen - wp_die("Deine IP-Adresse wurde aufgrund zu vieler Fehlversuche gesperrt. Bitte versuche es später noch einmal."); + wp_die( + __('Deine IP-Adresse wurde aufgrund zu vieler Fehlversuche gesperrt. Bitte versuche es später noch einmal.', 'wp-multi'), + __('Zugriff gesperrt', 'wp-multi'), + array('response' => 403) + ); } } -// Funktion zur Überwachung von Benutzeranmeldungen -function wp_multi_failed_login_hook($username) { - wp_multi_log_failed_login($username); -} +// Hook für fehlgeschlagene Anmeldungen +add_action('wp_login_failed', 'wp_multi_log_failed_login', 10, 1); -// Hook zum Abfangen fehlgeschlagener Anmeldungen -add_action('wp_login_failed', 'wp_multi_failed_login_hook'); - -// Funktion zur Erstellung der Tabelle für blockierte IPs (Einmal bei der Installation ausführen) +// Funktion zur Erstellung der Tabelle für blockierte IPs function wp_multi_create_blocked_ips_table() { global $wpdb; - $table_name = $wpdb->prefix . 'blocked_ips'; // Tabelle für blockierte IPs + $table_name = $wpdb->prefix . 'blocked_ips'; $charset_collate = $wpdb->get_charset_collate(); + $version = get_option('wp_multi_blocked_ips_version', '1.0'); - // SQL-Anweisung zur Erstellung der Tabelle - $sql = "CREATE TABLE $table_name ( - id mediumint(9) NOT NULL AUTO_INCREMENT, - ip varchar(45) NOT NULL, - attempts int NOT NULL DEFAULT 0, - last_attempt datetime NOT NULL, - PRIMARY KEY (id) - ) $charset_collate;"; + if (version_compare($version, '1.1', '<')) { + $sql = "CREATE TABLE $table_name ( + id mediumint(9) NOT NULL AUTO_INCREMENT, + ip varchar(45) NOT NULL, + attempts int NOT NULL DEFAULT 0, + last_attempt datetime NOT NULL, + PRIMARY KEY (id), + KEY ip (ip) + ) $charset_collate;"; - require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); - dbDelta($sql); // Tabellen erstellen oder aktualisieren + require_once ABSPATH . 'wp-admin/includes/upgrade.php'; + dbDelta($sql); + update_option('wp_multi_blocked_ips_version', '1.1'); + } } - -// Diese Funktion wird beim Aktivieren des Plugins aufgerufen register_activation_hook(__FILE__, 'wp_multi_create_blocked_ips_table'); +// Menüpunkt für blockierte IPs function wp_multi_blocked_ips_menu() { add_submenu_page( - 'wp-multi-security', // Übergeordnetes Menü: "Sicherheit" - 'Blockierte IPs', // Titel der Seite - 'Blockierte IPs', // Menüname - 'manage_options', // Berechtigung (nur Administratoren) - 'wp_multi_blocked_ips', // Slug - 'wp_multi_display_blocked_ips' // Callback-Funktion + 'wp-multi-security', + __('Blockierte IPs', 'wp-multi'), + __('Blockierte IPs', 'wp-multi'), + 'manage_options', + 'wp_multi_blocked_ips', + 'wp_multi_display_blocked_ips' ); } add_action('admin_menu', 'wp_multi_blocked_ips_menu'); -// Callback-Funktion für die Anzeige der blockierten IPs +// Anzeige der blockierten IPs im Admin-Bereich function wp_multi_display_blocked_ips() { global $wpdb; - - // Tabelle für blockierte IPs $table_name = $wpdb->prefix . 'blocked_ips'; - // Berechnen des Datums vor 5 Tagen $five_days_ago = date('Y-m-d H:i:s', strtotime('-5 days')); - - // Berechnung der Pagination $per_page = 50; - $page = isset($_GET['paged']) ? intval($_GET['paged']) : 1; + $page = max(1, isset($_GET['paged']) ? intval($_GET['paged']) : 1); $offset = ($page - 1) * $per_page; - // Hole alle blockierten IPs aus der Datenbank, die innerhalb der letzten 5 Tage liegen $blocked_ips = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $table_name WHERE last_attempt >= %s ORDER BY last_attempt DESC LIMIT %d OFFSET %d", @@ -1098,74 +1308,89 @@ function wp_multi_display_blocked_ips() { ) ); - // Wenn keine blockierten IPs vorhanden sind - if (empty($blocked_ips)) { - echo '

Keine blockierten IPs gefunden

'; - return; - } - - // HTML-Tabelle zur Anzeige der blockierten IPs - echo '

Blockierte IPs (letzte 5 Tage)

'; - echo ''; - echo ''; - echo ''; - - foreach ($blocked_ips as $ip) { - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - } - - echo ''; - echo '
IDIP-AdresseVersucheLetzter VersuchAktionen
' . $ip->id . '' . $ip->ip . '' . $ip->attempts . '' . $ip->last_attempt . 'Entfernen
'; - - // Berechne die Gesamtzahl der blockierten IPs - $total_ips = $wpdb->get_var("SELECT COUNT(*) FROM $table_name WHERE last_attempt >= '$five_days_ago'"); - - // Pagination + $total_ips = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM $table_name WHERE last_attempt >= %s", $five_days_ago)); $total_pages = ceil($total_ips / $per_page); - if ($total_pages > 1) { - echo '
'; - for ($i = 1; $i <= $total_pages; $i++) { - $class = ($i == $page) ? ' class="current"' : ''; - echo '' . $i . ' '; - } - echo '
'; - } - // Automatische Löschung von IPs mit weniger als 10 Versuchen, die älter als 3 Tage sind - $three_days_ago = date('Y-m-d H:i:s', strtotime('-3 days')); - $wpdb->query( - $wpdb->prepare( - "DELETE FROM $table_name WHERE attempts < 10 AND last_attempt < %s", - $three_days_ago - ) - ); + ?> +
+

+ +

+ + + + + + + + + + + + + + + + + + + + + + +
id); ?>ip); ?>attempts); ?>last_attempt); ?> + + + +
+ + 1) : ?> +
+
+ add_query_arg('paged', '%#%'), + 'format' => '', + 'prev_text' => __('«'), + 'next_text' => __('»'), + 'total' => $total_pages, + 'current' => $page, + )); + ?> +
+
+ + + + query( + $wpdb->prepare( + "DELETE FROM $table_name WHERE attempts < 10 AND last_attempt < %s", + $three_days_ago + ) + ); + ?> +
+ 403)); } global $wpdb; - - // Hole die IP-ID aus der URL $id = isset($_GET['id']) ? intval($_GET['id']) : 0; if ($id > 0) { - // Lösche die blockierte IP aus der Datenbank $table_name = $wpdb->prefix . 'blocked_ips'; - $wpdb->delete($table_name, array('id' => $id)); + $wpdb->delete($table_name, array('id' => $id), array('%d')); } - // Weiterleitung zurück zur Admin-Seite der blockierten IPs - wp_redirect(admin_url('users.php?page=wp_multi_blocked_ips')); + wp_safe_redirect(admin_url('admin.php?page=wp_multi_blocked_ips')); exit; } add_action('admin_post_remove_blocked_ip', 'wp_multi_remove_blocked_ip'); @@ -2393,181 +2618,6 @@ function wp_multi_localize_shortcodes() { add_action('admin_enqueue_scripts', 'wp_multi_localize_shortcodes'); -/* -* Update Admin-Dashboard widget -*/ - - -// Widget zum Admin-Dashboard hinzufügen -function wp_multi_update_dashboard_widget() { - wp_add_dashboard_widget( - 'wp_multi_update_widget', // Widget-ID - 'Verfügbare Updates für WP Multi', // Widget-Titel - 'wp_multi_update_dashboard_widget_content' // Callback-Funktion - ); -} -add_action('wp_dashboard_setup', 'wp_multi_update_dashboard_widget'); - -// Cron-Job registrieren -function wp_multi_update_schedule_check() { - if (!wp_next_scheduled('wp_multi_update_check_event')) { - // Registriere den Cron-Job, der alle 3 Minuten ausgeführt wird - wp_schedule_event(time(), 'three_minutes', 'wp_multi_update_check_event'); - } -} -add_action('wp', 'wp_multi_update_schedule_check'); - -// Cron-Job für Update-Überprüfung -function wp_multi_update_check() { - // Gitea API-URL - $api_url = 'https://git.viper.ipv64.net/api/v1/repos/M_Viper/wp-multi/releases'; - - // Die Version des Plugins aus den Metadaten der Plugin-Datei holen - $plugin_data = get_plugin_data( __FILE__ ); - $installed_version = $plugin_data['Version']; // Die installierte Version aus den Plugin-Metadaten - - // Hole die Einstellung, ob PreRelease-Versionen angezeigt werden sollen - $show_prereleases = get_option('wp_multi_update_show_prereleases', false); - - // Gitea API-Anfrage für die neuesten Releases ohne Authentifizierung - $response = wp_remote_get($api_url); - - if (is_wp_error($response)) { - return; // Fehler nicht weitergeben, aber nichts tun - } - - // API-Antwort verarbeiten - $body = wp_remote_retrieve_body($response); - $data = json_decode($body, true); - - // Finde das neueste, gültige Release (nicht PreRelease, falls deaktiviert) - $valid_release = null; - foreach ($data as $release) { - // Wenn PreRelease deaktiviert ist, überspringe alle PreRelease-Versionen - if (!$show_prereleases && isset($release['prerelease']) && $release['prerelease']) { - continue; - } - - if (!empty($release['tag_name'])) { - $valid_release = $release; - break; // Nur das erste gültige Release verwenden - } - } - - if ($valid_release) { - $latest_version = $valid_release['tag_name']; - $release_notes = isset($valid_release['body']) ? $valid_release['body'] : ''; - $is_prerelease = isset($valid_release['prerelease']) && $valid_release['prerelease']; - - // Speichern von Release-Daten - update_option('wp_multi_update_latest_version', $latest_version); - update_option('wp_multi_update_release_notes', $release_notes); - update_option('wp_multi_update_is_prerelease', $is_prerelease); - } -} -add_action('wp_multi_update_check_event', 'wp_multi_update_check'); - -// Callback-Funktion für das Widget -function wp_multi_update_dashboard_widget_content() { - // Gitea API-URL - $api_url = 'https://git.viper.ipv64.net/api/v1/repos/M_Viper/wp-multi/releases'; - - // Die Version des Plugins aus den Metadaten der Plugin-Datei holen - $plugin_data = get_plugin_data( __FILE__ ); - $installed_version = $plugin_data['Version']; // Die installierte Version aus den Plugin-Metadaten - - // Hole die Einstellung, ob PreRelease-Versionen angezeigt werden sollen - $show_prereleases = get_option('wp_multi_update_show_prereleases', false); - - // Gitea API-Anfrage für die neuesten Releases ohne Authentifizierung - $response = wp_remote_get($api_url); - - if (is_wp_error($response)) { - echo 'Fehler beim Abrufen der Versionsinformationen von Gitea.'; - return; - } - - // API-Antwort verarbeiten - $body = wp_remote_retrieve_body($response); - $data = json_decode($body, true); - - // Finde das neueste, gültige Release (nicht PreRelease, falls deaktiviert) - $valid_release = null; - foreach ($data as $release) { - // Wenn PreRelease deaktiviert ist, überspringe alle PreRelease-Versionen - if (!$show_prereleases && isset($release['prerelease']) && $release['prerelease']) { - continue; - } - - if (!empty($release['tag_name'])) { - $valid_release = $release; - break; // Nur das erste gültige Release verwenden - } - } - - if ($valid_release) { - $latest_version = $valid_release['tag_name']; - $release_notes = isset($valid_release['body']) ? $valid_release['body'] : ''; - $is_prerelease = isset($valid_release['prerelease']) && $valid_release['prerelease']; - - // Anzeige der Versionen und Text basierend auf PreRelease - if (version_compare($installed_version, $latest_version, '>=')) { - // Wenn die installierte Version gleich oder neuer ist als die Version in Gitea - echo '

Ihre Version ist aktuell. Version ' . $installed_version . ' ist die neueste Version.

'; - } else { - // Wenn die installierte Version älter ist als die Version in Gitea - echo '

Es ist eine neue Version von WP Multi verfügbar! Version ' . $latest_version . ' ist jetzt verfügbar.

'; - echo '

Aktuell installierte Version: ' . $installed_version . '

'; - echo '

Neue Version auf Gitea: ' . $latest_version . '

'; - - // PreRelease in blauer Schrift anzeigen, wenn erlaubt und das Update ein PreRelease ist - if ($is_prerelease && $show_prereleases) { - echo '

Dieses Update ist ein PreRelease.

'; - } - - // Verfassen-Text anzeigen, falls verfügbar - if (!empty($release_notes)) { - echo '

Information zum Update:

'; - echo '

' . nl2br(esc_html($release_notes)) . '

'; - } - - // Button-Text anpassen je nachdem, ob es ein PreRelease ist - $button_text = $is_prerelease ? 'PreRelease herunterladen' : 'Update herunterladen'; - $download_url = $valid_release['assets'][0]['browser_download_url']; - echo '

' . esc_html($button_text) . '

'; - } - } else { - echo 'Fehler beim Abrufen der neuesten Version von Gitea.'; - } -} - -// Benutzerdefinierte Intervalle für Cron hinzufügen -function wp_multi_update_custom_intervals($schedules) { - // 3 Minuten Intervall hinzufügen - $schedules['three_minutes'] = array( - 'interval' => 180, // Alle 3 Minuten - 'display' => __('Alle 3 Minuten'), - ); - return $schedules; -} -add_filter('cron_schedules', 'wp_multi_update_custom_intervals'); - -// PreRelease Option in den Einstellungen hinzufügen -function wp_multi_update_register_settings() { - add_option('wp_multi_update_show_prereleases', false); - register_setting('general', 'wp_multi_update_show_prereleases'); - add_settings_field('wp_multi_update_show_prereleases', 'Pre-Release-Versionen anzeigen', 'wp_multi_update_show_prereleases_field', 'general'); -} -add_action('admin_init', 'wp_multi_update_register_settings'); - -// Einstellung für PreRelease-Versionen -function wp_multi_update_show_prereleases_field() { - $value = get_option('wp_multi_update_show_prereleases', false); - echo ''; - echo '

Aktiviere diese Option, um Pre-Release-Versionen anzuzeigen, die noch nicht vollständig veröffentlicht wurden. Deaktiviere die Option, um nur stabile Versionen anzuzeigen.

'; -} - - /* * Notify Seite Discord & Telegram */ @@ -3776,24 +3826,23 @@ add_action('save_post', 'wp_multi_save_custom_text_choice'); // Funktion zum Hinzufügen des benutzerdefinierten Menüs function wp_stat_notice_add_custom_pages() { - // Prüfen, ob es Seiten gibt, die hinzugefügt werden müssen $custom_pages = get_option('wp_stat_notice_custom_pages', []); - // Menü hinzufügen, wenn es Seiten gibt - if ($custom_pages && is_array($custom_pages)) { + if (!empty($custom_pages) && is_array($custom_pages)) { foreach ($custom_pages as $page) { - if (isset($page['title']) && isset($page['url'])) { - // Menü hinzufügen mit WordPress Icon - add_menu_page( - $page['title'], - $page['title'], - 'manage_options', - $page['slug'], - 'wp_stat_notice_custom_page', - $page['icon'], - 100 - ); + if (!isset($page['title'], $page['slug'], $page['icon'])) { + continue; // Überspringe ungültige Einträge } + + add_menu_page( + $page['title'], + $page['title'], + 'manage_options', + $page['slug'], + 'wp_stat_notice_custom_page', + $page['icon'] ?: 'dashicons-admin-links', // Fallback-Icon + 100 + ); } } } @@ -3801,78 +3850,63 @@ add_action('admin_menu', 'wp_stat_notice_add_custom_pages'); // Callback-Funktion für das Anzeigen der benutzerdefinierten Seiten function wp_stat_notice_custom_page() { - // Aktuelle Seite abrufen - $current_slug = $_GET['page'] ?? ''; - - // Seiten aus der Option abrufen + $current_slug = isset($_GET['page']) ? sanitize_key($_GET['page']) : ''; $custom_pages = get_option('wp_stat_notice_custom_pages', []); - - if ($custom_pages && is_array($custom_pages)) { - foreach ($custom_pages as $page) { - if ($page['slug'] === $current_slug) { - // Externe Seite anzeigen - if (isset($page['url']) && filter_var($page['url'], FILTER_VALIDATE_URL)) { - // Link in einem neuen Fenster öffnen - echo ''; - } + + if (empty($custom_pages) || !is_array($custom_pages)) { + echo '

' . __('Keine benutzerdefinierten Seiten gefunden.', 'wp-stat-notice') . '

'; + return; + } + + foreach ($custom_pages as $page) { + if ($page['slug'] === $current_slug) { + if (isset($page['url']) && filter_var($page['url'], FILTER_VALIDATE_URL)) { + // Externe URL in neuem Fenster öffnen + echo ''; + echo '

' . esc_html($page['title']) . '

'; + echo '

' . __('Die externe Seite wird in einem neuen Fenster geöffnet.', 'wp-stat-notice') . '

'; + } else { // Interne Seite anzeigen - else if (isset($page['slug'])) { - echo '

' . esc_html($page['title']) . '

'; - echo '

' . __('Dies ist eine benutzerdefinierte Seite im Admin-Bereich.', 'wp-stat-notice') . '

'; - } - break; + echo '

' . esc_html($page['title']) . '

'; + echo '

' . __('Dies ist eine benutzerdefinierte Seite im Admin-Bereich.', 'wp-stat-notice') . '

'; } + return; } } + + echo '

' . __('Seite nicht gefunden.', 'wp-stat-notice') . '

'; } -// Funktion zum Hinzufügen neuer benutzerdefinierter Seiten über ein Admin-Formular +// Funktion zum Hinzufügen und Verwalten benutzerdefinierter Seiten function wp_stat_notice_add_custom_page_form() { - // Alle Dashicons laden $dashicons = [ - 'dashicons-admin-links', - 'dashicons-admin-site', - 'dashicons-admin-home', - 'dashicons-admin-plugins', - 'dashicons-admin-users', - 'dashicons-analytics', - 'dashicons-archive', - 'dashicons-book', - 'dashicons-calendar', - 'dashicons-camera', - 'dashicons-cart', - 'dashicons-cloud', - 'dashicons-clipboard', - 'dashicons-clock', - 'dashicons-cloud-upload', - 'dashicons-email', - 'dashicons-heart', - 'dashicons-laptop', - 'dashicons-lock', - 'dashicons-phone', - 'dashicons-rss', - 'dashicons-search', - 'dashicons-settings', - 'dashicons-share', - 'dashicons-tag', - 'dashicons-thumbs-up', - 'dashicons-welcome-learn-more', + 'dashicons-admin-links', 'dashicons-admin-site', 'dashicons-admin-home', + 'dashicons-admin-plugins', 'dashicons-admin-users', 'dashicons-analytics', + 'dashicons-archive', 'dashicons-book', 'dashicons-calendar', + 'dashicons-camera', 'dashicons-cart', 'dashicons-cloud', + 'dashicons-clipboard', 'dashicons-clock', 'dashicons-cloud-upload', + 'dashicons-email', 'dashicons-heart', 'dashicons-laptop', + 'dashicons-lock', 'dashicons-phone', 'dashicons-rss', + 'dashicons-search', 'dashicons-settings', 'dashicons-share', + 'dashicons-tag', 'dashicons-thumbs-up', 'dashicons-welcome-learn-more', 'dashicons-welcome-write-blog' ]; ?>

- + +
+ - - + + @@ -3886,82 +3920,72 @@ function wp_stat_notice_add_custom_page_form() { -
-
+
- -

- -

+

- + $title, - 'url' => $url, - 'slug' => $slug, - 'icon' => $icon, - ]; - - // Option speichern - update_option('wp_stat_notice_custom_pages', $custom_pages); - - // Menü neu hinzufügen - wp_stat_notice_add_custom_pages(); - - // Bestätigung - echo '

' . __('Benutzerdefinierte Seite wurde hinzugefügt!', 'wp-stat-notice') . '

'; + if (empty($title) || empty($slug)) { + echo '

' . __('Titel und Slug sind erforderlich.', 'wp-stat-notice') . '

'; + } else { + $custom_pages = get_option('wp_stat_notice_custom_pages', []); + $slugs = array_column($custom_pages, 'slug'); + if (in_array($slug, $slugs)) { + echo '

' . __('Dieser Slug wird bereits verwendet.', 'wp-stat-notice') . '

'; + } else { + $custom_pages[] = ['title' => $title, 'url' => $url, 'slug' => $slug, 'icon' => $icon]; + update_option('wp_stat_notice_custom_pages', $custom_pages); + echo '

' . __('Benutzerdefinierte Seite wurde hinzugefügt!', 'wp-stat-notice') . '

'; + } + } } - // Verwaltung der benutzerdefinierten Seiten + // Verwaltung der Seiten $custom_pages = get_option('wp_stat_notice_custom_pages', []); - if ($custom_pages) { + if (!empty($custom_pages)) { echo '

' . __('Verwaltung der benutzerdefinierten Seiten', 'wp-stat-notice') . '

'; echo ''; - echo ''; + echo ''; echo ''; foreach ($custom_pages as $index => $page) { echo ''; echo ''; - echo ''; - echo ''; + echo ''; + echo ''; + echo ''; echo ''; } - echo ''; - echo '
' . __('Titel', 'wp-stat-notice') . '' . __('URL', 'wp-stat-notice') . '' . __('Aktionen', 'wp-stat-notice') . '
' . __('Titel', 'wp-stat-notice') . '' . __('URL', 'wp-stat-notice') . '' . __('Slug', 'wp-stat-notice') . '' . __('Aktionen', 'wp-stat-notice') . '
' . esc_html($page['title']) . '' . esc_html($page['url']) . ''; - echo '' . __('Bearbeiten', 'wp-stat-notice') . ' | '; - echo '' . __('Löschen', 'wp-stat-notice') . ''; - echo '' . esc_html($page['url'] ?: '-') . '' . esc_html($page['slug']) . '' . __('Bearbeiten', 'wp-stat-notice') . ' | '; + echo '' . __('Löschen', 'wp-stat-notice') . '
'; + echo ''; } - // Bearbeiten und Löschen von Seiten - if (isset($_GET['edit'])) { - $edit_index = (int) $_GET['edit']; + // Bearbeiten + if (isset($_GET['edit']) && isset($custom_pages[$_GET['edit']])) { + $edit_index = (int)$_GET['edit']; $edit_page = $custom_pages[$edit_index]; - // Formular zum Bearbeiten der Seite echo '

' . __('Seite bearbeiten', 'wp-stat-notice') . '

'; ?>
+ - - + + @@ -3969,64 +3993,71 @@ function wp_stat_notice_add_custom_page_form() { - +
+ +
+
- -

- -

+

-

' . __('Seite erfolgreich bearbeitet!', 'wp-stat-notice') . '

'; + if (isset($_POST['save_custom_page']) && check_admin_referer('wp_stat_notice_edit_page', 'wp_stat_notice_nonce')) { + $title = sanitize_text_field($_POST['edit_page_title']); + $url = !empty($_POST['edit_page_url']) ? esc_url_raw($_POST['edit_page_url']) : ''; + $slug = sanitize_key($_POST['edit_page_slug']); + $icon = in_array($_POST['edit_page_icon'], $dashicons) ? $_POST['edit_page_icon'] : 'dashicons-admin-links'; + + if (empty($title) || empty($slug)) { + echo '

' . __('Titel und Slug sind erforderlich.', 'wp-stat-notice') . '

'; + } else { + $custom_pages[$edit_index] = ['title' => $title, 'url' => $url, 'slug' => $slug, 'icon' => $icon]; + update_option('wp_stat_notice_custom_pages', $custom_pages); + echo '

' . __('Seite erfolgreich bearbeitet!', 'wp-stat-notice') . '

'; + } } } - // Löschen der Seite - if (isset($_GET['delete'])) { - $delete_index = (int) $_GET['delete']; + // Löschen + if (isset($_GET['delete']) && isset($custom_pages[$_GET['delete']])) { + $delete_index = (int)$_GET['delete']; unset($custom_pages[$delete_index]); - $custom_pages = array_values($custom_pages); + $custom_pages = array_values($custom_pages); update_option('wp_stat_notice_custom_pages', $custom_pages); - echo '

' . __('Seite wurde gelöscht.', 'wp-stat-notice') . '

'; } ?>