Добавление onload к тегу body
Сейчас я разрабатываю плагин, который будет встраивать тур по Google Earth в запись или страницу WordPress через шорткод.
Проблема, с которой я столкнулся, заключается в том, что для загрузки тура необходимо добавить атрибут onload="init()"
в тег <body>
.
Я могу изменить конкретный файл шаблона, но поскольку это для релиза, мне нужно добавить его динамически через хук. Есть идеи?

А вот решение на jQuery (как предложил Майк в своем первом комментарии).
function add_my_scripts() {
wp_enqueue_script( 'jquery' );
wp_enqueue_script( 'my_init_script', SCRIPTSRC, 'jquery', '1.0' );
}
add_action( 'init', 'add_my_scripts' );
Затем добавьте скрипт в ваш плагин, который делает следующее:
jQuery.noConflict();
jQuery(document).ready(function($) {
init();
});
Это запустит jQuery в режиме без конфликтов (если он еще не в этом режиме) и добавит вызов метода init()
, когда документ будет готов. Это более безопасный метод, чем использование body onready()
, потому что функция onready()
может вызывать только одну вещь... так что никто другой не сможет подключить что-либо к этому или добавить собственный скрипт. Лучше сделать ваш плагин как можно менее навязчивым, чтобы другие плагины не мешали ему или наоборот.

Я считаю, что ваш метод один из предпочтительных. Думаю, jQuery-код можно даже сократить, потому что jQuery предлагает сокращение для функции ready.

@EAMann - Не могли бы вы подробнее объяснить jQuery.noConflict()? Я никогда не использовал эту функцию, и документация мне не совсем понятна.

По умолчанию jQuery использует символ $
как синоним для jQuery
... это может нарушить работу других библиотек (Prototype, Scriptaculous и т.д.), а также пользовательских функций $
. Использование jQuery.noConflict()
отключает это поведение по умолчанию, но вы по-прежнему можете использовать функцию $
в своём коде, если передадите её... так что функция, которую я определил выше, может использовать $.ajax
и другие нативные вызовы внутри объявленной функции.

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

@EAMann - Спасибо. Я знал про использование внутри функции ready(), но не осознавал, что будет конфликт, если просто никогда не использовать $ за пределами замыкания. Я до сих пор не понимаю, что это делает. Возможно, мне стоит просто поизучать этот вопрос подробнее...

@MikeSchinkel - По умолчанию jQuery устанавливает глобальный $
как псевдоним объекта jQuery. Вызов jQuery в режиме noConflict()
переопределяет это поведение по умолчанию.

Вот один из подходов. Вы должны добавить вызов add_action()
внутри вашего хука, как я полагаю. Предполагается, что функция init уже определена в приведённом JavaScript коде. Если это не так, то данный код не сработает, но подключение скрипта, кажется, это проблема, которую вы уже решили, если я правильно вас понял. Обратите внимание, что вам не обязательно добавлять его в wp_foot
, вы так же легко можете добавить его в wp_head
:
<?php
function mypluginprefix_onload_init() { ?>
<script language="text/javascript">
// проверяем стандартный способ добавления событий onload
if ( typeof(window.addEventListener) !== 'undefined' )
window.addEventListener( "load", init, false );
// или старый нестандартный способ для msie
else if ( typeof(window.attachEvent) !== 'undefined' ) {
window.attachEvent( "onload", init );
}
</script>
<?php }
// это помещается в ваш хук
add_action('wp_foot', 'mypluginprefix_onload_event');
?>

Почему чистый JavaScript, а не jQuery? jQuery обрабатывает все крайние случаи, когда код может выполниться до полной загрузки страницы.

Для простого события onload, я считаю jQuery избыточным. Просто прикрепите обработчик и всё. jQuery создает дополнительную нагрузку в плане загрузки. Я люблю jQuery, но это не решение для всего. Если бы jQuery уже был подключен, тогда я бы сказал использовать его, но мой ответ обходится без него.

Игнорируя возможность сделать это с помощью jQuery, одним из вариантов является использование хука template_include
вместе с ob_start()
и callback-функцией. Ваша callback-функция может выполнить поиск строки '<body'
и заменить её на '<body onload="init()"'
, как показано в следующем коде. Вы можете использовать его напрямую в своем плагине, просто убедитесь, что изменили названия в соответствии с вашими соглашениями об именовании:
<?php
add_filter('template_include','start_buffer_capture',1);
function start_buffer_capture($template) {
ob_start('end_buffer_capture'); // Запускаем буферизацию вывода
return $template;
}
function end_buffer_capture($buffer) {
return str_replace('<body','<body onload="init()"',$buffer);
}
Обратите внимание, что я бы не считал приведенный выше код полностью надежным. Сомневаюсь, что он обработает все крайние случаи, так как я просто быстро его написал для ответа на ваш вопрос. Тем не менее, он показывает, как решить задачу в стандартном случае, и после тестирования вы сможете доработать его для обработки важных крайних случаев (например, что делать, если '<BODY'
написан в верхнем регистре и т.д.).

Вот JavaScript для динамического добавления callback при загрузке страницы, с jQuery или без него:
function add_onload() {
?>
<script type="text/javascript">
my_onload_callback = function() { alert('Привет!'); }; // тестовая функция
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' );
В вашем случае вам нужно просто заменить my_onload_callback на ваш метод инициализации.

Покопался ещё немного и нашёл «лучший» способ заставить это работать (Google усложняет встраивание своих туров по Земле, и их гаджет не работает).
В итоге я создал плагин, который использует комбинацию шорткода и произвольного поля.

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

Да, это помогло бы лучше понять, о чем вы изначально спрашивали. Вопрос и ответ должны идти вместе.

Для тех, кто может захотеть, вот плагин. Он размещен в репозитории WP http://wordpress.org/extend/plugins/google-earth-tours/
