PluginProbe
Code Engine – PHP Snippets, AI Functions & Automation for WordPress / trunk
Code Engine – PHP Snippets, AI Functions & Automation for WordPress vtrunk
0.5.6 0.5.5 0.5.4 0.5.3 0.5.2 0.5.1 0.5.0 0.4.9 0.4.8 0.4.7 0.4.6 trunk 0.0.1 0.0.2 0.2.8 0.2.9 0.3.0 0.3.1 0.3.2 0.3.3 0.3.4 0.3.5 0.3.6 0.3.7 0.3.8 All 32 releases
← All changes | classes/api.php +78 -21 0.3.3trunk View file →
@@ -101,28 +101,40 @@
101 101 * @return array The list of snippets.
102 102 */
103 103 public function getSnippets( $safe = true, $scope = null ) {
104 104 try {
105 - // Don't log here to avoid infinite loops during initialization
105 +
106 + $allSnippets = $this->snippet_module->select( 0, 9999,
107 + [ ['accessor' => 'scope', 'value' => $scope] ]
108 + , [] );
109 +
110 + $snippets = $allSnippets['data'] ?? [];
106 111
107 - // If scope is specified, use getSnippetsByScope
108 - if ( $scope ) {
109 - $snippets = $this->getSnippetsByScope( $scope );
110 - } else {
111 - // Get all snippets from the database
112 - $allSnippets = $this->snippet_module->select( 0, 9999, [], [] );
113 - $snippets = $allSnippets['data'] ?? [];
114 - }
115 112
116 113 if ( $safe ) {
114 +
117 115 $snippets = array_filter( $snippets, function( $snippet ) {
118 - $name = $snippet['name'];
119 - if ( !preg_match( '/^[a-zA-Z0-9_-]{1,64}$/', $name ) ) {
120 - if ( $this->debug ) {
121 - $this->core->log( sprintf( 'API [GetSnippets]: Filtered out snippet with invalid name: %s', $name ) );
116 +
117 + if( $snippet['scope'] === 'function' ) {
118 +
119 + if( array_key_exists( 'functionName', $snippet ) )
120 + {
121 + $name = $snippet['functionName'];
122 + if ( !preg_match( '/^[a-zA-Z0-9_-]{1,64}$/', $name ) ) {
123 + if ( $this->debug ) {
124 + $this->core->log( sprintf( 'API [GetSnippets]: Filtered out snippet with invalid name: %s', $name ) );
125 + }
126 + return false;
127 + }
128 + } else {
129 + if ( $this->debug ) {
130 + $this->core->log( 'API [GetSnippets]: Filtered out snippet with missing functionName.' );
131 + }
132 + return false;
122 133 }
123 - return false;
134 +
124 135 }
136 +
125 137 return true;
126 138 } );
127 139 }
128 140
@@ -159,9 +171,9 @@
159 171 *
160 172 * @return mixed The result of the snippet execution.
161 173 * @throws Exception If the snippet cannot be executed.
162 174 */
163 - public function executeSnippet( $id, $args = [] ) {
175 + public function executeSnippet( $id, $args = [], $reply = null ) {
164 176 try {
165 177 if ( empty( $id ) ) {
166 178 throw new Exception( 'The snippet ID is required.' );
167 179 }
@@ -174,9 +186,34 @@
174 186 $snippet = $this->snippet_module->get_function( $id );
175 187 if ( empty( $snippet ) ) {
176 188 throw new Exception( sprintf( 'Snippet with ID %d not found.', $id ) );
177 189 }
178 -
190 +
191 + $query = $reply ? $reply->query : null;
192 + $array_query = [];
193 + if( $query ) {
194 + $array_query['envId'] = $query->envId ?? 'No EnvId in Query';
195 + $array_query['botId'] = $query->botId ?? 'No BotId in Query';
196 + $array_query['customId'] = $query->customId ?? 'No CustomId in Query';
197 + $array_query['embeddingsEnvId'] = $query->embeddingsEnvId ?? 'No EmbeddingsEnvId in Query';
198 +
199 +
200 + $array_query['chatId'] = $query->chatId ?? 'No ChatId in Query';
201 + $array_query['session'] = $query->session ?? 'No Session in Query';
202 + $array_query['scope'] = $query->scope ?? 'No Scope in Query';
203 +
204 + $array_query['instructions'] = $query->instructions ?? 'No Instructions in Query';
205 + $array_query['context'] = $query->context ?? 'No Context in Query';
206 +
207 + $array_query['messages'] = $query->messages ? json_encode( $query->messages ) : 'No Messages in Query';
208 + $array_query['message'] = $query->message ?? 'No Message in Query';
209 +
210 + $array_query['model'] = $query->model ?? 'No Model in Query';
211 + $array_query['feature'] = $query->feature ?? 'No Feature in Query';
212 + }
213 +
214 + $args['__mwai_query'] = $array_query;
215 +
179 216 $output = $this->core->run_snippet( $id, $args );
180 217
181 218 if ( $this->debug ) {
182 219 $shortOutput = is_string( $output ) ? substr( $output, 0, 100 ) : json_encode( $output );
@@ -204,8 +241,20 @@
204 241 *
205 242 * @return mixed The result of the snippet execution.
206 243 * @throws Exception If the snippet cannot be executed.
207 244 */
245 + /**
246 + * Declare every active PHP function snippet in the current request so they can call
247 + * one another, without executing any of them. Idempotent and cheap (runs once per
248 + * request). executeSnippet()/executeSnippetByName() already call this internally, so
249 + * you only need it to make function snippets callable from your own custom PHP.
250 + *
251 + * @return void
252 + */
253 + public function loadFunctions() {
254 + $this->core->define_all_functions();
255 + }
256 +
208 257 public function executeSnippetByName( $name, $args = [] ) {
209 258 try {
210 259 if ( empty( $name ) ) {
211 260 throw new Exception( 'The snippet name is required.' );
@@ -238,9 +287,9 @@
238 287 * Create a new snippet.
239 288 *
240 289 * @param string $name Name of the snippet.
241 290 * @param string $code Code of the snippet.
242 - * @param string $scope Scope of the snippet: 'function', 'backend', 'frontend', 'scheduled', 'persistent'.
291 + * @param string $scope Scope of the snippet: 'function', 'backend', 'frontend', 'scheduled', 'persistent', 'content_php', 'content_js'.
243 292 * @param array $options Additional options:
244 293 * - target: 'php' or 'js' (for function snippets)
245 294 * - description: Description of the snippet
246 295 * - args: Arguments for function snippets
@@ -245,8 +294,9 @@
245 294 * - description: Description of the snippet
246 295 * - args: Arguments for function snippets
247 296 * - argsData: Argument data for function snippets (use 'description' for each argument's description)
248 297 * - behavior: 'dynamic' or 'static' (for function snippets)
298 + * - mcp: Expose this function as its own MCP tool in AI Engine (for function snippets)
249 299 * - tags: Array of tags
250 300 * - priority: Execution priority
251 301 * - active: Active status (true/false)
252 302 * - endpoint: REST endpoint
@@ -267,13 +317,13 @@
267 317 if ( empty( $code ) ) {
268 318 throw new Exception( 'The snippet code is required.' );
269 319 }
270 320
271 - $validScopes = ['function', 'backend', 'frontend', 'scheduled', 'persistent'];
321 + $validScopes = ['function', 'backend', 'frontend', 'scheduled', 'persistent', 'content_php', 'content_js'];
272 322 if ( !in_array( $scope, $validScopes ) ) {
273 323 throw new Exception( sprintf( 'Invalid scope. Must be one of: %s', implode( ', ', $validScopes ) ) );
274 324 }
275 -
325 +
276 326 // Extract options with defaults
277 327 $target = $options['target'] ?? 'php';
278 328 $description = $options['description'] ?? '';
279 329 $args = $options['args'] ?? [];
@@ -278,8 +328,9 @@
278 328 $description = $options['description'] ?? '';
279 329 $args = $options['args'] ?? [];
280 330 $argsData = $options['argsData'] ?? [];
281 331 $behavior = $options['behavior'] ?? 'dynamic';
332 + $mcp = $options['mcp'] ?? false;
282 333 $tags = $options['tags'] ?? ['api'];
283 334 $priority = $options['priority'] ?? 10;
284 335 $active = $options['active'] ?? true;
285 336 $endpoint = $options['endpoint'] ?? '';
@@ -323,8 +374,9 @@
323 374 $params['functionTarget'] = $target;
324 375 $params['functionArgs'] = $args;
325 376 $params['functionArgsDict'] = $argsData;
326 377 $params['functionBehavior'] = $behavior;
378 + $params['functionMcp'] = $mcp;
327 379 }
328 380
329 381 // Add scheduled-specific params
330 382 if ( $scope === 'scheduled' ) {
@@ -366,8 +418,9 @@
366 418 * - target: 'php' or 'js' (for function snippets)
367 419 * - args: Arguments (for function snippets)
368 420 * - argsData: Argument data (for function snippets)
369 421 * - behavior: 'dynamic' or 'static' (for function snippets)
422 + * - mcp: Expose this function as its own MCP tool in AI Engine (for function snippets)
370 423 * - intervalHours: Hours (for scheduled snippets)
371 424 * - intervalMinutes: Minutes (for scheduled snippets)
372 425 *
373 426 * @return array The updated snippet data.
@@ -390,9 +443,9 @@
390 443 }
391 444
392 445 // Validate scope if provided
393 446 if ( isset( $params['scope'] ) ) {
394 - $validScopes = ['function', 'backend', 'frontend', 'scheduled', 'persistent'];
447 + $validScopes = ['function', 'backend', 'frontend', 'scheduled', 'persistent', 'content_php', 'content_js'];
395 448 if ( !in_array( $params['scope'], $validScopes ) ) {
396 449 throw new Exception( sprintf( 'Invalid scope. Must be one of: %s', implode( ', ', $validScopes ) ) );
397 450 }
398 451 }
@@ -428,8 +481,12 @@
428 481 $updateParams['functionTarget'] = $params['target'] ?? $snippet['functionTarget'] ?? 'php';
429 482 $updateParams['functionArgs'] = $params['args'] ?? $snippet['functionArgs'] ?? [];
430 483 $updateParams['functionArgsDict'] = $params['argsData'] ?? $snippet['functionArgsDict'] ?? [];
431 484 $updateParams['functionBehavior'] = $params['behavior'] ?? $snippet['functionBehavior'] ?? 'dynamic';
485 + // select_one() doesn't carry function metadata, so read the current MCP flag
486 + // from the stored function to preserve it when the caller doesn't set it.
487 + $existingFn = $this->snippet_module->get_function( $id );
488 + $updateParams['functionMcp'] = $params['mcp'] ?? ( $existingFn['mcp'] ?? false );
432 489 }
433 490
434 491 // Add scheduled-specific params if it's a scheduled snippet
435 492 if ( $scope === 'scheduled' ) {
@@ -718,9 +775,9 @@
718 775
719 776 /**
720 777 * Get snippets by scope.
721 778 *
722 - * @param string $scope The scope to filter by: 'backend', 'frontend', 'function', 'scheduled', 'persistent'.
779 + * @param string $scope The scope to filter by: 'backend', 'frontend', 'function', 'scheduled', 'persistent', 'content_php', 'content_js'.
723 780 * @param array $filters Additional filters: 'active' (bool), 'tags' (array).
724 781 * @return array The list of snippets matching the criteria.
725 782 * @throws Exception If the scope is invalid.
726 783 */