Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions src/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ public function run(): void {
add_action( 'init', [ $this, 'load_translations' ] );

add_action( 'plugin_action_links_' . plugin_basename( $this->path ) . '/login-with-google.php', [ $this, 'add_plugin_action_links' ] );

add_action( 'get_avatar_url', [ $this, 'return_avatar_url' ], 10, 3 );
}

/**
Expand Down Expand Up @@ -162,4 +164,48 @@ public function add_plugin_action_links( $actions ) {

return array_merge( $new_actions, $actions );
}

/**
* Return the stored profile picture during the account creation.
*
* @param string $url The URL of the avatar.
* @param mixed $id_or_email The avatar to retrieve. Accepts a user ID, Gravatar SHA-256 or MD5 hash, user email, WP_User object, WP_Post object, or WP_Comment object.
* @param array $args Arguments passed to get_avatar_data() , after processing.
*
* @return string The URL of the avatar.
*/
public function return_avatar_url( $url, $id_or_email, $args ): string {
/**
* Filter to bypass the use of saved profile picture for avatar.
*
* @since n.e.x.t
*
* @param boolean $use_saved_profile_picture_for_avatar Whether to bypass the use the saved profile picture for avatar or not.
Copy link

Copilot AI Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant word 'the' in the docblock. Should be 'Whether to bypass the use of the saved profile picture' or 'Whether to use the saved profile picture'.

Suggested change
* @param boolean $use_saved_profile_picture_for_avatar Whether to bypass the use the saved profile picture for avatar or not.
* @param boolean $use_saved_profile_picture_for_avatar Whether to bypass the use of the saved profile picture for avatar or not.

Copilot uses AI. Check for mistakes.
*/
$use_avatar_url = apply_filters( 'rtcamp.google_use_saved_profile_picture_for_avatar', true );

if ( ! $use_avatar_url ) {
return $url;
}

$wp_user = null;
if ( is_int( $id_or_email ) ) {
$wp_user = get_user_by( 'id', $id_or_email );
} elseif ( is_string( $id_or_email ) && is_email( $id_or_email ) ) {
$wp_user = get_user_by( 'email', $id_or_email );
}

if ( $wp_user ) {
$width = isset( $args['width'] ) ? absint( $args['width'] ) : 64;
$height = isset( $args['height'] ) ? absint( $args['height'] ) : 64;

$profile_picture_id = get_user_meta( $wp_user->ID, 'rtlwg_profile_picture_id', true );

if ( ! empty( $profile_picture_id ) ) {
$url = wp_get_attachment_image_url( $profile_picture_id, [ $width, $height ] );
Copy link

Copilot AI Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wp_get_attachment_image_url() can return false if the attachment doesn't exist. The code should check the return value and only update $url if a valid URL is returned, otherwise the original URL will be lost.

Suggested change
$url = wp_get_attachment_image_url( $profile_picture_id, [ $width, $height ] );
$profile_picture_url = wp_get_attachment_image_url( $profile_picture_id, [ $width, $height ] );
if ( $profile_picture_url ) {
$url = $profile_picture_url;
}

Copilot uses AI. Check for mistakes.
}
}

return $url;
}
}
68 changes: 68 additions & 0 deletions src/Utils/Authenticator.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,21 @@ public function register( stdClass $user ): ?WP_User {
]
);

/**
* Filter to bypass the profile picture saving process.
*
* @since n.e.x.t
*
* @param boolean $save Whether to save profile picture or not.
* @param int $uid WP User ID.
* @param \stdClass User object return by Google.
Copy link

Copilot AI Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected spelling of 'return' to 'returned' in the docblock parameter description.

Suggested change
* @param \stdClass User object return by Google.
* @param \stdClass User object returned by Google.

Copilot uses AI. Check for mistakes.
*/
$save_profile_picture = apply_filters( 'rtcamp.google_save_user_profile_picture', true, $uid, $user );

if ( $save_profile_picture ) {
$this->save_user_profile_picture( $uid, $user );
}

/**
* Fires once the user has been registered successfully.
*/
Expand Down Expand Up @@ -179,4 +194,57 @@ private function can_register_with_email( string $email ): bool {

return in_array( $email_parts[1], $whitelisted_domains, true );
}

/**
* Save user profile picture.
*
* @param int $user_id WP User ID.
* @param \stdClass $user User object returned by google.
* @return void
*/
private function save_user_profile_picture( $user_id, $user ): void {
global $wp_filesystem;

if ( is_null( $wp_filesystem ) ) {
require_once ABSPATH . '/wp-admin/includes/file.php';
Copy link

Copilot AI Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent path separator usage. Line 209 uses '/wp-admin' while lines 213-215 use 'wp-admin' (without leading slash). The leading slash should be removed for consistency, as ABSPATH already ends with a trailing slash.

Suggested change
require_once ABSPATH . '/wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/file.php';

Copilot uses AI. Check for mistakes.
WP_Filesystem();
}

require_once ABSPATH . 'wp-admin/includes/media.php';
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/image.php';

// Using larger image size. By default, profile picture has 96 width size with cropped.
Copy link

Copilot AI Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing property existence check for $user->picture. The code should verify that the picture property exists on the user object before attempting to access it to avoid potential PHP warnings or errors.

Suggested change
// Using larger image size. By default, profile picture has 96 width size with cropped.
// Using larger image size. By default, profile picture has 96 width size with cropped.
if ( ! isset( $user->picture ) ) {
// No profile picture available, so nothing to do.
return;
}

Copilot uses AI. Check for mistakes.
$profile_picture_url = str_replace( '=s96-c', '', $user->picture );

$profile_picture_filename = download_url( $profile_picture_url );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a check for WPVIP? and if the site is hosted on WPVIP we directly use wpcom_vip_download_image() this function.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SH4LIN Yes, it can be a bit unclear—I’ll look into it further to make it more straightforward. As for re-syncing the image at each login, should we also extend this to include the First Name and Last Name, since those fields can also be updated?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SH4LIN Regarding vip check, that is a good catch. I will promptly implement this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we also extend this to include the First Name and Last Name, since those fields can also be updated?

In WordPress, we have the option to update the first name and last name. So, if they want to customize it, they can do so from the settings. However, there is no option in the WordPress dashboard to change the image.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a check for WPVIP? and if the site is hosted on WPVIP we directly use wpcom_vip_download_image() this function.

I tried to use this function, it seems it won't work in our scenario. I got the following error while trying to use it .
2025-05-15_15-38

The function was expecting a POST request, but Google calls the redirect URL using the GET method instead. We could try to change the global variables to make it work, but that would be a hacky solution. So, I decided to remove the function for now.


Copy link

Copilot AI Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing error handling for download_url() which can return a WP_Error object on failure. The code should check if the result is a WP_Error before proceeding to use it as a filename.

Suggested change
if ( is_wp_error( $profile_picture_filename ) ) {
// Optionally log the error: error_log( $profile_picture_filename->get_error_message() );
return;
}

Copilot uses AI. Check for mistakes.
if ( str_ends_with( $profile_picture_filename, '.tmp' ) ) {
$profile_picture_mime_type = wp_get_image_mime( $profile_picture_filename );

$mime_types = wp_get_mime_types();
foreach ( $mime_types as $ext => $mime_type ) {
if ( $profile_picture_mime_type === $mime_type ) {
$profile_picture_extension = current( explode( '|', $ext ) );
Copy link

Copilot AI Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable $profile_picture_extension may not be defined if no matching MIME type is found in the foreach loop. Initialize this variable before the loop or add an else condition to handle the case when no match is found.

Copilot uses AI. Check for mistakes.
break;
}
}

$new_profile_picture_filename = str_replace( '.tmp', ".{$profile_picture_extension}", $profile_picture_filename );
$wp_filesystem->move( $profile_picture_filename, $new_profile_picture_filename, true );

$profile_picture_filename = $new_profile_picture_filename;
}

$file_array = array(
'name' => basename( $profile_picture_filename ),
'tmp_name' => $profile_picture_filename,
);

$attachment_id = media_handle_sideload( $file_array );

Copy link

Copilot AI Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing error handling for media_handle_sideload() which can return a WP_Error object on failure. The code only checks if result is an integer but doesn't handle potential WP_Error cases or clean up the temporary file on error.

Suggested change
if ( is_wp_error( $attachment_id ) ) {
// Clean up the temporary file if there was an error.
if ( file_exists( $profile_picture_filename ) ) {
@unlink( $profile_picture_filename );
}
// Optionally, log the error.
// error_log( 'Failed to sideload profile picture: ' . $attachment_id->get_error_message() );
return;
}

Copilot uses AI. Check for mistakes.
if ( is_int( $attachment_id ) ) {
update_user_meta( $user_id, 'rtlwg_profile_picture_id', $attachment_id );
}
}
}