Aggiungi una classe unica al tag/elemento HTML
So che esiste la funzione body_class per WordPress. Ma esiste una funzione (o un modo) per aggiungere una classe all'elemento HTML?
Il mio obiettivo è poter aggiungere una classe unica (o un ID) all'elemento HTML di una pagina. Attualmente il mio tema aggiunge la classe page-id-XXXX all'elemento body, ma ho bisogno di un modo per avere una classe o ID unico sull'elemento HTML vero e proprio. Andrei bene anche con page-id-XXXX aggiunto all'elemento HTML, anche se preferirei poter avere un campo personalizzato aggiunto a ogni pagina, dove posso inserire la classe/ID che verrebbe poi aggiunta all'elemento HTML.
Come minimo, esiste una funzione che posso usare per aggiungere una classe o ID all'elemento HTML, simile a come funziona la funzione body_class?

WordPress non ha un equivalente di body_class()
per il tag html.
Ecco un approccio che utilizza l'output buffering per catturare l'output finale del documento HTML in fase di rendering. Il codice di output buffering qui sotto è stato adattato dalle soluzioni pubblicate qui e qui. Questo ci permette di accedere all'output finale del documento HTML che poi analizziamo e modifichiamo, tutto senza bisogno di modificare i file template del tema.
Per prima cosa, iniziamo l'output buffering e colleghiamo la nostra funzione shutdown
, che
funziona iterando attraverso tutti i livelli di buffer aperti, chiudendoli e catturandone l'output. Poi attiva il filtro wpse_final_output
, stampando il contenuto filtrato.
/**
* Avvia l'output buffering
*/
add_action( 'wp', 'wpse_ob_start' );
function wpse_ob_start() {
// Interrompi immediatamente se siamo nell'area amministrativa.
if ( is_admin() ) {
return;
}
// Interrompi immediatamente se è un feed.
if ( is_feed() ) {
return;
}
// Avvia l'output buffering.
ob_start();
add_action( 'shutdown', 'wpse_ob_clean', 0 );
}
/**
* Assicura che il buffer sia pulito e poi attiva il filtro wpse_final_output.
* Questo viene eseguito subito prima della funzionalità di shutdown simile di WP.
*/
function wpse_ob_clean() {
$final = '';
// Dobbiamo ottenere il numero di livelli ob in cui ci troviamo, così possiamo
// iterare su ognuno, raccogliendo l'output di quel buffer nell'output finale.
$levels = ob_get_level();
for ( $i = 0; $i < $levels; $i++ ) {
$final .= ob_get_clean();
}
// Applica eventuali filtri all'output finale
echo apply_filters( 'wpse_final_output', $final );
}
Qui l'HTML viene analizzato e viene attivato il filtro personalizzato wpse_additional_html_classes
che ci permette di aggiungere le nostre classi aggiuntive in una funzione separata. Questo codice è un po' dettagliato, ma copre diversi casi limite che ho incontrato usando DOMDocument
per analizzare l'HTML.
add_filter( 'wpse_final_output', 'wpse_html_tag', 10, 1 );
/**
* Analizza l'output finale del buffer. Attiva wpse_additional_html_classes, che
* ci permette di aggiungere classi all'elemento html.
*/
function wpse_html_tag( $output ) {
// Lista delle classi html filtrabili.
$additional_html_classes = apply_filters( 'wpse_additional_html_classes', array() );
// Interrompi se non ci sono classi da aggiungere poiché non c'è nulla da fare.
if ( ! $additional_html_classes ) {
return $output;
}
// Crea un'istanza di DOMDocument.
$dom = new \DOMDocument();
// Soppressione degli errori dovuti a HTML malformato.
// Vedi http://stackoverflow.com/a/17559716/3059883
$libxml_previous_state = libxml_use_internal_errors( true );
// Popola $dom con il buffer, assicurandosi di gestire UTF-8, altrimenti
// si verificheranno problemi con i caratteri UTF-8.
// Inoltre, assicurati che il doctype e i tag HTML non vengano aggiunti al nostro frammento HTML. Vedi http://stackoverflow.com/a/22490902/3059883
$dom->loadHTML( mb_convert_encoding( $output, 'HTML-ENTITIES', 'UTF-8' ), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD );
// Ripristina lo stato precedente di libxml_use_internal_errors() ora che abbiamo finito.
// Vedi di nuovo http://stackoverflow.com/a/17559716/3059883
libxml_use_internal_errors( $libxml_previous_state );
// Crea un'istanza di DOMXpath.
$xpath = new \DOMXpath( $dom );
// Ottieni il primo elemento html.
$html = $xpath->query( "/descendant::html[1]" );
// Ottieni le classi esistenti per l'elemento html.
$definedClasses = explode( ' ', $dom->documentElement->getAttribute( 'class' ) );
// Aggiunge le nostre classi aggiuntive a quelle esistenti. Assicura che venga usato lo spazio corretto tra i nomi delle classi
// e che non vengano aggiunti nomi di classe duplicati.
foreach ( $html as $html_tag ) {
$spacer = ' ';
// Lo spacer sarà impostato a una stringa vuota se non ci sono classi esistenti.
if ( isset( $definedClasses[0] ) && false == $definedClasses[0] ) {
$spacer = '';
}
foreach ( $additional_html_classes as $additional_html_class ) {
if ( ! in_array( $additional_html_class , $definedClasses ) ) {
$html_tag->setAttribute(
'class', $html_tag->getAttribute( 'class' ) . $spacer . $additional_html_class
);
}
$spacer = ' ';
}
}
// Salva l'HTML aggiornato.
$output = $dom->saveHTML();
return $output;
}
Il filtro wpse_additional_html_classes
ci permette di filtrare facilmente le classi aggiuntive da aggiungere all'elemento HTML. Nell'esempio sotto, viene aggiunta una classe speciale per l'ID del post (ovviamente ci sono molti casi in cui non ci sarà un ID del post). Viene anche aggiunto un array di nomi di classi personalizzate. Personalizza le classi/la logica per aggiungere classi in base alle tue esigenze, poi restituisci l'array dei nomi delle classi.
add_filter( 'wpse_additional_html_classes', 'wpse_add_additional_html_classes', 10, 1 );
/**
* Filtra la lista dei nomi di classe da aggiungere all'elemento HTML.
*
* @param array $classes
* @return array
*/
function wpse_add_additional_html_classes( $classes ) {
// Esempio di aggiunta di una classe con l'ID del post.
if ( is_singular() ) {
$post_id = get_the_ID();
if ( $post_id ) {
$post_id_class = "post-id-{$post_id}";
if ( ! in_array( $post_id_class, $classes ) ) {
$classes[] = $post_id_class;
}
}
}
// Aggiungi altre classi.
$additional_classes = [
'class-1',
'class-2',
'class-3',
];
$classes = array_merge( $classes, $additional_classes );
return $classes;
}

Sto valutando codice temporaneo per modificare tutti i tag di intestazione per aggirare un bug di WP v6 - e una ricerca mi ha portato qui. Ti ringrazio vivamente per questo codice che farebbe esattamente quello che stavo considerando. Tuttavia, considerando le prestazioni, ti ringrazio particolarmente per avermi aiutato a capire che questo è esattamente ciò che non voglio fare in un sito di produzione. Sì, questa è un'ottima soluzione, ma penso solo come ultima risorsa. Spero che questo commento aiuti qualcuno che è tentato di semplicemente copiare/incollare.

Questo metodo ha funzionato perfettamente per me
add_filter( 'language_attributes', 'add_no_js_class_to_html_tag', 10, 2 );
function add_no_js_class_to_html_tag( $output, $doctype ) {
if ( 'html' !== $doctype ) {
return $output;
}
$output .= ' class="no-js"';
return $output;
}
Non ho trovato nulla nel codex a riguardo. Crediti a https://gist.github.com/nickdavis/73d91d674b843b77a1cd0a21f9c0353a

Ha funzionato per aggiungere una classe personalizzata? A me non fa nulla. Se imposto un attributo diverso invece della classe, allora funziona. Ad esempio, questo funziona: function add_class_to_html_element( $output ) { $output .= ' attribute="value"'; return $output; } add_filter( 'language_attributes', 'add_class_to_html_element' );
... ma non appena cambi attribute
in class
, non viene visualizzato. Sembra che id
funzioni però.

Sto usando ClassicPress 1.2, che si è separato da WP 4.9 ma per me funziona. <html lang="en-US" class="no-focus-outline"> è come si presenta ora il mio head.

Dato che ti trovi al di fuori del loop, la soluzione più pulita è semplicemente creare la tua funzione in questo modo
function wpse_268339_get_post_class() {
global $post;
if ( ! empty( $post->ID ) ) {
return 'post-' . $post->ID;
}
}
Poi, nel tuo template header.php
chiama semplicemente la funzione e gestisci l'output in una classe del body. Questo esempio presuppone che tu abbia già un paio di classi sul tag <html>
.
<html <?php language_attributes(); ?> class="no-js no-svg <?php echo esc_attr( wpse_268339_get_post_class() ); ?>">
Questo produrrà un nome di classe solo se ti trovi su un Post/Page.
In alternativa, se tutte le normali classi del body non causano problemi, puoi semplicemente usare body_class()
anche sul tag <html>
. La funzione funziona ovunque.
<html <?php body_class(); ?>>

Grazie all'aiuto di questa risposta, ho scoperto che questa soluzione funziona per aggiungere un id
. Tuttavia non sono sicuro riguardo all'aggiunta all'attributo class
.
function add_id_to_html_element( $output ) {
global $post;
$output .= ' id="custom-id-' . $post->ID . '"';
return $output;
}
add_filter( 'language_attributes', 'add_id_to_html_element' );
