PluginProbe
Code Engine – PHP Snippets, AI Functions & Automation for WordPress / 0.4.2
Code Engine – PHP Snippets, AI Functions & Automation for WordPress v0.4.2
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 +796 -149 0.3.00.4.2 View file →
@@ -1,211 +1,858 @@
1 1 <?php
2 2
3 -class Meow_MWCODE_API
4 -{
5 - private $core = null;
6 - private $snippet = null;
3 +class Meow_MWCODE_API {
4 + public $core;
5 + private $snippet_module;
6 + private $debug = false;
7 7
8 + public function __construct( $core, $snippet_module ) {
9 + $this->core = $core;
10 + $this->snippet_module = $snippet_module;
11 + $this->debug = $this->core->get_option( 'server_debug_mode' );
12 + }
8 13
9 - public function __construct( $core, $snippet ) {
10 - $this->core = $core;
11 - $this->snippet = $snippet;
12 - }
13 -
14 + #region Simple API
15 +
14 16 /**
15 - * Get a function by its ID.
17 + * Get a snippet by its ID.
16 18 *
17 - * The options are used to filter the functions:
19 + * The options are used to filter the snippets:
18 20 * - 'php_ready_args' (bool): If false, the arguments will not be formatted for PHP. (no $ before the names).
19 21 *
20 - * @param $id
21 - * @param array $options
22 + * @param int $id The snippet ID.
23 + * @param array $options Options for filtering.
22 24 *
23 - * @return mixed
25 + * @return array|null The snippet data or null if not found.
26 + * @throws Exception If the snippet cannot be retrieved.
24 27 */
25 - public function get_function( $id, $options = [] ) {
26 - $snippet = $this->snippet->get_function( $id, $options );
27 - return $snippet;
28 + public function getSnippet( $id, $options = [] ) {
29 + try {
30 + if ( empty( $id ) ) {
31 + throw new Exception( 'The snippet ID is required.' );
32 + }
33 +
34 + if ( $this->debug ) {
35 + $this->core->log( sprintf( 'API [GetSnippet]: ID=%d, Options=%s', $id, json_encode( $options ) ) );
36 + }
37 +
38 + // Try to get as function snippet first (for backward compatibility)
39 + $snippet = $this->snippet_module->get_function( $id, $options );
40 +
41 + // If not found as function, get from general snippets
42 + if ( empty( $snippet ) ) {
43 + $snippet = $this->snippet_module->select_one( $id, $options );
44 + if ( empty( $snippet ) ) {
45 + throw new Exception( sprintf( 'Snippet with ID %d not found.', $id ) );
46 + }
47 + }
48 +
49 + return $snippet;
50 + }
51 + catch ( Exception $e ) {
52 + if ( $this->debug ) {
53 + $this->core->log( '⚠️ API Error [GetSnippet]: ' . $e->getMessage() );
54 + }
55 + throw $e;
56 + }
28 57 }
29 58
30 -
31 59 /**
32 - * Get a function by its name.
60 + * Get a snippet by its name.
33 61 *
34 - * The options are used to filter the functions:
62 + * The options are used to filter the snippets:
35 63 * - 'php_ready_args' (bool): If false, the arguments will not be formatted for PHP. (no $ before the names).
36 64 *
37 - * @param $name The name of the function to be retrieved.
38 - * @param array $options
65 + * @param string $name The name of the snippet to be retrieved.
66 + * @param array $options Options for filtering.
39 67 *
40 - * @return mixed
68 + * @return array|null The snippet data or null if not found.
69 + * @throws Exception If the snippet cannot be retrieved.
41 70 */
42 - public function get_function_by_name( $name, $options = [] ) {
43 - $snippet = $this->snippet->get_function_by_name( $name, $options );
44 - return $snippet;
71 + public function getSnippetByName( $name, $options = [] ) {
72 + try {
73 + if ( empty( $name ) ) {
74 + throw new Exception( 'The snippet name is required.' );
75 + }
76 +
77 + if ( $this->debug ) {
78 + $this->core->log( sprintf( 'API [GetSnippetByName]: Name=%s, Options=%s', $name, json_encode( $options ) ) );
79 + }
80 +
81 + $snippet = $this->snippet_module->get_function_by_name( $name, $options );
82 + if ( empty( $snippet ) ) {
83 + throw new Exception( sprintf( 'Snippet with name "%s" not found.', $name ) );
84 + }
85 +
86 + return $snippet;
87 + }
88 + catch ( Exception $e ) {
89 + if ( $this->debug ) {
90 + $this->core->log( '⚠️ API Error [GetSnippetByName]: ' . $e->getMessage() );
91 + }
92 + throw $e;
93 + }
45 94 }
46 95
47 96 /**
48 - * Get all functions.
97 + * Get all snippets.
49 98 *
50 - * @return mixed
51 - *
99 + * @param bool $safe Whether to filter out snippets with invalid names.
100 + * @param string|null $scope Optional scope filter: 'function', 'backend', 'frontend', 'scheduled', 'persistent'.
101 + * @return array The list of snippets.
52 102 */
53 - public function get_functions( $safe = true ) {
54 - $snippets = $this->snippet->get_functions();
103 + public function getSnippets( $safe = true, $scope = null ) {
104 + try {
55 105
56 - if ( $safe ) {
106 + $allSnippets = $this->snippet_module->select( 0, 9999,
107 + [ ['accessor' => 'scope', 'value' => $scope] ]
108 + , [] );
57 109
58 - $snippets = array_filter( $snippets, function( $snippet ) {
59 - $name = $snippet['name'];
60 - if ( !preg_match( '/^[a-zA-Z0-9_-]{1,64}$/', $name ) ) {
61 - return false;
62 - }
110 + $snippets = $allSnippets['data'] ?? [];
111 +
112 +
113 + if ( $safe ) {
63 114
64 - return true;
65 - } );
115 + $snippets = array_filter( $snippets, function( $snippet ) {
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;
133 + }
134 +
135 + }
136 +
137 + return true;
138 + } );
139 + }
66 140
141 + return array_values( $snippets ); // Reset array keys
67 142 }
68 -
69 - return $snippets;
143 + catch ( Exception $e ) {
144 + if ( $this->debug ) {
145 + $this->core->log( '⚠️ API Error [GetSnippets]: ' . $e->getMessage() );
146 + }
147 + throw $e;
148 + }
70 149 }
150 +
151 + /**
152 + * Backward compatibility wrapper for getSnippets().
153 + * @deprecated Use getSnippets() instead.
154 + *
155 + * @param bool $safe Whether to filter out snippets with invalid names.
156 + * @return array The list of function snippets only.
157 + */
158 + public function get_functions( $safe = true ) {
159 + $this->core->log( '⚠️ API Warning: get_functions() is deprecated. Please use getSnippets() instead.' );
160 + // Return only function snippets for backward compatibility
161 + return $this->getSnippets( $safe, 'function' );
162 + }
71 163
72 -
73 164 /**
74 - * Execute a function by its ID.
165 + * Execute a snippet by its ID.
75 166 * The arguments should be an associative array with the argument names as keys.
76 - * Example: [ "$city" => " 'Tokyo' ", "$date" => "1999" ]
167 + * Example: [ "$city" => "'Tokyo'", "$date" => "1999" ]
77 168 *
78 - * @param $id
79 - * @param $args
169 + * @param int $id The snippet ID.
170 + * @param array $args The arguments to pass to the snippet.
80 171 *
81 - * @return mixed
172 + * @return mixed The result of the snippet execution.
173 + * @throws Exception If the snippet cannot be executed.
82 174 */
83 - public function execute_function( $id, $args ) {
84 - $output = $this->core->run_snippet( $id, $args );
85 - return $output;
86 - }
175 + public function executeSnippet( $id, $args = [], $reply = null ) {
176 + try {
177 + if ( empty( $id ) ) {
178 + throw new Exception( 'The snippet ID is required.' );
179 + }
180 +
181 + if ( $this->debug ) {
182 + $this->core->log( sprintf( 'API [ExecuteSnippet]: ID=%d, Args=%s', $id, json_encode( $args ) ) );
183 + }
184 +
185 + // Verify the snippet exists
186 + $snippet = $this->snippet_module->get_function( $id );
187 + if ( empty( $snippet ) ) {
188 + throw new Exception( sprintf( 'Snippet with ID %d not found.', $id ) );
189 + }
87 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';
88 198
89 - /**
90 - * Create a new callable snippet ( Function ).
91 - *
92 - * @param string $name Name of the function. This should be the name of the function declaration, like 'get_weather'.
93 - * @param string $target Target of the snippet. This should be either 'php' or 'js'. This will be used to determine the type of the function.
94 - * @param string $code Code of the snippet. This should be either a PHP or a JS function. No code outside of the function itself should be included.
95 - * @param string $description Description of the snippet. This will be displayed in Code Engine and used for Function Calling.
96 - * @param array $args Arguments of the function. This array should have the full name of each argument, like ['$city', '$date']. The '$' is required if the function is PHP.
97 - * @param array $args_data Data of the arguments. This array should have the name of each argument as key and an array with the type, description and default value. Example: [ '$city' => ['type' => 'string', 'desc' => 'City name', 'default' => 'Tokyo' ] ]. This will be used for Function Calling.
98 - * @param string $behavior Behavior of the function. This should be either 'dynamic' or 'static'. This will be used for Function Calling.
99 - *
100 - */
101 - public function create_function( $name, $target, $code, $description, $args, $args_data, $behavior ) {
102 199
103 - $temp_name = 'mwcode_' . time();
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';
104 203
105 - $params = [
106 - // Predefined values
107 - 'id' => null,
108 - 'active' => 1,
109 - 'priority' => 10,
110 - 'tags' => ['api'],
111 - 'endpoint' => '',
112 - 'scope' => 'function',
204 + $array_query['instructions'] = $query->instructions ?? 'No Instructions in Query';
205 + $array_query['context'] = $query->context ?? 'No Context in Query';
113 206
114 - // Custom values
115 - 'name' => $name ?? $temp_name,
116 - 'code' => $code ?? "function $temp_name() { return 'Hello World'; }",
117 - 'description' => $description ?? '',
207 + $array_query['messages'] = $query->messages ? json_encode( $query->messages ) : 'No Messages in Query';
208 + $array_query['message'] = $query->message ?? 'No Message in Query';
118 209
119 - 'functionName' => $name ?? $temp_name,
120 - 'functionTarget' => $target ?? 'php',
121 - 'functionArgs' => $args ?? [],
122 - 'functionArgsDict' => $args_data ?? [],
123 - 'functionBehavior' => $behavior ?? 'dynamic',
124 - ];
210 + $array_query['model'] = $query->model ?? 'No Model in Query';
211 + $array_query['feature'] = $query->feature ?? 'No Feature in Query';
212 + }
125 213
126 - $res = $this->core->add_snippet( $params );
214 + $args['__mwai_query'] = $array_query;
127 215
128 - return $res;
216 + $output = $this->core->run_snippet( $id, $args );
217 +
218 + if ( $this->debug ) {
219 + $shortOutput = is_string( $output ) ? substr( $output, 0, 100 ) : json_encode( $output );
220 + $this->core->log( sprintf( 'API [ExecuteSnippet]: Success, Output=%s%s',
221 + $shortOutput,
222 + strlen( $shortOutput ) > 100 ? '...' : ''
223 + ) );
224 + }
225 +
226 + return $output;
227 + }
228 + catch ( Exception $e ) {
229 + if ( $this->debug ) {
230 + $this->core->log( '⚠️ API Error [ExecuteSnippet]: ' . $e->getMessage() );
231 + }
232 + throw $e;
233 + }
129 234 }
235 +
236 + /**
237 + * Execute a snippet by its name.
238 + *
239 + * @param string $name The snippet name.
240 + * @param array $args The arguments to pass to the snippet.
241 + *
242 + * @return mixed The result of the snippet execution.
243 + * @throws Exception If the snippet cannot be executed.
244 + */
245 + public function executeSnippetByName( $name, $args = [] ) {
246 + try {
247 + if ( empty( $name ) ) {
248 + throw new Exception( 'The snippet name is required.' );
249 + }
250 +
251 + if ( $this->debug ) {
252 + $this->core->log( sprintf( 'API [ExecuteSnippetByName]: Name=%s, Args=%s', $name, json_encode( $args ) ) );
253 + }
254 +
255 + // Get the snippet by name to find its ID
256 + $snippet = $this->snippet_module->get_function_by_name( $name );
257 + if ( empty( $snippet ) || empty( $snippet['snippetId'] ) ) {
258 + throw new Exception( sprintf( 'Snippet with name "%s" not found.', $name ) );
259 + }
260 +
261 + return $this->executeSnippet( $snippet['snippetId'], $args );
262 + }
263 + catch ( Exception $e ) {
264 + if ( $this->debug ) {
265 + $this->core->log( '⚠️ API Error [ExecuteSnippetByName]: ' . $e->getMessage() );
266 + }
267 + throw $e;
268 + }
269 + }
270 + #endregion
130 271
131 -
272 + #region Standard API
273 +
132 274 /**
133 - * Update a function by its name. If the function does not exist, it will return false. The parameters are the same as create_function, but except the name the rest are optional. If not specified, the current values will be used.
275 + * Create a new snippet.
134 276 *
135 - * @param string $name Name of the function. This should be the name of the function declaration, like 'get_weather'.
136 - * @param string $target Target of the snippet. This should be either 'php' or 'js'. This will be used to determine the type of the function.
137 - * @param string $code Code of the snippet. This should be either a PHP or a JS function. No code outside of the function itself should be included.
138 - * @param string $description Description of the snippet. This will be displayed in Code Engine and used for Function Calling.
139 - * @param array $args Arguments of the function. This array should have the full name of each argument, like ['$city', '$date']. The '$' is required if the function is PHP.
140 - * @param array $args_data Data of the arguments. This array should have the name of each argument as key and an array with the type, description and default value. Example: [ '$city' => ['type' => 'string', 'desc' => 'City name', 'default' => 'Tokyo' ] ]. This will be used for Function Calling.
141 - * @param string $behavior Behavior of the function. This should be either 'dynamic' or 'static'. This will be used for Function Calling.
277 + * @param string $name Name of the snippet.
278 + * @param string $code Code of the snippet.
279 + * @param string $scope Scope of the snippet: 'function', 'backend', 'frontend', 'scheduled', 'persistent'.
280 + * @param array $options Additional options:
281 + * - target: 'php' or 'js' (for function snippets)
282 + * - description: Description of the snippet
283 + * - args: Arguments for function snippets
284 + * - argsData: Argument data for function snippets (use 'description' for each argument's description)
285 + * - behavior: 'dynamic' or 'static' (for function snippets)
286 + * - tags: Array of tags
287 + * - priority: Execution priority
288 + * - active: Active status (true/false)
289 + * - endpoint: REST endpoint
290 + * - method: HTTP method (GET/POST)
291 + * - intervalHours: Hours for scheduled snippets
292 + * - intervalMinutes: Minutes for scheduled snippets
293 + *
294 + * @return array The created snippet data.
295 + * @throws Exception If the snippet cannot be created.
142 296 */
143 - public function update_function( $name, $target, $code, $description, $args, $args_data, $behavior ) {
144 - $snippet = $this->snippet->get_function_by_name( $name );
145 - if ( !$snippet ) { return false; }
297 + public function createSnippet( $name, $code, $scope = 'function', $options = [] ) {
146 298
147 - $params = [
148 - // Predefined values
149 - 'id' => $snippet['snippetId'],
150 - 'active' => 1,
151 - 'priority' => 10,
152 - 'tags' => ['api'],
153 - 'endpoint' => '',
154 - 'scope' => 'function',
299 + try {
300 + if ( empty( $name ) ) {
301 + throw new Exception( 'The snippet name is required.' );
302 + }
303 +
304 + if ( empty( $code ) ) {
305 + throw new Exception( 'The snippet code is required.' );
306 + }
307 +
308 + $validScopes = ['function', 'backend', 'frontend', 'scheduled', 'persistent'];
309 + if ( !in_array( $scope, $validScopes ) ) {
310 + throw new Exception( sprintf( 'Invalid scope. Must be one of: %s', implode( ', ', $validScopes ) ) );
311 + }
312 +
313 + // Extract options with defaults
314 + $target = $options['target'] ?? 'php';
315 + $description = $options['description'] ?? '';
316 + $args = $options['args'] ?? [];
317 + $argsData = $options['argsData'] ?? [];
318 + $behavior = $options['behavior'] ?? 'dynamic';
319 + $tags = $options['tags'] ?? ['api'];
320 + $priority = $options['priority'] ?? 10;
321 + $active = $options['active'] ?? true;
322 + $endpoint = $options['endpoint'] ?? '';
323 + $method = $options['method'] ?? 'POST';
324 + $intervalHours = $options['intervalHours'] ?? 0;
325 + $intervalMinutes = $options['intervalMinutes'] ?? 0;
326 +
327 + // Validate function-specific options
328 + if ( $scope === 'function' ) {
329 + if ( !in_array( $target, ['php', 'js'] ) ) {
330 + throw new Exception( 'The target must be either "php" or "js" for function snippets.' );
331 + }
332 + if ( !in_array( $behavior, ['dynamic', 'static'] ) ) {
333 + throw new Exception( 'The behavior must be either "dynamic" or "static" for function snippets.' );
334 + }
335 + }
336 +
337 + if ( $this->debug ) {
338 + $shortCode = substr( $code, 0, 100 );
339 + $this->core->log( sprintf( 'API [CreateSnippet]: Name=%s, Scope=%s, Options=%s',
340 + $name, $scope, json_encode( $options ) ) );
341 + }
342 +
343 + $params = [
344 + // Core values
345 + 'id' => null,
346 + 'name' => $name,
347 + 'code' => $code,
348 + 'scope' => $scope,
349 + 'active' => $active ? 1 : 0,
350 + 'priority' => $priority,
351 + 'tags' => $tags,
352 + 'description' => $description,
353 + 'endpoint' => $endpoint,
354 + 'method' => $method,
355 + ];
356 +
357 + // Add function-specific params
358 + if ( $scope === 'function' ) {
359 + $params['functionName'] = $name;
360 + $params['functionTarget'] = $target;
361 + $params['functionArgs'] = $args;
362 + $params['functionArgsDict'] = $argsData;
363 + $params['functionBehavior'] = $behavior;
364 + }
365 +
366 + // Add scheduled-specific params
367 + if ( $scope === 'scheduled' ) {
368 + $params['intervalHours'] = $intervalHours;
369 + $params['intervalMinutes'] = $intervalMinutes;
370 + }
371 +
372 + $result = $this->core->add_snippet( $params );
373 +
374 + if ( $this->debug ) {
375 + $this->core->log( sprintf( 'API [CreateSnippet]: Success, ID=%d', $result['id'] ?? 0 ) );
376 + }
377 +
378 + return $result;
379 + }
380 + catch ( Exception $e ) {
381 + if ( $this->debug ) {
382 + $this->core->log( '⚠️ API Error [CreateSnippet]: ' . $e->getMessage() );
383 + }
384 + throw $e;
385 + }
386 + }
155 387
156 - // Custom values
157 - 'name' => $name ?? $snippet['name'],
158 - 'code' => $code ?? $snippet['code'],
159 - 'description' => $description ?? '',
160 -
161 - 'functionName' => $name ?? $snippet['functionName'],
162 - 'functionTarget' => $target ?? $snippet['functionTarget'],
163 - 'functionArgs' => $args ?? $snippet['functionArgs'],
164 - 'functionArgsDict' => $args_data ?? $snippet['functionArgsDict'],
165 - 'functionBehavior' => $behavior ?? $snippet['functionBehavior'],
166 - ];
167 -
168 -
169 - $res = $this->core->add_snippet( $params );
170 -
171 - return $res;
388 + /**
389 + * Update a snippet by its ID.
390 + * All parameters except ID are optional. If not specified, the current values will be used.
391 + *
392 + * @param int $id ID of the snippet to update.
393 + * @param array $params Parameters to update. Can include:
394 + * - name: Snippet name
395 + * - code: Snippet code
396 + * - scope: Snippet scope
397 + * - description: Description
398 + * - active: Active status
399 + * - priority: Execution priority
400 + * - tags: Array of tags
401 + * - endpoint: REST endpoint
402 + * - method: HTTP method
403 + * - target: 'php' or 'js' (for function snippets)
404 + * - args: Arguments (for function snippets)
405 + * - argsData: Argument data (for function snippets)
406 + * - behavior: 'dynamic' or 'static' (for function snippets)
407 + * - intervalHours: Hours (for scheduled snippets)
408 + * - intervalMinutes: Minutes (for scheduled snippets)
409 + *
410 + * @return array The updated snippet data.
411 + * @throws Exception If the snippet cannot be updated.
412 + */
413 + public function updateSnippet( $id, $params = [] ) {
414 + try {
415 + if ( empty( $id ) ) {
416 + throw new Exception( 'The snippet ID is required.' );
417 + }
418 +
419 + if ( $this->debug ) {
420 + $this->core->log( sprintf( 'API [UpdateSnippet]: ID=%d, Params=%s', $id, json_encode( $params ) ) );
421 + }
422 +
423 + // Get existing snippet
424 + $snippet = $this->snippet_module->select_one( $id );
425 + if ( empty( $snippet ) ) {
426 + throw new Exception( sprintf( 'Snippet with ID %d not found.', $id ) );
427 + }
428 +
429 + // Validate scope if provided
430 + if ( isset( $params['scope'] ) ) {
431 + $validScopes = ['function', 'backend', 'frontend', 'scheduled', 'persistent'];
432 + if ( !in_array( $params['scope'], $validScopes ) ) {
433 + throw new Exception( sprintf( 'Invalid scope. Must be one of: %s', implode( ', ', $validScopes ) ) );
434 + }
435 + }
436 +
437 + // Validate function-specific parameters if provided
438 + $scope = $params['scope'] ?? $snippet['scope'];
439 + if ( $scope === 'function' ) {
440 + if ( isset( $params['target'] ) && !in_array( $params['target'], ['php', 'js'] ) ) {
441 + throw new Exception( 'The target must be either "php" or "js" for function snippets.' );
442 + }
443 + if ( isset( $params['behavior'] ) && !in_array( $params['behavior'], ['dynamic', 'static'] ) ) {
444 + throw new Exception( 'The behavior must be either "dynamic" or "static" for function snippets.' );
445 + }
446 + }
447 +
448 + // Build update params - merge with existing values
449 + $updateParams = [
450 + 'id' => $id,
451 + 'name' => $params['name'] ?? $snippet['name'],
452 + 'code' => $params['code'] ?? $snippet['code'],
453 + 'scope' => $scope,
454 + 'active' => isset( $params['active'] ) ? ( $params['active'] ? 1 : 0 ) : $snippet['active'],
455 + 'priority' => $params['priority'] ?? $snippet['priority'],
456 + 'tags' => $params['tags'] ?? $snippet['tags'],
457 + 'description' => $params['description'] ?? $snippet['description'] ?? '',
458 + 'endpoint' => $params['endpoint'] ?? $snippet['endpoint'] ?? '',
459 + 'method' => $params['method'] ?? $snippet['method'] ?? 'POST',
460 + ];
461 +
462 + // Add function-specific params if it's a function snippet
463 + if ( $scope === 'function' ) {
464 + $updateParams['functionName'] = $params['name'] ?? $snippet['name'];
465 + $updateParams['functionTarget'] = $params['target'] ?? $snippet['functionTarget'] ?? 'php';
466 + $updateParams['functionArgs'] = $params['args'] ?? $snippet['functionArgs'] ?? [];
467 + $updateParams['functionArgsDict'] = $params['argsData'] ?? $snippet['functionArgsDict'] ?? [];
468 + $updateParams['functionBehavior'] = $params['behavior'] ?? $snippet['functionBehavior'] ?? 'dynamic';
469 + }
470 +
471 + // Add scheduled-specific params if it's a scheduled snippet
472 + if ( $scope === 'scheduled' ) {
473 + $updateParams['intervalHours'] = $params['intervalHours'] ?? $snippet['intervalHours'] ?? 0;
474 + $updateParams['intervalMinutes'] = $params['intervalMinutes'] ?? $snippet['intervalMinutes'] ?? 0;
475 + }
476 +
477 + $result = $this->core->add_snippet( $updateParams );
478 +
479 + if ( $this->debug ) {
480 + $this->core->log( sprintf( 'API [UpdateSnippet]: Success, ID=%d', $result['id'] ?? $id ) );
481 + }
482 +
483 + return $result;
484 + }
485 + catch ( Exception $e ) {
486 + if ( $this->debug ) {
487 + $this->core->log( '⚠️ API Error [UpdateSnippet]: ' . $e->getMessage() );
488 + }
489 + throw $e;
490 + }
172 491 }
173 492
174 493 /**
175 - * Delete a function by its ID.
494 + * Delete a snippet by its ID.
176 495 *
177 - * @param int $id Function ID
178 - * @return mixed
496 + * @param int $id Snippet ID.
497 + * @return bool True if the snippet was deleted successfully.
498 + * @throws Exception If the snippet cannot be deleted.
179 499 */
180 - public function delete_function( $id ) {
181 - $params = [
182 - 'id' => $id,
183 - ];
184 -
185 - $this->snippet->delete_function_snippet( $params );
186 - $result = $this->snippet->delete( $params );
187 -
188 - return $result;
500 + public function deleteSnippet( $id ) {
501 + try {
502 + if ( empty( $id ) ) {
503 + throw new Exception( 'The snippet ID is required.' );
504 + }
505 +
506 + if ( $this->debug ) {
507 + $this->core->log( sprintf( 'API [DeleteSnippet]: ID=%d', $id ) );
508 + }
509 +
510 + // Verify the snippet exists
511 + $snippet = $this->snippet_module->select_one( $id );
512 + if ( empty( $snippet ) ) {
513 + throw new Exception( sprintf( 'Snippet with ID %d not found.', $id ) );
514 + }
515 +
516 + $params = [ 'id' => $id ];
517 +
518 + // Delete function snippet data if it's a function
519 + if ( $snippet['scope'] === 'function' ) {
520 + $this->snippet_module->delete_function_snippet( $params );
521 + }
522 +
523 + // Delete scheduled snippet data if it's scheduled
524 + if ( $snippet['scope'] === 'scheduled' ) {
525 + $this->snippet_module->delete_interval_snippet( $params );
526 + }
527 +
528 + $result = $this->snippet_module->delete( $params );
529 +
530 + if ( $this->debug ) {
531 + $this->core->log( sprintf( 'API [DeleteSnippet]: Success, ID=%d', $id ) );
532 + }
533 +
534 + return !empty( $result );
535 + }
536 + catch ( Exception $e ) {
537 + if ( $this->debug ) {
538 + $this->core->log( '⚠️ API Error [DeleteSnippet]: ' . $e->getMessage() );
539 + }
540 + throw $e;
541 + }
189 542 }
190 543
191 544 /**
192 - * Delete a function by its name.
545 + * Delete a snippet by its name.
193 546 *
194 - * @param string $name Function name
195 - * @return mixed
547 + * @param string $name Snippet name.
548 + * @return bool True if the snippet was deleted successfully.
549 + * @throws Exception If the snippet cannot be deleted.
196 550 */
197 - public function delete_function_by_name( $name ) {
198 - $snippet = $this->snippet->get_function_by_name( $name );
199 - if ( !$snippet ) { return false; }
200 -
201 - $params = [
202 - 'id' => $snippet['snippetId'],
203 - ];
204 -
205 - $this->snippet->delete_function_snippet( $params );
206 - $result = $this->snippet->delete( $params );
207 -
208 - return $result;
551 + public function deleteSnippetByName( $name ) {
552 + try {
553 + if ( empty( $name ) ) {
554 + throw new Exception( 'The snippet name is required.' );
555 + }
556 +
557 + if ( $this->debug ) {
558 + $this->core->log( sprintf( 'API [DeleteSnippetByName]: Name=%s', $name ) );
559 + }
560 +
561 + // Try to find as function first
562 + $snippet = $this->snippet_module->get_function_by_name( $name );
563 + if ( !empty( $snippet ) && !empty( $snippet['snippetId'] ) ) {
564 + return $this->deleteSnippet( $snippet['snippetId'] );
565 + }
566 +
567 + // If not found as function, search in all snippets
568 + $allSnippets = $this->snippet_module->select( 0, 9999, [], [] );
569 + foreach ( $allSnippets['data'] as $s ) {
570 + if ( $s['name'] === $name ) {
571 + return $this->deleteSnippet( $s['id'] );
572 + }
573 + }
574 +
575 + throw new Exception( sprintf( 'Snippet with name "%s" not found.', $name ) );
576 + }
577 + catch ( Exception $e ) {
578 + if ( $this->debug ) {
579 + $this->core->log( '⚠️ API Error [DeleteSnippetByName]: ' . $e->getMessage() );
580 + }
581 + throw $e;
582 + }
209 583 }
210 -
584 + #endregion
585 +
586 + #region Standard API (No REST API)
587 +
588 + /**
589 + * Check if a snippet exists by ID.
590 + *
591 + * @param int $id The snippet ID.
592 + * @return bool True if the snippet exists.
593 + */
594 + public function snippetExists( $id ) {
595 + try {
596 + if ( empty( $id ) ) {
597 + return false;
598 + }
599 +
600 + $snippet = $this->snippet_module->select_one( $id );
601 + return !empty( $snippet );
602 + }
603 + catch ( Exception $e ) {
604 + if ( $this->debug ) {
605 + $this->core->log( '⚠️ API Error [SnippetExists]: ' . $e->getMessage() );
606 + }
607 + return false;
608 + }
609 + }
610 +
611 + /**
612 + * Check if a snippet exists by name.
613 + *
614 + * @param string $name The snippet name.
615 + * @return bool True if the snippet exists.
616 + */
617 + public function snippetExistsByName( $name ) {
618 + try {
619 + if ( empty( $name ) ) {
620 + return false;
621 + }
622 +
623 + // Check in functions first
624 + $snippet = $this->snippet_module->get_function_by_name( $name );
625 + if ( !empty( $snippet ) ) {
626 + return true;
627 + }
628 +
629 + // Check in all snippets
630 + $allSnippets = $this->snippet_module->select( 0, 9999, [], [] );
631 + foreach ( $allSnippets['data'] as $s ) {
632 + if ( $s['name'] === $name ) {
633 + return true;
634 + }
635 + }
636 +
637 + return false;
638 + }
639 + catch ( Exception $e ) {
640 + if ( $this->debug ) {
641 + $this->core->log( '⚠️ API Error [SnippetExistsByName]: ' . $e->getMessage() );
642 + }
643 + return false;
644 + }
645 + }
646 +
647 + /**
648 + * Validates snippet code syntax.
649 + *
650 + * @param string $code The snippet code to validate.
651 + * @param string $target The target language ('php' or 'js').
652 + * @return array ['valid' => bool, 'error' => string|null]
653 + */
654 + public function validateSnippetCode( $code, $target = 'php' ) {
655 + try {
656 + if ( empty( $code ) ) {
657 + return [ 'valid' => false, 'error' => 'Code is empty.' ];
658 + }
659 +
660 + if ( !in_array( $target, ['php', 'js'] ) ) {
661 + return [ 'valid' => false, 'error' => 'Invalid target language.' ];
662 + }
663 +
664 + if ( $target === 'php' ) {
665 + // Use the core's validate_php_code method if available
666 + if ( method_exists( $this->core, 'validate_php_code' ) ) {
667 + $validation = $this->core->validate_php_code( $code );
668 + return [
669 + 'valid' => $validation['valid'] ?? false,
670 + 'error' => $validation['error'] ?? null
671 + ];
672 + }
673 + }
674 +
675 + // Basic validation if no specific validator available
676 + return [ 'valid' => true, 'error' => null ];
677 + }
678 + catch ( Exception $e ) {
679 + return [ 'valid' => false, 'error' => $e->getMessage() ];
680 + }
681 + }
682 + #endregion
683 +
684 + #region Snippet Management
685 +
686 + /**
687 + * Activate a snippet by its ID.
688 + *
689 + * @param int $id The snippet ID.
690 + * @return bool True if activated successfully.
691 + * @throws Exception If the snippet cannot be activated.
692 + */
693 + public function activateSnippet( $id ) {
694 + try {
695 + if ( empty( $id ) ) {
696 + throw new Exception( 'The snippet ID is required.' );
697 + }
698 +
699 + if ( $this->debug ) {
700 + $this->core->log( sprintf( 'API [ActivateSnippet]: ID=%d', $id ) );
701 + }
702 +
703 + // Get the snippet
704 + $snippet = $this->snippet_module->select_one( $id );
705 + if ( empty( $snippet ) ) {
706 + throw new Exception( sprintf( 'Snippet with ID %d not found.', $id ) );
707 + }
708 +
709 + // Update only the active status
710 + $result = $this->updateSnippet( $id, [ 'active' => true ] );
711 + return !empty( $result );
712 + }
713 + catch ( Exception $e ) {
714 + if ( $this->debug ) {
715 + $this->core->log( '⚠️ API Error [ActivateSnippet]: ' . $e->getMessage() );
716 + }
717 + throw $e;
718 + }
719 + }
720 +
721 + /**
722 + * Deactivate a snippet by its ID.
723 + *
724 + * @param int $id The snippet ID.
725 + * @return bool True if deactivated successfully.
726 + * @throws Exception If the snippet cannot be deactivated.
727 + */
728 + public function deactivateSnippet( $id ) {
729 + try {
730 + if ( empty( $id ) ) {
731 + throw new Exception( 'The snippet ID is required.' );
732 + }
733 +
734 + if ( $this->debug ) {
735 + $this->core->log( sprintf( 'API [DeactivateSnippet]: ID=%d', $id ) );
736 + }
737 +
738 + // Get the snippet
739 + $snippet = $this->snippet_module->select_one( $id );
740 + if ( empty( $snippet ) ) {
741 + throw new Exception( sprintf( 'Snippet with ID %d not found.', $id ) );
742 + }
743 +
744 + // Update only the active status
745 + $result = $this->updateSnippet( $id, [ 'active' => false ] );
746 + return !empty( $result );
747 + }
748 + catch ( Exception $e ) {
749 + if ( $this->debug ) {
750 + $this->core->log( '⚠️ API Error [DeactivateSnippet]: ' . $e->getMessage() );
751 + }
752 + throw $e;
753 + }
754 + }
755 +
756 + /**
757 + * Get snippets by scope.
758 + *
759 + * @param string $scope The scope to filter by: 'backend', 'frontend', 'function', 'scheduled', 'persistent'.
760 + * @param array $filters Additional filters: 'active' (bool), 'tags' (array).
761 + * @return array The list of snippets matching the criteria.
762 + * @throws Exception If the scope is invalid.
763 + */
764 + public function getSnippetsByScope( $scope, $filters = [] ) {
765 + try {
766 + $validScopes = ['function', 'backend', 'frontend', 'scheduled', 'persistent', 'content_js', 'content_php'];
767 + if ( !in_array( $scope, $validScopes ) ) {
768 + throw new Exception( sprintf( 'Invalid scope. Must be one of: %s', implode( ', ', $validScopes ) ) );
769 + }
770 +
771 + if ( $this->debug ) {
772 + $this->core->log( sprintf( 'API [GetSnippetsByScope]: Scope=%s, Filters=%s', $scope, json_encode( $filters ) ) );
773 + }
774 +
775 + // For function scope, we can use the existing get_functions method
776 + if ( $scope === 'function' && empty( $filters ) ) {
777 + return $this->snippet_module->get_functions();
778 + }
779 +
780 + // For other scopes or with filters, we need to query all snippets
781 + $allSnippets = $this->snippet_module->select( 0, 9999, [], [] );
782 + $filtered = [];
783 +
784 + foreach ( $allSnippets['data'] as $snippet ) {
785 + // Filter by scope
786 + if ( $snippet['scope'] !== $scope ) {
787 + continue;
788 + }
789 +
790 + // Apply additional filters
791 + if ( isset( $filters['active'] ) && $snippet['active'] != $filters['active'] ) {
792 + continue;
793 + }
794 +
795 + if ( isset( $filters['tags'] ) && is_array( $filters['tags'] ) ) {
796 + $snippetTags = is_array( $snippet['tags'] ) ? $snippet['tags'] : [];
797 + $hasAllTags = true;
798 + foreach ( $filters['tags'] as $tag ) {
799 + if ( !in_array( $tag, $snippetTags ) ) {
800 + $hasAllTags = false;
801 + break;
802 + }
803 + }
804 + if ( !$hasAllTags ) {
805 + continue;
806 + }
807 + }
808 +
809 + $filtered[] = $snippet;
810 + }
811 +
812 + return $filtered;
813 + }
814 + catch ( Exception $e ) {
815 + if ( $this->debug ) {
816 + $this->core->log( '⚠️ API Error [GetSnippetsByScope]: ' . $e->getMessage() );
817 + }
818 + throw $e;
819 + }
820 + }
821 +
822 + /**
823 + * Get all active snippets.
824 + *
825 + * @param string|null $scope Optional scope filter.
826 + * @return array The list of active snippets.
827 + */
828 + public function getActiveSnippets( $scope = null ) {
829 + try {
830 + if ( $this->debug ) {
831 + $this->core->log( sprintf( 'API [GetActiveSnippets]: Scope=%s', $scope ?? 'all' ) );
832 + }
833 +
834 + if ( $scope ) {
835 + return $this->getSnippetsByScope( $scope, [ 'active' => true ] );
836 + }
837 +
838 + // Get all active snippets
839 + $allSnippets = $this->snippet_module->select( 0, 9999, [], [] );
840 + $active = [];
841 +
842 + foreach ( $allSnippets['data'] as $snippet ) {
843 + if ( $snippet['active'] ) {
844 + $active[] = $snippet;
845 + }
846 + }
847 +
848 + return $active;
849 + }
850 + catch ( Exception $e ) {
851 + if ( $this->debug ) {
852 + $this->core->log( '⚠️ API Error [GetActiveSnippets]: ' . $e->getMessage() );
853 + }
854 + throw $e;
855 + }
856 + }
857 + #endregion
211 858 }