PluginProbe
Code Engine – PHP Snippets, AI Functions & Automation for WordPress / 0.3.0
Code Engine – PHP Snippets, AI Functions & Automation for WordPress v0.3.0
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 / rest.php

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

808 lines 28.3 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_Rest
4 {
5 private $admin = null;
6 private $core = null;
7 private $snippet = null;
8 private $namespace = 'code-engine/v1';
9
10 private $bearer_token = null;
11
12 public function __construct( $core, $admin, $snippet ) {
13 if ( !current_user_can( 'administrator' ) ) {
14 return;
15 }
16 $this->core = $core;
17 $this->admin = $admin;
18 $this->snippet = $snippet;
19 add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
20 }
21
22 function rest_api_init() {
23 try {
24 #region REST Settings
25 register_rest_route( $this->namespace, '/settings/update', array(
26 'methods' => 'POST',
27 'permission_callback' => array( $this->core, 'can_access_settings' ),
28 'callback' => array( $this, 'rest_settings_update' )
29 ) );
30 register_rest_route( $this->namespace, '/settings/list', array(
31 'methods' => 'GET',
32 'permission_callback' => array( $this->core, 'can_access_settings' ),
33 'callback' => array( $this, 'rest_settings_list' ),
34 ) );
35 register_rest_route( $this->namespace, '/settings/reset', array(
36 'methods' => 'POST',
37 'permission_callback' => array( $this->core, 'can_access_settings' ),
38 'callback' => array( $this, 'rest_settings_reset' ),
39 ) );
40 register_rest_route( $this->namespace, '/settings/functions', array(
41 'methods' => 'GET',
42 'permission_callback' => array( $this->core, 'can_access_settings' ),
43 'callback' => array( $this, 'rest_export_functions' ),
44 ) );
45 register_rest_route( $this->namespace, '/settings/functions/replace', array(
46 'methods' => 'POST',
47 'permission_callback' => array( $this->core, 'can_access_settings' ),
48 'callback' => array( $this, 'rest_replace_functions' ),
49 ) );
50 register_rest_route( $this->namespace, '/settings/functions/raw', array(
51 'methods' => 'GET',
52 'permission_callback' => array( $this->core, 'can_access_settings' ),
53 'callback' => array( $this, 'rest_functions_raw' ),
54 ) );
55 register_rest_route( $this->namespace, '/settings/functions/raw', array(
56 'methods' => 'POST',
57 'permission_callback' => array( $this->core, 'can_access_settings' ),
58 'callback' => array( $this, 'rest_functions_raw_update' ),
59 ) );
60 #endregion
61
62 #region MISC
63 register_rest_route( $this->namespace, '/quick_start', array(
64 'methods' => 'POST',
65 'permission_callback' => array( $this->core, 'can_access_settings' ),
66 'callback' => array( $this, 'rest_quick_start' ),
67 ) );
68
69 register_rest_route( $this->namespace, '/server_clock', array(
70 'methods' => 'GET',
71 'permission_callback' => array( $this->core, 'can_access_settings' ),
72 'callback' => array( $this, 'rest_server_clock' ),
73 ) );
74
75 #endregion
76
77 #region REST AI Engine
78 register_rest_route( $this->namespace, '/ai_read_comments', array(
79 'methods' => 'POST',
80 'permission_callback' => array( $this->core, 'can_access_settings' ),
81 'callback' => array( $this, 'rest_ai_read_comments' ),
82 ) );
83 register_rest_route( $this->namespace, '/ai_query', array(
84 'methods' => 'POST',
85 'permission_callback' => array( $this->core, 'can_access_settings' ),
86 'callback' => array( $this, 'rest_ai_query' ),
87 ) );
88 #endregion
89
90 #region REST Run
91 register_rest_route( $this->namespace, '/run/test', [
92 'methods' => 'POST',
93 'callback' => [ $this, 'rest_test' ],
94 'permission_callback' => [ $this->core, 'can_access_settings' ],
95 ] );
96
97 register_rest_route( $this->namespace, '/run/lint', [
98 'methods' => 'POST',
99 'callback' => [ $this, 'rest_lint' ],
100 'permission_callback' => [ $this->core, 'can_access_settings' ],
101 ] );
102 #endregion
103
104 #region REST Snippets
105
106 register_rest_route($this->namespace, '/snippets/list', [
107 'methods' => 'POST',
108 'callback' => [$this, 'rest_list'],
109 'permission_callback' => [$this->core, 'can_access_settings'],
110 ]);
111
112 register_rest_route( $this->namespace, '/snippets/stats', [
113 'methods' => 'GET',
114 'callback' => [$this, 'rest_stats'],
115 'permission_callback' => [$this->core, 'can_access_settings'],
116 ]);
117
118 register_rest_route($this->namespace, '/snippets/tags', [
119 'methods' => 'POST',
120 'callback' => [$this, 'rest_tags'],
121 'permission_callback' => [$this->core, 'can_access_settings'],
122 ]);
123
124 register_rest_route($this->namespace, '/snippets/import', [
125 'methods' => 'GET',
126 'callback' => [$this, 'rest_import'],
127 'permission_callback' => [$this->core, 'can_access_settings'],
128 ]);
129
130 register_rest_route($this->namespace, '/snippets/add', array(
131 'methods' => 'POST',
132 'callback' => array($this, 'rest_add'),
133 'permission_callback' => array($this->core, 'can_access_settings')
134 ));
135
136 register_rest_route($this->namespace, '/snippets/update', array(
137 'methods' => 'POST',
138 'callback' => array($this, 'rest_update'),
139 'permission_callback' => array($this->core, 'can_access_settings')
140 ));
141
142 register_rest_route($this->namespace, '/snippets/delete', array(
143 'methods' => 'POST',
144 'callback' => array($this, 'rest_delete'),
145 'permission_callback' => array($this->core, 'can_access_settings')
146 ));
147
148
149 register_rest_route($this->namespace, '/snippets/replace', array(
150 'methods' => 'POST',
151 'callback' => array($this, 'rest_replace'),
152 'permission_callback' => array($this->core, 'can_access_settings')
153 ));
154
155
156 // SNIPPETS ENDPOINTS
157 $snippets = $this->snippet->select(
158 null, // offset
159 -1, // limit
160 [
161 [ 'accessor' => 'active', 'value' => 1 ],
162 [ 'accessor' => 'endpoint', 'value' => 1 ],
163 ], // filter
164 null, // sort
165 );
166
167 $public_api_enabled = $this->core->get_option( 'api_endpoint', false );
168 if ( (int) $snippets['total'] > 0 && $public_api_enabled ) {
169
170 $this->bearer_token = $this->core->get_option( 'api_token', null );
171 if ( !empty( $this->bearer_token ) ) {
172 add_filter( 'mwcode_allow_public_api', [ $this, 'auth_via_bearer_token' ], 10, 3 );
173 }
174
175 $data = $snippets['data'];
176
177 foreach ( $data as $snippet ) {
178 register_rest_route( $this->namespace, '/snippets-endpoint/' . $snippet['endpoint'], array(
179 'methods' => $snippet['method'] ?: 'POST',
180 'permission_callback' => function( $request ) {
181 return $this->can_access_public_api( 'snippets-endpoint', $request );
182 },
183 'callback' => array( $this, 'rest_call_snippet' ),
184 'args' => array(
185 'id' => array( 'required' => true, 'default' => $snippet['id'] ),
186 ),
187 ) );
188
189 //$this->core->log( "Registered REST API endpoint: /{$this->namespace}/snippets-endpoint/{$snippet['endpoint']} ({$snippet['method']})" );
190 }
191 }
192
193 #endregion
194
195 #region REST Logs
196 register_rest_route( $this->namespace, '/get_logs', array(
197 'methods' => 'GET',
198 'permission_callback' => array( $this->core, 'can_access_features' ),
199 'callback' => array( $this, 'rest_get_logs' )
200 ) );
201 register_rest_route( $this->namespace, '/clear_logs', array(
202 'methods' => 'GET',
203 'permission_callback' => array( $this->core, 'can_access_features' ),
204 'callback' => array( $this, 'rest_clear_logs' )
205 ) );
206
207 #endregion
208 }
209 catch (Exception $e) {
210 var_dump($e);
211 }
212 }
213
214 #region Auth
215
216 public function auth_via_bearer_token( $allow, $feature, $extra ) {
217 if ( !empty( $extra ) && !empty( $extra->get_header( 'Authorization' ) ) ) {
218 $token = $extra->get_header( 'Authorization' );
219 $token = str_replace( 'Bearer ', '', $token );
220 if ( $token === $this->bearer_token ) {
221 $admin = $this->get_admin_user();
222 wp_set_current_user( $admin->ID, $admin->user_login );
223 return true;
224 }
225 }
226 return $allow;
227 }
228
229 function can_access_public_api( $feature, $extra ) {
230 $logged_in = is_user_logged_in();
231 return apply_filters( 'mwcode_allow_public_api', $logged_in, $feature, $extra );
232 }
233
234 function get_admin_user() {
235 $admin = get_users( [ 'role' => 'administrator' ] );
236 if ( !empty( $admin ) ) {
237 return $admin[0];
238 }
239 return null;
240 }
241
242 #endregion
243
244 #region Logs
245
246 function rest_get_logs() {
247 $logs = $this->core->get_logs();
248 return new WP_REST_Response( [ 'success' => true, 'data' => $logs ], 200 );
249 }
250
251 function rest_clear_logs() {
252 $this->core->clear_logs();
253 return new WP_REST_Response( [ 'success' => true ], 200 );
254 }
255
256
257 #endregion
258
259 #region Settings
260
261 function rest_settings_list() {
262 return new WP_REST_Response( [
263 'success' => true,
264 'options' => $this->core->get_all_options()
265 ], 200 );
266 }
267
268
269 function rest_settings_update( $request ) {
270 try {
271 $params = $request->get_json_params();
272 $value = $params['options'];
273 $options = $this->core->update_options( $value );
274 $success = !!$options;
275 $message = __( $success ? 'OK' : "Could not update options.", 'code-engine' );
276 return new WP_REST_Response([ 'success' => $success, 'message' => $message, 'options' => $options ], 200 );
277 }
278 catch ( Exception $e ) {
279 return new WP_REST_Response([ 'success' => false, 'message' => $e->getMessage() ], 500 );
280 }
281 }
282
283 function rest_settings_reset() {
284 try {
285 $options = $this->core->reset_options();
286 $success = !!$options;
287 $message = __( $success ? 'OK' : "Could not reset options.", 'code-engine' );
288 return new WP_REST_Response([ 'success' => $success, 'message' => $message, 'options' => $options ], 200 );
289 }
290 catch ( Exception $e ) {
291 return new WP_REST_Response([ 'success' => false, 'message' => $e->getMessage() ], 500 );
292 }
293 }
294
295 function rest_export_functions() {
296 $functions = $this->snippet->get_functions();
297 return new WP_REST_Response([ 'success' => true, 'functions' => $functions ], 200);
298 }
299
300 function rest_replace_functions( $request ) {
301 try {
302 $params = $request->get_json_params();
303 $functions = $params['functions'];
304
305 $this->snippet->set_functions( $functions );
306
307 return new WP_REST_Response([ 'success' => true, 'data' => $functions ], 200);
308 } catch (Exception $e) {
309 return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 );
310 }
311
312 }
313
314 function rest_functions_raw() {
315 $functions = $this->snippet->get_functions_raw();
316 return new WP_REST_Response([ 'success' => true, 'functions' => $functions ], 200);
317 }
318
319 function rest_functions_raw_update( $request ) {
320 try {
321 $params = $request->get_json_params();
322 $functions = $params['functions'];
323
324 if ( empty( $functions ) ) {
325 $functions = [];
326 } else {
327 // Decode the JSON string into a PHP array
328 $functions = json_decode($functions, true);
329
330 // Check if decoding was successful
331 if (json_last_error() !== JSON_ERROR_NONE) {
332 return new WP_REST_Response([ 'success' => false, 'message' => 'Invalid JSON format' ], 400);
333 }
334 }
335
336 $this->snippet->set_functions_raw( $functions );
337
338 return new WP_REST_Response([ 'success' => true, 'data' => $functions ], 200);
339 } catch (Exception $e) {
340 return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 );
341 }
342 }
343
344 #endregion
345
346
347 #region MISC
348
349 function rest_quick_start( $request ) {
350 global $mwai;
351
352 if ( is_null( $mwai ) || !isset( $mwai ) ) {
353 return new WP_REST_Response([ 'success' => false, 'message' => 'AI Engine is not available.' ], 500 );
354 }
355
356 $params = $request->get_json_params();
357 if( empty( $params['prompt'] ) ) {
358 return new WP_REST_Response([ 'success' => false, 'message' => 'Prompt is required.' ], 500 );
359 }
360
361 $user_prompt = "<user_prompt>" . $params['prompt'] . "</user_prompt>";
362
363 // Main instructions: explain the categories and how to generate the snippet
364 $prompt_instructions = "<instruction>"
365 . "Create a code snippet based on the user's prompt for a WordPress environment. "
366 . "The snippet can be in PHP or JS. If the prompt does not specify the language, assume PHP. "
367 . "Below are the categories you can use for the code snippet:\n\n"
368 . "1. 'function': This can be either a JS or PHP function. The snippet should only contain the function itself, "
369 . " with no code outside its declaration. The function can take parameters; for each parameter, specify a "
370 . " default value, type ('string', 'number', 'boolean', 'mixed', etc.), required boolean, and a description.\n"
371 . "2. 'scheduled': This can only be PHP. It’s code that will be run by a cron job for scheduled tasks. "
372 . " If the user wants a task to run over time or on a schedule, use this category. The scheduling itself "
373 . " is handled automatically, so you only need to generate the main code. You can specify a target hour "
374 . " and minute.\n"
375 . "3. 'persistent', 'back', 'front': This is a PHP-only snippet for use across the website, typically for WordPress filters or "
376 . " action hooks. You can specify if the snippet should be 'persistent', 'front', or 'back' to indicate "
377 . " whether it loads on the front end, back end, or both. These are know as global snippets.\n"
378 . "4. 'content': This can be either 'content_js' or 'content_php'. A shortcode will be generated for this "
379 . " snippet so the user can place it inside a post.\n"
380 . "</instruction>";
381
382 // Goal: specify what data to generate
383 $prompt_goal = "<goal>"
384 . "Generate the snippet’s code and the metadata needed to describe it, including:\n"
385 . "- A snippet name\n"
386 . "- A description\n"
387 . "- The type (one of 'backend', 'frontend', 'function', 'persistent', 'scheduled', 'content_php', 'content_js')\n"
388 . "- Tags (comma-separated)\n"
389 . "For certain types, include additional details:\n"
390 . "- For a 'function' type, provide the scope ('js' or 'php') and its parameters, including default values, types, required and descriptions.\n"
391 . "- For a 'scheduled' snippet, specify the target hour and minute.\n"
392 . "</goal>";
393
394 // Warning: any additional information the user should know
395 $prompt_warning = "<warning>"
396 . "Dont use any <?php tags, <script> tags or markdown ``` format, just provide the raw code. "
397 . " When using a 'scheduled' all the cron scheduling is handled automatically, so you only need to generate the main code and dont need to worry about the scheduling logic. "
398 . "If the type is 'function', the code should only contain the function itself, with no code outside its declaration, as well as no comments outside of the function. THIS IS THE CASE ONLY FOR FUNCTIONS. For any other type, the code is invoked using eval() and should be a complete snippet of code. If the snippet is a function type the default values should NOT be deplared in the parameters, this will be done automatically. If the snippet is not a function type but your wirte a function, make sure to call the function at the end of the code. "
399 . " If the snippet is a content type, the code should be the content of the shortcode, not the shortcode itself. and NOT a function, it should be raw code with an echo statement. There are no attributes for content snippets. The shortcode is generated automatically like [code-engine id=''] and the id is the snippet id. "
400 . "</warning>";
401
402 // Format: how to structure the final output
403 $prompt_format = "<format>"
404 . "Return all information in JSON format with the following keys:\n"
405 . "- 'code': the code for the snippet. It should not be on one line only, make sure it is well formated.\n"
406 . "- 'name': the snippet name\n"
407 . "- 'description': a description of the snippet\n"
408 . "- 'type': the snippet type\n"
409 . "- 'tags': the snippet tags\n"
410 . "- 'scope': the scope (only applicable if type is 'function')\n"
411 . "- 'parameters': an array of parameter objects (only for 'function'), each with 'name', 'default', 'type', and 'description'\n"
412 . "- 'target_hour': the target hour (only for 'scheduled')\n"
413 . "- 'target_minute': the target minute (only for 'scheduled')\n"
414 . "- 'misc': any additional information. If you had to assume some stuff, like a filter name or a thing the user didn't think about, let it know by adding messages in this key.\n"
415 . "</format>";
416
417 // Combine all prompt parts
418 $prompt = $prompt_instructions . $prompt_goal . $prompt_format . $prompt_warning . $user_prompt;
419
420 $response = $mwai->simpleJsonQuery( $prompt );
421
422 return new WP_REST_Response( [ 'success' => true, 'data' => $response ], 200 );
423 }
424
425 function rest_server_clock() {
426 $now = current_datetime();
427 $now = $now->format( 'H:i:s ( Y/m/d )' );
428
429 return new WP_REST_Response( [ 'success' => true, 'time' => $now ], 200 );
430 }
431
432 #endregion
433
434 #region AI Engine
435
436 function rest_ai_query( $request ) {
437
438 $query = $request->get_param('query');
439 $code = $request->get_param('code');
440
441 global $mwai;
442
443 if ( is_null( $query ) || !isset( $query ) ) {
444 return new WP_REST_Response([ 'success' => false, 'message' => 'No query provided.' ], 500 );
445 }
446
447 if ( is_null( $mwai ) || !isset( $mwai ) ) {
448 return new WP_REST_Response([ 'success' => false, 'message' => 'AI Engine is not available.' ], 500 );
449 }
450
451 $prompt = "In your response, do not include any explanation outside the code if this is a functon, everything should be inside. Any information should be added as comments only, not example function calls. Do not use <?php tags or markdown ``` format, just provide the raw code. Based on the code provided, modify it as needed: $query\n\n$code";
452 $response = $mwai->simpleTextQuery( $prompt );
453
454 return new WP_REST_Response([ 'success' => true, 'code' => $response ], 200);
455 }
456
457 function rest_ai_read_comments( $request ) {
458 $code = $request->get_param('code');
459 global $mwai;
460
461 if ( is_null( $code ) || !isset( $code ) ) {
462 return new WP_REST_Response([ 'success' => false, 'message' => 'No code provided.' ], 500 );
463 }
464
465 if ( is_null( $mwai ) || !isset( $mwai ) ) {
466 return new WP_REST_Response([ 'success' => false, 'message' => 'AI Engine is not available.' ], 500 );
467 }
468
469 $prompt = "Based on the comments in the code, modify the snippet so it accords with what the comments say. In your response, only include the modfied code with the comments removed and nothing else, no <?php tag, no markdown ``` format, just the raw code.\n\n$code";
470 $prompt = apply_filters( 'mwcode_ai_suggestion_prompt', $prompt, $code );
471
472 $response = $mwai->simpleTextQuery( $prompt );
473
474 return new WP_REST_Response([ 'success' => true, 'code' => $response ], 200);
475
476 }
477
478 #endregion
479
480 #region Snippets
481
482 function rest_call_snippet( $request ) {
483 try {
484 $route = $request->get_route();
485 $endpoint = basename( $route );
486
487 $id = $request->get_param( 'id' );
488
489 $snippet = $this->snippet->select_one( $id );
490 if ( empty( $snippet ) || $snippet['endpoint'] !== $endpoint ) {
491 return new WP_REST_Response( ['success' => false, 'message' => 'Snippet not found.' ], 404 );
492 } elseif ( !$snippet['active'] ) {
493 return new WP_REST_Response( ['success' => false, 'message' => 'Snippet is not active.' ], 403 );
494 }
495
496 // Get the arguments from the request
497 $args = $request->get_param('args');
498 if ( !empty( $args ) ) {
499 $args = json_decode( $args, true );
500 if ( json_last_error() !== JSON_ERROR_NONE ) {
501 throw new Exception('Failed to decode JSON from args: ' . json_last_error_msg() );
502 }
503 }
504
505 // Get the body from the request
506 $body = $request->get_body();
507 if ( !empty( $body ) ) {
508 $bodyDecoded = json_decode( $body, true );
509 if ( json_last_error() !== JSON_ERROR_NONE ) {
510 throw new Exception( 'Failed to decode JSON from body: ' . json_last_error_msg() );
511 }
512 if ( !empty( $args ) && is_array( $args ) ) {
513 $args = array_merge( $args, $bodyDecoded );
514 } else {
515 $args = $bodyDecoded;
516 }
517 }
518
519 $output = $this->core->run_snippet( $id, $args );
520
521 return new WP_REST_Response( $output, 200);
522 } catch (ParseError $e) {
523 return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 );
524 } catch ( Exception $e ) {
525 return new WP_REST_Response([ 'success' => false, 'message' => $e->getMessage() ], 500 );
526 }
527 }
528
529 public function rest_list( $request )
530 {
531 try {
532 $params = $request->get_json_params();
533 $page = $params['page'] ? intval($params['page']) : 1;
534 $limit = $params['limit'] ?? 10;
535 $offset = ($page - 1) * $limit;
536
537 $filters = $params['filters'] ?? [];
538
539 $filters = array_filter( $filters, function( $filter ) {
540 return $filter['value'] !== 'all';
541 });
542
543 foreach ($filters as $key => $filter) {
544 if ( $filter['accessor'] === 'scope' && $filter['value'] === 'disabled' ) {
545 $filters[] = ['accessor' => 'active', 'value' => 0];
546 unset( $filters[$key] );
547 }
548 }
549
550 $sort = ['accessor' => 'id', 'by' => 'asc'];
551 $sortByFunctionName = $params['sort']['accessor'] == 'functionName';
552
553 if ( !$sortByFunctionName && !empty( $params['sort'] ) ) {
554 $sort = $params['sort'];
555 }
556
557
558 if ( !empty( $filters['scope'] ) ) {
559 //$filters['scope'] = [ 'accessor' => 'scope', 'value' => 'frontend' ];
560 }
561
562 $list = $this->snippet->select( $offset, $limit, $filters, $sort );
563
564 //when listing let's reset any error message on the dashboard
565 $this->core->update_option( 'fatal_error', '' );
566
567
568 //TODO: Delete in future versions, we are converting the scopes since they have changed
569 $to_update = [];
570 foreach ( $list['data'] as $key => $snippet ) {
571 if ( $snippet['scope'] === 'admin' ) {
572 $list['data'][$key]['scope'] = 'backend';
573 $to_update[] = $key;
574 }
575
576 if ( $snippet['scope'] === 'front' ) {
577 $list['data'][$key]['scope'] = 'frontend';
578 $to_update[] = $key;
579 }
580
581 if ( $snippet['scope'] === 'front,admin' ) {
582 $list['data'][$key]['scope'] = 'persistent';
583 $to_update[] = $key;
584 }
585
586 if ( $snippet['scope'] === 'library' ) {
587 $list['data'][$key]['scope'] = 'persistent';
588 $to_update[] = $key;
589 }
590
591 if ( $snippet['scope'] === 'interval' ) {
592 $list['data'][$key]['scope'] = 'scheduled';
593 $to_update[] = $key;
594 }
595 }
596
597 foreach ( $to_update as $key ) {
598 $snippet = $list['data'][$key];
599 $this->core->log( "Updating snippet for new scopes: " . $snippet['id'] );
600 $this->snippet->update( $snippet );
601 }
602
603 if ( $sortByFunctionName ) {
604 // Manually sort by functionName
605 usort( $list['data'], function( $a, $b ) use ( $params ) {
606 $result = strcmp( $a['functionName'], $b['functionName'] );
607 // If sorting by 'desc', invert the comparison result
608 if ( $params['sort']['by'] === 'desc' ) {
609 return -$result;
610 }
611 // Otherwise, return the comparison result for 'asc'
612 return $result;
613 } );
614 }
615
616 //$this->core->log( "snippets" . print_r($list['data'], 1) );
617
618 return new WP_REST_Response([ 'success' => true, 'total' => $list['total'], 'data' => $list['data'] ], 200);
619 } catch (Exception $e) {
620 return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 );
621 }
622 }
623
624 public function rest_stats( )
625 {
626 try {
627 $stats = $this->snippet->stats();
628 return new WP_REST_Response([ 'success' => true, 'data' => $stats ], 200);
629 } catch (Exception $e) {
630 return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 );
631 }
632 }
633
634 public function rest_tags()
635 {
636 try {
637 $list = $this->snippet->select_tags();
638 return new WP_REST_Response([ 'success' => true, 'data' => $list ], 200);
639 } catch (Exception $e) {
640 return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 );
641 }
642 }
643
644 public function rest_import( )
645 {
646 try {
647 $snippet = $this->snippet->import( );
648 return new WP_REST_Response([ 'success' => true, 'total' => $snippet ], 200);
649 } catch (Exception $e) {
650 return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 );
651 }
652 }
653
654 public function rest_add( $request )
655 {
656 try {
657 $params = $request->get_json_params();
658 $name = $params['name'];
659 $code = $params['code'];
660 if ( empty( $name ) || empty( $code ) ) {
661 throw new Exception( __( 'Name and code are required.', 'code-engine' ) );
662 }
663
664 $res = $this->core->add_snippet( $params );
665 $snippet = $res['snippet'];
666 $result = $res['result'];
667
668 return new WP_REST_Response([ 'success' => true, 'data' => $result, 'snippet' => $snippet ], 200);
669 } catch (Exception $e) {
670 return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 );
671 }
672 }
673
674 public function rest_update( $request )
675 {
676 try {
677 $params = $request->get_json_params();
678 $id = $params['id'];
679 if ( empty( $id ) ) {
680 throw new Exception( __( 'ID is required.', 'code-engine' ) );
681 }
682
683 $params['update'] = true;
684 $this->snippet->validate( $params );
685 $this->snippet->create_or_update_function_snippet( $params );
686 $this->snippet->create_or_update_interval_snippet( $params );
687
688 $params = $this->snippet->formatParamsForDatabase( $params );
689 $result = $this->snippet->update( $params );
690 return new WP_REST_Response([ 'success' => true, 'data' => $result ], 200);
691 } catch (Exception $e) {
692 return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 );
693 }
694 }
695
696
697 public function rest_delete( $request )
698 {
699 try {
700 $params = $request->get_json_params();
701 $id = $params['id'];
702
703 if ( empty( $id ) ) {
704 throw new Exception( __( 'ID is required.', 'code-engine' ) );
705 }
706
707 $this->snippet->delete_function_snippet( $params );
708 $this->snippet->delete_interval_snippet( $params );
709
710 $result = $this->snippet->delete( $params );
711
712 return new WP_REST_Response([ 'success' => true, 'data' => $result ], 200);
713 } catch (Exception $e) {
714 return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 );
715 }
716 }
717
718 public function rest_replace( $request ){
719 try {
720 $params = $request->get_json_params();
721 $snippets = $params['snippets'];
722
723 // Delete all current snippets
724 $this->snippet->delete_all();
725
726 // Insert new snippets
727 $result = [];
728 foreach ( $snippets as $snippet ) {
729 $this->snippet->validate( $snippet );
730 $snippet = $this->snippet->formatParamsForDatabase( $snippet );
731 $result[] = $this->snippet->insert( $snippet );
732 }
733
734 return new WP_REST_Response([ 'success' => true, 'data' => $result ], 200);
735 } catch (Exception $e) {
736 return new WP_REST_Response( ['success' => false, 'message' => $e->getMessage() ], 500 );
737 }
738 }
739
740
741 #endregion
742
743 #region Run
744
745 /**
746 * Execute a function snippet and return the result.
747 *
748 * It executes the provided function code with the given arguments and returns the result or any error encountered.
749 *
750 * @param WP_REST_Request $request The REST API request object.
751 * @return WP_REST_Response The REST API response containing the result or error.
752 */
753 public function rest_test( $request ) {
754 if ( is_array( $request ) ) {
755 $params = $request;
756 } else {
757 $params = $request->get_json_params();
758 }
759
760 try {
761 $output = "(Code Engine) No output.";
762 $error = null;
763
764 $scope = $params['scope'];
765 if ( $scope === 'function' ) {
766 $output = $this->core->run_snippet( null, [], $params );
767 } else {
768 $output = $this->core->run_non_fn_snippet( null, $params['code'], true );
769 }
770
771 $error = $output['error'] ?? null;
772 unset( $output['error'] );
773
774 return new WP_REST_Response( [ 'success' => true, 'return' => $output, 'error' => $error ], 200 );
775 } catch ( Exception $e ) {
776 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
777 }
778 }
779
780
781 /**
782 * Lint the code.
783 *
784 * @param $request
785 * @return WP_REST_Response
786 */
787 public function rest_lint( $request ) {
788 try {
789 $params = $request->get_json_params();
790 $code = $params['code'];
791
792 if ( empty( $code ) ) {
793 throw new Exception( __( 'Code is required.', 'code-engine' ) );
794 }
795
796 $linting_new_code = empty( $params['id'] );
797 $result = $this->core->parse_snippet( $code, $linting_new_code );
798
799 return new WP_REST_Response( [ 'success' => true, 'lint' => $result ], 200 );
800 } catch ( ParseError $e ) {
801 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
802 } catch ( Exception $e ) {
803 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
804 }
805 }
806 #endregion
807 }
808