Willkommen beim WP Wegerl.at 'Lesemodus' + Tastaturnavigation!
Entspanntes Lesen und spannende Artikel warten auf dich.
Entdecke unsere besten Beiträge und genieße den Lesemodus sowie die Tastaturbedienung.
WP Wegerl.at: Einzigartige Designs, optimiert für das Nutzererlebnis.
Visit Duration: Verweildauer, Tracking
smilies.4-user.de

WordPress – 'Visit Duration': Besucher-Verweildauer messen

Illustration (inspire-studio und Mooreemilyc) var. pixabay
Werbung

Der Classic-Editor: Vertraut und zuverlässig –
Ihr bewährter Begleiter.


Erleben Sie den Classic Editor neu!
(Bilder von pixelcreatures)


Viele Nutzer schätzen die vertraute Umgebung des Classic-Editors, die eine einfache und schnelle Bearbeitung ermöglicht.




Werbung

Mit dem Advanced Editor Tools auf das nächste Level –
Mehr Funktionen, mehr Möglichkeiten.


Classic Editor + Advanced Editor Tools
= Ihr Erfolgsrezept


Der Advanced Editor erweitert den Funktionsumfang des Classic-Editors und ermöglicht es, Inhalte noch effektiver zu bearbeiten.




Werbung

Einfach und intuitiv –
Der Classic-Editor für alle.


Classic Editor & Advanced Editor Tools
Erleben Sie es.


Der Classic-Editor zeichnet sich durch Stabilität und Zuverlässigkeit aus, was für professionellen Anwender von Bedeutung ist.




Werbung

Mehr schaffen in weniger Zeit –
Der Advanced Editor für kreative Köpfe.


Optimieren Sie Ihre Bearbeitung:
Advanced Editor Tools


Mit dem Advanced Editor können Designer und
Content Creatoren kreative Ideen umsetzten.





Die Verweildauer von Besuchern ist ein signifikanter Indikator, um das Nutzerverhalten auf einer Website besser zu verstehen. In diesem Beitrag wird eine einfache Methode vorgestellt, mit der die Verweildauer auf einer WordPress-Seite gemessen werden kann – ganz ohne Cookies oder eine separate Datenbanktabelle. Das Plug-in bietet eine DSGVO-konforme Lösung, die die Privatsphäre der Nutzer wahrt. Es stellt eine hervorragende Ergänzung zu den Statistiken von Statify dar, um das Nutzerverhalten effektiv zu analysieren und ein realistischen Bild zu erhalten.

Über ein Dashboard-Widget können Administratoren die Verweildauer der Besucher in Echtzeit sehen. Die Besuchsdaten werden automatisch aktualisiert, sodass jederzeit ein aktueller Überblick über die Nutzeraktivitäten gewährleistet ist. Ideal für alle, die eine schnelle und unkomplizierte Möglichkeit suchen, das Nutzerverhalten auf ihrer Seite zu verstehen, ohne gegen die Datenschutzrichtlinien zu verstoßen.

Statify-Optimierung für rationelles Tracking:

  1. IP-Ausschlusslogik für Statify (für Entwickler geeignet)
    Dieser Beitrag erklärt, wie Admin-IP-Adressen automatisch vom Tracking ausgeschlossen werden. So kann die eigene Website in allen Browsern getestet werden, ohne in die Besucherstatistik von Statify einzufließen.
  2. Effektives Tracking mit Statify: Zeitverzögerung + Scrolltiefe
    Hier geht es um die Erweiterung der Statify-Tracking-Funktionen, einschließlich der Möglichkeit, Zeitverzögerungen und Scrolltiefe zu messen, um tiefergehende Einblicke in das Nutzerverhalten zu erhalten.

Erweiterungen für effektives Tracking:

  1. Click & Bounce Counter und Statify: im Duo für effektives Tracking
    Eine Anleitung, wie die Kombination von Statify und dem Bounce Counter Plug-in zu einem leistungsstarken Tracking-System führt.
  2. Der Beitrag hier:
    Verweildauer der Erweiterung 'Visit Duration'
    Der Artikel zeigt, wie die Verweildauer von Besucher gemessen werden kann – ohne Cookies und ohne zusätzliche Datenbanktabellen.

 'Visit Duration': Verweildauer messen

Das Plug-in 'Visit Duration' ermöglicht es Website-Betreibern, die Verweildauer der Besucher auf ihrer Seite zu messen – und das ohne den Einsatz von Cookies oder einer separaten Datenbanktabelle. Die Lösung wurde mit dem Ziel entwickelt, datenschutzkonform gemäß der DSGVO zu arbeiten und gleichzeitig wertvolle Einblicke in das Nutzerverhalten zu liefern.

Mit diesem Plug-in können Administratoren über ein Dashboard-Widget die Verweildauer der Besucher in Echtzeit einsehen. Die Daten werden dynamisch aktualisiert, ohne dass eine manuelle Eingabe erforderlich ist. Dadurch wird jederzeit ein aktueller Überblick über die Aktivitäten auf der Seite gewährleistet.

Wichtige Merkmale des Plug-ins:

  • DSGVO-konform: Keine Verwendung von Cookies, keine Speicherung personenbezogener Daten – das Plug-in hält sich strikt an die Datenschutzrichtlinien.
  • Echtzeit-Überwachung: Das Dashboard-Widget zeigt die Verweildauer der Besucher live an und wird bei jedem Seitenaufruf automatisch aktualisiert und ein separater Button ist auch implementiert.
  • Einfache Integration: Die Implementierung ist unkompliziert und benötigt keine speziellen technischen Kenntnisse.
  • Keine zusätzliche Datenbanktabelle erforderlich: Alle relevanten Daten werden direkt in der Optionstabelle von WordPress gespeichert, was die Serverlast minimiert.

Verweildauer in WordPress tracken:
Eine einfache Lösung mit "Visit Duration"

  • WordPress-Multisite-Umgebung: Das Plug-in ist aktuell nicht für eine WordPress-Multisite-Umgebung ausgelegt. In einer Multisite-Installation müsste das Plug-in angepasst werden, um Optionen und Tracking korrekt für alle Sites zu verwalten. Das Plug-in kann auf der Hauptseite einer Multisite-Installation aktiviert und genutzt werden. Beachte jedoch, dass es nicht für die Verwendung auf einzelnen Seiten innerhalb eines Multisite-Netzwerks entwickelt wurde.
  • Dieses Plugin bietet keine umfangreiche Statistik, wie man sie von großen Tracking-Plug-ins kennt. Es liefert punktuell Einblicke darüber, wie die Besuche auf der Website verlaufen.

Plug-in 'Visit Duration'

Plug-in: visit-duration herunterladen und im Dashboard unter Plugins > Neues Plugin hinzufügen die Option Plugin hochladen wählen. Anschließend das Plug-in aktivieren. Es sind keine weiteren Einstellungen erforderlich, und das Widget wird im Dashboard angezeigt.

/wp-content/plugins/visit-duration/
├── visit-duration.php
└── bot-functions.php

Hier ist der derselbe Code wie des Plug-ins, für des Moments

  1. visit-duration.php
<?php
/*
* Plugin Name: Visit Duration
* Description: Ermöglicht das Messen der Verweildauer von Besuchern auf einer WordPress-Seite ohne Cookies und ohne separate Datenbanktabelle. DSGVO-konform.
* Version: 1.0.0
* Entwicklung: 20.11.24
* Author: Team WP Wegerl
* Author URI: https://wegerl.at/visit-duration/
* Text Domain: visit-duration

Die Funktion 'is_bot_or_spider' prüft anhand des User-Agents, ob es sich bei einem Besucher um einen Bot handelt. 
Diese Funktion nutzt Caching, um wiederholte Anfragen zu vermeiden und verbessert so die Performance.
*/

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}

// Am Anfang der Datei, um die Bot-Erkennungsfunktion zu laden
if ( file_exists( plugin_dir_path( __FILE__ ) . 'bot-functions.php' ) ) {
    require_once plugin_dir_path( __FILE__ ) . 'bot-functions.php';
} else {
    // Fehlerbehandlung, falls die Datei nicht gefunden wurde
    error_log('bot-functions.php wurde nicht gefunden.');
}

// Prüft, ob es sich um einen Bot handelt
$is_bot = is_bot_or_spider();

function start_visit_handler() {
    check_ajax_referer('your_nonce', 'security');

    // Die unique_id aus der POST-Anfrage holen
    $unique_id = isset($_POST['unique_id']) ? sanitize_text_field($_POST['unique_id']) : '';
    // SHA-256 Hash der unique_id erstellen
    $hashed_unique_id = hash('sha256', $unique_id);
    
    // Den Seitentitel aus der POST-Anfrage holen
    $page_title = isset($_POST['page_title']) ? sanitize_text_field($_POST['page_title']) : '';

    // Überprüfen, ob sowohl unique_id als auch page_title gesetzt sind
    if ($unique_id && $page_title) {
        global $wpdb;
        $table_name = $wpdb->prefix . 'visit_tracking';

        // Gehashten Wert in die Datenbank einfügen
        $wpdb->insert($table_name, array(
            'unique_id'   => $hashed_unique_id,  // Gehashte unique_id speichern
            'page_title'  => $page_title,
            'visit_time'  => current_time('mysql')
        ));
        
        wp_send_json_success('Besuch protokolliert');
    } else {
        wp_send_json_error('Ungültige Daten');
    }
}


// Stelle sicher, dass die Sitzung zu Beginn der Verarbeitung gestartet wird
function start_session_if_needed() {
    if (session_status() == PHP_SESSION_NONE) {
        session_start();
    }
}
add_action('init', 'start_session_if_needed');

// Besuchs-Tracking initialisieren
function start_visit_tracking() {
    // Den angemeldeten Admin und Bots ausschließen
    if (current_user_can('administrator') || is_bot_or_spider() || is_test_tool()) {
        return; // Frühzeitig abbrechen, wenn der angemeldete Benutzer ein Admin ist, sich um einen Bot oder Testtool handelt
    }

    if (session_status() == PHP_SESSION_NONE) {
        session_start();
    }

    if (!isset($_SESSION['visit_start_time'])) {
        $_SESSION['visit_start_time'] = time();
    }

    // Besuchsdaten abrufen und AJAX-Skript laden
    echo "<script>
    (function() {
        var ajaxUrl = '" . esc_url(admin_url('admin-ajax.php')) . "';
        if (!ajaxUrl) {
            console.error('AJAX-URL konnte nicht geladen werden.');
            return;
        }

        window.ajaxUrl = ajaxUrl;
        window.uniqueId = 'id-' + Math.random().toString(36).substr(2, 16);
        var isTabActive = true;

        // Besuch nur nach 3 Sekunden tracken
        setTimeout(function() {
            fetch(window.ajaxUrl + '?action=start_visit', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({ unique_id: window.uniqueId, page_title: document.title })
            }).catch(err => console.error('Fehler beim Start des Besuchs:', err));
        }, 3000);

        // Timeout-Überprüfung alle 30 Sekunden
        setInterval(function() {
            if (isTabActive) {
                fetch(window.ajaxUrl + '?action=check_visit_timeout', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'}
                }).then(response => response.json()).then(data => {
                    if (data.timeout_reached) {
                        console.log('Besuch beendet wegen Timeout.');
                    }
                }).catch(err => console.error('Fehler bei Timeout-Überprüfung:', err));
            }
        }, 30000);

        // Besuch beenden: Sichtbarkeit oder Schließen
        function sendEndVisit() {
            if (window.uniqueId && window.ajaxUrl) {
                const payload = JSON.stringify({
                    unique_id: window.uniqueId,
                    end_time: Date.now()
                });

                const beaconSuccess = navigator.sendBeacon(window.ajaxUrl + '?action=check_visit_timeout', payload);

                if (!beaconSuccess) {
                    const xhr = new XMLHttpRequest();
                    xhr.open('POST', window.ajaxUrl + '?action=check_visit_timeout', false); // Synchrone Anfrage
                    xhr.setRequestHeader('Content-Type', 'application/json');
                    xhr.send(payload);
                }
            }
        }

        // Sichtbarkeitswechsel überwachen
        document.addEventListener('visibilitychange', function() {
            if (document.visibilityState === 'hidden') {
                isTabActive = false;
                sendEndVisit();
            } else {
                isTabActive = true;
            }
        });

        // Besuch beim Schließen des Tabs oder Browsers beenden
        window.addEventListener('beforeunload', sendEndVisit);
    })();

// Safari spezifisch	
	document.addEventListener('DOMContentLoaded', function() {
    // Safari-Erkennung
    const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);

    var visitStartTime = localStorage.getItem('visit_start_time') || Date.now();
    var uniqueId = window.uniqueId || 'default_user';
    var ajaxUrl = window.ajaxUrl || '/wp-admin/admin-ajax.php';

    localStorage.setItem('visit_start_time', visitStartTime);

    if (isSafari) {
        console.log('Safari-Browser erkannt: Spezifische Anpassung aktiv.');

        function sendDataForSafari(startTime, endTime) {
            var data = {
                unique_id: uniqueId,
                start_time: startTime,
                end_time: endTime,
            };

            var xhr = new XMLHttpRequest();
            xhr.open('POST', ajaxUrl + '?action=update_visit_duration', true);
            xhr.setRequestHeader('Content-Type', 'application/json');
            xhr.send(JSON.stringify(data));

            xhr.onload = function() {
                if (xhr.status === 200) {
                    console.log('Safari-Spezifisch:', xhr.responseText);
                } else {
                    console.error('Safari Fehler:', xhr.statusText);
                }
            };
        }

        document.addEventListener('visibilitychange', function() {
            if (document.visibilityState === 'hidden') {
                sendDataForSafari(visitStartTime, Date.now());
            }
        });

        window.addEventListener('beforeunload', function() {
            sendDataForSafari(visitStartTime, Date.now());
        });

        setInterval(function() {
            sendDataForSafari(visitStartTime, Date.now());
        }, 30000);
    }
});	
    </script>";
}

// Bot-Erkennungsfunktion laden, falls noch nicht geladen
if (!function_exists('is_bot_or_spider')) {
    if (file_exists(plugin_dir_path(__FILE__) . 'bot-functions.php')) {
        require_once plugin_dir_path(__FILE__) . 'bot-functions.php';
    } else {
        error_log('bot-functions.php wurde nicht gefunden.');
    }
}

add_action('wp_footer', 'start_visit_tracking');

// Besuch beenden und Verweildauer speichern
function end_visit_tracking() {
    if (isset($_SESSION['visit_start_time'])) {
        $duration = time() - $_SESSION['visit_start_time'];
        update_option('last_visitor_duration', $duration);
        unset($_SESSION['visit_start_time']);
        error_log("Visit ended. Duration: " . $duration . " seconds.");
    }
}

// Prüft, ob die IP ausgeschlossen ist
if (!function_exists('is_ip_excluded')) {
    function is_ip_excluded($user_ip) {
        $excluded_ips = get_option('excluded_ips', array());
        return in_array($user_ip, $excluded_ips);
    }
}

// AJAX-Handler zur Speicherung der Startzeit
function start_visit() {
    $data = json_decode(file_get_contents('php://input'), true);
    $unique_id = sanitize_text_field($data['unique_id']);
    $page_title = strip_tags($data['page_title']);
    $start_time = time();

    $visits = get_option('current_visits', []);

    // Neuer Eintrag für jeden Seitenaufruf speichern
    $visits[$unique_id] = [
        'unique_id' => $unique_id,
        'page_title' => $page_title,
        'start_time' => $start_time
    ];

    // Besuche auf 25 Einträge begrenzen
    $max_visits = get_option('max_visits', 25);
if (count($visits) > $max_visits) {
    array_shift($visits);
}
    update_option('current_visits', $visits);
    wp_send_json_success();
}

add_action('wp_ajax_start_visit', 'start_visit');
add_action('wp_ajax_nopriv_start_visit', 'start_visit');

// Funktion zur Aktualisierung der Verweildauer
function update_visit_duration() {
    $data = json_decode(file_get_contents('php://input'), true);
    
    // Überprüfen, ob die erforderlichen Daten vorhanden sind
    if (!isset($data['unique_id']) || !isset($data['end_time'])) {
        wp_send_json_error(['message' => 'Fehlende Parameter']);
        return;
    }

    $unique_id = sanitize_text_field($data['unique_id']);
    $end_time = intval($data['end_time'] / 1000); // Zeitstempel konvertieren

    $visits = get_option('current_visits', []);
    
    if (isset($visits[$unique_id])) {
        $duration = $end_time - $visits[$unique_id]['start_time'];
        $visits[$unique_id]['duration'] = $duration;
        update_option('current_visits', $visits);
    }

    wp_send_json_success();
}

add_action('wp_ajax_update_visit_duration', 'update_visit_duration');
add_action('wp_ajax_nopriv_update_visit_duration', 'update_visit_duration');

// Widget zur Anzeige der Verweildauer
function add_visit_duration_dashboard_widget() {
    wp_add_dashboard_widget(
        'visit_duration_widget',
        'Visit Duration: Aktuelle Verweildauer der Besucher',
        'display_visit_duration_widget'
    );
}

add_action('wp_dashboard_setup', 'add_visit_duration_dashboard_widget');

// Widget für das Dashboard mit aktualisierten Besuchsdaten und Scrollfunktion
function display_visit_duration_widget() {
    $visits = get_option('current_visits', []);

    if (empty($visits)) {
        echo '<p>Keine aktuellen Besuchsdaten verfügbar.</p>';
        return;
    }

    // Besuche nach Startzeit sortieren (neueste oben)
    usort($visits, function($a, $b) {
        return $b['start_time'] - $a['start_time']; // Sortiert absteigend nach Startzeit
    });

    // Füge CSS hinzu, um den Scrollbalken nur bei Bedarf anzuzeigen
    echo '<style>
        /* Standardmäßig versteckter Scrollbalken, der nur bei Bedarf erscheint */
        #visit-duration-container {
            height: 360px;
            overflow-y: auto; /* Scrollbalken erscheint nur bei Bedarf */
            border: 1px solid #ddd;
        }

        /* Schmaler Scrollbalken für Webkit-basierte Browser */
        #visit-duration-container::-webkit-scrollbar {
            width: 4px; /* Schmaler Scrollbalken */
        }

        #visit-duration-container::-webkit-scrollbar-thumb {
            background-color: darkgray;
            border-radius: 10px;
        }

        #visit-duration-container::-webkit-scrollbar-track {
            background: #f1f1f1;
            border-radius: 10px;
        }
    </style>';

    // Scrollbarer Container für die Tabelle
    echo '<div id="visit-duration-container">';
    echo '<table id="visit-duration-table" style="width:100%; text-align:left;">';

    // <thead> mit Sticky-Header-Styling
    echo '<thead style="position: sticky; top: 0; background-color: #fff; z-index: 1;">';
    echo '<tr><th>Seiten-Titel</th><th>Verweildauer (Min:Sek)</th><th>Status</th></tr>';
    echo '</thead>';
    
    echo '<tbody>';

    foreach ($visits as $visit_data) {
        // Setze den Status basierend auf dem Vorhandensein der Verweildauer
        $status = isset($visit_data['duration']) ? 'Beendet' : 'Aktiv';

        // Berechne Minuten und Sekunden für die Verweildauer
        if (isset($visit_data['duration'])) {
            $minutes = floor($visit_data['duration'] / 60);
            $seconds = $visit_data['duration'] % 60;
            $formatted_duration = sprintf('%02d:%02d', $minutes, $seconds);
        } else {
            $formatted_duration = 'Noch aktiv';
        }

        // Setze die Hintergrundfarbe abhängig vom Status
        $row_color = ($status === 'Aktiv') ? 'rgba(255, 235, 59, 0.7)' : '#fff';

        echo '<tr style="background-color: ' . $row_color . ';">';
        echo '<td>' . esc_html($visit_data['page_title']) . '</td>';
        echo '<td>' . esc_html($formatted_duration) . '</td>';
        echo '<td>' . esc_html($status) . '</td>';
        echo '</tr>';
    }

    echo '</tbody>';
    echo '</table>';
    echo '</div>'; // Ende des scrollbaren Containers

    echo '<button id="reset-duration-btn" class="reset-button" style="margin: 15px 15px 0;">Tabelle zurücksetzen</button>';
    echo '<button id="update-duration-btn" class="update-button">Verweildauer aktualisieren</button>';
    ?>
    <script type="text/javascript">
	
	// "Update"-Button	
	document.getElementById('update-duration-btn').addEventListener('click', function() {
    jQuery.ajax({
        url: '<?php echo admin_url('admin-ajax.php'); ?>',
        type: 'POST',
        data: {
            action: 'update_all_visit_durations',
        },
        success: function(response) {
            if (response.success) {
                // Die Tabelle aktualisieren und die Zeilen mit den korrekten Hintergrundfarben
                var tableBody = jQuery('#visit-duration-table').find('tbody');
                tableBody.empty(); // Bestehende Zeilen löschen

                // Besucher nach Startzeit absteigend sortieren
                response.data.updated_visits.sort(function(a, b) {
                    return b.start_time - a.start_time; // Sortiert absteigend nach Startzeit
                });

                // Besucher in die Tabelle einfügen
                response.data.updated_visits.forEach(function(visit) {
                    var rowColor = (visit.status === "Aktiv") ? "#ffeb3b" : "#fff";
                    var formattedDuration = visit.formatted_duration || 'Noch aktiv';
                    tableBody.append(
                        '<tr style="background-color: ' + rowColor + '">' +
                        '<td>' + visit.page_title + '</td>' +
                        '<td>' + formattedDuration + '</td>' +
                        '<td>' + visit.status + '</td>' +
                        '</tr>'
                    );
                });
            } else {
                alert('Fehler bei der Aktualisierung der Verweildauer.');
            }
        },
        error: function() {
            alert('Fehler beim Aktualisieren der Verweildauer.');
        }
    });
});

    // "Reset"-Button mit Doppel-Klick-Mechanismus
    document.getElementById('reset-duration-btn').addEventListener('click', function(event) {
        event.preventDefault();

        if (this.dataset.clickedOnce === "true") {
            jQuery.ajax({
                url: '<?php echo admin_url('admin-ajax.php'); ?>',
                type: 'POST',
                data: {
                    action: 'reset_visit_duration',
                },
                success: function(response) {
                    if (response.success) {
                        // Die Tabelle zurücksetzen und nur die Kopfzeile anzeigen
                        jQuery('#visit-duration-table').html('<thead><tr><th>Seiten-Titel</th><th>Verweildauer (Min:Sek)</th><th>Status</th></tr></thead><tbody></tbody>');
                    } else {
                        alert('Fehler beim Zurücksetzen der Tabelle.');
                    }
                },
                error: function() {
                    alert('Fehler beim Zurücksetzen der Tabelle.');
                }
            });

            this.dataset.clickedOnce = "false";
            this.innerText = "Tabelle zurücksetzen";
        } else {
            this.dataset.clickedOnce = "true";
            this.innerText = "Zum Bestätigen erneut klicken";

            setTimeout(() => {
                this.dataset.clickedOnce = "false";
                this.innerText = "Tabelle zurücksetzen";
            }, 1500);
        }
    });
    </script>
<?php
}

// AJAX-Handler zur Aktualisierung der Verweildauer aller Besucher
function update_all_visit_durations() {
    $visits = get_option('current_visits', []);
    
    $updated_visits = [];

    foreach ($visits as $visit_id => $visit_data) {
        // Nur Besucher, bei denen die Verweildauer noch nicht festgelegt wurde (d.h., die noch aktiv sind)
        if (isset($visit_data['start_time']) && !isset($visit_data['duration'])) {
            // Berechne die Verweildauer für die aktiven Besuche
            $duration = time() - $visit_data['start_time']; // Verwende aktuelle Zeit
            $visit_data['duration'] = $duration;
            $visit_data['status'] = 'Aktiv'; // Status bleibt 'Aktiv', wenn noch keine Dauer
        } else {
            // Wenn die Verweildauer bereits festgelegt ist, wird der Status als 'Beendet' angezeigt
            $visit_data['status'] = 'Beendet';
        }

        // Berechne Minuten und Sekunden für jede Verweildauer
        if (isset($visit_data['duration'])) {
            $minutes = floor($visit_data['duration'] / 60);
            $seconds = $visit_data['duration'] % 60;
            $formatted_duration = sprintf('%02d:%02d', $minutes, $seconds);
            $visit_data['formatted_duration'] = $formatted_duration;
        } else {
            $visit_data['formatted_duration'] = 'Noch aktiv';
        }

        $updated_visits[] = $visit_data; // Füge die (aktualisierte) Besuchsdaten hinzu
    }

    // Besuchsdaten nach Startzeit absteigend sortieren
    usort($updated_visits, function($a, $b) {
        return $b['start_time'] - $a['start_time']; // Sortiert absteigend nach Startzeit
    });

    // Speichern der neuen Verweildauern
    update_option('current_visits', $visits); 

    // Sende die aktualisierten Daten mit der formatierten Dauer und dem Status zurück
    wp_send_json_success(['updated_visits' => $updated_visits]); 
}

add_action('wp_ajax_update_all_visit_durations', 'update_all_visit_durations');
add_action('wp_ajax_nopriv_update_all_visit_durations', 'update_all_visit_durations');

// Besuchsdaten zurücksetzen sehr funktionell
function reset_visit_duration() {
    delete_option('current_visits');
    update_option('current_visits', []);
    wp_cache_flush();
    wp_send_json_success();
}
add_action('wp_ajax_reset_visit_duration', 'reset_visit_duration');
add_action('wp_ajax_nopriv_reset_visit_duration', 'reset_visit_duration');

// JavaScript zur Timeout-Überprüfung und Beendigung beim Seitenverlassen oder bei Inaktivität, nur für nicht-Admins
// Option 1
// test Vorteil: Sitzungen bleiben nach automatischen Beenden bis zum Seitenverlassen im Hintergrund offen. 
// test Nachteil: Überlange Sitzungszeiten möglich, die nicht real sind.
add_action('wp_footer', function() {
    if ( !current_user_can('administrator') ) {  // Überprüft, ob der aktuelle Benutzer kein Administrator ist
        echo "<script>
            // Funktionsblock zur Überwachung der Inaktivität
            let inactivityTime = function() {
                let timeout;

                function resetTimer() {
                    clearTimeout(timeout);
                    timeout = setTimeout(endSessionDueToInactivity, 5 * 60 * 1000); // 5 Minuten Inaktivität
                }

                function endSessionDueToInactivity() {
                    if (window.uniqueId && window.ajaxUrl) {
                        navigator.sendBeacon(window.ajaxUrl + '?action=update_visit_duration', JSON.stringify({
                            unique_id: window.uniqueId,
                            end_time: Date.now()
                        }));
                        console.log('Besuch beendet wegen Inaktivität.');
                    }
                }

                // Events für Maus- und Tastaturaktivität zur Reaktivierung des Timers
                document.onload = resetTimer;
                document.onmousemove = resetTimer;
                document.onkeypress = resetTimer;
                document.onscroll = resetTimer;
            };

            inactivityTime();

            // Besuch beim Schließen des Tabs oder Browsers beenden
            window.addEventListener('beforeunload', function() {
                if (window.uniqueId && window.ajaxUrl) {
                    navigator.sendBeacon(window.ajaxUrl + '?action=update_visit_duration', JSON.stringify({
                        unique_id: window.uniqueId,
                        end_time: Date.now()
                    }));
                    console.log('Daten erfolgreich gesendet: Tab oder Browser geschlossen.');
                }
            });
        </script>";
    }
});

// JavaScript zur Timeout-Überprüfung und Beendigung beim Seitenverlassen oder bei Inaktivität, nur für nicht-Admins.
// Option 2:
// test Vorteil: Sitzungen werden endgültig nach Timeout abgeschlossen, keine überlangen Zeiten. 
// test Nachteil: Nachträgliche Aktionen können nicht mehr hinzugefügt werden.
/*add_action('wp_footer', function() {
    if ( !current_user_can('administrator') ) {  // Überprüft, ob der aktuelle Benutzer kein Administrator ist
        echo "<script>
            let timeout;
            let sessionEnded = false; // Flag, um den Status der Sitzung zu verfolgen

            function resetTimer() {
                clearTimeout(timeout);
                timeout = setTimeout(endSessionDueToInactivity, 5 * 60 * 1000); // 5 Minuten Inaktivität
            }

            function endSessionDueToInactivity() {
                if (!sessionEnded) { // Sitzung nur einmal als beendet markieren
                    sessionEnded = true;
                    console.log('Besuch beendet wegen Inaktivität.');
                    sendSessionUpdate();
                }
            }

            function sendSessionUpdate() {
                if (window.uniqueId && window.ajaxUrl) {
                    navigator.sendBeacon(window.ajaxUrl + '?action=update_visit_duration', JSON.stringify({
                        unique_id: window.uniqueId,
                        end_time: Date.now()
                    }));
                }
            }

            function handlePageNavigation() {
                // Sitzung vor dem Verlassen der Seite sauber beenden
                if (!sessionEnded) {
                    console.log('Seitenwechsel erkannt, Sitzung wird beendet.');
                    sendSessionUpdate();
                    sessionEnded = true; // Markiere Sitzung als beendet
                }
            }

            // Benutzeraktivität überwachen
            document.onmousemove = resetTimer;
            document.onkeypress = resetTimer;
            document.onscroll = resetTimer;

            // Besuch beim Schließen des Tabs oder bei internem Navigieren beenden
            window.addEventListener('beforeunload', handlePageNavigation);
            window.addEventListener('unload', handlePageNavigation);

            // Timer starten, sobald die Seite geladen wird
            resetTimer();
        </script>";
    }
});*/
  • Die Anzahl der angezeigten Besucher ist auf 25 begrenzt, sodass nur die letzten 25 Besucher angezeigt werden. Möchte man diese Zahl erhöhen, kann man den Wert an der Stelle "// Besuche auf 25 Einträge begrenzen" im Code anpassen. Weitere Anpassungen sind möglich und unter Beschreibung des Codes erklärlich.

Die Grenze von 25 Besuchern bietet eine gute Balance zwischen Übersichtlichkeit und Performance, da sie eine schnelle Anzeige der letzten Besucher ermöglicht, ohne die Benutzeroberfläche zu überlasten. Bei Bedarf kann diese Zahl erhöht werden, jedoch sollte darauf geachtet werden, dass die Performance nicht negativ beeinflusst wird, insbesondere bei größeren Besucherzahlen. Werte im Bereich von 30 bis 50 Besuchern sind möglicherweise ebenfalls geeignet, solange die Benutzeroberfläche übersichtlich bleibt und keine merklichen Verzögerungen auftreten.

  1. bot-functions.php
<?php
/**
 * Erkennung von Bots, Spidern und Testtools basierend auf dem User-Agent.
 *
 * Diese Funktion überprüft, ob der aktuelle Benutzeragent (User-Agent) mit einem bekannten Bot- oder Spider-Identifikator übereinstimmt.
 * Die Funktion nutzt Caching, um wiederholte Anfragen innerhalb eines bestimmten Zeitrahmens zu vermeiden.
 * Die Ergebnisse werden für 12 Stunden gespeichert, um unnötige Bot-Überprüfungen zu minimieren.
 *
 * Wenn der Benutzeragent mit einem bekannten Bot übereinstimmt, wird `true` zurückgegeben,
 * andernfalls `false`. Das Ergebnis wird auch in einem transienten Cache für 12 Stunden gespeichert,
 * um die Performance zu verbessern.
 *
 * @since 1.0.0
 * @return bool True, wenn es sich um einen Bot handelt, sonst False.
 */
if (!function_exists('is_bot_or_spider')) {
    function is_bot_or_spider() {
        // Cache-Schlüssel auf Basis der IP und des User-Agents erstellen
        $cache_key = 'is_bot_' . md5($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']);
        $cached_result = get_transient($cache_key);
        
        if ($cached_result !== false) {
            return $cached_result;
        }

        $user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
        $bots = [
            'googlebot', 'bingbot', 'slurp', 'duckduckbot', 'baidu', 'yandex',
            'sogou', 'exabot', 'facebook', 'twitter', 'linkedin', 'pinterest',
            'msnbot', 'bot', 'crawl', 'crawler', 'spider', 'ia_archiver',
            'curl', 'fetch', 'python', 'wget', 'monitor', 'botcheck',
            'crawlerbot', 'webcrawler', 'robozilla', 'mj12bot', 
        ];

        $pattern = '/(' . implode('|', $bots) . ')/i';

        if (preg_match($pattern, $user_agent)) {
            set_transient($cache_key, true, 12 * HOUR_IN_SECONDS);
            return true;
        }

        set_transient($cache_key, false, 12 * HOUR_IN_SECONDS);
        return false;
    }
}

function is_test_tool() {
    // User-Agent prüfen
    $user_agent = strtolower($_SERVER['HTTP_USER_AGENT'] ?? '');
    $test_tools = ['lighthouse', 'pagespeed', 'gtmetrix', 'webpagetest', 'chrome-lighthouse', 'pingdom', 'uptimerobot', 'newrelic', 'siteimprove'];
    
    // Weitere Header analysieren
    $is_test_tool = false;
    
    // 1. Prüfen, ob der User-Agent eines bekannten Tools entspricht
    foreach ($test_tools as $tool) {
        if (strpos($user_agent, $tool) !== false) {
            $is_test_tool = true;
            break;
        }
    }

    // 2. Zusätzliche Header prüfen
    $special_headers = ['x-lighthouse-request', 'chrome-proxy'];
    foreach ($special_headers as $header) {
        if (isset($_SERVER[$header])) {
            $is_test_tool = true;
            break;
        }
    }

    // Ergebnis zurückgeben
    return $is_test_tool;
}

Beschreibung des Plug-ins

Das Plug-in wurde entwickelt, um die Verweildauer von Besuchern auf einer WordPress-Seite zu erfassen – DSGVO-konform, ohne Cookies und ohne separate Datenbanktabellen.

Funktionen des Plug-ins

  1. Bot- und Crawler-Erkennung
    • Bots (z. B. Suchmaschinen-Crawler), Testtools und Admin-Benutzer werden vom Tracking ausgeschlossen.
    • Der Tracking-Mechanismus wird nur bei echten Nutzern aktiviert.
  2. Verweildauer-Erfassung
    • Startzeitaufzeichnung: Sobald die Seite geladen wird, wird die Startzeit einer Sitzung erfasst.
    • Automatisierte Updates: Alle 30 Sekunden überprüft das Plugin die Aktivität des Besuchers.
    • Endzeit-Aufzeichnung: Beim Schließen des Tabs oder Inaktivität wird die Sitzung abgeschlossen.
  3. Anpassung für Safari & Inkognito-Modus
    • Spezieller Mechanismus für Safari, um Probleme mit beforeunload zu umgehen.
    • Funktioniert auch zuverlässig im Inkognito-Modus und bei eingeschränkter Browserunterstützung.
  4. Timeout- und Inaktivitäts-Handling
    • Timeout nach 5 Minuten Inaktivität.
    • Option zur Beendigung oder Fortsetzung der Sitzung bei Reaktivierung nach Timeout.
  5. Keine Cookies oder persönliche Daten
    • Keine Speicherung von IP-Adressen oder personenbezogenen Daten. Stattdessen wird eine anonymisierte, gehashte unique_id verwendet, um jeden Besucher zu identifizieren.
    • Der Hashwert wird in der Datenbank gespeichert, wodurch eine direkte Rückverfolgbarkeit des Nutzers ausgeschlossen wird.
    • Daten werden nur temporär in der Session oder lokal gespeichert.
  6. Dashboard-Widget
    • Zeigt die aktuellen Besucher und deren Verweildauer in Echtzeit an.
    • Sortierung der Sitzungen nach Startzeit (neueste zuerst).
    • Interaktive Elemente:
      • Aktualisieren: Zeigt die aktuellsten Sitzungsdaten an.
      • Zurücksetzen: Setzt die Besucher-Tabelle zurück.

Spezielle Anpassungen für Browser

  • Safari-Support:
    • Das Plugin verwendet localStorage, um Sitzungsdaten zu speichern, da Safari beforeunload und sendBeacon oft blockiert.
    • Spezifische Funktionen senden regelmäßig Sitzungsdaten, um diese auch bei Safari zuverlässig zu erfassen.
  • Inkognito-Modus:
    • Das Plugin funktioniert auch im Inkognito-Modus, da keine Cookies und nur temporäre Browser-Speicher genutzt werden.

Beispielablauf einer Sitzung

  1. Sitzungseröffnung
    • Nach 3 Sekunden Aktivität wird die Sitzung gestartet.
  2. Aktivitätsüberwachung
    • Alle 30 Sekunden wird die Sitzung überprüft und aktualisiert.
  3. Inaktivität und Beendigung
    • Nach 5 Minuten Inaktivität wird die Sitzung automatisch beendet.
    • Beim Schließen des Tabs oder Browsers wird die Verweildauer sofort gespeichert.

Technische Highlights

  • Verwendung von fetch und sendBeacon, um Sitzungsdaten auch bei Tab-Schließung sicher zu übertragen.
  • Safari-spezifische Optimierungen durch localStorage und regelmäßiges Senden der Daten.
  • Flexible Konfigurationsoptionen zur Timeout-Handhabung.
Weitere technische Details:
  1. Initialisierung des Besuchs-Trackings:
    • Die Funktion start_visit_tracking() wird durch den wp_footer-Hook in den Footer jeder Seite eingebunden.
    • Sie erfasst die IP-Adresse des Besuchers ($user_ip) und prüft, ob dieser Besucher ein Bot oder Admin ist. Falls ja, wird das Tracking abgebrochen.
    • Wenn keine Sitzung aktiv ist, wird eine neue Sitzung gestartet (session_start()), und es wird überprüft, ob bereits eine Startzeit für den Besuch gesetzt wurde. Wenn nicht, wird die aktuelle Zeit als Startzeit gespeichert.
    • Ein JavaScript-Skript wird im Footer eingebunden, das beim Laden der Seite eine eindeutige ID für den Besuch erzeugt und die Startzeit des Besuchs über AJAX an den Server sendet.
  2. Überprüfung des Besuchs-Timeouts:
    • Im JavaScript wird alle 30 Sekunden eine Anfrage an den Server gesendet, um zu prüfen, ob das Besuchs-Timeout erreicht wurde. Dieser Wert kann auch angepasst werden.
      • Die 30-Sekunden-Prüfung stellt grundsätzlich einen guten Kompromiss zwischen einer angemessenen Überprüfungsfrequenz und der Vermeidung zu hoher Serverlast dar. Eine Reduzierung der Häufigkeit könnte die Serverlast zwar weiter senken, allerdings könnte dies auch dazu führen, dass der Timeout später erkannt wird und die Präzision der Benutzererkennung etwas abnimmt, insbesondere wenn eine schnelle und zuverlässige Timeout-Erkennung angestrebt wird.
    • Falls das Timeout erreicht ist (90 Minuten in diesem Fall), wird im Frontend eine Meldung angezeigt, und der Besuch wird als beendet markiert. Dieser Wert kann auch angepasst werden. 

Das Timeout (90 Minuten) ist im Code nicht mehr enthalten. Daher ist die 30-Sekunden-Beschränkung nicht mehr relevant und kann entfernt werden.

  1. Besuch beenden und Verweildauer speichern:
    • Die Funktion end_visit_tracking() wird aufgerufen, wenn der Besuch abgeschlossen ist. Sie berechnet die Verweildauer und speichert diese als Option in WordPress (last_visitor_duration). Die Startzeit des Besuchs wird dann aus der Sitzung entfernt.
    • Dies ermöglicht die Speicherung der Verweildauer für spätere Auswertungen.
  2. Timeout-Überprüfung im Backend (AJAX-Handler):
    • Die Funktion check_visit_timeout() wird durch AJAX-Anfragen aufgerufen, um zu prüfen, ob das Besuchs-Timeout überschritten wurde. Wenn ja, wird der Besuch als beendet markiert und die Besuchsdaten im Backend aktualisiert.
    • Wenn das Timeout erreicht ist, wird der Status des Besuchs auf "Beendet" gesetzt und die Verweildauer wird berechnet und gespeichert.
  3. Ausschluss von IPs und Bots:
    • Zwei Funktionen (is_ip_excluded() und is_bot_or_spider()) werden verwendet, um Besucher anhand ihrer IP-Adresse oder durch eine Bot-Detektion aus dem Tracking auszuschließen.
    • Diese Funktionen prüfen, ob die IP-Adresse in einer Liste von ausgeschlossenen IPs enthalten ist oder ob der User-Agent des Besuchers auf bekannte Bots hinweist.
  4. Verarbeitung der Besuchsdaten:
    • Mit der Funktion start_visit() werden Besuchsdaten beim Seitenaufruf gespeichert. Eine eindeutige ID für den Besuch sowie der Titel der Seite werden zusammen mit der Startzeit in einer Option (current_visits) abgelegt.
    • Diese Funktion stellt sicher, dass nur eine begrenzte Anzahl von 25 Besuchsdaten gleichzeitig gespeichert wird. Wird diese Zahl überschritten, wird der älteste Besuch gelöscht, um Platz für neue Daten zu schaffen.
    • Der Wert für die maximale Anzahl der gespeicherten Besucher ist auf 25 festgelegt. Dieser Wert kann angepasst werden, indem man den Wert an der Stelle // Besuche auf 25 Einträge begrenzen im Code ändert.
  5. Update der Verweildauer:
    • Die Funktion update_visit_duration() aktualisiert die Verweildauer eines Besuchs, indem sie den Endzeitpunkt des Besuchs erfasst und die Differenz zur Startzeit berechnet.
    • Falls keine Verweildauer vorhanden ist, wird der Besuch als "Aktiv" markiert.
  6. Anzeige der Besuchsdaten im Dashboard:
    • Über das WordPress-Dashboard wird ein Widget mit der Funktion add_visit_duration_dashboard_widget() erstellt, das die Besuchsdaten anzeigt.
    • Im Widget werden die Besucher nach ihrer Startzeit sortiert, und es wird die Verweildauer in Minuten und Sekunden sowie der Status des Besuchs (aktiv oder beendet) angezeigt.
    • Ein scrollbarer Bereich zeigt die Besuchsdaten, und der Status wird farblich hervorgehoben: Aktive Besuche werden gelb markiert.
  7. JavaScript für die Interaktivität:
    • Der Update-Button aktualisiert die Besuchsdaten, indem alle aktiven Besuchsdaten überprüft und in die Tabelle eingefügt werden.
    • Der Reset-Button ermöglicht das Zurücksetzen der Besuchsdaten im Widget, indem alle Besuchsdaten gelöscht werden.
  8. Speicherung und Anzeige von Besuchsdaten:
    • Wenn ein Besucher den Browser schließt (oder die Seite verlässt), wird die Verweildauer durch die beforeunload-Ereignisbehandlung erfasst und an den Server gesendet.
  9. Verwaltung der Besuchsdaten im Backend:
    • Die Funktion update_all_visit_durations() aktualisiert die Verweildauer aller aktiven Besucher. Dies erfolgt regelmäßig oder auf Anfrage, um sicherzustellen, dass die Daten im Dashboard immer aktuell sind.
  10. Zurücksetzen der Besuchsdaten:
    • Die Funktion reset_visit_duration() löscht alle gespeicherten Besuchsdaten, sowohl im Frontend als auch im Backend.

Weitere Erwägungen:

Eine separate Datenbanktabelle wäre eventuell sinnvoll.  Zudem wäre eine vernünftige Strukturierung zur besseren Übersicht gut:  

/wp-content/plugins/visit-duration/
├── visit-duration.php # Haupt-Plugin-Datei
├── bot-functions.php # Funktionen für Bot-Handling
├── script.js # JavaScript-Datei
└── style.css # CSS-Datei

Oder:

/wp-content/plugins/visit-duration/
├── visit-duration.php # Haupt-Plugin-Datei
├── bot-functions.php # Funktionen für Bot-Handling
├── assets/
│ ├── js/
│ │ └── script.js # JavaScript-Datei für das Plugin
│ └── css/
│ └── style.css # CSS-Datei für das Plugin
└── includes/
└── helper-functions.php # Hilfsfunktionen für das Plugin

DSGVO-Konformität

  • Keine Speicherung von personenbezogenen Daten.
  • Verzicht auf Cookies und IP-Adressen.
  • Alle Daten werden ausschließlich für die aktuelle Sitzung verarbeitet und nicht langfristig gespeichert.

Verweildauer im Blick –
für eine bessere Analyse, ohne Daten zu sammeln!

Hinweise zur Zähler-Funktionalität 'Visit Duration'

Bei der Implementierung von 'Visit Duration, gibt es grundsätzliche Punkte zu beachten, um eine zuverlässige Funktionalität sicherzustellen. Im Folgenden werden die Aspekte behandelt, die zu berücksichtigen sind, um eine fehlerfreie und stabile Zählerfunktion zu gewährleisten.

Startseite und die statische Seite  konsistent trackbar

Im Zusammenhang mit dem Tracking kann der folgende Code integriert werden, damit der Titel der Startseite und der statischen Seite beim Laden der Seite dynamisch geändert wird. Dadurch wird sichergestellt, dass beim Tracking diese Seiten mit einem spezifischen Titel erfasst werden.

Die JavaScript-Anweisungen document.title = 'Startseite …' und document.title = 'Statische Seite …' sollten entsprechend angepasst werden, um die gewünschten Titel für diese Seiten zu setzen. So erhält die Startseite sowie die statische Seite einen eindeutigen Titel, was die Nachverfolgbarkeit und Auswertung im Tracking-System erleichtert.

functions.php

/* --- Titel für Startseite und Beitragsseite für den Tracker definieren --- */

function set_custom_title_for_pages() {
    // JavaScript-Code je nach Seite dynamisch einfügen
    if (is_front_page()) {
        echo "<script>
            // Setze den Titel für die Startseite
            document.title = 'Startseite von WP Wegerl'; // Beispiel-Titel für die Startseite
        </script>";
    } elseif (is_home()) {
        echo "<script>
            // Setze den Titel für die Beitragsseite
            document.title = 'Beitrags-Blogseite'; // Beispiel-Titel für die Blogseite
        </script>";
    }
}
add_action('wp_footer', 'set_custom_title_for_pages');

/* - Ende Titel für Startseite und Beitragsseite - */
  • Der Titel der Startseite und der statischen Seite wird durch den Code dynamisch gesetzt, was es ermöglicht, beide Seiten korrekt zu tracken.
  • Dies trägt dazu bei, den Titel der Seiten bei der Erfassung der Besuchsdaten festzulegen und eine präzise Verweildauer zu messen.

Dieser kleine Code sorgt also dafür, dass die Startseite im Kontext des Besuchs-Trackings klar identifizierbar ist.

Weiterer Nutzen:

  • SEO: Der benutzerdefinierte Titel hilft, die Startseite eindeutig zu kennzeichnen, was für Suchmaschinen von Vorteil sein kann, da der Titel dann gezielt für diese Seite optimiert werden kann.
  • Benutzerfreundlichkeit: Falls der Titel der Startseite von Belang für die Identifikation der Seite ist (zum Beispiel „Startseite von [Website-Name]“), sorgt dieser Code dafür, dass dies auch im Browser-Tab korrekt angezeigt wird.

Aktualisierung des Dashboards nach Inaktivität

Wenn man nach längerer Zeit zum Dashboard zurückkehrt, kann es sein, dass die Aktualisierung nicht sofort funktioniert und ein Neuladen der Seite erforderlich ist. Dies ist technisch bedingt, da das Dashboard in der Regel auf AJAX-basierte Datenabfragen angewiesen ist, die eine gewisse Lebensdauer haben. Nach einer längeren Inaktivität oder einem Timeout der Sitzung können diese Abfragen nicht mehr die aktuellen Daten liefern. Ein Neuladen der Seite sorgt dafür, dass die Verbindung zu den Serverressourcen und den neuesten Daten neu hergestellt wird.

Beenden des Trackings beim Schließen des Browsers zs. Tabs

Es kann vorkommen, dass beim Schließen des Browsers, einschließlich des geöffneten Tabs, das Tracking nicht korrekt abgebrochen wird. In solchen Fällen kann es passieren, dass das Tracking fortgeführt wird und sogar über die eingestellten 90 Minuten hinausgeht. Das wurde in Entwicklung Augenfällig und dürfte der aktuellen Version weitgehend ausgemerzt sein, kann aber wieder mal vorkommen.

Normalerweise würde man erwarten, dass beim Schließen eines Browsers oder Tabs das Tracking automatisch beendet wird – das ist schließlich der Moment, in dem der Nutzer die Seite verlässt. Aber in der Praxis ist das nicht ganz so einfach, besonders wenn es darum geht, Daten zuverlässig zu senden.

Das wurde in Entwicklung Augenfällig und dürfte der aktuellen Version weitgehend ausgemerzt sein, kann aber wieder mal vorkommen.

In vielen modernen Browsern gibt es Einschränkungen, wie Ereignisse wie beforeunload verarbeitet werden. Das bedeutet, dass beim Schließen eines Tabs oder Browsers nicht immer sichergestellt ist, dass eine Anfrage, wie etwa zum Beenden des Besuchs, tatsächlich gesendet wird. Dies liegt daran, dass der Browser die Seite möglicherweise sofort schließt, ohne der Anfrage ausreichend Zeit zu geben.

Warum funktioniert das nicht immer?

  1. Abgebrochene Requests: Wenn ein Browser-Tab geschlossen wird, wird oft auch die ausstehende Anfrage abgebrochen. Standardmethoden wie fetch() reichen dann nicht aus, um die Anfrage zuverlässig zu senden.
  2. Browser-Beschränkungen: Moderne Browser haben Mechanismen eingebaut, die verhindern, dass eine Webseite beim Verlassen des Tabs unnötige Prozesse blockiert oder verzögert. Das bedeutet, dass viele Funktionen (wie das Senden von Daten zum Server) in diesem Moment nicht immer zuverlässig durchgeführt werden.

Die Lösung: navigator.sendBeacon() Eine stabilere Lösung in solchen Fällen ist die Verwendung von navigator.sendBeacon(). Diese Methode ist speziell dafür konzipiert, Daten auch dann zu senden, wenn die Seite oder der Tab geschlossen wird. Der Browser garantiert, dass die Anfrage auch dann gesendet wird, wenn der Nutzer die Seite schließt oder einen anderen Tab öffnet – und das ohne Verzögerungen oder Blockierungen.

Im Vergleich zu normalen Methoden wie fetch() funktioniert sendBeacon() zuverlässiger und stellt sicher, dass wir beim Verlassen der Seite keine wichtigen Tracking-Daten verlieren. Damit sollte das Besuchstracking sauber abgeschlossen werden, selbst wenn der Nutzer die Seite abrupt verlässt.

Datenbanktabelle 'wp_options'

Hinweis: Die Aufrufe befinden sich in der Datenbank unter ‚Options‘ (wp_options).

Siehe auch hier In der Datenbank …

Dem Reiter SQL, der SELECT-Befehl:

SELECT option_value FROM wp_options WHERE option_name = 'current_visits';

… ruft den gesamten Inhalt von option_value für current_visits ab. Das bedeutet:

  • Alle gespeicherten Besuchsdaten: Wenn das Plug-in neue Besuchsdaten hinzufügt oder aktualisiert, werden sie alle unter dem option_name "current_visits" in der option_value-Spalte abgelegt.
  • Datenformat: Da WordPress hier Arrays oder Objekte als serialisierte Zeichenketten speichert, wird alles in einem einzigen option_value-Eintrag zusammengefasst.

Der gesamte Datensatz für "current_visits" wird in einem einzigen Datenbankeintrag gespeichert. Die get_option('current_visits')-Funktion holt diesen Eintrag und wandelt ihn in das ursprüngliche Array um, sodass das Plug-in direkt auf die strukturierten Daten zugreifen kann.

Falls das Plugin nicht mehr verwendet wird, kann der oben genannte Eintrag manuell aus der Datenbank gelöscht werden. Alternativ kann folgender Code in die Datei eingefügt werden, um die Option automatisch beim Deaktivieren des Plugins zu entfernen.

Nicht getestet:

// Hook for plugin deactivation
register_deactivation_hook(__FILE__, 'visit_duration_deactivate');

// Function to delete 'current_visits' option on deactivation
function visit_duration_deactivate() {
    delete_option('current_visits');
}

Tracking im Sprintmodus: Warum der Code nicht mitkommt

Der Code ist nicht dafür konzipiert, Sitzungen mit schnellen, aufeinanderfolgenden Klicks, wie sie in Testszenarien auftreten können, vollständig zu erfassen – selbst wenn diese außerhalb der festgelegten 3-Sekunden-Schwelle liegen (Besuchstracking startet erst nach 3 Sekunden).

Von Rennmäusen und Webseiten:
Klicks wie Käsefallen – Tracking,
das sich im Mauseloch versteckt!

Dabei ist zu berücksichtigen, dass Testszenarien oft anders mit dem Tracking-Skript interagieren als ein typischer Nutzer. Besonders bei raschen Klickfolgen kann es vorkommen, dass der Aufruf zum Beenden einer Seite nicht rechtzeitig verarbeitet wird, bevor die nächste Anfrage gestellt wird. Solche Fälle sind im gewöhnlichen Nutzerverhalten selten, können jedoch in Testsituationen auftreten.

Zusammenfassend:  Kommen schnelle Klickfolgen ins Spiel, bleibt der Beendigungsaufruf manchmal "hängen". Das bedeutet, die Zeit des vorherigen Seitenbesuchs wird nicht korrekt abgeschlossen, da der nächste Seitenaufruf die Verarbeitung unterbricht.


wp wegerl.at

Der Beitrag wurde mit fachlicher Unterstützung erstellt.


Aktualisiert im Jahr 2024 November