Как добавить атрибут defer="defer" для скриптов плагина?
Я не могу добавить атрибут 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" в приведенный выше код?

Начиная с 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 );
Предупреждение: не тестировалось, просто идея. :)
Обновление
Я написал и протестировал плагин с этим кодом.

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

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

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

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

Принятый ответ верен, но я хотел внести некоторые улучшения/обновления для более общего случая, которые могут быть полезны любому, включая меня в будущем, кто наткнется на этот вопрос во время поиска решения. Для общих случаев, не связанных с плагином 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);
?>
