restore_current_blog() sert-il à quelque chose ? #73

J’adore le multisite mais certaines fonctions me laissent perplexes. Attention vieux débat mais malheureusement toujours d’actu !

🔗 Rappels du contexte

Dès lors qu’on veut récupérer les données d’un autre site du réseau multisite, sous WordPress, on nous conseille de passer par un duo de fonctions : switch_to_blog() et restore_current_blog(). La première permet, comme son nom l’indique, de switcher (en français on pourrait dire « basculer ») vers le site dont on connaît l’ID, la deuxième devrait donc nous permettre de revenir à notre point de départ comme son nom l’indique mais c’est pas ça du tout !

restore_current_blog() va juste « remettre le curseur » sur le site qui précède. Typiquement si vous cherchez à faire une boucle pour récupérer la liste des sites du réseau, vous allez trouver ce genre d’exemple :

foreach ( get_sites() as $site ){
 switch_to_blog( $site->blog_id );
 //ici du code
 restore_current_blog();
}

Remarque : ici j’utilise get_sites() car wp_get_sites() est maintenant déprécié, pensez-y wink

Mais ça devient donc lourd et faux suivant le contexte qui nous intéresse. Au bout du troisième site on ne va plus du tout revenir sur le site d’origine avec restore_current_blog() mais au deuxième !

🔗 Donc il ne faut plus utiliser restore_current_blog() ?

Bon si je reformule, je souhaite faire une boucle sur l’ensemble des sites du réseau et exécuter des actions à chaque fois, grâce au tableau fourni par get_sites(), je vais pouvoir le faire, et switch_to_blog() va me faire passer d’un blog à l’autre pour exécuter mon code.

Plusieurs problèmes se posent :

  • restore_current_blog() ne fait pas du tout ce que son nom indique
  • en termes de performance l’impact est très important

Mais on ne va pas non plus enlever la fonction complètement parce sinon on va potentiellement avoir quelques soucis car la fonction assure pas mal de traitements.

🔗 Détails de la fonction

Quand on explore les codes des deux fonctions, on note l’utilisation d’une globale :

$GLOBALS['_wp_switched_stack']

c’est un tableau qui se remplit avec l’ID du site vers lequel on switche et inverserment se vide d’un cran quand on utilise restore_current_blog() :

$blog = array_pop( $GLOBALS['_wp_switched_stack'] );

Le souci c’est que WordPress a une deuxième globale qui lui permet de se mettre « en mode switched »:

$GLOBALS['switched'] = ! empty( $GLOBALS['_wp_switched_stack'] );

Cette même globale est utilisée ailleurs dans le core, ms_is_switched() :

function ms_is_switched() {
 return ! empty( $GLOBALS['_wp_switched_stack'] );
}

Cette dernière fonction est utilisée à plusieurs endroits du core notamment pour les URLs d’uploads de chaque site et là ça peut devenir problématique, on peut aboutir à des résultats inattendus voire à des erreurs de traitements si on zappe la fonction restore_current_blog().

🔗 Que fait-on alors ?

On pourrait donc diminuer très fortement le temps d’exécution de notre script en écrasant nous-mêmes ces globales puisque c’est l’usage qui est fait ici par les fonctions de WordPress. J’avais commencé à écrire ce bout de code mais je suis tombé sur un stackoverflow qui en parlait déjà :

$current_site = get_current_blog_id();

foreach ( $sites as $site ) {
 switch_to_blog( $site[ 'blog_id' ] );
 // le code
}

switch_to_blog( $current_site );
$GLOBALS['_wp_switched_stack'] = array();
$GLOBALS['switched'] = FALSE;

🔗 État de l’affaire et considérations personnelles

Le ticket référent est #37958 et le principal obstacle aux évolutions reste comme souvent avec WordPress la rétro-compatibilité (ce qui fait sa force aussi). J’insiste sur le contexte d’utilisation ici, c’est d’ailleurs pour cela que j’ai consacré une partie de l’article à le définir. Je ne dis à aucun moment qu’il ne faut plus utiliser la fonction restore_current_blog(). Le genre de hack proposé dans l’avant-dernière partie de ce billet est à relier à un contexte donc et surtout pas à utiliser systématiquement au motif que c’est ostensiblement plus perf !

Il suffit cependant d’ouvrir le code du core pour avoir les tickets trac suivants en commentaires de la phpdoc de switch_to_blog() :

Il y est dit que certains éléments ne sont pas « switchés » et que la présence de cache objet peut faire buguer l’affaire. Faire attention :

Switch_to_blog serves relatively limited purpose and cannot swap everything.

 

Catégoriesdev