23 Commits
Author SHA1 Message Date
M_Viper 90f388f49c Upload via GUI (39 Dateien) 2026-08-14 07:59:43 +00:00
M_Viper 05a2e1c7b6 Upload via GUI (39 Dateien) 2026-08-14 07:59:42 +00:00
M_Viper cfcbcd5b02 Upload via GUI (39 Dateien) 2026-08-14 07:59:41 +00:00
M_Viper 96d4c07cc6 Delete css/admin-style.css via Git Manager GUI 2026-08-14 07:58:37 +00:00
M_Viper 7b58dea6ff wp-multi.php aktualisiert 2025-10-03 07:51:07 +00:00
M_Viper 778563d991 README.md aktualisiert 2025-04-20 15:59:34 +00:00
M_Viper d332fac418 wp-multi.php aktualisiert 2025-04-20 14:00:59 +00:00
M_Viper 2a7042bb4e wp-multi.php aktualisiert 2025-04-15 18:41:59 +00:00
M_Viper 78ccb38f36 wp-multi.php aktualisiert 2025-04-12 10:51:49 +00:00
M_Viper 2456a72d41 wp-multi.php aktualisiert 2025-04-09 20:24:38 +00:00
M_Viper b4bf55c611 wp-multi.php aktualisiert 2025-04-09 14:24:42 +00:00
M_Viper 8822dad583 wp-multi.php aktualisiert 2025-04-07 22:18:26 +00:00
M_Viper 0b02e28c8a wp-multi.php aktualisiert 2025-04-07 12:06:17 +00:00
M_Viper 0a8b364de6 README.md aktualisiert 2025-03-26 08:02:57 +00:00
M_Viper 13e26ada1a README.md aktualisiert 2025-03-26 07:50:16 +00:00
M_Viper 5704f6d86b wp-multi.php aktualisiert 2025-03-25 16:35:55 +00:00
M_Viper 7ff5fc952a includes/bad-words.json aktualisiert 2025-03-15 22:09:16 +00:00
M_Viper 1f08bcd9c0 includes/bad-words.json aktualisiert 2025-03-15 22:04:33 +00:00
M_Viper aa71c2bbc8 includes/bad-words.json aktualisiert 2025-03-15 22:03:14 +00:00
M_Viper 8c77da9a1f includes/bad-words.json aktualisiert 2025-03-15 22:02:32 +00:00
M_Viper b155b952a3 includes/bad-words.json aktualisiert 2025-03-15 21:51:38 +00:00
M_Viper efafb156a7 includes/bad-words.json aktualisiert 2025-03-09 18:21:35 +00:00
M_Viper 32dea5d00b wp-multi.php aktualisiert 2025-03-08 20:23:02 +00:00
34 changed files with 17038 additions and 16557 deletions
+119 -132
View File
@@ -1,159 +1,146 @@
# WP-Multi Plugin für WordPress
# WP Multi
**WP-Multi** ist ein multifunktionales WordPress-Plugin, das eine breite Palette von leistungsstarken Funktionen zur Verwaltung deiner Website bietet. Es umfasst Statistiken, benutzerdefinierte Admin-Links, Schutzmechanismen gegen Spam und Brute-Force-Angriffe, sowie viele nützliche Tools für die Verbesserung des Benutzererlebnisses und der Website-Verwaltung.
**Erweiterter Anti-Spam-Schutz, Sicherheitsfeatures, Inhaltsmanagement und mehr für WordPress**
Das Plugin ist darauf ausgelegt, dir zu helfen, eine detaillierte Übersicht über die Interaktionen auf deiner Seite zu erhalten, Beiträge effizient zu verwalten und gleichzeitig die Sicherheit und das Benutzererlebnis zu optimieren.
[![PHP Version](https://img.shields.io/badge/PHP-7.4%2B-blue)](https://www.php.net/)
[![WordPress Version](https://img.shields.io/badge/WordPress-6.7.2%2B-green)](https://wordpress.org/)
[![License](https://img.shields.io/badge/License-GPLv2-brightgreen)](https://www.gnu.org/licenses/gpl-2.0.html)
**WP Multi** ist ein umfassendes WordPress-Plugin, das fortschrittlichen Anti-Spam-Schutz mit Funktionen wie Honeypot, Keyword-Filter, Link-Limit und mehr bietet. Es integriert Statistiken im Dashboard, HappyForms-Unterstützung und zahlreiche nützliche Tools wie automatische Tags, Lesezeichen für Gäste und Schutz vor Brute-Force-Angriffen. Zusätzlich bietet es Anpassungen des Admin-Bereichs und Schutz vor dem Kopieren von Inhalten.
## Funktionen
### 1. **Statistik-Übersicht**
- **Zeigt detaillierte Statistiken an:**
- Anzahl der Beiträge
- Anzahl der Kommentare
- Anzahl der Kategorien
- Anzahl der Serien
- **Shortcode für die Anzeige der Statistik:** `[statistik_manager]`
- **Anti-Spam-Schutz:**
- Honeypot-Felder zur Erkennung von Bots
- Blockierung von Einweg-Mail-Adressen (Trash-Mails)
- Filter für blockierte Schlüsselwörter und maximale Links in Kommentaren
- Statistik über blockierte Kommentare und Spammer-IPs
### 2. **Benachrichtigungen auf Telegram und Discord**
- **Telegram & Discord Benachrichtigungen:**
- Du erhältst Benachrichtigungen in Echtzeit über neue Beiträge auf deiner Website. So bleibst du immer auf dem Laufenden.
- Unterstützt sowohl Telegram als auch Discord.
- **Sicherheitsfunktionen:**
- Schutz vor Brute-Force-Angriffen mit IP-Sperrung
- Textkopierschutz und Einschränkung der Entwicklertools
- Möglichkeit, Benutzer-Logins zu deaktivieren
### 3. **Custom Admin Links**
- **Fügt benutzerdefinierte Links im WordPress-Adminbereich hinzu:**
- Erstelle und verwalte eigene Links, die direkt im Admin-Dashboard angezeigt werden, um den Verwaltungsaufwand zu reduzieren und deine Arbeit zu optimieren.
- **Inhaltsmanagement:**
- Automatische Generierung von Tags für Beiträge
- Alphabetisches Index für Beiträge mit Shortcode `[alphabetical_index]`
- Beitrag melden mit Shortcode `[report_button]`
### 4. **Gast-Autor**
- **Gast-Autor Feature:**
- Ermögliche es, einen Gast-Autornamen für Beiträge festzulegen. Der Name wird im Frontend des Beitrags angezeigt und dient dazu, die Quellen klar darzustellen.
### 5. **Beitrags-Report**
- **Melden unangemessener oder falscher Beiträge:**
- Benutzer können Beiträge melden, die unangemessen oder fehlerhaft sind. Du erhältst eine Benachrichtigung im Admin-Panel und kannst sofort handeln.
- Der Admin kann alle gemeldeten Beiträge im Adminbereich einsehen und gegebenenfalls Maßnahmen ergreifen.
- **Benutzerfreundlichkeit:**
- Lesezeichen für Gäste mit Shortcodes `[add_bookmark]` und `[display_bookmarks]`
- Statistik-Widget mit Shortcode `[statistik_manager]`
- Anpassbares Banner mit Position, Farbe und Icon
### 6. **Custom Textbox**
- **Fügt benutzerdefinierte Textboxen hinzu:**
- Erstelle Textboxen mit vordefinierten Inhalten, die in jedem Beitrag angezeigt werden.
- Diese Textboxen können leicht im Admin-Panel konfiguriert werden.
- **Gast Autoren:**
- Alphabetisches Index für Gast Autoren mit Shortcode `[guest_authors]`
### 7. **Banner für Nachrichten**
- **Banner für Ankündigungen und Informationen:**
- Zeige wichtige Nachrichten als Banner im Frontend deiner Website an. Die Banner können entweder im Header oder im Footer angezeigt werden.
- **Admin-Tools:**
- Dashboard-Widget für Plugin-Updates (mit Pre-Release-Unterstützung)
- Pinnwand für Administratoren
- Verwaltung benutzerdefinierter Seiten und gemeldeter Beiträge
### 8. **Admin Dashboard Update Anzeige**
- **Plugin-Update Benachrichtigung im Admin-Dashboard:**
- Zeigt im Admin-Dashboard an, ob eine neue Version von **WP-Multi** verfügbar ist und ob ein Update notwendig ist.
### 9. **Gast Lesezeichen**
- **Lesezeichen für Gäste:**
- Gäste können Beiträge mit einem Lesezeichen versehen, das über Cookies gespeichert wird.
- **Shortcodes:**
- `[add_bookmark]` Fügt ein Lesezeichen hinzu.
- `[display_bookmarks]` Zeigt alle Lesezeichen des Besuchers an.
### 10. **Benutzer für Kommentare sperren**
- **Verhindert störende Kommentare:**
- Sperre bestimmte Benutzer vom Kommentieren, indem du ihren Benutzernamen, ihre IP-Adresse oder E-Mail-Adresse eingibst. Diese Benutzer können dann keine weiteren Kommentare abgeben.
### 11. **Kommentar Filter**
- **Automatischer Filter für schadhafte Inhalte:**
- Verhindert das Senden von bestimmten Informationen in Kommentaren wie:
- Rufnummern
- E-Mail-Adressen
- URLs
- IP-Adressen
- Schimpfwörtern
- Diese Elemente werden automatisch durch `*` ersetzt, wenn sie gesendet werden.
### 12. **Custom Shortcodes**
- **Erstellung benutzerdefinierter Shortcodes:**
- Du kannst benutzerdefinierte Shortcodes erstellen, die im WordPress-Editor per Auswahl eingefügt werden können, um die Flexibilität und Funktionalität deiner Seite zu erweitern.
### 13. **Besucher Analytics**
- **Verfolge die beliebtesten Beiträge:**
- Sieh dir an, welche Beiträge am häufigsten angesehen oder kommentiert werden.
- Es wird angezeigt:
- Art der Aktion (View oder Comment)
- Titel des Beitrags
- Beitrag-ID
- Zeitstempel der Aktion
### 14. **Pinwand für Administratoren**
- **Nachrichten und Ankündigungen für Administratoren:**
- Erstelle, bearbeite und lösche Nachrichten auf der Pinwand im Admin-Panel. Diese Nachrichten können für andere Administratoren und Benutzer sichtbar sein.
### 15. **Schutz vor Brute-Force-Angriffen**
- **Sperrung nach Fehlversuchen:**
- Alle fehlgeschlagenen Login-Versuche werden protokolliert. Nach fünf fehlgeschlagenen Versuchen wird der Account automatisch gesperrt und eine E-Mail-Benachrichtigung an den Administrator und den betroffenen Benutzer gesendet.
### 16. **Anti-Spam Honey**
- **Automatischer Spam-Schutz:**
- Das Plugin erkennt Spam, Bots und andere unerwünschte Aktivitäten und blockiert diese automatisch.
- Eine detaillierte Übersicht über blockierte Inhalte wird im Admin-Panel bereitgestellt.
### 17. **Auto Tagging**
- **Automatisches Hinzufügen von Tags:**
- Wenn ein Beitrag keine Tags hat, fügt das Plugin automatisch relevante Tags hinzu.
- Du kannst im Admin-Panel eine Liste von unerwünschten Tags definieren, die das Plugin niemals hinzufügen soll.
### 18. **Login Deaktivieren**
- **Deaktiviere das Login für bestimmte Benutzer:**
- Du kannst das Login für bestimmte Benutzer deaktivieren, um unbefugten Zugriff zu verhindern. Diese Funktion kann direkt im Benutzerprofil aktiviert werden.
### 19. **Text Copy Schutz**
- **Schutz vor unerlaubtem Kopieren:**
- Verhindert das Kopieren von Texten auf deiner Website, um die Inhalte zu schützen.
### 20. **Sperre Trash-Mail-Adressen**
- **Blockiere Trash-Mail-Adressen in Kommentaren:**
- Trash-Mail-Adressen werden in Kommentaren blockiert. Die Liste der blockierten Domains kann nur vom Entwickler des Plugins erweitert werden.
### 21. **Inhaltsverzeichnis für Beiträge**
- **Erstelle ein Inhaltsverzeichnis für Beiträge:**
- Erstelle automatisch ein alphabetisches Inhaltsverzeichnis aller Beiträge auf deiner Website.
- **Shortcode:** `[alphabetical_index]`
---
- **Integrationen:**
- HappyForms-Unterstützung
- Gitea-API für automatische Update-Prüfungen
## Installation
### Schritt 1: Plugin herunterladen
Lade das **WP-Multi Plugin** als ZIP-Datei von GitHub oder deinem bevorzugten Source-Repository herunter.
1. **Download:**
- Lade das Plugin von [Gitea](https://git.viper.ipv64.net/M_Viper/wp-multi) herunter oder klone das Repository:
### Schritt 2: Plugin installieren
1. Gehe in deinem WordPress-Adminbereich zu **Plugins** > **Installieren**.
2. Klicke auf **Plugin hochladen** und wähle die ZIP-Datei des Plugins aus.
3. Klicke auf **Jetzt installieren** und dann auf **Aktivieren**.
```
git clone https://git.viper.ipv64.net/M_Viper/wp-multi.git
```
### Schritt 3: Plugin konfigurieren
Nach der Aktivierung kannst du das Plugin über das **WP-Multi** Menü im Adminbereich konfigurieren. Passe die Einstellungen nach deinen Bedürfnissen an, um alle Funktionen optimal zu nutzen.
2. **Installation:**
---
Kopiere den Ordner `wp-multi` in dein WordPress-Plugin-Verzeichnis (`/wp-content/plugins/`).
Alternativ: Lade die ZIP-Datei über das WordPress-Admin-Panel hoch (`Plugins > Neu hinzufügen > Plugin hochladen`).
## Verwendung
3. **Aktivierung:**
Nach der Installation kannst du die Funktionen und Shortcodes im Adminbereich oder direkt in deinen Beiträgen verwenden. Hier sind einige nützliche Shortcodes:
Gehe im WordPress-Admin-Bereich zu "Plugins" und aktiviere "WP Multi".
- **Statistik anzeigen:** `[statistik_manager]`
- **Lesezeichen hinzufügen:** `[add_bookmark]`
- **Lesezeichen anzeigen:** `[display_bookmarks]`
- **Inhaltsverzeichnis anzeigen:** `[alphabetical_index]`
## Nutzung
Im Adminbereich kannst du auch die benutzerdefinierten Funktionen wie die Textboxen, Kommentar-Filter und Anti-Spam-Maßnahmen konfigurieren.
### Admin-Konfiguration
---
Nach der Aktivierung finden Sie die WP Multi-Einstellungen im WordPress-Admin-Bereich. Hier können Sie die verschiedenen Funktionen konfigurieren:
* **WP Multi -> Sicherheit:**
* Konfigurieren Sie den Honeypot-Schutz.
* Verwalten Sie blockierte IPs und Schlüsselwörter zur Spam-Bekämpfung.
* Aktivieren Sie den Schutz vor dem Kopieren von Text und den Schutz der Entwicklertools.
* **WP Multi -> Automatische Tags:**
* Passen Sie Stopwörter an, die bei der automatischen Tag-Generierung ignoriert werden sollen.
* Führen Sie die automatische Tag-Generierung für vorhandene Beiträge aus.
* **WP Multi -> WP Stat & Notice:**
* Aktivieren oder deaktivieren Sie die Statistik-Funktionen.
* Konfigurieren Sie das anpassbare Admin-Banner (Farbe, Position, Text).
* **WP Multi -> Gemeldete Beiträge:**
* Überprüfen und verwalten Sie von Benutzern gemeldete Beiträge.
* **WP Multi -> Admin-Pinnwand:**
* Zeigen Sie wichtige Nachrichten und Hinweise für Administratoren an.
### Shortcodes
* `[alphabetical_index]`: Zeigt ein alphabetisches Verzeichnis aller Beiträge an.
- Attribute:
- `posts_per_page`: Anzahl der Beiträge pro Seite (Standard: 20).
* `[report_button]`: Fügt einen "Beitrag melden"-Button hinzu (nur für eingeloggte Benutzer).
* `[add_bookmark]`: Fügt ein Formular zum Hinzufügen von Lesezeichen für Gäste hinzu.
- Ermöglicht es nicht registrierten Besuchern, Beiträge zu ihren Lesezeichen hinzuzufügen.
* `[display_bookmarks]`: Zeigt die gespeicherten Lesezeichen eines Gastes an.
- Zeigt eine Liste der gespeicherten Lesezeichen an, die mit einem Cookie identifiziert werden.
* `[statistik_manager]`: Zeigt eine Statistikübersicht an (Beiträge, Kommentare, Kategorien, etc.).
### Beispielkonfiguration
* Füge den Shortcode `[statistik_manager]` in eine Seite ein, um detaillierte Website-Statistiken anzuzeigen.
* Aktiviere das Banner unter "WP Stat & Notice" und wähle eine Farbe sowie Position (oben/unten), um Administratoren wichtige Hinweise anzuzeigen.
* Konfiguriere blockierte Schlüsselwörter wie `viagra`, `casino` im Anti-Spam-Menü, um unerwünschte Kommentare zu filtern.
* Verwende den Shortcode `[alphabetical_index posts_per_page="30"]`, um das alphabetische Verzeichnis mit 30 Beiträgen pro Seite anzuzeigen.
### Details zu Kernfunktionen
* **Update Benachrichtigungen:** Das Plugin überprüft regelmäßig über die Gitea-API auf neue Versionen. Sie können in den Einstellungen festlegen, ob Pre-Release-Versionen angezeigt werden sollen. Im Dashboard wird ein Widget angezeigt, das Sie über verfügbare Updates informiert und einen direkten Download-Link bereitstellt.
* **Schutz vor Trash-Mails:** Das Plugin verwendet eine Blockliste von Einweg-E-Mail-Anbietern, um zu verhindern, dass Spam-Kommentare über temporäre E-Mail-Adressen abgegeben werden.
* **Text Copy Schutz und Schutz vor Entwicklertools:** Das Plugin verhindert das Markieren und Kopieren von Text auf Ihrer Webseite und blockiert den Zugriff auf Entwicklertools, um den Quellcode vor unbefugtem Zugriff zu schützen.
* **Admin Banner:** Über das Admin-Panel kann ein anpassbares Banner angezeigt werden, um Administratoren wichtige Informationen oder Hinweise zu geben.
## Voraussetzungen
* WordPress 6.7.2 oder höher
* PHP 7.4 oder höher
## Support
* Microsoft Teams: [Support-Community](https://teams.live.com/l/community/FEAzokphpZTJ2u6OgI)
* Telegram: [Support-Chat](https://t.me/M_Viper04)
* Gitea: [Erstelle ein Issue auf Gitea](https://git.viper.ipv64.net/M_Viper/wp-multi/issues)
## Beitrag leisten
1. Forke das Repository auf Gitea.
2. Erstelle einen neuen Branch: `git checkout -b feature/deine-funktion`.
3. Committe deine Änderungen: `git commit -m "Beschreibung deiner Änderungen"`.
4. Pushe den Branch: `git push origin feature/deine-funktion`.
5. Erstelle einen Pull-Request auf Gitea.
## Lizenz
Dieses Plugin ist unter der [GPL-2.0 Lizenz](https://www.gnu.org/licenses/old-licenses/gpl-2.0.de.html) veröffentlicht.
Dieses Plugin ist unter der GPLv2-Lizenz veröffentlicht. Siehe [LICENSE](LICENSE) -Datei für Details.
---
## Danksagung
## Unterstützung
Wenn du Fragen hast oder auf Probleme stößt, eröffne ein **Issue** auf GitHub. Wir sind gerne bereit, dir zu helfen!
---
Vielen Dank, dass du **WP-Multi** verwendest! Wir hoffen, dass es dir hilft, deine WordPress-Website effizient zu verwalten und zu schützen.
Entwickelt von M\_Viper. Vielen Dank an die WordPress-Community für die Inspiration und Unterstützung.
-193
View File
@@ -1,193 +0,0 @@
/* Allgemeines Styling für die Admin-Seite */
.wrap {
max-width: 1200px;
margin: 0 auto;
padding: 30px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
font-family: Arial, sans-serif;
}
.wrap h1 {
font-size: 28px;
color: #333;
font-weight: 700;
text-transform: uppercase;
margin-bottom: 30px;
}
/* Logo */
/* Blaues Banner hinter dem Logo */
.statistik-manager-logo {
text-align: center;
margin-bottom: 30px;
background: linear-gradient(135deg, #0073aa, #00c6ff); /* Blaues Farbverlauf-Banner */
padding: 20px;
border-radius: 10px;
}
/* Logo im Banner */
.statistik-manager-logo img {
max-width: 200px;
display: block;
margin: 0 auto;
}
/* Container, der die Statistikoptionen und die Werbung nebeneinander anordnet */
.statistik-manager-content {
display: flex;
flex-wrap: wrap;
gap: 30px;
align-items: stretch; /* Stellt sicher, dass beide Boxen die gleiche Höhe haben */
}
/* Linke Spalte Statistik-Einstellungen (größerer Bereich) */
.statistik-manager-settings {
flex: 2;
display: flex;
flex-direction: column;
}
/* Titel in der Auswahlbox "Statistiken anzeigen" */
.statistik-manager-settings h2 {
font-size: 22px;
color: #0073aa;
text-transform: uppercase;
text-align: center;
padding: 10px 0;
margin-bottom: 20px;
border-bottom: 2px solid #0073aa;
}
/* Rechte Spalte Werbung für weitere Plugins (kleinerer Bereich) */
.statistik-manager-advertisement {
flex: 1;
background-color: #fff;
border: 1px solid #eaeaea;
border-radius: 8px;
padding: 20px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
height: fit-content;
margin-top: 80px; /* Größerer Abstand nach oben */
}
/* Werbung Überschrift */
.statistik-manager-advertisement h2 {
font-size: 20px;
color: #333;
margin-bottom: 15px;
text-transform: uppercase;
letter-spacing: 1px;
text-align: center;
}
/* Werbung Liste */
.statistik-manager-advertisement ul {
list-style: none;
padding: 0;
margin: 0;
}
.statistik-manager-advertisement ul li {
margin-bottom: 12px;
}
.statistik-manager-advertisement ul li a {
font-size: 16px;
color: #0073aa;
text-decoration: none;
transition: color 0.3s ease, transform 0.3s ease;
display: inline-block;
}
.statistik-manager-advertisement ul li a:hover {
color: #005177;
transform: translateX(5px);
}
/* Formular-Tabelle für die Einstellungen */
.form-table {
width: 100%;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
padding: 25px 35px;
margin-bottom: 30px;
}
.form-table th {
font-size: 16px;
color: #444;
padding-bottom: 15px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.form-table td {
font-size: 15px;
color: #666;
padding: 8px 0;
}
/* Submit-Button */
button.submit, .submit {
font-size: 12px; /* Kleinere Schriftgröße */
cursor: pointer;
}
/* Zusätzlicher Abstand nach links für den Text in der Tabellenüberschrift */
.form-table th {
padding-left: 30px; /* Erhöht den Abstand nach links */
}
.statistik-manager-banner {
width: 100%;
text-align: center;
padding: 10px;
font-size: 18px;
font-weight: bold;
}
.statistik-manager-container {
display: flex;
flex-direction: column;
gap: 20px; /* Abstand zwischen den Boxen */
}
.statistik-manager-plugins,
.statistik-manager-advertisement {
background-color: #f5f5f5;
padding: 20px;
border-radius: 8px;
border: 1px solid #ddd;
}
.statistik-manager-plugins h3,
.statistik-manager-advertisement h3 {
font-size: 18px;
font-weight: bold;
color: #333;
margin-bottom: 15px;
}
.statistik-manager-plugins ul {
list-style-type: none;
padding-left: 0;
}
.statistik-manager-plugins ul li {
margin-bottom: 10px;
}
.statistik-manager-plugins ul li a {
text-decoration: none;
color: #0073aa;
font-weight: 500;
}
.statistik-manager-plugins ul li a:hover {
color: #005077;
}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 372 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 641 KiB

+108
View File
@@ -0,0 +1,108 @@
<?php
/**
* WP Multi Modul: Admin-Panel-Banner & Plugin-Links
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Admin - Panel Banner
*/
// Anzahl Tage, die das Banner nach dem Schließen ausgeblendet bleibt
if (!defined('WP_MULTI_BANNER_DAYS')) {
define('WP_MULTI_BANNER_DAYS', 7);
}
// Prüft, ob das Banner für den aktuellen Benutzer noch ausgeblendet ist
function wp_multi_banner_is_dismissed() {
$ts = (int) get_user_meta(get_current_user_id(), 'wp_multi_banner_dismissed', true);
return $ts > 0 && (time() - $ts) < (WP_MULTI_BANNER_DAYS * DAY_IN_SECONDS);
}
// Admin-Banner als Notice mit Blauem Hintergrund (#0073aa)
function wp_multi_add_warning_banner() {
// Nach dem Schließen für WP_MULTI_BANNER_DAYS Tage nicht mehr anzeigen
if (wp_multi_banner_is_dismissed()) {
return;
}
// Verwende printf für bessere Lesbarkeit und Übersetzbarkeit
printf(
'<div class="notice notice-warning is-dismissible wp-multi-feedback-notice" data-wpm-nonce="%s" style="background-color: #0073aa; color: white; border-left: 4px solid #005177;">
<p><strong>%s</strong> %s <a href="%s" target="_blank" style="color: #FFDD00; text-decoration: none;">%s</a> %s</p>
<p><strong>%s:</strong> %s <a href="%s" target="_blank" style="color: #FFDD00; text-decoration: none;">%s</a> %s <a href="%s" target="_blank" style="color: #FFDD00; text-decoration: none;">%s</a> %s</p>
</div>',
esc_attr(wp_create_nonce('wp_multi_dismiss_banner')),
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://discord.com/invite/FdRs4BRd8D',
esc_html__('Discord', 'wp-multi'),
esc_html__('oder', 'wp-multi'),
'https://t.me/M_Viper04',
esc_html__('Telegram', 'wp-multi'),
esc_html__('erreichen.', 'wp-multi')
);
// Beim Klick auf das X den Schließ-Zeitpunkt speichern (per AJAX)
?>
<script>
(function () {
var notice = document.querySelector('.wp-multi-feedback-notice');
if (!notice || typeof ajaxurl === 'undefined') { return; }
notice.addEventListener('click', function (e) {
if (e.target && e.target.classList.contains('notice-dismiss')) {
var body = 'action=wp_multi_dismiss_banner&nonce=' + encodeURIComponent(notice.getAttribute('data-wpm-nonce'));
fetch(ajaxurl, {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: body
});
}
});
})();
</script>
<?php
}
add_action('admin_notices', 'wp_multi_add_warning_banner');
// AJAX: Schließ-Zeitpunkt des Banners für den aktuellen Benutzer merken
function wp_multi_dismiss_banner() {
check_ajax_referer('wp_multi_dismiss_banner', 'nonce');
update_user_meta(get_current_user_id(), 'wp_multi_banner_dismissed', time());
wp_send_json_success();
}
add_action('wp_ajax_wp_multi_dismiss_banner', 'wp_multi_dismiss_banner');
// Support-Links in der Plugin-Übersicht anzeigen
function wp_multi_plugin_row_meta($links, $file) {
if ($file === plugin_basename(WP_MULTI_FILE)) {
$new_links = array(
'support_teams' => sprintf(
'<a href="%s" target="_blank" style="color: rgb(255, 0, 0);">%s</a>',
esc_url('https://discord.com/invite/FdRs4BRd8D'),
esc_html__('Discord Support', 'wp-multi')
),
'support_telegram' => sprintf(
'<a href="%s" target="_blank" style="color: rgb(255, 0, 0);">%s</a>',
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);
+88
View File
@@ -0,0 +1,88 @@
<?php
/**
* WP Multi Modul: Zentrale Menü-Registrierung
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Zentrale Menü-Registrierung
*
* Alle Admin-Seiten von WP Multi hängen als Submenüs am gemeinsamen
* Top-Level-Menü "WP Multi" (Slug 'wp-multi'), das das Toolkit mit
* admin_menu-Priorität 9 registriert. Diese Funktion läuft mit
* Priorität 20 und legt bei fehlendem Toolkit-Menü ein Fallback an.
*/
function wp_multi_register_admin_menus() {
global $admin_page_hooks;
$parent = 'wp-multi';
// Fallback: falls das Toolkit-Top-Level (noch) nicht existiert
if (empty($admin_page_hooks[$parent])) {
add_menu_page(
__('WP Multi', 'wp-multi'),
__('WP Multi', 'wp-multi'),
'manage_options',
$parent,
'wp_multi_security_settings_page',
'dashicons-screenoptions',
59
);
}
$hooks = array();
// Sicherheit
$hooks[] = add_submenu_page($parent, __('Sicherheit', 'wp-multi'), __('Sicherheit', 'wp-multi'), 'manage_options', 'wp-multi-security', 'wp_multi_security_settings_page');
$hooks[] = add_submenu_page($parent, __('WP Multi Statistik', 'wp-multi'), __('Sicherheits-Statistik', 'wp-multi'), 'manage_options', 'wp-multi-statistics', 'wp_multi_statistics_page');
$hooks[] = add_submenu_page($parent, __('Sicherheitseinstellungen', 'wp-multi'), __('Benutzer-Sicherheit', 'wp-multi'), 'manage_options', 'wp_multi_users_security_settings', 'wp_multi_users_security_settings_page');
$hooks[] = add_submenu_page($parent, __('Blockierte IPs', 'wp-multi'), __('Blockierte IPs', 'wp-multi'), 'manage_options', 'wp_multi_blocked_ips', 'wp_multi_display_blocked_ips');
$hooks[] = add_submenu_page($parent, __('Gesperrte Benutzer', 'wp-multi'), __('Gesperrte Benutzer', 'wp-multi'), 'manage_options', 'wp-multi-blocked-users', 'wp_multi_blocked_users_page');
$hooks[] = add_submenu_page($parent, __('Login-URL', 'wp-multi'), __('Login-URL', 'wp-multi'), 'manage_options', 'wp_multi_login_url', 'wp_multi_login_url_page');
$hooks[] = add_submenu_page($parent, __('Login-Design', 'wp-multi'), __('Login-Design', 'wp-multi'), 'manage_options', 'wp_multi_login_design', 'wp_multi_login_design_page');
// Analyse & Inhalte
$hooks[] = add_submenu_page($parent, __('Benutzer Analytics', 'wp-multi'), __('Benutzer-Analytics', 'wp-multi'), 'manage_options', 'wp_multi_analytics', 'wp_multi_display_user_analytics');
$hooks[] = add_submenu_page($parent, __('Gast-Autor Übersicht', 'wp-multi'), __('Gast-Autoren', 'wp-multi'), 'manage_options', 'guest_author_overview', 'wp_multi_guest_author_overview_page');
$hooks[] = add_submenu_page($parent, __('Pinwand', 'wp-multi'), __('Pinwand', 'wp-multi'), 'manage_options', 'message-board', 'wp_multi_add_message_board');
$hooks[] = add_submenu_page($parent, __('Gemeldete Beiträge', 'wp-multi'), __('Gemeldete Beiträge', 'wp-multi'), 'manage_options', 'reported-posts', 'wp_stat_notice_reported_posts_page');
$hooks[] = add_submenu_page($parent, __('WP Stat & Notice', 'wp-multi'), __('Statistik & Notice', 'wp-multi'), 'manage_options', 'statistik_manager', 'statistik_manager_options_page');
// Werkzeuge
$hooks[] = add_submenu_page($parent, __('Custom Shortcodes', 'wp-multi'), __('Shortcodes', 'wp-multi'), 'manage_options', 'wp_multi_shortcodes', 'wp_multi_shortcode_page');
$hooks[] = add_submenu_page($parent, __('Automatische Tags', 'wp-multi'), __('Auto-Tags', 'wp-multi'), 'manage_options', 'wp-multi-auto-tags', 'wp_multi_auto_tags_page');
$hooks[] = add_submenu_page($parent, __('Custom Text Einstellungen', 'wp-multi'), __('Custom Text', 'wp-multi'), 'manage_options', 'wp_multi_custom_text_settings', 'wp_multi_custom_text_settings_page_content');
// Benachrichtigungen
$hooks[] = add_submenu_page($parent, __('Notify', 'wp-multi'), __('Notify', 'wp-multi'), 'manage_options', 'wp-multi-notify', 'wp_multi_notify_page');
$hooks[] = add_submenu_page($parent, __('DC-Notify Einstellungen', 'wp-multi'), __('DC-Notify', 'wp-multi'), 'manage_options', 'wp-multi-dc-notify', 'wp_multi_settings_page');
$hooks[] = add_submenu_page($parent, __('TG-Notify Einstellungen', 'wp-multi'), __('TG-Notify', 'wp-multi'), 'manage_options', 'tg-notify', 'tg_notify_page');
// Custom Admin-Links
$hooks[] = add_submenu_page($parent, __('Admin-Link hinzufügen', 'wp-multi'), __('Admin-Links', 'wp-multi'), 'manage_options', 'wp-stat-notice-custom-page', 'wp_stat_notice_add_custom_page_form');
// Benutzerdefinierte Admin-Link-Seiten (dynamisch aus Option)
$custom_pages = get_option('wp_stat_notice_custom_pages', []);
if (!empty($custom_pages) && is_array($custom_pages)) {
foreach ($custom_pages as $page) {
if (!isset($page['title'], $page['slug'])) {
continue;
}
$hooks[] = add_submenu_page($parent, $page['title'], $page['title'], 'manage_options', $page['slug'], 'wp_stat_notice_custom_page');
}
}
// Hooks beim Design-System des Toolkits anmelden (lädt das gemeinsame CSS)
if (function_exists('wpmt_register_admin_hook')) {
foreach ($hooks as $hook) {
wpmt_register_admin_hook($hook);
}
}
}
add_action('admin_menu', 'wp_multi_register_admin_menus', 20);
+178
View File
@@ -0,0 +1,178 @@
<?php
/**
* WP Multi Modul: Inhaltsverzeichnis [alphabetical_index]
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Index Verzeichnis [alphabetical_index]
*/
// Shortcode zum Erstellen des Indexes
function wp_multi_alphabetical_index($atts) {
// Definiere die Argumente für den Shortcode
$atts = shortcode_atts(array(
'posts_per_page' => 20, // Maximale Beiträge pro Seite
), $atts, 'alphabetical_index');
// Hole alle Beiträge
$args = array(
'post_type' => 'post',
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
);
$posts = get_posts($args);
// Beiträge nach Anfangsbuchstaben gruppieren
$alphabet = range('A', 'Z');
$posts_by_letter = array();
foreach ($posts as $post) {
$first_letter = strtoupper(substr($post->post_title, 0, 1));
if (in_array($first_letter, $alphabet)) {
$posts_by_letter[$first_letter][] = $post;
}
}
// Holen des aktuellen Buchstabens aus der URL
$letter = isset($_GET['letter']) ? strtoupper($_GET['letter']) : ''; // Der Buchstabe aus der URL
// Bestimme, welche Beiträge angezeigt werden
$posts_in_letter = [];
if ($letter && isset($posts_by_letter[$letter])) {
$posts_in_letter = $posts_by_letter[$letter];
}
// Teile die Beiträge in zwei Hälften für die Boxen
$halfway = ceil(count($posts_in_letter) / 2); // Rundet die Hälfte auf
$first_half = array_slice($posts_in_letter, 0, $halfway); // Erste Hälfte der Beiträge
$second_half = array_slice($posts_in_letter, $halfway); // Zweite Hälfte der Beiträge
// Ausgabe
ob_start();
?>
<div class="alphabetical-index">
<!-- Links zu den Buchstaben -->
<div class="alphabet-links">
<?php foreach ($alphabet as $char): ?>
<a href="?letter=<?php echo $char; ?>" class="letter-link"><?php echo $char; ?></a>
<?php endforeach; ?>
</div>
<?php if ($letter): ?>
<!-- Box für den aktuellen Buchstaben -->
<div class="letter-heading-box">
<h2>Beiträge für: <?php echo $letter; ?></h2>
</div>
<!-- Zeige die Beiträge für den ausgewählten Buchstaben in zwei Boxen -->
<div class="letter-pair-container">
<div class="letter-box">
<ul class="post-list">
<?php foreach ($first_half as $post): ?>
<li><a href="<?php echo get_permalink($post->ID); ?>"><?php echo $post->post_title; ?></a></li>
<?php endforeach; ?>
</ul>
</div>
<div class="letter-box">
<ul class="post-list">
<?php foreach ($second_half as $post): ?>
<li><a href="<?php echo get_permalink($post->ID); ?>"><?php echo $post->post_title; ?></a></li>
<?php endforeach; ?>
</ul>
</div>
</div>
<?php endif; ?>
</div>
<style>
.alphabetical-index {
font-family: Arial, sans-serif;
margin: 20px;
}
.alphabet-links {
margin-bottom: 20px;
display: flex;
justify-content: center;
flex-wrap: wrap;
}
.alphabet-links a {
margin-right: 10px;
font-size: 18px;
text-decoration: none;
color: #0073aa;
}
.alphabet-links a:hover {
text-decoration: underline;
}
.letter-heading-box {
margin-bottom: 20px;
background-color: #f0f0f0;
padding: 20px;
text-align: center;
border-radius: 8px;
}
.letter-heading-box h2 {
font-size: 24px;
margin: 0;
}
.letter-pair-container {
display: flex;
gap: 30px;
justify-content: space-between;
}
.letter-box {
width: 48%;
background-color: #f0f0f0;
padding: 20px;
border-radius: 8px;
}
.letter-box h2 {
font-size: 24px;
margin-bottom: 10px;
}
.post-list {
list-style-type: none;
padding: 0;
}
.post-list li {
margin-bottom: 5px;
}
.post-list a {
text-decoration: none;
color: #333;
}
.post-list a:hover {
text-decoration: underline;
}
</style>
<?php
return ob_get_clean();
}
// Shortcode registrieren
add_shortcode('alphabetical_index', 'wp_multi_alphabetical_index');
+345
View File
@@ -0,0 +1,345 @@
<?php
/**
* WP Multi Modul: Benutzer-Analytics
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Benutzer-Analytics mit verbesserten Sicherheits-, Performance- und Benutzerfreundlichkeits-Features
*/
// global ist nötig, weil die Plugin-Datei bei der Aktivierung innerhalb einer
// Funktion eingebunden wird und $wpdb dort sonst nicht verfügbar ist.
global $wpdb;
define('WP_MULTI_ANALYTICS_TABLE', $wpdb->prefix . 'wp_multi_user_analytics');
/**
* Erstellt die Datenbanktabelle für Benutzer-Analytics.
*/
function wp_multi_create_analytics_table() {
global $wpdb;
$table_name = WP_MULTI_ANALYTICS_TABLE;
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
user_id bigint(20) NOT NULL,
action varchar(255) NOT NULL,
post_id bigint(20) DEFAULT NULL,
timestamp datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX idx_timestamp (timestamp),
INDEX idx_action (action)
) $charset_collate;";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta($sql);
}
register_activation_hook(WP_MULTI_FILE, 'wp_multi_create_analytics_table');
/**
* Verfolgt Benutzerinteraktionen (Kommentare und Beitragsaufrufe).
*
* @param int $user_id Benutzer-ID.
* @param string $action Aktion (z. B. 'view', 'comment').
* @param int $post_id Beitrag-ID (optional).
* @return bool Erfolg der Operation.
*/
function wp_multi_track_user_activity($user_id, $action, $post_id = null) {
global $wpdb;
$table_name = WP_MULTI_ANALYTICS_TABLE;
$user_id = absint($user_id);
$action = sanitize_text_field($action);
$post_id = $post_id ? absint($post_id) : null;
if ($action === 'view' && is_single()) {
$post_id = get_the_ID();
}
if (!$user_id || !$action) {
return false;
}
return $wpdb->insert(
$table_name,
array(
'user_id' => $user_id,
'action' => $action,
'post_id' => $post_id,
),
array('%d', '%s', '%d')
);
}
/**
* Verfolgt Kommentar-Aktivitäten.
*
* @param int $comment_id Kommentar-ID.
*/
function wp_multi_comment_activity($comment_id) {
$comment = get_comment($comment_id);
$user_id = absint($comment->user_id);
if ($user_id) {
wp_multi_track_user_activity($user_id, 'comment', $comment->comment_post_ID);
}
}
add_action('comment_post', 'wp_multi_comment_activity');
/**
* Verfolgt Beitragsaufrufe.
*/
function wp_multi_post_view_activity() {
if (is_single() && is_user_logged_in()) {
$user_id = get_current_user_id();
$post_id = get_the_ID();
wp_multi_track_user_activity($user_id, 'view', $post_id);
}
}
add_action('wp_head', 'wp_multi_post_view_activity');
/**
* Ruft rohe Analytics-Daten aus der Datenbank ab.
*
* @param string $date_query Datum für die Abfrage.
* @return array Rohe Analytics-Daten.
*/
function wp_multi_fetch_raw_analytics($start_datetime = null, $end_datetime = null) {
global $wpdb;
if (!$start_datetime) {
$start_datetime = gmdate('Y-m-d H:i:s', strtotime('-7 days'));
}
$where = 'WHERE timestamp >= %s';
$params = [$start_datetime];
if ($end_datetime) {
$where .= ' AND timestamp <= %s';
$params[] = $end_datetime;
}
$sql = "SELECT DATE(timestamp) AS date, action, post_id, COUNT(*) AS count, user_id, timestamp
FROM " . WP_MULTI_ANALYTICS_TABLE . "
$where
GROUP BY date, action, post_id, user_id, timestamp
ORDER BY date ASC";
return $wpdb->get_results($wpdb->prepare($sql, $params));
}
/**
* 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) {
$date = $result->date;
if (!in_array($date, $dates)) {
$dates[] = $date;
}
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;
}
}
$all_dates = [];
$datasets = ['comments' => [], 'views' => []];
for ($i = 6; $i >= 0; $i--) {
$date = date('Y-m-d', strtotime("-$i day"));
$all_dates[] = $date;
$datasets['comments'][] = $comment_counts[$date] ?? 0;
$datasets['views'][] = $view_counts[$date] ?? 0;
}
return [
'dates' => array_reverse($all_dates),
'datasets' => [
[
'label' => __('Kommentare', 'wp-multi'),
'data' => array_reverse($datasets['comments']),
'borderColor' => 'rgba(75, 192, 192, 1)',
'borderWidth' => 1,
'fill' => false,
],
[
'label' => __('Beitragsaufrufe', 'wp-multi'),
'data' => array_reverse($datasets['views']),
'borderColor' => 'rgba(153, 102, 255, 1)',
'borderWidth' => 1,
'fill' => false,
]
],
'data' => $results
];
}
/**
* 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($start_datetime = null, $end_datetime = null) {
$cache_key = 'wp_multi_analytics_data_' . md5($start_datetime . '|' . $end_datetime);
$cached_data = get_transient($cache_key);
if ($cached_data !== false) {
return $cached_data;
}
$results = wp_multi_fetch_raw_analytics($start_datetime, $end_datetime);
$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 '<div class="error"><p>' . esc_html__('Die Analytics-Tabelle existiert nicht. Bitte aktiviere das Plugin erneut.', 'wp-multi') . '</p></div>';
return;
}
$time_range = isset($_GET['time_range']) ? sanitize_text_field($_GET['time_range']) : '7days';
$start_datetime = gmdate('Y-m-d H:i:s', strtotime('-7 days'));
$end_datetime = null;
if ($time_range === '30days') {
$start_datetime = gmdate('Y-m-d H:i:s', strtotime('-30 days'));
} elseif ($time_range === 'custom' && isset($_GET['start_date'], $_GET['end_date'])) {
$custom_start = sanitize_text_field(wp_unslash($_GET['start_date']));
$custom_end = sanitize_text_field(wp_unslash($_GET['end_date']));
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $custom_start) && preg_match('/^\d{4}-\d{2}-\d{2}$/', $custom_end)) {
$start_datetime = $custom_start . ' 00:00:00';
$end_datetime = $custom_end . ' 23:59:59';
}
}
$results = wp_multi_get_analytics_data($start_datetime, $end_datetime);
wpmt_admin_page_open(
__('Benutzer Analytics', 'wp-multi'),
__('Beitragsaufrufe und Kommentar-Aktivität deiner Besucher', 'wp-multi')
);
wpmt_admin_card_open(__('Zeitraum', 'wp-multi'));
?>
<form method="get">
<input type="hidden" name="page" value="wp_multi_analytics">
<select name="time_range" onchange="this.form.submit()" style="max-width:240px;">
<option value="7days" <?php selected($time_range, '7days'); ?>><?php esc_html_e('Letzte 7 Tage', 'wp-multi'); ?></option>
<option value="30days" <?php selected($time_range, '30days'); ?>><?php esc_html_e('Letzte 30 Tage', 'wp-multi'); ?></option>
<option value="custom" <?php selected($time_range, 'custom'); ?>><?php esc_html_e('Benutzerdefiniert', 'wp-multi'); ?></option>
</select>
<?php if ($time_range === 'custom') : ?>
<input type="date" name="start_date" value="<?php echo esc_attr($_GET['start_date'] ?? ''); ?>" style="max-width:180px;">
<input type="date" name="end_date" value="<?php echo esc_attr($_GET['end_date'] ?? ''); ?>" style="max-width:180px;">
<?php endif; ?>
<button type="submit" class="wpm-btn wpm-btn--primary"><?php esc_html_e('Filtern', 'wp-multi'); ?></button>
</form>
<?php
wpmt_admin_card_close();
if (empty($results['data'])) {
wpmt_admin_notice('info', __('Keine Daten für den gewählten Zeitraum verfügbar.', 'wp-multi'));
} else {
wpmt_admin_card_open(__('Aktivitätsverlauf', 'wp-multi'));
?>
<canvas id="userActivityChart" style="height: 300px; width: 100%;"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
if (typeof Chart !== 'undefined') {
document.addEventListener('DOMContentLoaded', function () {
var ctx = document.getElementById('userActivityChart').getContext('2d');
var chart = new Chart(ctx, {
type: 'line',
data: {
labels: <?php echo wp_json_encode($results['dates']); ?>,
datasets: <?php echo wp_json_encode($results['datasets']); ?>,
},
options: {
scales: {
x: { title: { display: true, text: '<?php echo esc_js(__('Datum', 'wp-multi')); ?>' } },
y: { title: { display: true, text: '<?php echo esc_js(__('Anzahl', 'wp-multi')); ?>' }, beginAtZero: true }
}
}
});
});
} else {
console.error('Chart.js konnte nicht geladen werden.');
}
</script>
<?php
wpmt_admin_card_close();
wpmt_admin_card_open(__('Einzelne Aktivitäten', 'wp-multi'));
?>
<div class="wpm-table-wrap">
<table class="wpm-table">
<thead>
<tr>
<th><?php esc_html_e('Benutzer ID', 'wp-multi'); ?></th>
<th><?php esc_html_e('Aktion', 'wp-multi'); ?></th>
<th><?php esc_html_e('Beitrag Titel', 'wp-multi'); ?></th>
<th><?php esc_html_e('Beitrag ID', 'wp-multi'); ?></th>
<th><?php esc_html_e('Zeitstempel', 'wp-multi'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($results['data'] as $row) : ?>
<tr>
<td><?php echo esc_html($row->user_id); ?></td>
<td><span class="wpm-badge <?php echo $row->action === 'comment' ? 'wpm-badge--success' : ''; ?>"><?php echo esc_html($row->action); ?></span></td>
<td>
<?php
if ($row->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');
}
?>
</td>
<td><?php echo esc_html($row->post_id ?: '-'); ?></td>
<td><?php echo esc_html($row->timestamp); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php
wpmt_admin_card_close();
}
wpmt_admin_page_close();
}
// Der Analytics-Menüpunkt wird zentral in wp_multi_register_admin_menus() registriert.
+263
View File
@@ -0,0 +1,263 @@
<?php
/**
* WP Multi Modul: Anti-Spam Honeypot
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Anti Spam Honey
*/
// Standardwerte setzen
function wp_multi_set_default_options() {
add_option('wp_multi_honeypot_field', 'iwlxja5187');
add_option('wp_multi_honeypot_error', 'Spamming or your Javascript is disabled !!');
add_option('wp_multi_honeypot_widget', 0);
add_option('wp_multi_max_links', 3);
add_option('wp_multi_blocked_keywords', 'viagra,casino,bitcoin');
add_option('wp_multi_blocked_ips', '');
add_option('wp_multi_blocked_comments', 0); // Zähler für blockierte Kommentare
add_option('wp_multi_honeypot_hits', 0); // Zähler für Honeypot-Aktivierungen
add_option('wp_multi_spammer_ips', []); // Liste der blockierten Spammer-IP-Adressen
add_option('wp_multi_spam_submissions', []); // Liste der Spam-Einreichungen
}
register_activation_hook(WP_MULTI_FILE, 'wp_multi_set_default_options');
// Die Sicherheits-Menüpunkte werden zentral in wp_multi_register_admin_menus() registriert.
// Einstellungsseite mit CSS & JS für Generator
function wp_multi_security_settings_page() {
wpmt_admin_page_open(
__('Sicherheit', 'wp-multi'),
__('Anti-Spam, Honeypot und Kommentarfilter konfigurieren', 'wp-multi')
);
wpmt_admin_card_open();
?>
<form method="post" action="options.php">
<?php
settings_fields('wp_multi_security_settings');
do_settings_sections('wp-multi-security');
submit_button();
?>
</form>
<script>
function generateHoneypotName() {
let field = document.getElementById('wp_multi_honeypot_field');
let randomString = Math.random().toString(36).substring(2, 12);
field.value = randomString;
}
</script>
<?php
wpmt_admin_card_close();
wpmt_admin_page_close();
}
// Statistikseite im Dashboard
function wp_multi_statistics_page() {
$blocked_comments = get_option('wp_multi_blocked_comments', 0);
$honeypot_hits = get_option('wp_multi_honeypot_hits', 0);
$spammer_ips = get_option('wp_multi_spammer_ips', []);
$spam_submissions = get_option('wp_multi_spam_submissions', []);
wpmt_admin_page_open(
__('Anti-Spam Statistik', 'wp-multi'),
__('Blockierte Kommentare, Honeypot-Treffer und erfasste Spammer-IPs', 'wp-multi')
);
echo '<div class="wpm-stats">';
wpmt_admin_stat_card(__('Blockierte Kommentare', 'wp-multi'), number_format_i18n($blocked_comments), 'dashicons-dismiss');
wpmt_admin_stat_card(__('Honeypot-Treffer', 'wp-multi'), number_format_i18n($honeypot_hits), 'dashicons-shield');
wpmt_admin_stat_card(__('Spammer-IPs', 'wp-multi'), number_format_i18n(count($spammer_ips)), 'dashicons-admin-site-alt3');
wpmt_admin_stat_card(__('Spam-Einreichungen', 'wp-multi'), number_format_i18n(count($spam_submissions)), 'dashicons-email-alt');
echo '</div>';
wpmt_admin_card_open(__('Spammer-IP-Adressen', 'wp-multi'));
if (!empty($spammer_ips)) {
?>
<div class="wpm-table-wrap">
<table class="wpm-table">
<thead>
<tr><th><?php esc_html_e('IP-Adresse', 'wp-multi'); ?></th></tr>
</thead>
<tbody>
<?php foreach ($spammer_ips as $ip) : ?>
<tr><td><?php echo esc_html($ip); ?></td></tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php
} else {
wpmt_admin_notice('info', __('Keine Spammer-IP-Adressen gefunden.', 'wp-multi'));
}
wpmt_admin_card_close();
wpmt_admin_page_close();
}
// Einstellungen registrieren
function wp_multi_register_security_settings() {
register_setting('wp_multi_security_settings', 'wp_multi_honeypot_field');
register_setting('wp_multi_security_settings', 'wp_multi_honeypot_error');
register_setting('wp_multi_security_settings', 'wp_multi_honeypot_widget');
register_setting('wp_multi_security_settings', 'wp_multi_max_links');
register_setting('wp_multi_security_settings', 'wp_multi_blocked_keywords');
register_setting('wp_multi_security_settings', 'wp_multi_blocked_ips');
add_settings_section('wp_multi_honeypot_section', 'Honeypot Einstellungen', null, 'wp-multi-security');
add_settings_field('wp_multi_honeypot_field', 'Honey Pot Field Name', 'wp_multi_honeypot_field_callback', 'wp-multi-security', 'wp_multi_honeypot_section');
add_settings_field('wp_multi_honeypot_error', 'Honey Pot Error Message', 'wp_multi_honeypot_error_callback', 'wp-multi-security', 'wp_multi_honeypot_section');
add_settings_field('wp_multi_honeypot_widget', 'Disable Honeypot Test Widget', 'wp_multi_honeypot_widget_callback', 'wp-multi-security', 'wp_multi_honeypot_section');
add_settings_field('wp_multi_max_links', 'Maximale Links im Kommentar', 'wp_multi_max_links_callback', 'wp-multi-security', 'wp_multi_honeypot_section');
add_settings_field('wp_multi_blocked_keywords', 'Blockierte Schlüsselwörter', 'wp_multi_blocked_keywords_callback', 'wp-multi-security', 'wp_multi_honeypot_section');
add_settings_field('wp_multi_blocked_ips', 'Blockierte IP-Adressen', 'wp_multi_blocked_ips_callback', 'wp-multi-security', 'wp_multi_honeypot_section');
}
add_action('admin_init', 'wp_multi_register_security_settings');
function wp_multi_honeypot_field_callback() {
?>
<div class="wp-multi-honeypot-group">
<input type="text" id="wp_multi_honeypot_field" name="wp_multi_honeypot_field" value="<?php echo esc_attr(get_option('wp_multi_honeypot_field')); ?>">
<button type="button" onclick="generateHoneypotName()">Generieren</button>
</div>
<small>Verwenden Sie ein zufälliges Zeichenfolgen für das Honeypot-Feld.</small>
<?php
}
function wp_multi_honeypot_error_callback() {
?>
<input type="text" name="wp_multi_honeypot_error" value="<?php echo esc_attr(get_option('wp_multi_honeypot_error')); ?>">
<small>Die Nachricht, die angezeigt wird, wenn ein Honeypot ausgelöst wird.</small>
<?php
}
function wp_multi_honeypot_widget_callback() {
?>
<input type="checkbox" name="wp_multi_honeypot_widget" value="1" <?php checked(1, get_option('wp_multi_honeypot_widget'), true); ?>>
<small>Deaktivieren Sie das Honeypot-Test-Widget im Frontend.</small>
<?php
}
function wp_multi_max_links_callback() {
?>
<input type="number" name="wp_multi_max_links" value="<?php echo esc_attr(get_option('wp_multi_max_links')); ?>">
<small>Maximale Anzahl von Links, die in einem Kommentar erlaubt sind.</small>
<?php
}
function wp_multi_blocked_keywords_callback() {
?>
<input type="text" name="wp_multi_blocked_keywords" value="<?php echo esc_attr(get_option('wp_multi_blocked_keywords')); ?>">
<small>Schlüsselwörter, die blockiert werden sollen (durch Kommas getrennt).</small>
<?php
}
function wp_multi_blocked_ips_callback() {
?>
<textarea name="wp_multi_blocked_ips" rows="5"><?php echo esc_textarea(get_option('wp_multi_blocked_ips')); ?></textarea>
<small>Blockierte IP-Adressen (jede Adresse in einer neuen Zeile).</small>
<?php
}
// Honeypot-Feld (unsichtbar für Menschen) im Kommentarformular ausgeben
function wp_multi_render_honeypot_field() {
$field_name = get_option('wp_multi_honeypot_field', 'iwlxja5187');
?>
<p class="wp-multi-honeypot" style="position:absolute !important; left:-9999px !important; top:-9999px !important;" aria-hidden="true">
<label for="<?php echo esc_attr($field_name); ?>"><?php esc_html_e('Website (bitte leer lassen)', 'wp-multi'); ?></label>
<input type="text" name="<?php echo esc_attr($field_name); ?>" id="<?php echo esc_attr($field_name); ?>" value="" tabindex="-1" autocomplete="off">
</p>
<input type="hidden" name="wp_multi_form_time" value="<?php echo esc_attr(time()); ?>">
<?php
}
add_action('comment_form_top', 'wp_multi_render_honeypot_field');
// Zähler/Statistik für einen geblockten Spam-Versuch aktualisieren
function wp_multi_register_spam_hit($reason, $ip = '') {
update_option('wp_multi_honeypot_hits', get_option('wp_multi_honeypot_hits', 0) + 1);
update_option('wp_multi_blocked_comments', get_option('wp_multi_blocked_comments', 0) + 1);
if ($ip) {
$spammer_ips = get_option('wp_multi_spammer_ips', []);
if (!in_array($ip, $spammer_ips, true)) {
$spammer_ips[] = $ip;
update_option('wp_multi_spammer_ips', $spammer_ips);
}
}
$submissions = get_option('wp_multi_spam_submissions', []);
$submissions[] = [
'reason' => $reason,
'ip' => $ip,
'timestamp' => current_time('mysql'),
];
// Auf die letzten 200 Einträge begrenzen, damit die Option nicht unbegrenzt wächst
if (count($submissions) > 200) {
$submissions = array_slice($submissions, -200);
}
update_option('wp_multi_spam_submissions', $submissions);
}
// Honeypot-/Zeitfallen-Prüfung sowie IP-/Keyword-/Link-Filter beim Absenden eines Kommentars
function wp_multi_validate_comment_submission($commentdata) {
$ip = function_exists('get_user_ip') ? get_user_ip() : (isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : '');
// Honeypot-Feld: darf von einem Menschen nie ausgefüllt werden
$field_name = get_option('wp_multi_honeypot_field', 'iwlxja5187');
if (!empty($_POST[$field_name])) {
wp_multi_register_spam_hit('honeypot', $ip);
wp_die(esc_html(get_option('wp_multi_honeypot_error', 'Spamming or your Javascript is disabled !!')));
}
// Zeit-Falle: Formular darf nicht schneller als 3 Sekunden nach dem Laden abgeschickt werden
if (isset($_POST['wp_multi_form_time'])) {
$elapsed = time() - absint($_POST['wp_multi_form_time']);
if ($elapsed < 3) {
wp_multi_register_spam_hit('honeypot_zeitfalle', $ip);
wp_die(esc_html(get_option('wp_multi_honeypot_error', 'Spamming or your Javascript is disabled !!')));
}
}
// Blockierte IP-Adressen
$blocked_ips = array_filter(array_map('trim', explode("\n", (string) get_option('wp_multi_blocked_ips', ''))));
if ($ip && in_array($ip, $blocked_ips, true)) {
wp_multi_register_spam_hit('blocked_ip', $ip);
wp_die(esc_html__('Deine IP-Adresse wurde für Kommentare gesperrt.', 'wp-multi'));
}
$content = isset($commentdata['comment_content']) ? $commentdata['comment_content'] : '';
// Blockierte Schlüsselwörter
$blocked_keywords = array_filter(array_map('trim', explode(',', (string) get_option('wp_multi_blocked_keywords', ''))));
foreach ($blocked_keywords as $keyword) {
if ($keyword !== '' && stripos($content, $keyword) !== false) {
wp_multi_register_spam_hit('keyword', $ip);
wp_die(esc_html__('Dein Kommentar enthält nicht erlaubte Inhalte.', 'wp-multi'));
}
}
// Maximale Anzahl an Links im Kommentar
$max_links = absint(get_option('wp_multi_max_links', 3));
if ($max_links > 0 && preg_match_all('#https?://#i', $content) > $max_links) {
wp_multi_register_spam_hit('links', $ip);
wp_die(esc_html__('Dein Kommentar enthält zu viele Links.', 'wp-multi'));
}
// Kommentarfilter: Telefonnummern, E-Mails, URLs, IPs, Schimpfwörter durch * ersetzen
$commentdata['comment_content'] = wp_multi_apply_comment_content_filter($content);
return $commentdata;
}
add_filter('preprocess_comment', 'wp_multi_validate_comment_submission');
+313
View File
@@ -0,0 +1,313 @@
<?php
/**
* WP Multi Modul: Automatische Tags
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* 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');
/**
* Fügt automatische Tags zu einem Beitrag hinzu.
*
* @param int $post_id ID des Beitrags.
*/
function wp_multi_auto_add_tags($post_id) {
if (get_post_type($post_id) !== 'post') {
return;
}
$existing_tags = wp_get_post_tags($post_id, ['fields' => 'names']);
if (!empty($existing_tags)) {
return;
}
$post = get_post($post_id);
if (!$post) {
error_log("WP Multi Auto Tags: Beitrag $post_id nicht gefunden.");
return;
}
$content = strip_tags($post->post_content);
$content = mb_strtolower($content, 'UTF-8');
// Stopwörter laden
$stopwords = wp_multi_get_stopwords();
$words = wp_multi_extract_words($content, $stopwords);
if (empty($words)) {
return;
}
$word_counts = array_count_values($words);
arsort($word_counts);
$top_tags = array_slice(array_keys($word_counts), 0, 5);
if (!empty($top_tags)) {
wp_set_post_tags($post_id, $top_tags, true);
}
}
/**
* 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.
*/
// Der Auto-Tags-Menüpunkt wird zentral in wp_multi_register_admin_menus() registriert.
/**
* 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'));
}
wpmt_admin_page_open(
__('Automatische Tags', 'wp-multi'),
__('Fügt Beiträgen ohne Tags automatisch passende Schlagwörter hinzu', 'wp-multi')
);
wpmt_admin_card_open(__('Einstellungen', 'wp-multi'));
?>
<form method="post" action="options.php">
<?php
settings_fields('wp_multi_auto_tags_options');
do_settings_sections('wp-multi-auto-tags');
wp_nonce_field(WP_MULTI_AUTO_TAGS_NONCE, WP_MULTI_AUTO_TAGS_NONCE);
?>
<div class="wpm-field">
<label class="wpm-field__label" for="wp_multi_custom_stopwords"><?php esc_html_e('Stopwörter (kommagetrennt)', 'wp-multi'); ?>
<small class="wpm-field__hint"><?php esc_html_e('Diese Wörter werden nicht als Tags verwendet. Beispiele: wird, auch, aber', 'wp-multi'); ?></small>
</label>
<textarea id="wp_multi_custom_stopwords" name="wp_multi_custom_stopwords" rows="5"><?php echo esc_textarea(get_option(WP_MULTI_AUTO_TAGS_OPTION, '')); ?></textarea>
</div>
<p><input type="submit" value="<?php esc_attr_e('Speichern', 'wp-multi'); ?>" class="wpm-btn wpm-btn--primary"></p>
</form>
<?php
wpmt_admin_card_close();
wpmt_admin_card_open(__('Alle Beiträge verarbeiten', 'wp-multi'));
?>
<p><?php esc_html_e('Durchsucht alle vorhandenen Beiträge ohne Tags und ergänzt automatisch passende Schlagwörter.', 'wp-multi'); ?></p>
<button id="start-auto-tags" class="wpm-btn wpm-btn--primary"><?php esc_html_e('Jetzt ausführen', 'wp-multi'); ?></button>
<div id="progress-container" style="display:none; width:100%; background:#f4f4f4; border-radius:8px; margin-top:20px; overflow:hidden;">
<div id="progress-bar" style="width:0%; height:30px; background:#2ecc71; text-align:center; color:#fff; line-height:30px; font-weight:bold; transition:width .4s;">0%</div>
</div>
<p id="status-message" style="margin-top:15px; font-weight:600; color:var(--wpm-primary,#0073aa);"></p>
<?php
wpmt_admin_card_close();
wpmt_admin_page_close();
?>
<script>
var wpMultiAutoTags = <?php echo wp_json_encode([
'ajaxurl' => admin_url('admin-ajax.php'),
'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'),
],
]); ?>;
jQuery(document).ready(function($) {
$('#start-auto-tags').on('click', function() {
const button = $(this);
const progressContainer = $('#progress-container');
const progressBar = $('#progress-bar');
const statusMessage = $('#status-message');
button.prop('disabled', true).text(wpMultiAutoTags.messages.processing);
progressContainer.show();
progressBar.css('width', '0%').text('0%');
statusMessage.text(wpMultiAutoTags.messages.loading);
$.ajax({
url: wpMultiAutoTags.ajaxurl,
method: 'POST',
data: {
action: 'wp_multi_process_auto_tags',
nonce: wpMultiAutoTags.nonce,
},
success: function(response) {
if (!response.data.total) {
statusMessage.text(wpMultiAutoTags.messages.no_posts);
button.prop('disabled', false).text(wpMultiAutoTags.messages.run);
return;
}
const total = response.data.total;
let processed = 0;
const batchSize = 10;
function processBatch() {
$.ajax({
url: wpMultiAutoTags.ajaxurl,
method: 'POST',
data: {
action: 'wp_multi_process_auto_tags_step',
batchSize: batchSize,
nonce: wpMultiAutoTags.nonce,
},
success: function(result) {
if (result.data.done) {
processed += batchSize;
const percent = Math.min(Math.round((processed / total) * 100), 100);
progressBar.css('width', percent + '%').text(percent + '%');
if (processed < total) {
processBatch();
} else {
button.prop('disabled', false).text(wpMultiAutoTags.messages.run);
statusMessage.text(wpMultiAutoTags.messages.success);
}
}
},
error: function() {
statusMessage.text(wpMultiAutoTags.messages.error);
button.prop('disabled', false).text(wpMultiAutoTags.messages.run);
},
});
}
processBatch();
},
error: function() {
statusMessage.text(wpMultiAutoTags.messages.start_error);
button.prop('disabled', false).text(wpMultiAutoTags.messages.run);
},
});
});
});
</script>
<?php
}
/**
* Registriert die Einstellungen für automatische Tags.
*/
function wp_multi_auto_tags_settings_init() {
register_setting('wp_multi_auto_tags_options', WP_MULTI_AUTO_TAGS_OPTION, [
'sanitize_callback' => function($input) {
$input = sanitize_text_field($input);
return implode(',', array_map('trim', explode(',', $input)));
},
]);
}
add_action('admin_init', 'wp_multi_auto_tags_settings_init');
/**
* Verarbeitet die Initialisierung der Auto-Tag-Verarbeitung via AJAX.
*/
function wp_multi_process_auto_tags() {
check_ajax_referer(WP_MULTI_AUTO_TAGS_NONCE, 'nonce');
$args = [
'post_type' => 'post',
'posts_per_page' => 100,
'fields' => 'ids',
'no_found_rows' => true, // Optimierung
];
$posts = get_posts($args);
if (empty($posts)) {
wp_send_json_success(['total' => 0]);
}
set_transient(WP_MULTI_AUTO_TAGS_QUEUE, $posts, 300);
wp_send_json_success(['total' => count($posts)]);
}
add_action('wp_ajax_wp_multi_process_auto_tags', 'wp_multi_process_auto_tags');
/**
* Verarbeitet einen Batch von Beiträgen für die Auto-Tag-Verarbeitung.
*/
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']) ? absint($_POST['batchSize']) : 10;
$batchSize = max(1, min($batchSize, 50));
if (!$queue || empty($queue)) {
wp_send_json_success(['done' => false]);
}
set_time_limit(30); // Timeout verhindern
$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_success(['done' => true]);
}
add_action('wp_ajax_wp_multi_process_auto_tags_step', 'wp_multi_process_auto_tags_step');
/**
* Fügt Tags automatisch bei neuen oder aktualisierten Beiträgen hinzu.
*
* @param int $post_id ID des Beitrags.
*/
function wp_multi_auto_tag_on_save($post_id) {
if (wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) {
return;
}
wp_multi_auto_add_tags($post_id);
}
add_action('save_post', 'wp_multi_auto_tag_on_save', 10, 1);
+11111 -11271
View File
File diff suppressed because it is too large Load Diff
+198
View File
@@ -0,0 +1,198 @@
<?php
/**
* WP Multi Modul: Benutzer für Kommentare sperren
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* User Kommentar Blocken
*/
function wp_multi_create_blocked_users_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'blocked_users';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
username varchar(100) DEFAULT '' NOT NULL,
email varchar(100) DEFAULT '' NOT NULL,
ip_address varchar(45) DEFAULT '' NOT NULL,
PRIMARY KEY (id)
) $charset_collate;";
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
dbDelta( $sql );
}
function wp_multi_activate() {
wp_multi_create_blocked_users_table();
}
register_activation_hook( WP_MULTI_FILE, 'wp_multi_activate' );
function wp_multi_block_user($username = '', $email = '', $ip_address = '') {
global $wpdb;
if (empty($username) && empty($email) && empty($ip_address)) {
return false;
}
$result = $wpdb->insert(
$wpdb->prefix . 'blocked_users',
[
'username' => $username,
'email' => $email,
'ip_address' => $ip_address
]
);
return $result !== false;
}
function wp_multi_delete_blocked_user($id) {
global $wpdb;
return $wpdb->delete($wpdb->prefix . 'blocked_users', ['id' => $id], ['%d']);
}
// Der Menüpunkt "Gesperrte Benutzer" wird zentral in wp_multi_register_admin_menus() registriert.
function wp_multi_blocked_users_page() {
global $wpdb;
$notices = array();
if (isset($_POST['block_username']) || isset($_POST['block_email']) || isset($_POST['block_ip'])) {
check_admin_referer('wp_multi_block_user');
$username = sanitize_text_field($_POST['block_username']);
$email = sanitize_email($_POST['block_email']);
$ip_address = sanitize_text_field($_POST['block_ip']);
if (wp_multi_block_user($username, $email, $ip_address)) {
$notices[] = array('success', __('Benutzer wurde gesperrt!', 'wp-multi'));
} else {
$notices[] = array('error', __('Fehler beim Sperren des Benutzers!', 'wp-multi'));
}
}
if (isset($_GET['delete']) && isset($_GET['_wpnonce'])) {
if (wp_verify_nonce($_GET['_wpnonce'], 'wp_multi_delete_user_' . $_GET['delete'])) {
$user_id = intval($_GET['delete']);
if ($user_id > 0 && wp_multi_delete_blocked_user($user_id)) {
$notices[] = array('success', __('Benutzer wurde gelöscht!', 'wp-multi'));
} else {
$notices[] = array('error', __('Fehler beim Löschen des Benutzers!', 'wp-multi'));
}
}
}
$search_query = '';
if (isset($_GET['search'])) {
$search_query = sanitize_text_field($_GET['search']);
}
$blocked_users = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}blocked_users WHERE username LIKE %s OR email LIKE %s OR ip_address LIKE %s",
'%' . $search_query . '%', '%' . $search_query . '%', '%' . $search_query . '%'
));
wpmt_admin_page_open(
__('Gesperrte Benutzer', 'wp-multi'),
__('Benutzer per Name, E-Mail oder IP von Kommentaren ausschließen', 'wp-multi')
);
foreach ($notices as $notice) {
wpmt_admin_notice($notice[0], $notice[1]);
}
echo '<div class="wpm-grid wpm-grid--2">';
wpmt_admin_card_open(__('Benutzer sperren', 'wp-multi'));
?>
<form method="post">
<?php wp_nonce_field('wp_multi_block_user'); ?>
<div class="wpm-field">
<label class="wpm-field__label"><?php _e('Benutzername', 'wp-multi'); ?></label>
<input type="text" name="block_username" placeholder="Benutzername">
</div>
<div class="wpm-field">
<label class="wpm-field__label"><?php _e('E-Mail-Adresse', 'wp-multi'); ?></label>
<input type="email" name="block_email" placeholder="E-Mail-Adresse">
</div>
<div class="wpm-field">
<label class="wpm-field__label"><?php _e('IP-Adresse', 'wp-multi'); ?></label>
<input type="text" name="block_ip" placeholder="IP-Adresse">
</div>
<p><input type="submit" class="wpm-btn wpm-btn--primary" value="<?php esc_attr_e('Benutzer sperren', 'wp-multi'); ?>"></p>
</form>
<?php
wpmt_admin_card_close();
wpmt_admin_card_open(__('Suchen', 'wp-multi'));
?>
<form method="get">
<input type="hidden" name="page" value="wp-multi-blocked-users">
<div class="wpm-field">
<label class="wpm-field__label"><?php _e('Suchbegriff', 'wp-multi'); ?></label>
<input type="text" name="search" value="<?php echo esc_attr($search_query); ?>" placeholder="<?php esc_attr_e('Benutzername, E-Mail oder IP', 'wp-multi'); ?>">
</div>
<p><input type="submit" class="wpm-btn" value="<?php esc_attr_e('Suchen', 'wp-multi'); ?>"></p>
</form>
<?php
wpmt_admin_card_close();
echo '</div>';
wpmt_admin_card_open(__('Gesperrte Benutzer', 'wp-multi'));
?>
<div class="wpm-table-wrap">
<table class="wpm-table">
<thead>
<tr>
<th><?php _e('Benutzername', 'wp-multi'); ?></th>
<th><?php _e('E-Mail-Adresse', 'wp-multi'); ?></th>
<th><?php _e('IP-Adresse', 'wp-multi'); ?></th>
<th><?php _e('Aktionen', 'wp-multi'); ?></th>
</tr>
</thead>
<tbody>
<?php if ($blocked_users) : ?>
<?php foreach ($blocked_users as $user) : ?>
<tr>
<td><?php echo esc_html($user->username); ?></td>
<td><?php echo esc_html($user->email); ?></td>
<td><?php echo esc_html($user->ip_address); ?></td>
<td>
<a href="<?php echo esc_url(wp_nonce_url(admin_url('admin.php?page=wp-multi-blocked-users&delete=' . $user->id), 'wp_multi_delete_user_' . $user->id)); ?>" class="wpm-btn wpm-btn--danger"><?php _e('Löschen', 'wp-multi'); ?></a>
</td>
</tr>
<?php endforeach; ?>
<?php else : ?>
<tr>
<td colspan="4"><?php _e('Keine gesperrten Benutzer gefunden.', 'wp-multi'); ?></td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
<?php
wpmt_admin_card_close();
wpmt_admin_page_close();
}
function wp_multi_check_blocked_user($commentdata) {
global $wpdb;
$username = isset($commentdata['comment_author']) ? $commentdata['comment_author'] : '';
$email = isset($commentdata['comment_author_email']) ? $commentdata['comment_author_email'] : '';
$ip_address = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
$blocked_user = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}blocked_users WHERE username = %s OR email = %s OR ip_address = %s",
$username, $email, $ip_address
));
if ($blocked_user) {
wp_die('Ihr Kommentar konnte nicht abgesendet werden, da Sie gesperrt sind. Bitte wenden Sie sich an den Support.');
}
return $commentdata;
}
add_filter('preprocess_comment', 'wp_multi_check_blocked_user');
+346
View File
@@ -0,0 +1,346 @@
<?php
/**
* WP Multi Modul: Gast-Lesezeichen
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Verbessertes Gast-Lesezeichen-Plugin mit erhöhter Sicherheit und Benutzerfreundlichkeit
*/
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(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');
/**
* 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) {
$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
);
}
return $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);
}
/**
* 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;
}
$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');
/**
* Fügt ein Lesezeichen via AJAX hinzu.
*/
function statistik_manager_add_bookmark_ajax() {
check_ajax_referer('statistik_manager_bookmark_nonce', 'nonce');
if (!isset($_POST['bookmark_url']) || !isset($_POST['bookmark_name'])) {
wp_send_json_error(['message' => __('Bitte alle Felder ausfüllen.', 'statistik-manager')]);
}
$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' => '<li><button class="delete-bookmark-btn" data-bookmark-id="' . esc_attr($post_id) . '">' . esc_html__('Löschen', 'statistik-manager') . '</button><a href="' . esc_url($bookmark_url) . '" target="_blank">' . esc_html($bookmark_name) . '</a></li>',
]);
}
add_action('wp_ajax_add_bookmark', 'statistik_manager_add_bookmark_ajax');
add_action('wp_ajax_nopriv_add_bookmark', 'statistik_manager_add_bookmark_ajax');
/**
* 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();
?>
<div class="statistik-manager-bookmarks">
<h3><?php esc_html_e('Gespeicherte Lesezeichen', 'statistik-manager'); ?></h3>
<?php if (empty($bookmarks)) : ?>
<p><?php esc_html_e('Keine Lesezeichen gefunden.', 'statistik-manager'); ?></p>
<?php else : ?>
<ul>
<?php foreach ($bookmarks as $bookmark) : ?>
<li>
<button class="delete-bookmark-btn" data-bookmark-id="<?php echo esc_attr($bookmark->ID); ?>">
<?php esc_html_e('Löschen', 'statistik-manager'); ?>
</button>
<a href="<?php echo esc_url(get_post_meta($bookmark->ID, '_bookmark_url', true)); ?>" target="_blank">
<?php echo esc_html(get_the_title($bookmark)); ?>
</a>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>
<?php
return ob_get_clean();
}
/**
* Shortcode zum Anzeigen der Lesezeichen.
*
* @return string HTML-Ausgabe.
*/
function statistik_manager_bookmarks_shortcode() {
return statistik_manager_display_bookmarks();
}
add_shortcode('display_bookmarks', 'statistik_manager_bookmarks_shortcode');
/**
* Shortcode zum Hinzufügen eines Lesezeichens.
*
* @return string HTML-Ausgabe.
*/
function statistik_manager_add_bookmark_shortcode() {
ob_start();
?>
<form id="add-bookmark-form" class="statistik-manager-bookmark-form">
<input type="hidden" name="nonce" value="<?php echo esc_attr(wp_create_nonce('statistik_manager_bookmark_nonce')); ?>">
<div class="form-field">
<label for="bookmark_name"><?php esc_html_e('Name des Lesezeichens:', 'statistik-manager'); ?></label>
<input type="text" name="bookmark_name" id="bookmark_name" required>
</div>
<div class="form-field">
<label for="bookmark_url"><?php esc_html_e('URL des Lesezeichens:', 'statistik-manager'); ?></label>
<input type="url" name="bookmark_url" id="bookmark_url" required>
</div>
<div class="form-field">
<button type="submit"><?php esc_html_e('Lesezeichen hinzufügen', 'statistik-manager'); ?></button>
</div>
<div class="form-message"></div>
</form>
<style>
.statistik-manager-bookmark-form { max-width: 500px; margin: 20px 0; }
.statistik-manager-bookmark-form .form-field { margin-bottom: 15px; }
.statistik-manager-bookmark-form label { display: block; margin-bottom: 5px; font-weight: bold; }
.statistik-manager-bookmark-form input { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; }
.statistik-manager-bookmark-form button { background-color: #0073aa; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; }
.statistik-manager-bookmark-form button:hover { background-color: #005177; }
.statistik-manager-bookmark-form .form-message { margin-top: 10px; color: green; }
.statistik-manager-bookmark-form .form-message.error { color: red; }
.statistik-manager-bookmarks ul { list-style: none; padding: 0; }
.statistik-manager-bookmarks li { margin-bottom: 10px; display: flex; align-items: center; }
.statistik-manager-bookmarks button { margin-right: 10px; background-color: #d63638; color: white; padding: 5px 10px; border: none; border-radius: 4px; cursor: pointer; }
.statistik-manager-bookmarks button:hover { background-color: #a12b2d; }
@media (max-width: 600px) {
.statistik-manager-bookmark-form input, .statistik-manager-bookmark-form button { font-size: 14px; }
.statistik-manager-bookmarks li { flex-direction: column; align-items: flex-start; }
.statistik-manager-bookmarks button { margin-bottom: 5px; }
}
</style>
<?php
return ob_get_clean();
}
add_shortcode('add_bookmark', 'statistik_manager_add_bookmark_shortcode');
/**
* Fügt JavaScript für AJAX-Interaktionen hinzu.
*/
function statistik_manager_add_bookmark_script() {
if (!is_singular() && !has_shortcode(get_the_content(), 'add_bookmark') && !has_shortcode(get_the_content(), 'display_bookmarks')) {
return;
}
?>
<script type="text/javascript">
jQuery(document).ready(function($) {
$('#add-bookmark-form').on('submit', function(e) {
e.preventDefault();
var $form = $(this);
var $message = $form.find('.form-message');
var data = {
action: 'add_bookmark',
nonce: $form.find('[name="nonce"]').val(),
bookmark_url: $form.find('#bookmark_url').val(),
bookmark_name: $form.find('#bookmark_name').val(),
};
$.post('<?php echo esc_url(admin_url('admin-ajax.php')); ?>', data, function(response) {
$message.removeClass('error');
if (response.success) {
$message.addClass('success').text(response.data.message);
$('.statistik-manager-bookmarks ul').append(response.data.html);
$form.find('#bookmark_url, #bookmark_name').val('');
} else {
$message.addClass('error').text(response.data.message);
}
});
});
$('body').on('click', '.delete-bookmark-btn', function() {
var $button = $(this);
var bookmarkId = $button.data('bookmark-id');
var data = {
action: 'delete_bookmark',
nonce: $('#add-bookmark-form [name="nonce"]').val(),
bookmark_id: bookmarkId,
};
$.post('<?php echo esc_url(admin_url('admin-ajax.php')); ?>', data, function(response) {
var $message = $('.statistik-manager-bookmark-form .form-message');
$message.removeClass('error success');
if (response.success) {
$message.addClass('success').text(response.data.message);
$button.closest('li').remove();
} else {
$message.addClass('error').text(response.data.message);
}
});
});
});
</script>
<?php
}
add_action('wp_footer', 'statistik_manager_add_bookmark_script');
+405
View File
@@ -0,0 +1,405 @@
<?php
/**
* WP Multi Modul: Brute-Force-Schutz
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Schutz vor Brute-Force-Angriffen mit wöchentlicher Zusammenfassung
* Sperr-E-Mails entfernt, Zusammenfassung deaktivierbar unter Benutzer mit verbessertem Design
*/
// Funktion zur Erfassung der echten IP-Adresse des Benutzers
function get_user_ip() {
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'])) {
$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;
$ip = get_user_ip();
if ($ip === '0.0.0.0') {
return;
}
$blocked_table = $wpdb->prefix . 'blocked_ips';
$attempts_table = $wpdb->prefix . 'login_attempts';
$block_threshold = 5;
// Anmeldeversuch in attempts-Tabelle speichern
$wpdb->insert(
$attempts_table,
array(
'ip' => $ip,
'username' => $username,
'attempt_time' => current_time('mysql'),
),
array('%s', '%s', '%s')
);
// Prüfen, ob IP bereits in blocked_ips existiert
$row = $wpdb->get_row($wpdb->prepare("SELECT * FROM $blocked_table WHERE ip = %s", $ip));
if ($row) {
$wpdb->update(
$blocked_table,
array(
'attempts' => $row->attempts + 1,
'last_attempt' => current_time('mysql'),
),
array('ip' => $ip),
array('%d', '%s'),
array('%s')
);
$attempts = $row->attempts + 1;
} else {
$wpdb->insert(
$blocked_table,
array(
'ip' => $ip,
'attempts' => 1,
'last_attempt' => current_time('mysql'),
),
array('%s', '%d', '%s')
);
$attempts = 1;
}
// IP sperren, wenn Schwellenwert erreicht
if ($attempts >= $block_threshold) {
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)
);
}
}
// Hook für fehlgeschlagene Anmeldungen
add_action('wp_login_failed', 'wp_multi_log_failed_login', 10, 1);
// Funktion zur Erstellung der Tabellen
function wp_multi_create_blocked_ips_table() {
global $wpdb;
$blocked_table = $wpdb->prefix . 'blocked_ips';
$attempts_table = $wpdb->prefix . 'login_attempts';
$charset_collate = $wpdb->get_charset_collate();
$version = get_option('wp_multi_blocked_ips_version', '1.0');
if (version_compare($version, '1.1', '<')) {
$sql_blocked = "CREATE TABLE $blocked_table (
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;";
$sql_attempts = "CREATE TABLE $attempts_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
ip varchar(45) NOT NULL,
username varchar(255) NOT NULL,
attempt_time datetime NOT NULL,
PRIMARY KEY (id),
KEY ip (ip),
KEY attempt_time (attempt_time)
) $charset_collate;";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta($sql_blocked);
dbDelta($sql_attempts);
update_option('wp_multi_blocked_ips_version', '1.1');
}
}
register_activation_hook(WP_MULTI_FILE, 'wp_multi_create_blocked_ips_table');
// Wöchentliche Zusammenfassung
function wp_multi_send_weekly_summary() {
global $wpdb;
// Prüfen, ob Zusammenfassung aktiviert ist
$summary_enabled = get_option('wp_multi_summary_enabled', 1);
if (!$summary_enabled) {
return;
}
$attempts_table = $wpdb->prefix . 'login_attempts';
$last_email_time = get_option('wp_multi_last_summary_email', 0);
$current_time = time();
// Prüfen, ob eine Woche vergangen ist (7 Tage = 604800 Sekunden)
if (($current_time - $last_email_time) < 604800) {
return;
}
// Zeitraum für die Zusammenfassung (letzte Woche)
$week_ago = date('Y-m-d H:i:s', strtotime('-7 days'));
$now = date('Y-m-d H:i:s');
// Gesamtzahl der Anmeldeversuche
$total_attempts = $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(*) FROM $attempts_table WHERE attempt_time >= %s",
$week_ago
)
);
$total_attempts = $total_attempts ? $total_attempts : 0;
// Top 10 IPs mit den meisten Anmeldeversuchen
$top_attempts = $wpdb->get_results(
$wpdb->prepare(
"SELECT ip, username, COUNT(*) as attempt_count, MAX(attempt_time) as last_attempt
FROM $attempts_table
WHERE attempt_time >= %s
GROUP BY ip, username
ORDER BY attempt_count DESC
LIMIT 10",
$week_ago
)
);
// E-Mail-Inhalt
$message = __("Wöchentliche Anmeldeversuche-Zusammenfassung\n\n", 'wp-multi');
$message .= sprintf(__("Zeitraum: %s bis %s\n\n", 'wp-multi'), $week_ago, $now);
$message .= sprintf(__("Gesamtzahl der Anmeldeversuche: %d\n\n", 'wp-multi'), $total_attempts);
$message .= __("Top 10 Anmeldeversuche (nach IP und Benutzername):\n", 'wp-multi');
if ($top_attempts) {
foreach ($top_attempts as $index => $attempt) {
$message .= sprintf(
__("%d. IP: %s, Benutzername: %s, Versuche: %d, Letzter Versuch: %s\n", 'wp-multi'),
$index + 1,
$attempt->ip,
$attempt->username,
$attempt->attempt_count,
$attempt->last_attempt
);
}
} else {
$message .= __("Keine Anmeldeversuche in diesem Zeitraum.\n", 'wp-multi');
}
// E-Mail an Admin senden
$admin_email = get_option('admin_email');
wp_mail(
$admin_email,
__('Wöchentliche Anmeldeversuche-Zusammenfassung', 'wp-multi'),
$message,
array('Content-Type: text/plain; charset=UTF-8')
);
// Aktualisiere den Zeitstempel der letzten E-Mail
update_option('wp_multi_last_summary_email', $current_time);
}
// Planen der wöchentlichen Zusammenfassung (jeden Montag um 8:00 Uhr)
function wp_multi_schedule_weekly_summary() {
if (!wp_next_scheduled('wp_multi_weekly_summary_event')) {
wp_schedule_event(strtotime('next Monday 08:00'), 'weekly', 'wp_multi_weekly_summary_event');
}
}
add_action('wp', 'wp_multi_schedule_weekly_summary');
// Hook für die Ausführung der Zusammenfassung
add_action('wp_multi_weekly_summary_event', 'wp_multi_send_weekly_summary');
// Einstellungsoption für die Zusammenfassung
function wp_multi_users_register_settings() {
add_option('wp_multi_summary_enabled', 1);
register_setting('wp_multi_users_settings_group', 'wp_multi_summary_enabled', array(
'type' => 'integer',
'sanitize_callback' => 'absint',
'default' => 1,
));
// Settings Section hinzufügen
add_settings_section(
'wp_multi_security_section',
__('Brute-Force-Schutz Einstellungen', 'wp-multi'),
'wp_multi_security_section_callback',
'wp_multi_users_security_settings'
);
// Settings Field hinzufügen
add_settings_field(
'wp_multi_summary_enabled',
__('Wöchentliche Zusammenfassung', 'wp-multi'),
'wp_multi_summary_enabled_callback',
'wp_multi_users_security_settings',
'wp_multi_security_section'
);
}
add_action('admin_init', 'wp_multi_users_register_settings');
// Callback für die Settings Section
function wp_multi_security_section_callback() {
echo '<p>' . __('Konfiguriere die Sicherheitseinstellungen für den Brute-Force-Schutz deiner Website. Aktiviere oder deaktiviere die wöchentliche Zusammenfassung der fehlgeschlagenen Anmeldeversuche.', 'wp-multi') . '</p>';
}
// Callback für das Settings Field
function wp_multi_summary_enabled_callback() {
$summary_enabled = get_option('wp_multi_summary_enabled', 1);
?>
<input type="checkbox" name="wp_multi_summary_enabled" id="wp_multi_summary_enabled" value="1" <?php checked(1, $summary_enabled); ?> />
<label for="wp_multi_summary_enabled"><?php _e('Wöchentliche E-Mail-Zusammenfassung für fehlgeschlagene Anmeldeversuche aktivieren', 'wp-multi'); ?></label>
<p class="description"><?php _e('Wenn aktiviert, erhält der Administrator jeden Montag um 8:00 Uhr eine E-Mail mit einer Zusammenfassung der fehlgeschlagenen Anmeldeversuche der letzten Woche.', 'wp-multi'); ?></p>
<?php
}
// Blockierte IPs & Sicherheitseinstellungen werden zentral in wp_multi_register_admin_menus() registriert.
// Einstellungsseite unter Benutzer
function wp_multi_users_security_settings_page() {
wpmt_admin_page_open(
__('Benutzer-Sicherheit', 'wp-multi'),
__('Brute-Force-Schutz und Benachrichtigungen für fehlgeschlagene Logins', 'wp-multi')
);
wpmt_admin_card_open(__('Brute-Force-Schutz', 'wp-multi'));
?>
<p><?php _e('Verwalte die Einstellungen für den Schutz vor Brute-Force-Angriffen. Passe die Benachrichtigungen für fehlgeschlagene Anmeldeversuche an.', 'wp-multi'); ?></p>
<form method="post" action="options.php">
<?php
settings_fields('wp_multi_users_settings_group');
do_settings_sections('wp_multi_users_security_settings');
submit_button(__('Einstellungen speichern', 'wp-multi'));
?>
</form>
<?php
wpmt_admin_card_close();
wpmt_admin_page_close();
}
// Anzeige der blockierten IPs im Admin-Bereich
function wp_multi_display_blocked_ips() {
global $wpdb;
$table_name = $wpdb->prefix . 'blocked_ips';
$five_days_ago = date('Y-m-d H:i:s', strtotime('-5 days'));
$per_page = 50;
$page = max(1, isset($_GET['paged']) ? intval($_GET['paged']) : 1);
$offset = ($page - 1) * $per_page;
$blocked_ips = $wpdb->get_results(
$wpdb->prepare(
"SELECT * FROM $table_name WHERE last_attempt >= %s ORDER BY last_attempt DESC LIMIT %d OFFSET %d",
$five_days_ago,
$per_page,
$offset
)
);
$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);
wpmt_admin_page_open(
__('Blockierte IPs', 'wp-multi'),
__('Vom Brute-Force-Schutz erfasste IP-Adressen der letzten 5 Tage', 'wp-multi')
);
wpmt_admin_card_open();
if (empty($blocked_ips)) {
wpmt_admin_notice('info', __('Keine blockierten IPs gefunden.', 'wp-multi'));
} else {
?>
<div class="wpm-table-wrap">
<table class="wpm-table">
<thead>
<tr>
<th><?php _e('ID', 'wp-multi'); ?></th>
<th><?php _e('IP-Adresse', 'wp-multi'); ?></th>
<th><?php _e('Versuche', 'wp-multi'); ?></th>
<th><?php _e('Letzter Versuch', 'wp-multi'); ?></th>
<th><?php _e('Aktionen', 'wp-multi'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($blocked_ips as $ip) : ?>
<tr>
<td><?php echo esc_html($ip->id); ?></td>
<td><?php echo esc_html($ip->ip); ?></td>
<td><span class="wpm-badge <?php echo $ip->attempts >= 5 ? 'wpm-badge--danger' : 'wpm-badge--warning'; ?>"><?php echo esc_html($ip->attempts); ?></span></td>
<td><?php echo esc_html($ip->last_attempt); ?></td>
<td>
<a class="wpm-btn wpm-btn--danger" href="<?php echo esc_url(wp_nonce_url(admin_url('admin-post.php?action=remove_blocked_ip&id=' . $ip->id), 'wp_multi_remove_blocked_ip_' . $ip->id)); ?>">
<?php _e('Entfernen', 'wp-multi'); ?>
</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php if ($total_pages > 1) : ?>
<div class="tablenav">
<div class="tablenav-pages">
<?php
echo paginate_links(array(
'base' => add_query_arg('paged', '%#%'),
'format' => '',
'prev_text' => __('«'),
'next_text' => __('»'),
'total' => $total_pages,
'current' => $page,
));
?>
</div>
</div>
<?php endif; ?>
<?php
}
wpmt_admin_card_close();
// Aufräumen: alte Einträge mit wenigen Versuchen entfernen
$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
)
);
wpmt_admin_page_close();
}
// Funktion zum Entfernen einer blockierten IP
function wp_multi_remove_blocked_ip() {
if (!current_user_can('manage_options')) {
wp_die(__('Du hast nicht die erforderlichen Berechtigungen.', 'wp-multi'), '', array('response' => 403));
}
$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
if (!$id || !isset($_GET['_wpnonce']) || !wp_verify_nonce(wp_unslash($_GET['_wpnonce']), 'wp_multi_remove_blocked_ip_' . $id)) {
wp_die(__('Ungültige oder abgelaufene Anfrage.', 'wp-multi'), '', array('response' => 403));
}
global $wpdb;
if ($id > 0) {
$table_name = $wpdb->prefix . 'blocked_ips';
$wpdb->delete($table_name, array('id' => $id), array('%d'));
}
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');
+153
View File
@@ -0,0 +1,153 @@
<?php
/**
* WP Multi Modul: Kommentarfilter (Telefon/E-Mail/URL/IP/Schimpfwörter)
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Kommentarfilter: Telefonnummern, E-Mails, URLs, IPs und Schimpfwörter
*/
// Einstellungen für den Kommentarfilter registrieren (auf der bestehenden "Sicherheit"-Seite)
function wp_multi_comment_filter_register_settings() {
register_setting('wp_multi_security_settings', 'wp_multi_filter_phone', ['sanitize_callback' => 'absint', 'default' => 0]);
register_setting('wp_multi_security_settings', 'wp_multi_filter_email', ['sanitize_callback' => 'absint', 'default' => 0]);
register_setting('wp_multi_security_settings', 'wp_multi_filter_url', ['sanitize_callback' => 'absint', 'default' => 0]);
register_setting('wp_multi_security_settings', 'wp_multi_filter_ip', ['sanitize_callback' => 'absint', 'default' => 0]);
register_setting('wp_multi_security_settings', 'wp_multi_filter_swearwords', ['sanitize_callback' => 'absint', 'default' => 0]);
add_settings_section(
'wp_multi_comment_filter_section',
__('Kommentarfilter', 'wp-multi'),
'wp_multi_comment_filter_section_callback',
'wp-multi-security'
);
add_settings_field('wp_multi_filter_phone', __('Telefonnummern filtern', 'wp-multi'), 'wp_multi_filter_phone_callback', 'wp-multi-security', 'wp_multi_comment_filter_section');
add_settings_field('wp_multi_filter_email', __('E-Mail-Adressen filtern', 'wp-multi'), 'wp_multi_filter_email_callback', 'wp-multi-security', 'wp_multi_comment_filter_section');
add_settings_field('wp_multi_filter_url', __('URLs filtern', 'wp-multi'), 'wp_multi_filter_url_callback', 'wp-multi-security', 'wp_multi_comment_filter_section');
add_settings_field('wp_multi_filter_ip', __('IP-Adressen filtern', 'wp-multi'), 'wp_multi_filter_ip_callback', 'wp-multi-security', 'wp_multi_comment_filter_section');
add_settings_field('wp_multi_filter_swearwords', __('Schimpfwörter filtern', 'wp-multi'), 'wp_multi_filter_swearwords_callback', 'wp-multi-security', 'wp_multi_comment_filter_section');
}
add_action('admin_init', 'wp_multi_comment_filter_register_settings');
function wp_multi_comment_filter_section_callback() {
echo '<p>' . esc_html__('Lege fest, welche Inhalte in Kommentaren automatisch durch * ersetzt werden, statt den ganzen Kommentar zu blockieren.', 'wp-multi') . '</p>';
}
function wp_multi_filter_phone_callback() {
?>
<input type="checkbox" name="wp_multi_filter_phone" value="1" <?php checked(1, get_option('wp_multi_filter_phone', 0)); ?>>
<?php
}
function wp_multi_filter_email_callback() {
?>
<input type="checkbox" name="wp_multi_filter_email" value="1" <?php checked(1, get_option('wp_multi_filter_email', 0)); ?>>
<?php
}
function wp_multi_filter_url_callback() {
?>
<input type="checkbox" name="wp_multi_filter_url" value="1" <?php checked(1, get_option('wp_multi_filter_url', 0)); ?>>
<?php
}
function wp_multi_filter_ip_callback() {
?>
<input type="checkbox" name="wp_multi_filter_ip" value="1" <?php checked(1, get_option('wp_multi_filter_ip', 0)); ?>>
<?php
}
function wp_multi_filter_swearwords_callback() {
?>
<input type="checkbox" name="wp_multi_filter_swearwords" value="1" <?php checked(1, get_option('wp_multi_filter_swearwords', 0)); ?>>
<small><?php esc_html_e('Nutzt die Wortliste aus includes/bad-words.json.', 'wp-multi'); ?></small>
<?php
}
// Lädt die Schimpfwortliste aus includes/bad-words.json (gecached via Transient)
function wp_multi_get_bad_words() {
$cache_key = 'wp_multi_bad_words';
$words = get_transient($cache_key);
if ($words !== false) {
return $words;
}
$words = [];
$file_path = plugin_dir_path(WP_MULTI_FILE) . 'includes/bad-words.json';
if (file_exists($file_path)) {
$data = json_decode(file_get_contents($file_path), true);
if (is_array($data) && !empty($data['words']) && is_array($data['words'])) {
$words = $data['words'];
}
}
set_transient($cache_key, $words, DAY_IN_SECONDS);
return $words;
}
// Baut die (teuren) Regex-Patterns aus der Schimpfwortliste und cached sie.
// Die Wortliste hat mehrere tausend Einträge - in ein einziges Regex gepackt
// überschreitet das die PCRE-Größenlimits, daher wird in Blöcken gearbeitet.
function wp_multi_get_bad_words_patterns() {
$cache_key = 'wp_multi_bad_words_patterns';
$patterns = get_transient($cache_key);
if ($patterns !== false) {
return $patterns;
}
$words = wp_multi_get_bad_words();
$patterns = [];
foreach (array_chunk($words, 500) as $chunk) {
$patterns[] = '/\b(' . implode('|', array_map('preg_quote', $chunk)) . ')\b/iu';
}
set_transient($cache_key, $patterns, DAY_IN_SECONDS);
return $patterns;
}
// Ersetzt einen Regex-Treffer durch eine gleich lange Folge von *
function wp_multi_mask_match($matches) {
$match = $matches[0];
return str_repeat('*', function_exists('mb_strlen') ? mb_strlen($match) : strlen($match));
}
// Wendet den Kommentarfilter (Telefon, E-Mail, URL, IP, Schimpfwörter) auf einen Text an
function wp_multi_apply_comment_content_filter($content) {
if (get_option('wp_multi_filter_phone', 0)) {
$content = preg_replace_callback('/(?:\+?\d[\d\s\-\/\(\)]{6,}\d)/', 'wp_multi_mask_match', $content);
}
if (get_option('wp_multi_filter_email', 0)) {
$content = preg_replace_callback('/[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}/', 'wp_multi_mask_match', $content);
}
if (get_option('wp_multi_filter_url', 0)) {
$content = preg_replace_callback('#\b(?:https?://|www\.)[^\s<>"]+#i', 'wp_multi_mask_match', $content);
}
if (get_option('wp_multi_filter_ip', 0)) {
$content = preg_replace_callback('/\b(?:\d{1,3}\.){3}\d{1,3}\b/', 'wp_multi_mask_match', $content);
}
if (get_option('wp_multi_filter_swearwords', 0)) {
foreach (wp_multi_get_bad_words_patterns() as $pattern) {
$content = preg_replace_callback($pattern, 'wp_multi_mask_match', $content);
}
}
return $content;
}
+63
View File
@@ -0,0 +1,63 @@
<?php
/**
* WP Multi Modul: Text-Copy-Schutz
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Text Copy Schutz und Schutz vor Entwicklertools
*/
// JavaScript für die Kopierschutz-Funktion einbinden
function wp_multi_enqueue_scripts() {
wp_add_inline_script('jquery', "
jQuery(document).ready(function($) {
// Verhindert das Öffnen der Entwicklertools mit F12, Strg+Shift+I und Strg+Shift+C
$(document).keydown(function(e) {
// Blockiert F12, Strg + Shift + I, Strg + Shift + C (Entwicklertools)
if (e.keyCode == 123 || (e.ctrlKey && e.shiftKey && e.keyCode == 73) || (e.ctrlKey && e.shiftKey && e.keyCode == 67)) {
e.preventDefault();
}
// Verhindert das Öffnen des Quellcodes mit Strg + U (view-source)
if ((e.ctrlKey && e.keyCode == 85) || (e.ctrlKey && e.shiftKey && e.keyCode == 85)) {
e.preventDefault();
}
// Verhindert den Zugriff auf die Konsole mit Strg + Shift + J (Konsole-Tab)
if ((e.ctrlKey && e.shiftKey && e.keyCode == 74) || (e.metaKey && e.altKey && e.keyCode == 74)) {
e.preventDefault();
}
// Verhindert das Öffnen des Quellcodes mit view-source
if (e.ctrlKey && e.keyCode == 85) {
e.preventDefault();
}
});
// Verhindert das Öffnen des Kontextmenüs (Rechtsklick)
$('body').on('contextmenu', function(e) {
e.preventDefault();
});
// Kopierschutz-Funktion
$('body').on('copy', function(e) {
e.preventDefault();
var selectedText = window.getSelection().toString();
var numericText = selectedText.replace(/./g, function(char) {
return Math.floor(Math.random() * 10);
});
e.originalEvent.clipboardData.setData('text/plain', numericText);
});
});
");
}
add_action('wp_enqueue_scripts', 'wp_multi_enqueue_scripts');
+227
View File
@@ -0,0 +1,227 @@
<?php
/**
* WP Multi Modul: Custom Admin-Links
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Custom Link im Admin Sidebar hinzufügen
*/
// Die benutzerdefinierten Admin-Link-Seiten werden zentral in wp_multi_register_admin_menus() registriert.
// Callback-Funktion für das Anzeigen der benutzerdefinierten Seiten
function wp_stat_notice_custom_page() {
$current_slug = isset($_GET['page']) ? sanitize_key($_GET['page']) : '';
$custom_pages = get_option('wp_stat_notice_custom_pages', []);
if (empty($custom_pages) || !is_array($custom_pages)) {
wpmt_admin_page_open(__('Benutzerdefinierte Seite', 'wp-stat-notice'));
wpmt_admin_notice('error', __('Keine benutzerdefinierten Seiten gefunden.', 'wp-stat-notice'));
wpmt_admin_page_close();
return;
}
foreach ($custom_pages as $page) {
if ($page['slug'] === $current_slug) {
wpmt_admin_page_open($page['title']);
wpmt_admin_card_open();
if (isset($page['url']) && filter_var($page['url'], FILTER_VALIDATE_URL)) {
echo '<script>window.open("' . esc_url($page['url']) . '", "_blank");</script>';
echo '<p>' . __('Die externe Seite wird in einem neuen Fenster geöffnet.', 'wp-stat-notice') . '</p>';
echo '<p><a href="' . esc_url($page['url']) . '" target="_blank" class="wpm-btn wpm-btn--primary">' . esc_html__('Seite manuell öffnen', 'wp-stat-notice') . '</a></p>';
} else {
echo '<p>' . __('Dies ist eine benutzerdefinierte Seite im Admin-Bereich.', 'wp-stat-notice') . '</p>';
}
wpmt_admin_card_close();
wpmt_admin_page_close();
return;
}
}
wpmt_admin_page_open(__('Benutzerdefinierte Seite', 'wp-stat-notice'));
wpmt_admin_notice('error', __('Seite nicht gefunden.', 'wp-stat-notice'));
wpmt_admin_page_close();
}
// Funktion zum Hinzufügen und Verwalten benutzerdefinierter Seiten
function wp_stat_notice_add_custom_page_form() {
$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-welcome-write-blog'
];
?>
<div class="wrap">
<h1><?php _e('Benutzerdefinierten Adminlink hinzufügen', 'wp-stat-notice'); ?></h1>
<!-- Formular zum Hinzufügen -->
<form method="post" action="">
<?php wp_nonce_field('wp_stat_notice_add_page', 'wp_stat_notice_nonce'); ?>
<table class="form-table">
<tr>
<th scope="row"><label for="page_title"><?php _e('Titel der Seite', 'wp-stat-notice'); ?></label></th>
<td><input type="text" name="page_title" id="page_title" required class="regular-text"></td>
</tr>
<tr>
<th scope="row"><label for="page_url"><?php _e('URL der Seite (optional)', 'wp-stat-notice'); ?></label></th>
<td><input type="url" name="page_url" id="page_url" class="regular-text" placeholder="https://example.com"></td>
</tr>
<tr>
<th scope="row"><label for="page_slug"><?php _e('Slug der Seite', 'wp-stat-notice'); ?></label></th>
<td><input type="text" name="page_slug" id="page_slug" required class="regular-text"></td>
</tr>
<tr>
<th scope="row"><label for="page_icon"><?php _e('Dashicon auswählen', 'wp-stat-notice'); ?></label></th>
<td>
<select name="page_icon" id="page_icon" onchange="updateIconPreview(this)">
<?php foreach ($dashicons as $dashicon): ?>
<option value="<?php echo esc_attr($dashicon); ?>"><?php echo esc_html($dashicon); ?></option>
<?php endforeach; ?>
</select>
<div id="icon-preview" class="dashicons" style="font-size: 24px; margin-top: 10px;"></div>
</td>
</tr>
</table>
<p><input type="submit" name="add_custom_page" class="button button-primary" value="<?php _e('Seite hinzufügen', 'wp-stat-notice'); ?>"></p>
</form>
<?php
// Formularverarbeitung für Hinzufügen
if (isset($_POST['add_custom_page']) && check_admin_referer('wp_stat_notice_add_page', 'wp_stat_notice_nonce')) {
$title = sanitize_text_field($_POST['page_title']);
$url = !empty($_POST['page_url']) ? esc_url_raw($_POST['page_url']) : '';
$slug = sanitize_key($_POST['page_slug']);
$icon = in_array($_POST['page_icon'], $dashicons, true) ? $_POST['page_icon'] : 'dashicons-admin-links';
if (empty($title) || empty($slug)) {
echo '<div class="notice notice-error"><p>' . __('Titel und Slug sind erforderlich.', 'wp-stat-notice') . '</p></div>';
} else {
$custom_pages = get_option('wp_stat_notice_custom_pages', []);
$slugs = array_column($custom_pages, 'slug');
if (in_array($slug, $slugs)) {
echo '<div class="notice notice-error"><p>' . __('Dieser Slug wird bereits verwendet.', 'wp-stat-notice') . '</p></div>';
} else {
$custom_pages[] = ['title' => $title, 'url' => $url, 'slug' => $slug, 'icon' => $icon];
update_option('wp_stat_notice_custom_pages', $custom_pages);
echo '<div class="updated"><p>' . __('Benutzerdefinierte Seite wurde hinzugefügt!', 'wp-stat-notice') . '</p></div>';
}
}
}
// Verwaltung der Seiten
$custom_pages = get_option('wp_stat_notice_custom_pages', []);
if (!empty($custom_pages)) {
echo '<h2>' . __('Verwaltung der benutzerdefinierten Seiten', 'wp-stat-notice') . '</h2>';
echo '<table class="widefat fixed" cellspacing="0">';
echo '<thead><tr><th>' . __('Titel', 'wp-stat-notice') . '</th><th>' . __('URL', 'wp-stat-notice') . '</th><th>' . __('Slug', 'wp-stat-notice') . '</th><th>' . __('Aktionen', 'wp-stat-notice') . '</th></tr></thead>';
echo '<tbody>';
foreach ($custom_pages as $index => $page) {
echo '<tr>';
echo '<td>' . esc_html($page['title']) . '</td>';
echo '<td>' . esc_html($page['url'] ?: '-') . '</td>';
echo '<td>' . esc_html($page['slug']) . '</td>';
$delete_url = wp_nonce_url(admin_url('admin.php?page=wp-stat-notice-custom-page&delete=' . $index), 'wp_stat_notice_delete_page_' . $index);
echo '<td><a href="' . esc_url(admin_url('admin.php?page=wp-stat-notice-custom-page&edit=' . $index)) . '">' . __('Bearbeiten', 'wp-stat-notice') . '</a> | ';
echo '<a href="' . esc_url($delete_url) . '" onclick="return confirm(\'' . esc_js(__('Möchtest du diese Seite wirklich löschen?', 'wp-stat-notice')) . '\')">' . __('Löschen', 'wp-stat-notice') . '</a></td>';
echo '</tr>';
}
echo '</tbody></table>';
}
// Bearbeiten
if (isset($_GET['edit']) && isset($custom_pages[(int) $_GET['edit']])) {
$edit_index = (int) $_GET['edit'];
$edit_page = $custom_pages[$edit_index];
echo '<h2>' . __('Seite bearbeiten', 'wp-stat-notice') . '</h2>';
?>
<form method="post" action="">
<?php wp_nonce_field('wp_stat_notice_edit_page', 'wp_stat_notice_nonce'); ?>
<table class="form-table">
<tr>
<th scope="row"><label for="edit_page_title"><?php _e('Titel der Seite', 'wp-stat-notice'); ?></label></th>
<td><input type="text" name="edit_page_title" id="edit_page_title" value="<?php echo esc_attr($edit_page['title']); ?>" required class="regular-text"></td>
</tr>
<tr>
<th scope="row"><label for="edit_page_url"><?php _e('URL der Seite (optional)', 'wp-stat-notice'); ?></label></th>
<td><input type="url" name="edit_page_url" id="edit_page_url" value="<?php echo esc_attr($edit_page['url']); ?>" class="regular-text"></td>
</tr>
<tr>
<th scope="row"><label for="edit_page_slug"><?php _e('Slug der Seite', 'wp-stat-notice'); ?></label></th>
<td><input type="text" name="edit_page_slug" id="edit_page_slug" value="<?php echo esc_attr($edit_page['slug']); ?>" required class="regular-text"></td>
</tr>
<tr>
<th scope="row"><label for="edit_page_icon"><?php _e('Dashicon', 'wp-stat-notice'); ?></label></th>
<td>
<select name="edit_page_icon" id="edit_page_icon" onchange="updateIconPreview(this)">
<?php foreach ($dashicons as $dashicon): ?>
<option value="<?php echo esc_attr($dashicon); ?>" <?php selected($edit_page['icon'], $dashicon); ?>><?php echo esc_html($dashicon); ?></option>
<?php endforeach; ?>
</select>
<div id="icon-preview" class="dashicons <?php echo esc_attr($edit_page['icon']); ?>" style="font-size: 24px; margin-top: 10px;"></div>
</td>
</tr>
</table>
<p><input type="submit" name="save_custom_page" class="button button-primary" value="<?php _e('Änderungen speichern', 'wp-stat-notice'); ?>"></p>
</form>
<?php
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, true) ? $_POST['edit_page_icon'] : 'dashicons-admin-links';
if (empty($title) || empty($slug)) {
echo '<div class="notice notice-error"><p>' . __('Titel und Slug sind erforderlich.', 'wp-stat-notice') . '</p></div>';
} else {
$custom_pages[$edit_index] = ['title' => $title, 'url' => $url, 'slug' => $slug, 'icon' => $icon];
update_option('wp_stat_notice_custom_pages', $custom_pages);
echo '<div class="updated"><p>' . __('Seite erfolgreich bearbeitet!', 'wp-stat-notice') . '</p></div>';
}
}
}
// Löschen
if (isset($_GET['delete']) && isset($custom_pages[(int) $_GET['delete']])) {
check_admin_referer('wp_stat_notice_delete_page_' . (int) $_GET['delete']);
$delete_index = (int) $_GET['delete'];
unset($custom_pages[$delete_index]);
$custom_pages = array_values($custom_pages);
update_option('wp_stat_notice_custom_pages', $custom_pages);
echo '<div class="updated"><p>' . __('Seite wurde gelöscht.', 'wp-stat-notice') . '</p></div>';
}
?>
</div>
<script>
function updateIconPreview(select) {
const preview = select.nextElementSibling;
preview.className = 'dashicons ' + select.value;
}
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('#page_icon, #edit_page_icon').forEach(select => {
updateIconPreview(select);
});
});
</script>
<?php
}
// Der Menüpunkt "Admin-Link hinzufügen" wird zentral in wp_multi_register_admin_menus() registriert.
+157
View File
@@ -0,0 +1,157 @@
<?php
/**
* WP Multi Modul: Custom Text Box
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Custom Text Box
*/
// Funktion zur Registrierung der zusätzlichen Einstellungen für benutzerdefinierte Texte
function wp_multi_custom_text_register_settings() {
add_option('wp_multi_custom_texts', '');
add_option('wp_multi_second_custom_text', '');
add_option('wp_multi_enable_custom_texts', '1');
register_setting('wp_multi_custom_text_options_group', 'wp_multi_custom_texts');
register_setting('wp_multi_custom_text_options_group', 'wp_multi_second_custom_text');
register_setting('wp_multi_custom_text_options_group', 'wp_multi_enable_custom_texts');
}
add_action('admin_init', 'wp_multi_custom_text_register_settings');
// Der Custom-Text-Menüpunkt wird zentral in wp_multi_register_admin_menus() registriert.
// Funktion zum Erstellen der Einstellungsseite
function wp_multi_custom_text_settings_page_content() {
wpmt_admin_page_open(
__('Custom Text', 'wp-multi'),
__('Vordefinierte Textboxen am Ende deiner Beiträge', 'wp-multi')
);
wpmt_admin_card_open();
?>
<form method="post" action="options.php">
<?php settings_fields('wp_multi_custom_text_options_group'); ?>
<table class="form-table">
<tr valign="top">
<th scope="row"><?php _e('Custom Texte aktivieren', 'wp-multi'); ?></th>
<td>
<input type="checkbox" name="wp_multi_enable_custom_texts" value="1" <?php checked(1, get_option('wp_multi_enable_custom_texts'), true); ?> />
<p class="description"><?php _e('Aktiviere oder deaktiviere die Anzeige der benutzerdefinierten Texte auf der Webseite.', 'wp-multi'); ?></p>
</td>
</tr>
<tr valign="top">
<th scope="row"><?php _e('Custom Texte', 'wp-multi'); ?></th>
<td>
<textarea name="wp_multi_custom_texts" rows="10" cols="50" class="large-text"><?php echo esc_textarea(get_option('wp_multi_custom_texts')); ?></textarea>
<p class="description"><?php _e('Gib jeden Text in einer neuen Zeile ein.', 'wp-multi'); ?></p>
</td>
</tr>
<tr valign="top">
<th scope="row"><?php _e('Zweiter Custom Text', 'wp-multi'); ?></th>
<td>
<textarea name="wp_multi_second_custom_text" rows="10" cols="50" class="large-text"><?php echo esc_textarea(get_option('wp_multi_second_custom_text')); ?></textarea>
<p class="description"><?php _e('Gib den zweiten Custom Text ein, der über der ersten Box angezeigt wird.', 'wp-multi'); ?></p>
</td>
</tr>
</table>
<?php submit_button(); ?>
</form>
<?php
wpmt_admin_card_close();
wpmt_admin_page_close();
}
// Anzeige der Custom Texts in einer Box im Frontend
function wp_multi_custom_text_display($content) {
$enable_custom_texts = get_option('wp_multi_enable_custom_texts', '1');
if ($enable_custom_texts !== '1') {
return $content;
}
if (is_single()) {
global $post;
$guest_author_name = get_post_meta($post->ID, '_guest_author', true);
$author_name = !empty($guest_author_name) ? $guest_author_name : get_the_author();
$custom_texts = get_option('wp_multi_custom_texts', '');
$second_custom_texts = get_option('wp_multi_second_custom_text', '');
$custom_texts_array = array_filter(array_map('trim', explode("\n", $custom_texts)));
$second_custom_texts_array = array_filter(array_map('trim', explode("\n", $second_custom_texts)));
$selected_custom_text = get_post_meta($post->ID, '_custom_text_choice', true);
$selected_second_custom_text = get_post_meta($post->ID, '_second_custom_text_choice', true);
if (empty($custom_texts_array) && empty($second_custom_texts_array)) {
return $content;
}
$output = '<div class="custom-text-box" style="margin-top: 40px; padding: 20px; background-color: #f0f0f0; border: 2px solid #ddd; border-radius: 10px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); max-width: 400px; width: auto; font-size: 16px; line-height: 1.2; clear: both; margin-left: auto; margin-right: 0; display: block; margin-bottom: 20px; position: relative;">';
$output .= '<p><strong>' . __('Autor:', 'wp-multi') . ' ' . esc_html($author_name);
if ($selected_second_custom_text !== '' && isset($second_custom_texts_array[$selected_second_custom_text])) {
$output .= ' | ' . esc_html($second_custom_texts_array[$selected_second_custom_text]);
}
$output .= '</strong></p>';
if ($selected_custom_text !== '' && isset($custom_texts_array[$selected_custom_text])) {
$output .= '<p><em>' . esc_html($custom_texts_array[$selected_custom_text]) . '</em></p>';
}
$output .= '</div>';
return $content . $output;
}
return $content;
}
add_filter('the_content', 'wp_multi_custom_text_display');
// Funktion zum Hinzufügen der Meta-Box für beide Custom Texts
function wp_multi_add_custom_text_fields($post) {
$custom_texts = get_option('wp_multi_custom_texts');
$custom_texts_array = array_filter(array_map('trim', explode("\n", $custom_texts)));
$second_custom_text = get_option('wp_multi_second_custom_text');
$second_custom_text_array = array_filter(array_map('trim', explode("\n", $second_custom_text)));
$selected_custom_text = get_post_meta($post->ID, '_custom_text_choice', true);
$selected_second_custom_text = get_post_meta($post->ID, '_second_custom_text_choice', true);
wp_nonce_field('wp_multi_custom_text_choice_nonce', 'wp_multi_custom_text_choice_nonce_field');
?>
<label for="custom_text_choice"><?php _e('Wähle den Custom Text (unterer Bereich):', 'wp-multi'); ?></label>
<select name="custom_text_choice" id="custom_text_choice" class="widefat">
<option value=""><?php _e('Keinen Text auswählen', 'wp-multi'); ?></option>
<?php foreach ($custom_texts_array as $key => $value) { ?>
<option value="<?php echo esc_attr($key); ?>" <?php selected($selected_custom_text, $key); ?>><?php echo esc_html($value); ?></option>
<?php } ?>
</select>
<label for="second_custom_text_choice"><?php _e('Wähle den zweiten Custom Text (oberer Bereich):', 'wp-multi'); ?></label>
<select name="second_custom_text_choice" id="second_custom_text_choice" class="widefat">
<option value=""><?php _e('Keinen Text auswählen', 'wp-multi'); ?></option>
<?php foreach ($second_custom_text_array as $key => $value) { ?>
<option value="<?php echo esc_attr($key); ?>" <?php selected($selected_second_custom_text, $key); ?>><?php echo esc_html($value); ?></option>
<?php } ?>
</select>
<?php
}
// Meta-Box hinzufügen
add_action('add_meta_boxes', function() {
add_meta_box('wp_multi_custom_text', __('Custom Text Auswahl', 'wp-multi'), 'wp_multi_add_custom_text_fields', 'post', 'normal', 'high');
});
// Speichern der benutzerdefinierten Textauswahl im Beitrag
function wp_multi_save_custom_text_choice($post_id) {
if (!isset($_POST['wp_multi_custom_text_choice_nonce_field']) || !wp_verify_nonce($_POST['wp_multi_custom_text_choice_nonce_field'], 'wp_multi_custom_text_choice_nonce')) {
return;
}
if (!current_user_can('edit_post', $post_id)) {
return;
}
if (isset($_POST['custom_text_choice'])) {
update_post_meta($post_id, '_custom_text_choice', sanitize_text_field(wp_unslash($_POST['custom_text_choice'])));
}
if (isset($_POST['second_custom_text_choice'])) {
update_post_meta($post_id, '_second_custom_text_choice', sanitize_text_field(wp_unslash($_POST['second_custom_text_choice'])));
}
}
add_action('save_post', 'wp_multi_save_custom_text_choice');
+61
View File
@@ -0,0 +1,61 @@
<?php
/**
* WP Multi Modul: Login deaktivieren (pro Benutzer)
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Login deaktivieren
*/
// Checkbox zum Benutzerprofil hinzufügen
function wp_multi_add_disable_login_checkbox($user) {
?>
<h3>Login deaktivieren</h3>
<table class="form-table">
<tr>
<th><label for="disable_login">Login deaktivieren</label></th>
<td>
<input type="checkbox" name="disable_login" id="disable_login" value="1" <?php checked( get_user_meta($user->ID, 'disable_login', true), 1 ); ?> />
<span class="description">Markiere diese Option, um den Login des Benutzers zu deaktivieren.</span>
</td>
</tr>
</table>
<?php
}
// Speichern der Checkbox-Option
function wp_multi_save_disable_login_checkbox($user_id) {
if ( isset( $_POST['disable_login'] ) ) {
update_user_meta( $user_id, 'disable_login', 1 );
} else {
delete_user_meta( $user_id, 'disable_login' );
}
}
// Die Checkbox in das Benutzerprofil einfügen
add_action( 'show_user_profile', 'wp_multi_add_disable_login_checkbox' );
add_action( 'edit_user_profile', 'wp_multi_add_disable_login_checkbox' );
// Speichern der Checkbox-Option
add_action( 'personal_options_update', 'wp_multi_save_disable_login_checkbox' );
add_action( 'edit_user_profile_update', 'wp_multi_save_disable_login_checkbox' );
// Login blockieren, wenn die Checkbox aktiviert ist
function wp_multi_block_login_if_disabled($user_login, $user) {
// Prüfen, ob der Benutzer das Flag "Login deaktivieren" gesetzt hat
if ( get_user_meta( $user->ID, 'disable_login', true ) ) {
// Fehlermeldung anzeigen, wenn der Login deaktiviert ist
wp_die( 'Dein Login wurde deaktiviert. Bitte kontaktiere den Administrator.' );
}
}
// Der Filter wird bei jedem Login-Versuch angewendet
add_action( 'wp_login', 'wp_multi_block_login_if_disabled', 10, 2 );
+44
View File
@@ -0,0 +1,44 @@
<?php
/**
* WP Multi Modul: Sperre Trash-Mail-Adressen
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Sperre Trash Mail Adressen
*/
// Funktion zum Laden der Liste von Einweg-Mail-Anbietern
function load_disposable_email_list() {
$file_path = plugin_dir_path(WP_MULTI_FILE) . 'includes/disposable_email_blocklist.conf'; // Pfad zur Datei im includes-Ordner
if (file_exists($file_path)) {
return file($file_path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
}
return [];
}
// Funktion zum Überprüfen der E-Mail-Adresse eines Kommentators
function check_disposable_email($commentdata) {
$disposable_list = load_disposable_email_list();
$email = $commentdata['comment_author_email'];
$domain = substr(strrchr($email, "@"), 1); // Nur die Domain extrahieren
// Überprüfen, ob die Domain auf der Liste steht
if (in_array($domain, $disposable_list)) {
wp_die(__('Fehler: Trash-Mail-Adressen sind in Kommentaren nicht erlaubt.'));
}
return $commentdata;
}
// Die Funktion wird beim Absenden eines Kommentars ausgeführt
add_filter('preprocess_comment', 'check_disposable_email');
+1 -1
View File
@@ -4048,4 +4048,4 @@ zymuying.com
zyns.com
zzi.us
zzrgg.com
zzz.com
zzz.com
+317
View File
@@ -0,0 +1,317 @@
<?php
/**
* WP Multi Modul: Gast-Autoren
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Gast Autoren
*/
// Gast-Autor Eingabefeld in der Sidebar im Admin-Bereich hinzufügen
function wp_multi_add_guest_author_field() {
add_meta_box(
'guest_author_meta_box',
__('Gast-Autor', 'wp-multi'),
'wp_multi_guest_author_field',
['post', 'page', 'dein_custom_post_type'],
'side',
'high'
);
}
add_action('add_meta_boxes', 'wp_multi_add_guest_author_field');
// Callback-Funktion, die das Eingabefeld anzeigt
function wp_multi_guest_author_field($post) {
$guest_author = get_post_meta($post->ID, '_guest_author', true);
wp_nonce_field('wp_multi_guest_author_nonce', 'wp_multi_guest_author_nonce_field');
?>
<label for="guest_author"><?php _e('Gast-Autor Name:', 'wp-multi'); ?></label>
<input type="text" id="guest_author" name="guest_author" value="<?php echo esc_attr($guest_author); ?>" class="widefat" />
<?php
}
// Speichern der Gast-Autor Daten
function wp_multi_save_guest_author_meta($post_id) {
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (!isset($_POST['wp_multi_guest_author_nonce_field']) || !wp_verify_nonce($_POST['wp_multi_guest_author_nonce_field'], 'wp_multi_guest_author_nonce')) return;
if (!current_user_can('edit_post', $post_id)) return;
if (isset($_POST['guest_author'])) {
$guest_author = sanitize_text_field(wp_unslash($_POST['guest_author']));
update_post_meta($post_id, '_guest_author', $guest_author);
} else {
delete_post_meta($post_id, '_guest_author');
}
}
add_action('save_post', 'wp_multi_save_guest_author_meta');
// Gast-Autor anzeigen anstelle des regulären Autors im Frontend
function wp_multi_display_guest_author($author_name) {
if ((is_single() || is_archive() || is_home()) && !is_admin()) {
$post = get_post();
if ($post) {
$guest_author = get_post_meta($post->ID, '_guest_author', true);
if (!empty($guest_author)) {
$author_name = $guest_author;
}
}
}
return $author_name;
}
add_filter('the_author', 'wp_multi_display_guest_author');
// Anzeige des Gast-Autors in der Beitragsübersicht (Backend)
function wp_multi_add_guest_author_column($columns) {
if (isset($columns['author'])) {
$columns['guest_author'] = __('Gast-Autor', 'wp-multi');
}
return $columns;
}
add_filter('manage_posts_columns', 'wp_multi_add_guest_author_column');
function wp_multi_display_guest_author_column($column_name, $post_id) {
if ($column_name == 'guest_author') {
$guest_author = get_post_meta($post_id, '_guest_author', true);
echo !empty($guest_author) ? esc_html($guest_author) : __('Kein Gast-Autor', 'wp-multi');
}
}
add_action('manage_posts_custom_column', 'wp_multi_display_guest_author_column', 10, 2);
// Der Gast-Autoren-Menüpunkt wird zentral in wp_multi_register_admin_menus() registriert.
// Callback-Funktion für die Gast-Autor-Übersicht
function wp_multi_guest_author_overview_page() {
// Sortierparameter aus URL lesen
$orderby = isset($_GET['orderby']) ? sanitize_key($_GET['orderby']) : 'guest_author';
$order = isset($_GET['order']) && in_array(strtoupper($_GET['order']), ['ASC', 'DESC']) ? strtoupper($_GET['order']) : 'ASC';
// Gültige Sortierfelder
$valid_orderby = ['guest_author' => 'pm.meta_value', 'posts' => 'post_count'];
$sql_orderby = isset($valid_orderby[$orderby]) ? $valid_orderby[$orderby] : 'pm.meta_value';
$sql_order = $order;
// Basis-URL für Sortier-Links
$base_url = add_query_arg(['page' => 'guest_author_overview'], admin_url('admin.php'));
global $wpdb;
$query = "
SELECT pm.meta_value AS guest_author, COUNT(*) AS post_count
FROM {$wpdb->posts} p
INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
WHERE pm.meta_key = '_guest_author'
AND pm.meta_value != ''
AND p.post_status = 'publish'
GROUP BY pm.meta_value
ORDER BY {$sql_orderby} {$sql_order}
";
$guest_authors = $wpdb->get_results($query);
wpmt_admin_page_open(
__('Gast-Autoren', 'wp-multi'),
__('Alle Gast-Autoren mit Anzahl ihrer veröffentlichten Beiträge', 'wp-multi')
);
wpmt_admin_card_open();
?>
<div class="wpm-table-wrap">
<table class="wpm-table">
<thead>
<tr>
<th>
<a href="<?php echo esc_url(add_query_arg(['orderby' => 'guest_author', 'order' => ($orderby === 'guest_author' && $order === 'ASC') ? 'DESC' : 'ASC'], $base_url)); ?>">
<?php _e('Gast-Autor', 'wp-multi'); ?>
<?php if ($orderby === 'guest_author') : ?>
<span><?php echo ($order === 'ASC') ? '↑' : '↓'; ?></span>
<?php endif; ?>
</a>
</th>
<th>
<a href="<?php echo esc_url(add_query_arg(['orderby' => 'posts', 'order' => ($orderby === 'posts' && $order === 'ASC') ? 'DESC' : 'ASC'], $base_url)); ?>">
<?php _e('Anzahl der Beiträge', 'wp-multi'); ?>
<?php if ($orderby === 'posts') : ?>
<span><?php echo ($order === 'ASC') ? '↑' : '↓'; ?></span>
<?php endif; ?>
</a>
</th>
</tr>
</thead>
<tbody>
<?php if ($guest_authors) : ?>
<?php foreach ($guest_authors as $author) : ?>
<tr>
<td><?php echo esc_html($author->guest_author); ?></td>
<td><span class="wpm-badge"><?php echo esc_html($author->post_count); ?></span></td>
</tr>
<?php endforeach; ?>
<?php else : ?>
<tr><td colspan="2"><?php _e('Keine Gast-Autoren gefunden.', 'wp-multi'); ?></td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
<?php
wpmt_admin_card_close();
wpmt_admin_page_close();
}
// Funktion zum Erstellen der Gastautoren-Beitragsseite
function wp_multi_create_guest_author_page() {
$page_title = __('Gastautor Beiträge', 'wp-multi');
$page_slug = 'gastautor-beitraege';
$page = get_page_by_path($page_slug);
if (!$page) {
$page_id = wp_insert_post(array(
'post_title' => $page_title,
'post_name' => $page_slug,
'post_content' => '[guest_author_posts]',
'post_status' => 'publish',
'post_type' => 'page',
));
if ($page_id && !is_wp_error($page_id)) {
update_option('wp_multi_guest_author_page_id', $page_id);
}
} else {
update_option('wp_multi_guest_author_page_id', $page->ID);
}
}
add_action('init', 'wp_multi_create_guest_author_page');
// Shortcode für Gastautoren-Liste
function wp_multi_guest_author_shortcode() {
ob_start();
global $wpdb;
// Alle Gastautoren mit Beitragsanzahl abrufen
$query = "
SELECT pm.meta_value AS guest_author, COUNT(*) AS post_count
FROM {$wpdb->posts} p
INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
WHERE pm.meta_key = '_guest_author'
AND pm.meta_value != ''
AND p.post_status = 'publish'
GROUP BY pm.meta_value
ORDER BY pm.meta_value ASC
";
$guest_authors = $wpdb->get_results($query);
// URL der Gastautoren-Beitragsseite
$guest_author_page_id = get_option('wp_multi_guest_author_page_id');
$guest_author_page_url = $guest_author_page_id ? get_permalink($guest_author_page_id) : '#';
?>
<div id="guest-author-section" class="container mx-auto px-4 py-8">
<!-- Gastautoren-Liste -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
<?php if ($guest_authors) : ?>
<?php foreach ($guest_authors as $author) : ?>
<a href="<?php echo esc_url(add_query_arg('guest_author', urlencode($author->guest_author), $guest_author_page_url)); ?>" class="guest-author-card bg-white p-6 rounded-lg shadow-md hover:shadow-lg transition">
<h3 class="text-xl font-semibold text-gray-800"><?php echo esc_html($author->guest_author); ?></h3>
<p class="text-gray-600"><?php echo esc_html($author->post_count); ?> <?php _e('Beiträge', 'wp-multi'); ?></p>
</a>
<?php endforeach; ?>
<?php else : ?>
<p class="col-span-2 text-center text-gray-600"><?php _e('Keine Gastautoren gefunden.', 'wp-multi'); ?></p>
<?php endif; ?>
</div>
</div>
<!-- Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<?php
return ob_get_clean();
}
add_shortcode('guest_authors', 'wp_multi_guest_author_shortcode');
// Shortcode für Gastautoren-Beiträge
function wp_multi_guest_author_posts_shortcode() {
ob_start();
$guest_author = isset($_GET['guest_author']) ? sanitize_text_field(wp_unslash($_GET['guest_author'])) : '';
?>
<div id="guest-author-posts" class="container mx-auto px-4 py-8">
<h2 class="text-2xl font-semibold text-gray-800 mb-4">
<?php
if ($guest_author) {
printf(__('Beiträge von %s', 'wp-multi'), esc_html($guest_author));
} else {
_e('Beiträge auswählen', 'wp-multi');
}
?>
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<?php
if ($guest_author) {
$args = array(
'post_type' => ['post', 'page', 'dein_custom_post_type'],
'post_status' => 'publish',
'meta_query' => array(
array(
'key' => '_guest_author',
'value' => $guest_author,
'compare' => '='
)
),
'tax_query' => array(
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => 'series',
'operator' => 'NOT IN'
)
),
'posts_per_page' => -1
);
$query = new WP_Query($args);
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
// Beitragsinhalt abrufen und kürzen
$content = get_the_content();
$content = wp_strip_all_tags($content); // HTML-Tags entfernen
$trimmed_content = wp_trim_words($content, 30, '...');
?>
<div class="post-card bg-white p-6 rounded-lg shadow-md">
<h3 class="text-lg font-medium text-gray-800">
<a href="<?php the_permalink(); ?>" class="hover:text-blue-600"><?php the_title(); ?></a>
</h3>
<p class="text-gray-600 line-clamp-3"><?php echo esc_html($trimmed_content); ?></p>
</div>
<?php
}
wp_reset_postdata();
} else {
?>
<p class="col-span-2 text-gray-600"><?php _e('Keine Beiträge gefunden.', 'wp-multi'); ?></p>
<?php
}
} else {
?>
<p class="col-span-2 text-gray-600"><?php _e('Wählen Sie einen Gastautor aus, um die Beiträge anzuzeigen.', 'wp-multi'); ?></p>
<?php
}
?>
</div>
</div>
<!-- Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<?php
return ob_get_clean();
}
add_shortcode('guest_author_posts', 'wp_multi_guest_author_posts_shortcode');
+273
View File
@@ -0,0 +1,273 @@
<?php
/**
* WP Multi Modul: Login-Design
*
* Ermöglicht die eigene Gestaltung der WordPress-Login-Seite:
* Logo, Hintergrund (Farbe/Bild), Formular-Farbe, Button- und Linkfarbe
* sowie eigenes CSS. Wird über den Loader in wp-multi.php eingebunden.
*/
if (!defined('ABSPATH')) { exit; }
/*
* Einstellungen registrieren
*/
function wp_multi_login_design_register() {
$group = 'wp_multi_login_design_group';
register_setting($group, 'wp_multi_login_form_text', ['sanitize_callback' => 'sanitize_hex_color', 'default' => '']);
register_setting($group, 'wp_multi_login_logo', ['sanitize_callback' => 'esc_url_raw', 'default' => '']);
register_setting($group, 'wp_multi_login_logo_home', ['sanitize_callback' => 'absint', 'default' => 1]);
register_setting($group, 'wp_multi_login_bg_color', ['sanitize_callback' => 'sanitize_hex_color', 'default' => '']);
register_setting($group, 'wp_multi_login_bg_image', ['sanitize_callback' => 'esc_url_raw', 'default' => '']);
register_setting($group, 'wp_multi_login_bg_size', ['sanitize_callback' => 'wp_multi_login_design_sanitize_bg_size', 'default' => 'cover']);
register_setting($group, 'wp_multi_login_form_bg', ['sanitize_callback' => 'sanitize_hex_color', 'default' => '']);
register_setting($group, 'wp_multi_login_button', ['sanitize_callback' => 'sanitize_hex_color', 'default' => '']);
register_setting($group, 'wp_multi_login_link', ['sanitize_callback' => 'sanitize_hex_color', 'default' => '']);
register_setting($group, 'wp_multi_login_custom_css', ['sanitize_callback' => 'wp_multi_login_design_sanitize_css', 'default' => '']);
}
add_action('admin_init', 'wp_multi_login_design_register');
// Eigenes CSS grob absichern (kein </style>-Ausbruch, keine Tags)
function wp_multi_login_design_sanitize_css($css) {
$css = (string) $css;
$css = wp_strip_all_tags($css);
return trim($css);
}
// Anzeige-Art des Hintergrundbilds (Whitelist)
function wp_multi_login_design_sanitize_bg_size($value) {
$allowed = array('cover', 'contain', 'stretch', 'tile', 'center');
return in_array($value, $allowed, true) ? $value : 'cover';
}
// Liefert die CSS-Regeln für die gewählte Hintergrund-Anzeigeart
function wp_multi_login_design_bg_rules($mode) {
switch ($mode) {
case 'contain':
return 'background-size:contain !important; background-repeat:no-repeat !important; background-position:center !important;';
case 'stretch':
return 'background-size:100% 100% !important; background-repeat:no-repeat !important; background-position:center !important;';
case 'tile':
return 'background-size:auto !important; background-repeat:repeat !important;';
case 'center':
return 'background-size:auto !important; background-repeat:no-repeat !important; background-position:center !important;';
case 'cover':
default:
return 'background-size:cover !important; background-repeat:no-repeat !important; background-position:center !important;';
}
}
/*
* Ausgabe auf der Login-Seite
*/
function wp_multi_login_design_styles() {
$form_text = get_option('wp_multi_login_form_text', '');
$logo = get_option('wp_multi_login_logo', '');
$bg_color = get_option('wp_multi_login_bg_color', '');
$bg_image = get_option('wp_multi_login_bg_image', '');
$form_bg = get_option('wp_multi_login_form_bg', '');
$button = get_option('wp_multi_login_button', '');
$link = get_option('wp_multi_login_link', '');
$css = get_option('wp_multi_login_custom_css', '');
// Nur ausgeben, wenn überhaupt etwas konfiguriert ist
if (!$logo && !$bg_color && !$bg_image && !$form_bg && !$button && !$link && !$css && !$form_text) {
return;
}
echo "<style id=\"wp-multi-login-design\">\n";
if ($logo) {
printf(
"#login h1 a, .login h1 a { background-image:url(%s) !important; background-size:contain !important; background-position:center !important; width:auto !important; height:90px !important; }\n",
esc_url($logo)
);
}
if ($bg_color) {
printf("body.login { background-color:%s !important; }\n", esc_attr($bg_color));
}
if ($bg_image) {
$bg_size = get_option('wp_multi_login_bg_size', 'cover');
printf(
"body.login { background-image:url(%s) !important; %s }\n",
esc_url($bg_image),
wp_multi_login_design_bg_rules($bg_size)
);
}
if ($form_bg) {
printf(".login form { background:%s !important; border-radius:8px !important; }\n", esc_attr($form_bg));
}
if ($button) {
printf(".login .button-primary { background:%1\$s !important; border-color:%1\$s !important; box-shadow:none !important; text-shadow:none !important; }\n", esc_attr($button));
}
if ($link) {
printf(".login #nav a, .login #backtoblog a, .login .wp-login-lost-password a { color:%s !important; }\n", esc_attr($link));
}
if ($form_text) {
printf(".login form label, .login form .forgetmenot label { color:%s !important; }\n", esc_attr($form_text));
}
if ($css) {
// bereits beim Speichern von Tags befreit
echo $css . "\n";
}
echo "</style>\n";
}
add_action('login_enqueue_scripts', 'wp_multi_login_design_styles');
// Logo-Link auf die eigene Startseite statt wordpress.org
function wp_multi_login_design_headerurl($url) {
return get_option('wp_multi_login_logo_home', 1) ? home_url('/') : $url;
}
add_filter('login_headerurl', 'wp_multi_login_design_headerurl');
// Logo-Titel = Seitenname
function wp_multi_login_design_headertext($text) {
return get_option('wp_multi_login_logo_home', 1) ? get_bloginfo('name') : $text;
}
add_filter('login_headertext', 'wp_multi_login_design_headertext');
/*
* Assets für die Einstellungsseite (Color-Picker + Medienauswahl)
*/
function wp_multi_login_design_admin_assets($hook) {
if ($hook !== 'wp-multi_page_wp_multi_login_design' && $hook !== 'toplevel_page_wp_multi_login_design') {
return;
}
wp_enqueue_style('wp-color-picker');
wp_enqueue_script('wp-color-picker');
wp_enqueue_media();
}
add_action('admin_enqueue_scripts', 'wp_multi_login_design_admin_assets');
/*
* Einstellungsseite
*/
function wp_multi_login_design_page() {
if (!current_user_can('manage_options')) {
wp_die(__('Zugriff verweigert.', 'wp-multi'));
}
wpmt_admin_page_open(
__('Login-Design', 'wp-multi'),
__('Die WordPress-Login-Seite nach deinen Wünschen gestalten', 'wp-multi')
);
$logo = get_option('wp_multi_login_logo', '');
$bg_image = get_option('wp_multi_login_bg_image', '');
wpmt_admin_notice('info', sprintf(
__('Vorschau: %s (in neuem Tab öffnen als eingeloggter Nutzer wirst du ggf. direkt weitergeleitet, dann kurz ausloggen).', 'wp-multi'),
'<a href="' . esc_url(wp_login_url()) . '" target="_blank">' . esc_html(wp_login_url()) . '</a>'
));
wpmt_admin_card_open(__('Gestaltung', 'wp-multi'));
?>
<form method="post" action="options.php">
<?php settings_fields('wp_multi_login_design_group'); ?>
<div class="wpm-field">
<label class="wpm-field__label"><?php esc_html_e('Logo', 'wp-multi'); ?>
<small class="wpm-field__hint"><?php esc_html_e('Ersetzt das WordPress-Logo über dem Formular.', 'wp-multi'); ?></small>
</label>
<div>
<input type="text" id="wp_multi_login_logo" name="wp_multi_login_logo" value="<?php echo esc_attr($logo); ?>" placeholder="https://…/logo.png" style="max-width:420px;">
<button type="button" class="wpm-btn wpm-media-btn" data-target="wp_multi_login_logo"><?php esc_html_e('Medien', 'wp-multi'); ?></button>
<div class="wpm-preview"><?php if ($logo) echo '<img src="' . esc_url($logo) . '" style="max-height:60px;margin-top:8px;">'; ?></div>
</div>
</div>
<div class="wpm-field">
<label class="wpm-field__label"><?php esc_html_e('Logo verlinkt zur Startseite', 'wp-multi'); ?></label>
<div><label><input type="checkbox" name="wp_multi_login_logo_home" value="1" <?php checked(1, get_option('wp_multi_login_logo_home', 1)); ?>> <?php esc_html_e('Ja (statt zu wordpress.org)', 'wp-multi'); ?></label></div>
</div>
<div class="wpm-field">
<label class="wpm-field__label"><?php esc_html_e('Seiten-Hintergrundfarbe', 'wp-multi'); ?></label>
<div><input type="text" class="wpm-color" name="wp_multi_login_bg_color" value="<?php echo esc_attr(get_option('wp_multi_login_bg_color', '')); ?>" data-default-color=""></div>
</div>
<div class="wpm-field">
<label class="wpm-field__label"><?php esc_html_e('Hintergrundbild', 'wp-multi'); ?>
<small class="wpm-field__hint"><?php esc_html_e('Optional. Überlagert die Hintergrundfarbe.', 'wp-multi'); ?></small>
</label>
<div>
<input type="text" id="wp_multi_login_bg_image" name="wp_multi_login_bg_image" value="<?php echo esc_attr($bg_image); ?>" placeholder="https://…/bg.jpg" style="max-width:420px;">
<button type="button" class="wpm-btn wpm-media-btn" data-target="wp_multi_login_bg_image"><?php esc_html_e('Medien', 'wp-multi'); ?></button>
</div>
</div>
<div class="wpm-field">
<label class="wpm-field__label"><?php esc_html_e('Hintergrundbild-Anzeige', 'wp-multi'); ?>
<small class="wpm-field__hint"><?php esc_html_e('Wie das Bild die Login-Seite füllt.', 'wp-multi'); ?></small>
</label>
<div>
<?php $bg_size = get_option('wp_multi_login_bg_size', 'cover'); ?>
<select name="wp_multi_login_bg_size" style="max-width:280px;">
<option value="cover" <?php selected($bg_size, 'cover'); ?>><?php esc_html_e('Ausfüllen (beschneidet ggf.)', 'wp-multi'); ?></option>
<option value="contain" <?php selected($bg_size, 'contain'); ?>><?php esc_html_e('Anpassen (ganz sichtbar)', 'wp-multi'); ?></option>
<option value="stretch" <?php selected($bg_size, 'stretch'); ?>><?php esc_html_e('Strecken (exakt füllen)', 'wp-multi'); ?></option>
<option value="tile" <?php selected($bg_size, 'tile'); ?>><?php esc_html_e('Kacheln (wiederholen)', 'wp-multi'); ?></option>
<option value="center" <?php selected($bg_size, 'center'); ?>><?php esc_html_e('Zentriert (Originalgröße)', 'wp-multi'); ?></option>
</select>
</div>
</div>
<div class="wpm-field">
<label class="wpm-field__label"><?php esc_html_e('Formular-Hintergrund', 'wp-multi'); ?></label>
<div><input type="text" class="wpm-color" name="wp_multi_login_form_bg" value="<?php echo esc_attr(get_option('wp_multi_login_form_bg', '')); ?>" data-default-color=""></div>
</div>
<div class="wpm-field">
<label class="wpm-field__label"><?php esc_html_e('Formular-Textfarbe', 'wp-multi'); ?>
<small class="wpm-field__hint"><?php esc_html_e('Farbe der Beschriftungen im Formular (z. B. hell auf dunklem Formular-Hintergrund).', 'wp-multi'); ?></small>
</label>
<div><input type="text" class="wpm-color" name="wp_multi_login_form_text" value="<?php echo esc_attr(get_option('wp_multi_login_form_text', '')); ?>" data-default-color=""></div>
</div>
<div class="wpm-field">
<label class="wpm-field__label"><?php esc_html_e('Button-Farbe', 'wp-multi'); ?></label>
<div><input type="text" class="wpm-color" name="wp_multi_login_button" value="<?php echo esc_attr(get_option('wp_multi_login_button', '')); ?>" data-default-color=""></div>
</div>
<div class="wpm-field">
<label class="wpm-field__label"><?php esc_html_e('Link-Farbe', 'wp-multi'); ?></label>
<div><input type="text" class="wpm-color" name="wp_multi_login_link" value="<?php echo esc_attr(get_option('wp_multi_login_link', '')); ?>" data-default-color=""></div>
</div>
<div class="wpm-field">
<label class="wpm-field__label"><?php esc_html_e('Eigenes CSS (Profi)', 'wp-multi'); ?>
<small class="wpm-field__hint"><?php esc_html_e('Wird zusätzlich auf der Login-Seite ausgegeben.', 'wp-multi'); ?></small>
</label>
<div><textarea name="wp_multi_login_custom_css" rows="6" style="width:100%;max-width:560px;font-family:monospace;"><?php echo esc_textarea(get_option('wp_multi_login_custom_css', '')); ?></textarea></div>
</div>
<?php submit_button(__('Speichern', 'wp-multi')); ?>
</form>
<script>
jQuery(function ($) {
// Farbwähler
if ($.fn.wpColorPicker) { $('.wpm-color').wpColorPicker(); }
// Medienauswahl
$('.wpm-media-btn').on('click', function (e) {
e.preventDefault();
var targetId = $(this).data('target');
var frame = wp.media({ title: '<?php echo esc_js(__('Bild auswählen', 'wp-multi')); ?>', multiple: false });
frame.on('select', function () {
var att = frame.state().get('selection').first().toJSON();
$('#' + targetId).val(att.url);
if (targetId === 'wp_multi_login_logo') {
$('.wpm-preview').html('<img src="' + att.url + '" style="max-height:60px;margin-top:8px;">');
}
});
frame.open();
});
});
</script>
<?php
wpmt_admin_card_close();
wpmt_admin_page_close();
}
+212
View File
@@ -0,0 +1,212 @@
<?php
/**
* WP Multi Modul: Custom Login-URL
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Custom Login-URL — Admin-Panel-Adresse ändern (versteckt wp-admin / wp-login.php)
*
* Ersetzt die Standard-Login-Adresse durch einen eigenen Slug, z. B. /team/.
* Standardmäßig DEAKTIVIERT (leerer Slug), damit ohne bewusste Aktivierung
* nichts an der Erreichbarkeit des Backends geändert wird.
*/
// Liefert den konfigurierten Login-Slug (leer = Feature aus)
function wp_multi_login_slug() {
$slug = get_option('wp_multi_login_slug', '');
return is_string($slug) ? trim($slug, '/') : '';
}
// Feature ist nur aktiv, wenn ein Slug gesetzt ist UND Permalinks aktiv sind
function wp_multi_login_active() {
return wp_multi_login_slug() !== '' && get_option('permalink_structure') && !is_multisite();
}
// Vollständige neue Login-URL
function wp_multi_login_new_url($scheme = null) {
return user_trailingslashit(home_url('/', $scheme) . wp_multi_login_slug());
}
// Pfad-Anteil (ohne Domain) der Home-URL, z. B. "" oder "/blog"
function wp_multi_login_home_path() {
return untrailingslashit((string) parse_url(home_url(), PHP_URL_PATH));
}
// Sendet eine echte 404-Antwort und beendet die Ausführung (verstecktes Login)
function wp_multi_login_die_404() {
status_header(404);
nocache_headers();
if (function_exists('wp_die')) {
// Nutze die Theme-404 wenn möglich, sonst schlichte Meldung
wp_die(__('Seite nicht gefunden.', 'wp-multi'), '404', array('response' => 404));
}
exit;
}
// Ersetzt "wp-login.php" in generierten URLs durch den eigenen Slug
function wp_multi_login_filter_url($url, $scheme = null) {
if (strpos($url, 'wp-login.php') === false) {
return $url;
}
if (is_ssl()) {
$scheme = 'https';
}
$query = parse_url($url, PHP_URL_QUERY);
$args = array();
if ($query) {
parse_str($query, $args);
}
$new = wp_multi_login_new_url($scheme);
if (!empty($args)) {
// add_query_arg kodiert selbst; parse_str liefert bereits dekodierte Werte.
$new = add_query_arg($args, $new);
}
return $new;
}
function wp_multi_login_filter_site_url($url, $path, $scheme, $blog_id = null) {
return wp_multi_login_filter_url($url, $scheme);
}
function wp_multi_login_filter_wp_redirect($location) {
return wp_multi_login_filter_url($location);
}
// Registriert die Filter und den Request-Handler, sobald WordPress geladen ist
function wp_multi_login_init() {
if (!wp_multi_login_active()) {
return;
}
add_filter('site_url', 'wp_multi_login_filter_site_url', 10, 4);
add_filter('network_site_url', 'wp_multi_login_filter_site_url', 10, 4);
add_filter('wp_redirect', 'wp_multi_login_filter_wp_redirect', 10, 1);
add_filter('login_url', 'wp_multi_login_filter_wp_redirect', 10, 1);
add_filter('logout_url', 'wp_multi_login_filter_wp_redirect', 10, 1);
add_filter('lostpassword_url', 'wp_multi_login_filter_wp_redirect', 10, 1);
add_filter('register_url', 'wp_multi_login_filter_wp_redirect', 10, 1);
}
add_action('plugins_loaded', 'wp_multi_login_init', 1);
// Fängt die eingehende Anfrage ab: geheimer Slug lädt das Login, wp-login.php/wp-admin werden versteckt
function wp_multi_login_handle_request() {
if (!wp_multi_login_active()) {
return;
}
// Systemendpunkte niemals blockieren
if ((defined('DOING_AJAX') && DOING_AJAX) || (defined('DOING_CRON') && DOING_CRON) || (defined('REST_REQUEST') && REST_REQUEST)) {
return;
}
$uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
$path = untrailingslashit((string) parse_url($uri, PHP_URL_PATH));
$home_path = wp_multi_login_home_path();
$login_path = $home_path . '/' . wp_multi_login_slug();
// 1) Aufruf des geheimen Slugs → echtes wp-login.php ausliefern
if ($path === $login_path) {
$GLOBALS['pagenow'] = 'wp-login.php';
require_once ABSPATH . 'wp-login.php';
exit;
}
// 2) Direkter Aufruf von wp-login.php (nicht über den Slug) → verstecken
if (strpos($uri, 'wp-login.php') !== false) {
wp_multi_login_die_404();
}
// 3) Der gesamte /wp-admin-Bereich für nicht eingeloggte Besucher → verstecken,
// statt zum versteckten Login weiterzuleiten. admin-ajax.php und admin-post.php
// bleiben ausdrücklich erreichbar (auch für Gäste / nopriv-Aktionen).
if (!is_user_logged_in()) {
$admin_path = $home_path . '/wp-admin';
$in_admin = ($path === $admin_path || strpos($path, $admin_path . '/') === 0);
$is_endpoint = (strpos($uri, 'admin-ajax.php') !== false || strpos($uri, 'admin-post.php') !== false);
if ($in_admin && !$is_endpoint) {
wp_multi_login_die_404();
}
}
}
add_action('wp_loaded', 'wp_multi_login_handle_request');
// Einstellung registrieren (mit Sanitisierung gegen reservierte Slugs)
function wp_multi_login_register_setting() {
register_setting('wp_multi_login_url_group', 'wp_multi_login_slug', array(
'type' => 'string',
'sanitize_callback' => 'wp_multi_login_sanitize_slug',
'default' => '',
));
}
add_action('admin_init', 'wp_multi_login_register_setting');
function wp_multi_login_sanitize_slug($value) {
$value = sanitize_title(trim((string) $value, '/'));
$reserved = array('wp-admin', 'wp-login', 'wp-content', 'wp-includes', 'admin-ajax', 'admin-post', 'wp-json', 'index');
if (in_array($value, $reserved, true)) {
add_settings_error('wp_multi_login_slug', 'reserved', __('Dieser Slug ist reserviert und kann nicht verwendet werden.', 'wp-multi'));
return '';
}
return $value;
}
// Admin-Seite "Login-URL"
function wp_multi_login_url_page() {
if (!current_user_can('manage_options')) {
wp_die(__('Zugriff verweigert.', 'wp-multi'));
}
$slug = wp_multi_login_slug();
$pretty = (bool) get_option('permalink_structure');
wpmt_admin_page_open(
__('Login-URL', 'wp-multi'),
__('Eigene Adresse für das Login / Admin-Panel festlegen', 'wp-multi')
);
if (is_multisite()) {
wpmt_admin_notice('error', __('Dieses Feature ist in einem Multisite-Netzwerk nicht verfügbar.', 'wp-multi'));
wpmt_admin_page_close();
return;
}
if (!$pretty) {
wpmt_admin_notice('warning', __('Für dieses Feature müssen „hübsche Permalinks" aktiviert sein (Einstellungen → Permalinks, nicht „Einfach"). Solange das nicht der Fall ist, bleibt die Login-URL unverändert.', 'wp-multi'));
}
wpmt_admin_notice('warning', __('Achtung: Merke dir die neue Adresse gut! Wenn du sie vergisst, kommst du nicht mehr ins Backend und musst das Feld per Datenbank oder FTP zurücksetzen. Leeres Feld = Standard-Login (/wp-login.php) bleibt aktiv.', 'wp-multi'));
if ($slug && $pretty) {
wpmt_admin_notice('success', sprintf(
__('Aktive Login-Adresse: %s', 'wp-multi'),
'<a href="' . esc_url(wp_multi_login_new_url()) . '"><strong>' . esc_html(wp_multi_login_new_url()) . '</strong></a>'
));
}
wpmt_admin_card_open(__('Einstellung', 'wp-multi'));
?>
<form method="post" action="options.php">
<?php settings_fields('wp_multi_login_url_group'); ?>
<div class="wpm-field">
<label class="wpm-field__label" for="wp_multi_login_slug"><?php esc_html_e('Login-Slug', 'wp-multi'); ?>
<small class="wpm-field__hint"><?php esc_html_e('Nur Kleinbuchstaben, Zahlen und Bindestriche. Leer lassen = deaktiviert.', 'wp-multi'); ?></small>
</label>
<div>
<span style="color:var(--wpm-text-muted);"><?php echo esc_html(trailingslashit(home_url('/'))); ?></span>
<input type="text" id="wp_multi_login_slug" name="wp_multi_login_slug" value="<?php echo esc_attr($slug); ?>" placeholder="team" style="max-width:220px; display:inline-block;">
</div>
</div>
<?php submit_button(__('Speichern', 'wp-multi')); ?>
</form>
<?php
wpmt_admin_card_close();
wpmt_admin_page_close();
}
+232
View File
@@ -0,0 +1,232 @@
<?php
/**
* WP Multi Modul: Pinnwand
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Admin - Pinnwand
*/
// Funktion zum Erstellen der Datenbanktabelle für Nachrichten
function wp_multi_create_message_board_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'message_board'; // Tabelle für Nachrichten
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
message text NOT NULL,
user_id bigint(20) NOT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
PRIMARY KEY (id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
register_activation_hook(WP_MULTI_FILE, 'wp_multi_create_message_board_table');
// Funktion zum Anzeigen der Nachrichten im Adminbereich
function wp_multi_add_message_board() {
if (!current_user_can('administrator')) {
return;
}
global $wpdb;
$table_name = $wpdb->prefix . 'message_board';
$created = false;
// Nachricht erstellen (VOR der Ausgabe, damit sie sofort erscheint)
if (isset($_POST['submit_message']) && !empty($_POST['new_message'])) {
if (!isset($_POST['wp_multi_pinwand_nonce_field']) || !wp_verify_nonce(wp_unslash($_POST['wp_multi_pinwand_nonce_field']), 'wp_multi_pinwand_create_message')) {
wp_die(__('Ungültige oder abgelaufene Anfrage.', 'wp-multi'));
}
$wpdb->insert(
$table_name,
array(
'message' => sanitize_textarea_field(wp_unslash($_POST['new_message'])),
'user_id' => get_current_user_id(),
)
);
$created = true;
}
$messages = $wpdb->get_results("SELECT * FROM $table_name ORDER BY created_at DESC");
wpmt_admin_page_open(
__('Pinwand', 'wp-multi'),
__('Interne Nachrichten für das Admin-Team', 'wp-multi')
);
if ($created) {
wpmt_admin_notice('success', __('Nachricht wurde erfolgreich erstellt.', 'wp-multi'));
}
wpmt_admin_card_open(__('Neue Nachricht erstellen', 'wp-multi'));
?>
<form method="post">
<?php wp_nonce_field('wp_multi_pinwand_create_message', 'wp_multi_pinwand_nonce_field'); ?>
<textarea name="new_message" rows="4" required style="width:100%;"></textarea>
<p><input type="submit" name="submit_message" value="<?php esc_attr_e('Nachricht erstellen', 'wp-multi'); ?>" class="wpm-btn wpm-btn--primary"></p>
</form>
<?php
wpmt_admin_card_close();
wpmt_admin_card_open(__('Nachrichten', 'wp-multi'));
if ($messages) {
echo '<div class="wpm-modules">';
foreach ($messages as $message) {
$user_info = get_userdata($message->user_id);
$author = $user_info ? $user_info->user_login : __('Unbekannt', 'wp-multi');
printf(
'<div class="wpm-module" style="cursor:pointer;" onclick="openMessagePopup(%d)"><span class="dashicons dashicons-admin-comments"></span><span><span class="wpm-module__title">%s</span><p class="wpm-module__desc">%s</p><p class="wpm-module__desc">%s</p></span></div>',
(int) $message->id,
esc_html($author),
esc_html(date('d-m-Y H:i', strtotime($message->created_at))),
esc_html(wp_trim_words($message->message, 20))
);
}
echo '</div>';
} else {
wpmt_admin_notice('info', __('Keine Nachrichten vorhanden.', 'wp-multi'));
}
wpmt_admin_card_close();
wpmt_admin_page_close();
?>
<div id="messagePopup" style="display:none; position:fixed; top:20%; left:50%; transform:translateX(-50%); background:#fff; padding:24px; border-radius:12px; box-shadow:0 4px 30px rgba(0,0,0,.2); z-index:99999; max-width:600px; width:90%;">
<div id="messageContent"></div>
<div style="display:flex; gap:10px; margin-top:20px;">
<button onclick="closeMessagePopup()" class="wpm-btn wpm-btn--primary"><?php esc_html_e('Schließen', 'wp-multi'); ?></button>
<button id="deleteMessageBtn" class="wpm-btn wpm-btn--danger" onclick="deleteMessage()"><?php esc_html_e('Löschen', 'wp-multi'); ?></button>
</div>
</div>
<script>
var wpMultiPinwandNonce = '<?php echo esc_js(wp_create_nonce('wp_multi_pinwand_nonce')); ?>';
function openMessagePopup(messageId) {
var data = { 'action': 'wp_multi_get_message', 'message_id': messageId, 'nonce': wpMultiPinwandNonce };
jQuery.post(ajaxurl, data, function(response) {
var messageData = JSON.parse(response);
document.getElementById('messageContent').innerHTML = '<h3>' + messageData.created_at + ' (' + messageData.user + ')</h3><p>' + messageData.message + '</p>';
document.getElementById('messagePopup').style.display = 'block';
document.getElementById('deleteMessageBtn').setAttribute('data-message-id', messageId);
});
}
function closeMessagePopup() {
document.getElementById('messagePopup').style.display = 'none';
}
function deleteMessage() {
var messageId = document.getElementById('deleteMessageBtn').getAttribute('data-message-id');
var data = { 'action': 'wp_multi_delete_message', 'message_id': messageId, 'nonce': wpMultiPinwandNonce };
jQuery.post(ajaxurl, data, function(response) {
if (response == 'success') { closeMessagePopup(); location.reload(); }
});
}
</script>
<?php
}
// Der Pinwand-Menüpunkt wird zentral in wp_multi_register_admin_menus() registriert.
// Funktion zum Abrufen der vollständigen Nachricht
function wp_multi_get_message() {
check_ajax_referer('wp_multi_pinwand_nonce', 'nonce');
if (!current_user_can('administrator')) {
wp_die();
}
if (isset($_POST['message_id'])) {
global $wpdb;
$table_name = $wpdb->prefix . 'message_board';
$message_id = intval($_POST['message_id']);
$message = $wpdb->get_row($wpdb->prepare("SELECT * FROM $table_name WHERE id = %d", $message_id));
if ($message) {
// Datum im gewünschten Format (DD-MM-JJJJ HH:MM:SS)
$formatted_date = date('d-m-Y H:i:s', strtotime($message->created_at));
echo json_encode([
'created_at' => $formatted_date,
'message' => nl2br(esc_textarea($message->message)),
'user' => get_userdata($message->user_id)->user_login
]);
}
}
wp_die();
}
add_action('wp_ajax_wp_multi_get_message', 'wp_multi_get_message');
// Funktion zum Löschen einer Nachricht
function wp_multi_delete_message() {
check_ajax_referer('wp_multi_pinwand_nonce', 'nonce');
if (!current_user_can('administrator')) {
wp_die();
}
if (isset($_POST['message_id'])) {
global $wpdb;
$table_name = $wpdb->prefix . 'message_board';
$message_id = intval($_POST['message_id']);
$wpdb->delete($table_name, array('id' => $message_id), array('%d'));
echo 'success';
}
wp_die();
}
add_action('wp_ajax_wp_multi_delete_message', 'wp_multi_delete_message');
// Funktion zum Deaktivieren der Pinwand bei der Deinstallation
function wp_multi_delete_message_board_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'message_board';
$wpdb->query("DROP TABLE IF EXISTS $table_name");
}
register_deactivation_hook(WP_MULTI_FILE, 'wp_multi_delete_message_board_table');
// Funktion, um das Dashboard-Widget zu registrieren
function wp_multi_dashboard_widget() {
wp_add_dashboard_widget(
'wp_multi_pinwand_widget', // Widget-ID
'Pinwand Übersicht', // Widget-Titel
'wp_multi_dashboard_widget_content' // Callback-Funktion
);
}
add_action('wp_dashboard_setup', 'wp_multi_dashboard_widget');
// Callback-Funktion, die den Inhalt des Widgets erstellt
function wp_multi_dashboard_widget_content() {
global $wpdb;
$table_name = $wpdb->prefix . 'message_board';
$messages = $wpdb->get_results("SELECT * FROM $table_name ORDER BY created_at DESC LIMIT 5"); // Zeige die neuesten 5 Nachrichten an
if ($messages) {
echo '<ul>';
foreach ($messages as $message) {
$user_info = get_userdata($message->user_id);
echo '<li>';
echo '<strong>' . esc_html($user_info->user_login) . ' (' . date('d-m-Y H:i:s', strtotime($message->created_at)) . ')</strong>: ';
echo wp_trim_words($message->message, 10) . '...'; // Zeigt nur eine Vorschau der Nachricht
echo '</li>';
}
echo '</ul>';
} else {
echo '<p>Keine neuen Nachrichten.</p>';
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
/**
* WP Multi Modul: Notify Dashboard-Zähler
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Admin-Dashboard Nachrichten sende Zähler
*/
// Admin Dashboard Widget für Telegram und Discord Nachrichten Zähler
function wp_multi_add_dashboard_widgets() {
wp_add_dashboard_widget(
'wp_multi_dashboard_widget',
'Telegram & Discord Nachrichten Zähler',
'wp_multi_display_dashboard_widget'
);
}
add_action('wp_dashboard_setup', 'wp_multi_add_dashboard_widgets');
// Callback-Funktion, die den Inhalt des Widgets anzeigt
function wp_multi_display_dashboard_widget() {
// Telegram-Nachrichtenzähler
$telegram_message_count = get_option('wp_multi_telegram_message_count', 0);
// Discord-Nachrichtenzähler
$discord_message_count = get_option('wp_multi_discord_message_count', 0);
// Ausgabe der Zähler
echo '<p><strong>Telegram Nachrichten gesendet:</strong> ' . esc_html($telegram_message_count) . '</p>';
echo '<p><strong>Discord Nachrichten gesendet:</strong> ' . esc_html($discord_message_count) . '</p>';
}
+182
View File
@@ -0,0 +1,182 @@
<?php
/**
* WP Multi Modul: Discord-Benachrichtigung
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Discord Notify
*/
// Einstellungsseite für Discord Webhook
function wp_multi_settings_page() {
wpmt_admin_page_open(
__('DC-Notify', 'wp-multi'),
__('Discord-Benachrichtigungen bei neuen Beiträgen', 'wp-multi')
);
wpmt_admin_card_open();
?>
<form method="post" action="options.php">
<?php
settings_fields('wp_multi_discord_options_group');
do_settings_sections('wp-multi');
?>
<table class="form-table">
<tr>
<th scope="row">Discord Webhook URL</th>
<td>
<input type="text" name="wp_multi_discord_webhook" value="<?php echo esc_attr(get_option('wp_multi_discord_webhook')); ?>" size="50">
<p class="description">Geben Sie die Webhook-URL für Discord ein, um Benachrichtigungen zu senden.</p>
</td>
</tr>
<tr>
<th scope="row">Bot Name</th>
<td>
<input type="text" name="wp_multi_discord_bot_name" value="<?php echo esc_attr(get_option('wp_multi_discord_bot_name', 'WP Multi Bot')); ?>" size="50">
<p class="description">Geben Sie den Namen des Bots ein, der in Discord angezeigt werden soll.</p>
</td>
</tr>
<tr>
<th scope="row">Discord Nachricht (Vorlage)</th>
<td>
<textarea name="wp_multi_discord_message_template" rows="4" cols="50"><?php echo esc_textarea(get_option('wp_multi_discord_message_template', 'Beitrag "{post_title}" von {post_author} | Link: {post_url}')); ?></textarea>
<p class="description">Passen Sie die Nachricht an, die an Discord gesendet wird. Verwenden Sie Platzhalter wie {post_title}, {post_author}, und {post_url}.</p>
</td>
</tr>
<tr>
<th scope="row">Discord Benutzerrollen ID (für Ping)</th>
<td>
<input type="text" name="wp_multi_discord_role_id" value="<?php echo esc_attr(get_option('wp_multi_discord_role_id')); ?>" size="50">
<p class="description">Geben Sie die ID der Discord-Benutzerrolle ein, die gepingt werden soll (z. B. @everyone).</p>
</td>
</tr>
<tr>
<th scope="row">Discord Avatar-URL</th>
<td>
<input type="text" name="wp_multi_discord_avatar_url" value="<?php echo esc_attr(get_option('wp_multi_discord_avatar_url')); ?>" size="50">
<p class="description">Geben Sie die URL des Avatar-Bildes ein, das in den Discord-Nachrichten angezeigt werden soll.</p>
</td>
</tr>
<tr>
<th scope="row">Footer Text (Custom Text 2)</th>
<td>
<input type="text" name="wp_multi_discord_footer_text" value="<?php echo esc_attr(get_option('wp_multi_discord_footer_text')); ?>" size="50">
<p class="description">Geben Sie den benutzerdefinierten Text ein, der am Ende der Nachricht angezeigt wird (z. B. "Powered by WP Multi"). Sie können auch Platzhalter wie {post_title}, {post_author} und {post_url} verwenden.</p>
</td>
</tr>
</table>
<?php submit_button(); ?>
</form>
<?php
wpmt_admin_card_close();
wpmt_admin_page_close();
}
// Funktion, um die Einstellungen zu registrieren
function wp_multi_register_settings() {
register_setting('wp_multi_discord_options_group', 'wp_multi_discord_webhook');
register_setting('wp_multi_discord_options_group', 'wp_multi_discord_bot_name');
register_setting('wp_multi_discord_options_group', 'wp_multi_discord_message_template');
register_setting('wp_multi_discord_options_group', 'wp_multi_discord_role_id');
register_setting('wp_multi_discord_options_group', 'wp_multi_discord_avatar_url');
register_setting('wp_multi_discord_options_group', 'wp_multi_discord_footer_text');
}
add_action('admin_init', 'wp_multi_register_settings');
// Funktion, um die Discord-Benachrichtigung zu senden
function wp_multi_send_discord_notification($ID, $post) {
$send_notification = get_post_meta($ID, '_wp_multi_checkbox', true);
if ($send_notification !== '1') {
return;
}
$webhook_url = get_option('wp_multi_discord_webhook');
if (empty($webhook_url)) {
return;
}
$bot_name = get_option('wp_multi_discord_bot_name', 'WP Multi Bot');
$avatar_url = get_option('wp_multi_discord_avatar_url');
$post_title = esc_html(get_the_title($ID));
$post_url = esc_url(get_permalink($ID));
$post_author = esc_html(get_the_author_meta('display_name', $post->post_author));
$content = get_post_field('post_content', $ID);
$excerpt = wp_trim_words($content, 60, '...');
$role_id = get_option('wp_multi_discord_role_id');
$mention_role = (!empty($role_id) && is_numeric($role_id)) ? "<@&" . esc_attr($role_id) . ">" : '';
$footer_text = get_option('wp_multi_discord_footer_text');
$footer = !empty($footer_text) ? str_replace(
['{post_title}', '{post_author}', '{post_url}'],
[$post_title, $post_author, $post_url],
$footer_text
) : '';
$message_template = get_option('wp_multi_discord_message_template', 'Beitrag "{post_title}" von {post_author} | Link: {post_url}');
$message = str_replace(
['{post_title}', '{post_author}', '{post_url}'],
[$post_title, $post_author, $post_url],
$message_template
);
$message .= "\n\n" . $excerpt . "\n\n" . $footer;
$data = json_encode([
'username' => $bot_name,
'avatar_url' => $avatar_url,
'content' => $mention_role . "\n" . $message
]);
$response = wp_remote_post($webhook_url, [
'method' => 'POST',
'body' => $data,
'headers' => ['Content-Type' => 'application/json']
]);
if (!is_wp_error($response)) {
wp_multi_increment_discord_message_count();
} else {
error_log('Discord Webhook Fehler: ' . $response->get_error_message());
}
}
add_action('publish_post', 'wp_multi_send_discord_notification', 10, 2);
// Funktion zum Erhöhen des Discord-Nachrichtenzählers
function wp_multi_increment_discord_message_count() {
$current_count = get_option('wp_multi_discord_message_count', 0);
update_option('wp_multi_discord_message_count', $current_count + 1);
}
// Funktion, um die Checkbox in der Sidebar des Beitrag Editors hinzuzufügen
function wp_multi_add_checkbox_to_sidebar() {
global $post;
wp_nonce_field('wp_multi_checkbox_nonce', 'wp_multi_checkbox_nonce_field');
$value = get_post_meta($post->ID, '_wp_multi_checkbox', true);
?>
<div class="misc-pub-section">
<label for="wp_multi_checkbox">
<input type="checkbox" name="wp_multi_checkbox" id="wp_multi_checkbox" value="1" <?php checked($value, '1'); ?>>
Discord Benachrichtigung senden
</label>
</div>
<?php
}
add_action('post_submitbox_misc_actions', 'wp_multi_add_checkbox_to_sidebar');
// Funktion, um den Wert der Checkbox zu speichern
function wp_multi_save_checkbox_value($post_id) {
if (!isset($_POST['wp_multi_checkbox_nonce_field']) || !wp_verify_nonce($_POST['wp_multi_checkbox_nonce_field'], 'wp_multi_checkbox_nonce')) {
return;
}
if (isset($_POST['wp_multi_checkbox']) && $_POST['wp_multi_checkbox'] === '1') {
update_post_meta($post_id, '_wp_multi_checkbox', '1');
} else {
delete_post_meta($post_id, '_wp_multi_checkbox');
}
}
add_action('save_post', 'wp_multi_save_checkbox_value');
+209
View File
@@ -0,0 +1,209 @@
<?php
/**
* WP Multi Modul: Telegram-Benachrichtigung
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Telegram Notify
*/
// Admin-Seiten Callback
function tg_notify_page() {
wpmt_admin_page_open(
__('TG-Notify', 'wp-stat-notice'),
__('Telegram-Benachrichtigungen bei neuen Beiträgen', 'wp-stat-notice')
);
wpmt_admin_card_open();
?>
<form method="post" action="options.php">
<?php
settings_fields('tg_notify_options_group');
do_settings_sections('tg-notify');
submit_button('Speichern', 'primary', 'submit', true);
?>
</form>
<?php
wpmt_admin_card_close();
wpmt_admin_page_close();
}
// Einstellungen registrieren
function tg_notify_register_settings() {
register_setting('tg_notify_options_group', 'tg_notify_bot_name');
register_setting('tg_notify_options_group', 'tg_notify_bot_token');
register_setting('tg_notify_options_group', 'tg_notify_chat_ids');
register_setting('tg_notify_options_group', 'tg_notify_custom_message');
add_settings_section('tg_notify_main_section', __('Telegram Einstellungen', 'wp-stat-notice'), null, 'tg-notify');
add_settings_field('tg_notify_bot_name', __('Bot Name', 'wp-stat-notice'), 'tg_notify_bot_name_callback', 'tg-notify', 'tg_notify_main_section');
add_settings_field('tg_notify_bot_token', __('Bot Token', 'wp-stat-notice'), 'tg_notify_bot_token_callback', 'tg-notify', 'tg_notify_main_section');
add_settings_field('tg_notify_chat_ids', __('Kanal IDs', 'wp-stat-notice'), 'tg_notify_chat_ids_callback', 'tg-notify', 'tg_notify_main_section');
add_settings_field('tg_notify_custom_message', __('Custom Nachricht', 'wp-stat-notice'), 'tg_notify_custom_message_callback', 'tg-notify', 'tg_notify_main_section');
}
add_action('admin_init', 'tg_notify_register_settings');
// Callback-Funktionen
function tg_notify_bot_name_callback() {
$value = get_option('tg_notify_bot_name', '');
echo '<input type="text" name="tg_notify_bot_name" value="' . esc_attr($value) . '" class="regular-text">';
}
function tg_notify_bot_token_callback() {
$value = get_option('tg_notify_bot_token', '');
echo '<input type="text" name="tg_notify_bot_token" value="' . esc_attr($value) . '" class="regular-text">';
}
function tg_notify_chat_ids_callback() {
$value = get_option('tg_notify_chat_ids', '');
echo '<textarea name="tg_notify_chat_ids" class="large-text code" rows="3">' . esc_textarea($value) . '</textarea>';
echo '<p>Kanal ohne Thema: -1001234567890</p>';
echo '<p>Kanal mit Thema: -1001234567890_123</p>';
}
function tg_notify_custom_message_callback() {
$value = get_option('tg_notify_custom_message', '');
echo '<textarea name="tg_notify_custom_message" class="large-text code" rows="5">' . esc_textarea($value) . '</textarea>';
echo '<p>Verfügbare Variablen: {title}, {author}, {link}</p>';
}
// Checkbox beim Beitrag hinzufügen
function tg_notify_add_meta_box() {
add_meta_box(
'tg_notify_meta_box',
__('Telegram Benachrichtigung', 'wp-stat-notice'),
'tg_notify_meta_box_callback',
'post',
'side',
'high'
);
}
add_action('add_meta_boxes', 'tg_notify_add_meta_box');
function tg_notify_meta_box_callback($post) {
$value = get_post_meta($post->ID, '_tg_notify_send', true);
// Standardmäßig auf 1 setzen, wenn der Beitrag neu ist
if (empty($value) && get_post_status($post->ID) !== 'publish') {
$value = 1;
}
wp_nonce_field('tg_notify_meta_box', 'tg_notify_meta_box_nonce');
echo '<label><input type="checkbox" name="tg_notify_send" value="1" ' . checked($value, 1, false) . '> ' . __('Benachrichtigung senden', 'wp-stat-notice') . '</label>';
}
function tg_notify_save_post($post_id) {
// Sicherheitsprüfungen
if (!isset($_POST['tg_notify_meta_box_nonce']) || !wp_verify_nonce($_POST['tg_notify_meta_box_nonce'], 'tg_notify_meta_box')) return;
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) return;
if (!current_user_can('edit_post', $post_id)) return;
// Prüfen, ob der Beitrag wirklich veröffentlicht wurde
if (get_post_status($post_id) !== 'publish') return;
// Prüfen, ob die Nachricht bereits gesendet wurde
$already_sent = get_post_meta($post_id, '_tg_notify_sent', true);
if ($already_sent) return;
$send_notification = isset($_POST['tg_notify_send']) ? 1 : 0;
update_post_meta($post_id, '_tg_notify_send', $send_notification);
if ($send_notification) {
tg_notify_send_telegram_message($post_id);
update_post_meta($post_id, '_tg_notify_sent', 1);
}
}
add_action('save_post', 'tg_notify_save_post');
function tg_notify_send_telegram_message($post_id) {
$bot_token = get_option('tg_notify_bot_token');
$chat_ids = explode("\n", get_option('tg_notify_chat_ids'));
$message_template = get_option('tg_notify_custom_message');
$post = get_post($post_id);
// Überprüfen, ob der Beitrag von einem Gast-Author stammt
$author_name = get_the_author_meta('display_name', $post->post_author);
if (empty($author_name)) {
// Falls kein Name vorhanden ist (Gast-Author), den Gast-Namen verwenden oder einen Platzhalter setzen
$author_name = 'Gast-Author';
}
// Nachricht formatieren
$message = str_replace(
['{title}', '{author}', '{link}'],
[$post->post_title, $author_name, get_permalink($post_id)],
$message_template
);
foreach ($chat_ids as $chat_id) {
$chat_id = trim($chat_id);
if (!empty($chat_id)) {
// Überprüfen, ob die ID das Thema enthält (Format: -1001234567890_123)
if (strpos($chat_id, '_') !== false) {
// Kanal-ID und Themen-ID trennen
list($channel_id, $topic_id) = explode('_', $chat_id);
$chat_id = $channel_id;
// Telegram API-Anfrage senden
$url = "https://api.telegram.org/bot$bot_token/sendMessage";
$args = [
'body' => json_encode([
'chat_id' => $chat_id,
'text' => $message,
'parse_mode' => 'HTML',
'reply_to_message_id' => $topic_id
]),
'headers' => ['Content-Type' => 'application/json'],
'method' => 'POST',
];
// API-Request senden und Fehlerprotokollierung
$response = wp_remote_post($url, $args);
if (is_wp_error($response)) {
$error_message = $response->get_error_message();
error_log("Telegram Fehler: $error_message");
} else {
// Erhöhe den Telegram-Nachrichtenzähler
tg_notify_increment_telegram_message_count();
}
} else {
// Normaler Kanal ohne Thema
$url = "https://api.telegram.org/bot$bot_token/sendMessage";
$args = [
'body' => json_encode([
'chat_id' => $chat_id,
'text' => $message,
'parse_mode' => 'HTML'
]),
'headers' => ['Content-Type' => 'application/json'],
'method' => 'POST',
];
// API-Request senden und Fehlerprotokollierung
$response = wp_remote_post($url, $args);
if (is_wp_error($response)) {
$error_message = $response->get_error_message();
error_log("Telegram Fehler: $error_message");
} else {
// Erhöhe den Telegram-Nachrichtenzähler
tg_notify_increment_telegram_message_count();
}
}
}
}
}
function tg_notify_increment_telegram_message_count() {
$current_count = get_option('wp_multi_telegram_message_count', 0);
update_option('wp_multi_telegram_message_count', $current_count + 1);
}
+59
View File
@@ -0,0 +1,59 @@
<?php
/**
* WP Multi Modul: Notify-Übersichtsseite
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Notify Seite Discord & Telegram
*/
// Die Notify-Menüpunkte werden zentral in wp_multi_register_admin_menus() registriert
// (DC-Notify-Slug wurde von 'wp-multi' zu 'wp-multi-dc-notify' umbenannt, da 'wp-multi'
// jetzt das gemeinsame Top-Level-Menü ist).
// Callback-Funktion für die Hauptseite Notify
function wp_multi_notify_page() {
wpmt_admin_page_open(
__('Notify', 'wp-multi'),
__('Discord- und Telegram-Benachrichtigungen für neue Beiträge', 'wp-multi')
);
wpmt_admin_notice('info', __('Um Benachrichtigungen zu senden, müssen zuerst die entsprechenden Webhooks und Bots eingerichtet werden. Diese Seite erklärt die Einrichtung - die eigentlichen Einstellungen findest du unter DC-Notify bzw. TG-Notify.', 'wp-multi'));
echo '<div class="wpm-grid wpm-grid--2">';
wpmt_admin_card_open(__('Discord', 'wp-multi'));
?>
<p><?php _e('Erstellen Sie einen Webhook in einem Discord-Kanal und fügen Sie die Webhook-URL in die entsprechenden Felder ein.', 'wp-multi'); ?></p>
<ol>
<li><?php _e('Gehen Sie zu Ihrem Discord-Server und öffnen Sie die Server-Einstellungen.', 'wp-multi'); ?></li>
<li><?php _e('Wählen Sie "Integrationen" und dann "Webhook erstellen".', 'wp-multi'); ?></li>
<li><?php _e('Kopieren Sie die Webhook-URL und fügen Sie diese in das entsprechende Feld ein.', 'wp-multi'); ?></li>
</ol>
<p><a href="<?php echo esc_url(admin_url('admin.php?page=wp-multi-dc-notify')); ?>" class="wpm-btn wpm-btn--primary"><?php _e('DC-Notify einrichten', 'wp-multi'); ?></a></p>
<?php
wpmt_admin_card_close();
wpmt_admin_card_open(__('Telegram', 'wp-multi'));
?>
<p><?php _e('Erstellen Sie einen Bot über BotFather und fügen Sie den Token und die Kanal-ID in die entsprechenden Felder ein.', 'wp-multi'); ?></p>
<ol>
<li><?php _e('Öffnen Sie Telegram und suchen Sie nach "BotFather".', 'wp-multi'); ?></li>
<li><?php _e('Geben Sie /newbot ein, um einen neuen Bot zu erstellen.', 'wp-multi'); ?></li>
<li><?php _e('Speichern Sie den Bot-Token und die Kanal-ID und tragen Sie diese in die Felder ein.', 'wp-multi'); ?></li>
</ol>
<p><a href="<?php echo esc_url(admin_url('admin.php?page=tg-notify')); ?>" class="wpm-btn wpm-btn--primary"><?php _e('TG-Notify einrichten', 'wp-multi'); ?></a></p>
<?php
wpmt_admin_card_close();
echo '</div>';
wpmt_admin_page_close();
}
+338
View File
@@ -0,0 +1,338 @@
<?php
/**
* WP Multi Modul: Beitrags-Report
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Beitrags Report
*/
// Funktion zum Erstellen und Aktualisieren der Datenbanktabelle für gemeldete Beiträge
function wp_stat_notice_create_reported_posts_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'reported_posts';
$charset_collate = $wpdb->get_charset_collate();
// SQL für die Tabelle
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
post_id BIGINT(20) NOT NULL,
report_date DATETIME DEFAULT CURRENT_TIMESTAMP,
reason TEXT NOT NULL,
name VARCHAR(255) NOT NULL,
status VARCHAR(20) DEFAULT 'reported',
user_id BIGINT(20) UNSIGNED DEFAULT NULL,
PRIMARY KEY (id),
KEY post_id (post_id),
KEY user_id (user_id)
) $charset_collate;";
// Tabelle zuerst erstellen bzw. aktualisieren - erst danach kann die
// Spaltenprüfung laufen (vorher schlug SHOW COLUMNS bei der Erstaktivierung fehl).
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
// Migration für Alt-Installationen: Spalte `name` ergänzen, falls sie fehlt
$columns = $wpdb->get_results("SHOW COLUMNS FROM $table_name");
$column_names = array_map(function($column) {
return $column->Field;
}, $columns);
if (!in_array('name', $column_names, true)) {
$wpdb->query("ALTER TABLE $table_name ADD COLUMN `name` VARCHAR(255) NOT NULL");
}
}
register_activation_hook(WP_MULTI_FILE, 'wp_stat_notice_create_reported_posts_table');
// Shortcode für den "Beitrag melden"-Button
function wp_stat_notice_report_button($atts) {
global $post;
if (!is_user_logged_in()) return '';
$atts = shortcode_atts(array('post_id' => $post->ID), $atts, 'report_button');
$nonce = wp_create_nonce('report_post_nonce');
// Report-Button & Eingabefelder für Name und Grund
ob_start();
?>
<button class="report-post" data-post-id="<?php echo esc_attr($atts['post_id']); ?>" data-nonce="<?php echo esc_attr($nonce); ?>">
Beitrag melden
</button>
<div class="report-reason" style="display:none;">
<input type="text" class="report-name" placeholder="Geben Sie Ihren Namen an" required />
<textarea class="report-reason-text" placeholder="Geben Sie den Grund an" required></textarea>
<button class="submit-report">Bericht absenden</button>
</div>
<?php
return ob_get_clean();
}
add_shortcode('report_button', 'wp_stat_notice_report_button');
// Stil für das Meldeformular
function wp_stat_notice_report_button_styles() {
?>
<style>
.report-reason {
display: none;
margin-top: 10px;
background-color: #f9f9f9;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
width: 300px;
margin-top: 10px;
}
.report-reason input, .report-reason textarea {
width: 100%;
padding: 10px;
margin: 5px 0;
border: 1px solid #ccc;
border-radius: 4px;
}
.report-reason button {
background-color: #0073aa;
color: white;
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.report-reason button:hover {
background-color: #005177;
}
.report-post {
background-color: #ff7f00;
color: white;
padding: 10px;
border-radius: 5px;
cursor: pointer;
}
.report-post:hover {
background-color: #e07b00;
}
</style>
<?php
}
add_action('wp_head', 'wp_stat_notice_report_button_styles');
// Dashboard-Widget hinzufügen
function wp_stat_notice_add_dashboard_widget() {
wp_add_dashboard_widget(
'wp_stat_notice_dashboard_widget',
'Letzte 10 gemeldete Beiträge',
'wp_stat_notice_dashboard_widget_display'
);
}
add_action('wp_dashboard_setup', 'wp_stat_notice_add_dashboard_widget');
// Funktion, die das Dashboard-Widget anzeigt
function wp_stat_notice_dashboard_widget_display() {
global $wpdb;
$table_name = $wpdb->prefix . 'reported_posts';
// Abfrage, um die letzten 10 gemeldeten Beiträge zu holen
$reports = $wpdb->get_results(
"SELECT * FROM $table_name ORDER BY report_date DESC LIMIT 10"
);
if (empty($reports)) {
echo '<p>Es gibt keine gemeldeten Beiträge.</p>';
return;
}
// Tabelle mit den letzten 10 gemeldeten Beiträgen anzeigen
echo '<table class="wp-list-table widefat fixed striped">';
echo '<thead><tr><th>Beitrag</th><th>Datum</th><th>Grund</th></tr></thead><tbody>';
foreach ($reports as $report) {
$post = get_post($report->post_id);
echo '<tr>';
echo '<td>' . esc_html($post->post_title) . '</td>';
echo '<td>' . esc_html($report->report_date) . '</td>';
echo '<td>' . esc_html($report->reason) . '</td>';
echo '</tr>';
}
echo '</tbody></table>';
}
// AJAX-Handler zum Senden eines Reports
function wp_stat_notice_handle_report() {
check_ajax_referer('report_post_nonce', 'nonce');
if (!isset($_POST['post_id'], $_POST['reason'], $_POST['name']) || !is_user_logged_in()) {
wp_send_json_error(array('message' => 'Ungültige Anfrage.'));
return;
}
global $wpdb;
$table_name = $wpdb->prefix . 'reported_posts';
$post_id = intval($_POST['post_id']);
$reason = sanitize_textarea_field($_POST['reason']);
$name = sanitize_text_field($_POST['name']);
$user_id = get_current_user_id();
// Versuche den Eintrag in die Datenbank zu schreiben
$result = $wpdb->insert(
$table_name,
array(
'post_id' => $post_id,
'reason' => $reason,
'name' => $name,
'status' => 'reported',
'user_id' => $user_id
),
array('%d', '%s', '%s', '%s', '%d')
);
if ($result === false) {
error_log("Datenbankfehler: " . $wpdb->last_error); // WP Debug Log
wp_send_json_error(array('message' => 'Datenbankfehler: ' . $wpdb->last_error));
} else {
wp_send_json_success(array('message' => 'Bericht erfolgreich gesendet.'));
}
}
add_action('wp_ajax_report_post', 'wp_stat_notice_handle_report');
// JavaScript in den Footer einfügen
function wp_stat_notice_inline_js() {
?>
<script>
jQuery(document).ready(function ($) {
$(document).on("click", ".report-post", function () {
let reasonBox = $(this).next(".report-reason");
reasonBox.toggle();
});
$(document).on("click", ".submit-report", function () {
let button = $(this);
let container = button.closest(".report-reason");
let reason = container.find(".report-reason-text").val();
let name = container.find(".report-name").val();
let postId = button.closest(".report-reason").prev(".report-post").data("post-id");
let nonce = button.closest(".report-reason").prev(".report-post").data("nonce");
if (!reason || !name) {
alert("Bitte geben Sie sowohl Ihren Namen als auch einen Grund an.");
return;
}
$.ajax({
url: "<?php echo admin_url('admin-ajax.php'); ?>",
type: "POST",
data: {
action: "report_post",
post_id: postId,
reason: reason,
name: name,
nonce: nonce
},
success: function (response) {
if (response.success) {
alert("Der Bericht wurde erfolgreich gesendet.");
container.hide();
} else {
alert("Fehler: " + response.data.message);
}
}
});
});
});
</script>
<?php
}
add_action('wp_footer', 'wp_stat_notice_inline_js');
// Admin-Seite für gemeldete Beiträge
function wp_stat_notice_reported_posts_page() {
global $wpdb;
$table_name = $wpdb->prefix . 'reported_posts';
$reports = $wpdb->get_results("SELECT * FROM $table_name ORDER BY report_date DESC");
wpmt_admin_page_open(
__('Gemeldete Beiträge', 'wp-stat-notice'),
__('Von Besuchern gemeldete Inhalte prüfen und bearbeiten', 'wp-stat-notice')
);
wpmt_admin_card_open();
if (empty($reports)) {
wpmt_admin_notice('info', __('Es liegen keine Meldungen vor.', 'wp-stat-notice'));
} else {
?>
<div class="wpm-table-wrap">
<table class="wpm-table">
<thead>
<tr>
<th><?php _e('Beitrag', 'wp-stat-notice'); ?></th>
<th><?php _e('Datum', 'wp-stat-notice'); ?></th>
<th><?php _e('Name', 'wp-stat-notice'); ?></th>
<th><?php _e('Grund', 'wp-stat-notice'); ?></th>
<th><?php _e('Status', 'wp-stat-notice'); ?></th>
<th><?php _e('Aktionen', 'wp-stat-notice'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($reports as $report):
$post = get_post($report->post_id); ?>
<tr>
<td><?php echo $post ? esc_html($post->post_title) : '—'; ?></td>
<td><?php echo esc_html($report->report_date); ?></td>
<td><?php echo esc_html($report->name); ?></td>
<td><?php echo esc_html($report->reason); ?></td>
<td><span class="wpm-badge <?php echo $report->status === 'reported' ? 'wpm-badge--warning' : ''; ?>"><?php echo esc_html($report->status); ?></span></td>
<td>
<a href="<?php echo esc_url(wp_nonce_url('?page=reported-posts&delete_report=' . $report->id, 'wp_stat_notice_delete_report_' . $report->id)); ?>" class="wpm-btn" onclick="return confirm('<?php esc_attr_e('Report wirklich löschen?', 'wp-stat-notice'); ?>');"><?php _e('Report löschen', 'wp-stat-notice'); ?></a>
<a href="<?php echo esc_url(wp_nonce_url('?page=reported-posts&unpublish_report=' . $report->id, 'wp_stat_notice_unpublish_report_' . $report->id)); ?>" class="wpm-btn"><?php _e('Unpublish', 'wp-stat-notice'); ?></a>
<a href="<?php echo esc_url(wp_nonce_url('?page=reported-posts&delete_post=' . $report->post_id, 'wp_stat_notice_delete_post_' . $report->post_id)); ?>" class="wpm-btn wpm-btn--danger" onclick="return confirm('<?php esc_attr_e('Beitrag wirklich unwiderruflich löschen?', 'wp-stat-notice'); ?>');"><?php _e('Beitrag löschen', 'wp-stat-notice'); ?></a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php
}
wpmt_admin_card_close();
wpmt_admin_page_close();
}
// Aktionen für Report-Handling
function wp_stat_notice_handle_report_actions() {
if (!isset($_GET['page']) || $_GET['page'] !== 'reported-posts') {
return;
}
if (!current_user_can('manage_options')) {
return;
}
global $wpdb;
if (isset($_GET['delete_report'])) {
check_admin_referer('wp_stat_notice_delete_report_' . intval($_GET['delete_report']));
$wpdb->delete($wpdb->prefix . 'reported_posts', array('id' => intval($_GET['delete_report'])), array('%d'));
} elseif (isset($_GET['unpublish_report'])) {
check_admin_referer('wp_stat_notice_unpublish_report_' . intval($_GET['unpublish_report']));
$wpdb->update($wpdb->prefix . 'reported_posts', array('status' => 'unpublished'), array('id' => intval($_GET['unpublish_report'])), array('%s'), array('%d'));
} elseif (isset($_GET['delete_post'])) {
check_admin_referer('wp_stat_notice_delete_post_' . intval($_GET['delete_post']));
wp_delete_post(intval($_GET['delete_post']), true);
}
}
add_action('admin_init', 'wp_stat_notice_handle_report_actions');
// Der Menüpunkt "Gemeldete Beiträge" wird zentral in wp_multi_register_admin_menus() registriert.
+238
View File
@@ -0,0 +1,238 @@
<?php
/**
* WP Multi Modul: Custom Shortcodes
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* custom shortcodes
*/
// Funktion, um die Datenbanktabelle für Shortcodes zu erstellen
function wp_multi_create_shortcodes_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'wp_multi_shortcodes'; // Name der Tabelle mit Präfix
$charset_collate = $wpdb->get_charset_collate();
// SQL-Abfrage zum Erstellen der Tabelle
$sql = "CREATE TABLE $table_name (
id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
shortcode_name varchar(255) NOT NULL,
shortcode_content text NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY shortcode_name (shortcode_name)
) $charset_collate;";
// Datenbank abfragen und ausführen
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
dbDelta( $sql );
}
register_activation_hook( WP_MULTI_FILE, 'wp_multi_create_shortcodes_table' );
// Der Shortcodes-Menüpunkt wird zentral in wp_multi_register_admin_menus() registriert.
// Callback-Funktion für das Shortcode-Verwaltungs-Interface
function wp_multi_shortcode_page() {
global $wpdb;
$message = ''; // Variable für benutzerdefinierte Nachrichten
// Verarbeite das Speichern von Shortcodes
if (isset($_POST['wp_multi_shortcode_name']) && isset($_POST['wp_multi_shortcode_content'])) {
check_admin_referer('wp_multi_save_shortcode', 'wp_multi_shortcode_nonce');
// Hole die übermittelten Shortcodes
$name = sanitize_key($_POST['wp_multi_shortcode_name']);
$content = wp_kses_post(wp_unslash($_POST['wp_multi_shortcode_content']));
// Prüfen, ob der Shortcode bereits existiert
$existing_shortcode = $wpdb->get_var($wpdb->prepare("SELECT id FROM {$wpdb->prefix}wp_multi_shortcodes WHERE shortcode_name = %s", $name));
if ($existing_shortcode) {
// Aktualisiere den Shortcode, falls er bereits existiert
$wpdb->update(
$wpdb->prefix . 'wp_multi_shortcodes',
['shortcode_content' => $content],
['shortcode_name' => $name]
);
$message = 'Shortcode wurde aktualisiert!';
} else {
// Andernfalls einen neuen Shortcode einfügen
$wpdb->insert(
$wpdb->prefix . 'wp_multi_shortcodes',
[
'shortcode_name' => $name,
'shortcode_content' => $content
]
);
$message = 'Shortcode wurde hinzugefügt!';
}
}
// Shortcode löschen
if (isset($_GET['delete_shortcode']) && !empty($_GET['delete_shortcode'])) {
check_admin_referer('wp_multi_delete_shortcode_' . intval($_GET['delete_shortcode']));
$delete_id = intval($_GET['delete_shortcode']);
$wpdb->delete(
$wpdb->prefix . 'wp_multi_shortcodes',
['id' => $delete_id]
);
$message = 'Shortcode wurde gelöscht!';
}
// Holen der gespeicherten Shortcodes aus der Datenbank
$custom_shortcodes = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}wp_multi_shortcodes");
wpmt_admin_page_open(
__('Shortcodes', 'wp-multi'),
__('Eigene Shortcodes erstellen, die im Editor eingefügt werden können', 'wp-multi')
);
if (!empty($message)) {
wpmt_admin_notice('success', $message);
}
wpmt_admin_card_open(__('Shortcode anlegen / aktualisieren', 'wp-multi'));
?>
<form method="post">
<?php wp_nonce_field('wp_multi_save_shortcode', 'wp_multi_shortcode_nonce'); ?>
<div class="wpm-field">
<label class="wpm-field__label" for="wp_multi_shortcode_name"><?php _e('Name des Shortcodes', 'wp-multi'); ?>
<small class="wpm-field__hint"><?php _e('Nur Kleinbuchstaben, Zahlen und Unterstriche.', 'wp-multi'); ?></small>
</label>
<input type="text" name="wp_multi_shortcode_name" id="wp_multi_shortcode_name" required />
</div>
<div class="wpm-field">
<label class="wpm-field__label" for="wp_multi_shortcode_content"><?php _e('Inhalt des Shortcodes', 'wp-multi'); ?></label>
<textarea name="wp_multi_shortcode_content" id="wp_multi_shortcode_content" rows="5" required></textarea>
</div>
<?php submit_button(__('Shortcode speichern', 'wp-multi')); ?>
</form>
<?php
wpmt_admin_card_close();
wpmt_admin_card_open(__('Verfügbare Shortcodes', 'wp-multi'));
if (!empty($custom_shortcodes)) {
?>
<div class="wpm-table-wrap">
<table class="wpm-table">
<thead>
<tr>
<th><?php _e('Shortcode', 'wp-multi'); ?></th>
<th><?php _e('Inhalt', 'wp-multi'); ?></th>
<th><?php _e('Aktionen', 'wp-multi'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($custom_shortcodes as $shortcode) :
$delete_url = wp_nonce_url(
admin_url('admin.php?page=wp_multi_shortcodes&delete_shortcode=' . $shortcode->id),
'wp_multi_delete_shortcode_' . $shortcode->id
);
?>
<tr>
<td><code>[<?php echo esc_html($shortcode->shortcode_name); ?>]</code></td>
<td><?php echo esc_html(wp_trim_words($shortcode->shortcode_content, 15)); ?></td>
<td><a href="<?php echo esc_url($delete_url); ?>" class="wpm-btn wpm-btn--danger" onclick="return confirm('<?php esc_attr_e('Möchten Sie diesen Shortcode wirklich löschen?', 'wp-multi'); ?>');"><?php _e('Löschen', 'wp-multi'); ?></a></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php
} else {
wpmt_admin_notice('info', __('Keine benutzerdefinierten Shortcodes gefunden.', 'wp-multi'));
}
wpmt_admin_card_close();
wpmt_admin_page_close();
}
// Shortcode-Verwaltung: Ermöglicht Benutzern das Erstellen eigener Shortcodes
function wp_multi_register_custom_shortcodes() {
global $wpdb;
// Holen der gespeicherten Shortcodes aus der Datenbank
$custom_shortcodes = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}wp_multi_shortcodes");
// Wenn keine benutzerdefinierten Shortcodes vorhanden sind, abbrechen
if (empty($custom_shortcodes)) {
return;
}
// Definiere die Shortcodes in WordPress
foreach ($custom_shortcodes as $shortcode) {
add_shortcode($shortcode->shortcode_name, function() use ($shortcode) {
return wp_kses_post($shortcode->shortcode_content);
});
}
}
add_action('init', 'wp_multi_register_custom_shortcodes');
// Inhalt der Meta-Box anzeigen
function wp_multi_render_shortcode_meta_box($post) {
global $wpdb;
// Alle gespeicherten Shortcodes aus der Datenbank holen
$shortcodes = $wpdb->get_results("SELECT shortcode_name FROM {$wpdb->prefix}wp_multi_shortcodes");
if (!empty($shortcodes)) {
echo '<select id="wp_multi_shortcode_dropdown">';
echo '<option value="">-- Shortcode auswählen --</option>';
foreach ($shortcodes as $shortcode) {
echo '<option value="' . esc_attr($shortcode->shortcode_name) . '">' . esc_html($shortcode->shortcode_name) . '</option>';
}
echo '</select>';
echo '<button type="button" class="button button-primary" id="wp_multi_insert_shortcode">Einfügen</button>';
} else {
echo '<p>Keine Shortcodes vorhanden.</p>';
}
}
// JavaScript für Meta-Box einbinden (Classic Editor: fügt den gewählten Shortcode ein)
function wp_multi_enqueue_admin_scripts($hook) {
if ('post.php' === $hook || 'post-new.php' === $hook) {
wp_enqueue_script('wp-multi-shortcode', plugin_dir_url(WP_MULTI_FILE) . 'js/classic-editor-shortcodes.js', array('jquery'), '1.0', true);
}
}
add_action('admin_enqueue_scripts', 'wp_multi_enqueue_admin_scripts');
// Funktion zum Registrieren des TinyMCE Plugins
function wp_multi_add_shortcode_button() {
add_filter('mce_external_plugins', 'wp_multi_register_tinymce_plugin');
add_filter('mce_buttons', 'wp_multi_add_tinymce_button');
}
add_action('admin_head', 'wp_multi_add_shortcode_button');
// Plugin für TinyMCE registrieren (angepasster Pfad zum JS-File)
function wp_multi_register_tinymce_plugin($plugins) {
$plugins['wp_multi_shortcodes'] = plugin_dir_url(WP_MULTI_FILE) . 'js/tinymce-shortcodes.js';
return $plugins;
}
// Button zur TinyMCE Toolbar hinzufügen
function wp_multi_add_tinymce_button($buttons) {
array_push($buttons, 'wp_multi_shortcodes');
return $buttons;
}
// Shortcodes aus der Datenbank für das JavaScript bereitstellen
function wp_multi_localize_shortcodes() {
global $wpdb;
$shortcodes = $wpdb->get_results("SELECT shortcode_name FROM {$wpdb->prefix}wp_multi_shortcodes", ARRAY_A);
// Shortcodes als JSON an das JS-File übergeben
wp_enqueue_script('wp-multi-tinymce', plugin_dir_url(WP_MULTI_FILE) . 'js/tinymce-shortcodes.js', array('jquery'), null, true);
wp_localize_script('wp-multi-tinymce', 'wpMultiShortcodes', $shortcodes);
}
add_action('admin_enqueue_scripts', 'wp_multi_localize_shortcodes');
+510
View File
@@ -0,0 +1,510 @@
<?php
/**
* WP Multi Modul: Statistik & Banner
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Statistik & Banner
*/
// Funktion zum Einbinden von CSS direkt im Plugin-Code
function statistik_manager_inline_styles() {
?>
<style>
/* CSS für das Statistik Manager Plugin */
.statistik-manager-bookmarks {
font-family: Arial, sans-serif;
margin-top: 20px;
}
.statistik-manager-bookmarks ul {
list-style-type: none;
padding: 0;
}
.statistik-manager-bookmarks li {
margin-bottom: 10px;
}
.statistik-manager-bookmarks a {
text-decoration: none;
color: #0073aa;
font-size: 1.6em; /* Größerer Text für den Titel */
}
.statistik-manager-bookmarks a:hover {
color: #005177;
}
.delete-bookmark-btn {
background-color: #f44336;
color: white;
border: none;
padding: 5px 10px;
cursor: pointer;
margin-right: 10px; /* Abstand zwischen Button und Titel */
margin-bottom: 10px; /* Mehr Abstand nach unten */
}
.delete-bookmark-btn:hover {
background-color: #d32f2f;
}
.form-field {
margin-bottom: 15px;
}
.form-field label {
display: block;
margin-bottom: 5px;
}
.form-field input {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
.form-field button {
background-color: #0073aa;
color: white;
border: none;
padding: 10px 20px;
cursor: pointer;
}
.form-field button:hover {
background-color: #005177;
}
</style>
<?php
}
add_action('wp_head', 'statistik_manager_inline_styles');
// Font Awesome einbinden
function statistik_manager_enqueue_fontawesome() {
wp_enqueue_style('fontawesome', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css', [], null);
}
add_action('wp_enqueue_scripts', 'statistik_manager_enqueue_fontawesome');
// Sprachdateien laden
function statistik_manager_load_textdomain() {
load_plugin_textdomain('statistik-manager', false, dirname(plugin_basename(WP_MULTI_FILE)) . '/languages');
}
add_action('plugins_loaded', 'statistik_manager_load_textdomain');
// Funktion zum Abrufen der Statistiken
function statistik_manager_get_statistics() {
global $wpdb;
// Beiträge
$posts_count = wp_count_posts()->publish;
// Kommentare
$comments_count = wp_count_comments()->total_comments;
// Kategorien
$selected_categories = get_option('statistik_manager_selected_categories', []);
$categories_count = 0;
if (!empty($selected_categories)) {
$categories_count = count($selected_categories);
} else {
// Alle Kategorien zählen, wenn keine ausgewählt wurden
$categories_count = wp_count_terms('category');
}
// Serien (angenommen, Serien sind benutzerdefinierte Taxonomie)
$series_count = 0;
if (taxonomy_exists('series')) {
$count = wp_count_terms('series');
$series_count = is_wp_error($count) ? 0 : (int) $count;
}
// Eröffnungsdatum
$opening_date = get_option('statistik_manager_opening_date', '');
return [
'posts_count' => $posts_count,
'comments_count' => $comments_count,
'categories_count' => $categories_count,
'series_count' => $series_count,
'opening_date' => $opening_date
];
}
// Banner-Funktion
function statistik_manager_display_banner($position) {
if (!get_option('statistik_manager_banner_enabled', 1)) {
return;
}
$banner_text = get_option('statistik_manager_banner_text', 'Willkommen auf unserer Webseite!');
$banner_color = get_option('statistik_manager_banner_color', '#0073aa');
$banner_position = get_option('statistik_manager_banner_position', 'top');
$font_size = get_option('statistik_manager_banner_font_size', 'medium');
$banner_icon = get_option('statistik_manager_banner_icon', 'fas fa-info-circle'); // Standard-Icon
$show_icon = get_option('statistik_manager_show_icon', 1); // Option zur Aktivierung des Icons
// Schriftgröße je nach Auswahl setzen
switch ($font_size) {
case 'small':
$font_size_css = '14px';
break;
case 'medium':
$font_size_css = '18px';
break;
case 'large':
$font_size_css = '24px';
break;
default:
$font_size_css = '18px';
}
if ($banner_position !== $position) {
return;
}
// Standard-Styles für das Banner
$style = "background-color: " . esc_attr($banner_color) . ";
color: #fff;
text-align: center;
padding: 10px;
width: 100%;
height: 50px; /* Feste Höhe */
line-height: 30px; /* Zentrierte Schrift */
z-index: 9999;
position: fixed;
top: 0;
left: 0;";
$text_style = "font-size: " . esc_attr($font_size_css) . ";";
$icon_style = "font-size: 24px; margin-right: 8px;"; // Feste Größe für Icon
echo '<div class="statistik-manager-banner" id="statistik-manager-banner" style="' . esc_attr($style) . '">';
// Icon nur anzeigen, wenn gewünscht
if ($show_icon && !empty($banner_icon)) {
echo '<i class="' . esc_attr($banner_icon) . '" style="' . esc_attr($icon_style) . '"></i>';
}
echo '<span style="' . esc_attr($text_style) . '">' . esc_html($banner_text) . '</span>';
echo '</div>';
}
// Funktion für das Banner im Header (nach <body>)
function statistik_manager_display_banner_header() {
add_action('wp_body_open', function() {
statistik_manager_display_banner('top');
});
}
// Falls `wp_body_open` nicht unterstützt wird, als Fallback `wp_footer` nutzen
function statistik_manager_display_banner_header_fallback() {
add_action('wp_footer', function() {
statistik_manager_display_banner('top');
}, 5);
}
// Funktion für das Banner im Footer
function statistik_manager_display_banner_footer() {
add_action('wp_footer', function() {
statistik_manager_display_banner('bottom');
}, 10);
}
// Banner laden (Header mit Fallback)
if (function_exists('wp_body_open')) {
statistik_manager_display_banner_header();
} else {
statistik_manager_display_banner_header_fallback();
}
// Fix: Admin-Leiste (Wenn Admin angemeldet ist, Banner nach unten verschieben)
function statistik_manager_admin_bar_fix() {
if (is_admin_bar_showing()) {
echo '<style>
#statistik-manager-banner {
top: 32px !important; /* Admin-Leiste ausgleichen */
}
body {
padding-top: 82px !important; /* Extra Platz für Admin-Leiste */
}
</style>';
} else {
echo '<style>
body {
padding-top: 70px !important; /* Standard Abstand */
}
</style>';
}
}
add_action('wp_head', 'statistik_manager_admin_bar_fix');
// Shortcode für die Anzeige der Statistiken
function statistik_manager_shortcode() {
$statistics = statistik_manager_get_statistics();
$webseitenname = get_bloginfo('name');
$output = '<div class="statistik-manager">';
$output .= '<h3>Statistikübersicht</h3>';
$output .= '<div class="statistik-items">';
if (get_option('statistik_manager_show_posts')) {
$output .= '<div class="stat-item"><i class="fas fa-file-alt"></i>';
$output .= '<p><strong>Beiträge:</strong></br> ' . esc_html($statistics['posts_count']) . '</p></div>';
}
if (get_option('statistik_manager_show_comments')) {
$output .= '<div class="stat-item"><i class="fas fa-comments"></i>';
$output .= '<p><strong>Kommentare:</strong></br> ' . esc_html($statistics['comments_count']) . '</p></div>';
}
if (get_option('statistik_manager_show_categories')) {
$output .= '<div class="stat-item"><i class="fas fa-th-list"></i>';
$output .= '<p><strong>Kategorien:</strong></br> ' . esc_html($statistics['categories_count']) . '</p></div>';
}
if (get_option('statistik_manager_show_series')) {
$output .= '<div class="stat-item"><i class="fas fa-tv"></i>';
$output .= '<p><strong>Serien:</strong></br> ' . esc_html($statistics['series_count']) . '</p></div>';
}
$output .= '</div>';
// Eröffnungsdatum anzeigen, wenn gesetzt
if (!empty($statistics['opening_date'])) {
$formatted_date = date('d.m.Y', strtotime($statistics['opening_date']));
$output .= '<div class="stat-opening-date">';
$output .= '<i class="fas fa-calendar-alt"></i>';
$output .= '<p><strong>' . sprintf(__('%s wurde am %s eröffnet.', 'statistik-manager'), esc_html($webseitenname), esc_html($formatted_date)) . '</strong></p>';
$output .= '</div>';
}
$output .= '</div>';
return $output;
}
add_shortcode('statistik_manager', 'statistik_manager_shortcode');
// Admin-Panel CSS einbinden, nur auf der Plugin-Seite
// Das frühere seitenspezifische admin-style.css wurde durch das gemeinsame
// Design-System (wp-multi-toolkit/assets/admin.css) ersetzt.
// Frontend CSS nur einbinden, wenn der Shortcode verwendet wird
function statistik_manager_enqueue_frontend_styles() {
if (has_shortcode(get_post()->post_content, 'statistik_manager')) {
wp_enqueue_style('statistik-manager-frontend-style', plugins_url('css/style.css', WP_MULTI_FILE));
}
}
add_action('wp_enqueue_scripts', 'statistik_manager_enqueue_frontend_styles');
// Der Menüpunkt "Statistik & Notice" wird zentral in wp_multi_register_admin_menus() registriert.
// Funktion für die Plugin-Optionen-Seite
function statistik_manager_options_page() {
wpmt_admin_page_open(
__('Statistik & Notice', 'statistik-manager'),
__('Statistik-Shortcode, Lesezeichen und Frontend-Banner konfigurieren', 'statistik-manager')
);
wpmt_admin_card_open(__('Einstellungen', 'statistik-manager'));
?>
<form method="post" action="options.php">
<?php
settings_fields('statistik_manager_settings_group');
do_settings_sections('statistik_manager');
?>
<h2><?php _e('Statistiken anzeigen', 'statistik-manager'); ?></h2>
<table class="form-table">
<tr valign="top">
<th scope="row"><?php _e('Anzeigen', 'statistik-manager'); ?></th>
<td>
<input type="checkbox" name="statistik_manager_show_posts" value="1" <?php checked(get_option('statistik_manager_show_posts'), 1); ?> />
<label for="statistik_manager_show_posts"><?php _e('Beiträge anzeigen', 'statistik-manager'); ?></label><br>
<input type="checkbox" name="statistik_manager_show_comments" value="1" <?php checked(get_option('statistik_manager_show_comments'), 1); ?> />
<label for="statistik_manager_show_comments"><?php _e('Kommentare anzeigen', 'statistik-manager'); ?></label><br>
<input type="checkbox" name="statistik_manager_show_categories" value="1" <?php checked(get_option('statistik_manager_show_categories'), 1); ?> />
<label for="statistik_manager_show_categories"><?php _e('Kategorien anzeigen', 'statistik-manager'); ?></label><br>
<input type="checkbox" name="statistik_manager_show_series" value="1" <?php checked(get_option('statistik_manager_show_series'), 1); ?> />
<label for="statistik_manager_show_series"><?php _e('Serien anzeigen', 'statistik-manager'); ?></label>
</td>
</tr>
</table>
<h2><?php _e('Kategorien auswählen', 'statistik-manager'); ?></h2>
<table class="form-table">
<tr valign="top">
<th scope="row"><?php _e('Angezeigte Kategorien', 'statistik-manager'); ?></th>
<td>
<?php
$categories = get_terms(array(
'taxonomy' => 'category',
'orderby' => 'name',
'order' => 'ASC',
'hide_empty' => false,
));
if (!empty($categories) && !is_wp_error($categories)) :
$selected_categories = get_option('statistik_manager_selected_categories', []);
?>
<select name="statistik_manager_selected_categories[]" multiple="multiple" style="width: 300px; height: 150px;">
<?php foreach ($categories as $category) : ?>
<option value="<?php echo esc_attr($category->term_id); ?>"
<?php echo in_array($category->term_id, $selected_categories) ? 'selected' : ''; ?>>
<?php echo esc_html($category->name); ?>
</option>
<?php endforeach; ?>
</select>
<?php endif; ?>
</td>
</tr>
</table>
<h2><?php _e('Eröffnungsdatum der Webseite', 'statistik-manager'); ?></h2>
<table class="form-table">
<tr valign="top">
<th scope="row"><?php _e('Eröffnungsdatum', 'statistik-manager'); ?></th>
<td>
<input type="date" name="statistik_manager_opening_date" value="<?php echo esc_attr(get_option('statistik_manager_opening_date')); ?>" />
</td>
</tr>
</table>
<h2>Banner-Einstellungen</h2>
<table class="form-table">
<tr>
<th>Banner anzeigen</th>
<td>
<input type="checkbox" name="statistik_manager_banner_enabled" value="1" <?php checked(get_option('statistik_manager_banner_enabled', 1)); ?> />
<label for="statistik_manager_banner_enabled">Banner aktivieren</label>
</td>
</tr>
<tr>
<th>Banner Text</th>
<td><input type="text" name="statistik_manager_banner_text" value="<?php echo esc_attr(get_option('statistik_manager_banner_text', 'Willkommen auf unserer Webseite!')); ?>" /></td>
</tr>
<tr>
<th>Banner Farbe</th>
<td><input type="color" name="statistik_manager_banner_color" value="<?php echo esc_attr(get_option('statistik_manager_banner_color', '#0073aa')); ?>" /></td>
</tr>
<tr>
<th>Banner Position</th>
<td>
<select name="statistik_manager_banner_position">
<option value="top" <?php selected(get_option('statistik_manager_banner_position'), 'top'); ?>>Oben</option>
<option value="bottom" <?php selected(get_option('statistik_manager_banner_position'), 'bottom'); ?>>Unten</option>
</select>
</td>
</tr>
<tr>
<th>Icon auswählen</th>
<td>
<select name="statistik_manager_banner_icon">
<option value="fas fa-info-circle" <?php selected(get_option('statistik_manager_banner_icon'), 'fas fa-info-circle'); ?>>️ Info</option>
<option value="fas fa-exclamation-triangle" <?php selected(get_option('statistik_manager_banner_icon'), 'fas fa-exclamation-triangle'); ?>>⚠️ Warnung</option>
<option value="fas fa-bell" <?php selected(get_option('statistik_manager_banner_icon'), 'fas fa-bell'); ?>>🔔 Benachrichtigung</option>
<option value="fas fa-thumbs-up" <?php selected(get_option('statistik_manager_banner_icon'), 'fas fa-thumbs-up'); ?>>👍 Daumen hoch</option>
<option value="">Kein Icon</option>
</select>
</td>
</tr>
<tr>
<th>Icon anzeigen</th>
<td>
<input type="checkbox" name="statistik_manager_show_icon" value="1" <?php checked(get_option('statistik_manager_show_icon', 1)); ?> />
<label for="statistik_manager_show_icon">Icon anzeigen</label>
</td>
</tr>
<tr>
<th>Schriftgröße</th>
<td>
<select name="statistik_manager_banner_font_size">
<option value="small" <?php selected(get_option('statistik_manager_banner_font_size'), 'small'); ?>>Klein</option>
<option value="medium" <?php selected(get_option('statistik_manager_banner_font_size'), 'medium'); ?>>Mittel</option>
<option value="large" <?php selected(get_option('statistik_manager_banner_font_size'), 'large'); ?>>Groß</option>
</select>
</td>
</tr>
</table>
<?php submit_button(); ?>
</form>
<?php
wpmt_admin_card_close();
echo '<div class="wpm-grid wpm-grid--2">';
wpmt_admin_card_open(__('Kurzanleitung: Statistik-Box', 'statistik-manager'));
?>
<ol>
<li><strong>Shortcode einfügen:</strong> Füge <code>[statistik_manager]</code> an der gewünschten Stelle in einem Beitrag oder einer Seite ein.</li>
<li><strong>Statistiken wählen:</strong> Beiträge, Kommentare, Kategorien und Serien lassen sich einzeln ein- und ausblenden.</li>
<li><strong>Kategorien:</strong> Wähle aus, welche Kategorien in die Zählung einbezogen werden.</li>
<li><strong>Eröffnungsdatum:</strong> Wird automatisch in der Statistik-Box angezeigt.</li>
<li><strong>Banner:</strong> Ein konfigurierbares Hinweis-Banner kann im Header oder Footer der Website eingeblendet werden.</li>
</ol>
<?php
wpmt_admin_card_close();
wpmt_admin_card_open(__('Kurzanleitung: Lesezeichen', 'statistik-manager'));
?>
<ol>
<li><strong>Anzeigen:</strong> Der Shortcode <code>[display_bookmarks]</code> listet die gespeicherten Lesezeichen der Besucher auf.</li>
<li><strong>Hinzufügen:</strong> Über <code>[add_bookmark]</code> erhalten Besucher ein Formular zum Speichern eines Lesezeichens.</li>
<li><strong>Löschen:</strong> Nur der Besitzer eines Lesezeichens kann es über den Löschen-Button entfernen.</li>
</ol>
<p><?php printf(__('Weitere Plugins der WP-Multi-Familie findest du auf %s.', 'statistik-manager'), '<a href="https://git.viper.ipv64.net/M_Viper" target="_blank">git.viper.ipv64.net</a>'); ?></p>
<?php
wpmt_admin_card_close();
echo '</div>';
wpmt_admin_page_close();
}
// Optionen registrieren
function statistik_manager_register_settings() {
register_setting('statistik_manager_settings_group', 'statistik_manager_show_posts');
register_setting('statistik_manager_settings_group', 'statistik_manager_show_comments');
register_setting('statistik_manager_settings_group', 'statistik_manager_show_categories');
register_setting('statistik_manager_settings_group', 'statistik_manager_show_series');
register_setting('statistik_manager_settings_group', 'statistik_manager_selected_categories');
register_setting('statistik_manager_settings_group', 'statistik_manager_opening_date');
register_setting('statistik_manager_settings_group', 'statistik_manager_banner_text');
register_setting('statistik_manager_settings_group', 'statistik_manager_banner_color', [
'sanitize_callback' => 'sanitize_hex_color',
]);
register_setting('statistik_manager_settings_group', 'statistik_manager_banner_position');
register_setting('statistik_manager_settings_group', 'statistik_manager_banner_enabled');
register_setting('statistik_manager_settings_group', 'statistik_manager_banner_icon', [
'sanitize_callback' => function($value) {
// Icon-Wert besteht aus mehreren space-getrennten CSS-Klassen (z. B. "fas fa-bell")
$classes = array_map('sanitize_html_class', explode(' ', (string) $value));
return implode(' ', array_filter($classes));
},
]);
register_setting('statistik_manager_settings_group', 'statistik_manager_show_icon');
register_setting('statistik_manager_settings_group', 'statistik_manager_banner_font_size');
}
add_action('admin_init', 'statistik_manager_register_settings');
// Standardwerte setzen
function statistik_manager_set_default_options() {
if (get_option('statistik_manager_show_posts') === false) {
update_option('statistik_manager_show_posts', 1);
}
if (get_option('statistik_manager_show_comments') === false) {
update_option('statistik_manager_show_comments', 1);
}
if (get_option('statistik_manager_show_categories') === false) {
update_option('statistik_manager_show_categories', 1);
}
if (get_option('statistik_manager_show_series') === false) {
update_option('statistik_manager_show_series', 1);
}
if (get_option('statistik_manager_selected_categories') === false) {
update_option('statistik_manager_selected_categories', []);
}
if (get_option('statistik_manager_banner_enabled') === false) {
update_option('statistik_manager_banner_enabled', 1);
}
if (get_option('statistik_manager_banner_font_size') === false) {
update_option('statistik_manager_banner_font_size', 'medium');
}
}
add_action('admin_init', 'statistik_manager_set_default_options');
+142
View File
@@ -0,0 +1,142 @@
<?php
/**
* WP Multi Modul: Admin-Dashboard Update-Anzeige
*
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
*/
if (!defined('ABSPATH')) { exit; }
/*
* Admin Dashboard Update-Anzeige
*/
define('WP_MULTI_UPDATE_REPO', 'wp-multi');
define('WP_MULTI_UPDATE_CACHE_KEY', 'wp_multi_latest_release');
define('WP_MULTI_UPDATE_HOST', 'git.viper.ipv64.net');
// Fragt den Gitea-Server nach dem neuesten Release ab (gecached via Transient)
function wp_multi_get_latest_release() {
$cached = get_transient(WP_MULTI_UPDATE_CACHE_KEY);
if ($cached !== false) {
return $cached;
}
$api_url = 'https://' . WP_MULTI_UPDATE_HOST . '/api/v1/repos/M_Viper/' . WP_MULTI_UPDATE_REPO . '/releases';
$response = wp_remote_get($api_url, array(
'timeout' => 10,
'headers' => array('Accept' => 'application/json'),
));
if (is_wp_error($response)) {
// Kurz erneut versuchen statt für 12 Stunden zu sperren
set_transient(WP_MULTI_UPDATE_CACHE_KEY, false, HOUR_IN_SECONDS);
return false;
}
$body = wp_remote_retrieve_body($response);
$releases = json_decode($body, true);
if (empty($releases) || !is_array($releases)) {
set_transient(WP_MULTI_UPDATE_CACHE_KEY, false, HOUR_IN_SECONDS);
return false;
}
usort($releases, function ($a, $b) {
$a_date = !empty($a['created_at']) ? $a['created_at'] : '';
$b_date = !empty($b['created_at']) ? $b['created_at'] : '';
return strtotime($b_date) - strtotime($a_date);
});
$latest = false;
foreach ($releases as $release) {
if (!empty($release['prerelease'])) {
continue;
}
if (!empty($release['tag_name'])) {
// Nur Download-URLs auf dem erwarteten Host akzeptieren
$html_url = !empty($release['html_url']) ? $release['html_url'] : '';
$release_host = $html_url ? wp_parse_url($html_url, PHP_URL_HOST) : '';
$latest = array(
'version' => ltrim($release['tag_name'], 'v'),
'url' => ($release_host === WP_MULTI_UPDATE_HOST)
? esc_url_raw($html_url)
: 'https://' . WP_MULTI_UPDATE_HOST . '/M_Viper/' . WP_MULTI_UPDATE_REPO . '/releases',
);
break;
}
}
set_transient(WP_MULTI_UPDATE_CACHE_KEY, $latest, 12 * HOUR_IN_SECONDS);
return $latest;
}
// Liest die installierte Version aus dem Plugin-Header
function wp_multi_get_installed_version() {
if (!function_exists('get_plugin_data')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$data = get_plugin_data(WP_MULTI_FILE, false, false);
return !empty($data['Version']) ? $data['Version'] : '0';
}
// Dashboard-Widget registrieren
function wp_multi_add_update_dashboard_widget() {
wp_add_dashboard_widget(
'wp_multi_update_widget',
__('WP Multi - Update-Status', 'wp-multi'),
'wp_multi_update_dashboard_widget_content'
);
}
add_action('wp_dashboard_setup', 'wp_multi_add_update_dashboard_widget');
// Zeigt im Dashboard-Widget an, ob WP Multi aktuell ist oder ein Update verfügbar ist
function wp_multi_update_dashboard_widget_content() {
$installed_version = wp_multi_get_installed_version();
$latest = wp_multi_get_latest_release();
echo '<p><strong>' . esc_html__('Installierte Version:', 'wp-multi') . '</strong> ' . esc_html($installed_version) . '</p>';
if (!$latest || empty($latest['version'])) {
echo '<p>' . esc_html__('Der Update-Server konnte nicht erreicht werden.', 'wp-multi') . '</p>';
return;
}
if (version_compare($latest['version'], $installed_version, '>')) {
echo '<p style="color:#dc3545;"><strong>' . esc_html__('Update verfügbar:', 'wp-multi') . '</strong> ' . esc_html($latest['version']) . '</p>';
echo '<p><a href="' . esc_url($latest['url']) . '" target="_blank" class="button button-primary">' . esc_html__('Update herunterladen', 'wp-multi') . '</a></p>';
} else {
echo '<p style="color:#28a745;"><strong>' . esc_html__('WP Multi ist aktuell.', 'wp-multi') . '</strong></p>';
}
}
// Admin-Hinweis anzeigen, wenn ein Update verfügbar ist
function wp_multi_update_admin_notice() {
if (!current_user_can('manage_options') || !is_admin()) {
return;
}
$installed_version = wp_multi_get_installed_version();
$latest = wp_multi_get_latest_release();
if (!$latest || empty($latest['version'])) {
return;
}
if (version_compare($latest['version'], $installed_version, '>')) {
printf(
'<div class="notice notice-warning is-dismissible"><p>%1$s <a href="%2$s" target="_blank">%3$s</a></p></div>',
sprintf(
esc_html__('Für "WP Multi" ist ein Update verfügbar: Version %1$s (installiert: %2$s).', 'wp-multi'),
esc_html($latest['version']),
esc_html($installed_version)
),
esc_url($latest['url']),
esc_html__('Jetzt herunterladen', 'wp-multi')
);
}
}
add_action('admin_notices', 'wp_multi_update_admin_notice');
+108 -4960
View File
File diff suppressed because it is too large Load Diff