Discourse가 SSO 제공자인 경우 WordPress 아바타

저는 WordPress에 Discourse를 설정했으며, Discourse가 WP의 DiscourseConnect 제공자 역할을 하고 있습니다. WP Discourse 플러그인을 사용하고 있으며, 지금까지는 잘 작동하고 있습니다. 지금까지 만난 유일한 문제는 Discourse의 아바타 이미지를 WP에 표시할 수 없다는 것입니다.

Could you update user avatar for wordpress plugin sso? - #2 by angus 의 해결책을 구현해 보려고 WP 사이트의 function.php 파일에 코드를 추가했습니다. 하지만 제 환경에서는 작동하지 않으며, 아바타를 설정하기 위해 어떤 코드를 추가해야 하는지 모르겠습니다.

혹시 이 문제를 해결하신 분이 계신지 궁금합니다. 저는 Simple Local Avatar 플러그인을 사용 중이지만, 다른 플러그인으로 성공한 사례가 있다면 변경할 의향이 있습니다.

안녕하세요 @uffehe

어떤 코드를 추가하고 있으며, Simple Local Avatar 플러그인은 아바타를 어떻게 저장하나요?

안녕하세요 @angus

저는 개발자가 아니라서 여기서는 추측하는 부분이 좀 있지만, 제 이해로는 Simple Local Avatar 플러그인이 일반적으로 이미지를 미디어 라이브러리에 추가하는 방식이라고 알고 있습니다. URL을 통해 제공되는 경우 어떻게 작동하는지에 대한 문서를 많이 찾지 못했습니다. 제가 시도하고 있는 코드는 다음과 같습니다:

add_filter( 'wpdc_sso_client_updated_user', 'my_wpdc_sso_client_updated_user', 10, 2 );
function my_wpdc_sso_client_updated_user( $updated_user, $query ) {
    if (isset($query['avatar_url'])) {
        $new_avatar_url = $query['avatar_url'];

        $avatar_data = array(
            'full' => $new_avatar_url,  // 새 아바타 이미지의 URL
        );
        update_user_meta($updated_user, 'simple_local_avatar', $avatar_data);
    }
}

이렇게 하면 SSO를 사용하여 로그인하려고 할 때 처리되지 않은 예외가 발생합니다.

개발자를 고용해서 도움을 받을 수도 있겠지만, 이는 다른 사람들도 이미 구현했을 가능성이 있는 꽤 일반적인 사용 사례인 것 같습니다 - 이 플러그인을 사용하지 않았더라도요.

예외의 원인은 function my_wpdc_sso_client_updated_user가 $updated_user 배열을 반환하지 않기 때문일 것입니다. 이 배열은 wpdc_sso_client_updated_user 필터를 추가하는 함수가 계속 진행되려면 필요합니다.

또한 update_user_meta 호출 시 사용자의 WordPress 사용자 ID를 설정해야 합니다.

다음은 작동하지만 Simple Local Avatars 플러그인의 리스케일링 기능을 비활성화합니다:

add_filter( 'simple_local_avatars_dynamic_resize', '__return_false' ); // 아바타 리사이즈 방지
add_filter( 'wpdc_sso_client_updated_user', 'my_wpdc_sso_client_updated_user', 10, 2 );
function my_wpdc_sso_client_updated_user( $updated_user, $query ) {
	if ( isset( $query['avatar_url'] ) ) {
		$new_avatar_url = $query['avatar_url'];
		$wp_user_id = $updated_user['ID'];

		$avatar_data = array(
			'full' => $new_avatar_url,  // 새 아바타 이미지의 URL
		);
		update_user_meta( $wp_user_id, 'simple_local_avatar', $avatar_data );
	}

	return $updated_user;
}

아바타 리사이즈를 방지하는 이유는 리사이즈가 WordPress 이미지 편집기 코드로 수행되기 때문입니다. 이 기능이 작동하려면 이미지가 WordPress로 다운로드되어야 합니다. 참고로 위의 코드에서 add_filter( 'simple_local_avatars_dynamic_resize', '__return_false' ) 줄을 제거하면 Simple Local Avatars 플러그인이 이미지를 리사이즈하려고 시도하고 PHP 경고를 발생시킨 후 전체 크기의 이미지를 사용합니다. 따라서 사용자 관점에서는 아무것도 깨진 것처럼 보이지 않을 수 있습니다.

Discourse 아바타 사용과 Simple Local Avatars 플러그인을 결합하는 것에 대해 다소 불확실합니다. 제가 발견한 문제는 이 플러그인이 WordPress에서 사용자 정의 아바타를 업로드할 수 있는 옵션을 사용자에게 제공한다는 점입니다. 사용자가 그렇게 한 후 Discourse에서 다시 WordPress에 로그인하면 업로드한 아바타가 어디로 갔는지 궁금해할 수 있습니다. 개발이 더 복잡해지겠지만, 사용자의 WordPress 프로필 페이지에서 Discourse 아바타를 의도적으로 WordPress 아바타로 설정할 수 있는 기능을 추가하는 것이 더 나은 방법일 수 있습니다.

그럴 수도 있습니다. 어쨌든 살펴보고 있었기 때문에, Simple Local Avatars 플러그인을 사용하지 않는 방식을 시도해 보았습니다.

아래 코드는 사용자가 Discourse를 통해 WordPress에 로그인될 때 호출되는 'wpdc_sso_client_updated_user' 필터에 연결됩니다. 사용자가 Discourse에 커스텀 아바타를 업로드한 경우, 해당 사용자의 Discourse custom_avatar_template이 WordPress의 사용자 메타데이터로 저장됩니다. 이후 WordPress의 'get_avatar_url' 필터에 연결하여 Discourse의 custom_avatar_template을 사용해 아바타 URL을 설정합니다. 이 방식은 Discourse의 템플릿 리사이징 기능을 활용할 수 있기 때문에 마음에 듭니다.

로컬에서만 테스트했다는 점을 유의해 주세요.

use WPDiscourse\Utilities\Utilities as DiscourseUtilities;
add_filter( 'wpdc_sso_client_updated_user', 'my_wpdc_sso_client_updated_user', 10, 2 );
function my_wpdc_sso_client_updated_user( $updated_user, $query ) {
	$options  = DiscourseUtilities::get_options();
	$base_url = $options['url'];
	$discourse_username    = $query['username'];
	$discourse_profile_url = "{$base_url}/u/{$discourse_username}.json";
	$wp_user_id             = $updated_user['ID'];
	$profile_data           = DiscourseUtilities::discourse_request( $discourse_profile_url );
	if ( is_wp_error( $profile_data ) ) {

		return $updated_user;
	}

    // 사용자가 Discourse에서 업로드한 아바타에 대한 템플릿이 있는지 확인합니다.
	$user_data = $profile_data->user;
	if ( ! property_exists( $user_data, 'custom_avatar_template' ) ) {

		return $updated_user;
	}

	$custom_avatar_template_path = $profile_data->user->custom_avatar_template;
    $custom_avatar_template = "{$base_url}{$custom_avatar_template_path}";
    // 아바타 템플릿을 저장합니다. 표시할 크기는 `get_avatar_url` 필터에서 치환됩니다.
    update_user_meta( $wp_user_id, 'discourse_avatar_template', $custom_avatar_template );

    return $updated_user;
}

add_filter('get_avatar_url', 'my_get_avatar_url', 10, 3 );
function my_get_avatar_url($url, $id_or_email, $args ) {
    // `$user_id`는 `null`로 시작합니다. 아래 코드는 일부 경우를 놓칠 수 있습니다.
    $user_id = null;
    if ( is_numeric( $id_or_email ) ) {
        $user_id = $id_or_email;
    } elseif ( $id_or_email instanceof WP_User ) {
        $user_id = $id_or_email->ID;
    } elseif ( $id_or_email instanceof WP_Post ) {
        $user_id = $id_or_email->user_id;
    } elseif ( $id_or_email instanceof WP_Comment ) {
        $user_id = $id_or_email->user_id;
    }

    // `$user_id`가 설정되지 않은 경우, `$url` 매개변수를 반환합니다.
    if ( empty( $user_id ) ) {

        return $url;
    }

    $discourse_avatar_template = get_user_meta( $user_id, 'discourse_avatar_template', true );
    // 템플릿 메타데이터가 설정되지 않은 경우, `$url`을 반환합니다.
    if (empty( $discourse_avatar_template ) ) {

        return $url;
    }

    $size = isset( $args['size']) ? $args['size'] : 128;  // 'size'가 비어 있을 수 있는지 확실하지 않습니다. 128이 안전한 기본값으로 보입니다.

    return str_replace( '{size}', $size, $discourse_avatar_template );
}

안녕하세요 @simon

완벽합니다 — 설명하신 대로 정확히 작동합니다. 그리고 동의합니다. WP 플러그인이 필요 없고, 충돌하는 아바타에 대한 혼란도 없으니 훨씬 깔끔하네요. 감사합니다!