| @@ -5,8 +5,10 @@ | ||
| 5 | 5 | class MeowKit_MWCODE_Admin { |
| 6 | 6 | public static $loaded = false; |
| 7 | 7 | public static $version = '4.0'; |
| 8 | 8 | public static $admin_version = '4.0'; |
| 9 | + public static $network_license_modal_added = false; | |
| 10 | + public static $network_license_plugins = []; | |
| 9 | 11 | |
| 10 | 12 | /** |
| 11 | 13 | * Storage for instances that need deferred initialization. |
| 12 | 14 | * |
| @@ -196,19 +198,191 @@ | ||
| 196 | 198 | return $links; |
| 197 | 199 | } |
| 198 | 200 | $isIssue = $this->isPro && !$this->is_registered(); |
| 199 | 201 | if ( strpos( $pathName, $thisPathName ) !== false ) { |
| 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 | - ]; | |
| 202 | + // In network admin, handle differently (no settings page available) | |
| 203 | + if ( is_network_admin() ) { | |
| 204 | + if ( $this->isPro && !$this->is_registered() ) { | |
| 205 | + // Show "Register License" link for unregistered Pro plugins | |
| 206 | + $new_links = [ | |
| 207 | + 'license' => sprintf( | |
| 208 | + '<a href="#" class="meowapps-network-license-link" data-prefix="%s" data-plugin="%s" style="color: #d63638;">%s</a>', | |
| 209 | + esc_attr( $this->prefix ), | |
| 210 | + esc_attr( $this->nice_name_from_file( $this->mainfile ) ), | |
| 211 | + __( 'Register License', $this->domain ) | |
| 212 | + ), | |
| 213 | + ]; | |
| 214 | + // Track this plugin for the modal | |
| 215 | + self::$network_license_plugins[ $this->prefix ] = $this->nice_name_from_file( $this->mainfile ); | |
| 216 | + // Add modal output hook (only once) | |
| 217 | + if ( !self::$network_license_modal_added ) { | |
| 218 | + add_action( 'admin_footer', [ __CLASS__, 'output_network_license_modal' ] ); | |
| 219 | + self::$network_license_modal_added = true; | |
| 220 | + } | |
| 221 | + } | |
| 222 | + elseif ( $this->isPro && $this->is_registered() ) { | |
| 223 | + // Pro plugin is registered | |
| 224 | + $new_links = [ | |
| 225 | + 'license' => '<span style="color: #a75bd6;">' . __( 'Pro Version', $this->domain ) . '</span>', | |
| 226 | + ]; | |
| 227 | + } | |
| 228 | + else { | |
| 229 | + // Free plugin | |
| 230 | + $new_links = [ | |
| 231 | + 'license' => sprintf( '<span>' . __( '<a target="_blank" href="https://meowapps.com">Get the <u>Pro Version</u></a>', $this->domain ), $this->prefix ) . '</span>', | |
| 232 | + ]; | |
| 233 | + } | |
| 234 | + } | |
| 235 | + else { | |
| 236 | + // Regular admin - show settings and license status | |
| 237 | + $new_links = [ | |
| 238 | + 'settings' => | |
| 239 | + sprintf( __( '<a href="admin.php?page=%s_settings">Settings</a>', $this->domain ), $this->prefix ), | |
| 240 | + 'license' => | |
| 241 | + $this->is_registered() ? | |
| 242 | + ( '<span style="color: #a75bd6;">' . __( 'Pro Version', $this->domain ) . '</span>' ) : | |
| 243 | + ( $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>' ) ), | |
| 244 | + ]; | |
| 245 | + } | |
| 208 | 246 | $links = array_merge( $new_links, $links ); |
| 209 | 247 | } |
| 210 | 248 | return $links; |
| 249 | + } | |
| 250 | + | |
| 251 | + /** | |
| 252 | + * Output the network license registration modal. | |
| 253 | + * Called via admin_footer hook in network admin. | |
| 254 | + */ | |
| 255 | + public static function output_network_license_modal() { | |
| 256 | + $rest_url = esc_url( rest_url() ); | |
| 257 | + $nonce = wp_create_nonce( 'wp_rest' ); | |
| 258 | + ?> | |
| 259 | + <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;"> | |
| 260 | + <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);"> | |
| 261 | + <h2 style="margin:0 0 8px 0; font-size:18px;">Register License</h2> | |
| 262 | + <p id="meowapps-license-plugin-name" style="margin:0 0 16px 0; color:#666;"></p> | |
| 263 | + <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;" /> | |
| 264 | + <p id="meowapps-license-message" style="margin:12px 0 0 0; padding:10px; border-radius:4px; display:none;"></p> | |
| 265 | + <div style="margin-top:16px; display:flex; gap:10px; justify-content:flex-end;"> | |
| 266 | + <button type="button" id="meowapps-license-cancel" class="button">Cancel</button> | |
| 267 | + <button type="button" id="meowapps-license-submit" class="button button-primary">Validate & Register</button> | |
| 268 | + </div> | |
| 269 | + </div> | |
| 270 | + </div> | |
| 271 | + <script> | |
| 272 | + (function() { | |
| 273 | + var modal = document.getElementById('meowapps-network-license-modal'); | |
| 274 | + var input = document.getElementById('meowapps-license-key-input'); | |
| 275 | + var message = document.getElementById('meowapps-license-message'); | |
| 276 | + var pluginName = document.getElementById('meowapps-license-plugin-name'); | |
| 277 | + var submitBtn = document.getElementById('meowapps-license-submit'); | |
| 278 | + var cancelBtn = document.getElementById('meowapps-license-cancel'); | |
| 279 | + var currentPrefix = ''; | |
| 280 | + | |
| 281 | + function showMessage(text, isError) { | |
| 282 | + message.textContent = text; | |
| 283 | + message.style.display = 'block'; | |
| 284 | + message.style.background = isError ? '#fcf0f1' : '#edfaef'; | |
| 285 | + message.style.color = isError ? '#d63638' : '#1e7e34'; | |
| 286 | + message.style.border = '1px solid ' + (isError ? '#d63638' : '#1e7e34'); | |
| 287 | + } | |
| 288 | + | |
| 289 | + function hideMessage() { | |
| 290 | + message.style.display = 'none'; | |
| 291 | + } | |
| 292 | + | |
| 293 | + function openModal(prefix, plugin) { | |
| 294 | + currentPrefix = prefix; | |
| 295 | + pluginName.textContent = plugin; | |
| 296 | + input.value = ''; | |
| 297 | + hideMessage(); | |
| 298 | + submitBtn.disabled = false; | |
| 299 | + submitBtn.textContent = 'Validate & Register'; | |
| 300 | + modal.style.display = 'flex'; | |
| 301 | + input.focus(); | |
| 302 | + } | |
| 303 | + | |
| 304 | + function closeModal() { | |
| 305 | + modal.style.display = 'none'; | |
| 306 | + currentPrefix = ''; | |
| 307 | + } | |
| 308 | + | |
| 309 | + // Handle click on "Register License" links | |
| 310 | + document.addEventListener('click', function(e) { | |
| 311 | + if (e.target.classList.contains('meowapps-network-license-link')) { | |
| 312 | + e.preventDefault(); | |
| 313 | + var prefix = e.target.getAttribute('data-prefix'); | |
| 314 | + var plugin = e.target.getAttribute('data-plugin'); | |
| 315 | + openModal(prefix, plugin); | |
| 316 | + } | |
| 317 | + }); | |
| 318 | + | |
| 319 | + // Close modal on cancel or clicking outside | |
| 320 | + cancelBtn.addEventListener('click', closeModal); | |
| 321 | + modal.addEventListener('click', function(e) { | |
| 322 | + if (e.target === modal) closeModal(); | |
| 323 | + }); | |
| 324 | + | |
| 325 | + // Handle escape key | |
| 326 | + document.addEventListener('keydown', function(e) { | |
| 327 | + if (e.key === 'Escape' && modal.style.display === 'flex') { | |
| 328 | + closeModal(); | |
| 329 | + } | |
| 330 | + }); | |
| 331 | + | |
| 332 | + // Handle enter key in input | |
| 333 | + input.addEventListener('keydown', function(e) { | |
| 334 | + if (e.key === 'Enter') { | |
| 335 | + submitBtn.click(); | |
| 336 | + } | |
| 337 | + }); | |
| 338 | + | |
| 339 | + // Submit license | |
| 340 | + submitBtn.addEventListener('click', function() { | |
| 341 | + var licenseKey = input.value.trim(); | |
| 342 | + if (!licenseKey) { | |
| 343 | + showMessage('Please enter a license key.', true); | |
| 344 | + return; | |
| 345 | + } | |
| 346 | + | |
| 347 | + submitBtn.disabled = true; | |
| 348 | + submitBtn.textContent = 'Validating...'; | |
| 349 | + hideMessage(); | |
| 350 | + | |
| 351 | + var restUrl = '<?php echo $rest_url; ?>meow-licenser/' + currentPrefix + '/v1/set_license/'; | |
| 352 | + | |
| 353 | + fetch(restUrl, { | |
| 354 | + method: 'POST', | |
| 355 | + headers: { | |
| 356 | + 'Content-Type': 'application/json', | |
| 357 | + 'X-WP-Nonce': '<?php echo $nonce; ?>' | |
| 358 | + }, | |
| 359 | + body: JSON.stringify({ serialKey: licenseKey }) | |
| 360 | + }) | |
| 361 | + .then(function(response) { return response.json(); }) | |
| 362 | + .then(function(data) { | |
| 363 | + if (data.success && data.data && !data.data.issue) { | |
| 364 | + showMessage('License registered successfully! Reloading...', false); | |
| 365 | + setTimeout(function() { location.reload(); }, 1500); | |
| 366 | + } else { | |
| 367 | + var errorMsg = 'License validation failed.'; | |
| 368 | + if (data.data && data.data.issue) { | |
| 369 | + errorMsg = 'License issue: ' + data.data.issue; | |
| 370 | + } | |
| 371 | + showMessage(errorMsg, true); | |
| 372 | + submitBtn.disabled = false; | |
| 373 | + submitBtn.textContent = 'Validate & Register'; | |
| 374 | + } | |
| 375 | + }) | |
| 376 | + .catch(function(error) { | |
| 377 | + showMessage('Error: ' + error.message, true); | |
| 378 | + submitBtn.disabled = false; | |
| 379 | + submitBtn.textContent = 'Validate & Register'; | |
| 380 | + }); | |
| 381 | + }); | |
| 382 | + })(); | |
| 383 | + </script> | |
| 384 | + <?php | |
| 211 | 385 | } |
| 212 | 386 | |
| 213 | 387 | public function request_verify_ssl() { |
| 214 | 388 | return get_option( 'force_sslverify', false ); |