Добавление уникального класса к HTML-тегу/элементу

28 мая 2017 г., 02:34:13
Просмотры: 16K
Голосов: 0

Я знаю, что в WordPress есть функция body_class. Но существует ли аналогичная функция (или способ) для добавления класса к HTML-элементу?

Моя цель - иметь возможность добавлять уникальный класс (или ID) к HTML-элементу страницы. В настоящее время моя тема добавляет класс page-id-XXXX к элементу body, но мне нужно, чтобы уникальный класс или ID был на самом HTML-элементе. Меня бы устроило, если бы класс page-id-XXXX также добавлялся к HTML-элементу, хотя я бы предпочел иметь возможность использовать произвольное поле на каждой странице, где можно ввести класс/ID, который затем будет добавлен к HTML-элементу.

Как минимум, существует ли функция, которую я могу использовать для добавления класса или ID к HTML-элементу, аналогично тому, как работает функция body_class?

4
Комментарии

Не могли бы вы объяснить, зачем вам это нужно? (Просто интересно.) Также, подойдет ли решение на JavaScript или вы предпочитаете подход на PHP?

Dave Romsey Dave Romsey
28 мая 2017 г. 02:52:14

@DaveRomsey моя основная причина в том, что я создаю индивидуальную разовую страницу на существующем сайте WordPress. Это страница, которая будет использоваться для слайд-шоу на 4K телевизоре.

Текущая тема задает CSS для font-size и line-height в элементе <html>. Кроме того, в некоторых стилях содержимого темы используется rem для размера шрифта.

По сути, я хочу значительно увеличить font-size и line-height элемента HTML — только для этой страницы — чтобы я мог продолжать использовать rem-размеры (поскольку rem работает от размеров HTML).

Garconis Garconis
28 мая 2017 г. 04:27:18

Я определенно предпочитаю PHP, а не JS. Пока я просто использую внутренний CSS для изменения размеров элемента HTML, но предпочел бы добавить CSS в основной внешний CSS-файл... отсюда и желание иметь возможность нацелиться именно на элемент HTML этой конкретной страницы.

Garconis Garconis
28 мая 2017 г. 04:30:35

Проверьте этот ответ, он решил мою проблему.

hayatbiralem hayatbiralem
5 сент. 2017 г. 10:57:27
Все ответы на вопрос 5
1

Почему бы просто не добавить класс напрямую в тег?

<html <?php language_attributes(); ?> class="page-id-<?php the_ID(); ?>">
10 окт. 2019 г. 00:00:35
Комментарии

Я пытаюсь избежать переопределения файлов темы.

Garconis Garconis
10 окт. 2019 г. 04:04:45
1

В WordPress нет эквивалента функции body_class() для HTML-тега.

Вот подход, использующий буферизацию вывода для захвата финального HTML-документа перед рендерингом. Код буферизации ниже адаптирован из решений, размещённых здесь и здесь. Это позволяет получить доступ к финальному выводу HTML-документа, который мы затем анализируем и редактируем, не изменяя файлы шаблонов темы.

Сначала мы запускаем буферизацию вывода и подключаем нашу функцию shutdown, которая работает, перебирая все уровни открытых буферов, закрывает их и захватывает их вывод. Затем она запускает фильтр wpse_final_output, выводя отфильтрованное содержимое.

    /**
     * Начинаем буферизацию вывода
     */
    add_action( 'wp', 'wpse_ob_start' );
    function wpse_ob_start() {
        // Выходим, если это админка.
        if ( is_admin() ) {
            return;
        }
    
        // Выходим, если это фид.
        if ( is_feed() ) {
            return;
        }
        
        // Запускаем буферизацию вывода.
        ob_start();
        add_action( 'shutdown', 'wpse_ob_clean', 0 );
    }
    
    /**
     * Очищаем буфер и запускаем фильтр wpse_final_output.
     * Срабатывает прямо перед аналогичной функцией завершения в WordPress.
     */
    function wpse_ob_clean() {
        $final = '';
    
        // Получаем количество уровней буферизации, чтобы пройтись по каждому
        // и собрать вывод в финальный результат.
        $levels = ob_get_level();
    
        for ( $i = 0; $i < $levels; $i++ ) {
            $final .= ob_get_clean();
        }
    
        // Применяем фильтры к финальному выводу
        echo apply_filters( 'wpse_final_output', $final );
    }

Здесь HTML анализируется, и срабатывает пользовательский фильтр wpse_additional_html_classes, позволяющий добавить дополнительные классы в отдельной функции. Этот код немного многословен, но он охватывает несколько крайних случаев, с которыми я сталкивался при использовании DOMDocument для разбора HTML.

    add_filter( 'wpse_final_output', 'wpse_html_tag', 10, 1 );
    /**
     * Анализирует финальный вывод буфера. Запускает wpse_additional_html_classes,
     * что позволяет добавить классы к HTML-элементу.
     */
    function wpse_html_tag( $output ) {
        
        // Фильтруемый список классов HTML.
        $additional_html_classes = apply_filters( 'wpse_additional_html_classes', array() );
        
        // Выходим, если нечего добавлять.
        if ( ! $additional_html_classes ) {
            return $output;
        }
    
        // Создаём экземпляр DOMDocument.
        $dom = new \DOMDocument();
        
        // Подавляем ошибки из-за некорректного HTML.
        // См. http://stackoverflow.com/a/17559716/3059883
        $libxml_previous_state = libxml_use_internal_errors( true );
    
        // Заполняем $dom содержимым буфера, учитывая UTF-8,
        // чтобы избежать проблем с UTF-8 символами.
        // Также убеждаемся, что doctype и HTML теги не добавляются к нашему фрагменту. http://stackoverflow.com/a/22490902/3059883
        $dom->loadHTML( mb_convert_encoding( $output, 'HTML-ENTITIES', 'UTF-8' ), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD );
        
        // Восстанавливаем предыдущее состояние libxml_use_internal_errors().
        // См. http://stackoverflow.com/a/17559716/3059883
        libxml_use_internal_errors( $libxml_previous_state );
        
        // Создаём экземпляр DOMXpath.
        $xpath = new \DOMXpath( $dom );
    
        // Получаем первый html элемент.
        $html = $xpath->query( "/descendant::html[1]" );
        
        // Получаем существующие классы для HTML элемента.
        $definedClasses = explode( ' ', $dom->documentElement->getAttribute( 'class' ) );
        
        // Добавляем дополнительные классы к существующим. Убеждаемся, что пробелы между именами классов
        // используются правильно и дублирующиеся классы не добавляются.
        foreach ( $html as $html_tag ) {
            $spacer = ' ';
            // Пробел будет пустым, если классов нет.
            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 = ' ';
            }
        }
        
        // Сохраняем обновлённый HTML.
        $output = $dom->saveHTML();     
    
        return $output;
    }

Фильтр wpse_additional_html_classes позволяет легко добавлять классы к HTML-элементу. В примере ниже добавляется специальный класс для ID записи (конечно, во многих случаях ID записи может отсутствовать). Также добавляется массив пользовательских классов. Настройте классы и логику их добавления под свои нужды, затем верните массив имён классов.

    add_filter( 'wpse_additional_html_classes', 'wpse_add_additional_html_classes', 10, 1 );
    /**
     * Фильтрует список имён классов для добавления к HTML элементу.
     *
     * @param array $classes
     * @return array
     */
    function wpse_add_additional_html_classes( $classes ) {
        // Пример добавления класса с ID записи.
        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;
                }
            }
        }
        
        // Добавляем ещё несколько классов.
        $additional_classes = [
            'class-1',
            'class-2',
            'class-3',
        ];
        $classes = array_merge( $classes, $additional_classes );
        
        return $classes;
    }
28 мая 2017 г. 14:28:51
Комментарии

Я рассматриваю временный код для изменения всех заголовков, чтобы обойти баг в WP версии 6 — поиск привел меня сюда. Большое спасибо за этот код, который делает именно то, что я рассматривал. Однако, учитывая производительность, я особенно благодарен за то, что вы помогли мне осознать, что это именно то, чего я не хочу делать на рабочем сайте. Да, это отличное решение, но, думаю, только как последнее средство. Надеюсь, этот комментарий поможет тем, кто будет искушен просто скопировать/вставить.

TonyG TonyG
13 окт. 2023 г. 23:56:34
3

Этот вариант отлично сработал для меня

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;
}

Я не смог найти ничего об этом в кодексе. Спасибо https://gist.github.com/nickdavis/73d91d674b843b77a1cd0a21f9c0353a

11 дек. 2020 г. 01:06:17
Комментарии

Это сработало для добавления пользовательского класса? У меня это ничего не делает. Если я установлю другой атрибут вместо class, тогда это работает. Например, это работает: function add_class_to_html_element( $output ) { $output .= ' attribute="value"'; return $output; } add_filter( 'language_attributes', 'add_class_to_html_element' ); ... но как только вы меняете attribute на class, это не отображается. Похоже, что id будет работать.

Garconis Garconis
11 дек. 2020 г. 16:30:56

Я использую ClassicPress 1.2, который форкнулся от WP 4.9, но у меня это работает. <html lang="en-US" class="no-focus-outline"> - вот как сейчас выглядит мой head.

James0r James0r
11 дек. 2020 г. 21:03:27

А, у меня уже есть класс no-js или js от темы, так что, возможно, если класс уже есть, он не может добавить ещё один?

Garconis Garconis
12 дек. 2020 г. 01:20:36
1

Поскольку вы находитесь вне цикла, самым чистым решением будет просто создать свою собственную функцию, например так:

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

Затем в вашем шаблоне header.php просто вызовите функцию и экранируйте вывод в классе body. Этот пример предполагает, что у вас уже есть несколько классов в теге <html>.

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

Это будет выводить имя класса только если вы находитесь на странице записи/страницы.

Альтернативно, если все стандартные классы body не мешают, вы можете просто использовать body_class() и в теге <html>. Эта функция работает везде.

<html <?php body_class(); ?>>
28 мая 2017 г. 03:32:07
Комментарии

Я бы предпочел не изменять сам PHP-файл. В текущей теме уже есть классы (не уникальные) на HTML-элементе. Я также предпочел бы не добавлять классы body к HTML-элементу, так как уверен, что тема этого не ожидает.

Garconis Garconis
28 мая 2017 г. 04:33:11
0

Благодаря помощи этого ответа, я нашел решение, которое работает для добавления id. Хотя я не уверен насчет добавления к атрибуту 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 дек. 2020 г. 16:39:29