<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Yoda Condition &#187; WordPress</title>
	<atom:link href="http://yoda.neun12.de/artikel-category/wordpress/feed" rel="self" type="application/rss+xml" />
	<link>http://yoda.neun12.de</link>
	<description>Debuggen du musst</description>
	<lastBuildDate>Sun, 18 May 2014 13:49:01 +0000</lastBuildDate>
	<language>de-DE</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.9.40</generator>
	<item>
		<title>TinyMCE zur Bearbeitung von Mediendateien</title>
		<link>http://yoda.neun12.de/artikel-143</link>
		<comments>http://yoda.neun12.de/artikel-143#comments</comments>
		<pubDate>Sun, 18 May 2014 13:40:02 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[HowTo]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=143</guid>
		<description><![CDATA[Alle sagen es geht nicht bis einer kommt und es einfach macht. So ging es mir bei diesem G+ Post. Das Problem ist einfach umrissen: In der Medienübersicht wird der Standard-Editor zur Bearbeitung der Medienbeschreibung verwendet. Der Wunsch war jedoch den TinyMCE dafür einzusetzen. Normalerweise reicht es dafür aus einen Filter auf die Editor-Einstellungen zu [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Alle sagen es geht nicht bis einer kommt und es einfach macht. So ging es mir bei <a title="Google+" href="https://plus.google.com/u/0/+ReneWelz/posts/H4RMbXhaVb2">diesem G+ Post</a>. Das Problem ist einfach umrissen: In der Medienübersicht wird der Standard-Editor zur Bearbeitung der Medienbeschreibung verwendet. Der Wunsch war jedoch den TinyMCE dafür einzusetzen. Normalerweise reicht es dafür aus einen Filter auf die Editor-Einstellungen zu verwenden und das Flag für den TinyMCE auf <code>True</code> zu setzen.</p>
<p>Wir haben im Prinzip drei Möglichkeiten um die Editor-Einstellungen zu beeinflussen. Zum einen dann wenn sie definiert werden.</p>
<pre class="brush:php">$editor_args = array(
	'textarea_name' =&gt; 'content',
	'textarea_rows' =&gt; 5,
	'media_buttons' =&gt; false,
	'tinymce' =&gt; false,
	'quicktags' =&gt; $quicktags_settings,
);

$editor_args = apply_filter( 'some_filter', $editor_args );
</pre>
<p>Leider ist dies nicht immer möglich, vor allen Dingen im gegebenen Fall nicht. Leider bietet auch die verwendetet Funktion <code>wp_editor()</code> noch die die Klasse <code>_WP_Editors</code> einen entsprechenden Filter an. Warum das so ist, sei mal dahingestellt. Ebenso das es bereits diverse Tickets im Trac zu den Thema gibt. Wenn man sein Ziel nicht auf direkten Weg erreichen kann, dann muss man manchmal einen kleinen Umweg gehen.</p>
<p>Eine Lösung wäre, wenn die Funktion <code>wp_editor()</code> plugable wäre, man sie also gegen eine eigene Funktion austauschen kann. Ist sie aber nicht, muss man den Hebel also woanders ansetzen.</p>
<p>Im betreffenden Fall wurde angeregt in der <a title="Trac Ticket #28259" href="https://core.trac.wordpress.org/ticket/28259">Klasse einen zusätzlichen Filter</a> einzubauen. Bis dies umgesetzt ist, muss man sich also mit einen kleinen Workaround behelfen.<br />
Wirft man einen Blick in den <a title="Core WordPress Browse Trunk" href="https://core.trac.wordpress.org/browser/trunk/src/wp-includes/general-template.php#L2280">Code</a>, so sieht man das abgefragt wird ob die Klasse <code>_WP_Editors</code> bereits geladen wurde. Nur wenn sie <em>nicht</em> geladen wurde, wird die Klasse aus dem WordPress-Core geladen. Für uns bedeutet dies also, wir können die Original-Klasse durch eine gleichnamige eigene Klasse ersetzen. Wir müssen nur dafür sorgen das unsere Klasse möglichst früh geladen wird. Am einfachsten erreicht man dies indem man einen der sehr früh ausgelösten Hooks benutzt um die eigene Klasse mittels <code>require_once()</code>/<code>include_once()</code> einzubinden.</p>
<p>Wie man sieht, gibt es in WordPress nicht nur eine Möglichkeit um etwas zu beeinflussen. Der einfachste Weg sind Filter und Actions um Variablen direkt zu beeinflussen. Sind diese nicht gegeben, schaut man sich an ob die betreffende Funktion etwas hergibt, also ob diese ggf. einen Filter/Action besitzt oder ob man sie ersetzen kann. Ist dies auch nicht gegeben, so kann man, wie hier im Beispiel, noch eine letzte Chance nutzen und eine Klasse komplett austauschen.</p>
<p>Der erste Schritt zum Plugin besteht also darin die Klasse <code>_WP_Editors</code> komplett in sein Plugin-Ordner zu kopieren. Der nächste Schritt ist das Einbinden der kopierten Klasse:</p>
<pre class="brush:php">/**
 * Including the modified WP class _WP_Editors
 */
add_action(
	'plugins_loaded',
	function() {
		require_once dirname( __FILE__ ) . '/class-wp-editor.php';
	},
	0,
	0
);
</pre>
<p>Um zu überprüfen ob nun die kopierte oder die Original-Klasse geladen wird, kann man am Anfang der Kopie einfach mal ein <code>die( 'Kopierte Klasse' );</code> setzen. Bricht WordPress nach einem Neuladen mit einen weißen Bildschirm ab auf dem nur &#8220;<em>Kopierte Klasse</em>&#8221; steht, so können wir sicher sein das nur unsere kopierte Klasse geladen wird. Nun geht es daran die kopierte Klasse zu modifizieren. Wie im Ticket vorgeschlagen ergänzen wir die Klasse um einen zusätzlichen Filter.</p>
<p>Da wir nun in der kopierten Klasse einen Filter haben den wir nutzen können, reicht es aus diesen zu setzen und in einer passenden Funktion die Werte entsprechend zu ändern.</p>
<pre class="brush:php">/**
 * Add the filter to modify the editor settings
 */

add_filter( 'wp_editor_settings', 'modify_editor_settings', 0, 2 );

/**
 * Modify the editor settings. Currently only set the value for using the TinyMCE to true.
 *
 * @param array $settings Array with editor settings
 * @param array $editor_id The ID of the editor
 * @return array
 */
function modify_editor_settings( $settings, $editor_id ) {

	if ( 'attachment_content' == $editor_id )
		$settings['tinymce'] = true;

	return $settings;

}
</pre>
<p>Ich habe hier bewusst auf umständliche Prüfungen verzichtet um das Beispiel einfach zu halten. Man könnte zusätzlich darauf prüfen ob man sich auch tatsächlich in der Medienübersicht bzw. Medienbearbeitung befindet. Es wird lediglich geprüft ob die Editor-ID <code>attachment_content</code> ist und dann das Flag für den TinyMCE auf <code>true</code> gesetzt.<br />
Durch Anpassung der Funktion <code>modify_editor_settings()</code> lässt sich so der TinyMCE für nahezu alle Eingabefelder aktivieren sofern die Editor-ID bekannt ist und das Eingabefeld über die Funktion <code>wp_editor()</code> erzeugt wird.</p>
<p>Das Plugin ist recht wartungsfreundlich. Sollte eines Tages ein Filter zum Modifizieren der Editor-Einstellungen vorhanden sein, so muss man nicht das komplette Plugin neu konstruieren. Es reicht aus die Einbindung der eigenen Klasse zu entfernen und ggf. den Filter-Namen anzupassen.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-143/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress in einer Nussschale</title>
		<link>http://yoda.neun12.de/artikel-131</link>
		<comments>http://yoda.neun12.de/artikel-131#comments</comments>
		<pubDate>Thu, 26 Dec 2013 01:56:20 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[HowTo]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=131</guid>
		<description><![CDATA[Es gibt verschiedene Gründe warum man WordPress in einer Sandbox installieren möchte, ich habe nun einen weiteren Weg entdeckt den ich hier vorstellen möchte. Mit &#8220;Sandbox&#8221; meine ich hierbei, eine relativ abgeschlossene Umgebung die alles benötigte (Server, PHP, MySQL) mitbringt. Sandboxes Eine Möglichkeit ist Instant WordPress, welches auf Apache, PHP und MySQL setzt. Mit diesen [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Es gibt verschiedene Gründe warum man WordPress in einer Sandbox installieren möchte, ich habe nun einen weiteren Weg entdeckt den ich hier vorstellen möchte. Mit &#8220;Sandbox&#8221; meine ich hierbei, eine relativ abgeschlossene Umgebung die alles benötigte (Server, PHP, MySQL) mitbringt.</p>
<h3>Sandboxes</h3>
<p>Eine Möglichkeit ist <a title="Instant WordPress" href="http://www.instantwp.com/" target="_blank">Instant WordPress</a>, welches auf Apache, PHP und MySQL setzt. Mit diesen Programm lässt sich WordPress inkl. der nötigen Umgebung z.B. auf einen USB-Stick installieren. Soweit eine tolle Sache, jedoch kann man die installierte Umgebung nur schlecht bis gar nicht anpassen. WordPress liegt i.d.R. in einer sehr alten Version bei, so dass man dies erst einmal updaten darf. Ob man PHP und MySQL überhaupt updaten kann, damit habe ich mich schon gar nicht mehr beschäftigt. Das Paket selber kann man ohne Fachwissen nicht anpassen, man muss nehmen was der Entwickler einen liefert.<br />
So toll Instant WordPress auf den ersten Blick ist, für mein Problem, das mich aktuell beschäftigt, ist es nicht das richtige. Schnell fiel mir wieder <a title="nginx webserver" href="http://nginx.org/" target="_blank">Nginx</a> ein, ein Webserver der vor einiger Zeit wegen seiner hohen Geschwindigkeit für viel Aufsehen sorgte. Für mich war Nginx eher deshalb interessant, da man ihn unabhängig von anderen, bereits installierten Komponenten, verwenden kann. Es wäre also möglich sich seine eigene Sandbox mit Nginx, PHP und MySQL zu basteln, was ich auch versucht habe. Jedoch ist das Frustlevel recht schnell sehr hoch. Denn im Netz findet man häufig nur Anleitungen zu Nginx 0.8.x, die aktuelle Version (Stand zur Veröffentlichung des Artikels) ist jedoch schon 1.5.8. Wobei &#8220;Anleitung&#8221; häufig geschmeichelt ist. Viele &#8220;Anleitungen&#8221; setzen enormes Wissen voraus und verschweigen das meiste. Irgendwann habe ich es dennoch geschafft Nginx mit PHP zum laufen zu bekommen, hatte dann aber Probleme mit dem von XAMPP installierten MySQL.</p>
<h3>WT-NMP</h3>
<p>Eine weitere Suche im Netz förderte dann <a title="WT-NMP - portable Nginx Mysql Php development stack for Windows" href="http://wtriple.com/wtnmp/" target="_blank">WT-NMP</a> zu Tage. WT-NMP kann man zwischen XAMPP und Instant WordPress ansiedeln. Das Paket liegt u.a. als Zip-Archive vor und kann sowohl als Verzeichnis auf der Festplatte als auch auf einen portablen Medium wie z.B. einen USB-Stick installiert werden. Der große Vorteil an dem Paket ist, es konfiguriert sich selbst, man muss also nicht händisch viel anpassen damit man es zum Laufen bekommt. Der dickste Bonuspunkt ist, wenn man das Paket z.B. auf der Festplatte installiert und eingerichtet hat und anschließend auf einen USB-Stick kopiert, ändert es automatisch die Konfiguration so um, dass es auch auf dem USB-Stick weiterhin läuft.<br />
Ein weiterer Bonuspunkt ist das Fehlen von WordPress. Hört sich merkwürdig an, jedoch kann man sich so selber aussuchen welche Version oder gar welche Software man mit dem Paket bündelt. Da ich das Zip-Archiv und nicht den WT-NMP Installer verwende, kann ich ohne große Probleme alles ins Zip-Archiv schieben was ich brauche, sogar eine Auswahl an Plugins die ich immer wieder einsetze. Im Ergebnis habe ich dann ein Zip-Archiv das meinen Bedürfnissen entspricht, das ich selber Up-To-Date halten kann und an dem ich nicht jedes mal rumfummeln muss wenn ich eine neue WordPress-Sandbox benötige.<br />
Nach der Installation schlägt das Herz dann sogar noch einen Ticken höher, denn schlauerweise sind neben Nginx, MySQL und PHP noch HeidiSQL und Adminer zur Verwaltung der Datenbanken installiert. Obendrein gibt es noch einen RegExp-Tester für PHP (PCRE) und JavaScript. Das man das PHP Error-Log mit einen Mausklick aufrufen kann, Testmails verschicken und <a title="Xdebug - Debugger and Profiler Tool for PHP" href="http://xdebug.org/" target="_blank">XDebug</a>, <a title="xCache" href="http://xcache.lighttpd.net/" target="_blank">PHP XCache</a> und <a title="PHP: OPcache - Manual " href="http://php.net/opcache" target="_blank">PHP OPcache</a> vorinstalliert sind, macht die Sache dann komplett rund. Alles in allem ein Traum für alle die WordPress in einer Sandbox betreiben wollen.</p>
<h3>Wie geht&#8217;s?</h3>
<p>Ich möchte nun im folgenden kurz beschreiben wie man zum einen das Paket für den Betrieb mit WordPress bereit macht und wie man WordPress damit zum Laufen bekommt. Und keine Angst, mehr als einen Texteditor und 5-10 Minuten Zeit braucht es nicht. Als erstes brauchen wir natürlich WT-NMP und WordPress.</p>
<ul>
<li><a title="WT-NMP 13.12 Zip-Archive" href="http://sourceforge.net/projects/wtnmp/files/wt-nmp-13/wt-nmp-13.12.zip/download" target="_blank">WT-NMP 13.12 als Zip-Archive</a></li>
<li><a title="WP3.8 de-Edition" href="http://de.wordpress.org/wordpress-3.8-de_DE.zip" target="_blank">WordPress 3.8 (deutsche Version)</a></li>
</ul>
<p>Es gibt zwar neben dem Zip-Archive auch noch einen Windows-Installer, den kann man jedoch nicht so bequem anpassen wie das Zip-Archive. Nach dem Download entpackt man das Zip-Archive in ein Verzeichnis, bei mir ist es das Laufwerk <code>D:/</code> und als Verzeichnis <code>WT-NMP</code>. Wenn ihr es woanders hin entpackt, kein Problem. Das Laufwerk ist eh egal, der Verzeichnisname sollte zum besseren Verständnis jedoch <code>WT-NMP</code> lauten.<br />
Im Verzeichnis <code>WT-NMP</code> können wir den Unterordner <code>WWW</code> sehen. Man kann es sich fast denken, dass ist der Document Root, also das Verzeichnis in dem alle Web-Projekte landen werden. Dorthin entpacken wir nun WordPress ins Verzeichnis <code>wordpress</code> (man kann natürlich auch einen anderen Namen wählen<code></code>). Die Verzeichnisse <code>project1</code>, <code>project2</code> und <code>project3</code> kann man löschen. Die letzten beiden genannten sind ohnehin leere Verzeichnisse, in <code>project1</code> ist lediglich eine Testdatei die uns hier jedoch nicht weiter interessieren soll.<br />
An dieser Stelle könnte man das Verzeichnis <code>WT-NMP</code> zu einen Archive packen und hätte so schon mal eine gute Ausgangsbasis für eine fertige Sandbox. Man kann aber auch WT-NMP und WordPress komplett konfigurieren, so dass man in Zukunft nur noch das Zip-Archive entpacken muss um quasi WordPress Out-Of-The-Box starten zu können. Gehen wir zur Konfiguration über.</p>
<h3>Konfiguration der php.ini</h3>
<p>Eine Datei muss man auf alle Fälle anfassen, und zwar die <code>php.ini</code>. Hier gilt es einige Erweiterungen (Extensions) zu aktivieren und einige kleinere Einstellungen zu korrigieren. Wichtig ist jedoch das man <strong>nicht</strong> die <code>php.ini</code> aus dem PHP-Verzeichnis nimmt, sie dient als Vorlage wenn WT-NMP automatisch angepasst wird. Alle Dateien die wir anpassen müssen finden wir im Verzeichnis <code>conf</code>!</p>
<p>Beginnen wir mit den Extensions und öffnen die Datei <code>conf/php.ini</code> im Texteditor unserer Wahl. Die Extension <code>php_xcache</code> und die Zend Extension <code>php_opcache</code> <em>kann</em> man aktivieren, muss man aber nicht. Es gibt wohl einige Probleme mit diesen Erweiterungen, so dass man es mal ausprobieren muss ob man besser mit aktivierten oder deaktivierten Cache-Extensions zurecht kommt. Ein aktiviertes XDebug (die Erweiterung steht ganz am Ende der <code>php.ini</code>) gehört zum guten Ton und sollte aktiviert werden. Zudem musste ich auf meinem System (Windows7 64bit) noch <code>php_mysql</code> aktivieren da ich ansonsten keine Verbindung zur Datenbank bekommen habe.<br />
<code>memory_limit</code> sollte man von 64MB auf 128MB herauf setzen. Bei einer lokalen Installation können es auch gerne mehr sein damit PHP möglichst flüssig arbeitet. <code>short_open_tag</code> stellen wir mal brav auf <code>Off</code>, das sollte nirgendwo mehr aktiviert sein. Ob man <code>allow_url_fopen</code> zulässt oder nicht, muss man ggf. im Einzelfall entscheiden. Bei mir steht es eigentlich immer auf <code>On</code> da es vieles leichter macht.<br />
Eine Besonderheit ist noch unter <code>disable_classes</code> zu beachten. Hier sollte man alle deaktivierten PHP-Klassen entfernen da es sonst unter WordPress von SimplePie Fehlermeldungen hagelt. Auch die Liste darüber mit den <code>disable_functions</code> sollte man mal kurz durchschauen. In einer reinen Entwicklungsumgebung stehen dort einige Funktionen die man ganz gut gebrauchen kann und ansonsten nicht zur Verfügung stehen würden.<br />
Im Großen und Ganzen war es das auch schon mit den Änderungen an der <code>php.ini</code>. Erfahrene Benutzer können noch mal alle Einstellungen durchgehen und ihren Bedürfnissen anpassen, für die Mehrheit sollte es so passen.</p>
<h3>Eigener Server und Domäne</h3>
<p>Wenn man nicht ständig über <em>http://localhost/wordpress</em> auf sein Blog zugreifen möchte und stattdessen lieber eine eigene Domäne verwenden möchte, so muss man sich noch einen zusätzlichen Server in der <code>nginx.conf</code> anlegen und einen Eintrag in der <code>hosts</code> Datei von Windows.<br />
Der Server ist schnell angelegt. Dazu kopieren wir uns einfach den bereits vorhandenen Server und fügen die Kopie hinter den bestehenden an. Lediglich die Zeilen mit <code>listen</code>, <code>server_name</code> und <code>root</code> müssen wir anpassen. In der Zeile <code>listen</code> löschen wir nur den <code>default_server</code>, den <code>server_name</code> ändern wir auf unsere Wunsch-Domäne und bei <code>root</code> ergänzen wir <code>/wordpress</code> damit der <code>root</code>-Eintrag auch auf unsere WordPress-Installation zeigt.</p>
<pre class="brush:plain">	server {
		listen       127.0.0.1:80;
		server_name  samplewp.tld;

		root "d:/wt-nmp/www/wordpress";
		autoindex on;

		allow		127.0.0.1;
		deny		all;

		# deny access to .htaccess files, if Apache's document root
		# concurs with nginx's one
		#
		location ~ /\.ht {
		    deny  all;
		}

		location ~ \.php$ {
		    try_files $uri =404; 
	            fastcgi_pass	php_farm;
		    include		nginx.fastcgi.conf;
	        }

	}</pre>
<p>So sieht das ganze bei mir aus. Das ist lediglich eine Grundkonfiguration, wer mehr benötigt (z.B. URL-Rewriting), muss sich näher mit Nginx beschäftigen, dass geht etwas über diesen Artikel hinaus. In der Windows <code>hosts</code>-Datei machen wir dann noch den Eintrag für unsere Domäne was bei mir so aussieht: <code>127.0.0.1 samplewp.tld</code></p>
<p>An der <code>mysql.ini</code> musste ich nichts verändern, hier kann es aber sinnvoll sein die Einstellungen für <code>wait_timeout</code> und <code>connect_timeout</code> hoch zu setzen. Vor allem wenn man WT-NMP auf einen langsamen USB-Stick installiert können schon mal längere Wartezeiten auftreten.</p>
<h3>Erster Start</h3>
<div id="attachment_133" style="width: 310px" class="wp-caption alignright"><a class="highslide" onclick="return hs.expand(this)"  href="http://yoda.neun12.de/wp-content/uploads/2013/12/wtnmp_launcher.png"><img class="size-medium wp-image-133 " alt="WT-NMP Launcher" src="http://yoda.neun12.de/wp-content/uploads/2013/12/wtnmp_launcher-300x190.png" width="300" height="190" /></a><p class="wp-caption-text">Der WT-NMP Launcher</p></div>
<p>Nun müssen wir noch Nginx, MySQL und PHP starten. Das erfolgt recht bequem über den WT-NMP Launcher <em>WT-NMP.exe</em> im Verzeichnis <code>WT-NMP</code>. Mit dem Launcher lassen sich auch die einzelnen Prozesse von Nginx, MySQL und PHP starten und stoppen, was recht wichtig ist wenn man Änderungen an den jeweiligen Einstellungs-Dateien (ini-Dateien) vorgenommen hat. Im Launcher sieht man neben den einzelnen Komponenten auch noch ein paar Icons, was sich dahinter verbirgt wird angezeigt wenn man mit dem Mauspfeil über das jeweilige Icon verbleibt. Das einzig wirklich interessante dürfte der Datenbank-Manager (HeidiSQL) neben der MySQL-Komponente sein.<br />
Jetzt kann man auch schon loslegen und im Browser seiner Wahl testweise mal <em>http://localhost/wordpress</em> bzw. seine zuvor angelegte Domäne <em>http://samplewp.tld</em> aufrufen. WordPress wird uns nun mit der einen oder anderen Meldung beglücken das dies und jenes noch nicht vorhanden sei. Bisher haben wir ja auch weder Datenbank noch Datenbank-Benutzer oder eine <code>wp-config.php</code> angelegt.</p>
<h3>Datenbank anlegen</h3>
<div id="attachment_132" style="width: 310px" class="wp-caption alignleft"><a class="highslide" onclick="return hs.expand(this)"  href="http://yoda.neun12.de/wp-content/uploads/2013/12/wtnmp_home.png"><img class="size-medium wp-image-132 " alt="WT-NMP Startbildschirm" src="http://yoda.neun12.de/wp-content/uploads/2013/12/wtnmp_home-300x167.png" width="300" height="167" /></a><p class="wp-caption-text">Der Startbildschirm von WT-NMP im Browser</p></div>
<p>Beginnen wir mit dem Anlegen einer Datenbank. Dazu rufen wir im Browser einfach <em>http://localhost</em> auf und sollten die Startseite von WT-NMP sehen (siehe Screenshot). Mit einen Klick auf <em>Adminer Database Manager</em> gelangen wir zur Datenbankverwaltung. Es ist schon fast Geschmackssache ob man HeidiSQL oder Adminer verwendet. Adminer ist jedoch deutlich schlanker und übersichtlicher.<br />
Im Adminer oben rechts eine neue Datenbank anlegen, einen Namen für die Datenbank vergeben und den Rest erst mal so belassen wie es ist. Danach sollte man sich einen neuen Benutzer anlegen, dazu klickt man oben rechts auf <em>Rechte</em>. Nun werden die vorhandenen Benutzer angezeigt und unterhalb der Tabelle mit den Benutzern der Link für <em>Neuer Benutzer</em>. Erneut einen Namen eingeben, Passwort und die Checkboxen <em>All Privileges</em> und <em>Grand option</em> anhaken, mit <em>Speichern</em> bestätigen und das war es dann auch schon.</p>
<p>Auf in den Schlussspurt. Dazu öffnen wir die <code>wp-config-sample.php</code>-Datei aus unserer WordPress-Installation und passen sie wie gewohnt mit Datenbankname, Nutzer und Passwort an. Noch bequemer geht es eigentlich nur indem man <em>http://samplewp.tld</em> (bzw. <em>http://localhost/wordpress</em>) aufruft und die <code>wp-config.php</code> von WordPress erstellen lässt. Diejenigen unter uns die öfters WordPress einrichten und zusätzliche Angaben in der <code>wp-config.php</code> machen werden ersten Weg wählen, ansonsten reicht halt auch der bequeme Weg.</p>
<p>Damit sind wir eigentlich auch schon fertig. Ich denke mal wer öfters WordPress installiert und auch schon mal mit XAMPP gearbeitet hat, dürfte für alles zusammen kaum mehr als 10 Minuten benötigen. Wobei man sich die Arbeit ab jetzt auch sparen kann, denn es reicht aus das Verzeichnis <code>WT-NMP</code> als Zip-Archive abzuspeichern und hat ab dann immer ein frisches WordPress komplett installiert parat.</p>
<h3>Bonus-Runde</h3>
<div id="attachment_134" style="width: 310px" class="wp-caption alignleft"><a class="highslide" onclick="return hs.expand(this)"  href="http://yoda.neun12.de/wp-content/uploads/2013/12/adminer.png"><img class="size-medium wp-image-134" alt="Adminer" src="http://yoda.neun12.de/wp-content/uploads/2013/12/adminer-300x169.png" width="300" height="169" /></a><p class="wp-caption-text">Adminer im Einsatz</p></div>
<p>Also auf zur Bonus-Runde. Es gibt tatsächlich noch Server die mit PHP5.2 arbeiten bzw. Nutzer die PHP5.2 verwenden (müssen). Für einen Entwickler ist das recht lästig, muss man doch ständig irgendwo einen Server mit PHP5.2 parat haben für den Fall der Fälle das man was entwickeln oder testen will. WT-NMP macht uns hier das Leben sehr leicht. Es wird zwar mit PHP5.4 bzw. PHP5.5 ausgeliefert, jedoch ist es sehr einfach auch noch PHP5.2 nachzurüsten. Dazu benötigt man lediglich das Zip-Archive von PHP5.2 <strong>Non Thread Safe</strong>. Das NTS (Non Thread Safe) ist wichtig, da PHP ansonsten nicht starten will. Das Zip-Archive bekommt man bei <a title="windows.php.net - /downloads/releases/archives/" href="http://windows.php.net/downloads/releases/archives/" target="_blank">PHP.net im Museum</a> (letzte verfügbare Version dort ist <a title="PHP Museuum" href="http://windows.php.net/downloads/releases/archives/php-5.2.16-nts-Win32-VC6-x86.zip" target="_blank">PHP-5.2.16-nts</a> (Windows Binairies)). Wer mit der von mir verlinkten Version nichts anfangen kann, muss ein wenig nach der für sein Betriebssystem passenden Version suchen.<br />
Das Zip-Archive entpacken wir einfach in einen Ordner in <code>WT-NMP/bin/</code> (z.B. <code>WT-NMP/bin/php-5.2.16</code>). Der WT-NMP Launcher bietet uns ab nun die Wahl zwischen den installierten PHP-Versionen an. Zum Wechseln der PHP-Version einfach den PHP-Prozess stoppen, Version wechseln und der Neustart von PHP wird automatisch eingeleitet. Bequemer geht es nun doch wirklich nicht, oder!?<br />
Ich habe es nun nicht ausprobiert mit welchen PHP-Versionen das funktioniert. Da aber immer die gleiche <code>php.ini</code> verwendet wird, hängt es wohl in erster Linie davon ab ob die PHP-Version mit der vorhandenen <code>php.ini</code> zusammen arbeitet.</p>
<h3>Fazit</h3>
<p>Für mich ist WT-NMP momentan das ultimative Tool wenn es darum geht mit verschiedenen PHP-Versionen zu entwickeln oder WordPress in einer Sandbox oder auf einen USB-Stick zu installieren. Bisher habe ich nur ein wenig mit WT-NMP herum gespielt und mich noch nicht näher z.B. mit der Konfiguration von Nginx beschäftigt. Auch habe ich noch nicht getestet ob die Aktivierung der Cache-Extensions (XCache und OPcache) wirklich so negative Auswirkungen haben wie auf der WT-NMP Webseite beschrieben. Deswegen würde ich mich über ein paar Erfahrungsberichte, gerne auch in Form eines Blog-Posts, freuen.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-131/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tutorial: HookUp</title>
		<link>http://yoda.neun12.de/artikel-130</link>
		<comments>http://yoda.neun12.de/artikel-130#comments</comments>
		<pubDate>Sun, 22 Dec 2013 19:01:44 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=130</guid>
		<description><![CDATA[Hooks ist ein Thema über das sich wahrscheinlich die wenigsten Gedanken machen, jedoch essentiell beim Schreiben von Plugins ist. Im Grunde genommen ist es ein relativ einfaches Thema, dass jedoch schnell recht komplex werden kann. Ich werde hier ein wenig auf die Do&#8217;s und Don&#8217;ts eingehen und dies anhand von einigen Beispielen demonstrieren. Das Tutorial [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Hooks ist ein Thema über das sich wahrscheinlich die wenigsten Gedanken machen, jedoch essentiell beim Schreiben von Plugins ist. Im Grunde genommen ist es ein relativ einfaches Thema, dass jedoch schnell recht komplex werden kann. Ich werde hier ein wenig auf die Do&#8217;s und Don&#8217;ts eingehen und dies anhand von einigen Beispielen demonstrieren.</p>
<p>Das Tutorial richtet sich an Fortgeschrittene Anwender. Um es ein wenig kompakter zu halten, werde ich hier nicht auf die Funktionsweise von Hooks oder die Unterschiede zwischen Actions und Filter eingehen. Kernpunkt des Tutorials ist das richtige setzen von Hooks damit diese auch wieder entfernt werden können.<br />
Wer etwas experementieren möchte, für den habe ich ein <a title="RalfAlbert/hookuptutorial · GitHub" href="https://github.com/RalfAlbert/hookuptutorial">Git-Repository</a> angelegt. In diesem befinden sich einige Scripte die als fertige Plugins abgespeichert sind. Einfach das Repo in das Pluginverzeichnis klonen und schon kann man testen und probieren.</p>
<h4>Etwas Geschichte</h4>
<p>WordPress wurde zu einer Zeit geschrieben, als PHP5 noch nicht veröffentlicht war und Objektorientierte Programmierung (OOP) noch nicht sehr verbreitet war. WordPress ist prozedural entwickelt worden und trägt diese Altlast bis heute mit sich herum. Zwar nutzt auch WordPress Klassen und Objekte, jedoch baut das Grundprinzip immer noch auf prozeduraler Programmierung auf. Das Handling von Objekten ist auf diese prozeduraler Basis aufgepflanzt, was jedoch keine saubere Lösung darstellen kann.<br />
So lange wir prozedural programmieren, werden wir kaum oder gar keine Probleme mit Hooks haben. Sobald wir jedoch auf OOP setzen, wird es sehr schnell sehr schwierig die richtige Lösung für die auftretende Probleme zu finden.</p>
<p>Hooks entsprechen dem Observer Pattern. Hierbei können sich Beobachter (Observer) für ein bestimmtes Ereignis (Hook) registrieren und werden benachrichtigt sobald das Ereignis eintritt. In einer prozeduralen Umgebung reicht es den Funktionsnamen als Observer zu speichern und diesen beim Eintritt des Ereignisses als Callback aufzurufen.<br />
In einer OOP-Umgebung ist dies schon nicht mehr ausreichend. Eine Klasse ist lediglich das Entwurfsmuster für ein Objekt und es können verschiedene Objekte von der gleichen Klasse erzeugt werden. Spätestens mit PHP5.3 wird die Lage noch komplizierter, da nun auch anonyme Funktionen als Callback registriert werden können.</p>
<h4>Prozedurale Programmierung</h4>
<p>In der Prozeduralen Programmierung ist es wie gesagt einfach:</p>
<pre class="brush:php">function hooker( $var ) {
  // do something
}

add_action( 'hook', 'hooker', 0, 1 );
do_action( 'hook' );

add_filter( 'hook', 'hooker', 0, 1 );
$var = 'old value';
$var = apply_filters( 'hook', $var );

// removes the action AND filter because both
// use the same callback
remove_action( 'hook', 'hooker' );</pre>
<p>Einfach aber nicht ganz unproblematisch. Als WordPress noch klein war und es nur wenige Plugins und Themes gab, war das alles relativ unproblematisch. Als WordPress jedoch wuchs und es immer mehr Themes und Plugins gab, stieg die Wahrscheinlichkeit das jemand anderes eine andere Funktion mit dem gleichen Namen erstellte.<br />
Eine Zwischenlösung war es, die Funktionen mit Prefixen zu versehen. Aber auch die Prefixe werden irgendwann knapp, denn man empfahl häufig die Initialen des Autors als vergleichsweise kurzen Prefix zu nehmen. Das dies nicht lange gut geht, kann man sich denken. Also wurde der Name des Plugins bzw. Themes hinzugefügt. Sowohl Theme- als auch Plugin-Namen sind einzigartig, jedoch nicht immer kurz.<br />
Hier wird eine konzeptionelle Schwäche von WordPress deutlich die vor 10 Jahren, als die Basis von WordPress entwickelt wurde, noch nicht abzusehen war. So lange man alleine oder in einen kleinen Team an einem Projekt arbeitet und die volle Kontrolle hat, funktioniert das Konzept von WordPress. Öffnet man jedoch eine Schnittstelle nach Außen die jeder nutzen kann, scheitert das Konzept.</p>
<p>Namespaces könnten eine Lösung für das Problem sein. Mit Namespaces lassen sich weite Teile des Codes &#8220;prefixen&#8221; was die Arbeit sehr erleichtert. Jedoch hat sich das Team um WordPress dafür entschieden das PHP5.2 als Mindestanforderung gilt, Namespaces gibt es leider erst ab PHP5.3. Will oder kann man seine Nutzer nicht dazu zwingen PHP5.3 zu verwenden, fällt diese Lösung also raus.</p>
<h4>OOP</h4>
<p>Objektorientierte Programmierung kommt immer mehr in Mode. Es ist wirklich eine Mode und das &#8220;objektorientiert&#8221; muss man in Anführungszeichen setzen. Zumindest was WordPress angeht.<br />
Man kann nun lange darüber diskutieren wie oder was objektorientiert bedeutet oder wie stark man das auslegen muss damit es als OOP gilt. Im Fall WordPress hat sich sehr schnell herausgestellt das viele Plugin-Programmierer Klassen als Namespaces missbrauchten. Bestehender Code wurde teilweise lediglich mit einem Klassen-Statement umschlossen und damit war die &#8220;objektorientierung&#8221; für den Programmierer gegessen. Daraus entstanden gravierende Probleme was das entfernen einmal gesetzter Hooks angeht. Prinzipiell bestehen diese Probleme auch dann, wenn man &#8220;streng objektorientiert&#8221; arbeitet. Der Grund ist nun einmal weniger die objektorientierte Programmierung, als viel mehr der veraltete Unterbau von WordPress.</p>
<h4>Hooks im Detail</h4>
<p>Um zu verstehen wo das Problem liegt, müssen wir uns kurz anschauen wie WordPress die Callbacks zu den einzelnen Hooks registriert. Damit beim Aufruf von z.B. <code>do_action( 'sample_hook' );</code> alle Callback-Funktionen aufgerufen werden die zu diesen Hook registriert wurden, muss man eine Liste der Callback-Funktionen führen. WordPress nutzt dazu das globale Array <code>wp_filter</code>. Schauen wir uns dazu das Plugin &#8220;<a title="hookuptutorial/part_one.php at master · RalfAlbert/hookuptutorial · GitHub" href="https://github.com/RalfAlbert/hookuptutorial/blob/master/part_one.php">01_HookUp Tutorial &#8211; Part One</a>&#8221; aus dem Git-Repo an. Nach der Aktivierung zeigt es im Dashboard eine Metabox mit ein paar Ausgaben. Unter anderem wird dort mittels <code>var_dump()</code> das Array <code>$GLOBALS['wp_filter']['test_hook'][0]</code> ausgegeben. Warum nun ausgerechnet dieses Array?<br />
Die Antwort ist relativ simpel. In <code>wp_filter</code> stehen, wie erwähnt, die registrierten Hooks. Mittels <code>add_action()</code> bzw. <code>add_filter()</code> fügt man einen Hook hinzu sofern dieser noch nicht besteht. Die <code>0</code> ist die Priorität mit der die Callbacks ausgeführt werden. Nun wird es interessant, denn ab hier wird der Name des Callbacks als Index verwendet. Wir haben die Funktion <code>hook_callback</code> für den Hook <code>test_hook</code> registriert. In der Ausgabe sehen wir dann auch das unter diesen Indexeintrag die Werte <code>function</code> und <code>accepted_args</code> gespeichert sind.<br />
Die Registrierung folgt also nach folgenden Muster ab: <code>[wp_filter][hook name][priorität][array mit callbacks]</code>. Das Array mit den Callbacks ist ein assoziatives Array (Schlüssel (Index) &#8211; Werte Paarung) mit dem Muster <code>[funktionsname] =&gt; [function], [accepted_args]</code>.</p>
<h4>Funktionen und Methoden</h4>
<p>So lange wir nur Funktionen als Callback registrieren, können diese im Klartext als Index verwendet werden. Schwierig wird es bei der Verwendung von Klassen. Fügen wir in unserem Script einfach mal eine Klasse ein und schauen uns an was passiert wenn wir eine Methode dieser Klasse als Callback registrieren. Zuerst einmal die Klasse, die kann einfach ans Ende des Scripts eingefügt werden:</p>
<pre class="brush:php">class Demo_Hook
{
  public function print_var( $var ) {
    printf( '&lt;p&gt;The var &lt;em&gt;%s&lt;/em&gt; was send by &lt;code&gt;do_action()&lt;/code&gt; to &lt;code&gt;%s&lt;/code&gt;&lt;/p&gt;', $var, __METHOD__ );
  }
}
</pre>
<p>In der Funktion <code>hooktest_output()</code> fügen wir nach der Zeile mit <code>add_action()</code> noch folgende zwei Zeilen ein:</p>
<pre class="brush:php">  $demo = new Demo_Hook();
  add_action( 'test_hook', array( $demo, 'print_var' ), 0, 1 );</pre>
<p>Schauen wir nun wieder ins Dashboard, so sehen wir das sich die Ausgabe des <code>var_dump()</code> dahingehend verändert hat, dass dort nun ein zweiter Index erscheint. Dieser neue Index besteht aus einem Hash<sup>1</sup> (die lange kryptische Zeichenkette) und den Namen der Methode (hier <code>print_var</code>). Nun drücken wir einfach ein paar mal F5 und beobachten den neuen Index. Wie gut zu erkennen ist, verändert sich der Hash mit jeden Seitenaufruf obwohl wir am Script nichts geändert haben. Und genau das ist unser Problem.</p>
<h4>Hooks und Callbacks entfernen</h4>
<p>Es wird wohl eher selten vorkommen das jemand einen kompletten Hook entfernen möchte, es wäre jedoch möglich. Dazu reicht es aus den Hook aus dem globalen Array <code>wp_filter</code> mit <code>unset()</code> zu entfernen. Dazu einfach mal testweise nach den Registrieren der Hooks (also vor <code>// [...]</code>) ein <code>unset( $GLOBALS['wp_filter']['test_hook'][0] );</code> einfügen.<br />
Nun spuckt der <code>var_dump()</code> eine Fehlermeldung aus weil der Index <code>test_hook</code> ja nicht mehr existiert. Aber auch die komplette Ausgabe da drunter ist verschwunden. Komplette Hooks entfernen ist also möglich, jedoch oft eher sinnlos.<br />
Viel häufiger kommt es vor das man einzelne Callbacks entfernen möchte. Wir erweitern den <code>unset()</code> Aufruf einfach mal um <code>['hook_callback']</code> (<code>unset( $GLOBALS['wp_filter']['test_hook'][0]['hook_callback'] );</code>) und schauen was passiert. Rufen wir das Dashboard erneut auf (ggf. aktualisieren), sehen wir das sowohl der erste Index (<code>hook_callback</code>) in der Ausgabe des <code>var_dump()</code> verschwunden ist, jedoch auch die Ausgabe da drunter ist weniger geworden. Nun steht nur noch die Ausgabe aus der Klasse <code>Demo_Hook</code> dort.</p>
<p>Durch Manipulation des globalen Arrays <code>wp_filter</code> können wir also Callbacks und sogar ganze Hooks entfernen. Natürlich hat WordPress dafür bereits eine Funktion zur Verfügung gestellt die uns einiges an Arbeit abnimmt. <code>remove_action()</code> und <code>remove_filter()</code> machen im Prinzip nichts anderes als das was wir gerade eben von Hand durchgeführt haben.<br />
Kommen wir wieder zurück zu unseren Problem. Wie wir anhand des <code>unset()</code> gesehen haben, müssen wir einen Index entfernen der aus dem Funktions- bzw. aus dem Hash plus Methoden-Namen besteht. Dementsprechend erwarten <code>remove_action()</code> und <code>remove_filter()</code> neben dem Hook aus dem der Callback entfernt werden soll einen Funktionsnamen. Bei <code>hook_callback</code> würde das dann so aussehen <code>remove_action( 'test_hook', 'hook_callback', 0 );</code>.<br />
Aber was ist wenn wir nicht die Callback-Funktion <code>hook_callback</code> sondern die Callback-Methode aus dem Objekt entfernen wollen? Um an eine Antwort zu gelangen ändern wir noch mal kurz das Script. Zuerst einmal löschen wir den <code>unset()</code> Aufruf wieder. Die Zeile mit <code>$demo = new Demo_Hook();</code> brauchen wir auch nicht mehr und kann gelöscht oder auskommentiert werden. Den <code>add_action()</code> Aufruf ändern wir zu <code>add_action( 'test_hook', array( 'Demo_Hook', 'print_var' ), 0, 1 );</code> und die Methode <code>print_var()</code> deklarieren wir als <code>static</code> (<code>public static function print_var( $var ){...}</code>.<br />
Nun das Dashboard neu laden und schon sehen wir das der Hash verschwunden ist und dafür ein Index <code>Demo_Hook::print_var</code> erscheint. Das ist gut, denn das können wir, anders als den Hash, vorhersagen. Klassenname Doppelter-Doppelpunkt Methoden-Name. Das können wir jetzt so in <code>remove_action()</code> einsetzen: <code>remove_action( 'test_hook', 'Demo_Hook::print_var', 0 );</code>. Alternativ können wir auch das gleiche Array verwenden das wir bei <code>add_action()</code> verwendet haben: <code>remove_action( 'test_hook', array( 'Demo_Hook', 'print_var' ), 0 );</code>.<br />
Woher WordPress weiß das der String <code>'Demo_Hook::print_var'</code> die gleiche Methode meint wie das Array <code>array( 'Demo_Hook', 'print_var' )</code>, dazu kommen wir später. Dann klären wir auch wie man ein Object bzw. nicht statischen Methoden-Aufruf entfernen kann.</p>
<p><sup>1</sup> Die Hash-Werte werden erst ab PHP5.2 erzeugt und verwendet. Unter PHP</p>
<h4>Zwischenfazit</h4>
<ul>
<li>Hooks in WordPress basieren auf eine Technik aus Zeiten vor OOP. Dadurch kommt es in Verbindung mit Objekten zu Problemen die sich nicht so einfach lösen lassen.</li>
<li>Die Callbacks werden in einem assoziativen Array mit Index-Werte-Paarung gespeichert. Zum Entfernen eines Callbacks benötigt man den Funktionsnamen, so wie er im Index erscheint.</li>
<li>Verwenden wir eine einfache Funktion als Callback für den Hook, so wird der Funktionsname als Index verwendet.</li>
<li>Bei verwendung einer statischen Methode aus einer Klasse, so wird der Klassenname gefolgt von einem Doppelten-Doppelpunkt und den Methoden-Name als Index verwendet. Zum Entfernen eines mittels statischen Methoden-Aufrufes hinzugefügten Callbacks, kann entweder ein String aus Klassenname::Methoden-Name oder ein Array mit den Werten Klassenname und Methodenname verwendet werden.</li>
<li>Callbacks aus Methoden in Objekten bzw. nicht statischen Methoden-Aufrufen können nicht ohne weiteres entfernt werden da der Index zum Teil aus einem Hash besteht der bei jeden Seitenaufruf verschieden ist.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-130/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Neues Plugin: Password Change Reminder</title>
		<link>http://yoda.neun12.de/artikel-126</link>
		<comments>http://yoda.neun12.de/artikel-126#comments</comments>
		<pubDate>Sun, 24 Nov 2013 11:47:59 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[Plugin]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=126</guid>
		<description><![CDATA[Einer der häufigsten Tipps zur Sicherheit ist, sein Passwort regelmäßig zu wechseln. In diesen eigentlich simplen Punkt unterstützt WordPress uns leider in keinster Weise. Zumindest habe ich bei einer schnellen Recherche nichts dazu gefunden. Also habe ich mich hingesetzt und selber ein Plugin geschrieben: Password Change Reminder Zielgruppe des Plugins sind Blogs die mit mehr [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Einer der häufigsten Tipps zur Sicherheit ist, sein Passwort regelmäßig zu wechseln. In diesen eigentlich simplen Punkt unterstützt WordPress uns leider in keinster Weise. Zumindest habe ich bei einer schnellen Recherche nichts dazu gefunden. Also habe ich mich hingesetzt und selber ein Plugin geschrieben: <a title="WordPress › Password Change Reminder « WordPress Plugins" href="http://wordpress.org/plugins/password-change-reminder/">Password Change Reminder</a><br />
Zielgruppe des Plugins sind Blogs die mit mehr oder minder unerfahrenen Benutzern (z.B. mehrere Autoren)  arbeiten. Aber auch Firmen die gewisse Vorgaben machen was das Passwort und die Häufigkeit zur Aktualisierung selbigen angeht. Natürlich ist es genauso für all diejenigen interessant, die sich zwar immer wieder vornehmen das Passwort regelmäßig zu wechseln, dies aber genauso regelmäßig vergessen.</p>
<p>Das Plugin ist sehr einfach gestrickt. Es prüft wie alt das aktuelle Passwort ist und gibt, sofern es veraltet ist, einen Warnhinweis im Adminbereich aus. Dieser Warnhinweis (engl. nag screen; deut. Nörgelbildschirm) erscheint auf allen Seiten im Adminbereich.<br />
Neben den Hinweis im Adminbereich kann das Plugin auch einen unübersehbaren Hinweis auf der Startseite ausgeben. Dies ist nützlich für Benutzer die sich um den Adminbereich drücken.</p>
<p>Natürlich gibt es auch ein paar Einstellungen. Die wichtigste ist wohl die Einstellung wie lange es dauern soll bevor ein Passwort veraltet ist. Es lässt sich aber zusätzlich noch einstellen ob der Hinweis auch auf der Startseite erscheinen soll. Ebenso lässt sich einstellen ob Benutzer den Hinweis eine Zeit lang ignorieren (ausblenden) können und nach welcher Zeitspanne der Hinweis wieder eingeblendet werden soll. Als letzte Einstellung lässt sich noch ein Text festlegen der zusätzlich im Hinweis erscheinen kann. So kann man die Benutzer z.B. auf die Risiken eines veralteten Passwortes aufmerksam machen oder auf verbindliche Nutzerregelungen hinweisen.</p>
<p>Da das Plugin, wie gesagt, sehr einfach gehalten ist, gibt es dazu nun auch nicht mehr viel zu sagen. Experten die das Plugin einsetzen und den Hinweis auf der Startseite optisch ändern möchten, steht ein Stylesheet zur Verfügung das angepasst werden kann.</p>
<p>Für Lob, Kritik, Anregungen und vor allem Fehlerberichte steht der <a title="WordPress › Support » Password Change Reminder" href="http://wordpress.org/support/plugin/password-change-reminder">Support auf WordPress</a> und das <a title="RalfAlbert/PasswordChangeReminder · GitHub" href="https://github.com/RalfAlbert/PasswordChangeReminder">Repo auf GitHub</a> zur Verfügung.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-126/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Das Ende einer langen Pause</title>
		<link>http://yoda.neun12.de/artikel-125</link>
		<comments>http://yoda.neun12.de/artikel-125#comments</comments>
		<pubDate>Wed, 20 Nov 2013 16:27:29 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=125</guid>
		<description><![CDATA[Seit rund 6 Monaten habe ich nun hier nichts mehr rein geschrieben. In etwa genauso lange hat man von mir generell nichts mehr in Sachen WordPress lesen können. Anfangs war es schlichtweg Zeitmangel aufgrund von mehreren Projekten die ich begonnen hatte. Aber dann kam irgendwann der Tag an dem gar nichts mehr ging. Von jetzt [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Seit rund 6 Monaten habe ich nun hier nichts mehr rein geschrieben. In etwa genauso lange hat man von mir generell nichts mehr in Sachen WordPress lesen können. Anfangs war es schlichtweg Zeitmangel aufgrund von mehreren Projekten die ich begonnen hatte. Aber dann kam irgendwann der Tag an dem gar nichts mehr ging. Von jetzt auf Gleich ein Balken im Kopf der die totale Blockade ausgelöst hatte. Nicht eine Zeile Code habe ich mehr hin bekommen. Nicht einen klaren Gedanken fassen können wenn ich ein Problem lösen wollte. Nichts ging mehr.</p>
<p>Zum Glück ist das Programmieren nicht meine Lebensgrundlage, ansonsten wäre ich einige Monate lang berufsunfähig gewesen. So konnte ich mir den Luxus einer langen Auszeit gönnen und habe mich rein gar nicht mehr mit WordPress, PHP oder verwandten Themen befasst.<br />
Andere Dinge rückten in den Mittelpunkt und das war gut so. Ich habe den nötigen Abstand gewonnen um wieder klar denken zu können. Den nötigen Abstand um Projekte, die ich begonnen hatte, wieder mit der nötigen Distanz und Kritikfähigkeit betrachten zu können. Abstand der es mir ermöglichte Wichtiges von Unwichtigen zu trennen.</p>
<p>Bei vielen reicht dafür ein Urlaub. Urlaub bedeutet bei mir jedoch oftmals Zeit zum Coden. Und das war dann wohl auch der Fehler den ich gemacht hatte, weswegen meine Auszeit etwas länger ausfiel.<br />
Dadurch das ich mir Zeit für mich selber und andere Dinge genommen hatte &#8211; eher nehmen musste &#8211; konnte ich den Akku wieder aufladen. Jetzt macht mir das Coden wieder Spaß, die Zeilen flutschen nur so auf den Bildschirm und ich verbeisse mich nicht mehr an unwichtigen Details.<br />
Viele Projekte habe ich auf Eis gelegt oder gleich ganz aufgegeben, ansonsten hätte ich das Coden wahrscheinlich aus lauter Frust komplett an den Nagel gehängt.<br />
Zu den jetzigen Neuanfang gehört auch ein kleines Plugin, welches ich ohne durch Altlasten aufgehalten zu werden, in den letzten vier Tagen umgesetzt habe.</p>
<p>Entstanden ist das Plugin durch die Beschäftigung mit Menschen die es schon als große Leistung ansehen Facebook zu starten. Denn es kann durchaus hinderlich sein wenn man ständig von Menschen umgeben ist die sich auskennen. Man verliert sehr schnell den Blick dafür was diejenigen benötigen (könnten), die sich weniger bis gar nicht auskennen. Raus aus den Elefenbeinturm ist hier die Devise gewesen.<br />
Und so ist in den letzten Tagen <a title="PwCR on GitHub" href="https://github.com/RalfAlbert/PasswordChangeReminder">Password Change Reminder (PwCR)</a> entstanden. Bei einer schnellen Recherche konnte ich kein Plugin finden welches den Benutzer daran erinnert regelmäßig sein Passwort zu ändern. PwCR macht genau das. Nicht mehr und nicht weniger.<br />
Das Plugin ist, wie so häufig bei mir, in einem sehr früher Stadium. Da können noch ein paar Fehler dabei sein, die (englischen) Texte sind alle noch etwas schief, Übersetzungsarbeit ist zu leisten und natürlich Dokumentation. Genaueres zu dem Plugin werde ich in eine  seperaten Artikel schreiben. Bis dahin kann jeder der möchte es schon mal ausprobieren.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-125/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Wohin mit den Daten &#8211; Ab in den DataContainer</title>
		<link>http://yoda.neun12.de/artikel-121</link>
		<comments>http://yoda.neun12.de/artikel-121#comments</comments>
		<pubDate>Fri, 31 May 2013 13:07:36 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[HowTo]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=121</guid>
		<description><![CDATA[Beim Schreiben von Plugins und Themes stößt man früher oder später auf ein Problem das WordPress recht pragmatisch gelöst hat: Der globale Zugriff auf Daten. Auf die Variable x die in Funktion y definiert wurde, kann nicht ohne weiteres in Funktion z zugegriffen werden. Das Problem ist der sogenannte Scope, also der Gültigkeitsbereich in PHP. [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Beim Schreiben von Plugins und Themes stößt man früher oder später auf ein Problem das WordPress recht pragmatisch gelöst hat: Der globale Zugriff auf Daten.</p>
<p>Auf die Variable <code>x</code> die in Funktion <code>y</code> definiert wurde, kann nicht ohne weiteres in Funktion <code>z</code> zugegriffen werden. Das Problem ist der sogenannte Scope, also der Gültigkeitsbereich in PHP. WordPress umgeht das Problem einfach dadurch, indem es recht rücksichtslos fast alle seine Variablen mit den Schlüsselwort <code>global</code> in den globalen Namensraum verfrachtet und somit überall verfügbar macht. Das ist zwar eine sehr einfache Lösung, jedoch auch eine sehr egoistische. Nehmen wir einfach mal an wir hätten ein Plugin oder Theme das die Variable <code>foo</code> verwendet.</p>
<pre class="brush:php">&lt;?php
function set_foo( $var ) {
  global $foo;
  $foo = $var;
}

function print_something() {
  global $foo;
  print( "Foo is {$foo}&lt;br&gt;" );
}

function do_something() {
  global $foo;
  $foo = (int) $foo;
  $foo++;
}</pre>
<h3>Prefixen</h3>
<p>Nun kommt die nächste Version von WordPress raus und BÄMM, WordPress verwendet selber die Variable <code>foo</code> und macht sie mittels <code>global</code> auch noch überall verfügbar. Eine Katastrophe, denn nun müssten wir unser Plugin/Theme komplett umschreiben.<br />
Bisher vermied man dieses Problem indem man alle seine Variablen und Funktionen mit einem Prefix versah, also anstatt einfach nur <code>$foo</code> mit einem Prefix wie z.B. <code>$fb_foo</code>. Diese Lösung hat jedoch auch seine Nachteile. <a title="Blog | bueltge.de [by:ltge.de]" href="http://bueltge.de/home/">Frank Bültge</a> hatte seit jeher den Prefix <code>fb_</code> verwendet, dieser wird jedoch mittlerweile häufig im Zusammenhang mit FaceBook verwendet. Einen kurzen und recht eindeutigen Prefix zu finden, dürfte so langsam schwer werden. Könnte man hingehen und einen längeren Prefix verwenden, zum Beispiel <code>frabue_</code> der so lange funktioniert, bis jemand anderes ihn ebenfalls verwendet. Eine Rüstungsspirale die dazu führt das der Prefix irgendwann länger ist als der Variablen- oder Funktionsname.</p>
<h3>Namespaces</h3>
<p>Seit PHP5.3 haben wir die Möglichkeit <a title="PHP: Namespaces - Manual" href="http://php.net/manual/de/language.namespaces.php">Namespaces</a> zu nutzen. Namspaces lösen eine ganze Reihe solcher und vergleichbarer Probleme, weshalb ich inzwischen nur noch für PHP5.3+ schreibe. Man sollte aber auch nicht verschweigen, dass man sich angewöhnen muss seinen Code anders zu schreiben. Am Anfang bedeutet dies etwas Frust, der schwindet jedoch recht schnell weil die Vorteile überwiegen. Leider hat nicht jeder die Möglichkeit PHP5.2 einfach zu ignorieren. Arbeitet man im Kundenauftrag und weigert der Kunde sich beharrlich auf PHP5.3+ zu wechseln, kann man nicht auf Namespaces zurück greifen.</p>
<h3>Containern</h3>
<p>Aber wir können zumindest für unsere Variablen unseren eigenen kleinen Namespace basteln. Und den können wir dann auch noch wesentlich komfortabler ausstatten als den globalen Namensraum. Dazu nutzen wir eine Klasse die in der Grundversion aus lediglich zwei magischen Methoden besteht, <code>__set()</code> und <code>__get()</code>. Der Klasse geben wir noch eine statische Eigenschaft mit in der wir dann alle unsere Variablen speichern können. Der große &#8220;Zauber&#8221; an dieser Klasse besteht im Grunde genommen darin, dass statische Eigenschaften immer ihren Wert behalten, egal wie viele Instanzen wir von der Klasse erstellen.</p>
<pre class="brush:php">&lt;?php 
class DataContainer
{
  public static $data = array();

  public function __set( $name, $value ) {
    self::$data[$name] = $value;
  }

  public function __get( $name ) {
    if ( isset( self::$data[$name] ) )
      return self::$data[$name];
    else
      return null;
  }
}</pre>
<p>Die Verwendung der Klasse ist recht simpel. Wollen wir eine Variable setzen, erzeugen wir eine Instanz der Klasse und setzen die Variable. Wollen wir an einer anderen Stelle die gleiche Variable wieder zurück lesen, erzeugen wir eine Instanz und lesen ganz einfach die Variable.</p>
<pre class="brush:php">&lt;?php
function set_foo( $var ) {
  $dc = new DataContainer;
  $dc-&gt;foo = $var;
}

function print_something() {
  $dc = new DataContainer;
  $foo = $dc-&gt;foo;
  print( "Foo inside DataContainer: {$dc-&gt;foo}
 Foo as local variable: {$foo}
" );
}

function do_something() {
  $dc = new DataContainer;
  $foo = &amp;$dc::$data['foo'];
  $foo = (int) $foo;
  $foo++;
}

set_foo( '1' );
do_something();

$dc = new DataContainer();
echo "Foo is now: {$dc-&gt;foo}";</pre>
<p>Wie man an der Funktion <code>do_something()</code> sieht, ist es auch möglich die Variablen innerhalb vom DataContainer mittels Referenz zu bearbeiten, so dass man bearbeitete Werte nicht zwangsweise wieder zurück in den DataContainer schreiben muss.</p>
<h3>Vererbung</h3>
<p>Nun ist es unter Umständen etwas mühselig in jeden Funktionsaufruf eine neue Instanz des DataContainers zu erzeugen. Arbeitet man objektorientiert, ist es etwas einfacher, da die Klassen den DataContainer erweitern können.</p>
<pre class="brush:php">&lt;?php
class Bar extends DataContainer
{
  public function hello_foo() {
    printf( 'Foo used inside %s: %s
', __CLASS__, $this-&gt;foo );
  }
}

$bar = new Bar();
$bar-&gt;hello_foo();</pre>
<p>Alle Variablen die im DataContainer abgelegt, gelöscht oder geändert werden, sind in der Klasse <code>Bar</code> genauso verfügbar. Vererbung ist nicht gerade die Paradedisziplin von PHP weswegen man wohl eher auf <a title="What is Dependency Injection? - Fabien Potencier" href="http://fabien.potencier.org/article/11/what-is-dependency-injection">Dependency Injection</a> zurück greifen würde. Ein weiterer, meinem persönlichen Geschmack nach, besonders wertvoller Vorteil von DI ist, man kann seinen DataContainer Mocken und die testbarkeit seiner Klassen deutlich erhöhen. DI, Unittest und Mockings sind aber ein ganz anderes Thema.</p>
<h3>RODC &#8211; Read Only DataContainer</h3>
<p>Es kann natürlich sein das unser Theme oder Plugin durch Filter und Hooks erweitert werden kann, dann könnte es durchaus sein das wir einmal gesetzte Variablen davor schützen wollen das sie von unbekannten Code überschrieben werden. Nutzt man den globalen Namensraum, so ist das nahezu unmöglich. In WordPress gibt es z.B. keine Möglichkeit die globale Variable <code>$post</code>, die eine zentrale Rolle spielt, vor dem Überschreiben zu schützen. Jeder kann sie jederzeit löschen oder ändern, was dazu führt das andere Codeabschnitte, die diese Variable benötigen, unter Umständen versagen. Mit einem DataContainer ist das deutlich einfacher zu handhaben, wir bauen einfach eine Methode ein die bestimmte Variablen als <em>Read Only</em> kennzeichnet.</p>
<pre class="brush:php">&lt;?php
class DataContainer
{
  public static $data = array();

  public static $protected = array();

  public function __set( $name, $value ) {
    if ( ! in_array( $name, self::$protected ) )
      self::$data[$name] = $value;
  }

  public function __get( $name ) {
    if ( isset( self::$data[$name] ) )
      return self::$data[$name];
    else
      return null;
  }

  public static function protect( $name ) {
    if ( ! in_array( $name, self::$protected ) )
      array_push( self::$protected, $name );
  }
}

function good_foo() {
  $dc = new DataContainer();
  $dc-&gt;foo = 'protected foo';
  $dc-&gt;bar = 'unprotected bar';
  $dc-&gt;protect( 'foo' );
}

function bad_bar() {
  $dc = new DataContainer();
  $dc-&gt;foo = 'hahaha!';
  $dc-&gt;bar = 'I change everything!';
}

$dc = new DataContainer();

echo "Set &lt;code&gt;foo&lt;/code&gt; to &lt;b&gt;protected foo&lt;/b&gt; and &lt;code&gt;bar&lt;/code&gt; to &lt;b&gt;unprotected bar&lt;/b&gt;&lt;br&gt;";
good_foo();

echo "Try to overwrite &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt;&lt;br&gt;";
bad_bar();

echo "&lt;code&gt;foo&lt;/code&gt; is still &lt;b&gt;{$dc-&gt;foo}&lt;/b&gt; and &lt;code&gt;bar&lt;/code&gt; is now &lt;b&gt;{$dc-&gt;bar}&lt;/b&gt;&lt;br&gt;";</pre>
<p>Das dürfte nun nicht jeden Tag vorkommen das man seine Variablen schützen muss, zeigt aber schön welche Vorteile ein DataContainer gegenüber den globalen Namensraum hat. Man ihn nämlich nahezu nach belieben an seine Bedürfnisse anpassen.</p>
<h3>Shutdown</h3>
<p>Zum Schluss noch ein kleines Beispiel wie ich bei einem Plugin, an dem ich gerade schreibe, mit Hilfe eines DataContainers ein paar Probleme gelöst habe.<br />
Das Plugin erforderte die Zwischenspeicherung einiger Daten da diese zur Laufzeit erstellt werden und über verschiedene Seitenaufrufe verfügbar bleiben müssen. Gegeben sei also z.B. ein Array <code>$a</code> das zur Laufzeit befüllt wird und bei einem Ajax-Request verfügbar sein muss. Mein erster Lösungsansatz war die Verwendung von <code>$_SESSION</code>, denn genau dazu sind Sessions da. Um Daten über verschiedene Seitenaufrufe breit zu stellen. Um sicher zu gehen das am Ende des Skripts auch alle Daten in der Session gespeichert wurden, habe ich <code>shutdown</code> Hook von WordPress benutzt. Dieser Hook wird bei Beendigung des Skriptes ausgeführt, zu einem Zeitpunkt also, wenn alle Daten vorhanden sein sollten. In der Callback-Funktion habe ich dann einfach alle Daten in die Session geschrieben und die Session geschlossen.<br />
Nun taten sich verschiedene Probleme auf. Zum einen ist das recht unflexibel. Fügt man noch weitere Daten hinzu, muss man sich darum kümmern das auch diese in der Session gespeichert werden. Genauso wenn Daten entfallen, muss man sich darum kümmern das diese, nicht mehr vorhandenen Daten, nicht gespeichert werden. Der erste Lösungsansatz war dann anstatt einzelner Arrays einen DataContainer zu verwenden und dann den kompletten DataContainer in der Session zu speichern. Das funktioniert erstaunlich gut, jedoch musste ich mich immer noch selber darum kümmern das die Daten in der Session gespeichert werden.<br />
Zudem ist der <code>shutdown</code> Hook nicht wirklich sicher. Wird das Skript z.B. mit einem <code>exit()</code> <code>die()</code> beendet bevor der Hook registriert wird, werden die Daten nicht in der Session gespeichert. Dieses Problem lässt sich dadurch lösen, indem man das Speichern und lesen der Daten in bzw. aus der Session in den DataContainer verlagert.</p>
<pre class="brush:php">&lt;?php
class DataContainer
{
	const SESSION_KEY = 'Example_DataConatiner';

	public static $data = array();

	public function __construct() {
		( ! session_id() ) AND session_start();

		if ( isset( $_SESSION[self::SESSION_KEY] ) &amp;&amp; ! empty( $_SESSION[self::SESSION_KEY] ) )
			self::$data = $_SESSION[self::SESSION_KEY];

		register_shutdown_function( array( $this, '__destruct' ) );
	}

	public function __destruct() {
		( ! session_id() ) AND session_start();

		$_SESSION[self::SESSION_KEY] = self::$data;
		session_write_close();
	}

	public function __set( $name, $value ) {
		self::$data[$name] = $value;
	}

	public function __get( $name ) {
		if ( isset( self::$data[$name] ) )
			return self::$data[$name];
		else
			return null;
	}

	public static function reset() {
		self::$data = array();
		unset($_SESSION[self::SESSION_KEY]);
		session_write_close();
	}
}

$dc  = new DataContainer();
$uri = $_SERVER['PHP_SELF'];

if ( null === $dc-&gt;session_data ) {
	$dc-&gt;session_data = 'Value from previous page request';
	echo 'This is the first run&lt;br&gt;';
	die( "&lt;a href='{$uri}?run=2'&gt;Klick&lt;/a&gt;" );
}

$pagerequest = filter_input( INPUT_GET, 'run', FILTER_SANITIZE_NUMBER_INT );
echo "This is the {$pagerequest}nd run with &lt;b&gt;{$dc-&gt;session_data}&lt;/b&gt; from session-data";
$dc::reset();</pre>
<p>Das funktioniert schon recht wunderbar. Durch die <code>__destruct()</code> Methode wird der Inhalt des DataContainers in der Session gespeichert sobald er zerstört wird. Da PHP am Ende eines Skriptes alle bestehenden Objekte zerstört (schließt), wird die <code>__destruct</code> Methode automatisch am Ende eines Skriptes aufgerufen. Im Beispiel oben wird die <code>__destruct()</code> Methode mittels <code>register_shutdown_function()</code> noch zusätzlich registriert, so dass sie beim Beenden des Skriptes auch definitiv ausgeführt wird. Verwendet man anstatt der magischen <code>__destruct()</code> Methode eine eigene Methode und registriert sie mit <code>register_shutdown_function()</code>, so kann man den DataContainer verwerfen ohne das seine Werte gespeichert werden, die Werte werden jedoch automatisch am Ende des Skriptes gespeichert.</p>
<p>Allerdings wurden Sessions zu einen Zeitpunkt erfunden als Browser keine Tabs kannten und anscheinend geht jeder Browser etwas anders damit um. Ich hatte zumindest massive Probleme mit dem FireFox wenn ich mehr als einen Tab zum gleichen Server offen hatte (z.B. die Startseite in den einen Tab, einen Artikel in der Einzelansicht in einen anderen). Chrome und Opera können das besser, aber ich kann meinen Besuchern ja schlecht vorschreiben welchen Browser sie zu benutzen haben oder wie viele Tabs sie öffnen dürfen.<br />
WordPress bietet uns einen guten Ersatz für Sessions sofern man damit Probleme hat. Wir verwenden einfach <a title="Transients API « WordPress Codex" href="http://codex.wordpress.org/Transients_API">Transients</a> zum Speichern der Daten. Man muss hier abwägen ob die zusätzlichen DB-Zugriffe und vor allem die Menge an Daten die man speichern möchte dies rechtfertigt. Transients haben den Vorteil das man recht genau einstellen kann wie lange sie gültig sind. Das geht zwar mit <a title="PHP: session_set_cookie_params - Manual" href="http://php.net/manual/en/function.session-set-cookie-params.php">Sessions auch</a>, jedoch erlaubt nicht jeder Hoster das Verändern des Wertes für die Session-Lifetime. Transients sind sogar beständiger als Sessions, so kann man einen Transient an einen Login koppeln und somit eine Art von Server-Cookie umsetzen.</p>
<h3>Fazit</h3>
<p>Ich hoffe es ist deutlich geworden das der globale Namensraum eigentlich mehr Nach- als Vorteile hat und das man mit nur wenig Aufwand eine bessere Lösung bekommen kann die man nach seinen eigenen Bedürfnissen anpassen kann. Vor allem das automatische Speichern, ob in Sessions oder Transients, erleichtert die tägliche Arbeit enorm da man sich weniger Gedanken darum machen muss ob man nun alles gespeichert hat oder nicht. Der DataContainer lässt sich enorm ausbauen, denkbar wäre z.B. auch eine Methode die Werte aus einen Aufruf der Settings-API validiert und speichert. Am Ende des Skriptes werden die Daten automatisch in die Options geschrieben, stehen aber während der Laufzeit weiterhin zur Verfügung ohne das man sie sich extra aus den Options holen müsste.<br />
Vor allem das man den DataContainer, und somit auch Zugriffe auf Transients und die Options-Tabelle, sehr einfach mocken kann, erleichtert das Unittesting ungemein wodurch man wiederum viel Zeit und Mühe beim Programmieren spart.<br />
Alle in diesen Artikel verwendeten <a title="Example files for DataContainer" href="https://gist.github.com/RalfAlbert/5684779">Skripte sind als Gist</a> erhältlich für den Fall das sich jemand dazu ermuntert fühlt ein wenig mit DataContainern zu experimentieren.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-121/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Empfehlung des Tages: Filter-Funktionen</title>
		<link>http://yoda.neun12.de/artikel-117</link>
		<comments>http://yoda.neun12.de/artikel-117#comments</comments>
		<pubDate>Sun, 19 May 2013 12:59:21 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Sicherheit]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=117</guid>
		<description><![CDATA[Seit PHP5.2 sind die Filter-Funktionen fester Bestandteil von PHP geworden. Jedoch greifen immer noch sehr wenige Programmierer auf diese Filter-Funktionen zurück, was ein kleines bis großes Sicherheitsrisiko darstellt. Der Normalfall sieht immer noch so aus, dass einfach abgefragt wird ob in $_GET, $_POST oder $_REQUEST ein Schlüssel vorhanden ist und dann der entsprechende Wert verwendet [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Seit PHP5.2 sind die <a title="PHP: Filter-Funktionen - Manual" href="http://www.php.net/manual/de/ref.filter.php">Filter-Funktionen</a> fester Bestandteil von PHP geworden. Jedoch greifen immer noch sehr wenige Programmierer auf diese Filter-Funktionen zurück, was ein kleines bis großes Sicherheitsrisiko darstellt.</p>
<p>Der Normalfall sieht immer noch so aus, dass einfach abgefragt wird ob in <code>$_GET</code>, <code>$_POST</code> oder <code>$_REQUEST</code> ein Schlüssel vorhanden ist und dann der entsprechende Wert verwendet wird. Leider viel zu oft sieht man auch, dass erst gar nicht geprüft wird ob der Schlüssel vorhanden ist und einfach davon ausgegangen wird das dieser vorhanden ist und verwendet werden kann. Das ist nicht nur schlechter Stil, sondern eröffnet auch eine Sicherheitslücke. Denn die superglobalen Arrays <code>$_GET</code>, <code>$_POST</code> und <code>$_REQUEST</code> sind keine Einbahnstraße, man kann aus ihnen lesen und in sie hinein schreiben. Schauen wir uns das mal etwas näher an.</p>
<p><code>$_REQUEST</code> lassen wir in der in diesem Artikel mal außen vor da es noch nicht von den Filter-Funktionen unterstützt wird. Zudem sollte man auf <code>$_REQUEST</code> auch nur in Ausnahmefällen zugreifen. <code>$_REQUEST</code> Enthält die Daten von <code>$_GET</code> und <code>$_POST</code>. Die Verwendung von <code>$_REQUEST</code> deutet also darauf hin, dass man nicht so wirklich weiß was man tut und einfach auf gut Glück auf ein superglobales Array zugreift in der Hoffnung die gesuchten Daten seien schon irgendwie da.<br />
Es gibt einige wenige Fälle wo der Zugriff auf <code>$_REQUEST</code> sinnvoll sein kann, man sollte sich jedoch im klaren darüber sein das der Zugriff auf <code>$_REQUEST</code> eben nicht so sicher ist als wenn man <code>$_GET</code> und <code>$_POST</code> mit den Filter-Funktionen abfragt.</p>
<h3>$_GET und $_POST sind keine Einbahnstraße</h3>
<p>Das man auf die superglobalen Arrays <code>$_GET</code> und <code>$_POST</code> nicht nur lesend, sondern auch schreibend zugreifen kann, ist anscheinend nicht allen klar. Schauen wir uns dazu mal dieses Script an</p>
<pre class="brush:php">$_POST['nonce'] = 'badnonce';
echo 'Was the nonce send with a POST request?&lt;br&gt;';
echo 'With &lt;code&gt;isset()&lt;/code&gt;: ' . ( isset( $_POST['nonce'] ) ? 'yes' : 'no' ) . '&lt;br&gt;';
echo 'With &lt;code&gt;filter_has_var()&lt;/code&gt;' . ( filter_has_var( INPUT_POST, 'nonce' ) ? 'yes' : 'no' ) . '&lt;br&gt;';
echo 'Value of &lt;code&gt;nonce&lt;/code&gt; with &lt;code&gt;$_POST[\'nonce\']&lt;/code&gt;: ' . $_POST['nonce'] . '&lt;br&gt;';
echo 'Value of &lt;code&gt;nonce&lt;/code&gt; with &lt;code&gt;filter_input( INPUT_POST, \'nonce\' )&lt;/code&gt;:' . filter_input( INPUT_POST, 'nonce' ) . '&lt;br&gt;';

echo '&lt;hr&gt;';

$_GET['nonce'] = 'badnonce';
echo 'Was the nonce send with a GET request?&lt;br&gt;';
echo 'With &lt;code&gt;isset()&lt;/code&gt;: ' . ( isset( $_GET['nonce'] ) ? 'yes' : 'no' ) . '&lt;br&gt;';
echo 'With &lt;code&gt;filter_has_var()&lt;/code&gt;' . ( filter_has_var( INPUT_GET, 'nonce' ) ? 'yes' : 'no' ) . '&lt;br&gt;';
echo 'Value of &lt;code&gt;nonce&lt;/code&gt; with &lt;code&gt;$_GET[\'nonce\']&lt;/code&gt;: ' . $_GET['nonce'] . '&lt;br&gt;';
echo 'Value of &lt;code&gt;nonce&lt;/code&gt; with &lt;code&gt;filter_input( INPUT_GET, \'nonce\' )&lt;/code&gt;:' . filter_input( INPUT_GET, 'nonce' ) . '&lt;br&gt;';</pre>
<p>Die <code>nonces</code> sind in <a title="Glossary « WordPress Codex" href="http://codex.wordpress.org/Glossary#Nonce">WordPress ein Sicherheitsmechanismus</a> mit dem man prüfen kann ob eine Anfrage tatsächlich von dort kommt, von wo man sie erwartet. Verlassen wir uns darauf das der Schlüssel <code>nonce</code> vorhanden ist und verwenden diesen, gehen wir das Risiko ein das er an einer anderen Stelle einfach überschrieben wurde.</p>
<p>Das man die Werte der superglobalen Arrays einfach überschreiben kann, lässt sich recht einfach mit vielen WordPress Funktionen testen die Werte aus den superglobalen Arrays <code>$_GET</code>, <code>$_POST</code> und/oder <code>$_REQUEST</code> verwenden.</p>
<pre class="brush:php">add_action(
	'admin_init',
	function(){
		if (
			( isset( $_GET['action'] ) &amp;&amp; 'delete-comment' == $_GET['action'] )
			||
			( isset( $_GET['action'] ) &amp;&amp; 'trash' == $_GET['action'] )
		) {
			$_GET['action'] = $_POST['action'] = $_REQUEST['action'] = 'not-now';
		}
	}
);</pre>
<p>Einfach mal diesen Code-Schnipsel in die <code>functions.php</code> einfügen und dann im Backend die Kommentarübersicht aufrufen. Dort dann wahllos ein paar Kommentare löschen. Entweder über die Checkboxen und eines der Bulk-Menüs oder über den Link der erscheint wenn man mit der Maus auf einen Kommentar zeigt.<br />
Nutzt man die Checkboxen und das Bulk-Menü, passiert gar nichts. Beim Löschen über den Link verschwindet zwar der Kommentar und der Zähler hinter &#8220;Papierkorb&#8221; geht hoch, ein Klick auf &#8220;Alle Kommentare&#8221; genügt um die vermeintlich gelöschten Kommentare wieder anzuzeigen.</p>
<p>Es geht aber deutlich böser</p>
<pre class="brush:php">add_action(
	'admin_init',
	function(){
		if (
			( isset( $_GET['action'] ) &amp;&amp; 'delete-comment' == $_GET['action'] )
			||
			( isset( $_GET['action'] ) &amp;&amp; 'trash' == $_GET['action'] )
		) {
			$a = array_fill( 0, 5, 0 );
			array_walk( $a, function( &amp;$e ){ $e = rand( 1,999 ); } );
			$_GET['delete_comments'] = $_POST['delete_comments'] = $_REQUEST['delete_comments'] = $a;
			$_GET['c'] = $_POST['c'] = $_REQUEST['c'] = rand( 1, 999 );
		}
	}
);</pre>
<p>Dieser Code überschreibt nicht einfach die <code>action</code>, sondern ersetzt die ausgewählten Kommentare durch zufällige Werte. Egal was man auswählt, welche Kommentaren gelöscht werden ist reiner Zufall. Im besten Fall passiert nichts, da die zufällig ausgewählten IDs nicht existieren. Im schlimmsten Fall werden ganz andere Kommentare gelöscht als ausgewählt. Man könnte auch über eine SQL-Abfrage alle vorhandenen Kommentar-IDS abfragen und dann zufällig IDs auswählen, dass ist dann richtig böse aber ein anderes Thema.</p>
<p>Mit <code>filter_input()</code> wäre dies nicht möglich, da <code>filter_input()</code> nur die Werte berücksichtigt, die auch tatsächlich über einen Request abgeschickt wurden (siehe erstes Beispiel). Nun fragt man sich vielleicht warum WordPress etwas so dummes macht wenn es doch eine solch einfache Lösung für das Problem gibt.<br />
Nun die Antwort liegt in meinen ersten Satz dieses Artkels. Die Filter-Funktionen sind erst ab PHP5.2 verfügbar, WordPress wurde jedoch zu PHP4 Zeiten entwickelt und enthält auch noch unendlich viel PHP4-Code. Wer das ändern möchte, kann gerne mal eine Suche nach <code>$_GET</code>, <code>$_POST</code> und <code>$_REQUEST</code> über die WordPress Dateien laufen lassen und die entsprechenden Stellen anpassen. Die Suche nach <code>$_GET</code> liefert aktuell 594 Treffer in 104 Dateien. Soviel zu diesen Thema.</p>
<p>Ich hoffe es ist klar geworden warum es nicht ganz unerheblich ist seinen Code mindestens auf PHP5.2 Niveau zu bringen und warum man in seinen Themes und Plugins unbedingt auf die <a title="PHP: Filter-Funktionen - Manual" href="http://www.php.net/manual/de/ref.filter.php">Filter-Funktionen</a> setzen sollte anstatt direkt auf die superglobalen Arrays <code>$_GET</code>, <code>$_POST</code> und <code>$_REQUEST</code> zuzugreifen.</p>
<p>Zum Schluss noch etwas Mehrwert. Manchmal kann es vorkommen das Werte sowohl per GET als auch POST Request übergeben werden (meist im Zusammenhang mit Ajax Requests), in diesen Fall greift man gerne auf <code>$_REQUEST</code> zurück. Da die Filter-Funktionen von PHP <code>$_REQUEST</code> (noch) nicht unterstützen, müsste man jedes mal umständlich <code>$_GET</code> und <code>$_POST</code> abfragen ob der benötigte Schlüssel vorhanden ist. Das kann man sich mit einer kleinen Funktion vereinfachen und den Mangel von PHP gleich etwas ausbügeln.</p>
<pre class="brush:php">function read_superglobals( $vars ) {
	
	if ( is_string( $vars ) )
		$vars = (array) $vars;
	
	$return = array();
	
	foreach ( $vars as $variable_name ) {
		if ( ! filter_has_var( INPUT_POST, $variable_name ) ) {
			if ( ! filter_has_var( INPUT_GET, $variable_name ) ) {
				$return[$variable_name] = '';
			} else {
				$return[$variable_name] = filter_input( INPUT_GET, $variable_name );
			}
		} else {
			$return[$variable_name] = filter_input( INPUT_GET, $variable_name );
		}
	}

	return $return;
}</pre>
<p>Die Funktion erwartet als Parameter ein Array oder einen String mit den jeweiligen Schlüssel(n) den/die man abfragen möchte. Die Funktion prüft dann mit <code>filter_input()</code> ob in <code>$_GET</code> oder <code>$_POST</code> der Schlüssel vorhanden ist. Ist er vorhanden, kopiert sie den Wert mit den zugehörigen Schlüssel in ein Array und gibt anschließend das Array zurück. Die Funktion arbeitet in etwa so wie <code>wp_reset_var()</code>, jedoch mit den Unterschied das sie keine globalen Variablen erzeugt und ausschließlich die Schlüssel zurück gibt, die auch tatsächlich mittels eines GET oder POST Requests abgesendet wurden.<br />
Natürlich kann man die Funktion auch dann verwenden, wenn man genau weiß ob die Werte mittels GET oder POST Request gesendet wurden. Dann bekommt man ein Array zurück mit exakt den Schlüssel-Werte Paaren die man benötigt.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-117/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linktitel automatisch ausfüllen lassen</title>
		<link>http://yoda.neun12.de/artikel-110</link>
		<comments>http://yoda.neun12.de/artikel-110#comments</comments>
		<pubDate>Sat, 11 May 2013 15:36:28 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[Plugin]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=110</guid>
		<description><![CDATA[Bitte beachten! Das Plugin steht nun auch auf WordPress.org zum Download bereit. Bitte alle Supportanfragen und Fehlermeldungen entweder im Support auf WordPress.org oder im Issue Tracker auf GitHub. Bitte keine Support-Anfragen in den Kommentaren! Danke für das Verständnis. Derzeit schreibe ich an ein paar Artikeln und ärgere mich immer das ich, wenn ich einen Link erstelle, [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><strong>Bitte beachten!</strong><br />
Das Plugin steht nun auch auf <a title="WordPress - Auto Title To Link &gt; WordPress Plugins" href="http://wordpress.org/plugins/auto-insert-title-to-link/">WordPress.org zum Download</a> bereit. Bitte alle Supportanfragen und Fehlermeldungen entweder im <a title="WordPress - Support &gt; Auto Title To Link" href="http://wordpress.org/support/plugin/auto-insert-title-to-link">Support auf WordPress.org</a> oder im <a title="Issues · RalfAlbert/auto-title-to-link · GitHub" href="https://github.com/RalfAlbert/auto-title-to-link/issues">Issue Tracker auf GitHub</a>. <strong>Bitte keine Support-Anfragen in den Kommentaren!</strong> Danke für das Verständnis.</p>
<hr />
<p>Derzeit schreibe ich an<a class="highslide" onclick="return hs.expand(this)"  href="http://yoda.neun12.de/wp-content/uploads/2013/05/autoinsertlinktitle.jpg"><img class=" wp-image-112 alignright" alt="Autoinsert Linktitle" src="http://yoda.neun12.de/wp-content/uploads/2013/05/autoinsertlinktitle-300x287.jpg" width="210" height="201" /></a> ein paar Artikeln und ärgere mich immer das ich, wenn ich einen Link erstelle, den Titel für den Link manuell ausfüllen muss. Wahrscheinlich bin ich der einzige auf diesen Planeten mit diesen Problem, deswegen habe ich mir schnell mal ein <a title="RalfAlbert/auto-title-to-link · GitHub" href="https://github.com/RalfAlbert/auto-title-to-link">kleines Plugin</a> geschrieben.</p>
<p>Gibt man im URL-Feld eine gültige URL ein und verlässt dieses Feld, dann wird ein Ajax-Request abgesetzt der versucht aus der verlinkten Webseite den <code>title</code>-Tag zu extrahieren. Gelingt dies, wird der Webseitentitel in das Feld für den Linktitel eingefügt. Wenn nicht, passiert nix. Den Titel kann man bei Bedarf dann noch anpassen oder wieder löschen.</p>
<p>Vielleicht nimmt sich ja mal jemand etwas Zeit und gibt ein wenig Feedback, wäre schön und hilfreich.</p>
<h3>Nachtrag</h3>
<p>Ich hatte nicht damit gerechnet das dass Plugin ein so hohes Interesse wecken würde. Github, dort wo der Plugin-Code derzeit liegt, ist nicht jedem bekannt und auch nicht jeder weiß wie man aus dem Repository ein Zip bekommt. Deswegen hier eine kleine Anleitung dazu.</p>
<p><a class="highslide" onclick="return hs.expand(this)"  href="http://yoda.neun12.de/wp-content/uploads/2013/05/github_autoinserttitle1.png"><img class="alignleft size-full wp-image-115" alt="#111" src="http://yoda.neun12.de/wp-content/uploads/2013/05/github_autoinserttitle1.png" width="323" height="239" /></a> Als erstes also mal das <a title="RalfAlbert/auto-title-to-link · GitHub" href="https://github.com/RalfAlbert/auto-title-to-link">Github-Repository</a> öffnen. Sollte euer Bildschirm anders aussehen als im Screenshot links, dann klickt auf <em>Code</em> (zwischen der Pulskurve und <em>Network</em> (die rote Markierung habe allerdings ich eingefügt)). Rechts neben <em> Clone in Windo</em>ws ist ein Button mit einer kleinen Wolke und dem Wort <em>ZIP (siehe Screenshot)</em>. Klickt ihr da drauf, dann sollte eine Aufforderung erscheinen eine Zip-Datei zu speichern.<br />
Diese Zip-Datei speichert ihr auf eurem Computer und kann dann bereits aus dem Backend von WordPress heraus installiert werden.<br />
Dazu im Backend auf die Plugins-Seite gehen, dort oben neben <em>Plugins</em> auf <em>Installieren</em> klicken, im nächsten Bildschirm auf <em> Hochladen</em> (oder in der englischen Version <em>Upload</em>), die zuvor gespeicherte Zip-Datei auswählen und fertig. Nun noch das Plugin aktivieren und das war es.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-110/feed</wfw:commentRss>
		<slash:comments>35</slash:comments>
		</item>
		<item>
		<title>Der kleine aber feine Unterschied zwischen is_email() und sanitize_email()</title>
		<link>http://yoda.neun12.de/artikel-104</link>
		<comments>http://yoda.neun12.de/artikel-104#comments</comments>
		<pubDate>Tue, 30 Apr 2013 11:53:15 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[HowTo]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=104</guid>
		<description><![CDATA[Wer mit E-Mails in WordPress arbeitet, sollte den Unterschied zwischen is_email() und sanitize_email() kennen. Er ist zwar klein, aber fein. Der offensichtlichste Unterschied ist erst einmal der Rückgabewert. is_email() prüft ob eine gegebene E-Mail Adresse überhaupt den Kriterien entspricht und gibt einen String zurück wenn dem so ist. Andernfalls gibt is_email() false zurück. sanitize_email() hingegen [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Wer mit E-Mails in WordPress arbeitet, sollte den Unterschied zwischen <code>is_email()</code> und <code>sanitize_email()</code> kennen. Er ist zwar klein, aber fein.</p>
<p>Der offensichtlichste Unterschied ist erst einmal der Rückgabewert. <code>is_email()</code> prüft ob eine gegebene E-Mail Adresse überhaupt den Kriterien entspricht und gibt einen String zurück wenn dem so ist. Andernfalls gibt <code>is_email()</code> <code>false</code> zurück. <code>sanitize_email()</code> hingegen gibt entweder einen String mit einer gültigen E-Mail Adresse oder einen leeren String zurück.<br />
<code>is_email()</code> gibt also einen boolschen Wert oder einen String, <code>sanitize_email()</code> immer einen String zurück.</p>
<p>Nun könnte man mit einer einfachen Typumwandlung <code>is_email()</code> dazu bringen ebenfalls immer einen String zurück zu geben. <code>(string) is_email( $email )</code> würde sich nahezu gleich verhalten wie <code>sanitize_email()</code>. Im Erfolgsfall eine gültige E-Mail Adresse, im Fehlerfall einen leeren String. Stimmt das? Überprüfen wir es:</p>
<pre class="brush:php">$emails = array( 'foo@bar.com', 'baz-at-example-org', 'öttö@wördpäss.com', 'meh@cöm.com' );
echo '&lt;ol&gt;';
array_walk(
	$emails,
	function ($email) {
		$empty = 'an empty string';
		$is = (string) is_email( $email );
		$se = sanitize_email( $email );

		printf(
			'&lt;li&gt;%s - %s (%s)&lt;/li&gt;',
			( '' != $is ) ? $is : $empty,
			( '' != $se ) ? $se : $empty,
             $email
		);
	}
);
echo '&lt;/ol&gt;';</pre>
<p>Die Ausgabe sieht in etwa so aus:</p>
<blockquote>
<ol>
<li>foo@bar.com &#8211; foo@bar.com (foo@bar.com)</li>
<li>an empty string &#8211; an empty string (baz-at-example-org)</li>
<li>an empty string &#8211; tt@wrdpss.com (öttö@wördpäss.com)</li>
<li>an empty string &#8211; meh@cm.com (meh@cöm.com)</li>
</ol>
</blockquote>
<p>Wie man sehen kann, gibt <code>(string) is_email( $email )</code> wie erwartet bei ungültigen E-Mail Adressen einen leeren String zurück. Das WordPress glaubt das Umlaute in E-Mail Adressen nicht erlaubt seien, lass wir an dieser Stelle mal dahingestellt. WordPress kann halt (noch) nicht mit Umlautdomains umgehen.<br />
Viel interessanter ist die Ausgabe von <code>sanitize_email()</code>. Auch <code>sanitize_email()</code> kann nicht mit Umlauten umgehen, streicht sie aber einfach aus der E-Mail Adresse anstatt sie z.B. zu kodieren.</p>
<p>Das führt nun natürlich zu Problemen wenn man es nicht weiß. Sollte mal eine größere Anzahl an E-Mails nicht versendet werden, kann das mitunter daran liegen das man vergessen hat vor dem Speichern zu prüfen ob WordPress damit umgehen kann.</p>
<pre class="brush:php">// FALSCH
$user = array(
  'name' =&gt; 'Hans'
  'email' =&gt; sanitize_email( $email )
);
update_option( 'awesome_options', $user );

// Richtig
$user = array(
  'name' =&gt; 'Hans'
  'email' =&gt; sanitize_email( (is_email( $email ) )
);
update_option( 'awesome_options', $user );</pre>
<h3>Merke!</h3>
<p>Jede E-Mail Adresse sollte bevor sie mit <code>sanitize_email()</code> verarbeitet wird erst mit <code>is_email()</code> validiert werden. Ansonsten bekommt man E-Mail Adressen die vielleicht lustig aussehen, es aber definitiv nicht sind.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-104/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Metaboxen eine CSS-Klasse zuordnen</title>
		<link>http://yoda.neun12.de/artikel-97</link>
		<comments>http://yoda.neun12.de/artikel-97#comments</comments>
		<pubDate>Thu, 04 Apr 2013 15:22:33 +0000</pubDate>
		<dc:creator><![CDATA[Ralf]]></dc:creator>
				<category><![CDATA[HowTo]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://yoda.neun12.de/?p=97</guid>
		<description><![CDATA[Auf WPSE tauchte die Frage auf wie man eine Metabox im Backend per Voreinstellung minimiert darstellt. WordPress bietet hierfür keine Option an, obwohl es wahrscheinlich keine schlechte Idee wäre. Denn fügt man relativ viele Metaboxen ein, wird es schnell unübersichtlich. Um eine Metabox minimiert (geschlossen) darzustellen, benötigt sie die CSS-Klasse closed. Auch wenn man eine [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Auf <a title="WordPress StackExchange" href="http://wordpress.stackexchange.com/questions/94401/auto-close-hide-custom-metabox-set-default-state">WPSE tauchte die Frage auf</a> wie man eine Metabox im Backend per Voreinstellung minimiert darstellt. WordPress bietet hierfür keine Option an, obwohl es wahrscheinlich keine schlechte Idee wäre. Denn fügt man relativ viele Metaboxen ein, wird es schnell unübersichtlich. Um eine Metabox minimiert (geschlossen) darzustellen, benötigt sie die CSS-Klasse <code>closed</code>.<br />
Auch wenn man eine Metabox in Abhängigkeit eines bestimmten Wertes besonders hervorheben möchte, z.B. weil eine Aktion beim Speichern fehlgeschlagen ist, bietet WordPress von Haus aus keine Option für zusätzliche CSS-Klassen an. Wer seine Metaboxen anders gestalten möchte, würde also wahrscheinlich auf JavaScript zurück greifen.</p>
<p>Die einfachste Lösung ist wie so oft ein Filter, der allerdings etwas versteckt ist. Die Funktion <code>add_meta_box()</code> selber hat keinerlei Filter oder Actions in die man sich einhängen könnte.<br />
Dafür aber die Funktion die dafür zuständig ist die Titleleiste der Metabox darzustellen. Damit es etwas klarer ist um welchen Teil des HTMLs es hier geht, auszugsweise das HTML der Excerpt-Metabox:</p>
<pre class="brush:php">&lt;div id="postexcerpt" class="postbox"&gt;
  &lt;div class="handlediv" title="Zum umschalten klicken"&gt;
    &lt;h3 class="hndle"&gt;
      &lt;span&gt;Auszug&lt;/span&gt;
    &lt;/h3&gt;
   &lt;div class="inside"&gt;
[...]
    &lt;/div&gt; &lt;!-- Ende div .inside --&gt;
  &lt;/div&gt; &lt;!-- Ende div .handlediv --&gt;
&lt;/div&gt; &lt;!-- Ende div #postexcerpt --&gt;</pre>
<p>Der Filter kann CSS-Klassen zum äußersten Div-Container, hier im Beispiel mit der ID <code>postexcerpt</code>, hinzufügen. Somit ist es dann auch möglich im Stylesheet die nachfolgenden HTML-Elemente zu stylen.</p>
<pre class="brush:php">add_action( 'add_meta_boxes', 'add_my_metabox' );

function add_my_metabox() {
  $id       = 'my-metabox';
  $title    = 'My Metabox';
  $callback = 'my_metabox_content';
  $page     = 'post';

  add_meta_box( $id, $title, $callback, $page );

  add_filter( "postbox_classes_{$page}_{$id}", 'minify_my_metabox' );
}

function my_metabox_content() { ... }

/**
 * Add extra css-classes to a meta-box
 *
 * @param array $classes Array with css-classes
 */
function minify_my_metabox( $classes ) {
  array_push( $classes, 'closed' );

  return $classes;
}</pre>
<p>In der Funktion <code>add_my_metabox()</code> wird zunächst einmal ganz normal eine Metabox erzeugt. Anschließend wird jedoch noch ein Filter gesetzt der als Callback die Funktion <code>minify_my_metabox()</code> aufruft. Der Hook für den Filter muss man um die ID der Metabox und den Post-Type ergänzen. An dieser Stelle wird es ein wenig kompliziert. Im Codex wird der Begriff &#8220;<em>Post Type</em>&#8221; verwendet, da der Filter und die zugehörige Funktion jedoch undokumentiert sind, muss man im Quellcode nachschauen. Und dort wird &#8220;<em>page</em>&#8221; als Variablenname verwendet.<br />
Ich persönlich finde den Begriff &#8220;<em>page</em>&#8221; sinnvoller, da man mit der gleichen Methode auch z.B. die Widgets im Dashboard beeinflussen kann (siehe Beispiel unten). Als &#8220;<em>page</em>&#8221; müsste man dazu lediglich <code>dashboard</code> angeben und kann dann eigenen oder bereits vorhandenen Widgets, weitere CSS-Klassen hinzufügen. Im <a href="http://codex.wordpress.org/Function_Reference/remove_meta_box#Parameters">Codex</a> findet man bei <code>remove_meta_box()</code> noch ein paar weitere mögliche Werte für <em>page</em>. Hier wird übrigens wieder von <em>page</em> gesprochen, im Gegensatz zu <em>post type</em> bei <code>add_meta_box()</code>.</p>
<pre class="brush:php">function register_dash_widget(){

	$id   = 'debugoutput';
	$page = 'dashboard';

	wp_add_dashboard_widget(
		$id,
		'Debug Output',
		function () { echo 'Hello World!'; }
	);

	add_filter(
		"postbox_classes_{$page}_{$id}",
		function ( $classes ) {
			array_push( $classes, 'closed' );
			return $classes;
		}
	);

}

add_action( 'wp_dashboard_setup', 'register_dash_widget' );</pre>
<p>Die Callback-Funktion <code>minify_my_metabox()</code> ist dann wieder recht unspektakulär. Sie erwartet als einzigen Parameter ein Array mit den CSS-Klassen. Fügt man z.B. die Klasse <code>closed</code> hinzu und gibt das Array zurück, so wird die Metabox (oder das Widget) minimiert anstatt geöffnet dargestellt. Denkbar wäre es natürlich auch eine CSS-Klasse <code>alert</code> hinzuzufügen um eine Metabox (oder Widget) farblich hervorzuheben.</p>
]]></content:encoded>
			<wfw:commentRss>http://yoda.neun12.de/artikel-97/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
