Skip to content

Building a CMS Adapter

A CMS adapter installs through the platform, keeps its settings in the platform’s own store, and adds a chat page and admin pages. This page compares how the six CMS adapters solve the same problems, so a new adapter can follow the closest one.

  • The same three tables: phpclaw_conversations, phpclaw_messages and phpclaw_memory, with the platform’s table prefix. PrestaShop adds a fourth, phpclaw_api_token, for its per-employee REST tokens.
  • The same settings: provider, model, API key, base URL, system prompt, store messages, max iterations (default 20), remote skill URLs, the three cloud fields, and the seven building block fields: fallback provider, model and key, rate limit, response cache and its TTL, and max token budget.
  • A fixed memory driver. None of the six lets the site owner choose one.
  • A permission for using the chat, a higher tier for seeing every user’s conversations, and an owner column on phpclaw_conversations.
  • Two commands: one to send a message and one to start the MCP server. No command reads or deletes stored conversations; Drupal’s chat page is the only screen that deletes one.
  • Lifecycle events forwarded into the platform’s own event system, and a way for other extensions to add tools, guards, hooks, skills, memory drivers and providers.
PlatformSettings stored inMemory driver
WordPressthe phpclaw_settings optionwpdb_router
Joomlathe phpClaw AI Agent system plugin’s parametersjoomladb
Drupalthe phpclaw.settings config objectdatabase
Magentocore_config_data under phpclaw/router memory
PrestaShopConfiguration keys prefixed PHPCLAW_ps_router
OpenCartOpenCart’s settingsoc_router

There is no shared adapter base class. Each CMS builds the agent in its own classes:

PlatformClasses
WordPressPlugin::getInstance() and the static Engine\EngineFactory::build()
JoomlaEngine\EngineFactory::build(), with EngineBootstrapper and ToolBuilder
DrupalPhpClawRegistrar, and PhpClawServiceFactory::create() or createChat() for the two tool sets
MagentoFactory\PhpClawFactory::create() behind PhpClawFactoryInterface
PrestaShopPlugin::getInstance() and Engine\EngineFactory::build()
OpenCartPlugin::getInstance() and Engine\OcEngineFactory::build(); Factory\PhpClawFactory::create() for PhpClawLibrary

Drupal’s admin pages are the controllers PhpClawAboutController, PhpClawAnalyticsController, PhpClawChatController and PhpClawGuideController, plus the Settings form PhpClawSettingsForm. PhpClawChatStreamController serves the Chat page’s POST stream endpoint.

No CMS adapter runs agent work in the background: there is no queue or scheduled job for agent runs.

PlatformUse the chat and toolsSee every conversationOwner column
WordPressphpclaw_use_chat (derived from manage_options or edit_posts)phpclaw_manage_all_conversationsuser_id
Joomlaphpclaw.chat.use on com_phpclawphpclaw.chat.managealluser_id
Drupaluse phpclaw chatmanage all phpclaw conversationsuser_id
MagentoPhpClaw_Magento::phpclaw_chatPhpClaw_Magento::phpclaw_settingsadmin_user_id
PrestaShopview on the Chat tabthe SuperAdmin profileid_employee
OpenCartaccess on the phpClaw routeaccess on the route’s /manage_allowner_id

Conversations created from the command line store 0 as the owner in every adapter. When you write a check that spans adapters, take the owner column as a parameter.

In each adapter the chat permission reaches every platform tool, except raw SQL in PrestaShop (SuperAdmin) and OpenCart (/manage_all). Treat it as administrator-level.

PlatformRoutesAuthentication
WordPress/wp-json/phpclaw/send, /wp-json/phpclaw/chat/streamWordPress REST authentication
Joomlaapi/index.php/v1/phpclaw/chat, .../chat/streamJoomla API token
Drupal/api/phpclaw/send, /api/phpclaw/chat/streamDrupal authentication providers
Magento/rest/V1/phpclaw/send, /rest/V1/phpclaw/chat/streamadmin bearer token
PrestaShopthe module front controller, action=send or action=chat/streamper-employee bearer token or back office session
OpenCartnone; the chat uses admin routesadmin session

Admin-only actions stay off these routes. WordPress’s chat page and Test Connection use admin-ajax.php (phpclaw_send, phpclaw_stream, phpclaw_test_connection). Joomla’s settings save, plugin enable and Test Connection run through the component’s admin ApiController, behind core.admin.

PlatformSend a messageMCP server
WordPresswp phpclaw sendwp phpclaw mcp-server
Joomlaphp cli/joomla.php phpclawphp cli/joomla.php phpclaw:mcp-server
Drupaldrush phpclaw:rundrush phpclaw:mcp-server
Magentobin/magento phpclaw:runbin/magento phpclaw:mcp-server
PrestaShopphp modules/phpclaw/cli/phpclaw.php send... mcp-server
OpenCartphp extension/phpclaw/cli/phpclaw.php send (OpenCart 4) or php system/library/phpclaw/cli/phpclaw.php send (OpenCart 3)... mcp-server

An MCP server started from the command line must build file_write with PHP writes off and must not skip the raw-SQL permission just because it runs in a terminal. See the cautions on the PrestaShop and OpenCart pages.

PlatformLifecycle events forwarded asExtensions add through
WordPressaction phpclaw_{event}filters phpclaw_extra_tools, _guards, _hooks, _skills, _memory_drivers, _providers
Joomlaevent onPhpClaw{Event}, currently delivers nothingplugin events onPhpClawExtraTools, ...Guards, ...Hooks, ...Skills, ...MemoryDrivers, ...Providers
DrupalPhpClawEvent named phpclaw.{event}service tags phpclaw.tool, phpclaw.guard, phpclaw.skill, phpclaw.provider, phpclaw.memory_driver, phpclaw.hook_listener
Magentoevent phpclaw_{event} with dots as underscoresobservers of phpclaw_extra_tools, _skills, _guards, _hooks, _memory, _providers
PrestaShophook actionPhpClaw{Event}hooks actionPhpclawExtraTools, ...Guards, ...Hooks, ...Skills, ...Memory, ...Providers
OpenCartevent phpclaw/{event}events phpclaw/extra/tools, .../guards, .../hooks, .../skills, .../memory, .../providers

All forward the 54 events of PhpClaw\Hooks\LifecycleEvent, except Joomla, whose bridge delivers no event. See Hooks and Joomla: lifecycle events.

WordPress checks for updates on WordPress’s own pre_set_site_transient_update_plugins filter and caches the answer for 12 hours; OpenCart and PrestaShop show a notice from their own AutoUpdater. On PrestaShop 9, Controller::ajaxDie() no longer exists, so admin JSON goes through AdminPhpClawBaseController::respondJson(), which works on 8 and 9.

For each adapter’s full reference, see All Adapters.