{"id":240696,"date":"2025-07-17T16:18:35","date_gmt":"2025-07-17T16:18:35","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/init-user-engine\/"},"modified":"2026-10-03T17:16:33","modified_gmt":"2026-10-03T17:16:33","slug":"init-user-engine","status":"publish","type":"plugin","link":"https:\/\/so.wordpress.org\/plugins\/init-user-engine\/","author":14479633,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.6.7","stable_tag":"1.6.7","tested":"7.1.2","requires":"5.5","requires_php":"7.4","requires_plugins":null,"header_name":"Init User Engine","header_author":"Init HTML","header_description":"Lightweight, gamified user engine with EXP, wallet, check-in, VIP, inbox, and referral \u2013 powered by REST API and Vanilla JS.","assets_banners_color":"535076","last_updated":"2026-10-03 17:16:33","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/inithtml.com\/plugin\/init-user-engine\/","header_author_uri":"https:\/\/inithtml.com\/","rating":5,"author_block_rating":0,"active_installs":40,"downloads":4971,"num_ratings":1,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.1":{"tag":"1.0.1","author":"brokensmile.2103","date":"2025-07-17 16:17:59","revision":3329854},"1.0.2":{"tag":"1.0.2","author":"brokensmile.2103","date":"2025-07-21 15:31:44","revision":3331601},"1.0.3":{"tag":"1.0.3","author":"brokensmile.2103","date":"2025-07-22 19:28:16","revision":3332488},"1.0.4":{"tag":"1.0.4","author":"brokensmile.2103","date":"2025-07-23 00:44:36","revision":3332556},"1.0.5":{"tag":"1.0.5","author":"brokensmile.2103","date":"2025-07-23 03:03:08","revision":3332573},"1.0.6":{"tag":"1.0.6","author":"brokensmile.2103","date":"2025-07-28 16:02:02","revision":3335470},"1.0.7":{"tag":"1.0.7","author":"brokensmile.2103","date":"2025-07-30 19:19:05","revision":3336829},"1.0.8":{"tag":"1.0.8","author":"brokensmile.2103","date":"2025-07-31 05:24:23","revision":3336967},"1.0.9":{"tag":"1.0.9","author":"brokensmile.2103","date":"2025-08-03 11:59:40","revision":3338441},"1.1.0":{"tag":"1.1.0","author":"brokensmile.2103","date":"2025-08-14 16:19:16","revision":3344780},"1.1.1":{"tag":"1.1.1","author":"brokensmile.2103","date":"2025-08-18 05:58:01","revision":3346131},"1.1.2":{"tag":"1.1.2","author":"brokensmile.2103","date":"2025-08-19 14:56:12","revision":3347099},"1.1.3":{"tag":"1.1.3","author":"brokensmile.2103","date":"2025-08-21 18:31:46","revision":3348316},"1.1.4":{"tag":"1.1.4","author":"brokensmile.2103","date":"2025-08-21 18:46:16","revision":3348322},"1.1.5":{"tag":"1.1.5","author":"brokensmile.2103","date":"2025-08-22 06:32:12","revision":3348462},"1.1.6":{"tag":"1.1.6","author":"brokensmile.2103","date":"2025-08-23 13:26:10","revision":3348985},"1.1.7":{"tag":"1.1.7","author":"brokensmile.2103","date":"2025-08-30 05:17:46","revision":3352973},"1.1.8":{"tag":"1.1.8","author":"brokensmile.2103","date":"2025-09-17 13:23:06","revision":3363239},"1.1.9":{"tag":"1.1.9","author":"brokensmile.2103","date":"2025-09-17 14:02:49","revision":3363269},"1.2.0":{"tag":"1.2.0","author":"brokensmile.2103","date":"2025-09-28 03:46:42","revision":3369073},"1.2.1":{"tag":"1.2.1","author":"brokensmile.2103","date":"2025-09-28 15:13:53","revision":3369239},"1.2.2":{"tag":"1.2.2","author":"brokensmile.2103","date":"2025-10-03 05:13:37","revision":3372128},"1.2.3":{"tag":"1.2.3","author":"brokensmile.2103","date":"2025-10-03 13:50:37","revision":3372398},"1.2.4":{"tag":"1.2.4","author":"brokensmile.2103","date":"2025-10-04 07:25:54","revision":3372735},"1.2.5":{"tag":"1.2.5","author":"brokensmile.2103","date":"2025-10-04 15:11:21","revision":3372880},"1.2.6":{"tag":"1.2.6","author":"brokensmile.2103","date":"2025-10-05 05:30:38","revision":3373020},"1.2.7":{"tag":"1.2.7","author":"brokensmile.2103","date":"2025-10-08 02:35:11","revision":3374753},"1.2.8":{"tag":"1.2.8","author":"brokensmile.2103","date":"2025-10-10 09:50:14","revision":3376152},"1.2.9":{"tag":"1.2.9","author":"brokensmile.2103","date":"2025-10-10 12:16:12","revision":3376221},"1.3.0":{"tag":"1.3.0","author":"brokensmile.2103","date":"2025-10-12 05:29:40","revision":3376832},"1.3.1":{"tag":"1.3.1","author":"brokensmile.2103","date":"2025-10-17 14:40:36","revision":3380195},"1.3.2":{"tag":"1.3.2","author":"brokensmile.2103","date":"2025-10-18 13:31:39","revision":3380537},"1.3.3":{"tag":"1.3.3","author":"brokensmile.2103","date":"2025-10-23 05:20:00","revision":3383060},"1.3.4":{"tag":"1.3.4","author":"brokensmile.2103","date":"2025-10-23 08:09:21","revision":3383150},"1.3.5":{"tag":"1.3.5","author":"brokensmile.2103","date":"2025-10-27 05:08:34","revision":3384944},"1.3.6":{"tag":"1.3.6","author":"brokensmile.2103","date":"2025-10-27 06:18:59","revision":3384975},"1.3.7":{"tag":"1.3.7","author":"brokensmile.2103","date":"2025-10-29 06:36:32","revision":3386208},"1.3.7.1":{"tag":"1.3.7.1","author":"brokensmile.2103","date":"2025-10-29 06:36:32","revision":3386208},"1.3.8":{"tag":"1.3.8","author":"brokensmile.2103","date":"2025-10-30 08:55:03","revision":3386913},"1.3.8.1":{"tag":"1.3.8.1","author":"brokensmile.2103","date":"2025-10-30 14:28:26","revision":3387141},"1.3.9":{"tag":"1.3.9","author":"brokensmile.2103","date":"2025-11-03 07:09:53","revision":3388640},"1.4.0":{"tag":"1.4.0","author":"brokensmile.2103","date":"2025-11-04 16:44:31","revision":3389813},"1.4.1":{"tag":"1.4.1","author":"brokensmile.2103","date":"2025-11-17 04:25:44","revision":3396870},"1.4.2":{"tag":"1.4.2","author":"brokensmile.2103","date":"2025-11-19 05:43:40","revision":3398509},"1.4.3":{"tag":"1.4.3","author":"brokensmile.2103","date":"2026-01-28 06:38:32","revision":3448397},"1.4.4":{"tag":"1.4.4","author":"brokensmile.2103","date":"2026-02-04 06:27:58","revision":3453513},"1.4.5":{"tag":"1.4.5","author":"brokensmile.2103","date":"2026-02-04 07:11:09","revision":3453557},"1.4.6":{"tag":"1.4.6","author":"brokensmile.2103","date":"2026-02-07 02:15:20","revision":3455726},"1.4.7":{"tag":"1.4.7","author":"brokensmile.2103","date":"2026-03-24 14:52:29","revision":3490129},"1.4.8":{"tag":"1.4.8","author":"brokensmile.2103","date":"2026-03-25 04:26:50","revision":3490489},"1.4.9":{"tag":"1.4.9","author":"brokensmile.2103","date":"2026-04-15 15:58:00","revision":3507249},"1.5.0":{"tag":"1.5.0","author":"brokensmile.2103","date":"2026-04-21 08:21:47","revision":3511523},"1.5.0.1":{"tag":"1.5.0.1","author":"brokensmile.2103","date":"2026-04-21 09:27:14","revision":3511585},"1.5.0.2":{"tag":"1.5.0.2","author":"brokensmile.2103","date":"2026-04-21 12:37:20","revision":3511809},"1.5.0.3":{"tag":"1.5.0.3","author":"brokensmile.2103","date":"2026-04-21 13:41:10","revision":3511884},"1.5.1":{"tag":"1.5.1","author":"brokensmile.2103","date":"2026-05-17 14:13:26","revision":3534601},"1.5.2":{"tag":"1.5.2","author":"brokensmile.2103","date":"2026-05-17 15:19:26","revision":3534639},"1.5.3":{"tag":"1.5.3","author":"brokensmile.2103","date":"2026-07-29 06:30:59","revision":3626741},"1.5.4":{"tag":"1.5.4","author":"brokensmile.2103","date":"2026-08-11 08:06:58","revision":3641511},"1.5.5":{"tag":"1.5.5","author":"brokensmile.2103","date":"2026-08-11 18:18:23","revision":3642371},"1.5.6":{"tag":"1.5.6","author":"brokensmile.2103","date":"2026-08-16 03:39:55","revision":3649241},"1.5.7":{"tag":"1.5.7","author":"brokensmile.2103","date":"2026-08-16 10:42:56","revision":3649617},"1.5.8":{"tag":"1.5.8","author":"brokensmile.2103","date":"2026-08-22 15:05:28","revision":3660771},"1.5.9":{"tag":"1.5.9","author":"brokensmile.2103","date":"2026-08-29 08:03:26","revision":3671242},"1.6.0":{"tag":"1.6.0","author":"brokensmile.2103","date":"2026-09-03 05:53:32","revision":3679046},"1.6.1":{"tag":"1.6.1","author":"brokensmile.2103","date":"2026-09-04 05:46:39","revision":3680680},"1.6.2":{"tag":"1.6.2","author":"brokensmile.2103","date":"2026-09-04 13:49:09","revision":3681309},"1.6.3":{"tag":"1.6.3","author":"brokensmile.2103","date":"2026-09-07 15:21:56","revision":3685175},"1.6.4":{"tag":"1.6.4","author":"brokensmile.2103","date":"2026-09-10 05:17:49","revision":3689313},"1.6.5":{"tag":"1.6.5","author":"brokensmile.2103","date":"2026-09-23 18:59:06","revision":3709991},"1.6.6":{"tag":"1.6.6","author":"brokensmile.2103","date":"2026-10-01 06:27:33","revision":3722490},"1.6.7":{"tag":"1.6.7","author":"brokensmile.2103","date":"2026-10-03 17:16:33","revision":3726531}},"upgrade_notice":[],"ratings":{"1":0,"2":0,"3":0,"4":0,"5":1},"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3329854,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3329854,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3329854,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3329854,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.1","1.0.2","1.0.3","1.0.4","1.0.5","1.0.6","1.0.7","1.0.8","1.0.9","1.1.0","1.1.1","1.1.2","1.1.3","1.1.4","1.1.5","1.1.6","1.1.7","1.1.8","1.1.9","1.2.0","1.2.1","1.2.2","1.2.3","1.2.4","1.2.5","1.2.6","1.2.7","1.2.8","1.2.9","1.3.0","1.3.1","1.3.2","1.3.3","1.3.4","1.3.5","1.3.6","1.3.7","1.3.7.1","1.3.8","1.3.8.1","1.3.9","1.4.0","1.4.1","1.4.2","1.4.3","1.4.4","1.4.5","1.4.6","1.4.7","1.4.8","1.4.9","1.5.0","1.5.0.1","1.5.0.2","1.5.0.3","1.5.1","1.5.2","1.5.3","1.5.4","1.5.5","1.5.6","1.5.7","1.5.8","1.5.9","1.6.0","1.6.1","1.6.2","1.6.3","1.6.4","1.6.5","1.6.6","1.6.7"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3678614,"resolution":"1","location":"assets","locale":"","width":1298,"height":2460},"screenshot-10.png":{"filename":"screenshot-10.png","revision":3329854,"resolution":"10","location":"assets","locale":"","width":650,"height":700},"screenshot-11.png":{"filename":"screenshot-11.png","revision":3329854,"resolution":"11","location":"assets","locale":"","width":403,"height":592},"screenshot-12.png":{"filename":"screenshot-12.png","revision":3329854,"resolution":"12","location":"assets","locale":"","width":664,"height":814},"screenshot-13.png":{"filename":"screenshot-13.png","revision":3329854,"resolution":"13","location":"assets","locale":"","width":664,"height":905},"screenshot-14.png":{"filename":"screenshot-14.png","revision":3329854,"resolution":"14","location":"assets","locale":"","width":664,"height":905},"screenshot-15.png":{"filename":"screenshot-15.png","revision":3329854,"resolution":"15","location":"assets","locale":"","width":664,"height":905},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3626741,"resolution":"2","location":"assets","locale":"","width":967,"height":298},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3626741,"resolution":"3","location":"assets","locale":"","width":633,"height":393},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3626741,"resolution":"4","location":"assets","locale":"","width":646,"height":485},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3626741,"resolution":"5","location":"assets","locale":"","width":719,"height":1581},"screenshot-6.png":{"filename":"screenshot-6.png","revision":3626741,"resolution":"6","location":"assets","locale":"","width":632,"height":448},"screenshot-7.png":{"filename":"screenshot-7.png","revision":3626741,"resolution":"7","location":"assets","locale":"","width":691,"height":670},"screenshot-8.png":{"filename":"screenshot-8.png","revision":3626741,"resolution":"8","location":"assets","locale":"","width":846,"height":1098},"screenshot-9.png":{"filename":"screenshot-9.png","revision":3329854,"resolution":"9","location":"assets","locale":"","width":650,"height":650}},"screenshots":{"1":"Settings with options for theme color, currency labels, and admin bar\/Gravatar control.","2":"Custom Links section for setting Register and Lost Password URLs.","3":"Check-in Reward configuration, including Coin, EXP, and Cash per check-in.","4":"Online Reward configuration based on active time with reward values.","5":"VIP Pricing options for various durations, including lifetime.","6":"VIP Bonus settings to configure extra Coin\/EXP for VIP users.","7":"Referral Reward settings for both referrer and new user.","8":"Admin panel to send notifications with content, targeting, priority, and expiration.","9":"Login modal interface for non-logged-in users.","10":"Registration modal with username, email, and password fields.","11":"Avatar button with dropdown panel showing user info, level, stats, and quick links.","12":"VIP Membership modal with Coin-based purchase options and expiration note.","13":"Inbox modal showing system messages, rewards, and user notifications.","14":"Transaction history modal showing all reward activities (check-in, referral, online time...).","15":"Referral modal with shareable code\/link, social sharing buttons, and referral history."}},"plugin_section":[262246],"plugin_tags":[27702,2108,387,2153,51149],"plugin_category":[],"plugin_contributors":[242666],"plugin_business_model":[],"class_list":["post-240696","plugin","type-plugin","status-publish","hentry","plugin_section-dashboard-widgets","plugin_tags-check-in","plugin_tags-level","plugin_tags-referral","plugin_tags-user","plugin_tags-vip","plugin_contributors-brokensmile2103-1","plugin_committers-brokensmile2103-1"],"banners":{"banner":"https:\/\/ps.w.org\/init-user-engine\/assets\/banner-772x250.png?rev=3329854","banner_2x":"https:\/\/ps.w.org\/init-user-engine\/assets\/banner-1544x500.png?rev=3329854","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/init-user-engine\/assets\/icon-128x128.png?rev=3329854","icon_2x":"https:\/\/ps.w.org\/init-user-engine\/assets\/icon-256x256.png?rev=3329854","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/init-user-engine\/assets\/screenshot-1.png?rev=3678614","caption":"Settings with options for theme color, currency labels, and admin bar\/Gravatar control."},{"src":"https:\/\/ps.w.org\/init-user-engine\/assets\/screenshot-2.png?rev=3626741","caption":"Custom Links section for setting Register and Lost Password URLs."},{"src":"https:\/\/ps.w.org\/init-user-engine\/assets\/screenshot-3.png?rev=3626741","caption":"Check-in Reward configuration, including Coin, EXP, and Cash per check-in."},{"src":"https:\/\/ps.w.org\/init-user-engine\/assets\/screenshot-4.png?rev=3626741","caption":"Online Reward configuration based on active time with reward values."},{"src":"https:\/\/ps.w.org\/init-user-engine\/assets\/screenshot-5.png?rev=3626741","caption":"VIP Pricing options for various durations, including lifetime."},{"src":"https:\/\/ps.w.org\/init-user-engine\/assets\/screenshot-6.png?rev=3626741","caption":"VIP Bonus settings to configure extra Coin\/EXP for VIP users."},{"src":"https:\/\/ps.w.org\/init-user-engine\/assets\/screenshot-7.png?rev=3626741","caption":"Referral Reward settings for both referrer and new user."},{"src":"https:\/\/ps.w.org\/init-user-engine\/assets\/screenshot-8.png?rev=3626741","caption":"Admin panel to send notifications with content, targeting, priority, and expiration."},{"src":"https:\/\/ps.w.org\/init-user-engine\/assets\/screenshot-9.png?rev=3329854","caption":"Login modal interface for non-logged-in users."},{"src":"https:\/\/ps.w.org\/init-user-engine\/assets\/screenshot-10.png?rev=3329854","caption":"Registration modal with username, email, and password fields."},{"src":"https:\/\/ps.w.org\/init-user-engine\/assets\/screenshot-11.png?rev=3329854","caption":"Avatar button with dropdown panel showing user info, level, stats, and quick links."},{"src":"https:\/\/ps.w.org\/init-user-engine\/assets\/screenshot-12.png?rev=3329854","caption":"VIP Membership modal with Coin-based purchase options and expiration note."},{"src":"https:\/\/ps.w.org\/init-user-engine\/assets\/screenshot-13.png?rev=3329854","caption":"Inbox modal showing system messages, rewards, and user notifications."},{"src":"https:\/\/ps.w.org\/init-user-engine\/assets\/screenshot-14.png?rev=3329854","caption":"Transaction history modal showing all reward activities (check-in, referral, online time...)."},{"src":"https:\/\/ps.w.org\/init-user-engine\/assets\/screenshot-15.png?rev=3329854","caption":"Referral modal with shareable code\/link, social sharing buttons, and referral history."}],"raw_content":"<!--section=description-->\n<p><strong>Init User Engine<\/strong> is a lightweight, no-bloat user system for modern WordPress sites. It's designed for maximum frontend flexibility and gamified user engagement. All dynamic interfaces are rendered via JavaScript with real-time REST API interaction.<\/p>\n\n<p>No jQuery. Minimal settings. Smart by default.<\/p>\n\n<p>What you get:<\/p>\n\n<ul>\n<li>Display user avatar and dashboard via shortcode<\/li>\n<li>Show level, EXP, Coin\/Cash, and full user wallet<\/li>\n<li>Frontend login &amp; registration modal with Cloudflare Turnstile (or built-in math captcha) protection<\/li>\n<li>Let users check-in daily and receive timed rewards<\/li>\n<li>Auto-track referral registrations with reward system<\/li>\n<li>Let users buy VIP status using Coin, Cash, or both<\/li>\n<li>Redeem Code \/ Gift Code and dedicated VIP Code system, with CSV export from wp-admin<\/li>\n<li>Built-in inbox for notifications (uses custom DB table), with pinned\/expiring messages and a stats dashboard<\/li>\n<li>Custom avatar support with upload &amp; preview modal<\/li>\n<li>Send custom notifications to selected users or all members from wp-admin<\/li>\n<li>Optional \"Require Login to Access Site\" mode that gates the entire frontend behind the built-in login modal<\/li>\n<li>Optional one-step \"Login After Register\" so new users land on the site already signed in<\/li>\n<\/ul>\n\n<p>This plugin is the core user system behind the <a href=\"https:\/\/en.inithtml.com\/init-plugin-suite-minimalist-powerful-and-free-wordpress-plugins\/\">Init Plugin Suite<\/a> \u2013 optimized for frontend-first interaction, extensibility, and real-time gamification.<\/p>\n\n<p>GitHub repository: <a href=\"https:\/\/github.com\/brokensmile2103\/init-user-engine\">https:\/\/github.com\/brokensmile2103\/init-user-engine<\/a><\/p>\n\n<h3>Features<\/h3>\n\n<p><strong>Profile &amp; Avatar<\/strong><\/p>\n\n<ul>\n<li>Avatar shortcode <code>[init_user_engine]<\/code> \u2013 renders the guest login button or the logged-in avatar with dropdown dashboard automatically  <\/li>\n<li>Modal dashboard showing level, EXP progress, Coin\/Cash wallet, and quick links  <\/li>\n<li>Custom avatar upload with live preview, crop-free flow, and one-click revert to the default\/Gravatar image  <\/li>\n<li>Configurable upload policy (allow everyone, VIP only, or disable uploads entirely) with a configurable max file size  <\/li>\n<li>Theme override support: any template file can be overridden by copying it to <code>your-theme\/init-user-engine\/<\/code><\/li>\n<\/ul>\n\n<p><strong>Accounts, Login &amp; Registration<\/strong><\/p>\n\n<ul>\n<li>Frontend login &amp; registration modal \u2013 no theme editing or template overrides required  <\/li>\n<li>\"Login After Register\" option to automatically sign users in right after they create an account (disabled by default)  <\/li>\n<li>Failed logins reopen the login modal on the current page with an inline error message, instead of redirecting to <code>wp-login.php<\/code>  <\/li>\n<li>Cloudflare Turnstile captcha on registration, with a built-in math-question captcha as automatic fallback when no Turnstile keys are set  <\/li>\n<li>Optional protection of the native WordPress login, registration, and lost-password forms (<code>wp-login.php<\/code>) using the same Turnstile setup  <\/li>\n<li>\"Forgot password?\" form right inside the login modal, using the native WordPress reset flow (can be turned off; a custom Lost Password URL always takes priority)  <\/li>\n<li>Custom redirect URLs for \"Register\" and \"Lost password\" links  <\/li>\n<li>Optional \"Require Login to Access Site\" mode that gates the entire frontend behind the built-in login modal  <\/li>\n<li>Ability to temporarily disable new registrations without affecting other plugins or WordPress core<\/li>\n<\/ul>\n\n<p><strong>Gamification<\/strong><\/p>\n\n<ul>\n<li>EXP &amp; Level system with hookable progression logic  <\/li>\n<li>Coin &amp; Cash dual-wallet system with transaction logs and a configurable exchange rate between the two currencies  <\/li>\n<li>Daily check-in with streak milestones and an online-time bonus timer  <\/li>\n<li>Optional <strong>Streak Recovery<\/strong>: members who miss a few days can spend Coin to keep their check-in streak alive (allowed missed days and Coin price per day are configurable, off by default)  <\/li>\n<li>Built-in reward hooks for registration, daily login, comments, published posts, and completed WooCommerce orders (when WooCommerce is active)<\/li>\n<\/ul>\n\n<p><strong>VIP Membership<\/strong><\/p>\n\n<ul>\n<li>VIP membership system with Coin-based, Cash-based, or combined purchase options  <\/li>\n<li>Multiple configurable pricing tiers per duration, including a lifetime option  <\/li>\n<li>VIP bonus multipliers for Coin\/EXP earning  <\/li>\n<li>Optional VIP purchase lock (globally disable new purchases) and stacking restriction<\/li>\n<\/ul>\n\n<p><strong>Referral<\/strong><\/p>\n\n<ul>\n<li>Referral module with cookie-based signup tracking  <\/li>\n<li>Separate, configurable rewards for both the referrer and the newly referred user<\/li>\n<\/ul>\n\n<p><strong>Redeem &amp; VIP Codes<\/strong><\/p>\n\n<ul>\n<li>Redeem Code \/ Gift Code module \u2013 code in, rewards out  <\/li>\n<li>Dedicated VIP Codes module to grant VIP duration through a code  <\/li>\n<li>One-click CSV export for both code lists (full list, streamed in batches, UTF-8 BOM, and sanitized against CSV\/formula injection)<\/li>\n<\/ul>\n\n<p><strong>Inbox &amp; Notifications<\/strong><\/p>\n\n<ul>\n<li>Built-in inbox system with pagination and read\/claim\/delete actions  <\/li>\n<li>Pinned messages that automatically unpin once read, or once their optional expiration time passes  <\/li>\n<li>Admin panel to send custom notifications to selected users or all members, with priority and expiration  <\/li>\n<li>Inbox Statistics dashboard (Users \u2192 Init User Engine \u2192 Inbox Statistics) with date-range filtering<\/li>\n<\/ul>\n\n<p><strong>Admin Tools<\/strong><\/p>\n\n<ul>\n<li>Manual Top-up tool for Coin\/Cash (Users \u2192 Init User Engine \u2192 Top-up Coin\/Cash)  <\/li>\n<li>Per-user overview metabox on the WordPress profile\/edit-user screen (level, wallet, VIP status, recent activity)<\/li>\n<\/ul>\n\n<p><strong>Developer-Friendly<\/strong><\/p>\n\n<ul>\n<li>REST API for all features (read\/write\/modify)  <\/li>\n<li>Action\/filter hooks for full customization  <\/li>\n<li>Pure Vanilla JS frontend \u2013 no jQuery, no server bloat<\/li>\n<\/ul>\n\n<h3>Developer Hooks<\/h3>\n\n<h3>Filters<\/h3>\n\n<ul>\n<li><code>init_plugin_suite_user_engine_online_minutes<\/code> \u2013 Modify required online minutes after check-in  <\/li>\n<li><code>init_plugin_suite_user_engine_vip_prices<\/code> \u2013 Modify VIP package prices  <\/li>\n<li><code>init_plugin_suite_user_engine_referral_rewards<\/code> \u2013 Modify referral rewards  <\/li>\n<li><code>init_plugin_suite_user_engine_localized_data<\/code> \u2013 Modify frontend JS data  <\/li>\n<li><code>init_plugin_suite_user_engine_calculated_coin_amount<\/code> \u2013 Modify Coin reward before apply  <\/li>\n<li><code>init_plugin_suite_user_engine_calculated_exp_amount<\/code> \u2013 Modify EXP reward before apply  <\/li>\n<li><code>init_plugin_suite_user_engine_exp_required<\/code> \u2013 Modify EXP required per level  <\/li>\n<li><code>init_plugin_suite_user_engine_checkin_milestones<\/code> \u2013 Set milestone streak days  <\/li>\n<li><code>init_plugin_suite_user_engine_format_inbox<\/code> \u2013 Modify formatted inbox data  <\/li>\n<li><code>init_plugin_suite_user_engine_render_level_badge<\/code> \u2013 Customize level badge HTML  <\/li>\n<li><code>init_plugin_suite_user_engine_inbox_insert_data<\/code> \u2013 Modify inbox data before inserting into database  <\/li>\n<li><code>init_plugin_suite_user_engine_validate_register_fields<\/code> \u2013 Validate or modify registration fields before account creation  <\/li>\n<li><code>init_plugin_suite_user_engine_after_register<\/code> \u2013 Hook after successful user registration (pass user ID and submitted data)  <\/li>\n<li><code>init_plugin_suite_user_engine_daily_tasks<\/code> \u2013 Add or modify daily task list and logic  <\/li>\n<li><code>init_plugin_suite_user_engine_captcha_bank<\/code> \u2013 Extend or modify the internal captcha question bank used for fallback validation  <\/li>\n<li><code>init_plugin_suite_user_engine_format_log_message<\/code> \u2013 Customize transaction log message display with access to entry data, source, type, and amount  <\/li>\n<li><code>init_plugin_suite_user_engine_should_keep_original<\/code> \u2013 Override decision to keep original uploaded avatar (GIF or other formats)  <\/li>\n<li><code>init_plugin_suite_user_engine_vip_expire_soon_threshold<\/code> \u2013 Modify the threshold (in seconds) used to determine when VIP is considered close to expiration  <\/li>\n<li><code>init_plugin_suite_user_engine_body_vip_classes<\/code> \u2013 Add, remove, or modify VIP-related CSS classes applied to the <code>&lt;body&gt;<\/code> element<\/li>\n<li><code>init_plugin_suite_user_engine_theme_colors<\/code> \u2013 Modify theme color system (primary and active colors)<\/li>\n<li><code>init_plugin_suite_user_engine_streak_restore_max_days<\/code> \u2013 Modify how many missed check-in days a user may cover to keep their streak (return <code>0<\/code> to disable it for that user)<\/li>\n<li><code>init_plugin_suite_user_engine_streak_restore_cost<\/code> \u2013 Modify the Coin cost of keeping a streak (receives total cost, missed days, and user ID)<\/li>\n<li><code>init_plugin_suite_user_engine_lostpassword_modal_enabled<\/code> \u2013 Enable or disable the lost password form inside the login modal (receives the current value and the plugin settings)<\/li>\n<\/ul>\n\n<h3>Actions<\/h3>\n\n<ul>\n<li><code>init_plugin_suite_user_engine_level_up<\/code> \u2013 When user levels up  <\/li>\n<li><code>init_plugin_suite_user_engine_exp_added<\/code> \u2013 After EXP is added  <\/li>\n<li><code>init_plugin_suite_user_engine_transaction_logged<\/code> \u2013 After Coin\/Cash is logged  <\/li>\n<li><code>init_plugin_suite_user_engine_exp_logged<\/code> \u2013 After EXP log is recorded  <\/li>\n<li><code>init_plugin_suite_user_engine_inbox_inserted<\/code> \u2013 After new inbox message  <\/li>\n<li><code>init_plugin_suite_user_engine_referral_completed<\/code> \u2013 When referral is completed  <\/li>\n<li><code>init_plugin_suite_user_engine_after_checkin<\/code> \u2013 After user check-in  <\/li>\n<li><code>init_plugin_suite_user_engine_streak_restored<\/code> \u2013 After a user paid Coin to keep their check-in streak (user ID, missed days, cost, new streak)  <\/li>\n<li><code>init_plugin_suite_user_engine_after_claim_reward<\/code> \u2013 After user claims reward  <\/li>\n<li><code>init_plugin_suite_user_engine_vip_purchased<\/code> \u2013 After VIP is purchased  <\/li>\n<li><code>init_plugin_suite_user_engine_add_exp<\/code> \u2013 Triggered when adding EXP via hook  <\/li>\n<li><code>init_plugin_suite_user_engine_add_coin<\/code> \u2013 Triggered when adding Coin via hook  <\/li>\n<li><code>init_plugin_suite_user_engine_coin_changed<\/code> \u2013 After user\u2019s Coin balance is updated  <\/li>\n<li><code>init_plugin_suite_user_engine_cash_changed<\/code> \u2013 After user\u2019s Cash balance is updated  <\/li>\n<li><code>init_plugin_suite_user_engine_admin_send_notice<\/code> \u2013 When admin sends notification via wp-admin.<\/li>\n<\/ul>\n\n<h3>REST API Endpoints<\/h3>\n\n<p><strong>Base:<\/strong> <code>\/wp-json\/inituser\/v1\/<\/code><\/p>\n\n<ul>\n<li><code>POST \/register<\/code> \u2013 Create a new user account  <\/li>\n<li><code>POST \/checkin<\/code> \u2013 Daily check-in (optional JSON body: <code>prompt_restore<\/code>, <code>restore_streak<\/code>, <code>restore_cost<\/code> for Streak Recovery)  <\/li>\n<li><code>POST \/claim-reward<\/code> \u2013 Claim reward after online duration  <\/li>\n<li><code>GET  \/transactions<\/code> \u2013 Get Coin\/Cash transaction log  <\/li>\n<li><code>GET  \/exp-log<\/code> \u2013 Get EXP log  <\/li>\n<li><code>GET  \/inbox<\/code> \u2013 Get inbox messages  <\/li>\n<li><code>POST \/inbox\/mark-read<\/code> \u2013 Mark a message as read  <\/li>\n<li><code>POST \/inbox\/mark-all-read<\/code> \u2013 Mark all as read  <\/li>\n<li><code>POST \/inbox\/delete<\/code> \u2013 Delete a single message  <\/li>\n<li><code>POST \/inbox\/delete-all<\/code> \u2013 Delete all messages  <\/li>\n<li><code>POST \/vip\/purchase<\/code> \u2013 Purchase VIP package  <\/li>\n<li><code>GET  \/referral-log<\/code> \u2013 Get referral history  <\/li>\n<li><code>POST \/avatar<\/code> \u2013 Upload new avatar  <\/li>\n<li><code>POST \/avatar\/remove<\/code> \u2013 Remove custom avatar and revert to default  <\/li>\n<li><code>GET  \/profile\/me<\/code> \u2013 Get current user profile  <\/li>\n<li><code>POST \/profile\/update<\/code> \u2013 Update profile information<\/li>\n<li><code>GET  \/daily-tasks<\/code> \u2013 Get list of completed daily tasks and rewards<\/li>\n<li><code>POST \/exchange<\/code> \u2013 Convert Cash \u2192 Coin based on exchange rate<\/li>\n<li><code>POST \/redeem-code<\/code> \u2013 Redeem gift code (returns Coin\/Cash rewards)<\/li>\n<\/ul>\n\n<h3>License<\/h3>\n\n<p>This plugin is licensed under the GPLv2 or later.<br \/>\nYou are free to use, modify, and distribute it under the same license.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin to <code>\/wp-content\/plugins\/init-user-engine<\/code>  <\/li>\n<li>Activate it via the Plugins screen  <\/li>\n<li>Use <code>[init_user_engine]<\/code> in any page\/post\/template  <\/li>\n<li>You're done \u2013 modals and logic load automatically<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"how%20do%20i%20customize%20the%20ui%3F\"><h3>How do I customize the UI?<\/h3><\/dt>\n<dd><p>The frontend is written in modular Vanilla JS with minimal HTML structure.<br \/>\nOverride styles via your theme or inject custom JS as needed.<\/p><\/dd>\n<dt id=\"where%20is%20user%20data%20stored%3F\"><h3>Where is user data stored?<\/h3><\/dt>\n<dd><ul>\n<li><code>user_meta<\/code>: EXP, level, Coin, Cash, VIP, referral  <\/li>\n<li><code>wp_init_user_engine_inbox<\/code>: inbox messages (custom DB table)<\/li>\n<\/ul><\/dd>\n<dt id=\"can%20i%20extend%20or%20integrate%20it%3F\"><h3>Can I extend or integrate it?<\/h3><\/dt>\n<dd><p>Yes. The plugin is built around WordPress hooks and REST API. You can inject logic via <code>add_action<\/code>, <code>add_filter<\/code>, or build your own UI on top of the endpoints.<\/p><\/dd>\n<dt id=\"is%20it%20compatible%20with%20woocommerce%20or%20buddypress%3F\"><h3>Is it compatible with WooCommerce or BuddyPress?<\/h3><\/dt>\n<dd><p>Not officially, but it\u2019s modular and can be integrated via code or future addons.<\/p><\/dd>\n<dt id=\"how%20do%20i%20send%20messages%20to%20users%20manually%3F\"><h3>How do I send messages to users manually?<\/h3><\/dt>\n<dd><p>Go to <strong>Users \u2192 Init User Engine \u2192 Send Notification<\/strong> in wp-admin.<br \/>\nYou can search users, customize message type, link, priority, and even set expiration.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.6.7 \u2013 October 3, 2026<\/h4>\n\n<ul>\n<li>Performance (large sites): rebuilt the database indexes used by the Inbox, after a production slow query log showed \"Mark All as Read\" (<code>UPDATE \u2026 WHERE user_id = \u2026 AND status = 'unread'<\/code>) taking 2.5 seconds on a 1.2M-message Inbox\n\n<ul>\n<li>New composite index <code>user_status (user_id, status)<\/code>: the unread badge count, \"Mark All as Read\" and the Unread tab now read the index only instead of loading every message row of the user (about 181 \u2192 3 pages read per unread count in our 1.25M-row benchmark)<\/li>\n<li>New composite index <code>user_pinned_created (user_id, pinned, created_at)<\/code>: the Inbox list (<code>ORDER BY pinned DESC, created_at DESC<\/code>) is read straight from the index, no more filesort<\/li>\n<li>Dropped single-column <code>user_id<\/code> indexes on the Inbox, Transaction log and EXP log tables. They were fully covered by composite indexes that start with <code>user_id<\/code>, so they only cost extra writes and disk space (every Coin\/EXP change writes to these tables)<\/li>\n<li>Safe on big databases: the index upgrade runs in the background through WP-Cron, never inside a page load (small and new sites are upgraded instantly). It uses online DDL (<code>ALGORITHM=INPLACE, LOCK=NONE<\/code>), so reads and writes keep working while indexes are built; it gives up after 3 seconds if it has to wait for a table lock, instead of making other queries queue behind it, then retries an hour later (up to 24 times); and a lock option makes sure only one process ever runs it. If WP-Cron is not running, the upgrade runs on the next admin page load after the event is more than an hour late<\/li>\n<li>You can also run it yourself during quiet hours (replace <code>wp_<\/code> with your table prefix); the plugin detects the new indexes and marks the upgrade as done: <code>ALTER TABLE wp_init_user_engine_inbox ADD KEY user_status (user_id, status), ADD KEY user_pinned_created (user_id, pinned, created_at), DROP KEY user_id, ALGORITHM=INPLACE, LOCK=NONE;<\/code> then <code>ALTER TABLE wp_init_user_engine_transaction_log DROP KEY user_id;<\/code> and <code>ALTER TABLE wp_init_user_engine_exp_log DROP KEY user_id;<\/code><\/li>\n<\/ul><\/li>\n<li>Performance: the weekly orphaned-Inbox cleanup no longer runs a single <code>DELETE \u2026 LEFT JOIN<\/code> over the whole Inbox table. That statement scanned and locked every row (even when nothing needed deleting), blocking every member's Inbox actions while it ran; in our benchmark a member's \"Mark All as Read\" waited 7.9 seconds. It now walks the distinct user IDs through the index, checks them against the users table in batches of 500 and deletes only orphaned messages, at most 1,000 rows per statement (0.45 s and no table-wide locks when there is nothing to delete)<\/li>\n<li>Performance: <strong>Inbox Statistics \u2192 Delete All of This Type<\/strong> now deletes in batches of 1,000 by primary key instead of one <code>DELETE \u2026 WHERE type = \u2026<\/code>, which locked the whole table until done (members' Inbox actions waited 7 seconds while 200k messages were deleted in our benchmark; now under 0.1 second)<\/li>\n<li>Fixed: the orphaned-Inbox cleanup used <code>$wpdb-&gt;prefix . 'users'<\/code> as the users table, which does not exist on Multisite sub-sites (the users table is shared network-wide). It now uses <code>$wpdb-&gt;users<\/code><\/li>\n<li>The new background event is cleared on deactivation along with the plugin's other cron events<\/li>\n<\/ul>\n\n<h4>1.6.6 \u2013 October 1, 2026<\/h4>\n\n<ul>\n<li>Added <strong>Lost Password in Modal<\/strong> (Init User Engine \u2192 Settings, right below <em>Login After Register<\/em>). The \"Forgot password?\" link in the login modal now opens a lost password form inside the same modal instead of sending visitors to <code>wp-login.php<\/code>\n\n<ul>\n<li>Enabled by default. Turn it off if your site cannot send emails yet \u2014 the link then goes to the default <code>wp-login.php?action=lostpassword<\/code> page as before<\/li>\n<li><strong>Custom Lost Password URL<\/strong> (Custom Links) still takes priority: when it is set, the link always goes there, whatever this option says<\/li>\n<li>Uses the native WordPress password reset flow: the form posts to <code>wp-login.php?action=lostpassword<\/code>, so the reset email, <code>lostpassword_form<\/code> \/ <code>lostpassword_post<\/code> hooks and the Turnstile \"Lost Password Form\" protection all keep working<\/li>\n<li>After submitting, visitors land back on the same page with the modal open: a success notice in the login form when the email was sent, or an inline error in the lost password form (unknown user, empty field, email sending failure, captcha failure). Any other error keeps WordPress's default <code>wp-login.php<\/code> behaviour so its exact message is still shown<\/li>\n<li>Template <code>lostpassword-form.php<\/code> can be overridden from <code>your-theme\/init-user-engine\/<\/code>; any element can also open it with <code>data-iue=\"lostpassword\"<\/code><\/li>\n<li>Added filter <code>init_plugin_suite_user_engine_lostpassword_modal_enabled<\/code><\/li>\n<\/ul><\/li>\n<li>Performance: the guest script no longer runs a <code>MutationObserver<\/code> on the whole <code>&lt;body&gt;<\/code> (it fired on every DOM change of the page just to attach the password toggle to the registration form, which is already in the page)<\/li>\n<li>Performance: the <code>get_avatar_url<\/code> filter no longer re-runs every plugin's <code>pre_get_avatar_data<\/code> callbacks for each avatar; it only applies Init User Engine's own avatar logic (the result is the same)<\/li>\n<li>Performance: the check-in countdown now saves its state on <code>pagehide<\/code> instead of <code>beforeunload<\/code>, so browsers can keep the page in the back\/forward cache<\/li>\n<li>Fixed: the deactivation hook was registered against <code>includes\/core.php<\/code> instead of the main plugin file, so it never ran and the plugin's cron events stayed scheduled after deactivation. All three recurring events are now cleared on deactivation (they are scheduled again automatically on reactivation)<\/li>\n<li>Fixed: the twice-daily cleanup compared transient expiry times (stored in UTC) with the site's local time, so on sites ahead of UTC it could delete registration captchas and rate-limit counters that had not expired yet<\/li>\n<li>Fixed: on sites using \"Plain\" permalinks (REST URL like <code>?rest_route=\/inituser\/v1<\/code>), requests that add their own query string were malformed: the registration math captcha never loaded, and Inbox, Transaction History and Experience Log pagination failed. Query strings are now appended with <code>&amp;<\/code> when the REST URL already has one<\/li>\n<li>Updated <code>.pot<\/code>\/<code>.po<\/code>\/<code>.mo<\/code> translation files with the new strings introduced above (Vietnamese translation included), regenerated with WP-CLI<\/li>\n<\/ul>\n\n<h4>1.6.5 \u2013 September 24, 2026<\/h4>\n\n<ul>\n<li>Added <strong>Streak Recovery<\/strong> (Init User Engine \u2192 Settings \u2192 Streak Recovery). When a member misses a few days, they can now spend Coin to keep their check-in streak instead of losing it\n\n<ul>\n<li>Two new settings: <strong>Missed Days Allowed<\/strong> (how many missed days can be covered, <code>0<\/code> = feature off) and <strong>Coin Cost per Missed Day<\/strong> (<code>0<\/code> = free). Off by default, so nothing changes on existing sites until an admin turns it on<\/li>\n<li>Clicking <strong>Check In<\/strong> after a gap opens the plugin's standard modal showing the current streak, missed days, total cost and the member's balance, with two choices: keep the streak (pay), or reset it and check in anyway. Closing the modal does nothing. Missing more days than allowed simply resets the streak as before<\/li>\n<li>Keeping a streak covers the missed days but does not count them as check-ins: the streak continues from where it was and today adds +1, so streak milestone rewards (7\/30\/90\u2026) behave exactly as before<\/li>\n<li>Every charge is written to the Coin transaction log as a deduction with a readable reason (e.g. \"Kept check-in streak (2 missed days)\"), shown in the member's Transaction History and in the admin user metabox<\/li>\n<li>The frontend only ever shows the configured <strong>Coin Label<\/strong>, never a hardcoded \"Coin\"; all new frontend and error strings are label-aware<\/li>\n<li>Safety: the price is re-checked on the server against what the member was shown (rejected if it changed), the balance is verified just before charging, and if the log entry cannot be written the Coin is handed back and the streak is left untouched<\/li>\n<li><code>POST \/checkin<\/code> gained three optional JSON fields: <code>prompt_restore<\/code> (answer with status <code>restore_available<\/code> instead of checking in when the streak can be kept \u2014 nothing is changed), <code>restore_streak<\/code> and <code>restore_cost<\/code>. Clients that don't send them behave exactly as before<\/li>\n<li>Added filters <code>init_plugin_suite_user_engine_streak_restore_max_days<\/code> and <code>init_plugin_suite_user_engine_streak_restore_cost<\/code>, and action <code>init_plugin_suite_user_engine_streak_restored<\/code><\/li>\n<li>New logic lives in <code>includes\/streak-restore.php<\/code><\/li>\n<\/ul><\/li>\n<li>Fixed: <code>POST \/checkin<\/code> had no protection against overlapping requests, so two requests fired at the same moment could both pass the \"already checked in today\" test and reward the same day twice. Check-ins are now serialized per user with the same short-lived mutex pattern used by the exchange endpoints; a request that arrives while another is running gets a <code>409 busy<\/code> response<\/li>\n<li>Fixed: modals opened from the logged-in dashboard never played their open animation. The <code>fadeIn<\/code>\/<code>slideDown<\/code> keyframes referenced by <code>#iue-modal<\/code> only existed in <code>style-guest.css<\/code>, which is not loaded for logged-in users. Added namespaced <code>iue-fade-in<\/code>\/<code>iue-slide-down<\/code> keyframes to <code>style-user.css<\/code> (so a theme's own <code>fadeIn<\/code>\/<code>slideDown<\/code> can no longer interfere) plus a <code>prefers-reduced-motion<\/code> opt-out<\/li>\n<li>Fixed: leaving the <strong>Coin Label<\/strong> or <strong>Cash Label<\/strong> field empty made the frontend (dashboard data, Referral benefits, exchange and VIP screens) display a blank currency name, and the VIP purchase inbox message could show an empty label. Both now fall back to \"Coin\" \/ \"Cash\" through the shared <code>init_plugin_suite_user_engine_get_coin_label()<\/code> \/ <code>..._get_cash_label()<\/code> helpers<\/li>\n<li>Fixed: after a failed check-in request (a server error, or a network failure) the check-in button used to switch to \"Checked in\" or fall back to an untranslated \"Check-in\" (it read a translation key that was never defined); it now returns to its normal, translated label and shows the error<\/li>\n<li>Fixed: the plugin's activation hook was registered against <code>includes\/init.php<\/code> instead of the main plugin file, so it never ran and the database tables were only created later, on the first <code>admin_init<\/code>. It now runs on activation as intended (the <code>admin_init<\/code> version check stays as the upgrade path)<\/li>\n<li>Updated <code>.pot<\/code>\/<code>.po<\/code>\/<code>.mo<\/code> translation files with the new strings introduced above (Vietnamese translation included), regenerated with WP-CLI<\/li>\n<\/ul>\n\n<h4>1.6.4 \u2013 September 10, 2026<\/h4>\n\n<ul>\n<li>Fixed: permanently deleting a user (from Users \u2192 All Users, bulk delete, or the REST Users endpoint) used to leave that user's <strong>EXP history<\/strong> and <strong>Inbox messages<\/strong> behind in the database forever, since nothing ever cleaned them up after the account itself was gone\n\n<ul>\n<li>Now hooked into WordPress core's <code>deleted_user<\/code> action (fires for both single-site <code>wp_delete_user()<\/code> and multisite <code>wpmu_delete_user()<\/code>, so one hook covers both): as soon as a user is permanently deleted, their EXP log rows and all Inbox messages are deleted right along with it<\/li>\n<li>Coin\/Cash <strong>transaction log stays untouched on purpose<\/strong> \u2014 wallet history feeds into site-wide statistics and reconciliation (total coin\/cash ever issued, revenue reports, etc.), so it's intentionally kept even after the user account is gone<\/li>\n<li><code>iue_*<\/code> user meta (check-in streak, login bonus flags, profile bonus flag...) needed no extra handling \u2014 WordPress core already wipes all usermeta for the user before <code>deleted_user<\/code> fires<\/li>\n<li>Added action hook <code>init_plugin_suite_user_engine_user_data_purged<\/code> (fires with the deleted user's ID right after cleanup) so other plugins\/add-ons can hook in and clean up their own related data too<\/li>\n<\/ul><\/li>\n<li>No new user-facing strings in this release, so <code>.pot<\/code>\/<code>.po<\/code> files are unchanged<\/li>\n<\/ul>\n\n<h4>1.6.3 \u2013 September 7, 2026<\/h4>\n\n<ul>\n<li>Added a new <strong>\"Login After Register\"<\/strong> option (Init User Engine \u2192 Settings \u2192 General, disabled by default). When enabled, a successful registration through the plugin's REST endpoint (<code>\/register<\/code>) immediately signs the new user in (<code>wp_set_auth_cookie()<\/code> + <code>wp_set_current_user()<\/code>, followed by the standard <code>wp_login<\/code> action for compatibility with other plugins\/themes) instead of leaving them on the Login form\n\n<ul>\n<li>The frontend register form now reloads the page after a successful auto-login (instead of switching to the Login form) so the UI, nonces, and avatar immediately reflect the signed-in state<\/li>\n<li>Left disabled by default so registration and login remain two explicit, separate steps unless a site owner opts in<\/li>\n<\/ul><\/li>\n<li>Fixed: a failed login attempt from the plugin's login modal (via <code>wp_login_form()<\/code>) used to fall back to WordPress's default behavior and redirect the visitor to <code>wp-login.php<\/code>, which felt out of place on sites that never expose that page. Failed logins now redirect back to the exact page the visitor was on, with the login modal automatically reopened and an inline error message (wrong username, wrong password, or missing fields)\n\n<ul>\n<li>Implemented via the <code>wp_login_failed<\/code> action combined with <code>wp_get_referer()<\/code>; only intervenes when the login attempt came from a normal frontend page, so logins made directly on <code>wp-login.php<\/code> or inside <code>wp-admin<\/code> keep WordPress's native behavior untouched<\/li>\n<li>The redirect uses two short-lived query arguments (<code>iue_login_failed<\/code>, <code>iue_login_code<\/code>) that <code>assets\/js\/guest.js<\/code> reads once to open the modal and show the right message, then immediately strips from the URL via <code>history.replaceState()<\/code> so refreshing or sharing the link never re-shows the notice<\/li>\n<\/ul><\/li>\n<li>Refreshed <code>readme.txt<\/code> \u2014 the <strong>Features<\/strong> section was rewritten from scratch to match the plugin's actual current feature set (Turnstile\/captcha, Require Login gate, Redeem\/VIP Codes with CSV export, Inbox Statistics, admin user metabox, and more), several of which had been implemented in past releases but never documented here<\/li>\n<li>Updated <code>.pot<\/code>\/<code>.po<\/code> translation files with the new strings introduced above (Vietnamese translation included)<\/li>\n<\/ul>\n\n<h4>1.6.2 \u2013 September 4, 2026<\/h4>\n\n<ul>\n<li>Changed: a pinned Inbox message now only stays pinned to the top while it is <strong>unread<\/strong>. As soon as it's marked as read (single message or \"mark all as read\"), it automatically unpins and behaves like any other message, so read messages no longer take up space at the top of the Inbox modal\n\n<ul>\n<li>Implemented by clearing <code>pinned<\/code> back to <code>0<\/code> in the exact same <code>UPDATE<\/code> query that already sets a message to <code>read<\/code> (<code>init_plugin_suite_user_engine_mark_inbox_read()<\/code> and the \"mark all as read\" REST endpoint) \u2014 no extra query, no change to the Inbox <code>SELECT<\/code>\/<code>ORDER BY<\/code>, and no new database index needed<\/li>\n<li>Added a one-time backfill (runs once on upgrade, same mechanism already used for schema updates) that clears <code>pinned<\/code> for any pre-existing message that was already pinned <strong>and<\/strong> read before this update<\/li>\n<li>Added a client-side safety net in the Inbox renderer so the pin icon never shows on a read message, even for the brief moment before the backfill above has run<\/li>\n<\/ul><\/li>\n<li>Updated <code>.pot<\/code>\/<code>.po<\/code> translation files (no new strings were needed for this change; existing ones were already sufficient)<\/li>\n<\/ul>\n\n<h4>1.6.1 \u2013 September 4, 2026<\/h4>\n\n<ul>\n<li>Added <strong>Export CSV<\/strong> for both code list screens (User Engine \u2192 Redeem Codes \/ VIP Codes)\n\n<ul>\n<li>New \"Export CSV\" button next to the \"Existing Redeem Codes\" \/ \"Existing VIP Codes\" heading, exporting the <strong>entire list<\/strong> (every page, not just the current one) as a downloadable <code>.csv<\/code> file<\/li>\n<li>Redeem Codes CSV columns: ID, Code, Type, Locked User ID, Locked Username, Coin Amount, Cash Amount, Max Uses, Used Count, Status, Valid From, Valid To, Created By, Created At, Updated At<\/li>\n<li>VIP Codes CSV columns: same as above, with VIP Days in place of Coin\/Cash Amount<\/li>\n<li>Data is streamed straight to the browser in batches of 500 rows so memory usage stays low even on sites with a large number of codes<\/li>\n<li>File is written with a UTF-8 BOM so it opens correctly in Excel, and every cell is sanitized against CSV\/formula injection (values starting with <code>=<\/code>, <code>+<\/code>, <code>-<\/code>, <code>@<\/code>, or a tab are safely prefixed)<\/li>\n<li>Gated behind the <code>manage_options<\/code> capability plus a dedicated nonce per screen (<code>iue_redeem_code_export_csv<\/code> \/ <code>iue_vip_code_export_csv<\/code>)<\/li>\n<\/ul><\/li>\n<li>Updated <code>.pot<\/code>\/<code>.po<\/code> translation files with the new strings introduced above (Vietnamese translation included); <code>.mo<\/code> not rebuilt as part of this change<\/li>\n<\/ul>\n\n<h4>1.6.0 \u2013 September 2, 2026<\/h4>\n\n<ul>\n<li>Added a new <strong>\"Require Login to Access Site\"<\/strong> option (Init User Engine \u2192 Settings \u2192 General). When enabled, visitors who are not logged in no longer see the site's actual content on any page\n\n<ul>\n<li>Instead, they see a blank page in the plugin's theme color with the built-in login modal opened automatically, so they can sign in without leaving the page<\/li>\n<li>Implemented via <code>template_redirect<\/code>, so <code>wp_head()<\/code>\/<code>wp_footer()<\/code> still run in full \u2014 the plugin's own login modal, and every other theme\/plugin hook attached to those actions, keeps working normally<\/li>\n<li>REST API, AJAX, cron, feed, and robots.txt requests are always excluded and are never blocked by this option<\/li>\n<li>Added filter <code>init_plugin_suite_user_engine_require_login_bypass<\/code> so other plugins\/themes can exclude specific requests (e.g. a payment callback URL) from the gate<\/li>\n<li>New dedicated <code>assets\/css\/require-login.css<\/code> and <code>assets\/js\/require-login.js<\/code> files render the gate's background and auto-open the login modal, kept separate from PHP output for coding-standards compliance<\/li>\n<\/ul><\/li>\n<li>Fixed: the frontend guest script (<code>guest.js<\/code>) only exposed <code>window.openLoginModal<\/code> (and wired up Escape-to-close, Alt+L, and hash-triggered opening) when an avatar element was present on the page. Pages without the avatar shortcode\/widget \u2014 including the new Require Login gate \u2014 could not open the login modal at all. The avatar element is now optional; the modal and its triggers work on any page as long as the modal itself is rendered (always the case via <code>wp_footer<\/code>)<\/li>\n<li>Updated <code>.pot<\/code>\/<code>.po<\/code> translation files with the new strings introduced above (Vietnamese translation included); <code>.mo<\/code> not rebuilt as part of this change<\/li>\n<\/ul>\n\n<p>View full changelog (all versions): <a href=\"https:\/\/en.inithtml.com\/plugin\/init-user-engine\/\">Init User Engine \u2013 Changelog<\/a><\/p>","raw_excerpt":"Gamified user engine with EXP levels, Coin\/Cash wallet, check-in, VIP, inbox, and referral \u2013 powered by REST API and Vanilla JS.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/so.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/240696","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/so.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/so.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/so.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=240696"}],"author":[{"embeddable":true,"href":"https:\/\/so.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/brokensmile2103-1"}],"wp:attachment":[{"href":"https:\/\/so.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=240696"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/so.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=240696"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/so.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=240696"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/so.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=240696"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/so.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=240696"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/so.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=240696"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}