Skip to content

MelisCmsProspects

Leads / contact management: a front-office contact form captures visitor messages as prospects, and a React back-office lets you browse, filter, edit, export and delete them, plus classify requests by themes. Package melisplatform/melis-cms-prospects.

Purpose

MelisCmsProspects captures visitor contact-form submissions as prospects (leads) stored in the database. Back-office users browse, filter, edit, export (CSV/Excel) and delete those leads, and classify them by themes. The module ships a dashboard statistics widget and plugs into the platform's GDPR tooling (user info / extract / delete + auto-delete cycle).

In Melis v6 the two back-office tools — Prospects and Themes — are native full-React UIs served under /melis-react, each talking to a JSON react-api layer. The underlying data model, services, the front Show Form plugin and the GDPR wiring are unchanged from v5.

Enable it

Add to config/melis.module.load.php:

php
return [
    'MelisCmsProspects',
];

Dependencies: melis-core, melis-engine, melis-front, melis-cms and laminas/laminas-mvc-plugin-flashmessenger. The module is dbdeploy: true — its tables are created/updated through the dbdeploy mechanism. Both React tools appear in the back-office only while the module is active (they are discovered from its brick.manifest.json).

React back-office

Where: left sidebar → MelisMarketingProspectsProspects / Themes. Each opens as its own top tab. Every tool keeps a New / Old toggle: New is the React UI (default), Old renders the legacy tool in an iframe (/melis/react-tool-page?key=<melisKey>).

Two bricks ship in one bundle (public/ui-react/brick.manifest.json):

ItemProspectsThemes
Brick id / routeprospects/prospectsprospect-themes/prospect-themes
forwardKey (menu → route)MelisCmsProspects/ToolProspectsMelisCmsProspects/ProspectThemes
Old-view iframe melisKey (zone)MelisCmsProspects_tool_prospectsMelisCmsProspects_tool_themes
Rights / capability melisKeymelisprospects_tool_prospects_sectionmelisprospects_tool_themes_section
API base/melis/react-api/prospects/melis/react-api/prospect-themes
ControllerMelisReactApiProspectControllerMelisReactApiProspectThemeController

Note: the manifest melisKey is the renderable zone key used for the Old-view iframe — rights do not hang on it. Access guard and capabilities key on the menu node melisprospects_tool_..._section (declared in config/app.interface.php).

Prospects tool

The React Prospects tool: KPI cards (Total / This month / Average per month / Anonymized), search, All-sites and All-types filters, a Date range picker, Reset filters, a Columns manager, Export, the New/Old toggle and a refresh button — each row has edit and delete actions

You see every prospect on the platform. The list has four KPI cards (Total, This month, Average per month, Anonymized), a search box (name / email / phone / company), a site filter, a type filter, a Date range picker (Today / Yesterday / Last 7 / Last 30 / This month / Last month / Custom), Reset filters, a persisted Columns manager, Export and a refresh button. Click a header to sort (all columns except Message). Each row has edit and delete.

Prospects are not created here — they arrive only from the front contact form. Clicking edit opens the prospect as a host sub-tab (← Back) showing a React form: a Contact information card (Name, Email, Phone, Company, Country), a Message card and a Details side card (Site picker, Theme picker, read-only Contact date). No field is mandatory (email is format-checked only if filled); Contact date and type are immutable — they are set at capture time by the front form.

The React prospect edit form — a Contact information card (Name, Email, Phone, Company, Country), a Message box and a Details side card (Site, Theme, read-only Contact date); the sub-tab bar shows the drill-down (← Back · Paul Martin)

Themes tool

The Themes list shows two KPI cards (Total themes, total Items), a search box, Reset filters, a Columns manager, Export, the New/Old toggle and + New theme. Each row shows the theme name and its item count, with three actions: rename (one-field modal), edit (opens the theme's Items sub-tab) and delete.

The React Themes tool: Total / Items KPI cards, search, Reset filters, Columns, Export, New/Old toggle and "+ New theme" — each row exposes rename, edit (open items) and delete

The "New theme" modal — a single Name field (the code is preserved by the back-end, not entered here)

Editing a theme opens its Items panel as a sub-tab (← Back + theme name): a searchable list of items (id + name) with per-row edit/delete and + New item. Adding or editing an item opens a modal capturing a name per CMS language — a row of language tabs (flag + green "filled" dot) plus the Name field for the active language. At least one language must be filled.

A theme's Items panel (sub-tab) for "My Billing" — a searchable list of items with per-row edit/delete and a "+ New item" button, shown as a drill-down sub-tab

The "New item" modal — "Content per language" tabs (English / Français) and the Name field for the active language

React API

Routes live in config/react-api.php (merged via Module::getConfig()). All under /melis/react-api/, contract { success, data, error }; every fetch sends X-Requested-With: XMLHttpRequest and credentials: 'include'.

ProspectsMelisReactApiProspectController:

Method & URLPurpose
GET /prospectsKeyset list (limit,search,site,type,dateFrom,dateTo,sort,dir,after) → {items,total,nextCursor}
GET /prospects/statsKPIs {total, thisMonth, avgPerMonth, anonymized}
GET /prospects/sitesSite filter options
GET /prospects/typesDistinct pros_type values
GET /prospects/themesTheme-item options for the form's Theme picker
GET /prospects/:idOne prospect (formatted)
POST /prospects/saveUpdate only (no create); contact date & type immutable server-side
DELETE /prospects/delete/:idDelete a prospect

Themes & itemsMelisReactApiProspectThemeController:

Method & URLPurpose
GET /prospect-themesKeyset list of themes → {items,total,nextCursor} with itemCount
GET /prospect-themes/statsKPIs {total, withCode, items}
GET /prospect-themes/:idOne theme {id,name,code,itemCount}
POST /prospect-themes/saveCreate (id=0) / update (name required ≤45, unique; code preserved if absent)
DELETE /prospect-themes/delete/:idDelete a theme + items + translations (cascade)
GET /prospect-themes/languagesCMS languages {languages:[{id,name,locale}]}
GET /prospect-themes/items?themeId=XA theme's items (name in session language)
GET /prospect-themes/items/:idOne item {id,themeId,translations:{langId:text}}
POST /prospect-themes/items/saveCreate/update an item (≥1 non-empty translation; per-lang upsert/delete)
DELETE /prospect-themes/items/delete/:idDelete an item + its translations
ts
// update a prospect (no create)
await apiFetch<{id:number}>('/melis/react-api/prospects/save', {
  method: 'POST', headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ id: 3, siteId: 1, name: 'Paul Martin',
    email: 'paul.martin@example.com', message: '…', theme: null }),
})
// save a theme item (name per language)
await apiFetch<{id:number}>('/melis/react-api/prospect-themes/items/save', {
  method: 'POST', headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ id: 0, themeId: 2, translations: { '1': 'My invoices', '2': 'Mes factures' } }),
})

Both controllers talk to the tables directly via parameterised SQL (AdapterInterface, keyset lists via MelisReactKeysetListTrait), reproducing the legacy business rules. They still fire the legacy log events (meliscmsprospects_toolprospects_save_end / _delete_end, meliscmsprospects_theme_save_end / _delete_end, meliscmsprospects_theme_item_save_end) so the module's flash/log listeners keep working.

Capabilities

Declared in config/react.capabilities.php (melisReactToolCapabilities), keyed by the rights-bearing menu-node melisKey. Capabilities::flatten() produces dotted strings passed to MelisCan(melisKey, cap) in React and denyUnlessCan(cap) server-side (default-allow for an undeclared cap).

php
'melisprospects_tool_prospects_section' => ['list', 'edit', 'delete', 'export'], // NO create
'melisprospects_tool_themes_section' => [
    'actions' => ['create', 'list', 'edit', 'delete', 'export'],
    'tabs' => [
        ['key' => 'items', 'label' => 'tr_melis_cms_prospects_theme_items',
         'actions' => ['list', 'create', 'edit', 'delete']],
    ],
],
  • Prospects: list, edit, delete, export (no create — a prospect is only born from the public contact form).
  • Themes: create, list, edit, delete, export, plus the items sub-tab (items, items.list, items.create, items.edit, items.delete).

Each controller action guards twice: denyUnlessAccess() (auth + MelisCoreRights::canAccess) then denyUnlessCan('list') etc. save picks edit vs create by id.

Key services

Service aliasRole
MelisCmsProspectsService / MelisProspectsServiceMain service. saveProspectsDatas($datas, $prosId = null) creates or updates a prospect; getProspectsDataForWidgets($widgetId = '') returns total / this-month / average counts; getProspectsDataByDate($type, $date) counts registrations by date; getWidgetProspects($identifier) retrieves data for a widget.
MelisProspectsGdprAutoDeleteServiceHandles the GDPR auto-delete cycle (module list, tags list, warning / second-warning user lists, account deletion).

Table gateways: MelisProspects, MelisCmsProspectsThemeTable, MelisCmsProspectsThemeItemTable, MelisCmsProspectsThemeItemTransTable.

The React controllers do not use MelisCmsProspectsService (they query the tables directly); the classic tools (Old view), the Show Form plugin, the dashboard widget and the GDPR listeners still rely on it.

Front office

The MelisCmsProspectsShowFormPlugin controller plugin renders the contact form on the front end. Drop the Show Form block onto a page from the React page editor's plugins panel (under Melis Cms Prospects). Its settings modal keeps three tabs:

The React page editor with the plugins panel open — the "Contact Form" block sits under the "Melis Cms Prospects" group, ready to drop onto the page

Show Form — Field list tab: the field-builder — per field a Show/Hide switch and a Mandatory checkbox; rows are drag-sortable so their order is the form order

TabControls
PropertiesRendering template (template_path) and source site (pros_site_id).
Field listField-builder — per field a Show/Hide switch and a Mandatory checkbox (enabled only when Show is on); drag rows to set the form order. Fields: pros_name, pros_company, pros_country, pros_email, pros_telephone, pros_message.
ThemesThe theme that populates the form's subject dropdown.

Config file: config/plugins/MelisCmsProspectsShowFormPlugin.config.php. Front template: view/.../plugins/prospects-form.phtml. On the back-office Dashboard, the Prospects Statistics widget (MelisCmsProspectsStatisticsPlugin, section MelisMarketing) charts registrations over time.

The "Prospects statistics" dashboard widget — a Daily/Monthly/Yearly registrations chart plus a table of the most recent prospects

Database tables

TableHolds
melis_cms_prospectsA captured lead: site, type, theme, name, email, telephone, message, company, country, contact date, GDPR last date. PK: pros_id.
melis_cms_prospects_themesSubject themes (pros_theme_name, pros_theme_code). PK: pros_theme_id.
melis_cms_prospects_theme_itemsItems belonging to a theme. PK: pros_theme_item_id.
melis_cms_prospects_theme_items_transPer-language translations of theme items. PK: item_trans_id.

Event hooks

Attach with MelisCmsProspects as the target identifier:

Event nameFired by
meliscmsprospects_toolprospects_save_start / _endProspects tool (classic + React controller)
meliscmsprospects_toolprospects_delete_start / _endProspects tool (classic + React controller)
meliscmsprospects_theme_save_end / _delete_endThemes tool (classic + React controller)
meliscmsprospects_theme_item_save_endTheme items (classic + React controller)
php
$sharedEvents->attach(
    'MelisCmsProspects',
    'meliscmsprospects_toolprospects_save_end',
    $fn,
    50
);

GDPR listeners (user info, extract, delete, auto-delete) are wired in src/Module.php. GDPR field mappings live in config/app.gdpr.php.

Key files

ConcernPath (under vendor/melisplatform/melis-cms-prospects/)
Module config / routes / servicesconfig/module.config.php
React-api routes + invokablesconfig/react-api.php
React capabilitiesconfig/react.capabilities.php
Back-office interface treeconfig/app.interface.php
Classic tool tables & formsconfig/app.tools.php
Templating plugin configconfig/plugins/MelisCmsProspectsShowFormPlugin.config.php
Dashboard widget configconfig/dashboard-plugins/
GDPR field mappingconfig/app.gdpr.php
React API controllerssrc/Controller/MelisReactApiProspectController.php, MelisReactApiProspectThemeController.php
Classic controllerssrc/Controller/ToolProspectsController.php, MelisCmsProspectsThemesController.php, MelisCmsProspectsThemeItemsController.php
Main servicesrc/Service/MelisCmsProspectsService.php
GDPR auto-delete servicesrc/Service/
Front form pluginsrc/Controller/Plugin/MelisCmsProspectsShowFormPlugin.php
Dashboard widgetsrc/Controller/DashboardPlugins/MelisCmsProspectsStatisticsPlugin.php
React bricks (source / build)ui-react/src/public/ui-react/brick.js + brick.manifest.json
Table gatewayssrc/Model/Tables/
GDPR listeners & bootstrapsrc/Module.php, src/Listener/

See also: Module reference · melis-cms · melis-core