=== DigitSummit Loginly ===
Contributors: digitsummit
Tags: login, custom login, hide login, login security, two-factor
Requires at least: 6.4
Tested up to: 7.1
Requires PHP: 8.0
Stable tag: 6.1.1
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Brand your login page, move it to an address only you know, and secure the door — with a safety net that will not lock you out.

== Description ==

DigitSummit Loginly takes care of the whole front door of your WordPress site: how it looks,
where it lives, what protects it, and how you get back in when something goes
wrong.

Everything is edited from one screen with a live preview. No Customizer, so it
works the same on classic and block themes.

= Looks =

* Logo, colours, background (solid, gradient or image), card, fields, button.
* Three layouts: centred, split screen with a visual panel, form to one side.
* Three ready-made templates — one per layout.
* A "Login" block for the editor: the same styling on any page.
* A built-in contrast check against WCAG 2.1 level AA, with a suggested fix when
  a pair falls short.

= A login address only you know =

Serve the login page from `example.com/your-address/` and make `/wp-login.php`
answer 404. This removes the automated background noise that hits every
WordPress site around the clock.

**It will not lock you out.** After you apply a new address, the server calls it
back like a logged-out visitor and checks that the form really appears — and
that the old address really stopped answering. If the check fails, the previous
setting is restored automatically. An hourly watch repeats that check: after
three consecutive failures, `/wp-login.php` comes back and you are emailed. On
top of that: a recovery address, a `wp-config.php` constant, and a
`wp loginly unlock` command.

= Security that is honest about itself =

An exposure report queries your own site from the server, without being logged
in, and tells you what a stranger actually gets: the account list through the
REST API, the `?author=1` probe, the author sitemap. Most findings have a button
that closes them on the spot.

The report also states plainly what moving the login page does *not* do. It is
not a lock. The lock is:

* attempt slowdown, per IP address, with a growing delay;
* a decoy field that costs nothing and depends on no third party;
* neutral error messages, so nobody learns which accounts exist;
* two-step verification by authenticator app, with backup codes.

= What you keep a trace of =

An access log with anonymised IP addresses: who came in, from where, with what
outcome. Seven days by default — enough to understand what just happened — and
up to a year if an audit asks for it.

= What Loginly Pro adds =

Loginly Pro is a separate plugin. Nothing here is switched off waiting for a
payment: the code of these features is not in this plugin at all.

One styling published once and fetched by every site under the same licence —
the login address, the recovery key and the secrets of each site never travel.
Sign-in hours and approved addresses by role, a session length of your own,
passwords checked against known breaches when they are chosen — the password
never leaves your server, only five characters of its fingerprint do. An
anti-bot shield that asks nothing of your visitors and shows them to nobody:
the server sets a puzzle only solvable by trying, which a browser answers in a
fraction of a second and a password-guessing program has to answer on every
single attempt. An email the moment someone signs in from an origin never seen
on this site, a
weekly summary, every event forwarded to Slack or your own endpoint with a
signature, and the log exported as CSV for an audit. Passkeys (Face ID, Touch
ID, Windows Hello, security keys), sign-in links sent by email, nine more
templates, redirects by role or by user, the same styling on
the WooCommerce "My account" page and in the authentication emails, passkeys and
one-time sign-in links, leaked-password checking, sign-in hours and approved
addresses by role, carrying a configuration from one site to the next, temporary
access links, connected-device limits, network-wide styling for multisite, and
admin white labelling.

= Does it call anyone? =

No analytics, no telemetry, no phone-home. Two-step verification runs entirely
on your own server. The full list of what can be contacted, and when, is in the
"External services" section below.

== Source code and build ==

The admin interface is written in JSX and bundled with esbuild. Both the sources
and the bundle ship inside the plugin: `assets/admin/` and `assets/block/` hold
the readable source, `build/` holds what WordPress loads.

To rebuild it from the sources shipped here:

`npm install && npm run build`

The build script is `build.mjs` at the plugin root — a hundred lines, one
esbuild call, no code generation. It bundles `assets/admin/index.jsx` and
`assets/block/index.jsx` and minifies the result, which is what `build/`
contains. Nothing in `build/` comes from anywhere else, and rebuilding from the
sources shipped here reproduces it.

Bundled third-party resources: Inter and JetBrains Mono (Latin subset, variable
weight), under the SIL Open Font License 1.1 — full text in
`assets/fonts/LICENSE.txt`. They are served from your own site: no request ever
leaves the browser to fetch them.

== External services ==

Loginly makes no external request unless you enable a feature that needs one, or
until you press play on the introduction video. Here is exactly what is
contacted, and when:

* **loginly.digitsummit.net** (DiGit Summit, the plugin author) — the one-minute
  introduction video on the plugin's Home screen is served from this domain. The
  poster image ships inside the plugin, so opening the screen contacts nobody:
  the request happens only when you press play. That server then receives your
  IP address and browser user agent. Nothing else is sent, and nothing is sent
  on any other screen.
  [Terms](https://digitsummit.net/conditions-dutilisation/) —
  [Privacy](https://digitsummit.net/politique-de-confidentialite/)
* **Cloudflare Turnstile** — only if you choose it as the anti-bot challenge.
  The login page loads a script from `challenges.cloudflare.com`, and your
  server sends the challenge token, your secret key and the visitor IP address
  to `challenges.cloudflare.com/turnstile/v0/siteverify`.
  [Terms](https://www.cloudflare.com/terms/) —
  [Privacy](https://www.cloudflare.com/privacypolicy/)
* **hCaptcha** — same, if you choose it instead. Script from `js.hcaptcha.com`,
  verification against `hcaptcha.com/siteverify`.
  [Terms](https://www.hcaptcha.com/terms) —
  [Privacy](https://www.hcaptcha.com/privacy)

That is the whole list for this plugin. It sends no analytics and no telemetry,
checks no licence server, and two-step verification runs entirely on your own
server. The anti-lockout check and the exposure report do make HTTP requests,
but only to your own site's address, from your own server: no third party is
involved.



== Installation ==

1. Plugins → Add New → Add New → search for "DigitSummit Loginly".
2. Activate.
3. Open the "Login page" menu in your admin sidebar.

To move your login address: open the "Login address" panel, note the recovery
address it shows you, then apply your address. **Test it in a private window
before logging out.** The plugin checks it for you as well.

== Frequently Asked Questions ==

= Can this lock me out of my own site? =

That is the risk the plugin is built around. Four safety nets, in order: the
server verifies any new address and rolls back a failing one; an hourly watch
restores `/wp-login.php` after three failed checks and emails you; a recovery
address opens the login page even if you forget the secret one; and
`define( 'LOGINLY_URL_DISABLE', true );` in `wp-config.php` restores the
original address immediately. Deactivating the plugin also restores it.

= Does hiding the login URL actually protect anything? =

It removes the automated noise, and that is all — the plugin says so in its own
exposure report. A visitor who obtains the new address reaches the same form.
Real protection comes from strong passwords, a second factor, attempt slowdown
and few administrator accounts. Loginly provides those too.

= Does it work with a caching plugin? =

Yes. The login page is marked "do not cache" on every request, and the address
is added to the exclusion lists of LiteSpeed Cache, WP Rocket and Cache Enabler
through their own public filters. **No third-party plugin's settings are ever
modified.** A cache placed in front of WordPress (CDN, host) cannot receive
those instructions: the diagnostics screen detects it and says so.

= I already use another plugin that hides the login page =

Loginly detects WPS Hide Login and the equivalent option in Really Simple
Security, and refuses to enable its own. Two guards fighting over one address is
a lockout waiting to happen.


== Screenshots ==

1. The editor, with the live preview of the login page.
2. Settings: activation, exposure report, login address, door status.
3. The exposure report: what a stranger actually gets from your site.
4. A branded login screen — the visitor's side of the plugin.
5. The access log: who signed in, when, and from where.

== Changelog ==

= 6.1.1 =
* The plugin was distributed as a zip under a `loginly/` folder before it
  reached this directory as `digitsummit-loginly/`. A site upgrading has both
  on disk, and activating the new one without deactivating the old gave PHP
  warnings on every request, two identical menus, and two guards fighting over
  the login address. The copy loaded second now declares nothing and says so,
  and the one that runs points at the other from the Plugins screen. Settings,
  login address and access log are untouched either way.

= 6.1.0 =
* Fixed: the attempt slowdown and the anti-bot challenge refused nothing. Both
  hooked `authenticate` below priority 20, where WordPress discards whatever it
  is handed and re-checks the password itself. Six failures in a row went
  unslowed, and the right password opened a session in the middle of a
  ten-minute lockout. Measured, fixed, and measured again.
* Fixed: three ways to make the site hand out the hidden login address without
  signing in — a canonical redirect carrying `wp-login.php` in its query string,
  `wp-signup.php`, and the `postpass` redirect. The address is now rewritten
  only when the URL path really is the login form.
* Fixed: `?loginly=off`, the escape hatch for a broken theme, also switched off
  the neutral error message — handing an attacker "this account does not exist".
* Fixed: the ten backup codes were generated, stored in clear in the options
  table for fifteen minutes, and never shown to anyone. They are now displayed
  once, right after you enable two-step verification, and erased in the same
  breath. They are longer, and hashed with the site salt.
* Fixed: the "roles reminded to enable two-step verification" setting did
  nothing at all. It now shows a reminder — and still never blocks anyone.
* Six settings that the code applied but no screen offered are now in the
  interface: trusted proxy addresses, author archives, oEmbed author name, and
  the three that were already there.
* The login address can no longer be changed through the generic settings
  route, which skipped the verification that keeps you from locking yourself
  out.
* Removed: four settings for features that live in the separate Pro plugin were
  declared here and commanded nothing.

= 6.0.3 =
* Fix: the version constant had drifted two releases behind the plugin header.
  The header named 6.0.2 while every stylesheet and script was still served
  under 6.0.0, so browsers kept the old appearance.

= 6.0.2 =
* Fix: the licence card showed a single "Installed version" — the free plugin's
  number — among lines that all describe the Pro licence. Each plugin now
  carries its own name and number.
* Fix: the compiled French catalogue was never regenerated, so translations
  added since 1 September never reached a French site.

= 6.0.1 =
* Fix: the "Visit plugin site" link in the plugins list pointed at an address
  that no longer exists, and landed on the marketing site's 404 page.

= 6.0.0 =
* The free plugin and the Loginly Pro add-on are split along a clear line: what
  is here makes your door beautiful and closed to strangers; what Pro adds is
  choosing finely, proving what happened, and applying it to a whole estate.
* New in Pro: an estate — publish the styling of one site and every other site
  under the same licence fetches it, locked or as a starting point. Sign-in
  hours and approved addresses by role, with your own
  address added automatically so the setting cannot lock you out. Refusing a
  password that already appears in a known breach, plus
  a minimum length and a ban on passwords containing the username. An anti-bot
  shield without a CAPTCHA — no third party sees your
  visitors, and nobody is asked to identify a traffic light. Alerts on a sign-in
  from an unknown origin, a weekly summary, a
  signed webhook for every event, and a CSV export of the access log.
* Moving to Pro: passkeys, sign-in links by email, nine of the twelve templates,
  redirects, the WooCommerce and email styling, leaked-password checking,
  sign-in hours and approved addresses by role, configuration export and import,
  plus temporary access links, network-wide policy, admin white labelling and
  connected devices.
* Never sold, and in this plugin for everyone: the recovery key that keeps you
  from being locked out, the brute-force protection AND its tuning — the
  threshold, the delay and the trusted addresses —, how long the access log is
  kept, and requiring two-step verification of a role. There is no timed trial
  either: a feature is in this plugin, or it is not.
* They are not switched off waiting for a payment: the code is no longer in this
  plugin at all. Your settings are kept: install Loginly Pro and they come back
  exactly as they were.
* Lighter as a result: fewer classes, fewer strings, a smaller package.
* New extension points, documented for anyone building on top: `loginly_routes`,
  `loginly_cron_tasks`, `loginly_cron_wanted`, `loginly_imposed_settings` and
  `loginly_settings_locked`.

= 5.1.0 =
* Lighter on the public side of your site: hooks moved to the context that
  needs them. A page view now carries three of our callbacks instead of nine,
  and none of them touch page rendering.
* Scheduling and URL routing handled in one place each, instead of spread
  across five services.
* Extension points for an add-on: settings schema, editor panels described
  without JavaScript, feature catalogue.

= 5.0.1 =
* A refused login link request now leaves a reason in the access log:
  administrator excluded, unknown account, or too many requests. The visitor
  still sees the same confirmation either way.
* The access log names every event it records, and shows the reason column.

= 5.0.0 =
* English is now the source language, with a complete French translation
  shipped. No feature change.

= 4.3.0 =
* Anti-bot challenge with Cloudflare Turnstile or hCaptcha.
* Simultaneous session cap and connected device list.
* Admin white labelling.
* WCAG 2.1 AA contrast check in the editor, with a suggested fix.

= 4.2.0 =
* Two-step verification (TOTP) with ten single-use backup codes.

= 4.1.0 =
* Passkeys (WebAuthn) and login link by email.

= 4.0.0 =
* Access log, redirects by role, temporary access links, configuration
  export/import, network styling for multisite.

= 3.2.0 =
* WooCommerce "My account" styling, "Login" block, branded authentication
  emails, twelve templates.

= 3.1.0 =
* Exposure report, attempt slowdown, account enumeration closures.

= 3.0.0 =
* Anti-lockout safety net: server-side verification, hourly watch, automatic
  cache exclusions, WP-CLI commands.

= 2.0.0 =
* Renamed to Loginly.

= 1.0.0 =
* Login page customisation with live preview.

== Upgrade Notice ==

= 6.1.1 =
Only matters if you installed this plugin from a zip before: two active copies
no longer collide, and the screen tells you which one to deactivate.

= 6.1.0 =
Security release. The attempt slowdown and the anti-bot challenge were refusing
nothing at all, and three requests could make the site hand out your hidden
login address. Update.

= 6.0.3 =
Housekeeping release: the version constant had drifted two releases behind, so
browsers kept serving the old stylesheets. Nothing to do on your side.

= 6.0.0 =
Security release: two ways around two-step verification and three around the
hidden login address are closed. Some features moved to Loginly Pro, a separate
plugin — what stays free stays free, and nothing you run today switches off.

= 5.0.0 =
The interface is now English by default, with French shipped as a translation.
Nothing else changes; your settings are untouched.
