Как добавить атрибут defer="defer" для скриптов плагина?

9 янв. 2012 г., 09:59:34
Просмотры: 40.9K
Голосов: 31

Я не могу добавить атрибут defer для скриптов плагина. Тест Google PageSpeed предлагает добавить атрибут defer для JavaScript файлов плагина Contact Form 7.

Вот как Contact Form 7 подключает JavaScript в header.

add_action( 'wp_enqueue_scripts', 'wpcf7_enqueue_scripts' );

function wpcf7_enqueue_scripts() {
    // jquery.form.js, изначально поставляемый с WordPress, устарел и не поддерживается
    // поэтому нам нужно отменить его регистрацию и зарегистрировать последнюю версию
    wp_deregister_script( 'jquery-form' );
    wp_register_script( 'jquery-form', wpcf7_plugin_url( 'jquery.form.js' ),
        array( 'jquery' ), '2.52', true );

    $in_footer = true;
    if ( 'header' === WPCF7_LOAD_JS )
        $in_footer = false;

    wp_enqueue_script( 'contact-form-7', wpcf7_plugin_url( 'scripts.js' ),
        array( 'jquery', 'jquery-form' ), WPCF7_VERSION, $in_footer );

    do_action( 'wpcf7_enqueue_scripts' );
}

Как теперь добавить атрибут defer="defer" в приведенный выше код?

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

Соответствующий тикет: http://core.trac.wordpress.org/ticket/12009

scribu scribu
9 янв. 2012 г. 19:15:15

Хороший вопрос, @Viruthagiri.

Ramkumar M Ramkumar M
2 февр. 2012 г. 15:30:47
Все ответы на вопрос 2
6
63

Начиная с WordPress 4.1 доступен фильтр: script_loader_tag. Вы можете использовать его для поиска нужного скрипта:

add_filter( 'script_loader_tag', function ( $tag, $handle ) {

    if ( 'contact-form-7' !== $handle )
        return $tag;

    return str_replace( ' src', ' defer="defer" src', $tag );
}, 10, 2 );

Старый ответ

Нет специального фильтра... по крайней мере, я его не вижу. Но ...

  • wp_print_scripts() вызывает WP_Scripts->do_items()
  • который вызывает WP_Scripts->do_item()
  • который использует esc_url()
  • который имеет фильтр: 'clean_url'.

И вот решение:

function add_defer_to_cf7( $url )
{
    if ( FALSE === strpos( $url, 'contact-form-7' )
      or FALSE === strpos( $url, '.js' )
    )
    { // не наш файл
        return $url;
    }
    // Должна быть ', а не "!
    return "$url' defer='defer";
}
add_filter( 'clean_url', 'add_defer_to_cf7', 11, 1 );

Предупреждение: не тестировалось, просто идея. :)

Обновление

Я написал и протестировал плагин с этим кодом.

9 янв. 2012 г. 13:56:46
Комментарии

Это также идеально подходит для использования с data-main в requirejs

Nicola Peluchetti Nicola Peluchetti
6 июн. 2012 г. 18:07:47

Отличный хак, и такой простой. Думаю, он также подойдёт для добавления charset='utf-8' при необходимости!

webaware webaware
16 янв. 2013 г. 10:16:09

Отлично, но почему: Должна быть ', а не "! ?

henrywright henrywright
1 февр. 2014 г. 04:09:52

@henrywright WordPress добавляет ' с обеих сторон возвращаемой строки, а " приведёт к невалидному HTML.

fuxia fuxia
1 февр. 2014 г. 12:54:48

Возможно, хорошей идеей будет добавить проверку для использования только на фронт-энде, например с помощью if( ! is_admin() ){}, на случай если кто-то захочет адаптировать это для работы с другими скриптами. Популярные плагины вроде ACF могут доставить головной боли.

crissoca crissoca
28 апр. 2015 г. 05:09:37

@crissoca, спасибо, друг. Совсем забыл об этом, пока TinyMCE не перестал работать как надо (пропали qtags и тому подобное :-D ). Так что да, используйте это ТОЛЬКО на фронт-энде!

Charles Charles
12 июн. 2015 г. 15:46:31
Показать остальные 1 комментариев
0

Принятый ответ верен, но я хотел внести некоторые улучшения/обновления для более общего случая, которые могут быть полезны любому, включая меня в будущем, кто наткнется на этот вопрос во время поиска решения. Для общих случаев, не связанных с плагином contact-form-7, где вы добавляете атрибут defer ко всем скриптам, скорее всего, стоит исключить его для административных страниц, так как они зависят от определенного порядка выполнения скриптов. Также для неадминистративных страниц стоит исключить jQuery, потому что jQuery, вероятно, должен загружаться в head до всего остального. Кроме того, вместо манипуляций со строкой тега, лучшим подходом будет загрузка его в объект DOMDocument, манипуляции с ним и последующее преобразование обратно в строку. Также в новых версиях PHP есть проверка типов, поэтому стоит добавить типы параметров и возвращаемого значения в объявление функции.

<?php

    add_filter('script_loader_tag', function (string $tag, string $handle, string $src):string {
        if (is_admin()) {
            return $tag;
        }
        if (in_array($handle, array('jquery-core', 'jquery-migrate'))) {
            return $tag;
        }
        $dom = new \DomDocument();
        $dom->loadHTML($tag, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
        $dom->getElementsByTagName('script')[0]->setAttribute("defer", "defer");
        $tag = $dom->saveHTML();
        return $tag;
    }, 10, 3);

?>
6 июн. 2023 г. 01:05:52