diff --git a/includes/admin-menu.php b/includes/admin-menu.php index e16522e..87a31d7 100644 --- a/includes/admin-menu.php +++ b/includes/admin-menu.php @@ -48,6 +48,7 @@ function wp_multi_register_admin_menus() { // 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, __('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, __('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'); diff --git a/includes/publication-stats.php b/includes/publication-stats.php new file mode 100644 index 0000000..ba12f7f --- /dev/null +++ b/includes/publication-stats.php @@ -0,0 +1,696 @@ + __('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') + ); + ?> +
+ + + + + + + + +
++ +
+| + | + |
|---|---|
| get_month($month)); ?> | ++ + + + 0 + + | +
+ +
+| + | + | + |
|---|---|---|
| + + + + | ++ | + —'; + } else { + $diff = $total - $totals_by_year[$year - 1]; + $sign = $diff > 0 ? '+' : ''; + echo '' . esc_html($sign . number_format_i18n($diff)) . ''; + } + ?> + | +
' . esc_html__('Noch keine Daten für eine Zeitlinie vorhanden.', 'wp-multi') . '
'; + 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')); + ?> ++ + + + + + + $label) : ?> + | + + + () + + + +
+ ++ +
+ [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')); + ?> ++ + + + + + +
++ + + + + + +
++ 0 ? '+' : '') . number_format_i18n($total_diff)) + ); + ?> +
+ + +