Como interceptar scripts já localizados

10

Se um plug-in usa algum script (exemplo em destaque: jQuery UI Datepicker), mas você não está satisfeito com a forma como o script renderiza a saída, existem duas possibilidades:

1. Cancele o registro do script> Adicione sua própria versão

Então, primeiro você precisa verificar o punho, em seguida, encontrar a prioridade e o gancho ( wp_enqueue_scripts, login_enqueue_scripts, etc.) ... você sabe o que fazer.

2. Altere os parâmetros do plugin jQuery

Normalmente - se o plugin não é uma porcaria - ele percorre os parâmetros de PHP para JS usando

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

Agora, essa é uma maneira inteligente de adicionar seus dados a um script JS, mas ... não é filtrável por padrão. Nem oferece WP_Scriptsnem nenhum filtro que os usuários possam utilizar posteriormenteWP_Dependencies

Pergunta: Como podemos filtrar os argumentos / parâmetros que são movidos do PHP para o Javascript usando wp_localize_script?

kaiser
fonte

Respostas:

9

wp_localize_script()chama o método localize()na variável global $wp_scripts. Podemos definir essa variável para uma instância de uma classe filho de 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;
});

O personalizador de temas não usa isso, ele cria uma instância separada de WP_Scripts(consulte wp-admin/customize.php). Também pode ser possível substituir isso:

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

Nada disso foi testado, apenas uma ideia.

fuxia
fonte
Você poderia especificar o que é $ l10n? Eu entendo passar a alça e o objeto, mas não $ 1010. Obrigado.
precisa
1
@EricLeroy É o terceiro parâmetro de wp_localize_script(): uma matriz única ou multidimensional .
fuxia
Essa implementação me ajudou muito, mas quero avisá-lo que isso atrapalhou muito meus scripts de administrador, pois o ACF parou de funcionar porque os javascripts não foram impressos devido à solução acima. Ainda não tenho uma correção, mas estou procurando agora.
Ogier Schelvis
4

@toscho ótima implementação. Testado e verdadeiro. Aqui está uma versão ligeiramente modificada, que também passa o $ handle e $ object_name para que você possa filtrar apenas quando necessário.

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;
}
Eric Holmes
fonte
1

A resposta aceita é ótima! Mas encontrei um problema em que os campos personalizados avançados pararam de funcionar no back-end devido a um erro de javascript. Depois de cavar por algumas horas, cheguei à conclusão de que o objeto Filterable_Scripts estava com falta dos arquivos javascript registrados pelo plug-in ACF. Não sei exatamente por que isso aconteceu, mas encontrei uma solução adequada para isso, se você encontrar o mesmo problema.

O $GLOBALS['wp_scripts']felizmente ainda continha os scripts apropriados. Então eu fiz o seguinte no 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;
});

Como o objeto contém uma matriz de todos os scripts registrados e as alças também são as chaves da matriz, eu poderia usar array_diff_key para determinar quais scripts estavam ausentes no objeto estendido e adicioná-los novamente. Eu fiz isso e não apenas

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

porque não queria sobrescrever nenhuma alteração feita pelo objeto estendido.

Ogier Schelvis
fonte
1
Eu tinha uma outra maneira de fazer isso: adicionar as duas tags de script acf $acf_field_group = $GLOBALS['wp_scripts']->registered['acf-field-group'];(também acf-input) e adicioná-las novamente à instância da WP_Scriptstag estendida :; $GLOBALS['wp_scripts']->registered['acf-field-group'] = $acf_field_groupentão, percebi que o ACF está usando apenas os scripts em Admin e eu estou somente l10nna frente, então envolva a ação e filtre em um !is_adminteste.
precisa saber é o seguinte
Bom ponto, em termos de desempenho, sua solução funciona melhor. Também estou adicionando a verificação is_admin à minha versão pessoal deste código. O que ainda gosto na minha abordagem é que, se os IDs dos scripts mudarem no futuro ou se houver novos scripts ausentes nas versões posteriores do plug-in ACF (ou outros plug-ins), não preciso alterar meu código.
Ogier Schelvis
Sim, isso faz sentido para mim também. Não tenho certeza se algo é necessário se você estiver executando apenas a ação no front end.
precisa saber é o seguinte
Hmm .. toque. Eu acho que às vezes eu me apaixono tanto por encontrar a solução perfeita que esqueço o que realmente era o problema inicial. No entanto, se a necessidade de que na administração pode mudar nunca já fez as contas ;-)
Ogier Schelvis
O mesmo aqui, amigo, mas é tudo sobre aprendizado, não é?
precisa saber é o seguinte