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:
93
inc/avatars.php
Normal file
93
inc/avatars.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/**
|
||||
* Avatars utilisateurs — chaîne de fallback
|
||||
* Simple Local Avatar → Gravatar (cache préchauffé par cron) → chaîne vide
|
||||
* (initiales côté template).
|
||||
*
|
||||
* Le rendu ne fait JAMAIS de requête réseau : l'existence du Gravatar est
|
||||
* vérifiée par un cron quotidien (thalim_warm_gravatar_cache) qui remplit
|
||||
* les transients. En cas de cache manquant (nouvel utilisateur, transient
|
||||
* expiré), on renvoie '' (initiales) et on planifie un réchauffage unitaire.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the avatar URL for a user:
|
||||
* 1. Simple Local Avatar (media library upload) if set
|
||||
* 2. Gravatar if the user has one (transient rempli par cron)
|
||||
* 3. Empty string → templates fall back to initials/placeholder
|
||||
*/
|
||||
function thalim_get_user_avatar_url( int $user_id ): string {
|
||||
// 1. Simple Local Avatar plugin
|
||||
$meta = get_user_meta( $user_id, 'simple_local_avatar', true );
|
||||
if ( is_array( $meta ) && ! empty( $meta['full'] ) ) {
|
||||
// Use media_id for a dynamic URL that works across environments
|
||||
if ( ! empty( $meta['media_id'] ) ) {
|
||||
$url = wp_get_attachment_url( (int) $meta['media_id'] );
|
||||
if ( $url ) return $url;
|
||||
}
|
||||
// Fallback: rewrite stored URL to current site domain
|
||||
$pos = strpos( $meta['full'], '/wp-content/' );
|
||||
if ( $pos !== false ) {
|
||||
return rtrim( site_url(), '/' ) . substr( $meta['full'], $pos );
|
||||
}
|
||||
return $meta['full'];
|
||||
}
|
||||
|
||||
// 2. Gravatar — uniquement depuis le cache (pas de HEAD dans le rendu)
|
||||
$cached = get_transient( 'thalim_gravatar_' . $user_id );
|
||||
if ( $cached !== false ) return $cached;
|
||||
|
||||
// Cache manquant : fallback initiales tout de suite, réchauffage en différé
|
||||
if ( ! wp_next_scheduled( 'thalim_warm_gravatar_user', [ $user_id ] ) ) {
|
||||
wp_schedule_single_event( time() + 60, 'thalim_warm_gravatar_user', [ $user_id ] );
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie l'existence du Gravatar d'un utilisateur (HEAD avec d=404) et met
|
||||
* le résultat (positif ou négatif) en transient. Appelé uniquement en cron.
|
||||
*/
|
||||
function thalim_refresh_gravatar_cache( int $user_id ): void {
|
||||
$user = get_userdata( $user_id );
|
||||
if ( ! $user ) return;
|
||||
|
||||
$hash = md5( strtolower( trim( $user->user_email ) ) );
|
||||
$response = wp_remote_head(
|
||||
'https://www.gravatar.com/avatar/' . $hash . '?d=404',
|
||||
[ 'timeout' => 3 ]
|
||||
);
|
||||
|
||||
// Erreur réseau : ne pas mettre en cache un faux négatif, retenter plus tard
|
||||
if ( is_wp_error( $response ) ) return;
|
||||
|
||||
$url = wp_remote_retrieve_response_code( $response ) === 200
|
||||
? 'https://www.gravatar.com/avatar/' . $hash . '?s=300'
|
||||
: '';
|
||||
set_transient( 'thalim_gravatar_' . $user_id, $url, WEEK_IN_SECONDS );
|
||||
}
|
||||
add_action( 'thalim_warm_gravatar_user', 'thalim_refresh_gravatar_cache' );
|
||||
|
||||
// Cron quotidien : réchauffe le cache Gravatar des utilisateurs sans avatar
|
||||
// local, avant expiration des transients (1 semaine) — le premier rendu de
|
||||
// /membres ne paie plus jamais N requêtes HEAD de 3 s.
|
||||
add_action( 'init', function () {
|
||||
if ( ! wp_next_scheduled( 'thalim_warm_gravatar_cache' ) ) {
|
||||
wp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', 'thalim_warm_gravatar_cache' );
|
||||
}
|
||||
} );
|
||||
|
||||
add_action( 'thalim_warm_gravatar_cache', function () {
|
||||
$users = get_users( [ 'fields' => 'ID' ] );
|
||||
foreach ( $users as $user_id ) {
|
||||
$user_id = (int) $user_id;
|
||||
// Avatar local → pas besoin de Gravatar
|
||||
$meta = get_user_meta( $user_id, 'simple_local_avatar', true );
|
||||
if ( is_array( $meta ) && ! empty( $meta['full'] ) ) continue;
|
||||
// Transient encore frais (posé il y a < 1 semaine) : on le rafraîchit
|
||||
// quand même s'il expire dans moins de 2 jours, sinon on saute.
|
||||
$timeout = (int) get_option( '_transient_timeout_thalim_gravatar_' . $user_id );
|
||||
if ( $timeout && $timeout - time() > 2 * DAY_IN_SECONDS ) continue;
|
||||
thalim_refresh_gravatar_cache( $user_id );
|
||||
}
|
||||
} );
|
||||
Reference in New Issue
Block a user