PluginProbe ʕ •ᴥ•ʔ
Robin Image Optimizer – Unlimited Image Optimization, WebP & AVIF / 2.0.6
Robin Image Optimizer – Unlimited Image Optimization, WebP & AVIF v2.0.6
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 / includes / class-wrio-subscribe-widget.php
robin-image-optimizer / admin / includes Last commit date
classes 7 months ago class-wrio-subscribe-widget.php 7 months ago index.php 3 years ago sidebar-widgets.php 7 months ago
class-wrio-subscribe-widget.php
227 lines
1 <?php
2 /**
3 * Subscribe Widget Class
4 *
5 * Self-contained newsletter subscription widget that can be used on any admin page.
6 * No dependencies on Factory libs.
7 *
8 * @package Robin_Image_Optimizer
9 * @subpackage Admin\Includes
10 */
11
12 // Exit if accessed directly.
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 /**
18 * Class WRIO_Subscribe_Widget
19 */
20 class WRIO_Subscribe_Widget {
21
22 /**
23 * ThemeIsle subscription API endpoint
24 */
25 const API_URL = 'https://api.themeisle.com/tracking/subscribe';
26
27 /**
28 * Option name to track subscription status
29 */
30 const OPTION_SUBSCRIBED = 'wrio_user_subscribed';
31
32 /**
33 * Plugin slug for API
34 *
35 * @var string
36 */
37 private $plugin_name = 'wbcr_image_optimizer';
38
39 /**
40 * Privacy policy URL
41 *
42 * @var string
43 */
44 private $privacy_url = 'https://themeisle.com/privacy-policy/';
45
46 /**
47 * Constructor
48 */
49 public function __construct() {
50 add_action( 'wp_ajax_wrio_subscribe', [ $this, 'ajax_handler' ] );
51 }
52
53 /**
54 * Check if user has already subscribed
55 *
56 * @return bool
57 */
58 public function is_subscribed() {
59 return (bool) get_option( self::OPTION_SUBSCRIBED, false );
60 }
61
62 /**
63 * Render the subscribe widget
64 *
65 * @return void
66 */
67 public function render() {
68 if ( $this->is_subscribed() ) {
69 return;
70 }
71
72 $nonce = wp_create_nonce( 'wrio_subscribe' );
73 ?>
74 <div class="wrio-subscribe-widget">
75 <div class="wrio-subscribe-widget__header">
76 <h3><?php esc_html_e( 'Subscribe to plugin\'s newsletter', 'robin-image-optimizer' ); ?></h3>
77 </div>
78 <div class="wrio-subscribe-widget__body">
79 <p><?php esc_html_e( 'Get the latest news and updates about the plugin:', 'robin-image-optimizer' ); ?></p>
80 <div class="wrio-subscribe-widget__messages">
81 <div class="wrio-subscribe-widget__success" style="display:none;">
82 <?php esc_html_e( 'Thank you for subscribing.', 'robin-image-optimizer' ); ?>
83 </div>
84 <div class="wrio-subscribe-widget__error" style="display:none;"></div>
85 </div>
86 <form class="wrio-subscribe-widget__form">
87 <div class="wrio-subscribe-widget__field-wrap">
88 <input
89 type="email"
90 name="email"
91 class="wrio-subscribe-widget__email"
92 placeholder="<?php esc_attr_e( 'Enter your email address', 'robin-image-optimizer' ); ?>"
93 required
94 >
95 <button type="submit" class="button button-primary wrio-subscribe-widget__button">
96 <?php esc_html_e( 'Subscribe', 'robin-image-optimizer' ); ?>
97 </button>
98 </div>
99 <label class="wrio-subscribe-widget__checkbox-label">
100 <input type="checkbox" name="agree_terms" checked required>
101 <?php
102 printf(
103 /* translators: %1$s: opening link tag, %2$s: closing link tag */
104 esc_html__( 'I agree to receive the Themeisle newsletter. See our %1$sPrivacy Policy%2$s for details.', 'robin-image-optimizer' ),
105 '<a href="' . esc_url( $this->privacy_url ) . '" target="_blank" rel="noopener">',
106 '</a>'
107 );
108 ?>
109 </label>
110 </form>
111 </div>
112 </div>
113 <script>
114 (function() {
115 const form = document.querySelector('.wrio-subscribe-widget__form');
116 if (!form) return;
117
118 form.addEventListener('submit', function(e) {
119 e.preventDefault();
120
121 const button = form.querySelector('.wrio-subscribe-widget__button');
122 const successEl = document.querySelector('.wrio-subscribe-widget__success');
123 const errorEl = document.querySelector('.wrio-subscribe-widget__error');
124 const email = form.querySelector('[name="email"]').value;
125 const agreed = form.querySelector('[name="agree_terms"]').checked;
126
127 if (!agreed) {
128 return;
129 }
130
131 button.disabled = true;
132 button.textContent = '<?php echo esc_js( __( 'Subscribing...', 'robin-image-optimizer' ) ); ?>';
133 errorEl.style.display = 'none';
134
135 const data = new FormData();
136 data.append('action', 'wrio_subscribe');
137 data.append('email', email);
138 data.append('_wpnonce', '<?php echo esc_js( $nonce ); ?>');
139
140 fetch(ajaxurl, {
141 method: 'POST',
142 body: data
143 })
144 .then(r => r.json())
145 .then(res => {
146 if (res.success) {
147 form.style.display = 'none';
148 successEl.style.display = 'block';
149 } else {
150 errorEl.textContent = res.data.message || '<?php echo esc_js( __( 'An error occurred. Please try again.', 'robin-image-optimizer' ) ); ?>';
151 errorEl.style.display = 'block';
152 button.disabled = false;
153 button.textContent = '<?php echo esc_js( __( 'Subscribe', 'robin-image-optimizer' ) ); ?>';
154 }
155 })
156 .catch(() => {
157 errorEl.textContent = '<?php echo esc_js( __( 'An error occurred. Please try again.', 'robin-image-optimizer' ) ); ?>';
158 errorEl.style.display = 'block';
159 button.disabled = false;
160 button.textContent = '<?php echo esc_js( __( 'Subscribe', 'robin-image-optimizer' ) ); ?>';
161 });
162 });
163 })();
164 </script>
165 <?php
166 }
167
168 /**
169 * Handle AJAX subscription request
170 *
171 * @return void
172 */
173 public function ajax_handler() {
174 check_ajax_referer( 'wrio_subscribe', '_wpnonce' );
175
176 if ( ! current_user_can( 'manage_options' ) ) {
177 wp_send_json_error( [ 'message' => __( 'Permission denied.', 'robin-image-optimizer' ) ] );
178 }
179
180 $email = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : '';
181
182 if ( ! is_email( $email ) ) {
183 wp_send_json_error( [ 'message' => __( 'Please enter a valid email address.', 'robin-image-optimizer' ) ] );
184 }
185
186 $body = wp_json_encode(
187 [
188 'slug' => $this->plugin_name,
189 'site' => home_url(),
190 'email' => $email,
191 ]
192 );
193
194 // Ensure body is a string, not false.
195 if ( false === $body ) {
196 wp_send_json_error( [ 'message' => __( 'Failed to encode request body.', 'robin-image-optimizer' ) ] );
197 }
198
199 $response = wp_remote_post(
200 self::API_URL,
201 [
202 'timeout' => 10,
203 'headers' => [
204 'Content-Type' => 'application/json',
205 'Cache-Control' => 'no-cache',
206 'Accept' => 'application/json, */*;q=0.1',
207 ],
208 'body' => $body,
209 ]
210 );
211
212 if ( is_wp_error( $response ) ) {
213 wp_send_json_error( [ 'message' => $response->get_error_message() ] );
214 }
215
216 $body = wp_remote_retrieve_body( $response );
217 $data = json_decode( $body, true );
218
219 if ( isset( $data['code'] ) ) {
220 update_option( self::OPTION_SUBSCRIBED, 1 );
221 wp_send_json_success( [ 'message' => __( 'Subscribed successfully!', 'robin-image-optimizer' ) ] );
222 }
223
224 wp_send_json_error( [ 'message' => __( 'Subscription failed. Please try again.', 'robin-image-optimizer' ) ] );
225 }
226 }
227