Archiv für den Monat: Juni 2018

Kontrastfarbe automatisch berechnen mit jquery/Javascript

Das hat jetzt mit WordPress nur insoweit was zu tun, als ich eine Anforderung vom Kunden hatte, ein Info-Widget mit in zufälligen Intervallen wechselnden Farben zu hinterlegen, der wollte das halt gern so haben. Dabei stellte sich aber gleich die Herausforderung, dass der Text (default schwarz) bei dunklen Hintergrundfarben natürlich schlecht bis gar nicht zu lesen war. Will heissen, die Textfarbe sollte dann auch dynamisch angepasst werden, und das mach ich mit jquery/Javascript. Dafür hab ich mir eine Lösungsstrategie zusammengegooglet, die man vielleicht mal irgendwo anders brauchen kann, deswegen kommt sie hier rein.

Zufällige Farbe für den Hintergrund bestimmen

Dafür habe ich mir dieses recht überschaubare Snippet ergooglet, das sehr zuverlässig funktioniert:

//******Zufällige Hex-Farbe erzeugen*********************/
    function randomColor(){
    
    var x=Math.round(0xffffff * Math.random()).toString(16);
    var y=(6-x.length);
    var z="000000";
    var z1 = z.substring(0,y);
    var color= "#" + z1 + x;
    
    return color;
    }

Relative (wahrgenommene) Helligkeit einer Farbe bestimmen

Dafür gibt es vom w3c eine Faustformel, die ich für den Kontrast bei barrierefreien Seiten immer wieder mal brauche, die geht so:

//***********relative Helligkeit von r,g,b bestimmen
    function Brightness(r, g, b)
    {
       return Math.sqrt(
          r * r * .241 + 
          g * g * .691 + 
          b * b * .068);
    }

Man füttert sie mit den RGB-Werten einer Farbe und kriegt einen Wert zwischen 0 und 255 heraus, der die relative Helligkeit einer Farbe bezeichnet. Man nimmt dann als Kontrastfarbe für die untere Hälfte des Farbspektrums weiß, für die obere Hälfte schwarz. Den Schwellwert von 130 kann man nach Geschmack noch ein bisschen nach oben oder unten anpassen.

//****************Textfarbe je nach Schwellwert zurückgeben
    function textfarbe(helligkeit){
    if (helligkeit > 130){return 'black'}
    if (helligkeit <= 130){return 'white'}

    }

Wir haben Hex und brauchen RGB

Deswegen gibts noch eine Umwandlungsfunktion, die uns den Hex-String zerlegt und die RGB_Werte liefert:

//************rgb-Werte aus hex holen
    function hexToR(h) {return parseInt((cutHex(h)).substring(0,2),16)}
    function hexToG(h) {return parseInt((cutHex(h)).substring(2,4),16)}
    function hexToB(h) {return parseInt((cutHex(h)).substring(4,6),16)}
    function cutHex(h) {return (h.charAt(0)=="#") ? h.substring(1,7):h}

var R = hexToR(aktfarbe);
var G = hexToG(aktfarbe);
var B = hexToB(aktfarbe);

Mit den drei Variablen kann man dann die Funktion Brightness() aufrufen, und mit der wiederum die Funktion textfarbe(), die uns dann schlussendlich die passende Kontrastfarbe für unsere zufällige Hintergrundfarbe liefert. Ich gebe zu es ist ein bisschen von hinten durch die Brust ins Auge, aber es funktioniert. Hier mal das ganze Script zum Nachvollziehen:

Das Script

<script>
    $(document).ready(function(){
    setInterval(farbwechsler, 5000)
    farbwechsler();
    
    //******Zufällige Hex-Farbe erzeugen*********************/
    function randomColor(){
    
    var x=Math.round(0xffffff * Math.random()).toString(16);
    var y=(6-x.length);
    var z="000000";
    var z1 = z.substring(0,y);
    var color= "#" + z1 + x;
    
    return color;
    }

    //************rgb-Werte aus hex holen
    function hexToR(h) {return parseInt((cutHex(h)).substring(0,2),16)}
    function hexToG(h) {return parseInt((cutHex(h)).substring(2,4),16)}
    function hexToB(h) {return parseInt((cutHex(h)).substring(4,6),16)}
    function cutHex(h) {return (h.charAt(0)=="#") ? h.substring(1,7):h}
    
    //***********relative Helligkeit von r,g,b bestimmen
    function Brightness(r, g, b)
    {
       return Math.sqrt(
          r * r * .241 + 
          g * g * .691 + 
          b * b * .068);
    }
    
    //****************Textfarbe je nach Schwellwert zurückgeben
    function textfarbe(helligkeit){
    if (helligkeit > 130){return 'black'}
    if (helligkeit < 130){return 'white'}

    }
        
function farbwechsler(){

var aktfarbe = randomColor();

var R = hexToR(aktfarbe);
var G = hexToG(aktfarbe);
var B = hexToB(aktfarbe);


           document.getElementById("zufall").style.backgroundColor = aktfarbe;
           document.getElementById("inhalt").innerHTML ="Hex: "+ aktfarbe;
           document.getElementById("rgb").innerHTML = "rgb: "+R+", "+G+", "+B;
           document.getElementById("brightness").innerHTML ="Helligkeit: "+ Brightness(R,G,B);
           document.getElementById("schrift").style.backgroundColor = aktfarbe;
           document.getElementById("schrift").style.color = textfarbe(Brightness(R,G,B));
           }

    
  })
</script>

Ich hab mal die Funktion farbwechsler() auf alle 5 Sekunden gesetzt, für den Demo-Effekt.

Und hier noch das passende HTML zum Ausprobieren:

<body>

<h1>Beispiel Contrast Colors mit Javascript</h1>
<div id = "zufall">Schriftfarbe statisch</div>
<div id="inhalt">...</div>
<div id="rgb">...</div>
<div id="brightness">...</div>
<div id="schrift"><h1>Schriftfarbe dynamisch</h1></div>

</body>

Das wars! So gibt es immer lesbare Schrift auch auf zufällig generierten Hintergrundfarben.

Ne kleine Fingerübung: Beitragshitparade mit AJAX-Refresh

Weil ich mich dabei erwischt habe, dass ich immer wieder F5 drücke, wenn ich meine Beitragshitparade anschaue, bin ich auf die Idee gekommen, den Refresh der Anzeige alle x Sekunden automatisch einzubauen. Das geht in WordPress ganz flott, hatten wir auch alles so ähnlich schonmal, aber weil man so etwas immer wieder mal brauchen kann, hier der Code.

Wir basteln uns dafür natürlich ein Plugin

In das kommt zuallererst ein sehr kurzer Shortcode, der macht eigentlich nichts anderes als eine benannte Div  für die Ausgabe bereitzustellen.

<?php
/*
Plugin Name: Ajax Hitparade
Plugin URI: http://localhost/wp_ajax/wp-content/plugins/wp-ajax
Description: Ausgabe der beliebtesten Beiträge mit Ajax Refresh
Version: 1.0
Author: Evi Leu
Author URI: http://www.evileu.de
*/


 function a_ausgabe(){
  return "Die 10 beliebtesten Rezepte<br><div id='ajax_ausgabe'>...</div>";
  
 }
 add_shortcode('ajax_ausgabe', 'a_ausgabe');

Dann geben wir WordPress bekannt, dass wir einen Ajax-Call ausführen wollen:

/**************ajax-action für wordpress definieren*/ 
add_action( 'wp_ajax_hitparade_action', 'hitparade_action' );
add_action( 'wp_ajax_nopriv_hitparade_action', 'hitparade_action' );


Das Javascript

Jetzt binden wir unsere js-Datei mit dem Script ein, und geben ihr mit dem wp_localize_script den Pfad zur Ajax-URL von WordPress mit:

/*********Externes Script einbinden und Pfad zur admin-ajax.php übergeben*/
function myhitparade_js() {
      
    wp_enqueue_script('myhitparade-js', plugins_url().'/ajax-hitparade/wp_ajax_hitparade.js', array('jquery'), false, false);
    
    wp_localize_script( 'myhitparade-js', 'my_ajaxurl', admin_url( 'admin-ajax.php' ) );
 
   }
add_action('wp_enqueue_scripts', 'myhitparade_js');

Die Script-Datei wp_ajax_hitparade.js liegt in unserem Plugin-Verzeichnis und sieht so aus:

$(document).ready(function() {
     setInterval(myFunction, 1000)  
       
    });
    
        
        function myFunction(){
                
        
        var data = {
            'action': 'hitparade_action',
            
            };

        // der volle Pfad zur admin-ajax.php liegt auf my_ajaxurl
        jQuery.post(my_ajaxurl, data, function(response) {
                    
            document.getElementById("ajax_ausgabe").innerHTML = response;
            
        });
        } //*********************End myFunction

Der Witz ist hier natürlich das setInterval(), das führt unsere Funktion alle X Millisekunden aus. Ansonsten geben wir der Funktion nur mit, dass sie die Callback-Funktion hitparade_action ausführen soll, es gibt keine zu übergebenden Parameter ausser der Ajax-URL. Das Ergebnis des Calls wird in die div ajax_ausgabe geschrieben.

Die Callback-Funktion

Kommt als Letztes in unser Plugin, sie ist sehr simpel und besteht nur aus einer Query auf die Tabelle Counter und einem foreach für die Ausgabe:

/********Callback-Funktion**************/
function hitparade_action() {
    global $wpdb; 
  
    $alleposts = $wpdb->get_results( "SELECT * from counter ORDER BY zaehler DESC limit 10");
    foreach($alleposts as $einpost){
        
        echo $einpost->titel." ".$einpost->zaehler."</br>";
}
    /**********************************************/
    
    
    wp_die(); // this is required to terminate immediately and return a proper response
} //**********End function hitparade_action

Das sollts gewesen sein! Das Script checkt alle 1000 Millisekunden die Datenbank neu ab und aktualisiert die Anzeige dementsprechend. Viel Spaß beim Nachbauen!

Die Beitrags-Hitparade V.01

Das, meine verehrten Besucher, sind die am öftesten aufgerufenen Beiträge der letzten Tage, ermittelt mit dem Rezeptecounter-Plugin. Es befindet sich noch im Beta-Stadium, aber ich bin schon ganz zufrieden damit, so hab ich einen echten Überblick, welche Themen am meisten gesucht werden. Klickt nur fleissig weiter, ich zähl jetzt mit! 🙂

Die beliebtesten Beiträge

Noch mehr postmeta: benutzerdefinierte Felder in wooCommerce (370)
Kraut und Rüben auf der Datenbank: wo wooCommerce die Produktdaten speichert (330)
WordPress AJAX Autocomplete für Minimalisten (311)
Ein einfaches Joomla-Template erstellen (226)
Kontaktformular in Joomla mit Bordmitteln (200)
Turnverein: die Mitglieder-Stammdaten (188)
Die bessere Alternative zum -zigfachen Join: Kreuztabelle (165)
Joomla-Template 2: die index.php (158)
Joomla: ein einfaches Modul erstellen (146)
Schmankerl für alte Datenbanker: Zugriff auf externe Daten mit dem wpdb-Objekt (135)

 

Wen es interessiert: ich habe hier einen Durchschnitt von ca 100 Beitragsaufrufen am Tag, am Wochenende waren es sogar über 200 – nicht schlecht für einen kleinen privaten Plauderblog, finde ich.

PHP 5.6 forever? Und kleine Auswertung des Rezeptecounters

Also, ich geb zu das hat mit WordPress nur am Rande was zu tun, aber ich denke mir dass andere Leute vor dem selben Dilemma stehen und werde deswegen ein paar Worte zu dem Thema verlieren.

Man ist ja mittlerweile bei PHP 7.x angelangt, und es hat sich seit den 5er Versionen einiges getan, besonders in Sachen Datenbankzugriff. PDO und mysqli hat mysql abgelöst, und wir sind nicht abwärtskompatibel. Das würde mir noch nicht mal viel ausmachen, weil ich auf meiner evileu.de kaum PHP-Skripte für den Datenbankzugriff benutze, das läuft eigentlich alles über WordPress. Aber an manchen Stellen kneifts dann doch, und besonders für meine kleinen SEO-Statistiken hätt ich dann doch das eine oder andere PHP-Script gebraucht. Lokal (XAMPP) arbeite ich schon lang mit PHP 7 und hab eigentlich gar nicht mehr darüber nachgedacht ob ich die 5er Version nochmal brauchen könnte.

Aber die Live-Seite evileu de läuft bei meinem Provider (Strato) noch auf PHP 5.6, und das wird wohl auch so bleiben. Ein Anruf bei der Hotline hat ergeben, daß von einer Umstellung auf PHP 7.x dringendst abgeraten wird, weil es keine Garantie dafür gibt, dass vorhandene Webseiten dann noch laufen. Der Hotliner meinte sogar, dass in den meisten Fällen die Webseiten neu aufgesetzt werden müssten… Vielleicht bin ich da auch nur übervorsichtig, WordPress sollte ja eigentlich mit den neuesten PHP-Versionen klarkommen, aber „der Teufel ist ein Oachkatzl“ – weiss man’s genau?

Jedenfalls rät Strato von einer Umstellung dringend ab, und ich bekam auch die Auskunft dass bei denen noch 99,9% aller Webseiten auf PHP 5.6 laufen. Tscha, da werde ich mich wohl der Mehrheit anschliessen, schon auch weil es bei Umstellungsproblemen der PHP-Version von Strato keinen Support gibt, jedenfalls nicht an der kostenfreien Hotline. Bin bloss gespannt wie lange WordPress die Grätsche noch mitmacht – irgendwann wird es eine Version geben, die nur noch auf PHP 7.x läuft, und dann wirds echt spannend.

Was mach ich bis dahin? Plugins und Shortcodes statt PHP-Scripte nutzen, wo immer es möglich ist, weil ich beim Programmieren Knoten in die Tippfinger kriege, wenn ich ständig zwischen PHP 5 und 7 wechseln muss. Gefallen tut mir das nicht, aber ich hab ja etwa ein Dutzend WordPress-Blogs am Laufen, und da will ich nicht das geringste Risiko eingehen. Also, PHP 5.6 forever – obs mir gefällt oder nicht.

PHP-5-Script für die Auswertung des Rezeptecounters

Für alle, die es auch nicht mehr parat haben, wie das mit dem mysql_connect damals so ging, hier ein kleines Script zur Auswertung der counter-Tabelle (siehe dieser Beitrag zum Rezeptecounter) Die Tabelle ist ja recht einfach aufgebaut:

tabelle_counter

tabelle_counter

Fehlte eigentlich nur noch die Aufsummierung der Gesamtzahl der Aufrufe, das erledigen wir hier gleich in einem Aufwasch:

$dbh = mysql_connect("[hostname]", "[db user]", "[password]");
$query = "[db name]";
if (!mysql_query($query, $dbh)) die("Fehler bei der Datenbankverbindung.");

//Gesamtaufrufe summieren***********************
$abfrage = "select sum(zaehler) as summe from counter";
$ergebnis = mysql_query($abfrage,$dbh);

while($row = mysql_fetch_assoc($ergebnis))
{
echo "<h2>Seitenaufrufe seit 20.6.2018: ".$row['summe']."</h2>";
}

//*********************

$sql = "SELECT * FROM counter ORDER BY zaehler DESC";

$result = mysql_query($sql);

while ($row = mysql_fetch_assoc($result)) {
    echo $row["cid"]." ";
    echo $row["rezeptid"]." ";
    echo $row["titel"]." ";
    echo "Z&auml;hler: ".$row["zaehler"]."<br>";
}

mysql_free_result($result);
?>

Das liefert einen ganz netten Überblick, hier die Zahlen von hier im Bistro seit gestern:

ausgabe_rezeptecounter

ausgabe_rezeptecounter

Ich gebe zu man könnte es schöner formatieren, aber mir langt das für einen groben Überblick. Ist echt eine Alternative zum Visitor Counter, der ja leider wegen der DSGVO weg musste.

Der Shortcode für die Rezepthitparade

… musste auch nur um zwei Zeilen ergänzt werden, damit er die Gesamtzahl der Aufrufe mit ausgibt:

function el_rezepthitparade(){
    global $wpdb;
    echo "<h2>Die 10 beliebtesten Rezepte</h2>";
    
    $gesamt = $wpdb->get_var("SELECT SUM(zaehler) FROM counter");
    echo $gesamt." Rezeptaufrufe seit Beginn der Zählung Juni 2018<br>";
    
    $alleposts = $wpdb->get_results( "SELECT * FROM counter 
    ORDER BY zaehler DESC LIMIT 10");
    foreach ($alleposts as $einpost){
        
        $pfad = get_the_permalink($einpost->rezeptid);
        echo "<a href = '".$pfad."'>".$einpost->titel."</a> (".$einpost->zaehler.")<br>";
    }
}
add_shortcode('hitparade','el_rezepthitparade');

Den get_var kann man hier einwandfrei nutzen, weil nur ein Wert von der Query zurückgegeben wird, den kann man dann auch gleich direkt mit echo ausgeben.

Nachtrag für Zählung der Seitenaufrufe

Mein Rezeptecounter ist schon fleissig im Einsatz, und ich bin mit den aussagekräftigen Ergebnissen sehr zufrieden. Nur noch eine kleine Ergänzung: in meinem Handarbeitsblog ist es für mich auch interessant zu wissen, welche statischen Seiten wie oft aufgerufen werden. Die kommen mit einer ganz kleinen Ergänzung der Zähler-Function mit in die counter-Tabelle. Statt nur if (is_single())… frage ich ab if(is:single() or is_page()), und schon sind die statischen Seiten auch mit in der Statistik.

Noch’n Nachschlag: Aufrufe pro Tag

Ich hab in meinem Archiv gekramt und eine Funktion aus dem Selfphp-Forum ausgebuddelt, mit der man die exakte Anzahl von Tagen zwischen zwei gegebenen Tagesdaten ermitteln kann. Die nutzen wir doch gleich mal um einen Tagesdurchschnitt auszurechnen. Das Startdatum der Zählung wird einfach fest eingegeben, das Enddatum (aktueller Tag) mit der date()-Funktion erzeugt, die Gesamtzahl der Aufrufe haben wir ja aus der Query, die liegt auf der Variablen $gesamt.

$gesamt = $row['summe'];
$timeA = '20.06.2018'; 
 $timeB = date("d.m.Y"); 

 $differenz = seDay($timeA,$timeB,"dmY","."); 
 
echo '<h3>In ' . $differenz . ' Tagen '.$gesamt.
" Aufrufe, das macht im Durchschnitt ".round(($gesamt/$differenz))." Aufrufe pro Tag</h3>";

Die Funktion seDay könnt ihr hier nachschlagen:  http://www.selfphp.de/kochbuch/kochbuch.php?code=11

Viel Spaß beim Nachbauen!

WordPress Beiträge: einfache nummerische Pagination

Dies ist als Ableger des vorigen Beitrags entstanden, eine simple nummerische Pagination der Rezepte ist auch nicht wesentlich schwieriger als die alphabetische Pagination und kann ganz ähnlich konstruiert werden. Ich mache das wieder mit einem Shortcode in einem Plugin. Zuerst wird die Anzahl der pro Seite auszugebenden Rezepte festgelegt und ermittelt, wie viele Seiten das werden:

function el_num_pagination(){

//Anzahl Rezepte pro Seite festlegen
$pro_seite = 15;
    
//Anzahl aller veröffentlichten Rezepte bestimmen
global $wpdb;

         $alleposts = $wpdb->get_results( "SELECT * from wp_posts 
         where post_type like 'post' and post_status like 'publish'");
        
        $gefunden = $wpdb->num_rows;
        echo $gefunden." Rezepte insgesamt<br>";
        
        //ceil: nächsthöhere Ganzzahl
        $anzahl_seiten = ceil($gefunden/$pro_seite);
        //Debug-Ausgabe
        echo "Das sind: ".$anzahl_seiten." Seiten bei ".$pro_seite." Rezepten pro Seite";

Dann baue ich mir das Formular mit den Buttons für die Seitenzahlen zusammen:

//Formular mit Buttons
echo "<form action = '#' method = 'post'>";

for ($i=1; $i <=$anzahl_seiten; $i++){
    echo "<input type='submit' id='el_num_button' name='".$i."' value='".$i."'>";
}
echo "</form>";

Die Buttons werden in der style.css noch ein bisschen hübscher formatiert, die müssen nur ein wenig breiter werden:

#el_num_button{
    height:30px;
    width:24px;
    padding:2px;
    border: 2px solid white;
    margin 2px;
    padding: 1px 1px 1px;
}

Dann laufe ich wieder durch alle Seitenzahlen durch und frage mit dem if(isset()) ab, ob eine Seitenzahl angeklickt wurde. Falls ja, wird die Ausgabefunktion mit zwei Parametern aufgerufen, der Nummer der aktuellen Seite und der Anzahl der Rezepte pro Seite:

for ($j = 1; $j <= $anzahl_seiten; $j++){    
        if (isset($_POST[''.$j.''])){
            
            return el_num_aufruf($j,$pro_seite);
        }
    }

In der Ausgabefunktion nutze ich die Tatsache, dass man dem SQL LIMIT einen Offset mitgeben kann. Dieser muss bei 0 (Null) auf der Seite 1 anfangen, auf Seite 2 ist er dann einmal die Anzahl der Beiträge pro Seite, auf Seite drei zweimal etc… deswegen die Konstruktion mit dem $akt_seite-1:

function el_num_aufruf($akt_seite, $aufderseite){
    
        
    global $wpdb;
        
        //Limit Offset eins weniger als aktuelle Seite
        $hilf = ($akt_seite-1)*$aufderseite;
        
        $alleposts = $wpdb->get_results( "SELECT * from wp_posts 
         where post_type like 'post' 
         and post_status like 'publish'
         LIMIT ".$hilf.", ".$aufderseite." ");
        $gefunden = $wpdb->num_rows;
        
        foreach ($alleposts as $einpost){
            
            $pfad = get_the_permalink($einpost->ID);
            echo "<a href = '".$pfad."'>".$einpost->post_title."</a><br>";
            
        }
    
} //end function el_num_aufruf

Am Ende gebe ich die Rezepte mit den Links wieder mit einem Foreach aus. Das wars!

15_pro_seite

15_pro_seite

Das funktioniert auch mit anderen Werten für die Ausgabe pro Seite, ich nehm mal 7:

7_pro_seite

7_pro_seite

Oder wesentlich mehr, 30, da sind wir komplett flexibel:

30_pro_seite

30_pro_seite

Man könnte jetzt natürlich noch ein Auswahlfeld für den Benutzer einbauen, so dass er selbst wählen kann wieviele Rezepte pro Seite er angezeigt haben möchte, aber damit kann sich jeder selber amüsieren. Ich werde eh die alfabetische Pagination nehmen, die taugt mir besser für meine Anwender.

WordPress Beiträge: alphabetische Pagination ganz spartanisch

Ich habe mich in einem kleinen PHP-Projekt kürzlich ausführlich mit seitenweiser und alfabetischer Pagination bei der Ausgabe von Datenbankabfragen beschäftigt, und bin dabei auf eine Idee gekommen, wie man das in WordPress relativ einfach umsetzen kann. Ich geh mal wieder auf meine Rezepte los, das sind über 300 Stück, da ist das alte Inhaltsverzeichnis doch inzwischen ein wenig lang.

Die Aufgabenstellung

Ich möchte eine Anzeige aller Buchstaben A-Z, und wenn man auf einen Buchstaben klickt, soll eine Liste aller Rezepte ausgegeben werden, die mit diesem Buchstaben anfangen. Klingt simpel, ist auch nicht arg schwierig unzusetzen. Ich mache ein Plugin daraus, und packe die ganze Sache in einen Shortcode.

Die Anzeige: ich nehme ein Formular

Dafür konstruiere ich mir ein Hilfs-Array, in das erstmal alle Buchstaben von a-z reinkommen. Groß/Kleinschreibung ist uninteressant, da MySQL-LIKE nicht case sensitive ist. Das Formular sieht erstmal so aus:

//Buchstaben a-z in Array schreiben
$letters = array();
for ($i = 'a', $j = 1; $j <= 26; $i++, $j++) {
    $letters[$j] = $i;    
}
//Formular mit Buttons
echo "<form action = '#' method = 'post'>";

for ($i=1; $i <=26; $i++){
    echo "<input type='submit' id='el_button' name='".$letters[$i]."' value='".$letters[$i]."'>";
}
    echo "</form>";

Ich steppe durch mein Buchstabenarray durch und lege für jeden Buchstaben einen Button mit dem Namen des aktuellen Buchstabens und der id el_button an. Das erzeugt 26 Buttons, die sehen erstmal noch recht häßlich aus:

buttons_ungestylt

buttons_ungestylt

Ein kleiner Eingriff in die style.css des Child Themes verschönert das Ganze beträchtlich.

#el_button{
    height:30px;
    width:18px;
    padding:2px;
    border: 2px solid white;
    margin 2px;
    padding: 1px 1px 1px;
}

Das Ergebnis kann sich schon besser sehen lassen:

buttons_gestylt

buttons_gestylt

Jetzt klemme ich mir wieder mein Buchstabenarray und steppe es wieder von 1 bis 26 durch. Für jeden Buchstaben frage ich mit einem if isset(…) ab, ob der entsprechende Button angeklickt wurde, und rufe falls ja meine Ausgabefunktion auf, die kriegt den aktuellen Buchstaben als Parameter übergeben.

for ($j = 1; $j <= 26; $j++){    
        if (isset($_POST[''.$letters[$j].''])){
            
            return el_aufruf("".$letters[$j]."");
        }
    }

Die Ausgabefunktion

… geht mit dem übergebenen Buchstaben auf die Tabelle wp_posts los und holt mir mit dem post_title LIKE ‚x%‘ alle veröffentlichten Rezepte, die mit diesem Buuchstaben anfangen. Ausgegeben wird die Sache wieder mal mit einem foreach, und ich hole mir gleich noch den Permalink und bastle einen Link zum Rezept daraus.

function el_aufruf($stabe){
    global $wpdb;
         $alleposts = $wpdb->get_results( "SELECT * from wp_posts 
         where post_title like '".$stabe."%' 
         and post_type like 'post' 
         and post_status like 'publish'
         order by post_title");
        $gefunden = $wpdb->num_rows;
        
        echo "<h2>".$gefunden." Rezepte zum Buchstaben ".strtoupper($stabe)."</h2>";
        
        foreach ($alleposts as $einpost){
            
            $pfad = get_the_permalink($einpost->ID);
            echo "<a href = '".$pfad."'>".$einpost->post_title."</a><br>";
            
        }
    
} //end function el_aufruf

Das wars schon! Hier als Beispiel die Ausgabe zum Buchstaben M:

buchstabe_m

buchstabe_m

Kleiner Aufwand, praktisch brauchbares Ergebnis. Wenn man unterschiedliche Post Types hat, könnte man die Ausgabe auch hierauf noch einschränken, das ist vielleicht mal ganz nützlich. Ich hab aber nur die einfachen Posts als Rezepte, das ist für meine Zwecke völlig ausreichend.

Shortcodes: echo vs. return

Ich arbeite ja gern mit Shortcodes und packe da auch oft komplexere Funktionalitäten rein, weil sie so praktisch sind. Wenn man allerdings Shortcodes in Beiträge einbinden will, die auch noch Text enthalten, muss man ein bisschen aufpassen mit den Ausgaben, wo man echo und wo man return verwendet, sonst kann es zu unerwünschten Effekten kommen. Ich mach mal ein einfaches Beispiel.

Simpler Shortcode mit return:

function el_harmlosertext(){
    return "<strong>Ich bin ein komplett harmloser ShortcodeText</strong>";
}
add_shortcode('harmlos','el_harmlosertext');

Den kann man im Fliesstext platzieren wo man will, er wird an der richtigen Stelle ausgeführt. Im Editor sieht das so aus:

editor

editor

Das erzeugt diese Bildschirmausgabe:

bildschirm

bildschirm

Ändert man jedoch den Shortcode und macht aus dem return ein echo, funktioniert das nicht mehr, die Ausgabe erfolgt vor dem Fliesstext des Artikels.

vor_fliesstext

vor_fliesstext

Das ist etwas irritierend, und komplett lästig wird es, wenn man zum Beispiel die Ergebnisse einer Datenbankabfrage ausgeben möchte, die nicht so ohne weiteres in ein return-Statement zu packen sind. Ich stricke mal eine kurze Liste aller bisher veröffentlichten Posts, und möchte diese am Ende meines Beitrags ausgeben. Der Shortcode sieht erstmal so aus:

function el_mit_datenbankabfrage(){
    
     global $wpdb;
            
      //Bisherige Anzahl posts holen
        $alleposts = $wpdb->get_results( "SELECT * from wp_posts where post_status like 'publish'");
        $anzahl = $wpdb->num_rows;
        echo $anzahl." Datensätze gefunden und mit echo ausgegeben<br>";
        $ausgabe = array();
        $i=0;
        foreach($alleposts as $einpost){
            echo $einpost->post_title."<br>";
            
        }
       
}
add_shortcode('db_abfrage','el_mit_datenbankabfrage');

Hier kann man das echo nicht einfach mit einem return ersetzen, weil sonst der foreach nach dem ersten Durchgang abbricht. So lassen kann man es aber auch nicht, weil die Liste so wie der Shortcode jetzt aussieht immer vor dem Fliesstext des Artikels ausgegeben wird:

echo_vor_text

echo_vor_text

Abhilfe: wir packen die Ausgaben des foreach in einen String und verketten den innerhalb der Schleife. Die Funktion des Shortcodes wird wie folgt geändert:

function el_mit_datenbankabfrage(){
    
     global $wpdb;
            
      //Bisherige Anzahl posts holen
        $alleposts = $wpdb->get_results( "SELECT * from wp_posts where post_status like 'publish'");
        $anzahl = $wpdb->num_rows;
        echo $anzahl." Datensätze gefunden und mit echo ausgegeben<br>";
        $ausgabe = "";
       
        foreach($alleposts as $einpost){
            $ausgabe=$ausgabe.$einpost->post_title."<br>";
            
        }
        
    return "Mit return ausgegeben:<br>".$ausgabe;
}

Diesen String gebe ich dann mit dem return der Shortcode-Funktion zurück, und meine Liste wird brav ans Ende des Beitrags gestellt, da wo ich sie auch haben will.

return

return

Ich könnte die Ausgabe auch mitten im Text platzieren, funktioniert auch. Man sieht hier auch noch, dass die mit echo ausgegebene Anzahl der Datensätze gnadenlos vor dem Beitragstext landet:

mitten_im_text

mitten_im_text

Das ist alles natürlich nur relevant, wenn man den Shortcode auf einer Seite oder auf einem Beitrag platzieren möchte, die sonst auch noch Text enthalten, bei sonst leeren Posts/Pages ist es egal. Wissen muss man halt, dass return und echo hier völlig unterschiedliche Effekte in der Ausgabe erzielen, dann kann man auch gegensteuern.

Rezeptecounter: so wird ein Widget draus

Wie man in WordPress ein eigenes Widget erstellt, habe ich in diesem Beitrag: Widget-Basteln macht Spaß schon mal ausführlich vorgestellt, deswegen machen wir das hier im Schnelldurchgang. Der Code läßt sich relativ leicht auf die Anforderungen für die Rezepthitparade anpassen. Wir brauchen zwei Eingabefelder, eines für den Titel des Widgets, und eins für die auszugebende Anzahl an Rezepten. In den OpCode des Widgets kommt unsere Ausgabelogik, die können wir 1:1 aus dem vorigen Beitrag übernehmen.

Nur kurz zur Erinnerung: Widgets werden von der Struktur her genau wie Plugins in einer eigenen PHP-Datei angelegt, die kommt auch ins Plugins-Verzeichnis. Hier mal der Code ohne die Ausgabefunktionalität:

<?php
/*
Plugin Name: Hitparaden Widget
Plugin URI: http://evileu.de/wordpress
Description: Gibt die am öftesten aufgerufenen Rezepte aus, Anzahl vom Benutzer wählbar
Author: Evi Leu
Version: 1.0
Author URI: http://evileu.de
*/


class HitparadenWidget extends WP_Widget
{
  function HitparadenWidget()
  {
    $widget_ops = array('classname' => 'HitparadenWidget', 'description' => 'Zeigt die am öftesten aufgerufenen Rezepte an' );
    $this->WP_Widget('HitparadenWidget', 'Hitparade', $widget_ops);
  }
 
  function form($instance)
  {
    $instance = wp_parse_args( (array) $instance, array( 'title' => '' ) );
    $title = $instance['title'];
        
    $instance = wp_parse_args( (array) $instance, array( 'anzahl' => '' ) );
    $anzahl = $instance['anzahl'];
    
    
?>
  <p><label for="<?php echo $this->get_field_id('title'); ?>">Titel: <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo attribute_escape($title); ?>" /></label></p>
  
  <p><label for="<?php echo $this->get_field_id('anzahl'); ?>">Anzahl: <input id="<?php echo $this->get_field_id('anzahl'); ?>" 
name="<?php echo $this->get_field_name('anzahl'); ?>" type="number" value="<?php echo attribute_escape($anzahl); ?>" /></label></p>
  
  
<?php
  }
 
  function update($new_instance, $old_instance)
  {
    $instance = $old_instance;
    $instance['title'] = $new_instance['title'];
    $instance['anzahl'] = $new_instance['anzahl'];
    return $instance;
  }
 
  function widget($args, $instance)
  {
    extract($args, EXTR_SKIP);
 
    echo $before_widget;
    
    $title = empty($instance['title']) ? ' ' : apply_filters('widget_title', $instance['title']);
    $anzahl    = empty( $instance['anzahl'] ) ? '' : esc_attr( $instance['anzahl'] );
   
    // WIDGET CODE GOES HERE
    /**********************/    
    //END WIDGET CODE
    
    echo $after_widget;
  }
 
}
add_action( 'widgets_init', create_function('', 'return register_widget("HitparadenWidget");') );?>

Das ist das Gerippe für das Widget, es werden zwei Eingabefelder erzeugt und deren Werte auf die Variablen $title und $anzahl gelegt. Mit denen kann man weiterarbeiten, hier kommt der Code aus dem vorigen Beitrag nahezu unverändert rein:

// WIDGET CODE GOES HERE
    echo "<h2>".$title."</h2>";
    echo "<h3>Die ".$anzahl." beliebtesten Rezepte</h3>"; 
    
        //Bisher gespeicherte Rezepte holen
    global $wpdb;
        $alleposts = $wpdb->get_results( "SELECT * from wp_options where option_name like 'zaehler_%'");
        
        
        $rohdaten = array();
        $i=0;
        foreach($alleposts as $einpost){
            
            //Optionswerte auslesen            
            $meineOption = get_option($einpost->option_name);
            $o_zaehler = $meineOption['zaehler'];
            $o_titel = $meineOption['titel'];
            $o_id = $meineOption['id'];
            //debug unsortierte Ausgabe
            //echo $o_titel." ".$o_zaehler."<br>";
            
            //Array befüllen
            $rohdaten[$i]['zaehler']= $o_zaehler;
            $rohdaten[$i]['titel']= $o_titel;
            $rohdaten[$i]['id']= $o_id;
            $i=$i+1;
        }
        //echo "<h2>Hitparade:</h2>";
    
        $counter = array();
        foreach ($rohdaten as $key => $row)
        {
            $counter[$key] = $row['zaehler'];
        }
        array_multisort($counter, SORT_DESC, $rohdaten);


        $hilf = array_slice($rohdaten, 0, $anzahl);
        foreach($hilf as $roh){
                
                    echo $roh['titel']." (".$roh['zaehler'].")<br>";
                    
            }

    
    //END WIDGET CODE

Ich verwende nur noch den $title für die Überschrift des Widgets und die $anzahl für den array_slice, um die Anzahl der ausgegebenen Datensätze zu begrenzen. Das wars auch schon! Nach erfolgreicher Aktivierung präsentiert sich das Widget so:

hitparadenwidget

hitparadenwidget

Die Ausgabe sieht so aus:

hitparade_ausgabe

hitparade_ausgabe

Funkt, kann man so lassen.

 

Rezeptecounter revisited: für WordPress-Puristen

Ich arbeite ja gern mit eigenen Tabellen, aber die WordPress-Puristen schreien da immer gleich Zetermordio und wollen eine WordPress-konforme Lösung sehen. Deswegen stricke ich die Logik für das Wegschreiben des Rezeptezählers nochmal um und verstaue die relevanten Daten in der wp_options. Ich habe zu jedem Datensatz drei relevante Kennzahlen: die ID des Rezeptes, den Titel und den Zählerstand – wobei man den Titel auch nachträglich über die ID dazujoinen könnte, der ist hier eigentlich redundant. Diese drei packe ich in ein Array, und mit diesem Array füttere ich die Option. Das Ganze sieht dann so aus:

function el_rezeptcounter() {
 
 if(is_single()) {
 
 //id und titel abholen
 $akt_id = get_the_id();
 $akt_titel = get_the_title();
 
 //option nachschauen
 $meineOption = get_option('zaehler_'.$akt_id.'');
 $o_zaehler = $meineOption['zaehler'];
 
 if ($o_zaehler == ''){$zahl = 0;}else{$zahl = $o_zaehler;}
 
 echo "Dieses Rezept wurde bisher ".$zahl." mal aufgerufen";
 
 if($o_zaehler == ''){
 
 //neu eintragen
 $myOptions = array(
 'zaehler' => 1,
 'id' => $akt_id,
 'titel' => html_entity_decode($akt_titel)
 );
 
 update_option('zaehler_'.$akt_id, $myOptions);
 
 }else{
 
 //Zähler updaten
 $o_zaehler = $o_zaehler +1;
 
 $myOptions = array(
 'zaehler' => $o_zaehler,
 'id' => $akt_id,
 'titel' => html_entity_decode($akt_titel)
 );
 
 update_option('zaehler_'.$akt_id, $myOptions); 
 }
 
 } //End von if( is_single)
 
}

Genau genommen könnte man sich die if-else-Konstruktion sparen und in jedem Fall einen Update mit Zähler+1 machen, da WordPress mit update_option die Option neu anlegt, falls sie noch nicht existieren sollte.

WordPress macht aus den Arrays serialisierte Strings, da sieht dann der option_value zum Beispiel so aus:

a:3:{s:7:"zaehler";i:4;s:2:"id";i:1392;s:5:"titel";s:20:"Test für Backwerk";}

Das kann man Klartext lesen:

a für Array, Länge drei{s für string: Länge7:wert „zaehler“; i für integer:Wert 4…

… und so weiter. Um jetzt zum Beispiel an den Wert des Zählers heranzukommen, verwendet man folgende Syntax:

$meineOption = get_option('[name_der_option]');
 $zaehler = $meineOption['zaehler'];

Da $meineOption hier ein Array zurückgibt, könnte man auch über die Einträge iterieren und alle ausgeben, wenn man es braucht.

Jedenfalls haben wir jetzt unsere relevanten Daten WordPress-konform in der wp_options gespeichert. Wie aber kommen wir jetzt an die Auswertung? Mit einem SQL sind die serialisierten Werte nicht zu packen, da muss eine andere Lösung her. Na ja, pack’mas.

Auswertung des Rezeptecounters aus der wp_options

Dafür holt man sich mit einem Select.. WHERE option_name like ‚zaehler_%‘ alle relevanten Einträge aus der wp_options. Die Werte kann man schon mal mit einem foreach ausgeben:

function el_opcounter_hitparade(){
 
 //Bisher gespeicherte Rezepte holen
 global $wpdb;
 $alleposts = $wpdb->get_results( "SELECT * from iii_wpoptions where option_name like 'zaehler_%'");
 $anzahl = $wpdb->num_rows;
 echo "Anzahl gefunden= ".$anzahl."<br>";
 
 
 foreach($alleposts as $einpost){
 
 //Optionswerte auslesen 
 $meineOption = get_option($einpost->option_name);
 $o_zaehler = $meineOption['zaehler'];
 $o_titel = $meineOption['titel'];
 $o_id = $meineOption['id'];
 echo $o_id." ".$o_titel." ".$o_zaehler."<br>";
 }
 
}

Damit kriegt man schon mal die Liste.

unsortiert

unsortiert

Die hätte ich jetzt aber gern nach der Anzahl der Aufrufe absteigend sortiert, aber hier geht nix mit Order by, mit SQL ist das leider nicht zu packen. Das muss mit PHP, und das ist nicht ohne, dafür muss man einen multisort bemühen. Für den lesen wir unsere Daten in ein Array ein, das machen wir so:

Einlesen der Rohdaten in ein Array

Dafür kann unser Select nochmal herhalten:

//Bisher gespeicherte Rezepte holen
 global $wpdb;
 $alleposts = $wpdb->get_results( "SELECT * from iii_wpoptions where option_name like 'zaehler_%'");
 $anzahl = $wpdb->num_rows;
 echo "Anzahl gefunden= ".$anzahl."<br>";
 
 $rohdaten = array();
 $i=0;
 foreach($alleposts as $einpost){
 
 //Optionswerte auslesen 
 $meineOption = get_option($einpost->option_name);
 $o_zaehler = $meineOption['zaehler'];
 $o_titel = $meineOption['titel'];
 $o_id = $meineOption['id'];
 //debug unsortierte Ausgabe
 //echo $o_titel." ".$o_zaehler."<br>";
 
 //Array befüllen
 $rohdaten[$i]['zaehler']= $o_zaehler;
 $rohdaten[$i]['titel']= $o_titel;
 $rohdaten[$i]['id']= $o_id;
 $i=$i+1;
 }

Jetzt wirds ein bisschen tricky. Ich hab mir folgende Lösung ergooglet:

Array als Parameter für den multisort

Unsere Daten stecken jetzt in dem Array $rohdaten. Jetzt brauchen wir aber noch ein zweites Array, um den array_multisort (s. PHP-Handbuch) damit zu bedienen, und zwar muss dieses die Spalte enthalten, nach der sortiert werden soll. Das Ganze sieht dann so aus:

$counter = array();
foreach ($rohdaten as $key => $row)
{
 $counter[$key] = $row['zaehler'];
}
array_multisort($counter, SORT_DESC, $rohdaten);

Damit werden die Rohdaten nach dem Zähler sortiert, und zwar DESC also absteigend. Jetzt können wir die ganze Chose als Hitparade ausgeben:

foreach($rohdaten as $roh){
 
 echo $roh['titel']." (".$roh['zaehler'].")<br>";
 
 }

Das sieht jetzt schon ganz gut aus.

hitparade

hitparade

Natürlich kann man auch hier anhand der Rezept-IDs einen Link zum Rezept mit dem get_permalink einbauen, aber das spare ich mir jetzt. Wenn man nur die ersten X Rezepte ausgeben möchte, den SQL um ein LIMIT X ergänzen. Achtung, Denkfehler! Das klappt natürlich nicht, da der Select die Daten nicht vorsortiert ausgeben kann. Da muss man dann nur die ersten X Zeilen des Arrays ausgeben, sonst wird das nix. Ich pack das Ding doch noch in ein Widget mit Benutzereingabe für die X auszugebenden Rezepte! Kurze Lösung: man verwendet ein array_slice:

$hilf = array_slice($rohdaten, 0, 3);
foreach($hilf as $roh){
        
            echo $roh['titel']." (".$roh['zaehler'].")<br>";
            
            }

Ich finde den Aufwand zum Auswerten der serialisierten Daten schon recht kopflastig, das geht über die eigene Tabelle wesentlich komfortabler. Na ja, kann jeder selber entscheiden, welche Lösung er einsetzen möchte.

Noch eine Anmerkung am Schluss

Ich bin gefragt worden, warum ich den Code für das Wegschreiben des Rezeptezählers nicht in einen Filter gepackt habe, sondern als Shortcode in die single.php eingefügt habe. Das hat einen guten Grund: ich habe mit komplexeren Filtern bei WordPress schon schlechte Erfahrungen gemacht, insbesondre bei eingebauten Datenbankabfragen kann es da zu kuriosen Nebenwirkungen kommen. Jedenfalls ist der Shortcode-Aufruf in der single.php eine unkomplizierte Lösung und liefert korrekte Ergebnisse, damit kann ich ganz gut leben.

Alternative zum Besucherzähler: der Rezeptecounter

Tscha, der nette kleine Visitor Counter auf meinen Webseiten musste leider weg, weil der die IP-Adressen der Besucher bunkert, und das ist nach der neuen Datenschutz-Verordnung nicht mehr erlaubt, IP-Adressen zählen als schutzwürdige persönliche Daten und dürfen nicht mehr ungecrypted gespeichert werden. Mich interessiert aber trotzdem, was die Besucher auf meinen Seiten anzieht, und ich hab mir fürs Inselfisch-Kochbuch eine „kleine“ Alternative gebastelt.

Rezeptecounter ganz minimalistisch

Eigentlich ist es für mich am Interessantesten, welche Rezepte am öftesten aufgerufen werden, die Aufrufe der wenigen statischen Seiten interessieren mich eher weniger. Das könnte ich mir zwar aus den Logfiles meines Providers herausfieseln, aber der Aufwand ist doch relativ hoch. Das geht auch einfacher, dachte ich mir, da klemme ich eine kleine PHP-Funktion ans Ende jedes Rezeptes und schreibe mir die Aufrufe in eine eigene Tabelle. Damit habe ich eine prima kleine Rezepte-Hitparade und kann z.B. die 10 beliebtesten Rezepte ausgeben oder sonstwas damit anstellen.

Damit kann ich in der single.php ansetzen und mir da einen kleinen Zähler einbauen, der mir in die Datenbank bunkert wie oft das jeweilige Rezept schon aufgerufen wurde. Die Funktion kommt in einen Shortcode, und der wiederum kommt in ein Plugin, der Plugin-Aufruf kommt ins Child-Theme in die single.php nach dem Content.

Die Tabelle counter

ist ganz einfach strukturiert:

tabelle_counter

tabelle_counter

Eine Autowert-ID, und drei Felder für Rezept-ID, Titel und der Zähler für die Aufrufe, das wars schon.

Die Funktionalität des Shortcodes

… ist auch nicht weiter kompliziert. Ich hole mir ID und Titel des aktuellen Rezeptes ab und gehe mit der ID auf die Tabelle counter. Falls die ID da noch nicht vorhanden ist, mache ich einen Insert, falls sie schon da ist, setze ich den Zähler um eins hoch und mache einen Update. Das wars schon!

function el_rezeptcounter() {
    
  if(is_single()) {
      
      //id und titel abholen
      global $wpdb;
      $akt_id = get_the_id();
      $akt_titel = get_the_title();
      
      //Bisherige Anzahl holen
        $alleposts = $wpdb->get_results( "SELECT * from counter where rezeptid = ".$akt_id."");
        $anzahl = $wpdb->num_rows;
        
        $zaehler = 0;
        foreach($alleposts as $einpost){
            $zaehler = $einpost->zaehler;
        }
        
        echo "Dieses Rezept wurde bisher ".$zaehler." mal aufgerufen";
        
        if($anzahl == 0){
            
            //Neuen Aufruf eintragen
            $wpdb->insert('counter', array(
            'rezeptid' => $akt_id,
            //Sonderbehandlung für - und " usw.
            'titel' => html_entity_decode($akt_titel),
            'zaehler' => 1
            ));
            
        }else{
            
            //Zähler updaten
            $zaehler = $zaehler +1;
            
            $wpdb->update( 
                'counter', 
                array( 
                    'zaehler' => $zaehler  // int
                  ), 
                array( 'rezeptid' => $akt_id )
            );
                    
        }
        
  } //End von if( is_single)
  
}
add_shortcode ('counter', 'el_rezeptcounter');

Dabei kann man sich überlegen, ob man bei der Ausgabe der bereits erfolgten Aufrufe bei 0 oder bei 1 das zählen anfängt, das ist Geschmackssache. Korrekter ist es wahrscheinlich, mit dem aktuell erfolgten Aufruf bei 1 anzufangen, Dann sähe die Zeile mit dem Zähler für die Ausgabe so aus:

if ($o_zaehler == ''){$zahl = 1;}else{$zahl = $o_zaehler+1;}

Den html_entity_decode($akt_titel) brauchts, weil ich in meinen Titeln auch mal Zeichen wie – oder “ verwende, damit das in der Datenbank sauber ankommt.

Der Aufruf des Shortcodes in der single.php

… wird nach Wunsch vor oder nach dem Content platziert:

       <!--Shortcode für den Rezepte-Counter-->
       <?php echo do_shortcode("[counter]"); ?>

Und so sieht die Ausgabe aus:

4malaufgerufen

4malaufgerufen

Update und Tipp:

Man kann die Counter-Funktionalität statt in einen Shortcode auch in einen Filter packen. Ich bin zwar mit komplexen Filtern in WordPress schon manchmal auf die Nase gefallen, aber hier scheint es stabil zu funktionieren. Der Code bleibt gleich, nur setze ich dann den Filter auf the_content:

function el_rezeptcounter($content) {
    
  if(is_single()) {
  ...
  ...(Hier kommt der Code wie oben)
  ...
      .
  } //End von if( is_single)
  return $content;
}
add_filter( 'the_content', 'el_rezeptcounter' );

Damit kann man sich den Umbau der single.php sparen.

Die Counter-Tabelle

Die Tabelle counter ist sehr übersichtlich, man kann sie sich gleich mal nach dem Zähler sortieren und sieht sofort, welche Rezepte die meisten Aufrufe haben.

counter_mit_eintraegen

counter_mit_eintraegen

Das kann man natürlich hübsch für eine Ausgabe z.B. als Rezept-Hitparade verwenden, dafür basteln wir uns:

Den Hitparaden-Shortcode

kann man sich selber dahin platzieren wo man ihn am liebsten hat, die Konstruktion ist denkbar einfach:

function el_rezepthitparade(){
    global $wpdb;
    echo "<h2>Die beliebtesten Rezepte</h2>";
    $alleposts = $wpdb->get_results( "SELECT * FROM counter ORDER BY zaehler DESC");
    foreach ($alleposts as $einpost){
        
        echo $einpost->titel." (".$einpost->zaehler.")<br>";
    }
}
add_shortcode('hitparade','el_rezepthitparade');

Ausgabe:

diebeliebtestenzezepte

diebeliebtestenzezepte

Man kann jetzt noch die Anzahl der ausgegebenen Zeilen mit einem LIMIT steuern, aber man kann auch noch ganz was anderes machen, nämlich das Ganze in ein Widget packen und die Anzahl der auszugebenden Zeilen als Benutzereingabe abfragen. Aber das ist dann doch recht aufwendig, ich nehme hier mal lieber eine kleine Lösung:

Shortcode in Text-Widget packen

Dafür zieht man sich einfach ein Text-Widget an die passende Stelle und gibt hier nur den Shortcode ein, z.B.

Die beliebtesten Beiträge

Noch mehr postmeta: benutzerdefinierte Felder in wooCommerce (370)
Kraut und Rüben auf der Datenbank: wo wooCommerce die Produktdaten speichert (330)
WordPress AJAX Autocomplete für Minimalisten (311)
Ein einfaches Joomla-Template erstellen (226)
Kontaktformular in Joomla mit Bordmitteln (200)
Turnverein: die Mitglieder-Stammdaten (188)
Die bessere Alternative zum -zigfachen Join: Kreuztabelle (165)
Joomla-Template 2: die index.php (158)
Joomla: ein einfaches Modul erstellen (146)
Schmankerl für alte Datenbanker: Zugriff auf externe Daten mit dem wpdb-Objekt (135)
. Wenn das nicht funktioniert, sind die Shortcodes für Textwidgets noch nicht enabled, das geht aber mit einer Zeile im Plugin oder in der functions.php des Child-Themes:

add_filter('widget_text', 'do_shortcode');

Das sollte es gewesen sein. Wir hübschen die Ausgabe noch mit Links zu den Rezepten auf, das ist auch nicht weiter schwierig, wir haben ja die IDs und packen das mit in den foreach:

foreach ($alleposts as $einpost){
        
        $pfad = get_the_permalink($einpost->rezeptid);
        echo "<a href = '".$pfad."'>".$einpost->titel."</a> (".$einpost->zaehler.")<br>";
    }

Jetzt ist es aber schön genug!

widgetmit_links

widgetmit_links

Nachschlag für WordPress-Puristen

Ich bin darauf hingewiesen worden, dass man die Anzahlen der Rezeptaufrufe auch in der wp_options speichern könnte, das wäre die sauberere Lösung. Ja bittesehr, kann man, ist nicht besonders schwierig. Man muss sich halt überlegen, wie man die Options benennt, damit man sie nachher auch auswerten kann. Ich hab da mal einen Versuch gemacht und die Optionsnamen nach dem Muster zaehler_[beitragsid] zusammengeschraubt. D:ie Funktion zum Wegschreiben ist recht übersichtlich geworden:

function el_rezeptcounter() {
    
  if(is_single()) {
      
      //id und titel abholen
      $akt_id = get_the_id();
      $akt_titel = get_the_title();
      
      //option nachschauen
      $o_zaehler = get_option('zaehler_'.$akt_id.'');
        
        if ($o_zaehler == ''){$zahl = 0;}else{$zahl = $o_zaehler;}
        
        echo "Dieses Rezept wurde bisher ".$zahl." mal aufgerufen";
        
        if($o_zaehler == ''){
            
            update_option('zaehler_'.$akt_id, 1);
            
        }else{
            
            //Zähler updaten
            $o_zaehler = $o_zaehler +1;    
            update_option('zaehler_'.$akt_id, $o_zaehler);        
        }
        
  } //End von if( is_single)
  
}

Man kann hier ohne Gefahr update_option() verwenden, da es eine Option einfach neu anlegt, falls sie noch nicht vorhanden sein sollte. Das funktioniert soweit ganz gut und hat hier zum Testen etliche Einträge korrekt in meiner wp_options hinterlassen:

wp_options

wp_options

Eine Übersicht bekäme man im ersten Ansatz mit diesem Select heraus:

( "SELECT * from wp_options where option_name like 'zaehler_%' 
ORDER BY option_value DESC");

Was mir an dieser Lösung allerdings nicht gefällt: wie wertet man das jetzt aus und kriegt die Rezepttitel mit zu den Zählerständen? Als Optionsnamen nur die Rezept-ID allein (ohne das zaehler_ vorneweg) zu vergeben wäre ein Lösungsansatz, aber das gefällt mir nicht so recht.

Man könnte natürlich in den option_value ein Array mit ID, Zähler und Titel packen und WordPress die Daten serialisieren lassen (hier bei wpengineer.com ein nettes Tutorial zu dem Thema), aber das ist mir eigentlich zu umständlich, da hat man dann das G’frett damit, die Daten wieder einzeln rauszufieseln. Da bleibe ich lieber bei meinem „kurzen Dienstweg“ mit der eigenen Tabelle.

Update

Ich bin gefragt worden, ob ich nicht ein Beispiel für das Wegschreiben der Options als Array bringen könnte. Ja OK, machen wir, aber dazu gibts einen neuen Beitrag.