Beliebteste Beiträge

Ich weiß nicht, ob’s jemand schon bemerkt hat^^, aber seit letzter Woche findet sich in meiner Sidebar ein Abschnitt mit den beliebtesten Beiträgen, und wie das bei mir so üblich ist, bemühe ich da nicht groß ein Plugin, sondern hab das selber gebastelt. Und da es vielleicht den einen oder anderen auch interessieren könnte, gibt’s diesen Beitrag… Verbesserungsvorschläge sind natürlich willkommen.

Die Frage war also: Welche Kriterien sollen für die Beliebtheit gelten, und wie krieg ich das mit einer Datenbankabfrage hin? Die Kriterien, an die ich gedacht habe, sind:

  • Aufrufzahlen der Beiträge, gezählt mit WP-PostViews1;
  • Anzahl der Kommentare;
  • Länge der Kommentare2 – kurze à la „toller Beitrag“ weniger stark gewichten;
  • Alter der Beiträge – neue Beiträge mit vielen Aufrufen oder Kommentaren sollen bevorzugt werden – bzw. Aufrufe pro Tag.

Wer ein Plugin zur Beitragsbewertung einsetzt, mag dessen Werte natürlich auch noch mit einschließen; entsprechendes gilt für ein anderes Statistik-Plugin als WP-PostViews. Und natürlich gibt’s auch etliche „Popular Posts“-Plugins, doch die wenigsten davon berücksichtigen mehr als die Kommentaranzahl – und eine maßgeschneiderte Lösung ist mir eben auch lieber…

Generell stellt sich noch die Frage nach der Gewichtung – wenn bei euch fast jeder Besucher kommentiert, müsst ihr die Kommentaranzahl nicht deutlich stärker als die Aufrufe gewichten, und man kann natürlich eigene Schwerpunkte setzen. Und man muss die einzelnen Kriterien auch nicht einfach mit einem Faktor addieren, sondern kann etwa alle anderen durch das Alter teilen u.v.a.m. Meine Gewichtung seht ihr unten im/nach dem Code.

Nun könnte man dazu mehrere Datenbankabfragen machen, die alle der Post-ID, also der eindeutigen Nummer eines Beitrags, ihren jeweiligen Wert zuordnen, und diese Arrays dann mittels PHP verrechnen und gewichten – ich hab’s hingegen in eine einzige MySQL-Abfrage gequetscht (war auch ’ne kleine Übung in Sachen MySQL… und ist sicher nicht perfekt…); mag sein, dass einzelne Abfragen schneller wären, aber nach etwas Optimierung hatte ich meine Query so weit, dass sie nicht viel länger dauert als das „Einsammeln“ der Kommentarlängen (die bei >10000 Kommentaren/Trackbacks schon ein bisschen dauert), und vermutlich geht’s nicht viel schneller – konkret: von ca. 1½ auf 0,3 Sekunden.

(Aus der Zeit vor der Optimierung stammt auch die kleine Cache-Funktionalität, die ihr gleich im Code seht; bei Verwendung eines Datenbank-Caches oder Verlassen auf den Query Cache der Datenbank selbst wäre die auch weniger wichtig.)

Hier also der Code3:

function ag_popular_posts($num=10) {
    global $wpdb;
    $lastupdate = (int) get_option("ag_popular_lastupdate",0);
    $output = '';
    if (time()-$lastupdate > 1800) {
        $exclude = "
            AND ID NOT IN (78,70)
            AND ID NOT IN (
                SELECT object_id FROM $wpdb->term_relationships
                WHERE $wpdb->term_relationships.term_taxonomy_id IN (92,384)
            )"
;
        $posts = $wpdb->get_results("
            SELECT ID,post_date,post_title,post_name,comment_count,
                $wpdb->postmeta.meta_value AS views,
                TO_DAYS(NOW())-TO_DAYS(post_date) AS age,
                comment_length,
                ($wpdb->postmeta.meta_value/2
                 +comment_count*50
                 +comment_length/comment_count*5
                 +(TO_DAYS(post_date)-TO_DAYS('2006-09-06'))*5) AS popularity
            FROM $wpdb->posts,$wpdb->postmeta,(
                SELECT comment_post_id, SUM(LENGTH(comment_content)) AS comment_length
                FROM $wpdb->comments
                WHERE comment_approved='1'
                GROUP BY comment_post_id) AS thecomm
            WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id
            AND $wpdb->posts.ID = thecomm.comment_post_id
            AND $wpdb->postmeta.meta_key = 'views'
            AND comment_count > 0
            AND post_status = 'publish'
            AND post_type = 'post'
            AND post_password = ''
            $exclude
            ORDER BY popularity DESC, post_date
            LIMIT $num"
);
        if ($posts) {
            $output="<ul>";
            $pop0=0;
            foreach ($posts as $p) {
                if ($pop0==0) $pop0=$p->popularity;
                $output.='<li><a href="'.get_permalink($p->ID).'" title="'.
                        $p->comment_count.' Kommentare mit durchschnittlich '.
                        ($p->comment_count==0?'0':number_format($p->comment_length/$p->comment_count,1)).' Zeichen, '.
                        number_format($p->views).'x aufgerufen, '.
                        number_format($p->age).' Tage alt'.
                    '">'.
                    $p->post_title."</a> ".
                    "<small>(".number_format($p->popularity/$pop0*100,0).'%'.")</small>".
                    "</li>\n";
            }
            $output.="</ul>\n";
        }
        update_option("ag_popular_lastupdate",time());
        update_option("ag_popular_cached",$output);
    } else {
        $output = get_option("ag_popular_cached",'');
    }
    if ($output!='') {
        echo "<li id=\"side-popular\">\n".
            "<h2>Beliebteste Beitr&auml;ge</h2>\n".
            $output.
            "</li>\n";
    }
}
 

Also gehen wir den Code mal durch:

Wir beginnen mit der Abfrage, ob die Liste aktualisiert werden soll – das Intervall liegt hier bei 1800 Sekunden, also einer halben Stunde.

Um bestimmte Beiträge auszuschließen, kann man ihre ID wie in der ersten Zeile des ausgelagerten $exclude-Statements angeben – bei mir ist es 78 = die Liste der Musik-Zitate, die aufgrund ihrer hohen Abrufzahlen unangefochten an Platz 1 wäre, aber nicht so interessant ist, dass ich sie hier in der Beliebtheitsliste hervorheben möchte, und die 70 = die damalige Technorati4-Ketten-Aktion, die nur bei manchen Gewichtungsversuchen in der Top 10 wäre –, oder alternativ z.B. auch post_name.

Eine ganze Kategorie oder ein ganzes Tag kann man mit dem zweiten AND ID NOT IN-Statement ausschließen. Dazu muss man die term_taxonomy_id der/des fraglichen Kategorie/Tag herausfinden – indem man in der Tabelle wp_terms anhand des Namens die term_id findet und mit dieser in wp_term_taxonomy nachschlägt (oder irgendwelche WP-Funktionen verwendet, mit get_term_by() könnt’s vielleicht gehen) – und am Ende einsetzen; bei mir will ich alle Quiz-Beiträge (92) und nur englische (384) ausschließen (bzw. in englischer Ansicht alle deutschen, da steht dann 385).

Weiter geht’s mit der eigentlichen SELECT-Abfrage. In deren ersten vier Zeilen stehen ein paar für die Ausgabe benötigte Angaben, danach in Klammern (...) AS popularity der eigentliche Beliebtheitswert.

Wie ihr (vielleicht) seht, gewichte ich die Seitenaufrufe mit 0,5, die Kommentaranzahl mit 50, die durchschnittliche Kommentarlänge ebenso wie die Neuheit des Beitrags (Tage seit Blog-Start, was ihr für euch natürlich ändern müsst, siehe gelb hinterlegtes Datum – wenn ihr stattdessen das Alter, also die Tage zwischen Beitrag und heute, verwenden wollt, nehmt TO_DAYS(NOW())-TO_DAYS(post_date)) mit 5, was sich nach etwas Herumspielen als recht passend für mein Blog gezeigt hat.

(Die kurz darüber deklarierten Felder (AS views, AS age) kann man hier übrigens nicht mit den neuen Namen nehmen, da meckert MySQL – also eben nochmal komplett einsetzen.)

Die FROM-Zeile enthält neben der wp_posts-Tabelle noch wp_postmeta, weil dort die Aufrufzahlen von WP-PostViews liegen – braucht ihr nicht, wenn ihr diese Werte nicht verwendet – und das untergeordnete SELECT für die Kommentarlänge, genauer: die Summe der Länge aller Kommentare mit derselben post_id (inkl. Trackbacks; diese könnte man mit AND comment_type='' vor GROUP ausschließen).

Die WHERE– und die erste AND-Zeile verknüpfen die beteiligten Tabellen über die Post-ID, die nächste wählt die WP-PostViews-Werte aus (die eben „views“ heißen) und der Rest beschränkt das ganze auf geeignete Beiträge.

Danach wird die Ausgabe zusammengebastelt, insb. in der foreach-Schleife, die über die Beiträge läuft, wo der Link samt Tooltip (title) mit statistischen Infos und einem Prozentwert der Beliebtheit mit 100% für den 1. Platz zusammengeklebt wird.

Wenn diese Ausgabe zusammengeklöppelt ist, wird sie noch schnell in die Datenbank für unseren kleinen Cache geschrieben, von wo aus sie (im else-Zweig) innerhalb der nächsten halben Stunde gelesen wird. Und zu guter Letzt muss das ganze natürlich noch (mit Überschrift) ausgegeben werden.

So, das war jetzt jede Menge Code. Wer Verständnis- oder sonstige Fragen, Anmerkungen, Stellungnahmen, Lob, Kritik, Verbesserungsvorschläge, Beleidigungen, Ideen oder Anregungen hat, nur raus damit – Moment, auf eine dieser Arten von Äußerungen solltet ihr besser verzichten.^^

 

  1. mit dem Nachteil, dass ich dieses anfangs alle Zugriffe inkl. Suchmaschinen zählen ließ, aber seitdem ich auch WP Super Cache nutze nur mittels JavaScript – wodurch die Zähler mittlerweile weit weniger stark steigen… ↺
  2. auf Anregung von Julia, dankeschön ↺
  3. ich hoffe, ich hab beim Wieder-Entfernen meiner Sprachumschaltung keinen Fehler eingebaut… ↺
  4. Berners-Lee hab es selig ↺

Link und Videos der Woche (2010/17)

(Hier war etwas als Flash-Objekt eingebunden. Nicht mehr zeitgemäß.)

 

  • In gewisser Weise das Lied der Woche – Tim Minchins Papst-Lied (NSFW). Hier in einer untertitelten Version, bei den Skepchicks (via) gibt’s auch den Text in Gänze zum Mitlesen.

Und wer sich darüber aufregt, wie hier mit dem Papst umgegangen wird, sollte besser auf den Text achten: Was ist schlimmer, dieses Lied oder der Verdacht, dass der Papst, Kopf einer sich als hohe moralische Autorität gebärdenden Institution, möglicherweise Kinderficker gedeckt hat?

 

  • Was? Widersprüche in der Bibel? Kann das sein?^^ Dazu eine Cartoon-Quizshow (via Pharyngula):

Plusieurs, Nostradamus und der Aufstieg 2012

Nostradamus Im GWUP-Blog findet sich aktuell eine Beitragsserie1 zum Thema „Wie analysiert man Nostradamus-Verse?“, in der Bernd Harder schön auf die Probleme und den Unsinn der diversen Übersetzer eingeht. Aber wie erwartet geht so ein pöhser verschlossener Skeptiker natürlich nicht auf die Einzig Wahre™ Interpretation ein – dabei sollte doch jeder mittlerweile wissen, dass Nostradamus gar nicht auf französisch geschrieben hat, wie ich Ende letzten Jahres anhand von zweimal drei Quatrains gezeigt hatte.

Konkret geht es um einen Sechszeiler, der nicht im Hauptwerk der zehn Centurien steht, also quasi aus den kryptischen Apokryphen:

Plusieurs mourront avant que Phoenix meure,
Jusques six cents est sa demeure,
Passé quinze ans, vingt et un, trente-neuf,
Le premier est subject à maladie,
Et le second au fer danger de vie
Au feu à l’eau est subject trente-neuf.

Mit meiner unfehlbaren (süd)deutschen Direkt-Leseweise – denn wie Ende letzten Jahres gesagt, hat Nostradamus ganz offensichtlich für uns heute geschrieben, alles andere diente nur als Ablenkungsmanöver – ergibt sich (mit zum Verständnis hinzuzufügenden Ergänzungen in eckigen Klammern) dieses unzweideutige zeilenweise Ergebnis:

(1) Plus-Kunden (liebevoll Plusierus genannt) murren an [der] Wand: kein Fön, nix Möhre,
(2) Just wenn 6 Cents ist [das] S[onder]a[ngebot für] die Möhre,

Schon Nostradamus wusste, dass sich Lebensmitteldiscounter-Kunden hin und wieder über ein zu gering bestücktes Warenlager ärgern müssen, wenn die Lockvogelangebote schon ausverkauft sind.

(3) Pass [auf] sein Kind [auf], seinen Hans, [er] winkt E.T. an: drenten [=da drüben] nauf,
Wenn man auf die Kinder nicht aufpasst, können sie sich sogar mit Außerirdischen unterhalten und ihnen Hinweise zum Weg geben. Und das ist nicht der einzige Hinweis darüber, wo’s hinauf geht:

(4) [Der] Lepra[kranke] mir [von] Ost[en] zublökt einmal am Di[enstag],
Das Wissen um den richtigen Weg ist offenbar weit verbreitet.

(5) E.T. lese[n] konnt[e] auf Erd-Anger, der wie
(6) [der Text] auf eurem Los [mir] zublökt: drenten nauf.

Auch auf der graslosen Dorfwiese und sogar auf einem Los steht es geschrieben, wo man hinauf gehen soll. Das muss ja wirklich enorm wichtig sein – der falsche Weg wäre wohl sehr fatal.

Aber das ist natürlich klar, denn was gibt es Wichtigeres auf esoterischen Erden als den Aufstieg 2012? Nicht auszudenken, wenn die lieben Realitätseskapisten herenten, innerhalb der Grobstofflichkeit, aufstiegen und nicht drenten mit metasubliminalem Feinstofflichkeitskontakt!

Aber zum Glück weist (nicht nur) die moderne Nostradamus­wissenschaft den wahren Irr-, äh, Weg.

  1. der es übrigens nicht schaden würde, wenn der Text „Fortsetzung folgt“ am Ende der ersten drei Teile durch entsprechende Links ersetzt würde… wäre komfortabler, als sich übers Tag durchzuklicken ↺

Projekt Hörsturz 19

Projekt Hörsturz Wie die Zeit vergeht – schon wieder eine neue Runde im „Projekt Hörsturz“, bei dem die Teilnehmer alle zwei Wochen einige Songs anhören und bewerten.

Hat mich ja schon überrascht, dass mein Emilie-Autumn-Vorschlag der letzten Runde sogar einen Schnitt von 2,4 Punkten bekommen hat – ich hatte mit weniger gerechnet. Naja, letzter Platz im recht guten Feld ist es trotzdem geworden. :) Aber widmen wir uns nun den neuen Titeln:

  • Tenacious D – Kickapoo (von Sir Donnerbold)
    Hey, das kenn ich sogar – konnte nur grad mit dem Titel nichts anfangen. Was soll ich groß sagen, einfach ein geniales Werk dieses Comedy-Rock-Duos. Nieder mit der religiösen Unterdrückung!!!1elf ;)
    4½ von 5 Sternen 4½ falsche Hollywoods

  • Bodo Wartke – Ja, Schatz! (von Stoffel)
    Aha, Kabarett mit Klavier. Da ist die Musik natürlich auch irgendwie zweitrangig, hier aber glücklicherweise ein bisschen mehr als nur belangloses Begleitgeklimper. Bei dem Text kann man froh sein, Single zu sein.^^ Okay, ist mal was anderes in diesem Projekt…
    3½ von 5 Sternen 3½x gute Nacht

  • Umbra et Imago – Milch (von Guldhan)
    Das Soundeffekt-Techno-Intro lässt einen erstmal neugierig und unschlüssig warten, wie das Lied schließlich wird – da ist die folgende Strophe fast schon zu poppig, auch wenn die Stimme das zu kaschieren versucht und noch die obligatorische Gitarre und mehr Härte dazukommt. Nun gut, im großen und ganzen ordentliche, aber eher uninteressante technoide NDH.
    2 von 5 Sternen 2 Godots

  • Demians – The Perfect Symmetry (von Stefan)
    Eine offenbar ziemlich lange Ballade, die sich langsam steigert – na zum Glück, sonst wär’s langweilig – und laut und leise abwechselt, wie sich’s gehört, sich dabei aber auch zieht wie Kaugummi – wobei mich die Gitarrenstrophe eben positiv überrascht. (Falls man das Strophe nennen will.) Und dann nochmal die furiose Steigerung, um sich nach über 8 Minuten quasi katharsisch zu beruhigen. Und dann leider abrupt abzubrechen – war wohl der Übergang zum nächsten Lied auf dem Album… das ich während des zweiten Durchlaufs auch schnell bestelle, wozu bekommt man denn ständig CDWOW-Gutscheinchen.^^
    4½ von 5 Sternen 4½ ungebrochene Symmetrien

  • Flight Of The Conchords – Robots (von Kamil)
    Elektronischer Pop mit überwiegend langweilig-robotisch vorgetragenem Text passen natürlich zum Thema, und der Text entbehrt nicht einer gewissen Komik – was einen Bonuspunkt bringt –, aber anders als Tenacious D reißt mich dieses Duo nicht gerade vom Bürostuhl.
    2½ von 5 Sternen 2½ fliegende Roboter

Womit diese stark komödiantische Runde nach der 14. und der 18. die dritte mit meinem Rekorddurchschnitt von 3,4 ist. Weiter mit den Bonussongs in der Kurzbewertung:

  • Art Garfunkel – Bright Eyes (von kasumi)
    Balladen-Klassiker zum Träumen, aber nicht zu mehr.
    3 von 5 Sternen 3 Augen – Zyklopen? Piraten? Wir werden es wohl nie erfahren…

  • Axel Rudi Pell – Devil Zone (von mir)
    Ob er das Ruhrgebiet, von wo er stammt, damit meint? Hartrockt jedenfalls ordentlich.
    5 von 5 Sternen 5 teuflische Saiten

  • Clara Luzia – All I wish for [MP3] (von dehkah – kostenloser Download!)
    Ein nettes, ruhig-flottes Liedchen, aber das, was da im Rhythmus nach Tuba klingt, stört mich etwas.
    2½ von 5 Sternen 2½ Wünsche frei

  • Cojones – Prozac (von Fini – kostenloser Download!)
    (Kann man auch direkt abspielen.)
    Heftige Antidepressiv-Instrumentierung, die den spärlichen Gesang ertränkt.
    3½ von 5 Sternen 3½ Eier (Und das will ich mir nicht näher vorstellen.)

  • Dendemann – Hörma (von WeGi)
    Na bitte, es geht doch… einigermaßen. ;)
    3 von 5 Sternen 3 Hörgeräte

  • Eisbrecher – Eiszeit (von Rakaniaz)
    Und wieder Eisbrecher, diesmal erfreulicherweise mit weniger Techno.
    4½ von 5 Sternen 4½ Kugeln Eis, bitte

  • Mystery Jets – Young Love (von JuliaL49)
    Ziemlich belangloser Gitarrenpop.
    2 von 5 Sternen 2 liebe Liebenden

  • Neil Hannon – Song for Ten (von Steve)
    Der Doctor, der Who, die Schlagerparade…
    1 von 5 Sternen 1 bester Tag

  • O.Children – Ruins (von Robert)
    Dark Wave? Jedenfalls düster, etwas poppig, ein paar Synthesizer, die erwartete Stimme.
    2½ von 5 Sternen 2½ ruinierte Kinder

  • Stolen Babies – Gathering Fingers (von beetFreeQ)
    Schräg. Vor allem, wenn man merkt, dass man nicht vergebens darauf gewartet hat, dass es mal richtig losgeht…
    4 von 5 Sternen 4 hoffentlich verhaftete Kidnapper

  • The Horror The Horror – I blame the sun (von Freddi)
    Und zum Schluss wieder „okayer“ Gitarrenpoprock.
    3 von 5 Sternen 3 Sonnenbrände

Macht einen guten Schnitt von 3,09 für die Bonussongs und 3,19 für alle.


Mein Vorschlag für die – von mir vorgeschlagene – Oldie-Runde, d.h. älter als 1980: Mott the Hoople mit „All The Way From Memphis“ von 1973 (» Wikipedia).