WP Manifestindependent plugin directory
manifest / integrations / crm-manager

CRM Ticketing

WordPress plugin that lets customers submit and track support tickets synced with Dynamics 365 CRM, with an AI agent answering automatically.

by ata ashrafi · github.com/elmira-ashrafi/crm-manager · website

0stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/elmira-ashrafi/crm-manager/archive/refs/heads/main.zip

Readme

CRM Ticketing — Dynamics 365 ↔ MuChat AI Integration for WordPress

A production-grade WordPress plugin that bridges a WordPress front-end with Microsoft Dynamics 365 CRM (Dataverse API v9.0), giving customers a self-service ticketing portal while an AI agent (MuChat) handles first-line responses. Built for high concurrency and reliability: ticket creation, file/voice attachments, and CRM/agent communication are dispatched as parallel async HTTP requests, and long-running work (bulk ticket sync, resolved-ticket archiving) runs in the background via Action Scheduler instead of blocking the request.

Originally built as a support-ticket integration for a live customer panel, so the plugin also ships a compatibility layer for the MihanPanel WordPress theme in addition to its own native routing.


✨ Key Features

  • Dynamics 365 OAuth2 authentication — token-based auth against an ADFS/Azure AD endpoint, with separate credentials for the end-user and for the AI agent (chatbot) identity.
  • Concurrent async HTTP with Guzzle — when a ticket update needs to hit both the CRM and the AI agent (and optionally upload an attachment) at the same time, requests are fired concurrently with GuzzleHttp\Promise and resolved with Promise\Utils::settle() instead of being chained sequentially, cutting response time under load.
  • Background job processing (Action Scheduler) — ticket creation triggers an as_enqueue_async_action() job so the CRM sync and AI hand-off can complete after the response is already sent to the user; failed jobs are logged to dedicated files (background/*-failed.txt) instead of failing silently.
  • Custom routing layer — registers its own rewrite rules (/my-tickets/, /my-tickets/new-ticket/, /my-tickets/ticket-{id}/) via add_rewrite_rule, independent of the CMS page structure.
  • MihanPanel compatibility shim — detects when the plugin is being rendered inside a MihanPanel tab and swaps in the right template/behavior without duplicating logic.
  • Jalali (Persian) date handling — converts and formats all CRM timestamps to Jalali dates with human-readable relative time (e.g. "۲ روز قبل") via morilog/jalali.
  • Attachment pipeline with real validation — audio/file uploads are checked against an explicit MIME allow-list using finfo (actual content sniffing, not just file extension), with size limits enforced before anything reaches the CRM.
  • Transient-based caching — support-agent lookups are cached with WordPress transients to avoid re-querying Dataverse on every page load.
  • Resolved-ticket archival job — a scheduled task walks Dataverse's @odata.nextLink pagination to pull newly resolved tickets and their full annotation thread into local conversation logs (conversations/*.txt), rotating files once a batch exceeds 5,000 tickets — useful as training/eval data for the AI agent.
  • Shutdown error logging — a register_shutdown_function hook captures fatal PHP errors with file/line context to a plugin-local log, even when WordPress's own error handling doesn't catch them.
  • CLI support — registers a wp crm command when running under WP-CLI.

🧠 Architecture Overview

                        ┌─────────────────────┐
                        │   Customer (Web UI)  │
                        └──────────┬───────────┘
                                   │ AJAX (jQuery)
                                   ▼
                  ┌────────────────────────────────┐
                  │   WordPress Plugin (this repo)  │
                  │  ┌──────────────────────────┐   │
                  │  │ CRMTicketManager (core)   │   │
                  │  │  • OAuth2 token handling  │   │
                  │  │  • routing / query vars   │   │
                  │  ├──────────────────────────┤   │
                  │  │ ArchiveTicketsHandler      │   │
                  │  │ SingleTicketsHandler       │   │
                  │  │  • Guzzle async requests   │   │
                  │  │  • file/voice validation   │   │
                  │  └──────────────────────────┘   │
                  └─────┬──────────────────┬────────┘
                         │                  │
             (parallel, via Guzzle Promises)
                         │                  │
                         ▼                  ▼
             ┌────────────────────┐  ┌────────────────────┐
             │ Dynamics 365 CRM    │  │  MuChat AI Agent    │
             │ (Dataverse API v9)  │  │  (LLM endpoint)      │
             └──────────┬──────────┘  └──────────┬──────────┘
                         │                        │
                         └───────────┬────────────┘
                                     ▼
                     Response merged & written back to
                     CRM ticket + returned to customer

        ┌─────────────────────────────────────────────┐
        │  Action Scheduler (background)                │
        │  • post-creation CRM/agent sync                │
        │  • daily resolved-ticket → conversation export  │
        └─────────────────────────────────────────────┘

📋 Requirements

  • WordPress 6.x+
  • PHP 8.1+
  • Composer
  • Microsoft Dynamics 365 CRM (Dataverse API v9.0)
  • OAuth2 token endpoint (ADFS or Azure AD)
  • MuChat Agent API credentials

Composer dependencies (see composer.json):

Package Version Purpose
guzzlehttp/guzzle ^7.9 Concurrent/async HTTP requests to CRM & AI agent
woocommerce/action-scheduler ^3.9 Reliable background job processing
morilog/jalali ^3.4 Gregorian → Jalali date conversion

⚙️ Installation & Setup

  1. Clone the plugin into wp-content/plugins/ and install dependencies:

    composer install --no-dev --optimize-autoloader
  2. Activate the plugin from the WordPress admin panel.

  3. Add the following constants to wp-config.php, before the line /* That's all, stop editing! Happy publishing. */:

    // CRM global data
    define('CRM_TOKEN_API_LINK', "https://sts.eversso.com/adfs/oauth2/token"); // token endpoint, almost always the same
    define('CRM_API_LINK', YOUR_ORGANIZATION_API_LINK); // e.g. https://your-organization-domain.com/api/data/v9.0
    
    // Client CRM credentials
    define('CLIENT_ID', YOUR_CRM_CLIENT_ID);           // from your ADFS server
    define('CLIENT_SECRET', YOUR_CRM_CLIENT_SECRET);   // from your ADFS server
    define('CLIENT_USERNAME', YOUR_CRM_CLIENT_USERNAME);
    define('CLIENT_PASSWORD', YOUR_CRM_CLIENT_PASSWORD);
    define('CLIENT_UUID', YOUR_CRM_CLIENT_USER_UUID);   // from .../api/data/v9.0/WhoAmI → UserId
    
    // MuChat chatbot identity (a dedicated CRM user acting on behalf of the AI agent)
    define('CHATBOT_USERNAME', CHATBOT_USERNAME);
    define('CHATBOT_PASSWORD', CHATBOT_PASSWORD);
    define('CHATBOT_UUID', CHATBOT_UUID); // from .../systemusers?$select=systemuserid&$filter=domainname eq 'CHATBOT_USERNAME'
    
    // MuChat agent credentials
    define('MUCHAT_TOKEN', MUCHAT_TOKEN_VALUE);
    define('AGENT_ID', AGENT_ID_VALUE);
  4. Flush permalinks once (the plugin does this automatically on activation/deactivation, but a manual visit to Settings → Permalinks → Save helps if custom routes 404).


🚀 How It Works

  1. The customer submits a new ticket or reply through the front-end UI (AJAX).
  2. The plugin authenticates with Dynamics CRM via OAuth2 and obtains an access token (cached per-request, one identity for the customer flow and one for the agent flow).
  3. For actions that need both systems — e.g. posting a reply and asking the AI agent for a response and uploading an attachment — the plugin fires the requests concurrently with Guzzle promises rather than one after another, and waits for all of them to settle.
  4. The MuChat LLM agent generates a response based on the ticket/conversation context.
  5. The plugin writes the agent's (or the customer's) message back into Dynamics CRM as an annotation, tagged with the correct identity (chatbot vs. customer).
  6. Heavier, non-blocking work — syncing a newly created ticket to the CRM/agent after the response is sent, and the daily export of resolved tickets — is handed off to Action Scheduler, so the customer-facing request stays fast.
  7. Newly resolved tickets and their full conversation thread are periodically pulled from Dataverse (paginated via @odata.nextLink) and written to local conversation logs, batched and rotated at 5,000 tickets per file.

⚠️ Security Notice

This plugin requires CRM credentials and API tokens.

  • Never commit wp-config.php to GitHub.
  • Never expose client secrets publicly.
  • Prefer environment variables over hardcoded constants where possible.
  • Restrict API permissions to the minimum required scope.

🔐 Recommended Security Improvements (for production)

  • Use environment variables instead of hardcoded wp-config.php constants.
  • Store secrets in server-level configuration (not in version control).
  • Restrict CRM API scopes to only the entities/operations this plugin needs.
  • Enable HTTPS only, and remove any verify => false / sslverify => false overrides used during development.
  • Add structured logging & rate limiting around the CRM/agent endpoints.

Author

Elmira Ashrafigithub.com/elmira-ashrafi

Read the full README on GitHub →