<?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>Aktuelle Artikel auf dNaber.de &#187; Webdesign</title>
	<atom:link href="http://dnaber.de/blog/kategorie/webdesign/feed/" rel="self" type="application/rss+xml" />
	<link>http://dnaber.de</link>
	<description>Die zehn neuesten Beiträge aus dem Blog von David Naber.</description>
	<lastBuildDate>Wed, 16 May 2012 16:42:35 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>daily</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>Wo $wp_scripts drauf steht, ist WP_Scripts drin</title>
		<link>http://dnaber.de/blog/2012/wo-wp-scripts-drauf-steht-ist-wp-scripts-drin/</link>
		<comments>http://dnaber.de/blog/2012/wo-wp-scripts-drauf-steht-ist-wp-scripts-drin/#comments</comments>
		<pubDate>Wed, 16 May 2012 16:42:35 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>

		<guid isPermaLink="false">http://dnaber.de/?p=1567</guid>
		<description><![CDATA[Verlass dich auf Annahmen und du bist verlassen.]]></description>
			<content:encoded><![CDATA[<p>Denkste. Hier hat sich für ein paar Tage der Fehlerteufel eingeschlichen. Und er wäre noch immer drin, hätte mich <a href="http://toscho.de/">Toscho</a> nicht darauf aufmerksam gemacht. In einem neuen <a href="https://github.com/dnaber-de/WP-Colored-Coding">Plugin</a>, dass ich hier gerade teste, soll möglichst flexibel aber sparsam mit externen Javascripts gearbeitet werden. WordPress handhabt das im Kern mit dem globalen Objekt <code>$wp_scripts</code>. Dessen Eigenschaft <code>queue</code> enthält alle registrierten, noch nicht im Template ausgespuckten Scripte. Ein blindes darauf-zugreifen führt dann zwangsläufig zum Crash, wenn das globale Objekt gar nicht gesetzt ist. Genau das ist – logischer weise – im <a href="/feed/">Feed</a> der Fall. Außer man ist angemeldet, dann schlummert in jener Eigenschaft das Script für die Adminbar. Auch im Feed.</p>
<p>Fazit: man sollte auch den eigenen Feed in irgend einem Reader haben und wenn man sich von den API-Funktionen von WordPress löst, lieber einmal öfter die benutzen Globalen prüfen. Und testen, testen, testen.</p>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2012/wo-wp-scripts-drauf-steht-ist-wp-scripts-drin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress: get_terms(), sortiert nach &#8216;description&#8217;</title>
		<link>http://dnaber.de/blog/2012/wordpress-get-terms-sortiert-nach-description/</link>
		<comments>http://dnaber.de/blog/2012/wordpress-get-terms-sortiert-nach-description/#comments</comments>
		<pubDate>Sun, 13 May 2012 16:21:37 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>

		<guid isPermaLink="false">http://dnaber.de/?p=1556</guid>
		<description><![CDATA[Wie man Taxonomie-Begriffe nach dem Beschreibungstext sortiert.]]></description>
			<content:encoded><![CDATA[<p>Die Funktion <code>get_terms()</code> nimmt einiges an Parametern in Form eines Arrays entgegen, so auch einen der bestimmt, nach welchem Attribut sortiert werden soll – leider akzeptiert WP keinen Wert um nach der Beschreibung der Begriffe zu sortieren. Zum Glück wird dieser Teil des SQL-Statements auch durch einen Filter geschickt, dieser heißt <code>get_terms_orderby</code> und den kann man dann nutzen. Die Funktionsparameter werden zu einer Datenbankabfrage über die Tabellen <code>wp_terms</code> und <code>wp_term_taxonomy</code> zusammen gefügt. Dabei wird <code>wp_terms</code> der Alias <code>t</code> und <code>wp_term_taxonomy</code> der Alias <code>tt</code> zugewiesen. Die Beschreibung der Begriffe ist in der Tabelle<code> wp_term_taxonomy</code> gespeichert, die Spalte nach der sortiert werden soll benennt man also mit <code>tt.description</code> und platziert diese über den Filter an Ort und Stelle. Das geht so lange gut, bis sich das SQL-Schema der Funktion <code>get_terms</code> mal ändert, dann hat man im schlimmsten Fall einen SQL-Fehler produziert. Um sicher zu gehen, dass wenigstens der Alias der entsprechenden Tabelle stimmt, kann man die Spalte für die Anzahl der mit diesem Begriff verknüpften Posts, genannt <code>count</code>, heranziehen, der sich die Tabelle mit der <code>description</code> teilt. Die Sortierung nach der Anzahl wird von Hause aus nämlich unterstützt. Also:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">/**
 * get SQL-clause to 
 * sort by wp_term_taxonomy.description
 * 
 * @param string $orderby
 * @return string
 */
function order_terms_by_desc( $orderby ) {

	return str_replace( &#039;.count&#039;, &#039;.description&#039;, $orderby );
}
</code></pre></div>
<p>Um dann im Theme (oder wo man sonst möchte) diverse Begriffe nach der Beschreibung sortiert zu bekommen, setzt man den Filter vor dem Funktionsaufruf (und nimmt ihn anschließend wieder raus!):</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">add_filter( &#039;get_terms_orderby&#039;, &#039;order_terms_by_desc&#039; );
$terms = get_terms( 
	&#039;eine-taxonomie&#039;,
	array(
		# some parameter
		&#039;orderby&#039; =&gt; &#039;count&#039; # important!
	)
);
remove_filter( &#039;get_terms_orderby&#039;, &#039;order_terms_by_desc&#039; );</code></pre></div>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2012/wordpress-get-terms-sortiert-nach-description/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mit PHP Klassen nach dem nth-child-Prinzip vergeben</title>
		<link>http://dnaber.de/blog/2012/mit-php-klassen-nach-dem-nth-child-prinzip-vergeben/</link>
		<comments>http://dnaber.de/blog/2012/mit-php-klassen-nach-dem-nth-child-prinzip-vergeben/#comments</comments>
		<pubDate>Mon, 07 May 2012 15:37:44 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>

		<guid isPermaLink="false">http://dnaber.de/?p=1541</guid>
		<description><![CDATA[Ein Codeschnipsel für zwischendurch: HTML-Klassen vergeben die den nth-child-Selektor entsprechen.]]></description>
			<content:encoded><![CDATA[<p>Es könnte alles so einfach sein wenn da nicht der IE wäre, der bis einschließlich Version 8 nichts von der CSS Pseudoklasse <code>:nth-child</code> weiß. Ich versuche inzwischen, das weitgehend zu ignorieren solange es sich um Schönheitsfehler handelt und nicht um elementare Gestaltungsprobleme. Für den zweiten Fall habe ich mir eine <a href="https://gist.github.com/2627721">PHP-Klasse</a> geschrieben, die im Template den HTML-Elementen nach der Nth-Child-Syntyx eine Klasse verpasst um diese Elemente mit dem Klassenselektor anzusprechen. Gibt es bestimmt schon in hundert-facher Ausführung, aber ich hatte gerade mal Lust auf ein klein <em>wenig</em> Mathe.</p>
<p>Das ganze funktioniert dann so:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">&lt;?php
# alle außer den ersten 4
$n = new Nth_Child_Class( &#039;-n+4&#039;, &#039;greater-than-four&#039; );
?&gt;
&lt;ul&gt;
&lt;?php for ( $i = 1; $i &lt;= 10; $i++; ) : ?&gt;
	&lt;li class=&quot;&lt;?php $n-&gt;print_class(); ?&gt;&quot;&gt;…&lt;/li&gt;
&lt;?php endfor; ?&gt;
&lt;/ul&gt;</code></pre></div>
<p>Es  lässt sich z.B. auch auf WordPress-Posts anwenden, wenn man die Klasse um zwei Methoden ergänzt:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">/**
 * applied to the wp filter &#039;post_class&#039;
 *
 * @param array $classes
 * @param string $class
 * @param int $post_id
 * @return array
 */
public function wp_get_class( $classes, $class, $post_id ) {

	$nth_class = $this-&gt;get_class();
	if ( &#039;&#039; !== $nth_class )
		$classes[] = $nth_class;

	return $classes;
}

/**
 * clean up
 */
public function __destruct() {
	remove_filter( &#039;post_class&#039;, array( $this, &#039;wp_get_class&#039; ), 10, 3 );
}
</code></pre></div>
<p>und im Constructor den Filter setzt:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">add_filter( &#039;post_class&#039;, array( $this, &#039;wp_get_class&#039; ), 10, 3 );</code></pre></div>
<p>Im Theme wird die Klasse dann vor dem Loop einmal instanziert. Direkt danach räumt man mit <code>unset()</code> auf die Instanzvariable alles sauber auf.</p>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2012/mit-php-klassen-nach-dem-nth-child-prinzip-vergeben/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Erkenntnisse Bloggen 2: Firefox&#8217; magische Paddings auf Listenelementen</title>
		<link>http://dnaber.de/blog/2012/firefox-magische-paddings-auf-listenelemente/</link>
		<comments>http://dnaber.de/blog/2012/firefox-magische-paddings-auf-listenelemente/#comments</comments>
		<pubDate>Mon, 19 Mar 2012 11:50:07 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Firefox]]></category>

		<guid isPermaLink="false">http://dnaber.de/?p=1497</guid>
		<description><![CDATA[… oder warum Reset-Stylesheets tückisch sind.]]></description>
			<content:encoded><![CDATA[<p>Firefox hat – wie ich seit heute weiß – die nette Angewohnheit, Listenelementen einen mysteriösen Innenabstand zu verpassen, wenn man <code>list-style-position</code> auf <code>inside</code> setzt. Auch dann, wenn der <code>list-style-type</code> auf <code>none</code> gesetzt ist. Warum das so ist, kann ich nicht genau sagen, Fakt ist, dass <em>alle</em> anderen bekannten Browser die – meiner Meinung nach – korrekte Darstellung zeigen. Folgendes Beispiel reproduziert das Verhalten: </p>
<div class="wp-cc wp-cc-html"><pre><code data-language="html">&lt;!DOCTYPE html&gt;
	&lt;!--
	  - some strange padding occurs on li-elements in firefox due to
	  - list-style-position: inside
	  --&gt;
&lt;html lang=&quot;en&quot;&gt;
	&lt;meta charset=&quot;utf-8&quot; /&gt;
	&lt;title&gt;Floated list elements&lt;/title&gt;
	&lt;style type=&quot;text/css&quot;&gt;
		* {
			margin: 0;
			padding: 0;
		}
		article {
			width: 50em;
			margin: 10px auto;
			padding: 10px;
			background: #ddd;
		}
		h1, ul {
			float:left;
		}
		ul {
			list-style-type: none;
			list-style-position: inside;
		}
		li {
			float: left;
			outline: 1px solid #000;
			border-right: 1px dotted #f00;
			padding-right: 0;
			margin-right: 0;
		}
		li span {
			background: #aaf;
			padding: 3px;
		}
		p:after {
			content:&quot;.&quot;;
			clear:left;
			display:block;
			wilih:0;
			height:0;
			text-indent: -9999px;
		}
	&lt;/style&gt;
	&lt;article&gt;
		&lt;h1&gt;List-style-possiton&lt;/h1&gt;
		&lt;ul&gt;
			&lt;li&gt;&lt;span&gt;one&lt;/span&gt;&lt;/li&gt;
			&lt;li&gt;&lt;span&gt;two&lt;/span&gt;&lt;/li&gt;
			&lt;li&gt;&lt;span&gt;foo&lt;/span&gt;&lt;/li&gt;
		&lt;/ul&gt;
	&lt;p&gt;Lorem Ipsum&lt;/p&gt;
	&lt;/article&gt;
&lt;/html&gt;	</code></pre></div>
<p>Was würde man in etwa erwarten?<br />
<img class="aligncenter size-full wp-image-1498" title="firefox-floated-lis" src="http://dnaber.de/wp-content/uploads/firefox-floated-lis.png" alt="" width="495" height="56" /><br />
Statt dessen erscheint einen Innenabstand, interessanter weise auf der rechten Seite der einzelnen Listenelemente:</p>
<p><img class="aligncenter size-full wp-image-1499" title="firefox-ghost-padding" src="http://dnaber.de/wp-content/uploads/firefox-ghost-padding.png" alt="" width="504" height="55" /></p>
<p>Danach sucht man gerne mal auch etwas länger. Das <code>float</code> hat dabei übrigens keinen Einfluss auf den mysteriösen Padding, er lässt sich auch nicht mit expliziten Angaben zum Verschwinden überreden. Was hilft ist entweder explizit den <code>list-style-type</code> auf <code>outside</code> zu setzen oder den Listenelementen als Inline-Block Elemente zu formatieren.  Zwar ist <code>outside</code> der Standard, sieht aber im Fließtext hässlich aus und wer verlässt sich schon gern auf Standards?</p>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2012/firefox-magische-paddings-auf-listenelemente/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Erkenntnisse bloggen 1: WordPress Post-GUID sind nicht verlässlich</title>
		<link>http://dnaber.de/blog/2012/erkenntnisse-bloggen-1-wordpress-post-guid-sind-nicht-verlasslich/</link>
		<comments>http://dnaber.de/blog/2012/erkenntnisse-bloggen-1-wordpress-post-guid-sind-nicht-verlasslich/#comments</comments>
		<pubDate>Sun, 12 Feb 2012 18:22:50 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>

		<guid isPermaLink="false">http://dnaber.de/?p=1493</guid>
		<description><![CDATA[Jede noch so banal erscheinende Einsicht ist es wert festgehalten zu werden.]]></description>
			<content:encoded><![CDATA[<p>Gerade habe ich mit <a href="http://toscho.de">Toscho</a> in einem kurzen Chat über die <a href="http://de.wikipedia.org/wiki/Globally_Unique_Identifier">GUIDs</a> in WordPress gesprochen und festgestellt, dass diese nicht immer so verlässlich sind, wie ich anfangs dachte. Darauf meinte er, dass solche Ensichten eigentlich gleich gebloggt werden müssen. Recht hat er.</p>
<p>Eine GUID ist eigentlich eine global eindeutige ID. Die WordPress GUID, die in der Posts-Tabelle ein eigenes Feld hat ist in aller Regel der Permalink zum Zeitpunkt an dem das Post angelegt wird und ändert sich nicht &#8211; theoretisch. Global bezieht sich hier auf den Blog, bzw. auf das Blognetzwerk einer Multisite-Umgebung. Für meine Zwecke reichte das.</p>
<p>Nun fristet die Post-GUID eher ein Nieschendasein (mir ist sie noch nie begegnet, entdeckt habe ich sie eher zufällig) und, so meint Toscho, wenn sie mal zu einer echten GUID mausert, dann war&#8217;s dass mit der Konsistenz der Daten, wenn man auf die GUID als Verknüpfung gesetzt hat. In meinem Fall hat dem entsprechend beim Import niemand an die GUID gedacht. In Zukunft werde ich gleich lieber ein Post-Meta mehr nehmen als an der falschen stelle zu sparen. Sogesehen kann ich froh sein, dass der große Chrash ausgeblieben ist und das Problem noch vor dem Release aufgefallen ist.</p>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2012/erkenntnisse-bloggen-1-wordpress-post-guid-sind-nicht-verlasslich/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>WordPress: TinyMCE Plugin mit Dialogbox</title>
		<link>http://dnaber.de/blog/2012/wordpress-tinymce-plugin-mit-dialogbox/</link>
		<comments>http://dnaber.de/blog/2012/wordpress-tinymce-plugin-mit-dialogbox/#comments</comments>
		<pubDate>Tue, 24 Jan 2012 09:51:45 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>

		<guid isPermaLink="false">http://dnaber.de/?p=1477</guid>
		<description><![CDATA[Tutorial zu den Grundlagen eines Dialogfensters in TinyMCE und Wordpress.]]></description>
			<content:encoded><![CDATA[<p class="remark">In diesem Beitrag zeige ich <em>eine</em> Möglichkeit, wie man den WordPress-standardeditor TinyMCE um einen Button erweitert der eine beliebig komplexes Dialogfenster öffnet mit dem man mit den gewohnten APIs auf die WordPressumgebung zugreifen kann. Sämtliche <a href="https://gist.github.com/1658122">Codebeispiele</a> sind als Gist direkt zu sehen.</p>
<p>Das Tutorial beschreibt ein erdachtes WordPress-Plugin mit folgender Verzeichnisstruktur:</p>
<div class="wp-cc"><pre><code data-language="">my-plugin/
	i18n/
		mce_locale.php
	js/
		editor_plugin.js
	my_plugin.php</code></pre></div>
<h3>TinyMCE</h3>
<p>Ein TinyMCE-Plugin ist wie <a href="http://www.tinymce.com/wiki.php/Creating_a_plugin">Folgt aufgebaut</a>:</p>
<p>Sämtliche Plugin-Dateien sind in einem eigenen Verzeichnis zusammengefasst. In der <code>editor_plugin.js</code> wird das Plugin initialisiert:</p>
<div class="wp-cc wp-cc-javascript"><pre><code data-language="javascript">// js/editor_plugin.js
/**
 * an example tinyMCE Plugin
 */
tinymce.create(
	&#039;tinymce.plugins.myPlugin&#039;,
	{
		/**
		 * @param tinymce.Editor editor
		 * @param string url
		 */
		init : function( editor, url ) {
			/**
			 * register a new button
			 */
			editor.addButton(
				&#039;my_plugin_button&#039;,
				{
					cmd : &#039;my_plugin_button_cmd&#039;,
					title : editor.getLang( &#039;myPlugin.buttonTitle&#039;, &#039;My Button&#039; ),
					image : url + &#039;/img/example.gif&#039;
				}
			);
			/**
		 	* and a new command
		 	*/
			editor.addCommand(
				&#039;my_plugin_cmd&#039;,
				function() {
					/**
					* @link http://www.tinymce.com/wiki.php/API3:method.tinymce.WindowManager.open
					* @param Object Popup settings
					* @param Object Arguments to pass to the Popup
					*/
					editor.windowManager.open(
						{
							file : url + &#039;/dialog.htm&#039;,
							width : 320,
							height : 120,
							inline : 1
						},
						{
							plugin_url : url,
							some_custom_arg : &#039;custom value&#039;
						}
					);
				}
			);
		}
	}
);
// register plugin
tinymce.PluginManager.add( &#039;myPlugin&#039;, tinymce.plugins.myPlugin );</code></pre></div>
<p>(Das ist der Standard von TinyMCE, die Datei kann natürlich auch anders heißen). Dafür wird der Methode <code>tinymce.create()</code> neben dem Namen des Plugin-Objekts an zweiter Stelle ein Objekt übergeben, welches u.A. die Methode <code>init</code> definiert. Diese akzeptiert wiederum zwei Parameter: das Objekt des Editorfensters und die URL zum Pluginverzeichnis. Mit dem <a href="http://www.tinymce.com/wiki.php/API3:class.tinymce.Editor">Editor-Objekt</a> und dessen Methoden kann man sich in die Funktionalität von TinyMCE einklinken und z.B. einen Button registrieren, ein Kommando definieren, dass beim Klick auf den Button zur Ausführung kommt und so fort. Über die Methode <code>editor.getLang()</code> kommt man an die übersetzten Textbausteine heran. Dazu später mehr. Um nun ein Dialog mit mehreren Eingabemöglichkeiten zu öffnen, geht TinyMCE den Weg über eine externe HTML-Datei die es in einem Inline-Frame öffnet. Das ist in sofern von Nachteil, da in diesem Kontext nur schwerlich an die WordPress API heranzukommen ist. Von der umständlichen Handhabung, das Fenster so zu stylen, dass es im WordPress-Look daher kommt mal ganz abgesehen.</p>
<p>WordPress bietet eine andere Option an: Das Markup (in den meisten Fällen ein HTML-Formular) für das Dialogfenster wird einfach über den Hook <code>wp_footer</code> in die Seite eingesetzt und per CSS ausgeblendet.</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php"># somewhere in my_plugin.php
if ( is_admin() ) {
	/**
	 * hook in only, if current user can
	 * see the editor and want to have
	 * a rich text editor
	 */
	if (
	    (    current_user_can( &#039;edit_posts&#039; )
          || current_user_can( &#039;edit_pages&#039; ) 
	    )
	    &amp;&amp; &#039;true&#039; == get_user_option( &#039;rich_editing&#039; )
	) {
		add_action( &#039;wp_footer&#039;, &#039;my_plugin_dialog&#039; );
	}
}

function my_plugin_dialog() { 
	?&gt;
	&lt;div style=&quot;display:none;&quot;&gt;
		&lt;form id=&quot;my_plugin_dialog&quot; tabindex=&quot;-1&quot; action=&quot;&quot;&gt;
			&lt;div&gt;
				&lt;input type=&quot;text&quot; name=&quot;foo&quot; /&gt;
			&lt;/div&gt;
			&lt;div&gt;
				&lt;input type=&quot;submit&quot; class=&quot;button-primary&quot; value=&quot;Go&quot; /&gt;
			&lt;/div&gt;
		&lt;/form&gt;
	&lt;/div&gt;
	&lt;?php
}

</code></pre></div>
<p>Die Funktionalität des Popups stellt das WP-Interne TinyMCE-Plugin »WP-Dialog« zur Verfügung. Der Methode <code>editor.windowManager.open</code> wird anstelle eines Pfads zum Popup einfach die ID des Formulars übergeben. Das ganze an ein Befehl gebunden, der wiederum an einen neuen Button gebunden wird, öffnet das Fenster beim Klick auf selbigen.</p>
<div class="wp-cc wp-cc-javascript"><pre><code data-language="javascript">// js/editor_plugin.js
/**
 * somewhere in the init-method
 * of the parameter object at
 * tinymce.create()...
 *
 * this requires the mce plugin WPDialog
 */
editor.addCommand(
	&#039;my_plugin_button_cmd&#039;,
	function() {
		/**
		 * @param Object Popup settings
		 * @param Object Arguments to pass to the Popup
		 */
		editor.windowManager.open(
			{
				 // this is the ID of the popups parent element
				 id : &#039;my_plugin_dialog&#039;,
				 width : 480,
				 title : editor.getLang( &#039;myPlugin.popupTitle&#039;, &#039;Default Title&#039; )
				 height : &#039;auto&#039;,
				 wpDialog : true,
			},
			{
				plugin_url : url
			}
    	);
	}
);</code></pre></div>
<h3>WordPress</h3>
<p>WordPress kümmert sich dankenswerter Weise um die Integration des Plugins in TinyMCE. Dazu sind die Filter <code>mce_external_plugins</code> für das Plugin-Script und <code>mce_buttons</code> für den Button bereit gestellt. Beide Filter werden auf je ein Array angewendet, dass erweitert zurück gegeben wird. Um etwas Abstand zwischen die Buttons zu bekommen, setzt man als ein Array-Element einen senkrechten Stricht <code>'|'</code>.</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php"># somewhere in my_plugin.php
add_filter( &#039;mce_external_plugins&#039;, &#039;register_my_tinymce_plugin&#039; );
add_filter( &#039;mce_buttons&#039;, &#039;register_my_tinymce_button&#039; );

/**
 * register_my_tinymce_plugin
 *
 * @param array $mce_plugins
 * @return array $mce_plugins
 */
function register_my_tinymce_plugin( $mce_plugins ) {
	$mce_plugins[ &#039;myPlugin&#039; ] = plugins_url() . &#039;/my-plugin/js/editor_plugin.js&#039;;

	return $mce_plugins;
}

/**
 * register_my_tinymce_button
 *
 * @param array $buttons
 * @return array $buttons
 */
function register_my_tinymce_button( $buttons ) {
	array_push( $buttons, &#039;|&#039;, &#039;my_plugin_button&#039; );

	return $buttons;
}

</code></pre></div>
<p>Dynamik in den Dialog bekommt man wie gewohnt über ein JavaScript, dass mit der Funktion <a href="http://codex.wordpress.org/Function_Reference/wp_enqueue_script"><code>wp_enqueue_script()</code></a> geladen wird. Innerhalb dieses Scripts kommt man über das globale JavaScript-Objekt <code>tinyMCEPopup</code> an den Editor bzw. mit <code>edCanvas</code> an die Textarea im HTML-Modus heran. Zu beachten ist, dass <code>tinyMCEPopup</code> zum Zeitpunkt des jQuery-eigenen Events <em>ready</em> nocht nicht verfügbar ist.</p>
<h3>i18n</h3>
<p>Um innerhalb des TinyMCE Plugins lokalisierbare Strings zu nutzen, bedarf es einer weiteren PHP-Datei, die über den Filter <code>mce_external_languages</code> geladen wird. Genauer gesagt loopt WordPress über mehrere solche Dateien und erweitert dabei einen String, der die entsprechenden Textausteine enthält, die in bekannter Weise übersetzt werden können. Der String selbst ist JavaScript-Code, der die Methode <code>tinymce.addI18n()</code> aufruft. Über den hier definierten Namensraum sind die Textbausteine dann verfügbar.</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">&lt;?php
# i18n/mce_locale.php
/**
 * @var string $strings a JavaScript snippet to add another language pack to TinyMCE
 * @var string $mce_locale an ISO 639-1 formated string of the current language e.g. en, de...
 * @deprecated wp_tiny_mce() at wp-admin/includes/post.php (for versions prior WP 3.3)
 * @see _WP_Editors::editor_settings in wp-includes/class-wp-editor.php
 */
$strings =
	&#039;tinyMCE.addI18n(
		&quot;&#039; . $mce_locale . &#039;.myPlugin&quot;,
		{
			buttonTitle : &quot;&#039; . esc_js( __( &#039;My Button Title:&#039;, &#039;my_textdomain&#039; ) ) . &#039;&quot;,
			popupTitle  : &quot;&#039; . esc_js( __( &#039;My Popup Title&#039;, &#039;my_textdomain&#039; ) ) . &#039;&quot;,
		}
	);&#039;;</code></pre></div>
<p>Das Laden übernimmt wieder WordPress:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">&lt;?php
# somewhere in my_plugin.php
# remember to load the plugin textdomain!
add_filter( &#039;mce_external_languages&#039;, &#039;my_mce_localisation&#039; );

/**
 * my_mce_localisation
 *
 * @see wp-admin/includes/post.php line 1474
 * @param array $mce_external_languages
 * @return array $mce_external_languages
 */
function my_mce_localisation( $mce_external_languages ) {
	$mce_external_languages[ &#039;myPlugin&#039; ] = plugin_dir_path( __FILE__ ) . &#039;i18n/mce_locale.php&#039;;

	return $mce_external_languages;
}</code></pre></div>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2012/wordpress-tinymce-plugin-mit-dialogbox/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Und alle so: px oder em – oder rem?</title>
		<link>http://dnaber.de/blog/2011/und-alle-so-px-oder-em-oder-rem/</link>
		<comments>http://dnaber.de/blog/2011/und-alle-so-px-oder-em-oder-rem/#comments</comments>
		<pubDate>Mon, 02 May 2011 16:08:37 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>

		<guid isPermaLink="false">http://dnaber.de/?p=1437</guid>
		<description><![CDATA[Mein wirklich allerletzter Beitrag zur leidigen em vs px Disskusion.]]></description>
			<content:encoded><![CDATA[<p>Es vergeht wohl kein Tag, an dem ich nicht einem zerstörten Weblayout begegne oder seufze, weil die Schrift wieder mal viel zu klein ist um sie vernünftig lesen zu können. Eigentlich habe ich mich zu der Problematik schon <a href="http://dnaber.de/blog/2009/schriftgroesse-in-px-oder-em/">ausführlich geäußert</a> und in den anderthalb Jahren hat sich die Lage auch nicht groß verändert, wenn, dann eher ins Negative. Da taucht ein Silberstreif am <abbr title="Cascading Stylesheets 3">CSS3</abbr>-Horizont auf, wie ich gerade durch den Artikel <a href="http://snook.ca/archives/html_and_css/font-size-with-rem">„Font sizing with <code>rem</code>“</a> erfahre.</p>
<p>Jonathan Snook reduziert das Problem der Einheit <code>px</code>, wie häufig in dieser Diskussion, auf den InternetExplorer. An der Einheit em stört ihn die Ungenauigkeit und die Vererbbarkeit. Ersteres ist leider nich einmal das Hauptproblem und Letztere <em>kann</em> man als Probleme sehen.</p>
<p>Absolut jeder Browser, nicht nur der <abbr title="Internet Explorer">IE</abbr>, stellt die Schrift in der Größe dar, in der sie <em>in <code>px</code> bemaßt</em> ist. Ebenfalls in jedem Browser ist die Möglichkeit gegeben, eine Schriftgröße einzustellen, die den persönlichen Gegebenheiten Rechnung trägt – das müssen noch nicht mal körperliche Einschränkungen sein, es reicht <abbr title="zum Beispiel">z.B.</abbr> ein 15&#8243;-Bildschirm mit einer hohen relativen Auflösung zu nutzen. Zugegeben, diese Möglichkeit wird wahrscheinlich eher selten genutz, aber wer nutzt sie denn? Jemand, der sich nicht jedesmal auf&#8217;s Neue den Text zurechtzoomen möchte. Muss er aber, wenn die Schriften mal wieder in <code>px</code> bemaßt sind! Einziger Ausweg ist, die Mindestschriftgröße (die in vielen Browsern ab Werk nicht gesetzt &#8211; also null &#8211; ist) auf einen erträglichen Wert herauf zu setzen. Die (bedauernswert häufige) Folge: zerschossene Layouts oder Text, der im Nirgendwo verschwindet. „Barrierefreies Webdesign? &#8211; Noch nie gehört!“</p>
<p>Die bessere Alternative zu <code>px</code> heißt <code>em</code>. Diese bedarf allerdings im Einsatz etwas mehr der Vorüberlegung. Unachtsam auf ein Element wie <code>ul</code> angewendet, führt eine Verschachtelung zu einer Multiplikation der relativen Schriftgrößenwerte. Für eine konsistente Schriftgößengestaltung würde man also darauf verzichten einzelne Textbausteine wie Absätze oder Listen mit Schriftgrößen zu versehen sondern ganze Inhaltsbereiche wie Navi oder die Sidebar. Wem das zu kompliziert ist, der darf auf <abbr title="Cascading Stylesheets 3">CSS3 </abbr>hoffen, dass mit <a href="http://www.w3.org/TR/css3-values/#relative0"><code>rem</code> eine Einheit einführt</a>, die sich auf das Wurzelelement bezieht und somit das Verschachtelungs-„problem“ umgeht.</p>
<p>Bleibt noch die Ungenauigkeit die <code>em</code>, bzw. auch <code>rem</code> als Nachteil ausgelegt wird. Jonathan fängt an rumzurechnen: auf Basis der Standardschriftgröße (in den meisten Fällen 16) versucht er, das Verhältniss 10:1 für <code>px</code>:<code>em</code> in der Darstellung zu erreichen und kommt auf einen Umrechnungsfaktor von 62,5%. Wem die Zahl bekannt vorkommt: Diese <a href="http://toscho.de/2009/mythos-font-size-62dot5-prozent/">Idee war schon vor über 5 Jahren schlecht</a> und sie ist es noch heute, denn es läuft auf das selbe Problem hinaus: die Ignorierung der Schriftgröße im Browser. Diese um über ein Drittel zu reduzieren nötigt Betroffene einmal mehr zur Mindestschriftgröße zu greifen. Schade eigentlich.</p>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2011/und-alle-so-px-oder-em-oder-rem/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Navigationsmenüs unter WordPress</title>
		<link>http://dnaber.de/blog/2010/navigationsmenus-unter-wordpress/</link>
		<comments>http://dnaber.de/blog/2010/navigationsmenus-unter-wordpress/#comments</comments>
		<pubDate>Tue, 16 Nov 2010 15:46:42 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>

		<guid isPermaLink="false">http://dnaber.de/?p=1292</guid>
		<description><![CDATA[Ein kleines Plugin und zwei Kniffe für schlankes und semantisches HTML der Navigations-Menüs von WordPress 3.0.]]></description>
			<content:encoded><![CDATA[<p>Mit der Version 3 von WordPress kam ein ziemlich cooles Feature hinzu, welches einem gerade auf nicht-nur-Blog-Seiten sehr gelegen kam: die „Nav-Menus“ oder: die Möglichkeit die Navigation aus dem Backend zu steuern. Endlich muss ich nicht mehr in den Templates rumschreiben, wenn ich die Navigation ändern will. Die dazu passende Template-Funktion heißst <a href="http://codex.wordpress.org/Function_Reference/wp_nav_menu"><code>wp_nav_menus()</code></a>, wird im Header- oder Sidebar-Template (oder wo man es halt möchte) untergebracht und nimmt wie gewohnt einige Parameter in Form einens Arrays entgegen um z.B. HTML-Attribute wie Titel, ID und Klassen zu vergeben. Das role-Attribut ist leider nicht vorgesehen. Ich wollte schon nach den passenden Filtern suchen, um dieses Attribut mit einfügen zu können, als ich spaßeshalber folgendes probierte:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">wp_nav_menu ( 
	array (
		&#039;menu&#039;       =&gt;; &#039;main_navigation&#039;,
		&#039;container&#039;  =&gt;; &#039;&#039;,
		# Seit Version 3.1 geht das hier nicht mehr, Nachtrag beachten!
		&#039;menu_id&#039;    =&gt;; &#039;navigation&quot; role=&quot;navigation&#039;,
		&#039;menu_class&#039; =&gt;; &#039;&#039;
	)
);</code></pre></div>
<p>Zu meinem Erstaunen funktioniert das so einwandfrei. Ich kann mir zwar kaum vorstellen, dass das so gewollt ist und dauerhaft funktionieren wird, aber wenn es so einfach ist, braucht es vorerst keinen zusätzlichen Filter. (Zur Erläuterung: die Funktion zeigt das Menü mit dem Namen „main_navigation“ ohne umschließendes Element und ohne eine Klasse an, allerdings mit dem ID-Wert: <code>navigation" role="navigation</code> woraus der Quelltext<br />
<code><br />
&lt;ul id=&quot;navigation&quot; role=&quot;navigation&quot;&gt;&#038;lt/ul&gt;<br />
</code><br />
 resultiert.) Der Wert wird also ungefiltert übernommen, also aufpassen, was man reinschreibt.</p>
<p><strong>Nachtrag:</strong></p>
<p>Achtung! Spätestens seit Version 3.1 funktioniert das nicht mehr (wahr auch zu erwarten). Hier kann man zu folgender kurzer Funktion greifen, die man in den Filter <code>wp_nav_menu</code> einhängt:<br />
<div class="wp-cc wp-cc-php"><pre><code data-language="php">/**
 * fügt ein role-Attribut mit dem Wert &#039;navigation&#039;
 * dem Ersten öffnenden HTML-Tag von $a
 * hinzu
 */
function mytheme_add_nav_role( $a ) {

    $a = preg_replace(
		&#039;#^\s*&lt;([a-z]+)([^&gt;]*)&gt;#i&#039;,
		&#039;&lt;${1}${2} role=&quot;navigation&quot;&gt;&#039;,
		$a
	);

    return $a;
}
add_filter( &#039;wp_nav_menu&#039;, &#039;mytheme_add_nav_role&#039; );</code></pre></div></p>
<h3>Seitenauswahl einrücken</h3>
<p>Jetzt aber ab ins Backend und das Menü anlegen um zu sehen, wie das funktioniert. In den meisten Fällen wird die Navigation sicher die Stuktur der angelegten Seiten abbilden. Warum die Seiten also nicht in ihrer hirarchischen Anordnung sondern in einer einfachen Liste, ihrem Titel nach sortiert, dargestellt werden, ist mir ein Räzel. Spätestens wenn die Seiten nicht mehr allein durch ihren Titel sondern durch die Beziehung zu anderen Seiten identifizierbar sind, steht man vor einem echten Problem.</p>
<p><img class="size-full wp-image-1296 alignnone" title="Unsortiertes Durcheinander" src="http://dnaber.de/wp-content/uploads/nav-menu-checklist.jpg" alt="" width="309" height="404" /></p>
<p>Dabei ist der Core-Code nur eine Zeile von der Lösung entfernt. Da in diesen untiefen des WordPress-Codes keine Möglichkeit besteht über die Plugin-API einzugreifen, habe ich die entsprechende Funktion und eine Klasse kurzerhand in einem Plugin geklont. Jetzt existiert eine weitere Metabox in der das Chaos weitgehend gebannt ist.</p>
<p><img class="size-full wp-image-1299 alignnone" title="Seiten in Baumstruktur" src="http://dnaber.de/wp-content/uploads/nav-menu-page-tree.jpg" alt="" width="291" height="392" /></p>
<p>Das Plugin trägt den schönen Namen „nav-menu-page-tree“ und kann hier herunter geladen werden:</p>
<p style="text-align: center;"><del><a title="Plugin obsolet, Nachtrag beachten!"class="download-link" href="http://dnaber.de/tools/plugins/nav-menu-page-tree.zip">nav-menu-page-tree.zip</a></del>.</p>
<p><strong>Nachtrag</strong><br />
<em>Mit Version 3.2 werden die existierenden Seiten von WordPress selbst auch hirarchisch geordnet dargestellt, womit das Plugin obsolet geworden ist</em>.</p>
<h3>Markup aufräumen</h3>
<p>Das durch <code>wp_nav_menus()</code> erzeugte Markup der Navigation im Frontend ist gewohnt tadellos, allerdings reichlich überladen. Jedes Listenelement hat eine ID und mehrere Klassen. Darauf kann ich getrost verzichten. Im Falle der ID geht das ganz unkompliziert mit folgendem Filter:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">add_filter( &#039;nav_menu_item_id&#039;, create_function( &#039;$a&#039;, &#039; return &quot;&quot;; &#039;) );</code></pre></div>
<p>Bevor Worpress das ID-Attribut in den Quelltext einfügt, wird geprüft, ob der Wert überhaupt existiert. Wir haben ihn hier gerade gelöscht. Bei den Klassen funktioniert das seltsamer weise nicht. Nachdem ein Filter die Klassen mit einem leeren String überschrieben hat, müssen vor der Ausgabe des Markups die leeren Attribute entfernt werden:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">add_filter( &#039;nav_menu_css_class&#039;, create_function( &#039;$a&#039;,&#039; return array();&#039; ) );
add_filter( &#039;wp_nav_menu&#039;, create_function( &#039;$a&#039;, &#039;return str_replace( &quot; class=\&quot;\&quot;&quot;,&quot;&quot;, $a );&#039; ) );</code></pre></div>
<p>Diese zwei Maßnahmen sparen unter Umständen einen ganze Menge Quelltext. Man kann sich jetzt drüber streiten, ob die Einsparung der Datenmenge die längere Scriptlaufzeit aufhebt, aber als Freund sauberen Quellcodes ist mir das allemal lieber.</p>
<p>Die Funktion <code>wp_nav_menus()</code> schicke ich in den Templates überdies noch durch Thomas&#8217; Funktion <a href="http://toscho.de/2009/deppenlink-entfernen/#toc-alte-version"><code>remove_self_links()</code></a> um Links zu entfernen die auf die aktuell angezeigte Seite zeigen. Das klappt hoffentlich auch irgendwann mal von Hause aus.</p>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2010/navigationsmenus-unter-wordpress/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Kampf dem Spam</title>
		<link>http://dnaber.de/blog/2010/kampf-dem-spam/</link>
		<comments>http://dnaber.de/blog/2010/kampf-dem-spam/#comments</comments>
		<pubDate>Mon, 19 Apr 2010 14:07:44 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>

		<guid isPermaLink="false">http://dnaber.de/?p=1201</guid>
		<description><![CDATA[Wie ich automatisiertem Spam begegne und warum ich dazu keine <abbr title="Completely Automated Public Turing test to tell Computers and Humans Apart" lang="en">CAPTCHAS</abbr> und keine zentralen schwarzen Listen benutze.]]></description>
			<content:encoded><![CDATA[<p>Was unterscheidet eine Maschine vom Menschen? Scheinbar ist die Antwort schnell gefunden: der Eine kann Gefühle empfinden, der Andere nicht, der Andere ist dumm der Eine… lassen wir das. Leider ist diese Frage, gerade wenn es darum geht Besucher einer Website von einem automatisierten Programm – einem Bot – zu unterscheiden, alles andere als leicht zu beantworten. Das wird einem spätestens dann leidlich bewusst, wenn man z.B. ein Kontaktformular oder Blog mit Kommentarfunktion ins Internet stellt. Früher oder später kommen E-Mails bzw. Kommentare herein, die so gar nicht zum Thema passen, wenn sie denn überhaupt sprachliche Inhalte und nicht nur unzählige Links und Kauderwelsch enthalten. Je populärer dabei das eingesetzte System (z.B. WordPress) desto mehr scheint man im Fokus der Spammer zu liegen. Es muss heutzutage Kinderleicht sein, Bots zu programmieren, die auf ihrem Streifzug durch das Netz sämtliche Formulare mit Links zu Glücksspielseiten und Blauen-Pillen-Händlern zupflastern. Es wäre wohl zu viel verlangt, würden diese Programme ihre Intention in die Browserkennung schreiben. Also müssen andere Möglichkeiten gefunden werden, um dem Spam Herr zu werden.</p>
<h3><abbr title="Completely Automated Public Turing test to tell Computers and Humans Apart" lang="en">CAPTCHAS</abbr></h3>
<div id="attachment_1225" class="wp-caption aligncenter" style="width: 323px"><img class="size-full wp-image-1225" title="Ein unleserliches Captcha" src="http://dnaber.de/wp-content/uploads/captcha.jpg" alt="" width="313" height="126" /><p class="wp-caption-text">Wer kann&#39;s lesen?</p></div>
<p>Die wohl zuverlässigste Methode um Spam-Bots zu behindern und echte Besucher auf lange Zeit zu vergraulen nennt sich <a href="http://de.wikipedia.org/wiki/CAPTCHA"><abbr title="Completely Automated Public Turing test to tell Computers and Humans Apart" lang="en">CAPTCHA</abbr></a>. Eine in eine Grafik eingebettete Zeichenfolge soll vom Benutzer erkannt und in ein Feld eingegeben werden. Der Vorteil dieser leider sehr verbreiteten Methode besteht lediglich darin, dass der Seitenbetreiber diesen Schutz sehr schnell in seine Seite integrieren kann. Aus der großen Popularität resultiert aber eben auch eine zunehmende Zahl an Programmen, die diese Bilder auf unterschiedlichen Wegen entschlüsseln oder umgehen können. Unnötig zu erwähnen, dass solche Lösungen nicht nur Barrieren aufbauen, sondern auch nerven. Nur wenig besser (aus Sicht der Zugänglichkeit) sind in Klartext formulierte Logikfragen oder Rechenaufgaben, deren Antwort in ein Feld geschrieben wird. (»Warum muss ich hier eingeben, wieviel Beine ein vierbeiniger Tisch hat?«)</p>
<p>Ich halte prinzipiell von Methoden Abstand, in denen sich der Benutzer als Mensch beweisen muss. Die eingangs gestellte Frage sollte man auch so stellen und nicht anders herum!</p>
<h3>(Zentrale) schwarze Listen</h3>
<p>Ein anderer Ansatz zur automatischen Erkennung von unerwünschtem Spam ist das Anlegen schwarzer Listen um bestimmte Regelmäßigkeiten in Spamkommentaren zu dokumentieren und jeden Kommentar gegen diese Listen abgleichen. Je größer dabei die betrachtete Menge der Kommentare, desto genauer und umfangreicher werden solche Listen. Zentrale Filterangebote wie <a href="http://de.wikipedia.org/wiki/Akismet">Akismet</a> werten alle Kommentare der teilnehmenden Websites aus und erstellen so effektive Filter, von denen alle Teilnehmer profitieren. Doch ist mir bei diesem Gedanken etwas unwohl, da die Formulardaten erstmal eine Reise um die halbe Welt antreten um durch die zentralen Server des Unternehmens zu laufen. Dazu kommt, dass nicht behobene falsch-positive Spamerkennungen einen unbedarften Kommentator gleich auf unzähligen anderen Websites ausschließt.</p>
<p>So effektiv und komfortabel Akismet auch sein mag, hier kommt es vorerst nicht zum Einsatz.</p>
<h3>Handarbeit</h3>
<p>Vorgefertigte Lösungen wie CAPTCHA-Dienste oder Akismet bedienen auch eines: die Bequemlichkeit dauergestresster Webmaster. Allerdings sind beide Lösungen nervig und/oder datenschutzrechtlich zumindest bedenklich. Dennoch habe ich keine Lust täglich zig Spamkommentare zu löschen. Also habe ich mir mit etwas Handarbeit ein eigenes Plugins gezimmert, in dem ich unterschiedliche Methoden zur Erkennung von Bots anwende. Dabei gehe ich von selbst aufgestellten, oder allgemein bekannten Thesen aus um daraus Filtermethoden abzuleiten.</p>
<ol>
<li>
<h4>Bots sind dumm</h4>
<p>oder zumindest häufig auf populäre Systeme zugeschnitten. Bei komplexeren Formularen mit mehreren obligatorischen Angaben kann eine Kontrolle der einzelnen Angaben auf Korrektheit schon eine menge Unsinn abfangen. Allerdings sollte man die Filter nicht zu streng auslegen. Eine URL muss nicht zwangsläufig mit ›http://‹ beginnen. Ein Name hingegen endet nur äußerst selten auf ›/index.html‹. Fakultative Felder sollten leer bleiben (Spambots können sich oftmals nur schwer bremsen und füllen gerne alles aus), oder eben den Ansprüchen der Logik genügen: Buchstaben z.B. haben in einer Telefonnummer oder Postleitzahl nichts zu suchen. Wem das zu heikel ist, der sucht nach bestimmten Zeichenketten (›http://‹), man kann sich ja mal vertippen.</p>
<p>Auf vielen WordPress-basierten Seiten ist die Angabe eines Namens und der E-Mailadresse gefordert, wenn man einen Kommentar hinterlassen will. Wahrscheinlich können die Spamprogramme deshalb die Namens-Attribute der Input-Felder lesen. Wir machen es ihnen aber auch einfach: geschätzte 99,9% aller WordPress-Installationen verwenden für die Namens-Attribute ›author‹, ›email‹, ›url‹ und ›comment‹. Ich habe nicht schlecht gestaunt, als das Spamaufkommen hier um gut 90% zurückging, nur weil ich diese Attributwerte durch zufällig generierte Zeichenketten wie ›df4928j‹ ersetzt habe. Die Bots hier verstehen offenbar noch keine Labels.</li>
<li>
<h4>Bots sind schnell</h4>
<p>Auf dieser Seite beträgt die Zeitspanne zwischen Aufruf des Artikels und Eintrag des Kommentars bei automatisiertem Spam im Durchschnitt 2,5 Sekunden. Selbst wenn ein Mensch den gesamten Artikel schon kennt, und einen vorbereiteten Kommentar einfach nur einfügt und absendet, dürfte er bedeutend länger brauchen. Momentan habe ich die Grenze bei 6 Sekunden gesetzt.</li>
<li>
<h4>Bots lesen keine Stylesheets</h4>
<p>Diese Theorie kann man sich zu nutze machen um eine Falle zu platzieren. Ein zufällig platziertes weiteres Formularfeld wird per Stylesheet für alle Parteien aus dem Sichtbereich geschoben bzw. gar nicht mehr angezeigt. Ist das Feld dennoch ausgefüllt, war mit sehr hoher Wahrscheinlichkeit ein Bot am Werk. Wer auf Nummer sicher gehen will, kann hier auch eine Logikfrage platzieren, für den seltenen Fall, dass ein Textbrowser verwendet wird, der kein CSS interpretiert.</li>
</ol>
<p>Die Kombination dieser Methoden klappt momentan so gut, dass ich auf die Angabe von Name und E-Mail inzwischen verzichten kann und Kommentare auch sofort eingetragen werden können, ohne von mir überprüft zu werden. Schlägt einer der Filter an, wird der Kommentar nicht gänzlich gelöscht, sondern nur als Spam markiert. Notfalls hole ich sie von Hand wieder zurück.</p>
<p>Auf statischen Seiten habe ich auf diesem Weg sehr gute Erfahrungen gemacht. Die Umsetzung als WordPress-Plugin ist noch in der Testphase. Wenn irgendwo Probleme beim Kommentieren auftreten, würde ich mich über eine kurze Problembeschreibung per E-Mail sehr freuen.</p>
<p>Mir ist bewusst, dass auf einer vergleichsweise kleinen Seite wie dieser andere Bedingungen herrschen als auf den großen Blogs und dass der Kampf gegen automatisierten Spam wahrscheinlich bis zum jüngsten Tag andauern wird, da sich auch Spambots weiter entwickeln. Solang ich aber mit etwas Handarbeit auf CAPTCHAS und Akismet verzichten kann, werde ich es auch tun.</p>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2010/kampf-dem-spam/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>WordPress: Aufzählung der Kategorien und Tags im Satz</title>
		<link>http://dnaber.de/blog/2010/aufzaehlung-in-ganzen-saetzen/</link>
		<comments>http://dnaber.de/blog/2010/aufzaehlung-in-ganzen-saetzen/#comments</comments>
		<pubDate>Tue, 02 Mar 2010 20:24:54 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Wordpress]]></category>

		<guid isPermaLink="false">http://blog.dnaber.de/?p=1107</guid>
		<description><![CDATA[Durch eine kleine Funktion werden Wordpress-Kategorien und Tags grammatikalisch korrekt durch Kommas und abschließend durch ein „und“ getrennt.]]></description>
			<content:encoded><![CDATA[<p>Die Template-Tags <a href="" rel="external"><code>the_category()</code></a> und <a href="" rel="external"><code>the_tags()</code></a> geben die Kateorien und Stichworte eines Artikels wahlweise als eine ungeordnete Liste, oder durch einen Seperator getrennt aus. Für eine lose Aufzählung wäre ein naheliegendes Trennzeichen das Komma; der Funktionsaufruf dazu schaut so aus: <code>the_tags(', ')</code>.  Das Ergebnis wäre eine Aufzählung aller Stichworte, die durch ein Komma getrennt sind.</p>
<p>Für diesen Beitrag würde das so aussehen: <a href="http://blog.dnaber.de/stichwort/php/" rel="tag">PHP</a>, <a href="http://blog.dnaber.de/stichwort/wordpress/" rel="tag">WordPress</a>. Kurz und knackig, aber ein ordentlicher Satz lässt sich daraus nicht formulieren, dazu fehlt das „und“ zwischen den beiden (letzten) Stichworten.</p>
<p>Um solche Aufzählungen in einen vernünftigen Satz einbinden zu können habe ich mir folgenden Code-Schnipsel in die functions.php des Themes geschrieben:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">/**
 *  Ersetzt das letzte Komma durch ein »und« 
 * 
 * @param string $tags
 * @return string
 */
function mytheme_tag_list( $tags ) {

	# wenn mehr als ein link vorhanden ist
	if ( substr_count( $tags, &#039;&lt;a href=&quot;&#039; ) &gt; 1 ) {
		$pattern = &#039;#&lt;/a&gt;\s*,\s*&lt;a ([^&gt;]*)&gt;([^&lt;]*)&lt;/a&gt;\s?$#&#039;;
		$replace = &#039;&lt;/a&gt; und &lt;a $1&gt;$2&lt;/a&gt;&#039;;
		$tags = preg_replace($pattern,$replace,$tags);
	}

	return $tags;
}
add_filter( &#039;the_category&#039;, &#039;mytheme_tag_list&#039;);
add_filter( &#039;the_tags&#039;, &#039;mytheme_tag_list&#039; );</code></pre></div>
<p>In dieser Form greift der reguläre Ausdruck nur Auflistungen heraus, die durch ein Komma (und evtl. Whitespace) getrennt sind. Aufzählungen ohne oder mit anderen Trennzeichen bleiben unberührt. </p>
<p>Nun kann ich formulieren, dass dieser Beitrag die Themen <a href="http://blog.dnaber.de/stichwort/php/" rel="tag">PHP</a> und <a href="http://blog.dnaber.de/stichwort/wordpress/" rel="tag">WordPress</a> behandelt.</p>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2010/aufzaehlung-in-ganzen-saetzen/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Kontaktformulare ohne Zeichensalat</title>
		<link>http://dnaber.de/blog/2010/kontaktformulare-ohne-zeichensalat/</link>
		<comments>http://dnaber.de/blog/2010/kontaktformulare-ohne-zeichensalat/#comments</comments>
		<pubDate>Wed, 27 Jan 2010 15:55:45 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zeichenkodierung]]></category>

		<guid isPermaLink="false">http://blog.dnaber.de/?p=955</guid>
		<description><![CDATA[Kontaktformulare bereiten nicht selten Probleme mit Umlauten oder Sonderzeichen. Dabei ist die Lösung recht einfach: die verwendete Zeichenkodierung wird in den E-Mail-Header geschrieben.]]></description>
			<content:encoded><![CDATA[<p>Sie sind wohl die am häufigsten anzutreffende Art von Formularen im Web. Man muss kein großer Programmierer sein um selbst ein Kontaktformular zu schreiben, oder man bedient sich der vielen fertigen Skripte, die man im Netz findet. Problematisch wird es, wenn in der E-Mail Umlaute und Sonderzeichen zu kryptischen Zeichen oder fetten Fragezeichen verkommen. Dann liegt ein Verständigungsproblem vor, das aber leicht behoben werden kann.<span id="more-955"></span></p>
<p>Um in PHP eine E-Mail zu versenden reicht theoretisch folgendes Codebeispiel aus:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">mail(
	&#039;mustermann@mail.de&#039;,
	&#039;Urlaubsgrüße&#039;,
	&#039;Hallo Max, Urlaub an der Ostsee ist toll!&#039;
);</code></pre></div>
<p>Der Funktion <a rel="external" href="http://de2.php.net/manual/de/function.mail.php"><code>mail()</code></a> werden drei Parameter übergeben: Empfänger, Betreff und der eigentliche Nachrichtentext. Nun besteht eine E-Mail nicht nur aus diesen drei Informationen. Genauer genommen, setzt sich eine E-Mail, ähnlich wie ein HTML-Dokument aus zwei Teilen zusammen: einem Kopf (Head) und einem Körper (Body). Im Head(er) werden wichtige Informationen über die E-Mail mit gesendet, unter anderem auch die verwendete <a rel="external" href="http://toscho.de/2008/grundlagen-zeichenkodierung/">Zeichenkodierung</a>. Wenn die Zeichenkodierung nicht angegeben wird, muss der Empfänger „raten“, rät er falsch kommt es zur fehlerhaften Darstellung von Umlauten und Sonderzeichen.</p>
<p>Für die Lösung des Problems sind zwei Schritte nötig:</p>
<ol>
<li>muss dafür gesorgt sein, dass die Daten des Formulars in einem bestimmten Zeichenkodierung zum Server gesendet werden und</li>
<li>muss diese Zeichenkodierung in der E-Mail <em>angegeben</em> werden.</li>
</ol>
<h3>Die Zeichenkodierung des Formulars</h3>
<p>Der Inhalt eines HTML-Formulars wird in der Zeichenkodierung gesendet, in der auch das HTML-Dokument an den Browser gesendet wird. Die zuverlässigste Art, den Browser über die Zeichenkodierung zu informieren ist das entsprechende HTTP-Headerfeld „Content-Type“. Auf dem Apache Webserver geht das recht unkompliziert, in dem man im Wurzelverzeichnis seiner Website die .htaccess-Datei um folgende Zeile ergänzt:</p>
<div class="wp-cc"><pre><code data-language="">AddDefaultCharset UTF-8</code></pre></div>
<p>Diese Methode setzt voraus, dass auch alle Text-Dokumente (Skripte, Stylesheets) in dieser Zeichenkodierung vorliegen.</p>
<p>Ob die Zeichenkodierung im HTTP-Header einer Seite gesendet wird, kann man <a rel="external" href="http://web-sniffer.net/">online testen</a>, oder z.B. in Firefox mit <a rel="external" href="https://addons.mozilla.org/en-US/firefox/addon/6647">verschiedenen</a> <a rel="external" href="https://addons.mozilla.org/de/firefox/addon/1843">Plugins</a>.</p>
<p>Darüber hinaus kann es nicht schaden, die Zeichenkodierung zusätzlich als Meta-Element in den Quelltext des HTML-Dokumentes zu übernehmen:</p>
<div class="wp-cc wp-cc-html"><pre><code data-language="html">&lt;meta charset=&quot;utf-8&quot;&gt;</code></pre></div>
<p>Eine weitere Möglichkeit bestünde darin, das Formular um das Attribut „accept-charset“ zu erweitern.</p>
<div class="wp-cc wp-cc-html"><pre><code data-language="html">&lt;form accept-charset=&quot;utf-8&quot;&gt;
	&lt;!-- … --&gt;
&lt;/form&gt;</code></pre></div>
<p>In der Regel reicht es jedoch aus, die Zeichenkodierung im HTTP-Header zu senden.</p>
<h3>E-Mails versenden mit Köpfchen</h3>
<p>Der <a rel="external" href="http://de.wikipedia.org/wiki/Header_%28E-Mail%29">E-Mail Header</a>, den die Funktion <code>mail()</code> generiert umfasst nur die nötigsten Informationen und  kann durch einen weiteren Parameter beeinflusst werden. Dabei werden die einzelnen Feld-Wert-Paare durch einen Zeilenumbruch (\r\n) voneinander getrennt. Die Zeichenkodierung wird im Feld „Content-Type“ angegeben. Mit dem „MIME-Version“ Feld wird gesagt, dass die E-Mail <a rel="external" href="http://de.wikipedia.org/wiki/Multipurpose_Internet_Mail_Extensions">MIME formatiert</a> vorliegt.</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">$email_header  = &quot;MIME-Version: 1.0 \r\n&quot;;
$email_header .= &quot;Content-Type: text/plain;charset=UTF-8 \r\n&quot;;
</code></pre></div>
<p>Die Variable <code>$email_header</code> wird als vierter Parameter der Funktion mail() übergeben:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php"># E-Mail senden
mail( 
	$address,
	$subject,
	$content,
	$email_header
);</code></pre></div>
<p><del>Damit hat sich der Zeichensalat erledigt.</del> So lange im E-Mailheader keine Sonderzeichen vorkommen, sind Unicodezeichen im Text der E-Mail ab jetzt kein Problem mehr. Wenn aber z.B. der Name und die E-Mailadresse des Absenders in den Header aufgenommen werden, oder der Betreff im Kontaktformular vom Benutzer eingegeben werden kann, dann muss man davon ausgehen, das nicht nur ASCII-Zeichen in den Header gelangen. Aber nur diese sind dort erlaubt.</p>
<p>In dem Fall müssen die Zeichenketten für den Header kodiert werden. Dazu gibt es zwei Möglichkeiten: <a rel="external" href="http://de.wikipedia.org/wiki/Base64">Base64</a> und <a rel="external" href="http://de.wikipedia.org/wiki/Quoted-printable">Quoted-printable</a>. Die kodierten Abschnitte werden von der Zeichenfolge <code>=?utf-8?q?</code> eingeleitet und von ?= beendet. Der einleitende Tag gibt die Ursprüngliche Zeichenkodierung (hier UFT-8) und die Kodierungsmethode (q für Quoted-printalbe und b für Base64) an.</p>
<p>Für die Kodierung bedient man sich der PHP-Funktionen <a rel="external" href="http://de2.php.net/manual/de/function.base64-encode.php"><code>base64_encode()</code></a> für Base64 bzw. <a rel="external" href="http://de3.php.net/manual/de/function.imap-8bit.php"><code>imap_8bit()</code></a> oder <a rel="external" href="http://de3.php.net/manual/de/function.quoted-printable-encode.php"><code>quoted_printable_encode()</code></a> für die Quoted-printable Methode. Allerdings ist die <code>Funktion imap_8bit()</code> an die IMAP-Extention geknüpft und <code>quoted_printable_encode()</code> gibt es erst seit PHP Version 5.3.</p>
<p>Der Betreff der E-Mail würde wie folgt kodiert werden:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php"># Zeilenumbrüche haben im Header nix verloren
$subject = str_replace(
	array( &quot;\n&quot;, &quot;\r&quot; ),
	&#039;&#039;,
	$_POST[ &#039;subject&#039; ]
);

# Quoted-printable
$subject = &#039;=?utf-8?q?&#039; . imab_8bit( $subject ) . &#039;?=&#039;;

# alternativ: Base64
$subject = &#039;=?utf-8?b?&#039; . base64_encode( $subject ) . &#039;?=&#039;;

# senden
mail( $address, $subject, $content, $email_header );</code></pre></div>
<p>Theoretisch sind beide Varianten legitim, in der Praxis scheinen einige Freemailanbieter noch <a href="http://www.walkingsmall.de/2009/04/07/email-clients-freemailer-und-utf-8/" rel="external">Probleme mit UTF-8</a> in der ein oder anderen Methode zu haben. Die Web.de Webmail-Oberfläche z.B. zeigte die dekodierten Betreffzeilen in der Übersicht an, in der Einzelansicht allerdings nicht. Thunderbird und auch Outlook (mobile Version) haben hingegen keine Probleme mit der Dekodierung.</p>
<p>Spätestens wenn die Komplexität der zu sendenene E-Mails über ein simples Kontaktformular hinaus geht, empfielt es sich, vorgefertigte Klassen wie <a rel="external" href="http://phpmailer.worxware.com/">phpmailer</a> zu verwenden. Notwendige Kodierungen werden damit intern abgehandelt und die E-Mail automatisch zusammengefügt.</p>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2010/kontaktformulare-ohne-zeichensalat/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Geordneter Umzug (zu WordPress)</title>
		<link>http://dnaber.de/blog/2010/geordneter-umzug/</link>
		<comments>http://dnaber.de/blog/2010/geordneter-umzug/#comments</comments>
		<pubDate>Mon, 25 Jan 2010 12:30:29 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Usability]]></category>
		<category><![CDATA[Wordpress]]></category>

		<guid isPermaLink="false">http://blog.dnaber.de/?p=979</guid>
		<description><![CDATA[Eine Handvoll sinnvoller HTTP-Statuscodes, die beim Umbau einer Website die richtigen Antworten geben und wie man sie via PHP und .htaccess sendet.]]></description>
			<content:encoded><![CDATA[<p>Ende letzten Jahres habe ich mich dazu entschlossen, die Website <a rel="external" href="http://volleyballfische.de/">meines Volleyballvereins</a> mit einem Redaktionssystem zu betreiben. Im Zuge der Neuerungen musste auch die URL-Struktur geändert werden, was naturgemäß zu dem Problem führt, dass Aufrufe über Lesezeichen, Links und Suchmaschinen unerwartet im „Seite nicht gefunden“-Nirwana landen. Um unseren Besuchern (und unserer guter Position in den Suchmaschinen) das zu ersparen habe ich den Umzug geordnet durchgeführt und alle alten Links übersetzt und leite die Besucher zur gewünschten Seite <em>weiter</em>.<br />
<span id="more-979"></span></p>
<h3>Die richtige Antwort</h3>
<p>Wenn man eine URL Aufruft, zu der keine passende Ressource gefunden wird, landet man für gewöhnlich auf einer weißen „<strong>404 – not found</strong>“ Seite, die vom Server automatisch generiert wird. Mit etwas Glück ist diese Seite aber im Design der Website und bietet mögliche Alternativen zum nicht gefundenen Inhalt. In beiden Fällen antwortete der Webserver auf die Anfrage mit dem <a rel="external" href="http://de.wikipedia.org/wiki/HTTP-Statuscode">Statuscode</a> „404“ der besagt: „Es wurde <em>nichts</em> gefunden“.</p>
<p>Ändern sich bei einem Umzug die URLs der Seiten, so landet jeder Aufruf der <em>alten</em> Links in der Sackgasse obwohl die Seite noch existiert. Folgerichtig wäre die korrekte Antwort vom Server: „der gesuchte Inhalt ist jetzt unter einer neuen URL verfügbar“. Der richtige Statuscode für diesen Fall ist „301 – Moved Permanently“.</p>
<p>Einige Seiten sind auch komplett verschwunden. Zum Teil weil sie in andere eingebunden wurden (Kontakt und Impressum können durchaus auf einer Seite unterkommen), andere waren einfach veraltet. Anfragen auf gelöschte Seiten beantwortet man ordnungsgemäß mit dem Statuscode „410 – gone“, der soviel bedeutet wie „Diese Seite ist von uns gegangen“. Somit ist auch gleich dafür gesorgt, dass Google &amp; co. bescheid wissen und ihre Indizes aktualisieren können.</p>
<h3>Die Umzugskisten auspacken</h3>
<p>Während <a rel="external" href="http://scriptshit.de/blog/show/warum-wordpress-als-cms-nicht-geeignet-ist">andernorts</a> noch <a rel="external" href="http://toscho.de/2010/wordpress-cms/">diskutiert</a> wird, ob WordPress als <abbr title="Content Management System" lang="en">CMS</abbr> taugt, setze ich es ein. Nicht zuletzt weil Anpassungen wie diese kinderleicht zu integrieren sind. Um alte URLs ihren neuen zuzuordnen und gelöschte Seiten zu kennzeichnen, ergänze ich die functions.php des eingesetzten Designs um folgende Funktion:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">/** 
* umleiten alter Permalinks auf die neuen
*/
function translate_permalinks() {

	$_301 = array(
		&#039;/startseite.html&#039; =&gt; &#039;/&#039;
		&#039;/kontakt.html&#039; =&gt; &#039;/kontakt&#039;,
		&#039;/mannschaften.html&#039; =&gt; &#039;/mannschaften&#039;,
		&#039;/news.html&#039; =&gt; &#039;/aktuell&#039;,
		&#039;/links.html&#039; =&gt; &#039;/weblinks&#039;,
		&#039;/impressum.html&#039; =&gt; &#039;/kontakt#impressum&#039;,
	);
	$_410 = array ( 
		&#039;/alt.html&#039;,
		&#039;/javascript/altes_script.js&#039;,
		&#039;/css/altes_stylesheet.css&#039;,
		&#039;/weg.html&#039;
	);
	if ( array_key_exists( $_SERVER[&#039;REQUEST_URI&#039;], $_301 ) ) {
		header(
			&#039;Location: &#039;
				. ( $_SERVER[&#039;HTTPS&#039;] 
					? &#039;https&#039;
					: &#039;http&#039;
				  )
				. &#039;://&#039; . $_SERVER[&#039;SERVER_NAME&#039;] 
                  		. $_301[$_SERVER[&#039;REQUEST_URI&#039;]],
			true,
			301
		);
		exit();
	}

	if ( in_array( $_SERVER[ &#039;REQUEST_URI&#039; ], $_410 ) ) {
		header(
			  ( $_SERVER[ &#039;SERVER_PROTOCOL&#039; ] == &#039;HTTP/1.1&#039; 
				? &#039;HTTP/1.1&#039;
				:  &#039;HTTP/1.0&#039;
			  )
			. &#039; 410 Gone&#039;
		);
		header(&#039;Content-type: text/html;charset=utf-8&#039;);
		echo 
			&#039;&lt;h1&gt;410 - Gone&lt;/h1&gt;
			&lt;p&gt;Dieses Dokument existiert nicht mehr bei uns.
			Besuch bitte unsere &lt;em&gt;neue&lt;/em&gt; Website:
			&lt;a href=&quot;http://domain.tld/&quot;&gt;http://domain.tld&lt;/a&gt;&lt;/p&gt;&#039;;
		exit();
	}
}</code></pre></div>
<p>In dem Array <code>$_301</code> ordne ich die neuen Links den alten in der Form zu:<br />
<code>/link/zur/alten-datei.html => /neue_datei</code>.<br />
Alle nicht mehr vorhandenen URLs werden in dem Array <code>$_410</code> lose aufgelistet. Die Elemente beider Arrays werden mit der <a rel="external" href="http://de3.php.net/manual/de/reserved.variables.server.php">Request-URI</a> verglichen und im Falle einer Übereinstimmung erfolgt die Weiterleitung bzw. die Antwort mit dem entsprechenden Statuscode.</p>
<p>Der Funktionsaufruf erfolgt am <em>Anfang</em> der functions.php. Je nach Umfang der Website ist das etwas mehr Handarbeit die sich aber lohnt.</p>
<p><strong>Nachtrag:</strong></p>
<p><a href="#comment-744">In den Kommentaren</a> hat mich Thomas darauf hingewiesen, dass es schneller geht, die Umleitungen in die .htaccess-Datei zu schreiben, da so nicht jedesmal das ganze System geladen wird. Wer also auf die Performance achtet, oder ein anderes System als WordPress nimmt, schreibt die Umleitungen und gelöschten Dokumente besser in die .htaccess.</p>
<p>Für diese Zwecke ist die <a href="http://httpd.apache.org/docs/2.0/mod/mod_alias.html#redirect" rel="external">Redirect-Direktive</a> des Moduls <em>„mod_alias“</em> geeignet. Alle permanenten Umleitungen werden so notiert:</p>
<div class="wp-cc"><pre><code data-language="">Redirect permanent /alte_seite.html http://domain.tld/neue_seite</code></pre></div>
<p>Hier muss man darauf achten, dass die URL zur neuen Seite vollständig angegeben werden muss, da Weiterleitungen nicht zwangsläufig auf eine Domain beschränkt sind.</p>
<p>Für gelöschte Dokumente lautet der Eintrag:</p>
<div class="wp-cc"><pre><code data-language="">&lt;IfModule mod_alias.c&gt;
	Redirect permanent /startseite.html http://domain.tld/
	Redirect permanent /kontakt.html http://domain.tld/kontakt
	Redirect permanent /mannschaften.html http://domain.tld/mannschaften
	Redirect permanent /news.html http://domain.tld/aktuell
	Redirect permanent /links.html http://domain.tld/weblinks
	Redirect permanent /impressum.html http://domain.tld/kontakt#impressum

	Redirect gone /alt.html
	Redirect gone /javascript
	Redirect gone /css
	Redirect gone /weg.html
&lt;/IfModule&gt;</code></pre></div>
<p>Mit der Redirect Direktive kann man nicht nur einzelne Dokumente sondern auch Verzeichnisse handhaben, wie im Fall der Stylesheets und der Skripte zu sehen ist.</p>
<p>Damit Anfragen auf die entfernten Dokumente nicht mit einer lieblosen Standardantwort abgespeist werden, kann man noch ein Error-Dokument in der .htaccess anlegen:</p>
<div class="wp-cc"><pre><code data-language="">ErrorDocument 410 /entfernt.html</code></pre></div>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2010/geordneter-umzug/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>WordPress: Kommentare nummerieren (v.2.7+)</title>
		<link>http://dnaber.de/blog/2009/wordpress-kommentare-nummerieren/</link>
		<comments>http://dnaber.de/blog/2009/wordpress-kommentare-nummerieren/#comments</comments>
		<pubDate>Tue, 01 Sep 2009 13:10:39 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Wordpress]]></category>

		<guid isPermaLink="false">http://blog.dnaber.de/?p=747</guid>
		<description><![CDATA[Wie man die Kommentare zu einem Artikel durchlaufend nummeriert.]]></description>
			<content:encoded><![CDATA[<p class="remark">Anmerkung: <a rel="external" href="http://webdesign-passau.com/wordpress/">Klaus</a> hat mich darauf hingewiesen, dass dieser Artikel in der ersten Fassung etwas zu kurz und zu abstrakt geraten ist und dadurch zu unverständlich ist. Aus diesem Grund habe ich diesen Artikel noch einmal überarbeitet um die einzelnen Schritte nachvollziehbarer zu machen.</p>
<h3>Worum es geht</h3>
<p>Dieses kurze Tutorial soll zeigen, wie man in WordPress die Kommentare fortlaufend nummeriert. Der Semantik wäre schon genüge getan, wenn man jeden einzelnen Kommentar als Punkt einer nummerierten Liste (<code>&lt;ol&gt;</code>) auszeichnet. Manchmal will man aber die <del>Nummern</del> Ziffern mit in die Gestaltung einbeziehen und mit CSS aufhübschen. Wie man die Nummer für jeden Kommentar als Zahl in den Quelltext bekommt, soll hier gezeigt werden.<span id="more-747"></span></p>
<h3>Die Idee</h3>
<p>Der HTML-Code für die Kommentare wird erzeugt, in dem die Datensätze in einer Schleife durchlaufen werden und für jeden Durchlauf der entsprechende Kommentar sein HTML-Kleid bekommt. Für unser Vorhaben reicht es also, <em>vor</em> dem Schleifenaufruf eine Zählvariable zu definieren (ich nenne sie hier mal <code>$comment_counter</code>). Innerhalb der Schleife setzen wir einen Befehl, der den Variablenwert um den Wert 1 erhöht.<br />
Vor der Version 2.7 musste man diese Schleife noch von Hand schreiben und die Zählvariable konnte man bequem mit unterbringen. Das Kommentartemplate (comments.php) sah bis 2.7 schematisch etwa so aus:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">/**  
* in der comments.php
*/
# Unsere Zählvariable
$comment_counter = 1;

# der Kommentar-Loop
foreach ( $comments as $comment ) : ?&gt;

	&lt;li id=&quot;comment-&lt;?php comment_ID(); ?&gt;&quot;&gt;
	&lt;cite&gt;
		&lt;?php 
		# Avater, Autor und Datum
		if ( function_exists( &#039;get_avatar&#039; ) ) echo get_avatar();
		comment_author_link(); ?&gt;
		–
		&lt;?php comment_date(); ?&gt; 
		um
		&lt;a href=&quot;#comment-&lt;?php comment_ID(); ?&gt;&quot;&gt;
			&lt;?php comment_time(); ?&gt;
		&lt;/a&gt;
	&lt;/cite&gt;
        &lt;?php edit_comment_link(); ?&gt;
        
	&lt;?php 
	# hier kommt die Nummer
	echo $comment_counter; ?&gt;

	&lt;?php comment_text(); ?&gt;
	&lt;?php
	# zum Schluss setzen wir die Zählvariable noch eins hoch:
	$comment_counter++; ?&gt;
	&lt;/li&gt;
	&lt;?php
endforeach; ?&gt;
</code></pre></div>
<p>Soweit, so gut.</p>
<h3>Umsetzung seit Version 2.7</h3>
<p>Seit Version 2.7 muss man die Schleife nicht mehr von Hand starten, sondern hat dafür die Funktion <a rel="external" href="http://codex.wordpress.org/Template_Tags/wp_list_comments"><code>wp_list_comments()</code></a> zur Verfügung. Diese Funktion organisiert den Schleifendurchlauf automatisch und erzeugt gleichzeitig das HTML, auf welches man geringfügig Einfluss nehmen kann, in dem man der Funktion bestimmte Parameter übergibt. Eine Nummerierung der Kommentare ist leider nicht vorgesehen.</p>
<p>Um das erzeugte HTML komplett selbst zu bestimmen (und somit die Kommentarnummer einzufügen), akzeptiert <code>wp_list_comments()</code> eine sogenannte Callback-Funktion, die man selbst schreiben muss und in der man die HTML-Maske für die einzelnen Kommentare bestimmt. Eine solche Funktion, man könnte sie z.B. <a rel="external" href="http://codex.wordpress.org/Template_Tags/wp_list_comments#Comments_Only_With_A_Custom_Comment_Display"><code>mytheme_comment()</code></a> nennen, schreiben wir in die functions.php. Der Name dieser Funktion kann beliebig gewählt werden, allerdings muss sie dem folgendem Schema genügen, um die Funktionalität zu gewährleisten:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">/**
 * functions.php
 */
function mytheme_comment( $comment, $args, $depth ) {

	$GLOBALS[&#039;comment&#039;] = $comment; 
	# Ab folgt die Gestaltung des einzelnen Kommentars
	?&gt;
	&lt;li&gt; id=&quot;comment-&lt; ?php comment_ID() ?&gt;&quot;&gt;
	&lt;h3 class=&quot;comment-author vcard&quot;&gt;
		&lt;cite class=&quot;fn&quot;&gt;&lt; ?php comment_author_link();?&gt;&lt;/cite&gt;
	&lt;/h3&gt;
	&lt;div class=&quot;comment-meta&quot;&gt;
		Geschrieben am
		&lt;?php comment_date() ?&gt;
		um 
		&lt;?php comment_time() ?&gt;
	&lt;/div&gt;
        &lt;?php 
	if ( &#039;0&#039; == $comment-&gt;comment_approved ) : ?&gt;
		&lt;p&gt;Dein Kommentar muss erst durch den Administrator freigeschaltet werden&lt;/p&gt;
		&lt;?php 
	endif ?&gt;
	&lt;div class=&quot;comment-content&quot;&gt;&lt; ?php comment_text() ?&gt;&lt;/div&gt;
	&lt; ?php
	/**
	 *   Das schließende&lt;/li&gt;-Tag für den einzelnen Kommentar
	 *   setzt die Funktion wp_list_comments() von selbst, der
	 *   darf hier nicht gesetzt werden!
	 */ 
}</code></pre></div>
<p>Um diese Callback-Funktion aufzurufen, übergeben wir deren Name als Parameter in Form eines Strings an die <code>wp_list_comments()</code>:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">/**
 * der Aufruf in der comments.php
 */
?&gt;
&lt;ol id=&quot;commentlist&quot;&gt;
	&lt;?php wp_list_comments( &#039;callback=mytheme_comment&#039; ); ?&gt;
&lt;/ol&gt;
</code></pre></div>
<p>Um auch hier die Kommentare mit ihrer Nummer zu versehen, definieren wir die Zählvariable wieder außerhalb der Schleife, also noch von dem Aufruf der Funktion <code>wp_list_comments()</code>:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">/**
 * comments.php
 */
?&gt;
&lt;ol&gt;
	&lt;?php
	$comment_counter = 0;
	wp_list_comments(&#039;callback=mytheme_comment&#039;); ?&gt;
&lt;/ol&gt;</code></pre></div>
<p>Da diese Zählvariable außerhalb der Funktion <code>mytheme_comment</code> definiert wird, ist sie innerhalb der Funktion auch <em>noch</em> nicht „sichtbar“. Da wir sie nich einfach als Parameter an die Funktion übergeben können, müssen wir sie innerhalb von <code>mytheme_comment</code> als global definieren um darauf zugreifen zu können. Anschließend kann man sie per <code>echo</code>-Befehl an der gewünschten Stelle ausgeben und setzt deren Wert zum Schluss noch um 1 höher:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">/**
 * functions.php
 */
function mytheme_comment( $comment, $args, $depth ) {

	# Zugriff auf die Zählvariable ( startet bei 0 )
	global $comment_counter;
	# Zähler heraufsetzen.
	$comment_counter ++;
	
	$GLOBALS[&#039;comment&#039;] = $comment;
	# ...

	echo &#039;&lt;p&gt;&#039; . $comment_counter . &#039;&lt;/p&gt;&#039;;
}
?&gt;</code></pre></div>
<p>Ab jetzt hat jeder Kommentar seine eigene Nummer, die man per CSS beliebig gestalten kann.</p>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2009/wordpress-kommentare-nummerieren/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>PHP: String auf die ersten Worte kürzen</title>
		<link>http://dnaber.de/blog/2009/string-auf-die-ersten-worte-kuerzen/</link>
		<comments>http://dnaber.de/blog/2009/string-auf-die-ersten-worte-kuerzen/#comments</comments>
		<pubDate>Tue, 01 Sep 2009 07:08:02 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[string bearbeiten]]></category>

		<guid isPermaLink="false">http://blog.dnaber.de/?p=739</guid>
		<description><![CDATA[Eine kleine Funktion, von der ich die ersten Worte eines Strings zurück bekomme, um z.B. in einem Vorschaublock den ersten Absatz eines Artikels anzureißen. Die Idee, ich habe sie mir bei Thomas Funktion end_on_word() abgeschaut, ist so simpel wie effektiv: Der String wird an den Leerzeichen in ein Array aufgespalten und mit diesem kann man …]]></description>
			<content:encoded><![CDATA[<p>Eine kleine Funktion, von der ich die ersten Worte eines Strings zurück bekomme, um z.B. in einem Vorschaublock den ersten Absatz eines Artikels anzureißen.<span id="more-739"></span></p>
<p>Die Idee, ich habe sie mir bei Thomas Funktion <a href="http://toscho.de/2009/php-funktion-end_on_word/" rel="external">end_on_word()</a> abgeschaut, ist so simpel wie effektiv: Der String wird an den Leerzeichen in ein Array aufgespalten und mit diesem kann man dann arbeiten:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">/** 
 * reduziert einen String auf die 
 * ersten Worte
 *
 * @param str $str
 * @param int $count (Default 10)
 * @return str
 */
function getFirstWords( $str, $count = 10 ) {
    
 	$str = trim( $str );

 	# Jedes Wort ein Arrayelement
 	$array = explode( &#039; &#039;, $str );
  
 	# Array in $count große Teile teilen
 	$array = array_chunk( $array, $count );

 	/**
 	 * Falls der String weniger Worte hatte als $count
 	 * geben wir den String unverändert zurück
 	 */
 	if ( empty( $array[ 1 ] ) ) 
 	 	return $str;

 	/**
 	 * andernfalls entfernen wir eventuelle Kommas am ende
 	 * und fügen ein Auslassungszeichen an
 	 */
  	 return rtrim( implode( &#039; &#039;, $array[ 0 ] ), &#039;,;&#039; ) . &#039;[…]&#039; ;
}

/** 
 * Anwendung
 */
$str = &quot;Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam.&quot;;

# Die ersten 5 Wörter bitte:
echo getFirstWords( $str, 5 );

/**
 * Ausgabe: Lorem ipsum dolor sit amet […]
 */</code></pre></div>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2009/string-auf-die-ersten-worte-kuerzen/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Schriftgröße in px oder em?</title>
		<link>http://dnaber.de/blog/2009/schriftgroesse-in-px-oder-em/</link>
		<comments>http://dnaber.de/blog/2009/schriftgroesse-in-px-oder-em/#comments</comments>
		<pubDate>Tue, 25 Aug 2009 16:16:03 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Schriftgröße]]></category>
		<category><![CDATA[Typografie]]></category>
		<category><![CDATA[Usability]]></category>

		<guid isPermaLink="false">http://blog.dnaber.de/?p=696</guid>
		<description><![CDATA[Die Schriftgröße auf Websites ist ein heißes Pflaster – nicht zuletzt, weil die entgültige Entscheidung beim Benutzer liegt. Man sollte es ihm also nicht unnötig schwer machen.]]></description>
			<content:encoded><![CDATA[<p>Ich spreche heut wieder mal ein Thema an, von dem ich dachte, dass es eigentlich schon vor langer Zeit in diverse <q>x-Dinge-die-man-nicht-macht</q>-Listen aufgenommen wurde. Die Rede ist von Schriftgrößen auf Webseiten und ob diese in der Einheit <code>px</code> angegeben werden sollten.<span id="more-696"></span></p>
<p>Die <abbr title="barrierefreie Informationstechnik-Verordnung">BITV</abbr> fordert ganz allgemein <a href="http://www.einfach-fuer-alle.de/artikel/bitv/anlage-1#bedingung-3.4" rel="external">die Verwendung von relativen statt absoluten Einheiten</a>. Ein <a href="http://www.w3.org/TR/CSS21/syndata.html#length-units" rel="external" title="Spezifikation des world wide web consortium" lang="en">Blick in die Spezifikation</a> verrät, dass in <abbr title="Cascading Style Sheets" lang="en">CSS</abbr> die Einheit <code>px</code> als relative Einheit zu verstehen ist. Logisch, denn wenn ich auf einen 15&#8243; Flachbildschirm 1024&#215;768 Bildpunkte aber auch 1400&#215;1050 Bildpunkte unterbekomme, dann muss der Platz pro Bildpunkt von Gerät zu Gerät unterschiedlich sein. Soweit die Theorie die sagt, <code>px</code> als Einheit ist okay für die Angabe der Schriftgröße. In der Praxis offenbaren sich dann doch einige Probleme, die ich hier demonstrieren will.</p>
<p>Als Testobjekt dient <a href="http://dnaber.de/tools/font-size.html">dieses HTML Dokument</a>, dessen Quelltext im wesentlichen so aussieht:</p>
<div class="wp-cc wp-cc-html"><pre><code data-language="html">&lt;style type=&quot;text/css&quot;&gt;
	body {
		font-size: 100%;
		line-height: 1.5;
	}
	h1 {
		font-size: 2em;
	}
	h2 {
		font-size: 32px;
	}
	h3 {
		font-size: 1em;
	}
	h4 {
		font-size: 16px;
	}
	h5 {    
		font-size:. 8em;
	}
	h6 {
		font-size: 13px;
	}
&lt;/style&gt;
	&lt;h1&gt;Text mit 2em Schriftgröße&lt;/h1&gt;
	&lt;h2&gt;Text mit 32px Schriftgröße&lt;/h2&gt;
	&lt;h3&gt;Text mit 1em Schriftgröße&lt;/h3&gt;
	&lt;h4&gt;Text mit 16px Schriftgröße&lt;/h4&gt;
	&lt;h5&gt;Text mit .8em Schriftgröße&lt;/h5&gt;
	&lt;h6&gt;Text mit 13px Schriftgröße&lt;/h6&gt;</code></pre></div>
<p>Anschauen werde ich die Seite unter WinXP, bei einer Bildschirmauflösung von 1400&#215;1050 mit Firefox 2, Opera 9.6, InternetExplorer 6-8 und Safari 3, sowie unter Vista, 1280&#215;800 mit Firefox 3.5 und IE8 jeweils bei einem im Browser eingestellten Schriftgrößengrad von ›16‹ (also die Standardeinstellung der meisten Browser).<br />
Auf Grund der 100%-Schriftgröße für den Body, die sich auf die im Browser eingestellte Schriftgröße bezieht, sind die jeweiligen Wortgruppen annähernd gleich groß (1em entspricht <em>hier</em> 16px). Mit Ausnahme <em>aller</em> Versionen des InternetExplorers werden bei reiner Schriftvergrößerung alle Texte gleichermaßen vergrößert. Der IE8 und Opera, aber auch Firefox ab Version 3 bieten zusätzlich noch eine komplette Zoomfunktion, die die gesamte Seite proportional vergrößert/verkleinert. </p>
<p>Soweit so gut. Was passiert aber, wenn ich von der Möglichkeit gebrauch mache, mir die Schriftgröße auf ein für mich optimales Maß im Browser voreinzustellen, z.B. auf 20? Hier zeigt sich das Problem der einheit <code>px</code>: der Text ist festzementiert auf die Größe, die im Stylesheet der Seite steh. Der Schriftgrad in der Browsereinstellung wird schlicht ignoriert. Als Besucher muss ich also erstmal am Mausrad drehen, oder auf die <em>Plus</em>-Taste drücken, um die Schrift zu vergrößern.</p>
<p>Jeder bessere Browser bietet außerdem die Möglichkeit an, eine Mindestschriftgröße festzulegen, die dann nicht mehr ignoriert werden kann. Diese stellt, wenn sie denn überhaupt eingestellt ist, meist die unterste Schmerzgrenze dar, unter der absolut nichts mehr geht, und die für Fließtext eigentlich schon zu klein ist. Spätestens da ist dann Schluss mit den Pixelschriftgrößen. Im schlimmsten Fall verspielt man so die Möglichkeit mit Schriftgrößenunterschieden auf der Seite zu arbeiten, wenn man mit seinen Schriftgrößen unterhalb der Mindestgröße agiert.</p>
<p>Aus diesen Gründen kann ich nur dringend davon abraten, Schriftgrößen in <code>px</code> anzugeben. Ansonsten drängt man den Besucher, zu erst zu Zoomen, um den Text lesen zu können. Dabei ist es unerheblich ob nun reiner Textzoom oder der komplette Seitenzoom eingesetzt wird.</p>
<p>Meine Herangehensweise sieht so aus, dass ich für den Body einen Prozentwert um 100 angebe (von mir aus auch 100.01% für die älteren IEs). Überschriften und große Texte werden dann im Bereich 1.4 bis 2em bemaßt, Fließtest zwischen 1.1 und .85em und Fußnoten .9 bis .8em. Dabei kann man durchaus sehr Genau arbeiten, da die Einheit <code>em</code> bis auf die vierte Nachkommastelle genau angegeben werden kann. Ich richte meine Schriftgröße nur so lang am Design aus, wie es mir die Bemaßung in <code>em</code> erlaubt und bin damit bisher immer gut gefahren, auf Pixelgenauigkeit achte ich auch sonst eher selten. Viel wichtiger sind optimale Zeilenlängen und vor allem ein ausreichender Zeilenabstand. Der <em>Besucher</em> sollte, unabhängig von seinen gewählten Einstellungen, ein lesbares Schriftbild vorfinden. Ihm diese Freiheit zu lassen, muss nicht im Widerspruch zu gutem und detailiertem Design stehen, man muss es nur berücksichtigen.</p>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2009/schriftgroesse-in-px-oder-em/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sonderzeichen unter Windows (Alt-Codes)</title>
		<link>http://dnaber.de/blog/2009/sonderzeichen-unter-windows-alt-codes/</link>
		<comments>http://dnaber.de/blog/2009/sonderzeichen-unter-windows-alt-codes/#comments</comments>
		<pubDate>Mon, 10 Aug 2009 18:37:01 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[Sonderzeichen]]></category>
		<category><![CDATA[Typografie]]></category>

		<guid isPermaLink="false">http://blog.dnaber.de/?p=685</guid>
		<description><![CDATA[Da dieser Artikel über Google so gut gefunden wird, ursprünglich aber nur einige wenige Sonderzeichen für bessere Typographie betrachtete, habe ich ihn erweitert und eine komplette Aufstellung aller Tastenkombinationen unter Windows XP mit ALT+Zahl erstellt Legt man beim Bloggen, Kommentieren oder (von mir aus auch) Twittern Wert auf den korrekten Einsatz von ganz alltäglichen Sonderzeichen, …]]></description>
			<content:encoded><![CDATA[<p class="remark">Da dieser Artikel über Google so gut gefunden wird, ursprünglich aber nur einige wenige Sonderzeichen für bessere Typographie betrachtete, habe ich ihn erweitert und eine <a href="#tabellen">komplette Aufstellung</a> aller Tastenkombinationen unter Windows XP mit <code>ALT+Zahl</code> erstellt</p>
<p>Legt man beim Bloggen, Kommentieren oder (von mir aus auch) Twittern Wert auf den korrekten Einsatz von ganz alltäglichen Sonderzeichen, ist man als Windows-Nutzer ganz schön aufgeschmissen. Wo in Word noch automatisch aus den Zollzeichen <code>"</code> (Shift + 2) Anführungszeichen <code>„ “</code> werden, hat man in einem Kommentarfeld im Netz nur zwei möglichkeiten: Entweder <q>Copy &amp; Paste</q> oder man kennt die <abbr title="so genannten">sog.</abbr> Alt-Codes. <span id="more-685"></span></p>
<p>Okay, wo in einem Forum ein solches Gebilde gerade noch als Zitat durch geht, sieht sowas auf einem Blog ziemlich peinlich aus: &#8220;Sein oder nicht sein, das ist hier die Frage&#8221;. Also hab ich die wichtigsten Sonderzeichen, die nicht auf der Tastatur sind <a rel="external" href="http://dnaber.de/tools/alt_keys.html">in einer Tabelle zusammengefasst</a>. Diese liegt jetzt ausgedruckt auf meinem Schreibtisch – immer griffbereit, wenn ich an statt dreimal auf den <q>Punkt</q> zu hacken, korrekter Weise lieber ein Auslassungszeichen verwenden will.</p>
<p>Bleibt zu hoffen, dass man eine Tastatur mit Ziffernblock hat, denn die Tastenkürzel für Windows müssen bei gedrückter ALT-Taste eben dort eingegeben werden. Andernfalls bleibt ja noch die <q>Copy&amp;Paste</q> Methode :)</p>
<p><strong>Nachtrag:</strong></p>
<h3 id="tabellen">ALT-Code Tabellen</h3>
<p>Was jetzt folgt ist alles reine Empirie, denn leider findet man nur wenig Informationen über die Systematik der Ziffernkombinationen mit denen man an Sonderzeichen kommt. Offenbar wird aber häufig danach gesucht, denn dieser Artikel hier ist der meistbesuchte auf meinem Blog. Selbst bei Microsoft habe ich noch keine Infos über die Tastenkombinationen gefunden. Also geht hier <q>Probieren über Studieren</q>!</p>
<p>In Windows XP verstecken sich hinter den ALT-Codes die Positionen der Zeichen von (wenigstens) zwei Zeichensatztabellen. Zum einen die Zeichen der <a href="http://de.wikipedia.org/wiki/Codepage_850" rel="external">Codepage-850</a>, die noch aus MS-DOS Zeiten stammt. Um also an ein Zeichen zu kommen, tippt man bei gedrückter ALT-Taste dessen Dezimalposition ein. Z.B. hat das Zeichen ¾ die Position F3<sub>HEX</sub> bzw. 243<sub>10</sub>. Also wäre die Tastenkombination <code>ALT+243</code>. Um nicht groß rumzurechnen, <a href="http://dnaber.de/tools/codepage-850.php">gibt es hier eine tabellarische Übersicht</a>.</p>
<p>Zum anderen kann man über die ALT-Tastenkombination auf die Zeichen des <a href="http://de.wikipedia.org/wiki/Windows-1252#Windows-1252" rel="external">Windows-1252</a> Zeichensatzes, der weitgehend mit ISO-8859-1 (auch (ISO-)Latin-1 genannt) übereinstimmt aber eben nicht identisch ist, zugreifen. Das Prinzip ist das gleiche wie für die Codepage-850, allerdings wird hier der Positionszahl eine Null &#8220;0&#8243; vorangestellt. Bsp.: „ƒ“ dessen Position ist 83<sub>HEX</sub> bzw. 131<sub>10</sub> also wäre die Tastenkombination <code>ALT-0131</code>. Auch hierfür gibt es eine <a href="http://dnaber.de/tools/windows-1252.php">Tabelle, die die ALT-Codes gleich mitliefert</a>. Die ersten 32 Zeichen sind <a href="http://de.wikipedia.org/wiki/Steuerzeichen" rel="external">Steuerzeichen</a>, die man wohl eher selten braucht. </p>
<p>Die möglichen Nummernkombinationen gehen nach 255 bzw. 0255 übrigens weiter, die Zeichen beginnen dann einfach wieder von vorn.</p>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2009/sonderzeichen-unter-windows-alt-codes/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>SEO-freundliches, Cookie-unabhängiges Session-Handling in PHP</title>
		<link>http://dnaber.de/blog/2009/seofreundliches-cookieunabhangiges-session-handling-in-php/</link>
		<comments>http://dnaber.de/blog/2009/seofreundliches-cookieunabhangiges-session-handling-in-php/#comments</comments>
		<pubDate>Thu, 30 Jul 2009 14:23:41 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Sessions]]></category>

		<guid isPermaLink="false">http://blog.dnaber.de/?p=549</guid>
		<description><![CDATA[Der Einsatz von Sessions ist nicht immer unproblematisch, vor allem wenn man auch für strikte Cookie-Verweigerer eine Möglichkeit finden muss. Wie man Suchmaschinen aus der Session außen vor lässt und die URIs dennoch einigermaßen sauber hält, stelle ich hier vor. Bisher konnte ich mich immer erfolgreich um den Einsatz von Sessions für Webseiten drücken oder …]]></description>
			<content:encoded><![CDATA[<p>Der Einsatz von Sessions ist nicht immer unproblematisch, vor allem wenn man auch für strikte Cookie-Verweigerer eine Möglichkeit finden muss. Wie man Suchmaschinen aus der Session außen vor lässt und die <abbr title="Uniform Resource Identifier" lang="en">URIs</abbr> dennoch einigermaßen sauber hält, stelle ich hier vor.<span id="more-549"></span></p>
<p>Bisher konnte ich mich immer erfolgreich um den Einsatz von Sessions für Webseiten drücken oder ich habe mich darauf verlassen, dass der Besucher Cookies akzeptiert und den Rest <dfn title="Scriptsprache, die auf einem Webserver ausgeführt wird" lang="en"><abbr>PHP</abbr></dfn> überlassen. Für Backends oder andere passwortgeschütze Seiten kann ich guten Gewissens den Benutzer bitten, eine Ausnahme zu machen und ein Cookie zu akzeptieren. Mit dieser Verfahrensweise ist spätestens dann Schluss, wenn man Warenkörbe, mehrseitige Formulare oder vergleichbare Erweiterungen der Funktionalität, unabhängig der Cookie-Einstellungen der Besucher, anbieten möchte. Mich persönlich nervt nichts mehr, als wenn mir eine Website vorschreibt <q>aktiviere dies, installiere jenes</q> um die Inhalte möglichst vollständig zu Gesicht zu bekommen.</p>
<p>Um die Session-ID mit dem folgenden Request wieder parat zu haben, hat man grundsätzlich drei Möglichkeiten zur Auswahl:<br />
Die SID</p>
<ul>
<li>in einem Cookie speichern</li>
<li>per Attribut in der <abbr title="Uniform Resource Identifier" lang="en">URI</abbr> übergeben</li>
<li>als verborgendes Feld in einem Formular per POST-Request (da aber eine Website nicht nur aus Formularen besteht, fällt das als Möglichkeit meist aus)</li>
</ul>
<p>Am elegantesten ist natürlich Variante 1, denn eine Session-ID in der <abbr title="Uniform Resource Identifier" lang="en">URI</abbr> kann eine menge Probleme verursachen. Zum ersten führt es zu Sicherheitslücken, denn so ist die Session-ID offen sichtbar und die Session kann im schlimmsten Fall von einem anderen Nutzer übernommen werden.<br />
Zweites Problem: Suchmaschinen und ihre Spider. Wenn Google &#038; Co <abbr>URIs</abbr> mit der Session-ID indizieren, dann ist das formal <q lang="en" title="doppelter Inhalt">dublicate content</q> (die selbe Seite wäre ja auch ohne, bzw. mit beliebig vielen Session-IDs erreichbar) und wirkt sich unter Umständen negativ auf das Ranking aus – oder ein Nutzer, der diesen Links folgt, findet vieleicht nicht dass, was er eigentlich sucht, wenn der Inhalt individuell an die Session geknüpft ist.<br />
Und zu guter Letzt sieht es einfach ziemlich blöd aus und es zerstört einem die mühsam zusammengebaute <abbr>URI</abbr>-Struktur: <code>http://blog.dnaber.de/2009/artikel?PHPSESSID=a3c4efg6ijk0m8o3ue</code>.<br />
Man sollte also diese Möglichkeit der Session-ID-Weitergabe nur dann nutzen, wenn der Benutzer keine Cookies akzeptiert. </p>
<p>Wie also kann man vorgehen?</p>
<h3>Die Grundeinstellungen</h3>
<p>Wir wollen, wenn möglich, Cookies verwenden, wir wollen allerdings <em>nicht</em> ausschließlich auf Cookies setzen. Also nutzen wir die Funktion <code>ini_set()</code> um die <a href="http://de2.php.net/manual/de/session.configuration.php" rel="external">Laufzeitkonfiguration der Sessionbehandlung</a> in PHP anzupassen:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php"># Cookieunterstützung aktivieren
ini_set( &#039;session.use_cookies&#039;, 1 );

# Sessionunterstützung ausschließlich mit Cookies deaktivieren
ini_set( &#039;session.use_only_cookies&#039;, 0 );</code></pre></div>
<p>Je nach Serverkonfiguration kann das auch schon dem Standard entsprechen.</p>
<h3>Die <em lang="en">Fall-forward</em>-Lösung für Cookie-Freunde</h3>
<p>Ein Problem bei Cookies ist, dass man frühestens beim zweiten Request erkennt, ob der Client das Cookie akzeptiert und damit im Request wieder mit gesendet hat. Es bleibt also nichts anderes übrig, als für den ersten Request die Session-ID an die <abbr title="Uniform Resource Identifier" lang="en">URIs</abbr> zu hängen. </p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">if ( empty( $_COOKIE[ session_name() ] ) ) 
	ini_set( &#039;session.use_trans_sid&#039;, 1 );

else     
	ini_set( &#039;session.use_trans_sid&#039;, 0 );
</code></pre></div>
<p>Wir aktivieren also für den ersten Request die automatische Weitergabe der Session-ID über die <abbr title="Uniform Resource Identifier" lang="en">URIs</abbr>. Beim Start der Session wird dennoch das Cookie an den Client gesendet und – falls akzeptiert – beim nächsten Request mit gesendet und wir können ohne die transparente SessionID Unterstützung weiter machen.<br />
Das ist nicht gerade schön, aber die einzige Möglichkeit die ich sehe, unabhängig von Cookie-Einstellungen des Client mit Sessions zu arbeiten. Wenn jemand eine elegantere Möglichkeit kennt, nur her damit.</p>
<h3 id="suchmaschinen">Die Extrawurst für Suchmaschinen</h3>
<p>In den Webmaster-Guidelines von Google lesen wir:</p>
<blockquote lang="en" cite="http://www.google.com/support/webmasters/bin/answer.py?hl=en&#038;answer=40349"><p>If features such as JavaScript, cookies, session IDs, frames, DHTML, or Macromedia Flash keep you from seeing your entire site in a text browser, then spiders may have trouble crawling it.
</p></blockquote>
<p>Okay, dann starten wir die Session gar nicht, wenn wir einen Besucher als Robot identifizieren. Damit sparen wir Ressourcen und gleichzeitig verhindern wir, dass unschöne <abbr title="Uniform Resource Identifier" lang="en">URIs</abbr> über diesen Weg im Index auftauchen. Dazu verwende ich folgende Funktion, der ich den User-Agent-String zur Überprüfung übergebe:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">/** 
 * Findet einen Crawler anhand des 
 * User-Agent Headers
 *
 * @param str $ua (User-Agent) 
 * @return bool
 */
function isRobot( $ua = &#039;&#039; ) {

	if ( empty( $ua ) ) 
        	return FALSE;

	$robot_list = array(
		&#039;googlebot&#039;,
		&#039;Google-Sitemaps&#039;,
		&#039;feedfetcher&#039;,
		&#039;Slurp&#039;,
		&#039;YahooSeeker&#039;,
		&#039;msnbot&#039;,
		&#039;archive.org&#039;,
		&#039;teoma&#039;,
		&#039;ia_archiver&#039;,
		&#039;baiduspider&#039;,
		&#039;WebDataCentreBot&#039;,
		&#039;gonzo&#039;,
		&#039;DotBot&#039;,
		&#039;orgbybot&#039;,
		&#039;web-sniffer&#039;
	);
	foreach ( $robot_list as $needle ) {
		if( stripos( $ua, $needle ) )
			return TRUE;
        }

	return FALSE;
}</code></pre></div>
<p>Die Liste der User-Agents für Robots habe ich hauptsächlich meinen Zugriffsstatistiken entnommen. Sie ist natürlich weit davon entfernt vollständig zu sein, aber damit sollte man die wichtigsten Spider auf dem Markt erfasst haben. (Um die Laufzeiten des Scripts möglichst kurz zu halten, bietet es sich an, die Spiderbezeichnungen nach absteigender Besuchshäufigkeit in das Array aufzunehmen.) </p>
<h3 id="unsaubere_uri">Und falls doch mal eine <q>unsaubere</q> <abbr title="Uniform Resource Identifier" lang="en">URI</abbr> im Netz auftauch?</h3>
<p>Es ist natürlich nicht auszuschließen, dass ein Link bzw. die <abbr>URI</abbr> eine Session-ID enthält, vieleicht hat ein Besucher einfach die Adresszeile seines Browsers kopiert und verlinkt. Diesen Link werden die <abbr title="Suchmaschinen">Sumas</abbr> natürlich finden. Um dennoch diese <abbr>URIs</abbr> nicht zu indizieren hilft uns der Meta-Tag <q>robots</q> weiter:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php"># im HTML-head
if ( FALSE !== stripos( $_SERVER[ &#039;QUERY_STRING&#039; ], session_name() . &#039;=&#039; ) ) {

	echo &#039;&lt;meta name=&quot;robots&quot; content=&quot;noindex,follow&quot; /&gt;&#039;;
	# oder kanonische Adresse angeben (siehe Nachtrag)
}</code></pre></div>
<p>Damit verhindern wir, dass die zusätzliche <abbr title="Uniform Resource Identifier" lang="en">URI</abbr> in den Index gelangt. Eine sauberere, aber auch aufwändigere Möglichkeit ist folgende Funktion, die die Session-ID aus der angefragten URI entfernt und die bereinigte URI zurückgibt. An diese können wir dann den Besucher weiterleiten.</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">/**
 * entfernt die Session-ID aus dem Request-URI
 *
 * @return str
 */
function getCleanURL() {

	if ( FALSE !== strpos( $_SERVER[ &#039;QUERY_STRING&#039; ], session_name() ) ) {

		# String der Form PHPSESSID=abcde12345 entfernen
		$clean_url = str_replace(
			session_name() . &#039;=&#039; . $_GET[session_name()],
			&#039;&#039;,
			$_SERVER[&#039;REQUEST_URI&#039;]
		);
       
		# &amp; und ? entfernen, falls die am Ende des Strings stehen
		$clean_url = trim( $clean_url, &#039;&amp;?&#039; );

		# sollten wir die Session ID zwischen zwei anderen Get-Parametern, oder 
		# am anfang des Query-Strings herausgelöst haben, müssen wir noch aufräumen:
		$clean_url = str_replace(
			array( &#039;?&amp;&#039;, &#039;&amp;&amp;&#039; ), 
			array( &#039;?&#039;, &#039;&amp;&#039; ), 
			$clean_url 
		);

		return $clean_url;
	}
	else {
		return $_SERVER[&#039;REQUEST_URI&#039;];
	}
}</code></pre></div>
<p>An diese <abbr title="Uniform Resource Identifier" lang="en">URI</abbr> dürfen wir den Besucher nur dann weiterleiten, wenn wir sicher sind, dass er Besucher von einer externen Seite kommt. Andernfalls wäre der ganze Aufwand umsonst gewesen – wir würden unsere eigenen Session-IDs abschneiden. Außerdem brauchen wir die Funktion nicht zu bemühen, wenn gar keine Variablen in der <abbr>URI</abbr> mitgegeben wurden, d.h. der Query-String leer ist.</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php"># Ein Referer von der eigene Seite würde so aussehen
# http://meine-seite.tld… 
# also:
$my_referer = ( empty( $_SERVER[&#039;HTTPS&#039;] ) ? &#039;http&#039; : &#039;https&#039; ) . &#039;://&#039; . $_SERVER[ &#039;HTTP_HOST&#039; ];

if ( FALSE !== strpos( $_SERVER[ &#039;QUERY_STRING&#039; ], session_name() )
    &amp;&amp; 
    ! empty( $_SERVER[ &#039;HTTP_REFERER&#039; ] ) 
    &amp;&amp;
    FALSE === strpos( $_SERVER[ &#039;HTTP_REFERER&#039; ], $my_referer )
) {
	# ab zur Adresse ohne Session-ID
	header( 
		&#039;Location: &#039; 
			. ( empty( $_SERVER[ &#039;HTTPS&#039; ] ) ? &#039;http&#039; : &#039;https&#039; )
			. &#039;://&#039; . $_SERVER[ &#039;HTTP_HOST&#039; ] 
			. getCleanURL(), 
		TRUE, 
		301
	);
}</code></pre></div>
<h3>Anmerkung</h3>
<p>Die hier gezeigte Lösung ist aus der Not heraus geboren, da man nur wenig über das <q>Wie</q> des Session-Handlings im Internet findet – vor allem, wenn man sich die o.g. Ziele steckt, dass die Session unabhängig von Cookies verwendet werden kann und man das SEO-Problem und die Nutzerfreundlichkeit nicht ganz außer Acht lassen will. </p>
<p>Konkret werde ich diese Methode für ein Bestellformular auf einer Seite einsetzen, in dem keine sensiblen Daten in der Session gespeichert werden und die Session nicht obligatorisch für die Funktion der Seite ist. Nach einiger Zeit werde ich hier meine Erfahrungen mit dieser Methode veröffentlichen. </p>
<p><strong>Nachtrag vom 04.08.</strong><br />
Gestern abend laß ich im Blog von Matt Cutts von dem <a href="http://www.mattcutts.com/blog/canonical-link-tag/" rel="external"><code>cannonical</code> Link-Element</a>. Damit zeigt man den Suchmaschinen die kanonische Adresse an und vermeidet somit doppelte Seiten. Um diesen Tag sinnvoll einzusetzen, habe ich die Funktion <code>sendToCleanURL()</code> durch die Funktion <code>getCleanURL()</code> ersetzt, weil ich sie so flexiebler einsetzen kann:</p>
<div class="wp-cc wp-cc-php"><pre><code data-language="php">if ( FALSE !== stripos( $_SERVER[ &#039;QUERY_STRING&#039; ], session_name() . &#039;=&#039; ) ) {
     $cannonical_url = 
		  ( $_SERVER[&#039;HTTPS&#039;] ? &#039;http&#039; : &#039;https&#039;)
		. &#039;://&#039;.$_SERVER[&#039;HTTP_HOST&#039;]
		. getCleanURL();
     echo &#039;&lt;meta name=&quot;cannonical&quot; content=&quot;&#039; . $cannonical_url . &#039;&quot; /&gt;&#039;;  
}</code></pre></div>
<p>Sollten wir also eine unsaubere URI im Umlauf haben, so ist damit sichergestellt, dass die Suchmaschinen keine Probleme damit haben.<br />
Weitere Infos: <a href="http://googlewebmastercentral.blogspot.com/2009/02/specify-your-canonical.html" rel="external">specify your cannonical</a></p>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2009/seofreundliches-cookieunabhangiges-session-handling-in-php/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Die Shopping-Qual</title>
		<link>http://dnaber.de/blog/2009/die-shopping-qual/</link>
		<comments>http://dnaber.de/blog/2009/die-shopping-qual/#comments</comments>
		<pubDate>Wed, 01 Jul 2009 12:02:30 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[Onlineshop]]></category>
		<category><![CDATA[Usability]]></category>

		<guid isPermaLink="false">http://blog.dnaber.de/?p=540</guid>
		<description><![CDATA[Ich habe noch nie Klamotten im Internet bestellt. Seit heute weiß ich, warum ich ganz gut daran getan habe. Eigentlich gehe ich gern mal in die Stadt zum Shoppen um mich neu einzukleiden, sogar – man mag es kaum glauben – mit meiner besseren Hälfte (der ich hier mal kurz danken möchte, da sie bis …]]></description>
			<content:encoded><![CDATA[<p>Ich habe noch nie Klamotten im Internet bestellt. Seit heute weiß ich, warum ich ganz gut daran getan habe.<br />
Eigentlich gehe ich gern mal in die Stadt zum Shoppen um mich neu einzukleiden, sogar – man mag es kaum glauben – mit meiner besseren Hälfte (der ich hier mal kurz danken möchte, da sie bis jetzt für jeden Artikel das Lektorat übernommen hat). Eine gute Freundin von ihr hat uns zu ihrer Hochzeit eingeladen. Ein solches Ereignis bedarf natürlich auch angemessener Abendgarderobe seitens der Gäste, also haben wir beide gestern Nachmittag ganz „zwo-nullig“ eine virtuelle Shoppingtour gemacht. D.h. sie hat mir die entsprechenden Links über den Messenger geschickt, und ich durfte meine Meinung kund tun. Lange Rede – kurzer Sinn: ich bin mir jetzt ziemlich Sicher den Grund für die Pleite von Quelle zu kennen. <span id="more-540"></span></p>
<p>Das Martyrium fing an, als der erste Link zu otto.de über ICQ hereinkam. Neben diversen Ordnern (u.a. mit dem Namen des Shop-Systems) die sicherlich keine sind, enthielt die URL auch die 72-stellige Session-ID und das, obwohl ich Cookies akzeptiere. Eine phänomenale Voraussetzung um dem Kunden die Möglichkeit zu bieten, die angebotenen Artikel zu vergleichen und ggf. auch mal zu verlinken bzw. zu den Lesezeichen zu legen. </p>
<p>Hat man JavaScript in seinem Browser aktiviert, so gelangt man über gigantische Drop-Down-Listen irgendwann zu der gewünschten Artikelübersicht. Ich nutze in solchen Situationen gern die Funktion der mittleren Maustaste um einen Link in einem neuen Tab zu öffnen, um – den vorsintflutlichen Ladezeiten Rechnung tragend – die Übersicht weiter begutachten zu können während die Detailansicht des Artikels lädt, oder ein Artikel „bei Seite zu legen“ um ihn mit anderen zu vergleichen. Das geht allerdings nur, wenn die Seite echte Links hinter die Vorschaubildchen legt anstatt JavaScript-Funktionen. </p>
<p>Spätestens an diesem Punkt stecke ich als Besucher in einer Zwickmühle: schalte ich JavaScipt ab, wodurch das Layout teilweise zusammenfällt und mir wichtige Funktionen wie die vergrößerte Ansicht oder die Links auf ähnliche Produkte verwehrt bleiben, oder schalte ich es nicht ab, was zu steinzeitlichen Ladezeiten führt und bei mir grundlegende Browserfunktionen blockiert. Ich dachte bisher die Zeiten, in denen man JavaScript zum Selbstschutz deaktiviert wären vorbei. </p>
<p>Dieses Shopsystem setzen leider noch etliche weitere bekannte deutsche Onlineshops ein u.a. auch Quelle. Ich als normaler Besucher bin da schon nach fünf Minuten satt und gehe lieber in ein Geschäft. Einen Blick in den Quelltext habe ich mir erspart.</p>
<p>Ein Shopsystem von einem solchen Umfang umzusetzen ist ein Haufen Arbeit, weswegen dahinter auch eine Agentur steht, die sich auf diese Produkte spezialisiert hat. Was mich wundert ist, dass in der Entwicklung offenbar kein Gedanke an Benutzerfreundlichkeit geschweige denn an Barrierearmut verschwendet wurde oder aber die falschen Schlüsse gezogen wurden. Bei den Budgets die in solchen Bereichen fließen muss es doch drin sein eine Seite auch, oder gerade für den Nutzer zu optimieren. Vieleicht fehlt aber einfach noch das Bewusstsein, dass das Internet die Nutzer sind und nicht die Shops, die möglichst viel Profit raus holen wollen. Vieleicht habe ich auch gerade eine Marktlücke entdeckt – der barrierefreie Onlineshop? </p>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2009/die-shopping-qual/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Verabschiedung der Accesskeys</title>
		<link>http://dnaber.de/blog/2009/verabschiedung_der_accesskeys/</link>
		<comments>http://dnaber.de/blog/2009/verabschiedung_der_accesskeys/#comments</comments>
		<pubDate>Wed, 13 May 2009 11:44:41 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[Barrierefreiheit]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Usability]]></category>

		<guid isPermaLink="false">http://blog.dnaber.de/?p=396</guid>
		<description><![CDATA[Bis jetzt dachte ich, dieses Thema sei spätestens mit HTML 5 vom Tisch. Aber Qualitätsprüfautomaten für Websites und die WHATWG sind da anderer Ansicht. Da müssen wir noch mal drüber reden. Das accesskey-Attribut erlaubt dem Webdesigner für fokussierbare Elemente wie Links und Formularelemente eine Taste auf der Tastatur zu definieren, die dieses Element aktiviert bzw. …]]></description>
			<content:encoded><![CDATA[<p>Bis jetzt dachte ich, dieses Thema sei spätestens mit <abbr title="Hypertext Markup Language" lang="en">HTML 5</abbr> vom Tisch. Aber  <q>Qualitätsprüfautomaten</q> für Websites und die <abbr title="Web Hypertext Application Technology Working Group" lang="en">WHATWG</abbr> sind da anderer Ansicht. Da müssen wir noch mal drüber reden.<span id="more-396"></span></p>
<p>Das <q>accesskey</q>-Attribut erlaubt dem Webdesigner für fokussierbare Elemente wie Links und Formularelemente eine Taste auf der Tastatur zu definieren, die dieses Element aktiviert bzw. den Fokus auf das Element setzt. Je nach Browser kann der Nutzer mit einer bestimmten Tastenkombination die Elemente direkt anspringen, ohne erst <q>hin-Tab-en</q> zu müssen. Schön und gut, aber hier hören die theoretischen Vorteile aus meiner Sicht auch schon auf und die Probleme fangen an:</p>
<ol>
<li>Niemand merkt sich die Tastenkürzel für jede Website. Möchte man also den Vorteil der Tastenkürzel nutzen, muss man erstmal die <q>Bedienungsanleitung</q> suchen &#8211; jedes mal auf&#8217;s Neue. Man müsste sich also auf Standards einigen &#8211; was bis heute nur unzureichend geschehen ist.</li>
<li>Wirklich sichere Tasten, die von keinem Programm als Tastenkürzel in der Grundeinstellung verwendet werden, gibt es kaum. Man würde also zwangsläufig mit den vom Nutzer verwendeten Tastenkombinationen kollidieren.</li>
<li>Die Seite schreibt dem Nutzer vor, welche Tastenkürzel er zu verwenden hat.</li>
<li>Kommt es zu dem Fall, dass von der Website definierte Tastenkürzel die Einstellungen des Benutzers überschreiben, dann haben wir nicht nur eine Barriere, dann haben wir eine vollständige Blockade geschaffen. Und einen Besucher auf Dauer vergrault.</li>
</ol>
<p>Es mögen wohl auch diese Gründe gewesen sein, warum das Accesskey-Attribut bis jetzt aus dem <abbr title="Hypertext Markup Language" lang="en">HTML</abbr> 5 Standard rausflog. Und es sind die Gründe, warum ich mich entschieden habe, die Accesskeys nicht einzusetzen obwohl sie auch heute noch mancherorts empfohlen werden. Beim Qualidator erreicht man die 100% in <q lang="en">Accessibility</q> nur, wenn man auch Accesskeys definiert  hat. Na dann.</p>
<p>Die Annahme, mit Accesskeys mehr Zugänglichkeit zu schaffen, scheint also noch weit verbreitet zu sein &#8211; ein Grund, das Thema noch einmal kritisch zu beleuchten. Ein Weiterer ist die <a rel="external" href="http://blog.whatwg.org/this-week-in-html-5-episode-32#accesskey">Wiedereinführung des Acceskey-Attributes</a> durch die <abbr title="Web Hypertext Application Technology Working Group" lang="en">WHATWG</abbr> auf ihrem Blog. Der Unterschied zu <abbr title="Hypertext Markup Language">HTML</abbr> 4.01 soll sein, dass in <abbr>HTML</abbr> 5 jedes Element das accesskey Attribut bekommen darf, außerdem kann man nun mehrere Werte angeben. Was ist denn da los? Für <abbr>HTML</abbr> 6(!) wird vorgeschlagen dem Attribut anstatt einem festen Wert eine Rolle zuzuweisen: <code>accesskey="help"</code>. Ein guter Gedanke in die richtige Richtung, der Benutzer sucht sich dann selbst die Tastenkombination aus um zur Hilfe zu gelangen. Das wird bis dahin sicherlich überflüssig sein.</p>
<p>Die Idee hinter den Accesskeys ist prinzipiell nicht verkehrt. Nur ist die Umsetzung unglücklich geraten. Einen ganz anderen Weg sehe ich in HTML 5. Eine bisher recht sinnfreie <q>Div-Suppe</q> weicht damit einem Dokument, welches mit Elementen wie <code>&lt;nav&gt;, &lt;header&gt;, &lt;article&gt;</code> wesentlich mehr Semantik bietet. Es ist dann eine Sache der Implementierung dem Nutzer die Möglichkeit zu bieten, zwischen den einzelnen Bereichen zu navigieren. Eine weitere, zur Zeit schon wesentlich praxistauglichere Möglichkeit bietet <a href="http://www.w3.org/WAI/intro/aria.php" rel="external"><abbr title="Web Accessibility Initiative - Accessible Rich Internet Applications" lang="en">WAI-ARIA</abbr></a> mit den sog. <q lang="en">Landmarks</q>, die einzelnen Bereichen wie Navigation, Hauptinhalt, Header etc. Rollen zuweist. Dazu nur einige Links, da dass schon wieder einen ganzen Artikel füllen würde.</p>
<ul>
<li><a href="http://www.w3.org/WAI/intro/aria" rel="external" lang="en">Überblick über <abbr>WAI-ARIA</abbr>(en)</a></li>
<li><a href="http://www.vorsprungdurchwebstandards.de/theory/7-gruende-wai-aria-landmarks-sofort-einzusetzen/" rel="external">7 Gründe Landmarks sofort einzusetzen</a></li>
<li><a href="http://www.hessendscher.de/wai-aria/" rel="external">Einführung in <abbr>WAI-ARIA</abbr></a></li>
</ul>
<p>Accesskeys waren gut gemeint, sind aber in der Praxis eher ungeeignet, bzw. sogar störend und sollten, wie das tabindex-Attribut, nicht eingesetzt werden um die Seite <q>Barrierefrei(er)</q> zu gestalten, da damit im schlimmsten Fall das Gegenteil erreicht wird.</p>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2009/verabschiedung_der_accesskeys/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Externe Links auszeichnen und hervorheben</title>
		<link>http://dnaber.de/blog/2009/externe_links_hervorheben/</link>
		<comments>http://dnaber.de/blog/2009/externe_links_hervorheben/#comments</comments>
		<pubDate>Thu, 07 May 2009 15:31:14 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Links]]></category>
		<category><![CDATA[Usability]]></category>

		<guid isPermaLink="false">http://blog.dnaber.de/?p=349</guid>
		<description><![CDATA[Geht es euch auch so? Wenn ich durch das Web surfe und mir nicht sicher bin ob der Link da nun auf eine interne Seite zeigt, oder zu einer fremden Seite führt, so wandert der Blick meist erstmal Richtung Statuszeile im Browser, um zu sehen, wo es denn hin geht. An dieser Stelle finde ich …]]></description>
			<content:encoded><![CDATA[<p>Geht es euch auch so? Wenn ich durch das Web surfe und mir nicht sicher bin ob der Link da nun auf eine interne Seite zeigt, oder zu einer fremden Seite führt, so wandert der Blick meist erstmal Richtung Statuszeile im Browser, um zu sehen, wo es denn hin geht. An dieser Stelle finde ich es immer von Vorteil, wenn der Autor seine externen Links, in Form einer kleinen Pfeilgrafik zum Beispiel, gesondert hervorhebt. <span id="more-349"></span></p>
<p>Bisher habe ich das in diesem Fall naheliegendste getan: den Links eine extra Klasse verpasst und diese dann per <abbr title="Cascading Style Sheets" lang="en">CSS</abbr> entsprechend geschönt. </p>
<div class="wp-cc wp-cc-html"><pre><code data-language="html">&lt;a href=&quot;#&quot; class=&quot;extern&quot;&gt;Linktext&lt;/a&gt;</code></pre></div>
<div class="wp-cc wp-cc-css"><pre><code data-language="css">a.extern {
	background: transparent url(extern.gif) center left no-repeat;
	padding-left: 17px;
}</code></pre></div>
<p>Nun sieht man seit einiger Zeit, dass vor allem <abbr title="Content Management System" lang="en">CMS</abbr> und Blogsysteme von vornherein externe Links gern mal mit dem Attribut <q>rel</q> und den Werten  <q>external</q> (und nicht selten mit <q>nofollow</q>) auszeichnen.  Dass <q>nofollow</q> als präventiver Spamschutz unsinnig ist, <a href="http://toscho.de/2009/no-no-no-nofollow/" rel="external">hab nicht nur</a> <a href="http://blog.dnaber.de/2009/nofollow_nein_danke/">ich schon mal geschrieben</a>. Mir gehts es hier aber um das <q>external</q>. Das taucht zwar erst in der vorläufigen <a href="http://dev.w3.org/html5/spec/Overview.html#linkTypes" rel="external">HTML 5 Spezifikation</a> auf, validiert aber auch prima mit den <abbr>HTML</abbr> 4.01 und <abbr>XHTML</abbr> 1.0 Doctypes. Wenn das Attribut also schon da ist, wozu eine extra Klasse vergeben? <abbr title="Cascading Style Sheets" lang="en">CSS</abbr> bietet dafür den Attributselektor an:</p>
<div class="wp-cc wp-cc-css"><pre><code data-language="css">a[rel~=external] {
	background:transparent url(extern.gif) center left no-repeat;
	padding-left:17px;
}</code></pre></div>
<div class="wp-cc wp-cc-html"><pre><code data-language="html">&lt;a href=&quot;#&quot; rel=&quot;external&quot;&gt;Externer Link&lt;/a&gt;</code></pre></div>
<p>Bis hierher versteht das sogar der <abbr title="Internet Explorer 7">IE 7</abbr>. Die Puristen unter uns verzichten vieleicht gern auf überflüssigen Grafikballast. Warum auch nicht, die <a href="http://en.wikipedia.org/wiki/Arrow_(symbol)" rel="external">Unicodetabelle hält so einiges an Pfeilen bereit.</a> So sieht die Kür im CSS aus:</p>
<div class="wp-cc wp-cc-css"><pre><code data-language="css">a[rel~=external]:after {
	/**  
	 * Allen Links folgt ein  geschütztes Leerzeichen U+00A0 
	 * und ein Nord-Ost-Pfeil U+2197
	 */
	content: &quot; 0A02197&quot;;
}</code></pre></div>
<p>Hier steigt allerdings auch der <abbr>IE 7</abbr> aus, der mit den Pseudoelementen <code>:before</code> und <code>:after</code> nicht klar kommt. Die Extrawurst könnte in Form einer Hintergrundgrafik gereicht werden.</p>
<p>Sieht man mal von der Tatsache ab, dass sowohl der IE6 als <a href="http://www.thestyleworks.de/ref/se_attribute.shtml#handheld" rel="external">auch Mobile Geräte</a> die Attributselektoren ignorieren, und legt man Wert auf schlankes und semantisches Markup, so kann man die Umsetzung mit Hilfe des <q>rel</q>-Attribut der Variante mit eigener Klasse durchaus vorziehen, da so gleichzeitig ein semantischer Mehrwert geschaffen ist.</p>
<p>Das bleibt natürlich nicht auf externe Links beschränkt. Vorhergehende, oder nachfolgende Seiten eines zusammenhängenden Artikels werden mit <code>rel="prev"</code> bzw. <code>rel="next"</code> ausgezeichnet. Ein Pfeil nach links oder nach rechts verdeutlicht dann die Sache ( ←,→ )</p>
<p>Eine kurze Bemerkung zu dem Target-Attribut sei noch gestattet. Sucht man nach Informationen zu <q>rel</q> und <q>external</q>, findet man hier und da Vergleiche zu <code>target="_blank"</code> oder gar Versuche, das fehlende Target-Attribut in den Srict-Doctypes durch <code>rel="external"</code> und diverse JavaScripts zu ersetzen. PFUI SPINNE! Liebe Webmaster, lasst dem Besucher doch bitte selber die Entscheidung was er wo in welchem Fenster oder Tab öffnet! Danke.</p>
<p><strong>Nachtrag 25.05.09</strong><br />
In den Kommentartexten werden die Links nicht automatisch mit dem Attribut <code>rel="external"</code> versehen. Da ich nur ungern in dem WordPress-Code herumdocktoren möchte, genemige ich mir hier schon eine kleine portion <abbr title="Cascading Style Sheets Version 3" lang="en">CSS 3</abbr>: </p>
<p>Alle Links in den Kommentaren, die mit <q>http://</q> beginnen, bekommen einen Pfeil hinten angesetzt:</p>
<div class="wp-cc wp-cc-css"><pre><code data-language="css">a[href^=&quot;http://&quot;]:after {
	content: &quot; 0A02197&quot;;
}</code></pre></div>
<p>Die Links, die auf meine Subdomain zeigen, bekommen den wieder überschrieben: </p>
<div class="wp-cc wp-cc-css"><pre><code data-language="css">a[href^=&quot;http://blog.dnaber.de&quot;]:after {
	content: &quot;&quot; ! important;
}</code></pre></div>
]]></content:encoded>
			<wfw:commentRss>http://dnaber.de/blog/2009/externe_links_hervorheben/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

