web-dev-qa-db-fra.com

Comment faire écho à JS juste après un script mis en file d'attente pour le mettre en mode noConflict?

Je souhaite inclure et utiliser un fichier JavaScript tiers ( Boottrap Tooltip ) dans mon plug-in. Comme Bootstrap est un framework très populaire et que tooltip() est un nom générique, je souhaite utiliser la fonctionnalité incluse noConflict() pour isoler l'instance d'infobulle dans ma propre variable.

Si je comprends bien le timing, cela doit être fait juste après le chargement du fichier de script - de sorte que rien d'autre ne puisse gâcher l'instance (il venait juste d'être configuré) ou de s'y perdre.

Cependant, il semble n'y avoir aucune convention dans la fonctionnalité de file d'attente pour faire écho à JS à un tel moment. $wp_scripts->print_extra_script() est appelé avant le script.

Est-ce possible d'accomplir la mise en œuvre de la file d'attente actuelle?

4
Rarst

WordPress> = 4.1

WordPress 4.1 avait ajouté script_loader_tag un filtre pour le code HTML complet du script en file d'attente. Parfait pour ajouter quelque chose juste après.


WordPress <4.1

J'ai fini par me connecter à wp_print_footer_scripts à la priorité 11 (une fois la file d'attente terminée) et à appeler wp_print_scripts() explicitement sur le descripteur du script, en faisant ensuite écho à ce que je devais faire.

J'hésiterais à utiliser ceci pour quelque chose de majeur, mais pour un petit script contenu, cela semble acceptable.

3
Rarst

Vous devez filtrer script_loader_src, vérifier si vous utilisez le bon script et ajouter un filtre ponctuel pour clean_url. Ajoutez ensuite votre script supplémentaire et assurez-vous que la sortie est syntaxiquement valide.

Assez simple, bien que plutôt hacky.

class Extra_Script
{
    private $extra = [];
    private $handle;
    private $url;
    private $versioned_url;

    public function __construct( $handle, $url )
    {
        $this->handle = $handle;
        $this->url    = $url;
        add_filter( 'script_loader_src', array( $this, 'filter_script_src' ), 10, 2 );
    }

    public function add_script( $script )
    {
        $this->extra[] = $script;
    }

    public function filter_script_src( $src, $handle )
    {
        if ( empty ( $this->extra ) )
            return $src;

        if ( $this->handle !== $handle )
            return $src;

        if ( 0 !== strpos( $src, $this->url ) )
            return $src;

        $this->versioned_url = $src;

        add_filter( 'clean_url', array( $this, 'filter_esc_url' ) );
        remove_filter( current_filter(), array( $this, __FUNCTION__ ) );

        return $src;
    }

    public function filter_esc_url( $url )
    {
        if ( $url !== $this->versioned_url )
            return $url;

        remove_filter( current_filter(), array( $this, __FUNCTION__ ) );

        $scripts = join( "\n", $this->extra );

        return "$url'></script><script>$scripts</script><script class='";
    }
}

Usage

add_action( 'wp_enqueue_scripts', function()
{
    $handle = 'foo';
    $url    = plugins_url( '/foo.js', __FILE__ );

    wp_enqueue_script( $handle, $url );

    $extra = new Extra_Script( $handle, $url );
    $extra->add_script( "alert('bar!');" );
});

Cela ajoutera un script en ligne juste après votre script mis en file d'attente.

Une alternative pourrait être Patchwork . Vous pouvez redéfinir le code de WordPress lors de l’exécution avec cela. Mais ce ne serait pas moins hacky.

5
fuxia

Aujourd'hui, je devais faire plus ou moins la même chose, aboutissant à une solution alternative que je voudrais partager au cas où cela pourrait être utile pour quelqu'un.

J'ai écrit une classe personnalisée qui étend WP_Script, quelque chose comme ceci:

class GM_Scripts extends WP_Scripts {

    static function buildFromWp( WP_Scripts $scripts ) {
        $class = get_called_class();
        $obj = new $class;
        foreach ( get_object_vars( $scripts ) as $n => $v ) {
            $obj->$n = $v;
        }
        return $obj;
    }

    public function do_item( $handle, $group = false ) {
        $done = parent::do_item( $handle, $group );
        do_action( 'after_script_done', $handle, $done );
    }

}

Cette classe hérite de toutes les méthodes de la classe parent WP, à l'exception de l'une, do_item, qui est celle utilisée pour imprimer efficacement le script sur le balisage.

GM_Scripts::do_item() appelle la même méthode sur WP_Script et immédiatement après déclenche l'action personnalisée 'after_script_done' en transmettant comme arguments le descripteur de script et une valeur booléenne vraie si le script était effectivement imprimé sur la page.

Après cela, j'ai accroché wp_print_scripts pour écraser l'objet global $wp_scripts avec une instance de ma classe, construite à l'aide de la méthode statique buildFromWp qui hérite du statut d'un WP_Scripts passé en argument.

add_action( 'wp_print_scripts', function() {

  if ( is_admin() || did_action('login_head') || ! isset($GLOBALS['wp_scripts']) ) {
    return;
  }

  $GLOBALS[ 'wp_scripts' ] = GM_Scripts::buildFromWp( $GLOBALS[ 'wp_scripts' ] );

}, 0 );

Une fois que mon instance a hérité du statut, tapez et et méthodes de la classe d'origine WP qui ne devrait pas causer de problème avec le code WordPress ou tiers.

En outre, cela ne se produit que sur le front, afin de réduire davantage les chances de conflits.

Enfin, j'ai ajouté l'action qui fait écho à ce dont j'ai besoin:

add_action( 'after_script_done', function( $handle, $done ) {

  if ( $handle === 'myscript' && $done ) {
     // echo what needed
  }

}, 0, 2 );

et mis en file d'attente mon script comme d'habitude:

add_action( 'wp_enqueue_script', function() {

  wp_enqueue_script( 'myscript', $script_url );

} );

Quel est l'avantage de cette approche par rapport à celle acceptée?

Tout d'abord, il s'agit d'une approche plus générique utilisable pour chaque script et, plus important encore, toute dépendance à mon script est résolue correctement.

Par exemple, un autre morceau de code peut utiliser

add_action( 'wp_enqueue_script', function() {

  wp_enqueue_script( 'another-script', $another_url, array( 'myscript' ) );

} );

En utilisant l'approche acceptée, dans ce cas

  • si mon script est déjà enregistré avant 'wp_head', il sera inséré dans la page sans conflit ni quoi que je veuille imprimer après.

  • s'il n'est pas enregistré, le 'another-script' ne sera pas inséré car WordPress ne pourra pas résoudre la dépendance

2
gmazzap