post_it_man

WPML + sticky_posts = BUG

WPML vous connaissez ? C’est le fameux plugin de traduction pour les sites WordPress. Et les sticky posts ? Moins ? Et si je dis « articles à la une » ? Ok ça va mieux. Et bien selon certaines conditions, le combo est détonnant …

WPML

WPML est pour moi LE plugin de traduction WordPress. Vous le trouvez lourd ? Oui ok, mais il en fait du lourd ! Traduction des articles, custom post types, images, menus, plugins, themes, bref il peut tout vous traduire. De plus, si vous n’avez pas encore testé la version 3, alors vous avez raté quelquechose, fini les notices et warning PHP en mode DEBUG !

Petit rappel du fonctionnement de WPML : il utilise plein plein de hooks partout pour intercepter ce que vous souhaitez afficher, et selon la langue en cours, il transforme la demande. Pas mal ! Par exemple si votre article 123 est en français et que le 456 est son équivalent anglais, lorsque vous demandez à WordPress le post 123, WPML vous sortira le 456 si vous êtes dans un contexte anglais.

Démo :

// Code lancé sur une page single.php demandée en anglais via /en/
$ID = 123;
$_post = get_post( $ID );
var_dump( $_post->ID] );
// int 456

Sticky Posts

Les sticky posts ou articles collants ou articles à la une servent à pouvoir mettre en avant certains articles sur votre blog. Vous pouvez par exemple faire en sorte de toujours afficher ces articles en premier sur la page 1, ou les utiliser pour les afficher dans un slider, la seule limite est votre imagination.

Néanmoins il existe une autre limite, celle de WordPress qui a décidé via ses développeurs de ne pas supporter d’autres types d’articles que les « post », les articles de blogs. Lisez la discussion sur les tickets Enable sticky post checkbox for custom post type Publish metabox.

Oui mais

héhé il y a un mais ! Il existe une astuce postée chez GeekPress nommée Ajouter les sticky posts aux Custom Post Types et aussi un plugin nommé Sticky Custom Post Types. Ces 2 cas permettent finalement d’ajouter le support des sticky posts pour les types de posts de votre choix, yippie kai yay embêteurs de mamans !

Maintenant, vous avez les articles à la une pour tous vos types de posts ! Vous pouvez donc mettre dans un slider des articles d’un shop, ou des items de portfolio, etc

COMBO BREAKER

Sauf que, je vous l’ai dit, WPML intercepte ce que vous lui demandez, et modifie le retour, et ça … ça nous fait vraiment chi…euh chialer ! Pourquoi ? Pour ça ; faites ceci :

  1. Mettez des articles de blog à la une (je mets le 123, 789)
  2. Mettez d’autres types d’articles à la une (je mets 456, 666)
  3. Testez ça :
$stickies = get_option( 'sticky_posts' );
var_dump( $stickies );
// array(2) ['123','789']

Je m’attendais naturellement à avoir « 123,456,789,666′ … mais là, c’est le drame, vous ne voyez sortir QUE les articles de blogs, et pas votre autre type d’article … Pourtant, il n’y a aucune ligne de code entre 2 ! SIIII, il y a WPML HAAAAAAA #rire_maléfique

Que fait WPML ?

Ce gentil plugin (oui je commence à être ironique là) va en fait filtrer nos IDs pour ne garder que ceux qui sont de type « post », pourquoi ? Car WordPress est fait comme ça ! Aïe, pas notre site ! Nous avons utilisé l’astuce ou le plugin … sniff

J’ai de suite compris qu’i y a avait un hook qui interférait et j’ai alors trouvé qu’il s’agissait de WPML …

Voici le grand méchant hook venant du fichier sitepress-multilingual-cms/sitepress.class.php :

    add_filter('option_sticky_posts', array($this,'option_sticky_posts')); 
    function option_sticky_posts($posts){
        global $wpdb;
        if(is_array($posts) && !empty($posts)){
            $posts = array_filter($posts, create_function('$a', 'return $a > 0;'));
            $posts = $wpdb->get_col("SELECT element_id FROM {$wpdb->prefix}icl_translations WHERE element_id IN (".join(',',$posts).") AND element_type='post_post' AND language_code = '{$this->this_lang}'");
        }
        return $posts;
    }

Et maintenant …

Comment s’en sortir

Le hook en question est option_sticky_posts qui vient de option_$option où $option est l’option désirée (venant de WordPress ou pas, plugins, thèmes etc).

J’ai alors utilisé un autre hook similaire qui est déclenché avant celui que WPML utilise, ce qui me permets de le fourber : pre_option_sticky_posts

Ce hook intervient avant (pre_) et si une valeur est retournée, alors le hook option_sticky_posts ne sera pas déclenché, WPML ne pourra pas faire ch … changer la valeur de retour de nos articles à la une.

Du code du code !

Du calme, le voilà :

add_filter( 'pre_option_sticky_posts', 'avoid_faux_king_filters', PHP_INT_MAX );
function avoid_faux_king_filters() {
	require_once( ABSPATH . '/wp-admin/includes/upgrade.php' );
	return __get_option( 'sticky_posts' );
}

J’utilise la fonction __get_option() qui n’est normalement pas destinée à un usage « normal », comme toutes les fonctions commençant par un double « _ », je dois donc inclure un fichier auparavant. Cette fonction est la même que get_option() à la différence qu’elle ne contient aucun hook, cela revient à faire une requête manuelle en base pour aller lire la valeur (mais je préfère quand même utiliser les fonctions WordPress). Je mets aussi la priorité à PHP_INT_MAX qui est une constante PHP pour essayer d’être le dernier à me déclencher et ainsi écraser les autres hooks déclenchés avant le mien.

Voilà, vous vous en êtes sortis, mais moi avec des cheveux blancs … Avez vous déjà eu ce problème ?

Lire la suite

Vous aimez ? Partagez !

4 réflexions sur “ WPML + sticky_posts = BUG  ”

  1. Bonjour Julio,

    Merci pour cet article très utile ! Je me le mets dans un signet pour y retourner facilement.
    Article que j’ai découvert en live lorsqu’un petit onglet de notification est apparu directement sur mon Mac ;-) Je me rappelle bien avoir donné une autorisation à boiteaweb il y a peu. Et bien maintenant je sais ce que j’ai autorisé: des astuces du tonnerre en temps réel et que je ne vais plus manquer dorénavant ! Plutôt cool ;-)

    Bonne continuation.

Envie de dire quelque chose ?

Avant de parler, merci de lire la charte des commentaires.

Utiliser le tag [php][/php] pour ajouter du code ou utilisez un service comme pastebin.com.
Cibler un commentateur avec un "@", merci à Mention Comments Authors !