Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6ebdde2cf | ||
|
|
0f1c5632d6 | ||
|
|
8bcb7f1303 | ||
|
|
2b162e581f |
@@ -48,6 +48,7 @@ function wp_multi_register_admin_menus() {
|
|||||||
// Analyse & Inhalte
|
// 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, __('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, __('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, __('Veröffentlichungen', 'wp-multi'), __('Veröffentlichungen', 'wp-multi'), 'manage_options', 'wp-multi-publications', 'wp_multi_publication_stats_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, __('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, __('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');
|
$hooks[] = add_submenu_page($parent, __('WP Stat & Notice', 'wp-multi'), __('Statistik & Notice', 'wp-multi'), 'manage_options', 'statistik_manager', 'statistik_manager_options_page');
|
||||||
|
|||||||
+126
-19
@@ -62,7 +62,8 @@ function wp_multi_track_user_activity($user_id, $action, $post_id = null) {
|
|||||||
$post_id = get_the_ID();
|
$post_id = get_the_ID();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$user_id || !$action) {
|
// user_id 0 ist gewollt: Die Seite bietet keinen Login, Aufrufe sind anonym.
|
||||||
|
if (!$action) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,26 +93,93 @@ function wp_multi_comment_activity($comment_id) {
|
|||||||
add_action('comment_post', 'wp_multi_comment_activity');
|
add_action('comment_post', 'wp_multi_comment_activity');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verfolgt Beitragsaufrufe.
|
* Erkennt Bots und Crawler anhand des User-Agents.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function wp_multi_is_bot_request() {
|
||||||
|
$user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? strtolower(sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT']))) : '';
|
||||||
|
|
||||||
|
// Ohne User-Agent ist es so gut wie nie ein echter Besucher
|
||||||
|
if ($user_agent === '') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$signatures = apply_filters('wp_multi_bot_signatures', [
|
||||||
|
'bot', 'crawl', 'spider', 'slurp', 'archiver', 'preview', 'monitor', 'validator',
|
||||||
|
'facebookexternalhit', 'headless', 'phantomjs', 'python', 'curl', 'wget', 'go-http',
|
||||||
|
'java/', 'okhttp', 'axios', 'scrapy', 'lighthouse', 'pingdom', 'uptime',
|
||||||
|
]);
|
||||||
|
|
||||||
|
foreach ($signatures as $signature) {
|
||||||
|
if (strpos($user_agent, $signature) !== false) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prüft, ob dieser Besucher den Beitrag gerade erst aufgerufen hat.
|
||||||
|
*
|
||||||
|
* Ohne Login gibt es keine Benutzer-ID, deshalb dient ein kurzlebiger Hash aus
|
||||||
|
* IP und User-Agent als Erkennungsmerkmal. Gespeichert wird nur der Hash, nie
|
||||||
|
* die IP selbst – ein Reload zählt damit nicht mehrfach.
|
||||||
|
*
|
||||||
|
* @param int $post_id Beitrag-ID.
|
||||||
|
* @return bool True, wenn der Aufruf bereits gezählt wurde.
|
||||||
|
*/
|
||||||
|
function wp_multi_view_already_counted($post_id) {
|
||||||
|
$ip = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : '';
|
||||||
|
$user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : '';
|
||||||
|
|
||||||
|
$key = 'wp_multi_view_' . md5($post_id . '|' . $ip . '|' . $user_agent . '|' . wp_salt());
|
||||||
|
|
||||||
|
if (get_transient($key)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sperrfrist je Besucher und Beitrag
|
||||||
|
$ttl = (int) apply_filters('wp_multi_view_throttle', 30 * MINUTE_IN_SECONDS);
|
||||||
|
set_transient($key, 1, $ttl);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verfolgt Beitragsaufrufe – auch von nicht eingeloggten Besuchern.
|
||||||
*/
|
*/
|
||||||
function wp_multi_post_view_activity() {
|
function wp_multi_post_view_activity() {
|
||||||
if (is_single() && is_user_logged_in()) {
|
if (is_admin() || !is_single() || is_feed()) {
|
||||||
$user_id = get_current_user_id();
|
return;
|
||||||
$post_id = get_the_ID();
|
|
||||||
wp_multi_track_user_activity($user_id, 'view', $post_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Eigene Aufrufe der Redaktion verfälschen die Zahlen
|
||||||
|
if (is_user_logged_in() && current_user_can('edit_posts') && !apply_filters('wp_multi_track_editor_views', false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wp_multi_is_bot_request()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$post_id = get_the_ID();
|
||||||
|
if (!$post_id || wp_multi_view_already_counted($post_id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ohne Login ist die Benutzer-ID 0 – der Aufruf zählt trotzdem
|
||||||
|
wp_multi_track_user_activity(get_current_user_id(), 'view', $post_id);
|
||||||
}
|
}
|
||||||
add_action('wp_head', 'wp_multi_post_view_activity');
|
add_action('wp_head', 'wp_multi_post_view_activity');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ruft rohe Analytics-Daten aus der Datenbank ab.
|
* Baut die WHERE-Bedingung für den gewählten Zeitraum.
|
||||||
*
|
*
|
||||||
* @param string $date_query Datum für die Abfrage.
|
* @return array [WHERE-Fragment, Parameter]
|
||||||
* @return array Rohe Analytics-Daten.
|
|
||||||
*/
|
*/
|
||||||
function wp_multi_fetch_raw_analytics($start_datetime = null, $end_datetime = null) {
|
function wp_multi_analytics_date_where($start_datetime = null, $end_datetime = null) {
|
||||||
global $wpdb;
|
|
||||||
|
|
||||||
if (!$start_datetime) {
|
if (!$start_datetime) {
|
||||||
$start_datetime = gmdate('Y-m-d H:i:s', strtotime('-7 days'));
|
$start_datetime = gmdate('Y-m-d H:i:s', strtotime('-7 days'));
|
||||||
}
|
}
|
||||||
@@ -124,22 +192,60 @@ function wp_multi_fetch_raw_analytics($start_datetime = null, $end_datetime = nu
|
|||||||
$params[] = $end_datetime;
|
$params[] = $end_datetime;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = "SELECT DATE(timestamp) AS date, action, post_id, COUNT(*) AS count, user_id, timestamp
|
return [$where, $params];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ruft die Tagessummen je Aktion ab – Grundlage für das Diagramm.
|
||||||
|
*
|
||||||
|
* Aggregiert in der Datenbank statt in PHP: Seit auch anonyme Aufrufe gezählt
|
||||||
|
* werden, kämen hier sonst zehntausende Einzelzeilen an.
|
||||||
|
*
|
||||||
|
* @return array Zeilen mit date, action und count.
|
||||||
|
*/
|
||||||
|
function wp_multi_fetch_analytics_totals($start_datetime = null, $end_datetime = null) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
list($where, $params) = wp_multi_analytics_date_where($start_datetime, $end_datetime);
|
||||||
|
|
||||||
|
$sql = "SELECT DATE(timestamp) AS date, action, COUNT(*) AS count
|
||||||
FROM " . WP_MULTI_ANALYTICS_TABLE . "
|
FROM " . WP_MULTI_ANALYTICS_TABLE . "
|
||||||
$where
|
$where
|
||||||
GROUP BY date, action, post_id, user_id, timestamp
|
GROUP BY date, action
|
||||||
ORDER BY date ASC";
|
ORDER BY date ASC";
|
||||||
|
|
||||||
return $wpdb->get_results($wpdb->prepare($sql, $params));
|
return $wpdb->get_results($wpdb->prepare($sql, $params));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ruft die jüngsten Einzelereignisse ab – Grundlage für die Detailtabelle.
|
||||||
|
*
|
||||||
|
* @return array Rohe Analytics-Daten (begrenzt).
|
||||||
|
*/
|
||||||
|
function wp_multi_fetch_raw_analytics($start_datetime = null, $end_datetime = null) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
list($where, $params) = wp_multi_analytics_date_where($start_datetime, $end_datetime);
|
||||||
|
|
||||||
|
// Ohne Limit würde die Detailtabelle bei anonymem Tracking die Seite sprengen
|
||||||
|
$params[] = (int) apply_filters('wp_multi_analytics_detail_limit', 200);
|
||||||
|
|
||||||
|
$sql = "SELECT DATE(timestamp) AS date, action, post_id, 1 AS count, user_id, timestamp
|
||||||
|
FROM " . WP_MULTI_ANALYTICS_TABLE . "
|
||||||
|
$where
|
||||||
|
ORDER BY timestamp DESC
|
||||||
|
LIMIT %d";
|
||||||
|
|
||||||
|
return $wpdb->get_results($wpdb->prepare($sql, $params));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verarbeitet rohe Analytics-Daten für Diagramm und Tabelle.
|
* Verarbeitet rohe Analytics-Daten für Diagramm und Tabelle.
|
||||||
*
|
*
|
||||||
* @param array $results Rohe Analytics-Daten.
|
* @param array $results Rohe Analytics-Daten.
|
||||||
* @return array Verarbeitete Daten.
|
* @return array Verarbeitete Daten.
|
||||||
*/
|
*/
|
||||||
function wp_multi_process_analytics_data($results) {
|
function wp_multi_process_analytics_data($results, $recent = null) {
|
||||||
$dates = [];
|
$dates = [];
|
||||||
$comment_counts = [];
|
$comment_counts = [];
|
||||||
$view_counts = [];
|
$view_counts = [];
|
||||||
@@ -184,7 +290,7 @@ function wp_multi_process_analytics_data($results) {
|
|||||||
'fill' => false,
|
'fill' => false,
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'data' => $results
|
'data' => ($recent === null) ? $results : $recent
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,8 +308,9 @@ function wp_multi_get_analytics_data($start_datetime = null, $end_datetime = nul
|
|||||||
return $cached_data;
|
return $cached_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
$results = wp_multi_fetch_raw_analytics($start_datetime, $end_datetime);
|
$totals = wp_multi_fetch_analytics_totals($start_datetime, $end_datetime);
|
||||||
$data = wp_multi_process_analytics_data($results);
|
$recent = wp_multi_fetch_raw_analytics($start_datetime, $end_datetime);
|
||||||
|
$data = wp_multi_process_analytics_data($totals, $recent);
|
||||||
|
|
||||||
set_transient($cache_key, $data, HOUR_IN_SECONDS);
|
set_transient($cache_key, $data, HOUR_IN_SECONDS);
|
||||||
return $data;
|
return $data;
|
||||||
@@ -308,7 +415,7 @@ function wp_multi_display_user_analytics() {
|
|||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ($results['data'] as $row) : ?>
|
<?php foreach ($results['data'] as $row) : ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><?php echo esc_html($row->user_id); ?></td>
|
<td><?php echo $row->user_id ? esc_html($row->user_id) : esc_html__('Gast', 'wp-multi'); ?></td>
|
||||||
<td><span class="wpm-badge <?php echo $row->action === 'comment' ? 'wpm-badge--success' : ''; ?>"><?php echo esc_html($row->action); ?></span></td>
|
<td><span class="wpm-badge <?php echo $row->action === 'comment' ? 'wpm-badge--success' : ''; ?>"><?php echo esc_html($row->action); ?></span></td>
|
||||||
<td>
|
<td>
|
||||||
<?php
|
<?php
|
||||||
|
|||||||
+1825
-103
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,696 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* WP Multi – Modul: Veröffentlichungs-Statistik
|
||||||
|
*
|
||||||
|
* Zeigt, wie viele Geschichten pro Monat und pro Jahr veröffentlicht wurden.
|
||||||
|
* Eigener Menüpunkt, unabhängig von der Gast-Autoren-Übersicht.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) { exit; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Liefert die Reiter der Statistik-Seite.
|
||||||
|
*/
|
||||||
|
function wp_multi_get_publication_stats_tabs() {
|
||||||
|
return [
|
||||||
|
'month' => __('Monat', 'wp-multi'),
|
||||||
|
'year' => __('Jahr', 'wp-multi'),
|
||||||
|
'timeline' => __('Autoren-Zeitlinie', 'wp-multi'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Beitragstyp, der gezählt wird.
|
||||||
|
*/
|
||||||
|
function wp_multi_get_stats_post_type() {
|
||||||
|
return apply_filters('wp_multi_stats_post_type', 'post');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Liefert alle Jahre mit veröffentlichten Beiträgen samt Anzahl.
|
||||||
|
*
|
||||||
|
* @return array Zeilen mit year und total, aufsteigend nach Jahr.
|
||||||
|
*/
|
||||||
|
function wp_multi_get_publication_years() {
|
||||||
|
static $years = null;
|
||||||
|
|
||||||
|
if ($years !== null) {
|
||||||
|
return $years;
|
||||||
|
}
|
||||||
|
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$years = $wpdb->get_results($wpdb->prepare("
|
||||||
|
SELECT YEAR(post_date) AS year, COUNT(*) AS total
|
||||||
|
FROM {$wpdb->posts}
|
||||||
|
WHERE post_status = 'publish'
|
||||||
|
AND post_type = %s
|
||||||
|
GROUP BY YEAR(post_date)
|
||||||
|
ORDER BY year ASC
|
||||||
|
", wp_multi_get_stats_post_type()));
|
||||||
|
|
||||||
|
return $years;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback für den Menüpunkt "Veröffentlichungen".
|
||||||
|
*/
|
||||||
|
function wp_multi_publication_stats_page() {
|
||||||
|
$tabs = wp_multi_get_publication_stats_tabs();
|
||||||
|
$current_tab = isset($_GET['tab']) ? sanitize_key($_GET['tab']) : 'month';
|
||||||
|
if (!isset($tabs[$current_tab])) {
|
||||||
|
$current_tab = 'month';
|
||||||
|
}
|
||||||
|
|
||||||
|
$base_url = add_query_arg(['page' => 'wp-multi-publications'], admin_url('admin.php'));
|
||||||
|
|
||||||
|
wpmt_admin_page_open(
|
||||||
|
__('Veröffentlichungen', 'wp-multi'),
|
||||||
|
__('Wie viele Geschichten pro Monat und pro Jahr veröffentlicht wurden', 'wp-multi')
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
<h2 class="nav-tab-wrapper wpm-tabs">
|
||||||
|
<?php foreach ($tabs as $tab_key => $tab_label) : ?>
|
||||||
|
<a href="<?php echo esc_url(add_query_arg('tab', $tab_key, $base_url)); ?>"
|
||||||
|
class="nav-tab<?php echo ($current_tab === $tab_key) ? ' nav-tab-active' : ''; ?>">
|
||||||
|
<?php echo esc_html($tab_label); ?>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</h2>
|
||||||
|
<?php
|
||||||
|
|
||||||
|
if ($current_tab === 'year') {
|
||||||
|
wp_multi_render_publication_years($base_url);
|
||||||
|
} elseif ($current_tab === 'timeline') {
|
||||||
|
wp_multi_render_author_timeline($base_url);
|
||||||
|
} else {
|
||||||
|
wp_multi_render_publication_months($base_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
wpmt_admin_page_close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt eine Balkenzeile für die Statistik aus.
|
||||||
|
*
|
||||||
|
* Bewusst ohne Diagramm-Bibliothek: ein <div> mit prozentualer Breite reicht,
|
||||||
|
* lädt nichts nach und funktioniert auch ohne JavaScript.
|
||||||
|
*
|
||||||
|
* @param string $label Beschriftung links.
|
||||||
|
* @param int $value Wert.
|
||||||
|
* @param int $max Größter Wert der Reihe (für die Balkenbreite).
|
||||||
|
*/
|
||||||
|
function wp_multi_render_stat_bar($label, $value, $max) {
|
||||||
|
$percent = $max > 0 ? round(($value / $max) * 100) : 0;
|
||||||
|
?>
|
||||||
|
<div class="wpm-stat-row" style="display:flex;align-items:center;gap:10px;margin-bottom:6px;">
|
||||||
|
<span class="wpm-stat-label" style="flex:0 0 6em;"><?php echo esc_html($label); ?></span>
|
||||||
|
<span class="wpm-stat-track" style="flex:1 1 auto;background:rgba(125,125,125,.2);border-radius:3px;overflow:hidden;">
|
||||||
|
<span class="wpm-stat-fill" style="display:block;height:14px;width:<?php echo (int) $percent; ?>%;min-width:<?php echo $value > 0 ? '2px' : '0'; ?>;background:#2271b1;"></span>
|
||||||
|
</span>
|
||||||
|
<span class="wpm-stat-value" style="flex:0 0 5em;text-align:right;"><?php echo esc_html(number_format_i18n($value)); ?></span>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reiter "Monat": Veröffentlichungen je Monat eines Jahres.
|
||||||
|
*
|
||||||
|
* @param string $base_url Basis-URL der Seite.
|
||||||
|
*/
|
||||||
|
function wp_multi_render_publication_months($base_url) {
|
||||||
|
global $wpdb, $wp_locale;
|
||||||
|
|
||||||
|
$years = wp_multi_get_publication_years();
|
||||||
|
|
||||||
|
if (!$years) {
|
||||||
|
wpmt_admin_card_open(__('Veröffentlichungen pro Monat', 'wp-multi'));
|
||||||
|
echo '<p class="wpm-muted">' . esc_html__('Noch keine veröffentlichten Beiträge gefunden.', 'wp-multi') . '</p>';
|
||||||
|
wpmt_admin_card_close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$available_years = [];
|
||||||
|
foreach ($years as $row) {
|
||||||
|
$available_years[] = (int) $row->year;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jahr aus der URL, sonst das jüngste Jahr mit Beiträgen
|
||||||
|
$selected_year = isset($_GET['stats_year']) ? (int) $_GET['stats_year'] : 0;
|
||||||
|
if (!in_array($selected_year, $available_years, true)) {
|
||||||
|
$selected_year = end($available_years);
|
||||||
|
}
|
||||||
|
|
||||||
|
$months = $wpdb->get_results($wpdb->prepare("
|
||||||
|
SELECT MONTH(post_date) AS month, COUNT(*) AS total
|
||||||
|
FROM {$wpdb->posts}
|
||||||
|
WHERE post_status = 'publish'
|
||||||
|
AND post_type = %s
|
||||||
|
AND YEAR(post_date) = %d
|
||||||
|
GROUP BY MONTH(post_date)
|
||||||
|
ORDER BY month ASC
|
||||||
|
", wp_multi_get_stats_post_type(), $selected_year));
|
||||||
|
|
||||||
|
$month_totals = array_fill(1, 12, 0);
|
||||||
|
$max_month_total = 0;
|
||||||
|
$year_total = 0;
|
||||||
|
|
||||||
|
foreach ((array) $months as $row) {
|
||||||
|
$month_totals[(int) $row->month] = (int) $row->total;
|
||||||
|
$year_total += (int) $row->total;
|
||||||
|
if ((int) $row->total > $max_month_total) {
|
||||||
|
$max_month_total = (int) $row->total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$month_url = add_query_arg('tab', 'month', $base_url);
|
||||||
|
|
||||||
|
wpmt_admin_card_open(__('Veröffentlichungen pro Monat', 'wp-multi'));
|
||||||
|
?>
|
||||||
|
<p class="wpm-muted">
|
||||||
|
<?php _e('Jahr:', 'wp-multi'); ?>
|
||||||
|
<?php foreach (array_reverse($available_years) as $year) : ?>
|
||||||
|
<a href="<?php echo esc_url(add_query_arg('stats_year', $year, $month_url)); ?>" class="wpm-filter-link<?php echo ($year === $selected_year) ? ' wpm-filter-active' : ''; ?>">
|
||||||
|
<?php if ($year === $selected_year) : ?><strong><?php endif; ?>
|
||||||
|
<?php echo esc_html($year); ?>
|
||||||
|
<?php if ($year === $selected_year) : ?></strong><?php endif; ?>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</p>
|
||||||
|
<p class="wpm-muted">
|
||||||
|
<?php
|
||||||
|
printf(
|
||||||
|
/* translators: 1: Jahr, 2: Anzahl der Geschichten */
|
||||||
|
esc_html__('%1$d: %2$s Geschichten', 'wp-multi'),
|
||||||
|
(int) $selected_year,
|
||||||
|
esc_html(number_format_i18n($year_total))
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</p>
|
||||||
|
<div class="wpm-stat-chart" style="margin:16px 0;">
|
||||||
|
<?php for ($month = 1; $month <= 12; $month++) : ?>
|
||||||
|
<?php wp_multi_render_stat_bar($wp_locale->get_month_abbrev($wp_locale->get_month($month)), $month_totals[$month], $max_month_total); ?>
|
||||||
|
<?php endfor; ?>
|
||||||
|
</div>
|
||||||
|
<div class="wpm-table-wrap">
|
||||||
|
<table class="wpm-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><?php _e('Monat', 'wp-multi'); ?></th>
|
||||||
|
<th><?php _e('Geschichten', 'wp-multi'); ?></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php for ($month = 1; $month <= 12; $month++) : ?>
|
||||||
|
<tr>
|
||||||
|
<td><?php echo esc_html($wp_locale->get_month($month)); ?></td>
|
||||||
|
<td>
|
||||||
|
<?php if ($month_totals[$month]) : ?>
|
||||||
|
<?php echo esc_html(number_format_i18n($month_totals[$month])); ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<span class="wpm-muted">0</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endfor; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
wpmt_admin_card_close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reiter "Jahr": Veröffentlichungen je Jahr.
|
||||||
|
*
|
||||||
|
* @param string $base_url Basis-URL der Seite.
|
||||||
|
*/
|
||||||
|
function wp_multi_render_publication_years($base_url) {
|
||||||
|
$years = wp_multi_get_publication_years();
|
||||||
|
|
||||||
|
wpmt_admin_card_open(__('Veröffentlichungen pro Jahr', 'wp-multi'));
|
||||||
|
|
||||||
|
if (!$years) {
|
||||||
|
echo '<p class="wpm-muted">' . esc_html__('Noch keine veröffentlichten Beiträge gefunden.', 'wp-multi') . '</p>';
|
||||||
|
wpmt_admin_card_close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$max_total = 0;
|
||||||
|
$grand_total = 0;
|
||||||
|
$totals_by_year = [];
|
||||||
|
|
||||||
|
foreach ($years as $row) {
|
||||||
|
$totals_by_year[(int) $row->year] = (int) $row->total;
|
||||||
|
$grand_total += (int) $row->total;
|
||||||
|
if ((int) $row->total > $max_total) {
|
||||||
|
$max_total = (int) $row->total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$year_keys = array_keys($totals_by_year);
|
||||||
|
$month_url = add_query_arg('tab', 'month', $base_url);
|
||||||
|
?>
|
||||||
|
<p class="wpm-muted">
|
||||||
|
<?php
|
||||||
|
printf(
|
||||||
|
/* translators: 1: Gesamtzahl, 2: erstes Jahr, 3: letztes Jahr */
|
||||||
|
esc_html__('%1$s Geschichten von %2$d bis %3$d.', 'wp-multi'),
|
||||||
|
esc_html(number_format_i18n($grand_total)),
|
||||||
|
(int) reset($year_keys),
|
||||||
|
(int) end($year_keys)
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</p>
|
||||||
|
<div class="wpm-stat-chart" style="margin:16px 0;">
|
||||||
|
<?php foreach ($totals_by_year as $year => $total) : ?>
|
||||||
|
<?php wp_multi_render_stat_bar($year, $total, $max_total); ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<div class="wpm-table-wrap">
|
||||||
|
<table class="wpm-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><?php _e('Jahr', 'wp-multi'); ?></th>
|
||||||
|
<th><?php _e('Geschichten', 'wp-multi'); ?></th>
|
||||||
|
<th><?php _e('Veränderung', 'wp-multi'); ?></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach (array_reverse($totals_by_year, true) as $year => $total) : ?>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="<?php echo esc_url(add_query_arg('stats_year', (int) $year, $month_url)); ?>" title="<?php esc_attr_e('Monate dieses Jahres anzeigen', 'wp-multi'); ?>">
|
||||||
|
<?php echo esc_html($year); ?>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td><?php echo esc_html(number_format_i18n($total)); ?></td>
|
||||||
|
<td>
|
||||||
|
<?php
|
||||||
|
// Vergleich mit dem Vorjahr, sofern es Beiträge hatte
|
||||||
|
if (!isset($totals_by_year[$year - 1])) {
|
||||||
|
echo '<span class="wpm-muted">—</span>';
|
||||||
|
} else {
|
||||||
|
$diff = $total - $totals_by_year[$year - 1];
|
||||||
|
$sign = $diff > 0 ? '+' : '';
|
||||||
|
echo '<span class="wpm-muted">' . esc_html($sign . number_format_i18n($diff)) . '</span>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
wpmt_admin_card_close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Liefert die Beschriftungen der Autorengruppen.
|
||||||
|
*/
|
||||||
|
function wp_multi_get_timeline_groups() {
|
||||||
|
return [
|
||||||
|
'lost' => '🔥 ' . __('Verlorene Vielschreiber', 'wp-multi'),
|
||||||
|
'active' => '🟢 ' . __('Aktive Autoren', 'wp-multi'),
|
||||||
|
'new' => '🆕 ' . __('Neue Autoren', 'wp-multi'),
|
||||||
|
'quiet' => '🟡 ' . __('Stille Autoren', 'wp-multi'),
|
||||||
|
'one_off' => '💤 ' . __('Einmalige Autoren', 'wp-multi'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ordnet einen Autor anhand seiner Jahreswerte einer Gruppe zu.
|
||||||
|
*
|
||||||
|
* 🆕 Neue Autoren – erste Geschichte im aktuellen oder letzten Jahr
|
||||||
|
* 🔥 Verlorene Vielschreiber – früher ein starkes Jahr, seitdem so gut wie nichts
|
||||||
|
* 🟢 Aktive Autoren – im aktuellen oder letzten Jahr veröffentlicht
|
||||||
|
* 💤 Einmalige Autoren – höchstens zwei Geschichten und lange nichts mehr
|
||||||
|
* 🟡 Stille Autoren – alles dazwischen: mehr als zwei Geschichten, aber still
|
||||||
|
*
|
||||||
|
* @param array $per_year Zuordnung "Jahr => Anzahl".
|
||||||
|
* @param int $current_year Aktuelles Jahr.
|
||||||
|
* @return string Gruppenschlüssel.
|
||||||
|
*/
|
||||||
|
function wp_multi_get_author_timeline_group($per_year, $current_year) {
|
||||||
|
// Die letzten beiden Jahre gelten als "jetzt"
|
||||||
|
$recent_span = (int) apply_filters('wp_multi_timeline_recent_years', 2);
|
||||||
|
$recent_from = $current_year - ($recent_span - 1);
|
||||||
|
|
||||||
|
$total = 0;
|
||||||
|
$recent_total = 0;
|
||||||
|
$earlier_peak = 0;
|
||||||
|
$first_year = null;
|
||||||
|
|
||||||
|
foreach ($per_year as $year => $count) {
|
||||||
|
$year = (int) $year;
|
||||||
|
$count = (int) $count;
|
||||||
|
$total += $count;
|
||||||
|
|
||||||
|
if ($first_year === null || $year < $first_year) {
|
||||||
|
$first_year = $year;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($year >= $recent_from) {
|
||||||
|
$recent_total += $count;
|
||||||
|
} elseif ($count > $earlier_peak) {
|
||||||
|
$earlier_peak = $count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wer erst im "Jetzt"-Fenster angefangen hat, ist neu
|
||||||
|
if ($first_year !== null && $first_year >= $recent_from) {
|
||||||
|
return 'new';
|
||||||
|
}
|
||||||
|
|
||||||
|
$prolific_min = (int) apply_filters('wp_multi_timeline_prolific_min', 5);
|
||||||
|
$recent_max = (int) apply_filters('wp_multi_timeline_recent_max', 1);
|
||||||
|
|
||||||
|
if ($earlier_peak >= $prolific_min && $recent_total <= $recent_max) {
|
||||||
|
return 'lost';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($recent_total > 0) {
|
||||||
|
return 'active';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($total <= 2) {
|
||||||
|
return 'one_off';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'quiet';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Liest die Veröffentlichungen je Autor und Jahr.
|
||||||
|
*
|
||||||
|
* @return array Zuordnung "Autor => [Jahr => Anzahl]".
|
||||||
|
*/
|
||||||
|
function wp_multi_get_author_timeline_data() {
|
||||||
|
static $data = null;
|
||||||
|
|
||||||
|
if ($data !== null) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$rows = $wpdb->get_results($wpdb->prepare("
|
||||||
|
SELECT pm.meta_value AS guest_author, YEAR(p.post_date) AS year, COUNT(*) AS total
|
||||||
|
FROM {$wpdb->posts} p
|
||||||
|
INNER JOIN {$wpdb->postmeta} pm ON pm.post_id = p.ID AND pm.meta_key = '_guest_author' AND pm.meta_value != ''
|
||||||
|
WHERE p.post_status = 'publish'
|
||||||
|
AND p.post_type = %s
|
||||||
|
GROUP BY pm.meta_value, YEAR(p.post_date)
|
||||||
|
", wp_multi_get_stats_post_type()));
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
foreach ((array) $rows as $row) {
|
||||||
|
$data[$row->guest_author][(int) $row->year] = (int) $row->total;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reiter "Autoren-Zeitlinie": wer wann geschrieben hat und wer abgewandert ist.
|
||||||
|
*
|
||||||
|
* @param string $base_url Basis-URL der Seite.
|
||||||
|
*/
|
||||||
|
function wp_multi_render_author_timeline($base_url) {
|
||||||
|
$years = wp_multi_get_publication_years();
|
||||||
|
$timeline = wp_multi_get_author_timeline_data();
|
||||||
|
|
||||||
|
if (!$years || !$timeline) {
|
||||||
|
wpmt_admin_card_open(__('Autoren-Zeitlinie', 'wp-multi'));
|
||||||
|
echo '<p class="wpm-muted">' . esc_html__('Noch keine Daten für eine Zeitlinie vorhanden.', 'wp-multi') . '</p>';
|
||||||
|
wpmt_admin_card_close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$available_years = [];
|
||||||
|
foreach ($years as $row) {
|
||||||
|
$available_years[] = (int) $row->year;
|
||||||
|
}
|
||||||
|
|
||||||
|
$current_year = (int) end($available_years);
|
||||||
|
|
||||||
|
// Nur die letzten Jahre als Spalten, sonst wird die Tabelle unlesbar
|
||||||
|
$columns = (int) apply_filters('wp_multi_timeline_columns', 6);
|
||||||
|
$column_years = array_slice($available_years, -$columns);
|
||||||
|
|
||||||
|
$groups = wp_multi_get_timeline_groups();
|
||||||
|
$group_filter = isset($_GET['group']) ? sanitize_key($_GET['group']) : '';
|
||||||
|
if (!isset($groups[$group_filter])) {
|
||||||
|
$group_filter = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Autoren aufbereiten: Gruppe, Gesamtzahl und Jahreswerte
|
||||||
|
$authors = [];
|
||||||
|
$group_counts = array_fill_keys(array_keys($groups), 0);
|
||||||
|
|
||||||
|
foreach ($timeline as $name => $per_year) {
|
||||||
|
$group = wp_multi_get_author_timeline_group($per_year, $current_year);
|
||||||
|
$group_counts[$group]++;
|
||||||
|
|
||||||
|
$total = 0;
|
||||||
|
foreach ($per_year as $count) {
|
||||||
|
$total += (int) $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($group_filter !== '' && $group !== $group_filter) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$authors[] = [
|
||||||
|
'name' => $name,
|
||||||
|
'group' => $group,
|
||||||
|
'total' => $total,
|
||||||
|
'per_year' => $per_year,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nach Gesamtzahl sortieren – die produktivsten zuerst
|
||||||
|
usort($authors, function ($a, $b) {
|
||||||
|
if ($a['total'] === $b['total']) {
|
||||||
|
return strcasecmp($a['name'], $b['name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $b['total'] - $a['total'];
|
||||||
|
});
|
||||||
|
|
||||||
|
$timeline_url = add_query_arg('tab', 'timeline', $base_url);
|
||||||
|
$author_base_url = add_query_arg(['page' => 'guest_author_overview'], admin_url('admin.php'));
|
||||||
|
|
||||||
|
wpmt_admin_card_open(__('Autoren-Zeitlinie', 'wp-multi'));
|
||||||
|
?>
|
||||||
|
<p class="wpm-muted">
|
||||||
|
<?php _e('Gruppe:', 'wp-multi'); ?>
|
||||||
|
<a href="<?php echo esc_url(remove_query_arg('group', $timeline_url)); ?>" class="wpm-filter-link<?php echo ($group_filter === '') ? ' wpm-filter-active' : ''; ?>">
|
||||||
|
<?php if ($group_filter === '') : ?><strong><?php endif; ?>
|
||||||
|
<?php printf(esc_html__('Alle (%d)', 'wp-multi'), count($timeline)); ?>
|
||||||
|
<?php if ($group_filter === '') : ?></strong><?php endif; ?>
|
||||||
|
</a>
|
||||||
|
<?php foreach ($groups as $key => $label) : ?>
|
||||||
|
|
|
||||||
|
<a href="<?php echo esc_url(add_query_arg('group', $key, $timeline_url)); ?>" class="wpm-filter-link<?php echo ($group_filter === $key) ? ' wpm-filter-active' : ''; ?>">
|
||||||
|
<?php if ($group_filter === $key) : ?><strong><?php endif; ?>
|
||||||
|
<?php echo esc_html($label); ?> (<?php echo (int) $group_counts[$key]; ?>)
|
||||||
|
<?php if ($group_filter === $key) : ?></strong><?php endif; ?>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</p>
|
||||||
|
<div class="wpm-table-wrap">
|
||||||
|
<table class="wpm-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><?php _e('Autor', 'wp-multi'); ?></th>
|
||||||
|
<?php foreach ($column_years as $year) : ?>
|
||||||
|
<th><?php echo esc_html($year); ?></th>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<th><?php _e('Gesamt', 'wp-multi'); ?></th>
|
||||||
|
<th><?php _e('Gruppe', 'wp-multi'); ?></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if ($authors) : ?>
|
||||||
|
<?php foreach ($authors as $author) : ?>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<?php if (function_exists('wp_multi_get_guest_author_detail_url')) : ?>
|
||||||
|
<a href="<?php echo esc_url(wp_multi_get_guest_author_detail_url($author_base_url, $author['name'])); ?>"><?php echo esc_html($author['name']); ?></a>
|
||||||
|
<?php else : ?>
|
||||||
|
<?php echo esc_html($author['name']); ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<?php foreach ($column_years as $year) : ?>
|
||||||
|
<?php $count = isset($author['per_year'][$year]) ? (int) $author['per_year'][$year] : 0; ?>
|
||||||
|
<td>
|
||||||
|
<?php if ($count) : ?>
|
||||||
|
<?php echo esc_html(number_format_i18n($count)); ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<span class="wpm-muted">·</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<td><strong><?php echo esc_html(number_format_i18n($author['total'])); ?></strong></td>
|
||||||
|
<td><span class="wpm-muted"><?php echo esc_html($groups[$author['group']]); ?></span></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<tr><td colspan="<?php echo (int) (count($column_years) + 3); ?>"><?php _e('Keine Autoren in dieser Gruppe.', 'wp-multi'); ?></td></tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<p class="wpm-muted">
|
||||||
|
<?php
|
||||||
|
printf(
|
||||||
|
/* translators: 1: Anzahl Jahre, 2: Mindestanzahl für Vielschreiber */
|
||||||
|
esc_html__('Spalten zeigen die letzten %1$d Jahre. Als "verlorener Vielschreiber" gilt, wer früher mindestens %2$d Geschichten in einem Jahr hatte und seither so gut wie nichts mehr veröffentlicht.', 'wp-multi'),
|
||||||
|
count($column_years),
|
||||||
|
(int) apply_filters('wp_multi_timeline_prolific_min', 5)
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</p>
|
||||||
|
<?php
|
||||||
|
wpmt_admin_card_close();
|
||||||
|
|
||||||
|
wp_multi_render_year_comparison($base_url, $available_years, $timeline, $author_base_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vergleicht zwei Jahre und zeigt, bei welchen Autoren die Differenz entsteht.
|
||||||
|
*
|
||||||
|
* @param string $base_url Basis-URL der Seite.
|
||||||
|
* @param array $available_years Alle Jahre mit Beiträgen.
|
||||||
|
* @param array $timeline Zuordnung "Autor => [Jahr => Anzahl]".
|
||||||
|
* @param string $author_base_url Basis-URL der Autoren-Detailansicht.
|
||||||
|
*/
|
||||||
|
function wp_multi_render_year_comparison($base_url, $available_years, $timeline, $author_base_url) {
|
||||||
|
if (count($available_years) < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard: die beiden letzten abgeschlossenen Jahre
|
||||||
|
$default_to = $available_years[count($available_years) - 2];
|
||||||
|
$default_from = $available_years[count($available_years) - 3] ?? $available_years[0];
|
||||||
|
|
||||||
|
$from = isset($_GET['cmp_from']) ? (int) $_GET['cmp_from'] : $default_from;
|
||||||
|
$to = isset($_GET['cmp_to']) ? (int) $_GET['cmp_to'] : $default_to;
|
||||||
|
|
||||||
|
if (!in_array($from, $available_years, true)) {
|
||||||
|
$from = $default_from;
|
||||||
|
}
|
||||||
|
if (!in_array($to, $available_years, true)) {
|
||||||
|
$to = $default_to;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows = [];
|
||||||
|
$sum_from = 0;
|
||||||
|
$sum_to = 0;
|
||||||
|
|
||||||
|
foreach ($timeline as $name => $per_year) {
|
||||||
|
$count_from = isset($per_year[$from]) ? (int) $per_year[$from] : 0;
|
||||||
|
$count_to = isset($per_year[$to]) ? (int) $per_year[$to] : 0;
|
||||||
|
|
||||||
|
$sum_from += $count_from;
|
||||||
|
$sum_to += $count_to;
|
||||||
|
|
||||||
|
if ($count_from === $count_to) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows[] = [
|
||||||
|
'name' => $name,
|
||||||
|
'from' => $count_from,
|
||||||
|
'to' => $count_to,
|
||||||
|
'diff' => $count_to - $count_from,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Größte Rückgänge zuerst
|
||||||
|
usort($rows, function ($a, $b) {
|
||||||
|
if ($a['diff'] === $b['diff']) {
|
||||||
|
return strcasecmp($a['name'], $b['name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $a['diff'] - $b['diff'];
|
||||||
|
});
|
||||||
|
|
||||||
|
$compare_url = add_query_arg('tab', 'timeline', $base_url);
|
||||||
|
$total_diff = $sum_to - $sum_from;
|
||||||
|
|
||||||
|
wpmt_admin_card_open(__('Jahresvergleich', 'wp-multi'));
|
||||||
|
?>
|
||||||
|
<p class="wpm-muted">
|
||||||
|
<?php _e('Von:', 'wp-multi'); ?>
|
||||||
|
<?php foreach (array_reverse($available_years) as $year) : ?>
|
||||||
|
<a href="<?php echo esc_url(add_query_arg(['cmp_from' => $year, 'cmp_to' => $to], $compare_url)); ?>" class="wpm-filter-link<?php echo ($year === $from) ? ' wpm-filter-active' : ''; ?>">
|
||||||
|
<?php if ($year === $from) : ?><strong><?php endif; ?><?php echo esc_html($year); ?><?php if ($year === $from) : ?></strong><?php endif; ?>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</p>
|
||||||
|
<p class="wpm-muted">
|
||||||
|
<?php _e('Bis:', 'wp-multi'); ?>
|
||||||
|
<?php foreach (array_reverse($available_years) as $year) : ?>
|
||||||
|
<a href="<?php echo esc_url(add_query_arg(['cmp_from' => $from, 'cmp_to' => $year], $compare_url)); ?>" class="wpm-filter-link<?php echo ($year === $to) ? ' wpm-filter-active' : ''; ?>">
|
||||||
|
<?php if ($year === $to) : ?><strong><?php endif; ?><?php echo esc_html($year); ?><?php if ($year === $to) : ?></strong><?php endif; ?>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<?php
|
||||||
|
printf(
|
||||||
|
/* translators: 1: erstes Jahr, 2: Anzahl, 3: zweites Jahr, 4: Anzahl, 5: Differenz */
|
||||||
|
esc_html__('%1$d: %2$s Geschichten – %3$d: %4$s Geschichten – Differenz: %5$s', 'wp-multi'),
|
||||||
|
(int) $from,
|
||||||
|
esc_html(number_format_i18n($sum_from)),
|
||||||
|
(int) $to,
|
||||||
|
esc_html(number_format_i18n($sum_to)),
|
||||||
|
esc_html(($total_diff > 0 ? '+' : '') . number_format_i18n($total_diff))
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</p>
|
||||||
|
<div class="wpm-table-wrap">
|
||||||
|
<table class="wpm-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><?php _e('Autor', 'wp-multi'); ?></th>
|
||||||
|
<th><?php echo esc_html($from); ?></th>
|
||||||
|
<th><?php echo esc_html($to); ?></th>
|
||||||
|
<th><?php _e('Differenz', 'wp-multi'); ?></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if ($rows) : ?>
|
||||||
|
<?php foreach ($rows as $row) : ?>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<?php if (function_exists('wp_multi_get_guest_author_detail_url')) : ?>
|
||||||
|
<a href="<?php echo esc_url(wp_multi_get_guest_author_detail_url($author_base_url, $row['name'])); ?>"><?php echo esc_html($row['name']); ?></a>
|
||||||
|
<?php else : ?>
|
||||||
|
<?php echo esc_html($row['name']); ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td><?php echo esc_html(number_format_i18n($row['from'])); ?></td>
|
||||||
|
<td><?php echo esc_html(number_format_i18n($row['to'])); ?></td>
|
||||||
|
<td>
|
||||||
|
<?php if ($row['diff'] < 0) : ?>
|
||||||
|
<span class="wpm-badge wpm-badge--danger"><?php echo esc_html(number_format_i18n($row['diff'])); ?></span>
|
||||||
|
<?php else : ?>
|
||||||
|
<span class="wpm-badge wpm-badge--success">+<?php echo esc_html(number_format_i18n($row['diff'])); ?></span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<tr><td colspan="4"><?php _e('Kein Unterschied zwischen diesen Jahren.', 'wp-multi'); ?></td></tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<p class="wpm-muted"><?php _e('Gezählt werden nur Geschichten mit hinterlegtem Gast-Autor. Beiträge ohne dieses Feld tauchen in der Jahresstatistik auf, hier aber nicht.', 'wp-multi'); ?></p>
|
||||||
|
<?php
|
||||||
|
wpmt_admin_card_close();
|
||||||
|
}
|
||||||
+2
-1
@@ -3,7 +3,7 @@
|
|||||||
* 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.5
|
* Version: 3.6
|
||||||
* 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
|
||||||
@@ -93,6 +93,7 @@ $wp_multi_modules = array(
|
|||||||
'notify-telegram',
|
'notify-telegram',
|
||||||
'notify-dashboard',
|
'notify-dashboard',
|
||||||
'guest-authors',
|
'guest-authors',
|
||||||
|
'publication-stats',
|
||||||
'custom-text',
|
'custom-text',
|
||||||
'custom-admin-links',
|
'custom-admin-links',
|
||||||
'post-report',
|
'post-report',
|
||||||
|
|||||||
Reference in New Issue
Block a user