Der folgende Text ist ein Gastbeitrag von Scott Fennell. Scott hat kürzlich einen Beitrag auf CSS-Tricks über Klassennamen in WordPress gelesen und hatte eigene Ideen dazu, wie man Kontrolle ausüben kann, anstatt die Dinge so zu belassen, wie sie sind. Seine Idee ist es, wo möglich eine SMACSS-ähnliche Philosophie für Klassennamen durchzusetzen.
Ich habe kürzlich einen Artikel in diesem Bereich über Understanding WordPress CSS Classes genossen. Der Autor bemerkte
WordPress ist extrem anpassbar und es ist möglich, diese Standardklassen zu ändern, aber wir werden hier nicht darauf eingehen. — @carlosinho
Ich habe einige Tricks dazu aufgeschnappt und möchte diese mit Ihnen teilen.
Die SMACSS-Erkenntnis
Ich liebe das SMACSS-Buch. Von all den brillanten Praktiken, die dort empfohlen werden, sind meine Favoriten die Regeln für Klassennamen. Auf die Gefahr hin, viele Seiten Brillanz zu überfliegen, werde ich die Dinge auf ein Beispiel reduzieren
<div class="pod">
<h3 class="pod-header">heading</h3>
<ul class="pod-items">
<li class="pod-item"><a class="pod-item-link" href="#">Click me</a></li>
<li class="pod-item"><a class="pod-item-link" href="#">Click me</a></li>
</ul>
</div>
Das ist keine wörtliche Wiedergabe aus dem SMACSS-Buch, aber es repräsentiert, was SMACCS in meinem Workflow bedeutet hat. Bemerkenswert ist
- Jede Komponente von
.podist über eine CSS-Klasse zugänglich, die mitpod-präfixiert ist. - Komponenten, die eine Eltern-zu-viele-Kinder-Beziehung aufweisen, verwenden ein Singular/Plural-Namensschema, wie in
pod-itemundpod-items.
Das ist mehr oder weniger mein Idealaufbau für die Adressierung von HTML mit CSS. Es ist das Modell, das ich in diesem Artikel anstreben werde. Leider liefert WordPress das nicht mit.
WordPress SMACSS-ifizieren
Damit WordPress diesem Format folgt, sind vier breite Ansätze erforderlich
- Sehr schnelle und einfache Filter, um das, was WordPress ausgibt, mit wenigen Codezeilen zu ändern.
- WordPress anweisen, bestimmte Klassen auf Objekte anzuwenden, die wir registrieren.
- Gewohnheiten in unseren eigenen benutzerdefinierten Funktionen (entweder Plugin-Zeug oder functions.php) entwickeln, so dass sie leicht und überschaubar auf maßgeschneiderte Klassen übernommen werden können.
- Relativ große Überschreibungen von WordPress-Kernfunktionen, die sich letztendlich möglicherweise nicht lohnen.
Es sollte selbstverständlich sein (aber wir sagen es trotzdem): Das direkte Ändern von WordPress-Kerncodedateien ist keine Option.
Filter
Der einfachste Weg, viele der von WordPress gelieferten Klassen zu ändern, ist die Filterung. Nehmen wir an, wir haben einen Datenblock. Das könnten der Post-Titel (eine Zeichenkette) oder ein Array von Post-Klassen sein. Diese Daten sind auf dem Weg irgendwohin, vielleicht von der Datenbank zum Browser, um im Frontend angezeigt zu werden, oder vielleicht auf dem Weg vom Post-Editor zur Datenbank, wo sie gespeichert werden. Oft können wir, wenn Daten von einem Ort zum anderen bewegt werden, diese durch die Verwendung eines Filters ändern. Hier ist ein Beispiel, das die Klassen verwendet, die auf das Body-Tag angewendet werden
/**
* Extends the default WordPress body class.
*
* @param array $classes An array of css classes.
* @return array The array of css classes, filtered.
*/
function sjf_body_class( $classes ) {
// If the current post has a post thumbnail, append a body class.
if ( is_singular() && has_post_thumbnail() ) {
$classes[] = 'body-has-post-thumbnail';
}
return $classes;
}
// Apply these classes to the body tag.
add_filter( 'body_class', 'sjf_body_class' );
Beachten Sie, dass wir eine Bedingung haben, um dies nur zu tun, wenn es sich um einen einzelnen Beitrag mit einem Beitragsbild handelt. Es ist wichtig, dass wir das $classes-Array unabhängig vom Ergebnis dieser Bedingung zurückgeben, andernfalls erhalten alle unsere anderen Vorlagen keine Body-Klassen! Betrachten Sie diesen Punkt als ein "Fallen"-Symbol in den O'Reilly Tierbüchern.
Wir können der Klassen-Array jede beliebige Zeichenkette hinzufügen, obwohl wir, wenn wir etwas greifen, das nicht hartcodiert ist, es zuerst bereinigen sollten, mit sanitize_html_class(). Zum Beispiel möchten wir vielleicht einen post_meta-Wert hinzufügen, vielleicht wenn dieser Beitrag in einem speziellen Farbschema künstlerisch gestaltet wurde
/**
* Extends the default WordPress body class to include the accent color for this post.
*
* @param array $classes An array of css classes.
* @return array The array of css classes, plus a new class for accent-color.
*/
function sjf_body_class( $classes ) {
// If the current post has an accent color, append a body class.
if ( is_singular() ) {
$accent_color = get_post_meta( get_the_ID(), 'sjf_accent_color', TRUE );
$accent_color = sanitize_html_class( $accent_color );
if( ! empty( $accent_color ) ) {
$classes[] = "body-$accent_color";
}
}
return $classes;
}
// Apply these classes to the body tag.
add_filter( 'body_class', 'sjf_body_class' );
Wir können das Array von Klassen, das auf Beiträge in der Schleife angewendet wird, auf fast die gleiche Weise modifizieren. Der einzige Unterschied besteht darin, dass wir anstatt unsere Funktion zum body_class-Filter hinzuzufügen, sie zu post_class hinzufügen würden
/**
* Extends the default WordPress post class to include the accent color for this post.
*
* @param array $classes An array of css classes.
* @return array The array of css classes, plus a new class for accent-color.
*/
function sjf_post_class( $classes ) {
// If the current post has an accent color, append a post class.
if ( is_singular() ) {
$accent_color = get_post_meta( get_the_ID(), 'sjf_accent_color', TRUE );
$accent_color = sanitize_html_class( $accent_color );
if( ! empty( $accent_color ) ) {
$classes[] = "sjf-body-$accent_color-post";
}
}
return $classes;
}
// Apply these classes to the post tag.
add_filter( 'post_class', 'sjf_post_class' );
Es gibt viele weitere Hooks wie diesen. Sehen Sie sich Adam Browns Liste an und suchen Sie nach "class", um weitere Ideen zu erhalten. Einige der besten Kandidaten für zusätzliche Klassen sind
DRY es aus
Beachten Sie, dass meine Interpretation von SMACSS vorgibt, dass meine Post-Klassen die gleichen wie meine Body-Klassen sind, nur mit dem Suffix -post angehängt. Dank der Funktion current_filter() können wir tatsächlich dieselbe Funktion verwenden, um unsere Body-Klassen und unsere Post-Klassen auszuführen, was unseren Code DRY hält
function sjf_body_post_class( $classes ) {
// If the current post has an accent color, add a class.
if ( is_singular() ) {
$accent_color = get_post_meta( get_the_ID(), 'sjf_accent_color', TRUE );
$accent_color = sanitize_html_class( $accent_color );
if( ! empty( $accent_color ) ) {
// If we are on the post_class filter, tack on a '-post'.
$suffix = '';
if( current_filter() == 'post_class' ) { $suffix = '-post'; }
$classes[] = "sjf-body-$accent_color$suffix";
}
}
return $classes;
}
// Apply these classes to the body tag.
add_filter( 'body_class', 'sjf_body_post_class' );
// Apply these classes to the post tag.
add_filter( 'post_class', 'sjf_body_post_class' );
Filter sind ein mächtiges, aber einfaches Werkzeug, um WordPress-generierten Elementen neue Klassen hinzuzufügen. Aber was ist mit Elementen, die WordPress als Reaktion auf die Registrierung dieses Elements durch ein Theme oder Plugin generiert?
Registrierung
Betrachten Sie diesen Code, der verwendet wird, um eine Sidebar zu registrieren
function sjf_widgets_init() {
register_sidebar( array(
'name' => __( 'Main Sidebar', 'sjf' ),
'id' => 'sjf-main-widgets',
'description' => __( 'Widgets in this area will be shown on all posts and pages.', 'sjf' ),
'before_title' => '<h1>',
'after_title' => '</h1>',
) );
}
add_action( 'widgets_init', 'sjf_widgets_init' );
Schön und einfach. Aber wenn unser Ziel ist, SMACSS-ähnliche Klassen auf so viele Elemente wie möglich anzuwenden, was für eine verpasste Gelegenheit! Es gibt viele Stellen, an denen hier Klassen eingefügt werden können, aber im Gegensatz zu den Filtern von früher, wo wir mit einem Array von Klassen umgingen, erfordert diese Situation eine einfache Zeichenkette von Klassennamen. Für dieses Beispiel nehmen wir an, das Design erfordert unterschiedliche Widget-Stile basierend auf dem Anmeldestatus. Hier ist, was wir tun können
function sjf_widgets_init() {
$slug = 'sjf-main';
if( is_user_logged_in() ) {
$logged = 'logged-in';
} else {
$logged = 'logged-out';
}
register_sidebar( array(
'name' => __( 'Main Sidebar', 'theme-slug' ),
'id' => "$slug-widgets",
'description' => __( 'Widgets in this area will be shown on all posts and pages.', 'sjf' ),
'before_widget' => "<div id='%s' class='widget $slug-widget $slug-widget-$logged_in $slug-widget-%s'>",
'after_widget' => '</div>',
'before_title' => "<h1 class='widget-title $slug-widget-title $slug-widget-title-$logged_in'>",
'after_title' => '</h1>',
) );
}
add_action( 'widgets_init', 'sjf_widgets_init' );
Ein paar Dinge, die dort passieren
- Benutzerdaten. Mit
$loggedführen wir unseren alten Trick von früher aus und prüfen, ob dieser Beitrag in einem speziellen Farbschema künstlerisch gestaltet wurde. sprintf(). Mit%sfordern wir WordPress auf, diesen kleinen Teil durch den Slug-Namen für diese Art von Widget zu ersetzen. Dinge wiewidget_searchoderwidget_text.- Permutationen. Um SMACSS-bereit zu sein, fügen wir nicht nur die Klasse
$color_classoder die Klasse$idhinzu und sind damit zufrieden. Wir berücksichtigen verschiedene Kombinationen, die wir wahrscheinlich benötigen werden. Zum Beispiel, wenn wir Suchformulare auf Seiten mit rotem Akzent in der Haupt-Sidebar ansprechen müssen, können wir das mit einer einzigen CSS-Klassesjf-main-widget-red-widget_searchtun.
Um es klarzustellen, ein Grund, warum ich von meinem früheren post_meta-Beispiel abweiche, ist, dass Post-Daten noch nicht verfügbar sind, wenn Widgets registriert werden.
Einige Designs mögen nuanciert genug sein, um noch detailliertere Klassen für Widgets zu rechtfertigen. Es gibt Plugins im .org-Repository, die ein schnelles Klassifizieren pro Widget anbieten: pro Widget Klassifizierung.
Nachdem wir einige Möglichkeiten zur Klassifizierung von WordPress-generierten Elementen behandelt haben, werfen wir nun einen Blick auf unsere eigenen benutzerdefinierten Elemente.
Benutzerdefinierte Funktionen
Entweder in unserer `functions.php` oder in unseren Plugin-Dateien werden wir zweifellos viele unserer eigenen Funktionen registrieren. Ich habe eine Routine entwickelt, um die Dinge SMACSS-bereit zu halten. Betrachten Sie diese Funktion, die einfach hello world zurückgibt
function sjf_hello() {
return '<span class="sjf-hello">hello world</span>';
}
Überhaupt nicht SMACSS-bereit. Wir brauchen viel mehr, wenn wir dieses Element auf SMACSS-konforme Weise ansprechen wollen. Zum Beispiel, wenn dieses Element innerhalb unseres .pod-Beispiels vom Anfang des Artikels verwendet wird, möchten wir, dass es eine Klasse wie .pod-sjf-hello trägt. Was auch immer die Situation ist, wir wollen bequem so viele Klassen wie nötig injizieren können. Hier ist, was ich tue
/**
* Get the string "hello world", wrapped and classed.
*
* @param array $classes An array of CSS classes.
* @return string The "hello world" string, wrapped and classed.
*/
function sjf_hello( $classes = array() ) {
// The namespace for this element.
$slug = 'sjf-hello';
// Prepend the slug to each class name, convert to a string.
$classes_str = sjf_prepend_slug( $classes, $slug );
return "<span class='$slug $classes_str'>hello world</span>";
}
Beachten Sie, dass meine Funktion jetzt ein Argument für $classes nimmt, das ein Array von CSS-Klassennamen erwartet. Wenn ich ihm viele Klassen übergebe, möchte ich mich nicht darum kümmern, sie alle im Voraus zu präfixieren, also werden sie innerhalb dieser Funktion mit einer zweiten Funktion, sjf_prepend_slug(), präfixiert
/**
* Prepend a string to each member of an array.
*
* @param array $classes An array of CSS classes.
* @param string $slug A namespace to prepend to each class.
* @return string The $classes array, cleaned, slugged, and imploded.
*/
function sjf_prepend_slug( $classes, $slug ) {
$cleaned = array();
foreach( $classes as $class ) {
$cleaned []= sanitize_html_class( $slug . '-' . $class );
}
// Convert the array to a string, with a space between each class name.
$classes_str = implode( ' ', $cleaned );
return $classes_str;
}
Diese Funktion kümmert sich auch um die Bereinigung aller Klassen. Wir können sie für alle Template-Tags in unserem Theme oder Plugin verwenden.
Diese einfache Routine kann uns helfen, alle unsere benutzerdefinierten Funktionen SMACSS-bereit zu halten, mit minimalem zusätzlichem Code.
Überschreibungen
Alle bisher besprochenen Techniken waren in Bezug auf das Verhältnis von Code zu Ertrag sehr effizient. Das heißt, wir bekommen viel SMACSS-Güte mit relativ wenig Code, und das hat mich inspiriert, diesen Artikel zu schreiben. Es gibt jedoch einen weiteren Weg, den wir einschlagen könnten, und das ist die Überschreibung von Kernfunktionen mit unseren eigenen, um auf dem Weg unsere SMACSS-Klassen hinzuzufügen.
Ich würde dies wahrscheinlich nicht nur zum Zweck des Hinzufügens von SMACSS-Klassen empfehlen, da es viel Code sein kann und mehr Code mehr Fehler bedeutet. Vielmehr sollten wir, wenn es ein Element der Standard-WordPress-Ausgabe gibt, das für unser Projekt ohnehin überarbeitet werden muss (vielleicht aus Design- oder Funktionsgründen), diese Gelegenheit nutzen, es aufzuwerten.
searchform.php
Eine der ersten Überschreibungen, in die sich Theme-Entwickler stürzen, ist das Suchformular. Der Weg dorthin ist, ein neues Suchformular in unserem Theme in einer Datei mit dem reservierten Namen `searchform.php` hinzuzufügen. Ich möchte jedoch mein benutzerdefiniertes Suchformular woanders wiederverwenden können und definiere keine Funktionen außerhalb von `functions.php`, daher sieht mein `searchform.php` so aus
/**
* sjf search form.
*
* @package WordPress
* @subpackage sjf
* @since sjf 1.0
*/
echo sjf_get_search_form();
Meine sjf_get_search_form() lebt in `functions.php` und sieht so aus
/**
* Returns a WordPress search form.
*
* Accepts arguments to inject CSS classes into the form, which this theme uses
* in order to comply with SMACSS. Passing dynamic class values for each
* instance would not be possible with the normal use of searchform.php.
*
* @param array $classes CSS classes for the form.
* @return string A search form.
*
* @since anchorage 1.0
*/
if( ! function_exists( 'sjf_get_search_form' ) ) {
function sjf_get_search_form( $classes = array() ) {
$slug = 'sjf-searchform';
// An array of CSS classes for the search form.
$classes = sjf_prepend_slug( $classes, $slug );
// Grab the search term to use as a watermark.
$placeholder = esc_attr__( 'Search', 'sjf' );
if( get_query_var( 's' ) ) {
$placeholder = esc_attr( get_query_var( 's' ) );
}
$action = esc_url( home_url( '/' ) );
$search_for = esc_html__( 'Search for:', 'sjf' );
$search_for_attr = esc_attr__( 'Search for:', 'sjf' );
$submit = esc_html__( 'Submit', 'sjf' );
$out ="
<form action='$action' class='$classes $slug sjf-form' method='get' role='search'>
<label class='$classes-label $slug-label sjf-label' for='s'><span class='screen-reader-text'>$search_for</span></label>
<input id='s' type='search' title='$search_for_attr' name='s' value='$placeholder' class='$classes-input $slug-input sjf-input'>
<input type='submit' value='$submit' class='$classes-submit $slug-submit sjf-submit'>
</form>
";
return $out;
}
}
Das ist ein schickes Formular! Das Formular selbst und jedes darin enthaltene Element ist auf die SMACSS-ähnliche Weise zugänglich, die ich bevorzugee. Ich denke, die meisten Entwickler sind es gewohnt, das Standardformular zu ersetzen, daher ist es wahrscheinlich keine große Mühe, ihm unterwegs einige Klassen zu verpassen.
Dasselbe kann man nicht unbedingt von anderen Komponenten sagen. Ich habe eine ähnliche Anstrengung für die gesamte Kommentartemplate unternommen und bin 500 Zeilen später herausgekommen. Machbar, aber nicht unbedingt lohnenswert.
Navigationsmenü-Walker-Klassen: PHP-Klassen
Wie ich bereits erwähnte, werden die Klassen, die auf Navigationsmenü-Elemente angewendet werden, durch Filter zugänglich gemacht, aber wenn wir eine noch feinere Kontrolle wünschen, um vielleicht Klassen auf die Links selbst, die Untermenüs oder vielleicht einige Glyphen unserer gewählten Icon-Lösung anzuwenden, bietet WordPress eine Möglichkeit, tief einzudringen. Die Walker-Klasse ist fortgeschrittener Stoff und verdient wahrscheinlich ein eigenes Tutorial. Es gibt einige gute Beispiele online und wissen Sie einfach, dass dies ein Weg ist, um CSS-Klassen auf Menüs auf der feinsten Ebene vorstellbar anzuwenden.
Klasse abgewiesen
Ich habe festgestellt, dass im Laufe der Zeit der schwierigste Teil eines Projekts, sauber zu halten, das Stylesheet ist. Funktionen, Seitenvorlagen und Sidebars können kommen und gehen, aber Stylesheets scheinen ewig zu bestehen, mit allen ihren Makeln! Ich denke, eine anfängliche Investition in einige Klassifizierungen kann auf dem weiteren Weg erheblich dazu beitragen, die Dinge überschaubar zu halten.
Hallo Mann, TOLLEr Artikel! Ich habe gerade darüber nachgedacht, mit der Idee, meine Website von Grund auf neu zu entwickeln. Ich habe mir auch BEM angesehen. Als ich das hier gelesen habe, dachte ich, dass vieles davon auch mithilfe von Seiten-/Post-Vorlagen erreicht werden kann. Basierend auf der WP-Hierarchie werden die Vorlagennamen als Klassen ausgegeben, was Sie sicher wissen.
Meine persönliche Meinung ist, dass, wenn diese Art von Dingen für einen Entwickler wichtig ist und man so weit gehen muss, WordPress-Funktionalität zu hacken und zu überschreiben, um es so zu machen, wie wir es wollen, dann ist WordPress vielleicht nicht die idealste Lösung.
Ich glaube nicht, dass diese Art von Dingen die negative Art von Hacking und Überschreibung ist, es sind die eingebauten Hooks von WordPress, die speziell dafür entwickelt wurden, so verwendet zu werden.
Sehr schöner Artikel
Ich habe mich gefragt, wie tief editierbar WP ist, es scheint viel zu tun zu geben, wenn mehr Dinge zu ändern sind. Es ist jedoch nie einfach so, dass man sein Web gut zum Laufen/Aussehen bringt.
Kudos für das Schreiben des Artikels, aber das scheint einfach eine wirklich schlechte Idee zu sein! Ich habe den ganzen Artikel aufmerksam gelesen und verstehe immer noch nicht wirklich, was Sie tun – und DAS ist das Problem.
Wenn Sie alleine an diesem Projekt arbeiten, dann in Ordnung – was auch immer Sie glücklich macht. Aber wenn jemand anderes jemals Ihren Code aufgreift, dann ist das ein totaler Stolperstein!
Meiner Meinung nach sollte jeder Code ein Gleichgewicht zwischen Leistung und Lesbarkeit herstellen – und dies scheint keines von beiden zu bedienen.
Es erinnert mich an eine Geschichte über einen britischen Entwickler, der sich weigerte, die amerikanische Schreibweise 'color' in seinem CSS zu verwenden, und daher ein Skript erstellte, um sie von seiner bevorzugten Schreibweise 'colour' zur Kompilierungszeit zu konvertieren.
Warum nicht einfach 'color' verwenden? Warum nicht einfach die WordPress-Klassen verwenden? Es wirkt auf mich (SMACSS – versteht?) ein wenig wie Zwangsstörungen beim Programmieren (OCDing?). Ok, genug Wortspiele...
SMACSS ist großartig.
DRY ist großartig.
Aber denken Sie daran, KISS!
(Nicht die amerikanische Rockband)
Hallo Steve,
Danke, dass Sie meinen Artikel gelesen haben!
Ich stimme Ihnen zu, dass KISS eine große Tugend ist, und ich habe diesen Artikel als eine Möglichkeit geschrieben, KISS zu erreichen, nicht als eine Möglichkeit, es aufzugeben.
Ich glaube, dass die größte Herausforderung bei Webprojekten in unangemessenen CSS-Selektoren liegt, insbesondere nach einigen Runden von Kundenüberarbeitungen. SMACCS hilft Ihnen, die Dinge in Ihrem Stylesheet einfach zu halten.
Wenn Sie sagen, meine PHP-Funktionen seien komplex, würde ich argumentieren, dass die meisten von ihnen nur 5-10 Zeilen lang sind. Wenn sie obskur erscheinen, machen Sie sich keine Sorgen, dieser Artikel ist keine Einführung in PHP-Funktionen an sich.
Wenn Sie nach diesem Artikel nicht verstehen, was SMACCS ist, machen Sie sich keine Sorgen, dies ist kein SMACCS-Tutorial. Davon gibt es bereits ein großartiges, das im Artikel verlinkt ist.
Wenn Sie nach diesem Artikel nicht verstehen, was WordPress-Klassen sind und wie man sie ändert, entschuldige ich mich, ich habe das Ziel verfehlt.
Zu Ihrem Punkt, dass dies ein Stolperstein ist, wenn man mit einem Team arbeitet, was meinen Sie? SMACCS ist eine bekannte Konvention. Ich würde es viel lieber vorziehen, in ein SMACCS-Projekt einzusteigen als in das Benennungsschema von jemandem.
Zu Ihrem Punkt bezüglich der Leistung, was sehen Sie hier, das leistungsschwach ist? Ein paar zusätzliche Klassen im Markup? Ein wenig zusätzliche Logik auf dem Server? Ich glaube nicht, dass es hier einen relevanten Leistungseinbruch gibt.
Ich stimme zu, dass es möglich ist, zu viel Komplexität bei dem Versuch einzuführen, WordPress SMACCS-fähig zu machen, und ich erkenne einige Beispiele dafür im Artikel an.
Viel Erfolg bei Ihrer Arbeit, und ich hoffe, dass Sie, wenn ich das Glück habe, hier wieder etwas beitragen zu können, es nützlicher finden.
Schöner Code
Ich mag falsch liegen, aber es scheint, als gäbe es möglicherweise einen Fehler im Widget-Code-Beispiel
Sollten Instanzen von
$logged_innicht einfach$loggedsein, um mit der Variablen übereinzustimmenWie in diesem
class='widget $slug-widget $slug-widget-$logged_in $slug-widget-%s'
Sollte das sein
class='widget $slug-widget $slug-widget-$logged $slug-widget-%s'
Danke!