=== Desku.io - Live Chat, Help Desk & Knowledge Base ===
Contributors: desku
Tags: live chat, help desk, ecommerce customer support, no code chatbot builder, AI-powered customer support
Tested up to: 7.1
Stable tag: 2.3.1
Requires at least: 6.6
Requires PHP: 7.2
License: GPL-2.0-or-later

AI customer service software for WordPress—live chat, instant replies & a smart knowledge base to boost support in minutes.

== Description ==

### Add AI-Powered Live Chat & Help Desk to Your WordPress Site in Minutes ###

[Desku.io](https://desku.io) is an AI customer service platform that gathers live chat, help desk ticketing, and a knowledge base together in a single place. This plugin connects your WordPress site to Desku.io, allowing you to deploy a fully customizable live chat widget without writing code or editing theme files.

Once activated, the plugin adds the Desku.io chat widget across your entire site. Your visitors receive instant answers through AI-powered chat, while your team manages every conversation from a single dashboard.

Whether you're running a WooCommerce store, an Easy Digital Downloads storefront, or a SaaS product, Desku.io helps you respond faster, reduce support tickets, and keep customers returning.

No manual script placement. No developer required. Just install, connect, and go live.

### Why Choose Desku.io for WordPress? ###

- **Respond Faster, Close Tickets Sooner:** The Desku.io unified inbox brings live chat, email, and social messages into a single screen. Your team spends less time switching tabs and more time solving problems.
- **Let AI Handle Repetitive Questions:** The Desku.io no-code AI chatbot learns from your knowledge base and FAQs to answer common queries around the clock. When a conversation needs a human touch, the chatbot automatically hands it off to a live agent.
- **Manage eCommerce Support Without Extra Tools:** Built-in compatibility with WooCommerce and Easy Digital Downloads (EDD) lets you view order details, track customer history, and resolve purchase-related queries right in Desku.io.
- **Keep Your Entire Team on the Same Page:** Shared inbox, internal notes, and conversation assignments make it easy for multiple agents to collaborate on tickets without duplicating work.
- **Cut Support Costs as You Grow:** Desku.io AI automation can handle up to 70% of routine conversations, freeing your team to focus on complex issues that require human attention.

### Feature Deep-Dive ###

#### Live Chat Widget ####

Add a real-time chat widget to every page of your WordPress site. Customize the widget's colors, position, and welcome message to match your brand. Visitors can start a conversation instantly without leaving the page they're on.

#### AI Chatbot (No-Code Builder) ####

Build and train a support chatbot using the Desku.io drag-and-drop builder. Feed it your knowledge base articles, FAQs, or product information, and it starts answering questions on its own. No coding or developer time required.

#### Help Desk Ticketing ####

Every customer conversation, whether it starts from chat, email, or social media, turns into a trackable ticket. Assign tickets to team members, set priorities, and monitor resolution times from a single dashboard.

#### Unified Inbox ####

Stop juggling between email, live chat, Facebook, Instagram, and WhatsApp. Desku.io pulls all your support channels into a single inbox so nothing falls through the cracks.

#### Knowledge Base Integration ####

Create and organize help articles that your AI chatbot can reference automatically. Customers can also browse these articles directly through the chat widget for self-service support.

#### Smart Automation & Workflows ####

Set up rules that automatically assign, tag, or escalate tickets based on the conditions you define. Automate follow-ups, customer satisfaction surveys, and routine responses without writing a single line of code.

#### eCommerce Ready (WooCommerce & EDD) ####

Pull in real-time order data from WooCommerce or Easy Digital Downloads directly into your support conversations. Your agents see purchase history, order status, and customer details right alongside the chat.

#### Visitor Insights ####

See who's browsing your site in real time. Track visitor behavior, page views, and session details to better understand your customers and offer proactive support.

#### Analytics & Reporting ####

Track response times, resolution rates, conversation volume, and customer satisfaction scores. Use these insights to identify bottlenecks and continuously improve your support quality.

### How to Get Started ###

1. Install and activate the Desku.io plugin from the WordPress Plugin Directory.
2. Open the Desku.io menu item in your WordPress sidebar.
3. Log in to your Desku account using your API key or login credentials. If you don't have one yet, click on the Sign Up link to create a free account.
4. Once you're in, go to WordPress Dashboard → Desku → Install Widget tab.
5. Choose a live chat widget from the available options and customize its appearance.
6. Save your settings and install it. The widget goes live across your entire site immediately.

That's it. Six steps, no code, and your customers can start chatting with you immediately.

### Third-Party Service & Privacy Disclosure ###

This plugin connects your WordPress site to the Desku.io external servers to power the live chat widget, help desk, and AI chatbot features. When the plugin is active, data is transmitted between your site and the Desku.io platform:

- **Backend API:** [https://backend.desku.io/](https://backend.desku.io/) — contacted from your server (admin only) to authenticate, sync post content for AI training, and read widget settings. Nothing is sent until an administrator connects a Desku account.
- **Front-end widget script:** When the chat widget is connected and active, your visitors' browsers load the chat widget script from [https://widget.desku.io/chat-widget.js](https://widget.desku.io/chat-widget.js). This third-party script renders the chat widget and may set cookies/local storage. It is **not** loaded on a fresh or disconnected install.
- **Consent gate:** Site owners can prevent the front-end widget from loading (e.g. until a visitor grants consent) with the `desku_widget_load` filter — returning `false` from it stops the widget script from being injected. Example: `add_filter( 'desku_widget_load', '__return_false' );`

Desku.io is built with data protection in mind and follows GDPR guidelines. All data transmitted between your WordPress site and the Desku.io servers is encrypted.

For full details on how customer data is handled, stored, and protected, review the Desku.io [Privacy Policy](https://desku.io/privacy-policy/), [Terms of Service](https://desku.io/terms/), and [GDPR compliance documentation](https://desku.io/gdpr/).

== Frequently Asked Questions ==

= Do I need a Desku.io account to use this plugin? =

Yes. The plugin connects your WordPress site to the Desku.io platform, which is where you'll manage conversations, configure your chatbot, and access your support dashboard. You can get started with a free forever account at [desku.io](https://desku.io), or sign up for a 14-day free trial to experience the full functionality of the paid plans - no credit card required.

= Is any coding or technical knowledge required? =

Not at all. The plugin handles everything for you. Once you install and activate it, you can login through the setup wizard and choose your chat widget. There's no need to paste scripts into your header, edit theme files, or write any code.

= Can I use this to manage an ecommerce or EDD storefront? =

Yes. Desku.io integrates directly with WooCommerce and Easy Digital Downloads. Your support agents can view order details, transaction history, and customer information directly in the support dashboard, making it easier to resolve purchase-related questions without switching between tools.

= Does it include AI features and knowledge base functionality? =

Yes. Desku.io includes a no-code AI chatbot builder that you can train using your own knowledge base articles and FAQs. The chatbot answers common customer queries automatically and hands off complex conversations to your live agents. The knowledge base is also accessible to customers directly through the chat widget for self-service support.

= Is Desku.io GDPR-friendly? =

Yes. Desku.io is built with privacy and data protection as a priority. The platform follows GDPR guidelines, encrypts all data transmissions, and provides detailed documentation about its compliance practices. You can review the full details on the [GDPR compliance page](https://desku.io/gdpr/).

== Screenshots ==

- WordPress Helpdesk plugin: Check all your tickets in one place
- Reply to tickets faster with real-time customer insights
- WordPress Integration: EDD

== ChangeLog ==

= 2.3.1 =
- Fix: the "Notify me by email when the sync completes" checkbox could not be ticked — the popup markup no longer carried the class the script used to enable it and listen for changes; it is now targeted by its id.
- Fix: the "Retry Failed" button on the full and selective sync completion popups threw a JavaScript error (undefined id) and never started the retry; it now retries all failed items.
- Fix: a successful retry-failed run no longer stalls at 100% — the completion message referenced data that only exists in the full sync flow. It now lists the retried items per content type, shows the last run time, and is titled "Retry Completed Successfully".
- Enhancement: the sync progress popups show a neutral "Sync runs in the background" note under the notify checkbox, using a new grey (neutral) alert style.
- Removed a leftover debug console.log from the retry progress handler.
- Compatibility: tested up to WordPress 7.1.

= 2.3.0 =
- Enhancement: the full and selective sync progress popups now offer a "Notify me by email when the sync completes" checkbox. On large syncs that take a while, users can tick it and close the popup — the sync keeps running on Desku's side and an email is sent when the batch finishes.
- The opt-in is persisted the moment the checkbox is toggled (new desku_sync_notify AJAX handler → /api/wp-plugin/sync/notify with batch_id + notify_me), so the choice sticks regardless of when the popup is closed; the checkbox reverts if the request fails.
- The sync-start responses (/sync/full, /sync/selective) now surface the batch_id to the browser so the notify opt-in can target the correct batch; the checkbox stays disabled until a batch id is available.

= 2.2.1 =
- Fix: expired/revoked API tokens are now handled everywhere. A genuine HTTP 401 on a stored-token request is detected centrally in make_api_request(), so cron, REST, and every AJAX handler react consistently instead of only the plugin page.
- Fix: a stale token is flagged (api_health = expired) and kept — preserving subdomain/username for one-click reconnect — rather than silently wiped; the auto-sync cron is torn down so a dead credential is no longer POSTed every interval, and reschedules automatically once reconnected.
- Enhancement: an admin notice now appears on every wp-admin screen (not just the Desku page) when the connection has expired, so editors who never open the Desku page still learn syncing has stopped.
- Enhancement: the Desku settings page now presents the authentication form (with an "expired" explanation) instead of the non-functional connection status view when the stored token is stale.
- Enhancement: AJAX calls that hit an expired token now return a machine-readable token_stale flag; the admin page switches to the reconnect view and shows a persistent notice in place, without a page refresh, and clears it on successful re-authentication.

= 2.2.0 =
- Fix: saving the Permissions tab with no roles selected — or starting a sync with no post types selected — no longer triggers a PHP 8 fatal (array_map on null); the malformed input guard now coerces a missing $_POST field to an empty array, and empty permission submissions return a clean validation error.
- Fix: sync-log-details no longer fatals (PHP 8 TypeError) when the API returns a non-array "data" field; the response payload is built from a guarded array copy.
- Fix: check_authentication() now only clears the stored token on a genuine HTTP 401; a transient outage/timeout/5xx keeps the token and negative-caches the failure, so a momentary Desku API blip no longer silently disconnects the site.
- Fix: get_permissions() guards a non-array permissions payload (previously warned and silently denied all roles until the cache expired).
- Fix: handle_desku_sync_progress() defaults missing API data to safe values and reads with ?? so a partial response never persists null into settings or warns.
- Perf: desku_widget_settings is no longer autoloaded; a tiny desku_widget_public option (widget id, subdomain, active flag) is mirrored for the front-end render path, so the full settings blob is no longer parsed on every page request. Removed on deactivate/uninstall.
- Perf: automatic cron sync reuses the slugs from should_exclude_post() (removing a duplicate per-post term query) and clears the desku_train_eva flag for all synced posts in one query — deleting the meta rows rather than setting them to '0' so the meta_query working set stays small.
- Perf: selective-sync info/preview now paginates via the shared collector (fields=ids, 200/page, cache-primed) instead of loading up to 500 full post objects with a no-op fields arg.
- Perf: schedule_sync_event() skips the full cron-array scan behind a short transient; check_authentication() negative-caches API failures (60s); get_post_types() memoizes the synced-types lookup (avoids a duplicate API call per admin render).
- Perf: block-editor sidebar assets only enqueue when a Desku account is connected, so unconfigured sites get no editor REST round-trips; the index.asset.php include is guarded with file_exists()/is_array().
- Compatibility: remaining $response['success']/['message'] reads across the sync, login, and permission handlers now use ?? defaults to silence PHP 8 undefined-key warnings.
- Compatibility: corrected README headers — Tested up to: 7.0 and Requires at least: 6.6 (matches the actual editor-sidebar API floor).
- Security: admin notice shown on the Desku screen when the API token cannot be encrypted at rest (libsodium/key unavailable), recommending DESKU_ENCRYPTION_KEY.
- Privacy: README 3rd-Party section now documents the front-end widget.desku.io chat-widget.js script and the desku_widget_load consent filter for consent managers.
- Footprint: removed bundled Boxicons (unused) and the Remixicon icon font; the two widget-preview launcher icons are now inline SVG (~3.6 MB of admin-only assets removed). Added THIRD-PARTY-LICENSES.txt documenting bundled library/font licenses.
- Cleanup: removed dead code (legacy flat add_option activation seed, redundant register_uninstall_hook, unused assets/css/admin.css); renamed the editor block metadata from the create-block scaffold to desku/train-eva-sidebar @ 2.2.0; namespaced the editor registerPlugin/PluginSidebar ids to desku-; added index.php silence files to build/; pinned @wordpress/* dependencies (was "latest").
- Fix: load_settings() coerces a corrupted/cloned/scalar settings row to defaults before the typed deep_merge(), preventing an uncatchable TypeError (admin white-screen) on migrated sites; user_settings and the selected profile fall back to defaults when missing.
- Perf: full and selective sync now paginate posts (fields=ids, 200 per page) and bulk-prime the post + object-term cache per page; should_exclude_post() reads terms via get_the_terms(), eliminating the posts_per_page=-1 load and per-post N+1 term queries on large sites.
- Fix: refresh-status, sync-status, and get_widget_settings now gate on the API success flag and read fields with ?? defaults, so an error response no longer persists null into the stored settings (api_health, plan_*, last_sync, widget_id).
- Perf: removed blocking get_permissions() call from constructor; permissions now lazy-load on first use and cache in a 5-minute transient.
- Perf: removed blocking API call from save_post path; training settings cached in a 10-minute transient; DOING_AUTOSAVE guard added.
- Perf: block editor sidebar apiFetch moved from render body to mount-only useEffect; not-connected early return added to REST handlers.
- Perf: cron schedule (desku_auto_sync) now follows user-configured training delay with a 300s floor; self-reschedules when interval changes.
- Perf: get_post_types() now uses persisted training config and only calls the API when no cached config exists; guarded behind token check.
- Fix: execute_sync_task date_query removed (was racing against 30s cron and dropping posts); restricted to allowed post types; capped at 100 posts per run; exclusion rules applied before sync.
- Fix: training config persisted to wp_options so exclusion rules apply even when transient cache is cold.
- Fix: wp_parse_args defaults added to should_exclude_post() and sync handlers to prevent PHP 8 TypeError on missing API keys.
- Fix: permissions form now populates correctly on page load.
- Fix: renamed total_syncs to total_items throughout to match Desku API field name.
- Fix: make_api_request() now returns false on HTTP 401; check_authentication() correctly detects and clears an expired token.
- Fix: deactivation no longer wipes credentials; preserves user settings and only marks the widget inactive.
- Fix: PluginSidebar import moved from deprecated @wordpress/edit-post to @wordpress/editor (WP 6.6+).
- Fix: TinyMCE enqueued with DESKU_PLUGIN_VERSION instead of null for correct cache busting.
- Fix: training delay UI enforces minimum 300s via min attribute; default updated to 300; description updated.
- Security: esc_html/esc_attr added to all category, tag, role name, and post-type label outputs in templates.
- Security: current_user_can('edit_posts') floor added to all sync and log AJAX handlers.
- Security: showAlert() switched from .html() to .text(); safeUrl() scheme guard added to API-sourced hrefs.
- Security: decrypt_token() now preserves encrypted value on AUTH_KEY rotation instead of returning empty string.
- Security: handle_sync_post REST handler now verifies current_user_can('edit_post', $post_id) and requires published status.
- Security: all remote assets (Poppins, Lexend Deca, emoji-mart) bundled locally; no CDN or Google Fonts calls on page load.
- Renamed global constant SIDEBAR_MENU_NAME to DESKU_SIDEBAR_MENU_NAME to avoid plugin conflicts.
- Renamed cron hook sync_event_scheduled_hook to desku_sync_event to avoid conflicts with other plugins.
- Added uninstall.php to clean up options, post meta, cron, and transients on plugin removal; extended to cover all subsites on multisite installs.
- Added index.php silence files to all plugin subdirectories.
- Fix: corrected widget script URL to https://widget.desku.io/chat-widget.js (was incorrectly using the tenant subdomain).
- Fix: Text Domain header corrected to desku-chat-widget; load_plugin_textdomain() added so translations now load.
- Fix: Desku_Admin no longer instantiated on frontend page loads; scoped to admin, AJAX, and cron contexts only.
- Fix: block fallback path corrected to build/desku-chat-widget so the block registers correctly on WP < 6.8.
- Fix: String.prototype pollution removed; toSentenceCase, toUcWords, replaceInBraces converted to plain functions.
- Fix: DOM id="widget" renamed to id="desku-chat-widget" to avoid collision with reserved browser globals and WordPress widget system.
- Fix: widget preview fonts (16 families) now self-hosted via widget-fonts.css; runtime Google Fonts inject in updateVisualWidget() removed.
- Fix: desku.dev hard-coded image URLs in widget-preview.php replaced with locally bundled SVGs.
- Security: current_user_can('manage_options') floor added to handle_get/update_training_settings AJAX handlers.
- Security: make_api_request() returns false on non-array JSON body, collapsing undefined-index and PHP 8 TypeError cluster across all callers.
- Fix: load_settings() now deep-merges stored settings against defaults so nested keys (plan_summary, user_permissions) are never silently dropped.
- Perf: check_authentication() caches successful token verification in a 5-minute transient; eliminates blocking API call and option write on every admin page load.
- Fix: encrypt_token() guards against double-encrypting an already-encrypted enc: blob; decrypt_token() returns empty string on failure so a rotated AUTH_KEY triggers re-auth rather than sending the enc: blob as a Bearer token.
- Fix: frontend widget uses addEventListener('load') instead of window.onload; backtick template literal fixes non-interpolating cache-buster URL.
- Added apply_filters('desku_widget_load', true) hook so GDPR consent managers can suppress the widget before consent is given.
- Fix: training_delay_seconds input is disabled when manual training mode is active, preventing the unfocusable validation error on form submit.
- Fix: block type registration removed; replaced with enqueue_block_editor_assets so the sidebar plugin loads without adding a broken block to the inserter.
- Fix: cron scheduling hook changed from wp (frontend-only) to init so auto-sync cron schedules correctly in admin, AJAX, and cron contexts.
- Fix: REST API routes now register on rest_api_init for non-admin requests, fixing 404 on desku/v1/* endpoints from the block editor.
- Fix: $response array reads changed from ?: to ?? / (?? '') ?: pattern to eliminate PHP 8 undefined-key warnings across ~20 callers.
- Fix: array_merge guard added against non-array API response data in add_all_post_types_to_training_settings().
- Fix: load_settings() uses deep-merge so nested default keys are never dropped.
- Fix: post meta key renamed from train_eva to desku_train_eva to avoid collision with other plugins.
- Fix: sync-info handlers get_posts capped at 500 (was -1); enqueue handles prefixed with desku- to avoid conflicts.
- Security: escHtml() applied to all display_name outputs in sync modal JS (was unescaped API data in .html()).
- Security: current_user_can('manage_options') floor added to handle_get/update_training_settings handlers.
- Security: error_log() calls gated behind WP_DEBUG; commented-out token-logging lines deleted from make_api_request().
- Security: DESKU_ENCRYPTION_KEY wp-config.php constant supported for token encryption independent of AUTH_KEY rotation.
- Perf: bundled TinyMCE (~5.1 MB) removed; welcome message field uses WordPress built-in editor via wp-tinymce dependency.
- Fix: Poppins font files were incorrectly downloaded as Devanagari subset; re-downloaded as correct Latin subset for all three weights.
- Fix: TinyMCE toolbar icons restored by scoping .desku-admin-main font-family override to exclude .mce-ico elements.
- Added .distignore to exclude src/, package.json, node_modules, and dev files from distributed plugin zip.
- Added wp_set_script_translations() for block editor sidebar i18n readiness.

= 2.1.1 =
- Fix: wrapped wp_register_block_types_from_metadata_collection() in function_exists() with a register_block_type() fallback to prevent fatal errors on WordPress < 6.8.
- Fix: added Requires at least: 6.8 and Requires PHP: 7.2 to plugin header and README so WordPress blocks activation on incompatible installs.

= 2.1.0 =
- Security: added capability checks (manage_options) to all AJAX handlers to prevent privilege escalation.
- Security: encrypted stored API token at rest using libsodium, keyed from wp-config.php AUTH_KEY.
- Security: widget script rendered inline with esc_js/esc_url instead of storing a raw HTML blob.
- Security: sync-log rows and detail modal now use safe DOM construction to prevent stored XSS via post titles.
- Security: subdomain input validated to alphanumeric/hyphen hostname labels to reduce SSRF surface.
- Security: Bootstrap CSS and Popper.js moved from CDN to bundled local assets.
- Security: sanitized all $_POST array inputs with array_map/sanitize_text_field before allowlist checks.
- Security: replaced array_first() (Laravel-only) with reset() to fix fatal error in error branches.
- Security: fixed plan_active comparison using time() instead of microtime().
- Security: cron sync logging switched from web-accessible cron_log.txt to error_log().
- Security: fixed echo _e() misuse in templates; replaced with _e() or esc_html__() as appropriate.
- Security: escaped username, workspace href, and automation level output in admin templates.

= 2.0.5 =
- Added post links in Sync Logs.
- Further improved error responses.

= 2.0.4 =
- Test up to WP 7
- Load total syncs from api
- Add Workspace link in connection status section.
- Sync Char Limit in Connection Status section.
- Display Plugin version number at page bottom.
- Remove debug error logs.

= 2.0.3 =
- Handle Full/Selective Sync error responses.
- Display Sync Url Limit in connection status.
- Use started_at date as log date/time instead.

= 2.0.2 =
- Simplify User Login authentication.

= 2.0.1 =
- Simplify API key authentication.

= 2.0.0 =
- Fresh release

= 1.0.0 =
- Initial release