PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 3.6.4
AI Engine – The Chatbot, AI Framework & MCP for WordPress v3.6.4
3.6.6 3.6.4 3.6.5 3.6.3 3.6.2 3.6.1 3.6.0 3.5.9 3.5.8 3.5.7 3.5.6 3.5.5 3.5.4 3.5.3 3.5.2 3.5.1 3.5.0 3.4.9 3.4.8 3.4.7 0.2.1 1.6.91 0.2.2 1.6.92 0.2.3 1.6.93 0.2.4 1.6.94 0.2.5 1.6.95 0.2.6 1.6.96 0.2.7 1.6.97 0.2.8 1.6.98 0.2.9 1.6.99 0.3.0 1.7.0 0.3.1 1.7.1 0.3.2 1.7.2 0.3.3 1.7.3 0.3.4 1.7.4 0.3.5 1.7.5 0.3.6 1.7.6 0.4.0 1.7.7 0.4.1 1.7.8 0.4.2 1.7.9 0.4.3 1.8.0 0.4.4 1.8.1 0.4.5 1.8.2 0.4.6 1.8.3 0.4.7 1.8.4 0.4.8 1.8.5 0.4.9 1.8.6 0.5.0 1.8.7 0.5.1 1.8.8 0.5.2 1.8.9 0.5.3 1.9.0 0.5.4 1.9.1 0.5.5 1.9.2 0.5.6 1.9.3 0.5.7 1.9.4 0.5.8 1.9.5 0.5.9 1.9.6 0.6.0 1.9.7 0.6.1 1.9.8 0.6.2 1.9.81 0.6.3 1.9.82 0.6.4 1.9.83 0.6.5 1.9.84 0.6.6 1.9.85 0.6.7 1.9.86 0.6.8 1.9.87 0.6.9 1.9.88 0.7.0 1.9.89 0.7.1 1.9.90 0.7.2 1.9.91 0.7.3 1.9.92 0.7.4 1.9.93 0.7.5 1.9.94 0.7.6 1.9.95 0.7.7 1.9.96 0.7.8 1.9.97 0.7.9 1.9.98 0.8.0 1.9.99 0.8.1 2.0.0 0.8.2 2.0.1 0.8.3 2.0.2 0.8.4 2.0.3 0.8.5 2.0.4 0.8.6 2.0.5 0.8.7 2.0.6 0.8.8 2.0.7 0.8.9 2.0.8 0.9.0 2.0.9 0.9.2 2.1.0 0.9.3 2.1.1 0.9.4 2.1.2 0.9.5 2.1.3 0.9.6 2.1.4 0.9.7 2.1.5 0.9.8 2.1.6 0.9.81 2.1.7 0.9.82 2.1.8 0.9.83 2.1.9 0.9.84 2.2.0 0.9.85 2.2.1 0.9.86 2.2.2 0.9.87 2.2.3 0.9.88 2.2.4 0.9.89 2.2.5 0.9.9 2.2.51 0.9.91 2.2.52 0.9.92 2.2.53 0.9.93 2.2.54 0.9.94 2.2.56 0.9.95 2.2.57 0.9.96 2.2.6 0.9.97 2.2.60 0.9.98 2.2.61 0.9.99 2.2.62 1.0.0 2.2.63 1.0.01 2.2.70 1.0.1 2.2.80 1.0.2 2.2.81 1.0.3 2.2.90 1.0.4 2.2.91 1.0.5 2.2.92 1.0.6 2.2.93 1.0.7 2.2.94 1.0.8 2.2.95 1.0.9 2.3.0 1.1.0 2.3.1 1.1.1 2.3.2 1.1.2 2.3.3 1.1.3 2.3.4 1.1.4 2.3.5 1.1.5 2.3.6 1.1.6 2.3.7 1.1.7 2.3.8 1.1.8 2.3.9 1.1.9 2.4.0 1.2.0 2.4.1 1.2.1 2.4.2 1.2.2 2.4.3 1.2.21 2.4.4 1.2.3 2.4.5 1.2.30 2.4.6 1.3.0 2.4.7 1.3.1 2.4.8 1.3.2 2.4.9 1.3.3 2.5.0 1.3.31 2.5.1 1.3.32 2.5.2 1.3.33 2.5.3 1.3.34 2.5.4 1.3.35 2.5.5 1.3.36 2.5.6 1.3.37 2.5.7 1.3.38 2.5.8 1.3.39 2.5.9 1.3.40 2.6.0 1.3.41 2.6.1 1.3.42 2.6.2 1.3.43 2.6.3 1.3.44 2.6.5 1.3.45 2.6.6 1.3.46 2.6.7 1.3.47 2.6.8 1.3.48 2.6.9 1.3.49 2.7.0 1.3.50 2.7.1 1.3.51 2.7.2 1.3.52 2.7.3 1.3.53 2.7.4 1.3.54 2.7.5 1.3.56 2.7.6 1.3.57 2.7.7 1.3.58 2.7.8 1.3.59 2.7.9 1.3.60 2.8.0 1.3.61 2.8.1 1.3.62 2.8.2 1.3.63 2.8.3 1.3.64 2.8.4 1.3.65 2.8.5 1.3.66 2.8.6 1.3.67 2.8.7 1.3.68 2.8.8 1.3.69 2.8.9 1.3.70 2.9.0 1.3.71 2.9.1 1.3.72 2.9.2 1.3.73 2.9.3 1.3.74 2.9.4 1.3.75 2.9.5 1.3.76 2.9.6 1.3.77 2.9.7 1.3.78 2.9.8 1.3.79 2.9.9 1.3.80 3.0.0 1.3.81 3.0.1 1.3.82 3.0.2 1.3.83 3.0.3 1.3.84 3.0.4 1.3.85 3.0.5 1.3.86 3.0.6 1.3.87 3.0.7 1.3.88 3.0.8 1.3.89 3.0.9 1.3.90 3.1.0 1.3.91 3.1.1 1.3.92 3.1.2 1.3.93 3.1.3 1.3.94 3.1.4 1.3.95 3.1.5 1.3.96 3.1.6 1.3.97 3.1.7 1.3.98 3.1.8 1.3.99 3.1.9 1.4.0 3.2.0 1.4.1 3.2.1 1.4.2 3.2.2 1.4.3 3.2.3 1.4.4 3.2.4 1.4.5 3.2.5 1.4.6 3.2.6 1.4.7 3.2.7 1.4.8 3.2.8 1.4.9 3.2.9 1.5.0 3.3.0 1.5.1 3.3.1 1.5.2 3.3.2 1.5.3 3.3.3 1.5.4 3.3.4 1.5.5 3.3.5 1.5.6 3.3.6 1.5.7 3.3.7 1.5.8 3.3.8 1.5.9 3.3.9 1.6.0 3.4.0 1.6.1 3.4.1 1.6.2 3.4.2 1.6.3 3.4.3 1.6.5 3.4.4 1.6.51 3.4.5 1.6.52 3.4.6 1.6.53 1.6.54 1.6.55 1.6.56 1.6.57 1.6.58 1.6.59 1.6.60 1.6.61 1.6.62 1.6.63 1.6.64 1.6.65 1.6.66 1.6.67 1.6.68 trunk 1.6.69 0.0.1 1.6.70 0.0.2 1.6.71 0.0.3 1.6.72 0.0.4 1.6.73 0.0.5 1.6.74 0.0.6 1.6.75 0.0.7 1.6.76 0.0.8 1.6.77 0.0.9 1.6.78 0.1.0 1.6.79 0.1.1 1.6.81 0.1.2 1.6.82 0.1.3 1.6.83 0.1.4 1.6.84 0.1.5 1.6.85 0.1.6 1.6.86 0.1.7 1.6.87 0.1.8 1.6.88 0.1.9 1.6.89 0.2.0 1.6.90
ai-engine / classes / admin.php
ai-engine / classes Last commit date
data 1 year ago engines 2 days ago exceptions 3 days ago modules 2 days ago query 3 days ago services 2 days ago admin.php 2 days ago api.php 3 weeks ago core.php 3 days ago discussion.php 1 year ago event.php 1 year ago init.php 3 days ago logging.php 1 year ago reply.php 3 days ago rest.php 2 days ago
admin.php
499 lines
1 <?php
2
3 class Meow_MWAI_Admin extends MeowKit_MWAI_Admin {
4 public $core;
5 public $contentGeneratorEnabled;
6 public $imagesGeneratorEnabled;
7 public $videosGeneratorEnabled;
8 public $playgroundEnabled;
9 public $suggestionsEnabled;
10
11 public function __construct( $core ) {
12 $this->core = $core;
13 parent::__construct( MWAI_PREFIX, MWAI_ENTRY, MWAI_DOMAIN, class_exists( 'MeowPro_MWAI_Core' ) );
14 if ( is_admin() ) {
15 $this->contentGeneratorEnabled = $this->core->get_option( 'module_generator_content' );
16 $this->imagesGeneratorEnabled = $this->core->get_option( 'module_generator_images' );
17 $this->videosGeneratorEnabled = $this->core->get_option( 'module_generator_videos' );
18 $this->playgroundEnabled = $this->core->get_option( 'module_playground' );
19 $can_access_settings = $this->core->can_access_settings();
20 $can_access_features = $this->core->can_access_features();
21
22 if ( $can_access_settings || $can_access_features ) {
23 add_action( 'admin_enqueue_scripts', [ $this, 'admin_enqueue_scripts' ] );
24 }
25
26 if ( $can_access_settings ) {
27 add_action( 'admin_menu', [ $this, 'app_menu' ] );
28 }
29
30 if ( $can_access_features ) {
31 add_action( 'admin_menu', [ $this, 'admin_menu' ] );
32
33 // Only if the Suggestions are enabled.
34 $this->suggestionsEnabled = $this->core->get_option( 'module_suggestions' );
35 if ( $this->suggestionsEnabled ) {
36 add_filter( 'post_row_actions', [ $this, 'post_row_actions' ], 10, 2 );
37 add_filter( 'page_row_actions', [ $this, 'post_row_actions' ], 10, 2 );
38 }
39
40 if ( $this->imagesGeneratorEnabled ) {
41 add_filter( 'media_row_actions', [ $this, 'media_row_actions' ], 10, 2 );
42 }
43
44 add_action( 'admin_footer', [ $this, 'admin_footer' ] );
45 }
46 }
47 }
48
49 public function admin_menu() {
50
51 // Generate New (under Posts)
52 if ( $this->contentGeneratorEnabled ) {
53 add_submenu_page(
54 'edit.php',
55 'Generate New',
56 'Generate New',
57 'read',
58 'mwai_content_generator',
59 [ $this, 'ai_content_generator' ],
60 2
61 );
62 }
63
64 // In Tools
65 if ( $this->playgroundEnabled ) {
66 add_management_page(
67 'Playground',
68 __( 'Playground', 'ai-engine' ),
69 'read',
70 'mwai_dashboard',
71 [ $this, 'ai_playground' ]
72 );
73 }
74 if ( $this->contentGeneratorEnabled ) {
75 add_management_page(
76 'Generate Content',
77 'Generate Content',
78 'read',
79 'mwai_content_generator',
80 [ $this, 'ai_content_generator' ]
81 );
82 }
83 if ( $this->imagesGeneratorEnabled ) {
84 add_management_page(
85 'Generate Images',
86 'Generate Images',
87 'read',
88 'mwai_images_generator',
89 [ $this, 'ai_image_generator' ]
90 );
91 }
92 if ( $this->videosGeneratorEnabled ) {
93 add_management_page(
94 'Generate Videos',
95 'Generate Videos',
96 'read',
97 'mwai_videos_generator',
98 [ $this, 'ai_video_generator' ]
99 );
100 }
101
102 // In the Admin Bar:
103 add_action( 'admin_bar_menu', [ $this, 'admin_bar_menu' ], 100 );
104 }
105
106 public function admin_bar_menu( $wp_admin_bar ) {
107
108 $admin_bar = $this->core->get_option( 'admin_bar' );
109 $settings = isset( $admin_bar['settings'] ) && $admin_bar['settings'];
110 $playground = isset( $admin_bar['playground'] ) && $admin_bar['playground'];
111 $content_generator = isset( $admin_bar['content_generator'] ) && $admin_bar['content_generator'];
112 $images_generator = isset( $admin_bar['images_generator'] ) && $admin_bar['images_generator'];
113 $videos_generator = isset( $admin_bar['videos_generator'] ) && $admin_bar['videos_generator'];
114 // Workspace is checked by default (a missing key counts as enabled), but
115 // only appears when the module is on and its class is loaded. The Workspace
116 // itself is free core; Knowledge, MCP Servers and Functions inside it are Pro.
117 $workspace = ( !isset( $admin_bar['workspace'] ) || $admin_bar['workspace'] ) &&
118 $this->core->get_option( 'module_workspace' ) &&
119 class_exists( 'Meow_MWAI_Modules_Workspace' ) &&
120 current_user_can( 'manage_options' );
121
122 if ( $settings ) {
123 $wp_admin_bar->add_node( [
124 'id' => 'mwai-settings',
125 'title' => '<span class="ab-icon dashicons-before dashicons-admin-settings" style="top: 2px;"></span>' . __( 'AI Engine', 'ai-engine' ),
126 'href' => admin_url( 'admin.php?page=mwai_settings' ),
127 'meta' => [ 'class' => 'mwai-settings' ],
128 ] );
129 }
130
131 if ( $content_generator ) {
132 $wp_admin_bar->add_node( [
133 'id' => 'mwai-content-generator',
134 'title' => MWAI_IMG_WAND_HTML . __( 'Content', 'ai-engine' ),
135 'href' => admin_url( 'tools.php?page=mwai_content_generator' ),
136 'meta' => [ 'class' => 'mwai-content-generator' ],
137 ] );
138 }
139 if ( $images_generator ) {
140 $wp_admin_bar->add_node( [
141 'id' => 'mwai-image-generator',
142 'title' => MWAI_IMG_WAND_HTML . __( 'Images', 'ai-engine' ),
143 'href' => admin_url( 'tools.php?page=mwai_images_generator' ),
144 'meta' => [ 'class' => 'mwai-images-generator' ],
145 ] );
146 }
147 if ( $videos_generator ) {
148 $wp_admin_bar->add_node( [
149 'id' => 'mwai-video-generator',
150 'title' => MWAI_IMG_WAND_HTML . __( 'Videos', 'ai-engine' ),
151 'href' => admin_url( 'tools.php?page=mwai_videos_generator' ),
152 'meta' => [ 'class' => 'mwai-videos-generator' ],
153 ] );
154 }
155
156 // The Global Magic Wand
157 // if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
158 // $wp_admin_bar->add_node( array(
159 // 'id' => 'mwai-debug',
160 // 'title' => MWAI_IMG_WAND_HTML . __( 'Magic Wand', 'ai-engine' ),
161 // //'href' => admin_url( 'tools.php?page=mwai_debug' ),
162 // 'meta' => array( 'class' => 'mwai-debug' ),
163 // ) );
164 // }
165
166 if ( $playground ) {
167 $wp_admin_bar->add_node( [
168 'id' => 'mwai-playground',
169 'title' => MWAI_IMG_WAND_HTML . __( 'Playground', 'ai-engine' ),
170 'href' => admin_url( 'tools.php?page=mwai_dashboard' ),
171 'meta' => [ 'class' => 'mwai-playground' ],
172 ] );
173 }
174
175 if ( $workspace ) {
176 $nyao = "<img style='height: 20px; margin-bottom: -5px; margin-right: 8px;' src='" .
177 MWAI_URL . "images/chat-nyao-1.svg' alt='Workspace' />";
178 $wp_admin_bar->add_node( [
179 'id' => 'mwai-workspace',
180 'title' => $nyao . __( 'Workspace', 'ai-engine' ),
181 'href' => admin_url( 'admin.php?page=mwai_workspace' ),
182 'meta' => [ 'class' => 'mwai-workspace' ],
183 ] );
184 }
185 }
186
187 public function ai_playground() {
188 echo '<div id="mwai-playground"></div>';
189 }
190
191 public function ai_content_generator() {
192 echo '<div id="mwai-content-generator"></div>';
193 }
194
195 public function ai_image_generator() {
196 echo '<div id="mwai-image-generator"></div>';
197 }
198
199 public function ai_video_generator() {
200 echo '<div id="mwai-video-generator"></div>';
201 }
202
203 public function post_row_actions( $actions, $post ) {
204 $actions['ai_magic_wand'] = '<span class="mwai-magic-wand-action" data-id="' . $post->ID . '" data-title="' . esc_attr( $post->post_title ) . '">
205 <a href="#" class="mwai-magic-wand-trigger">' . MWAI_IMG_WAND_HTML_XS . ' ' . __( 'Magic Wand', 'ai-engine' ) . '</a>
206 <div class="mwai-magic-wand-dropdown" style="display: none;">
207 <a class="mwai-link-title" href="#" data-id="' . $post->ID . '" data-title="' . esc_attr( $post->post_title ) . '">
208 <span class="dashicons dashicons-edit" style="font-size: 14px; line-height: 1.4; margin-right: 4px; pointer-events: none;"></span>' . __( 'Generate Title', 'ai-engine' ) . '
209 </a>
210 <a class="mwai-link-excerpt" href="#" data-id="' . $post->ID . '" data-title="' . esc_attr( $post->post_title ) . '">
211 <span class="dashicons dashicons-text" style="font-size: 14px; line-height: 1.4; margin-right: 4px; pointer-events: none;"></span>' . __( 'Generate Excerpt', 'ai-engine' ) . '
212 </a>
213 </div>
214 </span>';
215 return $actions;
216 }
217
218 public function media_row_actions( $actions, $post ) {
219 if ( strpos( $post->post_mime_type, 'image/' ) === 0 ) {
220 $url = admin_url( 'tools.php?page=mwai_images_generator&editId=' . $post->ID );
221 $actions['mwai_remix'] = '<a href="' . $url . '">' . MWAI_IMG_WAND_HTML_XS . ' ' . __( 'Edit', 'ai-engine' ) . '</a>';
222 }
223 return $actions;
224 }
225
226 public function admin_footer() {
227 // Don't add our admin footer div on the Site Editor
228 $current_screen = get_current_screen();
229 if ( $current_screen && $current_screen->base === 'site-editor' ) {
230 return;
231 }
232 echo '<div id="mwai-admin-postsList"></div>';
233
234 // Add CSS for Magic Wand dropdown
235 ?>
236 <style>
237 .mwai-magic-wand-action {
238 position: relative;
239 display: inline-block;
240 }
241
242 .mwai-magic-wand-trigger {
243 text-decoration: none;
244 }
245
246 .mwai-magic-wand-dropdown {
247 position: absolute;
248 top: 100%;
249 left: 0;
250 background: #fff;
251 border: 1px solid #c3c4c7;
252 border-radius: 4px;
253 box-shadow: 0 2px 5px rgba(0,0,0,0.15);
254 min-width: 150px;
255 z-index: 1000;
256 margin-top: 4px;
257 }
258
259 .mwai-magic-wand-dropdown a {
260 display: flex;
261 align-items: center;
262 padding: 8px 12px;
263 text-decoration: none;
264 color: #2271b1;
265 border-bottom: 1px solid #f0f0f1;
266 white-space: nowrap;
267 }
268
269 .mwai-magic-wand-dropdown a .dashicons {
270 width: 16px;
271 height: 16px;
272 font-size: 14px;
273 }
274
275 .mwai-magic-wand-dropdown a:last-child {
276 border-bottom: none;
277 }
278
279 .mwai-magic-wand-dropdown a:hover {
280 background: #f0f6fc;
281 color: #135e96;
282 }
283
284 /* Ensure dropdown stays visible when hovering over it */
285 .mwai-magic-wand-action:hover .mwai-magic-wand-dropdown {
286 display: block !important;
287 }
288 </style>
289 <?php
290 }
291
292 /**
293 * Strip the site's secrets out of the options before they are localized.
294 *
295 * This script is enqueued for can_access_features(), which is Editor or above, but the
296 * Settings screen behind it is manage_options. Without this, an Editor opening any
297 * wp-admin page could read every provider API key and both bearer tokens straight from
298 * the page source. Administrators keep the real values so Settings still works.
299 *
300 * The secrets are masked rather than removed: helpers-admin.js only tests whether a key
301 * is a non-empty string to decide if an environment is configured, so dropping them
302 * would show Editors a false "no API key" warning.
303 */
304 private function redact_secrets( $options ) {
305 if ( !is_array( $options ) || $this->core->can_access_settings() ) {
306 return $options;
307 }
308 $mask = '********';
309 $secret = '/(apikey|api_key|bearer_token|token|secret|password)/i';
310 foreach ( $options as $key => $value ) {
311 if ( is_string( $value ) && $value !== '' && preg_match( $secret, $key ) ) {
312 $options[$key] = $mask;
313 }
314 }
315 foreach ( [ 'ai_envs', 'embeddings_envs', 'mcp_envs' ] as $envKey ) {
316 if ( empty( $options[$envKey] ) || !is_array( $options[$envKey] ) ) {
317 continue;
318 }
319 foreach ( $options[$envKey] as $i => $env ) {
320 if ( !is_array( $env ) ) {
321 continue;
322 }
323 foreach ( $env as $field => $value ) {
324 if ( is_string( $value ) && $value !== '' && preg_match( $secret, $field ) ) {
325 $options[$envKey][$i][$field] = $mask;
326 }
327 }
328 }
329 }
330 return $options;
331 }
332
333 public function admin_enqueue_scripts() {
334 // Previously bailed entirely on the Site Editor to avoid conflicts, but that left
335 // our block types unregistered there - patterns created via Appearance > Editor saved
336 // broken "Unsupported" placeholders for every AI Form/Chatbot block. The conditional
337 // dependency logic below already keeps wp-edit-post out of the Site Editor dep list,
338 // so the bundle can safely load here for block registration while the admin UI
339 // render targets (mwai-admin-settings, etc.) simply don't exist.
340 $current_screen = get_current_screen();
341
342 $physical_file = MWAI_PATH . '/app/index.js';
343 $cache_buster = file_exists( $physical_file ) ? filemtime( $physical_file ) : MWAI_VERSION;
344
345 // Cache override: Force cache refresh when ?mwai_cache=1 is in URL
346 if ( isset( $_GET['mwai_cache'] ) ) {
347 $cache_buster = time(); // Use current timestamp for guaranteed cache bust
348 }
349
350 wp_register_script( 'mwai-vendor', MWAI_URL . 'app/vendor.js', null, $cache_buster );
351
352 // Base dependencies
353 $deps = [ 'mwai-vendor', 'wp-element', 'wp-components', 'wp-plugins', 'wp-i18n' ];
354
355 // Check if we're on AI Engine admin pages
356 $is_ai_engine_page = $current_screen && (
357 strpos( $current_screen->id, 'mwai_settings' ) !== false ||
358 strpos( $current_screen->id, 'meowapps_page_mwai' ) !== false ||
359 $current_screen->id === 'meowapps_page_mwai_settings' ||
360 $current_screen->id === 'meowapps_page_mwai-ui' ||
361 strpos( $current_screen->id, 'meowapps' ) !== false && strpos( $_GET['page'] ?? '', 'mwai' ) !== false
362 );
363
364 // Only add wp-edit-post on actual post/page editor screens, not on AI Engine admin pages
365 $is_post_editor = $current_screen && in_array( $current_screen->base, [ 'post', 'page' ] );
366 if ( $is_post_editor ) {
367 $deps[] = 'wp-edit-post';
368 }
369
370 // Load block editor deps if:
371 // 1. We're on AI Engine admin pages (Forms.js component is always imported by Settings.js) OR
372 // 2. We are on a block editor screen (Edit Post)
373 $forms_module_enabled = $this->core->get_option( 'module_forms' );
374 $load_forms_editor = $forms_module_enabled && $this->core->get_option( 'forms_editor' );
375 $on_block_editor = function_exists( 'wp_should_load_block_editor_scripts_and_styles' ) && wp_should_load_block_editor_scripts_and_styles();
376
377 // Always load block editor deps on AI Engine admin pages because Forms.js is always imported
378 if ( $is_ai_engine_page || $on_block_editor ) {
379 $deps = array_merge( $deps, [ 'wp-blocks', 'wp-block-editor', 'wp-format-library', 'wp-block-library', 'wp-editor' ] );
380 }
381
382 wp_register_script( 'mwai', MWAI_URL . 'app/index.js', $deps, $cache_buster );
383 wp_enqueue_script( 'mwai' );
384
385 // Ensure core editor styles are available for embedded block editor UIs
386 // This helps Popovers, Inspector, and toolbars match Gutenberg styling
387 if ( function_exists( 'wp_enqueue_style' ) ) {
388 // Only load wp-edit-post styles on actual post/page editor screens
389 if ( $is_post_editor ) {
390 @wp_enqueue_style( 'wp-edit-post' );
391 }
392 @wp_enqueue_style( 'wp-components' );
393
394 // Load block editor styles if we're on AI Engine pages or on block editor
395 if ( $is_ai_engine_page || $on_block_editor ) {
396 @wp_enqueue_style( 'wp-block-editor' );
397 @wp_enqueue_style( 'wp-block-library' );
398 }
399 }
400 // Make sure core blocks and format tools are registered/available
401 if ( function_exists( 'wp_enqueue_script' ) ) {
402 if ( $is_ai_engine_page || $on_block_editor ) {
403 @wp_enqueue_script( 'wp-format-library' );
404 @wp_enqueue_script( 'wp-block-library' );
405 @wp_enqueue_script( 'wp-editor' );
406 }
407 }
408
409 // The MD5 of the translation file built by WP uses app/i18n.js instead of app/index.js
410 add_filter( 'load_script_translation_file', function ( $file, $handle, $domain ) {
411 if ( $domain !== 'ai-engine' ) {
412 return $file;
413 }
414 $file = str_replace( md5( 'app/index.js' ), md5( 'app/i18n.js' ), $file );
415 return $file;
416 }, 10, 3 );
417
418 // This is useless for AI Engine, but it avoids issues when themes and plugin calls
419 // wp_enqueue_media too late (usually, they call it in the footer). Until someone
420 // figures out what the issue is, let's load it here.
421 wp_enqueue_media();
422
423 wp_set_script_translations( 'mwai', 'ai-engine' );
424
425 // Prepare localization data
426 // Get build reference for asset management
427 $build_ref = null;
428 if ( class_exists( 'MeowKitPro_MWAI_Integrity' ) ) {
429 $integrity = new MeowKitPro_MWAI_Integrity( MWAI_PREFIX, MWAI_PATH );
430 $build_ref = $integrity->get_build_ref( MWAI_VERSION );
431 }
432
433 $localize_data = [
434 'api_url' => get_rest_url( null, 'mwai/v1' ),
435 'rest_url' => get_rest_url(),
436 'plugin_url' => MWAI_URL,
437 'user_data' => $this->core->get_user_data(),
438 'prefix' => MWAI_PREFIX,
439 'domain' => MWAI_DOMAIN,
440 'is_pro' => class_exists( 'MeowPro_MWAI_Core' ),
441 'is_registered' => !!$this->is_registered(),
442 'build_ref' => $build_ref,
443 'rest_nonce' => wp_create_nonce( 'wp_rest' ),
444 'session' => $this->core->get_session_id(),
445 'options' => $this->redact_secrets( $this->core->get_all_options() ),
446 'chatbots' => $this->core->get_chatbots(),
447 'themes' => $this->core->get_themes(),
448 'stream' => $this->core->get_option( 'ai_streaming' ),
449 'cache_buster' => $cache_buster, // Pass cache buster for lazy-loaded chunks
450 'fallback_models' => [
451 'default' => MWAI_FALLBACK_MODEL,
452 'fast' => MWAI_FALLBACK_MODEL_FAST,
453 'vision' => MWAI_FALLBACK_MODEL_VISION,
454 'json' => MWAI_FALLBACK_MODEL_JSON,
455 'images' => MWAI_FALLBACK_MODEL_IMAGES,
456 'audio' => MWAI_FALLBACK_MODEL_AUDIO,
457 'embeddings' => MWAI_FALLBACK_MODEL_EMBEDDINGS,
458 ],
459 'integrations' => [
460 'polylang' => function_exists( 'pll_get_post_language' ),
461 'woocommerce' => class_exists( 'WooCommerce' ),
462 ],
463 // So the admin can render stored UTC timestamps in the site's timezone.
464 'timezone' => [
465 'string' => get_option( 'timezone_string' ),
466 'offset' => (float) get_option( 'gmt_offset' ),
467 ],
468 ];
469
470 wp_localize_script( 'mwai', 'mwai', $localize_data );
471 }
472
473 public function is_registered() {
474 return apply_filters( MWAI_PREFIX . '_meowapps_is_registered', false, MWAI_PREFIX );
475 }
476
477 public function app_menu() {
478 // The menu is only registered when can_access_settings() passed (see __construct).
479 // Pass a low cap here so WordPress doesn't hide the submenu from filter-approved
480 // users who don't have manage_options. The page callback re-checks access for
481 // defense in depth.
482 add_submenu_page(
483 'meowapps-main-menu',
484 'AI Engine',
485 'AI Engine',
486 'read',
487 'mwai_settings',
488 [ $this, 'admin_settings' ]
489 );
490 }
491
492 public function admin_settings() {
493 if ( !$this->core->can_access_settings() ) {
494 wp_die( __( 'Sorry, you are not allowed to access this page.', 'ai-engine' ), 403 );
495 }
496 echo '<div id="mwai-admin-settings"></div>';
497 }
498 }
499