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 +81 -70 0.4.80.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,9 +471,9 @@
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
@@ -475,69 +517,31 @@
475 517 //
476 518 // The !important rules also override an older "display: none" style that
477 519 // previous-generation Meow Apps common copies inject for .wp-menu-image;
478 520 // if any of them load first, ours still wins.
479 - add_action( 'admin_head', function () {
480 - echo '<style>
481 - #toplevel_page_meowapps-main-menu .meowapps-menu-icon {
482 - width: 20px;
483 - height: auto;
484 - position: absolute;
485 - margin-left: -28px;
486 - margin-top: 3px;
487 - }
488 - #toplevel_page_meowapps-main-menu .wp-menu-image {
489 - display: block !important;
490 - position: relative;
491 - }
492 - #toplevel_page_meowapps-main-menu .wp-menu-image::before {
493 - display: none !important;
494 - }
495 - #toplevel_page_meowapps-main-menu .wp-menu-image .meowapps-menu-icon-folded {
496 - display: none;
497 - position: absolute;
498 - top: 50%;
499 - left: 50%;
500 - transform: translate(-50%, calc(-50% - 3px));
501 - width: 20px;
502 - height: auto;
503 - }
504 - body.folded #toplevel_page_meowapps-main-menu .wp-menu-image .meowapps-menu-icon-folded {
505 - display: block;
506 - }
507 - body.folded #toplevel_page_meowapps-main-menu .meowapps-menu-icon {
508 - display: none;
509 - }
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; }
510 530 @media only screen and (max-width: 960px) {
511 - body.auto-fold #toplevel_page_meowapps-main-menu .wp-menu-image .meowapps-menu-icon-folded {
512 - display: block;
513 - }
514 - body.auto-fold #toplevel_page_meowapps-main-menu .meowapps-menu-icon {
515 - display: none;
516 - }
517 - }
518 - </style>';
519 - }, 999 );
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 );
520 535
521 - // Inject a clone of the in-title cat icon into the .wp-menu-image slot.
522 - // CSS above shows it only when the sidebar is folded; in the normal
523 - // expanded state the .wp-menu-name <img> stays the visible icon.
524 - add_action( 'admin_footer', function () {
525 - ?>
526 - <script>
527 - ( function () {
528 - var li = document.getElementById( 'toplevel_page_meowapps-main-menu' );
529 - if ( !li ) { return; }
530 - var src = li.querySelector( '.meowapps-menu-icon' );
531 - var slot = li.querySelector( '.wp-menu-image' );
532 - if ( !src || !slot || slot.querySelector( '.meowapps-menu-icon-folded' ) ) { return; }
533 - var clone = src.cloneNode();
534 - clone.className = 'meowapps-menu-icon-folded';
535 - clone.removeAttribute( 'style' );
536 - slot.appendChild( clone );
537 - } )();
538 - </script>
539 - <?php
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 );
540 544 } );
541 545 }
542 546
543 547 public function meowapps_hide_dashboard_callback() {
@@ -637,10 +641,12 @@
637 641 'installUrl' => $install_url,
638 642 'wporgUrl' => $wporg_url,
639 643 'learnUrl' => $learn_url,
640 644 );
645 + wp_register_style( 'meowapps-common-inline', false );
646 + wp_enqueue_style( 'meowapps-common-inline' );
647 + ob_start();
641 648 ?>
642 - <style>
643 649 .meowapps-wpai-promo {
644 650 margin: 0 0 16px; padding: 14px 18px;
645 651 display: flex; align-items: flex-start; gap: 14px;
646 652 background: #f0f4ff; border: 1px solid #d6deff; border-radius: 4px;
@@ -683,10 +689,15 @@
683 689 background: transparent; color: #6b7280;
684 690 font-weight: 500; padding: 7px 10px;
685 691 }
686 692 .meowapps-wpai-promo-btn-dismiss:hover { color: #1e1e1e; background: rgba(0,0,0,0.04); }
687 - </style>
688 - <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 + ?>
689 700 (function () {
690 701 var D = <?php echo wp_json_encode( $payload ); ?>;
691 702 try { if (localStorage.getItem('meowapps-wpai-promo-dismissed') === '1') return; } catch (e) {}
692 703
@@ -767,9 +778,9 @@
767 778 if (app && 'MutationObserver' in window) {
768 779 new MutationObserver(ensure).observe(app, { childList: true, subtree: true });
769 780 }
770 781 })();
771 - </script>
772 782 <?php
783 + wp_add_inline_script( 'meowapps-common-inline', ob_get_clean() );
773 784 }
774 785 }
775 786 }