PluginProbe
Code Engine – PHP Snippets, AI Functions & Automation for WordPress / 0.4.7
Code Engine – PHP Snippets, AI Functions & Automation for WordPress v0.4.7
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
code-engine / classes / api.php

api.php in Code Engine – PHP Snippets, AI Functions & Automation for WordPress 0.4.7, at classes/api.php

859 lines 28.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class Meow_MWCODE_API {
4 public $core;
5 private $snippet_module;
6 private $debug = false;
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 }
13
14 #region Simple API
15
16 /**
17 * Get a snippet by its ID.
18 *
19 * The options are used to filter the snippets:
20 * - 'php_ready_args' (bool): If false, the arguments will not be formatted for PHP. (no $ before the names).
21 *
22 * @param int $id The snippet ID.
23 * @param array $options Options for filtering.
24 *
25 * @return array|null The snippet data or null if not found.
26 * @throws Exception If the snippet cannot be retrieved.
27 */
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 }
57 }
58
59 /**
60 * Get a snippet by its name.
61 *
62 * The options are used to filter the snippets:
63 * - 'php_ready_args' (bool): If false, the arguments will not be formatted for PHP. (no $ before the names).
64 *
65 * @param string $name The name of the snippet to be retrieved.
66 * @param array $options Options for filtering.
67 *
68 * @return array|null The snippet data or null if not found.
69 * @throws Exception If the snippet cannot be retrieved.
70 */
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 }
94 }
95
96 /**
97 * Get all snippets.
98 *
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.
102 */
103 public function getSnippets( $safe = true, $scope = null ) {
104 try {
105
106 $allSnippets = $this->snippet_module->select( 0, 9999,
107 [ ['accessor' => 'scope', 'value' => $scope] ]
108 , [] );
109
110 $snippets = $allSnippets['data'] ?? [];
111
112
113 if ( $safe ) {
114
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 }
140
141 return array_values( $snippets ); // Reset array keys
142 }
143 catch ( Exception $e ) {
144 if ( $this->debug ) {
145 $this->core->log( '⚠️ API Error [GetSnippets]: ' . $e->getMessage() );
146 }
147 throw $e;
148 }
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 }
163
164 /**
165 * Execute a snippet by its ID.
166 * The arguments should be an associative array with the argument names as keys.
167 * Example: [ "$city" => "'Tokyo'", "$date" => "1999" ]
168 *
169 * @param int $id The snippet ID.
170 * @param array $args The arguments to pass to the snippet.
171 *
172 * @return mixed The result of the snippet execution.
173 * @throws Exception If the snippet cannot be executed.
174 */
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 }
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
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 }
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
271
272 #region Standard API
273
274 /**
275 * Create a new snippet.
276 *
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.
296 */
297 public function createSnippet( $name, $code, $scope = 'function', $options = [] ) {
298
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 }
387
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 }
491 }
492
493 /**
494 * Delete a snippet by its ID.
495 *
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.
499 */
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 }
542 }
543
544 /**
545 * Delete a snippet by its name.
546 *
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.
550 */
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 }
583 }
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
858 }
859