PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 1.1.4
ShopBuilder – WooCommerce Builder For Elementor v1.1.4
3.4.2 3.4.1 3.4.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 All 63 releases
← All changes | app/Controllers/Admin/PluginRow.php +463 -762 3.4.21.1.4 View file →
@@ -1,762 +1,463 @@
1 -<?php
2 -
3 -namespace RadiusTheme\SB\Controllers\Admin;
4 -
5 -use RadiusTheme\SB\Traits\SingletonTrait;
6 -
7 -// Do not allow directly accessing this file.
8 -if ( ! defined( 'ABSPATH' ) ) {
9 - exit( 'This script cannot be accessed directly.' );
10 -}
11 -
12 -/**
13 - * Settings Page.
14 - */
15 -class PluginRow {
16 - /**
17 - * Singleton Trait.
18 - */
19 - use SingletonTrait;
20 -
21 - /**
22 - * Template builder post type
23 - *
24 - * @var string
25 - */
26 - public string $textdomain = 'shopbuilder';
27 -
28 - /**
29 - * Construct function
30 - */
31 - private function __construct() {
32 - // Plugins Setting Page.
33 - add_filter( 'plugin_action_links_' . plugin_basename( RTSB_FILE ), [ $this, 'plugins_setting_links' ] );
34 - add_filter( 'plugin_row_meta', [ $this, 'plugin_row_meta' ], 10, 2 );
35 - add_action( 'admin_footer', [ $this, 'deactivation_popup' ], 99 );
36 - }
37 -
38 - /**
39 - * @param array $links default plugin action link.
40 - *
41 - * @return array [array] plugin action link
42 - */
43 - public function plugins_setting_links( $links ) {
44 - $new_links = [];
45 - $demo_url = 'https://shopbuilderwp.com/';
46 - $new_links[] = '<a href="' . admin_url( 'admin.php?page=rtsb-settings' ) . '">' . esc_html__( 'Settings', 'shopbuilder' ) . '</a>';
47 - $new_links[] = '<a target="_blank" href="' . esc_url( $demo_url ) . '">' . esc_html__( 'Demo', 'shopbuilder' ) . '</a>';
48 - $new_links[] = '<a target="_blank" href="' . esc_url( 'https://shopbuilderwp.com/docs/' ) . '">' . esc_html__( 'Documentation', 'shopbuilder' ) . '</a>';
49 -
50 - $links = array_merge( $new_links, $links );
51 -
52 - $current = time();
53 - // Check if current date is within promotional period (Sept 19 - Jan 5).
54 - $start_date = strtotime( '2025-11-12 00:00:00' );
55 - $end_date = strtotime( '2025-12-30 23:59:59' );
56 - $is_promo_period = $start_date <= $current && $current <= $end_date;
57 - $text = esc_html__( 'Get Pro', 'shopbuilder' );
58 - if ( $is_promo_period ) {
59 - $text = esc_html__( 'Get 60% off', 'shopbuilder' );
60 - }
61 -
62 - if ( ! rtsb()->has_pro() ) {
63 - $links['shopbuilder_pro'] = '<a href="' . esc_url( rtsb()->pro_version_link() ) . '" target="_blank" style="color: #39b54a; font-weight: bold;">' . $text . '</a>';
64 - }
65 -
66 - return $links;
67 - }
68 -
69 - /**
70 - * Plugin links row.
71 - *
72 - * @param array $links Links.
73 - * @param string $file File.
74 - *
75 - * @return array
76 - */
77 - public function plugin_row_meta( $links, $file ) {
78 -
79 - if ( RTSB_ACTIVE_FILE_NAME === $file ) {
80 - $report_url = 'https://www.radiustheme.com/contact/';
81 - $row_meta['issues'] = sprintf(
82 - /* translators: %1$s: Report URL, %2$s: Facing issue?, %3$s: Please open a support ticket. */
83 - '%2$s <a target="_blank" href="%1$s"><span style="color: red">%3$s</span></a>',
84 - esc_url( $report_url ),
85 - esc_html__( 'Facing issue?', 'shopbuilder' ),
86 - esc_html__( 'Please open a support ticket.', 'shopbuilder' )
87 - );
88 -
89 - return array_merge( $links, $row_meta );
90 - }
91 -
92 - return (array) $links;
93 - }
94 -
95 - /***
96 - * @return mixed
97 - */
98 - public function deactivation_popup() {
99 - global $pagenow;
100 - if ( 'plugins.php' !== $pagenow ) {
101 - return;
102 - }
103 -
104 - $this->dialog_box_style();
105 - $this->deactivation_scripts();
106 - ?>
107 - <div id="deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?>" title="Quick Feedback">
108 - <!-- Modal content -->
109 - <div class="modal-content">
110 - <div id="feedback-form-body-<?php echo esc_attr( $this->textdomain ); ?>">
111 - <p class="rtsb-deactivate-intro" style="margin: 0 0 15px 0;">
112 - Having trouble? <br/>
113 - For faster and more accurate support, please
114 - <a target="_blank" href="https://www.radiustheme.com/contact/" class="rtsb-support-link">open a support ticket</a>
115 - — our support agent will personally review and resolve your issue.
116 - </p>
117 -
118 - <div class="feedback-input-header">
119 - <?php echo esc_html__( 'If you’d prefer not to open a support ticket, please take a moment to share why you’re deactivating ShopBuilder:', 'shopbuilder' ); ?>
120 - </div>
121 -
122 - <div class="feedback-input-wrapper">
123 - <input id="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-bug_issue_detected" class="feedback-input"
124 - type="radio" name="reason_key" value="bug_issue_detected">
125 - <label for="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-bug_issue_detected" class="feedback-label">Bug Or Issue detected.</label>
126 - </div>
127 -
128 - <div class="feedback-input-wrapper">
129 - <input id="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-no_longer_needed" class="feedback-input" type="radio"
130 - name="reason_key" value="no_longer_needed">
131 - <label for="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-no_longer_needed" class="feedback-label">I no longer
132 - need the plugin</label>
133 - </div>
134 - <div class="feedback-input-wrapper conditional">
135 - <input id="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-found_a_better_plugin" class="feedback-input"
136 - type="radio" name="reason_key" value="found_a_better_plugin">
137 - <label for="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-found_a_better_plugin" class="feedback-label">I found a
138 - better plugin</label>
139 - <input class="feedback-feedback-text" type="text" name="reason_found_a_better_plugin"
140 - placeholder="Please share the plugin name">
141 - </div>
142 - <div class="feedback-input-wrapper">
143 - <input id="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-couldnt_get_the_plugin_to_work" class="feedback-input"
144 - type="radio" name="reason_key" value="couldnt_get_the_plugin_to_work">
145 - <label for="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-couldnt_get_the_plugin_to_work" class="feedback-label">I
146 - couldn't get the plugin to work</label>
147 - </div>
148 -
149 - <div class="feedback-input-wrapper">
150 - <input id="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-temporary_deactivation" class="feedback-input"
151 - type="radio" name="reason_key" value="temporary_deactivation">
152 - <label for="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-temporary_deactivation" class="feedback-label">It's a
153 - temporary deactivation</label>
154 - </div>
155 - <span style="color:red;font-size: 13px;"></span>
156 - </div>
157 - <div class="rtsb-feedback-extra" style="display:none;">
158 - <p style="margin: 10px 0 15px 0;">
159 - Please let us know about any issues you are facing with the plugin.
160 - How can we improve the plugin?
161 - </p>
162 - <div class="feedback-text-wrapper-<?php echo esc_attr( $this->textdomain ); ?>">
163 - <textarea id="deactivation-feedback-<?php echo esc_attr( $this->textdomain ); ?>" rows="2" cols="40"
164 - placeholder=" Write something here. How can we improve the plugin?"></textarea>
165 - <span style="display: block;color:red;font-size: 13px;margin-top: 5px;"></span>
166 - </div>
167 - </div>
168 - </div>
169 - </div>
170 - <?php
171 - }
172 -
173 - /***
174 - * @return mixed
175 - */
176 - public function dialog_box_style() {
177 - ?>
178 - <style>
179 - /* Add Animation */
180 - @-webkit-keyframes animatetop {
181 - from {
182 - top: -300px;
183 - opacity: 0
184 - }
185 - to {
186 - top: 0;
187 - opacity: 1
188 - }
189 - }
190 -
191 - @keyframes animatetop {
192 - from {
193 - top: -300px;
194 - opacity: 0
195 - }
196 - to {
197 - top: 0;
198 - opacity: 1
199 - }
200 - }
201 -
202 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> {
203 - display: none;
204 - }
205 -
206 - .ui-dialog-titlebar-close {
207 - display: none;
208 - }
209 -
210 - /* The Modal (background) */
211 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal {
212 - display: none; /* Hidden by default */
213 - position: fixed; /* Stay in place */
214 - z-index: 1; /* Sit on top */
215 - padding-top: 100px; /* Location of the box */
216 - left: 0;
217 - top: 0;
218 - width: 100%; /* Full width */
219 - height: 100%; /* Full height */
220 - overflow: auto; /* Enable scroll if needed */
221 - }
222 -
223 - /* Modal Content */
224 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content {
225 - position: relative;
226 - margin: auto;
227 - padding: 0;
228 - }
229 -
230 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content > * {
231 - width: 100%;
232 - overflow: hidden;
233 - }
234 -
235 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content input.feedback-feedback-text {
236 - border: 1px solid #cbd5e1;
237 - min-width: 250px;
238 - border-radius: 6px;
239 - }
240 -
241 - .ui-dialog-title {
242 - font-size: 18px;
243 - font-weight: 600;
244 - }
245 -
246 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-body {
247 - padding: 2px 16px;
248 - }
249 -
250 - .ui-dialog-buttonset {
251 - background-color: #fefefe;
252 - padding: 0 17px 25px;
253 - display: flex;
254 - justify-content: space-between;
255 - gap: 10px;
256 - }
257 -
258 - .ui-dialog-buttonset button {
259 - min-width: 110px;
260 - text-align: center;
261 - border: 1px solid rgba(0, 0, 0, 0.1);
262 - padding: 0 15px;
263 - border-radius: 5px;
264 - height: 40px;
265 - font-size: 15px;
266 - font-weight: 600;
267 - display: inline-flex;
268 - align-items: center;
269 - justify-content: center;
270 - cursor: pointer;
271 - transition: 0.3s all;
272 - background: rgba(0, 0, 0, 0.02);
273 - margin: 0;
274 - }
275 -
276 - .ui-dialog-buttonset button:nth-child(2) {
277 - background: transparent;
278 - }
279 -
280 - .ui-dialog-buttonset button:hover {
281 - background: #2271b1;
282 - color: #fff;
283 - }
284 -
285 - .ui-dialog[aria-describedby="deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?>"] {
286 - background-color: #fefefe;
287 - box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
288 - z-index: 9999;
289 - position: fixed !important;
290 - top: 50% !important;
291 - left: 50% !important;
292 - transform: translate(-50%, -50%) !important;
293 - max-height: 90vh;
294 - overflow-y: auto;
295 - }
296 -
297 - .ui-dialog[aria-describedby="deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?>"] .ui-dialog-title {
298 - text-transform: uppercase;
299 - font-weight: 700;
300 - font-size: 16px;
301 - padding-left: 15px;
302 - padding-right: 15px;
303 - }
304 -
305 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> {
306 - padding: 30px !important;
307 - }
308 -
309 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .rtsb-support-link {
310 - display: inline-block;
311 - padding: 2px 8px;
312 - margin: 0 2px;
313 - background: rgba(216, 14, 14, 0.08);
314 - color: #d80e0e;
315 - font-weight: 600;
316 - border-radius: 4px;
317 - text-decoration: none;
318 - border: 1px solid rgba(216, 14, 14, 0.25);
319 - transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
320 - }
321 -
322 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .rtsb-support-link:hover,
323 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .rtsb-support-link:focus {
324 - background: #d80e0e;
325 - color: #fff;
326 - border-color: #d80e0e;
327 - text-decoration: none;
328 - outline: none;
329 - }
330 -
331 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .feedback-input-header {
332 - font-weight: 600;
333 - font-size: 14px;
334 - line-height: 1.5;
335 - margin-bottom: 16px;
336 - color: #1f2937;
337 - }
338 -
339 - div#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> p {
340 - font-size: 14px;
341 - color: #4b5563;
342 - line-height: 1.55;
343 - }
344 -
345 - div#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?>,
346 - .ui-draggable .ui-dialog-titlebar {
347 - padding: 18px 15px;
348 - box-shadow: 0 0 3px rgba(0, 0, 0, 0.1);
349 - text-align: left;
350 - }
351 -
352 - div#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content .feedback-input-wrapper {
353 - margin-bottom: 6px;
354 - display: flex;
355 - align-items: center;
356 - gap: 10px;
357 - padding: 10px 12px;
358 - font-size: 14px;
359 - border: 1px solid #e5e7eb;
360 - border-radius: 8px;
361 - background: #fff;
362 - cursor: pointer;
363 - transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
364 - }
365 -
366 - div#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content .feedback-input-wrapper:hover {
367 - border-color: #4360ef;
368 - background: rgba(67, 96, 239, 0.04);
369 - }
370 -
371 - div#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content .feedback-input-wrapper:has(input[type="radio"]:checked) {
372 - border-color: #4360ef;
373 - background: rgba(67, 96, 239, 0.06);
374 - }
375 -
376 - div#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content .feedback-input-wrapper .feedback-label {
377 - flex: 1;
378 - cursor: pointer;
379 - user-select: none;
380 - color: #1f2937;
381 - font-weight: 500;
382 - line-height: 1.4;
383 - }
384 -
385 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> input[type="radio"] {
386 - appearance: none;
387 - -webkit-appearance: none;
388 - width: 18px;
389 - height: 18px;
390 - border: 1.5px solid #cbd5e1;
391 - border-radius: 50%;
392 - background: #fff;
393 - cursor: pointer;
394 - position: relative;
395 - flex: 0 0 auto;
396 - box-sizing: border-box;
397 - outline: none;
398 - box-shadow: none;
399 - transition: border-color 0.15s ease;
400 - }
401 -
402 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> input[type="radio"]:hover,
403 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> input[type="radio"]:focus,
404 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> input[type="radio"]:focus-visible,
405 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> input[type="radio"]:active {
406 - outline: none;
407 - box-shadow: none;
408 - }
409 -
410 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> input[type="radio"]:hover {
411 - border-color: #94a3b8;
412 - }
413 -
414 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> input[type="radio"]:checked {
415 - border-color: #4360ef;
416 - outline: none;
417 - box-shadow: none;
418 - }
419 -
420 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> input[type="radio"]:checked::after {
421 - content: '';
422 - position: absolute;
423 - top: 50%;
424 - left: 50%;
425 - transform: translate(-50%, -50%);
426 - width: 8px;
427 - height: 8px;
428 - border-radius: 50%;
429 - background: #4360ef;
430 - }
431 -
432 - div#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content .feedback-input-wrapper.conditional {
433 - flex-wrap: wrap;
434 - }
435 -
436 - div#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content .feedback-input-wrapper.conditional .feedback-feedback-text {
437 - flex: 0 0 calc(100% - 28px);
438 - margin: 8px 0 0 28px;
439 - min-height: 38px;
440 - border: 1px solid #cbd5e1;
441 - border-radius: 6px;
442 - padding: 0 12px;
443 - font-size: 13px;
444 - transition: border-color 0.15s ease, box-shadow 0.15s ease;
445 - }
446 -
447 - div#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content .feedback-input-wrapper.conditional .feedback-feedback-text:focus {
448 - border-color: #4360ef;
449 - outline: none;
450 - box-shadow: 0 0 0 3px rgba(67, 96, 239, 0.15);
451 - }
452 -
453 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .rtsb-feedback-extra {
454 - margin: 6px 0 10px;
455 - padding: 12px 14px;
456 - background: #f8fafc;
457 - border: 1px dashed #cbd5e1;
458 - border-radius: 8px;
459 - }
460 -
461 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .rtsb-feedback-extra p {
462 - margin: 0 0 8px !important;
463 - font-size: 13px !important;
464 - font-weight: 500;
465 - color: #4b5563;
466 - line-height: 1.4;
467 - }
468 -
469 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content textarea {
470 - border: 1px solid #cbd5e1;
471 - border-radius: 6px;
472 - padding: 8px 10px;
473 - width: 100%;
474 - min-height: 56px;
475 - max-height: 120px;
476 - font-size: 13px;
477 - line-height: 1.45;
478 - resize: vertical;
479 - transition: border-color 0.15s ease, box-shadow 0.15s ease;
480 - }
481 -
482 - #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content textarea:focus {
483 - border-color: #4360ef;
484 - outline: none;
485 - box-shadow: 0 0 0 3px rgba(67, 96, 239, 0.15);
486 - }
487 -
488 - .ui-widget-overlay.ui-front {
489 - position: fixed;
490 - top: 0;
491 - left: 0;
492 - right: 0;
493 - bottom: 0;
494 - z-index: 999;
495 - background-color: rgba(0, 0, 0, 0.5);
496 - }
497 -
498 - .ui-dialog[aria-describedby="deactivation-dialog-shopbuilder"] .ui-dialog-buttonset {
499 - background-color: #fefefe;
500 - box-shadow: none;
501 - z-index: 99;
502 - padding-left: 30px;
503 - padding-right: 30px;
504 - }
505 -
506 - .ui-dialog[aria-describedby="deactivation-dialog-shopbuilder"] .ui-dialog-buttonpane,
507 - .ui-dialog[aria-describedby="deactivation-dialog-shopbuilder"] .ui-widget-content {
508 - border: 0;
509 - }
510 -
511 - .ui-dialog[aria-describedby="deactivation-dialog-shopbuilder"] .ui-resizable-handle {
512 - display: none !important;
513 - }
514 -
515 - .ui-dialog[aria-describedby="deactivation-dialog-shopbuilder"] .ui-dialog-buttonset .ui-button {
516 - font-size: 12px;
517 - font-weight: 500;
518 - line-height: 1.2;
519 - padding: 8px 16px;
520 - outline: none;
521 - border: none;
522 - }
523 -
524 - .ui-dialog[aria-describedby="deactivation-dialog-shopbuilder"] .ui-dialog-buttonset .ui-button:first-child {
525 - background: #4360ef;
526 - color: #fff;
527 - }
528 -
529 - .ui-dialog[aria-describedby="deactivation-dialog-shopbuilder"] .ui-dialog-buttonset .ui-button:first-child:hover {
530 - background: #1f3edc;
531 - }
532 -
533 - .ui-dialog[aria-describedby="deactivation-dialog-shopbuilder"] .ui-dialog-buttonset .ui-button:last-child {
534 - background: none;
535 - }
536 -
537 - .ui-dialog[aria-describedby="deactivation-dialog-shopbuilder"] .ui-dialog-buttonset .ui-button:last-child:hover {
538 - background: #d80e0e;
539 - color: #fff;
540 - }
541 -
542 - /* Loading overlay shown while submitting feedback / deactivating. */
543 - .rtsb-deactivate-loader {
544 - position: absolute;
545 - inset: 0;
546 - display: flex;
547 - align-items: center;
548 - justify-content: center;
549 - background: rgba(255, 255, 255, 0.72);
550 - z-index: 100;
551 - border-radius: inherit;
552 - }
553 -
554 - .rtsb-deactivate-loader .rtsb-deactivate-spinner {
555 - width: 40px;
556 - height: 40px;
557 - border: 3px solid rgba(67, 96, 239, 0.2);
558 - border-top-color: #4360ef;
559 - border-radius: 50%;
560 - animation: rtsb-deactivate-spin 0.8s linear infinite;
561 - }
562 -
563 - @keyframes rtsb-deactivate-spin {
564 - to {
565 - transform: rotate(360deg);
566 - }
567 - }
568 - </style>
569 -
570 - <?php
571 - }
572 -
573 - /***
574 - * @return void
575 - */
576 - public function deactivation_scripts() {
577 - wp_enqueue_script( 'jquery-ui-dialog' );
578 - ?>
579 - <script>
580 - jQuery(document).ready(function ($) {
581 -
582 - // Open the deactivation dialog when the 'Deactivate' link is clicked
583 - $('.deactivate #deactivate-shopbuilder').on('click', function (e) {
584 - e.preventDefault();
585 - var href = $('.deactivate #deactivate-shopbuilder').attr('href');
586 - $('#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content input[name="reason_found_a_better_plugin"]').hide();
587 - var dialogbox = $('#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?>').dialog({
588 - modal: true,
589 - width: 550,
590 - position: { my: "center", at: "center", of: window },
591 - show: {
592 - effect: "fadeIn",
593 - duration: 400
594 - },
595 - hide: {
596 - effect: "fadeOut",
597 - duration: 100
598 - },
599 -
600 - buttons: {
601 - Submit: function () {
602 - submitFeedback();
603 - },
604 - Cancel: function () {
605 - showDeactivateLoader();
606 - window.location.href = href;
607 - }
608 - }
609 - });
610 -
611 - // Keep the dialog centered on window resize.
612 - $(window).off('resize.rtsbDeactivate').on('resize.rtsbDeactivate', function () {
613 - if ( dialogbox.dialog('instance') ) {
614 - dialogbox.dialog('option', 'position', { my: 'center', at: 'center', of: window });
615 - }
616 - });
617 -
618 -
619 - // Make the entire feedback-input-wrapper card clickable to select its radio.
620 - dialogbox.on('click', '.feedback-input-wrapper', function (event) {
621 - // Ignore clicks on the inner radio/label (native behavior handles them) and the
622 - // "Found a better plugin" name input so typing inside it doesn't re-toggle.
623 - if ( $(event.target).is('input, label') ) {
624 - return;
625 - }
626 - var $radio = $(this).find('input[type="radio"]');
627 - if ( $radio.length && ! $radio.prop('checked') ) {
628 - $radio.prop('checked', true).trigger('change');
629 - }
630 - });
631 -
632 - // Close the dialog when clicking outside of it
633 - dialogbox.on('change', 'input[type="radio"]', function (event) {
634 - var $extra = $('#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .rtsb-feedback-extra');
635 - var $selectedRow = $(this).closest('.feedback-input-wrapper');
636 - var reasons = $('#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> input[type="radio"]:checked').val();
637 - // Temporary deactivation does not need a feedback message — keep the textarea hidden.
638 - if ( 'temporary_deactivation' === reasons ) {
639 - $extra.stop( true, true ).slideUp(200);
640 - } else if ( $selectedRow.length ) {
641 - // Move the feedback textarea so it appears directly below the selected radio.
642 - $extra.hide().insertAfter( $selectedRow ).slideDown(200);
643 - } else {
644 - $extra.slideDown(200);
645 - }
646 - if( 'found_a_better_plugin' === reasons ){
647 - $('#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content input[name="reason_found_a_better_plugin"]').show();
648 - } else {
649 - $('#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content input[name="reason_found_a_better_plugin"]').hide();
650 - }
651 - });
652 -
653 - // Close the dialog when clicking outside of it
654 - $(document).on('click', '.ui-widget-overlay.ui-front', function (event) {
655 - if ($(event.target).closest(dialogbox.parent()).length === 0) {
656 - dialogbox.dialog('close');
657 - }
658 - });
659 -
660 - // Customize the button text
661 - $('.ui-dialog-buttonpane button:contains("Submit")').text('Submit & Deactivate');
662 - $('.ui-dialog-buttonpane button:contains("Cancel")').text('Skip & Deactivate');
663 - });
664 -
665 - // Show a loading spinner over the dialog while submitting /
666 - // deactivating, and lock the footer buttons to avoid double clicks.
667 - function showDeactivateLoader() {
668 - var $content = $('#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?>');
669 - if ( ! $content.length || ! $content.hasClass('ui-dialog-content') ) {
670 - return;
671 - }
672 - var $widget = $content.dialog('widget');
673 - if ( ! $widget.find('.rtsb-deactivate-loader').length ) {
674 - $widget.append('<div class="rtsb-deactivate-loader"><span class="rtsb-deactivate-spinner"></span></div>');
675 - }
676 - $widget.find('.ui-dialog-buttonpane button').prop('disabled', true);
677 - }
678 -
679 - // Submit the feedback
680 - function submitFeedback() {
681 - var href = $('.deactivate #deactivate-shopbuilder').attr('href');
682 - var reasons = $('#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> input[type="radio"]:checked').val();
683 - var feedback = $('#deactivation-feedback-<?php echo esc_attr( $this->textdomain ); ?>').val();
684 - var better_plugin = $('#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content input[name="reason_found_a_better_plugin"]').val();
685 - // Perform AJAX request to submit feedback
686 - if (!reasons && !feedback && !better_plugin) {
687 - // Define flag variables
688 - $('#feedback-form-body-<?php echo esc_attr( $this->textdomain ); ?> span').text('Choose The Reason');
689 - $('.feedback-text-wrapper-<?php echo esc_attr( $this->textdomain ); ?> span').text('Please provide more details regarding the issue so we can address it in future updates.');
690 - return;
691 - }
692 -
693 - if (!reasons ) {
694 - // Define flag variables
695 - $('#feedback-form-body-<?php echo esc_attr( $this->textdomain ); ?> span').text('Choose The Reason');
696 - $('.feedback-text-wrapper-<?php echo esc_attr( $this->textdomain ); ?> span').text('Please provide more details regarding the issue so we can address it in future updates.');
697 - return;
698 - }
699 -
700 - if ( 'bug_issue_detected' === reasons && !feedback ) {
701 - // Define flag variables
702 - $('.feedback-text-wrapper-<?php echo esc_attr( $this->textdomain ); ?> span').text('Please provide more details regarding the issue so we can address it in future updates.');
703 - return;
704 - }
705 -
706 - if ('temporary_deactivation' === reasons || ! feedback ) {
707 - showDeactivateLoader();
708 - window.location.href = href;
709 - return;
710 - }
711 -
712 - if ( ! feedback.length > 0 ) {
713 - showDeactivateLoader();
714 - window.location.href = href;
715 - return;
716 - }
717 - var websiteUrl = '<?php echo esc_url( home_url() ); ?>';
718 - if ( ! websiteUrl.length > 0 ) {
719 - showDeactivateLoader();
720 - window.location.href = href;
721 - return;
722 - }
723 - showDeactivateLoader();
724 - $.ajax({
725 - url: 'https://shopbuilderwp.com/wp-json/RadiusTheme/pluginSurvey/v1/Survey/appendToSheet',
726 - method: 'GET',
727 - dataType: 'json',
728 - // Feedback is best-effort: if the endpoint is slow/unreachable,
729 - // fail fast so the user isn't stuck on the loader. `complete`
730 - // runs on success, error and timeout, so deactivation always
731 - // proceeds (redirects to the deactivate link) regardless.
732 - timeout: 5000,
733 - data: {
734 - website: websiteUrl,
735 - reasons: reasons ? reasons : '',
736 - better_plugin: better_plugin,
737 - feedback: feedback,
738 - wpplugin: 'ShopBuilder',
739 - version: '<?php echo esc_js( defined( 'RTSB_VERSION' ) ? RTSB_VERSION : '' ); ?>',
740 - date: '<?php echo esc_js( gmdate( 'M j, Y' ) ); ?>',
741 - },
742 - success: function (response) {
743 - },
744 - error: function (xhr, status, error) {
745 - // Handle the error response
746 - console.error('Error', error);
747 - },
748 - complete: function (xhr, status) {
749 - $('#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?>').dialog('close');
750 - window.location.href = href;
751 - }
752 -
753 - });
754 - }
755 -
756 - });
757 -
758 - </script>
759 -
760 - <?php
761 - }
762 -}
1 +<?php
2 +
3 +namespace RadiusTheme\SB\Controllers\Admin;
4 +
5 +use RadiusTheme\SB\Traits\SingletonTrait;
6 +
7 +// Do not allow directly accessing this file.
8 +if ( ! defined( 'ABSPATH' ) ) {
9 + exit( 'This script cannot be accessed directly.' );
10 +}
11 +
12 +/**
13 + * Settings Page.
14 + */
15 +class PluginRow {
16 + /**
17 + * Singleton Trait.
18 + */
19 + use SingletonTrait;
20 +
21 + /**
22 + * Template builder post type
23 + *
24 + * @var string
25 + */
26 + public string $textdomain = 'shopbuilder';
27 +
28 + /**
29 + * Construct function
30 + */
31 + private function __construct() {
32 + // Plugins Setting Page.
33 + add_filter( 'plugin_action_links_' . plugin_basename( RTSB_FILE ), [ $this, 'plugins_setting_links' ] );
34 + add_filter( 'plugin_row_meta', [ $this, 'plugin_row_meta' ], 10, 2 );
35 + add_action( 'admin_footer', [ $this, 'deactivation_popup' ], 99 );
36 + }
37 +
38 + /**
39 + * @param array $links default plugin action link
40 + *
41 + * @return array [array] plugin action link
42 + */
43 + public function plugins_setting_links( $links ) {
44 + $demo_url = 'https://shopbuilderwp.com/';
45 + $links[] = '<a href="' . admin_url( 'admin.php?page=rtsb-settings' ) . '">' . esc_html__( 'Settings', 'shopbuilder' ) . '</a>';
46 + $links[] = '<a target="_blank" href="' . esc_url( $demo_url ) . '">' . esc_html__( 'Demo', 'shopbuilder' ) . '</a>';
47 + $links[] = '<a target="_blank" href="' . esc_url( 'https://www.radiustheme.com/docs/shopbuilder/getting-started/requirements/' ) . '">' . esc_html__( 'Documentation', 'shopbuilder' ) . '</a>';
48 + // TODO:: This function will apply after pro version.
49 + if ( ! rtsb()->has_pro() ) {
50 + // $links['shopbuilder_pro'] = sprintf( '<a href="#" target="_blank" style="color: #39b54a; font-weight: bold;">' . esc_html__( 'Go Pro', 'shopbuilder' ) . '</a>' );
51 + }
52 +
53 + return $links;
54 + }
55 +
56 + /**
57 + * Plugin links row.
58 + *
59 + * @param array $links Links.
60 + * @param string $file File.
61 + *
62 + * @return array
63 + */
64 + public function plugin_row_meta( $links, $file ) {
65 +
66 + if ( RTSB_ACTIVE_FILE_NAME === $file ) {
67 + $report_url = 'https://www.radiustheme.com/contact/';
68 + $row_meta['issues'] = sprintf(
69 + '%2$s <a target="_blank" href="%1$s"><span style="color: red">%3$s</span></a>',
70 + esc_url( $report_url ),
71 + esc_html__( 'Facing issue?', 'shopbuilder' ),
72 + esc_html__( 'Please open a support ticket.', 'shopbuilder' )
73 + );
74 +
75 + return array_merge( $links, $row_meta );
76 + }
77 +
78 + return (array) $links;
79 + }
80 +
81 + // Servay
82 +
83 + /***
84 + * @param $mimes
85 + *
86 + * @return mixed
87 + */
88 + public function deactivation_popup() {
89 + global $pagenow;
90 + if ( 'plugins.php' !== $pagenow ) {
91 + return;
92 + }
93 +
94 + $this->dialog_box_style();
95 + $this->deactivation_scripts();
96 + ?>
97 + <div id="deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?>" title="Quick Feedback">
98 + <!-- Modal content -->
99 + <div class="modal-content">
100 + <div id="feedback-form-body-<?php echo esc_attr( $this->textdomain ); ?>">
101 +
102 + <div class="feedback-input-wrapper">
103 + <input id="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-bug_issue_detected" class="feedback-input"
104 + type="radio" name="reason_key" value="bug_issue_detected">
105 + <label for="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-bug_issue_detected" class="feedback-label">Bug Or Issue detected.</label>
106 + </div>
107 +
108 + <div class="feedback-input-wrapper">
109 + <input id="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-no_longer_needed" class="feedback-input" type="radio"
110 + name="reason_key" value="no_longer_needed">
111 + <label for="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-no_longer_needed" class="feedback-label">I no longer
112 + need the plugin</label>
113 + </div>
114 + <div class="feedback-input-wrapper">
115 + <input id="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-found_a_better_plugin" class="feedback-input"
116 + type="radio" name="reason_key" value="found_a_better_plugin">
117 + <label for="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-found_a_better_plugin" class="feedback-label">I found a
118 + better plugin</label>
119 + <input class="feedback-feedback-text" type="text" name="reason_found_a_better_plugin"
120 + placeholder="Please share the plugin name">
121 + </div>
122 + <div class="feedback-input-wrapper">
123 + <input id="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-couldnt_get_the_plugin_to_work" class="feedback-input"
124 + type="radio" name="reason_key" value="couldnt_get_the_plugin_to_work">
125 + <label for="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-couldnt_get_the_plugin_to_work" class="feedback-label">I
126 + couldn't get the plugin to work</label>
127 + </div>
128 +
129 + <div class="feedback-input-wrapper">
130 + <input id="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-temporary_deactivation" class="feedback-input"
131 + type="radio" name="reason_key" value="temporary_deactivation">
132 + <label for="feedback-deactivate-<?php echo esc_attr( $this->textdomain ); ?>-temporary_deactivation" class="feedback-label">It's a
133 + temporary deactivation</label>
134 + </div>
135 + <span style="color:red;font-size: 16px;"></span>
136 + </div>
137 + <p style="margin: 0 0 15px 0;">
138 + Please let us know about any issues you are facing with the plugin.
139 + How can we improve the plugin?
140 + </p>
141 + <div class="feedback-text-wrapper-<?php echo esc_attr( $this->textdomain ); ?>">
142 + <textarea id="deactivation-feedback-<?php echo esc_attr( $this->textdomain ); ?>" rows="4" cols="40"
143 + placeholder=" Write something here. How can we improve the plugin?"></textarea>
144 + <span style="color:red;font-size: 16px;"></span>
145 + </div>
146 + <p style="margin: 0;">
147 + Your satisfaction is our utmost inspiration. Thank you for your feedback.
148 + </p>
149 + </div>
150 + </div>
151 + <?php
152 + }
153 +
154 + /***
155 + * @param $mimes
156 + *
157 + * @return mixed
158 + */
159 + public function dialog_box_style() {
160 + ?>
161 + <style>
162 + /* Add Animation */
163 + @-webkit-keyframes animatetop {
164 + from {
165 + top: -300px;
166 + opacity: 0
167 + }
168 + to {
169 + top: 0;
170 + opacity: 1
171 + }
172 + }
173 +
174 + @keyframes animatetop {
175 + from {
176 + top: -300px;
177 + opacity: 0
178 + }
179 + to {
180 + top: 0;
181 + opacity: 1
182 + }
183 + }
184 +
185 + #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> {
186 + display: none;
187 + }
188 +
189 + .ui-dialog-titlebar-close {
190 + display: none;
191 + }
192 +
193 + /* The Modal (background) */
194 + #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal {
195 + display: none; /* Hidden by default */
196 + position: fixed; /* Stay in place */
197 + z-index: 1; /* Sit on top */
198 + padding-top: 100px; /* Location of the box */
199 + left: 0;
200 + top: 0;
201 + width: 100%; /* Full width */
202 + height: 100%; /* Full height */
203 + overflow: auto; /* Enable scroll if needed */
204 + }
205 +
206 + /* Modal Content */
207 + #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content {
208 + position: relative;
209 + margin: auto;
210 + padding: 0;
211 + }
212 +
213 + #deactivation-dialog-<?php echo esc_attr( $this->textdomain ) ; ?> .feedback-label {
214 + font-size: 15px;
215 + }
216 +
217 + div#deactivation-dialog-<?php echo esc_attr( $this->textdomain ) ; ?> p {
218 + font-size: 16px;
219 + }
220 +
221 + #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content > * {
222 + width: 100%;
223 + padding: 5px 2px;
224 + overflow: hidden;
225 + }
226 +
227 + #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content textarea {
228 + border: 1px solid rgba(0, 0, 0, 0.3);
229 + padding: 15px;
230 + width: 100%;
231 + }
232 +
233 + #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content input.feedback-feedback-text {
234 + border: 1px solid rgba(0, 0, 0, 0.3);
235 + min-width: 250px;
236 + }
237 +
238 + /* The Close Button */
239 + #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> input[type="radio"] {
240 + margin: 0;
241 + }
242 +
243 + .ui-dialog-title {
244 + font-size: 18px;
245 + font-weight: 600;
246 + }
247 +
248 + #deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-body {
249 + padding: 2px 16px;
250 + }
251 +
252 + .ui-dialog-buttonset {
253 + background-color: #fefefe;
254 + padding: 0 17px 25px;
255 + display: flex;
256 + justify-content: space-between;
257 + gap: 10px;
258 + }
259 +
260 + .ui-dialog-buttonset button {
261 + min-width: 110px;
262 + text-align: center;
263 + border: 1px solid rgba(0, 0, 0, 0.1);
264 + padding: 0 15px;
265 + border-radius: 5px;
266 + height: 40px;
267 + font-size: 15px;
268 + font-weight: 600;
269 + display: inline-flex;
270 + align-items: center;
271 + justify-content: center;
272 + cursor: pointer;
273 + transition: 0.3s all;
274 + background: rgba(0, 0, 0, 0.02);
275 + margin: 0;
276 + }
277 +
278 + .ui-dialog-buttonset button:nth-child(2) {
279 + background: transparent;
280 + }
281 +
282 + .ui-dialog-buttonset button:hover {
283 + background: #2271b1;
284 + color: #fff;
285 + }
286 +
287 + .ui-dialog[aria-describedby="deactivation-dialog-shopbuilder"] {
288 + background-color: #fefefe;
289 + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
290 + z-index: 99;
291 + }
292 +
293 + div#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?>,
294 + .ui-draggable .ui-dialog-titlebar {
295 + padding: 18px 15px;
296 + box-shadow: 0 0 3px rgba(0, 0, 0, 0.1);
297 + text-align: left;
298 + }
299 +
300 + .modal-content .feedback-input-wrapper {
301 + margin-bottom: 8px;
302 + display: flex;
303 + align-items: center;
304 + gap: 8px;
305 + line-height: 2;
306 + padding: 0 2px;
307 + }
308 +
309 + .ui-widget-overlay.ui-front {
310 + position: fixed;
311 + top: 0;
312 + left: 0;
313 + right: 0;
314 + bottom: 0;
315 + z-index: 999;
316 + background-color: rgba(0, 0, 0, 0.5);
317 + }
318 +
319 + </style>
320 +
321 + <?php
322 + }
323 +
324 + /***
325 + * @param $mimes
326 + *
327 + * @return mixed
328 + */
329 + public function deactivation_scripts() {
330 + wp_enqueue_script( 'jquery-ui-dialog' );
331 + ?>
332 + <script>
333 + jQuery(document).ready(function ($) {
334 +
335 + // Open the deactivation dialog when the 'Deactivate' link is clicked
336 + $('.deactivate #deactivate-shopbuilder').on('click', function (e) {
337 + e.preventDefault();
338 + var href = $('.deactivate #deactivate-shopbuilder').attr('href');
339 + var given = localRetrieveData("feedback-given");
340 +
341 + // If set for limited time.
342 + if ('given' === given) {
343 + // window.location.href = href;
344 + // return;
345 + }
346 + $('#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?>').dialog({
347 + modal: true,
348 + width: 500,
349 + show: {
350 + effect: "fadeIn",
351 + duration: 400
352 + },
353 + hide: {
354 + effect: "fadeOut",
355 + duration: 100
356 + },
357 +
358 + buttons: {
359 + Submit: function () {
360 + submitFeedback();
361 + },
362 + Cancel: function () {
363 + $(this).dialog('close');
364 + window.location.href = href;
365 + }
366 + }
367 + });
368 + // Customize the button text
369 + $('.ui-dialog-buttonpane button:contains("Submit")').text('Send Feedback & Deactivate');
370 + $('.ui-dialog-buttonpane button:contains("Cancel")').text('Skip & Deactivate');
371 + });
372 +
373 + // Submit the feedback
374 + function submitFeedback() {
375 + var href = $('.deactivate #deactivate-shopbuilder').attr('href');
376 + var reasons = $('#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> input[type="radio"]:checked').val();
377 + var feedback = $('#deactivation-feedback-<?php echo esc_attr( $this->textdomain ); ?>').val();
378 + var better_plugin = $('#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?> .modal-content input[name="reason_found_a_better_plugin"]').val();
379 + // Perform AJAX request to submit feedback
380 + if (!reasons && !feedback && !better_plugin) {
381 + // Define flag variables
382 + $('#feedback-form-body-<?php echo esc_attr( $this->textdomain ); ?> span').text('Choose The Reason');
383 + $('.feedback-text-wrapper-<?php echo esc_attr( $this->textdomain ); ?> span').text('Please provide me with some advice.');
384 + return;
385 + }
386 +
387 + if ('temporary_deactivation' == reasons && !feedback) {
388 + window.location.href = href;
389 + }
390 +
391 + $.ajax({
392 + url: 'https://shopbuilderwp.com/wp-json/RadiusTheme/pluginSurvey/v1/Survey/appendToSheet',
393 + method: 'GET',
394 + dataType: 'json',
395 + data: {
396 + website: '<?php echo esc_url( home_url() )?>',
397 + reasons: reasons ? reasons : '',
398 + better_plugin: better_plugin,
399 + feedback: feedback,
400 + wpplugin: 'ShopBuilder',
401 + },
402 + success: function (response) {
403 + if (response.success) {
404 + console.log('Success');
405 + localStoreData("feedback-given", 'given');
406 + }
407 + },
408 + error: function (xhr, status, error) {
409 + // Handle the error response
410 + console.error('Error', error);
411 + },
412 + complete: function (xhr, status) {
413 + $('#deactivation-dialog-<?php echo esc_attr( $this->textdomain ); ?>').dialog('close');
414 + window.location.href = href;
415 + }
416 +
417 + });
418 + }
419 +
420 + // Store data in local storage with an expiration time of 1 hour
421 + function localStoreData(key, value) {
422 + // Calculate the expiration time in milliseconds (1 hour = 60 minutes * 60 seconds * 1000 milliseconds)
423 + var expirationTime = Date.now() + (60 * 60 * 1000);
424 +
425 + // Create an object to store the data and expiration time
426 + var dataObject = {
427 + value: value,
428 + expirationTime: expirationTime
429 + };
430 +
431 + // Store the object in local storage
432 + localStorage.setItem(key, JSON.stringify(dataObject));
433 + }
434 +
435 + // Retrieve data from local storage
436 + function localRetrieveData(key) {
437 + // Get the stored data from local storage
438 + var data = localStorage.getItem(key);
439 + if (data) {
440 + // Parse the stored JSON data
441 + var dataObject = JSON.parse(data);
442 + // Check if the data has expired
443 + if (Date.now() <= dataObject.expirationTime) {
444 + // Return the stored value
445 + return dataObject.value;
446 + } else {
447 + // Data has expired, remove it from local storage
448 + localStorage.removeItem(key);
449 + }
450 + }
451 + // Return null if data doesn't exist or has expired
452 + return null;
453 + }
454 +
455 + });
456 +
457 + </script>
458 +
459 + <?php
460 + }
461 +
462 +
463 +}