Kapitel 4. Themen

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

WordPress-Themes steuern das Frontend deiner Webanwendung. In Kapitel 1 haben wir die Analogie vorgestellt, dass WordPress-Themes wie Views in einem traditionellen MVC-Framework sind. Die Analogie ist nicht perfekt, aber Themes und Views sind sich insofern ähnlich, als dass sie beide das Aussehen deiner App bestimmen und deine Designer die meiste Zeit damit verbringen.

Das von der WordPress-Community zusammengestellte Theme Developer Handbook ist die maßgebliche Quelle, um zu lernen, wie man Themes für WordPress auf der Grundlage von Standards entwickelt. Alle Theme-Entwickler sollten diese Ressource nutzen. Dieses Kapitel behandelt Bereiche der Theme-Entwicklung, die für App-Entwickler besonders wichtig sind.

Themes versus Plugins

In gewisser Weise sind alle Quelldateien in deinen Themes und Plugins nur .php-Dateien, die von WordPress zu verschiedenen Zeiten geladen werden. Theoretisch könnte dein gesamter App-Code in einem Theme oder einem Plugin untergebracht sein. In der Praxis solltest du dein Theme für den Code im Frontend (Views) deiner Website reservieren und Plugins für das Backend (Models und Controller) deiner App verwenden.

Wo du einen Teil des Codes unterbringst, hängt davon ab, ob du in erster Linie eine komplette App oder ein einzelnes Plugin oder Theme erstellst.

Wo soll der Code bei der Entwicklung von Apps platziert werden?

Wenn du eine vollständige Webapplikation - also eine WordPress-Installation - erstellst, hast du vollen Zugriff auf die Website und darauf, welche Themes und Plugins installiert sind. Dein Code kann überall hingehen. Trotzdem solltest du bei der Entscheidung, ob eine bestimmte Funktion als Modul des Plugins oder Themes deiner App oder als separates Plugin programmiert werden soll , einen gewissen Denkprozess durchlaufen. Der Hauptnutznießer deiner guten Planung in diesem Schritt werden deine Entwickler sein (vielleicht auch nur du). Wenn du deinen Code richtig organisierst, wird es für dich einfacher sein, deine App zu pflegen und weiterzuentwickeln.

Bei der Entwicklung von Apps versuchen wir, die folgenden Richtlinien einzuhalten:

  • Verwende ein Hauptplugin, um den Kerncode der App zu speichern, und ein Theme, um den Frontend-Code zu verwalten.

  • Jede modulare Funktion, die in anderen Projekten nützlich sein oder durch ein anderes Plugin ersetzt werden könnte, sollte als separates Plugin kodiert werden.

  • Hacke niemals den Kern!1

Was ist also der Kern-Code der App und was der Frontend-Code? Unser Pseudo-MVC-Framework sieht wie folgt aus:

Plugins = Modelle

Alle Datenstrukturen, Geschäftslogik und Ajax-Dienste, die du in deinem Code definierst, sollten in das Kern-Plugin aufgenommen werden. Dinge wie die Definitionen für CPTs und Taxonomien, die Verarbeitung von Formularen und die Klassenwrapper für die Klassen Post und User sollten ebenfalls in dein Core-Plugin aufgenommen werden.

Themen = Ansichten

Dein gesamter Templating-Code und die Frontend-Logik sollten in deinem Theme enthalten sein. Der Rahmen deiner Website, der Header, die Fußzeile, das Menü und die Seitenleisten sollten in deinem Theme codiert sein. Einfache Logik wie if(is_user_logged_in()) { //show menu } else { //show login } sollte in deinem Theme enthalten sein.

Eine Sache, die du bei der Entscheidung, wo du Funktionen codierst, berücksichtigen solltest, ist dein Entwicklungsteam. Wenn du einen Designer und einen Programmierer hast, solltest du die Dinge, die den Designer betreffen, im Theme unterbringen und die Dinge, die den Programmierer betreffen, im Core-Plugin. Auch wenn du ein bisschen tricksen musst, macht es die klare Trennung für deine Entwickler einfacher, das zu finden, wonach sie suchen.

Bei der Entwicklung von Plugins

Wenn du ein Plugin erstellst, das auf anderen Websites verwendet werden soll, oder modulare Funktionen, die projektübergreifend eingesetzt werden können, ist es sinnvoll, deinen Code in einem Plugin zu halten. In diesen Fällen kannst du Templating-Dateien in deinem Plugin speichern, um die UI-Komponenten zu verwalten. Es ist gängige Praxis, dass diese Dateien vom aktiven WordPress-Theme überschrieben werden können, was später in diesem Kapitel behandelt wird.

Wo soll der Code bei der Entwicklung von Themen platziert werden?

Ähnlich verhält es sich, wenn du ein Theme entwickelst, das vertrieben werden soll und auf CPTs oder andere Anpassungen angewiesen ist, die normalerweise in einem Plugin kodiert werden, kann es sinnvoll sein, diese in dein Theme zu integrieren. Wenn deine Nutzer/innen ein Plugin aktivieren müssen, bevor dein Theme überhaupt funktioniert, kannst du den Plugin-Code auch in dein Theme aufnehmen. Wenn dein Theme große grundlegende Änderungen an WordPress vornimmt, solltest du in Erwägung ziehen, den Plugin-ähnlichen Code in ein Parent-Theme und deinen designbezogenen Code in ein Child-Theme zu integrieren. Wenn deine Nutzer/innen das Design ihrer Website ändern wollen, ohne die anderen Funktionen des Themes zu verlieren, können sie das auf diese Weise leichter tun.

Wenn der Code, den du in dein Theme einfügen willst, für die Funktionsweise des Themes nicht entscheidend ist oder es andere Plugins gibt, die als Alternative für deinen Code verwendet werden können, solltest du den Code in ein Plugin verschieben und dein Theme als Paket mit den Themes und den empfohlenen Plugins vertreiben. Viele Premium-Themes fügen zum Beispiel SEO-bezogene Felder auf der Seite "Beitrag bearbeiten" hinzu, um Seitentitel, Meta-Beschreibungen und Meta-Keywords zu verwalten. Das macht Sinn, da diese SEO-bezogenen Felder eine Art Ansicht darstellen, die von Google und anderen Webcrawlern gesehen wird. Es gibt jedoch einige sehr beliebte Plugins, die dieselbe Funktion haben, und es ist schwer zu behaupten, dass dein Theme ohne die SEO-Funktionalität nicht funktionieren würde. Wir empfehlen den Theme-Entwicklern, ihre SEO-Funktionen in Plugins zu integrieren oder sie auf andere Weise leicht zu deaktivieren, damit andere Plugins verwendet werden können.

Letztendlich sollte die Entscheidung, wo du welchen Code einbaust und wie du die Dinge verpackst, von deinen Nutzern abhängig gemacht werden, sowohl von den Endnutzern als auch von den Entwicklern, die deine Themes und Plugins verwenden werden. Das Schöne an WordPress ist die Flexibilität, mit der du das System anpassen kannst. Es gibt keine strengen Regeln. Betrachte alles, was du über dieses Thema liest (auch von uns), als Richtlinien. Wenn du den Code aus einer Plugin-Datei in eine Theme-Datei verschieben kannst, um die Arbeit zu erleichtern, dann tu es.

Die Templating-Hierarchie

Wenn ein Nutzer deine Website besucht und zu einer Seite navigiert, verwendet WordPress ein System namens Templating-Hierarchie, um zu bestimmen, welche Datei im aktiven Theme für die Darstellung der Seite verwendet werden soll. Wenn der Nutzer zum Beispiel eine Seite mit einem einzelnen Beitrag aufruft, sucht WordPress nach single-post.php. Wenn diese nicht gefunden wird, sucht es nach single.php. Wenn diese nicht gefunden wird, sucht es nach index.php.

Die Datei index.php ist der Fallback für alle Seitenaufrufe und zusammen mit style.css die einzige erforderliche Datei für dein Theme. Normalerweise hast du eine Liste von Dateien wie die folgende:

  • 404.php

  • author.php

  • archive.php

  • attachment.php

  • category.php

  • comments.php

  • date.php

  • footer.php

  • front-page.php

  • functions.php

  • header.php

  • home.php

  • image.php

  • index.php

  • page.php

  • search.php

  • sidebar.php

  • single.php

  • single-(post-type).php

  • style.css

  • tag.php

  • taxonomy.php

Einige Dateien in dieser Liste werden geladen, wenn du eine bestimmte get Funktion aufrufst. Zum Beispiel lädt get_header() die Datei header.php, get_footer() die Datei footer.php und get_sidebar() die Datei sidebar.php. Wenn du diesen Funktionen einen name Parameter übergibst, wird dieser dem geladenen Dateinamen hinzugefügt. get_header('alternate'); lädt zum Beispiel header-alternate.php aus dem Theme-Ordner.

Die Funktion comments_template() lädt comments.php, es sei denn, du gibst einen anderen Dateinamen als ersten Parameter an.

Die Funktion get_search_form() sucht nach der Datei searchform.php in deinem Theme-Ordner oder gibt das Standard-Suchformular von WordPress aus, wenn keine Datei gefunden wird.

In der WordPress-Dokumentation zur Templating-Hierarchie sind die verschiedenen Dateien, nach denen WordPress beim Laden eines Themes sucht, übersichtlich dargestellt. Du kannst dir auch das Twenty Nineteen Theme oder anschauen, um zu sehen, welche Dateinamen von WordPress erkannt werden. Lies die Kommentare in diesen Themes, um zu sehen, wann welche Seite geladen wird.

Wenn du Apps mit benutzerdefinierten Beitragstypen entwickelst, möchtest du häufig eine andere Vorlage verwenden, wenn du deine Beitragstypen im Frontend anzeigst. Du kannst die Einzelbeitrags- und Archivansicht für deine Beitragstypen außer Kraft setzen, indem du Dateien mit den Namen single-<post_type>.php und archive-<post_type>.php hinzufügst, wobei post_type auf den Wert gesetzt wird, der bei der Registrierung des Beitragstyps verwendet wurde.

Seiten-Templates

Eine der einfachsten Möglichkeiten, beliebigen PHP-Code auf einer WordPress-Website zum Laufen zu bringen, ist, eine Seitenvorlage in dein Theme einzubauen und diese Vorlage dann auf einer deiner Seiten zu verwenden.

Zu den gängigen Templates in WordPress-Themes gehören Kontaktformulare und Landing Page-Formulare.

Muster Seitenvorlage

Beispiel 4-1 ist eine abgespeckte Version einer Kontaktformularvorlage, die du in den Ordner deines Themes legen kannst.

Beispiel 4-1. Beispiel einer Seitenvorlage
<?php
/*
Template Name: Page - Contact Form
*/

//get values possibly submitted by form
$email = sanitize_email( $_POST['email'] );
$cname = sanitize_text_field( $_POST['cname'] );
$phone = sanitize_text_field( $_POST['phone'] );
$message = sanitize_text_field( $_POST['message'] );
$sendemail = !empty( $_POST['sendemail'] );

// form submitted?
if ( !empty( $sendemail )
    && !empty( $cname )
	&& !empty( $email )
	&& empty( $lname ) ) {

	$mailto = get_bloginfo( 'admin_email' );
	$mailsubj = "Contact Form Submission from " . get_bloginfo( 'name' );
	$mailhead = "From: " . $cname . " <" . $email . ">\n";
	$mailbody = "Name: " . $cname . "\n\n";
	$mailbody .= "Email: $email\n\n";
	$mailbody .= "Phone: $phone\n\n";
	$mailbody .= "Message:\n" . $message;

	// send email to us
	wp_mail( $mailto, $mailsubj, $mailbody, $mailhead );

	// set message for this page and clear vars
	$msg = "Your message has been sent.";

	$email = "";
	$cname = "";
	$phone = "";
	$message = "";
}
elseif ( !empty( $sendemail ) && !is_email( $email ) )
	$msg = "Please enter a valid email address.";
elseif ( !empty( $lname ) )
	$msg = "Are you a spammer?";
elseif ( !empty( $sendemail ) && empty( $cname ) )
	$msg = "Please enter your name.";
elseif ( !empty( $sendemail ) && !empty( $cname ) && empty( $email ) )
	$msg = "Please enter your email address.";

// get the header
get_header();
?>
<div id="wrapper">
 <div id="content">
 <?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
  <h1><?php the_title(); ?></h1>
  <?php if ( !empty( $msg ) ) { ?>
   <div class="message"><?php echo $msg?></div>
  <?php } ?>
  <form class="general" action="<?php the_permalink(); ?>" method="post">
   <div class="form-row">
	<label for="cname">Name</label>
	<input type="text" name="cname" value="<?php echo esc_attr($cname);?>"/>
	<small class="red">* Required</small>
   </div>
   <div class="hidden">
	<label for="lname">Last Name</label>
	<input type="text" name="lname" value="<?php echo esc_attr($lname);?>"/>
	<small class="red">LEAVE THIS FIELD BLANK</small>
   </div>
   <div class="form-row">
	<label for="email">Email</label>
	<input type="text" name="email" value="<?php echo esc_attr($email);?>"/>
	<small class="red">* Required</small>
   </div>
   <div class="form-row">
	<label for="phone">Phone</label>
	<input type="text" name="phone" value="<?php echo esc_attr($phone);?>"/>
   </div>
   <div class="form-row">
	<label for="message">Question or Comment</label>
	<textarea class="textarea" id="message" name="message" rows="4" cols="55">
		<?php echo esc_textarea( $message )?>
	</textarea>
   </div>

   <div class="form-row">
	<label for="sendemail">&nbsp;</label>
	<input type="submit" id="sendemail" name="sendemail" value="Submit"/>
   </div>
  </form>
 <?php endwhile; endif; ?>
 </div>
</div>
<?php
// get the footer
get_footer();
?>

WordPress durchsucht alle .php-Dateien im Ordner und in den Unterordnern deines aktiven Themes (sowie im Ordner und in den Unterordnern des übergeordneten Themes) nach Templates. Jede gefundene Datei mit einem Kommentar, der den Ausdruck Template Name: enthält, wird dann als Template zur Verfügung gestellt.

Das Template wird geladen, nachdem die WordPress-Aktionen init und wp bereits ausgelöst wurden. Der Theme-Header und die Aktion wp_head werden erst geladen, wenn du get_header() in deinem Template aufrufst. Du kannst also den Anfang deiner Template-Datei nutzen, um Formulareingaben zu verarbeiten und möglicherweise eine Weiterleitung zu veranlassen, bevor die Kopfzeilen an die Seite gesendet werden.

Deine Templating-Datei muss das gleiche HTML-Markup enthalten wie die page.php oder die Single-Post-Vorlage deines Themes. Im vorangegangenen Beispiel fügen wir einen Wrapper <div> und einen Inhalt <div> um den Inhalt des Kontaktformulars ein.

Der vorstehende Code verwendet auch die Funktionen sanitize_text_field() und sanitize_email(), um die vom Formular übermittelten Werte zu bereinigen. Außerdem verwendet er die Funktionen esc_attr() und esc_textarea(), um Cross-Site-Scripting-Angriffe zu verhindern. Auf diese Funktionen wird in Kapitel 8 näher eingegangen.

Das vorangegangene Kontaktformular enthält auch einen "Honigtopf". Ein Feld mit der Bezeichnung lname wird mit CSS ausgeblendet, so dass normale Benutzer dieses Feld nicht sehen und es daher beim Absenden des Formulars leer lassen. Bots, die dein Kontaktformular ausnutzen wollen, um dir Spam zu schicken, sehen das Feld lname und werden es mit einem Wert versehen. Der Code, der das Formular verarbeitet, prüft, ob das Feld lname leer ist, bevor er die E-Mail verschickt. So wie ein Honigtopf Insekten anlockt, lockt das versteckte lname Feld Spammer an, damit du nicht in ihrem Namen E-Mails versendest.

Hooks zum Kopieren von Templates verwenden

Wenn du nicht mehrere Vorlagendateien ändern möchtest, wenn du die ID oder die Klassennamen deines Wrappers <div>s aktualisierst, kannst du eine Vorlage erstellen, die den Filter the_content oder eine andere themenspezifische Aktion verwendet, um Inhalte im Hauptinhaltsbereich deiner Seite zu platzieren. Dann kannst du eine andere Vorlagendatei laden, z. B. die Vorlage core page.php, die Aufrufe zum Laden des Frames und des Standardlayouts deiner Seite enthält. Beispiel 4-2 zeigt, wie du eine Seitenvorlage erstellst, die die Vorlage page.php lädt und auf bestimmten Seiten weitere Inhalte darunter einfügt.

Beispiel 4-2. Hooking-Vorlage
<?php
/*
    Template Name: Hooking Template Example
*/

//use the default page template
require_once(dirname(__FILE__) . "/page.php");

//now add content using a function called during the the_content hook
function template_content($content)
{
    //get the current post in this loop
    global $post;

    //get the post object for the current page
    $queried_object = get_queried_object();

    //we don't want to filter posts that aren't the main post
    if(empty($queried_object) || $queried_object->ID != $post->ID)
        return $content;

    //capture output
    ob_start();
    ?>
    <p>This content will show up under the page content.</p>
    <?php
    $temp_content = ob_get_contents();
    ob_end_clean();

    //append and return template content
    return $content . $temp_content;
}
add_action("the_content", "template_content");

In diesem Beispiel haben wir einen kleinen Trick angewandt, um die aktuelle $post mit der $queried_object zu vergleichen. Normalerweise ist die globale $post der Hauptbeitrag der Seite, zu der du navigiert hast. Andere Schleifen auf deiner Seite setzen die globale $post jedoch vorübergehend auf den Beitrag, mit dem sie gerade zu tun haben. Wenn deine Vorlage zum Beispiel ein WordPress-Menü verwendet, ist das in Wirklichkeit eine Schleife durch Beiträge des Typs menu. Viele Seitenleisten und Fußzeilen führen durch andere Beitragsgruppen.

Die Funktion get_queried_object() gibt das Hauptpost-Objekt für die aktuelle Seite zurück. Die Funktion gibt ein anderes, aber passendes Objekt zurück, wenn du dich auf einer Begriffs- oder Autorenseite befindest. Auf Archivseiten gibt die Funktion null zurück. Da es sich bei dem vorherigen Beispiel um eine Seitenvorlage handelt, die nur bei einzelnen Seitenaufrufen geladen wird, gibt der Aufruf von get_queried_object() dort immer ein $post Objekt für die aktuelle Seite zurück.

Du kannst auch einen eigenen Hook in deine page.php und andere Core Templates einfügen, um etwas Ähnliches zu erreichen. Füge einfach etwas wie do_action('my_template_hook'); an der Stelle in deiner Seitenvorlage ein, an der du zusätzliche Inhalte einfügen möchtest.

Wann solltest du eine Theme-Vorlage verwenden?

In Kapitel 3 haben wir besprochen, wie du Shortcodes verwendest, um Seiten für deine Plugins zu erstellen. Die Shortcodes sind nützlich, weil sie es dir ermöglichen, CMS-verwaltete Inhalte über und unter dem Shortcode im Inhaltsfeld des Beitrags einzufügen und deinen Code innerhalb deines Plugins zu organisieren. Wenn du also ein Plugin verteilst und die dazugehörige Seitenvorlage benötigst, solltest du die Shortcode-Methode verwenden, um deine Seite zu erstellen.

Wenn du ein eigenes Theme verteilst, musst du alle Templates, die für das Theme benötigt werden, in den Theme-Ordner aufnehmen. Du könntest auch Code für Shortcode-basierte Templates in dein Theme einbinden, aber Templates sind ein Standardverfahren für das Templating einer Seite.

Wenn deine Vorlage das HTML deiner Standardseitenlayouts ändern muss, solltest du eine Vorlagendatei innerhalb deines Themes verwenden. Beispiel 4-2 nutzt die Vorlage page.php, um zu vermeiden, dass das HTML umgeschrieben werden muss. Wenn es bei der Vorlage aber darum geht, den HTML-Code umzuschreiben (z. B. bei einer Landing Page-Vorlage, bei der du den Standard-Header, die Fußzeile und das Menü ausblenden möchtest), musst du unbedingt eine Vorlage verwenden.

Theme-bezogene WordPress-Funktionen

Als nächstes werden wir get_template_part( $slug,$name = null ) besprechen. Hier kann die Funktion get_template_part() verwendet werden, um andere .php-Dateien (Template-Teile) in eine Datei in deinem Theme zu laden.

Laut Codex bezieht sich $slug auf "den Slug-Namen für die generische Vorlage" und $name auf "den Namen der speziellen Vorlage". In Wirklichkeit werden beide Parameter einfach mit einem Bindestrich zusammengefügt, um den gesuchten Dateinamen zu bilden: slug-name.php.

Das Twenty Twelve-Theme verwendet get_template_part(), um einen bestimmten Postformat-"Content"-Teil in die WordPress-Schleife zu laden:

<?php /* Start the Loop */ ?>
<?php while ( have_posts() ) : the_post(); ?>
	<?php get_template_part( 'content', get_post_format() ); ?>
<?php endwhile; ?>

Wenn sich dein Template-Teil in einem Unterordner deines Themes befindet, füge den Ordnernamen vor dem Slug hinzu:

get_template_part('templates/content', 'page');

Die Funktion get_template_part() verwendet die Funktion locate_template() von WordPress, um den angegebenen Template-Teil zu finden, der dann die Datei mit der Funktion load_template() lädt. locate_template() sucht zunächst innerhalb des Child-Themes. Wenn im Child-Theme keine passende Datei gefunden wird, wird das Parent-Theme durchsucht.

Neben der Suche nach einer Datei sowohl im Child- als auch im Parent-Theme besteht der weitere Vorteil von get_template_part() gegenüber einem Standard-PHP-Aufruf include oder require darin, dass eine Reihe von globalen WordPress-Variablen eingerichtet wird, bevor die Datei eingebunden wird. Das folgende Beispiel ist der Quellcode für die Funktion load_template() ab WordPress 4.9.7,2 zeigt die globalen Variablen, die gesetzt werden. Beachte, dass das Array query_vars auch in den lokalen Bereich extrahiert wird. Der query_vars $s wird hier besondere Aufmerksamkeit gewidmet, da sie ein häufiger Angriffspunkt für XSS-Angriffe ist und viele Themes vergessen, die Suchanfrage zu escapen, wenn sie in das Suchfeld übertragen wird:

<?php
function load_template( $_template_file, $require_once = true ) {
	global $posts, $post, $wp_did_header, $wp_query, $wp_rewrite;
	global $wpdb, $wp_version, $wp, $id, $comment, $user_ID;

	if ( is_array( $wp_query->query_vars ) )
		extract( $wp_query->query_vars, EXTR_SKIP );

  if ( isset( $s ) )
		$s = esc_attr( $s );

	if ( $require_once )
		require_once( $_template_file );
	else
		require( $_template_file );
}
?>

Verwendung von locate_template in deinen Plugins

Ein gängiges Designmuster für Plugins ist es, Templates in den Plugin-Ordner aufzunehmen und den Nutzern zu erlauben, diese Templates zu überschreiben, indem sie ihre eigenen Versionen zum aktiven Theme hinzufügen. In SchoolPress können Lehrer/innen zum Beispiel Schüler/innen zu ihrem Unterricht einladen. Das Einladungsformular ist in einer Vorlage innerhalb des Plugins gespeichert:

//schoolpress/templates/invite-students.php
?>
<p>Enter</p>
<form action="" method="post">
	<label for="email">Email:</label>
<input type="text" id="email" name="email" value="" />
	<input type="submit" name="invite" value="Invite Student" />
</form>

SchoolPress ist als SaaS-Anwendung geplant, aber wir wollen auch eine Plugin-Version veröffentlichen, die andere für ihre eigenen Websites nutzen können. Nutzer/innen des Plugins können die Standardvorlage überschreiben, ohne das Kern-Plugin zu bearbeiten, da Änderungen am Kern-Plugin bei einem Upgrade des Plugins überschrieben werden würden.

Damit unsere Plugin-Nutzer die Einladungsvorlage überschreiben können, verwenden wir beim Einbinden der Vorlagendatei den folgenden Code:

//schoolpress/shortcodes/invite-students.php
function sp_invite_students_shortcode($atts, $content=null, $code="")
{
	//start output buffering
  ob_start();

	//look for an invite-students template part in the active theme
	$template = locate_template('schoolpress/templates/invite-students.php');

	//if not found, use the default
	if(empty($template))
		$template = dirname(__FILE__) .
            '/../templates/invite-students.php';

	//load the template
	load_template($template);

	//get content from buffer and output it
	$temp_content = ob_get_contents();
	ob_end_clean();
	return $temp_content;
}
add_shortcode('invite-students', 'sp_invite_students_shortcode');

Dieser Code verwendet unsere Shortcode-Vorlage aus Kapitel 3. Aber anstatt den HTML-Code in die Shortcode-Funktion einzubetten, laden wir ihn aus einer Template-Datei. Zuerst suchen wir mit locate_template() nach der Vorlage in den aktiven Child- und Parent-Themes. Wenn keine Datei gefunden wird, setzen wir $template auf den Pfad der Standardvorlage, die mit dem Plugin geliefert wird. Die Vorlage wird mit load_template() geladen.

Style.css

Die style.css Datei deines Themes muss einen Kommentar enthalten, der von WordPress verwendet wird, um die Version des Themes und andere Informationen im WordPress Dashboard anzuzeigen. Hier ist der Kommentar ganz oben in der style.css des Twenty Nineteen Themes:

/*
Theme Name: Twenty Nineteen
Theme URI: https://wordpress.org/themes/twentynineteen/
Author: the WordPress team
Author URI: https://wordpress.org/
Description: Our 2019 default theme is designed to show off the power of the
block editor. It features custom styles for all the default blocks, and is
built so that what you see in the editor looks like what you'll see on your
website. Twenty Nineteen is designed to be adaptable to a wide range of
websites, whether you’re running a photo blog, launching a new business, or
supporting a non-profit. Featuring ample whitespace and modern sans-serif
headlines paired with classic serif body text, it's built to be beautiful on
all screen sizes.
Requires at least: WordPress 4.9.6
Version: 1.4
License: GNU General Public License v2 or later
License URI: LICENSE
Text Domain: twentynineteen
Tags: one-column, flexible-header, accessibility-ready,
custom-colors, custom-menu, custom-logo, editor-style,
featured-images, footer-widgets, rtl-language-support,
sticky-post, threaded-comments, translation-ready
This theme, like WordPress, is licensed under the GPL.
Use it to make something cool, have fun, and share what
you've learned with others.
Twenty Nineteen is based on Underscores https://underscores.me/,
(C) 2012-2018 Automattic, Inc.
Underscores is distributed under the terms of the GNU GPL v2 or later.
Normalizing styles have been helped along thanks to the fine work of
Nicolas Gallagher and Jonathan Neal https://necolas.github.io/normalize.css/
*/

Die style.css-Datei des aktiven Themes (und ggf. des übergeordneten Themes) wird von WordPress automatisch in die Warteschlange gestellt.

Versionierung der CSS-Dateien deines Themes

Es ist eine gute Praxis, eine Version für deine CSS-Dateien festzulegen, wenn du sie über wp_enqueue_style() lädst. Wenn du dein CSS aktualisierst, kannst du auf diese Weise auch die Version aktualisieren. So vermeidest du, dass die Nutzer deiner Website eine scheinbar fehlerhafte Website sehen, die eine vom Browser zwischengespeicherte Version des Stylesheets verwendet.

Wenn WordPress die style.css-Datei deines Themes für dich in die Warteschlange stellt, verwendet es beim Laden des Stylesheets die gesamte WordPress-Version. Die Zeilenausgabe im Head-Tag deiner Website sieht dann so aus:

<link rel='stylesheet'
	id='twentynineteen-style-css'
	href='.../wp-content/themes/twentynineteen/style.css?ver=1.4'
	type='text/css'
	media='all' />

Aktualisierungen des Stylesheets, der Versionsnummer deiner App oder sogar der Versionsnummer, die im style.css-Kommentar angegeben ist, aktualisieren nicht die Version, die dem Stylesheet hinzugefügt wird, wenn es sich einreiht. Sie wird immer mit der WordPress-Versionsnummer übereinstimmen.

Eine Lösung ist, alle CSS aus der Datei style.css in andere CSS-Dateien in deinem Theme zu verschieben und diese CSS-Dateien über wp_enqueue_style() Aufrufe in der Datei functions.php des Themes zu laden. Für die Datei style.css würde das folgendermaßen aussehen:

/*
   Theme Name: SchoolPress
   Version: 1.0

   That's it! All CSS can be found in the "css" folder of the theme.
*/

und so für functions.php:

<?php
define( 'SCHOOLPRESS_VERSION', '1.0' );
function sp_enqueue_theme_styles() {
	if ( !is_admin() ) {
		wp_enqueue_style( 'schoolpress-theme',
			get_stylesheet_directory_uri() . '/css/main.css',
			NULL,
			SCHOOLPRESS_VERSION
		);
	}
}
add_action( 'init', 'sp_enqueue_theme_styles' );
?>

Eine Konstante wie SCHOOLPRESS_VERSION würde normalerweise in unserer Haupt-Plugin-Datei definiert werden, aber wir fügen sie der Übersichtlichkeit halber hier ein. Der vorangehende Code lädt unsere neue Datei /css/main.css mit der angehängten Hauptversion der App, damit neue Versionen der App nicht mit im Browser zwischengespeicherten Stylesheets in Konflikt geraten.

Es gibt eine weitere Möglichkeit, die Version der Hauptdatei style.css zu ändern, ohne sie in eine andere Datei zu verschieben. Wir verwenden den wp_default_styles Filter. Dieser Filter übergibt ein Objekt mit den Standardwerten, die verwendet werden, wenn ein Stylesheet angefordert wird. Einer dieser Werte ist der default_version, der wie folgt geändert werden kann:

define('SCHOOLPRESS_VERSION', '1.0');
function sp_wp_default_styles($styles)
{
    //use release version for stylesheets
	$styles->default_version = SCHOOLPRESS_VERSION;
}
add_action("wp_default_styles", "sp_wp_default_styles");

Jetzt wird unser Haupt-Stylesheet mit der SchoolPress-App-Version statt mit der WordPress-Hauptversion geladen. Wir können unser CSS in der style.css behalten, wenn wir wollen. Es ist aber oft eine gute Idee, zumindest einige Teile des CSS in separate Dateien in einem "css"-Ordner deines Themes zu verschieben.

functions.php

Die Datei functions.php deines aktiven Themes (und ggf. des Parent-Themes) wird jedes Mal geladen, wenn WordPress geladen wird. Aus diesem Grund ist die Datei functions.php ein beliebter Ort, um kleine Hacks und andere zufällige Codestücke hinzuzufügen. Auf einer typischen WordPress-Website kann die functions.php -Datei schnell unübersichtlich werden.

Aber wir entwickeln eine gut durchdachte WordPress-App, und unsere functions.php -Dateien müssen nicht unübersichtlich sein. So wie wir die Kernfunktionen unseres App-Plugins in kleinere includes aufteilen, solltest du das auch mit der functions.php deines Themes tun. Du könntest ähnliche Dateien wie die folgenden in den Ordner deines Themes einfügen:

/includes/functions.php

Wo du wirklich Hilfsfunktionen platzierst.

/includes/settings.php

Für Code, der sich auf die Themeneinstellungen und Optionen bezieht.

/includes/sidebars.php

Um Seitenleisten/Widgetbereiche zu definieren.

Vergewissere dich außerdem, dass der Code, den du der functions.php deines Themes hinzufügst, sich auf die Frontend-Anzeige deiner Website bezieht. Code, der sich auf das WordPress-Dashboard, die Backend-Verarbeitung für deine App oder deine gesamte App im Allgemeinen bezieht, sollte höchstwahrscheinlich irgendwo innerhalb des App-Plugins hinzugefügt werden.

Themen und CPTs

Da es sich bei CPTs nur um Beiträge handelt, werden sie standardmäßig mit der Vorlage single.php oder index.php dargestellt, wenn keine Vorlage single.php verfügbar ist. Du kannst auch eine Datei der Form single-<post_type>.php zu deinem Theme hinzufügen, wobei <post_type> der Slug deines CPTs ist. Falls vorhanden, wird diese Datei verwendet, um die Single-Post-Ansicht des jeweiligen Beitragstyps darzustellen.

Auf ähnliche Weise kannst du eine archive-<post_type>.php Datei hinzufügen, um die Archivansicht deines CPTs darzustellen, wenn das has_archive Flag in der CPT-Definition gesetzt ist. Wir behandeln CPTs (einschließlich der Angabe von Templates für sie) ausführlicher in Kapitel 5.

Beliebte Theme-Frameworks

Für die Erstellung von Anwendungen mit WordPress gibt es viele Theme-Frameworks - sowohl WordPress-spezifische Frameworks als auch allgemeine HTML/CSS-Frameworks - die du verwenden kannst. Ganz gleich, ob du das Theme-Framework für einen schnellen Proof of Concept oder als Kernkomponente deines selbst erstellten Themes nutzen willst, die Verwendung eines Theme-Frameworks kann dir eine Menge Zeit sparen.

Wir gehen kurz auf einige gängige Theme-Frameworks ein und zeigen dir, wie du zwei der beliebtesten Frameworks für die Entwicklung von WordPress-Apps nutzen kannst.

Aber zuerst: Was bietet ein Themen-Framework?

WordPress Theme Frameworks

WordPress-Theme-Frameworks sind Themes, die als übergeordnete Themes oder Starter-Themes verwendet werden können, um deine Frontend-Entwicklung in Gang zu bringen. Theme-Frameworks enthalten in der Regel grundlegende Stile und Layouts für Blogbeiträge, Archive, Seiten, Seitenleisten und Menüs. Sie sind unterschiedlich umfangreich und einige enthalten CSS-Klassen, Shortcodes und andere praktische Codes, mit denen du neue Layouts erstellen und UI-Elemente zu deinen Seiten hinzufügen kannst. Alle Frameworks werden dir wahrscheinlich eine Menge Zeit ersparen.

Es gibt zwei Gründe, sich für ein Theme-Framework zu entscheiden: Entweder du wählst ein Child-Theme, das deiner Vision für deine App optisch sehr nahe kommt, oder du entscheidest dich für ein Framework, das so codiert ist, dass es sich richtig anfühlt, wenn du mit ihm arbeitest.

_s (Unterstriche)

Das Starter-Theme _s (ausgesprochen "Unterstriche") wird von Automattic veröffentlicht und enthält alle gängigen Komponenten, die du in einem WordPress-Theme brauchst. Im Gegensatz zu den meisten anderen Frameworks ist _s nicht dazu gedacht, als übergeordnetes Theme verwendet zu werden, sondern als Ausgangspunkt für dein eigenes übergeordnetes Theme. Die meisten von Automattic für WordPress.com entwickelten Themes basieren auf dem _s-Theme.

Um _s zu verwenden, lade den Code herunter und ändere den Verzeichnisnamen und alle Verweise auf _s mit dem Namen deines Themes. Eine gute Anleitung dazu findest du in der README-Datei des Projekts oder, noch besser, ein Tool, das dies automatisch für dich erledigt, findest du auf der underscores-Website.

Das Stylesheet in _s ist sehr minimalistisch und enthält kein wirkliches Styling, nur ein bisschen Code für das Layout und einige allgemeine Einstellungen für die Lesbarkeit und Benutzerfreundlichkeit. _s ist am besten für Designer/innen geeignet, die ihr eigenes Theme von Grund auf erstellen können und wollen. Es handelt sich im Grunde um Code, den du selbst für dein Theme schreiben müsstest. Der _s-Code ist nicht so stark abstrahiert wie bei anderen Theme-Frameworks, so dass die Verwendung des Frameworks für Designer/innen, die mit HTML und CSS besser vertraut sind als mit PHP, einfacher zu erlernen ist.

Memberlite

Memberlite ist ein Theme, das von Jason Coleman und Kimberly Coleman von Stranger Studios entwickelt wurde. Dieses Theme wurde speziell für Mitgliederseiten entwickelt, kann aber für eine Vielzahl von Websites verwendet werden. Der "lite"-Teil des Titels beschreibt das leichtgewichtige (technische und ästhetische) Design des Themes.

Memberlite ist responsiv gestaltet und passt sich an Bildschirme unterschiedlicher Größe an. Es hat Templates und Abschnitte für alles, was eine moderne Website braucht. Es gibt eine Reihe von Plugins (Memberlite Elements und Memberlite Shortcodes), mit denen du Seitenleisten, Banner, Seitenlayouts und andere Aspekte deiner Website noch besser steuern kannst.

Memberlite eignet sich am besten für Designer und Entwickler und ist unsere erste Wahl für Themes, weil es ein ausgewogenes Verhältnis zwischen Framework-Unterstützung auf der Design- und der Coding-Seite der Theme-Entwicklung bietet.

Genesis

Genesis ist ein von StudioPress entwickeltes Theme-Framework, das in mehr als 40 von StudioPress veröffentlichten Child-Themes und in vielen weiteren von Drittanbietern veröffentlichten Themes verwendet wird. Das Genesis-Theme ist als Eltern-Theme gedacht. StudioPress bietet Child-Themes an, die für eine Reihe von Unternehmen und Website-Typen geeignet sind. Du kannst auch dein eigenes Child-Theme erstellen, das von Genesis erbt.

Das Genesis-Framework abstrahiert das zugrunde liegende HTML und CSS stärker als die anderen hier aufgeführten Frameworks. Das macht es bei größeren Anpassungen etwas schwieriger, damit zu arbeiten. Genesis ist jedoch eine gute Wahl, wenn du feststellst, dass eines der Child-Themes zu 80 % dem gewünschten Aussehen entspricht oder wenn du das Framework einfacher als andere Optionen findest.

Nicht-WordPress-Theme-Frameworks

Neben WordPress-Theme-Frameworks gibt es auch Anwendungs-UI-Frameworks, die Markup, Stylesheets und Bilder für gängige UI-Muster und Elemente bereitstellen. Zu den beliebtesten UI-Frameworks gehören Bootstrap von Twitter und Foundation von Zurb.

Die Einbindung eines UI-Frameworks in dein Theme kann so einfach sein wie das Kopieren einiger Dateien in den Theme-Ordner und das Einreihen der Stylesheets und des JavaScript in die Warteschlange. So hast du einfachen Zugriff auf gestylte UI-Elemente wie Schaltflächen, Tabs, Paginierung, Breadcrumbs, Labels, Alerts und Fortschrittsbalken.

Als Nächstes behandeln wir, wie du Bootstrap-Assets in ein Memberlite Child-Theme einfügst, aber der gleiche Prozess sollte auch für andere Kombinationen von WordPress-Themes und UI-Frameworks funktionieren.

Ein Child Theme für Memberlite erstellen

Um dein Thema zu erstellen, musst du die folgenden Schritte ausführen: :

  1. Erstelle einen neuen Ordner in deinem wp-content/themes Ordner. Gib ihm dann den Namen memberlite-child.

  2. Erstelle eine style.css-Datei im Ordner memberlite-child.

  3. Füge den folgenden Text in deine style.css-Datei ein:

    /*
    THEME NAME: Memberlite Child
    THEME URI: http://bwawwp.com/wp-content/themes/memberlite-child/
    DESCRIPTION: Memberlite Child Theme
    VERSION: 0.1
    AUTHOR: Jason Coleman
    AUTHOR Uri: http://bwawwp.com
    TAGS: memberlite, child, tag
    TEMPLATE: memberlite
    */
    @import url("../memberlite/style.css");

    Das Schlüsselfeld im Kommentar ist das Feld TEMPLATE, das mit dem Ordner des Elternthemas übereinstimmen muss, in diesem Fall memberlite. Die einzige erforderliche Datei für ein Child-Theme ist style.css. An dieser Stelle hast du also ein Child-Theme erstellt.

    Du kannst entweder das gesamte CSS aus der style.css des Eltern-Themes in die style.css des Kind-Themes kopieren und dort bearbeiten, was du willst, oder du kannst wie hier @import_url verwenden, um die Regeln aus dem Stylesheet des Eltern-Themes zu importieren und darunter weitere Regeln hinzuzufügen, um die Stile des Eltern-Themes zu überschreiben.

    Um die Bootstrap-Dateien einzureihen, brauchst du außerdem eine functions.php-Datei.

  4. Erstelle zunächst eine leere functions.php-Datei im Ordner memberlite-child.

Bootstrap in das Theme deiner App integrieren

Bootstrap in das Memberlite-Theme zu importieren, ist im Vergleich zu einem Theme, das auf Bootstrap basiert, und dem Kopieren der CSS-Regeln, die du brauchst, ziemlich dumm. Das Importieren von Frameworks und Bibliotheken in dein Theme ist jedoch etwas, das dir unter Umständen Probleme bereitet. Im Folgenden erfährst du, wie du andere Bibliotheken und Frameworks in dein Theme importieren kannst.

Lade die Bootstrap-ZIP-Datei in deinen Memberlite-Child-Ordnerherunter. Nachdem du sie entpackt hast, hast du einen dist-Ordner mit den CSS- und JavaScript-Dateien für Bootstrap. Du kannst diesen Ordner in bootstrap umbenennen und die Bootstrap-ZIP-Datei löschen. Dein Child-Theme-Ordner sollte jetzt wie folgt aussehen:

  • memberlite-child

    • bootstrap

      • css

      • js

    • functions.php

    • style.css

Jetzt fügen wir das Bootstrap-CSS und JavaScript ein, indem wir diesen Code in die Datei functions.php in deinem Child-Theme einfügen:

<?php
function memberlite_child_init() {
	wp_enqueue_style(
		'bootstrap',
		get_stylesheet_directory_uri() .
            '/bootstrap/css/bootstrap.min.css',
		'style',
		'3.0'
	);
	wp_enqueue_script(
		'bootstrap',
		get_stylesheet_directory_uri() .
            '/bootstrap/js/bootstrap.min.js',
		'jquery',
		'3.0'
	);
}
add_action( 'init', 'memberlite_child_init' );
?>

Beachte, dass wir die Abhängigkeiten für das Bootstrap-CSS auf style gesetzt haben, um sicherzustellen, dass das Bootstrap-Stylesheet nach dem Memberlite-Stylesheet geladen wird. Außerdem setzen wir das Bootstrap-JavaScript auf jquery und die Version beider Dateien auf 3.0, damit sie mit der Version von Bootstrap übereinstimmen.

An dieser Stelle kannst du alle deine bevorzugten Bootstrap-Stile oder JavaScript in deinem WordPress-Theme verwenden. Viele der Bootstrap-Stile für Spalten und Layout werden im Memberlite-Markup nicht verwendet (Memberlite hat sein eigenes Layout-System) und sind daher für dein Theme nicht anwendbar. Aber die Stile für Formularelemente und Schaltflächen sind für App-Entwickler nützlich.

Menüs

Menüs sind ein wichtiger Bestandteil der meisten Apps, und Apps haben oft besondere Anforderungen an ihre Menüs, die andere Websites nicht haben. Manche Apps haben mehrere Menüs. Viele mobile Apps haben ein Hauptnavigationsmenü am oberen Rand und ein Toolbar-ähnliches Menü am unteren Rand. Manche Apps haben dynamische Menüs. Viele Apps haben für angemeldete Nutzer/innen andere Menüs oder Menüpunkte als für abgemeldete Nutzer/innen. Die Menüpunkte können auf der Mitgliedsstufe oder den Admin-Fähigkeiten eines Nutzers basieren.

Bevor wir uns damit befassen, wie du kompliziertere Menüs und Navigationselemente mit WordPress erstellen kannst, gehen wir auf die Standardmethode ein, mit der du ein Menü zu deinem Theme hinzufügen kannst.

Navigation Menüs

Seit WordPress Version 3.0 bestand die Standardmethode zum Hinzufügen von Navigationsmenüs zu Themes darin, das Menü im Code des Themes zu registrieren, festzulegen, wo im Theme das Menü erscheinen soll, und das Menü dann über das WordPress-Dashboard zu verwalten.

Der Hauptvorteil der eingebauten Menüfunktionen von WordPress ist, dass die Endnutzer/innen den Inhalt ihrer Menüs über die Dashboard-GUI steuern können. Auch wenn du ein Entwickler bist, der die volle Kontrolle über deine App hat, ist es eine gute Idee, die eingebauten Menüs in WordPress zu nutzen, da du vielleicht Interessengruppen hast, die die Menüs verwalten wollen, oder du dein Theme in Zukunft an andere weitergeben möchtest. Die WordPress-Navigationsmenüs lassen sich außerdem sehr einfach neu positionieren und können mithilfe von menübezogenen Hooks oder CSS-Styles von anderem Code profitieren.

Um ein neues Navigationsmenü zu registrieren, verwende die Funktion register_nav_menu( $location, $description ). Der Parameter $location ist ein eindeutiger Slug, der zur Identifizierung des Menüs verwendet wird. Der Parameter $description ist ein längerer Titel für das Menü, der im Dropdown-Menü im Dashboard angezeigt wird:

register_nav_menu('main', 'Main Menu');

Du kannst auch viele Menüs auf einmal registrieren, indem du die Variante register_nav_menus() (mit einem s) verwendest. Diese Funktion akzeptiert ein Array von Orten, in dem die Schlüssel die $location Slugs und die Werte die $description Titel sind:

register_nav_menus(array(
	'main' => 'Main',
	'logged-in' => 'Logged-In'
));

Um ein Navigationsmenü in deinem Thema zu platzieren, verwendet die Funktion wp_nav_menu():

wp_nav_menu( array('theme_location' => 'main' ));

Der Parameter theme_location sollte auf den mit register_nav_menu() gesetzten $location gesetzt werden. Die Funktion wp_nav_menu() kann viele andere Parameter annehmen, um das Verhalten und das Markup des Menüs zu ändern. Diese WordPress Codex-Seite über Navigationsmenüs ist eine gute Quelle für die verschiedenen Parameter der Funktion wp_nav_menu() und andere Möglichkeiten zur Anpassung von Menüs. In den folgenden Abschnitten stellen wir einige unserer Lieblingsrezepte vor.

Dynamische Menüs

Es gibt zwei Hauptmethoden, um deine WordPress-Menüs dynamisch zu gestalten, so dass verschiedene Menüpunkte auf verschiedenen Seiten oder unter verschiedenen Umständen angezeigt werden. Die erste ist, zwei Menüs einzurichten und je nach Fall ein anderes Menü zu laden. Hier ist ein Code-Beispiel aus dem Codex, das zeigt, wie man ein unterschiedliches Menü für angemeldete und abgemeldete Nutzer/innen anzeigt:

if ( is_user_logged_in() ) {
     wp_nav_menu( array( 'theme_location' => 'logged-in-menu' ) );
} else {
     wp_nav_menu( array( 'theme_location' => 'logged-out-menu' ) );
}

Die andere Möglichkeit, dein Menü dynamisch zu gestalten, besteht darin, den Filter nav_menu_css_class zu verwenden, um bestimmten Menüpunkten zusätzliche CSS-Klassen hinzuzufügen. Dann kannst du CSS verwenden, um bestimmte Menüpunkte auf der Grundlage ihrer CSS-Klasse ein- oder auszublenden.

Angenommen, du möchtest einen Anmeldelink aus einem Menü entfernen, wenn du auf der Anmeldeseite bist.3 Du könntest den folgenden Code verwenden:

function remove_login_link($classes, $item)
{
	if(is_page('login') && $item->title == 'Login')
    $classes[] = 'hide';	//hide this item

  return $classes;
}
add_filter('nav_menu_css_class', 'sp_nav_menu_css_class', 10, 2);

Du kannst auch das Markup deiner Menüs anpassen, indem du benutzerdefinierte Walker-Klassen verwendest (siehe Kapitel 7).

Responsive Design

Wir könnten noch ein ganzes Buch über Responsive Design schreiben. Zu unserem Glück haben das schon viele getan, darunter Clarissa Peterson, die das Buch Learning Responsive Web Design (O'Reilly) geschrieben hat. Das allgemeine Konzept hinter Responsive Design besteht darin, die Eigenschaften des Endgeräts zu erkennen und das Layout, das Design und die Funktionen deiner App so anzupassen, dass sie für dieses Gerät optimal funktionieren. Jetzt wollen wir uns ein paar verschiedene Techniken ansehen, um dies zu erreichen.

Geräte- und Display-Erkennung in CSS

Media Queries sind die wichtigste Methode zur Geräteerkennung in CSS. Sie werden in Stylesheets verwendet oder als Eigenschaft des <link> -Tags hinzugefügt, mit dem ein Stylesheet eingebettet wird, um den Geltungsbereich der CSS-Regeln des Stylesheets auf einen bestimmten Medientyp oder einen Fall zu beschränken, in dem eine bestimmte Medienfunktion verfügbar ist. Mozilla erklärt Medienabfragen sehr gut und listet die verschiedenen Eigenschaften und Operatoren auf, die du zum Erstellen einer Medienabfrage verwenden kannst.

Eine häufige Anwendung von Media Queries ist das Ausblenden bestimmter Elemente und das Anpassen von Schrift- und Elementgrößen, wenn jemand druckt. Du würdest diese Media Query in einem <link> Tag, innerhalb eines Stylesheets und durch einen wp_enqueue_style Aufruf wie folgt angeben:

<link rel="stylesheet" media="print" href="example.css" />

<style>
@media print
{
	.hide-from-print {display: none;}
	.show-when-printing {display: auto;}
}
</style>

<?php
	wp_enqueue_style('example', 'example.css', NULL, '1.0', 'print');
?>

Ein typischeres Beispiel in der Welt des responsiven Designs ist die Überprüfung auf min-width und/oder max-width in der Media Query, um die Stile anzupassen, wenn der Bildschirm kleiner oder größer wird. Das folgende Beispiel stammt aus dem Bootstrap responsive Stylesheet, das die CSS-Regeln für Bildschirme zwischen 768 und 979 Pixeln anpasst (die aktuelle Breite eines typischen Browserfensters auf einem Monitor). Größen von mehr als 979 Pixeln können als extra breit angesehen werden:

@media (min-width: 768px) and (max-width: 979px) {
  .hidden-desktop {
    display: inherit !important;
  }
  .visible-desktop {
    display: none !important ;
  }
  .visible-tablet {
    display: inherit !important;
  }
  .hidden-tablet {
    display: none !important;
  }
}

Eine weitere häufige Aufgabe, die mit Media Queries erledigt wird, ist das Ändern von Stilen und insbesondere das Austauschen von Bildern, wenn ein Browser einen hochauflösenden Retina-Bildschirm hat.4

Hier ist eine Mischung aus Media-Queries, die in einigen CSS für das WordPress-Dashboard verwendet werden, um ein hochauflösendes Display zu erkennen. Die Abfragen prüfen das Pixelverhältnis und den DPI-Wert. Die Werte variieren von Display zu Display, aber die meisten Displays mit Standardauflösung haben ein Pixelverhältnis von 1:1 und 96 DPI. Ein Retina-Display hat ein Pixelverhältnis von 2:1 und einen DPI-Wert von 196 oder höher, aber wir können auch auf minimale Werte zwischen Standardauflösung und Retina-Auflösung testen, um andere hochauflösende Displays zu erkennen:

@media(-o-min-device-pixel-ratio: 5/4),                 /* Opera */
        (-webkit-min-device-pixel-ratio: 1.25),         /* Webkit */
        (min-resolution: 120dpi) {                      /* Others */
                /* add your high res CSS here */
        }

Media Queries sind mächtig, und du kannst sie nutzen, um UIs zu erstellen, die sehr flexibel sind. Browser und CSS-Standards entwickeln sich ständig weiter. Es ist wichtig, dass du auf dem Laufenden bleibst, damit aktuelle Handys, Tablets und Monitore deine App so anzeigen, wie du es geplant hast.

Auf welche Eigenschaften du achten musst und wie du dein Stylesheet anpasst, um sie zu berücksichtigen, liegt außerhalb des Rahmens dieses Buches, aber ich hoffe, du hast die Idee verstanden und weißt, wie du Media Queries in dein WordPress-Theme einbauen kannst.

Geräte- und Feature-Erkennung in JavaScript

Das JavaScript deiner App kann auch von der Geräte- und Funktionserkennung profitieren. jQuery bietet Methoden, um die Fenster- und Bildschirmgröße und andere Informationen über den Browser zu erkennen. Viele HTML5-Funktionen, die in einem bestimmten Browser verfügbar sind oder nicht, können getestet werden, bevor sie zum Einsatz kommen.

Erkennen der Bildschirm- und Fenstergröße mit JavaScript und jQuery

JavaScript stellt die Bildschirmbreite und -höhe in den Eigenschaften screen.width und screen.height zur Verfügung. Du kannst auch screen.availWidth und screen.availHeight verwenden, um die verfügbare Breite und Höhe zu ermitteln, die die Pixel berücksichtigt, die von Symbolleisten und Seitenleisten im Browserfenster beansprucht werden.

Wenn du bereits jQuery verwendest, kannst du die Methode width() für jedes beliebige Element auf deiner Seite verwenden, um seine Breite zu ermitteln. Du kannst sie aber auch für die Objekte $(document) und $(window) verwenden, um die Breite des Dokuments bzw. des Fensters zu ermitteln. Du kannst auch die Eigenschaft height() für die Objekte document und window und für jedes Element auf deiner Seite verwenden.

Die Werte für $(window).width() und $(window).height() sollten dieselben sein wie die für screen.availWidth und screen.availHeight. Dies ist die verfügbare Größe des Browserfensters, abzüglich aller Symbolleisten oder Seitenleisten, oder genauer gesagt, wie viel Platz du für die Anzeige von HTML hast.

Die Breite und Höhe von $(document) geben die gesamte scrollbare Breite und Höhe deiner gerenderten Webseite an. Wenn du die Breite und Höhe in deinem JavaScript-Code verwendest, musst du sie oft aktualisieren, wenn sich die Fenstergröße ändert. Das kann passieren, wenn jemand die Größe des Browserfensters auf seinem Desktop ändert, sein Handy vom Hoch- ins Querformat dreht oder andere Dinge tut, die die Breite oder Höhe des Fensters verändern können. jQuery bietet eine einfache Möglichkeit, diese Änderungen zu erkennen, damit du dein Layout entsprechend aktualisieren kannst:

//bind an event to run when the window is resized
jQuery(window).resize(function() {
  width = jQuery(window).width();
  height = jQuery(window).height();
  //update your layout, etc
});

Du kannst ein Größenänderungsereignis an jedes Element binden, nicht nur an das gesamte Fenster. Elemente auf deiner Seite können wachsen und schrumpfen, wenn ein Benutzer mit deiner Seite interagiert, indem er möglicherweise Elemente über Ajax-Formulare hinzufügt, größenveränderliche Elemente auf den Bildschirm zieht oder auf andere Weise Dinge verschiebt.

Feature-Erkennung in JavaScript

Wenn du eine moderne App-UI mit HTML5-Funktionen entwickelst, möchtest du manchmal feststellen, ob eine bestimmte HTML5-Funktion nicht verfügbar ist, damit du eine Alternative oder einen Fallback anbieten kannst. In Mark Pilgrims Dive into HTML5 findest du eine gute Liste mit allgemeinen Methoden zur Erkennung von HTML5-Funktionen:

  1. Prüfe, ob eine bestimmte Eigenschaft auf einem globalen Objekt existiert (z.B. window oder navigator).

  2. Erstelle ein Element und prüfe dann, ob eine bestimmte Eigenschaft auf diesem Element existiert.

  3. Erstelle ein Element, überprüfe, ob eine bestimmte Methode für dieses Element existiert, rufe dann die Methode auf und prüfe den Wert, den sie zurückgibt.

  4. Erstelle ein Element, setze eine Eigenschaft auf einen bestimmten Wert und prüfe dann, ob die Eigenschaft ihren Wert behalten hat.

Wenn du nur eine solche Erkennung brauchst, geben dir einige der Beispiele auf der Dive into HTML5-Website Anregungen, wie du deine eigene Erkennung erstellen kannst. Wenn du viele Merkmale erkennen musst, hilft dir eine Bibliothek wie Modernizr.js.

Um Modernizr.js zu verwenden, holst du dir zuerst die Version des Skripts, die du brauchst, von der Website: Modernizr bietet ein Tool an, das dich fragt, welche Teile des Skripts du brauchst, und dann eine verkleinerte .js-Datei erstellt, die nur diese Teile enthält. Lege diese Datei in deinem Theme- oder Plugin-Ordner ab und reihe sie ein:

<?php
function sp_wp_footer_modernizr() {
	wp_enqueue_script(
		'modernizr',
		get_stylesheet_directory_uri() . '/js/modernizr.min.js'
	);?>
	<script>
		//change search inputs to text if unsupported
		if(!Modernizr.inputtypes.search)
			jQuery('input[type=search]').attr('type', 'text');
	</script>
	<?php
}
add_action( 'wp_footer', 'sp_wp_footer_modernizr' );
?>

Die Modernizr-Dokumentation enthält eine Liste der Funktionen, die mit Modernizr.js erkannt werden können .

jQuery bietet auch eine ähnliche Reihe von Prüfungen, die sich auf Dinge beschränken, die jQuery selbst über das jQuery.support Objekt prüfen muss. Wenn eine Prüfung, die du durchführen willst, bereits von jQuery durchgeführt wird, kannst du den Overhead von Modernizr.js vermeiden, indem du die jQuery-Prüfung verwendest. Eine Liste der Feature Flags, die von jQuery.support gesetzt wurden, findest du auf deren Website:

jQuery(document).ready(function() {
	//only load AJAX code if AJAX is available
	if(jQuery.support.ajax)
	{
		//AJAX code goes here
	}
});

Geräteerkennung in PHP

Die Geräteerkennung in PHP ist und basiert auf dem von PHP erstellten $_SERVER['HTTP_USER_AGENT'] global. Dieser Wert wird vom Browser selbst festgelegt und ist daher definitiv nicht standardisiert, oft irreführend und kann von Webcrawlern und anderen Bots gefälscht werden. Am besten vermeidest du die PHP-basierte Browsererkennung, indem du deinen Code so standardbasiert wie möglich gestaltest und die beschriebenen CSS- und JavaScript-Methoden zur Feature-Erkennung verwendest.

Wenn du einen Überblick über die Art des Browsers haben willst, der auf deine App zugreift, ist der User-Agent-String das Beste, was wir haben. Hier ist ein einfaches Testskript, das den User-Agent-String ausgibt und ein Beispiel dafür, wie ein solcher aussieht:

<?php
echo $_SERVER['HTTP_USER_AGENT'];

/*
	Outputs something like:
	Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4)
	AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36
*/
?>

Dieser User Agent String enthält nützliche Informationen, aber vielleicht zu viele. Es gibt nicht weniger als fünf verschiedene Browsernamen in diesem String. Um welchen Browser handelt es sich also? Mozilla, KHTML, Gecko, Chrome oder Safari? In diesem Fall haben wir Chrome auf einem MacBook Air mit OS X verwendet.

Haben wir schon erwähnt, dass es keinen Standard für den User-Agent-String gibt, den die Browser senden? In der Vergangenheit haben die Browser die Namen älterer Browser übernommen, um zu sagen: "Ich kann alles, was dieser Browser kann, auch".

WebAIM enthält eine witzige Zusammenfassung der Geschichte der verschiedenen User-Agent-Strings, darunter auch dieser Teil, der die Herkunft des Chrome-Browsers erklärt:

Und dann hat Google Chrome entwickelt, und Chrome hat Webkit verwendet und war wie Safari und wollte Seiten, die für Safari erstellt wurden, und gab daher vor, Safari zu sein. Und so verwendete Chrome WebKit und gab vor, Safari zu sein, und WebKit gab vor, KHTML zu sein, und KHTML gab vor, Gecko zu sein, und alle Browser gaben vor, Mozilla zu sein, und Chrome nannte sich Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, wie Gecko) Chrome/0.2.149.27 Safari/525.13, und der User-Agent-String war ein völliges Durcheinander und nahezu nutzlos, und jeder gab vor, jeder andere zu sein, und es herrschte Verwirrung.

Aaron Anderson

Browser-Erkennung im WordPress-Kern

Glücklicherweise hat WordPress einen Teil der Arbeit hinter dem Parsen des User-Agent-Strings erledigt und stellt einige globale Variablen und einige Methoden zur Verfügung, die die häufigsten Fragen zur Browsererkennung abdecken. Die folgenden globalen Variablen werden von WordPress in wp-includes/vars.php gesetzt:

  • $is_lynx

  • $is_gecko

  • $is_winIE

  • $is_macIE

  • $is_opera

  • $is_NS4

  • $is_safari

  • $is_chrome

  • $is_iphone

  • $is_IE

Und um bestimmte Server zu erkennen, haben wir :

  • $is_apache

  • $is_IIS

  • $is_iis7

Schließlich kannst du die Funktion wp_is_mobile() verwenden, die nach dem Wort mobile im User-Agent-String sowie nach einigen gängigen mobilen Browsern sucht.

Hier ist ein kurzes Beispiel, das zeigt, wie du diese Globals verwenden kannst, um verschiedene Skripte und CSS zu laden:

<?php
function sp_init_browser_hacks() {
	global $is_IE;
	if ( $is_IE ) {
		//check version and load CSS
		$user_agent = strtolower( $_SERVER['HTTP_USER_AGENT'] );
		if ( strpos( 'msie 6.', $user_agent ) !== false &&
			strpos( 'opera', $user_agent ) === false ) {
			wp_enqueue_style(
				'ie6-hacks',
				get_stylesheet_directory_uri() . '/css/ie6.css'
			);
		}
	}

	if ( wp_is_mobile() ) {
		//load our mobile CSS and JS
		wp_enqueue_style(
			'sp-mobile',
			get_stylesheet_directory_uri() . '/css/mobile.css'
		);
		wp_enqueue_script(
			'sp-mobile',
			get_stylesheet_directory_uri() . '/js/mobile.js'
		);
	}
}
add_action( 'init', 'sp_init_browser_hacks' );
?>

Browsererkennung mit PHPs get_browser()

PHP hat eine großartige Funktion zur Browsererkennung eingebaut: get_browser(). Hier ist ein einfaches Beispiel, das get_browser() aufruft und einige typische Ergebnisse anzeigt:

<?php
$browser = get_browser();
print_r($browser);

/*
	Would produce output like:

	stdClass Object (
[browser_name_regex] => §^mozilla/5\.0 \(.*intel mac os x.*\)
applewebkit/.* \(khtml, like gecko\).*chrome/28\..*safari/.*$§
[browser_name_pattern] => Mozilla/5.0 (*Intel Mac OS X*)
AppleWebKit/* (KHTML, like Gecko)*Chrome/28.*Safari/*
[parent] => Chrome 28.0
[platform] => MacOSX
[win32] =>
[comment] => Chrome 28.0
[browser] => Chrome
[version] => 28.0
[majorver] => 28
[minorver] => 0
[frames] => 1
[iframes] => 1
[tables] => 1
[cookies] => 1
[javascript] => 1
[javaapplets] => 1
[cssversion] => 3
[platform_version] => unknown
[alpha] =>
[beta] =>
[win16] =>
[win64] =>
[backgroundsounds] =>
[vbscript] =>
[activexcontrols] =>
[ismobiledevice] =>
[issyndicationreader] =>
[crawler] =>
[aolversion] => 0
)
*/

Das ist ziemlich erstaunlich! Warum steht diese Funktion an letzter Stelle in dem Abschnitt über die Erkennung eines Browsers mit PHP? Die Antwort ist, dass die Funktion get_browser() auf den meisten Servern nicht verfügbar oder veraltet ist. Damit die Funktion dir nützliche Informationen liefert oder in den meisten Fällen überhaupt funktioniert, musst du eine aktuelle browscap.ini-Datei herunterladen und PHP so konfigurieren, dass es sie findet. Wenn du deine App verteilst, solltest du eine andere Methode verwenden, um die Browserfähigkeiten zu erkennen. Wenn du deine App jedoch auf deinen eigenen Servern betreibst, ist get_browser() eine gute Wahl.

Eine aktuelle browscap.ini-Datei findest du auf der Website des Browser Capabilities Project. Achte darauf, dass du eine der Dateien für PHP formatiert hast. Wir empfehlen die Datei lite_php_browscap.ini, die nur halb so groß ist, aber Informationen zu den gängigsten Browsern enthält.

Sobald du die .ini-Datei auf deinem Server hast, musst du deine php.ini-Datei aktualisieren, damit sie darauf verweist. In deiner php.ini-Datei ist wahrscheinlich eine Zeile für browscap auskommentiert. Entferne die Auskommentierung und stelle sicher, dass sie auf die heruntergeladene .ini-Datei verweist. Sie sollte in etwa so aussehen:

[browscap]
browscap = /etc/lite_php_browscap.ini

Starte nun deinen Webserver (Apache, Nginx, etc.) neu und get_browser() sollte funktionieren.

Abschließende Anmerkung zur Browser-Erkennung

Wir haben hier viel Platz auf die Browsererkennung verwendet, aber in der Praxis solltest du sie nur als letztes Mittel einsetzen. Wenn ein bestimmter Browser dir bei einem bestimmten Design oder einer bestimmten Funktion Probleme bereitet, ist es verlockend, ihn zu erkennen und zu umgehen. Wenn es jedoch möglich ist, eine andere Lösung zu finden, die ein ähnliches Ergebnis erzielt, ohne bestimmte Browser herauszufiltern, ist es in der Regel besser, sich für diese Lösung zu entscheiden.

Wie wir hier gesehen haben, gibt es für den User-Agent-String keine Standards, und du musst deinen Code regelmäßig aktualisieren, um ihn für neue Browser und Browserversionen zu parsen.

Zweitens: In manchen Fällen ist ein browserspezifisches Problem ein Symptom für ein größeres Problem in deinem Code. Vielleicht gibt es eine Möglichkeit, dein Design oder deine Funktionen zu vereinfachen, damit sie in verschiedenen Browsern, auf verschiedenen Geräten und in verschiedenen Bildschirmgrößen besser funktionieren.

Das Ziel von responsivem Design und Programmierung ist es, etwas zu entwickeln, das flexibel genug ist, um alle verschiedenen Browser und Clients zu berücksichtigen, die auf deine App zugreifen, egal ob du sie kennst oder nicht.

1 Wenn du feststellst, dass du die Kerndateien hacken musst, um etwas zum Laufen zu bringen, überlege dir zuerst, ob du das wirklich tun musst. Wenn du eine WordPress-Kerndatei ändern musst, füge stattdessen Hooks hinzu und lege diese Hooks als Patch für die nächste Version von WordPress vor.

2 Wir haben einen Zeilenumbruch hinzugefügt und einige geschweifte Klammern entfernt, damit es besser in den Druck passt.

3 Du könntest unter $_SERVER['PHP_SELF'] nachsehen, ob du dich auf der Seite wp-login.php befindest. In diesem Beispiel gehen wir davon aus, dass sich unser Login auf einer WordPress-Seite mit dem Slug login befindet.

4 Retina ist der Markenname von Apple für seine hochauflösenden Displays. In Codekommentaren und Dokumentationen wird der Begriff "Retina" jedoch für alle hochauflösenden Displays verwendet.

Get Erstellen von Webanwendungen mit WordPress, 2. Auflage now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.