Account and one-time code login
Customers log in with a one-time code sent by SMS or email, with a password, or both. The settings are in Theme Options → Shop → Account & login. The code is in inc/Account, and the form's script and styles are in src/frontend/account and src/scss/account (the account bundle, loaded only where a form shows).
How it works
- Sign in or sign up in one step: the visitor enters a mobile number (or an email, when email codes are on), gets a code, and types it. A number or email that has no account yet gets one when both of these allow it:
- Registration in Theme Options: mobile, email or both.
- The site's own registration setting: WooCommerce's "Allow customers to create an account on the My account page", or "Anyone can register" without WooCommerce.
- New accounts:
- From a mobile number: the username is the number, with no email. The number is saved to the profile.
- From an email: WooCommerce's own sign-up is used, with its username rules, hooks and welcome email.
- Numbers: they are accepted in any common spelling (Persian or Arabic digits, +98, 0098, 98, or without the leading zero) and stored as
09xxxxxxxxxin the user metabluetheme_mobile. With Save the verified mobile number… on, the billing phone gets it too. An account is found by that meta first, then by the billing phone. When two accounts share one billing phone, neither is used: the number counts as new, so it signs up a new account if registration allows. - Codes:
- Stored as a keyed hash in a transient for Code expires after seconds.
- Five wrong tries drop the code.
- Wait before sending again limits how soon a new code can be asked for.
- Hourly limits apply per number and per IP address. A site behind a proxy can pass the real IP with the
bluetheme_otp_ipfilter. - A complete code (pasted or autofilled too) is checked at once. Codes may be typed with Persian digits.
- Test mode: codes are not sent. The latest 20 are kept, and Show the latest codes lists them for administrators. The form says it is in test mode. Turn it off on a live site.
- After logging in: the customer goes back to the page they were on (or My Account). Core's
login_redirectfilter applies, and thewp_loginaction fires as with a password login.
Where the form appears
Set in Login form appears in:
- My Account: "One-time code" and "Password" tabs above WooCommerce's forms. The Password tab shows WooCommerce's login (and register) forms. Shown first picks the starting tab.
- With Email or username and password off, only the code form shows.
- With Registration set to mobile only, WooCommerce's email sign-up form is hidden and also refused on submit.
- Checkout: a "Returning customer? Log in with a one-time code" notice next to WooCommerce's own one. This works on the classic checkout (
[woocommerce_checkout]) only; the block checkout does not run these hooks. - Popup: the header account icon (classic header and the Account element) opens a login dialog with both tabs and a "Create an account" link. It does not appear on My Account and checkout, which have their own forms.
- wp-login.php (its own switch): a "Log in with a one-time code" link under the normal form switches between the two. The password form always stays, so administrators can always log in if SMS fails.
- Account details: signed-in customers add or change their mobile number. A code goes to the new number before it is saved. A number that belongs to another account is refused.
SMS providers
| Provider | Settings | With a pattern | Without a pattern |
|---|---|---|---|
| Kavenegar | API key, sender (optional) | verify/lookup with the template name; the code is token |
sms/send |
| Melipayamak | Username, password (or the panel's API key), sender | BaseServiceNumber with the message id (bodyId); the code is the only variable |
SendSMS |
| IPPanel (FarazSMS) | API key, sender line | Edge API api/send, sending_type: pattern; the code goes under Code variable (default code) |
sending_type: webservice |
| SMS.ir | API key, line number (without a pattern) | v1/send/verify with the template id; the code goes under Code variable (default CODE) |
v1/send/bulk |
- Patterns: most Iranian providers send codes quickly only through an approved pattern (template), so use one when the provider offers it.
- Plain messages: without a pattern, the Message is sent, with
{code}and{site}replaced. The code is added at the end if{code}is missing. - Send test SMS: sends a real SMS with a sample code to the saved Test mobile number, test mode or not, and shows the provider's error if it fails.
- Failures: when sending fails, the visitor sees a general message and the
bluetheme_sms_failedaction fires with the provider's error. - Other providers: add a class extending
BlueTheme\Account\Sms\Gatewaywith thebluetheme_sms_gatewaysfilter (id => class), and its name withbluetheme_sms_provider_labels.
Compatibility mode
With Step aside for Digits, Persian WooCommerce SMS or WP SMS on, the theme hides all of its code forms while one of those plugins is active. It looks for their plugin folders: digits, persian-woocommerce-sms and wp-sms. The bluetheme_otp_plugin_active filter can decide instead. The header popup then shows only the password form.
Those plugins' forms are not restyled by the theme beyond WooCommerce's general form styles, because they could not be tested here.
Routes (bluetheme/v1)
| Route | Who | Body |
|---|---|---|
POST otp/send |
Visitors (login), signed-in users (mobile) | channel sms or email, target, purpose login or mobile |
POST otp/verify |
Same | Also code, remember, redirect |
POST otp/test-sms |
manage_options |
none |
POST otp/test-log |
manage_options |
none |
The bluetheme_otp_registered action fires after a code sign-up created an account (id, channel, target).
Translate
Theme Options → Translate has new "Shop" and "Account & login" groups. The form's labels and messages, including the script's countdown text, come from PHP, so they can be changed there.