PluginProbe
Code Engine – PHP Snippets, AI Functions & Automation for WordPress / 0.5.7
Code Engine – PHP Snippets, AI Functions & Automation for WordPress v0.5.7
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 +104 -20 0.4.70.5.7 View file →
@@ -160,9 +160,9 @@
160 160
161 161 // Promote AI Engine on the WordPress 7 Connectors page when AI Engine
162 162 // itself isn't installed. When AI Engine is active, its own banner
163 163 // takes over — so this path only runs on "bare" Meow Apps installs.
164 - add_action( 'admin_footer', [ $this, 'maybe_render_wpai_promo' ] );
164 + add_action( 'admin_enqueue_scripts', [ $this, 'maybe_render_wpai_promo' ] );
165 165
166 166 MeowKit_MWCODE_Admin::$loaded = true;
167 167 }
168 168
@@ -202,8 +202,45 @@
202 202 if ( !$isActive ) {
203 203 return $links;
204 204 }
205 205 $isIssue = $this->isPro && !$this->is_registered();
206 +
207 + // The licenser already knows WHY validation failed and stores it as
208 + // license['issue'] (licenser.php), but this badge used to render a flat
209 + // "License Issue" for every case. That sent people to support to ask a
210 + // question the plugin could have answered: the most common one by far is a
211 + // licence whose activation slot is held by another site, which reads as
212 + // "my licence is broken" and gets reported as a billing problem.
213 + $issueLabel = __( 'License Issue', $this->domain );
214 + if ( $isIssue ) {
215 + $license = get_option( $this->prefix . '_license', '' );
216 + $issue = is_array( $license ) && !empty( $license['issue'] ) ? $license['issue'] : null;
217 + // Codes the store actually sends. Verified against EDD Software Licensing
218 + // rather than guessed: an invented key would silently never match, and a
219 + // wrong label is worse than the generic one.
220 + $labels = [
221 + // `error` codes, from a failed activation.
222 + 'no_activations_left' => __( 'License in use on another site', $this->domain ),
223 + 'expired' => __( 'License expired', $this->domain ),
224 + 'disabled' => __( 'License revoked', $this->domain ),
225 + 'missing' => __( 'License key not recognized', $this->domain ),
226 + 'key_mismatch' => __( 'License key not recognized', $this->domain ),
227 + 'item_name_mismatch' => __( 'License is for another plugin', $this->domain ),
228 + 'invalid_item_id' => __( 'License is for another plugin', $this->domain ),
229 + 'missing_item_id' => __( 'License is for another plugin', $this->domain ),
230 + 'bundle_activation_not_allowed' => __( 'This license cannot be activated directly', $this->domain ),
231 + // `license` statuses, when the key is known but not valid here.
232 + 'site_inactive' => __( 'License not activated on this site', $this->domain ),
233 + 'inactive' => __( 'License not activated on this site', $this->domain ),
234 + // Genuinely no answer from the store. NOT invalid_response, which means the
235 + // store replied and we could not make sense of it: blaming the connection
236 + // there would send people chasing a firewall that is working fine.
237 + 'no_response' => __( 'License server unreachable', $this->domain ),
238 + ];
239 + if ( $issue !== null && isset( $labels[ $issue ] ) ) {
240 + $issueLabel = $labels[ $issue ];
241 + }
242 + }
206 243 if ( strpos( $pathName, $thisPathName ) !== false ) {
207 244 // In network admin, handle differently (no settings page available)
208 245 if ( is_network_admin() ) {
209 246 if ( $this->isPro && !$this->is_registered() ) {
@@ -244,9 +281,9 @@
244 281 sprintf( __( '<a href="admin.php?page=%s_settings">Settings</a>', $this->domain ), $this->prefix ),
245 282 'license' =>
246 283 $this->is_registered() ?
247 284 ( '<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>' ) ),
285 + ( $isIssue ? ( '<span style="color: #ff3434;">' . esc_html( $issueLabel ) . '</span>' ) : ( sprintf( '<span>' . __( '<a target="_blank" href="https://meowapps.com">Get the <u>Pro Version</u></a>', $this->domain ), $this->prefix ) . '</span>' ) ),
249 286 ];
250 287 }
251 288 $links = array_merge( $new_links, $links );
252 289 }
@@ -272,9 +309,11 @@
272 309 <button type="button" id="meowapps-license-submit" class="button button-primary">Validate & Register</button>
273 310 </div>
274 311 </div>
275 312 </div>
276 - <script>
313 + <?php
314 + ob_start();
315 + ?>
277 316 (function() {
278 317 var modal = document.getElementById('meowapps-network-license-modal');
279 318 var input = document.getElementById('meowapps-license-key-input');
280 319 var message = document.getElementById('meowapps-license-message');
@@ -384,10 +423,10 @@
384 423 submitBtn.textContent = 'Validate & Register';
385 424 });
386 425 });
387 426 })();
388 - </script>
389 427 <?php
428 + wp_print_inline_script_tag( ob_get_clean() );
390 429 }
391 430
392 431 public function request_verify_ssl() {
393 432 return get_option( 'force_sslverify', false );
@@ -405,9 +444,12 @@
405 444 return $file;
406 445 }
407 446
408 447 public function admin_notices_licensed_free() {
409 - if ( isset( $_POST[$this->prefix . '_reset_sub'] ) ) {
448 + // Verify the nonce before removing the license from a POST request (CSRF protection).
449 + if ( isset( $_POST[$this->prefix . '_reset_sub'] )
450 + && isset( $_POST[ $this->prefix . '_reset_sub_nonce' ] )
451 + && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST[ $this->prefix . '_reset_sub_nonce' ] ) ), $this->prefix . '_reset_sub' ) ) {
410 452 delete_option( $this->prefix . '_pro_serial' );
411 453 delete_option( $this->prefix . '_license' );
412 454 return;
413 455 }
@@ -417,9 +459,9 @@
417 459 $this->nice_name_from_file( $this->mainfile )
418 460 );
419 461 $html .= '<p>
420 462 <form method="post" action="">
421 - <input type="hidden" name="' . $this->prefix . '_reset_sub" value="true">
463 + <input type="hidden" name="' . $this->prefix . '_reset_sub" value="true"><input type="hidden" name="' . $this->prefix . '_reset_sub_nonce" value="' . esc_attr( wp_create_nonce( $this->prefix . '_reset_sub' ) ) . '">
422 464 <input type="submit" name="submit" id="submit" class="button" value="'
423 465 . __( 'Remove the license', $this->domain ) . '">
424 466 </form>
425 467 </p>';
@@ -429,19 +471,23 @@
429 471
430 472 public function admin_menu_start() {
431 473 // Hide the admin if user doesn't like Meow much
432 474 if ( get_option( 'meowapps_hide_meowapps', false ) ) {
433 - register_setting( 'general', 'meowapps_hide_meowapps' );
475 + register_setting( 'general', 'meowapps_hide_meowapps', [ 'type' => 'boolean', 'sanitize_callback' => 'rest_sanitize_boolean' ] );
434 476 add_settings_field( 'meowapps_hide_ads', 'Meow Apps Menu', [ $this, 'meowapps_hide_dashboard_callback' ], 'general' );
435 477 return;
436 478 }
437 479
438 - // Create standard menu if it does not already exist
480 + // Create standard menu if it does not already exist.
481 + // The cat logo is injected as an <img> inside the menu title (rather than passed as
482 + // the $icon_url argument) so the original SVG fills are preserved — passing it via
483 + // $icon_url makes WordPress add the .svg class and the admin color scheme strips
484 + // the colors to a single fill.
439 485 global $submenu;
440 486 if ( !isset( $submenu[ 'meowapps-main-menu' ] ) ) {
441 487 add_menu_page(
442 488 'Meow Apps',
443 - '<img alt="Meow Apps" style="width: 21px; margin-left: -28px; position: absolute; margin-top: 2px;" src="' . MeowKit_MWCODE_Admin::$logo . '" />Meow Apps',
489 + '<img alt="Meow Apps" class="meowapps-menu-icon" src="' . MeowKit_MWCODE_Admin::$logo . '" />Meow Apps',
444 490 'manage_options',
445 491 'meowapps-main-menu',
446 492 [ $this, 'admin_meow_apps' ],
447 493 '',
@@ -456,15 +502,46 @@
456 502 [ $this, 'admin_meow_apps' ]
457 503 );
458 504 }
459 505
460 - // Add CSS to hide the default icon
461 - add_action( 'admin_head', function () {
462 - echo '<style>
463 - #toplevel_page_meowapps-main-menu .wp-menu-image {
464 - display: none;
465 - }
466 - </style>';
506 + // Position the cat icon so it sits in the standard icon column in both the
507 + // expanded and the collapsed (folded) sidebar.
508 + //
509 + // The image lives inside the .wp-menu-name title (where the original code
510 + // put it) so the <img> renders with its native SVG fills. When the sidebar
511 + // is collapsed, WP hides .wp-menu-name (and everything inside it), so a
512 + // small JS snippet below clones the same <img> into the .wp-menu-image
513 + // slot — which WP keeps visible in both states. We use a real <img>
514 + // (not a background-image) on purpose: at small sizes WP's admin renders
515 + // background-image SVGs noticeably lighter than the equivalent <img>,
516 + // and we want the colored cat in both states.
517 + //
518 + // The !important rules also override an older "display: none" style that
519 + // previous-generation Meow Apps common copies inject for .wp-menu-image;
520 + // if any of them load first, ours still wins.
521 + // Enqueue the menu-icon CSS/JS through the assets API instead of echoing inline tags.
522 + add_action( 'admin_enqueue_scripts', function () {
523 + $css = '
524 + #toplevel_page_meowapps-main-menu .meowapps-menu-icon { width: 20px; height: auto; position: absolute; margin-left: -28px; margin-top: 3px; }
525 + #toplevel_page_meowapps-main-menu .wp-menu-image { display: block !important; position: relative; }
526 + #toplevel_page_meowapps-main-menu .wp-menu-image::before { display: none !important; }
527 + #toplevel_page_meowapps-main-menu .wp-menu-image .meowapps-menu-icon-folded { display: none; position: absolute; top: 50%; left: 50%; transform: translate(-50%, calc(-50% - 3px)); width: 20px; height: auto; }
528 + body.folded #toplevel_page_meowapps-main-menu .wp-menu-image .meowapps-menu-icon-folded { display: block; }
529 + body.folded #toplevel_page_meowapps-main-menu .meowapps-menu-icon { display: none; }
530 + @media only screen and (max-width: 960px) {
531 + body.auto-fold #toplevel_page_meowapps-main-menu .wp-menu-image .meowapps-menu-icon-folded { display: block; }
532 + body.auto-fold #toplevel_page_meowapps-main-menu .meowapps-menu-icon { display: none; }
533 + }';
534 + wp_add_inline_style( 'admin-menu', $css );
535 +
536 + // Clone the in-title cat icon into the .wp-menu-image slot (CSS shows it only when folded).
537 + $js = 'document.addEventListener("DOMContentLoaded", function () {'
538 + . 'var li = document.getElementById("toplevel_page_meowapps-main-menu"); if ( !li ) { return; }'
539 + . 'var src = li.querySelector(".meowapps-menu-icon"); var slot = li.querySelector(".wp-menu-image");'
540 + . 'if ( !src || !slot || slot.querySelector(".meowapps-menu-icon-folded") ) { return; }'
541 + . 'var clone = src.cloneNode(); clone.className = "meowapps-menu-icon-folded"; clone.removeAttribute("style"); slot.appendChild(clone);'
542 + . '});';
543 + wp_add_inline_script( 'common', $js );
467 544 } );
468 545 }
469 546
470 547 public function meowapps_hide_dashboard_callback() {
@@ -564,10 +641,12 @@
564 641 'installUrl' => $install_url,
565 642 'wporgUrl' => $wporg_url,
566 643 'learnUrl' => $learn_url,
567 644 );
645 + wp_register_style( 'meowapps-common-inline', false );
646 + wp_enqueue_style( 'meowapps-common-inline' );
647 + ob_start();
568 648 ?>
569 - <style>
570 649 .meowapps-wpai-promo {
571 650 margin: 0 0 16px; padding: 14px 18px;
572 651 display: flex; align-items: flex-start; gap: 14px;
573 652 background: #f0f4ff; border: 1px solid #d6deff; border-radius: 4px;
@@ -610,10 +689,15 @@
610 689 background: transparent; color: #6b7280;
611 690 font-weight: 500; padding: 7px 10px;
612 691 }
613 692 .meowapps-wpai-promo-btn-dismiss:hover { color: #1e1e1e; background: rgba(0,0,0,0.04); }
614 - </style>
615 - <script>
693 + <?php
694 + wp_add_inline_style( 'meowapps-common-inline', ob_get_clean() );
695 +
696 + wp_register_script( 'meowapps-common-inline', false, array(), false, true );
697 + wp_enqueue_script( 'meowapps-common-inline' );
698 + ob_start();
699 + ?>
616 700 (function () {
617 701 var D = <?php echo wp_json_encode( $payload ); ?>;
618 702 try { if (localStorage.getItem('meowapps-wpai-promo-dismissed') === '1') return; } catch (e) {}
619 703
@@ -694,9 +778,9 @@
694 778 if (app && 'MutationObserver' in window) {
695 779 new MutationObserver(ensure).observe(app, { childList: true, subtree: true });
696 780 }
697 781 })();
698 - </script>
699 782 <?php
783 + wp_add_inline_script( 'meowapps-common-inline', ob_get_clean() );
700 784 }
701 785 }
702 786 }