Compare commits

..

2 Commits
3.2 ... main

Author SHA1 Message Date
778563d991 README.md aktualisiert 2025-04-20 15:59:34 +00:00
d332fac418 wp-multi.php aktualisiert 2025-04-20 14:00:59 +00:00
2 changed files with 338 additions and 62 deletions

View File

@ -31,6 +31,9 @@
- Statistik-Widget mit Shortcode `[statistik_manager]` - Statistik-Widget mit Shortcode `[statistik_manager]`
- Anpassbares Banner mit Position, Farbe und Icon - Anpassbares Banner mit Position, Farbe und Icon
- **Gast Autoren:**
- Alphabetisches Index für Gast Autoren mit Shortcode `[guest_authors]`
- **Admin-Tools:** - **Admin-Tools:**
- Dashboard-Widget für Plugin-Updates (mit Pre-Release-Unterstützung) - Dashboard-Widget für Plugin-Updates (mit Pre-Release-Unterstützung)
- Pinnwand für Administratoren - Pinnwand für Administratoren

View File

@ -3,11 +3,12 @@
* Plugin Name: WP Multi * Plugin Name: WP Multi
* Plugin URI: https://git.viper.ipv64.net/M_Viper/wp-multi * Plugin URI: https://git.viper.ipv64.net/M_Viper/wp-multi
* Description: Erweiterter Anti-Spam-Schutz mit Honeypot, Keyword-Filter, Link-Limit und mehr. Jetzt mit Statistik im Dashboard und HappyForms-Integration. * Description: Erweiterter Anti-Spam-Schutz mit Honeypot, Keyword-Filter, Link-Limit und mehr. Jetzt mit Statistik im Dashboard und HappyForms-Integration.
* Version: 3.0 * Version: 3.2
* Author: M_Viper * Author: M_Viper
* Author URI: https://m-viper.de * Author URI: https://m-viper.de
* Requires at least: 6.7.2 * Requires at least: 6.7.2
* Tested up to: 6.7.2 * Tested up to: 6.7.2
* PHP Version: 7.2
* License: GPL2 * License: GPL2
* License URI: https://www.gnu.org/licenses/gpl-2.0.html * License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: wp-multi * Text Domain: wp-multi
@ -312,6 +313,8 @@ function check_disposable_email($commentdata) {
add_filter('preprocess_comment', 'check_disposable_email'); add_filter('preprocess_comment', 'check_disposable_email');
/* /*
* Text Copy Schutz und Schutz vor Entwicklertools * Text Copy Schutz und Schutz vor Entwicklertools
*/ */
@ -3476,7 +3479,6 @@ function wp_multi_display_dashboard_widget() {
* Gast Autoren * Gast Autoren
*/ */
// Gast-Autor Eingabefeld in der Sidebar im Admin-Bereich hinzufügen // Gast-Autor Eingabefeld in der Sidebar im Admin-Bereich hinzufügen
function wp_multi_add_guest_author_field() { function wp_multi_add_guest_author_field() {
add_meta_box( add_meta_box(
@ -3492,7 +3494,6 @@ add_action('add_meta_boxes', 'wp_multi_add_guest_author_field');
// Callback-Funktion, die das Eingabefeld anzeigt // Callback-Funktion, die das Eingabefeld anzeigt
function wp_multi_guest_author_field($post) { function wp_multi_guest_author_field($post) {
// Die Metadaten des Beitrags laden (ob ein Gast-Autor gesetzt ist)
$guest_author = get_post_meta($post->ID, '_guest_author', true); $guest_author = get_post_meta($post->ID, '_guest_author', true);
?> ?>
<label for="guest_author"><?php _e('Gast-Autor Name:', 'wp-multi'); ?></label> <label for="guest_author"><?php _e('Gast-Autor Name:', 'wp-multi'); ?></label>
@ -3502,13 +3503,8 @@ function wp_multi_guest_author_field($post) {
// Speichern der Gast-Autor Daten // Speichern der Gast-Autor Daten
function wp_multi_save_guest_author_meta($post_id) { function wp_multi_save_guest_author_meta($post_id) {
// Sicherheit: Verhindere, dass die Metadaten beim Autosave überschrieben werden
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return; if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
// Überprüfen, ob der Benutzer Berechtigungen hat
if (!current_user_can('edit_post', $post_id)) return; if (!current_user_can('edit_post', $post_id)) return;
// Überprüfen, ob der Gast-Autor Name gesetzt wurde
if (isset($_POST['guest_author'])) { if (isset($_POST['guest_author'])) {
$guest_author = sanitize_text_field($_POST['guest_author']); $guest_author = sanitize_text_field($_POST['guest_author']);
update_post_meta($post_id, '_guest_author', $guest_author); update_post_meta($post_id, '_guest_author', $guest_author);
@ -3523,10 +3519,8 @@ function wp_multi_display_guest_author($author_name) {
if ((is_single() || is_archive() || is_home()) && !is_admin()) { if ((is_single() || is_archive() || is_home()) && !is_admin()) {
$post = get_post(); $post = get_post();
if ($post) { if ($post) {
// Wenn der Beitrag einen Gast-Autor hat, diesen verwenden
$guest_author = get_post_meta($post->ID, '_guest_author', true); $guest_author = get_post_meta($post->ID, '_guest_author', true);
if (!empty($guest_author)) { if (!empty($guest_author)) {
// Ersetze den Standard-Autor mit dem Gast-Autor
$author_name = $guest_author; $author_name = $guest_author;
} }
} }
@ -3544,15 +3538,10 @@ function wp_multi_add_guest_author_column($columns) {
} }
add_filter('manage_posts_columns', 'wp_multi_add_guest_author_column'); add_filter('manage_posts_columns', 'wp_multi_add_guest_author_column');
// Inhalt der Gast-Autor-Spalte
function wp_multi_display_guest_author_column($column_name, $post_id) { function wp_multi_display_guest_author_column($column_name, $post_id) {
if ($column_name == 'guest_author') { if ($column_name == 'guest_author') {
$guest_author = get_post_meta($post_id, '_guest_author', true); $guest_author = get_post_meta($post_id, '_guest_author', true);
if (!empty($guest_author)) { echo !empty($guest_author) ? esc_html($guest_author) : __('Kein Gast-Autor', 'wp-multi');
echo esc_html($guest_author);
} else {
echo __('Kein Gast-Autor', 'wp-multi');
}
} }
} }
add_action('manage_posts_custom_column', 'wp_multi_display_guest_author_column', 10, 2); add_action('manage_posts_custom_column', 'wp_multi_display_guest_author_column', 10, 2);
@ -3570,43 +3559,67 @@ function wp_multi_add_guest_author_page() {
} }
add_action('admin_menu', 'wp_multi_add_guest_author_page'); add_action('admin_menu', 'wp_multi_add_guest_author_page');
// Callback-Funktion für die Gast-Autor-Übersicht // Callback-Funktion für die Gast-Autor-Übersicht
function wp_multi_guest_author_overview_page() { 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('users.php'));
?> ?>
<div class="wrap"> <div class="wrap">
<h1><?php _e('Gast-Autor Übersicht', 'wp-multi'); ?></h1> <h1><?php _e('Gast-Autor Übersicht', 'wp-multi'); ?></h1>
<table class="wp-list-table widefat fixed striped posts"> <table class="wp-list-table widefat fixed striped posts">
<thead> <thead>
<tr> <tr>
<th><?php _e('Gast-Autor', 'wp-multi'); ?></th> <th class="column-guest_author">
<th><?php _e('Anzahl der Beiträge', 'wp-multi'); ?></th> <a href="<?php echo esc_url(add_query_arg(['orderby' => 'guest_author', 'order' => ($orderby === 'guest_author' && $order === 'ASC') ? 'DESC' : 'ASC'], $base_url)); ?>" class="<?php echo ($orderby === 'guest_author') ? 'sorted ' . strtolower($order) : 'sortable'; ?>">
<?php _e('Gast-Autor', 'wp-multi'); ?>
<?php if ($orderby === 'guest_author') : ?>
<span class="sorting-indicator"><?php echo ($order === 'ASC') ? '↑' : '↓'; ?></span>
<?php endif; ?>
</a>
</th>
<th class="column-posts">
<a href="<?php echo esc_url(add_query_arg(['orderby' => 'posts', 'order' => ($orderby === 'posts' && $order === 'ASC') ? 'DESC' : 'ASC'], $base_url)); ?>" class="<?php echo ($orderby === 'posts') ? 'sorted ' . strtolower($order) : 'sortable'; ?>">
<?php _e('Anzahl der Beiträge', 'wp-multi'); ?>
<?php if ($orderby === 'posts') : ?>
<span class="sorting-indicator"><?php echo ($order === 'ASC') ? '↑' : '↓'; ?></span>
<?php endif; ?>
</a>
</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<?php <?php
// Alle Autoren und die Anzahl der Beiträge abfragen
global $wpdb; global $wpdb;
$guest_authors = $wpdb->get_results("SELECT DISTINCT pm.meta_value AS guest_author $query = "
SELECT pm.meta_value AS guest_author, COUNT(*) AS post_count
FROM {$wpdb->posts} p FROM {$wpdb->posts} p
LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
WHERE pm.meta_key = '_guest_author' AND p.post_status = 'publish' WHERE pm.meta_key = '_guest_author'
ORDER BY guest_author ASC"); 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);
// Alle Gast-Autoren anzeigen
if ($guest_authors) { if ($guest_authors) {
foreach ($guest_authors as $author) { foreach ($guest_authors as $author) {
// Anzahl der Beiträge für den Gast-Autor zählen
$author_posts = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*)
FROM {$wpdb->posts} p
LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
WHERE pm.meta_key = '_guest_author'
AND pm.meta_value = %s
AND p.post_status = 'publish'", $author->guest_author));
?> ?>
<tr> <tr>
<td><?php echo esc_html($author->guest_author); ?></td> <td><?php echo esc_html($author->guest_author); ?></td>
<td><?php echo $author_posts; ?></td> <td><?php echo esc_html($author->post_count); ?></td>
</tr> </tr>
<?php <?php
} }
@ -3622,46 +3635,306 @@ function wp_multi_guest_author_overview_page() {
// Schönes CSS nur für die Gast-Autor-Übersicht // Schönes CSS nur für die Gast-Autor-Übersicht
function wp_multi_guest_author_overview_css() { function wp_multi_guest_author_overview_css() {
// CSS nur auf der Seite der Gast-Autor-Übersicht anwenden
if (isset($_GET['page']) && $_GET['page'] == 'guest_author_overview') { if (isset($_GET['page']) && $_GET['page'] == 'guest_author_overview') {
?> ?>
<style> <style>
.wrap {
background-color: #ffffff;
padding: 24px;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
margin: 20px 20px 20px 0;
max-width: 1200px;
}
.wrap h1 {
font-size: 28px;
font-weight: 600;
color: #1a1a1a;
margin-bottom: 24px;
line-height: 1.3;
}
.wp-list-table { .wp-list-table {
border-collapse: collapse;
width: 100%; width: 100%;
border-collapse: separate;
border-spacing: 0;
background-color: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
} }
.wp-list-table th, .wp-list-table td { .wp-list-table th, .wp-list-table td {
padding: 12px; padding: 16px;
text-align: left; font-size: 14px;
border: 1px solid #ddd; color: #374151;
border-bottom: 1px solid #e5e7eb;
text-align: left; /* Standard Textausrichtung */
}
/* Kopfzeilen und Datenzellen der Spalte 'posts' zentrieren */
.wp-list-table th.column-posts, .wp-list-table td.column-posts {
text-align: center !important; /* !important stellt sicher, dass diese Regel Vorrang hat */
vertical-align: middle !important; /* Vertikal mittig ausrichten mit !important */
width: 200px !important; /* Kann je nach Bedarf angepasst werden */
}
/* Optional: Wenn du sicherstellen möchtest, dass auch die Kopfzeile mit einer festen Breite arbeitet */
.wp-list-table th.column-posts {
width: 200px !important; /* Breite der Kopfzeile mit !important */
}
.wp-list-table th.column-guest_author {
width: auto;
} }
.wp-list-table th { .wp-list-table th {
background-color: #f4f4f4; background-color: #f8fafc;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #1f2937;
}
.wp-list-table tr:last-child td {
border-bottom: none;
} }
.wp-list-table tr:nth-child(even) { .wp-list-table tr:nth-child(even) {
background-color: #f9f9f9; background-color: #f9fafb;
}
.wp-list-table th a {
text-decoration: none;
color: #2563eb;
display: inline-flex;
align-items: center;
transition: color 0.2s ease;
font-weight: 600;
}
.wp-list-table th a:hover {
color: #1d4ed8;
text-decoration: underline;
}
.wp-list-table th a:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.3);
border-radius: 4px;
}
.wp-list-table th.sorted a {
color: #111827;
font-weight: 700;
}
.wp-list-table th .sorting-indicator {
margin-left: 8px;
font-size: 12px;
color: #6b7280;
transition: color 0.2s ease;
}
.wp-list-table th.sorted .sorting-indicator {
color: #111827;
}
.wp-list-table th.sortable a:hover .sorting-indicator {
color: #1d4ed8;
}
.wp-list-table td {
vertical-align: middle;
}
@media (max-width: 768px) {
.wp-list-table th, .wp-list-table td {
padding: 12px;
font-size: 13px;
}
.wp-list-table th.column-posts {
width: 100px;
} }
.wrap h1 { .wrap h1 {
font-size: 24px; font-size: 24px;
margin-bottom: 20px;
} }
.wrap {
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
} }
</style> </style>
<?php <?php
} }
} }
add_action('admin_head', 'wp_multi_guest_author_overview_css'); add_action('admin_head', 'wp_multi_guest_author_overview_css');
// 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(urldecode($_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) {
// Überprüfen, ob die Kategorie "series" existiert
$series_category = term_exists('series', 'category');
$debug_message = '';
if (!$series_category) {
$debug_message = '<p class="col-span-2 text-red-600">Debug: Kategorie mit Slug "series" wurde nicht gefunden. Bitte überprüfe den Kategorie-Slug.</p>';
}
$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');
/* /*
* Custom Text Box * Custom Text Box