diff --git a/README.md b/README.md index 7f8fca07..925a8394 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ passwords. Just one click and land into the site! 3. Once you create the app, you will receive the `Client ID` and `Client Secret`, add these credentials in `Settings > Login with Google` settings page in their respective fields. + - If you have a multisite setup, navigate to `Network Settings` for the site and place the credentials over there as they are globally applied. For the remaining settings mentioned below, you can choose for the subsites to have their individual configurations or have a standard configuration be applied globally to all subsites. 4. `Create new user` enables new user registration irrespective of `Membership` settings in `Settings > General`; as sometimes enabling user registration can lead to lots of spam users. diff --git a/readme.txt b/readme.txt index 266eed89..6cf37e27 100644 --- a/readme.txt +++ b/readme.txt @@ -29,12 +29,13 @@ Ultra minimal plugin to let your users login to WordPress applications using the 3. This will give you **Client ID** and **Secret key**. -4. Input these values either in `WP Admin > Settings > WP Google Login`, or in `wp-config.php` using the following code snippet: +4. Input these values either in `WP Admin > Settings > Login With Google`, or in `wp-config.php` using the following code snippet: ``` define( 'WP_GOOGLE_LOGIN_CLIENT_ID', 'YOUR_GOOGLE_CLIENT_ID' ); define( 'WP_GOOGLE_LOGIN_SECRET', 'YOUR_SECRET_KEY' ); ``` +If you have a multisite setup, only `Network Administrator` will be able to modify these credentials from `Network Admin > Settings > Login With Google`. ### Browser support [These browsers are supported](https://developers.google.com/identity/gsi/web/guides/supported-browsers). Note, for example, that One Tap Login is not supported in Safari. diff --git a/src/Container.php b/src/Container.php index 8ce01d65..762bbcc9 100644 --- a/src/Container.php +++ b/src/Container.php @@ -116,8 +116,8 @@ public function define_services(): void { return new GoogleClient( [ - 'client_id' => $settings->client_id, - 'client_secret' => $settings->client_secret, + 'client_id' => $settings->get_client_id(), + 'client_secret' => $settings->get_client_secret(), 'redirect_uri' => wp_login_url(), ] ); diff --git a/src/Modules/Settings.php b/src/Modules/Settings.php index 71215273..743452dd 100644 --- a/src/Modules/Settings.php +++ b/src/Modules/Settings.php @@ -15,30 +15,23 @@ use RtCamp\GoogleLogin\Interfaces\Module as ModuleInterface; /** - * Class Settings. - * - * @property string|null whitelisted_domains - * @property string|null client_id - * @property string|null client_secret - * @property bool|null registration_enabled - * @property bool|null one_tap_login - * @property string one_tap_login_screen + * Class Settings * * @package RtCamp\GoogleLogin\Modules */ class Settings implements ModuleInterface { /** - * Settings values. + * Options array. * * @var array */ public $options; /** - * Getters for settings values. + * List of getters for settings. * - * @var string[] + * @var array */ private $getters = [ 'WP_GOOGLE_LOGIN_CLIENT_ID' => 'client_id', @@ -50,22 +43,34 @@ class Settings implements ModuleInterface { ]; /** - * Getter method. + * Magic getter to access settings as properties. + * + * @param string $name Name of the property. * - * @param string $name Name of option to fetch. + * @return mixed */ public function __get( string $name ) { if ( in_array( $name, $this->getters, true ) ) { $constant_name = array_search( $name, $this->getters, true ); + if ( defined( $constant_name ) ) { + return constant( $constant_name ); + } - return defined( $constant_name ) ? constant( $constant_name ) : ( $this->options[ $name ] ?? '' ); - } + // Multisite: If apply_globally is enabled, use network settings. + if ( is_multisite() ) { + $network_settings = get_site_option( 'wp_google_login_network_settings', [] ); + if ( ! empty( $network_settings['apply_globally'] ) && array_key_exists( $name, $network_settings ) ) { + return $network_settings[ $name ]; + } + } + return $this->options[ $name ] ?? null; + } return null; } /** - * Return module name. + * Name of the module. * * @return string */ @@ -74,66 +79,310 @@ public function name(): string { } /** - * Initialization of module. - * - * @return void + * Initializes the settings module. */ public function init(): void { $this->options = get_option( 'wp_google_login_settings', [] ); - /** - * Actions. - */ add_action( 'admin_init', [ $this, 'register_settings' ] ); add_action( 'admin_menu', [ $this, 'settings_page' ] ); - /** - * Filters. - */ - // Add filters here. + if ( is_multisite() ) { + add_action( 'network_admin_menu', [ $this, 'register_network_settings_page' ] ); + add_action( 'network_admin_menu', [ $this, 'register_network_settings' ] ); + add_action( 'network_admin_edit_wp_google_login_network_settings', [ $this, 'save_network_settings' ] ); + } } /** - * Register the settings, section and fields. + * Retrieves the Google OAuth Client ID, always from the network settings in multisite. + * + * @since n.e.x.t + * + * @return string + */ + public function get_client_id(): string { + if ( is_multisite() ) { + $network_settings = get_site_option( 'wp_google_login_network_settings', [] ); + return $network_settings['client_id'] ?? ''; + } + return $this->client_id; + } + + /** + * Retrieves the Google OAuth Client Secret, always from the network settings in multisite. + * + * @return string + */ + public function get_client_secret(): string { + if ( is_multisite() ) { + $network_settings = get_site_option( 'wp_google_login_network_settings', [] ); + return $network_settings['client_secret'] ?? ''; + } + return $this->client_secret; + } + + /** + * Registers the network settings page for multisite installations. * * @return void */ - public function register_settings(): void { - register_setting( 'wp_google_login', 'wp_google_login_settings' ); + public function register_network_settings_page(): void { + add_submenu_page( + 'settings.php', + __( 'Login with Google Network Settings', 'login-with-google' ), + _x( 'Login with Google', 'Page title', 'login-with-google' ), + 'manage_network_options', + 'login-with-google-network', + [ $this, 'output_network_settings' ] + ); + } + + /** + * Outputs the network settings page HTML. + * + * @return void + */ + public function output_network_settings(): void { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended + if ( isset( $_GET['updated'] ) ) { + echo '

' . esc_html__( 'Settings saved.', 'login-with-google' ) . '

'; + } + ?> +
+

+
+ +
+
+ 'client-id' ] + 'login-with-google-network', + 'wp_google_login_network_section', + [ + 'context' => 'network', + 'label_for' => 'client-id', + ] ); add_settings_field( 'wp_google_login_client_secret', __( 'Client Secret', 'login-with-google' ), [ $this, 'client_secret_field' ], - 'login-with-google', + 'login-with-google-network', + 'wp_google_login_network_section', + [ + 'context' => 'network', + 'label_for' => 'client-secret', + ] + ); + + add_settings_field( + 'wp_google_login_apply_globally', + __( 'Apply settings to all sites in the network', 'login-with-google' ), + [ $this, 'apply_globally_field' ], + 'login-with-google-network', + 'wp_google_login_network_section', + [ + 'context' => 'network', + 'label_for' => 'apply-globally', + ] + ); + + add_settings_field( + 'wp_google_allow_registration', + __( 'Create New User', 'login-with-google' ), + [ $this, 'user_registration' ], + 'login-with-google-network', + 'wp_google_login_network_section', + [ + 'context' => 'network', + 'label_for' => 'user-registration', + ] + ); + + add_settings_field( + 'wp_google_one_tap_login', + __( 'Enable One Tap Login', 'login-with-google' ), + [ $this, 'one_tap_login' ], + 'login-with-google-network', + 'wp_google_login_network_section', + [ + 'context' => 'network', + 'label_for' => 'one-tap-login', + ] + ); + + add_settings_field( + 'wp_google_one_tap_login_screen', + __( 'One Tap Login Locations', 'login-with-google' ), + [ $this, 'one_tap_login_screens' ], + 'login-with-google-network', + 'wp_google_login_network_section', + [ + 'context' => 'network', + 'label_for' => 'one-tap-login-screen', + ] + ); + + add_settings_field( + 'wp_google_whitelisted_domain', + __( 'Whitelisted Domains', 'login-with-google' ), + [ $this, 'whitelisted_domains' ], + 'login-with-google-network', + 'wp_google_login_network_section', + [ + 'context' => 'network', + 'label_for' => 'whitelisted-domains', + ] + ); + } + + /** + * Saves the network settings for multisite installations. + * + * @since n.e.x.t + * + * @return void + */ + public function save_network_settings(): void { + if ( ! current_user_can( 'manage_network_options' ) ) { + wp_die( esc_html__( 'Sorry, you are not allowed to manage network options.', 'login-with-google' ) ); + } + + check_admin_referer( 'wp_google_login_network-options' ); + + $defaults = [ + 'apply_globally' => 0, + 'one_tap_login' => 0, + 'registration_enabled' => 0, + 'one_tap_login_screen' => 'login', + 'whitelisted_domains' => '', + 'client_id' => '', + 'client_secret' => '', + ]; + + $settings = $_POST['wp_google_login_network_settings'] ?? []; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + // Sanitizing the settings array below. + + // Sanitize each field. + $sanitized_settings = [ + 'apply_globally' => isset( $settings['apply_globally'] ) ? 1 : 0, + 'one_tap_login' => isset( $settings['one_tap_login'] ) ? 1 : 0, + 'registration_enabled' => isset( $settings['registration_enabled'] ) ? 1 : 0, + 'one_tap_login_screen' => isset( $settings['one_tap_login_screen'] ) ? sanitize_text_field( $settings['one_tap_login_screen'] ) : 'login', + 'whitelisted_domains' => isset( $settings['whitelisted_domains'] ) ? sanitize_text_field( $settings['whitelisted_domains'] ) : '', + 'client_id' => isset( $settings['client_id'] ) ? sanitize_text_field( $settings['client_id'] ) : '', + 'client_secret' => isset( $settings['client_secret'] ) ? sanitize_text_field( $settings['client_secret'] ) : '', + ]; + + $settings = array_merge( $defaults, $sanitized_settings ); + + update_site_option( 'wp_google_login_network_settings', $settings ); + + wp_cache_delete( 'wp_google_login_network_settings', 'site-options' ); + + wp_safe_redirect( + add_query_arg( + [ + 'page' => 'login-with-google-network', + 'updated' => 'true', + ], + network_admin_url( 'settings.php' ) + ) + ); + exit; + } + + /** + * Registers the settings for the single site installations. + * + * @return void + */ + public function register_settings(): void { + // Only allow registration in network admin for network settings. + if ( is_multisite() && is_network_admin() ) { + return; + } + + register_setting( 'wp_google_login', 'wp_google_login_settings' ); + + add_settings_section( 'wp_google_login_section', - [ 'label_for' => 'client-secret' ] + __( 'Log in with Google Settings', 'login-with-google' ), + function () {}, + 'login-with-google' ); + // Only show client_id/client_secret on single site installs. + if ( ! is_multisite() ) { + add_settings_field( + 'wp_google_login_client_id', + __( 'Client ID', 'login-with-google' ), + [ $this, 'client_id_field' ], + 'login-with-google', + 'wp_google_login_section', + [ 'label_for' => 'client-id' ] + ); + + add_settings_field( + 'wp_google_login_client_secret', + __( 'Client Secret', 'login-with-google' ), + [ $this, 'client_secret_field' ], + 'login-with-google', + 'wp_google_login_section', + [ 'label_for' => 'client-secret' ] + ); + } + + // For multisite subsites, check if apply_globally is enabled. + $readonly = false; + $network_settings = []; + if ( is_multisite() && ! is_network_admin() ) { + $network_settings = get_site_option( 'wp_google_login_network_settings', [] ); + $readonly = ! empty( $network_settings['apply_globally'] ); + } + add_settings_field( 'wp_google_allow_registration', __( 'Create New User', 'login-with-google' ), [ $this, 'user_registration' ], 'login-with-google', 'wp_google_login_section', - [ 'label_for' => 'user-registration' ] + [ + 'label_for' => 'user-registration', + 'readonly' => $readonly, + 'network_settings' => $network_settings, + ] ); add_settings_field( @@ -142,7 +391,11 @@ function () { [ $this, 'one_tap_login' ], 'login-with-google', 'wp_google_login_section', - [ 'label_for' => 'one-tap-login' ] + [ + 'label_for' => 'one-tap-login', + 'readonly' => $readonly, + 'network_settings' => $network_settings, + ] ); add_settings_field( @@ -151,7 +404,11 @@ function () { [ $this, 'one_tap_login_screens' ], 'login-with-google', 'wp_google_login_section', - [ 'label_for' => 'one-tap-login-screen' ] + [ + 'label_for' => 'one-tap-login-screen', + 'readonly' => $readonly, + 'network_settings' => $network_settings, + ] ); add_settings_field( @@ -160,18 +417,30 @@ function () { [ $this, 'whitelisted_domains' ], 'login-with-google', 'wp_google_login_section', - [ 'label_for' => 'whitelisted-domains' ] + [ + 'label_for' => 'whitelisted-domains', + 'readonly' => $readonly, + 'network_settings' => $network_settings, + ] ); } /** - * Render client ID field. + * Renders the input field for the Client ID setting. + * + * @param array $args Additional arguments for the field. * * @return void */ - public function client_id_field(): void { + public function client_id_field( $args = [] ): void { + $is_network = isset( $args['context'] ) && 'network' === $args['context']; + $value = $is_network + ? ( get_site_option( 'wp_google_login_network_settings' )['client_id'] ?? '' ) + : $this->get_client_id(); // Use the robust getter! + $name = $is_network ? 'wp_google_login_network_settings[client_id]' : 'wp_google_login_settings[client_id]'; ?> - disabled( 'client_id' ); ?> /> + +

get_client_secret(); + $name = $is_network ? 'wp_google_login_network_settings[client_secret]' : 'wp_google_login_settings[client_secret]'; ?> - disabled( 'client_secret' ); ?> /> + + + /> + + + General + * @param array $args Additional arguments for the field. + * @since n.e.x.t * * @return void */ - public function user_registration(): void { + public function user_registration( $args = [] ): void { + $is_network = isset( $args['context'] ) && 'network' === $args['context']; + $readonly = ! empty( $args['readonly'] ); + $network_settings = $args['network_settings'] ?? []; + + if ( $is_network ) { + $checked = ! empty( get_site_option( 'wp_google_login_network_settings', [] )['registration_enabled'] ); + ?> + +

+ membership setting is off.', 'login-with-google' ), + 'settings.php' + ) + ); + ?> +

+ + /> + +