Schlagwort-Archiv:

Webdesign

WordPress: Hinweis bei Spam-Falscherkennung

Papierspam ?! Und wieder eine kleine Code-für-das-Blog-Lösung von mir, die zwar nicht unbedingt perfekt ist, aber doch hilfreich sein kann…

Viele sind dem Problem schon begegnet, dass ein Kommentar fälschlicherweise im Spam landet, weil der Spamfilter – sei es das bekannte Akismet (wie bei meinem Blog), sei es ein anderes Plugin oder einfach eine versehentlich zu scharf eingestellte Blacklist – übereifrig ist. Auf meinem Blog kommt so ein false positive im Schnitt alle drei Wochen einmal vor.

Der erfahrene Blogger oder Blogkommentierer weiß, dass er dann i.d.R. einfach darauf warten muss, dass der Blogbetreiber den Kommentar (hoffentlich) herausfischt und freigibt. Der unerfahrenere Kommentierende steht aber nicht selten wie der (Pfingst-)Ochse vor dem Berg, wenn er nach dem Absenden des Kommentars oben auf der Seite landet und auch beim Runterscrollen seinen Kommentar nicht findet; manche versuchen es dann auch erneut, manche kommen vielleicht gar nicht wieder.

Ein Hinweis könnte da helfen – doch WordPress bietet da (anders als bei noch zu moderierenden Kommentaren) keinen. Die normale Schleife, die die Kommentare ausgibt, weiß auch nicht direkt, welcher Kommentar aktuell vom Aufrufenden ist, denn der Teil der URL, in der das steht – #comment-123, was ja insbesondere für die Positionierung der Ansicht im Browser sorgt1 – ist nicht Teil der Anforderung, die der Server sieht, sondern bleibt im Browser.

Nun könnte man vielleicht die Kommentarnummer bei der Weiterleitung nach dem Abschicken auch als &-Parameter in die URL einbauen (und dann in der Ausgabeschleife mit abfragen), doch finde ich das irgendwie unschön – wer weiß, ob dadurch nicht mehrere solche URLs durch die Suchmaschinen geistern. Mir kamen zwei andere Ideen, die ich hier vorstellen will:

Lösung 1: Spam-Kommentar von derselben IP-Adresse?

Die erste Idee: Man schaut nach der Kommentarausgabe nach, ob in den letzten paar Minuten ein Spam-Kommentar von derselben IP-Adresse kam, von der die aktuelle Anfrage kommt. Das sieht dann in einer Funktion für die functions.php des Themes so aus:

function ag_spammed_comment ($gotcomments) {
    global $wpdb, $post;
    $spamcom = $wpdb->get_results ("
        SELECT * FROM $wpdb->comments
        WHERE comment_post_ID = '$post->ID'
          AND comment_author_IP = '".$_SERVER['REMOTE_ADDR']."'
          AND comment_approved = 'spam'
          AND comment_type = ''
          AND TIME_TO_SEC(TIMEDIFF(NOW(),comment_date))<120");
    if ($spamcom) {
        if (!$gotcomments) echo '<ol class="commentlist">';
        foreach ($spamcom as $sc) {
            echo '<li id="comment-'.$sc->comment_ID.'" class="comment caughtasspam">'.
            '<strong>Anscheinend wurde Ihr Kommentar von der Automatik als Spam markiert.</strong><br/>'.
            'Falls das ein Versehen war: bitte etwas Geduld, bis er manuell freigeschaltet wird.'.
            '</li>'."\n";
        }
        if (!$gotcomments) echo '</ol>';
    }
}

Aufzurufen dann in der comments.php mit ag_spammed_comment (true); (in <?php ?> eingeschlossen) nach der Ausgabe der vorhandenen Kommentare und mit false statt true im Zweig für den Fall, dass es noch keine Kommentare gibt – wobei diese Unterscheidung nur nötig ist, wenn man den Hinweis wie einen Kommentar in die ol/ul mit einbinden (und gestalten) will; wer einen separaten div-Block verwenden will, kann sich die Unterscheidung sparen.

Die Klasse .caughtasspam Ist dann natürlich noch in der style.css angemessen (z.B. mit rotem Rahmen) zu formatieren.

Allerdings gibt’s da ein…

Problem: Der Cache

Wer ein Cache-Plugin wie WP Super Cache einsetzt, das die erzeugten Seiten zwischenspeichert, steht dann vor dem Problem, dass dieses – eigentlich sinnvollerweise – den Cache der betroffenen Seite bei einem Spam-Kommentar nicht invalidiert, d.h. noch dieselbe alte Seite ausliefert, ohne dass der Code oben zur Ausführung kommt und seinen Hinweis ausgeben kann.

Eine Lösung dafür: Man ändert das Plugin so, dass Spam-Kommentare (aber nicht Spam-Trackbacks) doch die gecachete Seite löschen. Das geht bei WP Super Cache in wp-cache-phase2.php in der function wp_cache_get_postid_from_comment, wo man nach

} elseif ( $comment['comment_approved'] == 'spam' ) { 

die beiden Zeilen

if ( isset( $GLOBALS[ 'wp_super_cache_debug' ] ) && $GLOBALS[ 'wp_super_cache_debug' ] ) wp_cache_debug( "Spam comment. Don't delete any cache files.", 4 );
return $postid;

durch diese ersetzt:

//--ag: for false-positive message
if ( $comment['comment_type'] == '' ) {
    if ( isset( $GLOBALS[ 'wp_super_cache_debug' ] ) && $GLOBALS[ 'wp_super_cache_debug' ] ) wp_cache_debug( "Spam comment. But update cache for post $postid to allow for false-positive message.", 4 );
    return wp_cache_post_change($postid);
} else {
    if ( isset( $GLOBALS[ 'wp_super_cache_debug' ] ) && $GLOBALS[ 'wp_super_cache_debug' ] ) wp_cache_debug( "Spam trackback. Don't delete any cache files.", 4 );
    return $postid;
}

Dann funktioniert’s auch mit dem Hinweis. Allerdings auf Kosten der Performance, falls zufällig echte Spammer viele Spamkommentare auf eine Seite abzuladen versuchen, die auch häufig von Besuchern aufgerufen wird – was bei den meisten Blogs aber nicht so häufig sein dürfte, denke ich.

Der größere Nachteil ist m.E., dass man ein (weiteres?) Plugin hat, bei dem man bei einem Update aufpassen muss, dass man die Änderungen auch in die neue Version übernimmt. Diesen Aufwand will ich mir sparen, deshalb habe ich hier eine andere Lösung eingebaut:

Lösung 2: JavaScript (mit jQuery)

Diese Lösung funktioniert natürlich nicht, wenn der Kommentator JavaScript deaktiviert hat – ein Nachteil, den ich hier aber in Kauf nehme in der Hoffnung, dass diese Kombination selten genug auftritt – dafür funktioniert sie aber auch, wenn jemand über für jede Anfrage wechselnde Proxy-Server surft.

Hier gibt’s sogar zwei Lösungsvarianten, deren erste ich nur kurz anschneiden will: Man ändert mittels comment_post_redirect-Filter (der von wp-comments-post.php aufgerufen wird) die Ziel-URL so, dass bei einem Spam-Kommentar das #comment-123 durch etwas wie #spammed ersetzt wird, und sorgt dann per JavaScript dafür, dass ein im Theme eingebauter, anfangs auf display: none gesetzter (oder leerer) Hinweisblock eingeblendet (oder mit dem Hinweistext gefüllt) wird, wenn #spammed in der URL vorkommt – denn anders als der Server hat JavaScript auf diesen Teil Zugriff.

Variante 2, die auch hier eingebaut ist, kommt ohne einen solchen Filter aus und schaut einfach nach, ob es ein Element namens #comment-123 auf der (vollständig geladenen) Seite überhaupt gibt. Wenn nicht, wird der Hinweistext eingefügt (durch JavaScript deswegen, damit Suchmaschinen den Hinweis nicht indizieren):

<div id="spammedhint" class="comment caughtasspam" style="display:none;"></div>
<script type="text/javascript">
<!--
var theUrl = document.location.toString();
if (theUrl.match("#comment-")) {
    var theHash = theUrl.substr(theUrl.indexOf("#"));
    if (jQuery(theHash).length==0) {
        jQuery(document).ready(function() {
            jQuery("#spammedhint").html("<strong>Anscheinend wurde Dein Kommentar von der Automatik als Spam markiert.</strong><br/>"+
            "Falls das ein Versehen war: bitte etwas Geduld, bis er manuell freigeschaltet wird.").fadeIn();
            var targetOfs = jQuery("#spammedhint").offset().top;
            jQuery("html,body").animate({scrollTop: targetOfs-20}, 500);
        });
    }
}
//-->
</script>

Die Frage der Existenz wird mit if (jQuery(theHash).length==0) abgefragt, da jQuery() immer ein Objekt zurückliefert und ein ansonsten naheliegendes if (jQuery(theHash)) immer wahr ist. Mit der letzten jQuery-Zeile wird dann innerhalb 500 ms zum Hinweisblock gescrollt (bzw. knapp drüber); mit einer ganz kurzen Zeit gab’s manchmal Probleme, weil das document irgendwie doch noch nicht ganz ready war und der Browser dann an eine andere Stelle zurücksprang. (Kann aber sein, dass das nur beim Neuladen einer Seite, wie man’s beim Testen nunmal macht, passiert.)

Ich habe diesen HTML/JS-Code direkt (und natürlich nicht in <?php ?> eingeschlossen) in die comments.php eingefügt (also nicht in die functions.php ausgelagert), und zwar direkt nach <?php if ('open' == $post->comment_status) : ?> und damit direkt vor die Ausgabe der Eingabefelder.

Auch hier sollte man die Klasse .caughtasspam dann natürlich noch in der style.css angemessen formatieren.

Nun hat auch diese Methode einen Nebeneffekt, der sowohl unerwünschterweise (aber wohl sehr selten) auftritt, wenn jemand irgendwoher einen falschen Link mit einer nicht existierenden bzw. unsinnigen Kommentarnummer hat, als auch erwünschterweise, wenn jemand den Link mit seinem erstmal durchgegangenen Kommentar gebookmarkt hat und dieser nachträglich in den Spameimer geworfen wird, denn dann wird dieser Hinweis auch ausgegeben.

Was es euch auch ermöglicht, diese Funktion einfach zu testen – ich habe hier einen Link für euch vorbereitet. :) Ihr könnt aber auch einen neuen Kommentar schreiben und dort „diesisteinspamtest“ einfügen, dieses Wortkonglomerat hab ich für ebendiesen Zweck auf die Blacklist gesetzt. Aber übertreibt’s nicht, ich muss die schließlich alle freischalten…

Wer kein Cache-Plugin verwendet, kann also die erste Lösung gut verwenden, andernfalls gilt es eben Vor- und Nachteile abzuwägen; ich habe mich wie gesagt für die JavaScript-Lösung entschieden.

Meinungen, Kritik, Anregungen, Probleme, Fragen…?

  1. wer ein fehlerhaftes Theme hat, das diese ID für die Kommentare nicht erzeugt und somit alle Kommentatoren nach dem Kommentieren am Seitenanfang landen, sollte das jetzt endlich auch reparieren… []

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 []

Links und Videos der Woche (2010/12)

 

  • Und noch mehr Death Metal, diesmal „von“ Louis Armstrong (via @JoergR):

     

  • Ein hochseriöser Beitrag der Heute-Show von einer Esoterikmesse: (via Uwes Kommentar)

 

  • Und zu guter Letzt: Ein Ast fällt auf eine Stromleitung (via ui.)

Kommentare zitieren

Pink Butterfly Little Girl With Colorful Message Clouds. Isolate Ich habe mal wieder eine kleine Bastelei ins Blog eingebaut: eine Möglichkeit, einen ganzen Kommentar als Zitat ins Eingabefeld zu übernehmen. Dazu findet sich jetzt in der Kopfzeile jedes Kommentars am Ende ein entsprechender Link, der diesen als HTML samt umschließendem <blockquote> und darüber einer Zeile „Zitat von …“ samt Link zum Kommentar an die bisherige Eingabe anhängt – und nicht etwa beim Cursor einfügt; dies würde natürlich auch gehen (mach ich bei den Smilies ja schon), aber ich denke, bei so langen Einfügungen ist das Anhängen besser.

Das Script

Das ganze benötigt zum einen ein kleines Script (was auch bedeutet, dass Javascript aktiviert sein muss), das man entweder in eine externe Javascript-Datei einfügt oder einfach inline in die comments.php des Themes, am besten ziemlich direkt nach der Zeile

<?php if ( have_comments() ) : ?>

vor der Ausgabe der Kommentare.

Und das ist das Script, das jQuery benötigt – wird in vielen Fällen ja eh schon geladen:

<script type="text/javascript">
<!--
    function quotecomment (cID) {
        p = jQuery('#edit-comment'+cID);
        if ((!p) || (p.length==0)) p = jQuery('#comment-text-'+cID);
        t = p.html();
        t = t.replace(/<img [^>]*alt=[" ]*([^ "]*)[" ]*[^>]*>/ig,' $1 ');
        jQuery('#comment').val(jQuery('#comment').val() + '\n' +
            'Zitat von <a href="#comment-'+cID+'">'+
            jQuery('#comment-author-'+cID).text()+
            '</a>:\n<blockquote>'+t+'</blockquote>\n\n');
    }
//-->
</script>

In der Funktion (zu deren Aufruf wir gleich noch kommen) wird zunächst das Element mit der ID edit-commentXXX gesucht (mit XXX=Kommentarnummer), das den Kommentartext enthält, wenn das Plugin Ajax Edit Comments aktiv ist und dieser Kommentar bearbeitet werden kann; gibt’s das nicht, ist comment-text-XXX gefragt – das ist eine der kleinen Theme-Anpassungen, die ihr werdet vornehmen müssen – auch dazu gleich mehr.

Von diesem Element wird dann der HTML-Inhalt genommen – so bleiben die ganzen Formatierungen erhalten, auch wenn es mehr Tags enthält (etwa <p>), als original eingegeben wurde. Gut, alternativ hätte ich den Originalinhalt via Ajax nachladen können wie dieses Plugin (oder gleich das Plugin verwenden) oder ihn nochmal direkt in den Funktionsaufruf im Seitenquelltext schreiben, aber dies ist irgendwie die sparsamste Lösung…

Da in diesem HTML-Inhalt auch Bilder – selbst die Smilies – als img-Tags drin sind, müssen sie mit dem regulären Ausdruck im replace wieder in die Smilie-Codes (die in den alt-Attributen stehen) umgewandelt werden – Bilder dürft ihr ja nicht direkt in euren Kommentaren verwenden, das darf nur ich. :mrgreen: (Und natürlich muss dieser Ausdruck komplizierter sein, weil der Internet-Explorer wieder ein eigenes Süppchen kocht und etwa die Anführungszeichen bei den Attributen weglässt.)

(Benutzer einer Live-Vorschau, die bei <br> einen Zeilenumbruch zu viel einfügte, sollten die Zeile ergänzen, die ixiter unten im Kommentar nennt.)

Und schließlich wird in dem langen jQuery-Aufruf der Text/Code dann an den Inhalt des Eingabefeldes – das wie üblich die ID "comment" haben muss, ansonsten müsst ihr’s ändern – angehängt.

Änderungen in der Kommentarausgabe

In der Kommentarausgabe des Themes müssen, wie oben schon erwähnt, zum einen die Namen der Elemente mit ausgegeben werden, zum anderen der Link mit dem Aufruf der obigen Funktion. Das wird natürlich von eurem Theme abhängen, aber wer etwas Erfahrung mit solchen Basteleien hat, wird die passenden Stellen schon finden und geeignet ändern können.

Da wäre zum ersten der Name des Kommentators, der die entsprechende ID braucht – und zwar möglichst nur der Name und nichts drumrum. Man nimmt am besten einen eigenen span direkt um den Aufruf der WordPress-Funktion comment_author_link() (oder wie auch immer bei euch der Name mit Link ausgegeben wird); bei mir sieht da sowieso ein strong zur Fettschrift, deswegen hab ich das gleich verwendet:

<strong id="comment-author-<?php comment_ID(); ?>">
<?php comment_author_link() ?></strong>

Das muss, wie man sieht, im HTML-Kontext stehen (also außerhalb des <?php ... ?>-Bereichs). Dann brauchen wir den „zitieren“-Link an der gewünschten Stelle – und in dieser Form muss es innerhalb von <?php ... ?> stehen:

if ($comment->comment_type=="") {
    echo ' <span class="quotecomment">';
    echo '<a href="#commentform" onclick="quotecomment('.get_comment_ID().');" '.
        'title="den Inhalt dieses Kommentars ans Ende des Eingabefelds anh&auml;ngen (als HTML)">'.
        'zitieren <img src="/pics/quote.png" width="17" height="16" alt="" /></a>';
    echo '</span>';
}

Wer nicht will, dass beim Klick auch die Fensterposition wieder zum Eingabefeld scrollt, ersetze das href="#commentform" onclick="quotecomment… durch href="javascript:quotecomment… Wer das Bildchen nicht will, muss das entspr. img-Tag weglassen; ansonsten dürft ihr euch gerne mein Bildchen kopieren1.

Zu guter Letzt muss noch der eigentliche Kommentarinhalt seine ID erhalten, wozu wir den comment_text()-Aufruf in einen div packen, wenn noch kein geeigneter vorhanden ist (ansonsten den einfach entsprechend benennen oder, wenn der in eurem Theme schon eine ID hat, im Script oben anpassen):

echo '<div id="comment-text-'.get_comment_ID().'">';
comment_text();
echo '</div>';

So, das war’s dann eigentlich, ich hoffe, ich habe nichts vergessen. Wenn ihr noch Fragen habt, nur raus damit…

Ausblick

Als weitere Idee wäre noch das Zitieren beliebiger Textabschnitte aus einem Kommentar oder dem Beitrag durch Markieren des Textes, wie es etwa hier bei Frank Bültge vorgestellt wurde. Aber das muss auf einen späteren Zeitpunkt warten…


Foto: Alexandr Zinchevici – Fotolia.com

  1. bitte auf euren Webspace kopieren und nicht etwa hotlinken []

Links und Video der Woche (2010/08)