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

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