<?php
class Jetpack_SSO {
static $instance = null;
private function __construct() {
self::$instance = $this;
add_action( 'admin_init', array( $this, 'admin_init' ) );
add_action( 'admin_init', array( $this, 'register_settings' ) );
add_action( 'login_init', array( $this, 'login_init' ) );
add_action( 'delete_user', array( $this, 'delete_connection_for_user' ) );
add_filter( 'jetpack_xmlrpc_methods', array( $this, 'xmlrpc_methods' ) );
add_action( 'init', array( $this, 'maybe_logout_user' ), 5 );
add_action( 'jetpack_modules_loaded', array( $this, 'module_configure_button' ) );
add_action( 'login_form_jetpack-sso', '__return_true' );
if (
$this->should_hide_login_form() &&
apply_filters( 'jetpack_sso_display_disclaimer', true )
) {
add_action( 'login_message', array( $this, 'msg_login_by_jetpack' ) );
}
}
public static function get_instance() {
if( !is_null( self::$instance ) )
return self::$instance;
return self::$instance = new Jetpack_SSO;
}
public static function module_configure_button() {
Jetpack::enable_module_configurable( __FILE__ );
Jetpack::module_configuration_load( __FILE__, array( __CLASS__, 'module_configuration_load' ) );
Jetpack::module_configuration_head( __FILE__, array( __CLASS__, 'module_configuration_head' ) );
Jetpack::module_configuration_screen( __FILE__, array( __CLASS__, 'module_configuration_screen' ) );
}
public static function module_configuration_load() {
}
public static function module_configuration_head() {}
public static function module_configuration_screen() {
?>
<form method="post" action="options.php">
<?php settings_fields( 'jetpack-sso' ); ?>
<?php do_settings_sections( 'jetpack-sso' ); ?>
<?php submit_button(); ?>
</form>
<?php
}
public function maybe_logout_user() {
global $current_user;
if( 1 == $current_user->jetpack_force_logout ) {
delete_user_meta( $current_user->ID, 'jetpack_force_logout' );
self::delete_connection_for_user( $current_user->ID );
wp_logout();
wp_safe_redirect( wp_login_url() );
}
}
public function xmlrpc_methods( $methods ) {
$methods['jetpack.userDisconnect'] = array( $this, 'xmlrpc_user_disconnect' );
return $methods;
}
public function xmlrpc_user_disconnect( $user_id ) {
$user_query = new WP_User_Query(
array(
'meta_key' => 'wpcom_user_id',
'meta_value' => $user_id
)
);
$user = $user_query->get_results();
$user = $user[0];
if( $user instanceof WP_User ) {
$user = wp_set_current_user( $user->ID );
update_user_meta( $user->ID, 'jetpack_force_logout', '1' );
self::delete_connection_for_user( $user->ID );
return true;
}
return false;
}
public function register_settings() {
add_settings_section(
'jetpack_sso_settings',
__( 'Single Sign On' , 'jetpack' ),
'__return_false',
'jetpack-sso'
);
register_setting(
'jetpack-sso',
'jetpack_sso_require_two_step',
array( $this, 'validate_jetpack_sso_require_two_step' )
);
add_settings_field(
'jetpack_sso_require_two_step',
'',
array( $this, 'render_require_two_step' ),
'jetpack-sso',
'jetpack_sso_settings'
);
register_setting(
'jetpack-sso',
'jetpack_sso_match_by_email',
array( $this, 'validate_jetpack_sso_match_by_email' )
);
add_settings_field(
'jetpack_sso_match_by_email',
'',
array( $this, 'render_match_by_email' ),
'jetpack-sso',
'jetpack_sso_settings'
);
}
public function render_require_two_step() {
echo '<label>';
echo '<input type="checkbox" name="jetpack_sso_require_two_step" ' . checked( 1 == get_option( 'jetpack_sso_require_two_step' ), true, false ) . '> ';
esc_html_e( 'Require Two-Step Authentication' , 'jetpack' );
echo '</label>';
}
public function validate_jetpack_sso_require_two_step( $input ) {
return ( ! empty( $input ) ) ? 1 : 0;
}
public function render_match_by_email() {
echo '<label>';
echo '<input type="checkbox" name="jetpack_sso_match_by_email"' . checked( 1 == get_option( 'jetpack_sso_match_by_email' ), true, false) . '> ';
esc_html_e( 'Match by Email', 'jetpack' );
echo '</label>';
}
public function validate_jetpack_sso_match_by_email( $input ) {
return ( ! empty( $input ) ) ? 1 : 0;
}
public function render_remove_login_form_checkbox() {
if( $this->is_user_connected( get_current_user_id() ) ) {
echo '<a name="configure-sso"></a>';
echo '<input type="checkbox" name="jetpack_sso_remove_login_form[remove_login_form]" ' . checked( 1 == get_option( 'jetpack_sso_remove_login_form' ), true, false ) . '>';
echo '<p class="description">Removes default login form and disallows login via POST</p>';
} else {
echo 'Your account must be connected to WordPress.com before disabling the login form.';
echo '<br/>' . $this->button();
}
}
public function validate_settings_remove_login_form_checkbox( $input ) {
return ( isset( $input['remove_login_form'] ) )? 1: 0;
}
public function remove_lost_password_text( $text ) {
if( 'Lost your password?' == $text )
$text = '';
return $text;
}
private function wants_to_login() {
$wants_to_login = false;
$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 'login';
$action = isset( $_GET['loggedout'] ) ? 'loggedout' : $action;
if( 'login' == $action ) {
$wants_to_login = true;
}
return $wants_to_login;
}
private function bypass_login_forward_wpcom() {
return apply_filters( 'jetpack_sso_bypass_login_forward_wpcom', false );
}
function login_init() {
global $action;
if( isset( $_GET['loggedout'] ) && $this->bypass_login_forward_wpcom() ) {
add_filter( 'jetpack_remove_login_form', '__return_true' );
add_filter( 'gettext', array( $this, 'remove_lost_password_text' ) );
}
if (
$this->wants_to_login()
&& $this->bypass_login_forward_wpcom()
) {
add_filter( 'allowed_redirect_hosts', array( $this, 'allowed_redirect_hosts' ) );
wp_safe_redirect( $this->build_sso_url() );
}
if ( 'login' === $action ) {
wp_enqueue_script( 'jquery' );
wp_enqueue_style( 'genericons' );
add_action( 'login_footer', array( $this, 'login_form' ) );
add_action( 'login_footer', array( $this, 'login_footer' ) );
} elseif ( 'jetpack-sso' === $action ) {
if ( isset( $_GET['result'], $_GET['user_id'], $_GET['sso_nonce'] ) && 'success' == $_GET['result'] ) {
$this->handle_login();
wp_enqueue_script( 'jquery' );
wp_enqueue_style( 'genericons' );
add_action( 'login_footer', array( $this, 'login_form' ) );
add_action( 'login_footer', array( $this, 'login_footer' ) );
} else {
if ( Jetpack::check_identity_crisis() ) {
wp_die( __( "Error: This site's Jetpack connection is currently experiencing problems.", 'jetpack' ) );
} else {
$this->maybe_save_cookie_redirect();
add_filter( 'allowed_redirect_hosts', array( $this, 'allowed_redirect_hosts' ) );
wp_safe_redirect( $this->build_sso_url() );
}
}
}
}
public static function maybe_save_cookie_redirect() {
if ( headers_sent() ) {
return new WP_Error( 'headers_sent', __( 'Cannot deal with cookie redirects, as headers are already sent.', 'jetpack' ) );
}
if ( ! empty( $_GET['redirect_to'] ) ) {
$url = esc_url_raw( $_GET['redirect_to'] );
setcookie( 'jetpack_sso_redirect_to', $url, time() + HOUR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, false, true );
} elseif ( ! empty( $_COOKIE['jetpack_sso_redirect_to'] ) ) {
setcookie( 'jetpack_sso_redirect_to', ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
}
if ( ! empty( $_GET['rememberme'] ) ) {
setcookie( 'jetpack_sso_remember_me', '1', time() + HOUR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, false, true );
} elseif ( ! empty( $_COOKIE['jetpack_sso_remember_me'] ) ) {
setcookie( 'jetpack_sso_remember_me', ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
}
}
private function should_hide_login_form() {
return apply_filters( 'jetpack_remove_login_form', get_option( 'jetpack_sso_remove_login_form', false ) );
}
function login_form() {
$classes = '';
if( $this->should_hide_login_form() ) {
$classes .= ' forced-sso';
}
echo '<div class="jetpack-sso-wrap' . $classes . '">' . $this->button() . '</div>';
}
function login_footer() {
$hide_login_form = $this->should_hide_login_form();
?>
<style>
#loginform {
overflow: hidden;
padding-bottom: 26px;
}
.jetpack-sso-wrap {
<?php if ( $hide_login_form ) : ?>
text-align: center;
<?php else : ?>
float: right;
<?php endif; ?>
margin: 1em 0 0;
clear: right;
display: block;
}
<?php if ( $hide_login_form ) : ?>
.forced-sso .jetpack-sso.button {
font-size: 16px;
line-height: 27px;
height: 37px;
padding: 5px 12px 6px 47px;
}
.forced-sso .jetpack-sso.button:before {
font-size: 28px !important;
height: 37px;
padding: 5px 5px 4px;
width: 37px;
}
<?php endif; ?>
</style>
<script>
jQuery(document).ready(function($) {
<?php if ( $hide_login_form ) : ?>
$( '#loginform' ).empty();
<?php endif; ?>
$( '#loginform' ).append( $( '.jetpack-sso-wrap' ) );
var $rememberme = $( '#rememberme' ),
$ssoButton = $( 'a.jetpack-sso.button' );
$rememberme.on( 'change', function() {
var url = $ssoButton.prop( 'href' ),
isChecked = $rememberme.prop( 'checked' ) ? 1 : 0;
if ( url.match( /&rememberme=\d/ ) ) {
url = url.replace( /&rememberme=\d/, '&rememberme=' + isChecked );
} else {
url += '&rememberme=' + isChecked;
}
$ssoButton.prop( 'href', url );
} ).change();
});
</script>
<?php
}
static function delete_connection_for_user( $user_id ) {
if ( ! $wpcom_user_id = get_user_meta( $user_id, 'wpcom_user_id', true ) ) {
return;
}
Jetpack::load_xml_rpc_client();
$xml = new Jetpack_IXR_Client( array(
'user_id' => $user_id
) );
$xml->query( 'jetpack.sso.removeUser', $wpcom_user_id );
if ( $xml->isError() ) {
return false;
}
return $xml->getResponse();
}
static function request_initial_nonce() {
Jetpack::load_xml_rpc_client();
$xml = new Jetpack_IXR_Client( array(
'user_id' => get_current_user_id()
) );
$xml->query( 'jetpack.sso.requestNonce' );
if ( $xml->isError() ) {
wp_die( sprintf( '%s: %s', $xml->getErrorCode(), $xml->getErrorMessage() ) );
}
return $xml->getResponse();
}
function handle_login() {
$wpcom_nonce = sanitize_key( $_GET['sso_nonce'] );
$wpcom_user_id = (int) $_GET['user_id'];
$result = sanitize_key( $_GET['result'] );
Jetpack::load_xml_rpc_client();
$xml = new Jetpack_IXR_Client( array(
'user_id' => get_current_user_id()
) );
$xml->query( 'jetpack.sso.validateResult', $wpcom_nonce, $wpcom_user_id );
if ( $xml->isError() ) {
wp_die( sprintf( '%s: %s', $xml->getErrorCode(), $xml->getErrorMessage() ) );
}
$user_data = $xml->getResponse();
if ( empty( $user_data ) ) {
wp_die( __( 'Error, invalid response data.', 'jetpack' ) );
}
$user_data = (object) $user_data;
$user = null;
do_action( 'jetpack_sso_pre_handle_login', $user_data );
$require_two_step = apply_filters( 'jetpack_sso_require_two_step', get_option( 'jetpack_sso_require_two_step' ) );
if( $require_two_step && 0 == (int) $user_data->two_step_enabled ) {
$this->user_data = $user_data;
do_action( 'wp_login_failed', $user_data->login );
add_action( 'login_message', array( $this, 'error_msg_enable_two_step' ) );
return;
}
if ( isset( $_GET['state'] ) && ( 0 < strpos( $_GET['state'], '|' ) ) ) {
list( $state, $nonce ) = explode( '|', $_GET['state'] );
if ( wp_verify_nonce( $nonce, $state ) ) {
if ( 'sso-link-user' == $state ) {
$user = wp_get_current_user();
update_user_meta( $user->ID, 'wpcom_user_id', $user_data->ID );
add_filter( 'login_redirect', array( __CLASS__, 'profile_page_url' ) );
}
} else wp_nonce_ays();
}
if ( empty( $user ) ) {
$user = $this->get_user_by_wpcom_id( $user_data->ID );
}
if ( empty( $user ) && self::match_by_email() ) {
$user = get_user_by( 'email', $user_data->email );
if ( $user ) {
update_user_meta( $user->ID, 'wpcom_user_id', $user_data->ID );
}
}
if ( empty( $user ) && ( get_option( 'users_can_register' ) || self::new_user_override() ) ) {
if ( self::match_by_email() || ! get_user_by( 'email', $user_data->email ) ) {
$username = $user_data->login;
if ( username_exists( $username ) ) {
$username = $user_data->login . '_' . $user_data->ID;
}
$tries = 0;
while ( username_exists( $username ) ) {
$username = $user_data->login . '_' . $user_data->ID . '_' . mt_rand();
if ( $tries++ >= 5 ) {
wp_die( __( "Error: Couldn't create suitable username.", 'jetpack' ) );
}
}
$password = wp_generate_password( 20 );
$user_id = wp_create_user( $username, $password, $user_data->email );
$user = get_userdata( $user_id );
$user->display_name = $user_data->display_name;
$user->first_name = $user_data->first_name;
$user->last_name = $user_data->last_name;
$user->url = $user_data->url;
$user->description = $user_data->description;
wp_update_user( $user );
update_user_meta( $user->ID, 'wpcom_user_id', $user_data->ID );
} else {
$this->user_data = $user_data;
add_action( 'login_message', array( $this, 'error_msg_email_already_exists' ) );
return;
}
}
do_action( 'jetpack_sso_handle_login', $user, $user_data );
if ( $user ) {
update_user_meta( $user->ID, 'wpcom_user_data', $user_data );
$remember = false;
if ( ! empty( $_COOKIE['jetpack_sso_remember_me'] ) ) {
$remember = true;
setcookie( 'jetpack_sso_remember_me', ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
}
$remember = apply_filters( 'jetpack_remember_login', $remember );
wp_set_auth_cookie( $user->ID, $remember );
do_action( 'wp_login', $user->user_login, $user );
$_request_redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
$redirect_to = user_can( $user, 'edit_posts' ) ? admin_url() : self::profile_page_url();
if ( ! empty( $_COOKIE['jetpack_sso_redirect_to'] ) ) {
$redirect_to = $_request_redirect_to = esc_url_raw( $_COOKIE['jetpack_sso_redirect_to'] );
setcookie( 'jetpack_sso_redirect_to', ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
}
wp_safe_redirect(
apply_filters( 'login_redirect', $redirect_to, $_request_redirect_to, $user )
);
exit;
}
$this->user_data = $user_data;
do_action( 'wp_login_failed', $user_data->login );
add_action( 'login_message', array( $this, 'cant_find_user' ) );
}
static function profile_page_url() {
return admin_url( 'profile.php' );
}
static function match_by_email() {
$match_by_email = ( 1 == get_option( 'jetpack_sso_match_by_email', true ) ) ? true: false;
$match_by_email = defined( 'WPCC_MATCH_BY_EMAIL' ) ? WPCC_MATCH_BY_EMAIL : $match_by_email;
return apply_filters( 'jetpack_sso_match_by_email', $match_by_email );
}
static function new_user_override() {
$new_user_override = defined( 'WPCC_NEW_USER_OVERRIDE' ) ? WPCC_NEW_USER_OVERRIDE : false;
return apply_filters( 'jetpack_sso_new_user_override', $new_user_override );
}
function allowed_redirect_hosts( $hosts ) {
if ( empty( $hosts ) ) {
$hosts = array();
}
$hosts[] = 'wordpress.com';
return array_unique( $hosts );
}
function button( $args = array() ) {
$defaults = array(
'action' => 'jetpack-sso',
);
$args = wp_parse_args( $args, $defaults );
if ( ! empty( $_GET['redirect_to'] ) ) {
$args['redirect_to'] = esc_url_raw( $_GET['redirect_to'] );
}
$url = add_query_arg( $args, wp_login_url() );
$css = "<style>
.jetpack-sso.button {
position: relative;
padding-left: 37px;
}
.jetpack-sso.button:before {
display: block;
box-sizing: border-box;
padding: 7px 0 0;
text-align: center;
position: absolute;
top: -1px;
left: -1px;
border-radius: 2px 0 0 2px;
content: '\\f205';
background: #0074a2;
color: #fff;
-webkit-font-smoothing: antialiased;
width: 30px;
height: 107%;
height: calc( 100% + 2px );
font: normal 22px/1 Genericons !important;
text-shadow: none;
}
@media screen and (min-width: 783px) {
.jetpack-sso.button:before {
padding-top: 3px;
}
}
.jetpack-sso.button:hover {
border: 1px solid #aaa;
}";
if ( version_compare( $GLOBALS['wp_version'], '3.8-alpha', '<' ) ) {
$css .= "
.jetpack-sso.button:before {
width: 25px;
font-size: 18px !important;
}
";
}
$css .= "</style>";
$button = sprintf( '<a href="%1$s" class="jetpack-sso button">%2$s</a>', esc_url( $url ), esc_html__( 'Log in with WordPress.com', 'jetpack' ) );
return $button . $css;
}
function build_sso_url( $args = array() ) {
$defaults = array(
'action' => 'jetpack-sso',
'site_id' => Jetpack_Options::get_option( 'id' ),
'sso_nonce' => self::request_initial_nonce(),
);
if ( isset( $_GET['state'] ) && check_admin_referer( $_GET['state'] ) ) {
$defaults['state'] = rawurlencode( $_GET['state'] . '|' . $_GET['_wpnonce'] );
}
$args = wp_parse_args( $args, $defaults );
$url = add_query_arg( $args, 'https:
return $url;
}
static function get_user_by_wpcom_id( $wpcom_user_id ) {
$user_query = new WP_User_Query( array(
'meta_key' => 'wpcom_user_id',
'meta_value' => intval( $wpcom_user_id ),
'number' => 1,
) );
$users = $user_query->get_results();
return $users ? array_shift( $users ) : null;
}
public function error_msg_enable_two_step( $message ) {
$err = __( sprintf( 'This site requires two step authentication be enabled for your user account on WordPress.com. Please visit the <a href="%1$s"> Security Settings</a> page to enable two step', 'https:
$message .= sprintf( '<p class="message" id="login_error">%s</p>', $err );
return $message;
}
public function error_msg_email_already_exists( $message ) {
$err = __( sprintf( 'You already have an account on this site. Please visit your <a href="%1$s">profile page</a> page to link your account to WordPress.com!', admin_url( 'profile.php' ) ) , 'jetpack' );
$message .= sprintf( '<p class="message" id="login_error">%s</p>', $err );
return $message;
}
public function msg_login_by_jetpack( $message ) {
$msg = __( sprintf( 'Jetpack authenticates through WordPress.com * to log in, enter your WordPress.com username and password, or <a href="%1$s">visit WordPress.com</a> to create a free account now.', 'http:
$msg = apply_filters( 'jetpack_sso_disclaimer_message', $msg );
$message .= sprintf( '<p class="message">%s</p>', $msg );
return $message;
}
public function error_msg_login_method_not_allowed( $message ) {
$err = __( 'Login method not allowed' , 'jetpack' );
$message .= sprintf( '<p class="message" id="login_error">%s</p>', $err );
return $message;
}
function cant_find_user( $message ) {
if ( self::match_by_email() ) {
$err_format = __( 'We couldn\'t find an account with the email <strong><code>%1$s</code></strong> to log you in with. If you already have an account on <strong>%2$s</strong>, please make sure that <strong><code>%1$s</code></strong> is configured as the email address, or that you have connected to WordPress.com on your profile page.', 'jetpack' );
} else {
$err_format = __( 'We couldn\'t find any account on <strong>%2$s</strong> that is linked to your WordPress.com account to log you in with. If you already have an account on <strong>%2$s</strong>, please make sure that you have connected to WordPress.com on your profile page.', 'jetpack' );
}
$err = sprintf( $err_format, $this->user_data->email, get_bloginfo( 'name' ) );
$message .= sprintf( '<p class="message" id="login_error">%s</p>', $err );
return $message;
}
function admin_init() {
add_action( 'show_user_profile', array( $this, 'edit_profile_fields' ) );
add_action( 'edit_user_profile', array( $this, 'edit_profile_fields' ) );
if ( isset( $_GET['jetpack_sso'] ) && 'purge' == $_GET['jetpack_sso'] && check_admin_referer( 'jetpack_sso_purge' ) ) {
$user = wp_get_current_user();
self::delete_connection_for_user( $user->ID );
delete_user_meta( $user->ID, 'wpcom_user_id' );
delete_user_meta( $user->ID, 'wpcom_user_data' );
wp_safe_redirect( remove_query_arg( array( 'jetpack_sso', '_wpnonce' ) ) );
}
}
public function is_user_connected( $user_id ) {
return $this->get_user_data( $user_id ) ;
}
public function get_user_data( $user_id ) {
return get_user_meta( $user_id, 'wpcom_user_data', true );
}
function edit_profile_fields( $user ) {
wp_enqueue_style( 'genericons' );
?>
<h3 id="single-sign-on"><?php _e( 'Single Sign On', 'jetpack' ); ?></h3>
<p><?php _e( 'Connecting with Single Sign On enables you to log in via your WordPress.com account.', 'jetpack' ); ?></p>
<?php if ( $this->is_user_connected( $user->ID ) ) : ?>
<?php $user_data = $this->get_user_data( $user->ID ); ?>
<table class="form-table jetpack-sso-form-table">
<tbody>
<tr>
<td>
<div class="profile-card">
<?php echo get_avatar( $user_data->email ); ?>
<p class="connected"><strong><?php _e( 'Connected', 'jetpack' ); ?></strong></p>
<p><?php echo esc_html( $user_data->login ); ?></p>
<span class="two_step">
<?php
if( $user_data->two_step_enabled ) {
?> <p class="enabled"><a href="https:
} else {
?> <p class="disabled"><a href="https:
}
?>
</span>
</div>
<p><a class="button button-secondary" href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'jetpack_sso', 'purge' ), 'jetpack_sso_purge' ) ); ?>"><?php _e( 'Unlink This Account', 'jetpack' ); ?></a></p>
</td>
</tr>
</tbody>
</table>
<style>
.jetpack-sso-form-table td {
padding-left: 0;
}
.jetpack-sso-form-table .profile-card {
padding: 10px;
background: #fff;
overflow: hidden;
max-width: 400px;
box-shadow: 0 1px 2px rgba( 0, 0, 0, 0.1 );
margin-bottom: 1em;
}
.jetpack-sso-form-table .profile-card img {
float: left;
margin-right: 1em;
width: 48px;
height: 48px;
}
.jetpack-sso-form-table .profile-card .connected {
float: right;
margin-right: 0.5em;
color: #0a0;
}
.jetpack-sso-form-table .profile-card p {
margin-top: 0.7em;
font-size: 1.2em;
}
.jetpack-sso-form-table .profile-card .two_step .enabled a {
float: right;
color: #0a0;
}
.jetpack-sso-form-table .profile-card .two_step .disabled a {
float: right;
color: red;
}
</style>
<?php elseif ( get_current_user_id() == $user->ID && Jetpack::is_user_connected( $user->ID ) ) : ?>
<?php echo $this->button( 'state=sso-link-user&_wpnonce=' . wp_create_nonce('sso-link-user') );
<?php else : ?>
<p><?php esc_html_e( wptexturize( __( "If you don't have a WordPress.com account yet, you can sign up for free in just a few seconds.", 'jetpack' ) ) ); ?></p>
<a href="<?php echo Jetpack::init()->build_connect_url( false, get_edit_profile_url( get_current_user_id() ) . '#single-sign-on' ); ?>" class="button button-connector" id="wpcom-connect"><?php esc_html_e( 'Link account with WordPress.com', 'jetpack' ); ?></a>
<?php endif;
}
}
Jetpack_SSO::get_instance();