Añadir onload al body
Actualmente estoy intentando desarrollar un plugin que incruste un Tour de Google Earth en una entrada/página de WP mediante un shortcode.
El problema que tengo es que para que el tour se cargue, necesito añadir un onload="init()"
dentro de la etiqueta <body>
.
Puedo modificar un archivo de plantilla específico, pero como esto es para lanzamiento público, necesito añadirlo dinámicamente mediante un hook. ¿Alguna idea?

Y aquí está una solución con jQuery (como Mike sugirió en su primer comentario).
function add_my_scripts() {
wp_enqueue_script( 'jquery' );
wp_enqueue_script( 'my_init_script', SCRIPTSRC, 'jquery', '1.0' );
}
add_action( 'init', 'add_my_scripts' );
Luego añade un script a tu plugin que haga esto:
jQuery.noConflict();
jQuery(document).ready(function($) {
init();
});
Esto iniciará jQuery en modo sin conflicto (si no lo está ya) y añadirá una llamada al método init()
cuando el documento esté listo. Es un método más seguro de usar que body onready()
porque la función onready()
solo puede llamar a una cosa... así que nadie más puede enganchar nada a eso o añadir scripts personalizados. Es mejor hacer tu plugin lo menos intrusivo posible para que otros plugins no interfieran o viceversa.

Creo que este es uno de tus métodos preferidos. Incluso creo que el código jQuery podría reducirse más, ya que jQuery ofrece un atajo para la función ready.

@EAMann - ¿Podrías explicar mejor jQuery.noConflict()? Nunca lo he usado y la documentación no me quedó clara.

Por defecto, jQuery establece el símbolo $
como sinónimo de jQuery
... esto puede romper otras librerías (Prototype, Scriptaculous, etc.) y también puede afectar funciones $
definidas por el usuario. Usar jQuery.noConflict()
desactiva este comportamiento predeterminado, pero aún puedes usar la función $
en tu código si la pasas como parámetro... así que la función que definí arriba podría usar $.ajax
y otras llamadas nativas dentro de la función definida.

@MikeSchinkel: http://hakre.wordpress.com/2010/08/11/selekturz-they-iz-serius-bizniss/

@EAMann - Gracias. Sabía sobre usar dentro de la función ready(), pero no me di cuenta de que habría un conflicto si nunca usas el $ fuera de un cierre. Todavía no entiendo qué hace. Tal vez debería investigar un poco más...

@MikeSchinkel - Por defecto, jQuery establece el $
global como un alias para el objeto jQuery. Invocar jQuery en modo noConflict()
anula ese valor predeterminado.

Aquí tienes un enfoque. Deberías agregar la llamada a add_action()
dentro de tu hook, según entiendo. El JavaScript que incluyo asume que la función init ya ha sido definida. Si no es así, esto fallará, pero incluir el script parece un problema que ya has resuelto si te estoy entendiendo bien. Ten en cuenta que no necesariamente debes agregarlo a wp_foot
, igualmente podrías agregarlo a wp_head
:
<?php
function mypluginprefix_onload_init() { ?>
<script language="text/javascript">
// verifica la forma estándar de agregar eventos onload
if ( typeof(window.addEventListener) !== 'undefined' )
window.addEventListener( "load", init, false );
// o la forma no estándar antigua de msie
else if ( typeof(window.attachEvent) !== 'undefined' ) {
window.attachEvent( "onload", init );
}
</script>
<?php }
// esto va en tu hook
add_action('wp_foot', 'mypluginprefix_onload_event');
?>

¿Por qué Javascript directo y no jQuery? jQuery maneja todos los casos extremos donde el código puede ejecutarse antes de que la página se cargue por completo.

Para un simple onload, creo que jQuery es excesivo. Simplemente adjunta el controlador y listo. jQuery implica un costo adicional en términos de descarga. Me encanta jQuery, pero no es la solución para todo. Ahora, si jQuery ya estuviera en cola, entonces diría que lo uses, pero mi respuesta prescinde de él.

Ignorando el potencial de hacer esto con jQuery, una cosa que podrías hacer es enganchar el filtro template_include
y usar ob_start()
con un callback. Tu callback puede entonces hacer una búsqueda de cadena en '<body'
y reemplazarlo con '<body onload="init()"'
como lo hace el siguiente código. Deberías poder colocarlo directamente en tu plugin, solo asegúrate de cambiar los nombres para seguir la convención de nomenclatura de tu propio plugin:
<?php
add_filter('template_include','start_buffer_capture',1);
function start_buffer_capture($template) {
ob_start('end_buffer_capture'); // Iniciar el búfer de página
return $template;
}
function end_buffer_capture($buffer) {
return str_replace('<body','<body onload="init()"',$buffer);
}
Ten en cuenta que no asumiría que el código anterior es completamente robusto todavía si fuera tú. Dudo que maneje todos los casos extremos ya que solo lo armé para responder tu pregunta, pero como mínimo te muestra cómo lograr el caso normal, y luego con algunas pruebas de casos de uso estoy seguro de que lograrás que maneje todos los casos extremos importantes (como ¿qué pasa si '<BODY'
está en mayúsculas, etc?)

Aquí tienes un código JavaScript para añadir dinámicamente un callback al cargar la página, con o sin jQuery:
function add_onload() {
?>
<script type="text/javascript">
my_onload_callback = function() { alert('¡Hola!'); }; // función de prueba
if( typeof jQuery == "function" ) {
jQuery(my_onload_callback); // document.ready
} else {
document.getElementsByTagName('body')[0].onload = my_onload_callback; // body.onload
}
</script>
<?php
}
add_action( 'wp_footer', 'add_onload' );
En tu caso, simplemente reemplazarías my_onload_callback con tu método de inicialización.

Investigué un poco más y encontré una forma "mejor" de hacerlo funcionar (Google dificulta la integración de sus Tours de Earth, y su gadget no funciona).
Terminé creando un plugin que usa una combinación de un shortcode y un campo personalizado.

Si puedes, te recomendaría publicar el código para beneficio de otros que encuentren esta publicación.

Sí, incluso sería útil para entender mejor lo que pediste en primer lugar. Pregunta y respuesta deberían ir juntas.

Para cualquiera que lo desee, aquí está el plugin. Está alojado en el repositorio de WP http://wordpress.org/extend/plugins/google-earth-tours/
