PluginProbe
Code Engine – PHP Snippets, AI Functions & Automation for WordPress / 0.4.0
Code Engine – PHP Snippets, AI Functions & Automation for WordPress v0.4.0
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 | common/admin.php +10 -377 0.4.60.4.0 View file →
@@ -3,12 +3,10 @@
3 3 if ( !class_exists( 'MeowKit_MWCODE_Admin' ) ) {
4 4
5 5 class MeowKit_MWCODE_Admin {
6 6 public static $loaded = false;
7 - public static $version = '5.0';
8 - public static $admin_version = '5.0';
9 - public static $network_license_modal_added = false;
10 - public static $network_license_plugins = [];
7 + public static $version = '4.0';
8 + public static $admin_version = '4.0';
11 9
12 10 /**
13 11 * Storage for instances that need deferred initialization.
14 12 *
@@ -157,13 +155,8 @@
157 155 if ( $page === 'meowapps-main-menu' ) {
158 156 add_filter( 'admin_footer_text', [ $this, 'admin_footer_text' ], 100000, 1 );
159 157 }
160 158
161 - // Promote AI Engine on the WordPress 7 Connectors page when AI Engine
162 - // itself isn't installed. When AI Engine is active, its own banner
163 - // takes over — so this path only runs on "bare" Meow Apps installs.
164 - add_action( 'admin_footer', [ $this, 'maybe_render_wpai_promo' ] );
165 -
166 159 MeowKit_MWCODE_Admin::$loaded = true;
167 160 }
168 161
169 162 // PER-INSTANCE SETUP: Run for each plugin that uses this library
@@ -203,193 +196,21 @@
203 196 return $links;
204 197 }
205 198 $isIssue = $this->isPro && !$this->is_registered();
206 199 if ( strpos( $pathName, $thisPathName ) !== false ) {
207 - // In network admin, handle differently (no settings page available)
208 - if ( is_network_admin() ) {
209 - if ( $this->isPro && !$this->is_registered() ) {
210 - // Show "Register License" link for unregistered Pro plugins
211 - $new_links = [
212 - 'license' => sprintf(
213 - '<a href="#" class="meowapps-network-license-link" data-prefix="%s" data-plugin="%s" style="color: #d63638;">%s</a>',
214 - esc_attr( $this->prefix ),
215 - esc_attr( $this->nice_name_from_file( $this->mainfile ) ),
216 - __( 'Register License', $this->domain )
217 - ),
218 - ];
219 - // Track this plugin for the modal
220 - self::$network_license_plugins[ $this->prefix ] = $this->nice_name_from_file( $this->mainfile );
221 - // Add modal output hook (only once)
222 - if ( !self::$network_license_modal_added ) {
223 - add_action( 'admin_footer', [ __CLASS__, 'output_network_license_modal' ] );
224 - self::$network_license_modal_added = true;
225 - }
226 - }
227 - elseif ( $this->isPro && $this->is_registered() ) {
228 - // Pro plugin is registered
229 - $new_links = [
230 - 'license' => '<span style="color: #a75bd6;">' . __( 'Pro Version', $this->domain ) . '</span>',
231 - ];
232 - }
233 - else {
234 - // Free plugin
235 - $new_links = [
236 - 'license' => sprintf( '<span>' . __( '<a target="_blank" href="https://meowapps.com">Get the <u>Pro Version</u></a>', $this->domain ), $this->prefix ) . '</span>',
237 - ];
238 - }
239 - }
240 - else {
241 - // Regular admin - show settings and license status
242 - $new_links = [
243 - 'settings' =>
244 - sprintf( __( '<a href="admin.php?page=%s_settings">Settings</a>', $this->domain ), $this->prefix ),
245 - 'license' =>
246 - $this->is_registered() ?
247 - ( '<span style="color: #a75bd6;">' . __( 'Pro Version', $this->domain ) . '</span>' ) :
248 - ( $isIssue ? ( sprintf( '<span style="color: #ff3434;">' . __( 'License Issue', $this->domain ), $this->prefix ) . '</span>' ) : ( sprintf( '<span>' . __( '<a target="_blank" href="https://meowapps.com">Get the <u>Pro Version</u></a>', $this->domain ), $this->prefix ) . '</span>' ) ),
249 - ];
250 - }
200 + $new_links = [
201 + 'settings' =>
202 + sprintf( __( '<a href="admin.php?page=%s_settings">Settings</a>', $this->domain ), $this->prefix ),
203 + 'license' =>
204 + $this->is_registered() ?
205 + ( '<span style="color: #a75bd6;">' . __( 'Pro Version', $this->domain ) . '</span>' ) :
206 + ( $isIssue ? ( sprintf( '<span style="color: #ff3434;">' . __( 'License Issue', $this->domain ), $this->prefix ) . '</span>' ) : ( sprintf( '<span>' . __( '<a target="_blank" href="https://meowapps.com">Get the <u>Pro Version</u></a>', $this->domain ), $this->prefix ) . '</span>' ) ),
207 + ];
251 208 $links = array_merge( $new_links, $links );
252 209 }
253 210 return $links;
254 211 }
255 212
256 - /**
257 - * Output the network license registration modal.
258 - * Called via admin_footer hook in network admin.
259 - */
260 - public static function output_network_license_modal() {
261 - $rest_url = esc_url( rest_url() );
262 - $nonce = wp_create_nonce( 'wp_rest' );
263 - ?>
264 - <div id="meowapps-network-license-modal" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.6); z-index:100000; align-items:center; justify-content:center;">
265 - <div style="background:#fff; padding:24px; border-radius:8px; max-width:450px; width:90%; box-shadow:0 4px 20px rgba(0,0,0,0.3);">
266 - <h2 style="margin:0 0 8px 0; font-size:18px;">Register License</h2>
267 - <p id="meowapps-license-plugin-name" style="margin:0 0 16px 0; color:#666;"></p>
268 - <input type="text" id="meowapps-license-key-input" placeholder="Enter your license key" style="width:100%; padding:10px; font-size:14px; border:1px solid #8c8f94; border-radius:4px; box-sizing:border-box;" />
269 - <p id="meowapps-license-message" style="margin:12px 0 0 0; padding:10px; border-radius:4px; display:none;"></p>
270 - <div style="margin-top:16px; display:flex; gap:10px; justify-content:flex-end;">
271 - <button type="button" id="meowapps-license-cancel" class="button">Cancel</button>
272 - <button type="button" id="meowapps-license-submit" class="button button-primary">Validate & Register</button>
273 - </div>
274 - </div>
275 - </div>
276 - <script>
277 - (function() {
278 - var modal = document.getElementById('meowapps-network-license-modal');
279 - var input = document.getElementById('meowapps-license-key-input');
280 - var message = document.getElementById('meowapps-license-message');
281 - var pluginName = document.getElementById('meowapps-license-plugin-name');
282 - var submitBtn = document.getElementById('meowapps-license-submit');
283 - var cancelBtn = document.getElementById('meowapps-license-cancel');
284 - var currentPrefix = '';
285 -
286 - function showMessage(text, isError) {
287 - message.textContent = text;
288 - message.style.display = 'block';
289 - message.style.background = isError ? '#fcf0f1' : '#edfaef';
290 - message.style.color = isError ? '#d63638' : '#1e7e34';
291 - message.style.border = '1px solid ' + (isError ? '#d63638' : '#1e7e34');
292 - }
293 -
294 - function hideMessage() {
295 - message.style.display = 'none';
296 - }
297 -
298 - function openModal(prefix, plugin) {
299 - currentPrefix = prefix;
300 - pluginName.textContent = plugin;
301 - input.value = '';
302 - hideMessage();
303 - submitBtn.disabled = false;
304 - submitBtn.textContent = 'Validate & Register';
305 - modal.style.display = 'flex';
306 - input.focus();
307 - }
308 -
309 - function closeModal() {
310 - modal.style.display = 'none';
311 - currentPrefix = '';
312 - }
313 -
314 - // Handle click on "Register License" links
315 - document.addEventListener('click', function(e) {
316 - if (e.target.classList.contains('meowapps-network-license-link')) {
317 - e.preventDefault();
318 - var prefix = e.target.getAttribute('data-prefix');
319 - var plugin = e.target.getAttribute('data-plugin');
320 - openModal(prefix, plugin);
321 - }
322 - });
323 -
324 - // Close modal on cancel or clicking outside
325 - cancelBtn.addEventListener('click', closeModal);
326 - modal.addEventListener('click', function(e) {
327 - if (e.target === modal) closeModal();
328 - });
329 -
330 - // Handle escape key
331 - document.addEventListener('keydown', function(e) {
332 - if (e.key === 'Escape' && modal.style.display === 'flex') {
333 - closeModal();
334 - }
335 - });
336 -
337 - // Handle enter key in input
338 - input.addEventListener('keydown', function(e) {
339 - if (e.key === 'Enter') {
340 - submitBtn.click();
341 - }
342 - });
343 -
344 - // Submit license
345 - submitBtn.addEventListener('click', function() {
346 - var licenseKey = input.value.trim();
347 - if (!licenseKey) {
348 - showMessage('Please enter a license key.', true);
349 - return;
350 - }
351 -
352 - submitBtn.disabled = true;
353 - submitBtn.textContent = 'Validating...';
354 - hideMessage();
355 -
356 - var restUrl = '<?php echo $rest_url; ?>meow-licenser/' + currentPrefix + '/v1/set_license/';
357 -
358 - fetch(restUrl, {
359 - method: 'POST',
360 - headers: {
361 - 'Content-Type': 'application/json',
362 - 'X-WP-Nonce': '<?php echo $nonce; ?>'
363 - },
364 - body: JSON.stringify({ serialKey: licenseKey })
365 - })
366 - .then(function(response) { return response.json(); })
367 - .then(function(data) {
368 - if (data.success && data.data && !data.data.issue) {
369 - showMessage('License registered successfully! Reloading...', false);
370 - setTimeout(function() { location.reload(); }, 1500);
371 - } else {
372 - var errorMsg = 'License validation failed.';
373 - if (data.data && data.data.issue) {
374 - errorMsg = 'License issue: ' + data.data.issue;
375 - }
376 - showMessage(errorMsg, true);
377 - submitBtn.disabled = false;
378 - submitBtn.textContent = 'Validate & Register';
379 - }
380 - })
381 - .catch(function(error) {
382 - showMessage('Error: ' + error.message, true);
383 - submitBtn.disabled = false;
384 - submitBtn.textContent = 'Validate & Register';
385 - });
386 - });
387 - })();
388 - </script>
389 - <?php
390 - }
391 -
392 213 public function request_verify_ssl() {
393 214 return get_option( 'force_sslverify', false );
394 215 }
395 216
@@ -508,195 +329,7 @@
508 329 __( 'Thanks for using <a href="https://meowapps.com">Meow Apps</a>! This is the Meow Admin %1$s <br /><i>Loaded from %2$s </i>', $this->domain ),
509 330 MeowKit_MWCODE_Admin::$version,
510 331 __FILE__
511 332 );
512 - }
513 -
514 - /**
515 - * Renders a promo banner on WordPress 7's Connectors page when AI Engine
516 - * isn't installed. Kept self-contained so the common library stays simple:
517 - * no new file, no REST endpoint, dismissal persists in localStorage.
518 - */
519 - public function maybe_render_wpai_promo() {
520 - // WordPress 7+ only.
521 - if ( ! class_exists( 'WP_Connector_Registry' ) ) {
522 - return;
523 - }
524 - // If AI Engine is installed, its own Connectors banner takes over.
525 - if ( class_exists( 'Meow_MWAI_Core' ) ) {
526 - return;
527 - }
528 - // Another Meow Apps plugin's common copy may have rendered already.
529 - if ( defined( 'MEOWAPPS_WPAI_PROMO_RENDERED' ) ) {
530 - return;
531 - }
532 - // Gate on the Connectors screen. The hook suffix differs between the
533 - // direct file (`options-connectors.php`) and the menu-page variant.
534 - $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
535 - $id = $screen ? $screen->id : ( isset( $GLOBALS['hook_suffix'] ) ? $GLOBALS['hook_suffix'] : '' );
536 - $targets = array( 'options-connectors', 'options-connectors.php', 'settings_page_options-connectors-wp-admin' );
537 - if ( ! in_array( $id, $targets, true ) ) {
538 - return;
539 - }
540 - define( 'MEOWAPPS_WPAI_PROMO_RENDERED', true );
541 -
542 - // Install button → WordPress's own plugin-install search page, pre-
543 - // filtered for AI Engine. One click from there to install. This is the
544 - // most reliable path: no custom nonces, native progress UI, native
545 - // filesystem credential prompt if needed.
546 - $can_install = current_user_can( 'install_plugins' );
547 - $install_url = $can_install
548 - ? self_admin_url( 'plugin-install.php?tab=search&type=term&s=AI+Engine' )
549 - : 'https://wordpress.org/plugins/ai-engine/';
550 - $wporg_url = 'https://wordpress.org/plugins/ai-engine/';
551 - $learn_url = 'https://meowapps.com/wordpress-7-ai-engine-gateway/';
552 -
553 - // Title is split so "AI Engine" can carry an anchor to wp.org. Keeping
554 - // the pieces as data (not one HTML string) avoids escaping surprises and
555 - // keeps the translation unit stable.
556 - $payload = array(
557 - 'titleBefore' => __( 'Highly recommended: Let ', 'meowapps' ),
558 - 'titleLink' => __( 'AI Engine', 'meowapps' ),
559 - 'titleAfter' => __( ' handle your connections.', 'meowapps' ),
560 - 'sub' => __( 'One plugin for every provider. Keep your AI setup clean and consistent: monitor your API costs in one place, log every single request, and avoid the mess of juggling separate plugins for each AI model.', 'meowapps' ),
561 - 'install' => __( 'Install AI Engine', 'meowapps' ),
562 - 'learn' => __( 'Learn more', 'meowapps' ),
563 - 'dismiss' => __( 'Dismiss', 'meowapps' ),
564 - 'installUrl' => $install_url,
565 - 'wporgUrl' => $wporg_url,
566 - 'learnUrl' => $learn_url,
567 - );
568 - ?>
569 - <style>
570 - .meowapps-wpai-promo {
571 - margin: 0 0 16px; padding: 14px 18px;
572 - display: flex; align-items: flex-start; gap: 14px;
573 - background: #f0f4ff; border: 1px solid #d6deff; border-radius: 4px;
574 - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
575 - font-size: 13px; line-height: 1.45; color: #1e1e1e;
576 - }
577 - .meowapps-wpai-promo-icon {
578 - width: 32px; height: 32px; border-radius: 50%;
579 - background: #2f5fff; color: #fff;
580 - display: flex; align-items: center; justify-content: center;
581 - flex-shrink: 0;
582 - margin-top: 1px;
583 - }
584 - .meowapps-wpai-promo-icon svg { width: 18px; height: 18px; display: block; }
585 - .meowapps-wpai-promo-body {
586 - flex: 1; min-width: 0;
587 - display: flex; flex-direction: column; gap: 10px;
588 - }
589 - .meowapps-wpai-promo-text strong { font-weight: 700; display: block; margin-bottom: 3px; }
590 - .meowapps-wpai-promo-text span { color: #50575e; }
591 - .meowapps-wpai-promo-titlelink {
592 - color: #2f5fff; text-decoration: none; border-bottom: 1px dashed #2f5fff;
593 - }
594 - .meowapps-wpai-promo-titlelink:hover { color: #2448cc; border-bottom-color: #2448cc; }
595 - .meowapps-wpai-promo-actions {
596 - display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
597 - }
598 - .meowapps-wpai-promo-btn {
599 - appearance: none; border: 1px solid transparent; border-radius: 4px;
600 - padding: 7px 16px; font: inherit; font-size: 12.5px; font-weight: 600;
601 - cursor: pointer; text-decoration: none;
602 - transition: background 0.12s ease, border-color 0.12s ease;
603 - }
604 - .meowapps-wpai-promo-btn-primary { background: #2f5fff; color: #fff; }
605 - .meowapps-wpai-promo-btn-primary:hover { background: #2448cc; color: #fff; }
606 - .meowapps-wpai-promo-btn-secondary { background: #7c3aed; color: #fff; }
607 - .meowapps-wpai-promo-btn-secondary:hover { background: #6527c9; color: #fff; }
608 - .meowapps-wpai-promo-btn-dismiss {
609 - margin-left: auto;
610 - background: transparent; color: #6b7280;
611 - font-weight: 500; padding: 7px 10px;
612 - }
613 - .meowapps-wpai-promo-btn-dismiss:hover { color: #1e1e1e; background: rgba(0,0,0,0.04); }
614 - </style>
615 - <script>
616 - (function () {
617 - var D = <?php echo wp_json_encode( $payload ); ?>;
618 - try { if (localStorage.getItem('meowapps-wpai-promo-dismissed') === '1') return; } catch (e) {}
619 -
620 - function build() {
621 - var host = document.createElement('div');
622 - host.className = 'meowapps-wpai-promo';
623 - host.setAttribute('role', 'status');
624 - var iconSvg = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>';
625 - host.innerHTML = [
626 - '<span class="meowapps-wpai-promo-icon">', iconSvg, '</span>',
627 - '<div class="meowapps-wpai-promo-body">',
628 - '<div class="meowapps-wpai-promo-text">',
629 - '<strong></strong> <span class="meowapps-wpai-promo-sub"></span>',
630 - '</div>',
631 - '<div class="meowapps-wpai-promo-actions"></div>',
632 - '</div>'
633 - ].join('');
634 - // Title carries an anchor on "AI Engine" → wp.org plugin page.
635 - var strong = host.querySelector('strong');
636 - strong.appendChild(document.createTextNode(D.titleBefore));
637 - var tLink = document.createElement('a');
638 - tLink.href = D.wporgUrl;
639 - tLink.target = '_blank';
640 - tLink.rel = 'noopener noreferrer';
641 - tLink.className = 'meowapps-wpai-promo-titlelink';
642 - tLink.textContent = D.titleLink;
643 - strong.appendChild(tLink);
644 - strong.appendChild(document.createTextNode(D.titleAfter));
645 - host.querySelector('.meowapps-wpai-promo-sub').textContent = D.sub;
646 - var actions = host.querySelector('.meowapps-wpai-promo-actions');
647 -
648 - function link(label, cls, href, newTab) {
649 - var a = document.createElement('a');
650 - a.className = 'meowapps-wpai-promo-btn ' + cls;
651 - a.textContent = label;
652 - a.href = href;
653 - if (newTab) { a.target = '_blank'; a.rel = 'noopener noreferrer'; }
654 - actions.appendChild(a);
655 - return a;
656 - }
657 -
658 - // Install → WordPress's plugin-install search page, pre-filtered.
659 - // User lands on a familiar screen with AI Engine as the top hit and
660 - // can install with the native WordPress UX.
661 - link(D.install, 'meowapps-wpai-promo-btn-primary', D.installUrl, false);
662 - link(D.learn, 'meowapps-wpai-promo-btn-secondary', D.learnUrl, true);
663 -
664 - var d = document.createElement('button');
665 - d.type = 'button';
666 - d.className = 'meowapps-wpai-promo-btn meowapps-wpai-promo-btn-dismiss';
667 - d.textContent = D.dismiss;
668 - d.addEventListener('click', function () {
669 - try { localStorage.setItem('meowapps-wpai-promo-dismissed', '1'); } catch (e) {}
670 - if (host.parentNode) host.parentNode.removeChild(host);
671 - });
672 - actions.appendChild(d);
673 - return host;
674 - }
675 -
676 - function ensure() {
677 - if (document.querySelector('.meowapps-wpai-promo')) return;
678 - var page = document.querySelector('.connectors-page');
679 - if (page) { page.insertBefore(build(), page.firstChild); return; }
680 - var header = document.querySelector('.boot-layout__stage header');
681 - if (header && header.parentNode) {
682 - header.parentNode.insertBefore(build(), header.nextSibling);
683 - }
684 - }
685 -
686 - var tries = 0;
687 - var iv = setInterval(function () {
688 - ensure();
689 - if (document.querySelector('.meowapps-wpai-promo') || ++tries > 40) clearInterval(iv);
690 - }, 120);
691 -
692 - var app = document.getElementById('options-connectors-wp-admin-app')
693 - || document.getElementById('options-connectors-app');
694 - if (app && 'MutationObserver' in window) {
695 - new MutationObserver(ensure).observe(app, { childList: true, subtree: true });
696 - }
697 - })();
698 - </script>
699 - <?php
700 333 }
701 334 }
702 335 }