Статья актуализирована для версии WP 5.6, менять её буду только в том случае, если код перестанет работать.

Нужна помощь? Не проблема, напишите мне на почту: admin@workinnet.ru

С версии WP 4.1 был добавлен отличный фильтр — script_loader_tag. Теперь нет необходимости извергать пламя из не предназначенных для того мест при добавление к скриптам атрибутов async или defer. Все делается довольно просто.

P. S. весь предложенный ниже код подключать требуется через файл functions.php, желательно, в рамках дочерней темы. Также можно вынести в собственный плагин. Прочитайте о создании собственного плагина.

Соответственно, предлагаю вам рабочий вариант кода для асинхронной загрузки. Это результат небольшой переработки нижеследующих вариантов, но главное отличие в том, что «ручками» вам придётся только исключать код, который не хочет работать асинхронно. Нижеприведённый код оптимизирован под версию 5.6 и работает, рекомендую использовать именно его. Если кто-то устанавливал ранее приведённый код, то измените, иначе будете получать следующую ошибку:

jquery-migrate.min.js?ver=3.3.2:2 Uncaught ReferenceError: jQuery is not defined

А теперь сам код для асинхронной загрузки скриптов:

<?php
if (!is_admin()) {
    add_filter( 'script_loader_tag', function ( $tag, $handle ) {    
        if ( strpos( $tag, "jquery.js" ) || strpos( $tag, "jquery-migrate.min.js") || strpos ($tag, "jquery.min.js" ) ) {
            return $tag;
        }
        return str_replace( ' src', 'async src', $tag );
    }, 10, 2 );
}

Все исключения вносите в эту строку в таком же формате.

 if ( strpos( $tag, "jquery.js" ) || strpos( $tag, "jquery-migrate.min.js") ) //Исключение указывайте в таком виде "strpos( $tag, "jquery-migrate.min.js")", не забудьте разделитель ||

Если решите использовать отложенную загрузку, то вот вам вариант для неё.

add_filter( 'script_loader_tag', function ( $tag, $handle ) {    
        if ( strpos( $tag, "jquery.js" ) || strpos( $tag, "jquery-migrate.min.js") || strpos ($tag, "jquery.min.js" ) ) {
            return $tag;
        }
        return str_replace( ' src', 'defer src', $tag );
    }, 10, 2 );
}

Я всего лишь заменил async на defer.

Ну а если предложенные варианты не помогли, то попробуйте то, что указал ниже.

В самом начале я старался использовать что-нибудь универсальное, чтобы не было проблем, например, это:

function wcs_defer_javascripts ( $url ) {
    if(is_admin()) return $url;
    if ( FALSE === strpos( $url, '.js' ) ) return $url;
    if ( strpos( $url, 'jquery.js') ) return $url;
    return "$url' defer='defer";
}
add_filter( 'clean_url', 'wcs_defer_javascripts', 11, 1 );

Для запуска асинхронной загрузки достаточно поменять строку:

return "$url' defer='defer";

на:

return "$url' async='async";

Но, такой код не всегда давал значительный прирост, да и мог порушить структуру сайта.

async слайдер
Пример разрушенного асинхронной загрузкой скриптов слайдера

Я решил задачку усложнить, чтобы более точно управлять отложенной и асинхронной загрузкой в WordPress и нашел такое решение:

function add_async_forscript($url)
{
    if (strpos($url, '#asyncload')===false)
        return $url;
    else if (is_admin())
        return str_replace('#asyncload', '', $url);
    else
        return str_replace('#asyncload', '', $url)."' async='async"; 
}
add_filter('clean_url', 'add_async_forscript', 11, 1);

Теперь к любому скрипту можно просто добавить #asyncload, чтобы присвоить атрибут async. Пример ниже:

wp_enqueue_script('myscriptass', 'assest/js/myscriptass.js#asyncload' );

Таким образом требуется подключать скрипты в файле functions.php.

Для отложенной загрузки создавал аналогичный код с атрибутами defer. Все довольно просто. Но есть более правильное решение, о котором расскажу дальше. И появилось оно вместе с выпуском WP 4.1 и добавлением нового фильтра.

apply_filters('script_loader_tag', string $tag, string $handle, string $src);
//виновник торжества

Собственно, это нужный фильтр. Просто для примера, его вставлять никуда не требуется.

Теперь переходим непосредственно к добавлению асинхронной загрузки на отдельный скрипт:

function add_async_attribute($tag, $handle) {
    if ( 'my-js-handle' !== $handle )
        return $tag;
    return str_replace( ' src', ' async="async" src', $tag );
}
add_filter('script_loader_tag', 'add_async_attribute', 10, 2);

Если необходимо добавить отложенную загрузку, то код будет выглядеть так:

function add_defer_attribute($tag, $handle) {
    if ( 'my-js-handle' !== $handle )
        return $tag;
    return str_replace( ' src', ' defer="defer" src', $tag );
}
add_filter('script_loader_tag', 'add_defer_attribute', 10, 2);

Как видите, просто заменили async на defer.

Наверное, содержание вызвало вопрос. Итак, все довольно просто. Данная функция проверяет скрипт на соответствие. Если js не соответствует параметру $handle, то возвращает атрибут по умолчанию, если же соответствует, то присваивает нужный атрибут. Наверное, возник вопрос, где найти значение $handle?

В таких строках:

wp_register_script('my-js-handle', $src, $deps, $ver, $in_footer);

или:

wp_enqueue_script('my-js-handle', $src, $deps, $ver, $in_footer);

Располагаться они могут практически в любом файле, который запускает загрузку скриптов. На скриншоте показываю наглядно, что вам нужно найти.

Асинхронная и отложенная загрузка js

Ничего сложно, кроме того, что на каждый скрипт пилить такую структуру трудоемко, потому, сделаем код более массовым.

function add_defer_attribute($tag, $handle) {
   // добавляем дескрипторы в массив
   $scripts_to_defer = array('my-js-handle', 'another-handle'); //здесь размещаем те самые $handle

   foreach($scripts_to_defer as $defer_script) {
      if ($defer_script === $handle) {
         return str_replace(' src', ' defer="defer" src', $tag);
      }
   }
   return $tag;
}
add_filter ('script_loader_tag', 'add_defer_attribute', 10, 2);

Отличие кода только в том, что на соответствие проверяются все значения массива. И если соответствие найдено, то будет присвоен атрибут defer. Для асинхронной загрузки код отдельный.

function add_async_attribute($tag, $handle) {
   // добавляем дескрипторы в массив
   $scripts_to_async = array('my-js-handle', 'another-handle'); //здесь размещаем те самые $handle

   foreach($scripts_to_async as $async_script) {
      if ($async_script === $handle) {
         return str_replace(' src', ' async="async" src', $tag);
      }
   }
   return $tag;
}
add_filter ('script_loader_tag', 'add_async_attribute', 10, 2);

Чем хорош данный вариант? Можно с легкостью разбить часть скриптов на отложенные, другую на асинхронные, избежав конфликтов. Но для этого придется понимать, как и в какой последовательности работают скрипты на сайте.

Надеюсь, сумел вам помочь, задача нелегкая, но, как видите, решаемая.

Насколько публикация полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка 4.6 / 5. Количество оценок: 14

Оценок пока нет. Поставьте оценку первым.

Если материалы с данного сайта были полезны, и вы желаете поддержать блог, то можете воспользоваться формой по ссылке: Донат на поддержку блога