From 20f9c310080baa8b01baadce54b350d3d2c642e2 Mon Sep 17 00:00:00 2001 From: MrRaph_ Date: Fri, 23 May 2025 09:54:50 +0000 Subject: [PATCH] feat: first working version --- admin/js/category-image.js | 32 ++++ elementor-category-grid-widget.php | 164 +++++++++++++++++ widgets/category-grid-widget.php | 272 +++++++++++++++++++++++++++++ 3 files changed, 468 insertions(+) create mode 100644 admin/js/category-image.js create mode 100644 elementor-category-grid-widget.php create mode 100644 widgets/category-grid-widget.php diff --git a/admin/js/category-image.js b/admin/js/category-image.js new file mode 100644 index 0000000..044bb8b --- /dev/null +++ b/admin/js/category-image.js @@ -0,0 +1,32 @@ +jQuery( document ).ready( function( $ ) { + var frame; + // Quand on clique sur "Choisir une image" + $( '.ccgw-upload-image' ).on( 'click', function( e ) { + e.preventDefault(); + // Si le frame existe déjà, on l’ouvre + if ( frame ) { + frame.open(); + return; + } + // Créer le frame + frame = wp.media({ + title: ccgw_data.title || 'Choisir une image de catégorie', + button: { text: ccgw_data.button || 'Sélectionner' }, + multiple: false + }); + // Quand on sélectionne une image + frame.on( 'select', function() { + var attachment = frame.state().get('selection').first().toJSON(); + $( '#category-image-id' ).val( attachment.id ); + $( '#category-image-wrapper' ).html( '' ); + }); + frame.open(); + }); + + // Quand on clique sur "Supprimer l’image" + $( '.ccgw-remove-image' ).on( 'click', function( e ) { + e.preventDefault(); + $( '#category-image-id' ).val(''); + $( '#category-image-wrapper' ).html(''); + }); +}); diff --git a/elementor-category-grid-widget.php b/elementor-category-grid-widget.php new file mode 100644 index 0000000..d27414b --- /dev/null +++ b/elementor-category-grid-widget.php @@ -0,0 +1,164 @@ + esc_js( __( 'Sélectionner une image de catégorie', 'category-grid-widget' ) ), +// 'button' => esc_js( __( 'Sélectionner', 'category-grid-widget' ) ), +// ] +// ); +// } +// add_action( 'admin_enqueue_scripts', 'ccgw_enqueue_media_uploader' ); +/** + * Charger les scripts Media Uploader et localiser les données JS + * sur les écrans d'ajout ET d'édition de catégorie. + */ +function ccgw_enqueue_media_uploader( $hook_suffix ) { + // On ne charge que sur edit-tags.php (création) OU term.php (édition) + if ( ! in_array( $hook_suffix, [ 'edit-tags.php', 'term.php' ], true ) ) { + return; + } + // Et seulement pour la taxonomie 'category' + if ( empty( $_GET['taxonomy'] ) || 'category' !== $_GET['taxonomy'] ) { + return; + } + + // Charge la librairie media de WP + wp_enqueue_media(); + + // Ton script JS + wp_enqueue_script( + 'ccgw-category-image', + plugin_dir_url( __FILE__ ) . 'admin/js/category-image.js', + [ 'jquery' ], + '1.0', + true + ); + + // Variable JS + wp_localize_script( + 'ccgw-category-image', + 'ccgw_data', + [ + 'title' => esc_js( __( 'Sélectionner une image de catégorie', 'category-grid-widget' ) ), + 'button' => esc_js( __( 'Sélectionner', 'category-grid-widget' ) ), + ] + ); +} +add_action( 'admin_enqueue_scripts', 'ccgw_enqueue_media_uploader' ); + + +/** + * Affiche le champ d'upload dans le formulaire de création de catégorie. + */ +function ccgw_category_image_field( $taxonomy ) { ?> +
+ + +
+

+ + +

+
+term_id, 'thumbnail_id', true ); + $image_url = $image_id ? wp_get_attachment_thumb_url( $image_id ) : ''; + ?> + + + + + + +
+ + + +
+

+ + +

+ + +register( new \Elementor_Category_Grid_Widget() ); +} +add_action( 'elementor/widgets/register', 'register_category_grid_widget' ); diff --git a/widgets/category-grid-widget.php b/widgets/category-grid-widget.php new file mode 100644 index 0000000..a3b1e68 --- /dev/null +++ b/widgets/category-grid-widget.php @@ -0,0 +1,272 @@ +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 d’articles à 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 : 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 d’articles', '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 arguments de requête pour récupérer les termes. + $term_args = [ + 'taxonomy' => 'category', + 'include' => $category_ids_to_show, + 'hide_empty' => false, + ]; + // Appliquer les options de tri. + if ( ! empty( $settings['order_by'] ) ) { + $term_args['orderby'] = $settings['order_by']; + } + if ( ! empty( $settings['order'] ) ) { + $term_args['order'] = $settings['order']; + } + + // Obtenir les termes de catégories à afficher. + $categories = get_terms( $term_args ); + if ( is_wp_error( $categories ) || empty( $categories ) ) { + return; + } + + // Calculer la classe CSS pour le nombre de colonnes (pour usage dans le CSS). + $columns = ! empty( $settings['columns'] ) ? (int) $settings['columns'] : 3; + $grid_class = 'columns-' . $columns; + + // Début du markup HTML de la grille. + echo '
'; + foreach ( $categories as $term ) { + $term_name = $term->name; + $term_link = get_term_link( $term ); + if ( is_wp_error( $term_link ) ) { + continue; // Ignorer si le lien d'archive pose un problème. + } + // Récupérer l'image de la catégorie via sa méta 'thumbnail_id' (image mise en avant de la catégorie). + $image_url = ''; + $thumbnail_id = get_term_meta( $term->term_id, 'thumbnail_id', true ); + if ( $thumbnail_id ) { + $size = ! empty( $settings['image_size'] ) ? $settings['image_size'] : 'medium'; + $image_url = wp_get_attachment_image_url( $thumbnail_id, $size ); + } + + echo ''; // .category-card + } + echo '
'; // .elementor-category-grid + + // Astuce : ajouter du CSS (feuille de style ou balise