Refactoring : sécurité (XSS), découpage en modules inc/* et js/admin/*, IDs résolus par slug, perf (caches, cron Gravatar, assets auto-hébergés), tests

This commit is contained in:
2026-06-10 21:30:25 +02:00
parent e6b73df516
commit 9280c3b9ce
44 changed files with 3209 additions and 2907 deletions

165
inc/admin-tweaks.php Normal file
View File

@@ -0,0 +1,165 @@
<?php
/**
* Customisations de l'admin WP : synchro display_name, champs Pods sur
* user-new.php, colonnes et filtres des taxonomies, filtre catégorie exact,
* admin bar, rewrite rule /autres, mode visuel forcé.
*/
// Auto-sync display_name from first_name + last_name on every profile save
add_action( 'profile_update', 'thalim_sync_display_name' );
add_action( 'user_register', 'thalim_sync_display_name' );
add_action( 'pods_api_post_save_pod_item_user', function( $pieces ) {
$user_id = isset( $pieces['id'] ) ? intval( $pieces['id'] ) : 0;
if ( $user_id ) thalim_sync_display_name( $user_id );
} );
function thalim_sync_display_name( int $user_id ): void {
$first = get_user_meta( $user_id, 'first_name', true );
$last = get_user_meta( $user_id, 'last_name', true );
// sanitize_text_field: le nom est réaffiché un peu partout (cards, data-*),
// on neutralise ici tout balisage saisi dans prénom/nom.
$name = sanitize_text_field( trim( "$first $last" ) );
if ( ! $name ) return;
// Bypass the filter to avoid infinite loop
remove_action( 'profile_update', 'thalim_sync_display_name' );
wp_update_user( [ 'ID' => $user_id, 'display_name' => $name ] );
add_action( 'profile_update', 'thalim_sync_display_name' );
}
// Show Pods user meta fields on the Add New User page (user-new.php).
// Fires the same hook Pods listens to on profile.php / user-edit.php.
add_action('user_new_form', function($operation) {
if ($operation === 'add-existing-user') return;
$user = new WP_User(0);
do_action('show_user_profile', $user);
});
// Save Pods user meta fields when a new user is registered.
// Re-fires Pods' personal_options_update callback with the new user ID
// while $_POST still contains the submitted form data.
add_action('user_register', function($user_id) {
do_action('personal_options_update', $user_id);
}, 20);
// Remove the Pods autocomplete 30-item cap for the "étiquettes" (post_tag) pick field
// so all tags are available in the dropdown, not just the first 30 alphabetically.
add_filter( 'pods_form_ui_field_pick_autocomplete_limit', function( $limit, $name ) {
if ( 'etiquettes' === $name ) {
return -1;
}
return $limit;
}, 10, 2 );
// Admin "Programmes de recherche" taxonomy list:
// - Filter by "Type de programme" (select injected via JS into the search form).
// - Add a "Type de programme" column to the list table.
// Server-side filtering: read the GET param and add a meta_query on pre_get_terms.
add_action( 'pre_get_terms', function( $query ) {
if ( ! is_admin() ) {
return;
}
if ( ! in_array( 'programme_de_recherche', (array) $query->query_vars['taxonomy'], true ) ) {
return;
}
$type = isset( $_GET['type_de_programme'] ) ? sanitize_text_field( $_GET['type_de_programme'] ) : '';
if ( '' === $type ) {
return;
}
$query->query_vars['meta_query'] = [
[
'key' => 'type_de_programme',
'value' => $type,
'compare' => '=',
],
];
} );
// Column: add "Type de programme" to the list table, replacing "Description".
add_filter( 'manage_edit-programme_de_recherche_columns', function( $columns ) {
unset( $columns['description'] );
$columns['type_de_programme'] = __( 'Type de programme', 'thalim' );
return $columns;
} );
add_filter( 'manage_programme_de_recherche_custom_column', function( $output, $column_name, $term_id ) {
if ( 'type_de_programme' !== $column_name ) {
return $output;
}
return esc_html( get_term_meta( (int) $term_id, 'type_de_programme', true ) ?: '&mdash;' );
}, 10, 3 );
// Admin tag list: replace the "Description" column with the custom boolean field
// "ne_pas_afficher_dans_le_nuage" (Ne pas afficher dans le nuage de mots-clé).
add_filter( 'manage_edit-post_tag_columns', function( $columns ) {
unset( $columns['description'] );
$columns['nuage_exclus'] = __( 'Exclure du nuage', 'thalim' );
return $columns;
} );
add_filter( 'manage_post_tag_custom_column', function( $output, $column_name, $term_id ) {
if ( 'nuage_exclus' !== $column_name ) {
return $output;
}
$val = get_term_meta( (int) $term_id, 'ne_pas_afficher_dans_le_nuage', true );
return $val ? '&#10003;' : '&mdash;';
}, 10, 3 );
// In admin post list, filter by exact category only (exclude subcategories)
function thalim_exact_category_filter( $query ) {
if ( is_admin() && $query->is_main_query() ) {
$cat = $query->get( 'cat' );
if ( $cat ) {
$query->set( 'cat', '' );
$query->set( 'tax_query', [
[
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => [ (int) $cat ],
'include_children' => false,
],
] );
}
}
}
add_action( 'pre_get_posts', 'thalim_exact_category_filter' );
// Rewrite rule for /category/{slug}/autres → posts directly in parent category
add_action('init', function() {
add_rewrite_rule(
'category/([^/]+)/autres/?$',
'index.php?category_name=$matches[1]&thalim_direct_posts=1',
'top'
);
});
add_filter('query_vars', function($vars) {
$vars[] = 'thalim_direct_posts';
return $vars;
});
// Admin bar customizations (front + back)
add_action('admin_bar_menu', function($wp_admin_bar) {
$wp_admin_bar->remove_node('wp-logo');
$wp_admin_bar->remove_node('customize');
foreach ($wp_admin_bar->get_nodes() as $node) {
if (empty($node->title) || stripos($node->title, 'article') === false) continue;
$node->title = preg_replace_callback('/article/i', function($m) {
$w = $m[0];
if ($w === strtoupper($w)) return 'ANNONCE';
if ($w[0] === strtoupper($w[0])) return 'Annonce';
return 'annonce';
}, $node->title);
$wp_admin_bar->add_node((array) $node);
}
}, 999);
add_action('wp_before_admin_bar_render', function() {
global $wp_admin_bar;
$wp_admin_bar->remove_node('wpforms-menu');
});
// Force visual (TinyMCE) editor for all users — our admin CSS hides the
// Visual/Code tabs, so if a user has "Disable the visual editor" checked
// in their profile they get stuck in code mode with no way to switch back.
add_filter( 'user_can_richedit', '__return_true' );