PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / trunk
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder vtrunk
6.2.15 6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 All 197 releases
fluentform / app / Modules / AgentReady / WebMCPModule.php

WebMCPModule.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder trunk, at app/Modules/AgentReady/WebMCPModule.php

136 lines 4.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentForm\App\Modules\AgentReady;
4
5 use FluentForm\App\Helpers\Helper;
6 use FluentForm\Framework\Foundation\Application;
7 use FluentForm\Framework\Helpers\ArrayHelper;
8 use FluentForm\Framework\Support\Str;
9
10 /**
11 * Emits the WebMCP declarative form attributes so agentic browsers can
12 * synthesize a tool from the rendered form instead of guessing at the DOM.
13 *
14 * Lives outside App\Modules\MCP deliberately: that module is a server-side MCP
15 * endpoint whose whole surface is gated behind WP auth and PermissionGate. This
16 * is public markup rendered for anonymous visitors and shares no code, transport
17 * or trust boundary with it — only an unfortunate acronym.
18 *
19 * @see https://github.com/webmachinelearning/webmcp/blob/main/declarative-api-explainer.md
20 */
21 class WebMCPModule
22 {
23 /**
24 * App instance
25 *
26 * @var \FluentForm\Framework\Foundation\Application
27 */
28 protected $app;
29
30 public function __construct(Application $app)
31 {
32 $this->app = $app;
33 }
34
35 public function register()
36 {
37 $this->app->addFilter('fluentform/html_attributes', [$this, 'addFormToolAttributes'], 10, 2);
38 $this->app->addFilter('fluentform/before_render_item', [$this, 'addFieldToolAttributes'], 10, 2);
39 }
40
41 public function addFormToolAttributes($attributes, $form)
42 {
43 if (!$this->isEnabledForForm($form)) {
44 return $attributes;
45 }
46
47 // Spec attribute names are all-lowercase and unprefixed; not a typo.
48 $attributes['toolname'] = $this->getToolName($form);
49 $attributes['tooldescription'] = $this->getToolDescription($form);
50
51 return $attributes;
52 }
53
54 public function addFieldToolAttributes($item, $form)
55 {
56 if (!$this->isEnabledForForm($form)) {
57 return $item;
58 }
59
60 // Composite fields (name, address) render each sub-field's own
61 // attributes, so anything set on the parent lands on a wrapper element
62 // instead of an input. Describe the sub-fields themselves.
63 if (ArrayHelper::get($item, 'fields')) {
64 foreach ($item['fields'] as $key => $subField) {
65 $item['fields'][$key] = $this->addParamAttributes($subField);
66 }
67
68 return $item;
69 }
70
71 return $this->addParamAttributes($item);
72 }
73
74 protected function addParamAttributes($field)
75 {
76 if (!ArrayHelper::get($field, 'attributes.name')) {
77 return $field;
78 }
79
80 $description = $this->getParamDescription($field);
81
82 if ($description) {
83 $field['attributes']['toolparamdescription'] = $description;
84 }
85
86 // No native `required`: it forces `novalidate`, which drops the browser's email/number/step checks.
87 return $field;
88 }
89
90 protected function isEnabledForForm($form)
91 {
92 $settings = Helper::getFormMeta($form->id, 'formSettings', []);
93
94 // TransferService imports write formSettings verbatim, so 'yes'/'no'
95 // reach this gate as strings — and rest_sanitize_boolean(),
96 // wp_validate_boolean() and ArrayHelper::isTrue() all read 'no' as true.
97 $isEnabled = (bool) Str::toBool(ArrayHelper::get($settings, 'webmcp.status'));
98
99 return apply_filters('fluentform/webmcp_enabled', $isEnabled, $form);
100 }
101
102 protected function getToolName($form)
103 {
104 $settings = Helper::getFormMeta($form->id, 'formSettings', []);
105 $name = ArrayHelper::get($settings, 'webmcp.tool_name');
106
107 return sanitize_title($name ? $name : $form->title);
108 }
109
110 protected function getToolDescription($form)
111 {
112 $settings = Helper::getFormMeta($form->id, 'formSettings', []);
113
114 $description = ArrayHelper::get($settings, 'webmcp.tool_description');
115
116 return $description ? $description : $form->title;
117 }
118
119 protected function getParamDescription($item)
120 {
121 $candidates = [
122 ArrayHelper::get($item, 'settings.help_message'),
123 ArrayHelper::get($item, 'settings.label'),
124 ArrayHelper::get($item, 'attributes.placeholder'),
125 ];
126
127 foreach ($candidates as $candidate) {
128 if ($candidate) {
129 return wp_strip_all_tags($candidate);
130 }
131 }
132
133 return '';
134 }
135 }
136