Как перехватить уже локализованные скрипты

10

Если плагин использует какой-либо сценарий (выдающийся пример: jQuery UI Datepicker), но вы недовольны тем, как скрипт отображает выходные данные, тогда есть две возможности:

1. Отмените регистрацию скрипта> Добавьте свою версию

Итак, сначала вам нужно проверить ручку, затем найти приоритет и крюк ( wp_enqueue_scripts, login_enqueue_scriptsи т. Д.) ... вы знаете упражнение.

2. Измените параметры плагина jQuery

Обычно - если плагин не дерьмовый - он проталкивает параметры из PHP в JS, используя

wp_localize_script( $handle, $object_name, array( 
    // data
) );

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

Вопрос: Как мы можем фильтровать аргументы / параметры, которые перемещаются из PHP в Javascript, используя wp_localize_script?

кайзер
источник

Ответы:

9

wp_localize_script()вызывает метод localize()для глобальной переменной $wp_scripts. Мы можем установить эту переменную для экземпляра дочернего класса WP_Scripts:

class Filterable_Scripts extends WP_Scripts
{
    function localize( $handle, $object_name, $l10n )
    {
        $l10n = apply_filters( 'script_l10n', $l10n, $handle, $object_name );
        return parent::localize($handle, $object_name, $l10n);
    }
}

add_action( 'wp_loaded', function() {
    $GLOBALS['wp_scripts'] = new Filterable_Scripts;
});

Настройщик темы не использует это, он создает отдельный экземпляр WP_Scripts(см. wp-admin/customize.php). Может быть возможно заменить это также:

add_action( 'customize_controls_init', function() {
    $GLOBALS['wp_scripts'] = new Filterable_Scripts;
    $GLOBALS['wp_scripts']->registered = $GLOBALS['registered'];
});

Ничто из этого не было проверено, просто идея.

Фуксия
источник
Не могли бы вы уточнить, что такое $ l10n? Я понимаю, что передаю ему ручку и объект, но не $ 10n. Спасибо.
Эрик Леруа
1
@EricLeroy Это третий параметр wp_localize_script(): одиночный или многомерный массив .
fuxia
Эта реализация очень мне помогла, но я хочу предупредить вас, что она испортила мои административные скрипты, ACF перестала работать, потому что javascripts не были напечатаны из-за вышеуказанного решения. У меня еще нет решения, но я сейчас его ищу.
Ожье
4

@toscho отличная реализация. Проверено и верно. Вот немного измененная версия, которая также передает $ handle и $ object_name, так что вы можете фильтровать только при необходимости.

class Filterable_Scripts extends WP_Scripts
{
    function localize( $handle, $object_name, $l10n )
    {
        $l10n = apply_filters( 'script_l10n', $l10n, $handle, $object_name );
        return parent::localize($handle, $object_name, $l10n);
    }
}

add_action( 'init', function() {
    $GLOBALS['wp_scripts'] = new Filterable_Scripts;
});

add_filter('script_l10n', 'se108362_example_filter', 10 , 3);

// Example
function se108362_example_filter($l10n, $handle, $object_name ) {
    if('js-handle' == $handle && 'jsVariable' == $object_name) {
       return 'Something Else';
    }
    return $l10n;
}
Эрик Холмс
источник
1

Принятый ответ отличный! Но я столкнулся с проблемой, что Расширенные пользовательские поля перестали работать в бэкэнде из-за ошибки JavaScript. После нескольких часов копания я пришел к выводу, что в объекте Filterable_Scripts отсутствуют файлы javascript, зарегистрированные плагином ACF. Я не знаю точно, почему он это сделал, но я нашел правильное решение, если вы столкнетесь с той же проблемой.

К $GLOBALS['wp_scripts']счастью, все еще содержал правильные сценарии. Итак, я сделал следующее в add_action:

add_action( 'wp_loaded', function() {
    $fscripts = new Filterable_Scripts();

    $missing_scripts = array_diff_key( $GLOBALS['wp_scripts']->registered, $fscripts->registered);
    foreach($missing_scripts as $mscript){
        $fscripts->registered[$mscript->handle] = $mscript;
    }

    $GLOBALS['wp_scripts'] = $fscripts;
});

Поскольку объект содержит массив всех зарегистрированных сценариев, а дескрипторы также являются ключами массива, я мог бы использовать array_diff_key, чтобы определить, какие сценарии отсутствовали в расширенном объекте, и повторно добавить их. Я сделал это, и не только

$fscripts->registered = $GLOBALS['wp_scripts']->registered;

потому что я не хотел перезаписывать какие-либо изменения, сделанные расширенным объектом.

Ожье Шелвис
источник
1
У меня был другой способ сделать это: добавить два тега сценария acf $acf_field_group = $GLOBALS['wp_scripts']->registered['acf-field-group'];(также acf-input), а затем снова добавить их в экземпляр расширенного WP_Scriptsтега:, а $GLOBALS['wp_scripts']->registered['acf-field-group'] = $acf_field_groupзатем понял, что ACF использует сценарии только в Admin, и я только l10nвпереди, поэтому просто завернул действие и фильтр в !is_adminтесте.
MikeiLL
Хороший вопрос, с точки зрения производительности ваше решение работает лучше. Я также добавляю проверку is_admin в мою личную версию этого кода. Что мне еще нравится в моем подходе, так это то, что если в будущем идентификатор скриптов изменится или в более поздних версиях плагина ACF (или других плагинов) будут отсутствовать новые скрипты, мне не придется менять свой код.
Ожье Шелвис
Да, это имеет смысл и для меня. Я не уверен, если что-то из этого необходимо, если вы запускаете действие только в передней части.
MikeiLL
Хм .. Туше. Я думаю, что иногда я настолько увлекаюсь поиском идеального решения, что забываю, о чем действительно была первоначальная проблема. Однако, если потребность в этом в админе когда-либо изменится, мы уже сделали математику ;-)
Ожье Шелвис,
Здесь то же самое, друг, но все дело в обучении, не так ли?
MikeiLL