PluginProbe
Copy Anything to Clipboard for WordPress – Copy Button, Copy Text & Copy Code / 5.5.3
Copy Anything to Clipboard for WordPress – Copy Button, Copy Text & Copy Code v5.5.3
5.5.3 3.1.0 3.2.0 3.2.1 3.3.0 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.6.0 3.7.0 3.8.0 3.8.1 3.8.2 3.8.3 4.0.0 4.0.2 4.0.3 4.0.4 4.0.5 4.1.0 4.1.1 All 78 releases
copy-the-code / includes / class-welcome.php

class-welcome.php in Copy Anything to Clipboard for WordPress – Copy Button, Copy Text & Copy Code 5.5.3, at includes/class-welcome.php

426 lines 11.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Welcome Notice
4 *
5 * Handles the welcome/onboarding experience for new installs and upgrades.
6 *
7 * @package CTC
8 * @since 5.0.0
9 */
10
11 namespace CTC;
12
13 /**
14 * Welcome Class
15 *
16 * Manages welcome notices and onboarding for new users.
17 *
18 * @since 5.0.0
19 */
20 class Welcome {
21
22 /**
23 * Instance
24 *
25 * @var Welcome|null
26 */
27 private static $instance = null;
28
29 /**
30 * Option key for tracking welcome notice dismissal.
31 *
32 * @var string
33 */
34 const NOTICE_DISMISSED_OPTION = 'ctc_welcome_notice_dismissed';
35
36 /**
37 * Option key for tracking first install.
38 *
39 * @var string
40 */
41 const FIRST_INSTALL_OPTION = 'ctc_first_install_version';
42
43 /**
44 * Get instance.
45 *
46 * @return Welcome
47 */
48 public static function get() {
49 if ( null === self::$instance ) {
50 self::$instance = new self();
51 }
52 return self::$instance;
53 }
54
55 /**
56 * Constructor.
57 */
58 private function __construct() {
59 // Track first install.
60 $this->maybe_set_first_install();
61
62 // Admin hooks.
63 add_action( 'admin_notices', [ $this, 'render_welcome_notice' ] );
64 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_notice_scripts' ] );
65 add_action( 'wp_ajax_ctc_dismiss_welcome_notice', [ $this, 'ajax_dismiss_notice' ] );
66
67 // Hook into updater for upgrade notices.
68 add_action( 'ctc/updater/after', [ $this, 'on_version_update' ], 10, 2 );
69 }
70
71 /**
72 * Set first install version if not set.
73 *
74 * @since 5.0.0
75 */
76 private function maybe_set_first_install() {
77 if ( ! get_option( self::FIRST_INSTALL_OPTION ) ) {
78 update_option( self::FIRST_INSTALL_OPTION, CTC_VER );
79 }
80 }
81
82 /**
83 * Check if this is a fresh install (no previous version).
84 *
85 * @return bool
86 */
87 public function is_fresh_install() {
88 $saved_version = get_option( Updater::VERSION_OPTION, '' );
89 return empty( $saved_version ) || '0.0.0' === $saved_version;
90 }
91
92 /**
93 * Check if user upgraded from a version before 5.0.0.
94 *
95 * @return bool
96 */
97 public function is_upgrade_to_5() {
98 $first_install = get_option( self::FIRST_INSTALL_OPTION, '' );
99 return ! empty( $first_install ) && version_compare( $first_install, '5.0.0', '<' );
100 }
101
102 /**
103 * Check if welcome notice should be shown.
104 *
105 * @return bool
106 */
107 public function should_show_notice() {
108 // Don't show if dismissed.
109 if ( get_option( self::NOTICE_DISMISSED_OPTION ) ) {
110 return false;
111 }
112
113 // Don't show on the Global Injector page.
114 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
115 if ( isset( $_GET['page'] ) && 'ctc-global-injector' === $_GET['page'] ) {
116 return false;
117 }
118
119 // Only show to users who can manage options.
120 if ( ! current_user_can( 'manage_options' ) ) {
121 return false;
122 }
123
124 return true;
125 }
126
127 /**
128 * Get the welcome message based on install type.
129 *
130 * @return array{title: string, message: string, type: string}
131 */
132 private function get_welcome_content() {
133 if ( $this->is_fresh_install() ) {
134 return [
135 'title' => __( 'Copy Anything to Clipboard is ready', 'ctc' ),
136 'message' => __( 'Add copy buttons to code blocks, tables, and any content with Global Injector. Optionally help improve the plugin by sharing anonymous usage data from this notice or Settings → Dashboard.', 'ctc' ),
137 'type' => 'fresh',
138 ];
139 }
140
141 // Upgrade message (aligned with 5.4.1 changelog).
142 return [
143 'title' => __( 'Copy Anything to Clipboard updated', 'ctc' ),
144 'message' => __( 'Telemetry opt-in is now available from this notice and Settings → Dashboard. Pro: copy-by-source analytics and telemetry summary. Includes uninstall cleanup and a fix for Freemius loading.', 'ctc' ),
145 'type' => 'upgrade',
146 ];
147 }
148
149 /**
150 * Render the welcome admin notice.
151 *
152 * @since 5.0.0
153 */
154 public function render_welcome_notice() {
155 if ( ! $this->should_show_notice() ) {
156 return;
157 }
158
159 $content = $this->get_welcome_content();
160 $global_injector_url = admin_url( 'admin.php?page=ctc-global-injector' );
161 $docs_url = 'https://docs.clipboard.agency/getting-started';
162
163 ?>
164 <div class="notice notice-info is-dismissible ctc-welcome-notice" id="ctc-welcome-notice">
165 <div class="ctc-welcome-notice-content">
166 <div class="ctc-welcome-notice-icon">
167 <span class="dashicons dashicons-clipboard"></span>
168 </div>
169 <div class="ctc-welcome-notice-text">
170 <p class="ctc-welcome-notice-title">
171 <strong><?php echo esc_html( $content['title'] ); ?></strong>
172 </p>
173 <p class="ctc-welcome-notice-message"><?php echo esc_html( $content['message'] ); ?></p>
174 <?php if ( ! Telemetry::get_opt_in() ) : ?>
175 <div class="ctc-welcome-telemetry-opt-in">
176 <label class="ctc-welcome-telemetry-label">
177 <input type="checkbox" name="ctc_telemetry_opt_in_checkbox" id="ctc-telemetry-opt-in-checkbox" value="1" />
178 <?php esc_html_e( 'Yes, help improve Copy Anything to Clipboard by sending anonymous usage data', 'ctc' ); ?>
179 </label>
180 <p class="ctc-welcome-telemetry-note">
181 <?php
182 printf(
183 /* translators: %s: URL to privacy documentation */
184 esc_html__( 'We collect environment info (WP, PHP, theme), feature usage, and error counts. No personal data. See our %s.', 'ctc' ),
185 '<a href="https://clipboard.agency/privacy-policy" target="_blank" rel="noopener noreferrer">' . esc_html__( 'privacy note', 'ctc' ) . '</a>'
186 );
187 ?>
188 </p>
189 </div>
190 <?php endif; ?>
191 <p class="ctc-welcome-notice-actions">
192 <a href="<?php echo esc_url( $global_injector_url ); ?>" class="button button-primary">
193 <?php esc_html_e( 'Open Rules', 'ctc' ); ?>
194 </a>
195 <a href="<?php echo esc_url( $docs_url ); ?>" class="button button-secondary" target="_blank" rel="noopener noreferrer">
196 <?php esc_html_e( 'View Documentation', 'ctc' ); ?>
197 <span class="dashicons dashicons-external" style="font-size: 14px; line-height: 1.8;"></span>
198 </a>
199 <?php if ( 'upgrade' === $content['type'] ) : ?>
200 <a href="https://clipboard.agency/changelog/" class="ctc-welcome-link" target="_blank" rel="noopener noreferrer">
201 <?php esc_html_e( "See what's new", 'ctc' ); ?>
202 </a>
203 <?php endif; ?>
204 </p>
205 </div>
206 </div>
207 </div>
208 <?php
209 }
210
211 /**
212 * Enqueue notice scripts and styles.
213 *
214 * @since 5.0.0
215 */
216 public function enqueue_notice_scripts() {
217 if ( ! $this->should_show_notice() ) {
218 return;
219 }
220
221 // Inline styles for the notice.
222 $styles = '
223 #ctc-welcome-notice {
224 padding: 12px 12px 12px 0;
225 border-left-color: #2271b1;
226 }
227 #ctc-welcome-notice .ctc-welcome-notice-content {
228 display: flex;
229 align-items: flex-start;
230 gap: 12px;
231 }
232 #ctc-welcome-notice .ctc-welcome-notice-icon {
233 flex-shrink: 0;
234 width: 40px;
235 height: 40px;
236 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
237 border-radius: 8px;
238 display: flex;
239 align-items: center;
240 justify-content: center;
241 margin-left: 12px;
242 }
243 #ctc-welcome-notice .ctc-welcome-notice-icon .dashicons {
244 color: #fff;
245 font-size: 20px;
246 width: 20px;
247 height: 20px;
248 }
249 #ctc-welcome-notice .ctc-welcome-notice-text {
250 flex: 1;
251 }
252 #ctc-welcome-notice .ctc-welcome-notice-title {
253 margin: 0 0 4px 0;
254 font-size: 14px;
255 }
256 #ctc-welcome-notice .ctc-welcome-emoji {
257 margin-left: 4px;
258 }
259 #ctc-welcome-notice .ctc-welcome-notice-message {
260 margin: 0 0 12px 0;
261 color: #50575e;
262 }
263 #ctc-welcome-notice .ctc-welcome-telemetry-opt-in {
264 margin: 12px 0;
265 }
266 #ctc-welcome-notice .ctc-welcome-telemetry-label {
267 display: flex;
268 align-items: flex-start;
269 gap: 8px;
270 cursor: pointer;
271 font-size: 13px;
272 color: #1d2327;
273 }
274 #ctc-welcome-notice .ctc-welcome-telemetry-label input {
275 margin-top: 2px;
276 flex-shrink: 0;
277 }
278 #ctc-welcome-notice .ctc-welcome-telemetry-note {
279 margin: 4px 0 0 27px;
280 font-size: 12px;
281 color: #646970;
282 line-height: 1.4;
283 }
284 #ctc-welcome-notice .ctc-welcome-telemetry-note a {
285 color: #2271b1;
286 }
287 #ctc-welcome-notice .ctc-welcome-notice-actions {
288 display: flex;
289 align-items: center;
290 gap: 8px;
291 flex-wrap: wrap;
292 margin: 0;
293 }
294 #ctc-welcome-notice .ctc-welcome-notice-actions .button-primary {
295 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
296 border-color: #667eea;
297 }
298 #ctc-welcome-notice .ctc-welcome-notice-actions .button-primary:hover {
299 background: linear-gradient(135deg, #5a6fd6 0%, #6a4190 100%);
300 border-color: #5a6fd6;
301 }
302 #ctc-welcome-notice .ctc-welcome-link {
303 color: #2271b1;
304 text-decoration: none;
305 font-weight: 500;
306 margin-left: 8px;
307 }
308 #ctc-welcome-notice .ctc-welcome-link:hover {
309 color: #135e96;
310 }
311 ';
312
313 wp_add_inline_style( 'wp-admin', $styles );
314
315 // Inline script for handling dismissal, Get Started, and checkbox opt-in.
316 $dismiss_nonce = wp_create_nonce( 'ctc_dismiss_welcome_notice' );
317 $opt_in_nonce = wp_create_nonce( 'ctc_telemetry_opt_in' );
318 $script = "
319 jQuery(document).ready(function($) {
320 function getOptIn() {
321 return $('#ctc-telemetry-opt-in-checkbox').is(':checked') ? '1' : '0';
322 }
323 function updateOptIn(callback) {
324 $.ajax({
325 url: ajaxurl,
326 type: 'POST',
327 data: {
328 action: 'ctc_update_telemetry_opt_in',
329 nonce: '" . esc_js( $opt_in_nonce ) . "',
330 opt_in: getOptIn()
331 }
332 }).always(function() { if (callback) callback(); });
333 }
334 function dismissNotice(callback) {
335 $.ajax({
336 url: ajaxurl,
337 type: 'POST',
338 data: {
339 action: 'ctc_dismiss_welcome_notice',
340 nonce: '" . esc_js( $dismiss_nonce ) . "',
341 telemetry_opt_in: getOptIn()
342 }
343 }).always(function() { if (callback) callback(); });
344 }
345 $('#ctc-telemetry-opt-in-checkbox').on('change', function() {
346 updateOptIn();
347 });
348 $('#ctc-welcome-notice').on('click', '.notice-dismiss', function() {
349 dismissNotice();
350 });
351 $('#ctc-welcome-notice .ctc-welcome-notice-actions .button-primary').on('click', function(e) {
352 var href = $(this).attr('href');
353 if (href) {
354 e.preventDefault();
355 dismissNotice(function() { window.location.href = href; });
356 }
357 });
358 });
359 ";
360
361 wp_add_inline_script( 'jquery', $script );
362 }
363
364 /**
365 * AJAX handler for dismissing the welcome notice.
366 *
367 * @since 5.0.0
368 */
369 public function ajax_dismiss_notice() {
370 // Verify nonce.
371 if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'ctc_dismiss_welcome_notice' ) ) {
372 wp_send_json_error( 'Invalid nonce' );
373 }
374
375 // Check permissions.
376 if ( ! current_user_can( 'manage_options' ) ) {
377 wp_send_json_error( 'Insufficient permissions' );
378 }
379
380 // Save telemetry opt-in (default opt-out if not explicitly set).
381 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above.
382 $opt_in = isset( $_POST['telemetry_opt_in'] ) && '1' === sanitize_text_field( wp_unslash( $_POST['telemetry_opt_in'] ) );
383 Telemetry::set_opt_in( $opt_in );
384
385 $telemetry = Telemetry::get();
386 if ( $opt_in ) {
387 $telemetry->maybe_send();
388 $telemetry->schedule_cron();
389 } else {
390 $telemetry->unschedule_cron();
391 }
392
393 // Mark as dismissed.
394 update_option( self::NOTICE_DISMISSED_OPTION, true );
395
396 wp_send_json_success();
397 }
398
399 /**
400 * Handle version updates - reset notice for major upgrades.
401 *
402 * @since 5.0.0
403 *
404 * @param string $from_version Previous version.
405 * @param string $to_version New version.
406 */
407 public function on_version_update( $from_version, $to_version ) {
408 // Show welcome notice again for major version upgrades.
409 $from_major = explode( '.', $from_version )[0];
410 $to_major = explode( '.', $to_version )[0];
411
412 if ( $from_major !== $to_major ) {
413 delete_option( self::NOTICE_DISMISSED_OPTION );
414 }
415 }
416
417 /**
418 * Reset welcome notice (useful for testing).
419 *
420 * @since 5.0.0
421 */
422 public static function reset_notice() {
423 delete_option( self::NOTICE_DISMISSED_OPTION );
424 }
425 }
426