Añadir Atributos Adicionales en la Etiqueta Script para JS de Terceros
Me encontré con esto al intentar integrar la API del selector de Dropbox en un plugin que estoy desarrollando.
La documentación de la API indica que debes colocar la siguiente etiqueta script
en la parte superior de tu archivo:
<script type="text/javascript" src="https://www.dropbox.com/static/api/1/dropins.js" id="dropboxjs" data-app-key="MY_APP_KEY"></script>
Todo bien, y de hecho funciona cuando lo pego directamente en la página que se llama en la sección de administración. Sin embargo, me gustaría usar alguna variación de wp_register_script(), wp_enqueue_script() y wp_localize_script() para pasar el id y data-app-key necesarios.
He probado diferentes variaciones de esto:
add_action('admin_enqueue_scripts', 'add_dropbox_stuff');
function add_dropbox_js() {
// Registrar y cargar el script de 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"));
}
Y:
add_action('admin_enqueue_scripts', 'add_dropbox_stuff');
function add_dropbox_stuff() {
// Registrar y cargar el script de Dropbox con múltiples atributos
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 está reemplazado con la clave de aplicación apropiada en mi código. Agradecería cualquier orientación. Gracias.
EDICIÓN: También intenté hacerlo con jQuery, pero sin éxito. Lo probé tanto en document load como en document ready. Recibo un retorno {"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');

Desde WP 4.1.0, está disponible un nuevo filtro para lograr esto fácilmente:
Úsalo de esta manera:
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="MI_CLAVE_DE_APP"></script>';
}
return $tag;
}

Puedes intentar usar el gancho de filtro script_loader_src
, por ejemplo:
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";
}
Actualización
Acabo de descubrir por mí mismo que el src es escapado por esc_url, así que investigando un poco más encontré el filtro clean_url
que puedes usar para devolver el valor con tu id y datos de 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;
}

No funciona. Antes de ser impreso, el resultado de 'script_loader_src' es escapado, por lo que las comillas son eliminadas y lo que muestras es reconocido como parte del atributo 'src' y no como atributos separados. Este código generará en el marcado HTML algo como <script type='text/javascript' src='https://www.dropbox.com/static/api/1/dropins.js?ver=3.6'id='dropboxjs'data-app-key='MY_APP_KEY'></script>

¡Genial! +1, pero todavía no funciona... Aunque creo que un pequeño ajuste lo hará funcionar.

He probado el código después de mi edición y funciona. Gracias por enseñarme algo con esto.

OK, parece (para mí) que con wp_enqueque_scripts
no es posible imprimir el id y la app key como atributos del tag script.
Estoy seguro al 90%, porque WP_Dependencies
no es una clase que conozca bien, pero al mirar el código me parece que no es posible.
Pero estoy seguro al 100% que usar wp_localize_script
es inútil para tu propósito.
Como dije en mi comentario anterior:
Lo que hace wp_localize_script es imprimir un objeto codificado en json en el html de la página. Este objeto es reconocido por el script y así puedes usarlo.
Lo que no mencioné en el comentario es que el objeto codificado en json tiene un nombre arbitrario que tú decides, de hecho, mirando la sintaxis:
wp_localize_script( $handle, $object_name, $l10n );
El objeto llamado $object_name
podría ser usado por el script porque está en el ámbito global e impreso en el html de la página.
Pero el $object_name
es un nombre que tú decides, así que puede ser cualquier cosa.
Así que pregúntate:
¿cómo puede el script en el servidor remoto de Dropbox hacer uso de una variable cuyo nombre desconocen?
Así que no hay ninguna razón para pasar el id y/o app key al script con wp_localize_script
: simplemente tienes que imprimirlos como atributos del tag script como se indica en la documentación de la API de Dropbox.
No soy desarrollador js, pero creo que lo que hace el script de Dropbox es:
- Obtener todos los elementos
<script>
html en la página - Ciclar a través de ellos buscando el que tenga 'id' == 'dropboxjs'
- Si ese script se encuentra, mirar el 'data-app-key' de ese script
- Verificar si esa app key (si está presente) es válida y autorizarte si es así
Por favor, ten en cuenta que no sé esto con seguridad, solo estoy adivinando.
De esta manera, el script cargado desde el servidor de Dropbox puede verificar tu app key de una manera fácil para ellos y fácil de implementar para ti.
Como en la primera frase dije que es no posible imprimir el id y la app key en el script usando wp_enqueque_scripts
, la moraleja es que tienes que imprimirlos en el markup de otra manera.
Una manera que no huela demasiado mal (cuando no hay alternativas) es usar el hook wp_print_scripts
para imprimir el tag script:
add_action('wp_print_scripts', 'do_dropbox_stuff');
function do_dropbox_stuff() {
if ( ! is_admin() ) return; // solo para el área de administración
$app_key = 'MY_APP_KEY';
// ¿por qué no crear una opción para ello?
// $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>';
}

Gracias G.M., logré que funcione usando esto. Estoy interesado en ver si hay soluciones alternativas usando los hooks de enqueue pero agradezco todo el pensamiento que pusiste en la respuesta.

@AndrewBartel Creo que no hay forma de usar wp_enqueque_scripts en tu caso, pero si encuentras una, ¡avísanos! :)

tu solución puede aumentar la carga en el servidor ya que estás haciendo directamente 1 solicitud http más al usar echo. La solución es buena pero no está optimizada.

@FaisalShaikh ¿te importaría explicar? La declaración echo
no realiza ninguna solicitud HTTP que yo sepa, y el wp_enqueue_script
de WordPress también hace un echo (ver https://core.trac.wordpress.org/browser/tags/4.9/src/wp-includes/class.wp-scripts.php#L343). Seguramente podrías reducir el número de solicitudes combinando el script con algún otro que tengas, pero: 1) en este caso, los scripts existen en un servidor de terceros 2) con HTTP/2 hoy en día, combinar los scripts reduciría el rendimiento, no lo aumentaría. ¿Quizás me estoy perdiendo algo?

Según la respuesta de Bainternet anterior. Este código funcionó para mí.
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";
}
}
Edición: La única diferencia con el código de Bainternet es que agregué una condición para verificar si la URL del script es de dropbox y si es un archivo .js.
Estoy ignorando todas las demás URL y reescribiendo solo la URL de Dropbox.

Por favor agrega alguna explicación sobre qué cambiaste y por qué lo cambiaste (o tuviste que cambiarlo).

Gracias por todas las publicaciones, realmente ayudaron. Creé mi propia versión para darle algo de estructura y hacerla más fácil de leer y actualizar. Usa enqueue como siempre, usa script para archivos CSS con un tag falso al final para que se cargue en la parte superior. Aunque probablemente se podría simplificar un poco más.
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;
}

Hice esto con mi plugin de eCards y es realmente simple.
Aquí tienes una copia directa del plugin:
$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>';
Observa que la clave API se pasa mediante una opción.

Hice algunas verificaciones en el código de dropbox.js (v2) para ver qué estaba sucediendo y cómo solucionarlo de la mejor manera. Resulta que el atributo data-app-key solo se usa para establecer la variable Dropbox.appKey. Pude establecer la variable con la siguiente línea adicional.
Usando el ejemplo de JavaScript en la página de Dropbox https://www.dropbox.com/developers/dropins/chooser/js:
<script>
Dropbox.appKey = "TU-ID-DE-APP";
var button = Dropbox.createChooseButton(options);
document.getElementById("container").appendChild(button);
</script>
En mi código establezco Dropbox.appKey en cada lugar donde hago referencia a las rutinas JavaScript de Dropbox. Hacer esto me permitió usar wp_enqueue_script() sin los parámetros adicionales.

Hay una forma más sencilla de hacer esto
function load_attributes( $url ){
if ( 'https://www.dropbox.com/static/api/1/dropins.js' === $url ){
return "$url' id='dropboxjs' data-app-key='MI_CLAVE_DE_APLICACION";
}
return $url;
}
add_filter( 'clean_url', 'load_attributes', 11, 1 );

Sintaxis de WordPress para script_loader_tag:
apply_filters( 'script_loader_tag', string $tag, string $handle, string $src )
Para agregar cualquier atributo, puedes modificar tu $tag de esta manera:
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;
}
Lo cual escapará correctamente la URL.
