{"id":1222,"date":"2018-06-03T15:02:20","date_gmt":"2018-06-03T13:02:20","guid":{"rendered":"http:\/\/evileu.de\/zum-schwarzen-pinguin\/?p=1222"},"modified":"2018-06-08T17:23:15","modified_gmt":"2018-06-08T15:23:15","slug":"rezeptecounter-revisited-fuer-wordpress-puristen","status":"publish","type":"post","link":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/2018\/06\/03\/rezeptecounter-revisited-fuer-wordpress-puristen\/","title":{"rendered":"Rezeptecounter revisited: f\u00fcr WordPress-Puristen"},"content":{"rendered":"<p>Ich arbeite ja gern mit eigenen Tabellen, aber die WordPress-Puristen schreien da immer gleich Zetermordio und wollen eine WordPress-konforme L\u00f6sung sehen. Deswegen stricke ich die Logik f\u00fcr das Wegschreiben des Rezeptez\u00e4hlers 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\u00e4hlerstand &#8211; wobei man den Titel auch nachtr\u00e4glich \u00fcber die ID dazujoinen k\u00f6nnte, der ist hier eigentlich redundant. Diese drei packe ich in ein Array, und mit diesem Array f\u00fcttere ich die Option. Das Ganze sieht dann so aus:<\/p>\n<pre>function el_rezeptcounter() {\r\n \r\n if(is_single()) {\r\n \r\n \/\/id und titel abholen\r\n $akt_id = get_the_id();\r\n $akt_titel = get_the_title();\r\n \r\n \/\/option nachschauen\r\n<span style=\"color: #ff0000;\"> $meineOption = get_option('zaehler_'.$akt_id.'');<\/span>\r\n<span style=\"color: #ff0000;\"> $o_zaehler = $meineOption['zaehler'];<\/span>\r\n \r\n if ($o_zaehler == ''){$zahl = 0;}else{$zahl = $o_zaehler;}\r\n \r\n echo \"Dieses Rezept wurde bisher \".$zahl.\" mal aufgerufen\";\r\n \r\n if($o_zaehler == ''){\r\n \r\n <span style=\"color: #008000;\">\/\/neu eintragen<\/span>\r\n<span style=\"color: #008000;\"> $myOptions = array(<\/span>\r\n<span style=\"color: #008000;\"> 'zaehler' =&gt; 1,<\/span>\r\n<span style=\"color: #008000;\"> 'id' =&gt; $akt_id,<\/span>\r\n<span style=\"color: #008000;\"> 'titel' =&gt; html_entity_decode($akt_titel)<\/span>\r\n<span style=\"color: #008000;\"> );<\/span>\r\n \r\n <span style=\"color: #ff0000;\">update_option('zaehler_'.$akt_id, <span style=\"color: #008000;\">$myOptions<\/span>);<\/span>\r\n \r\n }else{\r\n \r\n \/\/Z\u00e4hler updaten\r\n $o_zaehler = $o_zaehler +1;\r\n \r\n <span style=\"color: #008000;\">$myOptions = array(<\/span>\r\n<span style=\"color: #008000;\"> 'zaehler' =&gt; $o_zaehler,<\/span>\r\n<span style=\"color: #008000;\"> 'id' =&gt; $akt_id,<\/span>\r\n<span style=\"color: #008000;\"> 'titel' =&gt; html_entity_decode($akt_titel)<\/span>\r\n<span style=\"color: #008000;\"> );<\/span>\r\n \r\n <span style=\"color: #ff0000;\">update_option('zaehler_'.$akt_id, <span style=\"color: #008000;\">$myOptions<\/span>);<\/span> \r\n }\r\n \r\n } \/\/End von if( is_single)\r\n \r\n}<\/pre>\n<p>Genau genommen k\u00f6nnte man sich die if-else-Konstruktion sparen und in jedem Fall einen Update mit Z\u00e4hler+1 machen, da WordPress mit update_option die Option neu anlegt, falls sie noch nicht existieren sollte.<\/p>\n<p>WordPress macht aus den Arrays serialisierte Strings, da sieht dann der option_value zum Beispiel so aus:<\/p>\n<pre>a:3:{s:7:\"zaehler\";i:4;s:2:\"id\";i:1392;s:5:\"titel\";s:20:\"Test f\u00fcr Backwerk\";}<\/pre>\n<p>Das kann man Klartext lesen:<\/p>\n<p>a f\u00fcr Array, L\u00e4nge drei{s f\u00fcr string: L\u00e4nge7:wert &#8222;zaehler&#8220;; i f\u00fcr integer:Wert 4&#8230;<\/p>\n<p>&#8230; und so weiter. Um jetzt zum Beispiel an den Wert des Z\u00e4hlers heranzukommen, verwendet man folgende Syntax:<\/p>\n<pre><span style=\"color: #000000;\">$meineOption = get_option('[name_der_option]');<\/span>\r\n<span style=\"color: #000000;\"> $zaehler = $meineOption['zaehler'];<\/span><\/pre>\n<p>Da $meineOption hier ein Array zur\u00fcckgibt, k\u00f6nnte man auch \u00fcber die Eintr\u00e4ge iterieren und alle ausgeben, wenn man es braucht.<\/p>\n<p>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\u00f6sung her. Na ja, pack&#8217;mas.<\/p>\n<h2>Auswertung des Rezeptecounters aus der wp_options<\/h2>\n<p>Daf\u00fcr holt man sich mit einem <strong>Select.. WHERE option_name like &#8218;zaehler_%&#8216; <\/strong>alle relevanten Eintr\u00e4ge aus der wp_options. Die Werte kann man schon mal mit einem foreach ausgeben:<\/p>\n<pre>function el_opcounter_hitparade(){\r\n \r\n \/\/Bisher gespeicherte Rezepte holen\r\n global $wpdb;\r\n $alleposts = $wpdb-&gt;get_results( \"SELECT * from iii_wpoptions where option_name like 'zaehler_%'\");\r\n $anzahl = $wpdb-&gt;num_rows;\r\n echo \"Anzahl gefunden= \".$anzahl.\"&lt;br&gt;\";\r\n \r\n \r\n foreach($alleposts as $einpost){\r\n \r\n \/\/Optionswerte auslesen \r\n $meineOption = get_option($einpost-&gt;option_name);\r\n $o_zaehler = $meineOption['zaehler'];\r\n $o_titel = $meineOption['titel'];\r\n $o_id = $meineOption['id'];\r\n echo $o_id.\" \".$o_titel.\" \".$o_zaehler.\"&lt;br&gt;\";\r\n }\r\n \r\n}<\/pre>\n<p>Damit kriegt man schon mal die Liste.<\/p>\n<div id=\"attachment_1227\" style=\"width: 522px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-1227\" decoding=\"async\" loading=\"lazy\" class=\"size-full wp-image-1227\" src=\"http:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-content\/uploads\/2018\/06\/unsortiert.jpg\" alt=\"unsortiert\" width=\"512\" height=\"318\" srcset=\"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-content\/uploads\/2018\/06\/unsortiert.jpg 512w, https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-content\/uploads\/2018\/06\/unsortiert-300x186.jpg 300w\" sizes=\"(max-width: 512px) 100vw, 512px\" \/><p id=\"caption-attachment-1227\" class=\"wp-caption-text\">unsortiert<\/p><\/div>\n<p>Die h\u00e4tte 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\u00fcr muss man einen multisort bem\u00fchen. F\u00fcr den lesen wir unsere Daten in ein Array ein, das machen wir so:<\/p>\n<h2>Einlesen der Rohdaten in ein Array<\/h2>\n<p>Daf\u00fcr kann unser Select nochmal herhalten:<\/p>\n<pre>\/\/Bisher gespeicherte Rezepte holen\r\n global $wpdb;\r\n $alleposts = $wpdb-&gt;get_results( \"SELECT * from iii_wpoptions where option_name like 'zaehler_%'\");\r\n $anzahl = $wpdb-&gt;num_rows;\r\n echo \"Anzahl gefunden= \".$anzahl.\"&lt;br&gt;\";\r\n \r\n $rohdaten = array();\r\n $i=0;\r\n foreach($alleposts as $einpost){\r\n \r\n \/\/Optionswerte auslesen \r\n $meineOption = get_option($einpost-&gt;option_name);\r\n $o_zaehler = $meineOption['zaehler'];\r\n $o_titel = $meineOption['titel'];\r\n $o_id = $meineOption['id'];\r\n \/\/debug unsortierte Ausgabe\r\n \/\/echo $o_titel.\" \".$o_zaehler.\"&lt;br&gt;\";\r\n \r\n \/\/Array bef\u00fcllen\r\n $rohdaten[$i]['zaehler']= $o_zaehler;\r\n $rohdaten[$i]['titel']= $o_titel;\r\n $rohdaten[$i]['id']= $o_id;\r\n $i=$i+1;\r\n }<\/pre>\n<p>Jetzt wirds ein bisschen tricky. Ich hab mir folgende L\u00f6sung ergooglet:<\/p>\n<h2>Array als Parameter f\u00fcr den multisort<\/h2>\n<p>Unsere Daten stecken jetzt in dem Array $rohdaten. Jetzt brauchen wir aber noch ein zweites Array, um den <a href=\"http:\/\/docs.php.net\/manual\/en\/function.array-multisort.php\">array_multisort (s. PHP-Handbuch)<\/a> damit zu bedienen, und zwar muss dieses die Spalte enthalten, nach der sortiert werden soll. Das Ganze sieht dann so aus:<\/p>\n<pre>$counter = array();\r\nforeach ($rohdaten as $key =&gt; $row)\r\n{\r\n $counter[$key] = $row['zaehler'];\r\n}\r\narray_multisort($counter, SORT_DESC, $rohdaten);<\/pre>\n<p>Damit werden die Rohdaten nach dem Z\u00e4hler sortiert, und zwar DESC also absteigend. Jetzt k\u00f6nnen wir die ganze Chose als Hitparade ausgeben:<\/p>\n<pre>foreach($rohdaten as $roh){\r\n \r\n echo $roh['titel'].\" (\".$roh['zaehler'].\")&lt;br&gt;\";\r\n \r\n }<\/pre>\n<p>Das sieht jetzt schon ganz gut aus.<\/p>\n<div id=\"attachment_1228\" style=\"width: 561px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-1228\" decoding=\"async\" loading=\"lazy\" class=\"size-full wp-image-1228\" src=\"http:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-content\/uploads\/2018\/06\/hitparade.jpg\" alt=\"hitparade\" width=\"551\" height=\"297\" srcset=\"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-content\/uploads\/2018\/06\/hitparade.jpg 551w, https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-content\/uploads\/2018\/06\/hitparade-300x162.jpg 300w\" sizes=\"(max-width: 551px) 100vw, 551px\" \/><p id=\"caption-attachment-1228\" class=\"wp-caption-text\">hitparade<\/p><\/div>\n<p>Nat\u00fcrlich kann man auch hier anhand der Rezept-IDs einen Link zum Rezept mit dem get_permalink einbauen, aber das spare ich mir jetzt. <del>Wenn man nur die ersten\u00a0X Rezepte ausgeben m\u00f6chte, den SQL um ein LIMIT\u00a0X erg\u00e4nzen. <\/del><strong>Achtung, Denkfehler!<\/strong> Das klappt nat\u00fcrlich 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\u00fcr die X auszugebenden Rezepte! Kurze L\u00f6sung: man verwendet ein array_slice:<del><br \/>\n<\/del><\/p>\n<pre>\r\n$hilf = array_slice($rohdaten, 0, <span style=\"color: #ff0000;\">3<\/span>);\r\nforeach($hilf as $roh){\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0echo $roh['titel'].\" (\".$roh['zaehler'].\")&lt;br&gt;\";\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}<\/pre>\n<p>Ich finde den Aufwand zum Auswerten der serialisierten Daten schon recht kopflastig, das geht \u00fcber die eigene Tabelle wesentlich komfortabler. Na ja, kann jeder selber entscheiden, welche L\u00f6sung er einsetzen m\u00f6chte.<\/p>\n<h2>Noch eine Anmerkung am Schluss<\/h2>\n<p>Ich bin gefragt worden, warum ich den Code f\u00fcr das Wegschreiben des Rezeptez\u00e4hlers nicht in einen Filter gepackt habe, sondern als Shortcode in die single.php eingef\u00fcgt habe. Das hat\u00a0einen guten Grund:\u00a0ich 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\u00f6sung und liefert korrekte Ergebnisse, damit kann ich ganz gut leben.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ich arbeite ja gern mit eigenen Tabellen, aber die WordPress-Puristen schreien da immer gleich Zetermordio und wollen eine WordPress-konforme L\u00f6sung sehen. Deswegen stricke ich die Logik f\u00fcr das Wegschreiben des Rezeptez\u00e4hlers 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 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[7,4,14,2],"tags":[],"_links":{"self":[{"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/posts\/1222"}],"collection":[{"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/comments?post=1222"}],"version-history":[{"count":10,"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/posts\/1222\/revisions"}],"predecessor-version":[{"id":1237,"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/posts\/1222\/revisions\/1237"}],"wp:attachment":[{"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/media?parent=1222"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/categories?post=1222"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/evileu.de\/zum-schwarzen-pinguin\/wp-json\/wp\/v2\/tags?post=1222"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}