diff --git a/.gitignore b/.gitignore index 6c8d7791..6b5cf2df 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,5 @@ tests/cypress/screenshots tests/cypress/videos tests/cypress/downloads tests/cypress/reports + +.phpunit.result.cache diff --git a/includes/class-simple-local-avatars.php b/includes/class-simple-local-avatars.php index bff78c55..ef33b24e 100644 --- a/includes/class-simple-local-avatars.php +++ b/includes/class-simple-local-avatars.php @@ -65,9 +65,9 @@ class Simple_Local_Avatars { public function __construct() { $this->add_hooks(); - $this->options = (array) get_option( 'simple_local_avatars' ); - $this->user_key = 'simple_local_avatar'; - $this->rating_key = 'simple_local_avatar_rating'; + $this->options = (array) get_option( 'simple_local_avatars' ); + $this->user_key = 'simple_local_avatar'; + $this->rating_key = 'simple_local_avatar_rating'; if ( ! $this->is_avatar_shared() // Are we sharing avatars? @@ -136,18 +136,26 @@ public function add_hooks() { } if ( 'profile.php' === $pagenow ) { - add_filter( 'media_view_strings', function ( $strings ) { - $strings['skipCropping'] = esc_html__( 'Default Crop', 'simple-local-avatars' ); - - return $strings; - }, 10, 1 ); + add_filter( + 'media_view_strings', + function ( $strings ) { + $strings['skipCropping'] = esc_html__( 'Default Crop', 'simple-local-avatars' ); + + return $strings; + }, + 10, + 1 + ); } // Fix: An error occurred cropping the image (https://github.com/10up/simple-local-avatars/issues/141). if ( isset( $_POST['action'] ) && 'crop-image' === $_POST['action'] && is_admin() && wp_doing_ajax() ) { - add_action( 'plugins_loaded', function () { - remove_all_actions( 'setup_theme' ); - } ); + add_action( + 'plugins_loaded', + function () { + remove_all_actions( 'setup_theme' ); + } + ); } } @@ -330,14 +338,21 @@ public function get_user_id( $id_or_email ) { */ public function get_simple_local_avatar_url( $id_or_email, $size ) { $user_id = $this->get_user_id( $id_or_email ); + $size = (int) $size; if ( empty( $user_id ) ) { return ''; } - // Fetch local avatar from meta and make sure it's properly set. $local_avatars = get_user_meta( $user_id, $this->user_key, true ); - if ( empty( $local_avatars['full'] ) ) { + + // Return avatar if exists. + if ( is_array( $local_avatars ) && array_key_exists( $size, $local_avatars ) && ( strpos( $local_avatars[ $size ], content_url() ) === 0 ) ) { + return esc_url( $local_avatars[ $size ] ); + } + + // Fetch local avatar from meta and make sure it's properly set. + if ( empty( $local_avatars['media_id'] ) ) { return ''; } @@ -354,69 +369,66 @@ public function get_simple_local_avatar_url( $id_or_email, $size ) { } // handle "real" media - if ( ! empty( $local_avatars['media_id'] ) ) { - // If using shared avatars, make sure we validate the URL on the main site. - if ( $this->is_avatar_shared() ) { - $origin_blog_id = isset( $local_avatars['blog_id'] ) && ! empty( $local_avatars['blog_id'] ) ? $local_avatars['blog_id'] : get_main_site_id(); - switch_to_blog( $origin_blog_id ); - } + // If using shared avatars, make sure we validate the URL on the main site. + if ( $this->is_avatar_shared() ) { + $origin_blog_id = ! empty( $local_avatars['blog_id'] ) ? $local_avatars['blog_id'] : get_main_site_id(); + switch_to_blog( $origin_blog_id ); + } - $avatar_full_path = get_attached_file( $local_avatars['media_id'] ); + $avatar_full_path = get_attached_file( $local_avatars['media_id'] ); - if ( $this->is_avatar_shared() ) { - restore_current_blog(); - } + if ( $this->is_avatar_shared() ) { + restore_current_blog(); + } - // has the media been deleted? - if ( ! $avatar_full_path ) { - return ''; - } + // has the media been deleted? + if ( ! $avatar_full_path ) { + return ''; } - $size = (int) $size; + // Use dynamic full url in favour of host/domain change. + $local_avatars['full'] = wp_get_attachment_image_url( $local_avatars['media_id'], 'full' ); // Generate a new size. - if ( ! array_key_exists( $size, $local_avatars ) ) { - $local_avatars[ $size ] = $local_avatars['full']; // just in case of failure elsewhere - - // allow automatic rescaling to be turned off - if ( apply_filters( 'simple_local_avatars_dynamic_resize', true ) ) : + // Just in case of failure elsewhere, set the full size as default. + $local_avatars[ $size ] = $local_avatars['full']; - $upload_path = wp_upload_dir(); + // allow automatic rescaling to be turned off + if ( apply_filters( 'simple_local_avatars_dynamic_resize', true ) ) : - // get path for image by converting URL, unless its already been set, thanks to using media library approach - if ( ! isset( $avatar_full_path ) ) { - $avatar_full_path = str_replace( $upload_path['baseurl'], $upload_path['basedir'], $local_avatars['full'] ); - } + $upload_path = wp_upload_dir(); - // generate the new size - $editor = wp_get_image_editor( $avatar_full_path ); - if ( ! is_wp_error( $editor ) ) { - $resized = $editor->resize( $size, $size, true ); - if ( ! is_wp_error( $resized ) ) { - $dest_file = $editor->generate_filename(); - $saved = $editor->save( $dest_file ); - if ( ! is_wp_error( $saved ) ) { - // Transform the destination file path into URL. - $dest_file_url = ''; - if ( false !== strpos( $dest_file, $upload_path['basedir'] ) ) { - $dest_file_url = str_replace( $upload_path['basedir'], $upload_path['baseurl'], $dest_file ); - } else if ( is_multisite() && false !== strpos( $dest_file, ABSPATH . 'wp-content/uploads' ) ) { - $dest_file_url = str_replace( ABSPATH . 'wp-content/uploads', network_site_url( '/wp-content/uploads' ), $dest_file ); - } + // get path for image by converting URL, unless its already been set, thanks to using media library approach + if ( ! isset( $avatar_full_path ) ) { + $avatar_full_path = str_replace( $upload_path['baseurl'], $upload_path['basedir'], $local_avatars['full'] ); + } - $local_avatars[ $size ] = $dest_file_url; + // generate the new size + $editor = wp_get_image_editor( $avatar_full_path ); + if ( ! is_wp_error( $editor ) ) { + $resized = $editor->resize( $size, $size, true ); + if ( ! is_wp_error( $resized ) ) { + $dest_file = $editor->generate_filename(); + $saved = $editor->save( $dest_file ); + if ( ! is_wp_error( $saved ) ) { + // Transform the destination file path into URL. + $dest_file_url = ''; + if ( false !== strpos( $dest_file, $upload_path['basedir'] ) ) { + $dest_file_url = str_replace( $upload_path['basedir'], $upload_path['baseurl'], $dest_file ); + } elseif ( is_multisite() && false !== strpos( $dest_file, ABSPATH . 'wp-content/uploads' ) ) { + $dest_file_url = str_replace( ABSPATH . 'wp-content/uploads', network_site_url( '/wp-content/uploads' ), $dest_file ); } + + $local_avatars[ $size ] = $dest_file_url; } } + } - // save updated avatar sizes - update_user_meta( $user_id, $this->user_key, $local_avatars ); - - endif; - } + // save updated avatar sizes + update_user_meta( $user_id, $this->user_key, $local_avatars ); + endif; - if ( 'http' !== substr( $local_avatars[ $size ], 0, 4 ) ) { + if ( strpos( $local_avatars[ $size ], 'http' ) !== 0 ) { $local_avatars[ $size ] = home_url( $local_avatars[ $size ] ); } @@ -1004,7 +1016,7 @@ public function assign_new_user_avatar( $url_or_media_id, $user_id ) { * * @param int $user_id Id of the user who's avatar was updated */ - do_action( 'simple_local_avatar_updated' , $user_id ); + do_action( 'simple_local_avatar_updated', $user_id ); } /** @@ -1411,9 +1423,9 @@ private function clear_user_avatar_cache( $local_avatars, $user_id, $media_id ) $file_name_data = pathinfo( get_attached_file( $media_id ) ); } - $file_dir_name = $file_name_data['dirname']; - $file_name = $file_name_data['filename']; - $file_ext = $file_name_data['extension']; + $file_dir_name = $file_name_data['dirname']; + $file_name = $file_name_data['filename']; + $file_ext = $file_name_data['extension']; foreach ( $local_avatars as $local_avatars_key => $local_avatar_value ) { if ( ! in_array( $local_avatars_key, [ 'media_id', 'full' ], true ) ) { $file_size_path = sprintf( '%1$s/%2$s-%3$sx%3$s.%4$s', $file_dir_name, $file_name, $local_avatars_key, $file_ext ); diff --git a/tests/phpunit/SimpleLocalAvatarsTest.php b/tests/phpunit/SimpleLocalAvatarsTest.php index 7b7c3ce3..5f031475 100644 --- a/tests/phpunit/SimpleLocalAvatarsTest.php +++ b/tests/phpunit/SimpleLocalAvatarsTest.php @@ -64,6 +64,13 @@ public function setUp(): void { ->with( 101 ) ->andReturn( '/avatar.png' ); + WP_Mock::userFunction( 'wp_get_attachment_image_url' ) + ->with( 101, 'full' ) + ->andReturn( '/avatar.png' ); + + WP_Mock::userFunction( 'content_url' ) + ->andReturn( 'https://example.com/' ); + WP_Mock::userFunction( 'admin_url' ) ->with( 'options-discussion.php' ) ->andReturn( 'wp-admin/options-discussion.php' ); @@ -196,9 +203,18 @@ public function test_get_simple_local_avatar_url_media_file_deleted() { WP_Mock::userFunction( 'get_user_meta' ) ->with( 2, 'simple_local_avatar', true ) ->andReturn( [ 'media_id' => 102 ] ); + WP_Mock::userFunction( 'get_attached_file' ) ->with( 102 ) ->andReturn( false ); + + WP_Mock::userFunction( 'wp_get_attachment_image_url' ) + ->with( 102, 'full' ) + ->andReturn( false ); + + WP_Mock::userFunction( 'content_url' ) + ->andReturn( 'http://example.com' ); + $this->assertEquals( '', $this->instance->get_simple_local_avatar_url( 2, 96 ) ); } diff --git a/tests/phpunit/multisite/SimpleLocalAvatarsNetworkTest.php b/tests/phpunit/multisite/SimpleLocalAvatarsNetworkTest.php index 1b619bf8..7a073b4d 100644 --- a/tests/phpunit/multisite/SimpleLocalAvatarsNetworkTest.php +++ b/tests/phpunit/multisite/SimpleLocalAvatarsNetworkTest.php @@ -131,6 +131,40 @@ public function test_get_simple_local_avatar_url() { 'return' => '/avatar.png', 'times' => 1, ] ); + WP_Mock::userFunction( 'wp_get_attachment_image_url', [ + 'args' => [ 101, 'full' ], + 'return' => '/avatar.png', + 'times' => 1, + ] ); + WP_Mock::userFunction( 'content_url', [ + 'args' => [], + 'return' => 'http://example.com', + 'times' => 1, + ] ); + WP_Mock::userFunction( 'wp_upload_dir', [ + 'args' => [], + 'return' => ['baseurl' => '', 'basedir' => ''], + 'times' => 1, + ] ); + WP_Mock::userFunction( 'wp_get_image_editor', [ + 'args' => [ '/avatar.png' ], + 'return' => false, + 'times' => 1, + ] ); + WP_Mock::userFunction( 'is_wp_error', [ + 'return' => true, + 'times' => 1, + ] ); + WP_Mock::userFunction( 'update_user_meta', [ + 'args' => [ 1, 'simple_local_avatar', ['media_id' => 101, 'full' => '/avatar.png', 96 => '/avatar.png'] ], + 'return' => true, + 'times' => 1, + ] ); + WP_Mock::userFunction( 'home_url', [ + 'args' => [ '/avatar.png' ], + 'return' => 'https://example.com/avatar-96x96.png', + 'times' => 1, + ] ); WP_Mock::userFunction( 'get_option' ) ->with( 'avatar_rating' ) ->andReturn( false );