PluginProbe
Code Engine – PHP Snippets, AI Functions & Automation for WordPress / 0.4.3
Code Engine – PHP Snippets, AI Functions & Automation for WordPress v0.4.3
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/core.php +93 -43 0.3.20.4.3 View file →
@@ -12,8 +12,9 @@
12 12 public $is_rest = false;
13 13 public $is_cli = false;
14 14 public $site_url = null;
15 15 public $mwcode = null;
16 + public $licenser = null;
16 17
17 18 private $option_name = 'mwcode_options';
18 19
19 20 public function __construct() {
@@ -19,9 +20,9 @@
19 20 public function __construct() {
20 21 global $mwcode;
21 22
22 23 $this->site_url = get_site_url();
23 - $this->is_rest = MeowCommon_Helpers::is_rest();
24 + $this->is_rest = MeowKit_MWCODE_Helpers::is_rest();
24 25 $this->is_cli = defined( 'WP_CLI' ) && WP_CLI;
25 26
26 27 // Snippets
27 28 $snippet = new Meow_MWCODE_Modules_Snippet( $this );
@@ -37,8 +38,13 @@
37 38 add_action( 'plugins_loaded', array( $this, 'init' ) );
38 39 }
39 40
40 41 function init() {
42 + // Initialize the licenser for Pro version
43 + if ( class_exists( 'MeowKitPro_MWCODE_Licenser' ) ) {
44 + $this->licenser = new MeowKitPro_MWCODE_Licenser( MWCODE_PREFIX, MWCODE_ENTRY, MWCODE_DOMAIN, MWCODE_ITEM_ID, MWCODE_VERSION );
45 + }
46 +
41 47 // Part of the core, settings and stuff
42 48 $this->admin = new Meow_MWCODE_Admin( $this );
43 49
44 50 // Only for REST
@@ -83,14 +89,17 @@
83 89 return [
84 90 //Safemode
85 91 "safe_mode_status" => "on", // on, off, whitelist
86 92 "safe_mode_whitelist" => [],
93 + //"disallow_block_php" => true, // Do not allow PHP code to be execute through Blocks "code" parameter
94 + "code_blocks" => false,
95 + "code_blocks_whitelist" => [], // Whitelist for code blocks, if empty, all code blocks are allowed
87 96
88 97 //LOGS
89 98 "server_debug_mode" => false,
90 99
91 100 //UI
92 - "ui_show_preview" => true,
101 + "ui_show_preview" => false,
93 102
94 103 //AI
95 104 "ai_suggestions" => false,
96 105 "ai_engine_status"=> false,
@@ -101,8 +110,11 @@
101 110 "api_token" => md5( time() . rand() ),
102 111
103 112 //MCP
104 113 "mcp_support" => false,
114 +
115 + //MAINTENANCE
116 + "clean_uninstall" => false,
105 117 ];
106 118 }
107 119
108 120 function get_all_options( ) {
@@ -116,19 +128,15 @@
116 128 return $options;
117 129 }
118 130
119 131 function update_options( $options ) {
120 - $current_options = get_option($this->option_name);
121 132
122 - if ($current_options === $options) {
123 - // $this->log('💾 The options are already the expected value.');
124 - } else {
125 - if ( !update_option( $this->option_name, $options, false ) ) {
126 - $this->log( '💾 There was an issue updating the options.' );
127 - }
133 + $options = $this->sanitize_options( $options );
134 +
135 + if ( !update_option( $this->option_name, $options, false ) ) {
136 + $this->log( '💾 There was an issue updating the options.' );
128 137 }
129 -
130 - $options = $this->sanitize_options( $options );
138 +
131 139 return $options;
132 140 }
133 141
134 142 function update_option( $option, $value ) {
@@ -159,9 +167,9 @@
159 167 $options_modified = true;
160 168 }
161 169
162 170 // Update AI Engine status
163 - $options_modified = $this->updateAIEngineStatus( $options ) || $options_modified;
171 + $options = $this->updateAIEngineStatus( $options );
164 172
165 173 // Disable AI related features if AI Engine is not available
166 174 if ( ! $options['ai_engine_status'] ) {
167 175 if ( $options['ai_suggestions'] !== false ) {
@@ -171,12 +179,8 @@
171 179 // Note: We don't disable MCP support here anymore
172 180 // It will be checked at runtime in the MCP class
173 181 }
174 182
175 - if ( $options_modified ) {
176 - update_option( $this->option_name, $options, false );
177 - }
178 -
179 183 return $options;
180 184 }
181 185
182 186 private function updateAIEngineStatus( &$options ) {
@@ -184,28 +188,25 @@
184 188
185 189 if ( is_null( $mwai ) || ! isset( $mwai ) ) {
186 190 $options['ai_engine_status'] = false;
187 191 $options['ai_engine_message'] = 'AI Engine is not available.';
188 - return true;
192 +
193 + return $options;
189 194 }
190 195
191 196 try {
192 197 $status = $mwai->checkStatus();
193 198
194 - if ( $options['ai_engine_status'] != true || $options['ai_engine_message'] != $status ) {
195 - $options['ai_engine_status'] = true;
196 - $options['ai_engine_message'] = $status;
197 - return true;
198 - }
199 + $options['ai_engine_status'] = true;
200 + $options['ai_engine_message'] = is_array( $status ) ? "Environments: " . implode( ', ', $status ) : $status;
201 +
199 202 } catch ( Exception $e ) {
200 - if ( $options['ai_engine_status'] != false || $options['ai_engine_message'] != $e->getMessage() ) {
203 +
201 204 $options['ai_engine_status'] = false;
202 205 $options['ai_engine_message'] = $e->getMessage();
203 - return true;
204 - }
205 206 }
206 207
207 - return false;
208 + return $options;
208 209 }
209 210
210 211 #endregion
211 212
@@ -276,16 +277,16 @@
276 277 $value = array_map( 'trim', $value );
277 278 }
278 279
279 280 if ( $type === 'array' ) {
280 - $value = json_encode( $value );
281 - $value = str_replace( '\\', '', $value );
281 + // Convert to PHP array format instead of JSON
282 + $value = var_export( $value, true );
282 283 }
283 284
284 285 return [ $name, $value ];
285 286 }
286 287
287 - function run_non_fn_snippet( $id, $code = null, $test = false ) {
288 + function run_non_fn_snippet( $id, $code = null, $test = false, $prefix = '' ) {
288 289 // Retrieve the snippet code from the provided code or via the snippet ID.
289 290 if ( $code ) {
290 291 $snippet = [ 'code' => $code ];
291 292 } else {
@@ -292,13 +293,17 @@
292 293 $snippet = $this->get_snippet( $id );
293 294 }
294 295
295 296 // Remove any PHP opening tag.
296 - $snippet['code'] = preg_replace( '/<\?php/', '', $snippet['code'], 1 );
297 + $snippet['code'] = $this->snippet->sanitize_code( $snippet['code'] );
297 298
298 299 if ( $test ) {
299 300 $snippet['code'] = preg_replace( '/echo\s+(.+?);/s', 'echo $1 . "\n";', $snippet['code'] );
300 301 }
302 +
303 + if( $prefix ) {
304 + $snippet['code'] = $prefix . "\n" . $snippet['code'];
305 + }
301 306
302 307 $error = null;
303 308 $output = null;
304 309
@@ -432,13 +437,14 @@
432 437 if ( $index < count( $params['args'] ) - 1 ) {
433 438 $params['code'] .= ', ';
434 439 }
435 440 }
441 +
436 442 $params['code'] .= ");\necho print_r(\$mwcode_result, true);";
437 443
438 444 $error = null;
439 445 $output = null;
440 -
446 +
441 447 try {
442 448 ob_start();
443 449 eval( $params['code'] );
444 450 $output = ob_get_clean();
@@ -580,14 +586,17 @@
580 586
581 587 $blocked = false;
582 588 $page = isset( $_GET["page"] ) ? sanitize_text_field( $_GET["page"] ) : null;
583 589
584 - // Block on settings page for safety
590 +
585 591 if ( $page === 'mwcode_settings' ) {
586 - $blocked = true;
592 + // If we blocks global snippets like nonce_life filter, we would block the settings page so let's remove the block for this page
593 +
594 + $blocked = false;
595 + //$blocked = true;
587 596 }
588 597 // Block REST requests that aren't whitelisted
589 - elseif ( MeowCommon_Helpers::is_rest() && !Meow_MWCODE_Core::is_white_listed_rest() ) {
598 + elseif ( MeowKit_MWCODE_Helpers::is_rest() && !Meow_MWCODE_Core::is_white_listed_rest() ) {
590 599 $blocked = true;
591 600 }
592 601
593 602 if ( empty( $this->snippet ) ) {
@@ -618,9 +627,9 @@
618 627 return;
619 628 }
620 629
621 630 $snippets = array_map( function ( $snippet ) use ( $blocked ) {
622 - $snippet['code'] = preg_replace( '/<\?php/', '', $snippet['code'], 1 );
631 + $snippet['code'] = $this->snippet->sanitize_code( $snippet['code'] );
623 632 $snippet['blocked'] = $blocked;
624 633
625 634 // If the snippet must be executed only in the frontend, we bypass the block
626 635 if ( !is_admin() && $snippet['scope'] === 'frontend' ) {
@@ -636,25 +645,60 @@
636 645
637 646 #endregion
638 647
639 648 #region Shortcodes
649 + function separate_mwcode_atts( $atts ) {
640 650
651 + if( array_key_exists( 'id', $atts ) ) unset( $atts['id'] );
652 + if( array_key_exists( 'target', $atts ) ) unset( $atts['target'] );
653 + if( array_key_exists( 'code', $atts ) ) unset( $atts['code'] );
654 +
655 + return $atts;
656 + }
657 +
641 658 function content_shortcode( $atts ) {
642 659
660 + $user_atts = $this->separate_mwcode_atts( $atts );
661 +
643 662 $atts = shortcode_atts( array(
644 - 'id' => null,
645 - 'target' => null,
646 - 'code' => null,
647 - ), $atts );
663 + 'id' => null,
664 + 'target' => null, // js or php
665 + 'code' => null, // For Guttenberg block usage
666 + ), $atts, 'code-engine' );
648 667
649 668 $id = $atts['id'];
650 669 $target = $atts['target'];
651 670 $code = $atts['code'];
652 -
671 + $current_post = get_post();
672 +
673 + $no_js = defined( 'DISALLOW_UNFILTERED_HTML' ) && DISALLOW_UNFILTERED_HTML;
674 + $allow_php = $this->get_option( 'code_blocks', false );
675 + $allow_php_whitelist = $this->get_option( 'code_blocks_whitelist', [] );
676 +
653 677 // If the ID is null, it means it comes from a Guttenberg block
654 678 $is_block = empty( $id ) && !empty( $code );
655 - if( $is_block ){
656 679
680 + if( $is_block ) {
681 +
682 + if( $target !== 'js' && $target !== 'php' ) {
683 + return '<b>Code Engine:</b> Please provide a valid target (js or php).';
684 + }
685 +
686 + if ( $no_js && $target === 'js' ) {
687 + return '<b>Code Engine:</b> Code Block JS are disabled because unfiltered HTML is not allowed on your server.';
688 + }
689 +
690 + if ( $target === 'php' ) {
691 +
692 + if ( !$allow_php ) {
693 + return '<b>Code Engine:</b> Code Block PHP are disabled. If you are an administrator, you can enable it in the settings, this is not recommended. Please use a Content Snippet ( PHP ) instead.';
694 + }
695 +
696 + if ( !empty( $allow_php_whitelist ) && !in_array( $current_post->ID, $allow_php_whitelist ) ) {
697 + return '<b>Code Engine:</b> Code Block PHP are disabled for this post. If you are an administrator, you can enable it in the settings, this is not recommended. Please use a Content Snippet ( PHP ) instead.';
698 + }
699 + }
700 +
657 701 // Because the code from Blocks are sanitized, we need to replace the &quot; with "
658 702 $code = str_replace( '&quot;', '"', $code );
659 703
660 704 if ( $target === 'js' ) {
@@ -667,8 +711,9 @@
667 711
668 712 return $output;
669 713 }
670 714
715 + // If not a block, we get the snippet by ID
671 716 // If the ID is not null, it means it comes from a shortcode
672 717 if ( empty( $id ) && empty( $code ) ) {
673 718 return '<b>Code Engine:</b> Please provide a snippet ID.';
674 719 }
@@ -680,14 +725,18 @@
680 725 }
681 726
682 727 //Check if the snippet scope is either content_php or content_js
683 728 $is_content_php = $snippet['scope'] === 'content_php';
684 - $is_content_js = $snippet['scope'] === 'content_js';
729 + $is_content_js = $snippet['scope'] === 'content_js';
685 730
686 731 if ( !$is_content_php && !$is_content_js ) {
687 732 return '<b>Code Engine:</b> The snippet is not a content snippet.';
688 733 }
689 734
735 + if( $no_js && $is_content_js ) {
736 + return '<b>Code Engine:</b> Code Engine JS snippets are disabled because unfiltered HTML is not allowed on your server.';
737 + }
738 +
690 739 //Check if the snippet is active
691 740 if ( !$snippet['active'] ) {
692 741 return '<b>Code Engine:</b> The snippet is not active.';
693 742 }
@@ -698,9 +747,10 @@
698 747 $output = '<script>' . $snippet['code'] . '</script>';
699 748 }
700 749
701 750 if ( $is_content_php ) {
702 - $output = $this->run_non_fn_snippet( $id );
751 + $prefix = "\$mwcode_atts = unserialize( '" . serialize( $user_atts ) . "' );";
752 + $output = $this->run_non_fn_snippet( $id, null, false, $prefix );
703 753 }
704 754
705 755 return $output;
706 756 }