PluginProbe
Code Engine – PHP Snippets, AI Functions & Automation for WordPress / 0.5.7
Code Engine – PHP Snippets, AI Functions & Automation for WordPress v0.5.7
0.5.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 All 33 releases
← All changes | classes/modules/snippet.php +96 -12 0.2.80.5.7 View file →
@@ -137,20 +137,22 @@
137 137 $snippet['functionArgs'] = [];
138 138 $snippet['functionArgsDict'] = [];
139 139 $snippet['functionBehavior'] = '';
140 140 $snippet['functionTarget'] = 'PHP';
141 + $snippet['functionMcp'] = false;
141 142
142 143 foreach ( $functions_snippet as $function_snippet ) {
143 144 if ( $function_snippet['snippetId'] == $snippetId ) {
144 145
145 146 $snippet['functionName'] = $function_snippet['name'];
146 - if ( !isset( $snippet['functionBehavior'] ) || empty( $snippet['functionBehavior'] ) ) {
147 + $snippet['functionMcp'] = !empty( $function_snippet['mcp'] );
148 + if ( !isset( $function_snippet['behavior'] ) || empty( $function_snippet['behavior'] ) ) {
147 149 $snippet['functionBehavior'] = 'dynamic';
148 150 }
149 151 else {
150 152 $snippet['functionBehavior'] = $function_snippet['behavior'];
151 153 }
152 - if ( !isset( $snippet['functionTarget'] ) || empty( $snippet['functionTarget'] ) ) {
154 + if ( !isset( $function_snippet['target'] ) || empty( $function_snippet['target'] ) ) {
153 155 $snippet['functionTarget'] = 'PHP';
154 156 }
155 157 else {
156 158 $snippet['functionTarget'] = $function_snippet['target'];
@@ -215,8 +217,9 @@
215 217 'name' => $params['functionName'],
216 218 'behavior' => $params['functionBehavior'],
217 219 'desc' => $params['description'] ?? '',
218 220 'target' => $params['functionTarget'] ?? 'PHP',
221 + 'mcp' => !empty( $params['functionMcp'] ),
219 222 'args' => [],
220 223 ];
221 224
222 225 foreach ( $params['functionArgs'] as $argName ) {
@@ -223,9 +226,9 @@
223 226 if ( !empty( $argName ) ) {
224 227 $argData = $params['functionArgsDict'][$argName];
225 228 $snippet['args'][] = [
226 229 'name' => $argName,
227 - 'desc' => $argData['desc'],
230 + 'desc' => $argData['description'] ?? $argData['desc'] ?? '', // Support both 'description' and 'desc'
228 231 'default' => $argData['default'],
229 232 'required' => empty( $argData['default'] ),
230 233 'type' => $argData['type'],
231 234 ];
@@ -332,8 +335,48 @@
332 335 }
333 336 return null;
334 337 }
335 338
339 + public function get_function_by_name( $name, $options = [] )
340 + {
341 + $functions = $this->get_functions( );
342 +
343 + foreach ( $functions as $function ) {
344 + if ( $function['name'] == $name ) {
345 +
346 + if ( array_key_exists( 'php_ready_args', $options ) && $options['php_ready_args'] === false ) {
347 + $function['args'] = array_map( function ( $arg ) {
348 + $arg['name'] = ltrim( $arg['name'], '$' );
349 + return $arg;
350 + }, $function['args'] );
351 + }
352 +
353 + return $function;
354 + }
355 + }
356 +
357 + return null;
358 + }
359 +
360 + /**
361 + * Return the snippet IDs of every function that opted in to MCP exposure.
362 + * Used by the "MCP" list filter and its count (functionMcp lives in the
363 + * functions option, not a snippets table column, so it can't be queried in SQL).
364 + *
365 + * @return int[]
366 + */
367 + public function get_mcp_function_ids()
368 + {
369 + $functions = get_option( $this->option_functions, [] );
370 + $ids = [];
371 + foreach ( $functions as $fn ) {
372 + if ( !empty( $fn['mcp'] ) && !empty( $fn['snippetId'] ) ) {
373 + $ids[] = (int) $fn['snippetId'];
374 + }
375 + }
376 + return $ids;
377 + }
378 +
336 379 #endregion
337 380
338 381 #region Utilities
339 382
@@ -346,9 +389,9 @@
346 389 * @throws Exception
347 390 */
348 391 public function validate( $params )
349 392 {
350 - $valide_scopes = ['backend', 'frontend', 'function', 'persistent', 'scheduled'];
393 + $valide_scopes = ['backend', 'frontend', 'function', 'persistent', 'scheduled', 'content_php', 'content_js'];
351 394 $errors = [];
352 395 if ( isset( $params['endpoint'] ) && !empty( $params['endpoint'] ) ) {
353 396 $query = $this->wpdb->prepare(
354 397 "SELECT * FROM $this->table_name where endpoint = %s",
@@ -369,8 +412,9 @@
369 412 $scopes = [
370 413 "global" => "persistent",
371 414 "front-end" => "frontend",
372 415 "admin" => "backend",
416 + "content" => "content_php",
373 417 ];
374 418
375 419 if ( array_key_exists( $params['scope'], $scopes ) ) {
376 420 $params['scope'] = $scopes[$params['scope']];
@@ -515,9 +559,9 @@
515 559 return $tag !== '';
516 560 } );
517 561 }
518 562 $params['tags'] = $tags ? implode( ',', $tags ) : '';
519 - $params['code'] = $this->sanitize_code( $params['code'] );
563 + //$params['code'] = $this->sanitize_code( $params['code'] );
520 564 return $params;
521 565 }
522 566
523 567 /**
@@ -528,9 +572,9 @@
528 572 */
529 573 private function formatParamsForFront( $params )
530 574 {
531 575 // Separate the scope tags from the tags
532 - $scopes = ['backend', 'frontend', 'function', 'persistent', 'scheduled'];
576 + $scopes = ['backend', 'frontend', 'function', 'persistent', 'scheduled', 'content_php', 'content_js'];
533 577
534 578 if ( isset( $params['tags'] ) && !empty( $params['tags'] ) ) {
535 579
536 580 $tags = array_map( function ( $tag ) use ( $scopes ) {
@@ -547,9 +591,9 @@
547 591 }
548 592
549 593 public function stats()
550 594 {
551 - $scopes = ['function', 'scheduled', 'global'];
595 + $scopes = ['function', 'scheduled', 'global', 'content_php', 'content_js'];
552 596 $globalScopes = ['backend', 'frontend', 'persistent'];
553 597
554 598 $stats = [
555 599 'all' => 0,
@@ -564,9 +608,15 @@
564 608 $stats[$scope] = $this->wpdb->get_var( $this->wpdb->prepare( "SELECT COUNT( * ) FROM $this->table_name WHERE scope = %s", $scope ) );
565 609 }
566 610 $stats['all'] += $stats[$scope];
567 611 }
568 -
612 +
613 + // Combined count for the "Content" filter (PHP + JS). Not added to 'all', already counted above.
614 + $stats['content'] = (int) $stats['content_php'] + (int) $stats['content_js'];
615 +
616 + // Functions exposed via MCP. A subset of 'function', so not added to 'all'.
617 + $stats['mcp'] = count( $this->get_mcp_function_ids() );
618 +
569 619 return $stats;
570 620 }
571 621
572 622 public function import( )
@@ -589,15 +639,34 @@
589 639
590 640 return count( $snippets );
591 641 }
592 642
593 - private function sanitize_code( $code )
643 + public function sanitize_code( $code )
594 644 {
595 - $code = preg_replace( '/<\?php/', '', $code, 1 );
596 645 $code = ltrim( $code );
646 +
647 + $first_chats = substr( $code, 0, 5 );
648 + if( $first_chats === '<?php' ) {
649 + $code = substr( $code, 5 );
650 + $code = ltrim( $code );
651 + }
652 +
597 653 return $code;
598 654 }
599 655
656 + public function delete_duplicates() {
657 + // Delete snippets that have the same code and scope, keeping only the most recent one ( based on the updated column )
658 + $query = "DELETE t1 FROM $this->table_name t1
659 + INNER JOIN $this->table_name t2
660 + WHERE t1.id < t2.id
661 + AND t1.code = t2.code
662 + AND t1.scope = t2.scope";
663 +
664 + $this->wpdb->query( $query );
665 +
666 + return $this->wpdb->rows_affected;
667 + }
668 +
600 669 #endregion
601 670
602 671 #region Snippet CRUD
603 672
@@ -628,8 +697,11 @@
628 697 }
629 698 else if ( $filter['accessor'] === 'scope' && $filter['value'] === 'global' ) {
630 699 $freshFilters[] = [ 'accessor' => 'scope', 'value' => ['backend', 'frontend', 'persistent'] ];
631 700 }
701 + else if ( $filter['accessor'] === 'scope' && $filter['value'] === 'content' ) {
702 + $freshFilters[] = [ 'accessor' => 'scope', 'value' => ['content_php', 'content_js'] ];
703 + }
632 704 else {
633 705 $freshFilters[] = $filter;
634 706 }
635 707 }
@@ -661,14 +733,22 @@
661 733 $where[] = $this->wpdb->prepare( "active = %d", $value );
662 734 } elseif ( $filter['accessor'] === 'endpoint' ) {
663 735 $where[] = boolval( $filter['value'] ) ? "endpoint <> ''" : "endpoint = ''";
664 736 } elseif ( $filter['accessor'] === 'scope' ) {
665 - if ( is_array( $filter['value'] ) ) {
737 + if ( $filter['value'] === 'mcp' ) {
738 + // Not a scope: constrain to the functions opted in to MCP exposure.
739 + $ids = $this->get_mcp_function_ids();
740 + if ( empty( $ids ) ) {
741 + $where[] = '1 = 0';
742 + } else {
743 + $where[] = 'id IN (' . implode( ',', array_map( 'intval', $ids ) ) . ')';
744 + }
745 + } else if ( is_array( $filter['value'] ) ) {
666 746 $scopes = array_map( function( $scope ) {
667 747 return esc_sql( $scope );
668 748 }, $filter['value'] );
669 749 $where[] = "scope IN ('" . implode( "', '", $scopes ) . "')";
670 - } else {
750 + } else if ( !empty( $filter['value'] ) ) {
671 751 $value = esc_sql( $filter['value'] );
672 752 $where[] = $this->wpdb->prepare( "scope = %s", $value );
673 753 }
674 754 }
@@ -853,8 +933,12 @@
853 933 }
854 934
855 935 function check_db( )
856 936 {
937 + if ( $this->db_check ) {
938 + return true;
939 + }
940 +
857 941 if ( $this->does_table_exist( $this->table_name ) ) {
858 942 $this->check_columns( );
859 943 $this->db_check = true;
860 944 } else {