Un widget wordpress pour afficher vos derniers custom post type

Comment créer un widget pour afficher ses derniers CPT ?

Dans ce petit mémo, je donne un exemple d’un widget censé afficher les derniers custom post type.

Ce que contient le widget

Ce widget devra contenir :

  • un titre
  • Une case à cocher pour afficher les posts de manière aléatoire
  • Un champ select pour choisir la taxonomie (catégorie) du CPT
  • Un champ texte pour le choix du nombre de post à afficher.

Le rendu du widget

Voici un exemple de rendu en front, avec une vignette

widget last custom post type wordpress

Et au niveau du rendu des options en backoffice

widget last custom post type wordpress backoffice03

Le code du widget

Ce code est à placer dans functions.php ou tout autre fichier dédié

class Cc_Last_Formation_Posts_Widget extends WP_Widget {

/*
* Register widget with WordPress.
*/

function __construct() {
parent::__construct(
'cc_last_formation_posts_widget ',
__( 'Cc Last formation posts', 'text_domain' ),
array( 'description' => __( 'Shows last formation posts.', 'text_domain' ), )
);
}


/**
* Front-end display of widget.
*/

public function widget( $args, $instance ) {
echo $args['before_widget'];
// Catch result
$tax_id = absint( $instance['tax_id'] ) ;
$random = $instance['rand'] ? true : false;
$number = ( ! empty( $instance['number'] ) ) ? absint( $instance['number'] ) : 5;
if ( ! $number ) {
$number = 3;
}
if( true === $random ) {
$loop = new WP_Query(
array(
'post_type' => 'formation',
'orderby' => 'rand',
'posts_per_page' => $number,
)
);
}else{
$loop = new WP_Query(
array(
'post_type' => 'formation',
'posts_per_page' => $number,
'tax_query' => array(
array(
'taxonomy' => 'categories-formations',
'field' => 'term_id',
'terms' => array($tax_id),
)
)
)
);
}



if( $loop->have_posts() ) {

echo '<h2 class="heading">'. esc_html( $instance['title'] ) .'</h2>';
echo '<div id="related-formation-post"><div class="flex-row">';

while ($loop->have_posts()){
$loop->the_post();
?>
<div class="flex-col-sm-4">
<article id="post-<?php the_ID(); ?>" <?php post_class('related-formation-post'); ?>>
<div class="isotope-thumbnail">
<?php
if ( has_post_thumbnail() ) {
the_post_thumbnail('masonryLayout');
} ;

?>
</div>
<div class="entry-header isotope-title">
<h3><?php the_title(); ?></h3>
</div>
<div class="entry-meta">
<?php $duree = get_field_object('duree');
if($duree){

echo '<div><span class="isotope-duree">' . $duree['value'] . '</span></div>';
}
?>
</div>
<div class="isotope-excerpt">
<?php echo get_post_meta(get_the_ID(), '_yoast_wpseo_metadesc', true); ?>
</div>
<div class="isotope-cta">
<a href="<?php esc_url( the_permalink() );?>" rel="bookmark">Voir</a>
</div>
</article>
</div>
<?php
}


echo '</div></div>';
wp_reset_query();
echo $args['after_widget'];
}
}

/**
* Sanitize widget form values as they are saved.
*
* @see WP_Widget::update()
*
* @param array $new_instance Values just sent to be saved.
* @param array $old_instance Previously saved values from database.
*
* @return array Updated safe values to be saved.
*/

public function update( $new_instance, $old_instance ) {
$instance = array();
$instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
$instance['tax_id'] = ( ! empty( $new_instance['tax_id'] ) ) ? strip_tags( $new_instance['tax_id'] ) : '';
$instance['rand'] = ( ! empty( $new_instance['rand']) ) ? strip_tags( $new_instance['rand'] ) : '';
$instance['number'] =( ! empty( (int) $new_instance['number']) ) ? strip_tags( (int) $new_instance['number'] ) : '';
return $instance;
}

/**
* Back-end widget form.
*/

public function form( $instance ) {
$title = '';
if( !empty( $instance['title'] ) ) {
$title = $instance['title'];
}

$tax_id = '';
if( !empty( $instance['tax_id'] ) ) {
$tax_id = absint( $instance['tax_id'] ) ;
}
$number = isset( $instance['number'] ) ? absint( $instance['number'] ) : 3;
$random = isset( $instance['rand'] ) ? $instance['rand'] : false;
?>
<p>
<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:' ); ?></label>
<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>">
</p>
<p>
<label for="<?php echo $this->get_field_id( 'number' ); ?>"><?php _e( 'Number of posts to show:' ); ?></label>
<input id="<?php echo $this->get_field_id( 'number' ); ?>" name="<?php echo $this->get_field_name( 'number' ); ?>" type="text" value="<?php echo $number; ?>" size="3" />
</p>
<p>
<label for="<?php echo $this->get_field_id('tax_id'); ?>"><?php _e( 'Taxonomy Name:' )?></label>
<select id="<?php echo $this->get_field_id('tax_id'); ?>" name="<?php echo $this->get_field_name('tax_id'); ?>">
<?php
$custom_terms = get_terms('categories-formations');

foreach($custom_terms as $custom_term) {
$selected = ( $custom_term->term_id == esc_attr( $tax_id ) ) ? ' selected = "selected" ' : '';
$option = '<option '.$selected .'value="' . $custom_term->term_id;
$option = $option .'">';
$option = $option .$custom_term->name;
$option = $option .'</option>';
echo $option;
}
?>
</select>

</p>
<p>
<label for="<?php echo $this->get_field_id('rand'); ?>"><?php _e( 'Show random posts' ); ?></label>
<?php $checked = ( $random ) ? ' checked=\"checked\" ' : ''; ?>
<input type="checkbox" id="<?php echo $this->get_field_id( 'rand' ); ?>" name="<?php echo $this->get_field_name( 'rand' ); ?>" value="true" <?php echo $checked; ?> />
</p>
<?php
}


}

Ici plusieurs choses sont à remarquer :

Pour la fonction du constructeur, rien de particulier

Pour la fonction widget d’affichage en front : on commence par afficher un nombre par défaut d’articles, si jamais l’utilisateur ne remplit pas le champ

 if ( ! $number ) {
$number = 3;
}

dans notre boucle, on crée une condition pour afficher les post soit dans un ordre aléatoire

if( true === $random ) {
$loop = new WP_Query(
array(
'post_type' => 'formation',
'orderby' => 'rand',
'posts_per_page' => $number,
)
);
}

Soit en fonction d’une taxonomie sélectionnée. C’est l’attribut tax_query qui va nous permettre d’aller chercher la taxonomie et la sous taxonomie ou « term » choisie.

$loop = new WP_Query(
array(
'post_type' => 'formation',
'posts_per_page' => $number,
'tax_query' => array(
array(
'taxonomy' => 'categories-formations',
'field' => 'term_id',
'terms' => array($tax_id),
)
)
)
);

J’entoure le title d’une classe pour pouvoir la styliser directement

echo '<h2 class="heading">'.  esc_html( $instance['title'] ) .'</h2>';

Dans mon code, j’utilise aussi un template_tag d’ACF pour aller cherche la valeur du post_object « durée ».

Ensuite comme extrait, je choisis d’afficher l’extrait de Yoast plutôt que l’extrait classique. Celui de Yoast étant plus court, je trouve ca plus pratique.

echo get_post_meta(get_the_ID(), '_yoast_wpseo_metadesc', true);

La fonction update, rien de particulier

Puis la fonction form dans laquelle je construit le champ select. Je prends ici en compte les taxonomies dans mon foreach

<p>
<label for="<?php echo $this->get_field_id('tax_id'); ?>"><?php _e( 'Taxonomy Name:' )?></label>
<select id="<?php echo $this->get_field_id('tax_id'); ?>" name="<?php echo $this->get_field_name('tax_id'); ?>">
<?php
$custom_terms = get_terms('categories-formations');

foreach($custom_terms as $custom_term) {
$selected = ( $custom_term->term_id == esc_attr( $tax_id ) ) ? ' selected = "selected" ' : '';
$option = '<option '.$selected .'value="' . $custom_term->term_id;
$option = $option .'">';
$option = $option .$custom_term->name;
$option = $option .'</option>';
echo $option;
}
?>
</select>

</p>

Enfin la case à cocher pour l’affichage aléatoire

<p>
<label for="<?php echo $this->get_field_id('rand'); ?>"><?php _e( 'Show random posts' ); ?></label>
<?php $checked = ( $random ) ? ' checked=\"checked\" ' : ''; ?>
<input type="checkbox" id="<?php echo $this->get_field_id( 'rand' ); ?>" name="<?php echo $this->get_field_name( 'rand' ); ?>" value="true" <?php echo $checked; ?> />
</p>

Voilà, à vous ensuite de styliser le rendu de vos CPT !

N’hésitez pas, si vous avez des idées d’amélioration ou des corrections à apporter à ce tuto !