Skip to content

Lotmanine/nimbusops-wp-showcase

Repository files navigation

NimbusOps - WordPress CRM Integration Showcase

CI WordPress PHP Tests License

A WordPress lead pipeline built the way I'd ship it for production: capture a lead, score it, store it, and sync it out to a CRM and to HubSpot without ever blocking the visitor or losing a lead when a downstream service is down.

This repo holds only the custom code (MU-plugins, a child theme, ACF exports, tests, CI, docs). WordPress core and third-party plugins are git-ignored, so bring your own WordPress: drop wp-content/ into an install, or use the setup steps below.

What it does

NimbusOps is a fictional SaaS company. A visitor submits the demo form, and the pipeline:

  1. Validates and scores the lead (corporate domain, company, plan, message length).
  2. Writes it to an append-only wp_nimbusops_leads table.
  3. Fires a nimbusops/lead/captured event.
  4. Two listeners react, independently of each other:
    • FluentCRM (in-process): upserts the contact, tags it by score band, lets a funnel take over.
    • n8n (async): posts a signed webhook that retries with backoff, which upserts the contact in HubSpot.

The FluentCRM hop runs inline because it's local. The network hop to n8n is scheduled, so a slow or down n8n never slows the form response.

Skills it demonstrates

Area Where
MU-plugin architecture, deterministic load order nimbusops-loader.php + nimbusops/
Unit-testable business logic pulled out of the framework lib/scoring.php + tests/ (29 tests)
Endpoint hardening: nonce, capability, honeypot, rate-limit, sanitize/escape form-logger.php
Custom $wpdb table via dbDelta with proper indexes form-logger.php
Event-driven design (listeners don't know about each other) nimbusops/lead/captured + bridges
Async jobs, HMAC-signed webhooks, retry with backoff, idempotency n8n-dispatcher.php
CRM integration: idempotent upsert, score-to-tag mapping, consent/double opt-in fluentcrm-bridge.php
CPT + taxonomy, ACF as version-controlled JSON, JSON-LD + SEO meta cpt.php
Dependency-free front end, a11y, RTL-ready shortcodes.php + child theme
CI: lint + test matrix on PHP 8.2/8.3/8.4 .github/workflows/ci.yml

Stack

  • WordPress 7.0, PHP 8.2+, MySQL 8.0+ / MariaDB 10.6+
  • FluentCRM (on-site CRM), n8n (orchestration via signed webhook), HubSpot (synced from n8n)
  • ACF (field groups as local JSON), Hello Elementor parent + a child theme, LiteSpeed Cache

Structure

wp-content/
├── mu-plugins/
│   ├── nimbusops-loader.php        # the only auto-loaded file; requires modules in order
│   └── nimbusops/
│       ├── config.php              # constants, logger, secret resolution
│       ├── lib/scoring.php         # pure logic, no WP, unit-tested
│       ├── form-logger.php         # leads table + REST endpoint + scoring + admin viewer
│       ├── cpt.php                 # Solution CPT + taxonomy + ACF JSON + JSON-LD/SEO
│       ├── shortcodes.php          # lead form, solutions grid, pricing table
│       └── integrations/
│           ├── fluentcrm-bridge.php   # lead event -> FluentCRM (sync)
│           └── n8n-dispatcher.php     # lead event -> signed n8n webhook (async, retrying)
├── themes/nimbusops-child/         # styles + single-Solution template
└── acf-json/                       # ACF field group export

tests/      29 PHPUnit tests (scoring + name parsing)
docs/       hubspot-mapping, automation-flows, performance
n8n/        importable workflow scaffold + setup notes
scripts/    test-lead-capture.sh, healthcheck.sh, seed-demo.php

WordPress only auto-loads top-level files in mu-plugins/, alphabetically. nimbusops-loader.php is the single entry point and requires the nimbusops/ modules in a fixed order, so nothing depends on filename luck.

Usage

Add the shortcodes to any page (Elementor, block editor, or classic):

[nimbusops_lead_form title="Request a demo" source="homepage"]
[nimbusops_solutions count="6" category="automation"]
[nimbusops_plan_table]

The form posts to POST /wp-json/nimbusops/v1/lead with a wp_rest nonce. Captured leads show under Tools > NimbusOps Leads. Full flow in docs/automation-flows.md.

Testing

The scoring and name-parsing logic lives in lib/scoring.php with no WordPress dependency, so it's unit-tested directly:

composer install && composer test
# or, without Composer:
php phpunit.phar --bootstrap tests/bootstrap.php tests/Unit
# OK (29 tests, 31 assertions)

CI runs the suite plus a php -l lint of every custom file on PHP 8.2 / 8.3 / 8.4. The WordPress-coupled paths are exercised with scripts/test-lead-capture.sh and scripts/healthcheck.sh against a running site.

Setup

You need a WordPress 7.0 site (XAMPP, LocalWP, or any host). Then:

  1. Copy wp-content/mu-plugins/, wp-content/themes/nimbusops-child/, and wp-content/acf-json/ into the install. The mu-plugins auto-load.
  2. Install and activate Elementor (Hello Elementor parent), ACF, FluentCRM, LiteSpeed Cache, then activate the NimbusOps Child theme.
  3. Copy .env.example to .env (or set the constants in wp-config.php) and set NIMBUSOPS_N8N_WEBHOOK_URL and NIMBUSOPS_N8N_SIGNING_SECRET.
  4. Map FluentCRM tag ids: wp option update nimbusops_fluentcrm_tag_map '{"hot":12,"warm":13,"cold":14}' --format=json
  5. Import n8n/nimbusops-lead-to-hubspot.workflow.json into n8n and wire credentials (see n8n/README.md).

Optional WP-CLI quickstart (from the project root, with wp-cli.phar present):

php wp-cli.phar config create --dbname=nimbusops --dbuser=root --dbpass=''
php wp-cli.phar core install --url="http://localhost/nimbusops" --title="NimbusOps" \
  --admin_user=admin --admin_password=admin123 --admin_email=admin@example.com --skip-email
php wp-cli.phar plugin install elementor advanced-custom-fields fluent-crm litespeed-cache --activate
php wp-cli.phar theme install hello-elementor
php wp-cli.phar theme activate nimbusops-child
php wp-cli.phar eval-file scripts/seed-demo.php
php wp-cli.phar rewrite structure '/%postname%/' --hard

Notes:

  • The benefits ACF field is a repeater, which needs ACF Pro. The other fields and the template work fine on free ACF.
  • A lead's sync_status stays pending until NIMBUSOPS_N8N_WEBHOOK_URL is set. The FluentCRM sync runs either way.
  • Elementor's Cloud Library fails to load on a dotless host (localhost) with a long sub-path. Use a short URL like http://localhost/nimbusops or a .test vhost and it loads fine.

Docs

Security

Never commit wp-config.php or .env. Secrets live in constants or environment, never in tracked files. The lead endpoint enforces nonce, honeypot, rate-limit, and input sanitization; admin output is escaped.

License

MIT for the custom code in this repo. Premium plugins (Elementor Pro, ACF Pro) need their own licenses if you use them.

Author

Lotfi O. · GitHub · oldev.site · LinkedIn

About

WordPress CRM integration showcase with automation

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages