Affected versions: at least 2.9.12 and 2.9.16 (current as of this filing).
PHP: 8.0+ (confirmed on 8.3.13)
Summary
includes/admin/class-wpum-avatars.php line 205 builds a transient cache key by concatenating $id_or_email directly:
$cache_key = 'wpum_default_avatar_' . $id_or_email;
Per the function's own docblock, $id_or_email is mixed — WordPress passes a WP_User, WP_Comment, user ID, or email depending on the caller. On PHP 8, concatenating an object without __toString() throws:
Uncaught Error: Object of class WP_Comment could not be converted to string
…fatalling the request (HTTP 500, white screen).
Reproduction
Any front-end single-post page whose theme calls comments_template() and which has ≥1 approved comment. Walker_Comment invokes get_avatar(), which applies the get_avatar_url filter with a WP_Comment object.
Stack trace:
#0 class-wpum-avatars.php(205): WPUM_Avatars->set_default_avatar('https://secure...', Object(WP_Comment), Array)
#1 class-wp-hook.php(324): WP_Hook->apply_filters(...)
#3 link-template.php(4571): apply_filters('get_avatar_url', ...)
#5 pluggable.php(3157): get_avatar_url(Object(WP_Comment), Array)
#6 class-walker-comment.php(427): get_avatar(Object(WP_Comment), 40)
...
#11 theme/comments.php(17): wp_list_comments(Array)
#13 theme/single.php(60): comments_template()
The same fatal also fires with Object(WP_User) when author avatars are rendered via the same filter.
Suggested fix
Derive a safe scalar key from any input type:
if ( is_object( $id_or_email ) ) {
if ( ! empty( $id_or_email->comment_ID ) ) {
$key_part = 'c' . $id_or_email->comment_ID;
} elseif ( ! empty( $id_or_email->ID ) ) {
$key_part = 'u' . $id_or_email->ID;
} elseif ( ! empty( $id_or_email->user_email ) ) {
$key_part = 'e' . md5( $id_or_email->user_email );
} else {
$key_part = md5( serialize( $id_or_email ) );
}
} else {
$key_part = (string) $id_or_email;
}
$cache_key = 'wpum_default_avatar_' . $key_part;
Side note
The early-return guard
if ( is_admin() && ( ! isset( $pagenow ) || 'options-discussion.php' !== $pagenow ) ) {
return $url;
}
…means the expensive path (including a synchronous wp_remote_head() to Gravatar) runs on every front-end avatar URL resolution. That's a separate performance concern worth addressing alongside the fix.
Workaround currently in use
We replaced the filter callback from an mu-plugin on one affected production site. Happy to share the mu-plugin file if useful.
Affected versions: at least 2.9.12 and 2.9.16 (current as of this filing).
PHP: 8.0+ (confirmed on 8.3.13)
Summary
includes/admin/class-wpum-avatars.phpline 205 builds a transient cache key by concatenating$id_or_emaildirectly:Per the function's own docblock,
$id_or_emailismixed— WordPress passes aWP_User,WP_Comment, user ID, or email depending on the caller. On PHP 8, concatenating an object without__toString()throws:…fatalling the request (HTTP 500, white screen).
Reproduction
Any front-end single-post page whose theme calls
comments_template()and which has ≥1 approved comment.Walker_Commentinvokesget_avatar(), which applies theget_avatar_urlfilter with aWP_Commentobject.Stack trace:
The same fatal also fires with
Object(WP_User)when author avatars are rendered via the same filter.Suggested fix
Derive a safe scalar key from any input type:
Side note
The early-return guard
…means the expensive path (including a synchronous
wp_remote_head()to Gravatar) runs on every front-end avatar URL resolution. That's a separate performance concern worth addressing alongside the fix.Workaround currently in use
We replaced the filter callback from an mu-plugin on one affected production site. Happy to share the mu-plugin file if useful.