Добавление дополнительных атрибутов в тег Script для сторонних JS

20 авг. 2013 г., 22:39:36
Просмотры: 29.6K
Голосов: 29

Я столкнулся с этим при попытке интегрировать API выбора файлов Dropbox в плагин, который я разрабатываю.

Документация API предписывает разместить следующий тег script в верхней части вашего файла:

<script type="text/javascript" src="https://www.dropbox.com/static/api/1/dropins.js" id="dropboxjs" data-app-key="MY_APP_KEY"></script>

Все хорошо, и это действительно работает, когда я непосредственно вставляю его на страницу, которая вызывается в админ-разделе. Но я хотел бы использовать какую-то вариацию wp_register_script(), wp_enqueue_script() и wp_localize_script() для передачи необходимых id и data-app-key.

Я пробовал несколько различных вариаций:

add_action('admin_enqueue_scripts', 'add_dropbox_stuff');
function add_dropbox_js() {
    // Регистрируем скрипт Dropbox
    wp_register_script('dropbox.js','https://www.dropbox.com/static/api/1/dropins.js');
    wp_enqueue_script('dropbox.js');
    wp_localize_script('dropbox.js','dropboxdata',array('id'=>"dropboxjs",'data-app-key'=>"MY_APP_KEY"));
}

И:

add_action('admin_enqueue_scripts', 'add_dropbox_stuff');
function add_dropbox_stuff() {
        // Регистрируем скрипт Dropbox
        wp_register_script('dropbox.js','https://www.dropbox.com/static/api/1/dropins.js');
        wp_enqueue_script('dropbox.js');
        wp_localize_script('dropbox.js','dropboxdata',array(array('id'=>"dropboxjs"),array('data-app-key'=>"MY_APP_KEY")));
    }

MY_APP_KEY в моем коде заменяется соответствующим ключом приложения. Буду признателен за любые указания. Спасибо.

РЕДАКТИРОВАНИЕ: Также пробовал сделать это с помощью jQuery, но безуспешно. Пробовал при загрузке документа и при готовности документа. Получаю ответ {"error": "Invalid app_key"}.

$('script[src="https://www.dropbox.com/static/api/1/dropins.js?ver=3.6"]').attr('id','dropboxjs').attr('data-multiselect','true').attr('data-app-key','MY_APP_KEY');
7
Комментарии

Функция wp_localize_script выводит json-закодированный объект в HTML-вывод страницы. Этот объект распознаётся скриптом, и вы можете его использовать. Но вам нужно добавить атрибуты к тегу script, а для этого wp_localize_script не подходит.

gmazzap gmazzap
20 авг. 2013 г. 23:10:40

G. M. прав, что wp_localize_script не создаёт атрибуты скрипта. Но можно ли передать app key напрямую в dropbox.js? Просто предположение: вы пробовали array('appKey'=>"MY_APP_KEY")? Вот код, который получает ключ из атрибута: if(!Dropbox.appKey){Dropbox.appKey=(e=document.getElementById("dropboxjs"))!=null?e.getAttribute("data-app-key"):void 0}

epilektric epilektric
20 авг. 2013 г. 23:21:21

Эй, @epilektric, не могли бы вы оформить это как ответ? Я не совсем понял, как это реализовать.

Andrew Bartel Andrew Bartel
21 авг. 2013 г. 00:40:57

@epilektric с помощью wp_localize_script вы действительно можете передавать атрибуты в скрипт. Я не уверен, сработает ли это, но в любом случае это не вопрос, связанный с WordPress.

gmazzap gmazzap
21 авг. 2013 г. 01:00:44

@AndrewBartel Я тоже не совсем уверен, как это сделать. Возможно, это поможет. http://pippinsplugins.com/use-wp_localize_script-it-is-awesome/

epilektric epilektric
21 авг. 2013 г. 02:39:07

Дубликат ... или, по крайней мере, очень близкий к нему. В настоящее время не может быть закрыт из-за открытого баунти.

kaiser kaiser
28 авг. 2013 г. 14:34:00

Я думаю, это дубликат этого вопроса.

fuxia fuxia
28 авг. 2013 г. 20:55:52
Показать остальные 2 комментариев
Все ответы на вопрос 9
1
29

Начиная с версии WP 4.1.0, доступен новый фильтр-хук для удобного решения этой задачи:

script_loader_tag

Используйте его следующим образом:

add_filter( 'script_loader_tag', 'add_id_to_script', 10, 3 );

function add_id_to_script( $tag, $handle, $source ) {
    if ( 'dropbox.js' === $handle ) {
        $tag = '<script type="text/javascript" src="' . $source . '" id="dropboxjs" data-app-key="MY_APP_KEY"></script>';
    }

    return $tag;
}
1 нояб. 2016 г. 01:17:16
Комментарии

выполняется ли это до какого-либо кэширования JS?

JoaMika JoaMika
22 авг. 2018 г. 14:16:14
7
19

вы можете попробовать использовать хук фильтра script_loader_src, например:

add_filter('script_loader_src','add_id_to_script',10,2);
function add_id_to_script($src, $handle){
    if ($handle != 'dropbox.js') 
            return $src;
    return $src."' id='dropboxjs' data-app-key='MY_APP_KEY";
}

Обновление

я только что сам разобрался, что src экранируется функцией esc_url, поэтому, поискав немного больше, я нашел фильтр clean_url, который можно использовать для возврата значения с вашим id и данными app key:

add_filter('clean_url','unclean_url',10,3);
function unclean_url( $good_protocol_url, $original_url, $_context){
    if (false !== strpos($original_url, 'data-app-key')){
      remove_filter('clean_url','unclean_url',10,3);
      $url_parts = parse_url($good_protocol_url);
      return $url_parts['scheme'] . '://' . $url_parts['host'] . $url_parts['path'] . "' id='dropboxjs' data-app-key='MY_APP_KEY";
    }
    return $good_protocol_url;
}
28 авг. 2013 г. 00:57:21
Комментарии

Это не работает. Перед выводом результат 'script_loader_src' экранируется, поэтому кавычки удаляются, и то, что вы выводите, воспринимается как часть атрибута 'src', а не как отдельные атрибуты. Этот код добавит в HTML-разметку что-то вроде <script type='text/javascript' src='https://www.dropbox.com/static/api/1/dropins.js?ver=3.6&#039;id=&#039;dropboxjs&#039;data-app-key=&#039;MY_APP_KEY'></script>

gmazzap gmazzap
28 авг. 2013 г. 10:21:02

Да, я обновил свой ответ.

Bainternet Bainternet
28 авг. 2013 г. 10:29:41

Отлично! +1, но всё равно не работает... Думаю, совсем небольшая правка поможет это исправить.

gmazzap gmazzap
28 авг. 2013 г. 10:42:20

Я проверил код после своих правок, и он работает. Спасибо, что научили меня этому.

gmazzap gmazzap
28 авг. 2013 г. 10:45:30

рад, что у тебя всё заработало :)

Bainternet Bainternet
28 авг. 2013 г. 10:45:58

Думаю, автор вопроса будет счастливее нас с тобой. ;)

gmazzap gmazzap
28 авг. 2013 г. 10:49:28

Спасибо @Bainternet за вашу помощь, ваш ответ помог решить проблему.

Andrew Bartel Andrew Bartel
30 авг. 2013 г. 02:40:47
Показать остальные 2 комментариев
5

ОК, похоже (на мой взгляд), что с wp_enqueque_scripts невозможно вывести id и ключ приложения в виде атрибутов тега script.

Я уверен на 90%, потому что класс WP_Dependencies мне не очень хорошо знаком, но, просматривая код, мне кажется, что это невозможно.

Но я уверен на 100%, что использование wp_localize_script не полезно для вашей задачи.

Как я уже сказал в своём комментарии выше:

Что делает wp_localize_script — выводит json-кодированный объект в html-код страницы. Этот объект распознаётся скриптом, и вы можете его использовать.

Что я не сказал в комментарии — json-кодированный объект имеет произвольное имя, которое вы задаёте. Например, если посмотреть на синтаксис:

wp_localize_script( $handle, $object_name, $l10n );

Объект с именем $object_name может использоваться скриптом, потому что он находится в глобальной области видимости и выводится в html страницы.

Но $object_name — это имя, которое вы задаёте, поэтому оно может быть любым.

Так что задайте себе вопрос:

как скрипт на удалённом сервере Dropbox может использовать переменную, название которой ему неизвестно?

Таким образом, нет никакого смысла передавать id и/или ключ приложения через wp_localize_script: вам нужно просто вывести их как атрибуты тега script, как указано в документации Dropbox API.

Я не js-разработчик, но думаю, что скрипт Dropbox делает следующее:

  1. получает все элементы <script> на странице
  2. перебирает их в поисках того, у которого 'id' == 'dropboxjs'
  3. если такой скрипт найден, проверяет его атрибут 'data-app-key'
  4. проверяет, является ли этот app key (если он есть) действительным, и авторизует вас, если это так

Обратите внимание, что я не уверен в этом на 100%, я просто предполагаю.

Таким образом, скрипт, загружаемый с сервера Dropbox, может проверить ваш app key удобным для них и простым для реализации способом.

Поскольку в начале я сказал, что нельзя вывести id и app key в скрипте с помощью wp_enqueque_scripts, мораль в том, что вам нужно вывести их в разметке другим способом.

Один из способов, который не выглядит слишком уж плохо (если нет альтернатив) — использовать хук wp_print_scripts для вывода тега script:

add_action('wp_print_scripts', 'do_dropbox_stuff');

function do_dropbox_stuff() {

  if ( ! is_admin() ) return; // только для админки

  $app_key = 'MY_APP_KEY';

  // почему бы не создать опцию для этого?
  // $app_key = get_option('dropbox_app_key');

  if ( empty($app_key) ) return;

  echo '<script type="text/javascript" src="https://www.dropbox.com/static/api/1/dropins.js" id="dropboxjs" data-app-key="' . esc_attr($app_key) . '"></script>';

}
24 авг. 2013 г. 04:14:29
Комментарии

Спасибо, G.M., мне удалось заставить это работать с помощью этого решения. Мне интересно узнать, есть ли альтернативные варианты с использованием хуков enqueue, но я ценю все усилия, которые вы вложили в ответ.

Andrew Bartel Andrew Bartel
27 авг. 2013 г. 00:59:10

@AndrewBartel Думаю, в вашем случае нет возможности использовать wp_enqueque_scripts, но если найдете способ, дайте нам знать! :)

gmazzap gmazzap
27 авг. 2013 г. 03:37:53

Ваше решение может увеличить нагрузку на сервер, так как вы напрямую создаете еще один HTTP-запрос с помощью echo. Решение хорошее, но не оптимальное.

Faisal Shaikh Faisal Shaikh
17 июл. 2018 г. 00:19:46

@FaisalShaikh не хочешь объяснить? Насколько я понимаю, оператор echo не выполняет никаких HTTP-запросов, и WordPress wp_enqueue_script также использует echo (см. https://core.trac.wordpress.org/browser/tags/4.9/src/wp-includes/class.wp-scripts.php#L343) Конечно, ты мог бы уменьшить количество запросов, объединив скрипт с каким-то другим, но: 1) в данном случае скрипт находится на стороннем сервере 2) с HTTP/2 в наше время объединение скриптов скорее снизит производительность, чем повысит её. Возможно, я что-то упускаю?

gmazzap gmazzap
17 июл. 2018 г. 17:55:32

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

Faisal Shaikh Faisal Shaikh
18 июл. 2018 г. 14:22:08
2

Из ответа Bainternet выше. Этот код сработал для меня.

function pmdi_dropbox( $good_protocol_url, $original_url, $_context){
    if ( FALSE === strpos($original_url, 'dropbox') or FALSE === strpos($original_url, '.js')) {
        return $url;
    } else {
        remove_filter('clean_url','pmdi_dropbox',10,3);
        $url_parts = parse_url($good_protocol_url);
        return $url_parts['scheme'] . '://' . $url_parts['host'] . $url_parts['path'] . "' id='dropboxjs' data-app-key='APIKEY";
    }
}

Примечание: Единственное отличие от кода Bainternet - я добавил условие для проверки, является ли URL скрипта Dropbox и является ли он файлом .js.

Я игнорирую все остальные URL и переписываю только URL Dropbox.

17 февр. 2014 г. 14:14:16
Комментарии

Пожалуйста, добавьте объяснение, что вы изменили и почему вы это изменили (или почему пришлось изменить).

tfrommen tfrommen
17 февр. 2014 г. 14:42:33

Я знаю, что это старый ответ, но в вашем коде выше, вы имели в виду возвращать $original_url внутри оператора IF вместо просто $url?

leromt leromt
12 мар. 2015 г. 23:01:09
0

Спасибо за все публикации, они действительно помогли. Я создал свою версию, чтобы придать ей структуру и сделать более удобочитаемой и обновляемой. Используйте enqueue как обычно, для CSS-файлов применяйте script с параметром false в конце, чтобы они загружались в верхней части страницы. Хотя, вероятно, это можно несколько упростить.

add_filter('script_loader_tag', 'add_attributes_to_script', 10, 3); 
function add_attributes_to_script( $tag, $handle, $src ) {

    $scripts_to_load = array (

        (0) => Array
          (
            ('name') => 'bootstrap_min_css',
            ('type') => '<link rel="stylesheet" href="',            
            ('integrity') => 'sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB',
            ('close') => ' type="text/css" media="all">'
          ),

        (1) => Array
          (
            ('name') => 'popper_min_js',
            ('type') => '<script type="text/javascript" src="',         
            ('integrity') => 'sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49',
            ('close') => '></script>'
          ),

         (2) => Array
           (
            ('name') => 'bootstrap_min_js', 
            ('type') => '<script type="text/javascript" src="',
            ('integrity') => 'sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T',
            ('close') => '></script>'
           )
    );  

    $key = array_search($handle, array_column($scripts_to_load, 'name'));

    if ( FALSE !== $key){

        $tag = $scripts_to_load[$key]['type'] . esc_url($src) . '" integrity="' . $scripts_to_load[$key]['integrity'] .'" crossorigin="anonymous"' . $scripts_to_load[$key]['close'] . "\n";

    }
    return $tag;
}
9 мая 2018 г. 00:39:10
2

Я реализовал это в своем плагине eCards, и это действительно просто.

Вот прямая копия/вставка из плагина:

$output .= '<!-- https://www.dropbox.com/developers/chooser -->';
$output .= '<script type="text/javascript" src="https://www.dropbox.com/static/api/1/dropbox.js" id="dropboxjs" data-app-key="' . get_option('ecard_dropbox_private') . '"></script>';
$output .= '<p><input type="dropbox-chooser" name="selected-file" style="visibility: hidden;" data-link-type="direct" /></p>';

Обратите внимание, что API-ключ передается через опцию.

26 авг. 2013 г. 16:55:59
Комментарии

Как используется $output? Выводится через echo? Добавляется в wp_print_scripts()?

Andrew Bartel Andrew Bartel
27 авг. 2013 г. 00:57:41

Он либо возвращается, либо выводится через echo, в зависимости от вашей функции.

Ciprian Ciprian
27 авг. 2013 г. 13:23:06
0

Я проверил код dropbox.js (версия 2), чтобы понять, что происходит и как лучше решить эту проблему. Оказалось, что data-app-key используется только для установки переменной Dropbox.appKey. Я смог установить эту переменную с помощью следующей дополнительной строки.

Используя пример JavaScript со страницы Dropbox https://www.dropbox.com/developers/dropins/chooser/js:

<script>
Dropbox.appKey = "ВАШ-APP-ID";
var button = Dropbox.createChooseButton(options);
document.getElementById("container").appendChild(button);
</script>

В моем коде я устанавливаю Dropbox.appKey в каждом месте, где ссылаюсь на JavaScript-функции Dropbox. Это позволило мне использовать wp_enqueue_script() без дополнительных параметров.

7 апр. 2014 г. 22:19:19
0

Есть более простой способ сделать это

 function load_attributes( $url ){
    if ( 'https://www.dropbox.com/static/api/1/dropins.js' === $url ){
        return "$url' id='dropboxjs' data-app-key='MY_APP_KEY";
    }

    return $url;
}

add_filter( 'clean_url', 'load_attributes', 11, 1 );
8 дек. 2015 г. 11:58:44
0

Синтаксис Wordpress для script_loader_tag:

apply_filters( 'script_loader_tag', string $tag, string $handle, string $src )

Чтобы добавить любой атрибут, вы можете изменить ваш $tag следующим образом:

add_filter('script_loader_tag', 'add_attributes_to_script', 10, 3); 
function add_attributes_to_script( $tag, $handle, $src ) {
    if ( 'dropbox.js' === $handle ) {
        $tag = '<script type="text/javascript" src="' . esc_url( $src ) . '" id="dropboxjs" data-app-key="MY_APP_KEY"></script>';
    } 
    return $tag;
}

Этот метод правильно экранирует URL.

28 янв. 2018 г. 12:57:09