Upload via GUI (30 Dateien)

This commit is contained in:
2026-08-23 13:35:10 +00:00
parent 90f388f49c
commit 2b162e581f
2 changed files with 1973 additions and 144 deletions
+126 -19
View File
@@ -62,7 +62,8 @@ function wp_multi_track_user_activity($user_id, $action, $post_id = null) {
$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;
}
@@ -92,26 +93,93 @@ function wp_multi_comment_activity($comment_id) {
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() {
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);
if (is_admin() || !is_single() || is_feed()) {
return;
}
// 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');
/**
* 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 Rohe Analytics-Daten.
* @return array [WHERE-Fragment, Parameter]
*/
function wp_multi_fetch_raw_analytics($start_datetime = null, $end_datetime = null) {
global $wpdb;
function wp_multi_analytics_date_where($start_datetime = null, $end_datetime = null) {
if (!$start_datetime) {
$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;
}
$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 . "
$where
GROUP BY date, action, post_id, user_id, timestamp
GROUP BY date, action
ORDER BY date ASC";
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.
*
* @param array $results Rohe Analytics-Daten.
* @return array Verarbeitete Daten.
*/
function wp_multi_process_analytics_data($results) {
function wp_multi_process_analytics_data($results, $recent = null) {
$dates = [];
$comment_counts = [];
$view_counts = [];
@@ -184,7 +290,7 @@ function wp_multi_process_analytics_data($results) {
'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;
}
$results = wp_multi_fetch_raw_analytics($start_datetime, $end_datetime);
$data = wp_multi_process_analytics_data($results);
$totals = wp_multi_fetch_analytics_totals($start_datetime, $end_datetime);
$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);
return $data;
@@ -308,7 +415,7 @@ function wp_multi_display_user_analytics() {
<tbody>
<?php foreach ($results['data'] as $row) : ?>
<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>
<?php
+1815 -93
View File
File diff suppressed because it is too large Load Diff