Files
thalim-theme/inc/avatars.php

94 lines
3.9 KiB
PHP

<?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 );
}
} );