Support custom login pages
- Add the button (and error messages) to every wp_login_form() form via login_form_top/login_form_bottom; in button-only mode the password fields are wrapped and hidden there. - New template functions m365_login_button() and m365_login_messages(); the shortcode gains divider and messages attributes. - New setting for the custom login page URL: failed sign-ins, the fallback link and the logout redirect point there instead of wp-login.php. Must be a same-site URL. - Button-only mode now blocks every interactive password sign-in through the authenticate filter, not only wp-login.php; XML-RPC, REST, WP-CLI and cron are exempt, plus a filter for trusted exceptions. - Fallback key accepted on any page (init) instead of login_init only. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JJxAHYdMfKPoN4koRc4Ci2
This commit is contained in:
parent
e5db0d49be
commit
701e85ab88
15 changed files with 804 additions and 300 deletions
|
|
@ -32,6 +32,133 @@ class M365_Login_Button {
|
|||
add_filter( 'login_message', array( $this, 'render_above' ), 20 );
|
||||
add_action( 'login_footer', array( $this, 'render_below' ) );
|
||||
add_shortcode( 'm365_login_button', array( $this, 'shortcode' ) );
|
||||
|
||||
// Custom login pages built with wp_login_form().
|
||||
add_filter( 'login_form_top', array( $this, 'form_top' ), 10, 2 );
|
||||
add_filter( 'login_form_bottom', array( $this, 'form_bottom' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the plugin should hook into wp_login_form() output.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function inject_into_forms() {
|
||||
return $this->settings->is_configured() && (bool) $this->settings->get( 'inject_form' ) && ! is_user_logged_in();
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_login_form(): messages above the fields; in button-only mode the fields are wrapped and hidden.
|
||||
*
|
||||
* @param string $content Existing content.
|
||||
* @param array $args wp_login_form() arguments.
|
||||
* @return string
|
||||
*/
|
||||
public function form_top( $content, $args = array() ) {
|
||||
if ( ! $this->inject_into_forms() ) {
|
||||
return $content;
|
||||
}
|
||||
$this->enqueue_frontend();
|
||||
$content .= $this->messages_markup();
|
||||
if ( $this->password_login_hidden() ) {
|
||||
$content .= '<div class="m365-login__hidden-fields" hidden>';
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* wp_login_form(): closes the wrapper and appends the button.
|
||||
*
|
||||
* @param string $content Existing content.
|
||||
* @param array $args wp_login_form() arguments.
|
||||
* @return string
|
||||
*/
|
||||
public function form_bottom( $content, $args = array() ) {
|
||||
if ( ! $this->inject_into_forms() ) {
|
||||
return $content;
|
||||
}
|
||||
$hidden = $this->password_login_hidden();
|
||||
$redirect_to = isset( $args['redirect'] ) ? (string) $args['redirect'] : '';
|
||||
if ( $hidden ) {
|
||||
$content .= '</div>';
|
||||
}
|
||||
$divider = $hidden ? '' : $this->divider_markup();
|
||||
return $content . '<div class="m365-login m365-login--form">' . $divider . $this->button( $redirect_to ) . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether password fields should be hidden right now (button-only mode without fallback).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function password_login_hidden() {
|
||||
return $this->settings->button_only() && ! M365_Login::instance()->auth->fallback_active();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues the stylesheet on the front end (custom login pages).
|
||||
*/
|
||||
public function enqueue_frontend() {
|
||||
wp_enqueue_style( 'm365-login', M365_LOGIN_URL . 'assets/css/login.css', array(), M365_LOGIN_VERSION );
|
||||
wp_add_inline_style( 'm365-login', $this->css_variables() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Divider line markup ('' when the divider text is empty).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function divider_markup() {
|
||||
$divider = (string) $this->settings->get( 'divider_text' );
|
||||
return '' === trim( $divider ) ? '' : '<div class="m365-login__divider" aria-hidden="true"><span>' . esc_html( $divider ) . '</span></div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Error / info messages for custom login pages.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function messages_markup() {
|
||||
$html = '';
|
||||
foreach ( M365_Login::instance()->auth->current_messages() as $msg ) {
|
||||
$html .= '<div class="m365-login__notice m365-login__notice--' . esc_attr( $msg['type'] ) . '" role="' . ( 'error' === $msg['type'] ? 'alert' : 'status' ) . '">' . esc_html( $msg['text'] ) . '</div>';
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Full markup for templates and shortcodes.
|
||||
*
|
||||
* @param array $args {
|
||||
* @type string $redirect Destination after login.
|
||||
* @type bool $show_messages Show error/info messages. Default true.
|
||||
* @type bool $show_divider Show the divider line. Default false.
|
||||
* }
|
||||
* @return string
|
||||
*/
|
||||
public function standalone( $args = array() ) {
|
||||
if ( ! $this->settings->is_configured() || is_user_logged_in() ) {
|
||||
return '';
|
||||
}
|
||||
$args = wp_parse_args(
|
||||
$args,
|
||||
array(
|
||||
'redirect' => '',
|
||||
'show_messages' => true,
|
||||
'show_divider' => false,
|
||||
)
|
||||
);
|
||||
$this->enqueue_frontend();
|
||||
|
||||
$html = '<div class="m365-login m365-login--shortcode">';
|
||||
if ( $args['show_messages'] ) {
|
||||
$html .= $this->messages_markup();
|
||||
}
|
||||
if ( $args['show_divider'] && ! $this->password_login_hidden() ) {
|
||||
$html .= $this->divider_markup();
|
||||
}
|
||||
$html .= $this->button( esc_url_raw( (string) $args['redirect'] ) );
|
||||
return $html . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -142,15 +269,22 @@ class M365_Login_Button {
|
|||
* @return string
|
||||
*/
|
||||
public function shortcode( $atts ) {
|
||||
if ( ! $this->settings->is_configured() || is_user_logged_in() ) {
|
||||
return '';
|
||||
}
|
||||
$atts = shortcode_atts( array( 'redirect' => '' ), $atts, 'm365_login_button' );
|
||||
|
||||
wp_enqueue_style( 'm365-login', M365_LOGIN_URL . 'assets/css/login.css', array(), M365_LOGIN_VERSION );
|
||||
wp_add_inline_style( 'm365-login', $this->css_variables() );
|
||||
|
||||
return '<div class="m365-login m365-login--shortcode">' . $this->button( esc_url_raw( $atts['redirect'] ) ) . '</div>';
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'redirect' => '',
|
||||
'messages' => 'yes',
|
||||
'divider' => 'no',
|
||||
),
|
||||
$atts,
|
||||
'm365_login_button'
|
||||
);
|
||||
return $this->standalone(
|
||||
array(
|
||||
'redirect' => $atts['redirect'],
|
||||
'show_messages' => 'no' !== strtolower( (string) $atts['messages'] ),
|
||||
'show_divider' => 'yes' === strtolower( (string) $atts['divider'] ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -163,8 +297,7 @@ class M365_Login_Button {
|
|||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- passed through to the flow, validated there.
|
||||
$redirect_to = isset( $_REQUEST['redirect_to'] ) ? esc_url_raw( wp_unslash( $_REQUEST['redirect_to'] ) ) : '';
|
||||
|
||||
$divider = $this->form_hidden() ? '' : (string) $this->settings->get( 'divider_text' );
|
||||
$divider = '' === trim( $divider ) ? '' : '<div class="m365-login__divider" aria-hidden="true"><span>' . esc_html( $divider ) . '</span></div>';
|
||||
$divider = $this->form_hidden() ? '' : $this->divider_markup();
|
||||
|
||||
$html = '<div class="m365-login m365-login--' . esc_attr( $position ) . '" id="m365-login-block">';
|
||||
$html .= 'above' === $position ? $this->button( $redirect_to ) . $divider : $divider . $this->button( $redirect_to );
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue