PluginProbe
Code Engine – PHP Snippets, AI Functions & Automation for WordPress / 0.3.4
Code Engine – PHP Snippets, AI Functions & Automation for WordPress v0.3.4
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.3.4, at classes/api.php

834 lines 26.9 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 = [] ) {
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 $output = $this->core->run_snippet( $id, $args );
192
193 if ( $this->debug ) {
194 $shortOutput = is_string( $output ) ? substr( $output, 0, 100 ) : json_encode( $output );
195 $this->core->log( sprintf( 'API [ExecuteSnippet]: Success, Output=%s%s',
196 $shortOutput,
197 strlen( $shortOutput ) > 100 ? '...' : ''
198 ) );
199 }
200
201 return $output;
202 }
203 catch ( Exception $e ) {
204 if ( $this->debug ) {
205 $this->core->log( '⚠️ API Error [ExecuteSnippet]: ' . $e->getMessage() );
206 }
207 throw $e;
208 }
209 }
210
211 /**
212 * Execute a snippet by its name.
213 *
214 * @param string $name The snippet name.
215 * @param array $args The arguments to pass to the snippet.
216 *
217 * @return mixed The result of the snippet execution.
218 * @throws Exception If the snippet cannot be executed.
219 */
220 public function executeSnippetByName( $name, $args = [] ) {
221 try {
222 if ( empty( $name ) ) {
223 throw new Exception( 'The snippet name is required.' );
224 }
225
226 if ( $this->debug ) {
227 $this->core->log( sprintf( 'API [ExecuteSnippetByName]: Name=%s, Args=%s', $name, json_encode( $args ) ) );
228 }
229
230 // Get the snippet by name to find its ID
231 $snippet = $this->snippet_module->get_function_by_name( $name );
232 if ( empty( $snippet ) || empty( $snippet['snippetId'] ) ) {
233 throw new Exception( sprintf( 'Snippet with name "%s" not found.', $name ) );
234 }
235
236 return $this->executeSnippet( $snippet['snippetId'], $args );
237 }
238 catch ( Exception $e ) {
239 if ( $this->debug ) {
240 $this->core->log( '⚠️ API Error [ExecuteSnippetByName]: ' . $e->getMessage() );
241 }
242 throw $e;
243 }
244 }
245 #endregion
246
247 #region Standard API
248
249 /**
250 * Create a new snippet.
251 *
252 * @param string $name Name of the snippet.
253 * @param string $code Code of the snippet.
254 * @param string $scope Scope of the snippet: 'function', 'backend', 'frontend', 'scheduled', 'persistent'.
255 * @param array $options Additional options:
256 * - target: 'php' or 'js' (for function snippets)
257 * - description: Description of the snippet
258 * - args: Arguments for function snippets
259 * - argsData: Argument data for function snippets (use 'description' for each argument's description)
260 * - behavior: 'dynamic' or 'static' (for function snippets)
261 * - tags: Array of tags
262 * - priority: Execution priority
263 * - active: Active status (true/false)
264 * - endpoint: REST endpoint
265 * - method: HTTP method (GET/POST)
266 * - intervalHours: Hours for scheduled snippets
267 * - intervalMinutes: Minutes for scheduled snippets
268 *
269 * @return array The created snippet data.
270 * @throws Exception If the snippet cannot be created.
271 */
272 public function createSnippet( $name, $code, $scope = 'function', $options = [] ) {
273
274 try {
275 if ( empty( $name ) ) {
276 throw new Exception( 'The snippet name is required.' );
277 }
278
279 if ( empty( $code ) ) {
280 throw new Exception( 'The snippet code is required.' );
281 }
282
283 $validScopes = ['function', 'backend', 'frontend', 'scheduled', 'persistent'];
284 if ( !in_array( $scope, $validScopes ) ) {
285 throw new Exception( sprintf( 'Invalid scope. Must be one of: %s', implode( ', ', $validScopes ) ) );
286 }
287
288 // Extract options with defaults
289 $target = $options['target'] ?? 'php';
290 $description = $options['description'] ?? '';
291 $args = $options['args'] ?? [];
292 $argsData = $options['argsData'] ?? [];
293 $behavior = $options['behavior'] ?? 'dynamic';
294 $tags = $options['tags'] ?? ['api'];
295 $priority = $options['priority'] ?? 10;
296 $active = $options['active'] ?? true;
297 $endpoint = $options['endpoint'] ?? '';
298 $method = $options['method'] ?? 'POST';
299 $intervalHours = $options['intervalHours'] ?? 0;
300 $intervalMinutes = $options['intervalMinutes'] ?? 0;
301
302 // Validate function-specific options
303 if ( $scope === 'function' ) {
304 if ( !in_array( $target, ['php', 'js'] ) ) {
305 throw new Exception( 'The target must be either "php" or "js" for function snippets.' );
306 }
307 if ( !in_array( $behavior, ['dynamic', 'static'] ) ) {
308 throw new Exception( 'The behavior must be either "dynamic" or "static" for function snippets.' );
309 }
310 }
311
312 if ( $this->debug ) {
313 $shortCode = substr( $code, 0, 100 );
314 $this->core->log( sprintf( 'API [CreateSnippet]: Name=%s, Scope=%s, Options=%s',
315 $name, $scope, json_encode( $options ) ) );
316 }
317
318 $params = [
319 // Core values
320 'id' => null,
321 'name' => $name,
322 'code' => $code,
323 'scope' => $scope,
324 'active' => $active ? 1 : 0,
325 'priority' => $priority,
326 'tags' => $tags,
327 'description' => $description,
328 'endpoint' => $endpoint,
329 'method' => $method,
330 ];
331
332 // Add function-specific params
333 if ( $scope === 'function' ) {
334 $params['functionName'] = $name;
335 $params['functionTarget'] = $target;
336 $params['functionArgs'] = $args;
337 $params['functionArgsDict'] = $argsData;
338 $params['functionBehavior'] = $behavior;
339 }
340
341 // Add scheduled-specific params
342 if ( $scope === 'scheduled' ) {
343 $params['intervalHours'] = $intervalHours;
344 $params['intervalMinutes'] = $intervalMinutes;
345 }
346
347 $result = $this->core->add_snippet( $params );
348
349 if ( $this->debug ) {
350 $this->core->log( sprintf( 'API [CreateSnippet]: Success, ID=%d', $result['id'] ?? 0 ) );
351 }
352
353 return $result;
354 }
355 catch ( Exception $e ) {
356 if ( $this->debug ) {
357 $this->core->log( '⚠️ API Error [CreateSnippet]: ' . $e->getMessage() );
358 }
359 throw $e;
360 }
361 }
362
363 /**
364 * Update a snippet by its ID.
365 * All parameters except ID are optional. If not specified, the current values will be used.
366 *
367 * @param int $id ID of the snippet to update.
368 * @param array $params Parameters to update. Can include:
369 * - name: Snippet name
370 * - code: Snippet code
371 * - scope: Snippet scope
372 * - description: Description
373 * - active: Active status
374 * - priority: Execution priority
375 * - tags: Array of tags
376 * - endpoint: REST endpoint
377 * - method: HTTP method
378 * - target: 'php' or 'js' (for function snippets)
379 * - args: Arguments (for function snippets)
380 * - argsData: Argument data (for function snippets)
381 * - behavior: 'dynamic' or 'static' (for function snippets)
382 * - intervalHours: Hours (for scheduled snippets)
383 * - intervalMinutes: Minutes (for scheduled snippets)
384 *
385 * @return array The updated snippet data.
386 * @throws Exception If the snippet cannot be updated.
387 */
388 public function updateSnippet( $id, $params = [] ) {
389 try {
390 if ( empty( $id ) ) {
391 throw new Exception( 'The snippet ID is required.' );
392 }
393
394 if ( $this->debug ) {
395 $this->core->log( sprintf( 'API [UpdateSnippet]: ID=%d, Params=%s', $id, json_encode( $params ) ) );
396 }
397
398 // Get existing snippet
399 $snippet = $this->snippet_module->select_one( $id );
400 if ( empty( $snippet ) ) {
401 throw new Exception( sprintf( 'Snippet with ID %d not found.', $id ) );
402 }
403
404 // Validate scope if provided
405 if ( isset( $params['scope'] ) ) {
406 $validScopes = ['function', 'backend', 'frontend', 'scheduled', 'persistent'];
407 if ( !in_array( $params['scope'], $validScopes ) ) {
408 throw new Exception( sprintf( 'Invalid scope. Must be one of: %s', implode( ', ', $validScopes ) ) );
409 }
410 }
411
412 // Validate function-specific parameters if provided
413 $scope = $params['scope'] ?? $snippet['scope'];
414 if ( $scope === 'function' ) {
415 if ( isset( $params['target'] ) && !in_array( $params['target'], ['php', 'js'] ) ) {
416 throw new Exception( 'The target must be either "php" or "js" for function snippets.' );
417 }
418 if ( isset( $params['behavior'] ) && !in_array( $params['behavior'], ['dynamic', 'static'] ) ) {
419 throw new Exception( 'The behavior must be either "dynamic" or "static" for function snippets.' );
420 }
421 }
422
423 // Build update params - merge with existing values
424 $updateParams = [
425 'id' => $id,
426 'name' => $params['name'] ?? $snippet['name'],
427 'code' => $params['code'] ?? $snippet['code'],
428 'scope' => $scope,
429 'active' => isset( $params['active'] ) ? ( $params['active'] ? 1 : 0 ) : $snippet['active'],
430 'priority' => $params['priority'] ?? $snippet['priority'],
431 'tags' => $params['tags'] ?? $snippet['tags'],
432 'description' => $params['description'] ?? $snippet['description'] ?? '',
433 'endpoint' => $params['endpoint'] ?? $snippet['endpoint'] ?? '',
434 'method' => $params['method'] ?? $snippet['method'] ?? 'POST',
435 ];
436
437 // Add function-specific params if it's a function snippet
438 if ( $scope === 'function' ) {
439 $updateParams['functionName'] = $params['name'] ?? $snippet['name'];
440 $updateParams['functionTarget'] = $params['target'] ?? $snippet['functionTarget'] ?? 'php';
441 $updateParams['functionArgs'] = $params['args'] ?? $snippet['functionArgs'] ?? [];
442 $updateParams['functionArgsDict'] = $params['argsData'] ?? $snippet['functionArgsDict'] ?? [];
443 $updateParams['functionBehavior'] = $params['behavior'] ?? $snippet['functionBehavior'] ?? 'dynamic';
444 }
445
446 // Add scheduled-specific params if it's a scheduled snippet
447 if ( $scope === 'scheduled' ) {
448 $updateParams['intervalHours'] = $params['intervalHours'] ?? $snippet['intervalHours'] ?? 0;
449 $updateParams['intervalMinutes'] = $params['intervalMinutes'] ?? $snippet['intervalMinutes'] ?? 0;
450 }
451
452 $result = $this->core->add_snippet( $updateParams );
453
454 if ( $this->debug ) {
455 $this->core->log( sprintf( 'API [UpdateSnippet]: Success, ID=%d', $result['id'] ?? $id ) );
456 }
457
458 return $result;
459 }
460 catch ( Exception $e ) {
461 if ( $this->debug ) {
462 $this->core->log( '⚠️ API Error [UpdateSnippet]: ' . $e->getMessage() );
463 }
464 throw $e;
465 }
466 }
467
468 /**
469 * Delete a snippet by its ID.
470 *
471 * @param int $id Snippet ID.
472 * @return bool True if the snippet was deleted successfully.
473 * @throws Exception If the snippet cannot be deleted.
474 */
475 public function deleteSnippet( $id ) {
476 try {
477 if ( empty( $id ) ) {
478 throw new Exception( 'The snippet ID is required.' );
479 }
480
481 if ( $this->debug ) {
482 $this->core->log( sprintf( 'API [DeleteSnippet]: ID=%d', $id ) );
483 }
484
485 // Verify the snippet exists
486 $snippet = $this->snippet_module->select_one( $id );
487 if ( empty( $snippet ) ) {
488 throw new Exception( sprintf( 'Snippet with ID %d not found.', $id ) );
489 }
490
491 $params = [ 'id' => $id ];
492
493 // Delete function snippet data if it's a function
494 if ( $snippet['scope'] === 'function' ) {
495 $this->snippet_module->delete_function_snippet( $params );
496 }
497
498 // Delete scheduled snippet data if it's scheduled
499 if ( $snippet['scope'] === 'scheduled' ) {
500 $this->snippet_module->delete_interval_snippet( $params );
501 }
502
503 $result = $this->snippet_module->delete( $params );
504
505 if ( $this->debug ) {
506 $this->core->log( sprintf( 'API [DeleteSnippet]: Success, ID=%d', $id ) );
507 }
508
509 return !empty( $result );
510 }
511 catch ( Exception $e ) {
512 if ( $this->debug ) {
513 $this->core->log( '⚠️ API Error [DeleteSnippet]: ' . $e->getMessage() );
514 }
515 throw $e;
516 }
517 }
518
519 /**
520 * Delete a snippet by its name.
521 *
522 * @param string $name Snippet name.
523 * @return bool True if the snippet was deleted successfully.
524 * @throws Exception If the snippet cannot be deleted.
525 */
526 public function deleteSnippetByName( $name ) {
527 try {
528 if ( empty( $name ) ) {
529 throw new Exception( 'The snippet name is required.' );
530 }
531
532 if ( $this->debug ) {
533 $this->core->log( sprintf( 'API [DeleteSnippetByName]: Name=%s', $name ) );
534 }
535
536 // Try to find as function first
537 $snippet = $this->snippet_module->get_function_by_name( $name );
538 if ( !empty( $snippet ) && !empty( $snippet['snippetId'] ) ) {
539 return $this->deleteSnippet( $snippet['snippetId'] );
540 }
541
542 // If not found as function, search in all snippets
543 $allSnippets = $this->snippet_module->select( 0, 9999, [], [] );
544 foreach ( $allSnippets['data'] as $s ) {
545 if ( $s['name'] === $name ) {
546 return $this->deleteSnippet( $s['id'] );
547 }
548 }
549
550 throw new Exception( sprintf( 'Snippet with name "%s" not found.', $name ) );
551 }
552 catch ( Exception $e ) {
553 if ( $this->debug ) {
554 $this->core->log( '⚠️ API Error [DeleteSnippetByName]: ' . $e->getMessage() );
555 }
556 throw $e;
557 }
558 }
559 #endregion
560
561 #region Standard API (No REST API)
562
563 /**
564 * Check if a snippet exists by ID.
565 *
566 * @param int $id The snippet ID.
567 * @return bool True if the snippet exists.
568 */
569 public function snippetExists( $id ) {
570 try {
571 if ( empty( $id ) ) {
572 return false;
573 }
574
575 $snippet = $this->snippet_module->select_one( $id );
576 return !empty( $snippet );
577 }
578 catch ( Exception $e ) {
579 if ( $this->debug ) {
580 $this->core->log( '⚠️ API Error [SnippetExists]: ' . $e->getMessage() );
581 }
582 return false;
583 }
584 }
585
586 /**
587 * Check if a snippet exists by name.
588 *
589 * @param string $name The snippet name.
590 * @return bool True if the snippet exists.
591 */
592 public function snippetExistsByName( $name ) {
593 try {
594 if ( empty( $name ) ) {
595 return false;
596 }
597
598 // Check in functions first
599 $snippet = $this->snippet_module->get_function_by_name( $name );
600 if ( !empty( $snippet ) ) {
601 return true;
602 }
603
604 // Check in all snippets
605 $allSnippets = $this->snippet_module->select( 0, 9999, [], [] );
606 foreach ( $allSnippets['data'] as $s ) {
607 if ( $s['name'] === $name ) {
608 return true;
609 }
610 }
611
612 return false;
613 }
614 catch ( Exception $e ) {
615 if ( $this->debug ) {
616 $this->core->log( '⚠️ API Error [SnippetExistsByName]: ' . $e->getMessage() );
617 }
618 return false;
619 }
620 }
621
622 /**
623 * Validates snippet code syntax.
624 *
625 * @param string $code The snippet code to validate.
626 * @param string $target The target language ('php' or 'js').
627 * @return array ['valid' => bool, 'error' => string|null]
628 */
629 public function validateSnippetCode( $code, $target = 'php' ) {
630 try {
631 if ( empty( $code ) ) {
632 return [ 'valid' => false, 'error' => 'Code is empty.' ];
633 }
634
635 if ( !in_array( $target, ['php', 'js'] ) ) {
636 return [ 'valid' => false, 'error' => 'Invalid target language.' ];
637 }
638
639 if ( $target === 'php' ) {
640 // Use the core's validate_php_code method if available
641 if ( method_exists( $this->core, 'validate_php_code' ) ) {
642 $validation = $this->core->validate_php_code( $code );
643 return [
644 'valid' => $validation['valid'] ?? false,
645 'error' => $validation['error'] ?? null
646 ];
647 }
648 }
649
650 // Basic validation if no specific validator available
651 return [ 'valid' => true, 'error' => null ];
652 }
653 catch ( Exception $e ) {
654 return [ 'valid' => false, 'error' => $e->getMessage() ];
655 }
656 }
657 #endregion
658
659 #region Snippet Management
660
661 /**
662 * Activate a snippet by its ID.
663 *
664 * @param int $id The snippet ID.
665 * @return bool True if activated successfully.
666 * @throws Exception If the snippet cannot be activated.
667 */
668 public function activateSnippet( $id ) {
669 try {
670 if ( empty( $id ) ) {
671 throw new Exception( 'The snippet ID is required.' );
672 }
673
674 if ( $this->debug ) {
675 $this->core->log( sprintf( 'API [ActivateSnippet]: ID=%d', $id ) );
676 }
677
678 // Get the snippet
679 $snippet = $this->snippet_module->select_one( $id );
680 if ( empty( $snippet ) ) {
681 throw new Exception( sprintf( 'Snippet with ID %d not found.', $id ) );
682 }
683
684 // Update only the active status
685 $result = $this->updateSnippet( $id, [ 'active' => true ] );
686 return !empty( $result );
687 }
688 catch ( Exception $e ) {
689 if ( $this->debug ) {
690 $this->core->log( '⚠️ API Error [ActivateSnippet]: ' . $e->getMessage() );
691 }
692 throw $e;
693 }
694 }
695
696 /**
697 * Deactivate a snippet by its ID.
698 *
699 * @param int $id The snippet ID.
700 * @return bool True if deactivated successfully.
701 * @throws Exception If the snippet cannot be deactivated.
702 */
703 public function deactivateSnippet( $id ) {
704 try {
705 if ( empty( $id ) ) {
706 throw new Exception( 'The snippet ID is required.' );
707 }
708
709 if ( $this->debug ) {
710 $this->core->log( sprintf( 'API [DeactivateSnippet]: ID=%d', $id ) );
711 }
712
713 // Get the snippet
714 $snippet = $this->snippet_module->select_one( $id );
715 if ( empty( $snippet ) ) {
716 throw new Exception( sprintf( 'Snippet with ID %d not found.', $id ) );
717 }
718
719 // Update only the active status
720 $result = $this->updateSnippet( $id, [ 'active' => false ] );
721 return !empty( $result );
722 }
723 catch ( Exception $e ) {
724 if ( $this->debug ) {
725 $this->core->log( '⚠️ API Error [DeactivateSnippet]: ' . $e->getMessage() );
726 }
727 throw $e;
728 }
729 }
730
731 /**
732 * Get snippets by scope.
733 *
734 * @param string $scope The scope to filter by: 'backend', 'frontend', 'function', 'scheduled', 'persistent'.
735 * @param array $filters Additional filters: 'active' (bool), 'tags' (array).
736 * @return array The list of snippets matching the criteria.
737 * @throws Exception If the scope is invalid.
738 */
739 public function getSnippetsByScope( $scope, $filters = [] ) {
740 try {
741 $validScopes = ['function', 'backend', 'frontend', 'scheduled', 'persistent', 'content_js', 'content_php'];
742 if ( !in_array( $scope, $validScopes ) ) {
743 throw new Exception( sprintf( 'Invalid scope. Must be one of: %s', implode( ', ', $validScopes ) ) );
744 }
745
746 if ( $this->debug ) {
747 $this->core->log( sprintf( 'API [GetSnippetsByScope]: Scope=%s, Filters=%s', $scope, json_encode( $filters ) ) );
748 }
749
750 // For function scope, we can use the existing get_functions method
751 if ( $scope === 'function' && empty( $filters ) ) {
752 return $this->snippet_module->get_functions();
753 }
754
755 // For other scopes or with filters, we need to query all snippets
756 $allSnippets = $this->snippet_module->select( 0, 9999, [], [] );
757 $filtered = [];
758
759 foreach ( $allSnippets['data'] as $snippet ) {
760 // Filter by scope
761 if ( $snippet['scope'] !== $scope ) {
762 continue;
763 }
764
765 // Apply additional filters
766 if ( isset( $filters['active'] ) && $snippet['active'] != $filters['active'] ) {
767 continue;
768 }
769
770 if ( isset( $filters['tags'] ) && is_array( $filters['tags'] ) ) {
771 $snippetTags = is_array( $snippet['tags'] ) ? $snippet['tags'] : [];
772 $hasAllTags = true;
773 foreach ( $filters['tags'] as $tag ) {
774 if ( !in_array( $tag, $snippetTags ) ) {
775 $hasAllTags = false;
776 break;
777 }
778 }
779 if ( !$hasAllTags ) {
780 continue;
781 }
782 }
783
784 $filtered[] = $snippet;
785 }
786
787 return $filtered;
788 }
789 catch ( Exception $e ) {
790 if ( $this->debug ) {
791 $this->core->log( '⚠️ API Error [GetSnippetsByScope]: ' . $e->getMessage() );
792 }
793 throw $e;
794 }
795 }
796
797 /**
798 * Get all active snippets.
799 *
800 * @param string|null $scope Optional scope filter.
801 * @return array The list of active snippets.
802 */
803 public function getActiveSnippets( $scope = null ) {
804 try {
805 if ( $this->debug ) {
806 $this->core->log( sprintf( 'API [GetActiveSnippets]: Scope=%s', $scope ?? 'all' ) );
807 }
808
809 if ( $scope ) {
810 return $this->getSnippetsByScope( $scope, [ 'active' => true ] );
811 }
812
813 // Get all active snippets
814 $allSnippets = $this->snippet_module->select( 0, 9999, [], [] );
815 $active = [];
816
817 foreach ( $allSnippets['data'] as $snippet ) {
818 if ( $snippet['active'] ) {
819 $active[] = $snippet;
820 }
821 }
822
823 return $active;
824 }
825 catch ( Exception $e ) {
826 if ( $this->debug ) {
827 $this->core->log( '⚠️ API Error [GetActiveSnippets]: ' . $e->getMessage() );
828 }
829 throw $e;
830 }
831 }
832 #endregion
833 }
834