PluginProbe
Code Engine – PHP Snippets, AI Functions & Automation for WordPress / 0.4.5
Code Engine – PHP Snippets, AI Functions & Automation for WordPress v0.4.5
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 +90 -55 0.3.20.4.5 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 ) {
@@ -181,31 +185,13 @@
181 185
182 186 private function updateAIEngineStatus( &$options ) {
183 187 global $mwai;
184 188
185 - if ( is_null( $mwai ) || ! isset( $mwai ) ) {
186 - $options['ai_engine_status'] = false;
187 - $options['ai_engine_message'] = 'AI Engine is not available.';
188 - return true;
189 - }
189 + $options['mwai_has_ai'] = !empty( $mwai ) && method_exists( $mwai, 'hasAI' ) && $mwai->hasAI();
190 + // Legacy
191 + $options['ai_engine_status'] = $options['mwai_has_ai'];
190 192
191 - try {
192 - $status = $mwai->checkStatus();
193 -
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 - } catch ( Exception $e ) {
200 - if ( $options['ai_engine_status'] != false || $options['ai_engine_message'] != $e->getMessage() ) {
201 - $options['ai_engine_status'] = false;
202 - $options['ai_engine_message'] = $e->getMessage();
203 - return true;
204 - }
205 - }
206 -
207 - return false;
193 + return $options;
208 194 }
209 195
210 196 #endregion
211 197
@@ -276,16 +262,16 @@
276 262 $value = array_map( 'trim', $value );
277 263 }
278 264
279 265 if ( $type === 'array' ) {
280 - $value = json_encode( $value );
281 - $value = str_replace( '\\', '', $value );
266 + // Convert to PHP array format instead of JSON
267 + $value = var_export( $value, true );
282 268 }
283 269
284 270 return [ $name, $value ];
285 271 }
286 272
287 - function run_non_fn_snippet( $id, $code = null, $test = false ) {
273 + function run_non_fn_snippet( $id, $code = null, $test = false, $prefix = '' ) {
288 274 // Retrieve the snippet code from the provided code or via the snippet ID.
289 275 if ( $code ) {
290 276 $snippet = [ 'code' => $code ];
291 277 } else {
@@ -292,13 +278,17 @@
292 278 $snippet = $this->get_snippet( $id );
293 279 }
294 280
295 281 // Remove any PHP opening tag.
296 - $snippet['code'] = preg_replace( '/<\?php/', '', $snippet['code'], 1 );
282 + $snippet['code'] = $this->snippet->sanitize_code( $snippet['code'] );
297 283
298 284 if ( $test ) {
299 285 $snippet['code'] = preg_replace( '/echo\s+(.+?);/s', 'echo $1 . "\n";', $snippet['code'] );
300 286 }
287 +
288 + if( $prefix ) {
289 + $snippet['code'] = $prefix . "\n" . $snippet['code'];
290 + }
301 291
302 292 $error = null;
303 293 $output = null;
304 294
@@ -432,13 +422,14 @@
432 422 if ( $index < count( $params['args'] ) - 1 ) {
433 423 $params['code'] .= ', ';
434 424 }
435 425 }
426 +
436 427 $params['code'] .= ");\necho print_r(\$mwcode_result, true);";
437 428
438 429 $error = null;
439 430 $output = null;
440 -
431 +
441 432 try {
442 433 ob_start();
443 434 eval( $params['code'] );
444 435 $output = ob_get_clean();
@@ -580,14 +571,17 @@
580 571
581 572 $blocked = false;
582 573 $page = isset( $_GET["page"] ) ? sanitize_text_field( $_GET["page"] ) : null;
583 574
584 - // Block on settings page for safety
575 +
585 576 if ( $page === 'mwcode_settings' ) {
586 - $blocked = true;
577 + // If we blocks global snippets like nonce_life filter, we would block the settings page so let's remove the block for this page
578 +
579 + $blocked = false;
580 + //$blocked = true;
587 581 }
588 582 // Block REST requests that aren't whitelisted
589 - elseif ( MeowCommon_Helpers::is_rest() && !Meow_MWCODE_Core::is_white_listed_rest() ) {
583 + elseif ( MeowKit_MWCODE_Helpers::is_rest() && !Meow_MWCODE_Core::is_white_listed_rest() ) {
590 584 $blocked = true;
591 585 }
592 586
593 587 if ( empty( $this->snippet ) ) {
@@ -618,9 +612,9 @@
618 612 return;
619 613 }
620 614
621 615 $snippets = array_map( function ( $snippet ) use ( $blocked ) {
622 - $snippet['code'] = preg_replace( '/<\?php/', '', $snippet['code'], 1 );
616 + $snippet['code'] = $this->snippet->sanitize_code( $snippet['code'] );
623 617 $snippet['blocked'] = $blocked;
624 618
625 619 // If the snippet must be executed only in the frontend, we bypass the block
626 620 if ( !is_admin() && $snippet['scope'] === 'frontend' ) {
@@ -636,25 +630,60 @@
636 630
637 631 #endregion
638 632
639 633 #region Shortcodes
634 + function separate_mwcode_atts( $atts ) {
640 635
636 + if( array_key_exists( 'id', $atts ) ) unset( $atts['id'] );
637 + if( array_key_exists( 'target', $atts ) ) unset( $atts['target'] );
638 + if( array_key_exists( 'code', $atts ) ) unset( $atts['code'] );
639 +
640 + return $atts;
641 + }
642 +
641 643 function content_shortcode( $atts ) {
642 644
645 + $user_atts = $this->separate_mwcode_atts( $atts );
646 +
643 647 $atts = shortcode_atts( array(
644 - 'id' => null,
645 - 'target' => null,
646 - 'code' => null,
647 - ), $atts );
648 + 'id' => null,
649 + 'target' => null, // js or php
650 + 'code' => null, // For Guttenberg block usage
651 + ), $atts, 'code-engine' );
648 652
649 653 $id = $atts['id'];
650 654 $target = $atts['target'];
651 655 $code = $atts['code'];
652 -
656 + $current_post = get_post();
657 +
658 + $no_js = defined( 'DISALLOW_UNFILTERED_HTML' ) && DISALLOW_UNFILTERED_HTML;
659 + $allow_php = $this->get_option( 'code_blocks', false );
660 + $allow_php_whitelist = $this->get_option( 'code_blocks_whitelist', [] );
661 +
653 662 // If the ID is null, it means it comes from a Guttenberg block
654 663 $is_block = empty( $id ) && !empty( $code );
655 - if( $is_block ){
656 664
665 + if( $is_block ) {
666 +
667 + if( $target !== 'js' && $target !== 'php' ) {
668 + return '<b>Code Engine:</b> Please provide a valid target (js or php).';
669 + }
670 +
671 + if ( $no_js && $target === 'js' ) {
672 + return '<b>Code Engine:</b> Code Block JS are disabled because unfiltered HTML is not allowed on your server.';
673 + }
674 +
675 + if ( $target === 'php' ) {
676 +
677 + if ( !$allow_php ) {
678 + 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.';
679 + }
680 +
681 + if ( !empty( $allow_php_whitelist ) && !in_array( $current_post->ID, $allow_php_whitelist ) ) {
682 + 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.';
683 + }
684 + }
685 +
657 686 // Because the code from Blocks are sanitized, we need to replace the &quot; with "
658 687 $code = str_replace( '&quot;', '"', $code );
659 688
660 689 if ( $target === 'js' ) {
@@ -667,8 +696,9 @@
667 696
668 697 return $output;
669 698 }
670 699
700 + // If not a block, we get the snippet by ID
671 701 // If the ID is not null, it means it comes from a shortcode
672 702 if ( empty( $id ) && empty( $code ) ) {
673 703 return '<b>Code Engine:</b> Please provide a snippet ID.';
674 704 }
@@ -680,14 +710,18 @@
680 710 }
681 711
682 712 //Check if the snippet scope is either content_php or content_js
683 713 $is_content_php = $snippet['scope'] === 'content_php';
684 - $is_content_js = $snippet['scope'] === 'content_js';
714 + $is_content_js = $snippet['scope'] === 'content_js';
685 715
686 716 if ( !$is_content_php && !$is_content_js ) {
687 717 return '<b>Code Engine:</b> The snippet is not a content snippet.';
688 718 }
689 719
720 + if( $no_js && $is_content_js ) {
721 + return '<b>Code Engine:</b> Code Engine JS snippets are disabled because unfiltered HTML is not allowed on your server.';
722 + }
723 +
690 724 //Check if the snippet is active
691 725 if ( !$snippet['active'] ) {
692 726 return '<b>Code Engine:</b> The snippet is not active.';
693 727 }
@@ -698,9 +732,10 @@
698 732 $output = '<script>' . $snippet['code'] . '</script>';
699 733 }
700 734
701 735 if ( $is_content_php ) {
702 - $output = $this->run_non_fn_snippet( $id );
736 + $prefix = "\$mwcode_atts = unserialize( '" . serialize( $user_atts ) . "' );";
737 + $output = $this->run_non_fn_snippet( $id, null, false, $prefix );
703 738 }
704 739
705 740 return $output;
706 741 }