<?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>toscho.design&#187; Markup</title>
	<atom:link href="http://toscho.de/thema/markup/feed/" rel="self" type="application/rss+xml" />
	<link>http://toscho.de</link>
	<description>Redaktion und schwer geprüftes Webdesign aus Halle (Saale)</description>
	<lastBuildDate>Sat, 07 Jan 2012 14:55:02 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>daily</sy:updatePeriod>
	<sy:updateFrequency>4</sy:updateFrequency>
	
		<item>
		<title>WordPress-Plugin: Magische Widgets</title>
		<link>http://toscho.de/2011/wordpress-plugin-magische-widgets/</link>
		<comments>http://toscho.de/2011/wordpress-plugin-magische-widgets/#comments</comments>
		<pubDate>Wed, 05 Jan 2011 14:19:56 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Markup]]></category>
		<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[backend]]></category>
		<category><![CDATA[Javascript]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1768</guid>
		<description><![CDATA[Wie man Widgets auch in die heikelsten Stellen schiebt. Download und ausführliche Dokumentation inklusive.]]></description>
			<content:encoded><![CDATA[<p class="downloadlink"><a href="http://wordpress.org/extend/plugins/magic-widgets/">Download auf wordpress.org</a></p>
<p>Neulich stand ich vor einem spannenden Problem: Ein Freund wollte eine Zeile JavaScript und einen Link auf ein Stylesheet in den Header seines <a href="http://toscho.de/angebote/wordpress/themes/" title="Ich baue auch eigene!">Themes</a> bringen. Dieses Theme stammt aus dem <a href="http://wordpress.org/extend/themes/">Verzeichnis auf wordpress.org</a>, und es sollte weiterhin automatisch aktualisiert werden. Ich konnte also nicht direkt hineinschreiben.<br />
Nun hätte ich ein <a href="http://codex.wordpress.org/Child_Themes">Child-Theme</a> anlegen können, aber das fand ich dann etwas zu umständlich. Obendrein wäre das eine Speziallösung gewesen, und ich bin nun einmal Generalist.<br />
Ich wollte eine Lösung, die ich wiederverwenden kann. Und ihr vielleicht auch.</p>
<p>Zeit für einen kleinen Zaubertrick.</p>
<h2>Das Konzept</h2>
<p>Im Kopfteil eines jeden Themes, das auf wordpress.org zugelassen wird, finden wir die Funktion <a href="http://codex.wordpress.org/Plugin_API/Action_Reference/wp_head">wp_head</a>. Diese löst eine gleichnamige Aktion aus. Wenn wir uns in diese Aktion einklinken, können wir tun, was immer uns beliebt. Zum Beispiel Text ausgeben.</p>
<p>Als Plugin wäre das ein Vierzeiler:</p>
<pre class="notranslate">&lt;?php
<i>/* Plugin Name: Simple Head Insert */</i>
add_action( <code class="string">'wp_head'</code>, <code class="string">'simple_head_insert'</code> );
function simple_head_insert() { echo <code class="string">'&lt;!-- Buh! --&gt;'</code>; }</pre>
<p>Ganz nett, aber irgendwie … nicht gut genug. Es ist immer noch zu speziell, weil die Ausgabe fest im PHP-Code steht. Wenn die Ausgabe oder die Position geändert werden soll, muß das Plugin umgeschrieben werden. Das ist sehr fehleranfällig.</p>
<p>Jemand anderes möchte vielleicht Code im Backend einfügen. Der muß sich das Plugin im Grunde selbst neu schreiben.</p>
<p>Also habe ich mir gedacht: Dann hänge ich doch einfach an die Aktion <code>widgets_init</code> eine Funktion, die eine Instanz einer Klasse erzeugt, die für die Aktionen <code>wp_head</code>, <code>wp_footer</code>, <code>admin_head</code> und <code>admin_footer</code> eine weitere Funktion registriert, die wiederum den Inhalt einer ebenfalls registrierten Sidebar ausgibt, die man frei mit einem Widget befüllen kann, das ich in eine weiteren Klasse gepackt habe.</p>
<p>Klarsoweit?</p>
<p>Nicht? Dann kannst du dir den <strong><a href="https://github.com/toscho/WP-Magic-Widgets">Code auf GitHub ansehen und herunterladen</a></strong>. Für die Eingabe des HTML-Codes habe ich eine einfachere Variante des nativen Text-Widgets geschrieben; sie heißt <strong>Unfiltered Text Widget</strong>.</p>
<p>150 Zeilen mehr als die erste Version, dafür um so mächtiger. Frank wird mich sicher noch ermahnen, daß ich doch eine Sprachdatei einarbeiten sollte. Keine Lust. Insgesamt finde ich den Code immer noch angenehm einfach und enorm flexibel zugleich. Ich bin ausnahmsweise und sicher nur für kurze Zeit mal zufrieden damit.</p>
<h2>Einsatz</h2>
<p>Jetzt wollen wir uns noch ansehen, wie man das verdammte Ding benutzt.</p>
<p>Zunächst laden wir es herunter, packen es ins Pluginverzeichnis und aktivieren es. Ja, sehr spannend.</p>
<p><img src="http://toscho.de/wp-content/uploads/2011/01/activate.png" alt="" title="Plugin aktivieren" width="588" height="109" class="alignnone size-full wp-image-1774 border" /></p>
<p>Jetzt gehen wir auf »Design/Widgets«, und da haben wir vier neue Sidebars und ein neues Widget namens »Unfiltered Text«.</p>
<p><img src="http://toscho.de/wp-content/uploads/2011/01/sidebars-backend.png" alt="" title="Sidebars im Backend" width="309" height="281" class="alignnone size-full wp-image-1775 border" /><img src="http://toscho.de/wp-content/uploads/2011/01/unfiltered-text-widget.png" alt="" title="Widget Unfiltered Text" width="274" height="71" class="alignnone size-full wp-image-1776 border" /></p>
<p>Wir klappen zur Probe mal die Box für den »Front End Header« auf und ziehen das neue Widget hinein. Das können wir übrigens überall benutzen, auch in anderen Sidebars.</p>
<p>In das Eingabefeld schreiben wir ein Script:</p>
<pre class="notranslate">&lt;script&gt;alert('Buh!');&lt;/script&gt;</pre>
<p><img src="http://toscho.de/wp-content/uploads/2011/01/unfiltered-text-widget-edit.png" alt="" title="Widget-Editor" width="375" height="339" class="alignnone size-full wp-image-1773 border" /></p>
<p>Und dann rufen wir das Frontend unserer Website auf:</p>
<p><img src="http://toscho.de/wp-content/uploads/2011/01/script-test.png" alt="" title="Script-Test" width="347" height="129" class="alignnone size-full wp-image-1777" /></p>
<p>Faaaantastisch! Jetzt kann uns nichts mehr bremsen.</p>
<ul>
<li>In den Footer des Frontends können wir den Tracking-Code des <a href="http://toscho.de/2009/piwik-ueberblick-installation/">Analyse-Tools unserer Wahl</a> eingeben – und schon geht das Gezähle los.</li>
<li>In den Header des Backends können wir schreiben:
<pre class="notranslate">&lt;style&gt;#footer{display:none}&lt;/style&gt;</pre>
<p>Und – zack! – ist der Footer weg.</li>
<li>Wir können den JavaScript-Code des <a href="http://toscho.de/2010/wordpress-plugin-icon-to-link/">Plugins Icon to Link</a> einbauen.</li>
<li>Wer so richtig Spaß haben will, schreibt sich dies in beide Header:
<pre class="notranslate">&lt;style&gt;body{display:none}&lt;/style&gt;</pre>
</li>
</ul>
<p>Für weitere kreative Ideen und die obligatorischen … Verbesserungsvorschläge stehen euch die Kommentare offen.</p>
<h2>Anpassen</h2>
<p>Für Hacker habe ich zwei Filter eingebaut, die eine Kombination des Plugins mit dem eigenen Theme erlauben:</p>
<ol>
<li><code class="string">'magic_widgets_actions'</code> übergibt einen Array mit den Aktionen. Den können wir per Filter in der <code>functions.php</code> frei ändern:
<pre class="notranslate">add_filter( <code class="string">'magic_widgets_actions'</code>, <code class="string">'change_magic_widget_actions'</code>, 10, 1 );
function change_magic_widget_actions( <var>$arr</var> )
{
    <i>// Add</i>
    <var>$arr</var>[<code class="string">'loop_start'</code>] = <code class="string">'Post List Start'</code>;
    <i>// Remove</i>
    unset( <var>$arr</var>[<code class="string">'admin_footer'</code>] );
    <i>// Rename</i>
    <var>$arr</var>[<code class="string">'admin_head'</code>] = <code class="string">'HTML-Kopf Administration'</code>;
    return <var>$arr</var>;
}</pre>
<p>Mehr Aktionen findet ihr im <a href="http://codex.wordpress.org/Plugin_API/Action_Reference">Codex</a>, bei <a href="http://adambrown.info/p/wp_hooks">Adam R Brown</a> und auf <a href="http://docs.der-design.com/wp-actions-filters/">der-design.com</a>.</p>
<p>Ich habe mich auf die vier oben genannten Aktionen beschränkt, um die Widgetliste im Backend übersichtlich zu halten. Im Prinzip können wir aber auch 40 oder 400 Aktionen ansprechen.
</li>
<li>Den Namen <strong>Unfiltered Text</strong> können wir über den Filter <code class="string">'magic_widgets_name'</code> ändern (I18n für Arme!).</li>
</ol>
<p>Fehlt was? Funktioniert alles?</p>
<h2>Weitere Artikel dazu hier im Blog</h2>
<ul>
<li><a href="http://toscho.de/2010/wordpress-tutorial-ein-framebreaker-plugin-schreiben/">WordPress-Tutorial: Ein Framebreaker-Plugin schreiben</a></li>
<li><a href="http://toscho.de/2010/wordpress-tutorial-eigenes-widget-schreiben/">WordPress-Tutorial: Eigenes Widget schreiben</a></li>
<li><a href="http://toscho.de/2009/wordpress-parallele-widgets/">WordPress: Parallele Widgets</a></li>
<li><a href="http://toscho.de/2010/wordpress-plugin-backend-style-enhancements/">WordPress-Plugin: Backend Style Enhancements</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2011/wordpress-plugin-magische-widgets/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>WordPress: Internet Explorer ohne CSS-Hacks ansprechen</title>
		<link>http://toscho.de/2010/wordpress-internet-explorer-ohne-css-hacks-ansprechen/</link>
		<comments>http://toscho.de/2010/wordpress-internet-explorer-ohne-css-hacks-ansprechen/#comments</comments>
		<pubDate>Tue, 28 Sep 2010 07:43:50 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Browser]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Markup]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Trickkiste]]></category>
		<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1731</guid>
		<description><![CDATA[Wie man jede Version des Internet Explorers einfach mit einem Klassennamen ansprechen kann. Extra Code für WordPress-Themes inklusive.]]></description>
			<content:encoded><![CDATA[<p><img src="http://toscho.de/wp-content/uploads/2010/09/ie-150.png" alt="" title="ie-150" width="150" height="150" class="alignright size-full wp-image-1732" />Den Internet Explorer betrachten die meisten Webentwickler zu Recht als chronische Krankheit. Neben anderen Browsern sieht auch die kommende Version 9 <a href="http://www.findmebyip.com/litmus">eher bedrückend</a> aus. Ehe wir diesem Browser keine Extrawurst mehr braten müssen, wird noch viel Zeit vergehen.</p>
<p>Um den IE im Stylesheet gesondert anzusprechen, brauchen wir weder Hacks im CSS noch eine zusätzliche Datei oder gar (pfui!) eine serverseitige Browserweiche. Wir müssen nur das Element <code>&lt;html&gt;</code> über <a href="http://msdn.microsoft.com/en-us/library/ms537512(VS.85).aspx" lang="en" hreflang="en">Conditional Comments</a> anpassen. Diese Idee <a href="http://paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/" hreflang="en">hatte Paul Irish schon 2008</a>.</p>
<p>Ich habe das neulich in einem WordPress-Theme eingesetzt und mag es so sehr, daß ich künftig all meine Themes damit ausrüsten werde.<br />
Ein wenig umständlich: Die Sprachattribute werden in WordPress mit der Funktion <a href="http://codex.wordpress.org/Function_Reference/language_attributes"><code>language_attributes()</code></a> erzeugt – und die hat ein fest eingebautes <code>echo</code>, das man nicht abschalten kann. Ich will nun nicht drei Meter Code in der <code>header.php</code> stehen haben, deshalb habe ich mir zwei kleine Funktionen gebaut. Die Funktion <code>get_language_attributes()</code> ist obendrein etwas schlanker als das Original, und sie gibt das Attribut <code>dir</code> nur aus, wenn der Text von rechts nach links läuft. Andernfalls ist es an dieser Stelle überflüssig.</p>
<p>Doch zum Code, er gehört in die <code>functions.php</code>:</p>
<div class="php-code">
<pre class="notranslate php"><span class='openclose'>&lt;?php
</span><i class='comment'>/**
 * html5 start tag + language attribute + conditional tags for IE Win
 * @link   <a href="http://paulirish.com/?p=88">http://paulirish.com/?p=88</a>
 * @param  bool $print
 * @return void|string
 */</i>
<span class='internal'>function</span> htmlstart(<var>$print</var> <span class='operator'>=</span> <span class='internal'>TRUE</span>)
{
    <var>$out</var>  <span class='operator'>=</span> <span class='string'>&#039;&lt;!Doctype html&gt;&#039;</span>;
    <var>$lang</var> <span class='operator'>=</span> get_language_attributes();
    <var>$ies</var>  <span class='operator'>=</span> <span class='internal'>array</span> (
        6 <span class='operator'>=&gt;</span> <span class='string'>&#039;lte6 lte7 lte8&#039;</span>
    ,   7 <span class='operator'>=&gt;</span> <span class='string'>&#039;lte7 lte8&#039;</span>
    ,   8 <span class='operator'>=&gt;</span> <span class='string'>&#039;lte8&#039;</span>
    ,   9 <span class='operator'>=&gt;</span> <span class='string'>&#039;&#039;</span>
    );

    <span class='internal'>foreach</span> ( <var>$ies</var> <span class='internal'>as</span> <var>$n</var> <span class='operator'>=&gt;</span> <var>$class</var> )
    {
        <var>$out</var> <span class='operator'>.=</span> &quot;<span class='string'>&lt;!--[if IE </span><var>$n</var><span class='string'>]&gt;&lt;html </span><var>$lang</var><span class='string'> class=&#039;ie ie</span><var>$n</var><span class='string'> </span><var>$class</var><span class='string'> lte9&#039;&gt;&lt;![endif]--&gt;</span>&quot;;
    }

    <var>$out</var> <span class='operator'>.=</span> &quot;<span class='string'>&lt;!--[if !IE]&gt;&lt;!--&gt;&lt;html </span><var>$lang</var><span class='string'>&gt;&lt;!--&lt;![endif]--&gt;</span>&quot;;

    <span class='internal'>if</span> ( <span class='operator'>!</span> <var>$print</var> )
    {
        <span class='internal'>return</span> <var>$out</var>;
    }

    <span class='internal'>print</span> <var>$out</var>;
}

<span class='internal'>if</span> ( <span class='operator'>!</span> <a href='http://php.net/function_exists'>function_exists</a>(<span class='string'>&#039;get_language_attributes&#039;</span>) )
{
    <i class='comment'>/**
     * Returns the language attributes.
     *
     * Unobstrusive copy from the core.
     * Requires WP 3.0+
     *
     * @param string $doctype The type of html document (xhtml|html).
     */</i>
    <span class='internal'>function</span> get_language_attributes(<var>$doctype</var> <span class='operator'>=</span> <span class='string'>&#039;html&#039;</span>) {
        <var>$output</var> <span class='operator'>=</span> is_rtl() <span class='operator'>?</span> <span class='string'>&#039;dir=&quot;rtl&quot;&#039;</span> <span class='operator'>:</span> <span class='string'>&#039;&#039;</span>;

        <span class='internal'>if</span> ( <var>$lang</var> <span class='operator'>=</span> get_bloginfo(<span class='string'>&#039;language&#039;</span>) )
        {
            <var>$output</var> <span class='operator'>.=</span> ( ( get_option(<span class='string'>&#039;html_type&#039;</span>) <span class='operator'>!=</span> <span class='string'>&#039;text/html&#039;</span>
                <span class='operator'>||</span> <var>$doctype</var> <span class='operator'>==</span> <span class='string'>&#039;xhtml&#039;</span> )
                <span class='operator'>?</span> <span class='string'>&#039; xml:&#039;</span> <span class='operator'>:</span> <span class='string'>&#039;&#039;</span>) <span class='operator'>.</span> <span class='string'>&#039;lang=&quot;&#039;</span> <span class='operator'>.</span> <var>$lang</var> <span class='operator'>.</span> <span class='string'>&#039;&quot;&#039;</span>;
        }

        <span class='internal'>return</span> apply_filters(<span class='string'>&#039;language_attributes&#039;</span>, <var>$output</var>);
    }
}</pre>
</div>
<p>Im Theme rufen wir die Funktion dort auf, wo früher die Doctype-Deklaration und das Start-Tag standen.<br />
Die Ausgabe sieht (hier aufgehübscht) etwa so aus:</p>
<pre class="notranslate html">&lt;!Doctype html&gt;
&lt;!--[if IE 6]&gt;
    &lt;html lang=<code class="string">"de-DE"</code> class=<code class="string">'ie ie6 lte6 lte7 lte8 lte9'</code>&gt;
&lt;![endif]--&gt;
&lt;!--[if IE 7]&gt;
    &lt;html lang=<code class="string">"de-DE"</code> class=<code class="string">'ie ie7 lte7 lte8 lte9'</code>&gt;
&lt;![endif]--&gt;
&lt;!--[if IE 8]&gt;
    &lt;html lang=<code class="string">"de-DE"</code> class=<code class="string">'ie ie8 lte8 lte9'</code>&gt;
&lt;![endif]--&gt;
&lt;!--[if IE 9]&gt;
    &lt;html lang=<code class="string">"de-DE"</code> class=<code class="string">'ie ie9 lte9'</code>&gt;
&lt;![endif]--&gt;
&lt;!--[if !IE]&gt;&lt;!--&gt;
    &lt;html lang=<code class="string">"de-DE"</code>&gt;
&lt;!--&lt;![endif]--&gt;</pre>
<p>Nein, das ist kein sehr schönes Markup mehr. Aber so richtig schlimmes auch nicht. Obendrein validiert es.</p>
<p>Im Stylesheet können wir den Internet Explorer jetzt ganz einfach mit der passenden Klasse ansprechen:</p>
<pre class="notranslate">.ie8
{
    top:        10px;
}
.lte7
{
    top:        15px;
}</pre>
<p>Das kann ich mir viel besser merken als Kommentarhacks oder Spielereien mit ungültigen Selektoren und Eigenschaften.</p>
<p>Mehrere Internet Explorer auf einem Windows kann man sich mit der <a href="http://utilu.com/IECollection/" lang='en' hreflang='en'>Utilo IE Collection</a> einrichten. Zum Testen der Conditional Comments habe ich im Labor eine kleine Seite eingerichtet: <a href="http://labs.toscho.de/test/conditional-comments/">CC-Test</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2010/wordpress-internet-explorer-ohne-css-hacks-ansprechen/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>WordPress: Sprache der Ausgabe einstellen</title>
		<link>http://toscho.de/2010/wordpress-sprache-der-ausgabe-einstellen/</link>
		<comments>http://toscho.de/2010/wordpress-sprache-der-ausgabe-einstellen/#comments</comments>
		<pubDate>Mon, 02 Aug 2010 17:00:52 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Markup]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Sprache]]></category>
		<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1707</guid>
		<description><![CDATA[Wie man die <i lang="en">Language-Tags</i> in WordPress an die tatsächlich verwendete Sprache anpaßt. Hintergründe, Links und Beispielcode inklusive.]]></description>
			<content:encoded><![CDATA[<!--TOC-->
<h2>Meine Sprache</h2>
<p>Ich bin kein viel versprechendes Talent. Aber ein vielversprechendes … nun, lassen wir das. Will sagen: Mich hat die <a href="http://www.schriftdeutsch.de/ortr-rat.htm">Reform der deutschen Rechtschreibung im Jahre 1996</a> nicht überzeugt. Die Reformen der Reform ebensowenig. Deshalb halte ich mich heute überwiegend an die <em>klassische</em> Orthographie, die seit dem letzten amtlichen Eingriff 1901 ganz allmählich durch den allgemeinen Sprachgebrauch entwickelt wurde.<br />
Und gerade weil ich den Gedanken einer <em>organischen</em> Entwicklung so mag, halte ich mich nicht immer genau an die Regeln von 1995: Ich übertrete sie, wenn mein Sprachgefühl mir dazu rät.</p>
<p>Im Großen aber muß ich meine Sprache für Maschinen als <a hreflang="en" href="http://www.iana.org/assignments/lang-tags/de-DE-1901"><code>de-DE-1901</code></a> kennzeichnen — der <a hreflang="en" lang="en" title="Request for comments 3066" href="ftp://ftp.rfc-editor.org/in-notes/rfc3066.txt">RFC 3066</a> verlangt es so.</p>
<p class="wideimg"><img src="http://toscho.de/wp-content/uploads/2010/08/language-tags-500.png" alt="" width="500" height="282" class="alignnone size-full wp-image-1708" /></p>
<h2>Sprachausgabe in WordPress</h2>
<p>In WordPress wird die Sprache des Blogs in der Datei <code>wp-config.php</code> angegeben:</p>
<pre class="notranslate">define (<code class="string">'WPLANG'</code>, <code class="string">'de_DE'</code>);</pre>
<p>Dann holt sich das CMS automagisch die <a href="http://wordpress-deutschland.org/download/sprachdatei/">passende Sprachdatei</a> namens <samp>de_DE.mo</samp>. Deshalb bringt es mir nichts, die präzise Sprache in der <code>wp-config.php</code> zu setzen: Eine Datei <samp>de_DE_1901.mo</samp> existiert ja leider nicht, und ich möchte auch nicht nach jeder Aktualisierung den Dateinamen hinterherrennen müssen.</p>
<p>Macht nichts.</p>
<p>In der Ausgabe für den Leser, im <i lang="en">Frontend</i> also, wird die Sprache nur an zwei Stellen angegeben: Im <code>lang</code>-Attribut des Elementes <code>html</code>:</p>
<pre class="notranslate">&lt;html lang=<code class="string">"de-DE-1901"</code>&gt;</pre>
<p>Und im Feed, beispielsweise in der Datei <code>/wp-includes/feed-atom.php</code>:</p>
<pre class="notranslate">xml:lang="&lt;?php echo get_option(<code class="string">'rss_language'</code>); ?&gt;"</pre>
<p>Im Theme kann man diese Angabe entweder konkret in den Code schreiben oder die Funktion <a hreflang="en" href="http://codex.wordpress.org/Function_Reference/language_attributes"><code>language_attributes()</code></a> verwenden:</p>
<pre class="notranslate">&lt;html &lt;?php language_attributes(); ?&gt;&gt;</pre>
<p>Diese Funktion gibt die Schreibrichtung und die Sprache aus. Da <code>ltr</code> der <a href="http://www.w3.org/TR/html401/struct/dirlang.html#h-8.2.2" hreflang="en">Standardwert für das Attribut <code>dir</code></a> ist, kann das hier weggefiltert werden.</p>
<p>Die beiden Filter, die wir ansprechen müssen, lauten <code class="string">'language_attributes'</code> und <code class="string">'pre_option_rss_language'</code>.</p>
<h2>Code zum Anpassen</h2>
<p>Ich habe mir dafür eine kleine Klasse geschrieben, die ich in der functions.php des Themes einfach per <a href="http://php.net/require"><code>require</code></a> aufrufe:</p>
<p class="downloadlink"><a href="http://gist.github.com/raw/504854/4aeaa5c3bce59206401f1a6b5a92c69d906a2afa/class.Toscho_Language_Filter.php">Download class.Toscho_Language_Filter.php</a></p>
<div class="php-code">
<pre class="notranslate php"><span class='openclose'>&lt;?php
</span><i class='comment'>/**
 * Adjust the public visible language declarations.
 *
 * @author &quot;Thomas Scholz&quot; <a href="http://toscho.de">http://toscho.de</a>
 * @version 1.0
 */</i>
<span class='internal'>class</span> Toscho_Language_Filter
{
    <i class='comment'>/**
     * @var string
     */</i>
    <span class='internal'>public</span> <span class='internal'>static</span> <var>$lang</var> <span class='operator'>=</span> <span class='string'>&#039;de&#039;</span>;

    <i class='comment'>/**
     * Pseudo constructor.
     *
     * @param  string $lang The language according to …
     * @link   <a href="http://www.evertype.com/standards/iso639/iana-lang-assignments.html">http://www.evertype.com/standards/iso639/iana-lang-assignments.html</a>
     * @return void
     */</i>
    <span class='internal'>public</span> <span class='internal'>static</span> <span class='internal'>function</span> setup(<var>$lang</var> <span class='operator'>=</span> <span class='string'>&#039;de-DE-1901&#039;</span>)
    {
        self<span class='operator'>::</span><var>$lang</var> <span class='operator'>=</span> <var>$lang</var>;

        add_filter(
            <span class='string'>&#039;language_attributes&#039;</span>
        ,   <span class='internal'>array</span> ( <span class='constant'>__CLASS__</span>, <span class='string'>&#039;html&#039;</span> )
        );
        add_filter(
            <span class='string'>&#039;pre_option_rss_language&#039;</span>
        ,   <span class='internal'>array</span> ( <span class='constant'>__CLASS__</span>, <span class='string'>&#039;get_lang&#039;</span> )
        );
    }

    <i class='comment'>/**
     * Returns the language string.
     * @return string
     */</i>
    <span class='internal'>public</span> <span class='internal'>static</span> <span class='internal'>function</span> get_lang()
    {
        <span class='internal'>return</span> self<span class='operator'>::</span><var>$lang</var>;
    }

    <i class='comment'>/**
     * Output for language_attributes().
     * We drop the &#039;dir&#039; attribute.
     *
     * @return string
     */</i>
    <span class='internal'>public</span> <span class='internal'>static</span> <span class='internal'>function</span> html()
    {
        <span class='internal'>return</span> <span class='string'>&#039;lang=&quot;&#039;</span> <span class='operator'>.</span> self<span class='operator'>::</span><var>$lang</var> <span class='operator'>.</span> <span class='string'>&#039;&quot;&#039;</span>;
    }

}
<i class='comment'>// Adjust this to your needs.
</i>Toscho_Language_Filter<span class='operator'>::</span>setup(<span class='string'>&#039;de-DE-1901&#039;</span>);</pre>
</div>
<p>Wer mag, kann die Funktion <code>setup()</code> auch mit einer eigenen Kreation aufrufen. Dann muß man ein <code>-x-</code> davorsetzen, wie Ian Hickson das in den <a hreflang="en" href="http://www.whatwg.org/specs/web-apps/current-work/multipage/">Spezifikationen zu HTML5</a> macht: <code>lang=<code class="string">"en-US-x-hixie"</code></code>.<br />
Über den Nutzen möchte ich lieber nicht diskutieren.</p>
<h2>Mehr davon</h2>
<ul>
<li><a href="http://toscho.de/2010/wordpress-dashboard-approved-nicht-genehmigt/">WordPress-Dashboard: ›Approved‹ nicht ›Genehmigt‹</a></li>
<li><a href="http://toscho.de/2010/wordpress-auszug-zeichenzahl/">WordPress: Auszug mit bestimmter Zeichenzahl</a></li>
<li><a href="http://toscho.de/2009/php-funktion-genitiv/">PHP-Funktion Genitiv</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2010/wordpress-sprache-der-ausgabe-einstellen/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>WordPress: Moderationslinks für Kommentare</title>
		<link>http://toscho.de/2010/wordpress-moderationslinks-fuer-kommentare/</link>
		<comments>http://toscho.de/2010/wordpress-moderationslinks-fuer-kommentare/#comments</comments>
		<pubDate>Thu, 29 Apr 2010 20:58:09 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Interna]]></category>
		<category><![CDATA[Markup]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1671</guid>
		<description><![CDATA[Wie man jeden Kommentar um Links ergänzt, die beim Verwalten helfen. Mit vollständigem PHP- und CSS-Code.]]></description>
			<content:encoded><![CDATA[<p>Trotz des <a href="http://toscho.de/2010/spam-verhindern-akismet-htaccess/">Antispam-Plugins</a> schlüpft auch hier manchmal ein Müllkommentar durch den Filter, oder ich vertippe mich … für diese Fälle bietet WordPress an, Kommentare zu bearbeiten, als Spam zu markieren oder ganz zu löschen. Im Backend.</p>
<p>Das ist mir ein wenig zu umständlich; deshalb habe ich in meiner Klasse ›XWP‹, die zusätzliche Templatetags erzeugt, folgenden kleinen Schnipsel eingebaut, den ich <a href="http://yoast.com/wordpress-functions-supercharge-theme/" hreflang="en">von Joost de Valk abgeguckt</a> habe:</p>
<pre class="notranslate">    <i>/* Generates comment moderation links.
     *
     * @author Joost de Valk
     * @link   <a href="http://yoast.com/wordpress-functions-supercharge-theme/">http://yoast.com/wordpress-functions-supercharge-theme/</a>
     * @param  int <var>$id</var> Comment id - use get_comment_ID()
     * @return void
     */</i>
    public static function delete_comment_link(<var>$id</var>)
    {
        if ( ! <a href="http://codex.wordpress.org/Roles_and_Capabilities#moderate_comments">current_user_can</a>('<code class="string">moderate_comments</code>') )
        {
            return;
        }

        global <var>$post</var>;

        <var>$redirect</var> = get_permalink( <var>$post</var>-&gt;ID );

        <var>$links</var> = array (
            '<code class="string">delete</code>'  =&gt; '<code class="string">cdc</code>',
            '<code class="string">spam</code>' =&gt; '<code class="string">cdc&amp;dt=spam</code>',
            '<code class="string">edit</code>' =&gt; '<code class="string">editcomment</code>'
        );

        <var>$return</var> = '<code class="string">&lt;span class="comment_admin"&gt;</code>';

        foreach ( <var>$links</var> as <var>$name</var> =&gt; <var>$param</var> )
        {
            <var>$return</var> .= "<code class="string">&lt;a href='</code>"
                    . admin_url("<code class="string">comment.php?c=<var>$id</var>&amp;action=<var>$param</var>&amp;redirect_to=<var>$redirect</var></code>")
                    . "<code class="string">'&gt;<var>$name</var>&lt;/a&gt;</code>";
        }

        print <var>$return</var> . '<code class="string">&lt;/span&gt;</code>';

        return;
    }</pre>
<p>In der <code>comments.php</code> rufe ich die Funktion innerhalb des Kommentarloops auf:</p>
<pre class="notranslate">XWP::delete_comment_link( get_comment_ID() );</pre>
<p>Das erzeugt etwa dieses <a href="http://toscho.de/thema/markup/">Markup</a>:</p>
<pre class="notranslate">&lt;span class="<code class="string">comment_admin</code>"&gt;
  &lt;a href='<code class="string">/wp-admin/comment.php?c=905&amp;action=cdc&amp;redirect_to=/2010/beispiel/</code>'
     &gt;delete&lt;/a&gt;
  &lt;a href='<code class="string">/wp-admin/comment.php?c=905&amp;action=cdc&amp;dt=spam&amp;redirect_to=/2010/beispiel/</code>'
     &gt;spam&lt;/a&gt;
  &lt;a href='<code class="string">/wp-admin/comment.php?c=905&amp;action=editcomment&amp;redirect_to=/2010/beispiel/</code>'
     &gt;edit&lt;/a&gt;
&lt;/span&gt;</pre>
<p>Mit ein wenig <a href="http://toscho.de/thema/css/">CSS</a> aufgepeppt …</p>
<pre class="notranslate">.comment_admin
    {
        float:              right;
        font:               .9em/1 Calibri;
        text-align:         center;
    }
.comment_admin a
    {
        color:              #444;
        background:         #f9f9f9;
        text-decoration:    none;
        border:             1px solid #bbb;
        border-radius:      4px;
        box-shadow:         0 2px 3px rgba(0,0,0,0.2);
        display:            inline-block;
        width:              3em;
        margin:             4px;
        padding:            4px 15px;
    }
#content .comment_admin a:hover
    {
        background:         #666;
        color:              #fff;
        border:             1px solid #222;
    }</pre>
<p>… sieht das Ergebnis dann so aus:</p>
<p><img src="http://toscho.de/wp-content/uploads/2010/04/comment-moderation.png" alt="" title="comment moderation" width="280" height="123" class="alignnone size-full wp-image-1672 border" /></p>
<p>Nach einem Klick landet man in der Bearbeitungsmaske im Backend, <em>dann erst</em> wird der Kommentar per Knopfdruck gelöscht oder als Spam markiert.</p>
<p>Mehr so’n Zeug:</p>
<ul>
<li><a href="http://toscho.de/2009/wordpress-administrator-php-herausfinden/">Administrator mit PHP herausfinden</a></li>
<li><a href="http://toscho.de/2009/wordpress-moderationsfalle-offenlegen/">Moderationsfalle offenlegen</a></li>
<li><a href="http://toscho.de/2009/no-no-no-nofollow/">No no no nofollow</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2010/wordpress-moderationslinks-fuer-kommentare/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Twitter: Einen Tweet formatieren</title>
		<link>http://toscho.de/2010/twitter-einen-tweet-formatieren/</link>
		<comments>http://toscho.de/2010/twitter-einen-tweet-formatieren/#comments</comments>
		<pubDate>Wed, 20 Jan 2010 22:59:59 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Links]]></category>
		<category><![CDATA[Markup]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Webdesign]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1611</guid>
		<description><![CDATA[Wie man in einem Tweet Hashtags, User und viele URLs erkennt.]]></description>
			<content:encoded><![CDATA[<p>Twitter bietet Feeds für fast alles an. Prima.<br />
Ohne jegliches Markup. <em>Auch prima.</em></p>
<p>Denn wenn wir Twitter per Webinterface erleiden, sehen wir schnell: Mit Umlauten in Hashtags kommt Twitter schlecht zurecht, ebenso mit URLs, denen kein Leerzeichen vorangeht. Und so richtig viele Protokollbezeichner kennt der Parser auch nicht.</p>
<p>Wollen wir also <a href="http://twitter.com/statuses/user_timeline/19575603.rss">einen Twitterfeed</a> per RSS einbinden, müssen wir die Links selbst erzeugen. Auf <a href="http://labs.toscho.de/twegolicious/">Twegolicious</a>, wo ich nur meine eigene <span lang="en">Timeline</span> einbinde, entferne ich auch noch meinen Nutzernamen.</p>
<p>Der einzelne Tweet sieht im Quelltext so aus:</p>
<pre class="notranslate">&lt;item&gt;
    &lt;title&gt;toscho: Informieren statt Sperren: http://toscho.de/p1609 #gebloggt&lt;/title&gt;
    &lt;description&gt;toscho: Informieren statt Sperren: http://toscho.de/p1609 #gebloggt&lt;/description&gt;
    &lt;pubDate&gt;Tue, 19 Jan 2010 21:44:21 +0000&lt;/pubDate&gt;
    &lt;guid&gt;http://twitter.com/toscho/statuses/7960752682&lt;/guid&gt;
    &lt;link&gt;http://twitter.com/toscho/statuses/7960752682&lt;/link&gt;
&lt;/item&gt;</pre>
<p><code>title</code> und <code>description</code> unterscheiden sich also nicht. Ich finde, daß man zumindest in einem von beiden den Nutzernamen hätte entfernen können …</p>
<p>Den Feed hole ich mit <a href="http://simplepie.org/" hreflang="en">SimplePie</a>, und den einzelnen Tweet werte ich mit dieser Funktion auf:</p>
<pre class="notranslate">function format_tweet(<var>$content</var>, <var>$user</var> = NULL)
{
    <var>$uri_schemes</var> = array (
        '<code class="string">mailto</code>', '<code class="string">news</code>', '<code class="string">nntp</code>', '<code class="string">callto</code>', '<code class="string">ed2k</code>', '<code class="string">irc</code>', '<code class="string">ssh</code>', '<code class="string">svn</code>',
        '<code class="string">s?ftps?</code>', '<code class="string">https?</code>' );
    <var>$regex</var>['<code class="string">url</code>'] = '(' . implode('<code class="string">|</code>', <var>$uri_schemes</var>)
            . '<code class="string">)://([-\w\.]+)+(:\d+)?(/([\w/_\.]*(\?\S+)?)?)?</code>';
    <var>$regex</var>['username'] = "<code class="string">@([a-zA-Z_\d]+)</code>";
    <var>$regex</var>['hashtag']  = "<code class="string">([^\pL]){0,1}(#([-_\pL\d]+))</code>";

    if ( ! is_null(<var>$user</var>) )
    {
        <i>// Usernamen + ': ' aus Text entfernen</i>
        <var>$content</var> = substr( <var>$content</var>, ( strlen(<var>$user</var> ) + 2 ) );
    }
    <i>// Hyperlinks umwandeln</i>
    <var>$content</var> = preg_replace(
        '<code class="string">~</code>' . <var>$regex</var>['<code class="string">url</code>'] . '<code class="string">~u</code>', '<code class="string">&lt;a href="${0}"&gt;${0}&lt;/a&gt; </code>', <var>$content</var>);
    <i>// Usernamen verlinken</i>
    <var>$content</var> = preg_replace(
        '<code class="string">~</code>' . <var>$regex</var>['username'] . '<code class="string">~u</code>',
        '<code class="string">&lt;a class="user" href="http://twitter.com/${1}"&gt;${0}&lt;/a&gt;</code>',
        <var>$content</var>);
    <i>// Hashtags verlinken</i>
    <var>$content</var> = preg_replace(
        '<code class="string">~</code>' . <var>$regex</var>['hashtag'] . '<code class="string">~u</code>',
        '<code class="string"> ${1}&lt;a class="tag" href="http://twitter.com/search?q=%23${3}"&gt;${2}&lt;/a&gt;</code>',
        <var>$content</var>);

    return <var>$content</var>;
}</pre>
<p>Das hätte ich wesentlich kompakter schreiben können, aber die Übersicht geht vor.</p>
<p>Aus dem oben gezeigten Quelltext wird per …</p>
<pre class="notranslate">echo format_tweet(<var>$item</var>, '<code class="string">toscho</code>');</pre>
<p>… dieses Markup:</p>
<pre class="notranslate">Informieren statt Sperren:
&lt;a href="<code class="string"><a href="http://toscho.de/p1609">http://toscho.de/p1609</a></code>"&gt;http://toscho.de/p1609&lt;/a&gt;
&lt;a class="<code class="string">tag</code>"
    href="<code class="string"><a href="http://twitter.com/search?q=%23gebloggt">http://twitter.com/search?q=%23gebloggt</a></code>"
&gt;#gebloggt&lt;/a&gt;</pre>
<p>In einem Projekt, das ich hier nicht nennen kann, habe ich Feeds zu bestimmten Suchworten eingebunden. Um Spam herauszufiltern, habe ich die Hashtags und die URLs eines Tweets gezählt, und den Tweet beim Überschreiten bestimmter Grenzen verworfen. Das funktioniert zwar nicht sehr zuverlässig, aber wer darauf verzichtet, holt sich schnell viel Schund auf die eigene Seite.</p>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2010/twitter-einen-tweet-formatieren/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>WordPress: Shortlinks reloaded</title>
		<link>http://toscho.de/2010/wordpress-shortlinks-reloaded/</link>
		<comments>http://toscho.de/2010/wordpress-shortlinks-reloaded/#comments</comments>
		<pubDate>Mon, 11 Jan 2010 21:25:07 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Browser]]></category>
		<category><![CDATA[Interna]]></category>
		<category><![CDATA[Links]]></category>
		<category><![CDATA[Markup]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[Plugin]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1594</guid>
		<description><![CDATA[Wie man Short-URIs in WordPress erzeugt, ausgibt und narrensicher per .htaccess abfängt. Code und ein Plugin zum Download.]]></description>
			<content:encoded><![CDATA[<!--TOC-->
<p>Im April 2009 habe ich gezeigt, wie man in WordPress <a href="http://toscho.de/2009/shortlinks-in-wordpress/">mit Bordmitteln kurze URLs</a> für Seiten und Artikel erzeugt: Blog-Adresse plus »<code class="string">?p=</code>« plus Post-Id. Das funktioniert einfach und schnell. Nicht.</p>
<h2>Formatkrieg</h2>
<p>Meine Grundidee war: Ich habe nur einen Ort für die Logik des Verfahrens – die <code>functions.php</code>. Das stellte sich als zu naiv heraus, als die ersten <strong>kaputten Crawler</strong> aufschlugen, die das Fragezeichen mit einem <code>urlencode()</code> vorbehandelten. Requests auf <samp>/%3F=762</samp> sind eben etwas anderes als auf <samp>/?=762</samp>.</p>
<p>Jetzt mußte ich doch einen zweiten Ort anfassen: die .htaccess.</p>
<pre class="notranslate">RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^/\<strong>%3f</strong>p\=(\d+)$
RewriteRule ^.* /?p=%1 [L,R=301]</pre>
<p>Dann versagte auch die URL-Erkennung bei <strong>Twitter</strong>: Verlinkt wurde nur der Teil bis zum Fragezeichen, alles dahinter fiel weg.<br />
Also habe ich die Kurz-URLs auf das Format /p762 umgestellt und die .htaccess angepaßt:</p>
<pre class="notranslate">RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^/\%3fp\=(\d+)$ [OR]
RewriteCond %{REQUEST_URI} ^<strong>/p</strong>\=?(\d+)$
RewriteRule ^.* /?p=%1 [L,R=301]</pre>
<p>Auftritt <strong>Rivva-Bot</strong>: Der hat das neue Format um einen Slash <code>/</code> ergänzt, <a href="http://toscho.de/2010/logfiles-analysieren/#toc-400er">die Fehlerseite bestaunt</a> – und dann blieb er weg. Kein Problem:</p>
<pre class="notranslate">RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^/\%3fp\=(\d+)$ [OR]
RewriteCond %{REQUEST_URI} ^/p\=?(\d+)<strong>/?</strong>$
RewriteRule ^.* /?p=%1 [L,R=301]</pre>
<h2>Markup</h2>
<p>In einem sehr fruchtbaren <a href="http://toscho.de/2009/shortlinks-in-wordpress/#comment-405">Ideen-Pingpong</a> (vulgo: Dialog) mit <a href="http://bernhardhaeussner.de/">Bernhard Häussner</a> haben wir die perfekte Notation für die Bekanntgabe des Shortlinks gefunden: Ein separater HTTP-Header samt <code>meta</code>-Element:</p>
<pre class="notranslate">&lt;meta http-equiv="<code class="string">X-Short-URI</code>" content="<code class="string">http://toscho.de/?p=762</code>"&gt;</pre>
<p>Interessiert kein Schwein. Am 14. August <a href="http://en.blog.wordpress.com/2009/08/14/shorten/">schuf WordPress.com Tatsachen</a> und verstetigte die sehr schlechte Lösung <code>rel="shortlink"</code> (<a href="http://microformats.org/wiki/rel-shortlink">Referenz</a>). Schade.</p>
<p>Jetzt könnte die URL also so angegeben werden:</p>
<pre class="notranslate">&lt;link rel="shortlink" href="http://toscho.de/?p=762"&gt;</pre>
<p><div id="attachment_1595" class="wp-caption alignright" style="width: 287px"><img src="http://toscho.de/wp-content/uploads/2010/01/opera-shortlink-info.png" alt="Opera: Shortlink im Infopanel" width="277" height="279" class="border size-full wp-image-1595" /><p class="wp-caption-text">Opera: Shortlink im Infopanel</p></div><em>Könnte.</em> Opera, auf den ich unter keinen Umständen verzichte, ignoriert leider genau diesen Link im Info-Panel. Also füge ich als Beziehung noch ein <code>alternate</code> hinzu, damit die Erkennung wieder klappt.<br />
Wer es ausprobieren möchte: F4 drücken, »Leiste anpassen/Erscheinungsbild/Paneele/« und ein Häkchen bei »Info« setzen.</p>
<h2 style="clear:right">PHP-Code</h2>
<p>Ich habe den Code zur Ausgabe in WordPress in eine kleine Klasse mit statischen Methoden gegossen – des armen Mannes Namensraum. Verzeiht mir.</p>
<pre class="notranslate">&lt;?php
<i>/**
 * Class Short_URI: Short-URIs erzeugen und ausgeben.
 * @author Thomas Scholz &lt;http://toscho.de&gt;
 * @see <a href="http://microformats.org/wiki/rel-shortlink">http://microformats.org/wiki/rel-shortlink</a>
 * @license GPL 3 &lt;<a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a>&gt;
 * @version 1.3
 *
 */</i>
class Short_URI {

    <i>/**
     * Kurz-URI
     * @var string
     */</i>
    protected static <var>$short_uri</var>      = NULL;

    <i>/**
     * Sendet einen Link-HTTP-Header
     * @param bool <var>$headonly</var> Nur bei HEAD-Requests senden?
     * @return void
     */</i>
    public static function send_header(<var>$headonly</var> = TRUE)
    {
        if (<var>$headonly</var> and ('<code class="string">HEAD</code>' != <var>$_SERVER</var>['<code class="string">REQUEST_METHOD</code>']) )
        {
            return;
        }
        if ( ! self::prepare() )
        {
            return;
        }
        header('<code class="string">Link: &lt;</code>' . self::<var>$short_uri</var> . '<code class="string">&gt;; rel="shortlink"</code>');
        return;
    }

    public static function link_elem(<var>$echo</var> = TRUE)
    {
        if ( ! self::prepare() )
        {
            return;
        }
        <var>$link</var> = '<code class="string">&lt;link rel="alternate shortlink" title="Shortlink"</code>'
                . '<code class="string"> href="</code>' . self::<var>$short_uri</var> . '<code class="string">" /&gt;</code>';

        if ( ! <var>$echo</var>)
        {
            return <var>$link</var>;
        }

        echo <var>$link</var>;
        return;

    }

    <i>/**
     * Erzeugt einen Link zum Twittern der aktuellen Seite.
     * @param string|array <var>$args</var>
     * @return string
     */</i>
    static function tweet_link(<var>$args</var> = NULL)
    {
        <var>$message_template</var> = '<code class="string">Lese gerade: %TITLE %URL von @toscho</code>';
        <var>$link_text</var>        = '<code class="string">Artikel twittern</code>';
        <var>$title_length</var>     = 80;
        <var>$class</var>            = '<code class="string">twitterlink</code>';
        <i>// Zum Ändern echo=0 übergeben.</i>
        <var>$echo</var>             = TRUE;

        if ( ! is_null(<var>$args</var>) )
        {
            if ( is_array(<var>$args</var>) )
            {
                extract(<var>$args</var>);
            }
            elseif ( is_string(<var>$args</var>) )
            {
                parse_str(<var>$args</var>);
            }
            else
            {
                trigger_error(
                    '<code class="string"><var>$args</var> muss ein Array oder ein String sein.</code>',
                    E_USER_ERROR
                );
            }
        }
        global <var>$post</var>;

        <var>$title</var>       = trim(<var>$post</var>-&gt;post_title);

        if ( isset ( <var>$title</var>[<var>$title_length</var>+2] ) )
        {<i>// Verkürzen bei Bedarf</i>
            <var>$title</var> = self::end_on_word(substr(<var>$title</var>, 0, <var>$title_length</var>)) . '<code class="string"> …</code>';
        }

        <var>$message</var> = str_replace(
            array('<code class="string">%TITLE</code>', '<code class="string">%URL</code>'),
            array(<var>$title</var>, self::<var>$short_uri</var> ),
            <var>$message_template</var>
        );

        <var>$link</var> = '<code class="string">&lt;a class="</code>' . <var>$class</var>
            . '<code class="string">" href="http://twitter.com/home?status=</code>' . urlencode(<var>$message</var>)
            . '<code class="string">" title="</code>' . <var>$message</var> . '<code class="string">"&gt;</code>'
            . <var>$link_text</var> . '<code class="string">&lt;/a&gt;</code>';

        if (<var>$echo</var>)
        {
            echo <var>$link</var>;
            return;
        }

        return <var>$link</var>;
    }

    <i>/**
     * Prüft, ob eine Short-URI erstellt werden soll
     * @return bool
     */</i>
    public static function prepare()
    {
        if ( is_front_page() )
        {
            return FALSE;
        }
        if ( is_page() or is_single() or is_attachment() )
        {
            global <var>$post</var>;

            if ( is_null( self::<var>$short_uri</var> ) )
            {
                self::<var>$short_uri</var> =
                    rtrim(get_option('home'), '<code class="string">/</code>') . '<code class="string">/p</code>' . <var>$post</var>-&gt;ID;
            }
            return TRUE;
        }
        <i>// Archive</i>
        return FALSE;
    }

    <i>/**
     * Entfernt unvollständige Worte am Ende eines Strings.
     * @see http://toscho.de/2009/php-funktion-end_on_word/
     * @param <var>$str</var> Zeichenkette
     * @return string
     */</i>
    static function end_on_word(<var>$str</var>)
    {
        <var>$str</var> = trim(<var>$str</var>);

        <i>// Nur ein Wort, wird also nicht gekürzt.</i>
        if ( FALSE === strpos(<var>$str</var>, '<code class="string"> </code>') )
        {
            return <var>$str</var>;
        }

        <i>// Jedes Wort ein Eintrag im Array …</i>
        <var>$arr</var>   = explode('<code class="string"> </code>', <var>$str</var>);
        <i>// … letztes Stück wegwerfen …</i>
        array_pop(<var>$arr</var>);
        <i>// … den String wieder herstellen und Kommas trimmen.</i>
        return rtrim( implode('<code class="string"> </code>', <var>$arr</var>), '<code class="string">,;</code>');
    }
}</pre>
<p>Wer bis hierhin durchgehalten hat, darf sich das auch als …</p>
<p class="downloadlink"><a class='piwik_download' href="http://f.toscho.de/php-skripte/short-uri.0.1.zip">WordPress-Plugin Short-URI herunterladen</a>.</p>
<p>Den Tweetlink baut ihr <em>innerhalb des Loops</em> mit diesem Code ein:</p>
<pre class="notranslate">do_action('tweet_link');</pre>
<p>Oder so:</p>
<pre class="notranslate">do_action('tweet_link', 'parameter=wert');</pre>
<p>Die darin enthaltene Klasse könnt ihr natürlich auch einfach in die <code>functions.php</code> einbinden, um den Code direkt zu verwenden.</p>
<p>Ich habe ihn unter die <a href="http://www.gnu.org/licenses/gpl.html">GPL 3</a> gestellt (<a href="http://toscho.de/2009/no-no-no-nofollow/#comment-1109">hallo Helmut!</a>), damit ihr damit machen könnt, was immer ihr wollt. Er ist mir länger geraten, als ich erhofft hatte; das heißt: Er hat sicher auch mehr Fehler. Findet sie!</p>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2010/wordpress-shortlinks-reloaded/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Suchformular in HTML5</title>
		<link>http://toscho.de/2010/suchformular-in-html5/</link>
		<comments>http://toscho.de/2010/suchformular-in-html5/#comments</comments>
		<pubDate>Fri, 08 Jan 2010 21:57:49 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Browser]]></category>
		<category><![CDATA[Interna]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Markup]]></category>
		<category><![CDATA[Suchmaschinen]]></category>
		<category><![CDATA[Webdesign]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1578</guid>
		<description><![CDATA[Wie ich versuche, mein Suchfeld aufzuwerten: Mit HTML5 und Javascript.]]></description>
			<content:encoded><![CDATA[<!--TOC-->
<p>Ein großer Teil der HTML5-Spezifikation sieht aus, als werde bislang ungenormtes Browserverhalten schlicht dokumentiert. Aber der HTML-3.2-Geruch verfliegt, sobald wir unser Auge auf Formulare richten.</p>
<p>Mein Suchformular habe ich endlich ganz und gar auf die neuen Verhältnisse umgestellt.</p>
<h2>Beispiel</h2>
<pre class="notranslate">&lt;form
  method="<code class="string">GET</code>"
  id="<code class="string">searchform</code>"
  accept-charset="<code class="string">utf-8</code>"
  action="<code class="string">/</code>"
&gt;
  &lt;div&gt;
    &lt;input
      title="<code class="string">Suche</code>"
      type="<code class="string">search</code>"
      value="&lt;?php <a href="http://codex.wordpress.org/Template_Tags/the_search_query">the_search_query()</a>; ?&gt;"
      name="<code class="string">s</code>"
      id="<code class="string">s</code>"
      pattern="<code class="string">.+</code>"
      required
    &gt; 
    &lt;input
      type="<code class="string">submit</code>"
      id="<code class="string">searchsubmit</code>"
      value="<code class="string">Suche</code>"
    &gt;
  &lt;/div&gt;
&lt;/form&gt;</pre>
<h2>Markup</h2>
<p>Na, um das herauszufinden, braucht niemand einen Artikel. Ich möchte aber gerne meine Gründe mit euch diskutieren.</p>
<p>Auf das Element <code>label</code> verzichte ich. Das Eingabefeld hat ein <code>title</code>-Attribut, und der Button gleich danach trägt einen unmißverständlichen Text. Damit kommt auch der Nutzer eines Screenreaders gut zurecht.</p>
<p>Das Attribut <code>accept-charset</code> fungiert als redundante Sicherheitsleine. Ich <a href="http://toscho.de/2009/zeichenkodierung-angeben/">gebe die Zeichenkodierung</a> im HTTP-Header schon an, und im <code>meta</code>-Element steht sie auch. </p>
<p>Interessant wird endlich der Wert des Attributes <code>type</code> im ersten <code>input</code>-Element: <code>search</code> wurde <a href="http://ln.hixie.ch/?start=1089635050&#038;count=1" hreflang="en">von <i lang="en">Apple</i> durch die Hintertür in HTML5 eingeschmuggelt</a>, sieht jetzt aber doch recht vernünftig aus.</p>
<p><div id="attachment_289" class="wp-caption alignright" style="width: 314px"><img src="http://toscho.de/wp-content/uploads/2009/01/safari-suche.png" alt="Suchfeld in Safari 3" title="Safari-Suche" width="304" height="243" class="size-full wp-image-289" /><p class="wp-caption-text">Suchfeld in Safari 3</p></div>Safari hat solche Elemente in der Version 3 noch <em>generell</em> mit abgerundeten Ecken verziert.</p>
<p>Das hat sich aber mit einigen Formatierungen gebissen, die hier und da auftauchten (insbesondere <code>border</code>, <code>outline</code> und <code>background</code>), und inzwischen beschränkt sich zumindest die Windowsversion auf eine Lupe und einen Pfeil.<br />
<div id="attachment_1579" class="wp-caption alignnone" style="width: 257px"><img src="http://toscho.de/wp-content/uploads/2010/01/safari-suche.png" alt="Suchfeld in Safari 4" title="Safari-4-Suche" width="247" height="46" class="size-full wp-image-1579" /><p class="wp-caption-text">Suchfeld in Safari 4</p></div></p>
<p>Browser, die diesen Attributwert nicht kennen, unterstellen automatisch <code>type="text"</code>.</p>
<p>Wenn jemand schon etwas gesucht hat, dann steht der Suchbegriff natürlich im Feld, damit derjenige seine Anfrage bei Bedarf verbessern kann.</p>
<p>Sonst steht nichts darin. <strong>Kein Fülltext.</strong> An diesem Punkt laufen viele Gestalter leicht in eine Falle: Vor vielen, vielen Jahren gab es ein paar Screenreader, die Eingabefelder nur dann erkannten, wenn Text darin stand. Die haben sich verständlicherweise nicht lange gehalten. Deutlich länger freilich blieb die Idee, so ein Text sei hilfreich.</p>
<p>Der Text muß automatisch verschwinden, wenn man den Fokus ins Feld legt – sonst zwingt man den Besucher zu umständlichen Löscharbeiten. Also darf er nur per Javascript eingefügt werden, denn nur so funktioniert das automatische Löschen. Wer ohne Javascript auf die Seite kommt, hätte andernfalls ja doch die Löscherei von Hand zu erledigen.</p>
<p>Die Funktion des Feldes muß also schon ohne Javascript klar erkennbar sein. Ist das nicht der Fall, muß man das Formular entsprechend reparieren.</p>
<p>Wenn also ohne Javascript schon alles klar ist, brauchen wir auch den Fülltext nicht. Ich habe noch keine Seite gesehen, auf der dieser Text irgendeinen erkennbaren Mehrwert gebracht hat.</p>
<p>Das Attribut <code>pattern</code> beschreibt mit einem regulären Ausdruck, welche Zeichen erwartet werden. Hier möchte ich mindestens eines, denn sonst vergeudet der Leser nur seine Zeit.<br />
Dieses Attribut ist im Grunde redundant, denn das nächste – <code>required</code> – verlangt auch mindestens ein Zeichen. Ich habe beide eingebaut, um denjenigen zu helfen, deren Browser nur eins erkennt.</p>
<p>Diese Attribute erzwingen eine clientseitige Validierung der Eingabe auch dann, wenn der Leser Javascript ausgeschaltet hat.</p>
<p>Der Absendebutton hat kein Attribut <code>name</code>. So wird dessen Wert auch nicht übertragen, und die URL für die Suche bleibt hübsch übersichtlich.</p>
<h2>Javascript</h2>
<p>Das Suchformular habe ich mit einer kleinen Funktion aufgepeppt:</p>
<pre class="notranslate">function addEvent(<var>target</var>, <var>eventType</var>, <var>functionRef</var>, <var>capture</var>) {
    if (typeof <var>target</var>.addEventListener != "<code class="string">undefined</code>") {
        <var>target</var>.addEventListener(<var>eventType</var>, <var>functionRef</var>, <var>capture</var>);
    } else if (typeof <var>target</var>.attachEvent != "<code class="string">undefined</code>") {
        <var>target</var>.attachEvent("<code class="string">on</code>" + <var>eventType</var>, <var>functionRef</var>);
    } else {
        <var>eventType</var> = "<code class="string">on</code>" + <var>eventType</var>;
        if (typeof <var>target</var>[eventType] == "<code class="string">function</code>") {
            var <var>oldListener</var> = <var>target</var>[eventType];
            <var>target</var>[eventType] = function() {
                <var>oldListener</var>();
                return <var>functionRef</var>();
            };
        } else {
            <var>target</var>[eventType] = <var>functionRef</var>;
        }
    }
}
function checkSearch() {
    var <var>sform</var>           = document.getElementById("<code class="string">searchform</code>");
    var <var>s</var>               = document.getElementById('<code class="string">s</code>');
    <var>s</var>.setAttribute('<code class="string">autosave</code>', '<code class="string">toscho.de</code>');
    <var>s</var>.setAttribute('<code class="string">results</code>', '<code class="string">15</code>');
    var <var>submit</var>          = document.getElementById('<code class="string">searchsubmit</code>');
    <var>sform</var>.onsubmit = function() {
        if ( '' == <var>this</var>.<var>s</var>.value ) {
            alert('<code class="string">Wenn Sie nach nichts suchen, werden Sie nichts finden.</code>');
            <var>s</var>.focus();
            return false;
        }
        return true;
    };
}
addEvent(window, '<code class="string">load</code>', checkSearch);</pre>
<p>Die erste Funktion <code>addEvent()</code> habe ich aus dem <a href="http://www.sitepoint.com/books/jsant1/">Javascript-Buch von SitePoint</a>. Den Rest habe ich mir selbst zusammengeschustert. Ihr seht bestimmt, was ich alles besser machen kann.</p>
<p>Hier werden zunächst diese beiden Zeilen relevant:</p>
<pre class="notranslate"><var>s</var>.setAttribute('<code class="string">autosave</code>', '<code class="string">toscho.de</code>');
<var>s</var>.setAttribute('<code class="string">results</code>', '<code class="string">15</code>');</pre>
<p>Die helfen den Nutzern webkit-basierter Browser wie Safari oder Google Chrome. Sie sagen: Merke dir automatisch die letzten 15 Einträge, und ordne sie der Domain toscho.de zu. Im Screenshot aus Safari 3 oben sieht man solch einen gespeicherten Ausdruck.<br />
Das ist praktisch bei langen Worten oder solchen, die man leicht falsch schreibt. Noch praktischer wäre eine Methode, die Suchausdrücke ohne Treffer aus der Liste heraushalten könnte. Soweit ich weiß, gibt es die noch nicht. Korrigiert mich <em>bitte</em>!</p>
<p>Kurz darauf kommt noch eine kleine Kontrolle auf leere Einsendungen. Nicht jeder benutzt schließlich einen modernen Browser, der die neuen Attribute schon unterstützt.</p>
<h2>Links</h2>
<ul>
<li><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#forms" hreflang="en">HTML5: Formulare</a></li>
<li>Anne van Kesteren: <a hreflang="en" lang="en" href="http://dev.opera.com/articles/view/improve-your-forms-using-html5/">Improve your forms using HTML5!</a></li>
<li>Dave Hyatt: <a hreflang="en" lang="en" href="http://weblogs.mozillazine.org/hyatt/archives/2004_07.html#005890">[Introducing] The Search Field</a> (in Webkit)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2010/suchformular-in-html5/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>Designlinks 10</title>
		<link>http://toscho.de/2009/designlinks-10/</link>
		<comments>http://toscho.de/2009/designlinks-10/#comments</comments>
		<pubDate>Tue, 08 Dec 2009 05:05:50 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Links]]></category>
		<category><![CDATA[Markup]]></category>
		<category><![CDATA[Suchmaschinen]]></category>
		<category><![CDATA[Typographie]]></category>
		<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Kommentare]]></category>
		<category><![CDATA[Spam]]></category>
		<category><![CDATA[SVG]]></category>
		<category><![CDATA[Tabelle]]></category>
		<category><![CDATA[Video]]></category>
		<category><![CDATA[VML]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1555</guid>
		<description><![CDATA[Videos untertiteln, ein schräges Impressum, dumme Ratschläge zur Vermeidung von Kommentarspam, Schriftenglättung mit Javascript und Canvas erkennen, JAWS’ Tabellenheuristik und Bilder drehen mit SVG und VML.]]></description>
			<content:encoded><![CDATA[<ul>
<li><a lang="en" hreflang="en" href="http://www.iheni.com/make-video-accessible-localised-mobile-and-searchable-by-captioning/">Henny Swan: Make video accessible, localised, mobile and searchable by captioning</a>.
<p>Henny stellt mehrere Programme vor und gibt gute Hinweise. Auch die Kommentare sind einen Blick wert.</li>
<li><a href="http://seat-1.com/ERP/Impressum.html">seat-1 Software GmbH: Impressum</a>
<p>Bis zum Ende lesen!</li>
<li><a lang="en" hreflang="en" href="http://googlewebmastercentral.blogspot.com/2009/11/hard-facts-about-comment-spam.html">Adel Saoud and Paolo Petrolini (Google): Hard facts about comment spam</a>.
<p>Ich habe schon lange nicht mehr solchen Unsinn gelesen. Zur Vermeidung von Kommentarspam empfehlen die Autoren dies:</p>
<blockquote lang="en"><ul>
<li>Disallow anonymous posting.</li>
<li>Use CAPTCHAs and other methods to prevent automated comment spamming.</li>
<li>Turn on comment moderation.</li>
<li>Use the "nofollow" attribute for links in the comment field.</li>
<li>Disallow hyperlinks in comments.</li>
<li>Block comment pages using robots.txt or meta tags.</li>
</ul>
</blockquote>
<p>Aus meiner eigenen Erfahrung kann ich dazu dies beisteuern: </p>
<ul>
<li>Ich erlaube schon lange anonyme Kommentare, aber die Spammer füllen immer alle Felder aus. Wirkungslos.</li>
<li>Captchas stellen auch für richtige Besucher immer eine Hürde dar. Der Schaden wiegt den Nutzen nicht auf.</li>
<li>Kommentare moderiere ich im Nachhinein. Für den Schreiber ist es sehr frustrierend, etwas beizutragen und es dann nicht zu sehen. Wenn doch mal ein Spamkommentar durchrutscht, dann hat derjenige ein paar Stunden lang einen Backlink. Na und?</li>
<li>Nofollow interessiert keinen Spammer. Für eine weitere Diskussion verweise ich auf meinen <a href="http://toscho.de/2009/no-no-no-nofollow/">Nofollow-Artikel</a>.</li>
<li>Ein Linkverbot für Kommentare würde <del datetime="2009-12-08T04:25:03+00:00">dieses</del> <ins datetime="2009-12-08T04:25:03+00:00">jedes</ins> Blog sehr entwerten.</li>
<li>Selbst wenn man Kommentarseiten von den Artikeln separiert – was mich als Leser eher nervt – so habe ich doch noch keinen Spammer gesehen, der erst die robots.txt prüft.</li>
</ul>
<p>All diese Hinweise nützen nur einem: Google. Wer sie befolgt, hilft Google dabei, den Index sauber zu halten. Aber er beschädigt die Qualität der eigenen Website.<br />
Mein Rat an Google: Macht eure Arbeit selbst. Wir benutzen serverseitige Spamfilter.</li>
<li><a lang="en" hreflang="en" href="http://www.useragentman.com/blog/2009/11/29/how-to-detect-font-smoothing-using-javascript/">Zoltan Hawryluk: How to Detect Font-Smoothing Using JavaScript</a>.
<p>Clevere Lösung mit Canvas. Ob das aufs Tempo geht? Mal sehen.</li>
<li><a lang="en" hreflang="en" href="http://webaim.org/blog/jaws-ate-my-tables/">Jared Smith: JAWS ate my tables</a>.
<p>Ob eine Tabelle für Daten oder fürs Layout gedacht wurde, entscheidet JAWS nach dieser Regel: Wenn sie mindestens zwei Spalten und zwei Reihen hat und mindestens vier Zellen zwischen 200 und 16000 Pixel groß sind –  dann muß es eine Datentabelle sein, sonst nicht. Im Artikel illustrieren zwei Beispiele, warum das eine dämliche Heuristik ist.</li>
<li>
<p><a lang="ru" hreflang="ru" href="http://0range.ru/archives/20">Тагир Юсупов: Поворот изображении с помощью SVG и VML</a>.<br />
(<a title="Automatische Übersetzung ins Deutsche" href="http://translate.google.com/translate?hl=de&#038;sl=ru&#038;tl=de&#038;u=http%3A%2F%2F0range.ru%2Farchives%2F20">Tagir Yusupov: Bilder drehen mit SVG und VML</a>)</p>
<p>Eigentlich ganz einfach. Man muß nur drauf kommen. Via <a href="http://twitter.com/pawelf">Andreas Fritsch, @pawelf</a>.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2009/designlinks-10/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>E-Mail: HTML in Opera abschalten</title>
		<link>http://toscho.de/2009/html-e-mail-opera-abschalten/</link>
		<comments>http://toscho.de/2009/html-e-mail-opera-abschalten/#comments</comments>
		<pubDate>Sat, 05 Dec 2009 21:16:20 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Browser]]></category>
		<category><![CDATA[Markup]]></category>
		<category><![CDATA[e-mail]]></category>
		<category><![CDATA[Opera]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1552</guid>
		<description><![CDATA[Wie man mit Opera E-Mails so versendet, wie sie jeder lesen kann: als reinen Text.]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.opera.com/docs/changelogs/windows/1000/">Seit Version 10</a> kann Opera auch HTML-E-Mails verfassen. Eigentlich stört mich das nicht; ich muß dieses Feature ja nicht benutzen.</p>
<p>Leider stört ein Bug dabei die Empfänger dieser Mails: Antwortet man mit HTML auf eine Textnachricht, dann ist der Textteil dieser Antwort nur eine Kopie der Ursprungsnachricht. Er enthält <em>nicht</em> den Antworttext.<br />
Wer die Textdarstellung bevorzugt, sieht die »richtige« Antwort nicht.</p>
<p>Hat man also (versehentlich) den HTML-Modus beim Schreiben eingestellt, dann empfehle ich dringend, dieses wieder abzustellen. So geht es:</p>
<ol>
<li>Gehe auf »Extras/E-Mail- und Chatkonten«.</li>
<li>Markiere das E-Mailkonto, und klicke auf »Bearbeiten«.</li>
<li>Im Reiter »Postausgang« nimm den Haken aus »HTML-Formatierung vorziehen« und drücke »OK«. Fertig.</li>
</ol>
<p class="wideimg"><a href="http://img.toscho.de/screenshots/opera/kein-html-opera.png"><img class="border" src="http://img.toscho.de/screenshots/opera/kein-html-opera.png" alt="Einstellung für den HTML-Modus in Opera" width="627" height="502" /></a></p>
<p>Beim Schreiben einer E-Mail kann man zwischen den beiden Modi auch wechseln; die entsprechenden Buttons stehen rechts oben:</p>
<p><img class="aligncenter border" src="http://img.toscho.de/screenshots/opera/opera-mail-ansicht.png" alt="Auswahl der Schreibmodi" width="287" height="213" /></p>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2009/html-e-mail-opera-abschalten/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress: Kommentarfeed mit Blognamen</title>
		<link>http://toscho.de/2009/wordpress-kommentarfeed-blogname/</link>
		<comments>http://toscho.de/2009/wordpress-kommentarfeed-blogname/#comments</comments>
		<pubDate>Fri, 09 Oct 2009 17:49:45 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Interna]]></category>
		<category><![CDATA[Markup]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[feed]]></category>
		<category><![CDATA[Plugin]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1539</guid>
		<description><![CDATA[Wie man die Kommentarfeeds deutlicher einer Website zuordnet: Indem man ihren Titel in den des Feeds packt.]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.gwendragon.de/blog/">GwenDragon</a> hat mich heute darauf <a href="http://toscho.de/2009/spinner-und-sauger/#comment-831">hingewiesen</a>, daß im Kommentarfeed zu einzelnen Artikeln der Titel ein bißchen zu dünn aussieht: Der Blogname fehlt.<br />
Wenn mehrere Blogs zum gleichen Thema schreiben und jemand bei allen den Newsfeed abonniert hat, wird die Übersicht schon etwas schwierig. </p>
<p>Am besten sollte der Name des Blogs <em>vor</em> dem des Artikels stehen, aber das geht leider nicht: Die Reihenfolge ist <a href="http://xref.yoast.com/trunk/nav.html?wp-includes/feed-rss2-comments.php.source.html" title="Ansicht des Quelltextes des Feedtemplates">im RSS-Template festgeschrieben</a>.</p>
<p>Immerhin kann man einen Filter auf den Titel legen und den Blognamen dahinter setzen.<br />
In die <code>functions.php</code> des aktuell verwendeten Themes schreiben wir:</p>
<pre class="notranslate"><a href="http://codex.wordpress.org/Function_Reference/add_filter">add_filter</a>('<code class="string"><a href="http://xref.yoast.com/trunk/nav.html?wp-includes/feed.php.source.html#l104">the_title_rss</a></code>', '<code class="string">rss_title_suffix</code>');
function rss_title_suffix(<var>$str</var>)
{
    if ( <a href="http://codex.wordpress.org/Conditional_Tags#A_Syndication">is_feed</a>() AND <a href="http://codex.wordpress.org/Conditional_Tags#A_Single_Page.2C_Single_Post_or_Attachment">is_singular</a>() )
    {
        return <var>$str</var> . '<code class="string"> - </code>' . <a href="http://codex.wordpress.org/Function_Reference/get_bloginfo">get_bloginfo</a>('<code class="string">name</code>');
    }
    return <var>$str</var>;
}</pre>
<p>Aus dem Titel …<br />
<samp>Kommentare zu: PHP: Funktion sanitize_ip</samp></p>
<p>… wird jetzt …</p>
<p><samp>Kommentare zu: PHP: Funktion sanitize_ip - toscho.design</samp></p>
<p>Das ist nicht perfekt, aber besser als vorher.</p>
<h2>Update 1 (10.10.2009)</h2>
<p><a href="http://peter.westwood.name/">Peter Westwood</a> hat mich auf eine <a href="http://lists.automattic.com/pipermail/wp-hackers/2009-October/027859.html">bessere Fährte</a> gelenkt. Die neue Fassung sieht so aus:</p>
<pre class="notranslate">add_filter('<code class="string">gettext</code>', '<code class="string">rss_title_prefix</code>');

function rss_title_prefix(<var>$str</var>)
{
    if ( is_feed() AND is_singular() )
    {
        return str_replace('<code class="string">Kommentare zu:</code>', get_bloginfo('<code class="string">name</code>') . '<code class="string"> - Kommentare zu:</code>', <var>$str</var>);
    }
    return <var>$str</var>;
}</pre>
<p>Ergebnis:<br />
<samp>toscho.design - Kommentare zu: PHP: Funktion sanitize_ip</samp></p>
<h2>Update 2 (10.10.2009)</h2>
<p>Zwei Mails später habe ich nun einen Code, der in jeder Sprache funktioniert. Danke nochmal an Peter Westwood und an <a href="http://bueltge.de/">Frank Bültge</a>.</p>
<pre class="notranslate">if ( !function_exists(&#039;<code class="string">rss_title_prefix</code>&#039;) )
{
    function rss_title_prefix(<var>$translation</var>, <var>$original</var>, <var>$domain</var>)
    {
        if ( ( &#039;<code class="string">default</code>&#039; == <var>$domain</var> )
            &amp;&amp; ( &#039;<code class="string">Comments on: %s</code>&#039; == <var>$original</var> ) )
        {
            return get_bloginfo(&#039;<code class="string">name</code>&#039;) . &#039;<code class="string"> - </code>&#039; . <var>$translation</var>;
        }
        return <var>$translation</var>;
    }
    add_filter(&#039;<code class="string">gettext</code>&#039;, &#039;<code class="string">rss_title_prefix</code>&#039;, 10, 3);
}</pre>
<h2>Update 3 (09.02.2010)</h2>
<p>Inzwischen hat sich der Originaltext von <code class="string">Comments on:</code> zu <code class="string">Comments for</code> geändert, daher muß das jetzt so aussehen:</p>
<pre class="notranslate">if ( !function_exists(&#039;<code class="string">rss_title_prefix</code>&#039;) )
{
    function rss_title_prefix(<var>$translation</var>, <var>$original</var>, <var>$domain</var>)
    {
        if ( ( &#039;<code class="string">default</code>&#039; == <var>$domain</var> )
            &amp;&amp; ( &#039;<code class="string">Comments for %s</code>&#039; == <var>$original</var> ) )
        {
            return get_bloginfo(&#039;<code class="string">name</code>&#039;) . &#039;<code class="string"> - </code>&#039; . <var>$translation</var>;
        }
        return <var>$translation</var>;
    }
    add_filter(&#039;<code class="string">gettext</code>&#039;, &#039;<code class="string">rss_title_prefix</code>&#039;, 10, 3);
}</pre>
<p>Das kommt, wie gesagt, in die <code>functions.php</code>, oder man benutzt den Code als Plugin:</p>
<p class="downloadlink"><a href="http://f.toscho.de/feed-title-plus-blogname.zip">Download Plugin »Feed title plus blogname«</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2009/wordpress-kommentarfeed-blogname/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Database Caching using disk: basic
Object Caching 660/805 objects using disk: basic

Served from: toscho.de @ 2012-02-04 12:28:54 -->
