PluginProbe ʕ •ᴥ•ʔ
Robin Image Optimizer – Unlimited Image Optimization, WebP & AVIF / trunk
Robin Image Optimizer – Unlimited Image Optimization, WebP & AVIF vtrunk
2.0.6 2.0.5 trunk 1.3.7 1.4.0 1.4.1 1.4.2 1.4.6 1.5.0 1.5.3 1.5.6 1.5.8 1.6.5 1.6.6 1.6.9 1.7.0 1.7.4 1.8.1 1.8.2 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4
robin-image-optimizer / admin / pages / class-rio-license.php
robin-image-optimizer / admin / pages Last commit date
class-rio-license.php 3 months ago class-rio-log.php 7 months ago class-rio-page.php 7 months ago class-rio-settings.php 7 months ago class-rio-statistic.php 7 months ago index.php 3 years ago
class-rio-license.php
692 lines
1 <?php
2 /**
3 * License Page class
4 *
5 * Self-contained license management page without Factory Templates dependency.
6 * Reuses existing factory-bootstrap-500 CSS framework.
7 *
8 * @package Robin_Image_Optimizer
9 * @subpackage Admin\Pages
10 */
11
12 // Exit if accessed directly
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 /**
18 * Class WRIO_License_Page_View
19 *
20 * Handles the license management admin page.
21 */
22 class WRIO_License_Page_View {
23
24 /**
25 * Page ID
26 *
27 * @var string
28 */
29 public $id = 'wrio_license';
30
31 /**
32 * Page hook suffix
33 *
34 * @var string|false
35 */
36 private $page_hook;
37
38 /**
39 * Premium provider instance
40 *
41 * @var WRIO_Premium_Provider
42 * @phpstan-ignore-next-line property.onlyRead
43 */
44 private $premium;
45
46 /**
47 * License instance
48 *
49 * @var WRIO_License
50 * @phpstan-ignore-next-line property.onlyRead
51 */
52 private $license;
53
54 /**
55 * Whether premium is activated
56 *
57 * @var bool|null
58 */
59 private $is_premium;
60
61 /**
62 * Plan name
63 *
64 * @var string
65 */
66 public $plan_name;
67
68 /**
69 * Subscribe widget instance
70 *
71 * @var WRIO_Subscribe_Widget
72 */
73 private $subscribe_widget;
74
75 /**
76 * Constructor
77 */
78 public function __construct() {
79 $this->is_premium = null;
80 $this->plan_name = __( 'Robin image optimizer Premium', 'robin-image-optimizer' );
81
82 // Initialize subscribe widget.
83 $this->subscribe_widget = new WRIO_Subscribe_Widget();
84
85 add_action( 'admin_menu', [ $this, 'register_page' ], 9 );
86 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
87 add_action( 'wp_ajax_wrio_license_action', [ $this, 'ajax_handler' ] );
88
89 // Register this page in the Factory navigation menu
90 $this->register_in_factory_menu();
91 }
92
93 /**
94 * Register this page in the Factory impressive menu system
95 *
96 * This allows the license page to appear in the left navigation bar
97 * alongside other Factory-registered pages.
98 *
99 * @return void
100 */
101 private function register_in_factory_menu() {
102 global $factory_impressive_page_menu;
103
104 $page_url = admin_url( 'admin.php?page=' . $this->id );
105
106 $factory_impressive_page_menu['robin-image-optimizer'][ $this->id ] = [
107 'type' => 'page',
108 'url' => $page_url,
109 'title' => __( 'License', 'robin-image-optimizer' ) . ' <span class="dashicons dashicons-admin-network"></span>',
110 'short_description' => __( 'Product activation', 'robin-image-optimizer' ),
111 'position' => 10,
112 'parent' => 'rio_general',
113 ];
114 }
115
116 /**
117 * Initialize premium data
118 *
119 * Called late to ensure WRIO_Plugin is available.
120 *
121 * @return void
122 */
123 private function init_premium() {
124 if ( null !== $this->premium ) {
125 return;
126 }
127
128 /**
129 * Initializes the premium provider instance.
130 *
131 * @var WRIO_Premium_Provider $premium
132 */
133 $premium = WRIO_Plugin::app()->premium;
134 $this->premium = $premium;
135 /**
136 * Gets the license instance from premium provider.
137 *
138 * @var WRIO_License $license
139 */
140 $license = $premium->get_license();
141 $this->license = $license;
142 $this->is_premium = $premium->is_activate();
143 }
144
145 /**
146 * Register the admin page
147 *
148 * @return void
149 */
150 public function register_page() {
151 // Parent slug follows Factory pattern: {page_id}-{plugin_name}
152 $parent_slug = 'rio_general-robin-image-optimizer';
153
154 $this->page_hook = add_submenu_page(
155 $parent_slug,
156 __( 'License', 'robin-image-optimizer' ),
157 __( 'License', 'robin-image-optimizer' ),
158 'manage_options',
159 $this->id,
160 [ $this, 'render_page' ],
161 90 // Position before About Us (which uses 100)
162 );
163 }
164
165 /**
166 * Enqueue page assets
167 *
168 * @param string $hook Current admin page hook.
169 * @return void
170 */
171 public function enqueue_assets( $hook ) {
172 if ( $this->page_hook !== $hook ) {
173 return;
174 }
175
176 wp_enqueue_script(
177 'wrio-license-manager',
178 WRIO_PLUGIN_URL . '/admin/assets/js/wrio-license-manager.js',
179 [ 'jquery' ],
180 WRIO_Plugin::app()->getPluginVersion(),
181 true
182 );
183
184 // Enqueue the Factory bootstrap core CSS (provides .btn, .form-control, etc.)
185 wp_enqueue_style(
186 'wrio-bootstrap-core',
187 WRIO_PLUGIN_URL . '/libs/factory/bootstrap/assets/css-min/bootstrap.core.min.css',
188 [],
189 WRIO_Plugin::app()->getPluginVersion()
190 );
191
192 // Enqueue the license manager CSS from Factory templates
193 wp_enqueue_style(
194 'wrio-license-manager',
195 WRIO_PLUGIN_URL . '/libs/factory/templates/assets/css/license-manager.css',
196 [ 'wrio-bootstrap-core' ],
197 WRIO_Plugin::app()->getPluginVersion()
198 );
199
200 // Enqueue the impressive page template CSS for full layout
201 wp_enqueue_style(
202 'wrio-impressive-template',
203 WRIO_PLUGIN_URL . '/libs/factory/templates/pages/templates/impressive/assets/css/impressive.page.template.css',
204 [ 'wrio-bootstrap-core' ],
205 WRIO_Plugin::app()->getPluginVersion()
206 );
207
208 // Enqueue subscribe widget CSS.
209 wp_enqueue_style(
210 'wrio-subscribe-widget',
211 WRIO_PLUGIN_URL . '/admin/assets/css/wrio-subscribe-widget.css',
212 [],
213 WRIO_Plugin::app()->getPluginVersion()
214 );
215
216 // Hide internal pages from sidebar (Custom Folders, Nextgen Gallery)
217 wp_add_inline_style(
218 'wrio-impressive-template',
219 '#io_folders_statistic-robin-image-optimizer-tab, #io_nextgen_gallery_statistic-robin-image-optimizer-tab { display: none !important; }'
220 );
221 }
222
223 /**
224 * Handle AJAX license actions
225 *
226 * @return void
227 */
228 public function ajax_handler() {
229 // Verify nonce
230 if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ), 'wrio_license_action' ) ) {
231 wp_send_json_error( [ 'message' => __( 'Security check failed.', 'robin-image-optimizer' ) ] );
232 }
233
234 // Check capabilities
235 if ( ! current_user_can( 'manage_options' ) ) {
236 wp_send_json_error( [ 'message' => __( 'You do not have permission to perform this action.', 'robin-image-optimizer' ) ] );
237 }
238
239 $this->init_premium();
240
241 $action = isset( $_POST['license_action'] ) ? sanitize_text_field( wp_unslash( $_POST['license_action'] ) ) : '';
242 $license_key = isset( $_POST['licensekey'] ) ? trim( wp_unslash( $_POST['licensekey'] ) ) : '';
243
244 $allowed_actions = [ 'activate', 'deactivate', 'unsubscribe' ];
245
246 if ( empty( $action ) || ! in_array( $action, $allowed_actions, true ) ) {
247 wp_send_json_error( [ 'message' => __( 'Invalid action.', 'robin-image-optimizer' ) ] );
248 }
249
250 try {
251 switch ( $action ) {
252 case 'activate':
253 if ( empty( $license_key ) ) {
254 wp_send_json_error( [ 'message' => __( 'Please enter a license key.', 'robin-image-optimizer' ) ] );
255 }
256 $this->premium->activate( $license_key );
257 $message = __( 'Your license has been successfully activated.', 'robin-image-optimizer' );
258 break;
259
260 case 'deactivate':
261 $this->premium->deactivate();
262 $message = __( 'Your license has been deactivated.', 'robin-image-optimizer' );
263 break;
264
265 case 'unsubscribe':
266 $this->premium->cancel_paid_subscription();
267 $message = __( 'Your subscription has been cancelled.', 'robin-image-optimizer' );
268 break;
269
270 default:
271 wp_send_json_error( [ 'message' => __( 'Unknown action.', 'robin-image-optimizer' ) ] );
272 }
273
274 wp_send_json_success( [ 'message' => $message ] );
275
276 } catch ( Exception $e ) {
277 wp_send_json_error( [ 'message' => $e->getMessage() ] );
278 }
279 }
280
281 /**
282 * Render the admin page
283 *
284 * @return void
285 */
286 public function render_page() {
287 $this->init_premium();
288 $min_height = $this->calculate_menu_height();
289 ?>
290 <div id="tsdk_banner" class="robin-banner"></div>
291 <div id="WBCR" class="wrap">
292 <div class="wbcr-factory-templates-759-impressive-page-template factory-bootstrap-500 factory-fontawesome-000">
293 <div class="wbcr-factory-page wbcr-factory-page-<?php echo esc_attr( $this->id ); ?>">
294 <?php $this->render_header(); ?>
295 <div class="wbcr-factory-left-navigation-bar">
296 <?php $this->render_page_menu(); ?>
297 </div>
298 <div class="wbcr-factory-page-inner-wrap">
299 <div class="wbcr-factory-content-section wbcr-fullwidth">
300 <div class="wbcr-factory-content" style="min-height:<?php echo esc_attr( (string) $min_height ); ?>px">
301 <div id="wrio-license-wrapper"
302 data-loader="<?php echo esc_url( admin_url( 'images/spinner.gif' ) ); ?>"
303 data-nonce="<?php echo esc_attr( wp_create_nonce( 'wrio_license_action' ) ); ?>">
304 <?php $this->render_license_form(); ?>
305 </div>
306 </div>
307 </div>
308 </div>
309 </div>
310 <div class="clearfix"></div>
311 </div>
312 </div>
313 <?php
314 }
315
316 /**
317 * Calculate minimum height for content based on menu items
318 *
319 * @return int
320 */
321 private function calculate_menu_height() {
322 global $factory_impressive_page_menu;
323
324 $menu_scope = 'robin-image-optimizer';
325 $min_height = 0;
326
327 if ( isset( $factory_impressive_page_menu[ $menu_scope ] ) ) {
328 foreach ( $factory_impressive_page_menu[ $menu_scope ] as $page ) {
329 if ( ! isset( $page['parent'] ) || empty( $page['parent'] ) ) {
330 $min_height += 77;
331 }
332 }
333 }
334
335 return $min_height;
336 }
337
338 /**
339 * Render the page header
340 *
341 * @return void
342 */
343 private function render_header() {
344 ?>
345 <div class="wbcr-factory-page-header">
346 <div class="wbcr-factory-header-logo">
347 <?php echo esc_html( WRIO_Plugin::app()->getPluginTitle() ); ?>
348 <span class="version"><?php echo esc_html( WRIO_Plugin::app()->getPluginVersion() ); ?></span>
349 <span class="dash"></span>
350 </div>
351 <div class="wbcr-factory-header-title">
352 <h2><?php esc_html_e( 'Page', 'robin-image-optimizer' ); ?>: <?php esc_html_e( 'License', 'robin-image-optimizer' ); ?></h2>
353 </div>
354 <div class="wbcr-factory-control">
355 <?php do_action( 'wbcr_factory_pages_impressive_header', WRIO_Plugin::app()->getPluginName() ); ?>
356 </div>
357 </div>
358 <?php
359 }
360
361 /**
362 * Render the left navigation menu
363 *
364 * @return void
365 */
366 private function render_page_menu() {
367 global $factory_impressive_page_menu;
368
369 $menu_scope = 'robin-image-optimizer';
370 $self_page_id = $this->id;
371
372 if ( ! isset( $factory_impressive_page_menu[ $menu_scope ] ) ) {
373 return;
374 }
375
376 $page_menu = $factory_impressive_page_menu[ $menu_scope ];
377
378 // Sort by position (descending - higher position = higher in menu)
379 uasort(
380 $page_menu,
381 function ( $a, $b ) {
382 return $b['position'] <=> $a['position'];
383 }
384 );
385
386 ?>
387 <ul>
388 <?php
389 // First, render parent pages
390 foreach ( $page_menu as $page_screen => $page ) :
391 if ( ! empty( $page['parent'] ) ) {
392 continue;
393 }
394 $active_tab = ( $page_screen === $self_page_id ) ? ' wbcr-factory-active-tab' : '';
395 ?>
396 <li class="wbcr-factory-nav-tab<?php echo esc_attr( $active_tab ); ?>">
397 <a href="<?php echo esc_url( $page['url'] ); ?>"
398 id="<?php echo esc_attr( $page_screen ); ?>-tab"
399 class="wbcr-factory-tab__link js-wbcr-factory-tab__link">
400 <div class="wbcr-factory-tab__title">
401 <?php echo wp_kses( $page['title'], [ 'span' => [ 'class' => [] ] ] ); ?>
402 </div>
403 <?php if ( ! empty( $page['short_description'] ) ) : ?>
404 <div class="wbcr-factory-tab__short-description">
405 <?php echo esc_html( $page['short_description'] ); ?>
406 </div>
407 <?php endif; ?>
408 </a>
409 </li>
410 <?php endforeach; ?>
411
412 <?php
413 // Then, render child pages
414 foreach ( $page_menu as $page_screen => $page ) :
415 if ( empty( $page['parent'] ) ) {
416 continue;
417 }
418 $active_tab = ( $page_screen === $self_page_id ) ? ' wbcr-factory-active-tab' : '';
419 ?>
420 <li class="wbcr-factory-nav-tab<?php echo esc_attr( $active_tab ); ?>">
421 <a href="<?php echo esc_url( $page['url'] ); ?>"
422 id="<?php echo esc_attr( $page_screen ); ?>-tab"
423 class="wbcr-factory-tab__link js-wbcr-factory-tab__link">
424 <div class="wbcr-factory-tab__title">
425 <?php echo wp_kses( $page['title'], [ 'span' => [ 'class' => [] ] ] ); ?>
426 </div>
427 <?php if ( ! empty( $page['short_description'] ) ) : ?>
428 <div class="wbcr-factory-tab__short-description">
429 <?php echo esc_html( $page['short_description'] ); ?>
430 </div>
431 <?php endif; ?>
432 </a>
433 </li>
434 <?php endforeach; ?>
435 </ul>
436 <?php
437 }
438
439 /**
440 * Get license type for CSS class
441 *
442 * @return string free|gift|trial|paid
443 */
444 private function get_license_type() {
445 if ( ! $this->is_premium || null === $this->license ) {
446 return 'free';
447 }
448
449 if ( $this->license->is_lifetime() ) {
450 return 'gift';
451 }
452
453 if ( $this->license->get_expiration_time( 'days' ) < 1 ) {
454 return 'trial';
455 }
456
457 return 'paid';
458 }
459
460 /**
461 * Get hidden license key (first 8 + last 4 characters)
462 *
463 * @return string
464 */
465 private function get_hidden_license_key() {
466 if ( ! $this->is_premium || null === $this->license ) {
467 return '';
468 }
469
470 return $this->license->get_masked_key();
471 }
472
473
474
475 /**
476 * Get unified expiration display string
477 *
478 * @return string
479 */
480 private function get_expiration_display() {
481 if ( ! $this->is_premium || null === $this->license ) {
482 return __( 'N/A', 'robin-image-optimizer' );
483 }
484
485 return $this->license->get_expiration_display();
486 }
487
488
489 /**
490 * Render the license form
491 *
492 * @return void
493 */
494 private function render_license_form() {
495 $license_type = $this->get_license_type();
496
497 $plan_title = __( 'Free', 'robin-image-optimizer' );
498 $has_pro = null !== $this->premium && null !== $this->premium->get_plan_id();
499 if ( $has_pro ) {
500 $plan_title = __( 'Pro', 'robin-image-optimizer' );
501 }
502
503 $license_status_label = __( 'License', 'robin-image-optimizer' );
504
505 ?>
506 <div id="license-manager"
507 class="factory-bootstrap-500 onp-page-wrap <?php echo esc_attr( $license_type ); ?>-license-manager-content">
508
509 <?php if ( ! $has_pro ) : ?>
510 <?php $this->render_upgrade_banner(); ?>
511 <?php endif; ?>
512
513 <div class="onp-container">
514 <div class="license-details">
515 <h3>
516 <?php echo esc_html( $license_status_label ); ?>
517 <span class="license-info-badge <?php echo esc_attr( 'license-info-badge--plan-' . ( $has_pro ? 'pro' : 'free' ) ); ?>">
518 <?php echo esc_html( $plan_title ); ?>
519 </span>
520 <?php if ( $this->is_premium ) : ?>
521 <span class="license-info-badge license-info-badge--expiration">
522 <?php echo esc_html( $this->get_expiration_display() ); ?>
523 </span>
524 <?php endif; ?>
525 </h3>
526 </div>
527
528 <div class="license-input">
529 <form action="" method="post">
530 <?php if ( $this->is_premium ) : ?>
531 <p><?php esc_html_e( 'Have a key to activate the premium version? Paste it here:', 'robin-image-optimizer' ); ?></p>
532 <?php else : ?>
533 <p><?php esc_html_e( 'Have a key to activate the plugin? Paste it here:', 'robin-image-optimizer' ); ?></p>
534 <?php endif; ?>
535
536
537
538 <div class="license-key-wrap">
539 <input
540 type="text"
541 id="license-key"
542 name="licensekey"
543 value=""
544 class="form-control"
545 placeholder="<?php echo esc_html( $this->get_hidden_license_key() ); ?>"
546 />
547
548 <?php if ( $this->is_premium ) : ?>
549 <button data-action="deactivate" class="button button-primary wrio-license-btn" type="button" id="license-submit">
550 <?php esc_html_e( 'Deactivate', 'robin-image-optimizer' ); ?>
551 </button>
552 <?php else : ?>
553 <button data-action="activate" class="button button-primary wrio-license-btn" type="button" id="license-submit">
554 <?php esc_html_e( 'Activate', 'robin-image-optimizer' ); ?>
555 </button>
556 <?php endif; ?>
557 </div>
558
559 <?php $this->render_learnmore_section(); ?>
560
561 <div id="license-form-error-container"></div>
562 <?php $this->render_freemius_migration_notice(); ?>
563 </form>
564 </div>
565
566 </div>
567
568 <?php $this->subscribe_widget->render(); ?>
569 </div>
570 <?php
571 }
572
573 /**
574 * Render the upgrade banner for free users
575 *
576 * @return void
577 */
578 private function render_upgrade_banner() {
579 $support = WRIO_Plugin::app()->get_support();
580 $pricing_url = $support->get_pricing_url( true, 'license_banner' );
581 ?>
582 <div class="wrio-license-upgrade-banner">
583 <div class="wrio-license-upgrade-icon">
584 <span></span>
585 </div>
586 <div class="wrio-license-upgrade-content">
587 <h2 class="wrio-license-upgrade-title"><?php esc_html_e( 'Supercharge Your Image Optimization', 'robin-image-optimizer' ); ?></h2>
588 <p class="wrio-license-upgrade-subtitle"><?php esc_html_e( "You're using the free version. Upgrade to unlock unlimited conversions and premium features.", 'robin-image-optimizer' ); ?></p>
589 <div class="wrio-license-upgrade-features">
590 <div class="wrio-license-upgrade-feature">
591 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
592 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
593 </svg>
594 <span><?php esc_html_e( 'Unlimited AVIF', 'robin-image-optimizer' ); ?></span>
595 </div>
596 <div class="wrio-license-upgrade-feature">
597 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
598 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
599 </svg>
600 <span><?php esc_html_e( 'Custom Folders Optimization', 'robin-image-optimizer' ); ?></span>
601 </div>
602 <div class="wrio-license-upgrade-feature">
603 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
604 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
605 </svg>
606 <span><?php esc_html_e( 'NextGen Gallery Support', 'robin-image-optimizer' ); ?></span>
607 </div>
608 <div class="wrio-license-upgrade-feature">
609 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
610 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
611 </svg>
612 <span><?php esc_html_e( 'Priority Support', 'robin-image-optimizer' ); ?></span>
613 </div>
614 <div class="wrio-license-upgrade-feature">
615 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
616 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
617 </svg>
618 <span><?php esc_html_e( 'More Compression Modes', 'robin-image-optimizer' ); ?></span>
619 </div>
620 <div class="wrio-license-upgrade-feature">
621 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
622 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
623 </svg>
624 <span><?php esc_html_e( 'Super Page Cache Pro', 'robin-image-optimizer' ); ?></span>
625 </div>
626 </div>
627 <a href="<?php echo esc_url( $pricing_url ); ?>" class="wrio-license-upgrade-button" target="_blank" rel="noopener">
628 <?php esc_html_e( 'View Pro Plans', 'robin-image-optimizer' ); ?>
629 </a>
630 </div>
631 </div>
632 <?php
633 }
634
635 /**
636 * Render learn more section
637 *
638 * @return void
639 */
640 private function render_learnmore_section() {
641 $support = WRIO_Plugin::app()->get_support();
642
643 if ( ! $this->is_premium ) :
644 ?>
645 <p style="margin-top: 10px;">
646 <?php
647 printf(
648 wp_kses(
649 /* translators: %1$s: opening link tag, %2$s: closing link tag */
650 __( 'Can\'t find your key? Go to %1$sthis page%2$s and login using the e-mail address associated with your purchase.', 'robin-image-optimizer' ),
651 [
652 'a' => [
653 'href' => [],
654 'target' => [],
655 'rel' => [],
656 ],
657 ]
658 ),
659 '<a href="' . esc_url( $support->get_contacts_url( true, 'license_page' ) ) . '" target="_blank" rel="noopener">',
660 '</a>'
661 );
662 ?>
663 </p>
664 <?php
665 endif;
666 }
667
668 /**
669 * Render migration notice for Freemius license holders
670 *
671 * @return void
672 */
673 private function render_freemius_migration_notice() {
674 if ( ! $this->is_premium || null === $this->license || $this->license->get_source() !== WRIO_License::SOURCE_FREEMIUS ) {
675 return;
676 }
677 ?>
678 <div class="wrio-migration-notice">
679 <p>
680 <strong><?php esc_html_e( 'Action Required:', 'robin-image-optimizer' ); ?></strong>
681 <?php esc_html_e( 'Your license was issued through our previous licensing system (Freemius). Please contact support to receive a new Themeisle license key for continued access to updates and support.', 'robin-image-optimizer' ); ?>
682 </p>
683 <p>
684 <a href="<?php echo esc_url( WRIO_Plugin::app()->get_support()->get_contacts_url( true, 'license_migration' ) ); ?>" target="_blank" rel="noopener" class="button button-primary">
685 <?php esc_html_e( 'Contact Support', 'robin-image-optimizer' ); ?>
686 </a>
687 </p>
688 </div>
689 <?php
690 }
691 }
692