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:
friloo 2026-09-22 14:52:11 +00:00
parent e5db0d49be
commit 701e85ab88
No known key found for this signature in database
15 changed files with 804 additions and 300 deletions

View file

@ -38,7 +38,7 @@ msgstr ""
msgid "Copied!"
msgstr ""
#: includes/class-m365-login-admin.php:148 includes/class-m365-login-admin.php:502 includes/class-m365-login-admin.php:545
#: includes/class-m365-login-admin.php:148 includes/class-m365-login-admin.php:529 includes/class-m365-login-admin.php:572
msgid "Copy"
msgstr ""
@ -62,11 +62,11 @@ msgstr ""
msgid "Add"
msgstr ""
#: includes/class-m365-login-admin.php:154 includes/class-m365-login-admin.php:476
#: includes/class-m365-login-admin.php:154 includes/class-m365-login-admin.php:503
msgid "Remove"
msgstr ""
#: includes/class-m365-login-admin.php:155 includes/class-m365-login-admin.php:210 includes/class-m365-login-admin.php:461
#: includes/class-m365-login-admin.php:155 includes/class-m365-login-admin.php:210 includes/class-m365-login-admin.php:488
msgid "Save the connection settings first, then search for groups."
msgstr ""
@ -284,265 +284,309 @@ msgstr ""
msgid "WordPress blue"
msgstr ""
#: includes/class-m365-login-admin.php:412
msgid "Custom login page"
msgstr ""
#: includes/class-m365-login-admin.php:413
msgid "Using your own login page instead of wp-login.php? Tell the plugin where it is so error messages, the fallback link and the post-logout redirect point there."
msgstr ""
#: includes/class-m365-login-admin.php:416
msgid "User matching & hardening"
msgid "URL of your login page"
msgstr ""
#: includes/class-m365-login-admin.php:417
msgid "Users are never created automatically. A Microsoft sign-in only succeeds when a WordPress user with the same e-mail address already exists."
#: includes/class-m365-login-admin.php:418
msgid "Must be on this site. Leave empty to use wp-login.php."
msgstr ""
#: includes/class-m365-login-admin.php:422
msgid "Bind WordPress accounts to the Microsoft object ID"
#: includes/class-m365-login-admin.php:424
msgid "Add the button to every wp_login_form() form automatically"
msgstr ""
#: includes/class-m365-login-admin.php:423
msgid "On first sign-in the immutable Microsoft object ID is stored with the user. Later sign-ins with the same e-mail but a different Microsoft identity are rejected. Strongly recommended."
#: includes/class-m365-login-admin.php:425
msgid "Covers themes and plugins that use the WordPress login form function. Page-builder widgets need the shortcode or the template function below."
msgstr ""
#: includes/class-m365-login-admin.php:430
msgid "Fall back to the user principal name (UPN)"
msgid "Manual placement"
msgstr ""
#: includes/class-m365-login-admin.php:431
msgid "If the token contains no \"email\" claim, use the UPN (e.g. jane@contoso.com) when it is a valid e-mail address. Usually required for work accounts."
msgid "Shortcode (block editor, page builders):"
msgstr ""
#: includes/class-m365-login-admin.php:438
msgid "Keep users signed in (\"Remember me\")"
#: includes/class-m365-login-admin.php:433
msgid "Template function (theme files):"
msgstr ""
#: includes/class-m365-login-admin.php:439
msgid "Issues a 14-day WordPress session instead of a browser session."
#: includes/class-m365-login-admin.php:435
msgid "Both show the error messages of the last attempt; use m365_login_messages() to place them separately."
msgstr ""
#: includes/class-m365-login-admin.php:443
msgid "User matching & hardening"
msgstr ""
#: includes/class-m365-login-admin.php:444
msgid "Allowed e-mail domains (optional)"
msgid "Users are never created automatically. A Microsoft sign-in only succeeds when a WordPress user with the same e-mail address already exists."
msgstr ""
#: includes/class-m365-login-admin.php:446
msgid "One or more domains separated by commas or new lines. Leave empty to allow any domain of your tenant."
#: includes/class-m365-login-admin.php:449
msgid "Bind WordPress accounts to the Microsoft object ID"
msgstr ""
#: includes/class-m365-login-admin.php:451
msgid "Allowed Entra groups (optional)"
msgstr ""
#: includes/class-m365-login-admin.php:452
msgid "Only members of at least one of these groups may sign in. Leave empty to allow every matched user. Nested memberships count."
msgstr ""
#: includes/class-m365-login-admin.php:455
msgid "Search groups"
#: includes/class-m365-login-admin.php:450
msgid "On first sign-in the immutable Microsoft object ID is stored with the user. Later sign-ins with the same e-mail but a different Microsoft identity are rejected. Strongly recommended."
msgstr ""
#: includes/class-m365-login-admin.php:457
msgid "Type a group name or paste an object ID…"
msgid "Fall back to the user principal name (UPN)"
msgstr ""
#: includes/class-m365-login-admin.php:458
msgid "Search"
msgid "If the token contains no \"email\" claim, use the UPN (e.g. jane@contoso.com) when it is a valid e-mail address. Usually required for work accounts."
msgstr ""
#: includes/class-m365-login-admin.php:463
msgid "Needs the application permission \"GroupMember.Read.All\" with admin consent. Without it you can still paste group object IDs."
#: includes/class-m365-login-admin.php:465
msgid "Keep users signed in (\"Remember me\")"
msgstr ""
#: includes/class-m365-login-admin.php:469
msgid "Selected groups"
#: includes/class-m365-login-admin.php:466
msgid "Issues a 14-day WordPress session instead of a browser session."
msgstr ""
#: includes/class-m365-login-admin.php:470
msgid "No groups selected every matched user may sign in."
#: includes/class-m365-login-admin.php:471
msgid "Allowed e-mail domains (optional)"
msgstr ""
#: includes/class-m365-login-admin.php:480
msgid "Membership is read from the \"groups\" claim of the ID token when present; otherwise the plugin asks Microsoft Graph (application permission \"User.Read.All\" or \"Directory.Read.All\"). If neither works, the sign-in is refused."
#: includes/class-m365-login-admin.php:473
msgid "One or more domains separated by commas or new lines. Leave empty to allow any domain of your tenant."
msgstr ""
#: includes/class-m365-login-admin.php:478
msgid "Allowed Entra groups (optional)"
msgstr ""
#: includes/class-m365-login-admin.php:479
msgid "Only members of at least one of these groups may sign in. Leave empty to allow every matched user. Nested memberships count."
msgstr ""
#: includes/class-m365-login-admin.php:482
msgid "Search groups"
msgstr ""
#: includes/class-m365-login-admin.php:484
msgid "Type a group name or paste an object ID…"
msgstr ""
#: includes/class-m365-login-admin.php:485
msgid "Button-only mode"
msgid "Search"
msgstr ""
#: includes/class-m365-login-admin.php:486
msgid "Hide the username/password form and the \"Lost your password?\" link, and refuse password sign-ins on the login page. Application passwords, REST and XML-RPC are not affected."
#: includes/class-m365-login-admin.php:490
msgid "Needs the application permission \"GroupMember.Read.All\" with admin consent. Without it you can still paste group object IDs."
msgstr ""
#: includes/class-m365-login-admin.php:491
msgid "Show only the Microsoft button on the login page"
msgstr ""
#: includes/class-m365-login-admin.php:492
msgid "Becomes active once the connection is configured. Make sure your own account can sign in via Microsoft before enabling this."
#: includes/class-m365-login-admin.php:496
msgid "Selected groups"
msgstr ""
#: includes/class-m365-login-admin.php:497
msgid "No groups selected every matched user may sign in."
msgstr ""
#: includes/class-m365-login-admin.php:507
msgid "Membership is read from the \"groups\" claim of the ID token when present; otherwise the plugin asks Microsoft Graph (application permission \"User.Read.All\" or \"Directory.Read.All\"). If neither works, the sign-in is refused."
msgstr ""
#: includes/class-m365-login-admin.php:512
msgid "Button-only mode"
msgstr ""
#: includes/class-m365-login-admin.php:513
msgid "Hides the username/password fields (on wp-login.php and in wp_login_form() forms) and refuses every interactive password sign-in on the site, including custom login forms. Application passwords, REST, XML-RPC and WP-CLI are not affected."
msgstr ""
#: includes/class-m365-login-admin.php:518
msgid "Show only the Microsoft button on the login page"
msgstr ""
#: includes/class-m365-login-admin.php:519
msgid "Becomes active once the connection is configured. Make sure your own account can sign in via Microsoft before enabling this."
msgstr ""
#: includes/class-m365-login-admin.php:524
msgid "Fallback link (keep it secret)"
msgstr ""
#: includes/class-m365-login-admin.php:498
msgid "Opening this link shows the password form again in that browser for 30 minutes. Bookmark it somewhere safe it is your way back in if Microsoft sign-in ever breaks."
#: includes/class-m365-login-admin.php:525
msgid "Opening this link shows the password form again in that browser for 30 minutes and allows password sign-in there. Bookmark it somewhere safe it is your way back in if Microsoft sign-in ever breaks."
msgstr ""
#: includes/class-m365-login-admin.php:506
#: includes/class-m365-login-admin.php:533
msgid "Generate a new key when saving"
msgstr ""
#: includes/class-m365-login-admin.php:509
#: includes/class-m365-login-admin.php:536
msgid "A key is generated automatically the first time you save these settings."
msgstr ""
#. translators: %s: PHP constant
#: includes/class-m365-login-admin.php:515
#: includes/class-m365-login-admin.php:542
msgid "Emergency switch: add %s to wp-config.php to disable button-only mode entirely."
msgstr ""
#. translators: %s: PHP constant
#: includes/class-m365-login-admin.php:524
#: includes/class-m365-login-admin.php:551
msgid "What the plugin does to keep sign-ins safe"
msgstr ""
#: includes/class-m365-login-admin.php:526
#: includes/class-m365-login-admin.php:553
msgid "OpenID Connect authorization code flow with PKCE (S256) no tokens ever pass through the browser."
msgstr ""
#: includes/class-m365-login-admin.php:527
#: includes/class-m365-login-admin.php:554
msgid "Single-use state and nonce values bound to the browser via an HttpOnly cookie (CSRF and replay protection)."
msgstr ""
#: includes/class-m365-login-admin.php:528
#: includes/class-m365-login-admin.php:555
msgid "ID token signature verified against Microsofts published signing keys; issuer, audience, tenant, expiry and nonce are checked."
msgstr ""
#: includes/class-m365-login-admin.php:529
#: includes/class-m365-login-admin.php:556
msgid "Client secret encrypted at rest; no accounts are created, no passwords are changed."
msgstr ""
#: includes/class-m365-login-admin.php:535
#: includes/class-m365-login-admin.php:562
msgid "Save changes"
msgstr ""
#: includes/class-m365-login-admin.php:541
#: includes/class-m365-login-admin.php:568
msgid "Redirect URI"
msgstr ""
#: includes/class-m365-login-admin.php:542
#: includes/class-m365-login-admin.php:569
msgid "Register this URI in your app registration under Authentication → Web → Redirect URIs:"
msgstr ""
#: includes/class-m365-login-admin.php:548
#: includes/class-m365-login-admin.php:575
msgid "Plain permalinks are active, so the callback uses a query string. If you enable pretty permalinks later, the redirect URI changes and must be updated in Entra ID."
msgstr ""
#: includes/class-m365-login-admin.php:551
#: includes/class-m365-login-admin.php:578
msgid "Your site does not use HTTPS. Microsoft only accepts http:// redirect URIs for localhost; production sites must use HTTPS."
msgstr ""
#: includes/class-m365-login-admin.php:556
#: includes/class-m365-login-admin.php:583
msgid "Setup in 5 steps"
msgstr ""
#: includes/class-m365-login-admin.php:558
#: includes/class-m365-login-admin.php:585
msgid "Open the Microsoft Entra admin center → App registrations → New registration."
msgstr ""
#: includes/class-m365-login-admin.php:559
#: includes/class-m365-login-admin.php:586
msgid "Choose \"Accounts in this organizational directory only\", set the platform to Web and paste the redirect URI above."
msgstr ""
#: includes/class-m365-login-admin.php:560
#: includes/class-m365-login-admin.php:587
msgid "Copy the Application (client) ID and Directory (tenant) ID from the overview page."
msgstr ""
#: includes/class-m365-login-admin.php:561
#: includes/class-m365-login-admin.php:588
msgid "Under Certificates & secrets create a client secret and copy its value (not the ID)."
msgstr ""
#: includes/class-m365-login-admin.php:562
#: includes/class-m365-login-admin.php:589
msgid "Under Token configuration add the optional claim \"email\" for ID tokens (recommended), then save this page."
msgstr ""
#: includes/class-m365-login-admin.php:564
#: includes/class-m365-login-admin.php:591
msgid "Required API permission: openid, profile, email (delegated) granted by default."
msgstr ""
#: includes/class-m365-login-admin.php:565
#: includes/class-m365-login-admin.php:592
msgid "Optional, for group restrictions: application permissions GroupMember.Read.All and User.Read.All (Microsoft Graph) with admin consent."
msgstr ""
#: includes/class-m365-login-admin.php:569
#: includes/class-m365-login-admin.php:596
msgid "Shortcode"
msgstr ""
#: includes/class-m365-login-admin.php:570
#: includes/class-m365-login-admin.php:597
msgid "Place the button on a custom login page:"
msgstr ""
#: includes/class-m365-login-auth.php:136
#: includes/class-m365-login-admin.php:599
msgid "More options on the Button tab under \"Custom login page\"."
msgstr ""
#: includes/class-m365-login-auth.php:173
msgid "Password sign-in is disabled on this site. Please use the Microsoft button."
msgstr ""
#: includes/class-m365-login-auth.php:751
#: includes/class-m365-login-auth.php:777
msgid "Password sign-in is temporarily enabled for this browser (30 minutes)."
msgstr ""
#: includes/class-m365-login-auth.php:758 includes/class-m365-login-graph.php:63
#: includes/class-m365-login-auth.php:798 includes/class-m365-login-graph.php:63
msgid "Microsoft login is not configured yet."
msgstr ""
#: includes/class-m365-login-auth.php:759
#: includes/class-m365-login-auth.php:799
msgid "The login request expired or was invalid. Please try again."
msgstr ""
#: includes/class-m365-login-auth.php:760
#: includes/class-m365-login-auth.php:800
msgid "Microsoft sign-in was cancelled."
msgstr ""
#: includes/class-m365-login-auth.php:761
#: includes/class-m365-login-auth.php:801
msgid "Microsoft returned an error. Please try again."
msgstr ""
#: includes/class-m365-login-auth.php:762
#: includes/class-m365-login-auth.php:802
msgid "Could not complete the sign-in with Microsoft. Please try again or contact an administrator."
msgstr ""
#: includes/class-m365-login-auth.php:763
#: includes/class-m365-login-auth.php:803
msgid "The Microsoft sign-in could not be verified."
msgstr ""
#: includes/class-m365-login-auth.php:764
#: includes/class-m365-login-auth.php:804
msgid "Your Microsoft account did not provide an e-mail address."
msgstr ""
#: includes/class-m365-login-auth.php:765
#: includes/class-m365-login-auth.php:805
msgid "Your e-mail domain is not allowed to sign in here."
msgstr ""
#: includes/class-m365-login-auth.php:766
#: includes/class-m365-login-auth.php:806
msgid "No WordPress account exists for your Microsoft e-mail address."
msgstr ""
#: includes/class-m365-login-auth.php:767
#: includes/class-m365-login-auth.php:807
msgid "This WordPress account is linked to a different Microsoft account. Please contact an administrator."
msgstr ""
#: includes/class-m365-login-auth.php:768
#: includes/class-m365-login-auth.php:808
msgid "You are not allowed to sign in with this account."
msgstr ""
#: includes/class-m365-login-auth.php:769
#: includes/class-m365-login-auth.php:809
msgid "Your Microsoft account is not a member of a group that is allowed to sign in here."
msgstr ""
#: includes/class-m365-login-auth.php:770
#: includes/class-m365-login-auth.php:810
msgid "Your group membership could not be verified. Please contact an administrator."
msgstr ""
#: includes/class-m365-login-auth.php:771
#: includes/class-m365-login-auth.php:811
msgid "The fallback key is not valid."
msgstr ""
#: includes/class-m365-login-auth.php:772
#: includes/class-m365-login-auth.php:812
msgid "Too many attempts. Please wait 15 minutes."
msgstr ""
@ -566,22 +610,26 @@ msgstr ""
msgid "or"
msgstr ""
#: includes/class-m365-login-settings.php:245
#: includes/class-m365-login-settings.php:272
msgid "The tenant ID must be a GUID (e.g. 1a2b3c4d-…) or one of \"organizations\", \"common\", \"consumers\"."
msgstr ""
#: includes/class-m365-login-settings.php:253
#: includes/class-m365-login-settings.php:280
msgid "The application (client) ID must be a GUID."
msgstr ""
#: includes/class-m365-login-settings.php:265
#: includes/class-m365-login-settings.php:292
msgid "The client secret contains invalid characters."
msgstr ""
#: includes/class-m365-login-settings.php:269
#: includes/class-m365-login-settings.php:296
msgid "The client secret could not be encrypted. Is the OpenSSL extension available?"
msgstr ""
#: includes/class-m365-login-settings.php:346
msgid "The custom login page must be a URL on this site."
msgstr ""
#: includes/class-m365-login.php:102
msgid "Settings"
msgstr ""