diff --git a/inc/Core/OAuth/BaseAuthProvider.php b/inc/Core/OAuth/BaseAuthProvider.php index 29b816074..8674dbf49 100644 --- a/inc/Core/OAuth/BaseAuthProvider.php +++ b/inc/Core/OAuth/BaseAuthProvider.php @@ -61,12 +61,27 @@ public function is_configured(): bool { } /** - * Get the callback URL for this provider + * Get the callback URL for this provider. + * + * @since 0.67.0 * * @return string Callback URL */ public function get_callback_url(): string { - return site_url( "/datamachine-auth/{$this->provider_slug}/" ); + $url = site_url( "/datamachine-auth/{$this->provider_slug}/" ); + + /** + * Filters the OAuth callback URL for an auth provider. + * + * Allows plugins to customize the callback URL to match their + * OAuth client's registered redirect URI. + * + * @since 0.67.0 + * + * @param string $url The default callback URL. + * @param string $provider_slug The provider slug (e.g. 'wpcom', 'twitter'). + */ + return apply_filters( 'datamachine_oauth_callback_url', $url, $this->provider_slug ); } /** diff --git a/inc/Engine/Filters/OAuth.php b/inc/Engine/Filters/OAuth.php index 87caad860..700dce9bf 100644 --- a/inc/Engine/Filters/OAuth.php +++ b/inc/Engine/Filters/OAuth.php @@ -16,7 +16,10 @@ * @return string Callback URL */ function datamachine_get_oauth_callback_url( string $provider ): string { - return site_url( "/datamachine-auth/{$provider}/" ); + $url = site_url( "/datamachine-auth/{$provider}/" ); + + /** This filter is documented in inc/Core/OAuth/BaseAuthProvider.php */ + return apply_filters( 'datamachine_oauth_callback_url', $url, $provider ); } // Legacy storage functions removed. Use BaseAuthProvider methods instead. diff --git a/tests/Unit/Core/OAuth/BaseAuthProviderTest.php b/tests/Unit/Core/OAuth/BaseAuthProviderTest.php index 965abf301..caa1f5b16 100644 --- a/tests/Unit/Core/OAuth/BaseAuthProviderTest.php +++ b/tests/Unit/Core/OAuth/BaseAuthProviderTest.php @@ -174,4 +174,64 @@ public function test_callback_url_uses_provider_slug(): void { $this->assertStringContainsString( '/datamachine-auth/test_provider/', $url ); } + + public function test_callback_url_is_filterable(): void { + $custom_url = 'https://example.com/oauth/callback'; + + add_filter( + 'datamachine_oauth_callback_url', + function ( $url, $slug ) use ( $custom_url ) { + if ( 'test_provider' === $slug ) { + return $custom_url; + } + return $url; + }, + 10, + 2 + ); + + $this->assertSame( $custom_url, $this->provider->get_callback_url() ); + + remove_all_filters( 'datamachine_oauth_callback_url' ); + } + + public function test_callback_url_filter_passes_provider_slug(): void { + $received_slug = null; + + add_filter( + 'datamachine_oauth_callback_url', + function ( $url, $slug ) use ( &$received_slug ) { + $received_slug = $slug; + return $url; + }, + 10, + 2 + ); + + $this->provider->get_callback_url(); + + $this->assertSame( 'test_provider', $received_slug ); + + remove_all_filters( 'datamachine_oauth_callback_url' ); + } + + public function test_callback_url_filter_does_not_affect_other_providers(): void { + add_filter( + 'datamachine_oauth_callback_url', + function ( $url, $slug ) { + if ( 'other_provider' === $slug ) { + return 'https://example.com/other/callback'; + } + return $url; + }, + 10, + 2 + ); + + $url = $this->provider->get_callback_url(); + + $this->assertStringContainsString( '/datamachine-auth/test_provider/', $url ); + + remove_all_filters( 'datamachine_oauth_callback_url' ); + } }