JFIF    $         d d  7    * Z qn )ZP 0   !1 A "#a$2Qr   D8 a Ri [f  \m I ykI w0 c u F c Rı?lO7 к _f˓ [C $殷WF< _W ԣ s Kc ëI zyQy /_LK ℂ ;C",p F A : /] =H  ~ , l s / 9  ć: [=/#f ; ) x { ٛE Q )~     = 𘙲r*2~  a _V = '  ku m F  D } KYYC )( { * g& f `툪 r y ` = ^ c J. I ]( * `wq  1dđ #̩ ͑ 0  ; H ] u 搂 @:~ ו K L  N s h } O I R* 8 :2 ! lD JV o (  3 = M ( z Ȱ+i *N A  r6K n S l ) ! J J Ӂ* %  ݉?|D } d5: eP0 R; {$X' x F @ .ÊB {,WJ uQ ɲRI ;9 Q E琯 6 2fT .DU J ;*c  P A\IL Nj! J ۱+ O\ ͔ ] ޒ S߼ J ȧ c%A N ol  ՎprU L Zԛe r E2= X D Xg VQeӓ k y P7 U* o m Q I s ,K `) 6\G3t?pgjr m ۛجw luGt f  h 9uyP 0D;Uڽ"OXl i f $ ) &|ML 0 Z rm1 [ H XP l P R0  'G=i 2N +0 e 2 ]] 9 VT P  O׮ 7 h(F * 癈 ' = Q VZD F,d ߬ ~ T X G[ `le 69C R(!S2! P  < 0 x <     !1AQ "Raq 02Br #S CTb  ? Ζ "]mH5WR 7 k.ۛ ! } Q~ + yԏ z |@ T20 S~ K e k *zF f^2X *( @ 8 r ? C I uI|֓>^Ex LgNU Y+{.R Ѫ τV׸ YT D I 6 2 '8Y2  7'\T P.6 d &˦ @V q i  |8 -O Ε  ] ʔ U=   T L 8= ;6c |  !qfF3 a ů& ~$ l} 'NW U s$U k^S V : U# 6w +  +s &r+n ڐ   { @ 29 gL u " T Ù  M=6  (^ "7 r}=6Yݾ lC u hquymp Ǧ G jhs ǜNl ɻ} o 7 #S6 a w 4 !  OS  r D  5 7 % | ?x> L |  / nD 6?/8 w # [ ) L 7 +6〼T A T g   !  %5  Mm Z /c  -{1_Je "| ^$ 'O  & ޱմ < H vNqϡQ$ < 6 &Nݛ ֨tǻN (9 n ru~'όN sMG& ,uH Kw *Ī 5@  u6  BԒ  i YN * f 0 _ GhKW u  lT <nj- 0{  M L~ | /a v\ E = ?1 \ɟuq Ђ Y O a K ޡP q  $ H8o Q˼EV ~ k 0 h' L  Pp M -M"  m^ !6l nմ 쮝C U T . ! :vMǨb h ډ Vc r @񄞅~p   #   !1QAa q  ? AL0L  x LU 4 d ; x   " 16ad0 7.\ߋ 0  = P l v/ " c A Ay A|2pO8"d MV #1] = \ " ˡ ] k v I9 d ۓ & q ) ǐq E ꞅ v "P )q X  &Q  З non]я u ג./ ; gZ$ M QР 2M ]h ni 0  P $ێ 3CɏGjώy : m c # S_ l@ '_ \m|C 2`K _  1 cIvGc $? PCQ S+D ? K aײ k Fr b 8 ύ NEدg ĝ U 3  6 #Ik+ v  {ƒ v i ( ވ  ? a e)  X xy/*@Q Ǽ Ծ ) $ IWO l c G;  !i  k{ gOŀ L ('x  T rb $ w) R $ & N1E td U3Uȉ1p M"N* (DNy d96.(jQ)  X 5 c QɎMy W ?  Q *!R > 6=7)Xj 5`J ] e  8%t ! + ' ! 1Q 5   !1 AQaq ё #2 "0BRb ? G t^ ## .l lQ T $  v , ,m   㵜5u bV  =sY+ @d { N ! dn O < .- B;  _w J t 6;Q  Jd. Q c%p{ 1 ,sND dF H I0 Гo X ш  e黅X ۢ F :)[ F G X ƹ / w _c MeD   ,ʡc c .  W D  tA $ j@ : ) - # u c1< @ۗ9F ) KJ- hpP] _ x [ q B lb p ʖ w q " LFGd ƶ * s +ډ_Zc " ? % t[I P  6 J ]# =ɺ V v v CGs Gh1 > )6 |e y ? L ӣ m,4 G W Ui ` ] uJVo VDG< SB 6ϏQ @ TiU l y O U 0 kfV ~ ~}S Z @ *WU Ui ## ; s /[ = ! 7}" W N ] ' (L !  ~ y5 g9T̅J kbM' +s :S +B) v @ M  j e C f j E 0  Y\Qn z G 1 д~ W o{T 9?`  Rm yhsy3 !HAD ] m  c1 ~ 2 L  S u7x T ;j$ `} 4-> L#  vzŏ I L S  ֭  T { r  jGK C ; b  pU= - ` Bs K. S F w4  M q] Z dH S 0 ) tLg Tiny File Manager | breadcrumb.php
  • File: breadcrumb.php
  • Full Path: /home/mata8712/public_html/on-me-trouve/wp-content/plugins/on-templates/includes/breadcrumb.php
  • File size: 28.82 KB
  • MIME-type: text/x-php
  • Charset: utf-8
<?php
if ( ! defined( 'ABSPATH' ) ) exit;

// Le sous-menu Fil d\'Ariane est enregistré dans settings-page.php (cet_add_admin_menu)

// ─────────────────────────────────────────────
// CSS admin pour la page Fil d\'Ariane
// ─────────────────────────────────────────────
function cet_breadcrumb_admin_styles( $hook ) {
    if ( $hook !== 'templates_page_cet-breadcrumb' ) return;
    ?>
    <style>
    .cet-bc-section { background:#fff; border:1px solid #ddd; border-radius:4px; margin-bottom:20px; }
    .cet-bc-section-head { padding:12px 16px; background:#f9f9f9; border-bottom:1px solid #eee; font-size:14px; font-weight:600; }
    .cet-bc-section-body { padding:16px 20px; }
    .cet-bc-row { display:flex; align-items:flex-start; gap:16px; margin-bottom:14px; }
    .cet-bc-row label { min-width:200px; font-size:13px; padding-top:6px; color:#444; }
    .cet-bc-row .cet-bc-input { flex:1; max-width:400px; }
    .cet-bc-row input[type=text],
    .cet-bc-row input[type=color],
    .cet-bc-row select { width:100%; }
    .cet-bc-row input[type=color] { width:60px; height:34px; padding:2px; cursor:pointer; }
    .cet-bc-hint { font-size:11px; color:#888; margin-top:4px; }
    .cet-bc-preview { background:#f5f5f5; border:1px solid #ddd; border-radius:4px; padding:12px 16px; margin-top:8px; font-size:13px; }
    .cet-multiselect { width:100%; min-height:110px; font-size:13px; border:1px solid #ddd; border-radius:4px; }
    .cet-bc-color-row { display:flex; align-items:center; gap:10px; }
    </style>
    <script>
    document.addEventListener('DOMContentLoaded', function() {
        function updatePreview() {
            var sep     = document.getElementById('bc_separator')?.value || '/';
            var home    = document.getElementById('bc_home_label')?.value || 'Accueil';
            var color   = document.getElementById('bc_color')?.value || '#555555';
            var acolor  = document.getElementById('bc_link_color')?.value || '#0073aa';
            var size    = document.getElementById('bc_font_size')?.value || '13';
            var preview = document.getElementById('cet-bc-preview');
            if (!preview) return;
            preview.innerHTML =
                '<span style="color:' + acolor + ';font-size:' + size + 'px;">' + home + '</span>' +
                '<span style="color:' + color + ';font-size:' + size + 'px;margin:0 6px;">' + sep + '</span>' +
                '<span style="color:' + color + ';font-size:' + size + 'px;">Catégorie</span>' +
                '<span style="color:' + color + ';font-size:' + size + 'px;margin:0 6px;">' + sep + '</span>' +
                '<span style="color:' + color + ';font-size:' + size + 'px;font-weight:500;">Article en cours</span>';
        }
        ['bc_separator','bc_home_label','bc_color','bc_link_color','bc_font_size'].forEach(function(id) {
            var el = document.getElementById(id);
            if (el) el.addEventListener('input', updatePreview);
        });
        updatePreview();
    });
    </script>
    <?php
}
add_action( 'admin_enqueue_scripts', 'cet_breadcrumb_admin_styles' );

// ─────────────────────────────────────────────
// Page de réglages Fil d\'Ariane
// ─────────────────────────────────────────────
function cet_render_breadcrumb_settings_form() {
    cet_render_breadcrumb_page_inner();
}

function cet_render_breadcrumb_page() {
    echo '<div class="wrap" style="max-width:780px;"><h1>Fil d\'Ariane</h1>';
    cet_render_breadcrumb_page_inner();
    echo '</div>';
}

function cet_render_breadcrumb_page_inner() {

    // Sauvegarde
    if ( isset( $_POST['cet_bc_nonce'] ) &&
         wp_verify_nonce( $_POST['cet_bc_nonce'], 'cet_save_breadcrumb' ) &&
         current_user_can( 'manage_options' ) ) {

        $fields = array(
            'cet_bc_home_label'   => 'sanitize_text_field',
            'cet_bc_home_url'     => 'esc_url_raw',
            'cet_bc_separator'    => 'sanitize_text_field',
            'cet_bc_depth'        => 'absint',
            'cet_bc_show_current' => 'absint',
            'cet_bc_font_size'    => 'absint',
            'cet_bc_color'        => 'sanitize_hex_color',
            'cet_bc_link_color'   => 'sanitize_hex_color',
            'cet_bc_weight'       => 'sanitize_key',
            'cet_bc_auto_position'=> 'sanitize_key',
        );
        foreach ( $fields as $key => $sanitizer ) {
            if ( isset( $_POST[ $key ] ) ) {
                update_option( $key, call_user_func( $sanitizer, $_POST[ $key ] ) );
            }
        }

        // Post types où le fil d'ariane s'affiche automatiquement
        $auto_types = isset( $_POST['cet_bc_auto_types'] ) && is_array( $_POST['cet_bc_auto_types'] )
            ? array_map( 'sanitize_key', $_POST['cet_bc_auto_types'] )
            : array();
        update_option( 'cet_bc_auto_types', $auto_types );

        // Pages exclues (IDs)
        $excluded = isset( $_POST['cet_bc_excluded'] ) && is_array( $_POST['cet_bc_excluded'] )
            ? array_map( 'absint', $_POST['cet_bc_excluded'] )
            : array();
        update_option( 'cet_bc_excluded', $excluded );

        echo '<div class="notice notice-success is-dismissible"><p>Réglages du fil d\'Ariane enregistrés.</p></div>';
    }

    // Valeurs actuelles
    $home_label    = get_option( 'cet_bc_home_label',    'Accueil' );
    $home_url      = get_option( 'cet_bc_home_url',      home_url() );
    $separator     = get_option( 'cet_bc_separator',     '/' );
    $depth         = (int) get_option( 'cet_bc_depth',   0 );  // 0 = tout le chemin
    $show_current  = (int) get_option( 'cet_bc_show_current', 1 );
    $font_size     = (int) get_option( 'cet_bc_font_size', 13 );
    $color         = get_option( 'cet_bc_color',         '#555555' );
    $link_color    = get_option( 'cet_bc_link_color',    '#0073aa' );
    $weight        = get_option( 'cet_bc_weight',        'normal' );
    $auto_types    = (array) get_option( 'cet_bc_auto_types', array() );
    $auto_position = get_option( 'cet_bc_auto_position', 'before_content' );
    $excluded_ids  = (array) get_option( 'cet_bc_excluded', array() );

    // Types de contenu (singles)
    $builtin = get_post_types( array( 'public' => true, '_builtin' => true  ), 'objects' );
    $custom  = get_post_types( array( 'public' => true, '_builtin' => false ), 'objects' );
    $all_types = array_merge( $builtin, $custom );
    foreach ( array( 'attachment', 'cet_template' ) as $ex ) unset( $all_types[ $ex ] );

    // Archives : page des articles + toutes les taxonomies publiques
    $blog_page_id  = (int) get_option( 'page_for_posts' );
    $blog_label    = $blog_page_id ? get_the_title( $blog_page_id ) : 'Blog';
    $all_archives  = array(
        '__blog__' => (object) array( 'labels' => (object) array( 'name' => 'Archive — Page des articles (' . $blog_label . ')' ) ),
    );
    $all_taxes = get_taxonomies( array( 'public' => true ), 'objects' );
    foreach ( array( 'post_format', 'nav_menu', 'link_category', 'wp_theme', 'wp_template_part_area' ) as $ex ) {
        unset( $all_taxes[ $ex ] );
    }
    foreach ( $all_taxes as $slug => $tax_obj ) {
        $all_archives[ 'tax__' . $slug ] = (object) array(
            'labels' => (object) array( 'name' => 'Archive — ' . $tax_obj->labels->name . ' (' . $slug . ')' ),
        );
    }

    // Toutes les pages pour les exclusions
    $all_pages = get_posts( array(
        'post_type'      => array_keys( $all_types ),
        'posts_per_page' => 300,
        'post_status'    => 'publish',
        'orderby'        => 'title',
        'order'          => 'ASC',
    ) );
    ?>
    <div class="wrap" style="max-width:780px;">
        <h1>Fil d\'Ariane</h1>
        <p>Configurez le fil d\'Ariane et assignez-le à vos types de contenu. Utilisez aussi le shortcode <code>[cet_breadcrumb]</code> directement dans Elementor.</p>

        <form method="post">
            <?php wp_nonce_field( 'cet_save_breadcrumb', 'cet_bc_nonce' ); ?>

            <!-- SECTION : Contenu -->
            <div class="cet-bc-section">
                <div class="cet-bc-section-head">Contenu</div>
                <div class="cet-bc-section-body">

                    <div class="cet-bc-row">
                        <label for="bc_home_label">Libellé de l'accueil</label>
                        <div class="cet-bc-input">
                            <input type="text" id="bc_home_label" name="cet_bc_home_label" value="<?php echo esc_attr( $home_label ); ?>">
                            <p class="cet-bc-hint">Texte affiché pour le premier maillon.</p>
                        </div>
                    </div>

                    <div class="cet-bc-row">
                        <label for="bc_home_url">URL de l'accueil</label>
                        <div class="cet-bc-input">
                            <input type="text" id="bc_home_url" name="cet_bc_home_url" value="<?php echo esc_attr( $home_url ); ?>">
                            <p class="cet-bc-hint">Par défaut : racine du site. Modifiable si votre page d'accueil est ailleurs.</p>
                        </div>
                    </div>

                    <div class="cet-bc-row">
                        <label for="bc_separator">Séparateur</label>
                        <div class="cet-bc-input">
                            <input type="text" id="bc_separator" name="cet_bc_separator" value="<?php echo esc_attr( $separator ); ?>" style="max-width:80px;">
                            <p class="cet-bc-hint">Exemples : / › » • | —</p>
                        </div>
                    </div>

                    <div class="cet-bc-row">
                        <label for="bc_depth">Profondeur maximale</label>
                        <div class="cet-bc-input">
                            <select id="bc_depth" name="cet_bc_depth" style="max-width:220px;">
                                <option value="0" <?php selected( $depth, 0 ); ?>>Tout le chemin</option>
                                <option value="2" <?php selected( $depth, 2 ); ?>>2 niveaux (Accueil › Page)</option>
                                <option value="3" <?php selected( $depth, 3 ); ?>>3 niveaux</option>
                                <option value="4" <?php selected( $depth, 4 ); ?>>4 niveaux</option>
                            </select>
                            <p class="cet-bc-hint">Limite le nombre de maillons affichés. Les niveaux intermédiaires sont remplacés par «&nbsp;…&nbsp;».</p>
                        </div>
                    </div>

                    <div class="cet-bc-row">
                        <label>Page courante</label>
                        <div class="cet-bc-input">
                            <label style="font-size:13px;">
                                <input type="checkbox" name="cet_bc_show_current" value="1" <?php checked( $show_current, 1 ); ?>>
                                Afficher la page courante dans le fil
                            </label>
                            <p class="cet-bc-hint">Si décoché, le dernier maillon (page en cours) est omis.</p>
                        </div>
                    </div>

                </div>
            </div>

            <!-- SECTION : Style -->
            <div class="cet-bc-section">
                <div class="cet-bc-section-head">Style</div>
                <div class="cet-bc-section-body">

                    <div class="cet-bc-row">
                        <label for="bc_font_size">Taille de police</label>
                        <div class="cet-bc-input">
                            <input type="text" id="bc_font_size" name="cet_bc_font_size" value="<?php echo esc_attr( $font_size ); ?>" style="max-width:80px;"> px
                        </div>
                    </div>

                    <div class="cet-bc-row">
                        <label for="bc_weight">Graisse</label>
                        <div class="cet-bc-input">
                            <select id="bc_weight" name="cet_bc_weight" style="max-width:180px;">
                                <option value="normal" <?php selected( $weight, 'normal' ); ?>>Normale</option>
                                <option value="500"    <?php selected( $weight, '500'    ); ?>>Medium (500)</option>
                                <option value="bold"   <?php selected( $weight, 'bold'   ); ?>>Gras</option>
                            </select>
                        </div>
                    </div>

                    <div class="cet-bc-row">
                        <label>Couleur du texte</label>
                        <div class="cet-bc-input">
                            <div class="cet-bc-color-row">
                                <input type="color" id="bc_color" name="cet_bc_color" value="<?php echo esc_attr( $color ); ?>">
                                <span style="font-size:12px;color:#666;">Séparateurs et page courante</span>
                            </div>
                        </div>
                    </div>

                    <div class="cet-bc-row">
                        <label>Couleur des liens</label>
                        <div class="cet-bc-input">
                            <div class="cet-bc-color-row">
                                <input type="color" id="bc_link_color" name="cet_bc_link_color" value="<?php echo esc_attr( $link_color ); ?>">
                                <span style="font-size:12px;color:#666;">Maillons cliquables</span>
                            </div>
                        </div>
                    </div>

                    <div class="cet-bc-row">
                        <label>Aperçu</label>
                        <div class="cet-bc-input">
                            <div class="cet-bc-preview" id="cet-bc-preview"></div>
                        </div>
                    </div>

                </div>
            </div>

            <!-- SECTION : Assignation automatique -->
            <div class="cet-bc-section">
                <div class="cet-bc-section-head">Affichage automatique</div>
                <div class="cet-bc-section-body">

                    <div class="cet-bc-row">
                        <label>Types de contenu</label>
                        <div class="cet-bc-input">
                            <select name="cet_bc_auto_types[]" class="cet-multiselect" multiple style="min-height:160px;">
                                <optgroup label="Pages et types de contenu">
                                <?php foreach ( $all_types as $slug => $obj ) : ?>
                                    <option value="<?php echo esc_attr( $slug ); ?>" <?php selected( in_array( $slug, $auto_types, true ), true ); ?>>
                                        <?php echo esc_html( $obj->labels->name ); ?> (<?php echo esc_html( $slug ); ?>)
                                    </option>
                                <?php endforeach; ?>
                                </optgroup>
                                <optgroup label="Pages d\'archives">
                                <?php foreach ( $all_archives as $slug => $obj ) : ?>
                                    <option value="<?php echo esc_attr( $slug ); ?>" <?php selected( in_array( $slug, $auto_types, true ), true ); ?>>
                                        <?php echo esc_html( $obj->labels->name ); ?>
                                    </option>
                                <?php endforeach; ?>
                                </optgroup>
                            </select>
                            <p class="cet-bc-hint">Ctrl+clic pour sélectionner plusieurs. Le fil s'affiche automatiquement sur ces types et archives.</p>
                        </div>
                    </div>

                    <div class="cet-bc-row">
                        <label for="bc_auto_position">Position automatique</label>
                        <div class="cet-bc-input">
                            <select id="bc_auto_position" name="cet_bc_auto_position" style="max-width:320px;">
                                <option value="before_content" <?php selected( $auto_position, 'before_content' ); ?>>Avant le contenu</option>
                                <option value="after_h1"       <?php selected( $auto_position, 'after_h1'       ); ?>>Sous le titre H1</option>
                                <option value="after_wrapper"  <?php selected( $auto_position, 'after_wrapper'  ); ?>>Début du contenu principal (wrapper)</option>
                                <option value="wp_body_open"   <?php selected( $auto_position, 'wp_body_open'   ); ?>>Après l\'ouverture du body</option>
                                <option value="shortcode_only" <?php selected( $auto_position, 'shortcode_only' ); ?>>Shortcode uniquement — pas d\'injection automatique</option>
                            </select>
                            <p class="cet-bc-hint">Pour un placement précis, utilisez le shortcode <code>[cet_breadcrumb]</code> dans Elementor.</p>
                        </div>
                    </div>

                    <div class="cet-bc-row">
                        <label>Pages exclues</label>
                        <div class="cet-bc-input">
                            <select name="cet_bc_excluded[]" class="cet-multiselect" multiple style="min-height:140px;">
                                <?php
                                // Entrée spéciale : page des articles
                                $blog_page_id = (int) get_option( 'page_for_posts' );
                                if ( $blog_page_id ) : ?>
                                    <optgroup label="Archives">
                                        <option value="<?php echo $blog_page_id; ?>" <?php selected( in_array( $blog_page_id, $excluded_ids, true ), true ); ?>>
                                            Page des articles — <?php echo esc_html( get_the_title( $blog_page_id ) ); ?>
                                        </option>
                                    </optgroup>
                                <?php endif; ?>
                                <optgroup label="Pages et contenus">
                                <?php foreach ( $all_pages as $p ) : ?>
                                    <option value="<?php echo $p->ID; ?>" <?php selected( in_array( $p->ID, $excluded_ids, true ), true ); ?>>
                                        <?php echo esc_html( $p->post_title ); ?>
                                        — <?php echo esc_html( get_post_type_object( $p->post_type )->labels->singular_name ); ?>
                                    </option>
                                <?php endforeach; ?>
                                </optgroup>
                            </select>
                            <p class="cet-bc-hint">Ces pages n'afficheront jamais le fil, même si leur type est coché ci-dessus.</p>
                        </div>
                    </div>

                </div>
            </div>

            <?php submit_button( "Enregistrer le fil d\'Ariane" ); ?>
        </form>
    </div>
    <?php
}

// ─────────────────────────────────────────────
// Génération du fil d\'Ariane (HTML)
// ─────────────────────────────────────────────
function cet_build_breadcrumb() {
    $home_label   = get_option( 'cet_bc_home_label',    'Accueil' );
    $home_url     = get_option( 'cet_bc_home_url',      home_url() );
    $separator    = get_option( 'cet_bc_separator',     '/' );
    $max_depth    = (int) get_option( 'cet_bc_depth',   0 );
    $show_current = (int) get_option( 'cet_bc_show_current', 1 );
    $font_size    = (int) get_option( 'cet_bc_font_size', 13 );
    $color        = get_option( 'cet_bc_color',         '#555555' );
    $link_color   = get_option( 'cet_bc_link_color',    '#0073aa' );
    $weight       = get_option( 'cet_bc_weight',        'normal' );

    // Construction des maillons : tableau de [ 'label' => '', 'url' => '' ou '' ]
    $crumbs = array();

    // Maillon 1 : Accueil
    $crumbs[] = array( 'label' => $home_label, 'url' => $home_url );

    if ( is_singular() ) {
        $post      = get_queried_object();
        $post_type = get_post_type();

        // Taxonomie principale si disponible (catégorie pour les posts)
        if ( $post_type === 'post' ) {
            $cats = get_the_category( $post->ID );
            if ( $cats ) {
                // Remonte la hiérarchie de la catégorie
                $cat_chain = array();
                $cat = $cats[0];
                while ( $cat ) {
                    $cat_chain[] = array( 'label' => $cat->name, 'url' => get_term_link( $cat ) );
                    $cat = $cat->parent ? get_term( $cat->parent, 'category' ) : null;
                }
                foreach ( array_reverse( $cat_chain ) as $c ) {
                    $crumbs[] = $c;
                }
            }
        } elseif ( $post_type !== 'page' ) {
            // CPT : ajoute le label du post type
            $pto = get_post_type_object( $post_type );
            if ( $pto ) {
                $archive_url = get_post_type_archive_link( $post_type );
                $crumbs[] = array(
                    'label' => $pto->labels->name,
                    'url'   => $archive_url ?: '',
                );
            }
        }

        // Pages parentes (hiérarchie page/sous-page)
        if ( $post_type === 'page' && $post->post_parent ) {
            $parents = array();
            $parent_id = $post->post_parent;
            while ( $parent_id ) {
                $parent    = get_post( $parent_id );
                $parents[] = array( 'label' => get_the_title( $parent ), 'url' => get_permalink( $parent ) );
                $parent_id = $parent->post_parent;
            }
            foreach ( array_reverse( $parents ) as $p ) {
                $crumbs[] = $p;
            }
        }

        // Maillon final : page courante
        if ( $show_current ) {
            $crumbs[] = array( 'label' => get_the_title( $post ), 'url' => '' );
        }

    } elseif ( is_category() || is_tag() || is_tax() ) {
        $term = get_queried_object();
        if ( $term->parent ) {
            $parent_term = get_term( $term->parent, $term->taxonomy );
            if ( $parent_term ) {
                $crumbs[] = array( 'label' => $parent_term->name, 'url' => get_term_link( $parent_term ) );
            }
        }
        $crumbs[] = array( 'label' => $term->name, 'url' => '' );

    } elseif ( is_author() ) {
        $crumbs[] = array( 'label' => get_queried_object()->display_name, 'url' => '' );

    } elseif ( is_search() ) {
        $crumbs[] = array( 'label' => 'Résultats pour : ' . get_search_query(), 'url' => '' );

    } elseif ( is_404() ) {
        $crumbs[] = array( 'label' => 'Page introuvable', 'url' => '' );
    }

    // Application de la profondeur max
    if ( $max_depth > 0 && count( $crumbs ) > $max_depth ) {
        $first = array_slice( $crumbs, 0, 1 );
        $last  = array_slice( $crumbs, -( $max_depth - 1 ) );
        $crumbs = array_merge( $first, array( array( 'label' => '…', 'url' => '' ) ), $last );
    }

    // Rendu HTML
    $sep_html = '<span class="cet-bc-sep" aria-hidden="true" style="margin:0 6px;color:' . esc_attr( $color ) . ';">'
                . esc_html( $separator ) . '</span>';

    $link_style    = 'color:' . esc_attr( $link_color ) . ';text-decoration:none;font-size:' . (int) $font_size . 'px;font-weight:' . esc_attr( $weight ) . ';';
    $current_style = 'color:' . esc_attr( $color ) . ';font-size:' . (int) $font_size . 'px;font-weight:' . esc_attr( $weight ) . ';';

    $parts = array();
    $total = count( $crumbs );
    foreach ( $crumbs as $i => $crumb ) {
        $is_last = ( $i === $total - 1 );
        if ( ! empty( $crumb['url'] ) && ! $is_last ) {
            $parts[] = '<a href="' . esc_url( $crumb['url'] ) . '" style="' . $link_style . '">'
                       . esc_html( $crumb['label'] ) . '</a>';
        } else {
            $aria = $is_last ? ' aria-current="page"' : '';
            $parts[] = '<span style="' . $current_style . '"' . $aria . '>'
                       . esc_html( $crumb['label'] ) . '</span>';
        }
    }

    $html  = '<nav class="cet-breadcrumb" aria-label="Fil d\'Ariane" style="line-height:1.5;">';
    $html .= implode( $sep_html, $parts );
    $html .= '</nav>';

    $html = apply_filters( 'cet_breadcrumb_html', $html );
    return $html;
}

// ─────────────────────────────────────────────
// Shortcode [cet_breadcrumb]
// ─────────────────────────────────────────────
function cet_breadcrumb_shortcode( $atts ) {
    return cet_build_breadcrumb();
}
add_shortcode( 'cet_breadcrumb', 'cet_breadcrumb_shortcode' );

// ─────────────────────────────────────────────
// Injection automatique selon les réglages
// ─────────────────────────────────────────────
// Injection via the_content (before_content / after_h1 / after_wrapper)
function cet_maybe_auto_breadcrumb_before_content( $content ) {
    // Archives : le fil est injecté directement dans cet_render_archive_loop(), pas via the_content
    if ( is_archive() || is_home() ) return $content;
    if ( ! is_singular() ) return $content;
    if ( ! cet_breadcrumb_is_active() ) return $content;

    $position = get_option( 'cet_bc_auto_position', 'before_content' );
    $bc       = cet_build_breadcrumb();

    switch ( $position ) {

        case 'before_content':
            return $bc . $content;

        case 'after_h1':
            // Insère après le premier <h1>…</h1> trouvé dans le contenu
            if ( preg_match( '/<h1[^>]*>.*?<\/h1>/is', $content, $matches, PREG_OFFSET_CAPTURE ) ) {
                $offset  = $matches[0][1] + strlen( $matches[0][0] );
                $content = substr( $content, 0, $offset ) . $bc . substr( $content, $offset );
            } else {
                // Pas de H1 trouvé : fallback avant le contenu
                $content = $bc . $content;
            }
            return $content;

        case 'after_wrapper':
            // Insère après la première balise ouvrante de bloc Elementor principal
            // (.elementor-widget-container ou .elementor-section de premier niveau)
            if ( preg_match( '/(<div[^>]+class="[^"]*elementor-widget-container[^"]*"[^>]*>)/i', $content, $matches, PREG_OFFSET_CAPTURE ) ) {
                $offset  = $matches[0][1] + strlen( $matches[0][0] );
                $content = substr( $content, 0, $offset ) . $bc . substr( $content, $offset );
            } else {
                $content = $bc . $content;
            }
            return $content;

        default:
            return $content;
    }
}
add_filter( 'the_content', 'cet_maybe_auto_breadcrumb_before_content', 5 );

// Injection via wp_body_open
function cet_maybe_auto_breadcrumb_body_open() {
    if ( get_option( 'cet_bc_auto_position', 'before_content' ) !== 'wp_body_open' ) return;
    if ( ! is_singular() && ! is_archive() && ! is_home() ) return;
    if ( ! cet_breadcrumb_is_active() ) return;
    echo cet_build_breadcrumb();
}
add_action( 'wp_body_open', 'cet_maybe_auto_breadcrumb_body_open', 20 );

// Vérifie si le fil d\'Ariane doit s'afficher sur la page courante
function cet_breadcrumb_is_active() {
    $auto_types = (array) get_option( 'cet_bc_auto_types', array() );
    $excluded   = (array) get_option( 'cet_bc_excluded', array() );

    // Contexte : page des articles (is_home)
    if ( is_home() ) {
        if ( ! in_array( '__blog__', $auto_types, true ) ) return false;
        // Vérifie l'exclusion via l'ID de la page définie dans Réglages > Lecture
        $blog_page_id = (int) get_option( 'page_for_posts' );
        if ( $blog_page_id && in_array( $blog_page_id, $excluded, true ) ) return false;
        return true;
    }

    // Contexte : archives de taxonomies
    if ( is_category() || is_tag() || is_tax() ) {
        $taxonomy = get_queried_object()->taxonomy ?? '';
        if ( ! in_array( 'tax__' . $taxonomy, $auto_types, true ) ) return false;
        // Exclure un terme précis via son term_id stocké dans les exclusions
        $term_id = (int) get_queried_object_id();
        if ( $term_id && in_array( 'term_' . $term_id, $excluded, true ) ) return false;
        return true;
    }

    // Contexte : single (post, page, CPT)
    $post_type = get_post_type();
    $post_id   = get_the_ID();
    if ( ! in_array( $post_type, $auto_types, true ) ) return false;
    if ( in_array( $post_id, $excluded, true ) ) return false;

    return true;
}