Files
elementor-category-grid-widget/widgets/category-grid-widget.php
2025-05-23 10:56:26 +00:00

328 lines
12 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
if (!defined('ABSPATH')) {
exit; // Empêche l'accès direct.
}
/**
* Classe Elementor_Category_Grid_Widget.
*
* Widget Elementor personnalisé qui affiche une grille de catégories d'articles.
* Chaque catégorie est affichée sous forme de carte avec son nom, son image et un lien vers son archive.
*/
class Elementor_Category_Grid_Widget extends \Elementor\Widget_Base
{
/**
* Identifiant unique du widget.
*
* @return string Slug du widget.
*/
public function get_name(): string
{
return 'category-grid';
}
/**
* Titre du widget affiché dans l'interface Elementor.
*
* @return string Titre du widget.
*/
public function get_title(): string
{
return esc_html__('Grille de Catégories', 'category-grid-widget');
}
/**
* Icône du widget (bibliothèque d'icônes Elementor).
*
* @return string Classe de l'icône du widget.
*/
public function get_icon(): string
{
return 'eicon-posts-grid';
}
/**
* Catégories Elementor dans lesquelles le widget apparaîtra.
*
* @return array Catégories du panneau Elementor.
*/
public function get_categories(): array
{
return ['general'];
}
/**
* Mots-clés facilitant la recherche du widget.
*
* @return array Mots-clés du widget.
*/
public function get_keywords(): array
{
return ['category', 'catégorie', 'grid', 'grille'];
}
/**
* Enregistrer les contrôles du widget (champs configurables dans Elementor).
*/
protected function register_controls(): void
{
/* Section "Contenu" pour le choix des catégories et options de requête */
$this->start_controls_section(
'section_content',
[
'label' => esc_html__('Catégories', 'category-grid-widget'),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
// Contrôle : Sélection des catégories à afficher (multisélection).
$options = [];
$categories = get_categories(['hide_empty' => false]);
foreach ($categories as $cat) {
$options[$cat->term_id] = $cat->name;
}
$this->add_control(
'categories',
[
'label' => esc_html__('Catégories à afficher', 'category-grid-widget'),
'type' => \Elementor\Controls_Manager::SELECT2,
'multiple' => true,
'label_block' => true,
'options' => $options,
'description' => esc_html__('Sélectionnez les catégories darticles à afficher.', 'category-grid-widget'),
]
);
// Contrôle : Inclure les sous-catégories.
$this->add_control(
'show_subcategories',
[
'label' => esc_html__('Afficher les sous-catégories', 'category-grid-widget'),
'type' => \Elementor\Controls_Manager::SWITCHER,
'label_on' => esc_html__('Oui', 'category-grid-widget'),
'label_off' => esc_html__('Non', 'category-grid-widget'),
'return_value' => 'yes',
'default' => 'yes',
'description' => esc_html__('Inclure aussi les sous-catégories des catégories sélectionnées.', 'category-grid-widget'),
]
);
// ----------------------------------------------------------------------
// Contrôle : Ne montrer que les catégories avec image
$this->add_control(
'hide_without_image',
[
'label' => esc_html__('Afficher uniquement catégories avec image', 'category-grid-widget'),
'type' => \Elementor\Controls_Manager::SWITCHER,
'label_on' => esc_html__('Oui', 'category-grid-widget'),
'label_off' => esc_html__('Non', 'category-grid-widget'),
'return_value' => 'yes',
'default' => 'no',
'description' => esc_html__('Si activé, les catégories sans image seront masquées.', 'category-grid-widget'),
]
);
// Contrôle : Trier par (critère de tri des catégories).
$this->add_control(
'order_by',
[
'label' => esc_html__('Trier par', 'category-grid-widget'),
'type' => \Elementor\Controls_Manager::SELECT,
'options' => [
'name' => esc_html__('Nom (alphabétique)', 'category-grid-widget'),
'count' => esc_html__('Nombre darticles', 'category-grid-widget'),
'id' => esc_html__('ID (date de création)', 'category-grid-widget'),
],
'default' => 'name',
]
);
// Contrôle : Ordre croissant/décroissant.
$this->add_control(
'order',
[
'label' => esc_html__('Ordre', 'category-grid-widget'),
'type' => \Elementor\Controls_Manager::SELECT,
'options' => [
'ASC' => esc_html__('Croissant (A-Z / 0-9)', 'category-grid-widget'),
'DESC' => esc_html__('Décroissant (Z-A / 9-0)', 'category-grid-widget'),
],
'default' => 'ASC',
]
);
$this->end_controls_section();
/* Section "Mise en page" pour les options d'affichage (colonnes, taille d'image) */
$this->start_controls_section(
'section_layout',
[
'label' => esc_html__('Mise en page', 'category-grid-widget'),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
// Contrôle : Nombre de colonnes de la grille.
$this->add_control(
'columns',
[
'label' => esc_html__('Nombre de colonnes', 'category-grid-widget'),
'type' => \Elementor\Controls_Manager::SELECT,
'options' => [
1 => '1',
2 => '2',
3 => '3',
4 => '4',
5 => '5',
6 => '6',
],
'default' => 3,
]
);
// Contrôle : Taille des images affichées.
$this->add_control(
'image_size',
[
'label' => esc_html__('Taille des images', 'category-grid-widget'),
'type' => \Elementor\Controls_Manager::SELECT,
'options' => [
'thumbnail' => esc_html__('Miniature (thumbnail)', 'category-grid-widget'),
'medium' => esc_html__('Moyen (medium)', 'category-grid-widget'),
'large' => esc_html__('Grand (large)', 'category-grid-widget'),
'full' => esc_html__('Plein (full)', 'category-grid-widget'),
],
'default' => 'medium',
]
);
$this->end_controls_section();
}
/**
* Générer l'affichage du widget côté front-end.
*/
protected function render(): void
{
$settings = $this->get_settings_for_display();
// Récupérer les ID des catégories sélectionnées.
$selected_ids = [];
if (!empty($settings['categories'])) {
// S'assurer d'avoir un tableau d'ID (entiers).
$selected_ids = is_array($settings['categories']) ? $settings['categories'] : [$settings['categories']];
$selected_ids = array_map('intval', $selected_ids);
}
if (empty($selected_ids)) {
// Aucune catégorie sélectionnée : ne rien afficher.
return;
}
// Déterminer les catégories à afficher (inclure les sous-catégories si demandé).
$category_ids_to_show = $selected_ids;
if (!empty($settings['show_subcategories']) && $settings['show_subcategories'] === 'yes') {
// Ajouter les sous-catégories de chaque catégorie sélectionnée.
foreach ($selected_ids as $cat_id) {
$child_ids = get_term_children($cat_id, 'category');
if (is_array($child_ids) && !empty($child_ids)) {
$category_ids_to_show = array_merge($category_ids_to_show, $child_ids);
}
}
// Éliminer les doublons d'ID au cas où.
$category_ids_to_show = array_unique($category_ids_to_show);
}
// Préparer les args pour get_terms() on ne précise PAS le tri si c'est par count
$term_args = [
'taxonomy' => 'category',
'include' => $category_ids_to_show,
'hide_empty' => false,
];
if ('count' !== $settings['order_by']) {
// tri natif pour 'name' ou 'id'
$term_args['orderby'] = $settings['order_by'];
$term_args['order'] = $settings['order'];
}
// Récupérer les termes
$raw_terms = get_terms($term_args);
if (is_wp_error($raw_terms) || empty($raw_terms)) {
return;
}
// Filtrer les termes sans image si demandé
$terms = [];
foreach ($raw_terms as $term) {
$thumb_id = get_term_meta($term->term_id, 'thumbnail_id', true);
$image_url = $thumb_id
? wp_get_attachment_image_url($thumb_id, $settings['image_size'])
: '';
if ('yes' === $settings['hide_without_image'] && empty($image_url)) {
continue;
}
// Stocker image_url temporaire pour éviter de recalculer
$term->_image_url = $image_url;
$terms[] = $term;
}
// Si tri par nombre d'articles, calculer et trier manuellement
if ('count' === $settings['order_by']) {
// Calcul du total d'articles (directs + descendants) pour chaque terme
$counts = [];
foreach ($terms as $term) {
$total = (int) $term->count;
$desc_ids = get_term_children($term->term_id, 'category');
if (is_array($desc_ids)) {
foreach ($desc_ids as $desc_id) {
$desc = get_term($desc_id, 'category');
if (!is_wp_error($desc)) {
$total += (int) $desc->count;
}
}
}
$counts[$term->term_id] = $total;
}
// Tri selon lordre choisi
usort($terms, function ($a, $b) use ($counts, $settings) {
$ca = $counts[$a->term_id];
$cb = $counts[$b->term_id];
if ($ca === $cb) {
return 0;
}
if ('ASC' === $settings['order']) {
return ($ca < $cb) ? -1 : 1;
}
return ($ca > $cb) ? -1 : 1;
});
}
// Calcul de la classe grille
$columns = (int) $settings['columns'];
$grid_class = 'columns-' . $columns;
// Rendu HTML
echo '<div class="elementor-category-grid ' . esc_attr($grid_class) . '">';
foreach ($terms as $term) {
$name = esc_html($term->name);
$link = esc_url(get_term_link($term));
$image_url = esc_url($term->_image_url);
echo '<div class="category-card">';
echo "<a href=\"{$link}\">";
if ($image_url) {
echo '<div class="category-card-image">';
echo '<img src="' . $image_url . '" alt="' . $name . '">';
echo '</div>';
}
echo '<div class="category-card-name">' . $name . '</div>';
echo '</a>';
echo '</div>';
}
echo '</div>';
}
}