Commit inicial - WordPress Análisis de Precios Unitarios

- WordPress core y plugins
- Tema Twenty Twenty-Four configurado
- Plugin allow-unfiltered-html.php simplificado
- .gitignore configurado para excluir wp-config.php y uploads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-11-03 21:04:30 -06:00
commit a22573bf0b
24068 changed files with 4993111 additions and 0 deletions

View File

@@ -0,0 +1,350 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\Authenticator
*
* @package Google\Site_Kit\Modules\Sign_In_With_Google
* @copyright 2024 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google;
use Google\Site_Kit\Core\Storage\User_Options;
use Google\Site_Kit\Core\Util\Input;
use WP_Error;
use WP_User;
/**
* The authenticator class that processes SiwG callback requests to authenticate users.
*
* @since 1.141.0
* @access private
* @ignore
*/
class Authenticator implements Authenticator_Interface {
/**
* Cookie name to store the redirect URL before the user signs in with Google.
*/
const COOKIE_REDIRECT_TO = 'googlesitekit_auth_redirect_to';
/**
* Error codes.
*/
const ERROR_INVALID_REQUEST = 'googlesitekit_auth_invalid_request';
const ERROR_SIGNIN_FAILED = 'googlesitekit_auth_failed';
/**
* User options instance.
*
* @since 1.141.0
* @var User_Options
*/
private $user_options;
/**
* Profile reader instance.
*
* @since 1.141.0
* @var Profile_Reader_Interface
*/
private $profile_reader;
/**
* Constructor.
*
* @since 1.141.0
*
* @param User_Options $user_options User options instance.
* @param Profile_Reader_Interface $profile_reader Profile reader instance.
*/
public function __construct( User_Options $user_options, Profile_Reader_Interface $profile_reader ) {
$this->user_options = $user_options;
$this->profile_reader = $profile_reader;
}
/**
* Authenticates the user using the provided input data.
*
* @since 1.141.0
*
* @param Input $input Input instance.
* @return string Redirect URL.
*/
public function authenticate_user( Input $input ) {
$credential = $input->filter( INPUT_POST, 'credential' );
$user = null;
$payload = $this->profile_reader->get_profile_data( $credential );
if ( ! is_wp_error( $payload ) ) {
$user = $this->find_user( $payload );
if ( ! $user instanceof WP_User ) {
// We haven't found the user using their Google user id and email. Thus we need to create
// a new user. But if the registration is closed, we need to return an error to identify
// that the sign in process failed.
if ( ! $this->is_registration_open() ) {
return $this->get_error_redirect_url( self::ERROR_SIGNIN_FAILED );
} else {
$user = $this->create_user( $payload );
}
}
}
// Redirect to the error page if the user is not found.
if ( is_wp_error( $user ) ) {
return $this->get_error_redirect_url( $user->get_error_code() );
} elseif ( ! $user instanceof WP_User ) {
return $this->get_error_redirect_url( self::ERROR_INVALID_REQUEST );
}
// Sign in the user.
$err = $this->sign_in_user( $user );
if ( is_wp_error( $err ) ) {
return $this->get_error_redirect_url( $err->get_error_code() );
}
return $this->get_redirect_url( $user, $input );
}
/**
* Gets the redirect URL for the error page.
*
* @since 1.145.0
*
* @param string $code Error code.
* @return string Redirect URL.
*/
protected function get_error_redirect_url( $code ) {
return add_query_arg( 'error', $code, wp_login_url() );
}
/**
* Gets the redirect URL after the user signs in with Google.
*
* @since 1.145.0
*
* @param WP_User $user User object.
* @param Input $input Input instance.
* @return string Redirect URL.
*/
protected function get_redirect_url( $user, $input ) {
// Use the admin dashboard URL as the redirect URL by default.
$redirect_to = admin_url();
// If we have the redirect URL in the cookie, use it as the main redirect_to URL.
$cookie_redirect_to = $this->get_cookie_redirect( $input );
if ( ! empty( $cookie_redirect_to ) ) {
$redirect_to = $cookie_redirect_to;
}
// Redirect to HTTPS if user wants SSL.
if ( get_user_option( 'use_ssl', $user->ID ) && str_contains( $redirect_to, 'wp-admin' ) ) {
$redirect_to = preg_replace( '|^http://|', 'https://', $redirect_to );
}
/** This filter is documented in wp-login.php */
$redirect_to = apply_filters( 'login_redirect', $redirect_to, $redirect_to, $user );
if ( ( empty( $redirect_to ) || 'wp-admin/' === $redirect_to || admin_url() === $redirect_to ) ) {
// If the user doesn't belong to a blog, send them to user admin. If the user can't edit posts, send them to their profile.
if ( is_multisite() && ! get_active_blog_for_user( $user->ID ) && ! is_super_admin( $user->ID ) ) {
$redirect_to = user_admin_url();
} elseif ( is_multisite() && ! $user->has_cap( 'read' ) ) {
$redirect_to = get_dashboard_url( $user->ID );
} elseif ( ! $user->has_cap( 'edit_posts' ) ) {
$redirect_to = $user->has_cap( 'read' ) ? admin_url( 'profile.php' ) : home_url();
}
}
return $redirect_to;
}
/**
* Signs in the user.
*
* @since 1.145.0
*
* @param WP_User $user User object.
* @return WP_Error|null WP_Error if an error occurred, null otherwise.
*/
protected function sign_in_user( $user ) {
// Redirect to the error page if the user is not a member of the current blog in multisite.
if ( is_multisite() ) {
$blog_id = get_current_blog_id();
if ( ! is_user_member_of_blog( $user->ID, $blog_id ) ) {
if ( $this->is_registration_open() ) {
add_user_to_blog( $blog_id, $user->ID, $this->get_default_role() );
} else {
return new WP_Error( self::ERROR_INVALID_REQUEST );
}
}
}
// Set the user to be the current user.
wp_set_current_user( $user->ID, $user->user_login );
// Set the authentication cookies and trigger the wp_login action.
wp_set_auth_cookie( $user->ID );
/** This filter is documented in wp-login.php */
do_action( 'wp_login', $user->user_login, $user );
return null;
}
/**
* Finds an existing user using the Google user ID and email.
*
* @since 1.145.0
*
* @param array $payload Google auth payload.
* @return WP_User|null User object if found, null otherwise.
*/
protected function find_user( $payload ) {
// Check if there are any existing WordPress users connected to this Google account.
// The user ID is used as the unique identifier because users can change the email on their Google account.
$g_user_hid = $this->get_hashed_google_user_id( $payload );
$users = get_users(
array(
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
'meta_key' => $this->user_options->get_meta_key( Hashed_User_ID::OPTION ),
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
'meta_value' => $g_user_hid,
'number' => 1,
)
);
if ( ! empty( $users ) ) {
return $users[0];
}
// Find an existing user that matches the email and link to their Google account by store their user ID in user meta.
$user = get_user_by( 'email', $payload['email'] );
if ( $user ) {
$user_options = clone $this->user_options;
$user_options->switch_user( $user->ID );
$user_options->set( Hashed_User_ID::OPTION, $g_user_hid );
return $user;
}
return null;
}
/**
* Create a new user using the Google auth payload.
*
* @since 1.145.0
*
* @param array $payload Google auth payload.
* @return WP_User|WP_Error User object if found or created, WP_Error otherwise.
*/
protected function create_user( $payload ) {
$g_user_hid = $this->get_hashed_google_user_id( $payload );
// Get the default role for new users.
$default_role = $this->get_default_role();
// Create a new user.
$user_id = wp_insert_user(
array(
'user_pass' => wp_generate_password( 64 ),
'user_login' => $payload['email'],
'user_email' => $payload['email'],
'display_name' => $payload['name'],
'first_name' => $payload['given_name'],
'last_name' => $payload['family_name'],
'role' => $default_role,
'meta_input' => array(
$this->user_options->get_meta_key( Hashed_User_ID::OPTION ) => $g_user_hid,
),
)
);
if ( is_wp_error( $user_id ) ) {
return new WP_Error( self::ERROR_SIGNIN_FAILED );
}
// Add the user to the current site if it is a multisite.
if ( is_multisite() ) {
add_user_to_blog( get_current_blog_id(), $user_id, $default_role );
}
// Send the new user notification.
wp_send_new_user_notifications( $user_id );
return get_user_by( 'id', $user_id );
}
/**
* Gets the hashed Google user ID from the provided payload.
*
* @since 1.145.0
*
* @param array $payload Google auth payload.
* @return string Hashed Google user ID.
*/
private function get_hashed_google_user_id( $payload ) {
return md5( $payload['sub'] );
}
/**
* Checks if the registration is open.
*
* @since 1.145.0
*
* @return bool True if registration is open, false otherwise.
*/
protected function is_registration_open() {
// No need to check the multisite settings because it is already
// incorporated in the following users_can_register check.
// See: https://github.com/WordPress/WordPress/blob/505b7c55f5363d51e7e28d512ce7dcb2d5f45894/wp-includes/ms-default-filters.php#L20.
return get_option( 'users_can_register' );
}
/**
* Gets the default role for new users.
*
* @since 1.141.0
* @since 1.145.0 Updated the function visibility to protected.
*
* @return string Default role.
*/
protected function get_default_role() {
$default_role = get_option( 'default_role' );
if ( empty( $default_role ) ) {
$default_role = 'subscriber';
}
return $default_role;
}
/**
* Gets the path for the redirect cookie.
*
* @since 1.141.0
*
* @return string Cookie path.
*/
public static function get_cookie_path() {
return dirname( wp_parse_url( wp_login_url(), PHP_URL_PATH ) );
}
/**
* Gets the redirect URL from the cookie and clears the cookie.
*
* @since 1.146.0
*
* @param Input $input Input instance.
* @return string Redirect URL.
*/
protected function get_cookie_redirect( $input ) {
$cookie_redirect_to = $input->filter( INPUT_COOKIE, self::COOKIE_REDIRECT_TO );
if ( ! empty( $cookie_redirect_to ) && ! headers_sent() ) {
// phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.cookies_setcookie
setcookie( self::COOKIE_REDIRECT_TO, '', time() - 3600, self::get_cookie_path(), COOKIE_DOMAIN );
}
return $cookie_redirect_to;
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\Authenticator_Interface
*
* @package Google\Site_Kit\Modules\Sign_In_With_Google
* @copyright 2024 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google;
use Google\Site_Kit\Core\Util\Input;
/**
* Defines methods that must be implemented by an authenticator class.
*
* @since 1.141.0
* @access private
* @ignore
*/
interface Authenticator_Interface {
/**
* Authenticates the user using the provided input data.
*
* @since 1.141.0
*
* @param Input $input Input instance.
* @return string Redirect URL.
*/
public function authenticate_user( Input $input );
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\Compatibility_Checks\Compatibility_Check
*
* @package Google\Site_Kit\Modules\Sign_In_With_Google
* @copyright 2025 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google\Compatibility_Checks;
/**
* Abstract base class for compatibility checks.
*
* @since 1.164.0
*/
abstract class Compatibility_Check {
/**
* Gets the unique slug for this compatibility check.
*
* @since 1.164.0
*
* @return string The unique slug for this compatibility check.
*/
abstract public function get_slug();
/**
* Runs the compatibility check.
*
* @since 1.164.0
*
* @return array The result of the compatibility check.
*/
abstract public function run();
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\Compatibility_Checks\Compatibility_Checks
*
* @package Google\Site_Kit\Modules\Sign_In_With_Google
* @copyright 2025 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google\Compatibility_Checks;
/**
* Manager class for compatibility checks.
*
* @since 1.164.0
*/
class Compatibility_Checks {
/**
* Collection of compatibility checks.
*
* @since 1.164.0
*
* @var array
*/
private $checks = array();
/**
* Adds a compatibility check to the collection.
*
* @since 1.164.0
*
* @param Compatibility_Check $check The compatibility check to add.
*/
public function add_check( Compatibility_Check $check ) {
$this->checks[] = $check;
}
/**
* Runs all compatibility checks.
*
* @since 1.164.0
*
* @return array Results of the compatibility checks.
*/
public function run_checks() {
$results = array();
foreach ( $this->checks as $check ) {
$result = $check->run();
if ( $result ) {
$results[ $check->get_slug() ] = $result;
}
}
return $results;
}
}

View File

@@ -0,0 +1,76 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\Compatibility_Checks\Conflicting_Plugins_Check
*
* @package Google\Site_Kit\Modules\Sign_In_With_Google
* @copyright 2025 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google\Compatibility_Checks;
/**
* Compatibility check for conflicting plugins.
*
* @since 1.164.0
*/
class Conflicting_Plugins_Check extends Compatibility_Check {
/**
* Gets the unique slug for this compatibility check.
*
* @since 1.164.0
*
* @return string The unique slug for this compatibility check.
*/
public function get_slug() {
return 'conflicting_plugins';
}
/**
* Runs the compatibility check.
*
* @since 1.164.0
*
* @return array|false Array of conflicting plugins data if found, false otherwise.
*/
public function run() {
$conflicting_plugins = array();
$active_plugins = get_option( 'active_plugins', array() );
$security_plugins = array(
'better-wp-security/better-wp-security.php',
'security-malware-firewall/security-malware-firewall.php',
'sg-security/sg-security.php',
'hide-my-wp/index.php',
'hide-wp-login/hide-wp-login.php',
'all-in-one-wp-security-and-firewall/wp-security.php',
'sucuri-scanner/sucuri.php',
'wordfence/wordfence.php',
'wps-hide-login/wps-hide-login.php',
);
foreach ( $active_plugins as $plugin_slug ) {
// If the plugin isn't in our array of known plugins with issues,
// try the next plugin slug in the list of active plugins
// (eg. "exit early").
if ( ! in_array( $plugin_slug, $security_plugins, true ) ) {
continue;
}
$plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin_slug );
$plugin_name = $plugin_data['Name'];
$conflicting_plugins[ $plugin_slug ] = array(
'pluginName' => $plugin_name,
'conflictMessage' => sprintf(
/* translators: %s: plugin name */
__( '%s may prevent Sign in with Google from working properly.', 'google-site-kit' ),
$plugin_name
),
);
}
return ! empty( $conflicting_plugins ) ? $conflicting_plugins : false;
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\Compatibility_Checks\WP_COM_Check
*
* @package Google\Site_Kit\Modules\Sign_In_With_Google
* @copyright 2025 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google\Compatibility_Checks;
/**
* Compatibility check for WordPress.com hosting.
*
* @since 1.164.0
*/
class WP_COM_Check extends Compatibility_Check {
/**
* Gets the unique slug for this compatibility check.
*
* @since 1.164.0
*
* @return string The unique slug for this compatibility check.
*/
public function get_slug() {
return 'host_wordpress_dot_com';
}
/**
* Runs the compatibility check.
*
* @since 1.164.0
*
* @return bool True if hosted on WordPress.com, false otherwise.
*/
public function run() {
return defined( 'WPCOMSH_VERSION' );
}
}

View File

@@ -0,0 +1,52 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\Compatibility_Checks\WP_Login_Accessible_Check
*
* @package Google\Site_Kit\Modules\Sign_In_With_Google
* @copyright 2025 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google\Compatibility_Checks;
/**
* Compatibility check for WordPress login accessibility.
*
* @since 1.164.0
*/
class WP_Login_Accessible_Check extends Compatibility_Check {
/**
* Gets the unique slug for this compatibility check.
*
* @since 1.164.0
*
* @return string The unique slug for this compatibility check.
*/
public function get_slug() {
return 'wp_login_inaccessible';
}
/**
* Runs the compatibility check.
*
* @since 1.164.0
*
* @return bool True if login is inaccessible (404), false otherwise.
*/
public function run() {
// Hardcode the wp-login at the end to avoid issues with filters - plugins modifying the wp-login page
// also override the URL request which skips the correct detection.
$login_url = site_url() . '/wp-login.php';
$response = wp_remote_head( $login_url );
if ( is_wp_error( $response ) ) {
return false;
}
$status_code = wp_remote_retrieve_response_code( $response );
return 404 === $status_code;
}
}

View File

@@ -0,0 +1,84 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\Datapoint\Compatibility_Checks
*
* @package Google\Site_Kit\Modules\Sign_In_With_Google\Datapoint
* @copyright 2025 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google\Datapoint;
use Google\Site_Kit\Core\Modules\Datapoint;
use Google\Site_Kit\Core\Modules\Executable_Datapoint;
use Google\Site_Kit\Core\Permissions\Permissions;
use Google\Site_Kit\Core\REST_API\Data_Request;
use Google\Site_Kit\Modules\Sign_In_With_Google\Compatibility_Checks\Compatibility_Checks as Checks;
use WP_Error;
/**
* Class for the compatibility-check datapoint.
*
* @since 1.164.0
* @access private
* @ignore
*/
class Compatibility_Checks extends Datapoint implements Executable_Datapoint {
/**
* Compatibilty checks instance.
*
* @since 1.164.0
* @var Checks
*/
private $checks;
/**
* Constructor.
*
* @since 1.164.0
*
* @param array $definition Definition fields.
*/
public function __construct( array $definition ) {
parent::__construct( $definition );
if ( isset( $definition['checks'] ) ) {
$this->checks = $definition['checks'];
}
}
/**
* Creates a request object.
*
* @since 1.164.0
*
* @param Data_Request $data Data request object.
*/
public function create_request( Data_Request $data ) {
if ( ! current_user_can( Permissions::MANAGE_OPTIONS ) ) {
return new WP_Error( 'rest_forbidden', __( 'You are not allowed to access this resource.', 'google-site-kit' ), array( 'status' => 403 ) );
}
return function () {
return array(
'checks' => $this->checks->run_checks(),
'timestamp' => time(),
);
};
}
/**
* Parses a response.
*
* @since 1.164.0
*
* @param mixed $response Request response.
* @param Data_Request $data Data request object.
* @return mixed The original response without any modifications.
*/
public function parse_response( $response, Data_Request $data ) {
return $response;
}
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\Existing_Client_ID
*
* @package Google\Site_Kit\Modules\Sign_In_With_Google
* @copyright 2024 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google;
use Google\Site_Kit\Core\Storage\Setting;
/**
* Class for persisting the client ID between module disconnection and
* reconnection.
*
* @since 1.142.0
* @access private
* @ignore
*/
class Existing_Client_ID extends Setting {
/**
* The option_name for this setting.
*/
const OPTION = 'googlesitekit_siwg_existing_client_id';
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\Hashed_User_ID
*
* @package Google\Site_Kit\Modules\Sign_In_With_Google
* @copyright 2024 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google;
use Google\Site_Kit\Core\Storage\User_Setting;
/**
* Class representing the hashed Google user ID.
*
* @since 1.141.0
* @access private
* @ignore
*/
final class Hashed_User_ID extends User_Setting {
/**
* User option key.
*/
const OPTION = 'googlesitekitpersistent_siwg_google_user_hid';
}

View File

@@ -0,0 +1,68 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\Profile_Reader
*
* @package Google\Site_Kit\Modules\Sign_In_With_Google
* @copyright 2024 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google;
use Exception;
use Google\Site_Kit_Dependencies\Google_Client;
use WP_Error;
/**
* Reads Google user profile data.
*
* @since 1.141.0
* @access private
* @ignore
*/
class Profile_Reader implements Profile_Reader_Interface {
/**
* Settings instance.
*
* @since 1.141.0
* @var Settings
*/
private $settings;
/**
* Constructor.
*
* @since 1.141.0
*
* @param Settings $settings Settings instance.
*/
public function __construct( Settings $settings ) {
$this->settings = $settings;
}
/**
* Gets the user profile data using the provided ID token.
*
* @since 1.141.0
*
* @param string $id_token ID token.
* @return array|WP_Error User profile data or WP_Error on failure.
*/
public function get_profile_data( $id_token ) {
try {
$settings = $this->settings->get();
$google_client = new Google_Client( array( 'client_id' => $settings['clientID'] ) );
$payload = $google_client->verifyIdToken( $id_token );
if ( empty( $payload['sub'] ) || empty( $payload['email'] ) || empty( $payload['email_verified'] ) ) {
return new WP_Error( 'googlesitekit_siwg_bad_payload' );
}
return $payload;
} catch ( Exception $e ) {
return new WP_Error( 'googlesitekit_siwg_failed_to_get_payload', $e->getMessage() );
}
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\Profile_Reader_Interface
*
* @package Google\Site_Kit\Modules\Sign_In_With_Google
* @copyright 2024 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google;
use WP_Error;
/**
* Defines methods that must be implemented by a profile reader class.
*
* @since 1.141.0
* @access private
* @ignore
*/
interface Profile_Reader_Interface {
/**
* Gets the user profile data using the provided ID token.
*
* @since 1.141.0
*
* @param string $id_token ID token.
* @return array|WP_Error User profile data or WP_Error on failure.
*/
public function get_profile_data( $id_token );
}

View File

@@ -0,0 +1,199 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\Settings
*
* @package Google\Site_Kit\Modules\Sign_In_With_Google
* @copyright 2024 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google;
use Google\Site_Kit\Core\Modules\Module_Settings;
/**
* Class for Sign_In_With_Google settings.
*
* @since 1.137.0
* @access private
* @ignore
*/
class Settings extends Module_Settings {
const OPTION = 'googlesitekit_sign-in-with-google_settings';
const TEXT_CONTINUE_WITH_GOOGLE = array(
'value' => 'continue_with',
'label' => 'Continue with Google',
);
const TEXT_SIGN_IN = array(
'value' => 'signin',
'label' => 'Sign in',
);
const TEXT_SIGN_IN_WITH_GOOGLE = array(
'value' => 'signin_with',
'label' => 'Sign in with Google',
);
const TEXT_SIGN_UP_WITH_GOOGLE = array(
'value' => 'signup_with',
'label' => 'Sign up with Google',
);
const TEXTS = array(
self::TEXT_CONTINUE_WITH_GOOGLE,
self::TEXT_SIGN_IN,
self::TEXT_SIGN_IN_WITH_GOOGLE,
self::TEXT_SIGN_UP_WITH_GOOGLE,
);
const THEME_LIGHT = array(
'value' => 'outline',
'label' => 'Light',
);
const THEME_NEUTRAL = array(
'value' => 'filled_blue',
'label' => 'Neutral',
);
const THEME_DARK = array(
'value' => 'filled_black',
'label' => 'Dark',
);
const THEMES = array(
self::THEME_LIGHT,
self::THEME_NEUTRAL,
self::THEME_DARK,
);
const SHAPE_RECTANGULAR = array(
'value' => 'rectangular',
'label' => 'Rectangular',
);
const SHAPE_PILL = array(
'value' => 'pill',
'label' => 'Pill',
);
const SHAPES = array(
self::SHAPE_RECTANGULAR,
self::SHAPE_PILL,
);
/**
* Gets the default value.
*
* @since 1.137.0
*
* @return array An array of default settings values.
*/
protected function get_default() {
return array(
'clientID' => '',
'text' => self::TEXT_SIGN_IN_WITH_GOOGLE['value'],
'theme' => self::THEME_LIGHT['value'],
'shape' => self::SHAPE_RECTANGULAR['value'],
'oneTapEnabled' => false,
'showNextToCommentsEnabled' => false,
);
}
/**
* Gets the callback for sanitizing the setting's value before saving.
*
* @since 1.137.0
*
* @return callable|null
*/
protected function get_sanitize_callback() {
return function ( $option ) {
if ( ! is_array( $option ) ) {
return $option;
}
if ( isset( $option['clientID'] ) ) {
$option['clientID'] = (string) $option['clientID'];
}
if ( isset( $option['text'] ) ) {
$text_options = array(
self::TEXT_CONTINUE_WITH_GOOGLE['value'],
self::TEXT_SIGN_IN['value'],
self::TEXT_SIGN_IN_WITH_GOOGLE['value'],
self::TEXT_SIGN_UP_WITH_GOOGLE['value'],
);
if ( ! in_array( $option['text'], $text_options, true ) ) {
$option['text'] = self::TEXT_SIGN_IN_WITH_GOOGLE['value'];
}
}
if ( isset( $option['theme'] ) ) {
$theme_options = array(
self::THEME_LIGHT['value'],
self::THEME_NEUTRAL['value'],
self::THEME_DARK['value'],
);
if ( ! in_array( $option['theme'], $theme_options, true ) ) {
$option['theme'] = self::THEME_LIGHT['value'];
}
}
if ( isset( $option['shape'] ) ) {
$shape_options = array(
self::SHAPE_RECTANGULAR['value'],
self::SHAPE_PILL['value'],
);
if ( ! in_array( $option['shape'], $shape_options, true ) ) {
$option['shape'] = self::SHAPE_RECTANGULAR['value'];
}
}
if ( isset( $option['oneTapEnabled'] ) ) {
$option['oneTapEnabled'] = (bool) $option['oneTapEnabled'];
}
if ( isset( $option['showNextToCommentsEnabled'] ) ) {
$option['showNextToCommentsEnabled'] = (bool) $option['showNextToCommentsEnabled'];
}
return $option;
};
}
/**
* Gets the label for a given Sign in with Google setting value.
*
* @since 1.140.0
*
* @param string $setting_name The slug for the Sign in with Google setting.
* @param string $value The setting value to look up the label for.
* @return string The label for the given setting value.
*/
public function get_label( $setting_name, $value ) {
switch ( $setting_name ) {
case 'text':
$constant = self::TEXTS;
break;
case 'theme':
$constant = self::THEMES;
break;
case 'shape':
$constant = self::SHAPES;
break;
}
if ( ! isset( $constant ) ) {
return '';
}
$key = array_search( $value, array_column( $constant, 'value' ), true );
if ( false === $key ) {
return '';
}
return $constant[ $key ]['label'];
}
}

View File

@@ -0,0 +1,128 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\Sign_In_With_Google_Block
*
* @package Google\Site_Kit\Modules\Sign_In_With_Google
* @copyright 2025 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google;
use Google\Site_Kit\Context;
use Google\Site_Kit\Core\Util\Block_Support;
/**
* Sign in with Google Gutenberg Block.
*
* @since 1.147.0
*/
class Sign_In_With_Google_Block {
/**
* Context instance.
*
* @since 1.147.0
* @var Context
*/
protected $context;
/**
* Constructor.
*
* @since 1.147.0
*
* @param Context $context Plugin context.
*/
public function __construct( Context $context ) {
$this->context = $context;
}
/**
* Checks whether the block can be registered.
*
* @since 1.147.0
*
* @return bool
*/
public static function can_register() {
return Block_Support::has_block_support();
}
/**
* Register this block.
*
* @since 1.147.0
*/
public function register() {
if ( ! self::can_register() ) {
return;
}
add_action(
'init',
function () {
register_block_type(
dirname( GOOGLESITEKIT_PLUGIN_MAIN_FILE ) . '/dist/assets/blocks/sign-in-with-google/block.json',
array(
'render_callback' => array( $this, 'render_callback' ),
)
);
},
99
);
}
/**
* Render callback for the Sign in with Google block.
*
* @since 1.147.0
* @since 1.165.0 Added the `$attributes` parameter.
*
* @param array $attributes Block attributes.
* @return string Rendered block.
*/
public function render_callback( $attributes = array() ) {
// If the user is already signed in, do not render a Sign in
// with Google button.
if ( is_user_logged_in() ) {
return '';
}
$attributes = is_array( $attributes ) ? $attributes : array();
$button_args = array();
$allowed_attributes = array(
'text' => wp_list_pluck( Settings::TEXTS, 'value' ),
'theme' => wp_list_pluck( Settings::THEMES, 'value' ),
'shape' => wp_list_pluck( Settings::SHAPES, 'value' ),
);
foreach ( array( 'text', 'theme', 'shape' ) as $key ) {
if ( ! empty( $attributes[ $key ] ) && in_array( $attributes[ $key ], $allowed_attributes[ $key ], true ) ) {
$button_args[ $key ] = $attributes[ $key ];
}
}
if ( ! empty( $attributes['buttonClassName'] ) && is_string( $attributes['buttonClassName'] ) ) {
$classes = array_filter(
preg_split( '/\s+/', trim( $attributes['buttonClassName'] ) )
);
if ( ! empty( $classes ) ) {
$button_args['class'] = $classes;
}
}
ob_start();
/**
* Display the Sign in with Google button.
*
* @since 1.164.0
*
* @param array $args Optional arguments to customize button attributes.
*/
do_action( 'googlesitekit_render_sign_in_with_google_button', $button_args );
return ob_get_clean();
}
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\Tag_Guard
*
* @package Google\Site_Kit\Modules\Sign_In_With_Google
* @copyright 2024 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google;
use Google\Site_Kit\Core\Modules\Module_Settings;
use Google\Site_Kit\Core\Modules\Tags\Module_Tag_Guard;
/**
* Class for the Sign in with Google tag guard.
*
* @since 1.159.0
* @access private
* @ignore
*/
class Tag_Guard extends Module_Tag_Guard {
/**
* Determines whether the guarded tag can be activated or not.
*
* @since 1.159.0
*
* @return bool|WP_Error TRUE if guarded tag can be activated, otherwise FALSE or an error.
*/
public function can_activate() {
$settings = $this->settings->get();
// If there's no client ID available, don't render the button.
if ( ! $settings['clientID'] ) {
return false;
}
// If the site does not use https, don't render the button.
if ( substr( wp_login_url(), 0, 5 ) !== 'https' ) {
return false;
}
return true;
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\Tag_Matchers
*
* @package Google\Site_Kit\Core\Modules\Sign_In_With_Google
* @copyright 2024 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google;
use Google\Site_Kit\Core\Modules\Tags\Module_Tag_Matchers;
use Google\Site_Kit\Core\Tags\Tag_Matchers_Interface;
/**
* Class for Tag matchers.
*
* @since 1.140.0
* @access private
* @ignore
*/
class Tag_Matchers extends Module_Tag_Matchers implements Tag_Matchers_Interface {
/**
* Holds array of regex tag matchers.
*
* @since 1.140.0
*
* @return array Array of regex matchers.
*/
public function regex_matchers() {
return array();
}
}

View File

@@ -0,0 +1,263 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\Web_Tag
*
* @package Google\Site_Kit\Modules\Sign_In_With_Google
* @copyright 2024 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google;
use Google\Site_Kit\Core\Modules\Tags\Module_Web_Tag;
use Google\Site_Kit\Core\Util\BC_Functions;
use Google\Site_Kit\Core\Util\Method_Proxy_Trait;
use Google\Site_Kit\Modules\Sign_In_With_Google\Authenticator;
/**
* Class for Web tag.
*
* @since 1.159.0
* @access private
* @ignore
*/
class Web_Tag extends Module_Web_Tag {
use Method_Proxy_Trait;
/**
* Module settings.
*
* @since 1.159.0
* @var Settings
*/
private $settings;
/**
* Whether the current page is the WordPress login page.
*
* `is_login()` isn't available until WP 6.1.
*
* @since 1.159.0
* @var bool
*/
private $is_wp_login;
/**
* Redirect to URL.
*
* @since 1.159.0
* @var string
*/
private $redirect_to;
/**
* Sets the module settings.
*
* @since 1.159.0
*
* @param array $settings Module settings as array.
*/
public function set_settings( array $settings ) {
$this->settings = $settings;
}
/**
* Sets whether the current page is the WordPress login page.
*
* @since 1.159.0
*
* @param bool $is_wp_login Whether the current page is the WordPress login page.
*/
public function set_is_wp_login( $is_wp_login ) {
$this->is_wp_login = $is_wp_login;
}
/**
* Sets the redirect to URL.
*
* @since 1.159.0
*
* @param string $redirect_to Redirect to URL.
*/
public function set_redirect_to( $redirect_to ) {
if ( ! empty( $redirect_to ) ) {
$this->redirect_to = trim( $redirect_to );
}
}
/**
* Registers tag hooks.
*
* @since 1.159.0
*/
public function register() {
// Render the Sign in with Google script that converts placeholder
// <div>s with Sign in with Google buttons.
add_action( 'wp_footer', $this->get_method_proxy( 'render' ) );
// Output the Sign in with Google JS on the WordPress login page.
add_action( 'login_footer', $this->get_method_proxy( 'render' ) );
$this->do_init_tag_action();
}
/**
* Renders the Sign in with Google JS script tags, One Tap code, and
* buttons.
*
* @since 1.139.0
* @since 1.144.0 Renamed to `render_signinwithgoogle` and conditionally
* rendered the code to replace buttons.
* @since 1.159.0 moved from main Sign_In_With_Google class to Web_Tag.
*/
protected function render() {
$is_woocommerce = class_exists( 'woocommerce' );
$is_woocommerce_login = did_action( 'woocommerce_login_form_start' );
$login_uri = add_query_arg( 'action', 'googlesitekit_auth', wp_login_url() );
$btn_args = array(
'theme' => $this->settings['theme'],
'text' => $this->settings['text'],
'shape' => $this->settings['shape'],
);
// Whether this is a WordPress/WooCommerce login page.
$is_login_page = $this->is_wp_login || $is_woocommerce_login;
// Check to see if we should show the One Tap prompt on this page.
//
// Show the One Tap prompt if:
// 1. One Tap is enabled in settings.
// 2. The user is not logged in.
$should_show_one_tap_prompt = ! empty( $this->settings['oneTapEnabled'] ) && ! is_user_logged_in();
// Set the cookie time to live to 5 minutes. If the redirect_to is
// empty, set the cookie to expire immediately.
$cookie_expire_time = 300000;
if ( empty( $this->redirect_to ) ) {
$cookie_expire_time *= -1;
}
// Render the Sign in with Google script.
ob_start();
?>
( () => {
async function handleCredentialResponse( response ) {
<?php if ( $is_woocommerce && ! $this->is_wp_login ) : // phpcs:ignore Generic.WhiteSpace.ScopeIndent.Incorrect ?>
response.integration = 'woocommerce';
<?php endif; // phpcs:ignore Generic.WhiteSpace.ScopeIndent.Incorrect ?>
try {
const res = await fetch( '<?php echo esc_js( $login_uri ); ?>', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams( response )
} );
/*
Preserve comment text in case of redirect after login on a page
with a Sign in with Google button in the WordPress comments.
*/
const commentText = document.querySelector( '#comment' )?.value;
const postId = document.querySelectorAll( '.googlesitekit-sign-in-with-google__comments-form-button' )?.[0]?.className?.match(/googlesitekit-sign-in-with-google__comments-form-button-postid-(\d+)/)?.[1];
if ( !! commentText?.length ) {
sessionStorage.setItem( `siwg-comment-text-${postId}`, commentText );
}
<?php if ( empty( $this->redirect_to ) && ! $is_login_page ) : // phpcs:ignore Generic.WhiteSpace.ScopeIndent.Incorrect ?>
location.reload();
<?php else : // phpcs:ignore Generic.WhiteSpace.ScopeIndent.Incorrect ?>
if ( res.ok && res.redirected ) {
location.assign( res.url );
}
<?php endif; // phpcs:ignore Generic.WhiteSpace.ScopeIndent.Incorrect ?>
} catch( error ) {
console.error( error );
}
}
if (typeof google !== 'undefined') {
google.accounts.id.initialize( {
client_id: '<?php echo esc_js( $this->settings['clientID'] ); ?>',
callback: handleCredentialResponse,
library_name: 'Site-Kit'
} );
}
<?php if ( $this->is_wp_login ) : // phpcs:ignore Generic.WhiteSpace.ScopeIndent.Incorrect ?>
const buttonDivToAddToLoginForm = document.createElement( 'div' );
buttonDivToAddToLoginForm.classList.add( 'googlesitekit-sign-in-with-google__frontend-output-button' );
document.getElementById( 'login' ).insertBefore( buttonDivToAddToLoginForm, document.getElementById( 'loginform' ) );
<?php endif; // phpcs:ignore Generic.WhiteSpace.ScopeIndent.Incorrect ?>
<?php if ( ! is_user_logged_in() || $this->is_wp_login ) : // phpcs:ignore Generic.WhiteSpace.ScopeIndent.Incorrect ?>
<?php
/**
* Render SiwG buttons for all `<div>` elements with the "magic
* class" on the page.
*
* Mainly used by Gutenberg blocks.
*/
?>
const defaultButtonOptions = <?php echo wp_json_encode( $btn_args ); ?>;
document.querySelectorAll( '.googlesitekit-sign-in-with-google__frontend-output-button' ).forEach( ( siwgButtonDiv ) => {
const buttonOptions = {
shape: siwgButtonDiv.getAttribute( 'data-googlesitekit-siwg-shape' ) || defaultButtonOptions.shape,
text: siwgButtonDiv.getAttribute( 'data-googlesitekit-siwg-text' ) || defaultButtonOptions.text,
theme: siwgButtonDiv.getAttribute( 'data-googlesitekit-siwg-theme' ) || defaultButtonOptions.theme,
};
if (typeof google !== 'undefined') {
google.accounts.id.renderButton( siwgButtonDiv, buttonOptions );
}
});
<?php endif; // phpcs:ignore Generic.WhiteSpace.ScopeIndent.Incorrect ?>
<?php if ( $should_show_one_tap_prompt ) : // phpcs:ignore Generic.WhiteSpace.ScopeIndent.Incorrect ?>
if (typeof google !== 'undefined') {
google.accounts.id.prompt();
}
<?php endif; // phpcs:ignore Generic.WhiteSpace.ScopeIndent.Incorrect ?>
<?php if ( ! empty( $this->redirect_to ) ) : // phpcs:ignore Generic.WhiteSpace.ScopeIndent.Incorrect ?>
const expires = new Date();
expires.setTime( expires.getTime() + <?php echo esc_js( $cookie_expire_time ); ?> );
document.cookie = "<?php echo esc_js( Authenticator::COOKIE_REDIRECT_TO ); ?>=<?php echo esc_js( $this->redirect_to ); ?>;expires=" + expires.toUTCString() + ";path=<?php echo esc_js( Authenticator::get_cookie_path() ); ?>";
<?php endif; // phpcs:ignore Generic.WhiteSpace.ScopeIndent.Incorrect ?>
/*
If there is a matching saved comment text in sessionStorage, restore it
to the comment field and remove it from sessionStorage.
*/
const postId = document.body.className.match(/postid-(\d+)/)?.[1];
const commentField = document.querySelector( '#comment' );
const commentText = sessionStorage.getItem( `siwg-comment-text-${postId}` );
if ( commentText?.length && commentField && !! postId ) {
commentField.value = commentText;
sessionStorage.removeItem( `siwg-comment-text-${postId}` );
}
} )();
<?php
// Strip all whitespace and unnecessary spaces.
$inline_script = preg_replace( '/\s+/', ' ', ob_get_clean() );
$inline_script = preg_replace( '/\s*([{};\(\)\+:,=])\s*/', '$1', $inline_script );
// Output the Sign in with Google script.
printf( "\n<!-- %s -->\n", esc_html__( 'Sign in with Google button added by Site Kit', 'google-site-kit' ) );
?>
<style>
.googlesitekit-sign-in-with-google__frontend-output-button{max-width:320px}
</style>
<?php
BC_Functions::wp_print_script_tag( array( 'src' => 'https://accounts.google.com/gsi/client' ) );
BC_Functions::wp_print_inline_script_tag( $inline_script );
printf( "\n<!-- %s -->\n", esc_html__( 'End Sign in with Google button added by Site Kit', 'google-site-kit' ) );
}
}

View File

@@ -0,0 +1,62 @@
<?php
/**
* Class Google\Site_Kit\Modules\Sign_In_With_Google\WooCommerce_Authenticator
*
* @package Google\Site_Kit\Modules\Sign_In_With_Google
* @copyright 2024 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/
namespace Google\Site_Kit\Modules\Sign_In_With_Google;
use Google\Site_Kit\Core\Storage\User_Options;
use Google\Site_Kit\Core\Util\Input;
use WP_Error;
use WP_User;
/**
* The authenticator class that processes Sign in with Google callback
* requests to authenticate users when WooCommerce is activated.
*
* @since 1.145.0
* @access private
* @ignore
*/
class WooCommerce_Authenticator extends Authenticator {
/**
* Gets the redirect URL for the error page.
*
* @since 1.145.0
*
* @param string $code Error code.
* @return string Redirect URL.
*/
protected function get_error_redirect_url( $code ) {
do_action( 'woocommerce_login_failed' );
return add_query_arg( 'error', $code, wc_get_page_permalink( 'myaccount' ) );
}
/**
* Gets the redirect URL after the user signs in with Google.
*
* @since 1.145.0
* @since 1.146.0 Updated to take into account redirect URL from cookie.
*
* @param WP_User $user User object.
* @param Input $input Input instance.
* @return string Redirect URL.
*/
protected function get_redirect_url( $user, $input ) {
$redirect_to = wc_get_page_permalink( 'myaccount' );
// If we have the redirect URL in the cookie, use it as the main redirect_to URL.
$cookie_redirect_to = $this->get_cookie_redirect( $input );
if ( ! empty( $cookie_redirect_to ) ) {
$redirect_to = $cookie_redirect_to;
}
return apply_filters( 'woocommerce_login_redirect', $redirect_to, $user );
}
}