PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more / 2.5.5
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more v2.5.5
4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 trunk 1.0.0 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 2.0.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.2.0 3.2.1 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.7.0 3.7.1 3.7.2 3.7.3 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9 4.0.0 4.0.1 4.0.10 4.0.11 4.0.12 4.0.13 4.0.14 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.10 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 4.2.0 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.8 4.2.9 4.3.0 4.3.1 4.4.0 4.4.1 4.4.10 4.4.11 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.5.0 4.5.1
embedpress / EmbedPress / Includes / Classes / EmbedPress_Plugin_Usage_Tracker.php
embedpress / EmbedPress / Includes / Classes Last commit date
EmbedPress_Core_Installer.php 6 years ago EmbedPress_Notice.php 6 years ago EmbedPress_Plugin_Usage_Tracker.php 6 years ago
EmbedPress_Plugin_Usage_Tracker.php
996 lines
1 <?php
2 /**
3 * This is the class that sends all the data back to the home site
4 * It also handles opting in and deactivation
5 * @version 1.1.2
6 */
7
8 namespace EmbedPress\Includes\Classes;
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit;
12 }// Exit if accessed directly
13
14 class EmbedPress_Plugin_Usage_Tracker {
15 private $wpins_version = '1.1.3';
16 private $home_url = '';
17 private $plugin_file = '';
18 private $plugin_name = '';
19 private $options = array();
20 private $require_optin = true;
21 private $include_goodbye_form = true;
22 private $marketing = false;
23 private $collect_email = false;
24
25 /**
26 * Class constructor
27 *
28 * @param $_home_url The URL to the site we're sending data to
29 * @param $_plugin_file The file path for this plugin
30 * @param $_options Plugin options to track
31 * @param $_require_optin Whether user opt-in is required (always required on WordPress.org)
32 * @param $_include_goodbye_form Whether to include a form when the user deactivates
33 * @param $_marketing Marketing method:
34 * 0: Don't collect email addresses
35 * 1: Request permission same time as tracking opt-in
36 * 2: Request permission after opt-in
37 */
38 public function __construct(
39 $_plugin_file,
40 $_home_url,
41 $_options,
42 $_require_optin=true,
43 $_include_goodbye_form=true,
44 $_marketing=false ) {
45
46 $this->plugin_file = $_plugin_file;
47 $this->home_url = trailingslashit( $_home_url );
48 $this->plugin_name = basename( $this->plugin_file, '.php' );
49 $this->options = $_options;
50 $this->require_optin = $_require_optin;
51 $this->include_goodbye_form = $_include_goodbye_form;
52 $this->marketing = $_marketing;
53
54 // Schedule some tracking when activated
55 register_activation_hook( $this->plugin_file, array( $this, 'schedule_tracking' ) );
56 // Deactivation hook
57 register_deactivation_hook( $this->plugin_file, array( $this, 'deactivate_this_plugin' ) );
58
59 // Get it going
60 $this->init();
61
62 }
63
64 public function init() {
65 // Check marketing
66 if( $this->marketing == 3 ) {
67 $this->set_can_collect_email( true, $this->plugin_name );
68 }
69 // Check whether opt-in is required
70 // If not, then tracking is allowed
71 if( ! $this->require_optin ) {
72 $this->set_can_collect_email( true, $this->plugin_name );
73 $this->set_is_tracking_allowed( true );
74 $this->update_block_notice();
75 $this->do_tracking( true );
76 }
77 // Hook our do_tracking function to the daily action
78 add_action( 'wpdeveloper_notice_clicked_for_' . $this->plugin_name, array( $this, 'clicked' ) );
79
80 add_action( 'put_do_weekly_action', array( $this, 'do_tracking' ) );
81 // Use this action for local testing and for one time force tracking in a life time.
82 // add_action( 'admin_init', array( $this, 'force_tracking' ) );
83
84 // Display the admin notice on activation
85 add_action( 'wpdeveloper_optin_notice_for_' . $this->plugin_name, array( $this, 'optin_notice' ) );
86 add_action( 'admin_notices', array( $this, 'marketing_notice' ) );
87
88 // Deactivation
89 add_filter( 'plugin_action_links_' . plugin_basename( $this->plugin_file ), array( $this, 'filter_action_links' ) );
90 add_action( 'admin_footer-plugins.php', array( $this, 'goodbye_ajax' ) );
91 add_action( 'wp_ajax_goodbye_form_' . esc_attr( $this->plugin_name ), array( $this, 'goodbye_form_callback' ) );
92
93 }
94
95 /**
96 * When the plugin is activated
97 * Create scheduled event
98 * And check if tracking is enabled - perhaps the plugin has been reactivated
99 *
100 * @since 1.0.0
101 */
102 public function schedule_tracking() {
103 // For historical reasons, this is called 'weekly' but is in fact daily
104 if ( ! wp_next_scheduled( 'put_do_weekly_action' ) ) {
105 wp_schedule_event( time(), 'daily', 'put_do_weekly_action' );
106 }
107 }
108 /**
109 * This function is responsible for force tracking the plugin,
110 * if users are allowed to do!
111 *
112 * @return void
113 */
114 public function force_tracking(){
115 $this->do_tracking( true );
116 }
117
118 /**
119 * This is our function to get everything going
120 * Check that user has opted in
121 * Collect data
122 * Then send it back
123 *
124 * @since 1.0.0
125 * @param $force Force tracking if it's not time
126 */
127 public function do_tracking( $force=false ) {
128 // If the home site hasn't been defined, we just drop out. Nothing much we can do.
129 if ( ! $this->home_url ) {
130 return;
131 }
132
133 // Check to see if the user has opted in to tracking
134 $allow_tracking = $this->get_is_tracking_allowed();
135 if( ! $allow_tracking ) {
136 return;
137 }
138
139 // Check to see if it's time to track
140 $track_time = $this->get_is_time_to_track();
141 if( ! $track_time && ! $force ) {
142 return;
143 }
144
145 $this->set_admin_email();
146
147 // Get our data
148 $body = $this->get_data();
149
150 // Send the data
151 $this->send_data( $body );
152 }
153
154 /**
155 * Send the data to the home site
156 *
157 * @since 1.0.0
158 */
159 public function send_data( $body ) {
160
161 $request = wp_remote_post(
162 esc_url( $this->home_url . '?usage_tracker=hello' ),
163 array(
164 'method' => 'POST',
165 'timeout' => 20,
166 'redirection' => 5,
167 'httpversion' => '1.1',
168 'blocking' => true,
169 'body' => $body,
170 'user-agent' => 'PUT/1.0.0; ' . get_bloginfo( 'url' )
171 )
172 );
173
174 $this->set_track_time();
175
176 if( is_wp_error( $request ) ) {
177 return $request;
178 }
179
180 }
181
182 /**
183 * Here we collect most of the data
184 *
185 * @since 1.0.0
186 */
187 public function get_data() {
188
189 // Use this to pass error messages back if necessary
190 $body['message'] = '';
191 // Use this array to send data back
192 $body = array(
193 'plugin_slug' => sanitize_text_field( $this->plugin_name ),
194 'url' => get_bloginfo( 'url' ),
195 'site_name' => get_bloginfo( 'name' ),
196 'site_version' => get_bloginfo( 'version' ),
197 'site_language' => get_bloginfo( 'language' ),
198 'charset' => get_bloginfo( 'charset' ),
199 'wpins_version' => $this->wpins_version,
200 'php_version' => phpversion(),
201 'multisite' => is_multisite(),
202 'file_location' => __FILE__
203 );
204
205 // Collect the email if the correct option has been set
206 if( $this->get_can_collect_email() ) {
207 $body['email'] = $this->get_admin_email();
208 }
209 $body['marketing_method'] = $this->marketing;
210
211 $body['server'] = isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : '';
212
213 // Retrieve current plugin information
214 if( ! function_exists( 'get_plugins' ) ) {
215 include ABSPATH . '/wp-admin/includes/plugin.php';
216 }
217
218 $plugins = array_keys( get_plugins() );
219 $active_plugins = get_option( 'active_plugins', array() );
220
221 foreach ( $plugins as $key => $plugin ) {
222 if ( in_array( $plugin, $active_plugins ) ) {
223 // Remove active plugins from list so we can show active and inactive separately
224 unset( $plugins[$key] );
225 }
226 }
227
228 $body['active_plugins'] = $active_plugins;
229 $body['inactive_plugins'] = $plugins;
230
231 // Check text direction
232 $body['text_direction'] = 'LTR';
233 if( function_exists( 'is_rtl' ) ) {
234 if( is_rtl() ) {
235 $body['text_direction'] = 'RTL';
236 }
237 } else {
238 $body['text_direction'] = 'not set';
239 }
240
241 /**
242 * Get our plugin data
243 * Currently we grab plugin name and version
244 * Or, return a message if the plugin data is not available
245 * @since 1.0.0
246 */
247 $plugin = $this->plugin_data();
248 if( empty( $plugin ) ) {
249 // We can't find the plugin data
250 // Send a message back to our home site
251 $body['message'] .= __( 'We can\'t detect any plugin information. This is most probably because you have not included the code in the plugin main file.', 'notificationx' );
252 $body['status'] = 'Data not found'; // Never translated
253 } else {
254 if( isset( $plugin['Name'] ) ) {
255 $body['plugin'] = sanitize_text_field( $plugin['Name'] );
256 }
257 if( isset( $plugin['Version'] ) ) {
258 $body['version'] = sanitize_text_field( $plugin['Version'] );
259 }
260 $body['status'] = 'Active'; // Never translated
261 }
262
263 /**
264 * Get our plugin options
265 * @since 1.0.0
266 */
267 $options = $this->options;
268 $plugin_options = array();
269 if( ! empty( $options ) && is_array( $options ) ) {
270 foreach( $options as $option ) {
271 $fields = get_option( $option );
272 // Check for permission to send this option
273 if( isset( $fields['wpins_registered_setting'] ) ) {
274 foreach( $fields as $key=>$value ) {
275 $plugin_options[$key] = $value;
276 }
277 }
278 }
279 }
280 $body['plugin_options'] = $this->options; // Returns array
281 $body['plugin_options_fields'] = $plugin_options; // Returns object
282
283 /**
284 * Get our theme data
285 * Currently we grab theme name and version
286 * @since 1.0.0
287 */
288 $theme = wp_get_theme();
289 if( $theme->Name ) {
290 $body['theme'] = sanitize_text_field( $theme->Name );
291 }
292 if( $theme->Version ) {
293 $body['theme_version'] = sanitize_text_field( $theme->Version );
294 }
295
296 // Return the data
297 return $body;
298
299 }
300
301 /**
302 * Return plugin data
303 * @since 1.0.0
304 */
305 public function plugin_data() {
306 // Being cautious here
307 if( ! function_exists( 'get_plugin_data' ) ) {
308 include ABSPATH . '/wp-admin/includes/plugin.php';
309 }
310 // Retrieve current plugin information
311 $plugin = get_plugin_data( $this->plugin_file );
312 return $plugin;
313 }
314
315 /**
316 * Deactivating plugin
317 * @since 1.0.0
318 */
319 public function deactivate_this_plugin() {
320 // Check to see if the user has opted in to tracking
321 $allow_tracking = $this->get_is_tracking_allowed();
322 if( ! $allow_tracking ) {
323 return;
324 }
325 $body = $this->get_data();
326 $body['status'] = 'Deactivated'; // Never translated
327 $body['deactivated_date'] = time();
328
329 // Add deactivation form data
330 if( false !== get_option( 'wpins_deactivation_reason_' . $this->plugin_name ) ) {
331 $body['deactivation_reason'] = get_option( 'wpins_deactivation_reason_' . $this->plugin_name );
332 }
333 if( false !== get_option( 'wpins_deactivation_details_' . $this->plugin_name ) ) {
334 $body['deactivation_details'] = get_option( 'wpins_deactivation_details_' . $this->plugin_name );
335 }
336
337 $this->send_data( $body );
338 // Clear scheduled update
339 wp_clear_scheduled_hook( 'put_do_weekly_action' );
340 }
341
342 /**
343 * Is tracking allowed?
344 * @since 1.0.0
345 */
346 public function get_is_tracking_allowed() {
347 // First, check if the user has changed their mind and opted out of tracking
348 if( $this->has_user_opted_out() ) {
349 $this->set_is_tracking_allowed( false, $this->plugin_name );
350 return false;
351 }
352 // The wpins_allow_tracking option is an array of plugins that are being tracked
353 $allow_tracking = get_option( 'wpins_allow_tracking' );
354 // If this plugin is in the array, then tracking is allowed
355 if( isset( $allow_tracking[$this->plugin_name] ) ) {
356 return true;
357 }
358 return false;
359 }
360
361 /**
362 * Set if tracking is allowed
363 * Option is an array of all plugins with tracking permitted
364 * More than one plugin may be using the tracker
365 * @since 1.0.0
366 * @param $is_allowed Boolean true if tracking is allowed, false if not
367 */
368 public function set_is_tracking_allowed( $is_allowed, $plugin=null ) {
369 if( empty( $plugin ) ) {
370 $plugin = $this->plugin_name;
371 }
372 // The wpins_allow_tracking option is an array of plugins that are being tracked
373 $allow_tracking = get_option( 'wpins_allow_tracking' );
374
375 // If the user has decided to opt out
376 if( $this->has_user_opted_out() ) {
377 if( isset( $allow_tracking[$plugin] ) ) {
378 unset( $allow_tracking[$plugin] );
379 }
380 } else if( $is_allowed || ! $this->require_optin ) {
381 // If the user has agreed to allow tracking or if opt-in is not required
382 if( empty( $allow_tracking ) || ! is_array( $allow_tracking ) ) {
383 // If nothing exists in the option yet, start a new array with the plugin name
384 $allow_tracking = array( $plugin => $plugin );
385 } else {
386 // Else add the plugin name to the array
387 $allow_tracking[$plugin] = $plugin;
388 }
389 } else {
390 if( isset( $allow_tracking[$plugin] ) ) {
391 unset( $allow_tracking[$plugin] );
392 }
393 }
394 update_option( 'wpins_allow_tracking', $allow_tracking );
395 }
396
397 /**
398 * Has the user opted out of allowing tracking?
399 * @since 1.1.0
400 * @return Boolean
401 */
402 public function has_user_opted_out() {
403 // Iterate through the options that are being tracked looking for wpins_opt_out setting
404 if( ! empty( $this->options ) ) {
405 foreach( $this->options as $option_name ) {
406 // Check each option
407 $options = get_option( $option_name );
408 // If we find the setting, return true
409 if( ! empty( $options['wpins_opt_out'] ) ) {
410 return true;
411 }
412 }
413 }
414 return false;
415 }
416
417 /**
418 * Check if it's time to track
419 * @since 1.1.1
420 */
421 public function get_is_time_to_track() {
422 // Let's see if we're due to track this plugin yet
423 $track_times = get_option( 'wpins_last_track_time', array() );
424 if( ! isset( $track_times[$this->plugin_name] ) ) {
425 // If we haven't set a time for this plugin yet, then we must track it
426 return true;
427 } else {
428 // If the time is set, let's see if it's more than a day ago
429 if( $track_times[$this->plugin_name] < strtotime( '-1 day' ) ) {
430 return true;
431 }
432 }
433 return false;
434 }
435
436 /**
437 * Record the time we send tracking data
438 * @since 1.1.1
439 */
440 public function set_track_time() {
441 // We've tracked, so record the time
442 $track_times = get_option( 'wpins_last_track_time', array() );
443 // Set different times according to plugin, in case we are tracking multiple plugins
444 $track_times[$this->plugin_name] = time();
445 update_option( 'wpins_last_track_time', $track_times );
446 }
447
448 /**
449 * Set if we should block the opt-in notice for this plugin
450 * Option is an array of all plugins that have received a response from the user
451 * @since 1.0.0
452 */
453 public function update_block_notice( $plugin=null ) {
454 if( empty( $plugin ) ) {
455 $plugin = $this->plugin_name;
456 }
457 $block_notice = get_option( 'wpins_block_notice' );
458 if( empty( $block_notice ) || ! is_array( $block_notice ) ) {
459 // If nothing exists in the option yet, start a new array with the plugin name
460 $block_notice = array( $plugin => $plugin );
461 } else {
462 // Else add the plugin name to the array
463 $block_notice[$plugin] = $plugin;
464 }
465 update_option( 'wpins_block_notice', $block_notice );
466 }
467
468 /**
469 * Can we collect the email address?
470 * @since 1.0.0
471 */
472 public function get_can_collect_email() {
473 // The wpins_collect_email option is an array of plugins that are being tracked
474 $collect_email = get_option( 'wpins_collect_email' );
475 // If this plugin is in the array, then we can collect the email address
476 if( isset( $collect_email[$this->plugin_name] ) ) {
477 return true;
478 }
479 return false;
480 }
481
482 /**
483 * Set if user has allowed us to collect their email address
484 * Option is an array of all plugins with email collection permitted
485 * More than one plugin may be using the tracker
486 * @since 1.0.0
487 * @param $can_collect Boolean true if collection is allowed, false if not
488 */
489 public function set_can_collect_email( $can_collect, $plugin=null ) {
490 if( empty( $plugin ) ) {
491 $plugin = $this->plugin_name;
492 }
493 // The wpins_collect_email option is an array of plugins that are being tracked
494 $collect_email = get_option( 'wpins_collect_email' );
495 // If the user has agreed to allow tracking or if opt-in is not required
496 if( $can_collect ) {
497 if( empty( $collect_email ) || ! is_array( $collect_email ) ) {
498 // If nothing exists in the option yet, start a new array with the plugin name
499 $collect_email = array( $plugin => $plugin );
500 } else {
501 // Else add the plugin name to the array
502 $collect_email[$plugin] = $plugin;
503 }
504 } else {
505 if( isset( $collect_email[$plugin] ) ) {
506 unset( $collect_email[$plugin] );
507 }
508 }
509 update_option( 'wpins_collect_email', $collect_email );
510 }
511
512 /**
513 * Get the correct email address to use
514 * @since 1.1.2
515 * @return Email address
516 */
517 public function get_admin_email() {
518 // The wpins_collect_email option is an array of plugins that are being tracked
519 $email = get_option( 'wpins_admin_emails' );
520 // If this plugin is in the array, then we can collect the email address
521 if( isset( $email[$this->plugin_name] ) ) {
522 return $email[$this->plugin_name];
523 }
524 return false;
525 }
526
527 /**
528 * Set the correct email address to use
529 * There might be more than one admin on the site
530 * So we only use the first admin's email address
531 * @param $email Email address to set
532 * @param $plugin Plugin name to set email address for
533 * @since 1.1.2
534 */
535 public function set_admin_email( $email=null, $plugin=null ) {
536 if( empty( $plugin ) ) {
537 $plugin = $this->plugin_name;
538 }
539 // If no email address passed, try to get the current user's email
540 if( empty( $email ) ) {
541 // Have to check that current user object is available
542 if( function_exists( 'wp_get_current_user' ) ) {
543 $current_user = wp_get_current_user();
544 $email = $current_user->user_email;
545 }
546 }
547 // The wpins_admin_emails option is an array of admin email addresses
548 $admin_emails = get_option( 'wpins_admin_emails' );
549 if( empty( $admin_emails ) || ! is_array( $admin_emails ) ) {
550 // If nothing exists in the option yet, start a new array with the plugin name
551 $admin_emails = array( $plugin => sanitize_email( $email ) );
552 } else if( empty( $admin_emails[$plugin] ) ) {
553 // Else add the email address to the array, if not already set
554 $admin_emails[$plugin] = sanitize_email( $email );
555 }
556 update_option( 'wpins_admin_emails', $admin_emails );
557 }
558
559 public function clicked(){
560 // Check for plugin args
561 if( isset( $_GET['plugin'] ) && isset( $_GET['plugin_action'] ) ) {
562 $plugin = sanitize_text_field( $_GET['plugin'] );
563 $action = sanitize_text_field( $_GET['plugin_action'] );
564 if( $action == 'yes' ) {
565 $this->set_is_tracking_allowed( true, $plugin );
566 $this->do_tracking( true ); // Run this straightaway
567 } else {
568 $this->set_is_tracking_allowed( false, $plugin );
569 }
570 $this->update_block_notice( $plugin );
571 }
572 }
573
574 /**
575 * Display the admin notice to users to allow them to opt in
576 *
577 * @since 1.0.0
578 */
579 public function optin_notice() {
580 // Check whether to block the notice, e.g. because we're in a local environment
581 // wpins_block_notice works the same as wpins_allow_tracking, an array of plugin names
582 $block_notice = get_option( 'wpins_block_notice' );
583 if( isset( $block_notice[$this->plugin_name] ) ) {
584 return;
585 }
586
587 if ( ! current_user_can( 'manage_options' ) ) {
588 return;
589 }
590
591 // @credit EDD
592 // Don't bother asking user to opt in if they're in local dev
593 $is_local = false;
594 if( stristr( network_site_url( '/' ), '.dev' ) !== false || stristr( network_site_url( '/' ), 'localhost' ) !== false || stristr( network_site_url( '/' ), ':8888' ) !== false ) {
595 $is_local = true;
596 }
597 $is_local = apply_filters( 'wpins_is_local_' . $this->plugin_name, $is_local );
598 if ( $is_local ) {
599 $this->update_block_notice();
600 } else {
601
602 // Display the notice requesting permission to track
603 // Retrieve current plugin information
604 $plugin = $this->plugin_data();
605 $plugin_name = $plugin['Name'];
606
607 // Args to add to query if user opts in to tracking
608 $yes_args = array(
609 'plugin' => $this->plugin_name,
610 'plugin_action' => 'yes'
611 );
612
613 // Decide how to request permission to collect email addresses
614 if( $this->marketing == 1 ) {
615 // Option 1 combines permissions to track and collect email
616 $yes_args['marketing_optin'] = 'yes';
617 } else if( $this->marketing == 2 ) {
618 // Option 2 enables a second notice that fires after the user opts in to tracking
619 $yes_args['marketing'] = 'yes';
620 }
621 $url_yes = add_query_arg( $yes_args );
622 $url_no = add_query_arg( array(
623 'plugin' => $this->plugin_name,
624 'plugin_action' => 'no'
625 ) );
626
627 // Decide on notice text
628 if( $this->marketing != 1 ) {
629 // Standard notice text
630 $notice_text = __( 'Thank you for installing our plugin. We would like to track its usage on your site. We don\'t record any sensitive data, only information regarding the WordPress environment and plugin settings, which we will use to help us make improvements to the plugin. Tracking is completely optional.', 'notificationx' );
631 } else {
632 // If we have option 1 for marketing, we include reference to sending product information here
633 $notice_text = __( 'Want to help make <strong>EmbedPress</strong> even more awesome? You can get a <strong>10% discount coupon</strong> for Premium extensions if you allow us to track the usage. <a class="embedpress-insights-data-we-collect" href="#">What we collect.</a>', 'notificationx' );
634 }
635 // And we allow you to filter the text anyway
636 $notice_text = apply_filters( 'wpins_notice_text_' . esc_attr( $this->plugin_name ), $notice_text ); ?>
637
638 <div class="notice notice-info updated put-dismiss-notice">
639 <p><?php echo __( $notice_text, 'notificationx' ); ?></p>
640 <div class="embedpress-insights-data" style="display: none;">
641 <p><?php echo __( 'We collect non-sensitive diagnostic data and plugin usage information. Your site URL, WordPress & PHP version, plugins & themes and email address to send you the discount coupon. This data lets us make sure this plugin always stays compatible with the most popular plugins and themes. No spam, I promise.', 'notificationx' ); ?></p>
642 </div>
643 <p>
644 <a href="<?php echo esc_url( $url_yes ); ?>" class="button-primary"><?php _e( 'Sure, I\'d like to help', 'notificationx' ); ?></a>
645 <a href="<?php echo esc_url( $url_no ); ?>" class="button-secondary"><?php _e( 'No Thanks', 'notificationx' ); ?></a>
646 </p>
647 <?php echo "<script type='text/javascript'>jQuery('.embedpress-insights-data-we-collect').on('click', function(e) {
648 e.preventDefault();
649 jQuery('.embedpress-insights-data').slideToggle('fast');
650 });
651 </script>";?>
652 </div>
653 <?php
654 }
655 }
656 /**
657 * Display the marketing notice to users if enabled
658 * Only displays after the user has opted in to tracking
659 *
660 * @since 1.0.0
661 */
662 public function marketing_notice() {
663 // Check if user has opted in to marketing
664 if( isset( $_GET['marketing_optin'] ) ) {
665 // Set marketing optin
666 $this->set_can_collect_email( sanitize_text_field( $_GET['marketing_optin'] ), $this->plugin_name );
667 // Do tracking
668 $this->do_tracking( true );
669 } else if( isset( $_GET['marketing'] ) && $_GET['marketing']=='yes' ) {
670 // Display the notice requesting permission to collect email address
671 // Retrieve current plugin information
672 $plugin = $this->plugin_data();
673 $plugin_name = $plugin['Name'];
674
675 $url_yes = add_query_arg( array(
676 'plugin' => $this->plugin_name,
677 'marketing_optin' => 'yes'
678 ) );
679 $url_no = add_query_arg( array(
680 'plugin' => $this->plugin_name,
681 'marketing_optin' => 'no'
682 ) );
683
684 $marketing_text = __( 'Thank you for opting in to tracking. Would you like to receive occasional news about this plugin, including details of new features and special offers?', 'notificationx' );
685 $marketing_text = apply_filters( 'wpins_marketing_text_' . esc_attr( $this->plugin_name ), $marketing_text ); ?>
686
687 <div class="notice notice-info updated put-dismiss-notice">
688 <p><?php echo '<strong>' . esc_html( $plugin_name ) . '</strong>'; ?></p>
689 <p><?php echo esc_html( $marketing_text ); ?></p>
690 <p>
691 <a href="<?php echo esc_url( $url_yes ); ?>" data-putnotice="yes" class="button-secondary"><?php _e( 'Yes Please', 'notificationx' ); ?></a>
692 <a href="<?php echo esc_url( $url_no ); ?>" data-putnotice="no" class="button-secondary"><?php _e( 'No Thank You', 'notificationx' ); ?></a>
693 </p>
694 </div>
695 <?php }
696 }
697
698 /**
699 * Filter the deactivation link to allow us to present a form when the user deactivates the plugin
700 * @since 1.0.0
701 */
702 public function filter_action_links( $links ) {
703 // Check to see if the user has opted in to tracking
704 if( ! $this->get_is_tracking_allowed() ) {
705 return $links;
706 }
707 if( isset( $links['deactivate'] ) && $this->include_goodbye_form ) {
708 $deactivation_link = $links['deactivate'];
709
710
711 // Insert an onClick action to allow form before deactivating
712 $deactivation_link = str_replace( '<a ', '<div class="wpdev-put-goodbye-form-wrapper-'. esc_attr( $this->plugin_name ) .'"><div class="wpdev-put-goodbye-form-bg-'. esc_attr( $this->plugin_name ) .'"></div><span class="wpdev-put-goodbye-form" id="wpdev-put-goodbye-form-' . esc_attr( $this->plugin_name ) . '"></span></div><a onclick="javascript:event.preventDefault();" id="wpdev-put-goodbye-link-' . esc_attr( $this->plugin_name ) . '" ', $deactivation_link );
713 $links['deactivate'] = $deactivation_link;
714 }
715 return $links;
716 }
717
718 /*
719 * Form text strings
720 * These are non-filterable and used as fallback in case filtered strings aren't set correctly
721 * @since 1.0.0
722 */
723 public function form_default_text() {
724 $form = array();
725 $form['heading'] = __( 'Sorry to see you go', 'notificationx' );
726 $form['body'] = __( 'Before you deactivate the plugin, would you quickly give us your reason for doing so?', 'notificationx' );
727
728 $form['options'] = array(
729 __( 'I no longer need the plugin', 'notificationx' ),
730 [
731 'label' => __( 'I found a better plugin', 'notificationx' ),
732 'extra_field' => __( 'Please share which plugin', 'notificationx' )
733 ],
734 __( "I couldn't get the plugin to work", 'notificationx' ),
735 __( 'It\'s a temporary deactivation', 'notificationx' ),
736 [
737 'label' => __( 'Other', 'notificationx' ),
738 'extra_field' => __( 'Please share the reason', 'notificationx' ),
739 'type' => 'textarea'
740 ]
741 );
742
743 return $form;
744 }
745
746 /**
747 * Form text strings
748 * These can be filtered
749 * The filter hook must be unique to the plugin
750 * @since 1.0.0
751 */
752 public function form_filterable_text() {
753 $form = $this->form_default_text();
754 return apply_filters( 'wpins_form_text_' . esc_attr( $this->plugin_name ), $form );
755 }
756
757 /**
758 * Form text strings
759 * These can be filtered
760 * @since 1.0.0
761 */
762 public function goodbye_ajax() {
763 // Get our strings for the form
764 $form = $this->form_filterable_text();
765 if( ! isset( $form['heading'] ) || ! isset( $form['body'] ) || ! isset( $form['options'] ) || ! is_array( $form['options'] ) || ! isset( $form['details'] ) ) {
766 // If the form hasn't been filtered correctly, we revert to the default form
767 $form = $this->form_default_text();
768 }
769 // Build the HTML to go in the form
770 $html = '<div class="wpdev-put-goodbye-form-head"><strong>' . esc_html( $form['heading'] ) . '</strong></div>';
771 $html .= '<div class="wpdev-put-goodbye-form-body"><p class="wpdev-put-goodbye-form-caption">' . esc_html( $form['body'] ) . '</p>';
772 if( is_array( $form['options'] ) ) {
773 $html .= '<div id="wpdev-'. esc_attr( $this->plugin_name ) .'-goodbye-options" class="wpdev-'. esc_attr( $this->plugin_name ) .'-goodbye-options"><ul>';
774 foreach( $form['options'] as $option ) {
775 if( is_array( $option ) ) {
776 $id = strtolower( str_replace( " ", "_", esc_attr( $option['label'] ) ) );
777 $id = $id . '_' . esc_attr( $this->plugin_name );
778 $html .= '<li class="has-goodbye-extra">';
779 $html .= '<input type="radio" name="wpdev-'. esc_attr( $this->plugin_name ) .'-goodbye-options" id="' . $id . '" value="' . esc_attr( $option['label'] ) . '">';
780 $html .= '<div><label for="' . $id . '">' . esc_attr( $option['label'] ) . '</label>';
781 if( isset( $option[ 'extra_field' ] ) && ! isset( $option['type'] )) {
782 $html .= '<input type="text" style="display: none" name="'. $id .'" id="' . str_replace( " ", "", esc_attr( $option['extra_field'] ) ) . '" placeholder="' . esc_attr( $option['extra_field'] ) . '">';
783 }
784 if( isset( $option[ 'extra_field' ] ) && isset( $option['type'] )) {
785 $html .= '<'. $option['type'] .' style="display: none" type="text" name="'. $id .'" id="' . str_replace( " ", "", esc_attr( $option['extra_field'] ) ) . '" placeholder="' . esc_attr( $option['extra_field'] ) . '"></' . $option['type'] . '>';
786 }
787 $html .= '</div></li>';
788 } else {
789 $id = strtolower( str_replace( " ", "_", esc_attr( $option ) ) );
790 $id = $id . '_' . esc_attr( $this->plugin_name );
791 $html .= '<li><input type="radio" name="wpdev-'. esc_attr( $this->plugin_name ) .'-goodbye-options" id="' . $id . '" value="' . esc_attr( $option ) . '"> <label for="' . $id . '">' . esc_attr( $option ) . '</label></li>';
792 }
793 }
794 $html .= '</ul></div><!-- .wpdev-'. esc_attr( $this->plugin_name ) .'-goodbye-options -->';
795 }
796 $html .= '</div><!-- .wpdev-put-goodbye-form-body -->';
797 $html .= '<p class="deactivating-spinner"><span class="spinner"></span> ' . __( 'Submitting form', 'notificationx' ) . '</p>';
798 ?>
799 <style type="text/css">
800 .wpdev-put-form-active-<?php echo esc_attr( $this->plugin_name ); ?> .wpdev-put-goodbye-form-bg-<?php echo esc_attr( $this->plugin_name ); ?> {
801 background: rgba( 0, 0, 0, .8 );
802 position: fixed;
803 top: 0;
804 left: 0;
805 width: 100%;
806 height: 100%;
807 z-index: 9;
808 }
809 .wpdev-put-goodbye-form-wrapper-<?php echo esc_attr( $this->plugin_name ); ?> {
810 position: relative;
811 display: none;
812 }
813 .wpdev-put-form-active-<?php echo esc_attr( $this->plugin_name ); ?> .wpdev-put-goodbye-form-wrapper-<?php echo esc_attr( $this->plugin_name ); ?> {
814 display: flex !important;
815 align-items: center;
816 justify-content: center;
817 width: 100%;
818 height: 100%;
819 position: fixed;
820 left: 0px;
821 top: 0px;
822 }
823 .wpdev-put-goodbye-form {
824 display: none;
825 }
826 .wpdev-put-form-active-<?php echo esc_attr( $this->plugin_name ); ?> .wpdev-put-goodbye-form {
827 position: relative !important;
828 width: 550px;
829 max-width: 80%;
830 background: #fff;
831 box-shadow: 2px 8px 23px 3px rgba(0,0,0,.2);
832 border-radius: 3px;
833 white-space: normal;
834 overflow: hidden;
835 display: block;
836 z-index: 999999;
837 }
838 .wpdev-put-goodbye-form-head {
839 background: #fff;
840 color: #495157;
841 padding: 18px;
842 box-shadow: 0 0 8px rgba(0,0,0,.1);
843 font-size: 15px;
844 }
845 .wpdev-put-goodbye-form .wpdev-put-goodbye-form-head strong {
846 font-size: 15px;
847 }
848 .wpdev-put-goodbye-form-body {
849 padding: 8px 18px;
850 color: #333;
851 }
852 .wpdev-put-goodbye-form-body label {
853 color: #6d7882;
854 padding-left: 5px;
855 }
856 .wpdev-put-goodbye-form-body .wpdev-put-goodbye-form-caption {
857 font-weight: 500;
858 font-size: 15px;
859 color: #495157;
860 line-height: 1.4;
861 }
862 .wpdev-put-goodbye-form-body #wpdev-<?php echo esc_attr( $this->plugin_name ); ?>-goodbye-options {
863 padding-top: 5px;
864 }
865 .wpdev-put-goodbye-form-body #wpdev-<?php echo esc_attr( $this->plugin_name ); ?>-goodbye-options ul > li {
866 margin-bottom: 15px;
867 }
868 .deactivating-spinner {
869 display: none;
870 padding-bottom: 20px !important;
871 }
872 .deactivating-spinner .spinner {
873 float: none;
874 margin: 4px 4px 0 18px;
875 vertical-align: bottom;
876 visibility: visible;
877 }
878 .wpdev-put-goodbye-form-footer {
879 padding: 8px 18px;
880 margin-bottom: 15px;
881 }
882 .wpdev-put-goodbye-form-footer > .wpdev-put-goodbye-form-buttons {
883 display: flex;
884 align-items: center;
885 justify-content: space-between;
886 }
887 .wpdev-put-goodbye-form-footer .wpsp-put-submit-btn {
888 background-color: #d30c5c;
889 -webkit-border-radius: 3px;
890 border-radius: 3px;
891 color: #fff;
892 line-height: 1;
893 padding: 15px 20px;
894 font-size: 13px;
895 }
896 .wpdev-put-goodbye-form-footer .wpsp-put-deactivate-btn {
897 font-size: 13px;
898 color: #a4afb7;
899 background: none;
900 float: right;
901 padding-right: 10px;
902 width: auto;
903 text-decoration: underline;
904 }
905 #wpdev-<?php echo esc_attr( $this->plugin_name ); ?>-goodbye-options ul li > div {
906 display: inline;
907 padding-left: 3px;
908 }
909 #wpdev-<?php echo esc_attr( $this->plugin_name ); ?>-goodbye-options ul li > div > input, #wpdev-<?php echo esc_attr( $this->plugin_name ); ?>-goodbye-options ul li > div > textarea {
910 margin: 10px 18px;
911 padding: 8px;
912 width: 80%;
913 }
914 </style>
915 <script>
916 jQuery(document).ready(function($){
917 $("#wpdev-put-goodbye-link-<?php echo esc_attr( $this->plugin_name ); ?>").on("click",function(){
918 // We'll send the user to this deactivation link when they've completed or dismissed the form
919 var url = document.getElementById("wpdev-put-goodbye-link-<?php echo esc_attr( $this->plugin_name ); ?>");
920 $('body').toggleClass('wpdev-put-form-active-<?php echo esc_attr( $this->plugin_name ); ?>');
921 $("#wpdev-put-goodbye-form-<?php echo esc_attr( $this->plugin_name ); ?>").fadeIn();
922 $("#wpdev-put-goodbye-form-<?php echo esc_attr( $this->plugin_name ); ?>").html( '<?php echo $html; ?>' + '<div class="wpdev-put-goodbye-form-footer"><div class="wpdev-put-goodbye-form-buttons"><a id="put-submit-form-<?php echo esc_attr( $this->plugin_name ); ?>" class="wpsp-put-submit-btn" href="#"><?php _e( 'Submit and Deactivate', 'notificationx' ); ?></a>&nbsp;<a class="wpsp-put-deactivate-btn" href="'+url+'"><?php _e( 'Just Deactivate', 'notificationx' ); ?></a></div></div>');
923 $('#put-submit-form-<?php echo esc_attr( $this->plugin_name ); ?>').on('click', function(e){
924 // As soon as we click, the body of the form should disappear
925 $("#wpdev-put-goodbye-form-<?php echo esc_attr( $this->plugin_name ); ?> .wpdev-put-goodbye-form-body").fadeOut();
926 $("#wpdev-put-goodbye-form-<?php echo esc_attr( $this->plugin_name ); ?> .wpdev-put-goodbye-form-footer").fadeOut();
927 // Fade in spinner
928 $("#wpdev-put-goodbye-form-<?php echo esc_attr( $this->plugin_name ); ?> .deactivating-spinner").fadeIn();
929 e.preventDefault();
930 var checkedInput = $("input[name='wpdev-<?php echo esc_attr( $this->plugin_name ); ?>-goodbye-options']:checked"),
931 checkedInputVal, details;
932 if( checkedInput.length > 0 ) {
933 checkedInputVal = checkedInput.val();
934 details = $('input[name="'+ checkedInput[0].id +'"], textarea[name="'+ checkedInput[0].id +'"]').val();
935 }
936
937 if( typeof details === 'undefined' ) {
938 details = '';
939 }
940 if( typeof checkedInputVal === 'undefined' ) {
941 checkedInputVal = 'No Reason';
942 }
943
944 var data = {
945 'action': 'goodbye_form_<?php echo esc_attr( $this->plugin_name ); ?>',
946 'values': checkedInputVal,
947 'details': details,
948 'security': "<?php echo wp_create_nonce ( 'wpins_goodbye_form' ); ?>",
949 'dataType': "json"
950 }
951
952 $.post(
953 ajaxurl,
954 data,
955 function(response){
956 // Redirect to original deactivation URL
957 window.location.href = url;
958 }
959 );
960 });
961 $('#wpdev-<?php echo esc_attr( $this->plugin_name ); ?>-goodbye-options > ul ').on('click', 'li label, li > input', function( e ){
962 var parent = $(this).parents('li');
963 parent.siblings().find('label').next('input, textarea').css('display', 'none');
964 parent.find('label').next('input, textarea').css('display', 'block');
965 });
966 // If we click outside the form, the form will close
967 $('.wpdev-put-goodbye-form-bg-<?php echo esc_attr( $this->plugin_name ); ?>').on('click',function(){
968 $("#wpdev-put-goodbye-form-<?php echo esc_attr( $this->plugin_name ); ?>").fadeOut();
969 $('body').removeClass('wpdev-put-form-active-<?php echo esc_attr( $this->plugin_name ); ?>');
970 });
971 });
972
973
974 });
975 </script>
976 <?php }
977
978 /**
979 * AJAX callback when the form is submitted
980 * @since 1.0.0
981 */
982 public function goodbye_form_callback() {
983 check_ajax_referer( 'wpins_goodbye_form', 'security' );
984 if( isset( $_POST['values'] ) ) {
985 $values = $_POST['values'];
986 update_option( 'wpins_deactivation_reason_' . $this->plugin_name, $values );
987 }
988 if( isset( $_POST['details'] ) ) {
989 $details = sanitize_text_field( $_POST['details'] );
990 update_option( 'wpins_deactivation_details_' . $this->plugin_name, $details );
991 }
992 $this->do_tracking(); // Run this straightaway
993 echo 'success';
994 wp_die();
995 }
996 }