Install
This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/361611074/at8-moonlight-user-center/archive/refs/heads/master.zipA lightweight, theme-agnostic front-end user center for WordPress. It gives a site front-end login, registration, password recovery and a personal account area without touching the WordPress admin.
Version 2.1.0 · GPL-2.0-or-later · PHP 7.4+ · WordPress 5.8+
What it does
| Feature | Shortcode |
|---|---|
| Login form | [at8_mluc_login] |
| Registration form | [at8_mluc_register] |
| Password recovery form | [at8_mluc_lostpassword] |
| Account dashboard | [at8_mluc_account] |
| Hidden content | [at8_mluc_hide type="logged\|reply"] |
| Social login buttons | [at8_mluc_oauth_buttons] |
The account dashboard has four sections:
- Overview — display name, email, registration date, approved comment count
- Profile — display name, nickname, first/last name, website, phone, bio
- Avatar — pick from an administrator-curated avatar library
- Password — change password, which signs the user out of every other device
Place each shortcode on its own page, then choose those pages under Settings → User Center. Any page you leave unset falls back to the equivalent WordPress screen.
Design principles
- The WordPress user system is the only user system. Accounts are created with
wp_create_user(), authenticated withwp_signon(), and reset throughretrieve_password(). This plugin never reads, stores, displays or transmits a plain-text password, and stores no password hash of its own. - No external communication. No external HTTP requests, no third-party scripts or fonts, no trackers, no analytics, no license or update server.
- No telemetry. Nothing about your site or your users leaves the server.
- Nothing is locked. Every feature described here is present and unlocked.
- Security by default. Per-action nonces, capability checks on every state-changing handler, sanitised input, escaped output, and rate limiting on public endpoints.
Requirements
- WordPress 5.8 or newer
- PHP 7.4 or newer
- For registration: the Anyone can register option enabled in Settings → General
Installation
- Download
at8-moonlight-user-center-1.0.2.zipfrom the releases, or clone this repository intowp-content/plugins/at8-moonlight-user-center/. - Activate the plugin under Plugins.
- Create pages containing the shortcodes listed above.
- Go to Settings → User Center and select those pages.
- To offer avatars, add entries under Avatar Library, set a featured image on each, and publish.
Theme overrides
Every template can be overridden from your theme. Copy a file from
templates/ into at8-moonlight-user-center/ inside your active theme:
wp-content/themes/your-theme/at8-moonlight-user-center/account-profile.php
Templates receive their data through an $args array, for example
$args['user'] or $args['library'].
Privacy and data
The plugin stores only what it needs:
| User meta key | Contents |
|---|---|
at8_mluc_phone |
Phone number entered in the profile |
at8_mluc_avatar_attachment_id |
Media ID of the chosen avatar |
at8_mluc_avatar_url |
URL of the chosen avatar |
at8_mluc_avatar_type |
How the avatar was chosen |
at8_mluc_last_login |
Last login timestamp |
Settings live in a single at8_mluc_options option. There are no custom database tables.
It registers a personal data exporter and eraser with the WordPress privacy tools, and suggests privacy policy wording under Settings → Privacy. On uninstall you choose whether the plugin's settings and profile fields are removed; WordPress user accounts, posts and comments are never deleted.
Development
Package layout
at8-moonlight-user-center/
├── at8-moonlight-user-center.php # bootstrap: constants, autoloader, module wiring
├── includes/ # AT8_MLUC_* classes + helper functions
├── templates/ # front-end templates (theme-overridable)
├── assets/css/ · assets/js/
├── languages/ # .pot + zh_CN (.po/.mo)
├── uninstall.php
├── readme.txt # WordPress.org readme
└── LICENSE # GPL-2.0 full text
The autoloader maps AT8_MLUC_Foo_Bar to includes/class-foo-bar.php, so a new class
needs no registration.
Conventions
- Every global function is prefixed
at8_mluc_, every class and constantAT8_MLUC_, every option and transientat8_mluc_. - All user-facing strings use the
at8-moonlight-user-centertext domain with English source strings, so GlotPress and language packs work normally. - All request input is unslashed and sanitised; all output is escaped late.
- State-changing handlers verify a nonce and a capability. Nonces are not authorization.
Regenerating translations
The .pot was generated from source rather than hand-maintained. Regenerate it after
changing any translatable string:
# canonical method, using WP-CLI
wp i18n make-pot . languages/at8-moonlight-user-center.pot --domain=at8-moonlight-user-center
# compile an edited .po into the .mo that WordPress loads
msgfmt languages/at8-moonlight-user-center-zh_CN.po \
-o languages/at8-moonlight-user-center-zh_CN.mo
msgfmt ships with gettext. On Windows it is available through Git for Windows or MSYS2.
Project history
This repository previously hosted a commercialised Free edition (v2.1.1) that bundled payment gateways (Alipay, PayPal, Stripe), a paywall, a license manager, paid membership tiers, and a credits/balance ledger.
Version 1.0.0 is a rebuild to meet the WordPress.org Plugin Directory Guidelines. Under guideline 5, functionality may not be restricted or locked behind payment, and premium code belongs in a separate add-on plugin hosted off WordPress.org. The commercial code was therefore removed entirely and the free plugin was rebuilt around login, registration, password recovery, the account dashboard and the avatar library.
1.0.1 — rebrand and the activation fatal error
The plugin shipped under the generic MLUC_ / mluc_ / moonlight-user-center namespace,
which the author's own shop plugin (at8-moonlight-shop) also defines when the old user
center is absent: the shop pre-defines MLUC_VERSION and MLUC_PLUGIN_DIR (pointing at
the shop's own directory) and registers its own MLUC_ autoloader. Activating the
rebuilt plugin on such a site produced:
PHP Fatal error: Uncaught TypeError: call_user_func_array(): Argument #1 ($callback)
must be a valid callback, class "MLUC_Activator" not found
The autoloader resolved includes/class-activator.php through the stolen
MLUC_PLUGIN_DIR, looked inside the shop plugin, found nothing, and the activation
hook died. Version 1.0.1 renames every identifier to the AT8_MLUC_ / at8_mluc_ /
at8-moonlight-user-center namespace, which no other plugin defines, and the
autoloader now resolves classes from __DIR__ so no shared constant can redirect
class loading. Shortcodes became [at8_mluc_login], [at8_mluc_register],
[at8_mluc_lostpassword] and [at8_mluc_account].
The previous version is preserved. It is reachable at any time:
git fetch --tags
git checkout legacy-v2.1.1 # the old commercial Free edition
Paid features continue in the separate repository
moonlight-user-center-pro,
which this plugin does not depend on. All extension points are plain WordPress hooks
(at8_mluc_loaded, at8_mluc_account_tabs, at8_mluc_template_args, at8_mluc_after_register, …).
1.0.2 — WordPress Plugin Check clean-up
Version 1.0.2 addresses every finding of the Plugin Check (PCP) report so the plugin is ready for the WordPress.org directory:
- Removed the
load_plugin_textdomain()call. Since WordPress 4.6 core loads the translation catalog for directory-hosted plugins from the translate server by itself; the manual call is discouraged there. - Nonce verification is inline. Each AJAX handler calls
check_ajax_referer( …, false )directly instead of routing the check through a helper method, so the verification is visible to static analysis. The two nonce helpers onAT8_MLUC_Securitywere removed; capability, login and rate-limit checks still go through that class. - Template variables are prefixed. The account templates' local variables are now
$at8_mluc_user,$at8_mluc_avatar_url,$at8_mluc_library, … matching the rest of the codebase. - The login redirect hint is passed as a parameter to
resolve_redirect()instead of being read from$_POSTinside a helper, and both query-string readers (current_view(),current_tab()) now reject non-string input. - The release zip no longer contains
.gitignore— hidden files are not permitted in distributed plugins.
Security fixes carried into 1.0.0
The rebuild also fixes defects found while auditing the previous code:
- Passwords were read without
wp_unslash()in login, registration, password change and password reset — any password containing a backslash locked the user out. - The post-login redirect was validated with
wp_http_validate_url(), which allows external hosts, turning the login form into an open redirect. - All seven AJAX endpoints shared one nonce, including the password-change endpoint. Every action now has its own nonce.
uninstall.phpdeleted meta withLIKE 'mluc_%', which would have destroyed other plugins'mluc_*keys. It now removes an explicit list of keys.- Every translatable string had a Chinese msgid, which made language packs and GlotPress unusable. Source strings are now English.
License
GPL-2.0-or-later. See LICENSE.
WordPress itself is licensed under the GPL, and plugins distributed through the WordPress.org directory must be GPL-compatible.