Blog Afficher des Templates Parts avec des Requêtes & Paramètres Intégrés

Afficher des Templates Parts avec des Requêtes & Paramètres Intégrés

5 April 2018

Lorsqu’il est nécessaire d’afficher plusieurs blocs de contenus sur une seule et même page WordPress, nous nous retrouvons vite à effectuer des tâches redondantes. Par exemple, dans le cadre du développement d’un thème de type Magazine, il n’est pas rare de devoir afficher: les articles à la une, vidéos, brèves ou encore un agenda.

Évidemment, chaque bloc nécessite d’exclure les résultats des requêtes antérieures, afin d’éviter les doublons. Dans cet atelier, nous allons créer une fonction dynamique afin de facilement intégrer n’importe quel type de blocs.

Les Objectifs

Notre fonction se nommera hwk_loop(), elle devra appeler un Template spécifique, lui injecter une requête et passer des paramètres en cas de besoin, pour un traitement personnalisé. Voici la liste des fonctionnalités:

  • Créer une WP_Query personnalisée
  • Utiliser la WP_Query globale en cours
  • Créer une WP_Query personnalisée, en utilisant les arguments de la WP_Query globale en cours
  • Exclure ou inclure les résultats des blocs précédents
  • Ajouter les résultats de notre WP_Query dans la liste des posts à exclure pour les prochains blocs
  • Gérer les résultats “introuvable” dans le Template Part
  • Gérer les résultats “introuvable” dans un Template Part séparé
  • Passer des paramètres arbitraire et les traiter dans le Template Part
  • Choisir l’élément HTML de notre conteneur de Template: <section> / <div>
  • Passer un ID, class, style ou attribut au conteneur

Exemple d’Utilisation

Dans cet exemple de page, nous allons afficher le contenu de la boucle WP_Query principale, un bloc d’articles relatifs et une sidebar à l’aide d’une seule et même fonction, seul les arguments vont diverger. Ici, pas besoin d’utiliser have_posts(): the_post(). Cette méthode sera directement traité dans chaque Template Part.

<?php get_header(); ?>
<div class="row">
<!– Contenu Principal –>
<div class="col-lg-8">
<!– Template: loop.php –>
<!– Query: WP_Query globale (page en cours) –>
<!– Not_found: Traitement dans le fichier de template –>
<!– Utilisation de tous les arguments par défaut… –>
<!– Pas besoin de while(have_posts()): the_post() (effectué dans le Template) –>
<?php hwk_loop(); ?>
<!– Posts Relatif –>
<!– Template: templates/related.php –>
<!– Query: New WP_Query / 3 derniers posts du post_type 'post' –>
<!– Exclude: Exclusion automatique des posts des requêtes hwk_loop() antérieures –>
<!– Not_found: Traitement dans le fichier templates/not-found.php –>
<!– Wrappert: Affichage du Template dans le html: –>
<!– <section class="related" data-post-id="8">{{Template}}</section> –>
<?php
hwk_loop(array(
'template' => 'templates/related.php',
'not_found' => 'templates/not-found.php',
'query' => array(
'post_type' => 'post',
'posts_per_page' => 3
),
'wrapper' => array(
'element' => 'section',
'attr' => array(
'class' => 'related',
'data-post-id' => get_the_ID() // Post ID de la page principale en cours.
)
)
));
?>
</div>
<!– Sidebar –>
<div class="col-lg-4">
<!– Template: templates/sidebar.php –>
<!– Query: New WP_Query / 3 derniers posts du post_type 'post' –>
<!– Exclude: Exclusion automatique des posts des requêtes hwk_loop() antérieures –>
<!– Not_found: Traitement dans le fichier de template –>
<?php
hwk_loop(array(
'template' => 'templates/sidebar.php',
'query' => array(
'post_type' => 'post',
'posts_per_page' => 3
)
));
?>
</div>
</div>
<?php get_footer(); ?>

Création de la fonction

Afin de pouvoir appeler hwk_loop() sur n’importe quelle page, nous allons définir des arguments par défaut. Ceux-ci vont de garantir l’utilisation de la boucle WP_Query principale en priorité.

<?php
function hwk_loop($args = array()){
// Arguments par défaut
$args = wp_parse_args_recursive($args, array(
'template' => 'loop.php', // Fichier de Template par défaut: /wp-content/themes/<theme>/loop.php
'not_found' => false, // Fichier de Template en cas de résultat non trouvé
'pagination' => false, // Paramètre de pagination. Utilisé par le fichier de Template. true | false
'query' => array(), // Arguments de WP_Query. Si vide, alors utiliser la WP_Query globale
'query_addon' => false, // Utiliser l'argument 'query' pour l'ajouter à la WP_Query globale. true | false
'result' => array(), // Injecter directement les résultats d'une Query antérieur. Bypass l'argument 'query'
'exclude' => array(
'add' => true, // Ajouter les résultats dans la liste des posts à exclure pour les prochains appels. true | false
'get' => true // Utiliser la liste des posts à exclure pour cette Query. true | false
),
'options' => array(), // Tableau d'options personnalisés.
'wrapper' => array(
'element' => 'div', // Element <div> qui servira de conteneur à notre Template
'attr' => array(
'id' => '', // Ajouter un attribut id=""
'class' => '', // Ajouter un attribut class=""
'style' => '' // Ajouter un attribut style=""
), // Note: Il est possible d'ajouter son propre attribut personnalisé ici.
)
));
// Get Global WP_Query
global $wp_query;
// Exclude: GET query_var
$exclude = get_query_var('hwk_loop_exclude', array());
// Result: si existe, pas de WP_Query
if(empty($args['result'])){
// Query: Executer une nouvelle WP_Query
if(!empty($args['query'])){
// Query Addon: Utiliser les arguments de la WP_Query globale pour créer une nouvelle Query
if($args['query_addon'] && isset($wp_query->query) && !empty($wp_query->query))
$args['query'] = $wp_query->query;
// Exclude: Ajouter 'post__not_in' à la WP_Query
if($args['exclude']['get'] && !empty($exclude))
$args['query']['post__not_in'] = $exclude;
// New WP_Query
$args['result'] = new WP_Query($args['query']);
}else{
// Utiliser la WP_Query globale
$args['result'] = $wp_query;
// Récupération des arguments de la WP_Query globale
if(isset($wp_query->query) && !empty($wp_query->query))
$args['query'] = $wp_query->query;
}
}
// Not Found: Inclure le fichier 'not_found' si défini
if(!$args['result']->have_posts() && $args['not_found'])
return locate_template(array($args['not_found']), true, false);
// Exclude: SET query_var
if($args['exclude']['add']){
foreach($args['result']->posts as $p){
if(in_array($p->ID, $exclude))
continue;
$exclude[] = $p->ID;
}
set_query_var('hwk_loop_exclude', $exclude);
}
// Ajout de tous les paramètres dans une query_var
set_query_var('hwk_loop', $args);
// Début du Wrapper. Si défini
hwk_loop_wrapper('start', $args);
// Affichage du Template
locate_template(array($args['template']), true, false);
// Fin du Wrapper. Si défini
hwk_loop_wrapper('end', $args);
return;
}

Les fonctions d’aide

Nous allons créer une fonction personnalisée wp_parse_args_recursive() qui permet de gérer les valeurs par défaut d’un tableau associatif, contrairement à son cousin wp_parse_args(), natif à WordPress.

<?php
if(!function_exists('wp_parse_args_recursive')){
function wp_parse_args_recursive(&$a, $b){
$a = (array) $a;
$b = (array) $b;
$result = $b;
foreach($a as $k => &$v){
if (is_array($v) && isset($result[$k])){
$result[$k] = wp_parse_args_recursive($v, $result[$k]);
}else{
$result[$k] = $v;
}
}
return $result;
}
}
function hwk_loop_wrapper($type = 'start', $args = false){
if(!$args)
$args = get_query_var('hwk_loop');
if(!$args)
return;
if($type == 'start' && $args['wrapper']['element'])
echo '<' . $args['wrapper']['element'] . hwk_loop_attr($args) . '>';
elseif($type == 'end' && $args['wrapper']['element'])
echo '</' . $args['wrapper']['element'] . hwk_loop_attr($args) . '>';
return;
}
function hwk_loop_attr($args = false){
if(!$args)
$args = get_query_var('hwk_loop');
if(!$args)
return;
if(!isset($args['wrapper']['attr']) || empty($args['wrapper']['attr']))
return;
$return = '';
foreach($args['wrapper']['attr'] as $attr => $value){
if(empty($value))
continue;
$return .= ' ' . $attr . '="' . $value . '"';
}
return $return;
}

Exemple de Template Part

Voici un exemple de notre fichier loop.php, affiché par défaut par notre fonction hwk_loop().

<?php
// On vérifie que notre Template est bien appelé via hwk_loop()
// $loop a accès à toutes les arguments de hwk_loop()
if(!$loop = get_query_var('hwk_loop'))
return;
?>
<!– Traitement de la boucle –>
<!– Les résultats sont stockés dans $loop['result'] –>
<?php if($loop['result']->have_posts()): ?>
<?php while($loop['result']->have_posts()): $loop['result']->the_post(); ?>
<div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<a href="<?php the_permalink(); ?>">
<?php the_title(); ?>
</a>
</div>
<?php endwhile; wp_reset_postdata(); ?>
<!– Si 'pagination' = true, alors gérer la pagination –>
<?php if($loop['pagination']){ ?>
<?php
echo paginate_links(array(
'current' => max(1, get_query_var('paged')),
'total' => $loop['result']->max_num_pages
));
?>
<?php } ?>
<!– Pas de résultats –>
<?php else: ?>
<div>
Aucun résultat.
</div>
<?php endif; ?>


Konrad Chmielewski

Evangeliste WordPress & Full Stack Developer depuis 10 années.