0WordPress Local Gravatar cache

I like to have avatars shown for people who com­ment on my blog. Word­Press sup­ports the gravatar ser­vice nat­ively so enabling this is very easy. How­ever it comes with a cost — access­ing extern­al files from anoth­er domain adds lots of extra load time in the form of new DNS look­ups, new SSL con­nec­tions to make, etc. Would­n’t it be nice to have gravatars stored loc­ally and served from your own serv­er. Well that’s what I’ve been doing for some time now, if you’d like to know how, read on…

In case you’re still won­der­ing just why you’d want to do this, let me offer a few more bene­fits — images served loc­ally can be com­pressed before serving them, for example ‑all my images are con­ver­ted into webp ver­sions, and any browser which sup­ports webp gets the webp ver­sion. This is in addi­tion to the reduc­tion from not hav­ing to con­nect to an extern­al serv­er. The loc­al resources can also have a cach­ing head­er set on them so that browsers will cache them. Gravatar does­n’t provide for a very long cache time.

I have cre­ated 3 cus­tom func­tions, which I simply place in my theme’s functions.php. The first is a cus­tom fil­ter for the nat­ive word­press get_avatar(). The second grabs avatars from gravatar and google when called upon, and the third cre­ates a daily cronjob which refreshes the gravatars — in case they’ve been changed, or a pre­vi­ously unavail­able one is now available.

You will need to do a little bit of tinker­ing to make it com­pat­ible with your theme — I use the “bones” frame­work as you’ll notice in the 3rd func­tion I’ve reused some code that it provided. You will also need to cre­ate, or cus­tom­ise the path to store the gravatars, which in my case are stored in the theme folder in the sub­path “/library/images/gravatars/”

/*********************************************\
* Filter get_avatar to use local avatars only *
\*********************************************/
function bones_gravatar($avatar, $id_or_email, $size, $default, $alt)
{
$root_path= get_template_directory_uri() . '/library/images/gravatars/';
$root_path_local= get_template_directory() . '/library/images/gravatars/';
$gravatar_path= $root_path . 'default_avatar';
$gravatar_path_hidpi= 'data-gravatar-hidpi="'.$root_path . 'default_avatar-hidpi.png"';

//shamelessly reuse original code to get the e-mail address

$email = '';
if ( is_numeric($id_or_email) )
{
$id = (int) $id_or_email;
$user = get_userdata($id);
if ( $user ) $email = $user->user_email;
}
elseif ( is_object($id_or_email) )
{
// No avatar for pingbacks or trackbacks
$allowed_comment_types = apply_filters( 'get_avatar_comment_types', array( 'comment' ) );
if ( ! empty( $id_or_email->comment_type ) && ! in_array( $id_or_email->comment_type, (array) $allowed_comment_types ) ) return false;
if ( !empty($id_or_email->user_id) )
{
$id = (int) $id_or_email->user_id;
$user = get_userdata($id);
if ( $user) $email = $user->user_email;
}
elseif ( !empty($id_or_email->comment_author_email) )
{
$email = $id_or_email->comment_author_email;
}
}
else
{
$email = $id_or_email;
}

if ( !empty($email) )
{
$email_hash = md5( strtolower( trim( $email ) ) );
if(file_exists($root_path_local . $email_hash . '.png'))
{
//if we have a local cache then use it
$gravatar_path= $root_path . $email_hash ;
$gravatar_path_hidpi= 'data-gravatar-hidpi="'.$root_path . $email_hash . '-hidpi.png"';
}
}
if($size >= 47) $avatar= '<img class="load-gravatar avatar avatar-'.$size.' photo" width="'.$size.'" height="'.$size.'" src="' . $gravatar_path . '-hidpi.png" alt="gravatar" />';
else $avatar= '<img class="load-gravatar avatar avatar-'.$size.' photo" width="'.$size.'" height="'.$size.'" src="' . $gravatar_path . '.png" alt="gravatar" ' . $gravatar_path_hidpi . ' />';

return $avatar;
}

add_filter('get_avatar', 'bones_gravatar', 10, 5);






/***********************\
* Create gravatar cache *
\***********************/
function grab_avatar($comment_id,$comment,$refresh=false,$email='')
{
usleep(20);
$root_path= get_template_directory_uri() . '/library/images/gravatars/';
$root_path_local= get_template_directory() . '/library/images/gravatars/';
if($refresh==false) $img_name= md5( get_comment_author_email($comment_id) );
else $img_name= md5( $email );
if(!file_exists($root_path_local . $img_name . '.png') || $refresh==true)
{
if($refresh==false) $bgauthemail = get_comment_author_email();
else $bgauthemail= $email;
//try google first
$domain= explode("@",$bgauthemail);
if($domain[1]=="gmail.com")
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, "https://picasaweb.google.com/data/entry/api/user/" . $bgauthemail . "?alt=json");
$result = curl_exec($ch);
curl_close($ch);

$obj = json_decode($result,true);
$avatar_from_gmail= $obj['entry']['gphoto$thumbnail']['$t'];

$extension= strrchr($avatar_from_gmail, '.');

$ch = curl_init($avatar_from_gmail);
curl_setopt( $ch, CURLOPT_NOBODY, true );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, false );
curl_setopt( $ch, CURLOPT_HEADER, false );
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
curl_setopt( $ch, CURLOPT_MAXREDIRS, 3 );
curl_exec( $ch );
$headers = curl_getinfo( $ch );
curl_close( $ch );
if($headers['http_code'] === 200)
{
$ch = curl_init($avatar_from_gmail);
$fp = fopen($root_path_local . $img_name . '-hidpi' . $extension, 'wb');
curl_setopt($ch,CURLOPT_USERAGENT,'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.62 Safari/537.36');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);

curl_exec($ch);
curl_close($ch);

fclose($fp);

$usegravatar=false;

$small_image= wp_get_image_editor($root_path_local . $img_name . '-hidpi' . $extension);
if ( ! is_wp_error( $small_image ) )
{
//check it isn't a blank man image, if so, delete it
if (md5_file($root_path_local . $img_name . '-hidpi.jpg') == strtolower("686E5C46776BA0E5C488853C1C0B492C"))
{
//delete
unlink($root_path_local . $img_name . '-hidpi.jpg');
//try gravatar
$usegravatar=true;
}
else if (md5_file($root_path_local . $img_name . '-hidpi.jpg') == strtolower("6D4083BE95FB32358A5110F5A83B9979"))
{
//delete
unlink($root_path_local . $img_name . '-hidpi.jpg');
//try gravatar
$usegravatar=true;
}
else
{
//always convert to png because some plugins expect all gravatars to be pngs
$small_image->save($root_path_local . $img_name . '-hidpi.png','image/png');
$small_image->resize(40, 40, true);
$small_image->set_quality( 10 );
$small_image->save($root_path_local . $img_name . '.png','image/png');
if($extension==".jpg") unlink($root_path_local . $img_name . '-hidpi.jpg');
}
}
}

}
//check e-mail isnt a blank generic one
else if($bgauthemail!=="noemail@intensedebate.com" || $usegravatar==true)
{
$avatar_from_gravatar= "https://www.gravatar.com/avatar/" . $img_name . "?s=80&d=404";
$ch = curl_init($avatar_from_gravatar);
curl_setopt( $ch, CURLOPT_NOBODY, true );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, false );
curl_setopt( $ch, CURLOPT_HEADER, false );
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
curl_setopt( $ch, CURLOPT_MAXREDIRS, 3 );
curl_exec( $ch );
$headers = curl_getinfo( $ch );
curl_close( $ch );
if($headers['http_code'] === 200)
{
$ch = curl_init($avatar_from_gravatar);
$fp = fopen($root_path_local . $img_name . '-hidpi.png', 'wb');
curl_setopt($ch,CURLOPT_USERAGENT,'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.62 Safari/537.36');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);

curl_exec($ch);
curl_close($ch);

fclose($fp);

$small_image= wp_get_image_editor($root_path_local . $img_name . '-hidpi.png');
if ( ! is_wp_error( $small_image ) )
{
$small_image->resize(40, 40, true);
$small_image->save($root_path_local . $img_name . '.png');
}
}
}
}
}
add_action('wp_insert_comment', 'grab_avatar');






/********************************************\
* Refresh gravatar cache in background daily *
\********************************************/
add_action( 'wp', 'bones_setup_schedule' );
function bones_setup_schedule() {
if ( ! wp_next_scheduled( 'bones_daily_event' ) ) {
wp_schedule_event( time(), 'daily', 'bones_daily_event');
}
}

add_action( 'bones_daily_event', 'bones_refresh_gravatars' );
function bones_refresh_gravatars()
{
//get list of gravatars somehow
global $wpdb;
$comment_author_emails= $wpdb->get_results( "SELECT DISTINCT(comment_author_email) FROM " . $wpdb->prefix . "comments" );
foreach($comment_author_emails as $key => $val)
{
foreach($val as $a => $b)
{
grab_avatar('','',true,$b);
}
}
}

Leave a Reply