<?php
/**
* Functions du thème enfant Twenty Twenty-Five
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
============================================================================
1) Charger les styles du thème parent + enfant
============================================================================
function dp_child_enqueue_styles() {
$parent_style = 'twentytwentyfive-style';
Style du parent
wp_enqueue_style(
$parent_style,
get_template_directory_uri() . '/style.css'
);
// Style du thème enfant
wp_enqueue_style(
'twentytwentyfive-child-style',
get_stylesheet_directory_uri() . '/style.css',
array( $parent_style ),
time() // version dynamique pour casser les caches
);
}
add_action( 'wp_enqueue_scripts', 'dp_child_enqueue_styles' );
============================================================================
2) Création des rôles personnalisés : Visiteur et Animateur
============================================================================
function dp_creer_roles_personnalises() {
— Rôle VISITEUR —
if ( ! get_role( 'visiteur' ) ) {
add_role(
'visiteur',
'Visiteur',
array(
'read' => true,
'edit_posts' => false,
'edit_pages' => false,
'publish_posts' => false,
'upload_files' => false,
'delete_posts' => false,
'moderate_comments' => false,
)
);
}
// --- Rôle ANIMATEUR ---
if ( ! get_role( 'animateur' ) ) {
add_role(
'animateur',
'Animateur',
array(
'read' => true,
'edit_posts' => true,
'edit_published_posts' => true,
'delete_posts' => true,
'delete_published_posts' => true,
'publish_posts' => true,
'edit_pages' => true,
'edit_published_pages' => true,
'publish_pages' => true,
'delete_pages' => true,
'delete_published_pages' => true,
'upload_files' => true,
)
);
}
}
add_action( 'init', 'dp_creer_roles_personnalises' );
============================================================================
3) Shortcode [page_discussion] : zone de discussion liée à la page
============================================================================
function dp_page_discussion_shortcode( $atts ) {
if ( ! is_singular() ) {
return ;
}
$post_id = get_the_ID();
if ( ! comments_open( $post_id ) ) {
return '<p>La discussion n’est pas ouverte pour cette page.</p>';
}
ob_start();
?>
<h2 class="dp-discussion-titre">Discussion</h2>
<div class="dp-discussion-liste">
<?php
$comments = get_comments( array(
'post_id' => $post_id,
'status' => 'approve',
'order' => 'ASC',
) );
if ( ! empty( $comments ) ) :
?>
<ul class="dp-commentaires">
<?php
wp_list_comments( array(
'style' => 'ul',
'short_ping' => true,
'avatar_size' => 32,
), $comments );
?>
</ul>
<?php
else :
?>
<p>Aucun message pour le moment. Lancez la discussion !</p>
<?php
endif;
?>
</div>
<div class="dp-discussion-formulaire">
<?php
comment_form( array(
'title_reply' => 'Ajouter un message',
'title_reply_to' => 'Répondre à %s',
'label_submit' => 'Envoyer',
'comment_notes_before' => '',
'comment_notes_after' => '',
), $post_id );
?>
</div>
</div>
<?php
return ob_get_clean();
}
add_shortcode( 'page_discussion', 'dp_page_discussion_shortcode' );
============================================================================
4) Taxonomie “Sources” pour les articles (post)
============================================================================
function journal_register_taxonomy_sources() {
$labels = array(
'name' ⇒ 'Sources',
'singular_name' ⇒ 'Source',
'search_items' ⇒ 'Rechercher des sources',
'all_items' ⇒ 'Toutes les sources',
'parent_item' ⇒ 'Source parente',
'parent_item_colon' ⇒ 'Source parente :',
'edit_item' ⇒ 'Modifier la source',
'update_item' ⇒ 'Mettre à jour la source',
'add_new_item' ⇒ 'Ajouter une nouvelle source',
'new_item_name' ⇒ 'Nom de la nouvelle source',
'menu_name' ⇒ 'Sources',
);
$args = array(
'labels' ⇒ $labels,
'public' ⇒ true,
'hierarchical' ⇒ true,
'show_ui' ⇒ true,
'show_admin_column' ⇒ true,
'show_in_rest' ⇒ true,
'rewrite' ⇒ array( 'slug' ⇒ 'sources' ),
);
register_taxonomy( 'sources', array( 'post' ), $args );
}
add_action( 'init', 'journal_register_taxonomy_sources' );
5) Fonction utilitaire : afficher un arbre hiérarchique de taxonomie
function journal_afficher_arbre_taxonomie( $taxonomy, $title ) {
$terms = get_terms( array(
'taxonomy' => $taxonomy,
'hide_empty' => false,
));
if ( empty( $terms ) || is_wp_error( $terms ) ) {
return '<p>Aucun terme trouvé pour : ' . esc_html( $taxonomy ) . '</p>';
}
// Hiérarchie parent -> enfants
$hierarchie = array();
foreach ( $terms as $term ) {
$hierarchie[ $term->parent ][] = $term;
}
$selected = array();
if ( isset( $_GET['tax_query'][ $taxonomy ] ) && is_array( $_GET['tax_query'][ $taxonomy ] ) ) {
$selected = array_map( 'intval', $_GET['tax_query'][ $taxonomy ] );
}
$build_tree = function( $parent_id ) use ( &$build_tree, $hierarchie, $selected, $taxonomy ) {
if ( ! isset( $hierarchie[ $parent_id ] ) ) {
return '';
}
$html = '<ul class="journal-arbre-taxo">';
foreach ( $hierarchie[ $parent_id ] as $term ) {
$has_children = isset( $hierarchie[ $term->term_id ] );
$checked = in_array( $term->term_id, $selected, true ) ? 'checked' : '';
$html .= '<li>';
$html .= $has_children
? '<span class="toggle-node">►</span>'
: '<span class="toggle-placeholder"></span>';
$html .= '<label><input type="checkbox" name="tax_query[' . esc_attr( $taxonomy ) . '][]" value="' . intval( $term->term_id ) . '" ' . $checked . '> ' . esc_html( $term->name ) . '</label>';
if ( $has_children ) {
$html .= '<div class="sub-tree" style="display:none;">' . $build_tree( $term->term_id ) . '</div>';
}
$html .= '</li>';
}
$html .= '</ul>';
return $html;
};
return '<h3>' . esc_html( $title ) . '</h3>' . $build_tree( 0 );
}
============================================================================
6) Shortcode [blog_filtrable_relevanssi]
============================================================================
function journal_shortcode_blog_filtrable_relevanssi( $atts = array() ) {
$atts = shortcode_atts(
array(
'post_type' ⇒ 'post',
'taxonomies' ⇒ 'category,sources',
'per_page' ⇒ 10,
'order_by' ⇒ 'date',
'order' ⇒ 'DESC',
'intro' ⇒ , ) {
),
$atts,
'blog_filtrable_relevanssi'
);
$post_type = sanitize_text_field( $atts['post_type'] );
$per_page = max( 1, intval( $atts['per_page'] ) );
$order_by = sanitize_key( $atts['order_by'] );
$order = ( strtoupper( $atts['order'] ) === 'ASC' ) ? 'ASC' : 'DESC';
$intro = wp_kses_post( $atts['intro'] );
$taxonomies = array();
foreach ( explode( ',', $atts['taxonomies'] ) as $tx ) {
$tx = trim( $tx );
if ( $tx !==
$taxonomies[] = $tx;
}
}
$search_term = isset( $_GET['bfrr_s'] ) ? sanitize_text_field( $_GET['bfrr_s'] ) : ;
$tax_query = array();
if ( isset( $_GET['tax_query'] ) && is_array( $_GET['tax_query'] ) ) {
foreach ( $_GET['tax_query'] as $taxonomy ⇒ $terms ) {
$terms = array_filter( array_map( 'intval', (array) $terms ) );
if ( ! empty( $terms ) ) {
$tax_query[] = array(
'taxonomy' ⇒ $taxonomy,
'field' ⇒ 'term_id',
'terms' ⇒ $terms,
'operator' ⇒ 'IN',
);
}
}
}
if ( count( $tax_query ) > 1 ) {
$tax_query = array_merge( array( 'relation' ⇒ 'AND' ), $tax_query );
}
Texte “Filtre appliqué”
$filtre_applique = array();
foreach ( $taxonomies as $tx ) {
if ( isset( $_GET['tax_query'][ $tx ] ) && is_array( $_GET['tax_query'][ $tx ] ) ) {
$ids = array_filter( array_map( 'intval', $_GET['tax_query'][ $tx ] ) );
if ( ! empty( $ids ) ) {
$terms_tx = get_terms( array(
'taxonomy' ⇒ $tx,
'include' ⇒ $ids,
) );
if ( ! is_wp_error( $terms_tx ) && ! empty( $terms_tx ) ) {
$noms = wp_list_pluck( $terms_tx, 'name' );
$tax_obj = get_taxonomy( $tx );
$label = ( $tax_obj && ! empty( $tax_obj→labels→name ) )
? $tax_obj→labels→name
: ucfirst( $tx );
$filtre_applique[] = $label . ' : ' . implode( ', ', $noms );
}
}
}
}
if ( empty( $filtre_applique ) && empty( $search_term ) ) {
$filtre_applique_texte = 'Aucun filtre : tous les articles';
} else {
$parts = array();
if ( ! empty( $search_term ) ) {
$parts[] = 'Texte : « ' . $search_term . ' »';
}
if ( ! empty( $filtre_applique ) ) {
$parts = array_merge( $parts, $filtre_applique );
}
$filtre_applique_texte = 'Filtre appliqué : ' . implode( ' | ', $parts );
}
ob_start();
$page_obj = get_post();
if ( ! $page_obj ) {
return ;
}
$form_action = get_permalink( $page_obj→ID );
$form_action = strtok( $form_action, '?' );
if ( ! empty( $intro ) ) {
echo '<p class=“journal-intro-formulaire”>' . $intro . '</p>';
}
echo '<form method=“get” action=“' . esc_url( $form_action ) . '” class=“journal-arbre-form”>';
echo '<p><input type=“text” name=“bfrr_s” placeholder=“Recherche texte (optionnel)” value=“' . esc_attr( $search_term ) . '” style=“width:100%; padding:6px;”></p>';
echo '
';
foreach ( $taxonomies as $tx ) {
$tax_obj = get_taxonomy( $tx );
$title = ( $tax_obj && ! empty( $tax_obj->labels->name ) ) ? $tax_obj->labels->name : ucfirst( $tx );
echo '<div class="journal-arbre-colonne">';
echo journal_afficher_arbre_taxonomie( $tx, $title );
echo '</div>';
}
echo '</div>';
echo '<p><input type="submit" value="Rechercher"></p>'; echo '</form>';
$paged = max(
1,
get_query_var( 'paged' )
? get_query_var( 'paged' )
: ( isset( $_GET['paged'] ) ? intval( $_GET['paged'] ) : 1 )
);
$args = array(
'post_type' => $post_type,
'post_status' => 'publish',
'ignore_sticky_posts' => true,
's' => $search_term,
'paged' => $paged,
'posts_per_page' => $per_page,
'orderby' => $order_by,
'order' => $order,
);
if ( ! empty( $tax_query ) ) {
$args['tax_query'] = $tax_query;
}
$query = new WP_Query( $args );
if ( function_exists( 'relevanssi_do_query' ) && ! empty( $search_term ) ) {
relevanssi_do_query( $query );
}
echo '<div class="journal-resultats">'; echo '<p class="journal-filtre-applique">' . esc_html( $filtre_applique_texte ) . '</p>';
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
echo '<article class="journal-resultat-article">';
echo '<h3 class="journal-resultat-titre"><a href="' . esc_url( get_permalink() ) . '">' . esc_html( get_the_title() ) . '</a></h3>';
echo '<div class="journal-resultat-extrait">' . wp_kses_post( wp_trim_words( get_the_excerpt(), 30, '...' ) ) . '</div>';
echo '</article>';
}
echo paginate_links( array(
'total' => $query->max_num_pages,
'current' => $paged,
) );
} else {
echo '<p>Aucun article trouvé.</p>';
}
echo '</div>';
wp_reset_postdata();
?>
<script>
document.addEventListener("DOMContentLoaded", function() {
document.querySelectorAll(".toggle-node").forEach(function(node) {
node.addEventListener("click", function() {
const subtree = this.parentNode.querySelector(".sub-tree");
if (!subtree) return;
if (subtree.style.display === 'none') {
subtree.style.display = 'block';
this.textContent = '▼';
} else {
subtree.style.display = 'none';
this.textContent = '►';
}
});
});
});
</script>
<?php
return ob_get_clean();
}
add_shortcode( 'blog_filtrable_relevanssi', 'journal_shortcode_blog_filtrable_relevanssi' );
============================================================================
7) Shortcode [dernier_article] : N derniers articles
============================================================================
if ( ! function_exists( 'bfrr_dernier_article_shortcode' ) ) {
function bfrr_dernier_article_shortcode( $atts = array() ) {
$atts = shortcode_atts(
array(
'nb' ⇒ 1,
),
$atts,
'dernier_article'
);
$nb = max( 1, intval( $atts['nb'] ) );
$args = array(
'post_type' ⇒ 'post',
'post_status' ⇒ 'publish',
'posts_per_page' ⇒ $nb,
);
$query = new WP_Query( $args );
if ( ! $query→have_posts() ) {
return '<p>Aucun article trouvé.</p>';
}
ob_start();
while ( $query→have_posts() ) {
$query→the_post();
$post_id = get_the_ID();
$permalink = get_permalink();
echo '<article class=“bfrr-dernier-article”>';
echo '<h2 class=“bfrr-da-titre”><a href=“' . esc_url( $permalink ) . '”>' . esc_html( get_the_title() ) . '</a></h2>';
echo '<p class=“bfrr-da-meta”>Publié le ' . esc_html( get_the_date() ) . '</p>';
$cats_list = get_the_category_list( ', ' );
if ( $cats_list ) {
echo '<p class=“bfrr-da-taxo bfrr-da-cats”><strong>Catégories : </strong>' . wp_kses_post( $cats_list ) . '</p>';
}
$sources = get_the_terms( $post_id, 'sources' );
if ( $sources && ! is_wp_error( $sources ) ) {
$sources_names = wp_list_pluck( $sources, 'name' );
echo '<p class=“bfrr-da-taxo bfrr-da-sources”><strong>Sources : </strong>' . esc_html( implode( ', ', $sources_names ) ) . '</p>';
}
$tags_list = get_the_tag_list( , ', ' );
if ( $tags_list ) {
echo '<p class=“bfrr-da-taxo bfrr-da-tags”><strong>Étiquettes : </strong>' . wp_kses_post( $tags_list ) . '</p>';
}
echo '
';
echo wp_kses_post( wp_trim_words( get_the_excerpt(), 55, '...' ) );
echo '</div>';
echo '<p class="bfrr-da-bouton-wrapper">';
echo '<a class="bfrr-da-bouton" href="' . esc_url( $permalink ) . '">Lire l’article complet</a>';
echo '</p>';
echo '</article>';
}
wp_reset_postdata();
return ob_get_clean(); }
}
add_shortcode( 'dernier_article', 'bfrr_dernier_article_shortcode' );
============================================================================
8) Injection du bouton “Vider la requête” en JS
============================================================================
add_action( 'wp_footer', function() {
?>
<script>
document.addEventListener('DOMContentLoaded', function() {
const interval = setInterval(() ⇒ {
const arbre = document.querySelector('.journal-arbre-taxo');
if (!arbre) return;
const formContainer = arbre.closest('form');
if (!formContainer) return;
clearInterval(interval);
const submitInput = formContainer.querySelector('p input[type=“submit”]');
if (!submitInput) return;
const submitP = submitInput.parentNode;
let clearBtn = document.getElementById('journal-clear-filters');
if (!clearBtn) {
clearBtn = document.createElement('button');
clearBtn.type = 'button';
clearBtn.id = 'journal-clear-filters';
clearBtn.className = 'journal-clear-btn';
clearBtn.textContent = 'Vider la requête';
}
submitP.appendChild(clearBtn);
clearBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
formContainer.querySelectorAll('input[type=“text”], input[type=“search”], textarea')
.forEach(el ⇒ el.value = '');
formContainer.querySelectorAll('input[type=“checkbox”], input[type=“radio”]')
.forEach(el ⇒ el.checked = false);
formContainer.querySelectorAll('select')
.forEach(sel ⇒ sel.selectedIndex = 0);
var url = window.location.protocol + '' + window.location.host + window.location.pathname;
window.location.href = url;
});
}, 200);
});
</script>
<?php
});
============================================================================
9) CPT “atelier” + taxonomies “atelier_sujet” et “atelier_fiche”
============================================================================
function dp_register_atelier_cpt() {
$labels = array(
'name' ⇒ 'atelier',
'singular_name' ⇒ 'Article atelier',
'menu_name' ⇒ 'Ateliers',
'name_admin_bar' ⇒ 'Atelier',
'add_new' ⇒ 'Ajouter',
'add_new_item' ⇒ 'Ajouter un article',
'new_item' ⇒ 'Nouvel article',
'edit_item' ⇒ 'Modifier l’article',
'view_item' ⇒ 'Voir l’article',
'all_items' ⇒ 'Tous les articles atelier',
'search_items' ⇒ 'Rechercher dans atelier',
'parent_item_colon' ⇒ 'Article parent :',
'not_found' ⇒ 'Aucun article trouvé.',
'not_found_in_trash' ⇒ 'Aucun article trouvé dans la corbeille.',
);
$args = array(
'labels' ⇒ $labels,
'public' ⇒ true,
'has_archive' ⇒ true,
'show_in_rest' ⇒ true,
'menu_position' ⇒ 21,
'menu_icon' ⇒ 'dashicons-welcome-write-blog',
'supports' ⇒ array(
'title',
'editor',
'excerpt',
'thumbnail',
'author',
'comments',
),
'rewrite' ⇒ array(
'slug' ⇒ 'atelier',
'with_front' ⇒ true,
),
);
register_post_type( 'atelier', $args );
}
add_action( 'init', 'dp_register_atelier_cpt' );
function dp_register_atelier_sujet_taxonomy() {
$labels = array(
'name' ⇒ 'Sujets',
'singular_name' ⇒ 'Sujet',
'search_items' ⇒ 'Rechercher des sujets',
'all_items' ⇒ 'Tous les sujets',
'parent_item' ⇒ 'Sujet parent',
'parent_item_colon' ⇒ 'Sujet parent :',
'edit_item' ⇒ 'Modifier le sujet',
'update_item' ⇒ 'Mettre à jour le sujet',
'add_new_item' ⇒ 'Ajouter un nouveau sujet',
'new_item_name' ⇒ 'Nom du nouveau sujet',
'menu_name' ⇒ 'Sujet',
);
$args = array(
'hierarchical' ⇒ true,
'labels' ⇒ $labels,
'show_ui' ⇒ true,
'show_admin_column' ⇒ true,
'public' ⇒ true,
'show_in_rest' ⇒ true,
'rewrite' ⇒ array(
'slug' ⇒ 'atelier-sujet',
),
);
register_taxonomy( 'atelier_sujet', array( 'atelier' ), $args );
}
add_action( 'init', 'dp_register_atelier_sujet_taxonomy' );
function dp_register_atelier_fiche_taxonomy() {
$labels = array(
'name' ⇒ 'fiche',
'singular_name' ⇒ 'fiche atelier',
'search_items' ⇒ 'Rechercher des fiches',
'all_items' ⇒ 'Tous les fiches',
'parent_item' ⇒ 'fiche parent',
'parent_item_colon' ⇒ 'fiche parent :',
'edit_item' ⇒ 'Modifier le fiche',
'update_item' ⇒ 'Mettre à jour le fiche',
'add_new_item' ⇒ 'Ajouter un nouveau fiche',
'new_item_name' ⇒ 'Nom du nouveau fiche',
'menu_name' ⇒ 'Fiche',
);
$args = array(
'hierarchical' ⇒ true,
'labels' ⇒ $labels,
'show_ui' ⇒ true,
'show_admin_column' ⇒ true,
'public' ⇒ true,
'show_in_rest' ⇒ true,
'rewrite' ⇒ array(
'slug' ⇒ 'atelier-fiche',
),
);
register_taxonomy( 'atelier_fiche', array( 'atelier' ), $args );
}
add_action( 'init', 'dp_register_atelier_fiche_taxonomy' );