<?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>Playground</title>
	<atom:link href="http://playground.ebiene.de/feed/" rel="self" type="application/rss+xml" />
	<link>http://playground.ebiene.de</link>
	<description>Magazin für WordPress, Cloud und Apps</description>
	<lastBuildDate>Fri, 11 May 2012 15:11:57 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>WordPress auf Nginx: Performance und Sicherheit optimieren</title>
		<link>http://playground.ebiene.de/nginx-wordpress-optimieren/</link>
		<comments>http://playground.ebiene.de/nginx-wordpress-optimieren/#comments</comments>
		<pubDate>Wed, 22 Feb 2012 20:50:41 +0000</pubDate>
		<dc:creator>Sergej</dc:creator>
				<category><![CDATA[Performance]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://playground.ebiene.de/?p=2896</guid>
		<description><![CDATA[Im letzten Teil der Serie &#8220;WordPress auf Nginx&#8221; beschreibt das heutige Tutorial die Perfektionierung der Ausgabe an den Browser: Angefangen mit der Gzip-Komprimierung der Daten bis hin zu bevorzugten Caching-Headern für Bilder, Stylesheets und JavaScript. Zum Thema werden auch die nachhaltige Absicherung des Administrationsbereichs und der Schutz gegen unerwünschte Versuche, das WordPress-System anzugreifen. Gzip-Aktivierung Im [...]]]></description>
			<content:encoded><![CDATA[<p>Im letzten Teil der Serie &#8220;<a href="http://playground.ebiene.de/nginx-php5-fpm/">WordPress auf Nginx</a>&#8221; beschreibt das heutige Tutorial die Perfektionierung der Ausgabe an den Browser: Angefangen mit der Gzip-Komprimierung der Daten bis hin zu bevorzugten Caching-Headern für Bilder, Stylesheets und JavaScript. Zum Thema werden auch die nachhaltige Absicherung des Administrationsbereichs und der Schutz gegen unerwünschte Versuche, das WordPress-System anzugreifen.<br />
<span id="more-2896"></span><br />
<strong>Gzip-Aktivierung</strong><br />
Im Auslieferungszustand komprimiert Nginx die Ausgabe der HTML-Dateien im Gzip-Format, so dass weniger Bytes durch die Leitung an den Browser gesendet werden. Doch das ist nur die halbe Mitte, denn ein (WordPress-)Blog beinhaltet auch Stylesheets, Feeds und nicht selten zahlreiche JavaScript-Files. All diese Ressourcen können vom Webserver ebenfalls verkleinert ausgegeben werden.</p>
<p>Dazu müssen in der Konfigurationsdatei <em>nginx.conf</em> &#8211; zu lokalisieren unter <em>/etc/nginx/</em> &#8211; alle Zeilen beginnend mit <em>gzip_</em> einkommentiert werden. <em>Einkommentiert</em> bedeutet, dass das Doppelkreuz am Anfang der jeweiligen Zeilen eliminiert gehört. Und zwar:</p>
<p>Die Standard-Einstellung</p>
<pre>
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json ...
</pre>
<p>verwandelt sich in:</p>
<pre>
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json ...
</pre>
<p>Änderungen speichern, Nginx neu starten:</p>
<pre>
/etc/init.d/nginx restart
</pre>
<p>Die letzte einkommentierte Zeile listet Dateiformate auf, die Nginx Gzip-komprimiert an den Client schickt. Diese kann auf Wunsch ausgedehnt oder reduziert werden.</p>
<div id="attachment_2897" class="wp-caption alignnone" style="width: 484px"><img src="http://playground.ebiene.de/wp-content/uploads/2012/02/nginx-gzip-header.png" alt="Nginx Gzip-Header" title="Nginx Gzip-Header" width="474" height="200" class="size-full wp-image-2897" /><p class="wp-caption-text">Caching- und Gzip-Header gesendet von Nginx</p></div>
<p><strong>Steuerungszentrale</strong><br />
<a href="http://playground.ebiene.de/nginx-mysql-config/">Im vorherigen Artikel</a> wurde gezeigt, wie eine Konfigurationsdatei pro Server erstellt und im Nginx-Verzeichnis <em>sites-available</em> abgelegt wird. In unserem Beispiel heißt die Datei <em>helpdesk.wpseo.de</em> &#8211; diese wurde mit minimalen Eigenschaften bereits versehen. Nun ist es an der Zeit, die empfohlene Konfiguration in voller Länge zu präsentieren. Die Devise bleibt nach wie vor: <em>Nginx optimiert für WordPress.</em></p>
<p><strong>Server-Konfigurationsdatei</strong><br />
<div id="gist-1887141" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'>server {</div><div class='line' id='LC2'>	## INIT</div><div class='line' id='LC3'>	listen 80 default_server;</div><div class='line' id='LC4'>	server_name helpdesk.wpseo.de;</div><div class='line' id='LC5'><br/></div><div class='line' id='LC6'><br/></div><div class='line' id='LC7'>	## ROOT</div><div class='line' id='LC8'>	root /var/www/helpdesk.wpseo.de;</div><div class='line' id='LC9'><br/></div><div class='line' id='LC10'><br/></div><div class='line' id='LC11'>	## LOGS</div><div class='line' id='LC12'>	error_log /var/log/nginx/helpdesk.error.log;</div><div class='line' id='LC13'><br/></div><div class='line' id='LC14'><br/></div><div class='line' id='LC15'>	# DEFAULT INDEX</div><div class='line' id='LC16'>	index index.php;</div><div class='line' id='LC17'><br/></div><div class='line' id='LC18'><br/></div><div class='line' id='LC19'>	## SECURITY</div><div class='line' id='LC20'>	if ( $request_method !~ ^(GET|HEAD|POST)$ ) {</div><div class='line' id='LC21'>		return 444;</div><div class='line' id='LC22'>	}</div><div class='line' id='LC23'>	location ~ /(\.|wp-config.php|liesmich.html|readme.html) {</div><div class='line' id='LC24'>		return 444;</div><div class='line' id='LC25'>	}</div><div class='line' id='LC26'><br/></div><div class='line' id='LC27'><br/></div><div class='line' id='LC28'>	## REWRITES</div><div class='line' id='LC29'>	location ~ ^/(\d+)/$ {</div><div class='line' id='LC30'>		return 301 /?p=$1;</div><div class='line' id='LC31'>	}</div><div class='line' id='LC32'><br/></div><div class='line' id='LC33'><br/></div><div class='line' id='LC34'>	## RESSOURCES</div><div class='line' id='LC35'>	location ~ \.(?:ico|png|jpe?g|css|js)$ {</div><div class='line' id='LC36'>		expires 31d;</div><div class='line' id='LC37'><br/></div><div class='line' id='LC38'>		add_header Pragma &quot;public&quot;;</div><div class='line' id='LC39'>		add_header Cache-Control &quot;public, must-revalidate, proxy-revalidate&quot;;</div><div class='line' id='LC40'><br/></div><div class='line' id='LC41'>		#location ~ \.(?!ico).+$ {</div><div class='line' id='LC42'>		#	valid_referers none blocked server_names ~(wpseo.|google.|yahoo.|bing.|facebook.|fbcdn.|pinterest.);</div><div class='line' id='LC43'>		#	if ( $invalid_referer ) {</div><div class='line' id='LC44'>		#		return 444;</div><div class='line' id='LC45'>		#	}</div><div class='line' id='LC46'>		#}</div><div class='line' id='LC47'>	}</div><div class='line' id='LC48'><br/></div><div class='line' id='LC49'><br/></div><div class='line' id='LC50'>	## REDIRECT INDEX</div><div class='line' id='LC51'>	location / { </div><div class='line' id='LC52'>		try_files $uri $uri/ /index.php;</div><div class='line' id='LC53'>	}</div><div class='line' id='LC54'><br/></div><div class='line' id='LC55'><br/></div><div class='line' id='LC56'>	## PHP FILES</div><div class='line' id='LC57'>	location ~ \.php$ {</div><div class='line' id='LC58'>		include fastcgi_params;</div><div class='line' id='LC59'><br/></div><div class='line' id='LC60'>		fastcgi_index index.php;</div><div class='line' id='LC61'>		fastcgi_pass 127.0.0.1:9000;</div><div class='line' id='LC62'>		fastcgi_split_path_info ^(.+\.php)(/.+)$;</div><div class='line' id='LC63'>	}</div><div class='line' id='LC64'><br/></div><div class='line' id='LC65'><br/></div><div class='line' id='LC66'>	## AUTH ADMIN</div><div class='line' id='LC67'>	location = /wp-login.php {</div><div class='line' id='LC68'>		#auth_basic            &quot;Restricted&quot;;</div><div class='line' id='LC69'>		#auth_basic_user_file  /etc/nginx/htpasswd;</div><div class='line' id='LC70'><br/></div><div class='line' id='LC71'>		include fastcgi_params;</div><div class='line' id='LC72'><br/></div><div class='line' id='LC73'>		fastcgi_index index.php;</div><div class='line' id='LC74'>		fastcgi_pass 127.0.0.1:9000;</div><div class='line' id='LC75'>		fastcgi_split_path_info ^(.+\.php)(/.+)$;</div><div class='line' id='LC76'>	}</div><div class='line' id='LC77'>}</div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1887141/41cf6b77fa3193b7c6347419b895540b312c9bce/helpdesk.wpseo.de" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1887141#file_helpdesk.wpseo.de" style="float:right;margin-right:10px;color:#666">helpdesk.wpseo.de</a>
            <a href="https://gist.github.com/1887141">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>
</p>
<p><strong>Erläuterungen</strong><br />
Die meisten Zeilen der Konfiguration kommen bekannt vor, da vorhin besprochen. Weiter geht&#8217;s mit dem Abschnitt <em>SECURITY</em>. An dieser Stelle werden unerlaubte Request-Methoden abgewehrt. Auch der Zugriff auf unsichtbare System- und WordPress-interne Dateien, welche möglicherweise die Nummer der eingesetzten Blogsoftware-Version verraten, wird sofort beendet. Unter <em>REWRITES</em> befindet sich eine Regel, die einen im Browser aufgerufenen Permalink im Format <em>/%post_id%/</em> auf <em>/?p=%post_id%</em> per 301 Redirect umleitet.</p>
<p>Der Bereich <em>RESSOURCES</em> vereint in sich die Behandlung aller Grafik-, CSS- und JavaScript-Ressourcen. Hier wird Nginx aufgefordert, korrekte Cache-Header zu senden. Die Gültigkeit des Caching beläuft sich auf 31 Tage.</p>
<p>In der gleichen Abfrage für Ressourcen sind sechs Zeilen Code auskommentiert &#8211; dabei handelt es sich um einen <a href="http://de.wikipedia.org/wiki/Hotlinking" target="_blank">Hotlinking</a>-Schutz. Sind die Zeilen nachträglich einkommentiert (wie? siehe oben), so unterbindet Nginx die Einbettung eigener Ressourcen auf fremden Webseiten. So schützt man sich gegen Diebstahl von Medien. Favicons sind von der Sperre ausgeschlossen. Die Liste mit Domains ist eine Whitelist &#8211; dort sind Domains eingetragen, wo die Einbindung erlaubt ist. Wichtig: Auch die eigene Domain gehört in die Auflistung mit rein (<em>wpseo.</em> = exemplarisch).</p>
<p><strong>Schutz des Administrationsbereichs</strong><br />
Aus Sicherheitsgründen wird es empfohlen, den Admin-Bereich mit einem zusätzlichen Zugang auszustatten. Genauer gesagt die Eingangstür dahin: die Datei <em>wp-login.php</em> (dazu passend: <a href="http://playground.ebiene.de/initiative-wordpress-sicherheit/">Mehr Sicherheit für WordPress durch den &#8220;Admin&#8221;-Schutz</a>). Für diesen Zweck sind folgende Schritte erforderlich:</p>
<ol>
<li>Z.B. unter <em>/etc/nginx/</em> eine neue Datei namens <em>htpasswd</em> anlegen (die Datei beinhaltet keine Punkte).</li>
<li>Der Dateiinhalt sind die Zugangsdaten des Nutzers. Das Format wäre <em>Nutzer:Passwort</em>. Diese können mit dem <a href="http://aspirine.org/htpasswd_en.html" target="_blank">Online-Generator</a> erzeugt werden. Wichtig: Unter <em>Algorithmus</em> bitte <em>Crypt</em> auswählen.</li>
<li>Passwortdatei speichern.</li>
<li>In der Server-Konfigurationsdatei die Zeilen mit <em>auth_basic</em> und <em>auth_basic_user_file</em> einkommentieren.</li>
<li>Nginx restarten.</li>
</ol>
<p><strong>Tipp zur Spam-Bekämpfung</strong><br />
Handelt es sich um eine CMS-Website, also um Inhalte mit abgestellten Kommentar- und XML-RPC-Funktionen, so würde es <a href="https://plus.google.com/110569673423509816572/posts/YQjrZaLqQjM" target="_blank">Sinn machen</a>, die Dateien <em>wp-comments-post.php</em> und <em>xmlrpc.php</em> auf die interne Blackliste zu setzen und jede Anfrage dahin mit dem Code 444 <a href="https://plus.google.com/110569673423509816572/posts/fVnoMDmHCrx" target="_blank">unverzüglich zu beenden</a>. Die betroffene Zeile aus dem Snippet oben müsste in diesem Fall wie folgt aussehen:</p>
<pre>
location ~ /(\.|wp-config.php|liesmich.html|readme.html|xmlrpc.php|wp-comments-post.php) {
  return 444;
}
</pre>
<div id="attachment_2898" class="wp-caption alignnone" style="width: 484px"><img src="http://playground.ebiene.de/wp-content/uploads/2012/02/twentyeleven-page-speed.png" alt="Twenty Eleven Page Speed" title="Twenty Eleven Page Speed" width="474" height="200" class="size-full wp-image-2898" /><p class="wp-caption-text">Nginx optimiert: 100 Page Speed Punkte beim Twentyeleven Theme</p></div>
<p><strong>Load Test</strong><br />
Die durchgeführten Optimierungen (samt <a href="http://playground.ebiene.de/cachify-wordpress-cache/">Cachify</a>) können sich sehen lassen: WordPress kann locker mit <a href="https://plus.google.com/110569673423509816572/posts/PAS8tpCWwGd" target="_blank">10 Millionen Hits pro Tag</a> umgehen.</p>
<p><strong>Outro</strong><br />
An dieser Stelle endet die Tutorial-Serie. Der WordPress-Blog läuft performant unter Nginx und PHP5-FPM. APC beschleunigt zusätzlich die Ausführung der Skripte. Durch die Erweiterung der Server-Konfigurationsdatei ist WordPress gegen böswillige Angriffe und unerwünschte Einbettungen der Medien geschützt. Ressourcen sind mit korrekten Caching-Mechanismen ausgestattet. Jetzt ist der Blogger mit hochwertigen Inhalten dran ;)</p>
<p><strong>Tutorials der Serie</strong></p>
<ul>
<li>Teil 1: <a href="http://playground.ebiene.de/nginx-php5-fpm/">Nginx + PHP5-FPM + APC + MySQL für WordPress installieren</a></li>
<li>Teil 2: <a href="http://playground.ebiene.de/nginx-mysql-config/">Nginx Webserver und MySQL für WordPress konfigurieren</a></li>
<li>Teil 3: <a href="http://playground.ebiene.de/nginx-wordpress-optimieren/">WordPress auf Nginx: Performance und Sicherheit optimieren</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://playground.ebiene.de/nginx-wordpress-optimieren/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Nginx Webserver und MySQL für WordPress konfigurieren</title>
		<link>http://playground.ebiene.de/nginx-mysql-config/</link>
		<comments>http://playground.ebiene.de/nginx-mysql-config/#comments</comments>
		<pubDate>Wed, 22 Feb 2012 09:20:15 +0000</pubDate>
		<dc:creator>Sergej</dc:creator>
				<category><![CDATA[Performance]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://playground.ebiene.de/?p=2893</guid>
		<description><![CDATA[Nginx, PHP5-FPM und MySQL sind dank der detaillierten Anleitung aus dem ersten Teil der Tutorial-Serie installiert und laufen einwandfrei. Was noch fehlt, ist die nicht ganz triviale Konfiguration des Webservers und die Einrichtung einer MySQL-Datenbank für den zukünftigen Blog auf WordPress-Basis. Wir beginnen mit dem letzten Task: Der Datenbank. Intro Exemplarisch wird die Einrichtung der [...]]]></description>
			<content:encoded><![CDATA[<p>Nginx, PHP5-FPM und MySQL sind dank der detaillierten <a href="http://playground.ebiene.de/nginx-php5-fpm/">Anleitung</a> aus dem ersten Teil der Tutorial-Serie installiert und laufen einwandfrei. Was noch fehlt, ist die nicht ganz triviale Konfiguration des Webservers und die Einrichtung einer MySQL-Datenbank für den zukünftigen Blog auf WordPress-Basis. Wir beginnen mit dem letzten Task: Der Datenbank.<br />
<span id="more-2893"></span><br />
<strong>Intro</strong><br />
Exemplarisch wird die Einrichtung der Services für die Subdomain <a href="http://helpdesk.wpseo.de" target="_blank">helpdesk.wpseo.de</a> gezeigt. Die im Tutorial aufgeführten Nutzer, Datenbanknamen und Subdomains sind entsprechend anzupassen.</p>
<p><strong>MySQL-Datenbank</strong><br />
Zunächst loggt sich der Administrator mit den Root-Zugangsdaten für MySQL ein (dafür erst per SSH auf dem Server anmelden):</p>
<pre>
mysql -uroot -p
</pre>
<p>Neue Datenbank kreieren:</p>
<pre>
CREATE DATABASE helpdesk;
</pre>
<p>Einen separaten Nutzer definieren:</p>
<pre>
CREATE USER 'helpdesk_user'@'localhost' IDENTIFIED BY 'MEIN-PASSWORT';
</pre>
<p>Alle MySQL-Tabellen der Datenbank an den neuen Nutzer binden:</p>
<pre>
GRANT ALL ON helpdesk.* TO helpdesk_user@localhost;
</pre>
<p>Mit <em>exit</em> auf der Konsole verlässt man MySQL.</p>
<p>Der MySQL-Zugang wird später in der WordPress-Konfigurationsdatei <em>wp-config.php</em> hinterlegt und baut sich wie folgt zusammen:</p>
<pre>
define('DB_NAME', 'helpdesk');
define('DB_USER', 'helpdesk_user');
define('DB_PASSWORD', 'MEIN-PASSWORT');
define('DB_HOST', 'localhost');
</pre>
<p>Soweit steht die Datenbank und kann ab sofort mit Inhalten gefüllt werden.</p>
<p><strong>Nginx Konfiguration</strong></p>
<p>Die nächsten Schritte beschreiben eine minimale, grundliegende Justierung des Nginx-Webservers für einen WordPress-Blog. In einem der kommenden Tutorials der Serie wird eine erweiterte Kalibrierung vorgestellt, die auf Performance und Sicherheit ausgelegt ist.</p>
<p>Als Erstes legt man das Root-Verzeichnis für die WordPress-Instanz an:</p>
<pre>
mkdir -p /var/www/helpdesk.wpseo.de
chown -R www-data:www-data /var/www
</pre>
<p>Der Verzeichnisname gehört selbstverständlich angepasst: Ordner = Domain ist eine gute Regel für mehr Übersicht auf der Serverebene. Alternativ würde auch der Projektname genügen. An diesen Speicherort (also unter <em>/var/www/helpdesk.wpseo.de</em>) können WordPress-Dateien via SFTP übertragen werden.</p>
<p>Jeder Blog bzw. jede (Sub)Domain bekommt nicht nur ein eigenes Document-Root, sondern auch eine eigene Nginx-Konfigurationsdatei. Ist keine Pflicht, doch die Trennung nach Projekten erlaubt eine maximale Flexibilität bei abweichenden Einstellungen. Aus diesem Grund erstellt der Administrator unter <em>/etc/nginx/sites-available/</em> eine für das Projekt zuständige Datei mit notwendigen Webserver-Regeln. In unserem Fall trägt die Datei den Namen <em>helpdesk.wpseo.de</em></p>
<div id="attachment_2894" class="wp-caption alignnone" style="width: 484px"><img src="http://playground.ebiene.de/wp-content/uploads/2012/02/nginx-sites-available.png" alt="Nginx sites available" title="Nginx sites available" width="474" height="200" class="size-full wp-image-2894" /><p class="wp-caption-text">Verfügbare Nginx-Konfigurationsdatei im Ordner sites-available</p></div>
<p>Innerhalb der Konfigurationsdatei werden alle Einstellungen, Weiterleitungen und andere Steuerungsmechanismen notiert. Auch kleinere Anpassungen rund um den Webserver finden dort ihr Zuhause, da Nginx keine &#8211; doch so schnell erreichbare und bequeme &#8211; Datei <em>.htaccess</em> unterstützt. Im Klartext: Aus der SEO-Sicht notwendige Redirects müssen ebenfalls dort behandelt werden.</p>
<p>Das wäre der simple Inhalt der Datei zum Copy&#038;Paste:</p>
<pre>
server {
  listen 80 default_server;
  server_name helpdesk.wpseo.de;

  root /var/www/helpdesk.wpseo.de;
  index index.php;

  location / {
    try_files $uri $uri/ /index.php;
  }

  location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    include fastcgi_params;
  }
}
</pre>
<p><strong>Erläuterung</strong><br />
Keine Hexerei: Sieht nach wenig aus, ist es auch.</p>
<ul>
<li><em>default_server</em>: Der virtuelle Server wird als Standard-Server festgelegt und kann im Browser direkt über die IP erreicht werden (bei einer DNS-Weiterleitung dann auch über die Domain).</li>
<li><em>server_name</em>: Als Servername ist die zukünftige (Sub)Domain definiert (erst bei DNS-Weiterleitungen relevant, kann auch <em>localhost</em> sein).</li>
<li><em>root</em>: Das im vorherigen Schritt zugewiesene Root-Verzeichnis der Website.</li>
</ul>
<p>Speichern. Per Terminal als &#8220;erreichbar&#8221; markieren:</p>
<pre>
ln -s /etc/nginx/sites-available/helpdesk.wpseo.de /etc/nginx/sites-enabled/
</pre>
<p>Nginx neu starten:</p>
<pre>
/etc/init.d/nginx restart
</pre>
<p>Falls noch nicht geschehen, WordPress-Files ins Stammverzeichnis per SFTP übertragen und <em>wp-config.php</em> mit Anmeldedaten der MySQL-Datenbank versehen.</p>
<p>Beim Aufruf der Server-IP im Browser erscheint der WordPress-Installationsassistent. Das deutet auf einen fehlerfreien Betrieb des Webservers in Zusammenspiel mit WordPress hin. </p>
<p><strong>Outro</strong><br />
Der WordPress-Blog steht ebenfalls, ist erreichbar und kann wie sonst üblich eingerichtet werden. Ein Tipp am Rande: Für <a href="https://plus.google.com/110569673423509816572/posts/BCtpJB2KwuV" target="_blank">SEO-freundliche Permalinks</a> empfiehlt sich das dafür programmierte <a href="https://gist.github.com/1615422" target="_blank">Toolbox-Modul</a> &#8211; nach der Aktivierung können Permalinks in den WordPress-Einstellungen im Format <em>/%postname%/</em> ausgewählt und genutzt werden.</p>
<div id="attachment_2895" class="wp-caption alignnone" style="width: 484px"><img src="http://playground.ebiene.de/wp-content/uploads/2012/02/nginx-toolbox-modul.png" alt="Nginx Toolbox-Modul" title="Nginx Toolbox-Modul" width="474" height="200" class="size-full wp-image-2895" /><p class="wp-caption-text">Toolbox-Modul speziell für Nginx-Webserver</p></div>
<p><strong>Hinweise</strong></p>
<ul>
<li>Befinden sich WordPress-Dateien in einem Unterordner (z.B. <em>wordpress</em>), müsste die Nginx-Konfiguration nachträglich <a href="http://wiki.nginx.org/WordPress#Non-root_try_files_to_URL_redirect" target="_blank">angepasst</a> werden.</li>
<li>Plugins, die für ihre korrekte Funktionsweise die Datei <em>.htaccess</em> beansprucht hatten, dürfen unter Nginx nicht länger zum Einsatz kommen und gehören abgestimmt oder abgestellt.</li>
</ul>
<p><strong>Tutorials der Serie</strong></p>
<ul>
<li>Teil 1: <a href="http://playground.ebiene.de/nginx-php5-fpm/">Nginx + PHP5-FPM + APC + MySQL für WordPress installieren</a></li>
<li>Teil 2: <a href="http://playground.ebiene.de/nginx-mysql-config/">Nginx Webserver und MySQL für WordPress konfigurieren</a></li>
<li>Teil 3: <a href="http://playground.ebiene.de/nginx-wordpress-optimieren/">WordPress auf Nginx: Performance und Sicherheit optimieren</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://playground.ebiene.de/nginx-mysql-config/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Nginx + PHP5-FPM + APC + MySQL für WordPress installieren</title>
		<link>http://playground.ebiene.de/nginx-php5-fpm/</link>
		<comments>http://playground.ebiene.de/nginx-php5-fpm/#comments</comments>
		<pubDate>Tue, 21 Feb 2012 09:07:40 +0000</pubDate>
		<dc:creator>Sergej</dc:creator>
				<category><![CDATA[Performance]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://playground.ebiene.de/?p=2888</guid>
		<description><![CDATA[Nginx ist die leistungsfähigere Alternative zum weltweit berühmten Webserver Apache. Nginx wurde auf Performance, Erreichbarkeit und Stabilität eines Servers optimiert, sodass die Software auf Websites mit extrem hoher Last (wie z.B. wordpress.com) zum Einsatz kommt. Dieser Artikel ist der erste Teil einer Tutorial-Serie, die beschreibt, wie Nginx installiert, eingerichtet und genutzt wird. Mit WordPress als [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://wiki.nginx.org/NginxDe" target="_blank">Nginx</a> ist die leistungsfähigere Alternative zum weltweit berühmten Webserver Apache. Nginx wurde auf Performance, Erreichbarkeit und Stabilität eines Servers optimiert, sodass die Software auf Websites mit extrem hoher Last (wie z.B. wordpress.com) zum Einsatz kommt. Dieser Artikel ist der erste Teil einer Tutorial-Serie, die beschreibt, wie Nginx installiert, eingerichtet und genutzt wird. Mit WordPress als Schwerpunkt.<br />
<span id="more-2888"></span><br />
<strong>Voraussetzungen</strong><br />
Für die Inbetriebnahme von Nginx wird ein Hoster benötigt, der solche Installationen auf seinen Maschinen erlaubt und Kunden mit root-Zugängen ausstattet. <a href="https://www.jiffybox.de" target="_blank">JiffyBox</a> wäre ein preiswerter Kandidat. Die Anleitung geht von einer Serverumgebung laufend unter <em>Debian squeeze 64 Bit</em> aus.</p>
<p><strong>Installation</strong><br />
Nach einem erfolgreichen SSH-Login via Konsole aktualisieren folgende Befehle die interne Liste mit Download-Quellen auf dem Server.</p>
<pre>
echo &quot;deb http://packages.dotdeb.org squeeze all&quot; &gt; /etc/apt/sources.list.d/squeeze-dotdeb.list
gpg --keyserver keys.gnupg.net --recv-key 89DF5277
gpg -a --export 89DF5277 | apt-key add -
aptitude update
</pre>
<p>Im Anschluss startet die eigentliche Installation der Komponenten: Nginx Webserver, PHP5-FPM samt Module, MySQL-Server.</p>
<pre>
aptitude install nginx
aptitude install php5-fpm php5-mysql php5-gd php5-curl php5-apc
aptitude install mysql-server
</pre>
<p><strong>Anmerkungen</strong></p>
<ol>
<li>Während der Installation des MySQL-Servers erscheint plötzlich eine in Blau hinterlegte Abfrage für das MySQL-Passwort des root-Nutzers. Bitte dran denken, die Eingabe aufzubewahren.</li>
<li>PHP-Module können jederzeit nachinstalliert werden, falls sich Anforderungen im Laufe des Blog-Betriebs ändern sollten. Das installierte Zusatzmodul <a href="http://de.wikipedia.org/wiki/Alternative_PHP_Cache" target="_blank">APC</a> (php5-apc) beschleunigt zusätzlich die Ausführung der PHP-Skripte, da diese im schnelleren Shared-Memory der Server-Instanz abgelegt werden. Das WordPress Caching-Plugin <a href="http://playground.ebiene.de/cachify-wordpress-cache/">Cachify</a> setzt ebenfalls auf APC.</li>
</ol>
<div id="attachment_2892" class="wp-caption alignnone" style="width: 484px"><img src="http://playground.ebiene.de/wp-content/uploads/2012/02/nginx-mysql-password.png" alt="Nginx MySQL-Password" title="Nginx MySQL-Password" width="474" height="200" class="size-full wp-image-2892" /><p class="wp-caption-text">Passwort-Abfrage für den MySQL-Server</p></div>
<p><strong>Start</strong><br />
Nach einer erfolgreichen Installation können die einzelnen Dienste gestartet (und später mit gleichen Befehlen rebootet) werden:</p>
<pre>
/etc/init.d/mysql restart
/etc/init.d/php5-fpm restart
/etc/init.d/nginx restart
</pre>
<p>Ab diesem Zeitpunkt ist Nginx als Webserver in Betrieb und liefert statische Inhalte an Clients aus. Das sollte der Aufruf der Server-IP in der Adressleiste des Browsers bestätigen: <strong>Welcome to nginx!</strong></p>
<p><strong>PHP-Aktivierung</strong><br />
Nginx ist von Haus aus tatsächlich so konfiguriert, dass ausschliesslich statische Dateien (HTML, Bilder, etc.) verarbeitetet und zurückgegeben werden. PHP ist zwar jetzt auf dem Server installiert und gestartet, doch das muss Nginx erst kommuniziert werden. Zur Veranschaulichung reicht vorerst das simple Einkommentieren der bereits vorbereiteten Zeilen in der Nginx-Konfigurationsdatei. Diese Default-Datei befindet sich unter <em>/etc/nginx/sites-available/</em>, kann via <a href="http://playground.ebiene.de/transmit-4-testbericht/">Transmit</a> erreicht und im Editor geöffnet werden. Dort nachfolgende Zeilen finden und Sternchen vor den Befehlen entfernen.</p>
<pre>
location ~ \.php$ {
  fastcgi_split_path_info ^(.+\.php)(/.+)$;
  fastcgi_pass 127.0.0.1:9000;
  fastcgi_index index.php;
  include fastcgi_params;
}
</pre>
<p>Ein Neustart quittiert jede Änderung der Konfiguration:</p>
<pre>
/etc/init.d/nginx restart
</pre>
<div id="attachment_2891" class="wp-caption alignnone" style="width: 484px"><img src="http://playground.ebiene.de/wp-content/uploads/2012/02/nginx-default-site.png" alt="Nginx Default-Site" title="Nginx Default-Site" width="474" height="200" class="size-full wp-image-2891" /><p class="wp-caption-text">Standardeinstellungen des Nginx-Webservers in der Datei &quot;default&quot;</p></div>
<p>Ab sofort interpretiert Nginx jede Datei mit der Endung <em>.php</em> als ein PHP-File und startet entsprechend den PHP-Interpreter. Zum Ausprobieren der korrekten Funktionsweise kann eine Datei namens <em>phpinfo.php</em> mit nachfolgendem Inhalt unter <em>/usr/share/nginx/www</em> erstellt, abgelegt und im Browser via <em>http://meine.ip/phpinfo.php</em> aufgerufen werden:</p>
<pre>
&lt;?php phpinfo() ?&gt;
</pre>
<p><strong>Outro</strong><br />
Erscheint die erwartete Übersicht an PHP-Informationen, hat alles wunderbar funktioniert. Nginx und PHP5-FPM arbeiten perfekt.</p>
<p><strong>Tutorials der Serie</strong></p>
<ul>
<li>Teil 1: <a href="http://playground.ebiene.de/nginx-php5-fpm/">Nginx + PHP5-FPM + APC + MySQL für WordPress installieren</a></li>
<li>Teil 2: <a href="http://playground.ebiene.de/nginx-mysql-config/">Nginx Webserver und MySQL für WordPress konfigurieren</a></li>
<li>Teil 3: <a href="http://playground.ebiene.de/nginx-wordpress-optimieren/">WordPress auf Nginx: Performance und Sicherheit optimieren</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://playground.ebiene.de/nginx-php5-fpm/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hosting: Website mit statischen Seiten auf Amazon S3</title>
		<link>http://playground.ebiene.de/amazon-s3-website/</link>
		<comments>http://playground.ebiene.de/amazon-s3-website/#comments</comments>
		<pubDate>Thu, 02 Feb 2012 09:06:22 +0000</pubDate>
		<dc:creator>Sergej</dc:creator>
				<category><![CDATA[Amazon]]></category>

		<guid isPermaLink="false">http://playground.ebiene.de/?p=2885</guid>
		<description><![CDATA[Heutzutage wird Vieles in die digitale Wolke verlagert: Dokumente, Musik, Bilder. Beim Hosting von Webinhalten ist es nicht anders. Dieser Tutorial veranschaulicht, wie eine Website mit unbegrenzt vielen Unterseiten (ohne serverseitiger Dynamik) auf Amazon S3 gepusht und von dort aus im Web erreichbar ist. Bei Bedarf unter eigener Domain. Jederzeit performant, zuverlässig und kostenüberschaubar. Für [...]]]></description>
			<content:encoded><![CDATA[<p>Heutzutage wird Vieles in die digitale Wolke verlagert: Dokumente, Musik, Bilder. Beim Hosting von Webinhalten ist es nicht anders. Dieser Tutorial veranschaulicht, wie eine Website mit unbegrenzt vielen Unterseiten (ohne serverseitiger Dynamik) auf Amazon S3 gepusht und von dort aus im Web erreichbar ist. Bei Bedarf unter eigener Domain. Jederzeit performant, zuverlässig und kostenüberschaubar. Für jedes Vorhaben geeignet.<br />
<span id="more-2885"></span><br />
<strong>Intro</strong><br />
Im Beitrag <a href="http://playground.ebiene.de/amazon-s3/">Dateien auf Amazon S3 unter eigener Subdomain hosten</a> wurde sehr ausführlich skizziert, wie Buckets angelegt und Inhalte auf den Server übertragen, richtig eingestellt und mit korrekten Caching-Informationen versehen werden. Ab dieser Position wird fortgesetzt.</p>
<p><strong>1. Bucket als Website definieren</strong><br />
Durch den Klick auf das betroffene Bucket in der linken Spalte öffnet sich rechts die entsprechende Datenstruktur. Die Schaltfläche <em>Properties</em> verbirgt im unteren Fensterbereich weitere Registerkarten mit zusätzlichen Eigenschaften des gewählten Bucket. Relevant an dieser Stelle ist der Tab <em>Website</em> mit seinen Einstellungen für den Betrieb einer Website auf Amazon S3.</p>
<p>Der Tab <em>Website</em> glänzt nicht wirklich durch eine Vielfalt an möglichen Optionen. Umso einfacher und verständlicher ist die Einschaltung der Möglichkeit, statische Webseiten auf Amazon S3 zu hosten. Checkbox aktivieren und als Index-Dokument <em>index.html</em> eintragen (weicht der Dateiname ab, so ist dieser anzupassen). Speichern. In der gleichen Ansicht präsentiert Amazon S3 die Zieladresse der aktuellen Website &#8211; unter der kryptischen URL ist die Startseite des Projekts aufzurufen.</p>
<p>Wichtig zu beachten: Amazon S3 gibt lediglich statische HTML-Dateien an den Browser aus. Webseiten mit angeblich dynamischen Inhalten (auf Basis von PHP, ASP, etc.) werden nicht geparst (da der Interpretor fehlt) und stets mit dem Original-Quelltext ausgegeben.</p>
<div id="attachment_2886" class="wp-caption alignnone" style="width: 484px"><img src="http://playground.ebiene.de/wp-content/uploads/2012/01/amazon-s3-website.png" alt="Amazon S3 Website" title="Amazon S3 Website" width="474" height="200" class="size-full wp-image-2886" /><p class="wp-caption-text">Einstellungen für das Hosting einer Website auf Amazon S3</p></div>
<p><strong>2. Bucket einer Domain zuweisen</strong><br />
Erlaubt der Hoster bzw. Domain-Verwalter eine DNS-Umleitung der Domain, so kann die gewünschte, deutlich kürzere (Sub)Domain auf die genannte URL des Amazon S3-Buckets (Endpoint) &#8220;gezeigt&#8221; werden. Beispiel: Für das Bucket <a href="http://xmas.wpseo.de" target="_blank">xmas.wpseo.de</a> lautet die CNAME-Zieladresse wie folgt (Punkt am Ende wichtig):</p>
<pre>
xmas.wpseo.de.s3-website-eu-west-1.amazonaws.com.
</pre>
<p>Der Artikel <a href="http://playground.ebiene.de/amazon-cloudfront/">Amazon CloudFront mit Amazon S3 verknüpfen</a> beschreibt den sinnvollen Weg, Amazon CloudFront als eine mögliche CDN-Lösung zu nutzen.</p>
<p><strong>Outro</strong><br />
Der wesentliche Vorteil des Hosting einer (statischen) Website auf Amazon S3 ist sicherlich die tadellose Verfügbarkeit der Seiten &#8211; auch bei Last (ja, auch statische Ressourcen können unter Last stehen bzw. Last bekommen). In ersten 12 Monaten sogar kostenlos (5 GB Speicher und andere <a href="http://aws.amazon.com/de/free/" target="_blank">Begrenzungen</a> beachten).</p>
]]></content:encoded>
			<wfw:commentRss>http://playground.ebiene.de/amazon-s3-website/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google SERPs: Produktseiten durch Bewertungen hervorheben</title>
		<link>http://playground.ebiene.de/google-produkt-snippet/</link>
		<comments>http://playground.ebiene.de/google-produkt-snippet/#comments</comments>
		<pubDate>Tue, 17 Jan 2012 09:23:24 +0000</pubDate>
		<dc:creator>Sergej</dc:creator>
				<category><![CDATA[E-Commerce]]></category>
		<category><![CDATA[Google]]></category>

		<guid isPermaLink="false">http://playground.ebiene.de/?p=2877</guid>
		<description><![CDATA[Aus der Sicht der SEO-Optimierung reicht es bei weitem nicht mehr aus, mit einer Webseite in den Google-Suchergebnissen vertreten zu sein. Ein ungeplantes Dasein ist kein Garant für Besucherströme. Heutzutage kommt es sehr stark auf den Informationsgehalt des Google Rich Snippets an: Der Nutzer will noch vor dem Klick wissen, ob das Ergebnis zum gesuchten [...]]]></description>
			<content:encoded><![CDATA[<p>Aus der Sicht der SEO-Optimierung reicht es bei weitem nicht mehr aus, mit einer Webseite in den Google-Suchergebnissen vertreten zu sein. Ein ungeplantes Dasein ist kein Garant für Besucherströme. Heutzutage kommt es sehr stark auf den Informationsgehalt des <a href="http://support.google.com/webmasters/bin/answer.py?answer=99170" target="_blank">Google Rich Snippets</a> an: Der Nutzer will noch vor dem Klick wissen, ob das Ergebnis zum gesuchten Treffer wird. Daher beinhaltet die moderne Suchmaschinenoptimierung auch das Befüllen der Snippets mit relevanten, Konversion-optimierten Daten. Dazu zählen u.a. eine Klick-attraktive Description und ein passender Seitentitel. Zusätzlich zu einer <a href="http://schema.org/WebPage" target="_blank">Breadcrumb</a>-Navigation können Snippets für Produktseiten um Bewertungen und Preisinformationen erweitert werden. Für mehr Blickfang.<br />
<span id="more-2877"></span><br />
<div id="attachment_2880" class="wp-caption alignnone" style="width: 484px"><img src="http://playground.ebiene.de/wp-content/uploads/2012/01/google-wpseo-plugin.png" alt="wpSEO bei Google" title="wpSEO bei Google" width="474" height="200" class="size-full wp-image-2880" /><p class="wp-caption-text">wpSEO bei Google mit einem Produkt-Snippet</p></div></p>
<p>Der Artikel beschreibt im Groben die Methode, eine Produktseite im HTML-Code mit den von Google und Yahoo festgelegten <a href="http://schema.org" target="_blank">schema.org</a>-Markierungen auszustatten und damit für das Produkt-Snippet innerhalb der Google-Suchergebnisse vorzubereiten. Wie im Screenshot abgebildet, konzentriert man sich hier ausschließlich auf Kundenbewertungen und Preisangaben. Google stellt dagegen deutlich mehr <a href="http://schema.org/Product" target="_blank">Merkmale</a> für Hervorhebungen von Produkteigenschaften (dazu zählen u.a. Marke, Bild, Verfügbarkeit) zur Verfügung. </p>
<p>Je nach Webseite indexiert Google die eingeführten Kennzeichnungen innerhalb eines Werktages. Als Beispiel für den nachfolgenden Code liegt die für wpSEO, das <a href="http://wpseo.de/" target="_blank">WordPress SEO Plugin</a> vorgenommene Umsetzung zugrunde.</p>
<p><strong>1. Deklarierung als Produkt</strong><br />
Zunächst sollte Google davon in Kenntnis gesetzt werden, dass es sich beim Seitenaufruf um eine <em>Produkt</em>seite handelt. Das geschieht wahlweise im betroffenen DIV-Container oder direkt beim Einstieg in den Quelltext im &lt;html&gt;-Tag. Die Injektion ins HTML-Tag ist dann vorzuziehen, wenn Produkteigenschaften teilweise in die Metatags als <a href="http://html5doctor.com/microdata/" target="_blank">Microdata</a> ausgelagert sind. Dazu zählt beispielsweise ein abweichendes Vorschaubild, welches ein Produkt repräsentiert, auf der Detailseite zwecks notwendiger Markierung jedoch nicht vorkommt.</p>
<p>Anbei die beiden Varianten:</p>
<pre>
&lt;div itemscope itemtype=&quot;http://schema.org/Product&quot;&gt;
</pre>
<pre>
&lt;html itemscope itemtype=&quot;http://schema.org/Product&quot;&gt;
</pre>
<p><strong>2. Auszeichnung der Kundenbewertungen</strong><br />
Idealerweise verfügt jedes Produkt im Shop über Bewertungen. Bestenfalls über eine ausreichende Anzahl an Bewertungen. Diese werden letztendlich im Google Produkt-Snippet abgebildet. Wichtig zu beachten ist die ernstgemeinte Regel, dort keine Shop-Bewertungen, vielmehr Produkt-abweichende Stimmen und Meinungen zu integrieren. Der Code-Auszug ist exemplarisch, dürfte allerdings in jedem E-Commerce- und Templating-System ähnlich aufgebaut sein.</p>
<pre>
&lt;p itemprop=&quot;aggregateRating&quot; itemscope itemtype=&quot;http://schema.org/AggregateRating&quot;>
  &lt;em itemprop=&quot;ratingValue&quot;>4.99&lt;/em> Sterne bei
  &lt;em itemprop=&quot;reviewCount&quot;>804&lt;/em> Bewertungen.
&lt;/p>
</pre>
<p>Die Daten sind vom System dynamisch gefüllt. Aus den beiden Kennzahlen generiert Google eine entsprechende Ausgabe im Produkt-Snippet. Die Eigenschaften im Einzelnen:</p>
<ul>
<li><em>ratingValue</em> steht für die aktuelle Durchschnittsmenge an Bewertungssternen. Per Default geht Google von einer Obergrenze mit 5 Sternen aus, dies kann ebenfalls <a href="http://schema.org/AggregateRating" target="_blank">nachjustiert</a> werden.</li>
<li><em>reviewCount</em> signalisiert die Gesamtzahl an Bewertungen, die lieber nicht manipuliert werden sollte.</li>
</ul>
<p>Tipp am Rande: Findet die Ausgabe der vergebenen Sterne auf der Produktseite als schicke Grafik statt, kann auf Textmarkierungen via &lt;em> und &lt;span> verzichtet werden und auf der Meta-Ebene erfolgen. Der obige Code würde entsprechend wie folgt aussehen:</p>
<pre>
&lt;p itemprop=&quot;aggregateRating&quot; itemscope itemtype=&quot;http://schema.org/AggregateRating&quot;>
  &lt;meta itemprop=&quot;ratingValue&quot; content=&quot;4.99&quot; />
  &lt;meta itemprop=&quot;reviewCount&quot; content=&quot;804&quot; />
&lt;/p>
</pre>
<p>Auch sieht Google es vor, Kundenmeinungen im Shop als einzelne <a href="http://schema.org/Review" target="_blank">Reviews</a> markieren zu können.</p>
<p><strong>3. Preisangaben zum Produkt</strong><br />
Dito beim Produktpreis: Hat ein Produkt einen festen Verkaufspreis, so wird dieser mit wenig Code an Suchmaschinen kommuniziert:</p>
<pre>
&lt;p itemprop=&quot;offers&quot; itemscope itemtype=&quot;http://schema.org/Offer&quot;>
  &lt;em itemprop=&quot;price&quot;>€ 19.99&lt;/em>
&lt;/p>
</pre>
<p>Variiert der VK dagegen je nach Größe, Farbe, Art, Händler oder Menge, können hierfür zusammengehörige Kommunikationsglieder eingefügt werden. In Einfach: Den kleinsten und den höchsten Preis zeichnet der Entwickler im Produkttext oder analog zu Bewertungen als Metatags aus.</p>
<pre>
&lt;p itemprop=&quot;offers&quot; itemscope itemtype=&quot;http://schema.org/AggregateOffer&quot;>
  &lt;em itemprop=&quot;lowPrice&quot;>€ 19,99&lt;/em> bis &lt;em itemprop=&quot;highPrice&quot;>€ 99,99&lt;/em>
&lt;/p>
</pre>
<p><strong>Fazit</strong><br />
Noch ist die Zahl der Shop-Betreiber, die auf Auszeichnungen der Artikeleigenschaften im Quelletxt setzen, sehr gering. Das sollte als Chance genutzt werden, um in den SERPs aufzufallen. Und zugleich einen Mehrwert durch (Mehr)Information bieten. SEO mit Köpfchen.</p>
<p><a href="http://www.google.com/webmasters/tools/richsnippets" target="_blank">Rich Snippets Testung Tool</a> steht wie immer helfend zur Seite.</p>
]]></content:encoded>
			<wfw:commentRss>http://playground.ebiene.de/google-produkt-snippet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>+Snippet: WordPress-Artikel für Google+ aufbereiten</title>
		<link>http://playground.ebiene.de/wordpress-google-plus/</link>
		<comments>http://playground.ebiene.de/wordpress-google-plus/#comments</comments>
		<pubDate>Thu, 12 Jan 2012 09:01:24 +0000</pubDate>
		<dc:creator>Sergej</dc:creator>
				<category><![CDATA[Google]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://playground.ebiene.de/?p=2870</guid>
		<description><![CDATA[Die Google-Suche wird sozialer. Google+ wird dabei intensiver als Quelle für personalisierte Suchergebnisse herangezogen. Für Blogger ein wichtiger Grund, Blog-Artikel mit der Sozial-Plattform der Suchmaschine stärker, nahtloser zu verknüpfen und zusätzlich für ein reges Teilen redaktioneller Nachrichten zu sorgen. Dabei spielen Metadaten einer Google+ Mitteilung (Titel, Kurzbeschreibung, Bild &#8211; auch +Snippet genannt) eine nicht unwichtige [...]]]></description>
			<content:encoded><![CDATA[<p>Die Google-Suche <a href="http://t3n.de/news/google-lasst-suche-google-357328/" target="_blank">wird sozialer</a>. Google+ wird dabei intensiver als Quelle für personalisierte Suchergebnisse herangezogen. Für Blogger ein wichtiger Grund, Blog-Artikel mit der Sozial-Plattform der Suchmaschine stärker, nahtloser zu verknüpfen und zusätzlich für ein reges Teilen redaktioneller Nachrichten zu sorgen. Dabei spielen Metadaten einer Google+ Mitteilung (Titel, Kurzbeschreibung, Bild &#8211; auch <em>+Snippet</em> genannt) eine nicht unwichtige Rolle, den genau diese Information trägt der Entscheidung bei, ob eine Mitteilung weitergereicht wird. Wie ein WordPress-Post richtig formatiert gehört, um in eine makellose aussehende und von der Länge passende Google+ Mitteilung verwandelt zu werden, zeigt dieser Artikel.<br />
<span id="more-2870"></span><br />
<img src="http://playground.ebiene.de/wp-content/uploads/2012/01/google-plus-anfrage.png" alt="Google+ Anfrage" title="Google+ Anfrage" width="474" height="200" class="alignnone size-full wp-image-2873" /><br />
<em>Auf eine URL-Eingabe folgt eine Anfrage an die Webseite</em></p>
<p><strong>Hervorhebungen im Quelltext</strong><br />
Beim Eintragen einer Webadresse in das dafür vorgesehene Feld (alternativ bei direkter Eingabe im Mitteilungstext) sendet Google+ unverzüglich eine Anfrage an die hinterlassene Webseite. Dabei versucht Google Metainformationen für das +Snippet zu extrahieren. Dazu gehören: Ein Titel, eine Kurzbeschreibung und ein Vorschaubild.</p>
<p>Damit notwendige Daten schnell und zuverlässig erkannt und als Snippet verfügbar sind, <a href="http://www.google.com/webmasters/+1/button/#customize-snippet" target="_blank">empfiehlt Google</a> eine Auszeichnung der einzelnen Werte direkt im Quelltext der Webseiten. Hierfür stehen zwei Möglichkeiten parat:</p>
<ul>
<li>Im <em>&lt;head&gt;</em> einer Blogseite als Metatag. Betroffen ist das WordPress-Template <em>header.php</em></li>
<li>Im <em>&lt;body&gt;</em> bzw. <a href="http://schema.org/Article" target="_blank">direkt</a> bei der Ausgabe des Artikelinhalts im WordPress-Loop. Betroffen ist <em>single.php</em></li>
</ul>
<p>Die zweite Methode ist klar zu bevorzugen, da die Auszeichnungen im Template nur platziert, jedoch nicht befüllt werden müssen. Zu beachten ist ebenfalls die Obergrenze von 200 Zeichen für eine Kurzbeschreibung, da Google diese im Snippet sonst kürzt.</p>
<p><strong>SEO-Metadaten als Referenz</strong><br />
<a href="http://wpseo.de/" target="_blank">WordPress SEO Plugin</a> Nutzer können sich die Mühe mit der Platzierung der Markierungen im Code sparen, denn Google wertet auch die Standard-Metadaten wie den Seitentitel (<em>title</em>-Tag) und die Seitenbeschreibung (Meta-Tag <em>description</em>) einer Blogseite aus. Die beiden Werte generiert das Plugin eh für Suchmaschinen, Google+ bedient sich lediglich an der Quelle.</p>
<p>Die empfohlene Länge der manuellen Metabeschreibungen im SEO-Plugin von 140 Zeichen zeigt hier ihre wahre Stärke: die von Google übernommene Kurzbeschreibung passt ausgezeichnet ins Snippet-Design. Dazu ein Screenshot:</p>
<p><img src="http://playground.ebiene.de/wp-content/uploads/2012/01/google-plus-snippet.png" alt="Google+ Snippet" title="Google+ Snippet" width="474" height="200" class="alignnone size-full wp-image-2872" /><br />
<em>Perfekt abgestimmter Google+ Snippet für ein Blogpost</em></p>
<p><strong>Thumbnail im Snippet</strong><br />
Für eine vollendete Optik eines gelungenen Google+ Snippet fehlt eine Bildvorschau für den verknüpften Blog-Artikel. Auch für diesen Zweck hält Google eine <a href="http://www.google.com/webmasters/+1/button/#customize-snippet" target="_blank">entsprechende</a> Auszeichnung nach dem gleichen Muster parat: Als Meta oder im Loop können Bilder im Artikel zur Nutzung im Snippet gekennzeichnet werden.</p>
<p>Für Vorschaubilder im Snippet benötigt Google+ ausschliesslich Bilder mit einer Mindesthöhe von 120 Pixel. Ist das festgelegte Artikelbild kleiner, wird es nicht verwendet und Google+ sucht sich eine passendere Grafik innerhalb der Webseite raus. Ist das Bild dagegen zu groß, skaliert Google automatisch auf die vorgegebene Höhe.</p>
<p>Wer Theme-interne Templates nicht anfassen mag oder kann, nutzt einfach das nachfolgende <a href="http://playground.ebiene.de/toolbox-wordpress-plugin/">Toolbox</a>-Modul, welches Artikelbilder im <a href="http://ogp.me/" target="_blank">Open Graph Protocol</a> als Metatag <em>og:image</em> ausgibt und Google+ (bei richtigen <em>html</em>-<a href="http://developers.facebook.com/docs/opengraph/" target="_blank">Attributen</a> auch für Facebook) somit ein brauchbares Vorschaubild zur Verfügung stellt. Bitte Hinweise am Seitenende beachten.</p>
<p><strong>Toolbox-Modul für Artikelbilder als Metatag</strong><br />
<div id="gist-1596767" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="cp">&lt;?php</span></div><div class='line' id='LC2'><span class="cm">/*</span></div><div class='line' id='LC3'><span class="cm">Module Name: Ausgabe der Artikelbilder als Metatag</span></div><div class='line' id='LC4'><span class="cm">Module URI: http://playground.ebiene.de/wordpress-google-plus/</span></div><div class='line' id='LC5'><span class="cm">Description: Fügt dem Head-Bereich ein og:image-Metatag mit aktuellem Artikelbild zu. [Frontend]</span></div><div class='line' id='LC6'><span class="cm">Author: Sergej Müller</span></div><div class='line' id='LC7'><span class="cm">Author URI: http://ebiene.de</span></div><div class='line' id='LC8'><span class="cm">*/</span></div><div class='line' id='LC9'><br/></div><div class='line' id='LC10'><br/></div><div class='line' id='LC11'><span class="cm">/* Sicherheitsabfrage */</span></div><div class='line' id='LC12'><span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="nb">class_exists</span><span class="p">(</span><span class="s1">&#39;Toolbox&#39;</span><span class="p">)</span> <span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC13'>	<span class="k">die</span><span class="p">();</span></div><div class='line' id='LC14'><span class="p">}</span></div><div class='line' id='LC15'><br/></div><div class='line' id='LC16'><br/></div><div class='line' id='LC17'><span class="cm">/* Ab hier kann&#39;s los gehen */</span></div><div class='line' id='LC18'><span class="k">function</span> <span class="nf">sm_meta_thumb</span><span class="p">()</span> <span class="p">{</span></div><div class='line' id='LC19'>	<span class="cm">/* Nur mit ID */</span></div><div class='line' id='LC20'>	<span class="k">if</span> <span class="p">(</span> <span class="k">empty</span><span class="p">(</span><span class="nv">$GLOBALS</span><span class="p">[</span><span class="s1">&#39;post&#39;</span><span class="p">])</span> <span class="k">or</span> <span class="o">!</span><span class="nb">is_object</span><span class="p">(</span><span class="nv">$GLOBALS</span><span class="p">[</span><span class="s1">&#39;post&#39;</span><span class="p">])</span> <span class="k">or</span> <span class="p">(</span><span class="o">!</span><span class="nv">$id</span> <span class="o">=</span> <span class="nv">$GLOBALS</span><span class="p">[</span><span class="s1">&#39;post&#39;</span><span class="p">]</span><span class="o">-&gt;</span><span class="na">ID</span><span class="p">)</span> <span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC21'>		<span class="k">return</span><span class="p">;</span></div><div class='line' id='LC22'>	<span class="p">}</span></div><div class='line' id='LC23'><br/></div><div class='line' id='LC24'>	<span class="cm">/* Keine Feeds und X-Backs */</span></div><div class='line' id='LC25'>	<span class="k">if</span> <span class="p">(</span> <span class="nx">is_feed</span><span class="p">()</span> <span class="k">or</span> <span class="nx">is_trackback</span><span class="p">()</span> <span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC26'>		<span class="k">return</span><span class="p">;</span></div><div class='line' id='LC27'>	<span class="p">}</span></div><div class='line' id='LC28'><br/></div><div class='line' id='LC29'>	<span class="cm">/* Beiträge mit Thumbs */</span></div><div class='line' id='LC30'>	<span class="k">if</span> <span class="p">(</span> <span class="nx">is_singular</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="nx">has_post_thumbnail</span><span class="p">(</span><span class="nv">$id</span><span class="p">)</span> <span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC31'>		<span class="nv">$image</span> <span class="o">=</span> <span class="nx">wp_get_attachment_image_src</span><span class="p">(</span></div><div class='line' id='LC32'>			<span class="nx">get_post_thumbnail_id</span><span class="p">(</span><span class="nv">$id</span><span class="p">)</span></div><div class='line' id='LC33'>		<span class="p">);</span></div><div class='line' id='LC34'><br/></div><div class='line' id='LC35'>		<span class="nv">$thumb</span> <span class="o">=</span> <span class="nv">$image</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span></div><div class='line' id='LC36'><br/></div><div class='line' id='LC37'>	<span class="cm">/* Default Thumb */</span></div><div class='line' id='LC38'>	<span class="p">}</span> <span class="k">else</span> <span class="p">{</span></div><div class='line' id='LC39'>		<span class="nv">$thumb</span> <span class="o">=</span> <span class="s1">&#39;http://cdn.wpseo.de/website/v3/img/logo/120x120.png&#39;</span><span class="p">;</span></div><div class='line' id='LC40'>	<span class="p">}</span></div><div class='line' id='LC41'><br/></div><div class='line' id='LC42'>	<span class="cm">/* Ausgabe */</span></div><div class='line' id='LC43'>	<span class="k">echo</span> <span class="nb">sprintf</span><span class="p">(</span></div><div class='line' id='LC44'>		<span class="s1">&#39;%s&lt;meta property=&quot;og:image&quot; content=&quot;%s&quot; /&gt;&#39;</span><span class="p">,</span></div><div class='line' id='LC45'>		<span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">,</span></div><div class='line' id='LC46'>		<span class="nx">esc_attr</span><span class="p">(</span><span class="nv">$thumb</span><span class="p">)</span></div><div class='line' id='LC47'>	<span class="p">);</span></div><div class='line' id='LC48'><span class="p">}</span></div><div class='line' id='LC49'><br/></div><div class='line' id='LC50'><span class="cm">/* Fire */</span></div><div class='line' id='LC51'><span class="nx">add_action</span><span class="p">(</span></div><div class='line' id='LC52'>	<span class="s1">&#39;wp_head&#39;</span><span class="p">,</span></div><div class='line' id='LC53'>	<span class="s1">&#39;sm_meta_thumb&#39;</span></div><div class='line' id='LC54'><span class="p">);</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1596767/cf83199e818f24ea64056e72d73d766cd13bc704/meta_thumb.php" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1596767#file_meta_thumb.php" style="float:right;margin-right:10px;color:#666">meta_thumb.php</a>
            <a href="https://gist.github.com/1596767">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>
</p>
<p><strong>Hinweise</strong></p>
<ul>
<li>Die Ausgabe erfolgt ausschließlich auf Seiten mit Artikelbildern. Auf restlichen Seiten im Blog (Startseite, Archiv, etc.) gibt das Modul ein Standard-Thumbnail aus, welches im Modul-Schnipsel als Pfad angepasst werden sollte.</li>
<li>Aufruf der WordPress-Funktion <em>wp_head()</em> muss in <em>header.php</em> stattfinden.</li>
</ul>
<p><strong>Testing</strong><br />
Das Ergebnis lässt sich wahlweise direkt in Google+ durch die Eingabe einer URL (ohne abzusenden) testen. Oder mithilfe des <a href="http://www.google.com/webmasters/tools/richsnippets" target="_blank">Google Snippet Tools</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://playground.ebiene.de/wordpress-google-plus/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Texteditor Espresso perfektionieren: Sugars verwalten</title>
		<link>http://playground.ebiene.de/espresso-sugars-verwalten/</link>
		<comments>http://playground.ebiene.de/espresso-sugars-verwalten/#comments</comments>
		<pubDate>Wed, 11 Jan 2012 09:04:50 +0000</pubDate>
		<dc:creator>Sergej</dc:creator>
				<category><![CDATA[Tipps]]></category>

		<guid isPermaLink="false">http://playground.ebiene.de/?p=2823</guid>
		<description><![CDATA[Der Texteditor Espresso in der aktuellen Version 2 ist bei Webentwicklern sehr beliebt. Durch seine native Unterstützung von Modulen &#8211; sogenannten Sugars &#8211; bleibt Espresso ausbaufähig und modifizierbar. Es existieren Sugars u.a. für Themes, Sprachsyntax und Vervollständigungen. Espresso bringt sehr viele Sugars im Lieferzustand mit, andere lassen sich im Web finden und installieren. Auch ein [...]]]></description>
			<content:encoded><![CDATA[<p>Der Texteditor <a href="http://macrabbit.com/espresso/" target="_blank">Espresso</a> in der aktuellen Version 2 ist bei Webentwicklern sehr beliebt. Durch seine native Unterstützung von Modulen &#8211; sogenannten <a href="http://wiki.macrabbit.com/index/SugarBasics/" target="_blank">Sugars</a> &#8211; bleibt Espresso ausbaufähig und modifizierbar. Es existieren Sugars u.a. für Themes, Sprachsyntax und Vervollständigungen. Espresso bringt sehr viele Sugars im Lieferzustand mit, andere lassen sich im Web finden und installieren. Auch ein WordPress Template Tags <a href="http://alisothegeek.com/2011/02/new-wordpress-sugar-for-espresso/" target="_blank">Auto-Complete Sugar</a> steht zur Verfügung. Nachfolgend soll in Bildern gezeigt werden, wie Espresso durch das Editieren von Sugars erweitert wird.<br />
<span id="more-2823"></span><br />
<img src="http://playground.ebiene.de/wp-content/uploads/2012/01/espresso-auto-complete.png" alt="Espresso Auto-Complete" title="Espresso Auto-Complete" width="474" height="200" class="alignnone size-full wp-image-2826" /><br />
<em>Praktisches Auto-Complete in Espresso</em></p>
<p><strong>Absicherung gegen Updates</strong><br />
Mitgelieferte Sugars speichert Espresso in sich selbst &#8211; zu finden unter <em>Programme</em> > <em>Espresso</em> > <em>Paketinhalt zeigen</em>. Der Vollständigkeit wegen, sei der komplette Pfad zu den verborgenen &#8220;Zuckerstückchen&#8221; genannt: <em>/Applications/Espresso.app/Contents/SharedSupport/Sugars/</em>. Dort bewahrt das Programm alle Module auf, die allerdings an der Stelle nicht bearbeitet werden dürfen. Das nächste Update würde die Sugars ersetzen, alle Änderungen seitens Nutzer gehen verloren.</p>
<p>Sobald man weiß, welche Sugar-Datei (die nach Formaten gegliedert sind) bearbeitet werden soll, gehört diese in die Zwischenablage kopiert. In unserem Fall ist es die <em>CSS.sugar</em>, weil dort eine Korrektur an der Autovervollständigung der CSS-Attribute vorgenommen werden soll. Die kopierte Datei landet vorerst auf dem Schreibtisch.</p>
<p><img src="http://playground.ebiene.de/wp-content/uploads/2012/01/espresso-xml.png" alt="Espresso CSS.xml" title="Espresso CSS.xml" width="474" height="200" class="alignnone size-full wp-image-2869" /><br />
<em>Einträge für die Autovervollständigung in Espresso XML</em></p>
<p><strong>XML als Funktionsquelle</strong><br />
Nach einem Doppelklick würde Espresso das File vom aktuellen Ort (Schreibtisch) in den Benutzerordner <em>/Library/Application Support/Espresso/Sugars/</em> befördern. Bleiben wir also bei unserem Vorhaben, diverse Einträge aus der Liste der Autovervollständigung für CSS-Dateien zu entfernen (<em>widows</em>, ja <a href="http://www.css4you.de/widows.html" target="_blank">widows</a> als erster Auto-Vorschlag beim Tippen von <em>width</em> nervt auf Dauer).</p>
<p>Hierfür wird das Sugar via <em>Rechtsklick</em> > <em>Paketinhalt zeigen</em> temporär &#8220;entpackt&#8221;. Dort navigiert man zum Ordner <em>CodeSenseLibraries</em> und weiter zu <em>CSS.xml</em>. Genau diese XML-Datei beinhaltet alle Vorschläge für CSS-Attribute im Editor. Jetzt nach Wunsch und Laune modifizieren, speichern. Doppelklick auf Sugar, Datei verschwindet vom Desktop. Espresso neu starten.</p>
<p><img src="http://playground.ebiene.de/wp-content/uploads/2012/01/css-sugar.png" alt="CSS.sugar entpacken" title="CSS.sugar entpacken" width="474" height="200" class="alignnone size-full wp-image-2825" /><br />
<em>CSS.sugar im Finder extrahieren</em></p>
<p><strong>LESS-Support</strong><br />
Für alle Nutzer von <a href="http://lesscss.org" target="_blank">LESS</a> kann das <a href="https://github.com/elliottcable/LESS.sugar" target="_blank">LESS.sugar</a> ans Herz gelegt werden. Alternativ zu <em>LESS.sugar</em> kann im <em>CSS.sugar</em> die Datei <em>Languages.xml</em> im Knotenpunk <em>detectors</em> um den Eintrag <em>&lt;extension&gt;less&lt;/extension>&gt;</em> erweitert werden.</p>
<p><strong>Outro</strong><br />
Der besprochene Weg zeigt die Möglichkeit, Espresso nach eigenen Bedürfnissen anzupassen. Wahlweise mithilfe von Installationen zusätzlicher Sugars oder unkomplizierter Bearbeitung der Sugars im Benutzerordner. Überflüssige, veraltete Werte in der Autovervollständigung sind so prompt eliminiert und stören nicht länger. Ein angelegtes Backup dient immer als Versicherung.</p>
]]></content:encoded>
			<wfw:commentRss>http://playground.ebiene.de/espresso-sugars-verwalten/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Github:Gist-Snippets in WordPress via Shortcode einbinden</title>
		<link>http://playground.ebiene.de/gist-toolbox-modul/</link>
		<comments>http://playground.ebiene.de/gist-toolbox-modul/#comments</comments>
		<pubDate>Tue, 10 Jan 2012 09:00:49 +0000</pubDate>
		<dc:creator>Sergej</dc:creator>
				<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://playground.ebiene.de/?p=2819</guid>
		<description><![CDATA[Früher oder später steht jeder Entwickler vor der Entscheidung: Wo eigene Code-Snippets &#8211; öffentlich zugänglich &#8211; speichern bzw. verwalten und dabei die Möglichkeit besitzen, diese in Beiträgen möglichst ohne Umstand einbinden zu können? Direkt im Blog? Dienstleister? Github:Gist ist für viele der Favorit. Für die Einbindung der eigenen Gist-Schnipsel hat Github eine JavaScript-Lösung vorgesehen, die [...]]]></description>
			<content:encoded><![CDATA[<p>Früher oder später steht jeder Entwickler vor der Entscheidung: Wo eigene Code-Snippets &#8211; öffentlich zugänglich &#8211; speichern bzw. verwalten und dabei die Möglichkeit besitzen, diese in Beiträgen möglichst ohne Umstand einbinden zu können? Direkt im Blog? Dienstleister? <a href="https://gist.github.com/" target="_blank">Github:Gist</a> ist für viele der Favorit. Für die Einbindung der eigenen Gist-Schnipsel hat Github eine JavaScript-Lösung vorgesehen, die den Code dynamisch in den Artikel einbindet. Der Nachteil: Es ruckelt beim Laden, zudem bleibt der Snippet nicht Feed- bzw. indexierbar, da kein fester Bestandteil der Seite. Abhilfe: Das <a href="http://playground.ebiene.de/toolbox-wordpress-plugin/">Toolbox</a>-Modul liest den Gist-Snippet ein, speichert diesen im Cache und gibt ihn an der gewünschten Stelle im WordPress-Artikel aus.<br />
<span id="more-2819"></span><br />
<strong>Gist-Snippets via Shortcode</strong><br />
Die überzeugende Eigenschaft der Toolbox-Module ist ihre Einfachheit und Verständlichkeit. So auch beim Modul für Gist-Snippets: Der Code ist übersichtlich gehalten, Kommentare begleiten den Funktionsumfang. Die Gist-Integration in Webseiten erfolgt mithilfe eines simplen Shortcodes:</p>
<pre>
&lbrack;gist id=xxxxx&rbrack;
</pre>
<p><img src="http://playground.ebiene.de/wp-content/uploads/2012/01/gist-id.png" alt="Github:Gist ID" title="Github:Gist ID" width="474" height="200" class="alignnone size-full wp-image-2822" /><br />
<em>Zuständige Gist-ID für den Shortcode</em></p>
<p><strong>Integration der Stylesheets</strong><br />
Das Modul kümmert sich nicht nur ums Auslesen, Caching und die Darstellung der Code-Auszüge. Die für die Syntax-Hervorhebung zuständige CSS-Datei wird auf Beiträgen mit der Gist-Einbindung ebenfalls eingebunden und nachgeladen. Sind eigene Stylesheets für die Code-Formatierung im Einsatz, so kann auf die CSS-Registrierung im Modul verzichtet werden.</p>
<p><strong>Toolbox-Modul für die Gist-Einbindung</strong><br />
<div id="gist-1571759" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="cp">&lt;?php</span></div><div class='line' id='LC2'><span class="cm">/*</span></div><div class='line' id='LC3'><span class="cm">Module Name: Einbindung der Gist-Snippets</span></div><div class='line' id='LC4'><span class="cm">Module URI: http://playground.ebiene.de/gist-toolbox-modul/</span></div><div class='line' id='LC5'><span class="cm">Description: Abfrage und Darstellung der Gist-Snippets via [gist id=xxxx] Shortcode. [Frontend]</span></div><div class='line' id='LC6'><span class="cm">Author: Sergej Müller</span></div><div class='line' id='LC7'><span class="cm">Author URI: http://ebiene.de</span></div><div class='line' id='LC8'><span class="cm">*/</span></div><div class='line' id='LC9'><br/></div><div class='line' id='LC10'><br/></div><div class='line' id='LC11'><span class="cm">/* Sicherheitsabfrage */</span></div><div class='line' id='LC12'><span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="nb">class_exists</span><span class="p">(</span><span class="s1">&#39;Toolbox&#39;</span><span class="p">)</span> <span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC13'>	<span class="k">die</span><span class="p">();</span></div><div class='line' id='LC14'><span class="p">}</span></div><div class='line' id='LC15'><br/></div><div class='line' id='LC16'><br/></div><div class='line' id='LC17'><span class="cm">/* Gist */</span></div><div class='line' id='LC18'><span class="k">class</span> <span class="nc">Gist</span></div><div class='line' id='LC19'><span class="p">{</span></div><div class='line' id='LC20'><br/></div><div class='line' id='LC21'><br/></div><div class='line' id='LC22'>	<span class="sd">/**</span></div><div class='line' id='LC23'><span class="sd">	* Initiator der Klasse</span></div><div class='line' id='LC24'><span class="sd">	*/</span></div><div class='line' id='LC25'><br/></div><div class='line' id='LC26'>	<span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">init</span><span class="p">()</span></div><div class='line' id='LC27'>	<span class="p">{</span></div><div class='line' id='LC28'>		<span class="nx">add_action</span><span class="p">(</span></div><div class='line' id='LC29'>			<span class="s1">&#39;wp_enqueue_scripts&#39;</span><span class="p">,</span></div><div class='line' id='LC30'>			<span class="k">array</span><span class="p">(</span></div><div class='line' id='LC31'>				<span class="nx">__CLASS__</span><span class="p">,</span></div><div class='line' id='LC32'>				<span class="s1">&#39;register_style&#39;</span></div><div class='line' id='LC33'>			<span class="p">)</span></div><div class='line' id='LC34'>		<span class="p">);</span></div><div class='line' id='LC35'><br/></div><div class='line' id='LC36'>		<span class="nx">add_shortcode</span><span class="p">(</span></div><div class='line' id='LC37'>			<span class="s1">&#39;gist&#39;</span><span class="p">,</span></div><div class='line' id='LC38'>			<span class="k">array</span><span class="p">(</span></div><div class='line' id='LC39'>				<span class="nx">__CLASS__</span><span class="p">,</span></div><div class='line' id='LC40'>				<span class="s1">&#39;handle_shortcode&#39;</span></div><div class='line' id='LC41'>			<span class="p">)</span></div><div class='line' id='LC42'>		<span class="p">);</span></div><div class='line' id='LC43'>	<span class="p">}</span></div><div class='line' id='LC44'><br/></div><div class='line' id='LC45'><br/></div><div class='line' id='LC46'>	<span class="sd">/**</span></div><div class='line' id='LC47'><span class="sd">	* Registrierung des CSS</span></div><div class='line' id='LC48'><span class="sd">	*/</span></div><div class='line' id='LC49'><br/></div><div class='line' id='LC50'>	<span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">register_style</span><span class="p">()</span></div><div class='line' id='LC51'>	<span class="p">{</span></div><div class='line' id='LC52'>		<span class="nx">wp_register_style</span><span class="p">(</span></div><div class='line' id='LC53'>			<span class="s1">&#39;gist_css&#39;</span><span class="p">,</span></div><div class='line' id='LC54'>			<span class="s1">&#39;https://gist.github.com/stylesheets/gist/embed.css&#39;</span></div><div class='line' id='LC55'>		<span class="p">);</span></div><div class='line' id='LC56'>	<span class="p">}</span></div><div class='line' id='LC57'><br/></div><div class='line' id='LC58'><br/></div><div class='line' id='LC59'>	<span class="sd">/**</span></div><div class='line' id='LC60'><span class="sd">	* Verarbeitung des Shortcodes</span></div><div class='line' id='LC61'><span class="sd">	*</span></div><div class='line' id='LC62'><span class="sd">	* @param   array   $atts    Array mit Attributen</span></div><div class='line' id='LC63'><span class="sd">	* @param   string  $txt     Text zwischen den Tags [optional]</span></div><div class='line' id='LC64'><span class="sd">	* @return  string  $output  Ermittelter Gist-Quelltext</span></div><div class='line' id='LC65'><span class="sd">	*/</span></div><div class='line' id='LC66'><br/></div><div class='line' id='LC67'>	<span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">handle_shortcode</span><span class="p">(</span><span class="nv">$atts</span><span class="p">,</span> <span class="nv">$txt</span> <span class="o">=</span> <span class="k">null</span><span class="p">)</span></div><div class='line' id='LC68'>	<span class="p">{</span></div><div class='line' id='LC69'>		<span class="cm">/* Leer? */</span></div><div class='line' id='LC70'>		<span class="k">if</span> <span class="p">(</span> <span class="k">empty</span><span class="p">(</span><span class="nv">$atts</span><span class="p">[</span><span class="s1">&#39;id&#39;</span><span class="p">])</span> <span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC71'>			<span class="k">return</span> <span class="s1">&#39;No Gist ID.&#39;</span><span class="p">;</span></div><div class='line' id='LC72'>		<span class="p">}</span></div><div class='line' id='LC73'><br/></div><div class='line' id='LC74'>		<span class="cm">/* Init */</span></div><div class='line' id='LC75'>		<span class="nv">$id</span> <span class="o">=</span> <span class="p">(</span><span class="nx">int</span><span class="p">)</span> <span class="nv">$atts</span><span class="p">[</span><span class="s1">&#39;id&#39;</span><span class="p">];</span></div><div class='line' id='LC76'>		<span class="nv">$transient</span> <span class="o">=</span> <span class="s1">&#39;sm_gist_&#39;</span> <span class="o">.</span><span class="nv">$id</span><span class="p">;</span></div><div class='line' id='LC77'><br/></div><div class='line' id='LC78'>		<span class="cm">/* Einbinden */</span></div><div class='line' id='LC79'>		<span class="nx">wp_enqueue_style</span><span class="p">(</span><span class="s1">&#39;gist_css&#39;</span><span class="p">);</span></div><div class='line' id='LC80'><br/></div><div class='line' id='LC81'>		<span class="cm">/* Im Cache */</span></div><div class='line' id='LC82'>		<span class="k">if</span> <span class="p">(</span> <span class="nv">$gist</span> <span class="o">=</span> <span class="nx">get_transient</span><span class="p">(</span><span class="nv">$transient</span><span class="p">)</span> <span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC83'>			<span class="k">return</span> <span class="nv">$gist</span><span class="p">;</span></div><div class='line' id='LC84'>		<span class="p">}</span></div><div class='line' id='LC85'><br/></div><div class='line' id='LC86'>		<span class="cm">/* Abrufen */</span></div><div class='line' id='LC87'>		<span class="nv">$response</span> <span class="o">=</span> <span class="nx">wp_remote_get</span><span class="p">(</span></div><div class='line' id='LC88'>			<span class="s1">&#39;https://gist.github.com/&#39;</span> <span class="o">.</span><span class="nv">$id</span><span class="o">.</span> <span class="s1">&#39;.json&#39;</span><span class="p">,</span></div><div class='line' id='LC89'>			<span class="k">array</span><span class="p">(</span><span class="s1">&#39;sslverify&#39;</span> <span class="o">=&gt;</span> <span class="k">false</span><span class="p">)</span></div><div class='line' id='LC90'>		<span class="p">);</span></div><div class='line' id='LC91'><br/></div><div class='line' id='LC92'>		<span class="cm">/* Fehler? */</span></div><div class='line' id='LC93'>		<span class="k">if</span> <span class="p">(</span> <span class="nx">is_wp_error</span><span class="p">(</span><span class="nv">$response</span><span class="p">)</span> <span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC94'>			<span class="k">return</span> <span class="nv">$response</span><span class="o">-&gt;</span><span class="na">get_error_message</span><span class="p">();</span></div><div class='line' id='LC95'>		<span class="p">}</span></div><div class='line' id='LC96'><br/></div><div class='line' id='LC97'>		<span class="cm">/* Holen und parsen */</span></div><div class='line' id='LC98'>		<span class="nv">$json</span> <span class="o">=</span> <span class="nb">json_decode</span><span class="p">(</span></div><div class='line' id='LC99'>			<span class="nx">wp_remote_retrieve_body</span><span class="p">(</span><span class="nv">$response</span><span class="p">)</span></div><div class='line' id='LC100'>		<span class="p">);</span></div><div class='line' id='LC101'><br/></div><div class='line' id='LC102'>		<span class="cm">/* Leer? */</span></div><div class='line' id='LC103'>		<span class="k">if</span> <span class="p">(</span> <span class="k">empty</span><span class="p">(</span><span class="nv">$json</span><span class="o">-&gt;</span><span class="na">div</span><span class="p">)</span> <span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC104'>			<span class="k">return</span> <span class="s1">&#39;Empty Data.&#39;</span><span class="p">;</span></div><div class='line' id='LC105'>		<span class="p">}</span></div><div class='line' id='LC106'><br/></div><div class='line' id='LC107'>		<span class="cm">/* Zuweisen */</span></div><div class='line' id='LC108'>		<span class="nv">$output</span> <span class="o">=</span> <span class="p">(</span><span class="nx">string</span><span class="p">)</span> <span class="nv">$json</span><span class="o">-&gt;</span><span class="na">div</span><span class="p">;</span></div><div class='line' id='LC109'><br/></div><div class='line' id='LC110'>		<span class="cm">/* Cachen */</span></div><div class='line' id='LC111'>		<span class="nx">set_transient</span><span class="p">(</span></div><div class='line' id='LC112'>			<span class="nv">$transient</span><span class="p">,</span></div><div class='line' id='LC113'>			<span class="nv">$output</span><span class="p">,</span></div><div class='line' id='LC114'>			<span class="mi">60</span> <span class="o">*</span> <span class="mi">60</span> <span class="o">*</span> <span class="mi">24</span></div><div class='line' id='LC115'>		<span class="p">);</span></div><div class='line' id='LC116'><br/></div><div class='line' id='LC117'>		<span class="k">return</span> <span class="nv">$output</span><span class="p">;</span></div><div class='line' id='LC118'>	<span class="p">}</span></div><div class='line' id='LC119'><span class="p">}</span></div><div class='line' id='LC120'><br/></div><div class='line' id='LC121'><br/></div><div class='line' id='LC122'><span class="cm">/* Fire */</span></div><div class='line' id='LC123'><span class="nx">add_action</span><span class="p">(</span></div><div class='line' id='LC124'>	<span class="s1">&#39;init&#39;</span><span class="p">,</span></div><div class='line' id='LC125'>	<span class="k">array</span><span class="p">(</span></div><div class='line' id='LC126'>		<span class="s1">&#39;Gist&#39;</span><span class="p">,</span></div><div class='line' id='LC127'>		<span class="s1">&#39;init&#39;</span></div><div class='line' id='LC128'>	<span class="p">)</span></div><div class='line' id='LC129'><span class="p">);</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1571759/91938bc8651499490cc1c7ff94d2e81499378c98/github_gist.php" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1571759#file_github_gist.php" style="float:right;margin-right:10px;color:#666">github_gist.php</a>
            <a href="https://gist.github.com/1571759">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>
</p>
<p><strong>Hinweise</strong></p>
<ul>
<li>Für eine fehlerfreie Funktionsweise des Toolbox-Moduls werden PHP 5.2.0 sowie ein Server mit ausgehenden Verbindungen vorausgesetzt.</li>
<li>Die Lösung behandelt einfache Gist-Snippets mit nur einem File. Bei komplexeren Ansätzen mit mehreren Dateien pro Gist empfiehlt sich die umfangreichere Methode von <a href="http://wpgrafie.de/schnipsel/gist-wordpress-einbinden/" target="_blank">Dominik Schilling</a>.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://playground.ebiene.de/gist-toolbox-modul/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Thematisch ähnliche Artikel in WordPress ohne Plugin anzeigen</title>
		<link>http://playground.ebiene.de/related-posts-wordpress-nativ/</link>
		<comments>http://playground.ebiene.de/related-posts-wordpress-nativ/#comments</comments>
		<pubDate>Mon, 02 Jan 2012 21:21:56 +0000</pubDate>
		<dc:creator>Sergej</dc:creator>
				<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://playground.ebiene.de/?p=2814</guid>
		<description><![CDATA[Das WordPress-Plugin Related Posts by Category erlaubt eine zuverlässige und anpassungsfähige Darstellungen der thematisch passenden Beiträge. Die aktuelle Kategorie dient dabei als Referenz. Es existiert mindestens eine Möglichkeit, benachbarte Posts eines Artikels mit nativen WordPress-Mitteln zu berechnen und auszugeben. Mit optionaler Ausgabe der zugewiesenen Vorschaubilder pro Beitrag. Inklusive exemplarischer CSS-Formatierung. Der weiter unten vorgestellte Code [...]]]></description>
			<content:encoded><![CDATA[<p>Das WordPress-Plugin <a href="http://playground.ebiene.de/related-posts-by-category-wp-plugin-fur-verwandte-beitrage-einer-kategorie/">Related Posts by Category</a> erlaubt eine zuverlässige und anpassungsfähige Darstellungen der thematisch passenden Beiträge. Die aktuelle Kategorie dient dabei als Referenz. Es existiert mindestens eine Möglichkeit, benachbarte Posts eines Artikels mit nativen WordPress-Mitteln zu berechnen und auszugeben. Mit optionaler Ausgabe der zugewiesenen Vorschaubilder pro Beitrag. Inklusive exemplarischer CSS-Formatierung.<br />
<span id="more-2814"></span><br />
Der weiter unten vorgestellte Code ist sehr strukturiert, ausreichend kommentiert und versteht sich praktisch von selbst. Für mehr Übersichtlichkeit und eine klare, striktere Trennung zwischen Code und Design wurde der <em>Related Posts</em> Snippet in Form eines <a href="http://playground.ebiene.de/toolbox-wordpress-plugin/">Toolbox-Moduls</a> abgelegt. Bei Bedarf besteht die Möglichkeit, die Codezeilen zu extrahieren und für eine direkte Injizierung im zuständigen WordPress-Theme zu verwenden. Notfalls gehört der Quelltext in die <em>functions.php</em>.</p>
<p><img src="http://playground.ebiene.de/wp-content/uploads/2012/01/wordpress-related-posts.png" alt="Related Posts im WordPress-Blog" title="Related Posts im WordPress-Blog" width="474" height="200" class="alignnone size-full wp-image-2817" /><br />
<em>Related Posts im WordPress-Blog</em></p>
<p><strong>Arbeitsweise der Lösung</strong><br />
Nach der Aktivierung des Moduls (<em>Frontend</em> als Bereich) und der Einbindung des Hooks (siehe weiter unten) prüft die Funktion zunächst, ob der Artikel mindestens einer Kategorie zugeordnet ist. Ist das der Fall, startet eine WordPress-Query die Suche nach ähnlichen Artikeln, wobei die Kategorie-ID als gemeinsamer Nenner gilt. Die Anzahl der gefundenen Treffer beschränkt sich auf zwei, eine Erhöhung der Zahl im Code ist jederzeit möglich.</p>
<p>Verfügen erstellte Beiträge über Artikelbilder, so werden diese im Modul berücksichtigt und zusätzlich zum Artikeltitel auf der Blogseite ausgegeben. Andernfalls kommt lediglich der alleinstehende Titel als klickbare Fläche zum Vorschein.</p>
<p><strong>Verknüpfung mit Themes</strong><br />
Die Einbettung der Treffer an der gewünschten Stelle im WordPress-Theme erfolgt durch ein speziell dafür angelegtes Hook namens <em>related_posts</em>. Der sparsame Aufruf lautet:</p>
<pre>
&lt;?php do_action('related_posts'); ?&gt;
</pre>
<p><strong>Toolbox-Modul für Related Posts</strong></p>
<div>
  <div id="gist-1552139" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="cp">&lt;?php</span></div><div class='line' id='LC2'><span class="cm">/*</span></div><div class='line' id='LC3'><span class="cm">Module Name: Ausgabe Kategorie-verwandter Artikel</span></div><div class='line' id='LC4'><span class="cm">Module URI: http://playground.ebiene.de/related-posts-wordpress-nativ/</span></div><div class='line' id='LC5'><span class="cm">Description: &amp;lt;?php do_action(&#39;related_posts&#39;); ?&amp;gt; für die Ausgabe der Treffer im Theme. [Frontend]</span></div><div class='line' id='LC6'><span class="cm">Author: Sergej Müller</span></div><div class='line' id='LC7'><span class="cm">Author URI: http://ebiene.de</span></div><div class='line' id='LC8'><span class="cm">*/</span></div><div class='line' id='LC9'><br/></div><div class='line' id='LC10'><br/></div><div class='line' id='LC11'><span class="cm">/* Sicherheitsabfrage */</span></div><div class='line' id='LC12'><span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="nb">class_exists</span><span class="p">(</span><span class="s1">&#39;Toolbox&#39;</span><span class="p">)</span> <span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC13'>	<span class="k">die</span><span class="p">();</span></div><div class='line' id='LC14'><span class="p">}</span></div><div class='line' id='LC15'><br/></div><div class='line' id='LC16'><br/></div><div class='line' id='LC17'><span class="cm">/* Ab hier kann&#39;s los gehen */</span></div><div class='line' id='LC18'><span class="k">function</span> <span class="nf">sm_related_posts</span><span class="p">()</span> <span class="p">{</span></div><div class='line' id='LC19'>	<span class="cm">/* Keine Kategorien */</span></div><div class='line' id='LC20'>	<span class="k">if</span> <span class="p">(</span> <span class="o">!</span> <span class="nv">$cat</span> <span class="o">=</span> <span class="nx">get_the_category</span><span class="p">()</span> <span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC21'>		<span class="k">return</span><span class="p">;</span></div><div class='line' id='LC22'>	<span class="p">}</span></div><div class='line' id='LC23'><br/></div><div class='line' id='LC24'>	<span class="cm">/* IDs */</span></div><div class='line' id='LC25'>	<span class="nv">$ids</span> <span class="o">=</span> <span class="nb">implode</span><span class="p">(</span></div><div class='line' id='LC26'>		<span class="s1">&#39;,&#39;</span><span class="p">,</span></div><div class='line' id='LC27'>		<span class="nb">array_reduce</span><span class="p">(</span></div><div class='line' id='LC28'>			<span class="nv">$cat</span><span class="p">,</span></div><div class='line' id='LC29'>			<span class="k">function</span><span class="p">(</span><span class="nv">$v</span><span class="p">,</span> <span class="nv">$w</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC30'>				<span class="nv">$v</span><span class="p">[]</span> <span class="o">=</span> <span class="nv">$w</span><span class="o">-&gt;</span><span class="na">term_id</span><span class="p">;</span></div><div class='line' id='LC31'>				<span class="k">return</span> <span class="nv">$v</span><span class="p">;</span></div><div class='line' id='LC32'>			<span class="p">}</span></div><div class='line' id='LC33'>		<span class="p">)</span></div><div class='line' id='LC34'>	<span class="p">);</span></div><div class='line' id='LC35'><br/></div><div class='line' id='LC36'>	<span class="cm">/* Query starten */</span></div><div class='line' id='LC37'>	<span class="nv">$query</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WP_Query</span><span class="p">(</span></div><div class='line' id='LC38'>		<span class="k">array</span><span class="p">(</span></div><div class='line' id='LC39'>			<span class="s1">&#39;cat&#39;</span> <span class="o">=&gt;</span> <span class="nv">$ids</span><span class="p">,</span></div><div class='line' id='LC40'>			<span class="s1">&#39;orderby&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;rand&#39;</span><span class="p">,</span></div><div class='line' id='LC41'>			<span class="s1">&#39;post__not_in&#39;</span> <span class="o">=&gt;</span> <span class="k">array</span><span class="p">(</span><span class="nx">get_the_ID</span><span class="p">()),</span></div><div class='line' id='LC42'>			<span class="s1">&#39;posts_per_page&#39;</span> <span class="o">=&gt;</span> <span class="mi">2</span></div><div class='line' id='LC43'>		<span class="p">)</span></div><div class='line' id='LC44'>	<span class="p">);</span></div><div class='line' id='LC45'><br/></div><div class='line' id='LC46'>	<span class="cm">/* Keine Ergebnisse */</span></div><div class='line' id='LC47'>	<span class="k">if</span> <span class="p">(</span> <span class="o">!</span> <span class="nv">$query</span><span class="o">-&gt;</span><span class="na">have_posts</span><span class="p">()</span> <span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC48'>		<span class="k">return</span><span class="p">;</span></div><div class='line' id='LC49'>	<span class="p">}</span></div><div class='line' id='LC50'><br/></div><div class='line' id='LC51'>	<span class="cm">/* Ausgabe */</span></div><div class='line' id='LC52'>	<span class="k">echo</span> <span class="s1">&#39;&lt;ul id=&quot;related&quot;&gt;&#39;</span><span class="p">;</span></div><div class='line' id='LC53'><br/></div><div class='line' id='LC54'>	<span class="k">while</span> <span class="p">(</span> <span class="nv">$query</span><span class="o">-&gt;</span><span class="na">have_posts</span><span class="p">()</span> <span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC55'>		<span class="nv">$query</span><span class="o">-&gt;</span><span class="na">the_post</span><span class="p">();</span></div><div class='line' id='LC56'><br/></div><div class='line' id='LC57'>		<span class="k">echo</span> <span class="nb">sprintf</span><span class="p">(</span></div><div class='line' id='LC58'>			<span class="s1">&#39;&lt;li class=&quot;item&quot;&gt;&lt;a href=&quot;%s&quot;&gt;%s%s&lt;/a&gt;&lt;/li&gt;&#39;</span><span class="p">,</span></div><div class='line' id='LC59'>			<span class="nx">get_permalink</span><span class="p">(),</span></div><div class='line' id='LC60'>			<span class="p">(</span> <span class="nb">function_exists</span><span class="p">(</span><span class="s1">&#39;has_post_thumbnail&#39;</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="nx">has_post_thumbnail</span><span class="p">()</span> <span class="o">?</span> <span class="nx">get_the_post_thumbnail</span><span class="p">()</span> <span class="o">:</span> <span class="s1">&#39;&#39;</span> <span class="p">),</span></div><div class='line' id='LC61'>			<span class="nx">get_the_title</span><span class="p">()</span></div><div class='line' id='LC62'>		<span class="p">);</span></div><div class='line' id='LC63'>	<span class="p">}</span></div><div class='line' id='LC64'><br/></div><div class='line' id='LC65'>	<span class="cm">/* Reset */</span></div><div class='line' id='LC66'>	<span class="nx">wp_reset_postdata</span><span class="p">();</span></div><div class='line' id='LC67'><br/></div><div class='line' id='LC68'>	<span class="k">echo</span> <span class="s1">&#39;&lt;/ul&gt;&#39;</span><span class="p">;</span></div><div class='line' id='LC69'><span class="p">}</span></div><div class='line' id='LC70'><br/></div><div class='line' id='LC71'><span class="cm">/* Funktionsaufruf */</span></div><div class='line' id='LC72'><span class="nx">add_action</span><span class="p">(</span></div><div class='line' id='LC73'>	<span class="s1">&#39;related_posts&#39;</span><span class="p">,</span></div><div class='line' id='LC74'>	<span class="s1">&#39;sm_related_posts&#39;</span></div><div class='line' id='LC75'><span class="p">);</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1552139/59a32eab21b95a19975487bb34b6ea82ab125072/related_posts.php" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1552139#file_related_posts.php" style="float:right;margin-right:10px;color:#666">related_posts.php</a>
            <a href="https://gist.github.com/1552139">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

</div>
<p><strong>Optische Anpassungen</strong><br />
Die CSS-Formatierung der Ausgabe kann analog zu der im Artikel <a href="http://playground.ebiene.de/wordpress-related-posts/">Thematisch ähnliche Beiträge samt Vorschaubilder in WordPress</a> beschriebenen Methode erfolgen. IDs und Klassen innerhalb der Tags können modifiziert werden.</p>
]]></content:encoded>
			<wfw:commentRss>http://playground.ebiene.de/related-posts-wordpress-nativ/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Toolbox-Plugin: WordPress-Snippets auslagern und modularisieren</title>
		<link>http://playground.ebiene.de/toolbox-wordpress-plugin/</link>
		<comments>http://playground.ebiene.de/toolbox-wordpress-plugin/#comments</comments>
		<pubDate>Wed, 28 Dec 2011 08:34:20 +0000</pubDate>
		<dc:creator>Sergej</dc:creator>
				<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://playground.ebiene.de/?p=2725</guid>
		<description><![CDATA[Irgendwann stößt jede functions.php an ihre Grenzen: Nahezu jede (kleinere) Funktionserweiterung im WordPress-Blog endet mit einem Eintrag in dieser Theme-gebundenen Datei, die eigentlich auch dafür gedacht ist. Kommt ein Blog in die Jahre, so ist die WordPress-interne Datei für Erweiterungen wortwörtlich mehrere DIN A4-Seiten lang &#8211; die Übersicht leidet, die Pflege kostet zunehmend Zeit. Das [...]]]></description>
			<content:encoded><![CDATA[<p>Irgendwann stößt jede <em>functions.php</em> an ihre Grenzen: Nahezu jede (kleinere) Funktionserweiterung im WordPress-Blog endet mit einem Eintrag in dieser Theme-gebundenen Datei, die eigentlich auch dafür gedacht ist. Kommt ein Blog in die Jahre, so ist die WordPress-interne Datei für Erweiterungen wortwörtlich mehrere DIN A4-Seiten lang &#8211; die Übersicht leidet, die Pflege kostet zunehmend Zeit. Das altbekannte Problem versucht das neue Plugin <em>Toolbox</em> anzugehen und in vielen Fällen sogar zu lösen.<br />
<span id="more-2725"></span><br />
<strong>Code Snippet Manager für WordPress</strong><br />
Die Grundidee: Der Inhalt der <em>functions.php</em> wird in eigenständige Module aufgeteilt und &#8211; wenn die Zeit es zulässt &#8211; mit Metadaten versehen. Die Module landen per (S)FTP im speziellen Plugin-Ordner <em>modules</em>, werden von <em>Toolbox</em> als solche erkannt und verwaltet. Wer mag, kann so komplett auf die <em>functions.php</em> verzichten und das Management der WordPress-Snippets nur noch über das Plugin unternehmen.</p>
<p><img src="/wp-content/uploads/2011/12/toolbox-wordpress-functions.png" alt="Toolbox hat die Aufgabe, functions.php zu revolutionieren" width="474" height="200" class="size-full" /><br />
<em>Toolbox hat die Aufgabe, functions.php zu revolutionieren</em></p>
<p><strong>Klarheit beim Funktionsaufbau</strong><br />
Welchen Vorteil hat die Modularisierung der Snippets? In erster Linie ist es die Übersichtlichkeit. Durch die Aufteilung und eine sinnvolle Benennung der Code-Schnipsel, erfolgt eine schnellere Zuordnung der Funktionen &#8211; man erfährt prompt und ohne ein komplexes Kommentarsystem zu besitzen, welches Modul (und somit auch welcher Code) für welche Funktionsweise im Blog zuständig ist. Mehr Struktur und Ordnung kommen rein. Der Gedanke ähnelt sehr der Verwaltung von Plugins innerhalb von WordPress: Zielsetzungen kapseln.</p>
<p>Zudem ist es ein weiterer Schritt in Richtung <em>Trennung zwischen Funktion und Layout</em>, denn die globalen Codeanweisungen gehören nicht unbedingt ins Theme.</p>
<p><strong>Zuweisung der Lade-Bereiche und Abschaltung</strong><br />
<em>Toolbox</em>-Module sind nichts anderes als gruppierte Funktions- und Hooks-Aufrufe. Doch die Module lassen sich auf Wunsch einzeln deaktivieren. Oder auch genau festlegen, wo diese geladen und ausgeführt werden. Dazu stehen Segmente <em>Nur im Frontend</em>, <em>Nur im Backend</em> und <em>Im Back- und Frontend</em> zur Auswahl bereit.</p>
<p><img src="/wp-content/uploads/2011/12/toolbox-module.png" alt="Verfügbare Toolbox-Module mit Beschreibung aufgelistet." width="474" height="200" class="size-full" /><br />
<em>Verfügbare Toolbox-Module mit Beschreibung aufgelistet</em></p>
<p><strong>Aufbau der Toolbox-Module</strong><br />
Ein <em>Toolbox</em>-Modul ist eine PHP-Datei im Plugin-Verzeichnis <em>modules</em>, bestehend aus optionalen Metadaten, einer Sicherheitsabfrage und benutzerdefinierten Code-Fragmenten. Wie auch bei WordPress-Plugins besitzen Meta-Informationen der <em>Toolbox</em>-Module über ein festgelegtes Muster. Der <em>Module Name</em>, die <em>Description</em> und <em>Module URI</em> werden ausgewertet und in der Auflistung der Module innerhalb der Plugin-Einstellungen angezeigt.</p>
<p>Als Linktipp eignen sich an dieser Stelle <a href="http://wpsnipp.com">wpsnipp.com</a> und <a href="http://wp-snippets.com/">wp-snippets.com</a> mit ihren zahlreichen WordPress-Snippets.</p>
<p><strong>Skelett eines Toolbox-Moduls</strong></p>
<pre>
&lt;?php
/*
Module Name: Name des Moduls
Description: Beschreibung des Moduls [Backend|Frontend]
Author: Sergej Müller
Author URI: http://ebiene.de
*/

/* Sicherheitsabfrage */
if ( !class_exists('Toolbox') ) {
  die();
}

/* Ab hier kann's los gehen */
echo 'Hier mein Snippet';
</pre>
<p><strong>Ratschläge zum Modulaufbau</strong></p>
<ul>
<li>Für die korrekte Darstellung der Sonderzeichen, sollte das Modul im UTF-8 Format gespeichert werden.</li>
<li>Abschließendes ?&gt; am Ende des Moduls ist nicht notwendig.</li>
</ul>
<p><strong>Potential bei Themes, Multisite und Performance</strong></p>
<ul>
<li><em>Toolbox</em> stellt die Funktionalität der aktiven Module Themes-übergreifend bereit, d.h. bei einem Layout-Wechsel sind die hinterlegten Funktionen sofort einsatzbereit. Dito bei Multisite-Blogs.</li>
<li>Im Vergleich zu WordPress Plugins, erfolgt bei den Modulen keine Prüfung auf vorhandene Updates. Das verringert wiederum die Ladezeiten.</li>
<li>Schon gewusst, das WordPress die <em>functions.php</em> aus aktuellem Theme sowohl im Blog-Frontend wie auch Backend lädt? Durch eine genaue Zuweisung der Lade-Bereiche (Frontend, Backend, FE und BE), lässt sich die Performance des Blogs steigern und die Fehlerquote senken, da Funktionen nur dort geladen und ausgeführt werden, wofür diese tatsächlich programmiert wurden.</li>
</ul>
<p><strong>Module im Lieferumfang</strong><br />
Dem Plugin liegen vorgefertigte Module bei.</p>
<p><strong>Neue oder weiterentwickelte Module</strong></p>
<ul>
<li><a href="https://gist.github.com/1615422" target="_blank">Kompatibilität für nginx Webserver</a></li>
<li><a href="https://gist.github.com/1596767" target="_blank">Artikelbilder als Metatag</a></li>
<li><a href="https://gist.github.com/1571759" target="_blank">Einbindung von Gist-Snippets</a></li>
<li><a href="https://gist.github.com/1535471" target="_blank">Modifizierung der Admin Bar</a></li>
<li><a href="https://gist.github.com/1543642" target="_blank">Bildoptimierung beim Upload</a></li>
<li><a href="https://gist.github.com/1552139" target="_blank">Ausgabe thematischer Artikel</a></li>
<li><a href="https://gist.github.com/1564201" target="_blank">Aktivierung der Vorschaubilder</a></li>
</ul>
<p><strong>Hinweise</strong></p>
<ul>
<li>Mindestvoraussetzungen: WordPress 3.3 und PHP 5 (5.3 empfohlen)</li>
<li>Plugin-interne Hilfe oben rechts beachten</li>
</ul>
<p><strong>Outro</strong><br />
Will der aktuelle Blog um eine Funktion erweitert werden, wo der PHP-Code eigentlich in die <em>functions.php</em> gehören sollte? Stop! Ein weiteres <em>Toolbox</em>-Modul anlegen, Metadaten anpassen, den Schnipsel einfügen, für einen Bereich aktivieren. Arbeiten lassen.</p>
<p><strong>Flattr</strong><br />
Unterstützung via <a href="http://flattr.com/profile/sergej.mueller" target="_blank">Flattr</a> ist jederzeit willkommen. Danke.</p>
<p><strong id="download">Download</strong><br />
<a href="http://wordpress.org/extend/plugins/toolbox/">&rsaquo; Toolbox &#8211; WordPress Snippets als Module &darr;</a></p>
]]></content:encoded>
			<wfw:commentRss>http://playground.ebiene.de/toolbox-wordpress-plugin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

