Añadir una clase única a una etiqueta/elemento HTML

28 may 2017, 02:34:13
Vistas: 16K
Votos: 0

Sé que existe la función body_class en WordPress. ¿Pero hay alguna función (o forma) de añadir una clase al elemento HTML?

Mi objetivo es poder añadir una clase única (o ID) al elemento HTML de una página. Actualmente mi tema está añadiendo la clase page-id-XXXX al elemento body, pero necesito una forma de tener una clase o ID único en el elemento HTML real. Me conformaría con que también se añada page-id-XXXX al elemento HTML, aunque preferiría poder tener un campo personalizado que se añada a cada página, donde pueda escribir la clase/ID que luego se agregaría al elemento HTML.

Como mínimo, ¿hay alguna función que pueda usar para añadir una clase o ID al elemento HTML, similar a cómo funciona body_class?

4
Comentarios

¿Podrías explicar por qué necesitas hacer esto? (Solo por curiosidad.) Además, ¿sería aceptable una solución en JavaScript o preferirías un enfoque con PHP?

Dave Romsey Dave Romsey
28 may 2017 02:52:14

@DaveRomsey mi principal razón para esto es que estoy creando una página personalizada única en un sitio web existente de WordPress. Es una página que se usará para una presentación de diapositivas en un TV 4K.

El tema actual establece CSS de font-size y line-height en el elemento <html>. Además, parte del estilo de contenido del tema usa rem para el tamaño de fuente.

Básicamente, me gustaría aumentar drásticamente el font-size y line-height del elemento HTML — solo para esta página — para poder seguir usando tamaños en rem (ya que rem funciona a partir de los tamaños del HTML).

Garconis Garconis
28 may 2017 04:27:18

Definitivamente preferiría PHP sobre JS. Por ahora solo estoy usando CSS interno para cambiar los tamaños del elemento HTML, pero preferiría agregar el CSS al archivo CSS externo principal... de ahí el deseo de poder apuntar al elemento HTML de esta página específica.

Garconis Garconis
28 may 2017 04:30:35

Revisa esta respuesta, resolvió mi problema.

hayatbiralem hayatbiralem
5 sept 2017 10:57:27
Todas las respuestas a la pregunta 5
1

¿Por qué no simplemente agregar la clase directamente a la etiqueta?

<html <?php language_attributes(); ?> class="page-id-<?php the_ID(); ?>">
10 oct 2019 00:00:35
Comentarios

Estoy tratando de evitar sobrescribir archivos del tema.

Garconis Garconis
10 oct 2019 04:04:45
1

WordPress no tiene un equivalente a body_class() para la etiqueta HTML.

Aquí hay un enfoque que utiliza el almacenamiento en búfer de salida para capturar el resultado final del documento HTML que se está renderizando. El código de almacenamiento en búfer a continuación fue adaptado de soluciones publicadas aquí y aquí. Esto nos permite acceder al resultado final del documento HTML, que luego analizamos y editamos sin necesidad de modificar los archivos de plantilla del tema.

Primero, iniciamos el almacenamiento en búfer de salida y conectamos nuestra función shutdown, que funciona iterando a través de todos los niveles de búfer abiertos, cerrándolos y capturando su salida. Luego activa el filtro wpse_final_output, mostrando el contenido filtrado.

    /**
     * Iniciar el almacenamiento en búfer de salida
     */
    add_action( 'wp', 'wpse_ob_start' );
    function wpse_ob_start() {
        // Salir inmediatamente si es el área de administración.
        if ( is_admin() ) {
            return;
        }
    
        // Salir inmediatamente si es un feed.
        if ( is_feed() ) {
            return;
        }
        
        // Iniciar el almacenamiento en búfer de salida.
        ob_start();
        add_action( 'shutdown', 'wpse_ob_clean', 0 );
    }
    
    /**
     * Asegurarse de que el búfer esté limpio y luego activar el filtro wpse_final_output.
     * Esto se ejecuta justo antes de la funcionalidad de cierre similar de WP.
     */
    function wpse_ob_clean() {
        $final = '';
    
        // Necesitamos obtener el número de niveles de búfer en los que estamos, para poder
        // iterar sobre cada uno, recopilando la salida de ese búfer en la salida final.
        $levels = ob_get_level();
    
        for ( $i = 0; $i < $levels; $i++ ) {
            $final .= ob_get_clean();
        }
    
        // Aplicar cualquier filtro a la salida final
        echo apply_filters( 'wpse_final_output', $final );
    }

Aquí se analiza el HTML y se activa el filtro personalizado wpse_additional_html_classes, que nos permite agregar nuestras clases adicionales en una función separada. Este código es un poco detallado, pero cubre varios casos extremos que he encontrado al usar DOMDocument para analizar HTML.

    add_filter( 'wpse_final_output', 'wpse_html_tag', 10, 1 );
    /**
     * Analizar la salida final del búfer. Activa wpse_additional_html_classes, lo que
     * nos permite agregar clases al elemento HTML.
     */
    function wpse_html_tag( $output ) {
        
        // Lista filtrable de clases HTML.
        $additional_html_classes = apply_filters( 'wpse_additional_html_classes', array() );
        
        // Salir si no hay clases para agregar, ya que no necesitamos hacer nada.
        if ( ! $additional_html_classes ) {
            return $output;
        }
    
        // Crear una instancia de DOMDocument.
        $dom = new \DOMDocument();
        
        // Suprimir errores debido a HTML mal formado.
        // Ver http://stackoverflow.com/a/17559716/3059883
        $libxml_previous_state = libxml_use_internal_errors( true );
    
        // Poblar $dom con el búfer, asegurándose de manejar UTF-8, de lo contrario
        // ocurrirán problemas con caracteres UTF-8.
        // Además, asegurarse de que las etiquetas doctype y HTML no se agreguen a nuestro fragmento HTML. http://stackoverflow.com/a/22490902/3059883
        $dom->loadHTML( mb_convert_encoding( $output, 'HTML-ENTITIES', 'UTF-8' ), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD );
        
        // Restaurar el estado anterior de libxml_use_internal_errors() ahora que hemos terminado.
        // Nuevamente, ver http://stackoverflow.com/a/17559716/3059883
        libxml_use_internal_errors( $libxml_previous_state );
        
        // Crear una instancia de DOMXpath.
        $xpath = new \DOMXpath( $dom );
    
        // Obtener el primer elemento HTML.
        $html = $xpath->query( "/descendant::html[1]" );
        
        // Obtener las clases existentes para el elemento HTML.
        $definedClasses = explode( ' ', $dom->documentElement->getAttribute( 'class' ) );
        
        // Agrega nuestras clases adicionales a las clases existentes. Asegura que se use el espaciado adecuado de nombres de clase
        // y que no se agreguen nombres de clase duplicados.
        foreach ( $html as $html_tag ) {
            $spacer = ' ';
            // El espaciador se establecerá en una cadena vacía si no hay clases existentes.
            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 = ' ';
            }
        }
        
        // Guardar el HTML actualizado.
        $output = $dom->saveHTML();     
    
        return $output;
    }

El filtro wpse_additional_html_classes nos permite filtrar fácilmente las clases adicionales agregadas al elemento HTML. En el ejemplo a continuación, se agrega una clase especial para el ID de la publicación (por supuesto, hay muchos casos en los que no habrá un ID de publicación). También se agrega una matriz de nombres de clases personalizados. Personaliza las clases/lógica para agregar clases según tus necesidades, luego devuelve la matriz de nombres de clases.

    add_filter( 'wpse_additional_html_classes', 'wpse_add_additional_html_classes', 10, 1 );
    /**
     * Filtra la lista de nombres de clase para agregar al elemento HTML.
     *
     * @param array $classes
     * @return array
     */
    function wpse_add_additional_html_classes( $classes ) {
        // Ejemplo de agregar una clase de ID de publicación.
        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;
                }
            }
        }
        
        // Agregar algunas clases más.
        $additional_classes = [
            'class-1',
            'class-2',
            'class-3',
        ];
        $classes = array_merge( $classes, $additional_classes );
        
        return $classes;
    }
28 may 2017 14:28:51
Comentarios

Estoy considerando código temporal para modificar todas las etiquetas de encabezado para solucionar un error en WP v6, y una búsqueda me trajo aquí. Te agradezco amablemente por este código que haría exactamente lo que he estado considerando. Sin embargo, considerando el rendimiento, especialmente te agradezco por ayudarme a reconocer que esto es exactamente lo que no quiero hacer en un sitio de producción. Sí, esta es una gran solución, pero creo que solo como último recurso. Espero que este comentario ayude a alguien que esté tentado a simplemente copiar/pegar.

TonyG TonyG
13 oct 2023 23:56:34
3

Esto funcionó perfectamente para mí

add_filter( 'language_attributes', 'add_no_js_class_to_html_tag', 10, 2 );

function add_no_js_class_to_html_tag( $output, $doctype ) {
    // Verifica si el doctype es HTML
    if ( 'html' !== $doctype ) {
        return $output;
    }

    // Agrega la clase no-js al atributo de lenguaje
    $output .= ' class="no-js"';

    return $output;
}

No pude encontrar nada en el codex sobre esto. Crédito a https://gist.github.com/nickdavis/73d91d674b843b77a1cd0a21f9c0353a

11 dic 2020 01:06:17
Comentarios

¿Eso funcionó para añadir una clase personalizada? No hace nada en mi caso. Si lo configuro para que sea un atributo diferente en lugar de class, entonces funciona. Por ejemplo, esto funciona: function add_class_to_html_element( $output ) { $output .= ' attribute="value"'; return $output; } add_filter( 'language_attributes', 'add_class_to_html_element' ); ... pero tan pronto como cambias attribute por class, no aparece. Parece que id sí funcionaría.

Garconis Garconis
11 dic 2020 16:30:56

Estoy usando ClassicPress 1.2, que se bifurcó desde WP 4.9, pero funciona en mi caso. <html lang="en-US" class="no-focus-outline"> es como se ve mi head ahora.

James0r James0r
11 dic 2020 21:03:27

Ah, el mío ya tiene una clase no-js o js del tema, así que quizás si ya tiene una clase, no puede añadir otra?

Garconis Garconis
12 dic 2020 01:20:36
1

Como estás fuera del bucle, la solución más limpia es simplemente crear tu propia función como esta:

function wpse_268339_get_post_class() {
    global $post;
    if ( ! empty( $post->ID ) ) {
        return 'post-' . $post->ID;
    }
}

Luego, en tu plantilla header.php simplemente llama a la función y escapa la salida en una clase del body. Este ejemplo asume que ya tienes un par de clases en la etiqueta <html>.

<html <?php language_attributes(); ?> class="no-js no-svg <?php echo esc_attr( wpse_268339_get_post_class() ); ?>">

Esto solo mostrará un nombre de clase si estás en una Entrada / Página.

Alternativamente, si todas las clases normales del body no causan ningún problema, puedes usar body_class() también en la etiqueta <html>. La función funciona en cualquier lugar.

<html <?php body_class(); ?>>
28 may 2017 03:32:07
Comentarios

Prefiero no modificar el archivo PHP real. El tema actualmente tiene clases (no únicas) en el elemento HTML. También prefiero no añadir las clases del cuerpo al elemento HTML, ya que estoy seguro de que el tema no espera eso.

Garconis Garconis
28 may 2017 04:33:11
0

Gracias a la ayuda de esta respuesta, encontré que esta solución funciona para agregar un id. Aunque no estoy seguro sobre cómo agregarlo al atributo 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' );
11 dic 2020 16:39:29