14.01.2006

So nett und praktisch das WP-Plugin WP-ShortStat auch ist, selbst die neueste Version 1.3 ist nicht frei von Fehlern - und diese sind überaus lästig.

Das beginnt damit, dass die extrahierten Suchbegriffe casesensitiv abgespeichert werden - vollkommener Blödsinn, denn Suchmaschinen ist es herzlich egal, wie man es mit der Gross/Kleinschreibung bei der Eingabe der Suchbegriffe hält. Folglich ist es erste Hoheitspflicht, dafür zu sorgen, dass das Plugin die Suchbegriffe in einer definierten Schreibweise sichert und abfragt - idealerweise in Kleinschreibung, wie es in URLs in der Regel ja auch üblich ist.

In der Funktion sniffKeywords() ist also eine Codezeile zu ergänzen, und zwar wie folgt:


if (isset($searchterms) && !empty($searchterms)) {
  $searchterms = strtolower($searchterms);
  // Remove BINARY from the SELECT statement for a case-insensitive comparison

Nach Zeile 193 ist also die Sicherstellung der Kleinschreibweise einzubinden.

Beim Auslesen der Keywords darf die Schreibweise dann natürlich auch nicht mehr interessieren. Wegen der Abwärtskompatibilität mit den mit älteren Versionen gesammelten Daten ergänze man daher kurzerhand die SQL-Abfrage in der Funktion getKeywords():


function getKeywords() {
        global $wpdb;
        $query = "SELECT LOWER(searchterms) AS s, SUM(count) AS c
                          FROM $this->table_search
                          GROUP BY s
                          ORDER BY c DESC
                          LIMIT 0,36";
        
        if ($results = $wpdb->get_results($query)) {
                $ul  = "<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n";
                $ul .= "\t<tr><th>Search Strings</th><th class=\"last\">Hits</th></tr>\n";
                foreach( $results as $r ) {
                        $ul .= "\t<tr><td>$r->s</td><td class=\"last\">$r->c</td></tr>\n";
                }
                $ul .= "</table>";
        }
        return $ul;
}

Der Einfachheit halber habe ich die gesamte Funktion gepastet, da ich empfehle den Query auf Aliasse umzustellen.

Der zweite Fehler (und damit die dritte Codeänderung) ist am lästigsten - die Funktion getWeeksHits() funktioniert schlichtweg nicht richtig, da sie einen konzeptionellen Denkfehler enthält. Die im Kern befindliche For-Schleife zählt $i von 0 bis 7 hoch, um die letzten sieben Tage zu berücksichtigen. Blöde nur, dass das Startdatum für jeden Tag nicht jeweils einfach 86400 Sekunden kleiner ist als vom Vortag, sondern 86400 mal Zählerstand! Das kann nicht funktionieren!

So macht mans richtig:


function getWeeksHits()
{
  global $wpdb;
  
  $dt = mktime(23,59,59,date('m',current_time('timestamp')),date('d',current_time('timestamp')),date('Y',current_time('timestamp')));
  $tmp = "";
  $dt_start = $dt;
  
  $tmp  = "<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n";
  $tmp .= "\t<tr><th colspan=\"2\">Hits in the last week</th></tr>\n";
  $tmp .= "\t<tr><td class=\"accent\">Day</td><td class=\"accent last\">Hits</td></tr>\n";
  
  for ($i=0; $i<7; $i++)
  {
    $dt_stop = $dt_start;
    $dt_start = $dt_start - 86400;
    $day = ($i > 0) ? gmdate("l, j M Y",$dt_stop) : "Today, ".gmdate("j M Y",$dt_stop);
    $query = "SELECT COUNT(*) AS 'total' FROM $this->table_stats WHERE dt >= $dt_start AND dt <$dt_stop";
    if ($total = $wpdb->get_var($query))
    {
      $tmp .= "\t<tr><td>$day</td><td class=\"last\">$total</td></tr>\n";
    }
  }
  $tmp .= "</table>";
  return $tmp;
}

Der Einfachheit halber stelle ich an dieser Stelle direkt den Download der korrigierten Fassung zur Verfügung. Have Phun!

Update 14.01.2006
Ich habe mir aufgrund einiger Irritationen bei den Tagesstatistiken (die Werte änderten sich dauernd) den Code in dieser Hinsicht nochmals untersucht, und nachdem mein Kackreiz abgeklungen ist, den mir dies beschert hat, habe ich sämtliche Datums- und Zeit-bezogene Abfragen runderneuert. Der oben dargestellte Code der Funktion getWeeksHits() ist schon auf dem neuesten - funktionierenden - Stand, und das Zipfile enthält nun folglich die korrigierte 1.4.0-4null4-Fassung ;)

Verwandte Artikel:



Hinweis: Wegen des hohen Aufkommens an Kommentarspam und als Kommentar getarnten Werbelinks werden alle Kommentare auf diesem Blog zuerst in die Moderation geschickt. Ich schalte neue Kommentare von echten Besuchern so schnell wie möglich frei. Beleidigende oder gegen geltendes Recht verstoßende Kommentare werden gelöscht.

Bisher 10 Kommentare zum Artikel

  1. Markus Kaemmerer meint

    Ich habe mittlerweile Korrekturen aus drei verschiedenen Quellen in wp-stat eingebaut und stelle diese unter blog.happyarts....e/2006/01/17/65 zum Download bereit .

  2. Jörg Petermann meint

    Danke für den Hinweis! :))

  3. CountZero meint

    danke für die idee mit dem sich-selbst-nicht-zählen ;) das kann ich aber noch ne ecke intelligenter lösen, immerhin bin ich ja der entwickler des PowerCounters, ne? ;) allerdings setzt das dann tatsächlich erstmalig ne options-page fürs plugin voraus, und dann werde ich das direkt auch für wp-shortstat selbst auch erledigen, da mich einige der voreinstellungen inzwischen doch ein bisschen stören.
    eventuell wird da sogar ne synergie aus dem powercounter und dem plugin draus und es entsteht direkt ein ganz neues plugin, mal sehen. muss ich zeit für haben, das is der einzige knackpunkt.

  4. Sven meint

    Und außerdem bastelt Carsten meinen Kot noch bitte in die dafür vorgesehenen Tags ein ;)

  5. Sven meint

    Find ich echt klasse, dass du dich da so reinkniest. Haste den Entwickler von dem Plugin schon mal angeschrieben?

    Ich hab da noch ein lecker Feature für Version 0.3 ;)

    Und zwar stört mich persönlich an solchen Countern immer, dass ich mitgezählt werde. Wenn ich am Testen bin lade ich die Seite teilweise 20 mal die Minute, und das gibt Hits, dass es kracht :)

    Also hab ich noch die Abfrage, ob der Besucher angemeldet ist oder nicht hinzugefügt. Ist ganz simpel:

    Sucht im oberen Drittel nach der Zeile function track() {. Das ist die Funktion, die für das Zählen verantwortlich ist. Unter dieser Zeile steht global $wpdb;. Hinter $wpdb bauen wir eine weitere Variable, die wir in dieser Funktin benötigen ein.

    global $wpdb, $cookiehash;

    Darunter finden wir schon die Abfrage, wann diese Funktion nicht zählen soll. Damit werden 404-error Seiten nicht gezählt, oder die admin-Seiten, was auch Sinn macht. Genau da friemeln wir jetzt noch 2 Zeilen rein:

    Die erste Zeile, damit ein angemeldeter Besucher nicht mitgezählt wird und die zweite dafür, dass die wp-login Seite nicht geloggt wird - für was auch ;)

    || isset($_COOKIE['wordpressuser_'.$cookiehash])
    || strstr($_SERVER['PHP_SELF'], 'wp-login.php')

    Super einfach, oder nicht …

    Die Funktion track() im ganzen sieht damit folgendermaßen aus:

    function track() {
     global $wpdb, $cookiehash;
    
      if($wpdb->is_admin
       || strstr($_SERVER['PHP_SELF'], 'wp-admin/')
       || is_404()
       || is_admin_page()
       || isset($_COOKIE['wordpressuser_'.$cookiehash])
       || strstr($_SERVER['PHP_SELF'], 'wp-login.php')
      )return; // let's not track the admin pages -- no one cares.
    
      $IP                = $_SERVER['REMOTE_ADDR'];
      $cntry        = $this->determineCountry($IP);
      $lang        = $this->determineLanguage();
      $ref        = $_SERVER['HTTP_REFERER'];
      $URL        = parse_url($ref);
      $domain        = eregi_replace("^www.","",$URL['host']);
      $res        = $_SERVER['REQUEST_URI'];
      $ua                = $_SERVER['HTTP_USER_AGENT'];
      $br                = $this->parseUserAgent($ua);
      $dt                = time();
    
      $this->sniffKeywords($URL);
    
      $query = "INSERT INTO $this->table_stats   (remote_ip,country,language,domain,referer,resource,user_agent,platform,browser,version,dt)
    VALUES ('$IP','$cntry','$lang','$domain','$ref','$res','$ua','$br[platform]','$br[browser]','$br[version]',$dt)";
    
     $wpdb->query($query);
    }

    Und das neue, auf Version 0.3 upgedatede Plugin bietet Carsten hier natürlich gleich zum Download an ;)

  6. Pingbacks & Trackbacks