PluginProbe
Code Engine – PHP Snippets, AI Functions & Automation for WordPress / trunk
Code Engine – PHP Snippets, AI Functions & Automation for WordPress vtrunk
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
← All changes | common/rest.php +134 -2 0.5.3trunk View file →
@@ -73,14 +73,146 @@
73 73 'methods' => 'POST',
74 74 'permission_callback' => $permission,
75 75 'callback' => [ $this, 'rest_installed_plugins' ]
76 76 ] );
77 + // The analysis needs PHP for one reason: $mwai is a PHP global, so the AI
78 + // call cannot be made from the dashboard's JavaScript. Everything it
79 + // analyses is gathered in the browser and posted here.
80 + register_rest_route( $this->namespace, '/analysis_status/', [
81 + 'methods' => 'POST',
82 + 'permission_callback' => $permission,
83 + 'callback' => [ $this, 'rest_analysis_status' ]
84 + ] );
85 + register_rest_route( $this->namespace, '/analysis_run/', [
86 + 'methods' => 'POST',
87 + 'permission_callback' => $permission,
88 + 'callback' => [ $this, 'rest_analysis_run' ]
89 + ] );
90 + register_rest_route( $this->namespace, '/analysis_forget/', [
91 + 'methods' => 'POST',
92 + 'permission_callback' => $permission,
93 + 'callback' => [ $this, 'rest_analysis_forget' ]
94 + ] );
77 95 }
78 96
97 + /**
98 + * Throw away the stored analysis and the consent that went with it.
99 + *
100 + * The analysis writes a verdict about this site into the options table and
101 + * keeps it. That is what makes it survive a reload, but it also means a
102 + * description of your server's weaknesses, written by a third-party model,
103 + * sits there indefinitely with nothing to remove it. Somebody should be able
104 + * to take it back, and clearing the consent means the panel explaining what
105 + * gets sent is shown again before anything is sent a second time.
106 + */
107 + public function rest_analysis_forget() {
108 + delete_option( 'meowapps_analysis_last' );
109 + delete_option( 'meowapps_analysis_consented' );
110 + return new WP_REST_Response( [ 'success' => true ], 200 );
111 + }
112 +
113 + /**
114 + * Whether an analysis can be run, and the last one if there is one.
115 + *
116 + * Three states matter and they are not the same: AI Engine absent, AI Engine
117 + * present but with no API key configured, and ready. Telling the second from
118 + * the first is what lets the dashboard say "finish setting it up" rather than
119 + * "install this", which would be wrong and mildly insulting.
120 + */
121 + public function rest_analysis_status() {
122 + global $mwai;
123 + $installed = !empty( $mwai );
124 + $ready = $installed && method_exists( $mwai, 'hasAI' ) && $mwai->hasAI();
125 + return new WP_REST_Response( [ 'success' => true, 'data' => [
126 + 'installed' => $installed,
127 + 'ready' => $ready,
128 + 'consented' => (bool) get_option( 'meowapps_analysis_consented', false ),
129 + 'last' => get_option( 'meowapps_analysis_last', null ),
130 + ] ], 200 );
131 + }
132 +
133 + public function rest_analysis_run( $request ) {
134 + global $mwai;
135 + if ( empty( $mwai ) || !method_exists( $mwai, 'simpleJsonQuery' ) ) {
136 + return new WP_REST_Response( [ 'success' => false,
137 + 'message' => 'AI Engine is not available on this site.' ], 200 );
138 + }
139 + if ( !method_exists( $mwai, 'hasAI' ) || !$mwai->hasAI() ) {
140 + return new WP_REST_Response( [ 'success' => false,
141 + 'message' => 'AI Engine has no AI environment configured yet.' ], 200 );
142 + }
143 +
144 + $params = $request->get_json_params();
145 + $facts = isset( $params['facts'] ) ? $params['facts'] : [];
146 +
147 + // Consent is recorded when a run is actually asked for, so the panel is
148 + // shown once rather than on every visit.
149 + update_option( 'meowapps_analysis_consented', '1' );
150 +
151 + try {
152 + $reply = $mwai->simpleJsonQuery( $this->analysis_prompt( $facts ) );
153 + }
154 + catch ( Exception $e ) {
155 + return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 200 );
156 + }
157 +
158 + $verdict = is_string( $reply ) ? json_decode( $reply, true ) : $reply;
159 + if ( empty( $verdict ) || !is_array( $verdict ) ) {
160 + return new WP_REST_Response( [ 'success' => false,
161 + 'message' => 'The AI reply could not be read as JSON.' ], 200 );
162 + }
163 +
164 + $verdict['ranAt'] = current_time( 'mysql' );
165 + update_option( 'meowapps_analysis_last', $verdict );
166 +
167 + return new WP_REST_Response( [ 'success' => true, 'data' => $verdict ], 200 );
168 + }
169 +
170 + /**
171 + * Written for the person who owns the site, not for a developer: somebody who
172 + * installed a plugin, not somebody who knows what max_execution_time is.
173 + *
174 + * Meow Apps plugins may be named as a remedy, but only where one genuinely
175 + * fixes the finding. An analysis that recommends its own author's plugins for
176 + * everything is an advert, and would be read as one.
177 + */
178 + private function analysis_prompt( $facts ) {
179 + $json = wp_json_encode( $facts, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
180 + return "You are reviewing a WordPress site's health for the person who owns it.\n"
181 + . "They are not a developer: explain what something means and why it matters before saying "
182 + . "what to do, and never assume they know what a PHP directive is.\n\n"
183 + . "Here is what was measured on their site:\n\n$json\n\n"
184 + . "Reply with JSON in exactly this shape:\n"
185 + . "{\n"
186 + . ' "areas": [ { "area": "Speed|Environment|Errors", "rating": 1-5, '
187 + . '"label": "a two or three word verdict", "summary": "one plain sentence" } ],' . "\n"
188 + . ' "findings": [ { "area": "Speed|Environment|Errors", "severity": "high|medium|low", '
189 + . '"title": "the recommendation itself, plain, under 60 characters", '
190 + . '"detail": "at most two short sentences on what it means and why it matters", '
191 + . '"action": "one sentence saying what to do", '
192 + . '"plugin": "meow plugin slug or null" } ],' . "\n"
193 + . ' "conclusion": "two short sentences tying it together"' . "\n"
194 + . "}\n\n"
195 + . "Rules:\n"
196 + . "- Rate each of the three areas from 1 (bad) to 5 (good). Do not invent an overall score.\n"
197 + . "- Only report findings genuinely worth acting on. An empty findings list is a perfectly "
198 + . "good answer for a healthy site. Do not manufacture problems.\n"
199 + . "- Order findings by how much they matter, worst first.\n"
200 + . "- Be brief. The reader sees the titles first and opens the ones they care about, so a "
201 + . "title has to work on its own and the detail must not repeat it. No preamble, no restating "
202 + . "the question, no filler.\n"
203 + . "- Set \"plugin\" to one of these Meow Apps slugs ONLY when that plugin genuinely fixes the "
204 + . "finding, otherwise null: ai-engine, code-engine, contact-form-block, database-cleaner, "
205 + . "media-cleaner, media-file-renamer, meow-gallery, meow-lightbox, meow-mailer, seo-engine, "
206 + . "social-engine, wp-retina-2x, wplr-sync.\n"
207 + . "- If an error in the log comes from a specific plugin, say which one.\n"
208 + . "- Write in the language of this site: " . get_bloginfo( 'language' ) . ".";
209 + }
210 +
79 211 public function file_rand( $filesize ) {
80 212 // Write the benchmark file inside a dedicated subfolder of the uploads
81 213 // directory (created on demand), then remove it. wp.org forbids writing to
82 - // the plugin folder or the uploads root — only a sanctioned subfolder.
214 + // the plugin folder or the uploads root, only a sanctioned subfolder.
83 215 $upload = wp_upload_dir();
84 216 if ( !empty( $upload['error'] ) || empty( $upload['basedir'] ) ) { return; }
85 217 $dir = trailingslashit( $upload['basedir'] ) . 'meowapps';
86 218 if ( !wp_mkdir_p( $dir ) ) { return; }
@@ -135,9 +267,9 @@
135 267 }
136 268 $all_plugins = get_plugins();
137 269 $result = [];
138 270 foreach ( $all_plugins as $plugin_file => $plugin_data ) {
139 - // Plugin file looks like "ai-engine/ai-engine.php" — the slug is the
271 + // Plugin file looks like "ai-engine/ai-engine.php", the slug is the
140 272 // first path segment. Some plugins live at the root (single file),
141 273 // those we just skip; we only care about Meow Apps directories anyway.
142 274 $parts = explode( '/', $plugin_file );
143 275 if ( count( $parts ) < 2 ) {