Kategorie- und Archiv-Dropdowns mit unobtrusive JavaScript

Die Zeiten ändern sich.

Dieser Beitrag scheint älter als 13 Jahre zu sein – eine lange Zeit im Internet. Der Inhalt ist vielleicht veraltet.

Eine gute Website funktioniert, wenn ein Benutzer mit deaktiviertem JavaScript vorbeikommt, genau so gut wie mit aktiviertem Scripting. Man trennt die JS-Schicht der Website sauber von allem anderen (und verzeichtet zum Beispiel auf onclick-Handler im HTML) und legt seine Scripts so an, dass nur die schon vorhandene Funktionalität der Seite verbessern und umformen. So kommen die Besucher sowohl mit als auch ohne JS an ihr Ziel, wenn der Weg ohne Scripting vielleicht etwas mühsamer oder weniger schön ausfällt. Diese Herangehensweise an Scripting auf Websites nennt sich Unobtrusive JavaScript und warum das eine Gute Sache ist, erklärt Jenn Lukas in diesem Talk von der JSConf 2010. Neben all den guten Gründen ist das wichtigste Argument für unobtrusive JavaScript, dass es bei entsprechender Planung so einfach umzusetzen ist, dass es grundlos verschenktes Potenzial wäre wenn man darauf verzichten würde. Problematisch kann es allein dann werden, wenn das einem das für die Website verwendete CMS einem einen Strich durch die Rechnung macht – womit wir beim Thema WordPress wären.

Gelegentlich möchte man in seiner Blog-Sidebar Dropdowns-Menüs (select-Elemente) zur Navigation der Kategorien und des Archivs unterbringen und der WordPress-Codex bietet in den Dokumentationen auch entsprechende Lösungen für Kategorien und Archiv an, die allerdings beide nur mit aktiviertem JavaScript funktionieren. In beiden Fällen wird die URL der Ziel-Seite im value-Wert der im Dropdown-Menü verbauten option-Elemente gespeichert und sobald man einen Eintrag auswählt, wird man via JavaScript auf eben jene URL weitergeleitet. Die fast gleiche Funktionalität ließe sich aber auch ganz ohne Scripts erreichen:

  1. Ein altmodisches GET-Formular mit Absendebutton anlegen, das an die Basisadresse der Website sendet
  2. Das select in eben dieses Formular stecken und name="cat" angeben
  3. Den option-Elementen als value den Slug der Kategorien geben

Das Absenden des Formulars resultiert dann in einem Aufruf von blog.de/?cat=kategorie und damit der gewünschten Kategorie, ggf. mit einem Redirect auf die suchmaschinenfreundliche Variante der URL. Das funktioniert für den Besucher genau so gute wie die Lösung aus dem Codex, sieht man einmal davon ab, dass man einen Button anklicken muss. Doch genau hier kann man mit JavaScript eingreifen, den Button verstecken und das Absenden des Formulars über einen via Script eingefügten onclick-Handler übernehmen. Das Endresultat sieht dann für Surfer mit Script wie die Codex-Lösung aus und alle anderen kommen dann eben über einen Klick auf den Button an ihr Ziel und alle sind zufrieden. Also an die Arbeit!

Die Grundlage für das Kategorie-Dropdown bildet ein ganz normales HTML-Formular:


<form id="kategorienform" action="<?php bloginfo('url'); ?>" method="get">
    <label for="kategorienselect">Zu Kategorie springen</label>
    <select id="kategorienselect" name="cat">
        <option value="">-- Bitte auswählen</option>
        <?php
            $categories = get_categories('hierarchical=0');
            foreach($categories as $category){
                $selected = (is_category($category->cat_ID)) ? 'selected' : '';
                echo '<option '.$selected.' value="'.$category->cat_ID.'">'.$category->cat_name.' ('.$category->count.')</option>';
            }
        ?>
    </select>
    <input id="kategorienbutton" value="Kategorie abrufen" type="submit">
</form>

Dieses könnte man so in die Seitenleiste des Dokuments werfen und es würde funktionieren, doch wir wollen ja noch den Absenden-Button loswerden und die Umleitung direkt bei der Auswahl einer Kategorie starten. Hierzu braucht es nicht mehr als 6 Zeilen JavaScript, die man direkt unter dem Formular einfügen kann:


<script type="text/javascript">
    document.getElementById('kategorienselect').onchange = function(){
        if(this.value){
            document.getElementById('kategorienform').submit();
        }
    };
    document.getElementById('kategorienbutton').style.display = 'none';
</script>

Ändert der Benutzer seine Auswahl im select-Element, wird (sofern nicht gerade der „Bitte auswählen“-Eintrag gewählt wird) das Formular automatisch abgesendet, auch ohne den mit style.display = 'none' unsichtbar gemachten Button aktivieren zu müssen – und fertig ist das benutzerfreundliche und trotzdem auch ohne JavaScript funktionierende Kategorie-Dropdown! Das ist zwar etwas mehr Code als die drei Zeilen aus dem Codex, funktioniert dafür aber garantiert bei jedem Besucher. Und das Prinzip ist recht simpel, vorausgesetzt man plant von vornherein entsprechend. Da eben das bei WordPress selbst nicht passiert ist, müssen wir etwas mehr tippen – beziehungsweise im Falle des Archiv-Dropdowns sogar sehr viel mehr:


<form id="archivform" action="<?php bloginfo('url'); ?>" method="get">
    <label for="archivselect">Zu Monat springen</label>
    <select id="archivselect" name="m">
        <option value="">-- Bitte auswählen</option>
        <?php
            $query = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, COUNT(ID) as `posts`
                FROM $wpdb->posts
                WHERE post_type = 'post' AND post_status = 'publish'
                GROUP BY YEAR(post_date), MONTH(post_date)
                ORDER BY post_date DESC";
            $key = md5($query);
            $cache = wp_cache_get('select_archives', 'general');
            if(!isset($cache[$key])){
                $arcresults = $wpdb->get_results($query);
                $cache[$key] = $arcresults;
                wp_cache_set('select_archives', $cache, 'general');
            }
            else{
                $arcresults = $cache[$key];
            }
            if($arcresults){
                global $wp_locale;
                foreach((array) $arcresults as $arcresult){
                    $value = $arcresult->year.$arcresult->month;
                    $text = sprintf(__('%1$s %2$d'), $wp_locale->get_month($arcresult->month), $arcresult->year);
                    $count = '&nbsp;('.$arcresult->posts.')';
                    $selected = (is_month() && get_query_var('year').get_query_var('monthnum') == $value) ? 'selected' : '';
                    echo '<option '.$selected.' value="'.$value.'">'.$text.$count.'</option>';
                }
            }
        ?>
    </select>
    <input id="archivbutton" value="Archiv abrufen" type="submit">
</form>

Das Problem beim Monatsarchiv ist, dass man ohne einen eigenen SQL-Query nicht an die Informationen herankommt, die man für ein Monats-Archiv braucht. So kommt man nicht drum herum, manuell die Datenbank zu bemühen und das Ergebnis händisch zu cachen. Das Prinzip ist aber identisch: einfach ein herkömmliches Formular ausgeben und wieder mit sechs kleinen Zeilen JavaScript aufwerten:


<script type="text/javascript">
    document.getElementById('archivselect').onchange = function(){
        if(this.value){
            document.getElementById('archivform').submit();
        }
    };
    document.getElementById('archivbutton').style.display = 'none';
</script>

Wir fassen zusammen: viele Zeilen Code, aber kompliziert ist das Prinzip nicht. Unobtrusive JavaScript ist eine Frage der intelligenten Planung und wenn die mal, wie bei WordPress, nicht von Haus aus mitgeliefert wird, muss man sich eben behelfen. Bei herkömmlichen Websites gibt es keinen Grund, die Bedienung komplett von JavaScript abhängig zu machen und falls doch mal etwas Mehraufwand entsteht, so ist er die saubere Trennung der Schichten und den Zugänglichkeits-Bonus allemal wert.

Gastbeitrag


Dieser Beitrag ist aus der Feder von Peter Kröner – peterkroener.de und ist ein Beitrag zum Adventskalender auf wpengineer.com zum Thema WordPress.
Peter Kröner ist selbstständiger Webdesigner und -entwickler sowie Autor des HTML5-Buchs.
Auf peterkroener.de bloggt er über alle Themen rund um Webtechnologie.

Vielen Dank auch hier nochmal von meiner Seite an Peter.

Von Frank Bültge

bueltge.de [by:ltge.de] wird von Frank Bültge geführt, administriert und gestaltet. Alle Inhalte sind persönlich von mir ausgewählt und erstellt, nach bestem Gewissen und Können, was die Möglichkeit von Fehlern nicht ausschließt.