{"id":248668,"date":"2025-09-01T08:16:37","date_gmt":"2025-09-01T08:16:37","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/init-chat-engine\/"},"modified":"2026-10-02T11:42:50","modified_gmt":"2026-10-02T11:42:50","slug":"init-chat-engine","status":"publish","type":"plugin","link":"https:\/\/ky.wordpress.org\/plugins\/init-chat-engine\/","author":14479633,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.3.9","stable_tag":"1.3.9","tested":"7.1.2","requires":"5.5","requires_php":"7.4","requires_plugins":null,"header_name":"Init Chat Engine","header_author":"Init HTML","header_description":"A lightweight, community-focused chat system built with REST API and Vanilla JS. Embed anywhere using the [init_chatbox] shortcode.","assets_banners_color":"39b3f8","last_updated":"2026-10-02 11:42:50","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/inithtml.com\/plugin\/init-chat-engine\/","header_author_uri":"https:\/\/inithtml.com\/","rating":0,"author_block_rating":0,"active_installs":60,"downloads":2731,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.1.6":{"tag":"1.1.6","author":"brokensmile.2103","date":"2025-09-01 08:31:03","revision":3353725},"1.1.7":{"tag":"1.1.7","author":"brokensmile.2103","date":"2025-09-13 11:20:42","revision":3360973},"1.1.8":{"tag":"1.1.8","author":"brokensmile.2103","date":"2025-09-13 14:57:02","revision":3361058},"1.1.9":{"tag":"1.1.9","author":"brokensmile.2103","date":"2025-10-01 03:09:10","revision":3370813},"1.2.0":{"tag":"1.2.0","author":"brokensmile.2103","date":"2025-10-02 06:50:04","revision":3371559},"1.2.1":{"tag":"1.2.1","author":"brokensmile.2103","date":"2025-10-07 13:34:20","revision":3374444},"1.2.2":{"tag":"1.2.2","author":"brokensmile.2103","date":"2025-10-07 14:52:10","revision":3374502},"1.2.3":{"tag":"1.2.3","author":"brokensmile.2103","date":"2025-10-14 15:39:20","revision":3378294},"1.2.4":{"tag":"1.2.4","author":"brokensmile.2103","date":"2025-10-18 03:25:17","revision":3380377},"1.2.5":{"tag":"1.2.5","author":"brokensmile.2103","date":"2025-10-18 08:22:09","revision":3380430},"1.2.6":{"tag":"1.2.6","author":"brokensmile.2103","date":"2025-10-29 14:28:45","revision":3386496},"1.2.7":{"tag":"1.2.7","author":"brokensmile.2103","date":"2025-11-10 02:52:18","revision":3392606},"1.2.8":{"tag":"1.2.8","author":"brokensmile.2103","date":"2025-11-11 05:27:09","revision":3393371},"1.2.9":{"tag":"1.2.9","author":"brokensmile.2103","date":"2026-02-13 02:10:24","revision":3460451},"1.3.0":{"tag":"1.3.0","author":"brokensmile.2103","date":"2026-03-02 13:35:12","revision":3472730},"1.3.1":{"tag":"1.3.1","author":"brokensmile.2103","date":"2026-03-26 04:20:31","revision":3491412},"1.3.2":{"tag":"1.3.2","author":"brokensmile.2103","date":"2026-03-30 03:53:44","revision":3494177},"1.3.3":{"tag":"1.3.3","author":"brokensmile.2103","date":"2026-03-30 04:52:25","revision":3494207},"1.3.4":{"tag":"1.3.4","author":"brokensmile.2103","date":"2026-04-07 04:00:12","revision":3500314},"1.3.4.1":{"tag":"1.3.4.1","author":"brokensmile.2103","date":"2026-05-17 16:08:13","revision":3534668},"1.3.4.2":{"tag":"1.3.4.2","author":"brokensmile.2103","date":"2026-05-18 14:48:52","revision":3535780},"1.3.5":{"tag":"1.3.5","author":"brokensmile.2103","date":"2026-08-01 08:00:42","revision":3630714},"1.3.6":{"tag":"1.3.6","author":"brokensmile.2103","date":"2026-08-14 11:42:58","revision":3647275},"1.3.7":{"tag":"1.3.7","author":"brokensmile.2103","date":"2026-08-21 07:23:52","revision":3658427},"1.3.8":{"tag":"1.3.8","author":"brokensmile.2103","date":"2026-10-01 14:33:28","revision":3723320},"1.3.9":{"tag":"1.3.9","author":"brokensmile.2103","date":"2026-10-02 11:42:50","revision":3724699}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3353713,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3353713,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3353713,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3353713,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["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.4.1","1.3.4.2","1.3.5","1.3.6","1.3.7","1.3.8","1.3.9"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3353713,"resolution":"1","location":"assets","locale":"","width":896,"height":644},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3353713,"resolution":"2","location":"assets","locale":"","width":841,"height":682},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3353713,"resolution":"3","location":"assets","locale":"","width":868,"height":716},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3353713,"resolution":"4","location":"assets","locale":"","width":756,"height":369}},"screenshots":{"1":"Admin settings panel - Basic configuration","2":"Admin settings panel - Security and moderation","3":"Admin settings panel - Advanced options and maintenance","4":"Frontend chatbox interface with guest and user messages"}},"plugin_section":[],"plugin_tags":[5707,2316,4035,3518,80],"plugin_category":[41,43,44],"plugin_contributors":[242666],"plugin_business_model":[],"class_list":["post-248668","plugin","type-plugin","status-publish","hentry","plugin_tags-chat","plugin_tags-community","plugin_tags-lightweight","plugin_tags-realtime","plugin_tags-shortcode","plugin_category-communication","plugin_category-customization","plugin_category-discussion-and-community","plugin_contributors-brokensmile2103-1","plugin_committers-brokensmile2103-1"],"banners":{"banner":"https:\/\/ps.w.org\/init-chat-engine\/assets\/banner-772x250.png?rev=3353713","banner_2x":"https:\/\/ps.w.org\/init-chat-engine\/assets\/banner-1544x500.png?rev=3353713","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/init-chat-engine\/assets\/icon-128x128.png?rev=3353713","icon_2x":"https:\/\/ps.w.org\/init-chat-engine\/assets\/icon-256x256.png?rev=3353713","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/init-chat-engine\/assets\/screenshot-1.png?rev=3353713","caption":"Admin settings panel - Basic configuration"},{"src":"https:\/\/ps.w.org\/init-chat-engine\/assets\/screenshot-2.png?rev=3353713","caption":"Admin settings panel - Security and moderation"},{"src":"https:\/\/ps.w.org\/init-chat-engine\/assets\/screenshot-3.png?rev=3353713","caption":"Admin settings panel - Advanced options and maintenance"},{"src":"https:\/\/ps.w.org\/init-chat-engine\/assets\/screenshot-4.png?rev=3353713","caption":"Frontend chatbox interface with guest and user messages"}],"raw_content":"<!--section=description-->\n<p>Init Chat Engine is a clean and minimal frontend chatbox plugin, designed for homepage or site-wide communication with comprehensive administrative controls.<\/p>\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-chat-engine\">https:\/\/github.com\/brokensmile2103\/init-chat-engine<\/a><\/p>\n\n<p><strong>Key Features:<\/strong><\/p>\n\n<p><strong>Frontend Experience:<\/strong>\n- Built with 100% REST API and Vanilla JS\n- No jQuery, no bloat \u2013 blazing fast\n- Fully embeddable via <code>[init_chatbox]<\/code> shortcode\n- Multiple chat rooms via <code>[init_chatbox room=\"...\"]<\/code> \u2013 each room has its own messages, pinned message and limits\n- Guest messaging support (optional)\n- Smart polling system (adaptive 3.5\u201310s based on activity, up to 20s when the chatbox is scrolled out of view)\n- Browser notifications when new messages arrive\n- Scroll-up to load history, scroll-down to auto-scroll\n- Optimistic sending &amp; \"new message\" jump button\n- Clean UI with customizable themes\n- Template override supported (<code>chatbox.php<\/code>)<\/p>\n\n<p><strong>Administrative Control:<\/strong>\n- <strong>Complete Settings Panel<\/strong> - Basic, Security, and Advanced configurations\n- <strong>Message Management<\/strong> - Search, view, delete messages with pagination\n- <strong>User Moderation<\/strong> - Ban\/unban users by IP or user ID with expiration\n- <strong>Rate Limiting<\/strong> - Prevent spam with configurable message limits\n- <strong>Word Filtering<\/strong> - Block messages containing prohibited words\n- <strong>Statistics Dashboard<\/strong> - View chat activity, user engagement, and trends\n- <strong>Cleanup Tools<\/strong> - Automatic and manual cleanup of old messages\n- <strong>Custom CSS Support<\/strong> - Full styling customization options<\/p>\n\n<p><strong>Security &amp; Moderation:<\/strong>\n- IP-based and user-based banning system\n- Configurable rate limiting (messages per minute)\n- Word filtering with custom blocked word lists\n- Message moderation queue (optional)\n- Automatic cleanup of old messages and expired bans\n- Admin override capabilities<\/p>\n\n<p><strong>Multilingual Ready:<\/strong>\n- Translation-ready with full <code>.pot<\/code> file included\n- Vietnamese translation included\n- Easy to translate to any language<\/p>\n\n<p>Perfect for community-based sites, forums, fanpages, manga readers, SaaS dashboards, customer support, or any interactive chat widget.<\/p>\n\n<h3>Shortcode Attributes<\/h3>\n\n<p>Shortcode <code>[init_chatbox]<\/code> supports the following attributes:<\/p>\n\n<ul>\n<li><code>height<\/code> - Set chat height (e.g., <code>height=\"400px\"<\/code>)<\/li>\n<li><code>width<\/code> - Set chat width (e.g., <code>width=\"100%\"<\/code>)<\/li>\n<li><code>theme<\/code> - Apply custom theme (e.g., <code>theme=\"dark\"<\/code>)<\/li>\n<li><code>show_avatars<\/code> - Override avatar setting (<code>true<\/code>\/<code>false<\/code>)<\/li>\n<li><code>show_timestamps<\/code> - Override timestamp setting (<code>true<\/code>\/<code>false<\/code>)<\/li>\n<li><code>title<\/code> - Add custom chat title<\/li>\n<li><code>class<\/code> - Add custom CSS classes<\/li>\n<li><code>id<\/code> - Set custom container ID<\/li>\n<li><code>room<\/code> - Chat room name (letters, numbers, <code>-<\/code> and <code>_<\/code>). Leave empty for the default room (the main chat, which keeps all existing messages). Each room has its own messages, pinned message and message limit (e.g. <code>room=\"vip\"<\/code>)<\/li>\n<li><code>allow_guests<\/code> - Per-room override of the \"Allow guests\" setting (<code>yes<\/code>\/<code>no<\/code>)<\/li>\n<li><code>max_messages<\/code> - Per-room override of the \"Maximum Messages\" setting (10\u201310,000)<\/li>\n<\/ul>\n\n<p>Example: <code>[init_chatbox height=\"500px\" title=\"Community Chat\" theme=\"modern\"]<\/code><\/p>\n\n<p>Room example: <code>[init_chatbox room=\"members\" title=\"Members Lounge\" allow_guests=\"no\" max_messages=\"500\"]<\/code><\/p>\n\n<p>Only one chatbox per page is supported. Room overrides (<code>allow_guests<\/code>, <code>max_messages<\/code>) are saved when the shortcode is displayed on published content (not in drafts or previews), so use the same attributes everywhere a room is embedded.<\/p>\n\n<p>Shortcode <code>[init_chat_stats]<\/code> also accepts <code>room<\/code> to show statistics for a single room (e.g. <code>[init_chat_stats room=\"vip\"]<\/code>); without it, all rooms are counted.<\/p>\n\n<h3>Filters for Developers<\/h3>\n\n<p>This plugin provides filters and actions to allow developers to extend word filtering, message processing, and chat behavior without modifying core files.<\/p>\n\n<p><strong><code>init_plugin_suite_chat_engine_word_filter_strategy<\/code><\/strong><br \/>\nModify word filtering strategy (<code>substring<\/code>, <code>word<\/code>, <code>regex<\/code>).<br \/>\n<strong>Applies to:<\/strong> Message validation<br \/>\n<strong>Params:<\/strong> <code>string $strategy<\/code>, <code>array $settings<\/code>, <code>string $message<\/code><\/p>\n\n<p><strong><code>init_plugin_suite_chat_engine_blocked_words<\/code><\/strong><br \/>\nModify the blocked-words list before validation.<br \/>\n<strong>Applies to:<\/strong> Message validation<br \/>\n<strong>Params:<\/strong> <code>array $blocked_words<\/code>, <code>array $settings<\/code>, <code>string $message<\/code><\/p>\n\n<p><strong><code>init_plugin_suite_chat_engine_bypass_filter<\/code><\/strong><br \/>\nBypass filtering under custom conditions (VIP, internal users, etc.).<br \/>\n<strong>Applies to:<\/strong> Message validation<br \/>\n<strong>Params:<\/strong> <code>bool $bypass<\/code>, <code>string $message<\/code>, <code>WP_User|null $user<\/code>, <code>array $settings<\/code><\/p>\n\n<p><strong><code>init_plugin_suite_chat_engine_word_block_hit<\/code><\/strong> <em>(action)<\/em><br \/>\nTriggered when a word filter rule blocks a message.<br \/>\n<strong>Applies to:<\/strong> Message validation<br \/>\n<strong>Params:<\/strong> <code>string $blocked_word<\/code>, <code>string $message<\/code>, <code>string $strategy<\/code><\/p>\n\n<p><strong><code>init_plugin_suite_chat_engine_enrich_message_row<\/code><\/strong><br \/>\nExtend chat message data (add flags, metadata, user info, etc.).<br \/>\n<strong>Applies to:<\/strong> Backend DB \u2192 JSON output<br \/>\n<strong>Params:<\/strong> <code>array $message_row<\/code>, <code>WP_User|null $user<\/code><\/p>\n\n<p><strong><code>init_plugin_suite_chat_engine_message_saved<\/code><\/strong> <em>(action)<\/em><br \/>\nFired after a message is stored.<br \/>\n<strong>Applies to:<\/strong> POST \/send<br \/>\n<strong>Params:<\/strong> <code>int $message_id<\/code>, <code>string $message<\/code>, <code>int|null $user_id<\/code>, <code>string $display_name<\/code>, <code>string $room<\/code> (added in 1.3.9; <code>''<\/code> = default room)<\/p>\n\n<p><strong><code>init_plugin_suite_chat_engine_ip_headers<\/code><\/strong><br \/>\nChoose which <code>$_SERVER<\/code> keys are trusted (in priority order) when detecting the visitor IP used for bans and rate limiting. Default keeps the existing list (Cloudflare \/ proxy headers first, then <code>REMOTE_ADDR<\/code>). Sites not behind a proxy or CDN can return <code>array( 'REMOTE_ADDR' )<\/code> to prevent spoofed <code>X-Forwarded-For<\/code> headers from bypassing IP bans.<br \/>\n<strong>Applies to:<\/strong> Ban check, rate limiting, message logging<br \/>\n<strong>Params:<\/strong> <code>array $ip_keys<\/code><\/p>\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 the <code>\/wp-content\/plugins\/<\/code> directory.<\/li>\n<li>Activate the plugin through the 'Plugins' menu in WordPress.<\/li>\n<li>Configure settings under <code>Settings \u2192 Chat Engine<\/code>.<\/li>\n<li>Add the <code>[init_chatbox]<\/code> shortcode anywhere you want the chatbox to appear.<\/li>\n<li>Optional: Visit <code>Chat Engine \u2192 Management<\/code> to moderate messages and users.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"can%20guests%20send%20messages%3F\"><h3>Can guests send messages?<\/h3><\/dt>\n<dd><p>Yes, if enabled in the plugin settings under Basic Settings. Guests will be asked to enter a display name before sending messages.<\/p><\/dd>\n<dt id=\"how%20do%20i%20moderate%20messages%20and%20users%3F\"><h3>How do I moderate messages and users?<\/h3><\/dt>\n<dd><p>Go to <code>Chat Engine \u2192 Management<\/code> to view recent messages, ban\/unban users, and see chat statistics. You can search messages, delete inappropriate content, and ban users by IP or user account.<\/p><\/dd>\n<dt id=\"does%20it%20support%20real-time%20messaging%3F\"><h3>Does it support real-time messaging?<\/h3><\/dt>\n<dd><p>This plugin uses REST API with smart polling (3.5-10 second intervals) for broad compatibility. No WebSocket setup required, works on any hosting.<\/p><\/dd>\n<dt id=\"how%20many%20messages%20are%20stored%3F\"><h3>How many messages are stored?<\/h3><\/dt>\n<dd><p>Configurable in settings (default: 1000 messages). Old messages are automatically deleted when the limit is reached. You can also set up automatic cleanup based on age.<\/p><\/dd>\n<dt id=\"can%20i%20customize%20the%20chat%20appearance%3F\"><h3>Can I customize the chat appearance?<\/h3><\/dt>\n<dd><p>Yes, multiple ways:\n- Use the Custom CSS field in Advanced Settings\n- Override the template by placing <code>chatbox.php<\/code> in your theme's <code>init-chat-engine\/<\/code> folder\n- Use shortcode attributes for basic styling\n- Disable plugin CSS entirely and use your own<\/p><\/dd>\n<dt id=\"how%20does%20the%20ban%20system%20work%3F\"><h3>How does the ban system work?<\/h3><\/dt>\n<dd><p>Administrators can ban users by IP address or user account from the Management panel. Bans can be temporary (with expiration date) or permanent. Banned users see a clear message explaining their restriction.<\/p><\/dd>\n<dt id=\"can%20i%20limit%20message%20frequency%3F\"><h3>Can I limit message frequency?<\/h3><\/dt>\n<dd><p>Yes, use the Rate Limiting setting to control how many messages users can send per minute (1-100 messages). This helps prevent spam and abuse.<\/p><\/dd>\n<dt id=\"is%20it%20translation-ready%3F\"><h3>Is it translation-ready?<\/h3><\/dt>\n<dd><p>Yes, the plugin is fully translation-ready with Vietnamese translation included. All text strings use proper WordPress internationalization functions.<\/p><\/dd>\n<dt id=\"can%20i%20have%20several%20chat%20rooms%3F\"><h3>Can I have several chat rooms?<\/h3><\/dt>\n<dd><p>Yes (since 1.3.9). Add the <code>room<\/code> attribute: <code>[init_chatbox room=\"vip\"]<\/code>. Rooms are created automatically from the shortcode and every room is isolated: messages, pinned message and message limit. The room name is signed by the server, so visitors cannot post into rooms that don't exist on your site. Bans, rate limiting, word filtering and account age rules are shared by all rooms. Manage rooms under <code>Chat Engine \u2192 Management<\/code> (room filter on Recent Messages and Statistics, plus a Chat Rooms overview).<\/p><\/dd>\n<dt id=\"how%20do%20i%20backup%20chat%20data%3F\"><h3>How do I backup chat data?<\/h3><\/dt>\n<dd><p>Chat messages are stored in your WordPress database in the <code>wp_init_chatbox_msgs<\/code> table. Use any WordPress backup plugin or database backup tool.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.3.9 \u2013 October 2, 2026<\/h4>\n\n<ul>\n<li>Fix: open chat tabs could get stuck and stop receiving new messages until the page was reloaded (polling kept requesting the same <code>after_id<\/code>), on sites with a persistent object cache such as Redis or Memcached. A slow poll request that read the database just before a new message was sent could write its outdated \"latest message ID\" into the shared cache <em>after<\/em> the new message had cleared it, so every client already at that ID was told there was nothing new. Frontend cache entries are now tagged with a generation token that changes on every message change, so a late write can never hide newer messages. Reproduced and verified fixed against a real Redis object cache under concurrent requests<\/li>\n<li>Fix: <code>GET \/messages<\/code> and <code>GET \/user-status<\/code> now send <code>no-cache<\/code> headers (plus <code>X-LiteSpeed-Cache-Control: no-cache<\/code>), and the chat script fetches with <code>cache: 'no-store'<\/code>, so page caches \/ CDNs (LiteSpeed Cache \"Cache REST API\", Cloudflare, Varnish, Nginx FastCGI cache) and the browser can no longer serve an old empty polling response for the same URL<\/li>\n<li>Fix: a request that hung (e.g. after the computer woke from sleep or switched networks) blocked all later polls forever because polling skips while a request is still pending. Requests now time out after 20 seconds and polling resumes automatically<\/li>\n<li>Performance: \"no new messages\" polls are cached safely again (1.3.7 had to disable this to avoid the race above): idle polls on a site with a persistent object cache no longer touch the database at all<\/li>\n<li>New: multiple chat rooms. Add <code>room=\"...\"<\/code> to <code>[init_chatbox]<\/code> to create an isolated room with its own messages, pinned message and message limit. Existing messages stay in the default room, so current chatboxes are unchanged (the <code>id<\/code> attribute is still only the HTML container ID)<\/li>\n<li>New: room names are signed (HMAC) by the server and printed into the page, so the REST API only accepts rooms that come from a shortcode on your site \u2014 nobody can create or spam hidden rooms. Works with page caching<\/li>\n<li>New: per-room shortcode overrides <code>allow_guests=\"yes|no\"<\/code> and <code>max_messages=\"...\"<\/code> (only saved from published content, so contributors cannot change a room's rules through drafts or previews)<\/li>\n<li>New: Management \u2192 Recent Messages has a room filter and a Room column; Management \u2192 Statistics can be filtered by room and lists all rooms (message count, last activity, guest access, message limit) with a \"Delete Room Messages\" action<\/li>\n<li>New: <code>[init_chat_stats room=\"...\"]<\/code> shows statistics for a single room<\/li>\n<li>New: the \"Maximum Messages\" limit and the daily cleanup now apply per room<\/li>\n<li>Developer: <code>init_plugin_suite_chat_engine_message_saved<\/code> now receives the room as a 5th argument; <code>GET \/messages<\/code> and <code>POST \/send<\/code> responses include <code>room<\/code><\/li>\n<li>Database: adds a <code>room<\/code> column and a <code>(room, is_deleted, id)<\/code> index to the messages table. The upgrade runs automatically on the first request after updating (also on the frontend, not only in wp-admin) and does not touch existing data<\/li>\n<li>New translatable strings for rooms (Vietnamese translation updated)<\/li>\n<\/ul>\n\n<h4>1.3.8 \u2013 October 1, 2026<\/h4>\n\n<ul>\n<li>Fix: the <strong>Rate Limiting<\/strong> setting was ignored \u2014 the limit was read from a legacy option the Settings page no longer writes to, so every site was silently limited to the default 10 messages\/minute regardless of what the admin configured. The saved value is now honored (sites that never saved Security settings keep the previous default of 10)<\/li>\n<li>Fix: the daily cleanup cron (and the \"Run Cleanup Now\" button) had the same problem with <strong>Maximum Messages<\/strong> and <strong>Automatic Cleanup<\/strong> days \u2014 it always used the defaults (1000 \/ 30 days). It now uses the configured values<\/li>\n<li>Fix: maximum message length was counted in bytes instead of characters, so Vietnamese \/ accented \/ emoji messages were rejected well before the configured limit even though the on-screen counter still showed room left. Length is now counted in characters, matching the counter and the setting's description<\/li>\n<li>Fix: using a custom container ID (<code>[init_chatbox id=\"...\"]<\/code>) stopped the chat from loading at all \u2014 the script only looked for the default <code>init-chatbox-root<\/code> ID<\/li>\n<li>Fix: on sites using the <strong>Plain<\/strong> permalink structure (REST URLs of the form <code>index.php?rest_route=...<\/code>) the chat never loaded any messages \u2014 the script appended its parameters with a second <code>?<\/code>, producing an invalid URL (HTTP 404). Query parameters are now appended correctly for both permalink styles<\/li>\n<li>Fix: Custom CSS containing <code>&gt;<\/code> child selectors or quotes (e.g. <code>content: \"...\"<\/code>, <code>font-family: \"...\"<\/code>) was broken by HTML-escaping on output. CSS is now output intact while still stripping HTML tags and neutralizing <code>&lt;\/<\/code> so it cannot break out of the <code>&lt;style&gt;<\/code> tag<\/li>\n<li>Fix: after <strong>Delete All Messages<\/strong> (or deleting the pinned message from the Management page \/ moderation endpoint), the pinned banner kept showing the deleted message because it renders from a stored snapshot. Admin deletions now unpin it too (automatic trimming of old messages by the Maximum Messages limit does not unpin)<\/li>\n<li>Fix: unbanning by user ID \/ IP (without a ban ID) did not clear the ban cache, so the user could stay blocked until the cache expired; cached temporary bans also never outlive their expiry time now<\/li>\n<li>Fix: validation error for <strong>Minimum Account Age<\/strong> (over 3650 days) was never displayed because it was added after the settings error notice had already been registered<\/li>\n<li>Fix: the \"has messages\" flag used to size the empty chatbox was cached for a day and never invalidated, so a freshly used chat could keep its \"empty\" layout<\/li>\n<li>Fix: the admin message list could show stale data for up to 5 minutes (new messages missing, wrong page size after changing Screen Options) on hosts with a persistent object cache. The list cache is now versioned and invalidated on every message change<\/li>\n<li>Fix: uninstalling the plugin left the <code>init_chatbox_stats<\/code> and <code>init_chatbox_banned<\/code> tables, settings options, the cleanup cron event and per-user Screen Options behind. Uninstall now removes all plugin data<\/li>\n<li>Security: hardened HTML escaping in the chat script \u2014 the previous helper did not escape quotes, so a crafted display name or same-site link inside a message could break out of an HTML attribute (stored XSS). Quotes are now escaped everywhere user content is placed into the chat markup<\/li>\n<li>Security: the <code>theme<\/code> shortcode attribute is now restricted to letters, numbers, <code>-<\/code> and <code>_<\/code> before being used in template \/ stylesheet paths, preventing path traversal (e.g. <code>theme=\"..\/..\/..\"<\/code>)<\/li>\n<li>Security: <code>GET \/user-status<\/code> no longer exposes the full ban record (banning admin's user ID, stored IP address); <code>ban_info<\/code> now contains only <code>reason<\/code>, <code>banned_at<\/code> and <code>expires_at<\/code><\/li>\n<li>Security: added the <code>init_plugin_suite_chat_engine_ip_headers<\/code> filter so sites not behind a proxy\/CDN can trust only <code>REMOTE_ADDR<\/code>, preventing spoofed forwarding headers from bypassing IP bans and rate limits. Default behavior is unchanged<\/li>\n<li>Performance: the \"not banned\" result was never actually served from cache (the negative cache stored <code>false<\/code>, which is indistinguishable from a cache miss), so every poll from every client queried the ban table 1\u20132 times. It is now cached correctly \u2014 on hosts with a persistent object cache most polls no longer touch the ban table at all<\/li>\n<li>Performance: sending a message now updates the <code>total_messages<\/code> \/ <code>messages_today<\/code> counters with a single atomic query each instead of a read + write pair, which also fixes lost increments when several messages are sent at the same moment<\/li>\n<li>Performance: removed a duplicate REST request on every page load (a separate <code>?limit=1<\/code> call only used to read the pinned message, which the initial message load already returns)<\/li>\n<li>Performance: the Management message list no longer runs ban-check and user lookups per row (previously up to 2 queries + 1 user lookup for each of the 20\u2013200 rows); bans and users are preloaded once per page. Bulk delete now runs a single query instead of one per selected message<\/li>\n<li>Performance: <code>[init_chat_stats]<\/code> results are cached for 1 minute and only the numbers actually displayed are queried (previously up to 6 <code>COUNT(*)<\/code> queries on every page view)<\/li>\n<li>Performance: the chat script no longer forces a style\/layout recalculation every time it hides an element, and mouse-move activity tracking is throttled to once per second<\/li>\n<li>Performance: the visitor IP is resolved once per request instead of on every ban \/ rate-limit \/ logging call<\/li>\n<li>New translatable string: \"Name is too long (max 50 characters).\" (Vietnamese translation updated)<\/li>\n<li>No changes to database schema, REST routes, or the message response shape used by third-party integrations<\/li>\n<\/ul>\n\n<h4>1.3.7 \u2013 August 21, 2026<\/h4>\n\n<ul>\n<li>Fix: intermittent missing messages on the frontend chat under concurrent traffic \u2014 a race condition in the <code>GET \/messages<\/code> polling cache could cause a newly sent message to be silently hidden from all clients until a <em>later<\/em> message triggered a cache clear (symptom: 2nd message never appears, then sending a 3rd makes both appear together; refreshing the page also \"fixes\" it since page load uses a separate, unaffected cache path). Only reproduces on hosts with a persistent object cache (Redis\/Memcached\/etc.) under concurrent request timing; does not affect message storage \u2014 only what polling clients see, and only temporarily<\/li>\n<li>Fix: account age requirement check (<code>min_account_age_days<\/code>) compared the site's local time against WordPress's <code>user_registered<\/code> field, which core always stores in UTC \u2014 could make the check off by the site's UTC offset. Now compares against a true UTC timestamp<\/li>\n<li>Performance: <code>get_all_settings()<\/code> could be called up to 3 times within a single POST \/send request (directly, plus internally by message validation and the account-age check) \u2014 now cached per-request so settings are read and merged only once<\/li>\n<li>Internal: full WordPress Coding Standards (WPCS) compliance pass \u2014 no functional changes intended; see notes below if you maintain a fork or patches against this plugin\n\n<ul>\n<li>Verified with a byte-for-byte token comparison against the previous release to confirm no logic changes beyond the two fixes above<\/li>\n<li><code>in_array()<\/code> calls now use strict comparison (<code>true<\/code> as third argument) to avoid loose-comparison type coercion edge cases<\/li>\n<li>All conditionals now use Yoda style, all <code>?:<\/code> short ternaries expanded, all inline comments end in proper punctuation, all functions have complete docblocks<\/li>\n<\/ul><\/li>\n<\/ul>\n\n<h4>1.3.6 \u2013 August 1, 2026<\/h4>\n\n<ul>\n<li>Enhancement: relative timestamps (\"x minutes...\") now also cover weeks, months, and years for older messages \u2014 previously capped at \"x days\"<\/li>\n<li>Change: dropped the \"ago\" suffix from relative timestamps to keep the UI compact (e.g. \"2 hours\" instead of \"2 hours ago\"), matching the convention used by most modern social apps. Translators: the <code>minutes_ago<\/code> \/ <code>hours_ago<\/code> \/ <code>days_ago<\/code> JS i18n strings were renamed to <code>unit_minutes<\/code> \/ <code>unit_hours<\/code> \/ <code>unit_days<\/code> \/ <code>unit_weeks<\/code> \/ <code>unit_months<\/code> \/ <code>unit_years<\/code> \u2014 please update custom translations accordingly<\/li>\n<li>Performance: polling now also accounts for whether the chatbox is actually scrolled into view (via <code>IntersectionObserver<\/code>), not just whether the browser tab itself is focused\/visible. If the chatbox is off-screen elsewhere on a long page, polling backs off further (up to 20s) and resumes instantly once it's back in view<\/li>\n<li>No changes to database schema or REST API response shape<\/li>\n<\/ul>\n\n<h4>1.3.5 \u2013 August 1, 2026<\/h4>\n\n<ul>\n<li>Fix: timestamps (\"x minutes ago\") could get stuck on \"now\" indefinitely (or show hours-old immediately after posting) on any site whose timezone setting differs from UTC. Caused by <code>created_at_iso<\/code> being computed from a local-time string without converting to true GMT first \u2014 now uses <code>get_gmt_from_date()<\/code> for a correct absolute timestamp. Only affects the new client-side timestamp feature below; does not affect message content, delivery, or ordering<\/li>\n<li>Performance: removed a redundant DB query that ran on every single poll request to refresh message timestamps (previously fetched + recomputed 50 rows every 3.5\u201310s per connected client)<\/li>\n<li>Performance: relative timestamps (\"x minutes ago\") are now computed client-side and refreshed locally every 60s, no extra network round-trip<\/li>\n<li>Performance: throttled the <code>last_activity<\/code> stat write so it's persisted at most once per minute instead of on every poll request, reducing DB write load on busy sites<\/li>\n<li>Performance: polling now pauses entirely (instead of just backing off) after 10 minutes of inactivity on a hidden\/unfocused tab, and resumes instantly on focus<\/li>\n<li>Performance: replaced the single-column <code>idx_is_deleted<\/code> index with a composite <code>(is_deleted, id)<\/code> index on the messages table \u2014 the composite index already covers every query the old one did, so keeping both only added write overhead. Existing sites are migrated automatically (old index dropped, new one added); new installs get the new index directly<\/li>\n<li>Performance: added object caching (<code>wp_cache_*<\/code>) to <code>GET \/messages<\/code> \u2014 polling requests with no new messages now skip the database entirely, and initial page loads share a single cached query across all visitors instead of querying per visitor. Effectiveness depends on your host providing a persistent object cache (see FAQ)<\/li>\n<li>Fix: <code>TRUNCATE<\/code>-based \"delete all messages\" and the automatic daily cleanup cron did not invalidate any cache before this release, so admin-side stats\/message list and (now) the frontend cache could show stale data after those actions. Both now invalidate all related caches<\/li>\n<li>Fix: the REST <code>\/admin\/moderate<\/code> delete action did not invalidate any cache before this release<\/li>\n<li>Tuned adaptive polling range to 3.5\u201310s (previously 2\u201312s) to match documented behavior and reduce request volume<\/li>\n<li>No changes to REST API response shape used by third-party integrations, except the internal <code>updated_messages<\/code> field (undocumented, poll-only) has been removed<\/li>\n<\/ul>\n\n<h4>1.3.4 \u2013 April 7, 2026<\/h4>\n\n<ul>\n<li>Fixed bulk delete and single message delete not working due to stale object cache<\/li>\n<li>Added <code>init_plugin_suite_chat_engine_clear_message_cache()<\/code> to properly invalidate message list, total count, and stats cache after every delete action<\/li>\n<li>Fixed nonce variable conflict between single action handler and cleanup handler that could cause cleanup verification to fail silently<\/li>\n<li>Added Screen Options support for configurable messages per page (default: 20, range: 5\u2013200)<\/li>\n<li>Per-page preference is saved per user via user meta \u2014 does not affect other admins<\/li>\n<li>Replaced WordPress screen option API with direct POST handler for reliable save behavior<\/li>\n<li>No changes to database schema, REST API, or existing chat flow<\/li>\n<\/ul>\n\n<h4>1.3.3 \u2013 March 30, 2026<\/h4>\n\n<ul>\n<li>Added expand\/collapse support for pinned message content in banner<\/li>\n<li>Allows viewing full pinned message without jumping to original message<\/li>\n<li>Stores full message content via <code>dataset<\/code> to avoid additional queries or requests<\/li>\n<li>Updated pinned banner to use absolute positioning to eliminate layout shift (CLS)<\/li>\n<li>Ensures stable layout when banner appears or updates<\/li>\n<li>Refined animation and interaction for smoother realtime UX<\/li>\n<li>No changes to API, database, or existing chat flow<\/li>\n<\/ul>\n\n<h4>1.3.2 \u2013 March 30, 2026<\/h4>\n\n<ul>\n<li>Introduced Pin Message feature for chat moderation (admin only)<\/li>\n<li>Allows pinning a single message to the top of the chat box (auto-replaces previous pin)<\/li>\n<li>Added hover-based Pin\/Unpin button on messages for admins with dynamic state handling<\/li>\n<li>Implemented pinned message banner with jump-to-message and highlight animation<\/li>\n<li>Added REST endpoints: POST \/pin and DELETE \/pin (nonce-verified, admin only)<\/li>\n<li><code>GET \/messages<\/code> now includes <code>pinned_message<\/code> for real-time sync across clients<\/li>\n<li>Pin state cached (5 minutes) with immediate invalidation on update<\/li>\n<li>Uses existing database (<code>init_chatbox_stats<\/code>) \u2014 no schema changes required<\/li>\n<li>Fully translation-ready via <code>InitChatEngineData.i18n<\/code><\/li>\n<li>Fully backwards-compatible and does not affect existing chat flow<\/li>\n<\/ul>\n\n<h4>1.3.1 \u2013 March 26, 2026<\/h4>\n\n<ul>\n<li>Performance optimization: added object caching for frequently called checks<\/li>\n<li><code>init_plugin_suite_chat_engine_has_messages()<\/code> now cached (24 hours) to reduce redundant DB queries during render<\/li>\n<li><code>init_plugin_suite_chat_engine_check_user_banned()<\/code> now uses 10-minute cache with multi-key strategy (user ID + IP)<\/li>\n<li>Implemented proper cache invalidation on ban\/unban actions to ensure real-time accuracy<\/li>\n<li>Added negative caching to eliminate repeated queries for non-banned users<\/li>\n<li>Internal optimization only \u2014 no UI or database changes<\/li>\n<li>Improves scalability and reduces database load under high traffic chat environments<\/li>\n<\/ul>\n\n<h4>1.3.0 \u2013 March 2, 2026<\/h4>\n\n<ul>\n<li>Introduced new <strong>Minimum Account Age Requirement<\/strong> (Security setting)<\/li>\n<li>Administrators can now require users to have an account older than <strong>X days<\/strong> before participating in chat<\/li>\n<li>Rule only applies when <strong>guest chatting is disabled<\/strong> (login required mode)<\/li>\n<li>Fully integrated across backend and frontend:\n\n<ul>\n<li>REST <code>\/send<\/code> endpoint now enforces account age validation via centralized security check<\/li>\n<li>Shared reusable function <code>init_plugin_suite_chat_engine_check_account_age_requirement()<\/code> ensures single source of truth<\/li>\n<\/ul><\/li>\n<li>Frontend UI enhancement:\n\n<ul>\n<li>Chat input is automatically disabled (<code>pointer-events: none; opacity: 0.6<\/code>) when account is too new<\/li>\n<li>Context-aware warning message displayed directly under the input area<\/li>\n<\/ul><\/li>\n<li>No impact on guest mode \u2014 public chats remain unaffected when guests are allowed<\/li>\n<li>Backwards-compatible with existing settings and database schema<\/li>\n<li>Security-focused enhancement to mitigate spam, clone accounts, and coordinated war activity<\/li>\n<\/ul>\n\n<p>View full changelog (all versions): <a href=\"https:\/\/en.inithtml.com\/plugin\/init-chat-engine\/\">Init Chat Engine \u2013 Changelog<\/a><\/p>","raw_excerpt":"A lightweight, real-time community chat system built with REST API and Vanilla JS. No jQuery, no reload. Full admin panel with moderation tools.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/248668","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=248668"}],"author":[{"embeddable":true,"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/brokensmile2103-1"}],"wp:attachment":[{"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=248668"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=248668"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=248668"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=248668"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=248668"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=248668"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}