ThirstyAffiliates Affiliate Link Manager - Version 3.10.6

Version Description

  • Bug Fix: Security fixes
Download this release

Release Info

Developer caseproof
Plugin Icon 128x128 ThirstyAffiliates Affiliate Link Manager
Version 3.10.6
Comparing to
See all releases

Code changes from version 3.10.5 to 3.10.6

Files changed (47) hide show
  1. Abstracts/Abstract_Main_Plugin_Class.php +12 -0
  2. Helpers/Helper_Functions.php +11 -27
  3. Helpers/Plugin_Constants.php +1 -1
  4. Models/Affiliate_Link.php +16 -7
  5. Models/Affiliate_Link_Attachment.php +9 -5
  6. Models/Affiliate_Links_CPT.php +52 -32
  7. Models/Bootstrap.php +4 -3
  8. Models/Guided_Tour.php +1 -1
  9. Models/Link_Fixer.php +4 -4
  10. Models/Link_Picker.php +29 -18
  11. Models/Marketing.php +12 -13
  12. Models/Migration.php +17 -19
  13. Models/Notifications.php +837 -0
  14. Models/Rewrites_Redirection.php +5 -5
  15. Models/Script_Loader.php +35 -17
  16. Models/Settings.php +109 -109
  17. Models/Stats_Reporting.php +61 -42
  18. css/admin/admin_notifications.css +257 -0
  19. css/lib/jquery-ui/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  20. css/lib/jquery-ui/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  21. css/lib/jquery-ui/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  22. css/lib/jquery-ui/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  23. css/lib/jquery-ui/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  24. css/lib/jquery-ui/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  25. css/lib/jquery-ui/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  26. css/lib/jquery-ui/images/ui-icons_222222_256x240.png +0 -0
  27. css/lib/jquery-ui/images/ui-icons_2e83ff_256x240.png +0 -0
  28. css/lib/jquery-ui/images/ui-icons_454545_256x240.png +0 -0
  29. css/lib/jquery-ui/images/ui-icons_888888_256x240.png +0 -0
  30. css/lib/jquery-ui/images/ui-icons_cd0a0a_256x240.png +0 -0
  31. css/lib/jquery-ui/jquery-ui.min.css +7 -0
  32. js/app/admin_notifications.js +140 -0
  33. readme.txt +4 -1
  34. thirstyaffiliates.php +7 -4
  35. views/cpt/view-attach-images-metabox-external-image.php +1 -1
  36. views/cpt/view-attach-images-metabox.php +8 -8
  37. views/cpt/view-inserted-link-scanner-metabox.php +6 -6
  38. views/cpt/view-link-options-metabox.php +21 -21
  39. views/cpt/view-save-affiliate-link-metabox.php +3 -3
  40. views/cpt/view-urls-metabox.php +11 -11
  41. views/exporter/exporter.php +5 -5
  42. views/importer/importer.php +3 -3
  43. views/linkpicker/advance-link-picker.php +8 -8
  44. views/linkpicker/edit-shortcode.php +8 -8
  45. views/linkpicker/quick-add-affiliate-link.php +19 -19
  46. views/reports/link-performance-report.php +12 -12
  47. views/ta-upgrade.php +3 -3
Abstracts/Abstract_Main_Plugin_Class.php CHANGED
@@ -73,6 +73,18 @@ abstract class Abstract_Main_Plugin_Class {
73
 
74
  }
75
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  /**
77
  * Add a "regular model" to the main plugin class "public models" array.
78
  *
73
 
74
  }
75
 
76
+ /**
77
+ * Retrieves a Model object.
78
+ *
79
+ * @since 3.10
80
+ * @access public
81
+ *
82
+ * @param Model_Interface $model Regular model.
83
+ */
84
+ public function get_model( $class_name ) {
85
+ return $this->__all_models[ $class_name ];
86
+ }
87
+
88
  /**
89
  * Add a "regular model" to the main plugin class "public models" array.
90
  *
Helpers/Helper_Functions.php CHANGED
@@ -224,25 +224,6 @@ class Helper_Functions {
224
 
225
  }
226
 
227
- /**
228
- * Check validity of a save post action.
229
- *
230
- * @since 3.0.0
231
- * @access private
232
- *
233
- * @param int $post_id Id of the coupon post.
234
- * @param string $post_type Post type to check.
235
- * @return bool True if valid save post action, False otherwise.
236
- */
237
- public function check_if_valid_save_post_action( $post_id , $post_type ) {
238
-
239
- if ( get_post_type() != $post_type || empty( $_POST ) || wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) || !current_user_can( 'edit_page' , $post_id ) )
240
- return false;
241
- else
242
- return true;
243
-
244
- }
245
-
246
  /**
247
  * Get user IP address.
248
  *
@@ -254,17 +235,19 @@ class Helper_Functions {
254
  */
255
  public function get_user_ip_address() {
256
 
 
 
257
  if ( get_option( 'ta_disable_ip_address_collection' ) === 'yes' ) {
258
- return '';
259
  }
260
 
261
  if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
262
- $ip = $_SERVER['HTTP_CLIENT_IP'];
263
  } elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
264
- $ip = explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] );
265
  $ip = trim( $ip[0] );
266
- } else {
267
- $ip = $_SERVER['REMOTE_ADDR'];
268
  }
269
 
270
  return apply_filters( 'ta_get_user_ip_address', $ip );
@@ -604,7 +587,8 @@ class Helper_Functions {
604
  */
605
  public function is_user_agent_bot() {
606
 
607
- $user_agent = isset( $_SERVER[ 'HTTP_USER_AGENT' ] ) ? strtolower( $_SERVER[ 'HTTP_USER_AGENT' ] ) : '';
 
608
  $bots = apply_filters( 'ta_useragent_bots_phrase_list' , $this->get_blocked_bots() );
609
  $pattern = '/' . $bots . '/i';
610
 
@@ -624,9 +608,9 @@ class Helper_Functions {
624
  if ( isset( $_GET[ 'post_type' ] ) && $_GET[ 'post_type' ] == Plugin_Constants::AFFILIATE_LINKS_CPT ) {
625
 
626
  if ( isset( $_GET[ 'taxonomy' ] ) )
627
- $screen_id = 'edit-' . $_GET[ 'taxonomy' ];
628
  elseif ( isset( $_GET[ 'page' ] ) )
629
- $screen_id = 'thirstylink_page_' . $_GET[ 'page' ];
630
  else
631
  $screen_id = 'edit-thirstylink';
632
 
224
 
225
  }
226
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  /**
228
  * Get user IP address.
229
  *
235
  */
236
  public function get_user_ip_address() {
237
 
238
+ $ip = '';
239
+
240
  if ( get_option( 'ta_disable_ip_address_collection' ) === 'yes' ) {
241
+ return $ip;
242
  }
243
 
244
  if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
245
+ $ip = sanitize_text_field( wp_unslash( $_SERVER['HTTP_CLIENT_IP'] ) );
246
  } elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
247
+ $ip = explode( ',', sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) );
248
  $ip = trim( $ip[0] );
249
+ } elseif ( ! empty( $_SERVER['REMOTE_ADDR'] ) ) {
250
+ $ip = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
251
  }
252
 
253
  return apply_filters( 'ta_get_user_ip_address', $ip );
587
  */
588
  public function is_user_agent_bot() {
589
 
590
+ $user_agent = isset( $_SERVER[ 'HTTP_USER_AGENT' ] ) ? sanitize_text_field( wp_unslash( ( $_SERVER[ 'HTTP_USER_AGENT' ] ) ) ) : '';
591
+ $user_agent = strtolower( $user_agent );
592
  $bots = apply_filters( 'ta_useragent_bots_phrase_list' , $this->get_blocked_bots() );
593
  $pattern = '/' . $bots . '/i';
594
 
608
  if ( isset( $_GET[ 'post_type' ] ) && $_GET[ 'post_type' ] == Plugin_Constants::AFFILIATE_LINKS_CPT ) {
609
 
610
  if ( isset( $_GET[ 'taxonomy' ] ) )
611
+ $screen_id = 'edit-' . sanitize_text_field( wp_unslash( $_GET[ 'taxonomy' ] ) );
612
  elseif ( isset( $_GET[ 'page' ] ) )
613
+ $screen_id = 'thirstylink_page_' . sanitize_text_field( wp_unslash( $_GET[ 'page' ] ) );
614
  else
615
  $screen_id = 'edit-thirstylink';
616
 
Helpers/Plugin_Constants.php CHANGED
@@ -27,7 +27,7 @@ class Plugin_Constants {
27
  // Plugin configuration constants
28
  const TOKEN = 'ta';
29
  const INSTALLED_VERSION = 'ta_installed_version';
30
- const VERSION = '3.10.5';
31
  const TEXT_DOMAIN = 'thirstyaffiliates';
32
  const THEME_TEMPLATE_PATH = 'thirstyaffiliates';
33
  const META_DATA_PREFIX = '_ta_';
27
  // Plugin configuration constants
28
  const TOKEN = 'ta';
29
  const INSTALLED_VERSION = 'ta_installed_version';
30
+ const VERSION = '3.10.6';
31
  const TEXT_DOMAIN = 'thirstyaffiliates';
32
  const THEME_TEMPLATE_PATH = 'thirstyaffiliates';
33
  const META_DATA_PREFIX = '_ta_';
Models/Affiliate_Link.php CHANGED
@@ -714,12 +714,23 @@ class Affiliate_Link {
714
  global $wpdb;
715
 
716
  $table_name = $wpdb->prefix . Plugin_Constants::LINK_CLICK_DB;
717
- $link_id = $this->get_id();
718
- $query = "SELECT count(*) from $table_name WHERE link_id = $link_id";
719
- $query .= ( $date_offset && \DateTime::createFromFormat('Y-m-d H:i:s', $date_offset ) !== false ) ? " AND date_clicked > '$date_offset'" : '';
720
- $clicks = $wpdb->get_var( $query );
 
 
 
 
 
 
 
 
 
 
721
 
722
  return (int) $clicks;
 
723
  }
724
 
725
  /**
@@ -736,9 +747,7 @@ class Affiliate_Link {
736
  global $wpdb;
737
 
738
  // prepare the query.
739
- $post_ids = array();
740
  $link_id = $this->get_id();
741
- $cpt_slug = Plugin_Constants::AFFILIATE_LINKS_CPT;
742
  $types = get_post_types( array( 'public' => true ) , 'names' , 'and' );
743
  $types_str = implode( "','" , $types );
744
  $permalink = $this->get_prop( 'permalink' );
@@ -753,7 +762,7 @@ class Affiliate_Link {
753
  $query = "SELECT ID FROM $wpdb->posts WHERE ( $like_query_str OR post_content LIKE '%[thirstylink%ids=\"$link_id%' ) AND post_type IN ( '$types_str' ) AND post_status = 'publish'";
754
 
755
  // fetch WP_Post IDs where link is inserted to.
756
- $raw_ids = $wpdb->get_col( $query );
757
 
758
  // save last scanned
759
  update_post_meta( $this->get_id() , Plugin_Constants::META_DATA_PREFIX . 'scanned_inserted' , current_time( 'mysql' , true ) );
714
  global $wpdb;
715
 
716
  $table_name = $wpdb->prefix . Plugin_Constants::LINK_CLICK_DB;
717
+
718
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
719
+ $query = $wpdb->prepare( "SELECT COUNT(*) FROM {$table_name} WHERE link_id = %d", $this->get_id() );
720
+
721
+ if ( $date_offset ) {
722
+ $date_offset = \DateTime::createFromFormat( 'Y-m-d H:i:s', $date_offset );
723
+
724
+ if ( $date_offset !== false ) {
725
+ $query .= $wpdb->prepare( " AND date_clicked > %s", $date_offset->format( 'Y-m-d H:i:s' ) );
726
+ }
727
+ }
728
+
729
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
730
+ $clicks = $wpdb->get_var( $query );
731
 
732
  return (int) $clicks;
733
+
734
  }
735
 
736
  /**
747
  global $wpdb;
748
 
749
  // prepare the query.
 
750
  $link_id = $this->get_id();
 
751
  $types = get_post_types( array( 'public' => true ) , 'names' , 'and' );
752
  $types_str = implode( "','" , $types );
753
  $permalink = $this->get_prop( 'permalink' );
762
  $query = "SELECT ID FROM $wpdb->posts WHERE ( $like_query_str OR post_content LIKE '%[thirstylink%ids=\"$link_id%' ) AND post_type IN ( '$types_str' ) AND post_status = 'publish'";
763
 
764
  // fetch WP_Post IDs where link is inserted to.
765
+ $raw_ids = $wpdb->get_col( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
766
 
767
  // save last scanned
768
  update_post_meta( $this->get_id() , Plugin_Constants::META_DATA_PREFIX . 'scanned_inserted' , current_time( 'mysql' , true ) );
Models/Affiliate_Link_Attachment.php CHANGED
@@ -136,7 +136,10 @@ class Affiliate_Link_Attachment implements Model_Interface , Initiable_Interface
136
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Missing required post data' , 'thirstyaffiliates' ) );
137
  else {
138
 
139
- $result = $this->add_attachments_to_affiliate_link( $_POST[ 'attachment_ids' ] , $_POST[ 'affiliate_link_id' ] );
 
 
 
140
 
141
  if ( is_wp_error( $result ) )
142
  $response = array( 'status' => 'fail' , 'error_msg' => $result->get_error_message() );
@@ -209,8 +212,9 @@ class Affiliate_Link_Attachment implements Model_Interface , Initiable_Interface
209
  elseif ( ! isset( $_POST[ 'attachment_id' ] ) || ! isset( $_POST[ 'affiliate_link_id' ] ) )
210
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Missing required post data' , 'thirstyaffiliates' ) );
211
  else {
212
-
213
- $result = $this->remove_attachment_to_affiliate_link( $_POST[ 'attachment_id' ] , $_POST[ 'affiliate_link_id' ] );
 
214
 
215
  if ( is_wp_error( $result ) )
216
  $response = array( 'status' => 'fail' , 'error_msg' => $result->get_error_message() );
@@ -312,11 +316,11 @@ class Affiliate_Link_Attachment implements Model_Interface , Initiable_Interface
312
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Security Check Failed' , 'thirstyaffiliates' ) );
313
  elseif ( ! isset( $_POST[ 'url' ] ) || ! isset( $_POST[ 'link_id' ] ) )
314
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Missing required post data' , 'thirstyaffiliates' ) );
315
- elseif ( ! filter_var( $_POST[ 'url' ] , FILTER_VALIDATE_URL ) || ! in_array( strtolower( pathinfo( $_POST[ 'url' ] , PATHINFO_EXTENSION ) ) , $allowed_extensions ) )
316
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'The external image source is not a valid url.' , 'thirstyaffiliates' ) );
317
  else {
318
 
319
- $img_url = esc_url_raw( $_POST[ 'url' ] );
320
  $link_id = absint( $_POST[ 'link_id' ] );
321
  $result = $this->add_attachments_to_affiliate_link( array( $img_url ) , $link_id );
322
 
136
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Missing required post data' , 'thirstyaffiliates' ) );
137
  else {
138
 
139
+ $attachment_ids = map_deep( $_POST[ 'attachment_ids' ], 'intval' ); // phpcs:ignore WordPress.Security
140
+ $affiliate_link_id = sanitize_text_field( wp_unslash( $_POST[ 'affiliate_link_id' ] ) );
141
+
142
+ $result = $this->add_attachments_to_affiliate_link( $attachment_ids, $affiliate_link_id );
143
 
144
  if ( is_wp_error( $result ) )
145
  $response = array( 'status' => 'fail' , 'error_msg' => $result->get_error_message() );
212
  elseif ( ! isset( $_POST[ 'attachment_id' ] ) || ! isset( $_POST[ 'affiliate_link_id' ] ) )
213
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Missing required post data' , 'thirstyaffiliates' ) );
214
  else {
215
+ $attachment_id = (int) sanitize_text_field( wp_unslash( $_POST[ 'attachment_id' ] ) );
216
+ $affiliate_link_id = (int) sanitize_text_field( wp_unslash( $_POST[ 'affiliate_link_id' ] ) );
217
+ $result = $this->remove_attachment_to_affiliate_link( $attachment_id, $affiliate_link_id );
218
 
219
  if ( is_wp_error( $result ) )
220
  $response = array( 'status' => 'fail' , 'error_msg' => $result->get_error_message() );
316
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Security Check Failed' , 'thirstyaffiliates' ) );
317
  elseif ( ! isset( $_POST[ 'url' ] ) || ! isset( $_POST[ 'link_id' ] ) )
318
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Missing required post data' , 'thirstyaffiliates' ) );
319
+ elseif ( ! filter_var( $_POST[ 'url' ] , FILTER_VALIDATE_URL ) || ! in_array( strtolower( pathinfo( $_POST[ 'url' ] , PATHINFO_EXTENSION ) ) , $allowed_extensions ) ) // phpcs:ignore WordPress.Security
320
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'The external image source is not a valid url.' , 'thirstyaffiliates' ) );
321
  else {
322
 
323
+ $img_url = esc_url_raw( $_POST[ 'url' ] ); // phpcs:ignore WordPress.Security
324
  $link_id = absint( $_POST[ 'link_id' ] );
325
  $result = $this->add_attachments_to_affiliate_link( array( $img_url ) , $link_id );
326
 
Models/Affiliate_Links_CPT.php CHANGED
@@ -530,12 +530,12 @@ class Affiliate_Links_CPT implements Model_Interface , Initiable_Interface {
530
  $inserted_to = $thirstylink->get_prop( 'inserted_to' );
531
  $timezone = new \DateTimeZone( $this->_helper_functions->get_site_current_timezone() );
532
  $last_scanned = \DateTime::createFromFormat( 'Y-m-d G:i:s' , $thirstylink->get_prop( 'scanned_inserted' ) );
533
- $not_yet_scanned = __( 'Not yet scanned' , 'thirstyaffiliates' );
534
 
535
  if ( $last_scanned )
536
  $last_scanned->setTimezone( $timezone );
537
 
538
- $last_scanned_txt = $last_scanned !== false ? __( 'Last scanned on:' , 'thirstyaffiliates' ) . ' <em>' . $last_scanned->format( 'F j, Y g:ia' ) . '</em>' : $not_yet_scanned;
539
  $inserted_into_rows_html = $this->get_inserted_into_rows_html( $inserted_to );
540
 
541
  include( $this->_constants->VIEWS_ROOT_PATH() . 'cpt/view-inserted-link-scanner-metabox.php' );
@@ -555,20 +555,25 @@ class Affiliate_Links_CPT implements Model_Interface , Initiable_Interface {
555
  global $wpdb;
556
 
557
  if ( ! is_array( $inserted_to ) || empty( $inserted_to ) )
558
- return '<tr><td colspan="4">' . __( 'No results found.' , 'thirstyaffiliates' ) . '</td></tr>';
559
 
 
560
  $inserted_to_str = implode( ',' , $inserted_to );
561
- $results = $wpdb->get_results( "SELECT ID , post_title , post_type FROM $wpdb->posts WHERE ID IN ( $inserted_to_str )" );
 
 
 
 
562
 
563
  ob_start();
564
  foreach ( $results as $object ) : ?>
565
  <tr>
566
  <td class="id"><?php echo esc_html( $object->ID ); ?></td>
567
- <td class="title"><?php echo mb_strimwidth( esc_html( $object->post_title ) , 0 , 60 , "..." ); ?></td>
568
  <td class="post-type"><?php echo esc_html( $object->post_type ); ?></td>
569
  <td class="actions">
570
- <a class="view" href="<?php echo get_permalink( $object->ID ); ?>" target="_blank"><span class="dashicons dashicons-admin-links"></span></a>
571
- <a class="edit" href="<?php echo get_edit_post_link( $object->ID ); ?>" target="_blank"><span class="dashicons dashicons-edit"></span></a>
572
  </td>
573
  </tr>
574
  <?php endforeach;
@@ -596,7 +601,7 @@ class Affiliate_Links_CPT implements Model_Interface , Initiable_Interface {
596
  */
597
  public function save_post( $post_id ) {
598
 
599
- if ( ! isset( $_POST[ '_thirstyaffiliates_nonce' ] ) || ! wp_verify_nonce( $_POST['_thirstyaffiliates_nonce'], 'thirsty_affiliates_cpt_nonce' ) )
600
  return;
601
 
602
  // remove save_post hooked action to prevent infinite loop
@@ -604,24 +609,39 @@ class Affiliate_Links_CPT implements Model_Interface , Initiable_Interface {
604
 
605
  $thirstylink = $this->get_thirstylink_post( $post_id );
606
 
 
 
 
 
 
 
607
  // set Properties
608
- $thirstylink->set_prop( 'destination_url' , esc_url_raw( $_POST[ 'ta_destination_url' ] ) );
609
- $thirstylink->set_prop( 'no_follow' , sanitize_text_field( $_POST[ 'ta_no_follow' ] ) );
610
- $thirstylink->set_prop( 'new_window' , sanitize_text_field( $_POST[ 'ta_new_window' ] ) );
611
- $thirstylink->set_prop( 'pass_query_str' , sanitize_text_field( $_POST[ 'ta_pass_query_str' ] ) );
612
- $thirstylink->set_prop( 'redirect_type' , sanitize_text_field( $_POST[ 'ta_redirect_type' ] ) );
613
- $thirstylink->set_prop( 'rel_tags' , sanitize_text_field( $_POST[ 'ta_rel_tags' ] ) );
614
- $thirstylink->set_prop( 'css_classes' , sanitize_text_field( $_POST[ 'ta_css_classes' ] ) );
 
 
 
 
 
 
 
 
 
615
 
616
  if ( isset( $_POST[ 'post_name' ] ) )
617
- $thirstylink->set_prop( 'slug' , sanitize_text_field( $_POST[ 'post_name' ] ) );
618
 
619
  if ( isset( $_POST[ 'ta_uncloak_link' ] ) )
620
- $thirstylink->set_prop( 'uncloak_link' , sanitize_text_field( $_POST[ 'ta_uncloak_link' ] ) );
621
 
622
- if ( isset( $_POST[ 'ta_category_slug' ] ) && $_POST[ 'ta_category_slug' ] ) {
623
 
624
- $category_slug_id = (int) sanitize_text_field( $_POST[ 'ta_category_slug' ] );
625
  $category_slug = get_term( $category_slug_id , Plugin_Constants::AFFILIATE_LINKS_TAX );
626
  $thirstylink->set_prop( 'category_slug_id' , $category_slug_id );
627
  $thirstylink->set_prop( 'category_slug' , $category_slug->slug );
@@ -733,7 +753,7 @@ class Affiliate_Links_CPT implements Model_Interface , Initiable_Interface {
733
 
734
  $post_type = get_post_type();
735
  if ( !$post_type && isset( $_GET[ 'post_type' ] ) )
736
- $post_type = $_GET[ 'post_type' ];
737
 
738
  if ( ! is_admin() || $post_type !== Plugin_Constants::AFFILIATE_LINKS_CPT )
739
  return;
@@ -778,25 +798,25 @@ class Affiliate_Links_CPT implements Model_Interface , Initiable_Interface {
778
  switch ( $column ) {
779
 
780
  case 'link_id' :
781
- echo '<span>' . $post_id . '</span>';
782
  break;
783
 
784
  case 'redirect_type' :
785
- echo $redirect_type;
786
- echo $redirect_type === 'global' ? ' (' . $this->_helper_functions->get_option( 'ta_link_redirect_type' , '302' ) . ')' : '';
787
  break;
788
 
789
  case 'cloaked_url' :
790
  echo '<div class="ta-display-input-wrap">';
791
- echo '<input style="width:100%;" type="text" value="' . $thirstylink->get_prop( 'permalink' ) . '" readonly>';
792
- echo '<a href="' . $edit_link . '"><span class="dashicons dashicons-edit"></span></a>';
793
  echo '</div>';
794
  break;
795
 
796
  case 'link_destination' :
797
  echo '<div class="ta-display-input-wrap">';
798
- echo '<input style="width:100%;" type="text" value="' . $thirstylink->get_prop( 'destination_url' ) . '" readonly>';
799
- echo '<a href="' . $edit_link . '"><span class="dashicons dashicons-edit"></span></a>';
800
  echo '</div>';
801
  break;
802
 
@@ -940,13 +960,13 @@ class Affiliate_Links_CPT implements Model_Interface , Initiable_Interface {
940
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Missing required post data' , 'thirstyaffiliates' ) );
941
  else {
942
 
943
- $link_cat_id = (int) sanitize_text_field( $_POST[ 'term_id' ] );
944
  $category = get_term( $link_cat_id , Plugin_Constants::AFFILIATE_LINKS_TAX );
945
 
946
  $response = array( 'status' => 'success' , 'category_slug' => $category->slug );
947
  }
948
 
949
- @header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
950
  echo wp_json_encode( $response );
951
  wp_die();
952
  }
@@ -969,7 +989,7 @@ class Affiliate_Links_CPT implements Model_Interface , Initiable_Interface {
969
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Missing required post data' , 'thirstyaffiliates' ) );
970
  else {
971
 
972
- $link_id = (int) sanitize_text_field( $_POST[ 'link_id' ] );
973
  $thirstylink = $this->get_thirstylink_post( $link_id );
974
  $inserted_to = $thirstylink->scan_where_links_inserted();
975
  $timezone = new \DateTimeZone( $this->_helper_functions->get_site_current_timezone() );
@@ -979,11 +999,11 @@ class Affiliate_Links_CPT implements Model_Interface , Initiable_Interface {
979
  $response = array(
980
  'status' => 'success',
981
  'results_markup' => $this->get_inserted_into_rows_html( $inserted_to ),
982
- 'last_scanned' => __( 'Last scanned on:' , 'thirstyaffiliates' ) . ' <em>' . $last_scanned->format( 'F j, Y g:ia' ) . '</em>'
983
  );
984
  }
985
 
986
- @header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
987
  echo wp_json_encode( $response );
988
  wp_die();
989
  }
530
  $inserted_to = $thirstylink->get_prop( 'inserted_to' );
531
  $timezone = new \DateTimeZone( $this->_helper_functions->get_site_current_timezone() );
532
  $last_scanned = \DateTime::createFromFormat( 'Y-m-d G:i:s' , $thirstylink->get_prop( 'scanned_inserted' ) );
533
+ $not_yet_scanned = esc_html__( 'Not yet scanned' , 'thirstyaffiliates' );
534
 
535
  if ( $last_scanned )
536
  $last_scanned->setTimezone( $timezone );
537
 
538
+ $last_scanned_txt = $last_scanned !== false ? esc_html__( 'Last scanned on:' , 'thirstyaffiliates' ) . ' <em>' . $last_scanned->format( 'F j, Y g:ia' ) . '</em>' : $not_yet_scanned;
539
  $inserted_into_rows_html = $this->get_inserted_into_rows_html( $inserted_to );
540
 
541
  include( $this->_constants->VIEWS_ROOT_PATH() . 'cpt/view-inserted-link-scanner-metabox.php' );
555
  global $wpdb;
556
 
557
  if ( ! is_array( $inserted_to ) || empty( $inserted_to ) )
558
+ return '<tr><td colspan="4">' . esc_html__( 'No results found.' , 'thirstyaffiliates' ) . '</td></tr>';
559
 
560
+ $inserted_to = array_map( 'intval', $inserted_to );
561
  $inserted_to_str = implode( ',' , $inserted_to );
562
+
563
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
564
+ $results = $wpdb->get_results(
565
+ "SELECT ID , post_title , post_type FROM $wpdb->posts WHERE ID IN ( $inserted_to_str )",
566
+ );
567
 
568
  ob_start();
569
  foreach ( $results as $object ) : ?>
570
  <tr>
571
  <td class="id"><?php echo esc_html( $object->ID ); ?></td>
572
+ <td class="title"><?php echo mb_strimwidth( esc_html( $object->post_title ) , 0 , 60 , "..." ); // phpcs:ignore WordPress.Security.EscapeOutput ?></td>
573
  <td class="post-type"><?php echo esc_html( $object->post_type ); ?></td>
574
  <td class="actions">
575
+ <a class="view" href="<?php echo esc_url( get_permalink( $object->ID ) ); ?>" target="_blank"><span class="dashicons dashicons-admin-links"></span></a>
576
+ <a class="edit" href="<?php echo esc_url( get_edit_post_link( $object->ID ) ); ?>" target="_blank"><span class="dashicons dashicons-edit"></span></a>
577
  </td>
578
  </tr>
579
  <?php endforeach;
601
  */
602
  public function save_post( $post_id ) {
603
 
604
+ if ( ! isset( $_POST[ '_thirstyaffiliates_nonce' ] ) || ! wp_verify_nonce( sanitize_key( $_POST['_thirstyaffiliates_nonce'] ), 'thirsty_affiliates_cpt_nonce' ) )
605
  return;
606
 
607
  // remove save_post hooked action to prevent infinite loop
609
 
610
  $thirstylink = $this->get_thirstylink_post( $post_id );
611
 
612
+ if( isset( $_POST[ 'ta_destination_url' ] ) ){
613
+ $thirstylink->set_prop( 'destination_url', esc_url_raw( $_POST[ 'ta_destination_url' ] ) ); // phpcs:ignore WordPress.Security
614
+ }else{
615
+ $thirstylink->set_prop( 'destination_url', '' );
616
+ }
617
+
618
  // set Properties
619
+ $properties = array(
620
+ 'no_follow' => 'ta_no_follow',
621
+ 'new_window' => 'ta_new_window',
622
+ 'pass_query_str' => 'ta_pass_query_str',
623
+ 'redirect_type' => 'ta_redirect_type',
624
+ 'rel_tags' => 'ta_rel_tags',
625
+ 'css_classes' => 'ta_css_classes',
626
+ );
627
+
628
+ foreach( $properties as $property_key => $post_key ){
629
+ if( isset( $_POST[ $post_key ] ) ){
630
+ $thirstylink->set_prop( $property_key, sanitize_text_field( wp_unslash( $_POST[ $post_key ] ) ) );
631
+ }else{
632
+ $thirstylink->set_prop( $property_key, '' );
633
+ }
634
+ }
635
 
636
  if ( isset( $_POST[ 'post_name' ] ) )
637
+ $thirstylink->set_prop( 'slug' , sanitize_text_field( wp_unslash( $_POST[ 'post_name' ] ) ) );
638
 
639
  if ( isset( $_POST[ 'ta_uncloak_link' ] ) )
640
+ $thirstylink->set_prop( 'uncloak_link' , sanitize_text_field( $_POST[ 'ta_uncloak_link' ] ) ); // phpcs:ignore WordPress.Security
641
 
642
+ if ( isset( $_POST[ 'ta_category_slug' ] ) && $_POST[ 'ta_category_slug' ] ) { // phpcs:ignore WordPress.Security
643
 
644
+ $category_slug_id = (int) sanitize_text_field( wp_unslash( $_POST[ 'ta_category_slug' ] ) );
645
  $category_slug = get_term( $category_slug_id , Plugin_Constants::AFFILIATE_LINKS_TAX );
646
  $thirstylink->set_prop( 'category_slug_id' , $category_slug_id );
647
  $thirstylink->set_prop( 'category_slug' , $category_slug->slug );
753
 
754
  $post_type = get_post_type();
755
  if ( !$post_type && isset( $_GET[ 'post_type' ] ) )
756
+ $post_type = $_GET[ 'post_type' ]; // phpcs:ignore WordPress.Security
757
 
758
  if ( ! is_admin() || $post_type !== Plugin_Constants::AFFILIATE_LINKS_CPT )
759
  return;
798
  switch ( $column ) {
799
 
800
  case 'link_id' :
801
+ echo '<span>' . esc_html( $post_id ) . '</span>';
802
  break;
803
 
804
  case 'redirect_type' :
805
+ echo esc_html( $redirect_type );
806
+ echo $redirect_type === 'global' ? ' (' . esc_html( $this->_helper_functions->get_option( 'ta_link_redirect_type' , '302' ) ) . ')' : '';
807
  break;
808
 
809
  case 'cloaked_url' :
810
  echo '<div class="ta-display-input-wrap">';
811
+ echo '<input style="width:100%;" type="text" value="' . esc_attr( $thirstylink->get_prop( 'permalink' ) ) . '" readonly>';
812
+ echo '<a href="' . esc_url( $edit_link ) . '"><span class="dashicons dashicons-edit"></span></a>';
813
  echo '</div>';
814
  break;
815
 
816
  case 'link_destination' :
817
  echo '<div class="ta-display-input-wrap">';
818
+ echo '<input style="width:100%;" type="text" value="' . esc_attr( $thirstylink->get_prop( 'destination_url' ) ) . '" readonly>';
819
+ echo '<a href="' . esc_url( $edit_link ) . '"><span class="dashicons dashicons-edit"></span></a>';
820
  echo '</div>';
821
  break;
822
 
960
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Missing required post data' , 'thirstyaffiliates' ) );
961
  else {
962
 
963
+ $link_cat_id = (int) sanitize_text_field( wp_unslash( $_POST[ 'term_id' ] ) );
964
  $category = get_term( $link_cat_id , Plugin_Constants::AFFILIATE_LINKS_TAX );
965
 
966
  $response = array( 'status' => 'success' , 'category_slug' => $category->slug );
967
  }
968
 
969
+ @header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
970
  echo wp_json_encode( $response );
971
  wp_die();
972
  }
989
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Missing required post data' , 'thirstyaffiliates' ) );
990
  else {
991
 
992
+ $link_id = (int) sanitize_text_field( wp_unslash( $_POST[ 'link_id' ] ) );
993
  $thirstylink = $this->get_thirstylink_post( $link_id );
994
  $inserted_to = $thirstylink->scan_where_links_inserted();
995
  $timezone = new \DateTimeZone( $this->_helper_functions->get_site_current_timezone() );
999
  $response = array(
1000
  'status' => 'success',
1001
  'results_markup' => $this->get_inserted_into_rows_html( $inserted_to ),
1002
+ 'last_scanned' => esc_html__( 'Last scanned on:' , 'thirstyaffiliates' ) . ' <em>' . $last_scanned->format( 'F j, Y g:ia' ) . '</em>'
1003
  );
1004
  }
1005
 
1006
+ @header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
1007
  echo wp_json_encode( $response );
1008
  wp_die();
1009
  }
Models/Bootstrap.php CHANGED
@@ -273,6 +273,7 @@ class Bootstrap implements Model_Interface {
273
 
274
  update_option( Plugin_Constants::INSTALLED_VERSION , Plugin_Constants::VERSION ); // Update current installed plugin version
275
  update_option( 'ta_activation_code_triggered' , 'yes' ); // Mark activation code triggered
 
276
 
277
  }
278
 
@@ -409,8 +410,8 @@ class Bootstrap implements Model_Interface {
409
  if ( ! $screen_id = $this->_helper_functions->get_screen_id( $object_id ) )
410
  return;
411
 
412
- $current_tab = isset( $_GET[ 'tab' ] ) ? $_GET[ 'tab' ] : '';
413
- $post_type = isset( $_GET[ 'post_type' ] ) ? sanitize_text_field( $_GET[ 'post_type' ] ) : '';
414
  $interfaces = apply_filters( 'ta_admin_interfaces' , array() );
415
  $current_interface = $screen_id && isset( $interfaces[ $screen_id ] ) ? $interfaces[ $screen_id ] : null;
416
 
@@ -432,7 +433,7 @@ class Bootstrap implements Model_Interface {
432
 
433
  // kill page display error message if current user does not have capability.
434
  if ( ( $capability && ! current_user_can( $capability ) ) || ( $object_id && isset( $_GET[ 'post' ] ) && get_current_user_id() != get_post_field( 'post_author' , $object_id ) && ! current_user_can( 'edit_others_posts' ) ) )
435
- wp_die( $error_message );
436
  }
437
 
438
  /**
273
 
274
  update_option( Plugin_Constants::INSTALLED_VERSION , Plugin_Constants::VERSION ); // Update current installed plugin version
275
  update_option( 'ta_activation_code_triggered' , 'yes' ); // Mark activation code triggered
276
+ update_option( 'ta_activation_time' , time() ); // Mark activation code triggered
277
 
278
  }
279
 
410
  if ( ! $screen_id = $this->_helper_functions->get_screen_id( $object_id ) )
411
  return;
412
 
413
+ $current_tab = isset( $_GET[ 'tab' ] ) ? sanitize_text_field( wp_unslash( $_GET[ 'tab' ] ) ) : '';
414
+ $post_type = isset( $_GET[ 'post_type' ] ) ? sanitize_text_field( wp_unslash( $_GET[ 'post_type' ] ) ) : '';
415
  $interfaces = apply_filters( 'ta_admin_interfaces' , array() );
416
  $current_interface = $screen_id && isset( $interfaces[ $screen_id ] ) ? $interfaces[ $screen_id ] : null;
417
 
433
 
434
  // kill page display error message if current user does not have capability.
435
  if ( ( $capability && ! current_user_can( $capability ) ) || ( $object_id && isset( $_GET[ 'post' ] ) && get_current_user_id() != get_post_field( 'post_author' , $object_id ) && ! current_user_can( 'edit_others_posts' ) ) )
436
+ wp_die( esc_html( $error_message ) );
437
  }
438
 
439
  /**
Models/Guided_Tour.php CHANGED
@@ -270,7 +270,7 @@ class Guided_Tour implements Model_Interface , Activatable_Interface , Initiable
270
  public function get_current_screen() {
271
 
272
  $screen = get_current_screen();
273
- $tab = isset( $_GET[ 'tab' ] ) ? sanitize_text_field( $_GET[ 'tab' ] ) : '';
274
 
275
  if ( ! isset( $this->_screens[ $screen->id ] ) || empty( $this->_screens[ $screen->id ] ) )
276
  return;
270
  public function get_current_screen() {
271
 
272
  $screen = get_current_screen();
273
+ $tab = isset( $_GET[ 'tab' ] ) ? sanitize_text_field( wp_unslash( $_GET[ 'tab' ] ) ) : '';
274
 
275
  if ( ! isset( $this->_screens[ $screen->id ] ) || empty( $this->_screens[ $screen->id ] ) )
276
  return;
Models/Link_Fixer.php CHANGED
@@ -142,8 +142,8 @@ class Link_Fixer implements Model_Interface , Initiable_Interface {
142
  foreach( $links as $link ) {
143
 
144
  $href = strtok( esc_url_raw( $link[ 'href' ] ) , '?' );
145
- $class = isset( $link[ 'class' ] ) ? sanitize_text_field( $link[ 'class' ] ) : '';
146
- $key = (int) sanitize_text_field( $link[ 'key' ] );
147
  $link_id = $this->url_to_affiliate_link_id( $href );
148
 
149
  $thirstylink = new Affiliate_Link( $link_id );
@@ -224,7 +224,7 @@ class Link_Fixer implements Model_Interface , Initiable_Interface {
224
  $slug = esc_sql( isset( $link_parts[ $key + 2 ] ) && $link_parts[ $key + 2 ] ? $link_parts[ $key + 2 ] : $link_parts[ $key + 1 ] );
225
 
226
  // fetch the ID based on the post type and slug.
227
- $id = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_type = '$cpt_slug' AND post_name = '$slug'" );
228
 
229
  return $id ? absint( $id ) : 0;
230
  }
@@ -243,7 +243,7 @@ class Link_Fixer implements Model_Interface , Initiable_Interface {
243
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Invalid AJAX call' , 'thirstyaffiliates' ) );
244
  else {
245
 
246
- $links = $_POST[ 'hrefs' ];
247
  $post_id = isset( $_POST[ 'post_id' ] ) ? intval( $_POST[ 'post_id' ] ) : 0;
248
  $response = array(
249
  'status' => 'success',
142
  foreach( $links as $link ) {
143
 
144
  $href = strtok( esc_url_raw( $link[ 'href' ] ) , '?' );
145
+ $class = isset( $link[ 'class' ] ) ? sanitize_text_field( wp_unslash( $link[ 'class' ] ) ) : '';
146
+ $key = (int) sanitize_text_field( wp_unslash( $link[ 'key' ] ) );
147
  $link_id = $this->url_to_affiliate_link_id( $href );
148
 
149
  $thirstylink = new Affiliate_Link( $link_id );
224
  $slug = esc_sql( isset( $link_parts[ $key + 2 ] ) && $link_parts[ $key + 2 ] ? $link_parts[ $key + 2 ] : $link_parts[ $key + 1 ] );
225
 
226
  // fetch the ID based on the post type and slug.
227
+ $id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND post_name = %s", $cpt_slug, $slug ) );
228
 
229
  return $id ? absint( $id ) : 0;
230
  }
243
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Invalid AJAX call' , 'thirstyaffiliates' ) );
244
  else {
245
 
246
+ $links = $_POST[ 'hrefs' ]; // phpcs:ignore
247
  $post_id = isset( $_POST[ 'post_id' ] ) ? intval( $_POST[ 'post_id' ] ) : 0;
248
  $response = array(
249
  'status' => 'success',
Models/Link_Picker.php CHANGED
@@ -344,13 +344,18 @@ class Link_Picker implements Model_Interface , Initiable_Interface {
344
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Missing required post data' , 'thirstyaffiliates' ) );
345
  else {
346
 
347
- $paged = ( isset( $_POST[ 'paged' ] ) && $_POST[ 'paged' ] ) ? $_POST[ 'paged' ] : 1;
348
- $category = ( isset( $_POST[ 'category' ] ) && $_POST[ 'category' ] ) ? esc_attr( $_POST[ 'category' ] ) : '';
 
 
 
349
  $exclude = ( isset( $_POST[ 'exclude' ] ) && is_array( $_POST[ 'exclude' ] ) && ! empty( $_POST[ 'exclude' ] ) ) ? $_POST[ 'exclude' ] : array();
350
- $is_gutenberg = isset( $_POST[ 'gutenberg' ] ) && $_POST[ 'gutenberg' ];
351
- $with_images = isset( $_POST[ 'with_images' ] ) && $_POST[ 'with_images' ];
352
- $affiliate_links = $this->_helper_functions->search_affiliate_links_query( $_POST[ 'keyword' ] , $paged , $category , $exclude , $is_gutenberg , $with_images );
353
- $advance = ( isset( $_POST[ 'advance' ] ) && $_POST[ 'advance' ] ) ? true : false;
 
 
354
  $post_id = isset( $_POST[ 'post_id' ] ) ? intval( $_POST[ 'post_id' ] ) : 0;
355
 
356
  if ( $is_gutenberg ) {
@@ -382,7 +387,7 @@ class Link_Picker implements Model_Interface , Initiable_Interface {
382
  $post_id = isset( $_REQUEST[ 'post_id' ] ) ? intval( $_REQUEST[ 'post_id' ] ) : 0;
383
  $affiliate_links = $this->_helper_functions->search_affiliate_links_query();
384
  $result_markup = $this->search_affiliate_links_result_markup( $affiliate_links , true , $post_id );
385
- $html_editor = isset( $_REQUEST[ 'html_editor' ] ) ? sanitize_text_field( $_REQUEST[ 'html_editor' ] ) : false;
386
 
387
  wp_enqueue_script('editor');
388
  wp_dequeue_script('jquery-ui-core');
@@ -422,15 +427,15 @@ class Link_Picker implements Model_Interface , Initiable_Interface {
422
  elseif ( ! isset( $_REQUEST[ 'imgid' ] ) )
423
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Missing required post data' , 'thirstyaffiliates' ) );
424
  else {
425
-
426
  if ( filter_var( $_REQUEST[ 'imgid' ] , FILTER_VALIDATE_URL ) ) {
427
 
428
- $image_url = esc_url( $_REQUEST[ 'imgid' ] );
429
  $image_markup = '<img src="' . $image_url . '">';
430
 
431
  } else {
432
 
433
- $image_id = (int) sanitize_text_field( $_REQUEST[ 'imgid' ] );
434
  $image_markup = wp_get_attachment_image( $image_id , 'full' );
435
  }
436
 
@@ -466,11 +471,11 @@ class Link_Picker implements Model_Interface , Initiable_Interface {
466
 
467
  $post_id = isset( $_REQUEST[ 'post_id' ] ) ? intval( $_REQUEST[ 'post_id' ] ) : 0;
468
  $redirect_types = $this->_constants->REDIRECT_TYPES();
469
- $selection = sanitize_text_field( $_REQUEST[ 'selection' ] );
470
  $default_redirect_type = get_option( 'ta_link_redirect_type' , '301' );
471
  $global_no_follow = get_option( 'ta_no_follow' ) == 'yes' ? 'yes' : 'no';
472
  $global_new_window = get_option( 'ta_new_window' ) == 'yes' ? 'yes' : 'no';
473
- $html_editor = isset( $_REQUEST[ 'html_editor' ] ) ? sanitize_text_field( $_REQUEST[ 'html_editor' ] ) : false;
474
  $categories = get_terms( Plugin_Constants::AFFILIATE_LINKS_TAX , array(
475
  'hide_empty' => false,
476
  ) );
@@ -501,12 +506,18 @@ class Link_Picker implements Model_Interface , Initiable_Interface {
501
 
502
  $thirstylink = new Affiliate_Link();
503
 
 
 
 
 
 
 
504
  // set Properties
505
- $thirstylink->set_prop( 'name' , sanitize_text_field( $_POST[ 'ta_link_name' ] ) );
506
- $thirstylink->set_prop( 'destination_url' , esc_url_raw( $_POST[ 'ta_destination_url' ] ) );
507
- $thirstylink->set_prop( 'no_follow' , sanitize_text_field( $_POST[ 'ta_no_follow' ] ) );
508
- $thirstylink->set_prop( 'new_window' , sanitize_text_field( $_POST[ 'ta_new_window' ] ) );
509
- $thirstylink->set_prop( 'redirect_type' , sanitize_text_field( $_POST[ 'ta_redirect_type' ] ) );
510
 
511
  do_action( 'ta_save_quick_add_affiliate_link' , $thirstylink );
512
 
@@ -557,7 +568,7 @@ class Link_Picker implements Model_Interface , Initiable_Interface {
557
  else {
558
 
559
  $thirstylink = $this->process_quick_add_affiliate_link();
560
- $post_id = isset( $_POST[ 'post_id' ] ) ? intval( sanitize_text_field( $_POST[ 'post_id' ] ) ) : 0;
561
  $rel = $thirstylink->is( 'no_follow' ) ? 'nofollow' : '';
562
  $target = $thirstylink->is( 'new_window' ) ? '_blank' : '';
563
  $class = ( get_option( 'ta_disable_thirsty_link_class' ) !== "yes" ) ? 'thirstylink' : '';
344
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Missing required post data' , 'thirstyaffiliates' ) );
345
  else {
346
 
347
+ $paged = ( isset( $_POST[ 'paged' ] ) ) ? sanitize_text_field( wp_unslash( $_POST[ 'paged' ] ) ): 1;
348
+ $paged = $paged ? $paged : 1;
349
+ $category = ( isset( $_POST[ 'category' ] ) ) ? sanitize_text_field( wp_unslash( $_POST[ 'category' ] ) ) : '';
350
+
351
+ //phpcs:ignore WordPress.Security
352
  $exclude = ( isset( $_POST[ 'exclude' ] ) && is_array( $_POST[ 'exclude' ] ) && ! empty( $_POST[ 'exclude' ] ) ) ? $_POST[ 'exclude' ] : array();
353
+ $exclude = map_deep( $exclude,'intval');
354
+
355
+ $is_gutenberg = isset( $_POST[ 'gutenberg' ] ) && $_POST[ 'gutenberg' ]; //phpcs:ignore WordPress.Security
356
+ $with_images = isset( $_POST[ 'with_images' ] ) && $_POST[ 'with_images' ]; //phpcs:ignore WordPress.Security
357
+ $affiliate_links = $this->_helper_functions->search_affiliate_links_query( sanitize_text_field( wp_unslash( $_POST[ 'keyword' ] ) ), $paged , $category , $exclude , $is_gutenberg , $with_images );
358
+ $advance = ( isset( $_POST[ 'advance' ] ) && $_POST[ 'advance' ] ) ? true : false; //phpcs:ignore WordPress.Security
359
  $post_id = isset( $_POST[ 'post_id' ] ) ? intval( $_POST[ 'post_id' ] ) : 0;
360
 
361
  if ( $is_gutenberg ) {
387
  $post_id = isset( $_REQUEST[ 'post_id' ] ) ? intval( $_REQUEST[ 'post_id' ] ) : 0;
388
  $affiliate_links = $this->_helper_functions->search_affiliate_links_query();
389
  $result_markup = $this->search_affiliate_links_result_markup( $affiliate_links , true , $post_id );
390
+ $html_editor = isset( $_REQUEST[ 'html_editor' ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ 'html_editor' ] ) ) : false;
391
 
392
  wp_enqueue_script('editor');
393
  wp_dequeue_script('jquery-ui-core');
427
  elseif ( ! isset( $_REQUEST[ 'imgid' ] ) )
428
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Missing required post data' , 'thirstyaffiliates' ) );
429
  else {
430
+ // phpcs:ignore WordPress.Security
431
  if ( filter_var( $_REQUEST[ 'imgid' ] , FILTER_VALIDATE_URL ) ) {
432
 
433
+ $image_url = esc_url( $_REQUEST[ 'imgid' ] ); // phpcs:ignore WordPress.Security
434
  $image_markup = '<img src="' . $image_url . '">';
435
 
436
  } else {
437
 
438
+ $image_id = (int) sanitize_text_field( wp_unslash( $_REQUEST[ 'imgid' ] ) );
439
  $image_markup = wp_get_attachment_image( $image_id , 'full' );
440
  }
441
 
471
 
472
  $post_id = isset( $_REQUEST[ 'post_id' ] ) ? intval( $_REQUEST[ 'post_id' ] ) : 0;
473
  $redirect_types = $this->_constants->REDIRECT_TYPES();
474
+ $selection = isset( $_REQUEST[ 'selection' ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ 'selection' ] ) ) : '';
475
  $default_redirect_type = get_option( 'ta_link_redirect_type' , '301' );
476
  $global_no_follow = get_option( 'ta_no_follow' ) == 'yes' ? 'yes' : 'no';
477
  $global_new_window = get_option( 'ta_new_window' ) == 'yes' ? 'yes' : 'no';
478
+ $html_editor = isset( $_REQUEST[ 'html_editor' ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ 'html_editor' ] ) ) : false;
479
  $categories = get_terms( Plugin_Constants::AFFILIATE_LINKS_TAX , array(
480
  'hide_empty' => false,
481
  ) );
506
 
507
  $thirstylink = new Affiliate_Link();
508
 
509
+ $ta_link_name = isset( $_POST[ 'ta_link_name' ] ) ? sanitize_text_field( wp_unslash( $_POST[ 'ta_link_name' ] ) ) : '';
510
+ $ta_destination_url = isset( $_POST[ 'ta_destination_url' ] ) ? esc_url_raw( $_POST[ 'ta_destination_url' ] ) : ''; // phpcs:ignore WordPress.Security
511
+ $ta_no_follow = isset( $_POST[ 'ta_no_follow' ] ) ? sanitize_text_field( wp_unslash( $_POST[ 'ta_no_follow' ] ) ) : '';
512
+ $ta_new_window = isset( $_POST[ 'ta_new_window' ] ) ? sanitize_text_field( wp_unslash( $_POST[ 'ta_new_window' ] ) ) : '';
513
+ $ta_redirect_type = isset( $_POST[ 'ta_redirect_type' ] ) ? sanitize_text_field( wp_unslash( $_POST[ 'ta_redirect_type' ] ) ) : '';
514
+
515
  // set Properties
516
+ $thirstylink->set_prop( 'name' , $ta_link_name );
517
+ $thirstylink->set_prop( 'destination_url' , $ta_destination_url );
518
+ $thirstylink->set_prop( 'no_follow' , $ta_no_follow );
519
+ $thirstylink->set_prop( 'new_window' , $ta_new_window );
520
+ $thirstylink->set_prop( 'redirect_type' , $ta_redirect_type );
521
 
522
  do_action( 'ta_save_quick_add_affiliate_link' , $thirstylink );
523
 
568
  else {
569
 
570
  $thirstylink = $this->process_quick_add_affiliate_link();
571
+ $post_id = isset( $_POST[ 'post_id' ] ) ? intval( sanitize_text_field( wp_unslash( $_POST[ 'post_id' ] ) ) ) : 0;
572
  $rel = $thirstylink->is( 'no_follow' ) ? 'nofollow' : '';
573
  $target = $thirstylink->is( 'new_window' ) ? '_blank' : '';
574
  $class = ( get_option( 'ta_disable_thirsty_link_class' ) !== "yes" ) ? 'thirstylink' : '';
Models/Marketing.php CHANGED
@@ -189,11 +189,11 @@ class Marketing implements Model_Interface , Activatable_Interface , Initiable_I
189
  ?>
190
  <div class="notice notice-info is-dismissible ta-review-notice" id="ta_review_notice">
191
  <div id="ta_review_intro">
192
- <p><?php _e( 'Are you enjoying using ThirstyAffiliates?', 'thirstyaffiliates' ); ?></p>
193
  <p><a data-review-selection="yes" class="ta-review-selection" href="#">Yes, I love it</a> 🙂 | <a data-review-selection="no" class="ta-review-selection" href="#">Not really...</a></p>
194
  </div>
195
  <div id="ta_review_yes" style="display: none;">
196
- <p><?php _e( 'That\'s awesome! Could you please do me a BIG favor and give it a 5-star rating on WordPress to help us spread the word and boost our motivation?', 'thirstyaffiliates' ); ?></p>
197
  <p style="font-weight: bold;">~ Blair Williams<br>CEO of ThirstyAffiliates</p>
198
  <p>
199
  <a style="display: inline-block; margin-right: 10px;" href="https://wordpress.org/support/plugin/thirstyaffiliates/reviews/?filter=5#new-post" onclick="delayReviewPrompt(event, 'remove', true, true)" target="_blank"><?php esc_html_e( 'Okay, you deserve it', 'thirstyaffiliates' ); ?></a>
@@ -202,7 +202,7 @@ class Marketing implements Model_Interface , Activatable_Interface , Initiable_I
202
  </p>
203
  </div>
204
  <div id="ta_review_no" style="display: none;">
205
- <p><?php _e( 'We\'re sorry to hear you aren\'t enjoying ThirstyAffiliates. We would love a chance to improve. Could you take a minute and let us know what we can do better?', 'thirstyaffiliates' ); ?></p>
206
  <p>
207
  <a style="display: inline-block; margin-right: 10px;" href="https://thirstyaffiliates.com/plugin-feedback/?utm_source=plugin_admin&utm_medium=link&utm_campaign=in_plugin&utm_content=request_review" onclick="delayReviewPrompt(event, 'remove', true, true)" target="_blank"><?php esc_html_e( 'Give Feedback', 'thirstyaffiliates' ); ?></a>
208
  <a href="#" onclick="delayReviewPrompt(event, 'remove', true, false)"><?php esc_html_e( 'No thanks', 'thirstyaffiliates' ); ?></a>
@@ -225,7 +225,7 @@ class Marketing implements Model_Interface , Activatable_Interface , Initiable_I
225
  type: 'POST',
226
  data: {
227
  action: 'ta_dismiss_review_prompt',
228
- _ajax_nonce: "<?php echo wp_create_nonce( 'ta_dismiss_review_prompt' ) ?>",
229
  type: type
230
  },
231
  })
@@ -268,7 +268,7 @@ class Marketing implements Model_Interface , Activatable_Interface , Initiable_I
268
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Missing required post data' , 'thirstyaffiliates' ) );
269
  else {
270
 
271
- $notice = sanitize_text_field( $_POST[ 'notice' ] );
272
 
273
  switch( $notice ) {
274
  case 'enable_js_redirect_notice' :
@@ -337,22 +337,21 @@ class Marketing implements Model_Interface , Activatable_Interface , Initiable_I
337
 
338
  $post_type = get_post_type();
339
  if ( !$post_type && isset( $_GET[ 'post_type' ] ) )
340
- $post_type = $_GET[ 'post_type' ];
341
 
342
  if ( ! is_admin() || ! current_user_can( 'manage_options' ) || $post_type !== Plugin_Constants::AFFILIATE_LINKS_CPT || get_option( 'ta_show_enable_js_redirect_notice' , 'yes' ) !== 'yes' || get_option( 'ta_enable_javascript_frontend_redirect' ) === 'yes' )
343
  return;
344
 
345
  ?>
346
  <div class="notice notice-error is-dismissible ta_enable_javascript_redirect_notice">
347
- <?php
348
- _e( "<h4>Enable Enhanced Javascript Redirect</h4>
349
- <p>ThirstyAffiliates version 3.2.5 introduces a new method of redirecting via javascript which will only run on your website's frontend.
350
  We've added this so the plugin can provide more accurate tracking data of your affiliate link clicks.
351
- This feature is turned on automatically for <strong>new installs</strong>, but for this install we would like to give you the choice of enabling the feature or not.</p>" , 'thirstyaffiliates' );
352
- ?>
353
  <p>
354
  <button type="button" class="button-primary" id="ta_enable_js_redirect_trigger">
355
- <?php _e( 'Enable enhanced javascript redirect feature' , 'thirstyaffiliates' ); ?>
356
  </button>
357
  </p>
358
  </div>
@@ -465,7 +464,7 @@ class Marketing implements Model_Interface , Activatable_Interface , Initiable_I
465
 
466
  $url = esc_url( 'https://thirstyaffiliates.com/pricing/?utm_source=Free%20Plugin&utm_medium=Pro&utm_campaign=Sidebar' );
467
  $img = esc_url( $this->_constants->IMAGES_ROOT_URL() . 'sidebar.jpg' );
468
- echo '<a href="' . $url . '" target="_blank"><img src="' . $img . '"></a>';
469
  }
470
 
471
  public function dismiss_review_prompt() {
189
  ?>
190
  <div class="notice notice-info is-dismissible ta-review-notice" id="ta_review_notice">
191
  <div id="ta_review_intro">
192
+ <p><?php esc_html_e( 'Are you enjoying using ThirstyAffiliates?', 'thirstyaffiliates' ); ?></p>
193
  <p><a data-review-selection="yes" class="ta-review-selection" href="#">Yes, I love it</a> 🙂 | <a data-review-selection="no" class="ta-review-selection" href="#">Not really...</a></p>
194
  </div>
195
  <div id="ta_review_yes" style="display: none;">
196
+ <p><?php esc_html_e( 'That\'s awesome! Could you please do me a BIG favor and give it a 5-star rating on WordPress to help us spread the word and boost our motivation?', 'thirstyaffiliates' ); ?></p>
197
  <p style="font-weight: bold;">~ Blair Williams<br>CEO of ThirstyAffiliates</p>
198
  <p>
199
  <a style="display: inline-block; margin-right: 10px;" href="https://wordpress.org/support/plugin/thirstyaffiliates/reviews/?filter=5#new-post" onclick="delayReviewPrompt(event, 'remove', true, true)" target="_blank"><?php esc_html_e( 'Okay, you deserve it', 'thirstyaffiliates' ); ?></a>
202
  </p>
203
  </div>
204
  <div id="ta_review_no" style="display: none;">
205
+ <p><?php esc_html_e( 'We\'re sorry to hear you aren\'t enjoying ThirstyAffiliates. We would love a chance to improve. Could you take a minute and let us know what we can do better?', 'thirstyaffiliates' ); ?></p>
206
  <p>
207
  <a style="display: inline-block; margin-right: 10px;" href="https://thirstyaffiliates.com/plugin-feedback/?utm_source=plugin_admin&utm_medium=link&utm_campaign=in_plugin&utm_content=request_review" onclick="delayReviewPrompt(event, 'remove', true, true)" target="_blank"><?php esc_html_e( 'Give Feedback', 'thirstyaffiliates' ); ?></a>
208
  <a href="#" onclick="delayReviewPrompt(event, 'remove', true, false)"><?php esc_html_e( 'No thanks', 'thirstyaffiliates' ); ?></a>
225
  type: 'POST',
226
  data: {
227
  action: 'ta_dismiss_review_prompt',
228
+ _ajax_nonce: "<?php echo wp_create_nonce( 'ta_dismiss_review_prompt' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>",
229
  type: type
230
  },
231
  })
268
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Missing required post data' , 'thirstyaffiliates' ) );
269
  else {
270
 
271
+ $notice = sanitize_text_field( wp_unslash( $_POST[ 'notice' ] ) );
272
 
273
  switch( $notice ) {
274
  case 'enable_js_redirect_notice' :
337
 
338
  $post_type = get_post_type();
339
  if ( !$post_type && isset( $_GET[ 'post_type' ] ) )
340
+ $post_type = sanitize_text_field( wp_unslash( $_GET[ 'post_type' ] ));
341
 
342
  if ( ! is_admin() || ! current_user_can( 'manage_options' ) || $post_type !== Plugin_Constants::AFFILIATE_LINKS_CPT || get_option( 'ta_show_enable_js_redirect_notice' , 'yes' ) !== 'yes' || get_option( 'ta_enable_javascript_frontend_redirect' ) === 'yes' )
343
  return;
344
 
345
  ?>
346
  <div class="notice notice-error is-dismissible ta_enable_javascript_redirect_notice">
347
+ <h4><?php esc_html_e('Enable Enhanced Javascript Redirect','thirstyaffiliates'); ?></h4>
348
+ <p><?php esc_html_e("ThirstyAffiliates version 3.2.5 introduces a new method of redirecting via javascript which will only run on your website's frontend.
 
349
  We've added this so the plugin can provide more accurate tracking data of your affiliate link clicks.
350
+ This feature is turned on automatically for <strong>new installs</strong>, but for this install we would like to give you the choice of enabling the feature or not.",'thirstyaffiliates'); ?>
351
+ </p>
352
  <p>
353
  <button type="button" class="button-primary" id="ta_enable_js_redirect_trigger">
354
+ <?php esc_html_e( 'Enable enhanced javascript redirect feature' , 'thirstyaffiliates' ); ?>
355
  </button>
356
  </p>
357
  </div>
464
 
465
  $url = esc_url( 'https://thirstyaffiliates.com/pricing/?utm_source=Free%20Plugin&utm_medium=Pro&utm_campaign=Sidebar' );
466
  $img = esc_url( $this->_constants->IMAGES_ROOT_URL() . 'sidebar.jpg' );
467
+ echo '<a href="' . $url . '" target="_blank"><img src="' . $img . '"></a>'; // phpcs:ignore WordPress.Security.EscapeOutput
468
  }
469
 
470
  public function dismiss_review_prompt() {
Models/Migration.php CHANGED
@@ -423,12 +423,7 @@ class Migration implements Model_Interface , Activatable_Interface , Initiable_I
423
 
424
  global $wpdb;
425
 
426
- $query = "SELECT *
427
- FROM $wpdb->posts
428
- WHERE post_type = 'thirstylink'";
429
-
430
- return $wpdb->get_results( $query );
431
-
432
  }
433
 
434
  /**
@@ -560,7 +555,7 @@ class Migration implements Model_Interface , Activatable_Interface , Initiable_I
560
  $old_link_meta = apply_filters( 'ta_migration_process_old_link_meta' , $old_link_meta , $affiliate_link );
561
 
562
  $query = $this->_generate_link_meta_insert_sql( $affiliate_link->ID , $old_link_meta , $old_link_meta_cache );
563
- if ( $query && $wpdb->query( $query ) )
564
  update_post_meta( $affiliate_link->ID , 'thirstyData' , serialize( $old_link_meta_cache ) );
565
 
566
  }
@@ -683,11 +678,14 @@ class Migration implements Model_Interface , Activatable_Interface , Initiable_I
683
 
684
  update_post_meta( $affiliate_link->ID , Plugin_Constants::META_DATA_PREFIX . 'image_ids' , $new_attachment_data );
685
 
686
- $wpdb->query( "UPDATE $wpdb->posts
687
- SET post_parent = ''
688
- WHERE ID IN ( " . implode( "," , array_map( 'intval' , $new_attachment_data ) ) . " )
689
- AND post_type = 'attachment'" );
690
 
 
 
 
 
 
691
  }
692
 
693
  }
@@ -780,7 +778,7 @@ class Migration implements Model_Interface , Activatable_Interface , Initiable_I
780
  if ( get_option( Plugin_Constants::MIGRATION_COMPLETE_FLAG ) === 'no' ) { ?>
781
 
782
  <div class="notice notice-warning">
783
- <p><?php _e( '<b>ThirstyAffiliates is currently migrating your old affiliate link data to the new data model.<br>Please hold off making changes to your affiliate links. Please refresh the page and if this message has disappeared, the migration is complete.</b>' , 'thirstyaffiliates' ); ?></p>
784
  </div>
785
 
786
  <?php }
@@ -813,14 +811,14 @@ class Migration implements Model_Interface , Activatable_Interface , Initiable_I
813
 
814
  global $wpdb;
815
 
816
- $affiliate_link_ids_str = implode( "," , array_map( 'intval' , $affiliate_link_ids ) );
817
-
818
- $query = "UPDATE $wpdb->postmeta
819
- SET meta_value = REPLACE( REPLACE( meta_value , '&amp;amp;' , '&' ) , '&amp;' , '&' )
820
- WHERE meta_key = '_ta_destination_url'
821
- AND post_id IN ( $affiliate_link_ids_str )";
822
 
823
- $wpdb->query( $query );
 
 
 
 
824
 
825
  }
826
 
423
 
424
  global $wpdb;
425
 
426
+ return $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_type = %s", 'thirstylink' ) );
 
 
 
 
 
427
  }
428
 
429
  /**
555
  $old_link_meta = apply_filters( 'ta_migration_process_old_link_meta' , $old_link_meta , $affiliate_link );
556
 
557
  $query = $this->_generate_link_meta_insert_sql( $affiliate_link->ID , $old_link_meta , $old_link_meta_cache );
558
+ if ( $query && $wpdb->query( $query ) ) // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
559
  update_post_meta( $affiliate_link->ID , 'thirstyData' , serialize( $old_link_meta_cache ) );
560
 
561
  }
678
 
679
  update_post_meta( $affiliate_link->ID , Plugin_Constants::META_DATA_PREFIX . 'image_ids' , $new_attachment_data );
680
 
681
+ $new_attachment_data = array_map( 'intval' , $new_attachment_data );
682
+ $new_attachment_data_str = implode( ',' , $new_attachment_data );
 
 
683
 
684
+ $wpdb->query( $wpdb->prepare(
685
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
686
+ "UPDATE $wpdb->posts SET post_parent = '' WHERE ID IN ( $new_attachment_data_str ) AND post_type = %s",
687
+ 'attachment' )
688
+ );
689
  }
690
 
691
  }
778
  if ( get_option( Plugin_Constants::MIGRATION_COMPLETE_FLAG ) === 'no' ) { ?>
779
 
780
  <div class="notice notice-warning">
781
+ <p><b><?php esc_html_e( 'ThirstyAffiliates is currently migrating your old affiliate link data to the new data model.<br>Please hold off making changes to your affiliate links. Please refresh the page and if this message has disappeared, the migration is complete.' , 'thirstyaffiliates' ); ?></b></p>
782
  </div>
783
 
784
  <?php }
811
 
812
  global $wpdb;
813
 
814
+ $affiliate_link_ids = array_map( 'intval' , $affiliate_link_ids );
815
+ $affiliate_link_ids_str = implode( ',' , $affiliate_link_ids );
 
 
 
 
816
 
817
+ $wpdb->query( $wpdb->prepare(
818
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
819
+ "UPDATE $wpdb->postmeta SET meta_value = REPLACE( REPLACE( meta_value , '&amp;amp;' , '&' ) , '&amp;' , '&' ) WHERE post_id IN ( $affiliate_link_ids_str ) AND meta_key = %s ",
820
+ '_ta_destination_url' )
821
+ );
822
 
823
  }
824
 
Models/Notifications.php ADDED
@@ -0,0 +1,837 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace ThirstyAffiliates\Models;
3
+
4
+ if(!defined('ABSPATH')) {die('You are not allowed to call this page directly.');}
5
+
6
+ use ThirstyAffiliates\Helpers\Plugin_Constants;
7
+ use ThirstyAffiliates\Interfaces\Model_Interface;
8
+ use ThirstyAffiliates\Abstracts\Abstract_Main_Plugin_Class;
9
+ use ThirstyAffiliates\Helpers\Helper_Functions;
10
+
11
+ /**
12
+ * Notifications.
13
+ *
14
+ * Class for logging in-plugin notifications.
15
+ * Includes:
16
+ * Notifications from our remote feed
17
+ * Plugin-related notifications (e.g. recent sales performances)
18
+ */
19
+ class Notifications implements Model_Interface {
20
+
21
+ /**
22
+ * Property that holds the single main instance of Shortcodes.
23
+ *
24
+ * @since 3.1.0
25
+ * @access private
26
+ * @var Redirection
27
+ */
28
+ private static $_instance;
29
+
30
+ /**
31
+ * Model that houses the main plugin object.
32
+ *
33
+ * @since 3.1.0
34
+ * @access private
35
+ * @var Redirection
36
+ */
37
+ private $_main_plugin;
38
+
39
+ /**
40
+ * Model that houses all the plugin constants.
41
+ *
42
+ * @since 3.1.0
43
+ * @access private
44
+ * @var Plugin_Constants
45
+ */
46
+ private $_constants;
47
+
48
+ /**
49
+ * Property that houses all the helper functions of the plugin.
50
+ *
51
+ * @since 3.1.0
52
+ * @access private
53
+ * @var Helper_Functions
54
+ */
55
+ private $_helper_functions;
56
+
57
+ /**
58
+ * Source of notifications content.
59
+ *
60
+ * @var string
61
+ */
62
+ const SOURCE_URL = 'https://mbr.press/UMj4Dg';
63
+ const SOURCE_URL_ARGS = [];
64
+
65
+ /**
66
+ * Option value.
67
+ *
68
+ * @var bool|array
69
+ */
70
+ public $option = false;
71
+
72
+ /**
73
+ * Initialize class.
74
+ */
75
+ public function run() {
76
+
77
+ $this->hooks();
78
+ }
79
+
80
+ /**
81
+ * Class constructor.
82
+ *
83
+ * @since 3.1.0
84
+ * @access public
85
+ *
86
+ * @param Abstract_Main_Plugin_Class $main_plugin Main plugin object.
87
+ * @param Plugin_Constants $constants Plugin constants object.
88
+ * @param Helper_Functions $helper_functions Helper functions object.
89
+ */
90
+ public function __construct( Abstract_Main_Plugin_Class $main_plugin , Plugin_Constants $constants , Helper_Functions $helper_functions ) {
91
+
92
+ $this->_constants = $constants;
93
+ $this->_helper_functions = $helper_functions;
94
+
95
+ $main_plugin->add_to_all_plugin_models( $this );
96
+ }
97
+
98
+ /**
99
+ * Ensure that only one instance of this class is loaded or can be loaded ( Singleton Pattern ).
100
+ *
101
+ * @since 3.1.0
102
+ * @access public
103
+ *
104
+ * @param Abstract_Main_Plugin_Class $main_plugin Main plugin object.
105
+ * @param Plugin_Constants $constants Plugin constants object.
106
+ * @param Helper_Functions $helper_functions Helper functions object.
107
+ * @return Redirection
108
+ */
109
+ public static function get_instance( Abstract_Main_Plugin_Class $main_plugin , Plugin_Constants $constants , Helper_Functions $helper_functions ) {
110
+
111
+ if ( !self::$_instance instanceof self )
112
+ self::$_instance = new self( $main_plugin , $constants , $helper_functions );
113
+
114
+ return self::$_instance;
115
+
116
+ }
117
+
118
+ /**
119
+ * Register hooks.
120
+ */
121
+ public function hooks() {
122
+
123
+ add_action( 'admin_enqueue_scripts', [ $this, 'enqueues' ] );
124
+ add_action( 'admin_footer', array( $this, 'admin_menu_append_count' ) );
125
+ add_action( 'admin_init', array( $this, 'schedule_fetch' ) );
126
+
127
+ add_action( 'admin_head', [ $this, 'admin_head' ] );
128
+ add_action( 'admin_footer', [ $this, 'output' ] );
129
+
130
+ add_action( 'thirstyaff_admin_notifications_update', [ $this, 'update' ] );
131
+ add_action( 'wp_ajax_thirstyaff_notification_dismiss', [ $this, 'dismiss' ] );
132
+ }
133
+
134
+ /**
135
+ * Check if user has access and is enabled.
136
+ *
137
+ * @return bool
138
+ */
139
+ public static function has_access() {
140
+
141
+ $access = false;
142
+
143
+ if (
144
+ current_user_can( 'manage_options' )
145
+ && ! get_option( 'thirstyaff_hide_announcements' )
146
+ ) {
147
+ $access = true;
148
+ }
149
+
150
+ return apply_filters( 'thirstyaff_admin_notifications_has_access', $access );
151
+ }
152
+
153
+ /**
154
+ * Get option value.
155
+ *
156
+ * @param bool $cache Reference property cache if available.
157
+ *
158
+ * @return array
159
+ */
160
+ public function get_option( $cache = true ) {
161
+
162
+ if ( $this->option && $cache ) {
163
+ return $this->option;
164
+ }
165
+
166
+ $option = get_option( 'thirstyaff_notifications', [] );
167
+
168
+ $this->option = [
169
+ 'update' => ! empty( $option['update'] ) ? $option['update'] : 0,
170
+ 'events' => ! empty( $option['events'] ) ? $option['events'] : [],
171
+ 'feed' => ! empty( $option['feed'] ) ? $option['feed'] : [],
172
+ 'dismissed' => ! empty( $option['dismissed'] ) ? $option['dismissed'] : [],
173
+ ];
174
+
175
+ return $this->option;
176
+ }
177
+
178
+ /**
179
+ * Make sure the feed is fetched when needed.
180
+ *
181
+ * @return void
182
+ */
183
+ public function schedule_fetch() {
184
+
185
+ $option = $this->get_option();
186
+
187
+ // Update notifications using async task.
188
+ if ( empty( $option['update'] ) || time() > $option['update'] + 3 * HOUR_IN_SECONDS ) {
189
+ if ( false === wp_next_scheduled( 'thirstyaff_admin_notifications_update' ) ) {
190
+ wp_schedule_single_event( time() + 10, 'thirstyaff_admin_notifications_update' );
191
+ }
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Fetch notifications from remote feed.
197
+ *
198
+ * @return array
199
+ */
200
+ public function fetch_feed() {
201
+
202
+ $res = wp_remote_get( self::SOURCE_URL, self::SOURCE_URL_ARGS );
203
+
204
+ if ( is_wp_error( $res ) ) {
205
+ return [];
206
+ }
207
+
208
+ $body = wp_remote_retrieve_body( $res );
209
+
210
+ if ( empty( $body ) ) {
211
+ return [];
212
+ }
213
+
214
+ return $this->verify( json_decode( $body, true ) );
215
+ }
216
+
217
+ /**
218
+ * Verify notification data before it is saved.
219
+ *
220
+ * @param array $notifications Array of notifications items to verify.
221
+ *
222
+ * @return array
223
+ */
224
+ public function verify( $notifications ) {
225
+
226
+ /*$pl_options = PrliOptions::get_options();
227
+ $license = get_site_transient( 'thirstyaff_license_info' );
228
+ global $plp_update;
229
+
230
+ if ( empty( $license['license_key'] ) ) {
231
+ global $plp_update;
232
+ $plp_update->manually_queue_update();
233
+ $license = get_site_transient( 'thirstyaff_license_info' );
234
+ }*/
235
+
236
+ $data = [];
237
+
238
+ if ( ! is_array( $notifications ) || empty( $notifications ) ) {
239
+ return $data;
240
+ }
241
+
242
+ $option = $this->get_option();
243
+
244
+ foreach ( $notifications as $id => $notification ) {
245
+
246
+ // The message and license should never be empty, if they are, ignore.
247
+ if ( empty( $notification['content'] ) ) {
248
+ continue;
249
+ }
250
+
251
+ // TA Pro is active
252
+ if ( defined( 'TAP_EDITION' ) ) {
253
+ // Ignore if license type does not match.
254
+ if ( ! empty( $notification['plans'] ) && ! in_array( TAP_EDITION, $notification['plans'], true ) ) {
255
+ continue;
256
+ }
257
+ } else {
258
+ // Running TA Lite
259
+ if ( ! empty( $notification['plans'] ) && ! in_array( 'thirstyaffiliates-lite', $notification['plans'], true ) ) {
260
+ // Not intended for TA Lite users
261
+ continue;
262
+ }
263
+ }
264
+
265
+ // Disabled for now until we get TA onboarded to MOSH
266
+ /*// Ignore if segment is for expired licenses, but license is current
267
+ if ( 'expired' === $notification['segment'] && ! empty( $plp_update->mothership_license ) && ! empty( $license['license_key']['expires_at'] ) && strtotime( $license['license_key']['expires_at'] ) > time() ) {
268
+ continue;
269
+ }
270
+
271
+ // Ignore if segment is for inactive licenses, but license is active
272
+ if ( 'inactive' === $notification['segment'] && ! empty( $plp_update->mothership_license ) && ! empty( $license['license_key'] ) ) {
273
+ continue;
274
+ }*/
275
+
276
+ // Ignore if expired.
277
+ if ( ! empty( $notification['end'] ) && time() > strtotime( $notification['end'] ) ) {
278
+ continue;
279
+ }
280
+
281
+ // Ignore if notifcation has already been dismissed.
282
+ if ( ! empty( $option['dismissed'] ) && array_key_exists( $notification['id'], $option['dismissed'] ) ) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
283
+ continue;
284
+ }
285
+
286
+ // Ignore if notification existed before installing the plugin.
287
+ // Prevents bombarding the user with notifications after activation.
288
+ $activated = get_option( 'ta_activation_time' );
289
+
290
+ if (
291
+ ! empty( $activated ) &&
292
+ ! empty( $notification['start'] ) &&
293
+ $activated > strtotime( $notification['start'] )
294
+ ) {
295
+ continue;
296
+ }
297
+
298
+ $data[$id] = $notification;
299
+
300
+ // Check if this notification has already been saved with a timestamp
301
+ if ( ! empty( $option['feed'][$id] ) ) { // Already exists in feed, so use saved time
302
+ $data[$id]['saved'] = $option['feed'][$id]['saved'];
303
+ } else if ( ! empty( $option['events'][$id] ) ) { // Already exists in events, so use saved time
304
+ $data[$id]['saved'] = $option['events'][$id]['saved'];
305
+ } else { // Doesn't exist in feed or events, so save current time
306
+ $data[$id]['saved'] = time();
307
+ }
308
+ }
309
+
310
+ return $data;
311
+ }
312
+
313
+ /**
314
+ * Verify saved notification data for active notifications.
315
+ *
316
+ * @param array $notifications Array of notifications items to verify.
317
+ *
318
+ * @return array
319
+ */
320
+ public function verify_active( $notifications ) {
321
+
322
+ if ( ! is_array( $notifications ) || empty( $notifications ) ) {
323
+ return [];
324
+ }
325
+
326
+ // Remove notfications that are not active.
327
+ foreach ( $notifications as $key => $notification ) {
328
+ if (
329
+ ( ! empty( $notification['start'] ) && strtotime( $notification['start'] . ' America/Denver' ) < strtotime( $notification['start'] . ' America/Denver' ) ) ||
330
+ ( ! empty( $notification['end'] ) && strtotime( $notification['end'] . ' America/Denver' ) > strtotime( $notification['end'] . ' America/Denver' ) )
331
+ ) {
332
+ unset( $notifications[ $key ] );
333
+ }
334
+ }
335
+
336
+ return $notifications;
337
+ }
338
+
339
+ /**
340
+ * Get notification data.
341
+ *
342
+ * @return array
343
+ */
344
+ public function get() {
345
+
346
+ if ( ! self::has_access() ) {
347
+ return [];
348
+ }
349
+
350
+ $option = $this->get_option();
351
+
352
+ $events = ! empty( $option['events'] ) ? $this->verify_active( $option['events'] ) : array();
353
+ $feed = ! empty( $option['feed'] ) ? $this->verify_active( $option['feed'] ) : array();
354
+
355
+ $notifications = array();
356
+ $notifications['active'] = array_merge( $events, $feed );
357
+ $notifications['active'] = $this->get_notifications_with_human_readeable_start_time( $notifications['active'] );
358
+ $notifications['active'] = $this->get_notifications_with_formatted_content( $notifications['active'] );
359
+ $notifications['dismissed'] = ! empty( $option['dismissed'] ) ? $option['dismissed'] : array();
360
+ $notifications['dismissed'] = $this->get_notifications_with_human_readeable_start_time( $notifications['dismissed'] );
361
+ $notifications['dismissed'] = $this->get_notifications_with_formatted_content( $notifications['dismissed'] );
362
+
363
+ return $notifications;
364
+ }
365
+
366
+
367
+ /**
368
+ * Improve format of the content of notifications before display. By default just runs wpautop.
369
+ *
370
+ * @param array $notifications The notifications to be parsed.
371
+ *
372
+ * @return mixed
373
+ */
374
+ public function get_notifications_with_formatted_content( $notifications ) {
375
+ if ( ! is_array( $notifications ) || empty( $notifications ) ) {
376
+ return $notifications;
377
+ }
378
+
379
+ foreach ( $notifications as $key => $notification ) {
380
+ if ( ! empty( $notification['content'] ) ) {
381
+ $notifications[ $key ]['content'] = wpautop( $notification['content'] );
382
+ $notifications[ $key ]['content'] = apply_filters( 'thirstyaff_notification_content_display', $notifications[ $key ]['content'] );
383
+ }
384
+ }
385
+
386
+ return $notifications;
387
+ }
388
+
389
+ /**
390
+ * Get notifications start time with human time difference
391
+ *
392
+ * @return array $notifications
393
+ */
394
+ public function get_notifications_with_human_readeable_start_time( $notifications ) {
395
+
396
+ if ( ! is_array( $notifications ) || empty( $notifications ) ) {
397
+ return;
398
+ }
399
+
400
+ foreach ( $notifications as $key => $notification ) {
401
+ if ( ! isset( $notification['start'] ) || empty( $notification['start'] ) ) {
402
+ continue;
403
+ }
404
+
405
+ // Translators: Readable time to display
406
+ $modified_start_time = sprintf( __( '%1$s ago', 'thirstyaffiliates' ), human_time_diff( strtotime( $notification['start'] ), current_time( 'timestamp' ) ) );
407
+ $notifications[ $key ]['start'] = $modified_start_time;
408
+ }
409
+
410
+ return $notifications;
411
+ }
412
+
413
+ /**
414
+ * Get notification count.
415
+ *
416
+ * @return int
417
+ */
418
+ public function get_count() {
419
+ return ! empty( $this->get()['active'] ) ? count( $this->get()['active'] ) : 0;
420
+ }
421
+
422
+ /**
423
+ * Add an event notification. This is NOT for feed notifications.
424
+ * Event notifications are for alerting the user to something internally (e.g. recent sales performances).
425
+ *
426
+ * @param array $notification Notification data.
427
+ */
428
+ public function add( $notification ) {
429
+
430
+ if ( empty( $notification['id'] ) ) {
431
+ return;
432
+ }
433
+
434
+ $option = $this->get_option();
435
+
436
+ // Already dismissed
437
+ if ( array_key_exists( $notification['id'], $option['dismissed'] ) ) {
438
+ return;
439
+ }
440
+
441
+ // Already in events
442
+ foreach ( $option['events'] as $item ) {
443
+ if ( $item['id'] === $notification['id'] ) {
444
+ return;
445
+ }
446
+ }
447
+
448
+ // Associative key is notification id.
449
+ $notification = $this->verify( [ $notification['id'] => $notification ] );
450
+
451
+ // The only thing changing here is adding the notification to the events
452
+ update_option(
453
+ 'thirstyaff_notifications',
454
+ [
455
+ 'update' => $option['update'],
456
+ 'feed' => $option['feed'],
457
+ 'events' => array_merge( $notification, $option['events'] ),
458
+ 'dismissed' => $option['dismissed'],
459
+ ]
460
+ );
461
+ }
462
+
463
+ /**
464
+ * Update notification data from feed.
465
+ * This pulls the latest notifications from our remote feed.
466
+ */
467
+ public function update() {
468
+
469
+ $feed = $this->fetch_feed();
470
+ $option = $this->get_option();
471
+
472
+ update_option(
473
+ 'thirstyaff_notifications',
474
+ [
475
+ 'update' => time(),
476
+ 'feed' => $feed,
477
+ 'events' => $option['events'],
478
+ 'dismissed' => $option['dismissed'],
479
+ ]
480
+ );
481
+ }
482
+
483
+ /**
484
+ * Admin area enqueues.
485
+ */
486
+ public function enqueues() {
487
+
488
+ if ( ! self::has_access() ) {
489
+ return;
490
+ }
491
+
492
+ $notifications = $this->get();
493
+
494
+ if ( empty( $notifications ) ) {
495
+ return;
496
+ }
497
+
498
+ wp_enqueue_style(
499
+ 'thirstyaff-admin-notifications',
500
+ $GLOBALS[ 'thirstyaffiliates' ]->helpers['Plugin_Constants']->_CSS_ROOT_URL . "admin/admin_notifications.css",
501
+ [],
502
+ Plugin_Constants::VERSION . "-" . uniqid()
503
+ );
504
+
505
+ wp_enqueue_script(
506
+ 'thirstyaff-admin-notifications',
507
+ $GLOBALS[ 'thirstyaffiliates' ]->helpers['Plugin_Constants']->_JS_ROOT_URL . "app/admin_notifications.js",
508
+ [ 'jquery' ],
509
+ Plugin_Constants::VERSION . "-" . uniqid(),
510
+ true
511
+ );
512
+
513
+ wp_localize_script(
514
+ 'thirstyaff-admin-notifications',
515
+ 'ThirstyAffAdminNotifications',
516
+ [
517
+ "ajax_url" => admin_url('admin-ajax.php'),
518
+ "nonce" => wp_create_nonce( "thirstyaff-admin-notifications" )
519
+ ]
520
+ );
521
+ }
522
+
523
+ /**
524
+ * Admin script for adding notification count to the MemberPress admin menu list item.
525
+ */
526
+ public function admin_menu_append_count() {
527
+
528
+ $notifications = $this->get();
529
+
530
+ if ( empty( $notifications['active'] ) || count( $notifications['active'] ) < 1 ) {
531
+ return;
532
+ }
533
+
534
+ ob_start();
535
+
536
+ ?>
537
+
538
+ <span class="awaiting-mod">
539
+ <span class="pending-count" id="thirstyaffAdminMenuUnreadCount" aria-hidden="true"><?php echo count( $notifications['active'] ); ?></span>
540
+ <span class="comments-in-moderation-text screen-reader-text"><?php printf( _n( '%s unread message', '%s unread messages', count( $notifications['active'] ), 'thirstyaffiliates' ), count( $notifications['active'] ) ); ?></span>
541
+ </span>
542
+
543
+ <?php $output = ob_get_clean(); ?>
544
+
545
+ <script>
546
+ jQuery(document).ready(function($) {
547
+ $('li.menu-icon-thirstylink .wp-menu-name').append(`<?php echo $output; ?>`);
548
+ });
549
+ </script>
550
+
551
+ <?php
552
+ }
553
+
554
+ public function admin_head() {
555
+ ?>
556
+ <style>
557
+ .menu-icon-thirstylink .awaiting-mod {
558
+ position: absolute;
559
+ }
560
+ </style>
561
+ <?php
562
+ }
563
+
564
+ /**
565
+ * Output notifications in MemberPress admin area.
566
+ */
567
+ public function output() {
568
+
569
+ if ( empty( $_GET['post_type'] ) || 'thirstylink' !== $_GET['post_type'] ) {
570
+ return;
571
+ }
572
+
573
+ $notifications = $this->get();
574
+
575
+ if ( empty( $notifications['active'] ) && empty( $notifications['dismissed'] ) ) {
576
+ return;
577
+ }
578
+
579
+ $notifications_html = '<div class="active-messages">';
580
+ if ( ! empty( $notifications['active'] ) ) {
581
+ foreach ( $notifications['active'] as $notification ) {
582
+
583
+ // Buttons HTML.
584
+ $buttons_html = '';
585
+ if ( ! empty( $notification['buttons'] ) && is_array( $notification['buttons'] ) ) {
586
+ foreach ( $notification['buttons'] as $btn_type => $btn ) {
587
+ if ( empty( $btn['url'] ) || empty( $btn['text'] ) ) {
588
+ continue;
589
+ }
590
+ $buttons_html .= sprintf(
591
+ '<a href="%1$s" class="button button-%2$s"%3$s>%4$s</a>',
592
+ ! empty( $btn['url'] ) ? esc_url( $btn['url'] ) : '',
593
+ $btn_type === 'main' ? 'primary' : 'secondary',
594
+ ! empty( $btn['thirstyaffrget'] ) && $btn['thirstyaffrget'] === '_blank' ? ' target="_blank" rel="noopener noreferrer"' : '',
595
+ ! empty( $btn['text'] ) ? sanitize_text_field( $btn['text'] ) : ''
596
+ );
597
+ }
598
+ $buttons_html .= sprintf( '<button class="thirstyaff-notice-dismiss" data-message-id="%s">%s</button>', $notification['id'], __( 'Dismiss', 'thirstyaffiliates' ) );
599
+ $buttons_html = ! empty( $buttons_html ) ? '<div class="thirstyaff-notifications-buttons">' . $buttons_html . '</div>' : '';
600
+ }
601
+
602
+ $time_diff = ceil( ( time() - $notification['saved'] ) );
603
+ $time_diff_string = '';
604
+ if ( $time_diff < MINUTE_IN_SECONDS ) {
605
+ $time_diff_string = sprintf( _n( '%s second ago', '%s seconds ago', $time_diff, 'thirstyaffiliates' ), $time_diff );
606
+ } else if ( $time_diff < HOUR_IN_SECONDS ) {
607
+ $time_diff_string = sprintf( _n( '%s minute ago', '%s minutes ago', ceil( ( $time_diff / MINUTE_IN_SECONDS ) ), 'thirstyaffiliates' ), ceil( ( $time_diff / MINUTE_IN_SECONDS ) ) );
608
+ } else if ( $time_diff < DAY_IN_SECONDS ) {
609
+ $time_diff_string = sprintf( _n( '%s hour ago', '%s hours ago', ceil( ( $time_diff / HOUR_IN_SECONDS ) ), 'thirstyaffiliates' ), ceil( ( $time_diff / HOUR_IN_SECONDS ) ) );
610
+ } else if ( $time_diff < WEEK_IN_SECONDS ) {
611
+ $time_diff_string = sprintf( _n( '%s day ago', '%s days ago', ceil( ( $time_diff / DAY_IN_SECONDS ) ), 'thirstyaffiliates' ), ceil( ( $time_diff / DAY_IN_SECONDS ) ) );
612
+ } else if ( $time_diff < MONTH_IN_SECONDS ) {
613
+ $time_diff_string = sprintf( _n( '%s week ago', '%s weeks ago', ceil( ( $time_diff / WEEK_IN_SECONDS ) ), 'thirstyaffiliates' ), ceil( ( $time_diff / WEEK_IN_SECONDS ) ) );
614
+ } else if ( $time_diff < YEAR_IN_SECONDS ) {
615
+ $time_diff_string = sprintf( _n( '%s month ago', '%s months ago', ceil( ( $time_diff / MONTH_IN_SECONDS ) ), 'thirstyaffiliates' ), ceil( ( $time_diff / MONTH_IN_SECONDS ) ) );
616
+ } else {
617
+ $time_diff_string = sprintf( _n( '%s year ago', '%s years ago', ceil( ( $time_diff / YEAR_IN_SECONDS ) ), 'thirstyaffiliates' ), ceil( ( $time_diff / YEAR_IN_SECONDS ) ) );
618
+ }
619
+
620
+ // Notification HTML.
621
+ $notifications_html .= sprintf(
622
+ '<div id="thirstyaff-notifications-message-%4$s" class="thirstyaff-notifications-message" data-message-id="%4$s">
623
+ <div class="thirstyaff-notification-icon-title">
624
+ <img src="%5$s" width="32" height="32">
625
+ <h3 class="thirstyaff-notifications-title">%1$s</h3>
626
+ <time datetime="%6$s">%7$s</time>
627
+ </div>
628
+ <div class="thirstyaff-notifications-content">%2$s</div>
629
+ %3$s
630
+ </div>',
631
+ ! empty( $notification['title'] ) ? sanitize_text_field( $notification['title'] ) : '',
632
+ ! empty( $notification['content'] ) ? apply_filters( 'the_content', $notification['content'] ) : '',
633
+ $buttons_html,
634
+ ! empty( $notification['id'] ) ? esc_attr( sanitize_text_field( $notification['id'] ) ) : 0,
635
+ ! empty( $notification['icon'] ) ? esc_url( sanitize_text_field( $notification['icon'] ) ) : '',
636
+ date( 'Y-m-d G:i a', $notification['saved'] ),
637
+ $time_diff_string
638
+ );
639
+ }
640
+ }
641
+ $notifications_html .= sprintf( '<div class="thirstyaff-notifications-none" %s>%s</div>', empty( $notifications['active'] ) || count( $notifications['active'] ) < 1 ? '' : 'style="display: none;"', __( 'You\'re all caught up!', 'thirstyaffiliates' ) );
642
+ $notifications_html .= '</div>';
643
+
644
+ $notifications_html .= '<div class="dismissed-messages">';
645
+ if ( ! empty( $notifications['dismissed'] ) ) {
646
+ foreach ( $notifications['dismissed'] as $notification ) {
647
+
648
+ // Buttons HTML.
649
+ $buttons_html = '';
650
+ if ( ! empty( $notification['buttons'] ) && is_array( $notification['buttons'] ) ) {
651
+ foreach ( $notification['buttons'] as $btn_type => $btn ) {
652
+ if ( empty( $btn['url'] ) || empty( $btn['text'] ) ) {
653
+ continue;
654
+ }
655
+ $buttons_html .= sprintf(
656
+ '<a href="%1$s" class="button button-%2$s"%3$s>%4$s</a>',
657
+ ! empty( $btn['url'] ) ? esc_url( $btn['url'] ) : '',
658
+ $btn_type === 'main' ? 'primary' : 'secondary',
659
+ ! empty( $btn['thirstyaffrget'] ) && $btn['thirstyaffrget'] === '_blank' ? ' target="_blank" rel="noopener noreferrer"' : '',
660
+ ! empty( $btn['text'] ) ? sanitize_text_field( $btn['text'] ) : ''
661
+ );
662
+ }
663
+ $buttons_html .= sprintf( '<button class="thirstyaff-notice-dismiss" data-message-id="%s">%s</button>', $notification['id'], __( 'Dismiss', 'thirstyaffiliates' ) );
664
+ $buttons_html = ! empty( $buttons_html ) ? '<div class="thirstyaff-notifications-buttons">' . $buttons_html . '</div>' : '';
665
+ }
666
+
667
+ $time_diff = ceil( ( time() - $notification['saved'] ) );
668
+ $time_diff_string = '';
669
+ if ( $time_diff < MINUTE_IN_SECONDS ) {
670
+ $time_diff_string = sprintf( _n( '%s second ago', '%s seconds ago', $time_diff, 'thirstyaffiliates' ), $time_diff );
671
+ } else if ( $time_diff < HOUR_IN_SECONDS ) {
672
+ $time_diff_string = sprintf( _n( '%s minute ago', '%s minutes ago', ceil( ( $time_diff / MINUTE_IN_SECONDS ) ), 'thirstyaffiliates' ), ceil( ( $time_diff / MINUTE_IN_SECONDS ) ) );
673
+ } else if ( $time_diff < DAY_IN_SECONDS ) {
674
+ $time_diff_string = sprintf( _n( '%s hour ago', '%s hours ago', ceil( ( $time_diff / HOUR_IN_SECONDS ) ), 'thirstyaffiliates' ), ceil( ( $time_diff / HOUR_IN_SECONDS ) ) );
675
+ } else if ( $time_diff < WEEK_IN_SECONDS ) {
676
+ $time_diff_string = sprintf( _n( '%s day ago', '%s days ago', ceil( ( $time_diff / DAY_IN_SECONDS ) ), 'thirstyaffiliates' ), ceil( ( $time_diff / DAY_IN_SECONDS ) ) );
677
+ } else if ( $time_diff < MONTH_IN_SECONDS ) {
678
+ $time_diff_string = sprintf( _n( '%s week ago', '%s weeks ago', ceil( ( $time_diff / WEEK_IN_SECONDS ) ), 'thirstyaffiliates' ), ceil( ( $time_diff / WEEK_IN_SECONDS ) ) );
679
+ } else if ( $time_diff < YEAR_IN_SECONDS ) {
680
+ $time_diff_string = sprintf( _n( '%s month ago', '%s months ago', ceil( ( $time_diff / MONTH_IN_SECONDS ) ), 'thirstyaffiliates' ), ceil( ( $time_diff / MONTH_IN_SECONDS ) ) );
681
+ } else {
682
+ $time_diff_string = sprintf( _n( '%s year ago', '%s years ago', ceil( ( $time_diff / YEAR_IN_SECONDS ) ), 'thirstyaffiliates' ), ceil( ( $time_diff / YEAR_IN_SECONDS ) ) );
683
+ }
684
+
685
+ // Notification HTML.
686
+ $notifications_html .= sprintf(
687
+ '<div id="thirstyaff-notifications-message-%4$s" class="thirstyaff-notifications-message" data-message-id="%4$s">
688
+ <div class="thirstyaff-notification-icon-title">
689
+ <img src="%5$s" width="32" height="32">
690
+ <h3 class="thirstyaff-notifications-title">%1$s</h3>
691
+ <time datetime="%6$s">%7$s</time>
692
+ </div>
693
+ <div class="thirstyaff-notifications-content">%2$s</div>
694
+ %3$s
695
+ </div>',
696
+ ! empty( $notification['title'] ) ? sanitize_text_field( $notification['title'] ) : '',
697
+ ! empty( $notification['content'] ) ? apply_filters( 'the_content', $notification['content'] ) : '',
698
+ $buttons_html,
699
+ ! empty( $notification['id'] ) ? esc_attr( sanitize_text_field( $notification['id'] ) ) : 0,
700
+ ! empty( $notification['icon'] ) ? esc_url( sanitize_text_field( $notification['icon'] ) ) : '',
701
+ date( 'Y-m-d G:i a', $notification['saved'] ),
702
+ $time_diff_string
703
+ );
704
+ }
705
+ }
706
+ $notifications_html .= '</div>';
707
+ ?>
708
+
709
+ <div id="thirstyaff-notifications">
710
+
711
+ <div class="thirstyaff-notifications-container">
712
+
713
+ <div class="thirstyaff-notifications-top-title">
714
+ <div class="thirstyaff-notifications-top-title__left">
715
+ <svg width="24" height="15" viewBox="0 0 24 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M23.6667 7.03125C23.8889 7.34375 24 7.69531 24 8.08594V13.125C24 13.6458 23.8056 14.0885 23.4167 14.4531C23.0278 14.8177 22.5556 15 22 15H2C1.44444 15 0.972222 14.8177 0.583333 14.4531C0.194444 14.0885 0 13.6458 0 13.125V8.08594C0 7.69531 0.111111 7.34375 0.333333 7.03125L4.75 0.820312C4.86111 0.690104 5 0.559896 5.16667 0.429688C5.36111 0.299479 5.56944 0.195312 5.79167 0.117188C6.01389 0.0390625 6.22222 0 6.41667 0H17.5833C17.8889 0 18.1944 0.0911458 18.5 0.273438C18.8333 0.429688 19.0833 0.611979 19.25 0.820312L23.6667 7.03125ZM6.75 2.5L3.20833 7.5H8.33333L9.66667 10H14.3333L15.6667 7.5H20.7917L17.25 2.5H6.75Z" fill="white"></path></svg>
716
+ <h3><?php _e( 'Inbox', 'thirstyaffiliates' ); ?></h3>
717
+ </div>
718
+ <div class="thirstyaff-notifications-top-title__right actions">
719
+ <a href="#" id="viewDismissed"><?php _e( 'View Dismissed', 'thirstyaffiliates' ); ?></a>
720
+ <a href="#" id="viewActive"><?php _e( 'View Active', 'thirstyaffiliates' ); ?></a>
721
+ <a href="#" id="thirstyaffNotificationsClose" class="close" title="<?php _e( 'Close', 'thirstyaffiliates' ); ?>">
722
+ <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.28409 6L11.6932 9.40909C11.8977 9.61364 12 9.86364 12 10.1591C12 10.4545 11.8977 10.7159 11.6932 10.9432L10.9432 11.6932C10.7159 11.8977 10.4545 12 10.1591 12C9.86364 12 9.61364 11.8977 9.40909 11.6932L6 8.28409L2.59091 11.6932C2.38636 11.8977 2.13636 12 1.84091 12C1.54545 12 1.28409 11.8977 1.05682 11.6932L0.306818 10.9432C0.102273 10.7159 0 10.4545 0 10.1591C0 9.86364 0.102273 9.61364 0.306818 9.40909L3.71591 6L0.306818 2.59091C0.102273 2.38636 0 2.13636 0 1.84091C0 1.54545 0.102273 1.28409 0.306818 1.05682L1.05682 0.306818C1.28409 0.102273 1.54545 0 1.84091 0C2.13636 0 2.38636 0.102273 2.59091 0.306818L6 3.71591L9.40909 0.306818C9.61364 0.102273 9.86364 0 10.1591 0C10.4545 0 10.7159 0.102273 10.9432 0.306818L11.6932 1.05682C11.8977 1.28409 12 1.54545 12 1.84091C12 2.13636 11.8977 2.38636 11.6932 2.59091L8.28409 6Z" fill="white"></path></svg>
723
+ </a>
724
+ </div>
725
+ </div>
726
+ <div class="thirstyaff-notifications-header <?php echo ! empty( $notifications['active'] ) && count( $notifications['active'] ) < 10 ? 'single-digit' : ''; ?>">
727
+ <div class="thirstyaff-notifications-header-bell">
728
+ <div class="thirstyaff-notifications-bell">
729
+ <svg viewBox="0 0 512 512" width="30" xmlns="http://www.w3.org/2000/svg"><path fill="#777777" d="m381.7 225.9c0-97.6-52.5-130.8-101.6-138.2 0-.5.1-1 .1-1.6 0-12.3-10.9-22.1-24.2-22.1s-23.8 9.8-23.8 22.1c0 .6 0 1.1.1 1.6-49.2 7.5-102 40.8-102 138.4 0 113.8-28.3 126-66.3 158h384c-37.8-32.1-66.3-44.4-66.3-158.2z"/><path fill="#777777" d="m256.2 448c26.8 0 48.8-19.9 51.7-43h-103.4c2.8 23.1 24.9 43 51.7 43z"/></svg>
730
+ <?php if ( ! empty( $notifications['active'] ) ) : ?>
731
+ <span id="thirstyaffNotificationsCountTray" class="thirstyaff-notifications-count"><?php echo count( $notifications['active'] ); ?></span>
732
+ <?php endif; ?>
733
+ </div>
734
+ <div class="thirstyaff-notifications-title"><?php esc_html_e( 'Notifications', 'thirstyaffiliates' ); ?></div>
735
+ </div>
736
+ <?php if ( ! empty( $notifications['active'] ) ) : ?>
737
+ <button id="dismissAll" class="dismiss-all"><?php _e( 'Dismiss All', 'thirstyaffiliates' ); ?></button>
738
+ <?php endif; ?>
739
+ </div>
740
+
741
+ <div class="thirstyaff-notifications-body">
742
+ <div class="thirstyaff-notifications-messages">
743
+ <?php echo $notifications_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
744
+ </div>
745
+ </div>
746
+
747
+ </div>
748
+
749
+ </div>
750
+ <?php
751
+ }
752
+
753
+ /**
754
+ * Dismiss notification(s) via AJAX.
755
+ */
756
+ public function dismiss() {
757
+
758
+ // Run a security check.
759
+ check_ajax_referer( 'thirstyaff-admin-notifications', 'nonce' );
760
+
761
+ // Check for access and required param.
762
+ if ( ! self::has_access() || empty( $_POST['id'] ) ) {
763
+ wp_send_json_error();
764
+ }
765
+
766
+ $id = sanitize_text_field( wp_unslash( $_POST['id'] ) );
767
+ $option = $this->get_option();
768
+
769
+ if ( 'all' === $id ) { // Dismiss all notifications
770
+
771
+ // Feed notifications
772
+ if ( ! empty( $option['feed'] ) ) {
773
+ foreach ( $option['feed'] as $key => $notification ) {
774
+ $option['dismissed'][$key] = $option['feed'][$key];
775
+ unset( $option['feed'][$key] );
776
+ }
777
+ }
778
+
779
+ // Event notifications
780
+ if ( ! empty( $option['events'] ) ) {
781
+ foreach ( $option['events'] as $key => $notification ) {
782
+ $option['dismissed'][$key] = $option['events'][$key];
783
+ unset( $option['events'][$key] );
784
+ }
785
+ }
786
+
787
+ } else { // Dismiss one notification
788
+
789
+ // Event notifications need a prefix to distinguish them from feed notifications
790
+ // For a naming convention, we'll use "event_{timestamp}"
791
+ // If the notification ID includes "event_", we know it's an even notification
792
+ $type = false !== strpos( $id, 'event_' ) ? 'events' : 'feed';
793
+
794
+ if( $type == 'events' ){
795
+ if( !empty($option[$type]) ){
796
+ foreach( $option[$type] as $index => $event_notification ){
797
+ if( $event_notification['id'] == $id ){
798
+ unset( $option[$type][$index] );
799
+ break;
800
+ }
801
+ }
802
+ }
803
+ }else{
804
+ if ( ! empty( $option[$type][$id] ) ) {
805
+ $option['dismissed'][$id] = $option[$type][$id];
806
+ unset( $option[$type][$id] );
807
+ }
808
+ }
809
+ }
810
+
811
+
812
+ update_option( 'thirstyaff_notifications', $option );
813
+
814
+ wp_send_json_success();
815
+ }
816
+
817
+ public function dismiss_events( $type ) {
818
+
819
+ $option = $this->get_option();
820
+
821
+ // Event notifications.
822
+ if ( ! empty( $option['events'] ) ) {
823
+ $found = 0;
824
+ foreach ( $option['events'] as $key => $notification ) {
825
+ // We found event.
826
+ if( $type === $notification['type'] ){
827
+ unset($option['events'][$key]);
828
+ $found = 1;
829
+ }
830
+ }
831
+
832
+ if( $found ){
833
+ update_option( 'thirstyaff_notifications', $option );
834
+ }
835
+ }
836
+ }
837
+ }
Models/Rewrites_Redirection.php CHANGED
@@ -278,7 +278,7 @@ class Rewrites_Redirection implements Model_Interface , Deactivatable_Interface
278
 
279
  $cat_slug = is_object( $thirstylink ) ? $thirstylink->get_category_slug() : '';
280
  $link_prefix = $this->_helper_functions->get_thirstylink_link_prefix();
281
- $referrer = isset( $_SERVER[ 'REQUEST_URI' ] ) ? $_SERVER[ 'REQUEST_URI' ] : '';
282
  $needle = '/' . $link_prefix . '/';
283
 
284
  // if setting is disabled or category slug is not defined, then return as validated.
@@ -303,7 +303,7 @@ class Rewrites_Redirection implements Model_Interface , Deactivatable_Interface
303
  public function pass_query_string_to_destination_url( $redirect_url , $thirstylink , $query_string = '' ) {
304
 
305
  if ( ! $query_string && isset( $_SERVER[ 'QUERY_STRING' ] ) )
306
- $query_string = $_SERVER[ 'QUERY_STRING' ];
307
 
308
  if ( ! $query_string || ! $thirstylink->is( 'pass_query_str' ) )
309
  return $redirect_url;
@@ -378,14 +378,14 @@ class Rewrites_Redirection implements Model_Interface , Deactivatable_Interface
378
 
379
  global $post;
380
 
381
- $is_apache = strpos( $_SERVER[ 'SERVER_SOFTWARE' ] , 'Apache' ) !== false;
382
 
383
  if ( $is_apache || ! is_object( $post ) || $post->post_type !== Plugin_Constants::AFFILIATE_LINKS_CPT || ! $this->_helper_functions->is_user_agent_bot() )
384
  return;
385
 
386
- $message = apply_filters( 'ta_blocked_bots_non_apache_message' , sprintf( __( "<h1>Forbidden</h1><p>You don't have permission to access %s on this server.</p>" , 'thirstyaffiliates' ) , $_SERVER[ 'REQUEST_URI' ] ) );
387
  header( 'HTTP/1.0 403 Forbidden' );
388
- die( $message );
389
  }
390
 
391
 
278
 
279
  $cat_slug = is_object( $thirstylink ) ? $thirstylink->get_category_slug() : '';
280
  $link_prefix = $this->_helper_functions->get_thirstylink_link_prefix();
281
+ $referrer = isset( $_SERVER[ 'REQUEST_URI' ] ) ? sanitize_text_field( wp_unslash( $_SERVER[ 'REQUEST_URI' ] ) ) : '';
282
  $needle = '/' . $link_prefix . '/';
283
 
284
  // if setting is disabled or category slug is not defined, then return as validated.
303
  public function pass_query_string_to_destination_url( $redirect_url , $thirstylink , $query_string = '' ) {
304
 
305
  if ( ! $query_string && isset( $_SERVER[ 'QUERY_STRING' ] ) )
306
+ $query_string = sanitize_text_field( wp_unslash( $_SERVER[ 'QUERY_STRING' ] ) );
307
 
308
  if ( ! $query_string || ! $thirstylink->is( 'pass_query_str' ) )
309
  return $redirect_url;
378
 
379
  global $post;
380
 
381
+ $is_apache = strpos( $_SERVER[ 'SERVER_SOFTWARE' ] , 'Apache' ) !== false; // phpcs:ignore WordPress.Security
382
 
383
  if ( $is_apache || ! is_object( $post ) || $post->post_type !== Plugin_Constants::AFFILIATE_LINKS_CPT || ! $this->_helper_functions->is_user_agent_bot() )
384
  return;
385
 
386
+ $message = apply_filters( 'ta_blocked_bots_non_apache_message' , sprintf( __( "<h1>Forbidden</h1><p>You don't have permission to access %s on this server.</p>" , 'thirstyaffiliates' ) , $_SERVER[ 'REQUEST_URI' ] ) ); // phpcs:ignore WordPress.Security
387
  header( 'HTTP/1.0 403 Forbidden' );
388
+ die( $message ); // phpcs:ignore WordPress.Security.EscapeOutput
389
  }
390
 
391
 
Models/Script_Loader.php CHANGED
@@ -122,7 +122,7 @@ class Script_Loader implements Model_Interface {
122
 
123
  $post_type = get_post_type();
124
  if ( !$post_type && isset( $_GET[ 'post_type' ] ) )
125
- $post_type = $_GET[ 'post_type' ];
126
 
127
  // Link picker styles and scripts.
128
  if ( is_admin() && current_user_can( 'edit_posts' ) && ! in_array( $screen->base , array( 'customize' ) ) ) {
@@ -200,7 +200,7 @@ class Script_Loader implements Model_Interface {
200
 
201
  } elseif ( $screen->id == 'thirstylink_page_thirsty-reports' ) {
202
 
203
- wp_enqueue_style( 'jquery-ui-styles' , '//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.min.css' , array() , '1.11.4', 'all' );
204
  wp_enqueue_style( 'ta_reports_css' , $this->_constants->CSS_ROOT_URL() . 'admin/ta-reports.css' , array( 'jquery-ui-styles' ) , Plugin_Constants::VERSION , 'all' );
205
 
206
  wp_enqueue_script( 'jquery-ui-core' );
@@ -348,20 +348,25 @@ class Script_Loader implements Model_Interface {
348
  return;
349
  }
350
 
 
 
 
351
  printf(
352
  '<div id="caseproof-flyout">
353
  <div id="caseproof-flyout-items">
354
  %1$s
355
  </div>
356
- <a href="#" class="caseproof-flyout-button caseproof-flyout-head">
 
357
  <div class="caseproof-flyout-label">%2$s</div>
358
  <img src="%3$s" alt="%2$s" data-active="%4$s" />
359
  </a>
360
  </div>',
361
- $this->get_items_html(),
362
  esc_attr__( 'See Quick Links', 'thirstyaffiliates' ),
363
  esc_url( $this->_constants->IMAGES_ROOT_URL() . 'admin-flyout.svg' ),
364
- esc_url( $this->_constants->IMAGES_ROOT_URL() . 'admin-flyout.svg' )
 
365
  );
366
  }
367
 
@@ -378,18 +383,19 @@ class Script_Loader implements Model_Interface {
378
  $items_html = '';
379
 
380
  foreach ( $items as $item_key => $item ) {
381
- $items_html .= sprintf(
382
- '<a href="%1$s" target="_blank" rel="noopener noreferrer" class="caseproof-flyout-button caseproof-flyout-item caseproof-flyout-item-%2$d"%5$s%6$s>
383
- <div class="caseproof-flyout-label">%3$s</div>
384
- %4$s
385
- </a>',
386
- esc_url( $item['url'] ),
387
- (int) $item_key,
388
- esc_html( $item['title'] ),
389
- $item['icon'],
390
- ! empty( $item['bgcolor'] ) ? ' style="background-color: ' . esc_attr( $item['bgcolor'] ) . '"' : '',
391
- ! empty( $item['hover_bgcolor'] ) ? ' onMouseOver="this.style.backgroundColor=\'' . esc_attr( $item['hover_bgcolor'] ) . '\'" onMouseOut="this.style.backgroundColor=\'' . esc_attr( $item['bgcolor'] ) . '\'"' : ''
392
- );
 
393
  }
394
 
395
  return $items_html;
@@ -402,6 +408,10 @@ class Script_Loader implements Model_Interface {
402
  */
403
  private function menu_items() {
404
 
 
 
 
 
405
  $items = array(
406
  array(
407
  'title' => esc_html__( 'Upgrade to ThirstyAffiliates Pro', 'thirstyaffiliates' ),
@@ -424,6 +434,14 @@ class Script_Loader implements Model_Interface {
424
  'bgcolor' => '#008871',
425
  'hover_bgcolor' => '#38AD9C',
426
  ),
 
 
 
 
 
 
 
 
427
  );
428
 
429
  return $items;
122
 
123
  $post_type = get_post_type();
124
  if ( !$post_type && isset( $_GET[ 'post_type' ] ) )
125
+ $post_type = sanitize_text_field( wp_unslash( $_GET[ 'post_type' ] ) );
126
 
127
  // Link picker styles and scripts.
128
  if ( is_admin() && current_user_can( 'edit_posts' ) && ! in_array( $screen->base , array( 'customize' ) ) ) {
200
 
201
  } elseif ( $screen->id == 'thirstylink_page_thirsty-reports' ) {
202
 
203
+ wp_enqueue_style( 'jquery-ui-styles' , $this->_constants->CSS_ROOT_URL() . 'lib/jquery-ui/jquery-ui.min.css' , array() , '1.11.4', 'all' );
204
  wp_enqueue_style( 'ta_reports_css' , $this->_constants->CSS_ROOT_URL() . 'admin/ta-reports.css' , array( 'jquery-ui-styles' ) , Plugin_Constants::VERSION , 'all' );
205
 
206
  wp_enqueue_script( 'jquery-ui-core' );
348
  return;
349
  }
350
 
351
+ $thirstyaff_notifications = ThirstyAffiliates()->get_model( 'Notifications' );
352
+ $notifications_count = $thirstyaff_notifications->get_count();
353
+
354
  printf(
355
  '<div id="caseproof-flyout">
356
  <div id="caseproof-flyout-items">
357
  %1$s
358
  </div>
359
+ <a href="#" id="caseproofFlyoutButton" class="caseproof-flyout-button caseproof-flyout-head">
360
+ %5$s
361
  <div class="caseproof-flyout-label">%2$s</div>
362
  <img src="%3$s" alt="%2$s" data-active="%4$s" />
363
  </a>
364
  </div>',
365
+ $this->get_items_html(), // phpcs:ignore WordPress.Security.EscapeOutput
366
  esc_attr__( 'See Quick Links', 'thirstyaffiliates' ),
367
  esc_url( $this->_constants->IMAGES_ROOT_URL() . 'admin-flyout.svg' ),
368
+ esc_url( $this->_constants->IMAGES_ROOT_URL() . 'admin-flyout.svg' ),
369
+ $notifications_count > 0 ? '<span id="thirstyaffAdminNotificationsBadge" class="thirstyaff-notifications-count">' . esc_html( $notifications_count ) . '</span>' : ''
370
  );
371
  }
372
 
383
  $items_html = '';
384
 
385
  foreach ( $items as $item_key => $item ) {
386
+ $items_html .= sprintf(
387
+ '<a id="%1$s" href="%2$s" target="_blank" rel="noopener noreferrer" class="caseproof-flyout-button caseproof-flyout-item caseproof-flyout-item-%3$d"%6$s%7$s>
388
+ <div class="caseproof-flyout-label">%4$s</div>
389
+ %5$s
390
+ </a>',
391
+ ! empty( $item['id'] ) ? esc_attr( $item['id'] ) : '',
392
+ esc_url( $item['url'] ),
393
+ (int) $item_key,
394
+ wp_kses_post( $item['title'] ),
395
+ $item['icon'],
396
+ ! empty( $item['bgcolor'] ) ? ' style="background-color: ' . esc_attr( $item['bgcolor'] ) . '"' : '',
397
+ ! empty( $item['hover_bgcolor'] ) ? ' onMouseOver="this.style.backgroundColor=\'' . esc_attr( $item['hover_bgcolor'] ) . '\'" onMouseOut="this.style.backgroundColor=\'' . esc_attr( $item['bgcolor'] ) . '\'"' : ''
398
+ );
399
  }
400
 
401
  return $items_html;
408
  */
409
  private function menu_items() {
410
 
411
+ $thirstyaff_notifications = ThirstyAffiliates()->get_model( 'Notifications' );
412
+ $notifications_count = $thirstyaff_notifications->get_count();
413
+ $notifications_count_text = $notifications_count > 0 ? sprintf( '(%s)', $notifications_count ) : '';
414
+
415
  $items = array(
416
  array(
417
  'title' => esc_html__( 'Upgrade to ThirstyAffiliates Pro', 'thirstyaffiliates' ),
434
  'bgcolor' => '#008871',
435
  'hover_bgcolor' => '#38AD9C',
436
  ),
437
+ array(
438
+ 'id' => 'thirstyaffAdminNotifications',
439
+ 'title' => esc_html__( 'Notifications ', 'thirstyaffiliates' ) . '<span id="thirstyaffNotificationsCount"> ' . $notifications_count_text . ' </span>',
440
+ 'url' => '#',
441
+ 'icon' => '<svg width="22" height="14" viewBox="0 0 22 14" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M21.6944 6.5625C21.8981 6.85417 22 7.18229 22 7.54687V12.25C22 12.7361 21.8218 13.1493 21.4653 13.4896C21.1088 13.8299 20.6759 14 20.1667 14H1.83333C1.32407 14 0.891204 13.8299 0.534722 13.4896C0.178241 13.1493 0 12.7361 0 12.25V7.54687C0 7.18229 0.101852 6.85417 0.305556 6.5625L4.35417 0.765625C4.45602 0.644097 4.58333 0.522569 4.73611 0.401042C4.91435 0.279514 5.10532 0.182292 5.30903 0.109375C5.51273 0.0364583 5.7037 0 5.88194 0H16.1181C16.3981 0 16.6782 0.0850694 16.9583 0.255208C17.2639 0.401042 17.4931 0.571181 17.6458 0.765625L21.6944 6.5625ZM6.1875 2.33333L2.94097 7H7.63889L8.86111 9.33333H13.1389L14.3611 7H19.059L15.8125 2.33333H6.1875Z" fill="#ffffff"></path></svg>',
442
+ 'bgcolor' => '#008871',
443
+ 'hover_bgcolor' => '#38AD9C'
444
+ )
445
  );
446
 
447
  return $items;
Models/Settings.php CHANGED
@@ -834,11 +834,11 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
834
 
835
  <div class="wrap ta-settings">
836
 
837
- <h2><?php _e( 'ThirstyAffiliates Settings' , 'thirstyaffiliates' ); ?></h2>
838
 
839
  <?php
840
  settings_errors(); // Show notices based on the outcome of the settings save action
841
- $active_tab = isset( $_GET[ 'tab' ] ) ? $_GET[ 'tab' ] : 'ta_general_settings';
842
  ?>
843
 
844
  <div class="ta-settings-wrapper">
@@ -847,11 +847,11 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
847
 
848
  <h2 class="nav-tab-wrapper">
849
  <?php foreach ( $this->_settings_sections as $section_key => $section_data ) { ?>
850
- <a href="?post_type=thirstylink&page=thirsty-settings&tab=<?php echo $section_key; ?>" class="nav-tab <?php echo $active_tab == $section_key ? 'nav-tab-active' : ''; ?> <?php echo $section_key; ?>"><?php echo $section_data[ 'title' ]; ?></a>
851
  <?php } ?>
852
 
853
  <?php if ( ! $this->_helper_functions->is_plugin_active( 'thirstyaffiliates-pro/thirstyaffiliates-pro.php' ) ) : ?>
854
- <a class="tapro-upgrade nav-tab" href="https://thirstyaffiliates.com/pricing/?utm_source=Free%20Plugin&utm_medium=Pro&utm_campaign=Admin%20Settings" target="_blank"><?php _e( 'Pro Features →' , 'thirstyaffiliates' ); ?></a>
855
  <?php endif; ?>
856
  </h2>
857
 
@@ -908,8 +908,8 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
908
 
909
  ?>
910
 
911
- <h2><?php echo $this->_settings_sections[ $active_tab ][ 'title' ]; ?></h2>
912
- <p class="desc"><?php echo $this->_settings_sections[ $active_tab ][ 'desc' ]; ?></p>
913
 
914
  <?php
915
 
@@ -932,7 +932,7 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
932
 
933
  ?>
934
 
935
- <input type="hidden" name="<?php echo esc_attr( $option[ 'id' ] ); ?>" value="<?php echo get_option( $option[ 'id' ] , '' ); ?>">
936
 
937
  <?php
938
 
@@ -977,7 +977,7 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
977
 
978
  <?php if ( ! in_array( $active_tab , $no_save_sections ) ) : ?>
979
  <p class="submit">
980
- <input name="submit" id="submit" class="button button-primary" value="<?php _e( 'Save Changes' , 'thirstyaffiliates' ); ?>" type="submit">
981
  </p>
982
  <?php endif;
983
 
@@ -1006,18 +1006,18 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1006
 
1007
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1008
 
1009
- <th scope="row"><?php echo sanitize_text_field( $option[ 'title' ] ); ?></th>
1010
 
1011
- <td class="forminp forminp-<?php echo sanitize_title( $option[ 'type' ] ) ?>">
1012
  <input
1013
  type = "text"
1014
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1015
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1016
  class = "option-field <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1017
- style = "<?php echo isset( $option[ 'style' ] ) ? $option[ 'style' ] : 'width: 360px;'; ?>"
1018
- value = "<?php echo get_option( $option[ 'id' ] ); ?>" >
1019
  <br>
1020
- <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? $option[ 'desc' ] : ''; ?></p>
1021
  </td>
1022
 
1023
  </tr>
@@ -1040,18 +1040,18 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1040
 
1041
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1042
 
1043
- <th scope="row"><?php echo sanitize_text_field( $option[ 'title' ] ); ?></th>
1044
 
1045
- <td class="forminp forminp-<?php echo sanitize_title( $option[ 'type' ] ) ?>">
1046
  <input
1047
  type = "url"
1048
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1049
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1050
  class = "option-field <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1051
- style = "<?php echo isset( $option[ 'style' ] ) ? $option[ 'style' ] : 'width: 360px;'; ?>"
1052
- value = "<?php echo get_option( $option[ 'id' ] ); ?>" >
1053
  <br>
1054
- <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? $option[ 'desc' ] : ''; ?></p>
1055
  </td>
1056
 
1057
  </tr>
@@ -1074,19 +1074,19 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1074
 
1075
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1076
 
1077
- <th scope="row"><?php echo sanitize_text_field( $option[ 'title' ] ); ?></th>
1078
 
1079
- <td class="forminp forminp-<?php echo sanitize_title( $option[ 'type' ] ) ?>">
1080
  <input
1081
  type = "number"
1082
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1083
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1084
  class = "option-field <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1085
- style = "<?php echo isset( $option[ 'style' ] ) ? $option[ 'style' ] : 'width: 100px;'; ?>"
1086
- value = "<?php echo get_option( $option[ 'id' ] ); ?>"
1087
- min = "<?php echo isset( $option[ 'min' ] ) ? $option[ 'min' ] : 0; ?>"
1088
- max = "<?php echo isset( $option[ 'max' ] ) ? $option[ 'max' ] : ''; ?>" >
1089
- <span><?php echo isset( $option[ 'desc' ] ) ? $option[ 'desc' ] : ''; ?></span>
1090
  </td>
1091
 
1092
  </tr>
@@ -1109,18 +1109,18 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1109
 
1110
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1111
 
1112
- <th scope="row"><?php echo sanitize_text_field( $option[ 'title' ] ); ?></th>
1113
 
1114
- <td class="forminp forminp-<?php echo sanitize_title( $option[ 'type' ] ) ?>">
1115
  <textarea
1116
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1117
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1118
  class = "option-field <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1119
  cols = "60"
1120
  rows = "8"
1121
- style = "<?php echo isset( $option[ 'style' ] ) ? $option[ 'style' ] : 'width: 360px;'; ?>"><?php echo get_option( $option[ 'id' ] ); ?></textarea>
1122
  <br />
1123
- <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? $option[ 'desc' ] : ''; ?></p>
1124
  </td>
1125
 
1126
  </tr>
@@ -1144,9 +1144,9 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1144
  $option_val = array(); ?>
1145
 
1146
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1147
- <th scope="row"><?php echo sanitize_text_field( $option[ 'title' ] ); ?></th>
1148
 
1149
- <td class="forminp forminp-<?php echo sanitize_title( $option[ 'type' ] ) ?>">
1150
  <?php foreach ( $option[ 'options' ] as $opt_key => $opt_text ) {
1151
 
1152
  $opt_key_class = str_replace( " " , "-" , $opt_key ); ?>
@@ -1156,16 +1156,16 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1156
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>[]"
1157
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1158
  class = "option-field <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1159
- style = "<?php echo isset( $option[ 'style' ] ) ? $option[ 'style' ] : ''; ?>"
1160
- value = "<?php echo $opt_key; ?>"
1161
  <?php echo in_array( $opt_key , $option_val ) ? 'checked' : ''; ?>>
1162
 
1163
- <label class="<?php echo esc_attr( $option[ 'id' ] ); ?>"><?php echo $opt_text; ?></label>
1164
  <br>
1165
 
1166
  <?php } ?>
1167
 
1168
- <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? $option[ 'desc' ] : ''; ?></p>
1169
  </td>
1170
 
1171
  <script>
@@ -1199,9 +1199,9 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1199
 
1200
 
1201
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1202
- <th scope="row"><?php echo sanitize_text_field( $option[ 'title' ] ); ?></th>
1203
 
1204
- <td class="forminp forminp-<?php echo sanitize_title( $option[ 'type' ] ) ?>">
1205
  <?php foreach ( $option[ 'options' ] as $opt_key => $opt_text ) { ?>
1206
 
1207
  <input
@@ -1209,16 +1209,16 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1209
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1210
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1211
  class = "option-field <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1212
- style = "<?php echo isset( $option[ 'style' ] ) ? $option[ 'style' ] : ''; ?>"
1213
- value = "<?php echo $opt_key; ?>"
1214
  <?php echo $opt_key == $option_val ? 'checked' : ''; ?>>
1215
 
1216
- <label class="<?php echo esc_attr( $option[ 'id' ] ); ?>"><?php echo $opt_text; ?></label>
1217
  <br>
1218
 
1219
  <?php } ?>
1220
 
1221
- <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? $option[ 'desc' ] : ''; ?></p>
1222
  </td>
1223
 
1224
  <script>
@@ -1251,23 +1251,23 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1251
  $option_value = $this->_helper_functions->get_option( $option[ 'id' ] , $option[ 'default' ] ); ?>
1252
 
1253
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1254
- <th scope="row"><?php echo sanitize_text_field( $option[ 'title' ] ); ?></th>
1255
 
1256
- <td class="forminp forminp-<?php echo sanitize_title( $option[ 'type' ] ) ?> <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>">
1257
  <select
1258
- data-placeholder = "<?php echo isset( $option[ 'placeholder' ] ) ? $option[ 'placeholder' ] : 'Choose an option...' ; ?>"
1259
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1260
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1261
  class = "option-field selectize-select <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1262
- style = "<?php echo isset( $option[ 'style' ] ) ? $option[ 'style' ] : 'width:360px;'; ?>">
1263
 
1264
  <?php foreach ( $option[ 'options' ] as $opt_key => $opt_text ) { ?>
1265
 
1266
- <option value="<?php echo $opt_key; ?>" <?php selected( $option_value , $opt_key ); ?>><?php echo $opt_text; ?></option>
1267
 
1268
  <?php } ?>
1269
  </select>
1270
- <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? $option[ 'desc' ] : ''; ?></p>
1271
  </td>
1272
 
1273
  <script>
@@ -1300,26 +1300,26 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1300
  $option_val = array(); ?>
1301
 
1302
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1303
- <th scope="row"><?php echo sanitize_text_field( $option[ 'title' ] ); ?></th>
1304
 
1305
- <td class="forminp forminp-<?php echo sanitize_title( $option[ 'type' ] ) ?>">
1306
  <select
1307
  multiple
1308
- data-placeholder = "<?php echo isset( $option[ 'placeholder' ] ) ? $option[ 'placeholder' ] : 'Choose an option...' ; ?>"
1309
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>[]"
1310
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1311
  class = "option-field selectize-select <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1312
- style = "<?php echo isset( $option[ 'style' ] ) ? $option[ 'style' ] : 'width:360px;'; ?>"
1313
  <?php echo isset( $option[ 'required' ] ) && $option[ 'required' ] ? 'required' : '' ?>>
1314
 
1315
  <?php foreach ( $option[ 'options' ] as $opt_key => $opt_text ) { ?>
1316
 
1317
- <option value="<?php echo $opt_key; ?>" <?php echo in_array( $opt_key , $option_val ) ? 'selected="selected"' : ''; ?>><?php echo $opt_text; ?></option>
1318
 
1319
  <?php } ?>
1320
  </select>
1321
  <br>
1322
- <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? $option[ 'desc' ] : ''; ?></p>
1323
  </td>
1324
 
1325
  <script>
@@ -1351,18 +1351,18 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1351
  ?>
1352
 
1353
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1354
- <th scope="row"><?php echo sanitize_text_field( $option[ 'title' ] ); ?></th>
1355
 
1356
- <td class="forminp forminp-<?php echo sanitize_title( $option[ 'type' ] ) ?>">
1357
  <input
1358
  type = "checkbox"
1359
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1360
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1361
  class = "option-field <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1362
- style = "<?php echo isset( $option[ 'style' ] ) ? $option[ 'style' ] : ''; ?>"
1363
  value = "yes"
1364
  <?php echo get_option( $option[ 'id' ] ) === "yes" ? 'checked' : ''; ?>>
1365
- <label class="<?php echo esc_attr( $option[ 'id' ] ); ?>"><?php echo isset( $option[ 'desc' ] ) ? $option[ 'desc' ] : ''; ?></label>
1366
  </td>
1367
 
1368
  <script>
@@ -1395,10 +1395,10 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1395
  $editor_value = html_entity_decode( get_option( $option[ 'id' ] ) ); ?>
1396
 
1397
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1398
- <th scope="row"><?php echo sanitize_text_field( $option[ 'title' ] ); ?></th>
1399
 
1400
- <td class="forminp forminp-<?php echo sanitize_title( $option[ 'type' ] ) ?>">
1401
- <style type="text/css"><?php echo "div#wp-" . $option[ 'id' ] . "-wrap{ width: 70% !important; }"; ?></style>
1402
 
1403
  <?php wp_editor( $editor_value , $option[ 'id' ] , array(
1404
  'wpautop' => true,
@@ -1406,7 +1406,7 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1406
  'editor_height' => '300'
1407
  ) ); ?>
1408
  <br>
1409
- <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? $option[ 'desc' ] : ''; ?></p>
1410
  </td>
1411
  </tr>
1412
 
@@ -1427,24 +1427,24 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1427
  ?>
1428
 
1429
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1430
- <th scope="row"><?php echo $option[ 'title' ]; ?></th>
1431
 
1432
- <td class="forminp forminp-<?php echo sanitize_title( $option[ 'type' ] ) ?>">
1433
  <input
1434
  type = "text"
1435
- name = "<?php echo $option[ 'id' ]; ?>"
1436
- id = "<?php echo $option[ 'id' ]; ?>"
1437
- class = "option-field <?php echo isset( $option[ 'class' ] ) ? $option[ 'class' ] : ''; ?>"
1438
- style = "<?php echo isset( $option[ 'style' ] ) ? $option[ 'style' ] : 'width: 360px;'; ?>"
1439
- value = "<?php echo get_option( $option[ 'id' ] ); ?>" >
1440
  <br>
1441
- <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? $option[ 'desc' ] : ''; ?></p>
1442
  </td>
1443
 
1444
  <script>
1445
  jQuery( document ).ready( function( $ ) {
1446
 
1447
- $( '#<?php echo $option[ 'id' ]; ?>' ).selectize( {
1448
  plugins : [ 'restore_on_backspace' , 'remove_button' , 'drag_drop' ],
1449
  delimiter : ',',
1450
  persist : false,
@@ -1479,15 +1479,15 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1479
  $option_value = array(); ?>
1480
 
1481
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1482
- <th scope="row"><?php echo $option[ 'title' ]; ?></th>
1483
 
1484
- <td class="forminp forminp-<?php echo sanitize_title( $option[ 'type' ] ) ?>">
1485
 
1486
- <div class="key-value-fields-container" data-field-id="<?php echo $option[ 'id' ]; ?>">
1487
 
1488
  <header>
1489
- <span class="key"><?php _e( 'Key' , 'thirstyaffiliates' ); ?></span>
1490
- <span class="value"><?php _e( 'Value' , 'thirstyaffiliates' ); ?></span>
1491
  </header>
1492
 
1493
  <div class="fields">
@@ -1508,8 +1508,8 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1508
  foreach ( $option_value as $key => $val ) { ?>
1509
 
1510
  <div class="data-set">
1511
- <input type="text" class="field key-field" value="<?php echo $key; ?>">
1512
- <input type="text" class="field value-field" value="<?php echo $val; ?>">
1513
  <div class="controls">
1514
  <span class="control add dashicons dashicons-plus-alt" autocomplete="off"></span>
1515
  <span class="control delete dashicons dashicons-dismiss" autocomplete="off"></span>
@@ -1524,7 +1524,7 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1524
 
1525
  </div>
1526
 
1527
- <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? $option[ 'desc' ] : ''; ?></p>
1528
 
1529
  </td>
1530
  </tr>
@@ -1546,11 +1546,11 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1546
  ?>
1547
 
1548
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1549
- <th scope="row"><?php echo sanitize_text_field( $option[ 'title' ] ); ?></th>
1550
  <td>
1551
- <a id="<?php echo esc_attr( $option[ 'id' ] ); ?>" href="<?php echo $option[ 'link_url' ]; ?>" target="_blank"><?php echo $option[ 'link_text' ]; ?></a>
1552
  <br>
1553
- <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? $option[ 'desc' ] : ''; ?></p>
1554
  </td>
1555
  </tr>
1556
 
@@ -1572,8 +1572,8 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1572
 
1573
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1574
  <th scope="row" colspan="2">
1575
- <h3><?php echo sanitize_text_field( $option[ 'title' ] ); ?></h3>
1576
- <?php echo isset( $option[ 'markup' ] ) ? $option[ 'markup' ] : ''; ?>
1577
  </th>
1578
  </tr>
1579
 
@@ -1604,13 +1604,13 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1604
 
1605
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1606
 
1607
- <th scope="row" class="title_desc"><?php echo sanitize_text_field( $option[ 'title' ] ); ?></th>
1608
 
1609
- <td class="forminp forminp-<?php echo sanitize_title( $option[ 'type' ] ) ?> <?php echo $processing; ?>">
1610
 
1611
  <?php if ( !$database_processing ) { ?>
1612
 
1613
- <p><?php _e( 'Another application is currently processing the database. Please wait for this to complete.' , 'thirstyaffiliates' ); ?></p>
1614
 
1615
  <?php } else { ?>
1616
 
@@ -1620,15 +1620,15 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1620
  id="<?php echo esc_attr( $option[ 'id' ] ); ?>"
1621
  class="button button-primary"
1622
  style="<?php echo isset( $option[ 'style' ] ) ? esc_attr( $option[ 'style' ] ) : ''; ?>"
1623
- value="<?php _e( 'Migrate' , 'thirstyaffiliates' ); ?>">
1624
 
1625
  <span class="spinner"></span>
1626
- <p class="status"><?php _e( 'Migrating data. Please wait...' , 'thirstyaffiliates' ); ?></p>
1627
 
1628
  <?php } ?>
1629
 
1630
  <br /><br />
1631
- <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? $option[ 'desc' ] : ''; ?></p>
1632
 
1633
  </td>
1634
 
@@ -1650,23 +1650,23 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1650
 
1651
  ?>
1652
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1653
- <th scope="row"><?php echo sanitize_text_field( $option[ 'title' ] ); ?></th>
1654
  <td>
1655
  <ul>
1656
  <li>
1657
- <a href="https://www.facebook.com/thirstyaffiliates/"><?php _e( 'Like us on Facebook' , 'thirstyaffiliates' ); ?></a>
1658
  <iframe src="//www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.facebook.com%2Fthirstyaffiliates&amp;send=false&amp;layout=button_count&amp;width=450&amp;show_faces=false&amp;font=arial&amp;colorscheme=light&amp;action=like&amp;height=21" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:21px; vertical-align: bottom;" allowTransparency="true"></iframe>
1659
  </li>
1660
  <li>
1661
- <a href="http://twitter.com/thirstyaff"><?php _e( 'Follow us on Twitter' , 'thirstyaffiliates' ); ?></a>
1662
  <a href="https://twitter.com/thirstyaff" class="twitter-follow-button" data-show-count="true" style="vertical-align: bottom;">Follow @thirstyaff</a><script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?"http":"https";if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document, "script", "twitter-wjs");</script>
1663
  </li>
1664
  <li>
1665
- <a href="https://www.linkedin.com/company-beta/2928598/"><?php _e( 'Follow us on Linkedin' , 'thirstyaffiliates' ); ?></a>
1666
  </li>
1667
  <li>
1668
- <a href="https://thirstyaffiliates.com/affiliates?utm_source=Free%20Plugin&utm_medium=Help&utm_campaign=Affiliates%20Link" target="_blank"><?php _e( 'Join Our Affiliate Program' , 'thirstyaffiliates' ); ?></a>
1669
- <?php _e( '(up to 30% commisions)' , 'thirstyaffiliates' ); ?>
1670
  </li>
1671
  </ul>
1672
  </td>
@@ -1687,8 +1687,8 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1687
  $global_settings_string = $this->get_global_settings_string(); ?>
1688
 
1689
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1690
- <th scope="row" class="title_desc"><?php echo sanitize_text_field( $option[ 'title' ] ); ?></th>
1691
- <td class="forminp forminp-<?php echo sanitize_title( $option[ 'type' ] ) ?>">
1692
  <textarea
1693
  name="<?php echo esc_attr( $option[ 'id' ] ); ?>"
1694
  id="<?php echo esc_attr( $option[ 'id' ] ); ?>"
@@ -1697,9 +1697,9 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1697
  placeholder="<?php echo isset( $option[ 'placeholder' ] ) ? esc_attr( $option[ 'placeholder' ] ) : ''; ?>"
1698
  autocomplete="off"
1699
  readonly
1700
- rows="10"><?php echo $global_settings_string; ?></textarea>
1701
  <div class="controls">
1702
- <a id="copy-settings-string" data-clipboard-target="#<?php echo esc_attr( $option[ 'id' ] ); ?>"><?php _e( 'Copy' , 'thirstyaffiliates' ); ?></a>
1703
  </div>
1704
  </td>
1705
  </tr>
@@ -1722,9 +1722,9 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1722
 
1723
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1724
  <th scope="row" class="title_desc">
1725
- <label for="<?php echo esc_attr( $option[ 'id' ] ); ?>"><?php echo sanitize_text_field( $option[ 'title' ] ); ?></label>
1726
  </th>
1727
- <td class="forminp forminp-<?php echo sanitize_title( $option[ 'type' ] ) ?>">
1728
  <textarea
1729
  name="<?php echo esc_attr( $option[ 'id' ] ); ?>"
1730
  id="<?php echo esc_attr( $option[ 'id' ] ); ?>"
@@ -1733,10 +1733,10 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1733
  placeholder="<?php echo esc_attr( $option[ 'placeholder' ] ); ?>"
1734
  autocomplete="off"
1735
  rows="10"></textarea>
1736
- <p class="desc"><?php echo isset( $option[ 'description' ] ) ? $option[ 'description' ] : ''; ?></p>
1737
  <div class="controls">
1738
  <span class="spinner"></span>
1739
- <input type="button" id="import-setting-button" class="button button-primary" value="<?php _e( 'Import Settings' , 'thirstyaffiliates' ); ?>">
1740
  </div>
1741
  </td>
1742
  </tr>
@@ -1952,7 +1952,7 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
1952
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Required parameter not passed' , 'thirstyaffiliates' ) );
1953
  else {
1954
 
1955
- $result = $this->import_settings( filter_var( $_POST[ 'ta_settings_string' ] , FILTER_SANITIZE_STRING ) );
1956
 
1957
  if ( is_wp_error( $result ) )
1958
  $response = array( 'status' => 'fail' , 'error_msg' => $result->get_error_message() );
@@ -2043,7 +2043,7 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
2043
  public function restrict_module_settings() {
2044
 
2045
  $screen = get_current_screen();
2046
- $tab = isset( $_GET[ 'tab' ] ) ? sanitize_text_field( $_GET[ 'tab' ] ) : null;
2047
 
2048
  if ( $screen->id !== 'thirstylink_page_thirsty-settings' || ! $tab ) return;
2049
 
@@ -2068,7 +2068,7 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
2068
  $default = in_array( $current_module , $modules ) ? $default_values[ $current_module ] : null;
2069
 
2070
  if ( ! is_null( $default ) && get_option( $current_module , $default ) !== 'yes' )
2071
- wp_die( __( "Sorry, you are not allowed to access this page." , 'thirstyaffiliates' ) );
2072
 
2073
  }
2074
 
@@ -2148,10 +2148,10 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
2148
 
2149
  <div class="ta-upgrade-header" id="ta-upgrade-header">
2150
  <span id="close-ta-upgrade-header">X</span>
2151
- <?php _e( 'You\'re using ThirstyAffiliates Lite. To unlock more features, consider <a href="https://thirstyaffiliates.com/pricing?utm_source=plugin_admin&utm_medium=link&utm_campaign=in_plugin&utm_content=upgrade_header">upgrading to Pro.</a>' ); ?>
2152
  </div>
2153
 
2154
- <div id="ta-admin-header"><img class="ta-logo" src="<?php echo $this->_constants->IMAGES_ROOT_URL() . 'TA.svg'; ?>" /></div>
2155
 
2156
  <script>
2157
  jQuery(document).ready(function($) {
@@ -2163,7 +2163,7 @@ class Settings implements Model_Interface , Activatable_Interface , Initiable_In
2163
  type: 'POST',
2164
  data: {
2165
  action: 'ta_dismiss_upgrade_header',
2166
- _ajax_nonce: "<?php echo wp_create_nonce( 'ta_dismiss_upgrade_header' ); ?>"
2167
  },
2168
  })
2169
  .done(function() {
834
 
835
  <div class="wrap ta-settings">
836
 
837
+ <h2><?php esc_html_e( 'ThirstyAffiliates Settings' , 'thirstyaffiliates' ); ?></h2>
838
 
839
  <?php
840
  settings_errors(); // Show notices based on the outcome of the settings save action
841
+ $active_tab = isset( $_GET[ 'tab' ] ) ? sanitize_text_field( wp_unslash( $_GET[ 'tab' ] ) ) : 'ta_general_settings';
842
  ?>
843
 
844
  <div class="ta-settings-wrapper">
847
 
848
  <h2 class="nav-tab-wrapper">
849
  <?php foreach ( $this->_settings_sections as $section_key => $section_data ) { ?>
850
+ <a href="?post_type=thirstylink&page=thirsty-settings&tab=<?php echo esc_attr( $section_key ); ?>" class="nav-tab <?php echo $active_tab == $section_key ? 'nav-tab-active' : ''; ?> <?php echo esc_attr( $section_key ); ?>"><?php echo esc_html( $section_data[ 'title' ] ); ?></a>
851
  <?php } ?>
852
 
853
  <?php if ( ! $this->_helper_functions->is_plugin_active( 'thirstyaffiliates-pro/thirstyaffiliates-pro.php' ) ) : ?>
854
+ <a class="tapro-upgrade nav-tab" href="https://thirstyaffiliates.com/pricing/?utm_source=Free%20Plugin&utm_medium=Pro&utm_campaign=Admin%20Settings" target="_blank"><?php esc_html_e( 'Pro Features →' , 'thirstyaffiliates' ); ?></a>
855
  <?php endif; ?>
856
  </h2>
857
 
908
 
909
  ?>
910
 
911
+ <h2><?php echo esc_html( $this->_settings_sections[ $active_tab ][ 'title' ] ); ?></h2>
912
+ <p class="desc"><?php echo wp_kses_post( $this->_settings_sections[ $active_tab ][ 'desc' ] ); ?></p>
913
 
914
  <?php
915
 
932
 
933
  ?>
934
 
935
+ <input type="hidden" name="<?php echo esc_attr( $option[ 'id' ] ); ?>" value="<?php echo esc_attr( get_option( $option[ 'id' ] , '' ) ); ?>">
936
 
937
  <?php
938
 
977
 
978
  <?php if ( ! in_array( $active_tab , $no_save_sections ) ) : ?>
979
  <p class="submit">
980
+ <input name="submit" id="submit" class="button button-primary" value="<?php esc_html_e( 'Save Changes' , 'thirstyaffiliates' ); ?>" type="submit">
981
  </p>
982
  <?php endif;
983
 
1006
 
1007
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1008
 
1009
+ <th scope="row"><?php echo esc_html( $option[ 'title' ] ); ?></th>
1010
 
1011
+ <td class="forminp forminp-<?php echo esc_attr( $option[ 'type' ] ) ?>">
1012
  <input
1013
  type = "text"
1014
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1015
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1016
  class = "option-field <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1017
+ style = "<?php echo isset( $option[ 'style' ] ) ? esc_attr( $option[ 'style' ] ) : 'width: 360px;'; ?>"
1018
+ value = "<?php echo esc_attr( get_option( $option[ 'id' ] ) ); ?>" >
1019
  <br>
1020
+ <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? wp_kses_post( $option[ 'desc' ] ) : ''; ?></p>
1021
  </td>
1022
 
1023
  </tr>
1040
 
1041
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1042
 
1043
+ <th scope="row"><?php echo esc_html( $option[ 'title' ] ); ?></th>
1044
 
1045
+ <td class="forminp forminp-<?php echo esc_attr( $option[ 'type' ] ) ?>">
1046
  <input
1047
  type = "url"
1048
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1049
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1050
  class = "option-field <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1051
+ style = "<?php echo isset( $option[ 'style' ] ) ? esc_attr( $option[ 'style' ] ) : 'width: 360px;'; ?>"
1052
+ value = "<?php echo esc_attr( get_option( $option[ 'id' ] ) ); ?>" >
1053
  <br>
1054
+ <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? wp_kses_post( $option[ 'desc' ] ) : ''; ?></p>
1055
  </td>
1056
 
1057
  </tr>
1074
 
1075
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1076
 
1077
+ <th scope="row"><?php echo esc_html( $option[ 'title' ] ); ?></th>
1078
 
1079
+ <td class="forminp forminp-<?php echo esc_attr( $option[ 'type' ] ) ?>">
1080
  <input
1081
  type = "number"
1082
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1083
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1084
  class = "option-field <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1085
+ style = "<?php echo isset( $option[ 'style' ] ) ? esc_attr( $option[ 'style' ] ) : 'width: 100px;'; ?>"
1086
+ value = "<?php echo esc_attr( get_option( $option[ 'id' ] ) ); ?>"
1087
+ min = "<?php echo isset( $option[ 'min' ] ) ? esc_attr( $option[ 'min' ] ) : 0; ?>"
1088
+ max = "<?php echo isset( $option[ 'max' ] ) ? esc_attr( $option[ 'max' ] ) : ''; ?>" >
1089
+ <span><?php echo isset( $option[ 'desc' ] ) ? wp_kses_post( $option[ 'desc' ] ) : ''; ?></span>
1090
  </td>
1091
 
1092
  </tr>
1109
 
1110
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1111
 
1112
+ <th scope="row"><?php echo esc_html( $option[ 'title' ] ); ?></th>
1113
 
1114
+ <td class="forminp forminp-<?php echo esc_attr( $option[ 'type' ] ) ?>">
1115
  <textarea
1116
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1117
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1118
  class = "option-field <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1119
  cols = "60"
1120
  rows = "8"
1121
+ style = "<?php echo isset( $option[ 'style' ] ) ? esc_attr( $option[ 'style' ] ) : 'width: 360px;'; ?>"><?php echo esc_attr( get_option( $option[ 'id' ] ) ); ?></textarea>
1122
  <br />
1123
+ <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? wp_kses_post( $option[ 'desc' ] ) : ''; ?></p>
1124
  </td>
1125
 
1126
  </tr>
1144
  $option_val = array(); ?>
1145
 
1146
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1147
+ <th scope="row"><?php echo esc_html( $option[ 'title' ] ); ?></th>
1148
 
1149
+ <td class="forminp forminp-<?php echo esc_attr( $option[ 'type' ] ) ?>">
1150
  <?php foreach ( $option[ 'options' ] as $opt_key => $opt_text ) {
1151
 
1152
  $opt_key_class = str_replace( " " , "-" , $opt_key ); ?>
1156
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>[]"
1157
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1158
  class = "option-field <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1159
+ style = "<?php echo isset( $option[ 'style' ] ) ? esc_attr( $option[ 'style' ] ) : ''; ?>"
1160
+ value = "<?php echo esc_attr( $opt_key ); ?>"
1161
  <?php echo in_array( $opt_key , $option_val ) ? 'checked' : ''; ?>>
1162
 
1163
+ <label class="<?php echo esc_attr( $option[ 'id' ] ); ?>"><?php echo wp_kses_post( $opt_text ); ?></label>
1164
  <br>
1165
 
1166
  <?php } ?>
1167
 
1168
+ <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? wp_kses_post( $option[ 'desc' ] ) : ''; ?></p>
1169
  </td>
1170
 
1171
  <script>
1199
 
1200
 
1201
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1202
+ <th scope="row"><?php echo esc_html( $option[ 'title' ] ); ?></th>
1203
 
1204
+ <td class="forminp forminp-<?php echo esc_attr( $option[ 'type' ] ) ?>">
1205
  <?php foreach ( $option[ 'options' ] as $opt_key => $opt_text ) { ?>
1206
 
1207
  <input
1209
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1210
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1211
  class = "option-field <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1212
+ style = "<?php echo isset( $option[ 'style' ] ) ? esc_attr( $option[ 'style' ] ) : ''; ?>"
1213
+ value = "<?php echo esc_attr( $opt_key ); ?>"
1214
  <?php echo $opt_key == $option_val ? 'checked' : ''; ?>>
1215
 
1216
+ <label class="<?php echo esc_attr( $option[ 'id' ] ); ?>"><?php echo wp_kses_post( $opt_text ); ?></label>
1217
  <br>
1218
 
1219
  <?php } ?>
1220
 
1221
+ <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? wp_kses_post( $option[ 'desc' ] ) : ''; ?></p>
1222
  </td>
1223
 
1224
  <script>
1251
  $option_value = $this->_helper_functions->get_option( $option[ 'id' ] , $option[ 'default' ] ); ?>
1252
 
1253
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1254
+ <th scope="row"><?php echo esc_html( $option[ 'title' ] ); ?></th>
1255
 
1256
+ <td class="forminp forminp-<?php echo esc_attr( $option[ 'type' ] ) ?> <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>">
1257
  <select
1258
+ data-placeholder = "<?php echo isset( $option[ 'placeholder' ] ) ? esc_attr( $option[ 'placeholder' ] ) : 'Choose an option...' ; ?>"
1259
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1260
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1261
  class = "option-field selectize-select <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1262
+ style = "<?php echo isset( $option[ 'style' ] ) ? esc_attr( $option[ 'style' ] ) : 'width:360px;'; ?>">
1263
 
1264
  <?php foreach ( $option[ 'options' ] as $opt_key => $opt_text ) { ?>
1265
 
1266
+ <option value="<?php echo esc_attr( $opt_key ); ?>" <?php selected( $option_value , $opt_key ); ?>><?php echo esc_html( $opt_text ); ?></option>
1267
 
1268
  <?php } ?>
1269
  </select>
1270
+ <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? wp_kses_post( $option[ 'desc' ] ) : ''; ?></p>
1271
  </td>
1272
 
1273
  <script>
1300
  $option_val = array(); ?>
1301
 
1302
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1303
+ <th scope="row"><?php echo esc_html( $option[ 'title' ] ); ?></th>
1304
 
1305
+ <td class="forminp forminp-<?php echo esc_attr( $option[ 'type' ] ) ?>">
1306
  <select
1307
  multiple
1308
+ data-placeholder = "<?php echo isset( $option[ 'placeholder' ] ) ? esc_attr( $option[ 'placeholder' ] ) : 'Choose an option...' ; ?>"
1309
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>[]"
1310
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1311
  class = "option-field selectize-select <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1312
+ style = "<?php echo isset( $option[ 'style' ] ) ? esc_attr( $option[ 'style' ] ) : 'width:360px;'; ?>"
1313
  <?php echo isset( $option[ 'required' ] ) && $option[ 'required' ] ? 'required' : '' ?>>
1314
 
1315
  <?php foreach ( $option[ 'options' ] as $opt_key => $opt_text ) { ?>
1316
 
1317
+ <option value="<?php echo esc_attr( $opt_key ); ?>" <?php echo in_array( $opt_key , $option_val ) ? 'selected="selected"' : ''; ?>><?php echo esc_html( $opt_text ); ?></option>
1318
 
1319
  <?php } ?>
1320
  </select>
1321
  <br>
1322
+ <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? wp_kses_post( $option[ 'desc' ] ) : ''; ?></p>
1323
  </td>
1324
 
1325
  <script>
1351
  ?>
1352
 
1353
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1354
+ <th scope="row"><?php echo esc_html( $option[ 'title' ] ); ?></th>
1355
 
1356
+ <td class="forminp forminp-<?php echo esc_attr( $option[ 'type' ] ) ?>">
1357
  <input
1358
  type = "checkbox"
1359
  name = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1360
  id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1361
  class = "option-field <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1362
+ style = "<?php echo isset( $option[ 'style' ] ) ? esc_attr( $option[ 'style' ] ) : ''; ?>"
1363
  value = "yes"
1364
  <?php echo get_option( $option[ 'id' ] ) === "yes" ? 'checked' : ''; ?>>
1365
+ <label class="<?php echo esc_attr( $option[ 'id' ] ); ?>"><?php echo isset( $option[ 'desc' ] ) ? wp_kses_post( $option[ 'desc' ] ) : ''; ?></label>
1366
  </td>
1367
 
1368
  <script>
1395
  $editor_value = html_entity_decode( get_option( $option[ 'id' ] ) ); ?>
1396
 
1397
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1398
+ <th scope="row"><?php echo esc_html( $option[ 'title' ] ); ?></th>
1399
 
1400
+ <td class="forminp forminp-<?php echo esc_attr( $option[ 'type' ] ) ?>">
1401
+ <style type="text/css"><?php echo "div#wp-" . esc_attr( $option[ 'id' ]) . "-wrap{ width: 70% !important; }"; ?></style>
1402
 
1403
  <?php wp_editor( $editor_value , $option[ 'id' ] , array(
1404
  'wpautop' => true,
1406
  'editor_height' => '300'
1407
  ) ); ?>
1408
  <br>
1409
+ <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? wp_kses_post( $option[ 'desc' ] ) : ''; ?></p>
1410
  </td>
1411
  </tr>
1412
 
1427
  ?>
1428
 
1429
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1430
+ <th scope="row"><?php echo esc_html( $option[ 'title' ] ); ?></th>
1431
 
1432
+ <td class="forminp forminp-<?php echo esc_attr( $option[ 'type' ] ) ?>">
1433
  <input
1434
  type = "text"
1435
+ name = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1436
+ id = "<?php echo esc_attr( $option[ 'id' ] ); ?>"
1437
+ class = "option-field <?php echo isset( $option[ 'class' ] ) ? esc_attr( $option[ 'class' ] ) : ''; ?>"
1438
+ style = "<?php echo isset( $option[ 'style' ] ) ? esc_attr( $option[ 'style' ] ) : 'width: 360px;'; ?>"
1439
+ value = "<?php echo esc_attr( get_option( $option[ 'id' ] ) ); ?>" >
1440
  <br>
1441
+ <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? wp_kses_post( $option[ 'desc' ] ) : ''; ?></p>
1442
  </td>
1443
 
1444
  <script>
1445
  jQuery( document ).ready( function( $ ) {
1446
 
1447
+ $( '#<?php echo esc_attr( $option[ 'id' ] ); ?>' ).selectize( {
1448
  plugins : [ 'restore_on_backspace' , 'remove_button' , 'drag_drop' ],
1449
  delimiter : ',',
1450
  persist : false,
1479
  $option_value = array(); ?>
1480
 
1481
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1482
+ <th scope="row"><?php echo esc_html( $option[ 'title' ] ); ?></th>
1483
 
1484
+ <td class="forminp forminp-<?php echo esc_attr( $option[ 'type' ] ) ?>">
1485
 
1486
+ <div class="key-value-fields-container" data-field-id="<?php echo esc_attr( $option[ 'id' ] ); ?>">
1487
 
1488
  <header>
1489
+ <span class="key"><?php esc_html_e( 'Key' , 'thirstyaffiliates' ); ?></span>
1490
+ <span class="value"><?php esc_html_e( 'Value' , 'thirstyaffiliates' ); ?></span>
1491
  </header>
1492
 
1493
  <div class="fields">
1508
  foreach ( $option_value as $key => $val ) { ?>
1509
 
1510
  <div class="data-set">
1511
+ <input type="text" class="field key-field" value="<?php echo esc_attr( $key ); ?>">
1512
+ <input type="text" class="field value-field" value="<?php echo esc_attr( $val ); ?>">
1513
  <div class="controls">
1514
  <span class="control add dashicons dashicons-plus-alt" autocomplete="off"></span>
1515
  <span class="control delete dashicons dashicons-dismiss" autocomplete="off"></span>
1524
 
1525
  </div>
1526
 
1527
+ <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? wp_kses_post( $option[ 'desc' ] ) : ''; ?></p>
1528
 
1529
  </td>
1530
  </tr>
1546
  ?>
1547
 
1548
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1549
+ <th scope="row"><?php echo esc_html( $option[ 'title' ] ); ?></th>
1550
  <td>
1551
+ <a id="<?php echo esc_attr( $option[ 'id' ] ); ?>" href="<?php echo esc_url( $option[ 'link_url' ] ); ?>" target="_blank"><?php echo esc_html( $option[ 'link_text' ] ); ?></a>
1552
  <br>
1553
+ <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? wp_kses_post( $option[ 'desc' ] ) : ''; ?></p>
1554
  </td>
1555
  </tr>
1556
 
1572
 
1573
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1574
  <th scope="row" colspan="2">
1575
+ <h3><?php echo esc_html( $option[ 'title' ] ); ?></h3>
1576
+ <?php echo isset( $option[ 'markup' ] ) ? wp_kses_post( $option[ 'markup' ] ) : ''; ?>
1577
  </th>
1578
  </tr>
1579
 
1604
 
1605
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1606
 
1607
+ <th scope="row" class="title_desc"><?php echo esc_html( $option[ 'title' ] ); ?></th>
1608
 
1609
+ <td class="forminp forminp-<?php echo esc_attr( $option[ 'type' ] ) ?> <?php echo esc_attr( $processing ); ?>">
1610
 
1611
  <?php if ( !$database_processing ) { ?>
1612
 
1613
+ <p><?php esc_html_e( 'Another application is currently processing the database. Please wait for this to complete.' , 'thirstyaffiliates' ); ?></p>
1614
 
1615
  <?php } else { ?>
1616
 
1620
  id="<?php echo esc_attr( $option[ 'id' ] ); ?>"
1621
  class="button button-primary"
1622
  style="<?php echo isset( $option[ 'style' ] ) ? esc_attr( $option[ 'style' ] ) : ''; ?>"
1623
+ value="<?php esc_html_e( 'Migrate' , 'thirstyaffiliates' ); ?>">
1624
 
1625
  <span class="spinner"></span>
1626
+ <p class="status"><?php esc_html_e( 'Migrating data. Please wait...' , 'thirstyaffiliates' ); ?></p>
1627
 
1628
  <?php } ?>
1629
 
1630
  <br /><br />
1631
+ <p class="desc"><?php echo isset( $option[ 'desc' ] ) ? wp_kses_post( $option[ 'desc' ] ) : ''; ?></p>
1632
 
1633
  </td>
1634
 
1650
 
1651
  ?>
1652
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1653
+ <th scope="row"><?php echo esc_html( $option[ 'title' ] ); ?></th>
1654
  <td>
1655
  <ul>
1656
  <li>
1657
+ <a href="https://www.facebook.com/thirstyaffiliates/"><?php esc_html_e( 'Like us on Facebook' , 'thirstyaffiliates' ); ?></a>
1658
  <iframe src="//www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.facebook.com%2Fthirstyaffiliates&amp;send=false&amp;layout=button_count&amp;width=450&amp;show_faces=false&amp;font=arial&amp;colorscheme=light&amp;action=like&amp;height=21" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:21px; vertical-align: bottom;" allowTransparency="true"></iframe>
1659
  </li>
1660
  <li>
1661
+ <a href="http://twitter.com/thirstyaff"><?php esc_html_e( 'Follow us on Twitter' , 'thirstyaffiliates' ); ?></a>
1662
  <a href="https://twitter.com/thirstyaff" class="twitter-follow-button" data-show-count="true" style="vertical-align: bottom;">Follow @thirstyaff</a><script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?"http":"https";if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document, "script", "twitter-wjs");</script>
1663
  </li>
1664
  <li>
1665
+ <a href="https://www.linkedin.com/company-beta/2928598/"><?php esc_html_e( 'Follow us on Linkedin' , 'thirstyaffiliates' ); ?></a>
1666
  </li>
1667
  <li>
1668
+ <a href="https://thirstyaffiliates.com/affiliates?utm_source=Free%20Plugin&utm_medium=Help&utm_campaign=Affiliates%20Link" target="_blank"><?php esc_html_e( 'Join Our Affiliate Program' , 'thirstyaffiliates' ); ?></a>
1669
+ <?php esc_html_e( '(up to 30% commisions)' , 'thirstyaffiliates' ); ?>
1670
  </li>
1671
  </ul>
1672
  </td>
1687
  $global_settings_string = $this->get_global_settings_string(); ?>
1688
 
1689
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1690
+ <th scope="row" class="title_desc"><?php echo esc_html( $option[ 'title' ] ); ?></th>
1691
+ <td class="forminp forminp-<?php echo esc_attr( $option[ 'type' ] ) ?>">
1692
  <textarea
1693
  name="<?php echo esc_attr( $option[ 'id' ] ); ?>"
1694
  id="<?php echo esc_attr( $option[ 'id' ] ); ?>"
1697
  placeholder="<?php echo isset( $option[ 'placeholder' ] ) ? esc_attr( $option[ 'placeholder' ] ) : ''; ?>"
1698
  autocomplete="off"
1699
  readonly
1700
+ rows="10"><?php echo esc_html( $global_settings_string ); ?></textarea>
1701
  <div class="controls">
1702
+ <a id="copy-settings-string" data-clipboard-target="#<?php echo esc_attr( $option[ 'id' ] ); ?>"><?php esc_html_e( 'Copy' , 'thirstyaffiliates' ); ?></a>
1703
  </div>
1704
  </td>
1705
  </tr>
1722
 
1723
  <tr valign="top" class="<?php echo esc_attr( $option[ 'id' ] ) . '-row'; ?>">
1724
  <th scope="row" class="title_desc">
1725
+ <label for="<?php echo esc_attr( $option[ 'id' ] ); ?>"><?php echo esc_html( $option[ 'title' ] ); ?></label>
1726
  </th>
1727
+ <td class="forminp forminp-<?php echo esc_attr( $option[ 'type' ] ) ?>">
1728
  <textarea
1729
  name="<?php echo esc_attr( $option[ 'id' ] ); ?>"
1730
  id="<?php echo esc_attr( $option[ 'id' ] ); ?>"
1733
  placeholder="<?php echo esc_attr( $option[ 'placeholder' ] ); ?>"
1734
  autocomplete="off"
1735
  rows="10"></textarea>
1736
+ <p class="desc"><?php echo isset( $option[ 'description' ] ) ? wp_kses_post( $option[ 'description' ] ) : ''; ?></p>
1737
  <div class="controls">
1738
  <span class="spinner"></span>
1739
+ <input type="button" id="import-setting-button" class="button button-primary" value="<?php esc_html_e( 'Import Settings' , 'thirstyaffiliates' ); ?>">
1740
  </div>
1741
  </td>
1742
  </tr>
1952
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Required parameter not passed' , 'thirstyaffiliates' ) );
1953
  else {
1954
 
1955
+ $result = $this->import_settings( filter_var( $_POST[ 'ta_settings_string' ] , FILTER_SANITIZE_STRING ) ); // phpcs:ignore WordPress.Security
1956
 
1957
  if ( is_wp_error( $result ) )
1958
  $response = array( 'status' => 'fail' , 'error_msg' => $result->get_error_message() );
2043
  public function restrict_module_settings() {
2044
 
2045
  $screen = get_current_screen();
2046
+ $tab = isset( $_GET[ 'tab' ] ) ? sanitize_text_field( wp_unslash( $_GET[ 'tab' ] ) ) : null;
2047
 
2048
  if ( $screen->id !== 'thirstylink_page_thirsty-settings' || ! $tab ) return;
2049
 
2068
  $default = in_array( $current_module , $modules ) ? $default_values[ $current_module ] : null;
2069
 
2070
  if ( ! is_null( $default ) && get_option( $current_module , $default ) !== 'yes' )
2071
+ wp_die( esc_html__( "Sorry, you are not allowed to access this page." , 'thirstyaffiliates' ) );
2072
 
2073
  }
2074
 
2148
 
2149
  <div class="ta-upgrade-header" id="ta-upgrade-header">
2150
  <span id="close-ta-upgrade-header">X</span>
2151
+ <?php _e( 'You\'re using ThirstyAffiliates Lite. To unlock more features, consider <a href="https://thirstyaffiliates.com/pricing?utm_source=plugin_admin&utm_medium=link&utm_campaign=in_plugin&utm_content=upgrade_header">upgrading to Pro.</a>' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
2152
  </div>
2153
 
2154
+ <div id="ta-admin-header"><img class="ta-logo" src="<?php echo esc_url( $this->_constants->IMAGES_ROOT_URL() . 'TA.svg' ); ?>" /></div>
2155
 
2156
  <script>
2157
  jQuery(document).ready(function($) {
2163
  type: 'POST',
2164
  data: {
2165
  action: 'ta_dismiss_upgrade_header',
2166
+ _ajax_nonce: "<?php echo wp_create_nonce( 'ta_dismiss_upgrade_header' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>"
2167
  },
2168
  })
2169
  .done(function() {
Models/Stats_Reporting.php CHANGED
@@ -263,8 +263,8 @@ class Stats_Reporting implements Model_Interface , Initiable_Interface , Activat
263
  if ( is_admin() ) return;
264
 
265
  $link_id = $thirstylink->get_id();
266
- $http_referer = isset( $_SERVER[ 'HTTP_REFERER' ] ) ? $_SERVER[ 'HTTP_REFERER' ] : '';
267
- $query_string = isset( $_SERVER[ 'QUERY_STRING' ] ) ? $_SERVER[ 'QUERY_STRING' ] : '';
268
  $cloaked_url = $query_string ? $thirstylink->get_prop( 'permalink' ) . '?' . $query_string : $thirstylink->get_prop( 'permalink' );
269
 
270
  $same_site = $http_referer && strrpos( 'x' . $http_referer , home_url() );
@@ -294,11 +294,11 @@ class Stats_Reporting implements Model_Interface , Initiable_Interface , Activat
294
  if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX )
295
  wp_die();
296
 
297
- $link_id = isset( $_REQUEST[ 'link_id' ] ) ? (int) sanitize_text_field( $_REQUEST[ 'link_id' ] ) : 0;
298
- $http_referer = isset( $_REQUEST[ 'page' ] ) ? esc_url_raw( $_REQUEST[ 'page' ] ) : '';
299
- $cloaked_url = isset( $_REQUEST[ 'href' ] ) ? esc_url_raw( $_REQUEST[ 'href' ] ) : '';
300
- $keyword = isset( $_REQUEST[ 'keyword' ] ) ? sanitize_text_field( $_REQUEST[ 'keyword' ] ) : '';
301
- $query_string = isset( $_REQUEST[ 'qs' ] ) ? sanitize_text_field( $_REQUEST[ 'qs' ] ) : '';
302
 
303
  if ( ! $link_id )
304
  $link_id = url_to_postid( $cloaked_url );
@@ -315,7 +315,7 @@ class Stats_Reporting implements Model_Interface , Initiable_Interface , Activat
315
 
316
  // print actual affiliate link redirect url for enhanced javascript redirect support.
317
  if ( get_option( 'ta_enable_javascript_frontend_redirect' ) == 'yes' )
318
- echo $redirect_url;
319
  }
320
 
321
  wp_die();
@@ -351,10 +351,14 @@ class Stats_Reporting implements Model_Interface , Initiable_Interface , Activat
351
  return array();
352
 
353
  $link_clicks_db = $wpdb->prefix . Plugin_Constants::LINK_CLICK_DB;
354
- $link_ids_str = implode( ', ' , $link_ids );
355
- $query = "SELECT * FROM $link_clicks_db WHERE date_clicked between '$start_date' and '$end_date' and link_id IN ( $link_ids_str )";
356
 
357
- return $wpdb->get_results( $query );
 
 
 
 
 
358
  }
359
 
360
  /**
@@ -375,15 +379,23 @@ class Stats_Reporting implements Model_Interface , Initiable_Interface , Activat
375
  $links_click_meta_db = $wpdb->prefix . Plugin_Constants::LINK_CLICK_META_DB;
376
 
377
  if ( $single ){
378
-
379
- $meta = $wpdb->get_row( "SELECT meta_value FROM $links_click_meta_db WHERE click_id = '$click_id' and meta_key = '$meta_key'" , ARRAY_A );
 
 
 
 
380
  return array_shift( $meta );
381
 
382
  } else {
383
 
384
  $meta = array();
385
- $raw_data = $wpdb->get_results( "SELECT meta_value FROM $links_click_meta_db WHERE click_id = '$click_id' and meta_key = '$meta_key'" , ARRAY_N );
386
-
 
 
 
 
387
  foreach ( $raw_data as $data )
388
  $meta[] = array_shift( $data );
389
 
@@ -409,14 +421,14 @@ class Stats_Reporting implements Model_Interface , Initiable_Interface , Activat
409
  else {
410
 
411
  // save timezone to use
412
- $timezone = isset( $_POST[ 'timezone' ] ) ? sanitize_text_field( $_POST[ 'timezone' ] ) : '';
413
  $this->set_browser_zone_str( $timezone );
414
 
415
- $link_id = isset( $_POST[ 'link_id' ] ) ? (int) sanitize_text_field( $_POST[ 'link_id' ] ) : 0;
416
  $thirstylink = new Affiliate_Link( $link_id );
417
- $range_txt = isset( $_POST[ 'range' ] ) ? sanitize_text_field( $_POST[ 'range' ] ) : '';
418
- $start_date = isset( $_POST[ 'start_date' ] ) ? sanitize_text_field( $_POST[ 'start_date' ] ) : '';
419
- $end_date = isset( $_POST[ 'end_date' ] ) ? sanitize_text_field( $_POST[ 'end_date' ] ) : '';
420
 
421
  if ( ! $thirstylink->get_id() )
422
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Selected affiliate link is invalid' , 'thirstyaffiliates' ) );
@@ -457,13 +469,13 @@ class Stats_Reporting implements Model_Interface , Initiable_Interface , Activat
457
  else {
458
 
459
  // save timezone to use
460
- $timezone = isset( $_POST[ 'timezone' ] ) ? sanitize_text_field( $_POST[ 'timezone' ] ) : '';
461
  $this->set_browser_zone_str( $timezone );
462
 
463
  $cpt_slug = Plugin_Constants::AFFILIATE_LINKS_CPT;
464
- $current_range = isset( $_POST[ 'range' ] ) ? sanitize_text_field( $_POST[ 'range' ] ) : '7day';
465
- $start_date = isset( $_POST[ 'start_date' ] ) ? sanitize_text_field( $_POST[ 'start_date' ] ) : '';
466
- $end_date = isset( $_POST[ 'end_date' ] ) ? sanitize_text_field( $_POST[ 'end_date' ] ) : '';
467
  $range = $this->get_report_range_details( $current_range , $start_date , $end_date );
468
 
469
  // get all published affiliate link ids
@@ -524,7 +536,7 @@ class Stats_Reporting implements Model_Interface , Initiable_Interface , Activat
524
  public function get_current_report( $tab = '' ) {
525
 
526
  if ( ! $tab )
527
- $tab = isset( $_GET[ 'tab' ] ) ? esc_attr( $_GET[ 'tab' ] ) : 'link_performance';
528
 
529
  // get all registered sections and fields
530
  $reports = $this->get_all_reports();
@@ -601,14 +613,14 @@ class Stats_Reporting implements Model_Interface , Initiable_Interface , Activat
601
  // skip if section data is empty
602
  if ( empty( $current_report ) ) return; ?>
603
 
604
- <div class="ta-settings ta-settings-<?php echo $current_report[ 'tab' ]; ?> wrap">
605
 
606
  <?php $this->render_reports_nav(); ?>
607
 
608
- <h1><?php echo $current_report[ 'title' ]; ?></h1>
609
- <p class="desc"><?php echo $current_report[ 'desc' ]; ?></p>
610
 
611
- <?php echo $report_content; ?>
612
  </div>
613
  <?php
614
  }
@@ -630,8 +642,8 @@ class Stats_Reporting implements Model_Interface , Initiable_Interface , Activat
630
  <nav class="thirsty-nav-tab">
631
  <?php foreach ( $reports as $report ) : ?>
632
 
633
- <a href="<?php echo $base_url . '&tab=' . $report[ 'tab' ]; ?>" class="tab <?php echo ( $current[ 'tab' ] === $report[ 'tab' ] ) ? 'tab-active' : ''; ?>">
634
- <?php echo $report[ 'name' ]; ?>
635
  </a>
636
 
637
  <?php endforeach; ?>
@@ -652,10 +664,10 @@ class Stats_Reporting implements Model_Interface , Initiable_Interface , Activat
652
  public function get_link_performance_report_content() {
653
 
654
  $cpt_slug = Plugin_Constants::AFFILIATE_LINKS_CPT;
655
- $current_range = isset( $_GET[ 'range' ] ) ? sanitize_text_field( $_GET[ 'range' ] ) : '7day';
656
- $start_date = isset( $_GET[ 'start_date' ] ) ? sanitize_text_field( $_GET[ 'start_date' ] ) : '';
657
- $end_date = isset( $_GET[ 'end_date' ] ) ? sanitize_text_field( $_GET[ 'end_date' ] ) : '';
658
- $link_id = isset( $_GET[ 'link_id' ] ) ? sanitize_text_field( $_GET[ 'link_id' ] ) : '';
659
  $range = $this->get_report_range_details( $current_range , $start_date , $end_date );
660
  $range_nav = apply_filters( 'ta_link_performances_report_nav' , array(
661
  'year' => __( 'Year' , 'thirstyaffiliates' ),
@@ -951,8 +963,11 @@ class Stats_Reporting implements Model_Interface , Initiable_Interface , Activat
951
  $clicks_meta_db = $wpdb->prefix . Plugin_Constants::LINK_CLICK_META_DB;
952
 
953
  // get click ids based on set range.
954
- $query = "SELECT id FROM $clicks_db WHERE date_clicked < DATE_ADD( NOW() , INTERVAL -" . $trim_point . " MONTH )";
955
- $click_ids = $wpdb->get_col( $query );
 
 
 
956
 
957
  // Proceed on deleting data when $click_ids are present
958
  if ( is_array( $click_ids ) && ! empty( $click_ids ) ) {
@@ -960,8 +975,8 @@ class Stats_Reporting implements Model_Interface , Initiable_Interface , Activat
960
  $click_ids_string = implode( ',', $click_ids );
961
 
962
  // delete click data
963
- $wpdb->query( "DELETE FROM $clicks_meta_db WHERE click_id IN ( $click_ids_string )" );
964
- $wpdb->query( "DELETE FROM $clicks_db WHERE id IN ( $click_ids_string )" );
965
  }
966
  }
967
 
@@ -1007,7 +1022,11 @@ class Stats_Reporting implements Model_Interface , Initiable_Interface , Activat
1007
 
1008
  $link_click_db = $wpdb->prefix . Plugin_Constants::LINK_CLICK_DB;
1009
  $link_click_meta_db = $wpdb->prefix . Plugin_Constants::LINK_CLICK_META_DB;
1010
- $click_ids = $wpdb->get_col( "SELECT id FROM $link_click_db WHERE link_id = $link_id" );
 
 
 
 
1011
 
1012
  if ( ! is_array( $click_ids ) || empty( $click_ids ) )
1013
  return;
@@ -1015,10 +1034,10 @@ class Stats_Reporting implements Model_Interface , Initiable_Interface , Activat
1015
  $click_ids_str = implode( ',' , $click_ids );
1016
 
1017
  // delete click meta records.
1018
- $wpdb->query( "DELETE FROM $link_click_meta_db WHERE click_id IN ( $click_ids_str )" );
1019
 
1020
  // delete click records.
1021
- $wpdb->query( "DELETE FROM $link_click_db WHERE id IN ( $click_ids_str )" );
1022
  }
1023
 
1024
  /**
263
  if ( is_admin() ) return;
264
 
265
  $link_id = $thirstylink->get_id();
266
+ $http_referer = isset( $_SERVER[ 'HTTP_REFERER' ] ) ? sanitize_text_field( wp_unslash( $_SERVER[ 'HTTP_REFERER' ] ) ) : '';
267
+ $query_string = isset( $_SERVER[ 'QUERY_STRING' ] ) ? sanitize_text_field( wp_unslash( $_SERVER[ 'QUERY_STRING' ] ) ) : '';
268
  $cloaked_url = $query_string ? $thirstylink->get_prop( 'permalink' ) . '?' . $query_string : $thirstylink->get_prop( 'permalink' );
269
 
270
  $same_site = $http_referer && strrpos( 'x' . $http_referer , home_url() );
294
  if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX )
295
  wp_die();
296
 
297
+ $link_id = isset( $_REQUEST[ 'link_id' ] ) ? (int) sanitize_text_field( wp_unslash( $_REQUEST[ 'link_id' ] ) ) : 0;
298
+ $http_referer = isset( $_REQUEST[ 'page' ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ 'page' ] ) ) : '';
299
+ $cloaked_url = isset( $_REQUEST[ 'href' ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ 'href' ] ) ) : '';
300
+ $keyword = isset( $_REQUEST[ 'keyword' ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ 'keyword' ] ) ) : '';
301
+ $query_string = isset( $_REQUEST[ 'qs' ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ 'qs' ] ) ) : '';
302
 
303
  if ( ! $link_id )
304
  $link_id = url_to_postid( $cloaked_url );
315
 
316
  // print actual affiliate link redirect url for enhanced javascript redirect support.
317
  if ( get_option( 'ta_enable_javascript_frontend_redirect' ) == 'yes' )
318
+ echo esc_url_raw( $redirect_url );
319
  }
320
 
321
  wp_die();
351
  return array();
352
 
353
  $link_clicks_db = $wpdb->prefix . Plugin_Constants::LINK_CLICK_DB;
354
+ $link_ids_str = implode( ',', array_map('intval', $link_ids) );
 
355
 
356
+ return $wpdb->get_results( $wpdb->prepare(
357
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
358
+ "SELECT * FROM $link_clicks_db WHERE link_id IN ({$link_ids_str}) AND date_clicked between %s and %s",
359
+ $start_date,
360
+ $end_date
361
+ ) );
362
  }
363
 
364
  /**
379
  $links_click_meta_db = $wpdb->prefix . Plugin_Constants::LINK_CLICK_META_DB;
380
 
381
  if ( $single ){
382
+ $meta = $wpdb->get_row( $wpdb->prepare(
383
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
384
+ "SELECT meta_value FROM $links_click_meta_db WHERE click_id = %d and meta_key = %s",
385
+ $click_id,
386
+ $meta_key
387
+ ), ARRAY_A );
388
  return array_shift( $meta );
389
 
390
  } else {
391
 
392
  $meta = array();
393
+ $raw_data = $wpdb->get_results( $wpdb->prepare(
394
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
395
+ "SELECT meta_value FROM $links_click_meta_db WHERE click_id = %d and meta_key = %s",
396
+ $click_id,
397
+ $meta_key
398
+ ), ARRAY_N );
399
  foreach ( $raw_data as $data )
400
  $meta[] = array_shift( $data );
401
 
421
  else {
422
 
423
  // save timezone to use
424
+ $timezone = isset( $_POST[ 'timezone' ] ) ? sanitize_text_field( wp_unslash( $_POST[ 'timezone' ] ) ) : '';
425
  $this->set_browser_zone_str( $timezone );
426
 
427
+ $link_id = isset( $_POST[ 'link_id' ] ) ? (int) sanitize_text_field( wp_unslash( $_POST[ 'link_id' ] ) ) : 0;
428
  $thirstylink = new Affiliate_Link( $link_id );
429
+ $range_txt = isset( $_POST[ 'range' ] ) ? sanitize_text_field( wp_unslash( $_POST[ 'range' ] ) ) : '';
430
+ $start_date = isset( $_POST[ 'start_date' ] ) ? sanitize_text_field( wp_unslash( $_POST[ 'start_date' ] ) ) : '';
431
+ $end_date = isset( $_POST[ 'end_date' ] ) ? sanitize_text_field( wp_unslash( $_POST[ 'end_date' ] ) ) : '';
432
 
433
  if ( ! $thirstylink->get_id() )
434
  $response = array( 'status' => 'fail' , 'error_msg' => __( 'Selected affiliate link is invalid' , 'thirstyaffiliates' ) );
469
  else {
470
 
471
  // save timezone to use
472
+ $timezone = isset( $_POST[ 'timezone' ] ) ? sanitize_text_field( wp_unslash( $_POST[ 'timezone' ] ) ) : '';
473
  $this->set_browser_zone_str( $timezone );
474
 
475
  $cpt_slug = Plugin_Constants::AFFILIATE_LINKS_CPT;
476
+ $current_range = isset( $_POST[ 'range' ] ) ? sanitize_text_field( wp_unslash( $_POST[ 'range' ] ) ) : '7day';
477
+ $start_date = isset( $_POST[ 'start_date' ] ) ? sanitize_text_field( wp_unslash( $_POST[ 'start_date' ] ) ) : '';
478
+ $end_date = isset( $_POST[ 'end_date' ] ) ? sanitize_text_field( wp_unslash( $_POST[ 'end_date' ] ) ) : '';
479
  $range = $this->get_report_range_details( $current_range , $start_date , $end_date );
480
 
481
  // get all published affiliate link ids
536
  public function get_current_report( $tab = '' ) {
537
 
538
  if ( ! $tab )
539
+ $tab = isset( $_GET[ 'tab' ] ) ? sanitize_text_field( wp_unslash( $_GET[ 'tab' ] ) ) : 'link_performance';
540
 
541
  // get all registered sections and fields
542
  $reports = $this->get_all_reports();
613
  // skip if section data is empty
614
  if ( empty( $current_report ) ) return; ?>
615
 
616
+ <div class="ta-settings ta-settings-<?php echo esc_attr( $current_report[ 'tab' ] ); ?> wrap">
617
 
618
  <?php $this->render_reports_nav(); ?>
619
 
620
+ <h1><?php echo esc_html( $current_report[ 'title' ] ); ?></h1>
621
+ <p class="desc"><?php echo wp_kses_post( $current_report[ 'desc' ] ); ?></p>
622
 
623
+ <?php echo $report_content; // phpcs:ignore WordPress.Security.EscapeOutput ?>
624
  </div>
625
  <?php
626
  }
642
  <nav class="thirsty-nav-tab">
643
  <?php foreach ( $reports as $report ) : ?>
644
 
645
+ <a href="<?php echo esc_url( $base_url . '&tab=' . esc_attr( $report[ 'tab' ] ) ); ?>" class="tab <?php echo ( $current[ 'tab' ] === $report[ 'tab' ] ) ? 'tab-active' : ''; ?>">
646
+ <?php echo esc_html( $report[ 'name' ] ); ?>
647
  </a>
648
 
649
  <?php endforeach; ?>
664
  public function get_link_performance_report_content() {
665
 
666
  $cpt_slug = Plugin_Constants::AFFILIATE_LINKS_CPT;
667
+ $current_range = isset( $_GET[ 'range' ] ) ? sanitize_text_field( wp_unslash( $_GET[ 'range' ] ) ) : '7day';
668
+ $start_date = isset( $_GET[ 'start_date' ] ) ? sanitize_text_field( wp_unslash( $_GET[ 'start_date' ] ) ) : '';
669
+ $end_date = isset( $_GET[ 'end_date' ] ) ? sanitize_text_field( wp_unslash( $_GET[ 'end_date' ] ) ) : '';
670
+ $link_id = isset( $_GET[ 'link_id' ] ) ? sanitize_text_field( wp_unslash( $_GET[ 'link_id' ] ) ) : '';
671
  $range = $this->get_report_range_details( $current_range , $start_date , $end_date );
672
  $range_nav = apply_filters( 'ta_link_performances_report_nav' , array(
673
  'year' => __( 'Year' , 'thirstyaffiliates' ),
963
  $clicks_meta_db = $wpdb->prefix . Plugin_Constants::LINK_CLICK_META_DB;
964
 
965
  // get click ids based on set range.
966
+ $click_ids = $wpdb->get_col( $wpdb->prepare(
967
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
968
+ "SELECT id FROM $clicks_db WHERE date_clicked < DATE_ADD( NOW() , INTERVAL - %d MONTH )",
969
+ $trim_point
970
+ ) );
971
 
972
  // Proceed on deleting data when $click_ids are present
973
  if ( is_array( $click_ids ) && ! empty( $click_ids ) ) {
975
  $click_ids_string = implode( ',', $click_ids );
976
 
977
  // delete click data
978
+ $wpdb->query( "DELETE FROM $clicks_meta_db WHERE click_id IN ( $click_ids_string )" );// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
979
+ $wpdb->query( "DELETE FROM $clicks_db WHERE id IN ( $click_ids_string )" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
980
  }
981
  }
982
 
1022
 
1023
  $link_click_db = $wpdb->prefix . Plugin_Constants::LINK_CLICK_DB;
1024
  $link_click_meta_db = $wpdb->prefix . Plugin_Constants::LINK_CLICK_META_DB;
1025
+ $click_ids = $wpdb->get_col( $wpdb->prepare(
1026
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
1027
+ "SELECT id FROM $link_click_db WHERE link_id = %d",
1028
+ $link_id
1029
+ ));
1030
 
1031
  if ( ! is_array( $click_ids ) || empty( $click_ids ) )
1032
  return;
1034
  $click_ids_str = implode( ',' , $click_ids );
1035
 
1036
  // delete click meta records.
1037
+ $wpdb->query( "DELETE FROM $link_click_meta_db WHERE click_id IN ( $click_ids_str )" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
1038
 
1039
  // delete click records.
1040
+ $wpdb->query( "DELETE FROM $link_click_db WHERE id IN ( $click_ids_str )" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
1041
  }
1042
 
1043
  /**
css/admin/admin_notifications.css ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #thirstyaff-notifications {
2
+ position: fixed;
3
+ min-height: 48px;
4
+ margin: 0 0 14px 0;
5
+ top: 0;
6
+ width: 100%;
7
+ max-width: 440px;
8
+ max-height: 100vh;
9
+ overflow-y: scroll;
10
+ background: #FFFFFF;
11
+ box-shadow: 0px 5px 15px #0000000D;
12
+ transform: translate3d(100%, 0, 0);
13
+ transition: transform .3s ease-in-out;
14
+ z-index: -9;
15
+ visibility: hidden;
16
+ right: -9999999999px;
17
+ }
18
+
19
+ #thirstyaff-notifications.visible {
20
+ transform: translate3d(0, 0, 0);
21
+ z-index: 999999;
22
+ visibility: visible;
23
+ right: 0;
24
+ }
25
+
26
+ .admin-bar #thirstyaff-notifications {
27
+ top: 32px;
28
+ max-height: calc( 100vh - 32px );
29
+ }
30
+
31
+ #thirstyaff-notifications * {
32
+ box-sizing: border-box;
33
+ }
34
+
35
+ #thirstyaff-notifications .thirstyaff-notifications-top-title {
36
+ background-color: #2679c1;
37
+ display: flex;
38
+ align-items: center;
39
+ padding: 0 16px;
40
+ }
41
+
42
+ #thirstyaff-notifications .thirstyaff-notifications-top-title h3 {
43
+ color: #fff;
44
+ }
45
+
46
+ #thirstyaff-notifications .thirstyaff-notifications-top-title > div {
47
+ flex-basis: 100%;
48
+ display: flex;
49
+ align-items: center;
50
+ }
51
+
52
+ #thirstyaff-notifications .thirstyaff-notifications-top-title svg {
53
+ margin-right: 10px;
54
+ margin-top: 5px;
55
+ }
56
+
57
+ #thirstyaff-notifications .thirstyaff-notifications-top-title .actions {
58
+ display: flex;
59
+ justify-content: flex-end;
60
+ }
61
+
62
+ #thirstyaff-notifications .thirstyaff-notifications-top-title .actions a {
63
+ color: #fff;
64
+ margin-right: 10px;
65
+ font-size: 14px;
66
+ text-decoration: underline;
67
+ }
68
+
69
+ #thirstyaff-notifications .thirstyaff-notifications-top-title .actions a.close {
70
+ text-decoration: none;
71
+ margin-right: 0;
72
+ }
73
+
74
+ #thirstyaff-notifications .thirstyaff-notifications-top-title .actions a.close svg {
75
+ margin-right: 0;
76
+ }
77
+
78
+ #thirstyaff-notifications .thirstyaff-notification-icon-title {
79
+ display: flex;
80
+ align-items: center;
81
+ }
82
+
83
+ #thirstyaff-notifications .thirstyaff-notification-icon-title img {
84
+ margin-right: 10px;
85
+ max-width: 32px;
86
+ }
87
+
88
+ #thirstyaff-notifications .thirstyaff-notification-icon-title time {
89
+ margin-left: auto;
90
+ font-size: 13px;
91
+ color: #7f899f;
92
+ min-width: 100px;
93
+ text-align: right;
94
+ }
95
+
96
+ #thirstyaff-notifications .thirstyaff-notifications-header {
97
+ display: flex;
98
+ align-items: center;
99
+ justify-content: space-between;
100
+ padding: 8px 16px;
101
+ border-bottom: 1px solid rgba(204, 208, 212, 0.5);
102
+ }
103
+
104
+ #thirstyaff-notifications .dismiss-all {
105
+ text-decoration: underline;
106
+ color: #99a1b3;
107
+ cursor: pointer;
108
+ background: none;
109
+ border: none;
110
+ padding: 0;
111
+ }
112
+
113
+ #thirstyaff-notifications .thirstyaff-notifications-header-bell {
114
+ display: flex;
115
+ align-items: center;
116
+ }
117
+
118
+ #thirstyaff-notifications .thirstyaff-notifications-header .thirstyaff-notifications-bell {
119
+ position: relative;
120
+ top: 2px;
121
+ margin-right: 10px;
122
+ }
123
+
124
+ #thirstyaff-notifications .thirstyaff-notifications-header .thirstyaff-notifications-bell svg {
125
+ max-width: 30px;
126
+ }
127
+
128
+ #thirstyaff-notifications .thirstyaff-notifications-header .thirstyaff-notifications-title {
129
+ font-style: normal;
130
+ font-weight: 500;
131
+ font-size: 14px;
132
+ line-height: 17px;
133
+ color: #23282D;
134
+ }
135
+
136
+ .thirstyaff-notifications-count {
137
+ display: flex;
138
+ align-items: center;
139
+ justify-content: center;
140
+ position: absolute;
141
+ top: -5px;
142
+ right: -5px;
143
+ background-color: #eb5757;
144
+ color: #fff;
145
+ width: 20px;
146
+ height: 20px;
147
+ border-radius: 50%;
148
+ font-size: 10px;
149
+ }
150
+
151
+ #thirstyaff-notifications .dismissed-messages,
152
+ #thirstyaff-notifications #viewActive {
153
+ display: none;
154
+ }
155
+
156
+ #thirstyaff-notifications .dismissed-messages .thirstyaff-notice-dismiss {
157
+ display: none;
158
+ }
159
+
160
+ #thirstyaff-notifications .thirstyaff-notifications-header.single-digit .thirstyaff-notifications-count {
161
+ font-size: 12px;
162
+ }
163
+
164
+ #thirstyaff-notifications .thirstyaff-notifications-body {
165
+ position: relative;
166
+ padding: 16px;
167
+ }
168
+
169
+ #thirstyaff-notifications .thirstyaff-notifications-messages {
170
+
171
+ }
172
+
173
+ #thirstyaff-notifications .thirstyaff-notifications-messages .thirstyaff-notifications-message {
174
+ margin-bottom: 30px;
175
+ padding-bottom: 30px;
176
+ position: relative;
177
+ border-bottom: 1px solid rgba(204, 208, 212, 0.5);
178
+ }
179
+
180
+ #thirstyaff-notifications .thirstyaff-notifications-messages .active-messages .thirstyaff-notifications-message:last-of-type,
181
+ #thirstyaff-notifications .thirstyaff-notifications-messages .dismissed-messages .thirstyaff-notifications-message:last-of-type {
182
+ border-bottom: none;
183
+ margin-bottom: 0;
184
+ padding-bottom: 0;
185
+ }
186
+
187
+ #thirstyaff-notifications .thirstyaff-notifications-messages .thirstyaff-notifications-title {
188
+ font-weight: bold;
189
+ font-size: 17px;
190
+ line-height: 17px;
191
+ margin: 0;
192
+ color: #444;
193
+ }
194
+
195
+ #thirstyaff-notifications .thirstyaff-notifications-messages .thirstyaff-notifications-content {
196
+ font-weight: normal;
197
+ font-size: 14px;
198
+ line-height: 18px;
199
+ margin: 8px 0 41px 0;
200
+ color: #777777;
201
+ }
202
+
203
+ #thirstyaff-notifications .thirstyaff-notifications-messages .thirstyaff-notifications-content img {
204
+ max-width: 100%;
205
+ height: auto;
206
+ }
207
+
208
+ #thirstyaff-notifications .thirstyaff-notifications-messages .thirstyaff-notifications-buttons {
209
+ margin: -30px 80px 0 0;
210
+ display: flex;
211
+ align-items: center;
212
+ }
213
+
214
+ #thirstyaff-notifications .thirstyaff-notifications-messages .thirstyaff-notifications-buttons a {
215
+ margin: 0 10px 0 0;
216
+ min-height: unset;
217
+ }
218
+
219
+ .thirstyaff-notifications-buttons button.thirstyaff-notice-dismiss {
220
+ font-size: 13px;
221
+ color: #7f899f;
222
+ background: none;
223
+ padding: 0;
224
+ border: 0;
225
+ }
226
+
227
+ #thirstyaff-notifications .thirstyaff-notifications-messages .thirstyaff-notifications-buttons button.thirstyaff-notice-dismiss:hover {
228
+ cursor: pointer;
229
+ }
230
+
231
+ #thirstyaff-notifications .thirstyaff-notifications-messages .thirstyaff-notifications-buttons button.thirstyaff-notice-dismiss[disabled] {
232
+ cursor: not-allowed;
233
+ }
234
+
235
+ @media screen and (max-width: 768px) {
236
+ #thirstyaff-notifications .thirstyaff-notifications-messages {
237
+ padding: 15px 50px 20px 16px;
238
+ }
239
+ #thirstyaff-notifications .thirstyaff-notifications-messages .thirstyaff-notifications-message .thirstyaff-notifications-title {
240
+ margin: 0 30px 0 0;
241
+ line-height: 22px;
242
+ }
243
+ #thirstyaff-notifications .thirstyaff-notifications-messages .thirstyaff-notifications-message .thirstyaff-notifications-content {
244
+ font-size: 16px;
245
+ line-height: 22px;
246
+ }
247
+ #thirstyaff-notifications .thirstyaff-notifications-messages .thirstyaff-notifications-message .thirstyaff-notifications-buttons {
248
+ margin: -30px 80px 0 0;
249
+ }
250
+ #thirstyaff-notifications .thirstyaff-notifications-messages .thirstyaff-notifications-message .thirstyaff-notifications-buttons a {
251
+ margin: 0;
252
+ display: table;
253
+ }
254
+ #thirstyaff-notifications .thirstyaff-notifications-messages .thirstyaff-notifications-message .thirstyaff-notifications-buttons .button-secondary {
255
+ margin-top: 6px;
256
+ }
257
+ }
css/lib/jquery-ui/images/ui-bg_flat_75_ffffff_40x100.png ADDED
Binary file
css/lib/jquery-ui/images/ui-bg_glass_55_fbf9ee_1x400.png ADDED
Binary file
css/lib/jquery-ui/images/ui-bg_glass_65_ffffff_1x400.png ADDED
Binary file
css/lib/jquery-ui/images/ui-bg_glass_75_dadada_1x400.png ADDED
Binary file
css/lib/jquery-ui/images/ui-bg_glass_75_e6e6e6_1x400.png ADDED
Binary file
css/lib/jquery-ui/images/ui-bg_glass_95_fef1ec_1x400.png ADDED
Binary file
css/lib/jquery-ui/images/ui-bg_highlight-soft_75_cccccc_1x100.png ADDED
Binary file
css/lib/jquery-ui/images/ui-icons_222222_256x240.png ADDED
Binary file
css/lib/jquery-ui/images/ui-icons_2e83ff_256x240.png ADDED
Binary file
css/lib/jquery-ui/images/ui-icons_454545_256x240.png ADDED
Binary file
css/lib/jquery-ui/images/ui-icons_888888_256x240.png ADDED
Binary file
css/lib/jquery-ui/images/ui-icons_cd0a0a_256x240.png ADDED
Binary file
css/lib/jquery-ui/jquery-ui.min.css ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ /*! jQuery UI - v1.11.4 - 2015-03-11
2
+ * http://jqueryui.com
3
+ * Includes: core.css, accordion.css, autocomplete.css, button.css, datepicker.css, dialog.css, draggable.css, menu.css, progressbar.css, resizable.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css
4
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
5
+ * Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
6
+
7
+ .ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;min-height:0;font-size:100%}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-dialog{overflow:hidden;position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:none}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{position:relative;margin:0;padding:3px 1em 3px .4em;cursor:pointer;min-height:0;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-button{display:inline-block;overflow:hidden;position:relative;text-decoration:none;cursor:pointer}.ui-selectmenu-button span.ui-icon{right:0.5em;left:auto;margin-top:-8px;position:absolute;top:50%}.ui-selectmenu-button span.ui-selectmenu-text{text-align:left;padding:0.4em 2.1em 0.4em 1em;display:block;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #aaa;background:#fff url("images/ui-bg_flat_75_ffffff_40x100.png") 50% 50% repeat-x;color:#222}.ui-widget-content a{color:#222}.ui-widget-header{border:1px solid #aaa;background:#ccc url("images/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x;color:#222;font-weight:bold}.ui-widget-header a{color:#222}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #d3d3d3;background:#e6e6e6 url("images/ui-bg_glass_75_e6e6e6_1x400.png") 50% 50% repeat-x;font-weight:normal;color:#555}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#555;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #999;background:#dadada url("images/ui-bg_glass_75_dadada_1x400.png") 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#212121;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #aaa;background:#fff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#212121;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee url("images/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_222222_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_222222_256x240.png")}.ui-state-default .ui-icon{background-image:url("images/ui-icons_888888_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url("images/ui-icons_454545_256x240.png")}.ui-state-active .ui-icon{background-image:url("images/ui-icons_454545_256x240.png")}.ui-state-highlight .ui-icon{background-image:url("images/ui-icons_2e83ff_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_cd0a0a_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#aaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30);border-radius:8px}
js/app/admin_notifications.js ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function($) {
2
+
3
+ $('#thirstyaffAdminNotifications').on('click', function(e) {
4
+ e.preventDefault();
5
+ $('#thirstyaff-notifications').toggleClass('visible');
6
+ $('#caseproofFlyoutButton').trigger('click');
7
+ });
8
+ $('#thirstyaffNotificationsClose').on('click', function(e) {
9
+ e.preventDefault();
10
+ $('#thirstyaff-notifications').removeClass('visible');
11
+ });
12
+
13
+ var viewDismissed = $('#viewDismissed');
14
+ var viewActive = $('#viewActive');
15
+ var dismissedMessages = $('.dismissed-messages');
16
+ var activeMessages = $('.active-messages');
17
+
18
+ viewDismissed.on('click', function(event) {
19
+ event.preventDefault();
20
+ dismissedMessages.show();
21
+ activeMessages.hide();
22
+ viewActive.show();
23
+ viewDismissed.hide();
24
+ });
25
+ viewActive.on('click', function(event) {
26
+ event.preventDefault();
27
+ dismissedMessages.hide();
28
+ activeMessages.show();
29
+ viewActive.hide();
30
+ viewDismissed.show();
31
+ });
32
+
33
+ $('body').on('click', '.thirstyaff-notice-dismiss', function(event) {
34
+
35
+ event.preventDefault();
36
+
37
+ var $this = $(this);
38
+ var messageId = $this.data('message-id');
39
+ var message = $('#thirstyaff-notifications-message-' + messageId);
40
+ var countEl = $('#thirstyaffNotificationsCount');
41
+ var mainCountEl = $('#thirstyaffAdminNotificationsBadge');
42
+ var trayCountEl = $('#thirstyaffNotificationsCountTray');
43
+ var count = parseInt(mainCountEl.html());
44
+ var adminMenuCount = $('#thirstyaffAdminMenuUnreadCount');
45
+
46
+ var data = {
47
+ action: 'thirstyaff_notification_dismiss',
48
+ nonce: ThirstyAffAdminNotifications.nonce,
49
+ id: messageId,
50
+ };
51
+
52
+ $this.prop('disabled', 'disabled');
53
+ message.fadeOut();
54
+
55
+ $.post( ThirstyAffAdminNotifications.ajax_url, data, function( res ) {
56
+
57
+ if ( ! res.success ) {
58
+ console.debug( res );
59
+ } else {
60
+ message.prependTo(dismissedMessages);
61
+ message.show();
62
+ count--;
63
+
64
+ if ( count < 0 ) {
65
+ count = 0;
66
+ countEl.hide();
67
+ mainCountEl.hide();
68
+ trayCountEl.hide();
69
+ adminMenuCount.closest('.awaiting-mod').remove();
70
+ } else if ( 0 == count ) {
71
+ countEl.hide();
72
+ mainCountEl.hide();
73
+ trayCountEl.hide();
74
+ $('.thirstyaff-notifications-none').show();
75
+ $('.dismiss-all').hide();
76
+ adminMenuCount.closest('.awaiting-mod').remove();
77
+ } else if ( count < 10 ) {
78
+ countEl.addClass('single-digit');
79
+ countEl.html('(' + count + ')');
80
+ mainCountEl.html(count);
81
+ trayCountEl.html(count);
82
+ adminMenuCount.html(count);
83
+ } else {
84
+ countEl.html('(' + count + ')');
85
+ mainCountEl.html(count);
86
+ trayCountEl.html(count);
87
+ adminMenuCount.html(count);
88
+ }
89
+ }
90
+
91
+ } ).fail( function( xhr, textStatus, e ) {
92
+
93
+ console.debug( xhr.responseText );
94
+ message.show('Message could not be dismissed.');
95
+ } );
96
+ });
97
+
98
+ $('body').on('click', '.dismiss-all' ,function(event) {
99
+
100
+ event.preventDefault();
101
+
102
+ var $this = $(this);
103
+ var countEl = $('#thirstyaffNotificationsCount');
104
+ var count = parseInt(countEl.html());
105
+ var mainCountEl = $('#thirstyaffAdminNotificationsBadge');
106
+ var adminMenuCount = $('#thirstyaffAdminMenuUnreadCount');
107
+ var trayCountEl = $('#thirstyaffNotificationsCountTray');
108
+
109
+ var data = {
110
+ action: 'thirstyaff_notification_dismiss',
111
+ nonce: ThirstyAffAdminNotifications.nonce,
112
+ id: 'all',
113
+ };
114
+
115
+ $this.prop('disabled', 'disabled');
116
+
117
+ $.post( ThirstyAffAdminNotifications.ajax_url, data, function( res ) {
118
+
119
+ if ( ! res.success ) {
120
+ console.debug( res );
121
+ } else {
122
+ countEl.hide();
123
+ mainCountEl.hide();
124
+ trayCountEl.hide();
125
+ adminMenuCount.closest('.awaiting-mod').remove();
126
+ $('.thirstyaff-notifications-none').show();
127
+ $('.dismiss-all').hide();
128
+
129
+ $.each($('.active-messages .thirstyaff-notifications-message'), function(i, el) {
130
+ $(el).appendTo(dismissedMessages);
131
+ });
132
+ }
133
+
134
+ } ).fail( function( xhr, textStatus, e ) {
135
+
136
+ console.debug( xhr.responseText );
137
+ message.show('Messages could not be dismissed.');
138
+ } );
139
+ });
140
+ });
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: affiliate, link, affiliate link management, link cloaker, link redirect, s
5
  Requires at least: 5.0
6
  Requires PHP: 5.6
7
  Tested up to: 5.9
8
- Stable tag: 3.10.5
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -159,6 +159,9 @@ See our [Knowledge Base](https://thirstyaffiliates.com/knowledge-base/?utm_sourc
159
 
160
  == Changelog ==
161
 
 
 
 
162
  = 3.10.5 =
163
  * Bug Fix: Security fixes
164
 
5
  Requires at least: 5.0
6
  Requires PHP: 5.6
7
  Tested up to: 5.9
8
+ Stable tag: 3.10.6
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
159
 
160
  == Changelog ==
161
 
162
+ = 3.10.6 =
163
+ * Bug Fix: Security fixes
164
+
165
  = 3.10.5 =
166
  * Bug Fix: Security fixes
167
 
thirstyaffiliates.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: ThirstyAffiliates
4
  * Plugin URI: http://thirstyaffiliates.com/
5
  * Description: ThirstyAffiliates is a revolution in affiliate link management. Collect, collate and store your affiliate links for use in your posts and pages.
6
- * Version: 3.10.5
7
  * Author: Caseproof
8
  * Author URI: https://caseproof.com/
9
  * Requires at least: 5.0
@@ -41,6 +41,7 @@ use ThirstyAffiliates\Models\Link_Picker;
41
  use ThirstyAffiliates\Models\Shortcodes;
42
  use ThirstyAffiliates\Models\Guided_Tour;
43
  use ThirstyAffiliates\Models\REST_API;
 
44
 
45
  /**
46
  * Register plugin autoloader.
@@ -231,8 +232,8 @@ class ThirstyAffiliates extends Abstract_Main_Plugin_Class {
231
 
232
  <div class="error">
233
  <p>
234
- <?php _e( '<b>ThirstyAffiliates</b> plugin missing dependency.<br/>' , 'thirstyaffiliates' ); ?>
235
- <?php echo $admin_notice_msg; ?>
236
  </p>
237
  </div>
238
 
@@ -322,6 +323,7 @@ class ThirstyAffiliates extends Abstract_Main_Plugin_Class {
322
  $rest_api = REST_API::get_instance( $this , $plugin_constants , $helper_functions );
323
  $rewrites = Rewrites_Redirection::get_instance( $this , $plugin_constants , $helper_functions );
324
  $link_picker = Link_Picker::get_instance( $this , $plugin_constants , $helper_functions );
 
325
 
326
  $activatables = array( $settings , $stats , $migration , $marketing , $guided_tour );
327
  $deactivatables = array( $rewrites );
@@ -336,7 +338,8 @@ class ThirstyAffiliates extends Abstract_Main_Plugin_Class {
336
  $migration,
337
  $marketing,
338
  $guided_tour,
339
- $rest_api
 
340
  );
341
 
342
  Bootstrap::get_instance( $this , $plugin_constants , $helper_functions , $activatables , $initiables , $deactivatables );
3
  * Plugin Name: ThirstyAffiliates
4
  * Plugin URI: http://thirstyaffiliates.com/
5
  * Description: ThirstyAffiliates is a revolution in affiliate link management. Collect, collate and store your affiliate links for use in your posts and pages.
6
+ * Version: 3.10.6
7
  * Author: Caseproof
8
  * Author URI: https://caseproof.com/
9
  * Requires at least: 5.0
41
  use ThirstyAffiliates\Models\Shortcodes;
42
  use ThirstyAffiliates\Models\Guided_Tour;
43
  use ThirstyAffiliates\Models\REST_API;
44
+ use ThirstyAffiliates\Models\Notifications;
45
 
46
  /**
47
  * Register plugin autoloader.
232
 
233
  <div class="error">
234
  <p>
235
+ <?php esc_html_e( '<b>ThirstyAffiliates</b> plugin missing dependency.<br/>' , 'thirstyaffiliates' ); ?>
236
+ <?php echo $admin_notice_msg; // phpcs:ignore WordPress.Security.EscapeOutput ?>
237
  </p>
238
  </div>
239
 
323
  $rest_api = REST_API::get_instance( $this , $plugin_constants , $helper_functions );
324
  $rewrites = Rewrites_Redirection::get_instance( $this , $plugin_constants , $helper_functions );
325
  $link_picker = Link_Picker::get_instance( $this , $plugin_constants , $helper_functions );
326
+ $notifications = Notifications::get_instance( $this , $plugin_constants , $helper_functions );
327
 
328
  $activatables = array( $settings , $stats , $migration , $marketing , $guided_tour );
329
  $deactivatables = array( $rewrites );
338
  $migration,
339
  $marketing,
340
  $guided_tour,
341
+ $rest_api,
342
+ $notifications
343
  );
344
 
345
  Bootstrap::get_instance( $this , $plugin_constants , $helper_functions , $activatables , $initiables , $deactivatables );
views/cpt/view-attach-images-metabox-external-image.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
 
3
  <div class="thirsty-attached-image external-image">
4
- <span class="thirsty-remove-img remove-external" title="<?php esc_attr_e( 'Remove This Image' , 'thirstyaffiliates' ); ?>" id="<?php echo md5( $img_url ); ?>">&times;</span>
5
  <a class="thirsty-img thickbox" href="<?php echo esc_url( $img_url ); ?>" rel="gallery-linkimgs" title="<?php esc_attr_e( 'external image' , 'thirstyaffiliates' ); ?>">
6
  <img src="<?php echo esc_url( $img_url ); ?>" width="100" height="100">
7
  </a>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
 
3
  <div class="thirsty-attached-image external-image">
4
+ <span class="thirsty-remove-img remove-external" title="<?php esc_attr_e( 'Remove This Image' , 'thirstyaffiliates' ); ?>" id="<?php echo esc_attr( md5( $img_url ) ); ?>">&times;</span>
5
  <a class="thirsty-img thickbox" href="<?php echo esc_url( $img_url ); ?>" rel="gallery-linkimgs" title="<?php esc_attr_e( 'external image' , 'thirstyaffiliates' ); ?>">
6
  <img src="<?php echo esc_url( $img_url ); ?>" width="100" height="100">
7
  </a>
views/cpt/view-attach-images-metabox.php CHANGED
@@ -10,14 +10,14 @@ wp_nonce_field( 'thirsty_affiliates_cpt_nonce', '_thirstyaffiliates_nonce' ); ?>
10
  data-editor="content"
11
  data-uploader-title="<?php esc_attr_e( 'Add Image To Affiliate Link' , 'thirstyaffiliates' ); ?>"
12
  data-uploader-button-text="<?php esc_attr_e('Add To Affiliate Link'); ?>" >
13
- <?php _e( 'Upload/Insert' , 'thirstyaffiliates' ); ?>
14
  <span class="wp-media-buttons-icon"></span>
15
  </div>
16
 
17
  <?php else : ?>
18
 
19
  <div class="button-secondary" id="ta_upload_insert_img">
20
- <?php _e( 'Upload/Insert' , 'thirstyaffiliates' ); ?>
21
  <a class="thickbox" href="<?php echo esc_attr( admin_url( 'media-upload.php?post_id=' . $post->ID . '?type=image&TB_iframe=1' ) ); ?>">
22
  <span class="wp-media-buttons-icon"></span>
23
  </a>
@@ -25,14 +25,14 @@ wp_nonce_field( 'thirsty_affiliates_cpt_nonce', '_thirstyaffiliates_nonce' ); ?>
25
 
26
  <?php endif; ?>
27
 
28
- <span class="or"><?php _e( 'or' , 'thirstyaffliates' ); ?></span>
29
 
30
  <div class="add-external-image">
31
- <button type="button" class="button" id="add-external-image"><?php _e( 'Add external image' , 'thirstyaffiliates' ); ?></button>
32
  <div class="external-image-form">
33
- <input type="url" value="" placeholder="<?php _e( 'Image source here' , 'thirstyaffiliates' ); ?>">
34
- <button type="button" class="button-primary add-external"><?php _e( 'Add image' , 'thirstyaffiliates' ); ?></button>
35
- <button type="button" class="button cancel"><?php _e( 'Cancel' , 'thirstyaffiliates' ); ?></button>
36
  </div>
37
  </div>
38
 
@@ -43,7 +43,7 @@ wp_nonce_field( 'thirsty_affiliates_cpt_nonce', '_thirstyaffiliates_nonce' ); ?>
43
  </script>
44
 
45
  <?php if ( ! empty( $attachments ) ) : ?>
46
- <div id="thirsty_image_holder" data-attachments="<?php echo esc_attr( json_encode( $attachments ) ); ?>">
47
  <?php foreach ( $attachments as $attachment_id ) {
48
 
49
  if ( filter_var( $attachment_id , FILTER_VALIDATE_URL ) ) {
10
  data-editor="content"
11
  data-uploader-title="<?php esc_attr_e( 'Add Image To Affiliate Link' , 'thirstyaffiliates' ); ?>"
12
  data-uploader-button-text="<?php esc_attr_e('Add To Affiliate Link'); ?>" >
13
+ <?php esc_html_e( 'Upload/Insert' , 'thirstyaffiliates' ); ?>
14
  <span class="wp-media-buttons-icon"></span>
15
  </div>
16
 
17
  <?php else : ?>
18
 
19
  <div class="button-secondary" id="ta_upload_insert_img">
20
+ <?php esc_html_e( 'Upload/Insert' , 'thirstyaffiliates' ); ?>
21
  <a class="thickbox" href="<?php echo esc_attr( admin_url( 'media-upload.php?post_id=' . $post->ID . '?type=image&TB_iframe=1' ) ); ?>">
22
  <span class="wp-media-buttons-icon"></span>
23
  </a>
25
 
26
  <?php endif; ?>
27
 
28
+ <span class="or"><?php esc_html_e( 'or' , 'thirstyaffliates' ); ?></span>
29
 
30
  <div class="add-external-image">
31
+ <button type="button" class="button" id="add-external-image"><?php esc_html_e( 'Add external image' , 'thirstyaffiliates' ); ?></button>
32
  <div class="external-image-form">
33
+ <input type="url" value="" placeholder="<?php esc_html_e( 'Image source here' , 'thirstyaffiliates' ); ?>">
34
+ <button type="button" class="button-primary add-external"><?php esc_html_e( 'Add image' , 'thirstyaffiliates' ); ?></button>
35
+ <button type="button" class="button cancel"><?php esc_html_e( 'Cancel' , 'thirstyaffiliates' ); ?></button>
36
  </div>
37
  </div>
38
 
43
  </script>
44
 
45
  <?php if ( ! empty( $attachments ) ) : ?>
46
+ <div id="thirsty_image_holder" data-attachments="<?php echo esc_attr( wp_json_encode( $attachments ) ); ?>">
47
  <?php foreach ( $attachments as $attachment_id ) {
48
 
49
  if ( filter_var( $attachment_id , FILTER_VALIDATE_URL ) ) {
views/cpt/view-inserted-link-scanner-metabox.php CHANGED
@@ -1,22 +1,22 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
 
3
  <div class="scanned-inserted-status">
4
- <button id="inserted-link-scan-trigger" class="button-primary" type="button"><?php _e( 'Start Scan' , 'thirstyaffiliates' ); ?></button>
5
- <span class="last-scanned"><?php echo $last_scanned_txt; ?></span>
6
  </div>
7
 
8
  <div class="inserted-into-table">
9
  <table>
10
  <thead>
11
  <tr>
12
- <th class="id"><?php _e( 'ID' , 'thirstyaffiliates' ); ?></th>
13
- <th class="title"><?php _e( 'Title' , 'thirstyaffiliates' ); ?></th>
14
- <th class="post-type"><?php _e( 'Post Type' , 'thirstyaffiliates' ); ?></th>
15
  <th class="actions"></th>
16
  </tr>
17
  </thead>
18
  <tbody>
19
- <?php echo $inserted_into_rows_html; ?>
20
  </tbody>
21
  </table>
22
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
 
3
  <div class="scanned-inserted-status">
4
+ <button id="inserted-link-scan-trigger" class="button-primary" type="button"><?php esc_html_e( 'Start Scan' , 'thirstyaffiliates' ); ?></button>
5
+ <span class="last-scanned"><?php echo wp_kses_post( $last_scanned_txt ); // phpcs:ignore WordPress.Security.EscapeOutput ?></span>
6
  </div>
7
 
8
  <div class="inserted-into-table">
9
  <table>
10
  <thead>
11
  <tr>
12
+ <th class="id"><?php esc_html_e( 'ID' , 'thirstyaffiliates' ); ?></th>
13
+ <th class="title"><?php esc_html_e( 'Title' , 'thirstyaffiliates' ); ?></th>
14
+ <th class="post-type"><?php esc_html_e( 'Post Type' , 'thirstyaffiliates' ); ?></th>
15
  <th class="actions"></th>
16
  </tr>
17
  </thead>
18
  <tbody>
19
+ <?php echo $inserted_into_rows_html; // phpcs:ignore WordPress.Security.EscapeOutput ?>
20
  </tbody>
21
  </table>
22
  </div>
views/cpt/view-link-options-metabox.php CHANGED
@@ -4,66 +4,66 @@ wp_nonce_field( 'thirsty_affiliates_cpt_nonce', '_thirstyaffiliates_nonce' ); ?>
4
 
5
  <p>
6
  <label class="info-label block" for="ta_no_follow">
7
- <?php _e( 'No follow this link? (server side redirects)' , 'thirstyaffiliates' ); ?>
8
  <span class="tooltip" data-tip="<?php esc_attr_e( 'Adds the rel="nofollow" tag so search engines don\'t pass link juice.' , 'thirstyaffiliates' ); ?>"></span>
9
  </label>
10
  <select id="ta_no_follow" name="ta_no_follow">
11
- <option value="global" <?php selected( $thirstylink->get_prop( 'no_follow' ) , 'global' ); ?>><?php echo sprintf( __( 'Global (%s)' , 'thirstyaffiliates' ) , $global_no_follow ); ?></option>
12
- <option value="yes" <?php selected( $thirstylink->get_prop( 'no_follow' ) , 'yes' ); ?>><?php _e( 'Yes' , 'thirstyaffiliates' ); ?></option>
13
- <option value="no" <?php selected( $thirstylink->get_prop( 'no_follow' ) , 'no' ); ?>><?php _e( 'No' , 'thirstyaffiliates' ); ?></option>
14
  <select>
15
  </p>
16
 
17
  <p>
18
  <label class="info-label block" for="ta_new_window">
19
- <?php _e( 'Open this link in new window?' , 'thirstyaffiliates' ); ?>
20
  <span class="tooltip" data-tip="<?php esc_attr_e( 'Opens links in a new window when clicked on.' , 'thirstyaffiliates' ); ?>"></span>
21
  </label>
22
  <select id="ta_new_window" name="ta_new_window">
23
- <option value="global" <?php selected( $thirstylink->get_prop( 'new_window' ) , 'global' ); ?>><?php echo sprintf( __( 'Global (%s)' , 'thirstyaffiliates' ) , $global_new_window ); ?></option>
24
- <option value="yes" <?php selected( $thirstylink->get_prop( 'new_window' ) , 'yes' ); ?>><?php _e( 'Yes' , 'thirstyaffiliates' ); ?></option>
25
- <option value="no" <?php selected( $thirstylink->get_prop( 'new_window' ) , 'no' ); ?>><?php _e( 'No' , 'thirstyaffiliates' ); ?></option>
26
  <select>
27
  </p>
28
 
29
  <p>
30
  <label class="info-label block" for="ta_pass_query_str">
31
- <?php _e( 'Pass query string to destination url?' , 'thirstyaffiliates' ); ?>
32
  <span class="tooltip" data-tip="<?php esc_attr_e( 'Passes the query strings present after the cloaked url automatically to the destination url when redirecting.' , 'thirstyaffiliates' ); ?>"></span>
33
  </label>
34
  <select id="ta_pass_query_str" name="ta_pass_query_str">
35
- <option value="global" <?php selected( $thirstylink->get_prop( 'pass_query_str' ) , 'global' ); ?>><?php echo sprintf( __( 'Global (%s)' , 'thirstyaffiliates' ) , $global_pass_query_str ); ?></option>
36
- <option value="yes" <?php selected( $thirstylink->get_prop( 'pass_query_str' ) , 'yes' ); ?>><?php _e( 'Yes' , 'thirstyaffiliates' ); ?></option>
37
- <option value="no" <?php selected( $thirstylink->get_prop( 'pass_query_str' ) , 'no' ); ?>><?php _e( 'No' , 'thirstyaffiliates' ); ?></option>
38
  <select>
39
  </p>
40
 
41
  <?php if ( get_option( 'ta_uncloak_link_per_link' ) === 'yes' ) : ?>
42
  <p>
43
  <label class="info-label block" for="ta_uncloak_link">
44
- <?php _e( 'Uncloak link?' , 'thirstyaffiliates' ); ?>
45
  <span class="tooltip" data-tip="<?php esc_attr_e( 'Uncloaks the link when loaded on the frontend.' , 'thirstyaffiliates' ); ?>"></span>
46
  </label>
47
  <select id="ta_uncloak_link" name="ta_uncloak_link">
48
- <option value="global" <?php selected( $thirstylink->get_prop( 'uncloak_link' ) , 'global' ); ?>><?php echo sprintf( __( 'Global (%s)' , 'thirstyaffiliates' ) , $global_uncloak ); ?></option>
49
- <option value="yes" <?php selected( $thirstylink->get_prop( 'uncloak_link' ) , 'yes' ); ?>><?php _e( 'Yes' , 'thirstyaffiliates' ); ?></option>
50
- <option value="no" <?php selected( $thirstylink->get_prop( 'uncloak_link' ) , 'no' ); ?>><?php _e( 'No' , 'thirstyaffiliates' ); ?></option>
51
  <select>
52
  </p>
53
  <?php endif; ?>
54
 
55
  <p>
56
  <label class="info-label block" for="ta_redirect_type">
57
- <?php _e( 'Redirect type (server side redirects):' , 'thirstyaffiliates' ); ?>
58
  <span class="tooltip" data-tip="<?php esc_attr_e( 'Override the default redirection type for this link.' , 'thirstyaffiliates' ); ?>"></span>
59
  </label>
60
  <select id="ta_redirect_type" name="ta_redirect_type">
61
  <option value="global" <?php selected( $post_redirect_type , 'global' ); ?>>
62
- <?php echo sprintf( __( 'Global (%s)' , 'thirstyaffiliates' ) , $default_redirect_type ); ?>
63
  </option>
64
  <?php foreach ( $redirect_types as $redirect_type => $redirect_label ) : ?>
65
  <option value="<?php echo esc_attr( $redirect_type ); ?>" <?php selected( $post_redirect_type , $redirect_type ); ?>>
66
- <?php echo $redirect_label; ?>
67
  </option>
68
  <?php endforeach; ?>
69
  <select>
@@ -71,14 +71,14 @@ wp_nonce_field( 'thirsty_affiliates_cpt_nonce', '_thirstyaffiliates_nonce' ); ?>
71
 
72
  <p>
73
  <label class="info-label" for="ta_rel_tags">
74
- <?php _e( 'Additional rel tags:' , 'thirstyaffiliates' ); ?>
75
  </label>
76
  <input type="text" class="ta-form-input" id="ta_rel_tags" name="ta_rel_tags" value="<?php echo esc_attr( $rel_tags ); ?>" placeholder="<?php echo esc_attr( $global_rel_tags ); ?>">
77
  </p>
78
 
79
  <p>
80
  <label class="info-label" for="ta_css_classes">
81
- <?php _e( 'Additional CSS classes:' , 'thirstyaffiliates' ); ?>
82
  </label>
83
  <input type="text" class="ta-form-input" id="ta_css_classes" name="ta_css_classes" value="<?php echo esc_attr( $css_classes ); ?>" placeholder="<?php echo esc_attr( $global_css_classes ); ?>">
84
  </p>
4
 
5
  <p>
6
  <label class="info-label block" for="ta_no_follow">
7
+ <?php esc_html_e( 'No follow this link? (server side redirects)' , 'thirstyaffiliates' ); ?>
8
  <span class="tooltip" data-tip="<?php esc_attr_e( 'Adds the rel="nofollow" tag so search engines don\'t pass link juice.' , 'thirstyaffiliates' ); ?>"></span>
9
  </label>
10
  <select id="ta_no_follow" name="ta_no_follow">
11
+ <option value="global" <?php selected( $thirstylink->get_prop( 'no_follow' ) , 'global' ); ?>><?php echo esc_html( sprintf( __( 'Global (%s)' , 'thirstyaffiliates' ) , $global_no_follow ) ); ?></option>
12
+ <option value="yes" <?php selected( $thirstylink->get_prop( 'no_follow' ) , 'yes' ); ?>><?php esc_html_e( 'Yes' , 'thirstyaffiliates' ); ?></option>
13
+ <option value="no" <?php selected( $thirstylink->get_prop( 'no_follow' ) , 'no' ); ?>><?php esc_html_e( 'No' , 'thirstyaffiliates' ); ?></option>
14
  <select>
15
  </p>
16
 
17
  <p>
18
  <label class="info-label block" for="ta_new_window">
19
+ <?php esc_html_e( 'Open this link in new window?' , 'thirstyaffiliates' ); ?>
20
  <span class="tooltip" data-tip="<?php esc_attr_e( 'Opens links in a new window when clicked on.' , 'thirstyaffiliates' ); ?>"></span>
21
  </label>
22
  <select id="ta_new_window" name="ta_new_window">
23
+ <option value="global" <?php selected( $thirstylink->get_prop( 'new_window' ) , 'global' ); ?>><?php echo esc_html( sprintf( __( 'Global (%s)' , 'thirstyaffiliates' ) , $global_new_window ) ); ?></option>
24
+ <option value="yes" <?php selected( $thirstylink->get_prop( 'new_window' ) , 'yes' ); ?>><?php esc_html_e( 'Yes' , 'thirstyaffiliates' ); ?></option>
25
+ <option value="no" <?php selected( $thirstylink->get_prop( 'new_window' ) , 'no' ); ?>><?php esc_html_e( 'No' , 'thirstyaffiliates' ); ?></option>
26
  <select>
27
  </p>
28
 
29
  <p>
30
  <label class="info-label block" for="ta_pass_query_str">
31
+ <?php esc_html_e( 'Pass query string to destination url?' , 'thirstyaffiliates' ); ?>
32
  <span class="tooltip" data-tip="<?php esc_attr_e( 'Passes the query strings present after the cloaked url automatically to the destination url when redirecting.' , 'thirstyaffiliates' ); ?>"></span>
33
  </label>
34
  <select id="ta_pass_query_str" name="ta_pass_query_str">
35
+ <option value="global" <?php selected( $thirstylink->get_prop( 'pass_query_str' ) , 'global' ); ?>><?php echo esc_html( sprintf( __( 'Global (%s)' , 'thirstyaffiliates' ) , $global_pass_query_str ) ); ?></option>
36
+ <option value="yes" <?php selected( $thirstylink->get_prop( 'pass_query_str' ) , 'yes' ); ?>><?php esc_html_e( 'Yes' , 'thirstyaffiliates' ); ?></option>
37
+ <option value="no" <?php selected( $thirstylink->get_prop( 'pass_query_str' ) , 'no' ); ?>><?php esc_html_e( 'No' , 'thirstyaffiliates' ); ?></option>
38
  <select>
39
  </p>
40
 
41
  <?php if ( get_option( 'ta_uncloak_link_per_link' ) === 'yes' ) : ?>
42
  <p>
43
  <label class="info-label block" for="ta_uncloak_link">
44
+ <?php esc_html_e( 'Uncloak link?' , 'thirstyaffiliates' ); ?>
45
  <span class="tooltip" data-tip="<?php esc_attr_e( 'Uncloaks the link when loaded on the frontend.' , 'thirstyaffiliates' ); ?>"></span>
46
  </label>
47
  <select id="ta_uncloak_link" name="ta_uncloak_link">
48
+ <option value="global" <?php selected( $thirstylink->get_prop( 'uncloak_link' ) , 'global' ); ?>><?php echo esc_html( sprintf( __( 'Global (%s)' , 'thirstyaffiliates' ) , $global_uncloak ) ); ?></option>
49
+ <option value="yes" <?php selected( $thirstylink->get_prop( 'uncloak_link' ) , 'yes' ); ?>><?php esc_html_e( 'Yes' , 'thirstyaffiliates' ); ?></option>
50
+ <option value="no" <?php selected( $thirstylink->get_prop( 'uncloak_link' ) , 'no' ); ?>><?php esc_html_e( 'No' , 'thirstyaffiliates' ); ?></option>
51
  <select>
52
  </p>
53
  <?php endif; ?>
54
 
55
  <p>
56
  <label class="info-label block" for="ta_redirect_type">
57
+ <?php esc_html_e( 'Redirect type (server side redirects):' , 'thirstyaffiliates' ); ?>
58
  <span class="tooltip" data-tip="<?php esc_attr_e( 'Override the default redirection type for this link.' , 'thirstyaffiliates' ); ?>"></span>
59
  </label>
60
  <select id="ta_redirect_type" name="ta_redirect_type">
61
  <option value="global" <?php selected( $post_redirect_type , 'global' ); ?>>
62
+ <?php echo esc_html( sprintf( __( 'Global (%s)' , 'thirstyaffiliates' ) , $default_redirect_type ) ); ?>
63
  </option>
64
  <?php foreach ( $redirect_types as $redirect_type => $redirect_label ) : ?>
65
  <option value="<?php echo esc_attr( $redirect_type ); ?>" <?php selected( $post_redirect_type , $redirect_type ); ?>>
66
+ <?php echo esc_html( $redirect_label ); ?>
67
  </option>
68
  <?php endforeach; ?>
69
  <select>
71
 
72
  <p>
73
  <label class="info-label" for="ta_rel_tags">
74
+ <?php esc_html_e( 'Additional rel tags:' , 'thirstyaffiliates' ); ?>
75
  </label>
76
  <input type="text" class="ta-form-input" id="ta_rel_tags" name="ta_rel_tags" value="<?php echo esc_attr( $rel_tags ); ?>" placeholder="<?php echo esc_attr( $global_rel_tags ); ?>">
77
  </p>
78
 
79
  <p>
80
  <label class="info-label" for="ta_css_classes">
81
+ <?php esc_html_e( 'Additional CSS classes:' , 'thirstyaffiliates' ); ?>
82
  </label>
83
  <input type="text" class="ta-form-input" id="ta_css_classes" name="ta_css_classes" value="<?php echo esc_attr( $css_classes ); ?>" placeholder="<?php echo esc_attr( $global_css_classes ); ?>">
84
  </p>
views/cpt/view-save-affiliate-link-metabox.php CHANGED
@@ -1,8 +1,8 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
 
3
  <input name="post_status" type="hidden" id="post_status" value="publish" />
4
- <input name="original_publish" type="hidden" id="original_publish" value="<?php _e( 'Save' , 'thirstyaffiliates' ); ?>" />
5
- <input name="save" type="submit" class="button-primary" id="publish" tabindex="5" accesskey="p" value="<?php _e( 'Save Link' , 'thirstyaffiliates' ); ?>">
6
 
7
  <?php if ( current_user_can( "delete_post" , $post->ID ) ) :
8
 
@@ -11,5 +11,5 @@
11
  else
12
  $delete_text = __( 'Move to Trash' , 'thirstyaffiliates' ); ?>
13
 
14
- <a class="submitdelete deletion" href="<?php echo get_delete_post_link( $post->ID ); ?>"><?php echo $delete_text; ?></a>
15
  <?php endif; ?>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
 
3
  <input name="post_status" type="hidden" id="post_status" value="publish" />
4
+ <input name="original_publish" type="hidden" id="original_publish" value="<?php esc_html_e( 'Save' , 'thirstyaffiliates' ); ?>" />
5
+ <input name="save" type="submit" class="button-primary" id="publish" tabindex="5" accesskey="p" value="<?php esc_html_e( 'Save Link' , 'thirstyaffiliates' ); ?>">
6
 
7
  <?php if ( current_user_can( "delete_post" , $post->ID ) ) :
8
 
11
  else
12
  $delete_text = __( 'Move to Trash' , 'thirstyaffiliates' ); ?>
13
 
14
+ <a class="submitdelete deletion" href="<?php echo esc_url( get_delete_post_link( $post->ID ) ); ?>"><?php echo esc_html( $delete_text ); ?></a>
15
  <?php endif; ?>
views/cpt/view-urls-metabox.php CHANGED
@@ -4,25 +4,25 @@ wp_nonce_field( 'thirsty_affiliates_cpt_nonce', '_thirstyaffiliates_nonce' ); ?>
4
 
5
  <p class="destination-url-field">
6
  <label class="info-label" for="ta_destination_url">
7
- <?php _e( 'Destination URL:' , 'thirstyaffiliates' ); ?>
8
  </label>
9
- <input type="url" class="ta-form-input" id="ta_destination_url" name="ta_destination_url" value="<?php echo $thirstylink->get_prop( 'destination_url' ); ?>">
10
  </p>
11
 
12
  <?php if ( $screen->action != 'add' ) : ?>
13
  <p class="cloaked-url-field">
14
  <label class="info-label" for="ta_destination_url">
15
- <?php _e( 'Cloaked URL:' , 'thirstyaffiliates' ); ?>
16
  </label>
17
  <span class="cloaked-fields">
18
  <input type="url" class="ta-form-input" id="ta_cloaked_url" name="ta_cloaked_url" value="<?php echo esc_attr( $thirstylink->get_prop( 'permalink' ) ); ?>" readonly>
19
- <button type="button" class="edit-ta-slug button"><?php _e( 'Edit slug' , 'thirstyaffiliates' ); ?></button>
20
- <a class="button" href="<?php echo esc_attr( $thirstylink->get_prop( 'permalink' ) ); ?>" target="_blank"><?php _e( 'Visit Link' , 'thirstyaffiliates' ); ?></a>
21
  </span>
22
  <span class="slug-fields" style="display: none;">
23
  <input type="text" class="ta-form-input" id="ta_slug" name="post_name" pattern="[a-z0-9-_% ]+" value="<?php echo esc_attr( $thirstylink->get_prop( 'slug' ) ); ?>">
24
- <span class="edit-slug-warning"><?php _e( '<strong>Warning:</strong> Editing the slug will break already inserted links for this affiliate link.' , 'thirstyaffiliates' ); ?></span>
25
- <button type="button" class="save-ta-slug button"><?php _e( 'Save' , 'thirstyaffiliates' ); ?></button>
26
  </span>
27
  </p>
28
  <?php endif; ?>
@@ -30,15 +30,15 @@ wp_nonce_field( 'thirsty_affiliates_cpt_nonce', '_thirstyaffiliates_nonce' ); ?>
30
  <?php if ( get_option( 'ta_show_cat_in_slug' ) === 'yes' ) : ?>
31
  <p>
32
  <label class="info-label" for="ta_category_slug">
33
- <?php _e( 'Category to show in slug:' , 'thirstyaffiliates' ); ?>
34
  </label>
35
  <select name="ta_category_slug" data-home-link-prefix="<?php echo esc_attr( $home_link_prefix ); ?>">
36
  <option value="" data-slug="<?php echo esc_attr( $default_cat_slug ); ?>" <?php selected( $thirstylink->get_prop( 'category_slug' ) , '' ) ?> >
37
- <?php _e( 'Default' , 'thirstylink' ); ?>
38
  </option>
39
  <?php foreach( $thirstylink->get_prop( 'categories' ) as $category ) : ?>
40
- <option value="<?php echo $category->term_id; ?>" data-slug="<?php echo esc_attr( $category->slug ); ?>" <?php selected( $thirstylink->get_prop( 'category_slug' ) , $category->slug ) ?> >
41
- <?php echo $category->name; ?>
42
  </option>
43
  <?php endforeach; ?>
44
  </select>
4
 
5
  <p class="destination-url-field">
6
  <label class="info-label" for="ta_destination_url">
7
+ <?php esc_html_e( 'Destination URL:' , 'thirstyaffiliates' ); ?>
8
  </label>
9
+ <input type="url" class="ta-form-input" id="ta_destination_url" name="ta_destination_url" value="<?php echo esc_url( $thirstylink->get_prop( 'destination_url' ) ); ?>">
10
  </p>
11
 
12
  <?php if ( $screen->action != 'add' ) : ?>
13
  <p class="cloaked-url-field">
14
  <label class="info-label" for="ta_destination_url">
15
+ <?php esc_html_e( 'Cloaked URL:' , 'thirstyaffiliates' ); ?>
16
  </label>
17
  <span class="cloaked-fields">
18
  <input type="url" class="ta-form-input" id="ta_cloaked_url" name="ta_cloaked_url" value="<?php echo esc_attr( $thirstylink->get_prop( 'permalink' ) ); ?>" readonly>
19
+ <button type="button" class="edit-ta-slug button"><?php esc_html_e( 'Edit slug' , 'thirstyaffiliates' ); ?></button>
20
+ <a class="button" href="<?php echo esc_attr( $thirstylink->get_prop( 'permalink' ) ); ?>" target="_blank"><?php esc_html_e( 'Visit Link' , 'thirstyaffiliates' ); ?></a>
21
  </span>
22
  <span class="slug-fields" style="display: none;">
23
  <input type="text" class="ta-form-input" id="ta_slug" name="post_name" pattern="[a-z0-9-_% ]+" value="<?php echo esc_attr( $thirstylink->get_prop( 'slug' ) ); ?>">
24
+ <span class="edit-slug-warning"><?php esc_html_e( '<strong>Warning:</strong> Editing the slug will break already inserted links for this affiliate link.' , 'thirstyaffiliates' ); ?></span>
25
+ <button type="button" class="save-ta-slug button"><?php esc_html_e( 'Save' , 'thirstyaffiliates' ); ?></button>
26
  </span>
27
  </p>
28
  <?php endif; ?>
30
  <?php if ( get_option( 'ta_show_cat_in_slug' ) === 'yes' ) : ?>
31
  <p>
32
  <label class="info-label" for="ta_category_slug">
33
+ <?php esc_html_e( 'Category to show in slug:' , 'thirstyaffiliates' ); ?>
34
  </label>
35
  <select name="ta_category_slug" data-home-link-prefix="<?php echo esc_attr( $home_link_prefix ); ?>">
36
  <option value="" data-slug="<?php echo esc_attr( $default_cat_slug ); ?>" <?php selected( $thirstylink->get_prop( 'category_slug' ) , '' ) ?> >
37
+ <?php esc_html_e( 'Default' , 'thirstylink' ); ?>
38
  </option>
39
  <?php foreach( $thirstylink->get_prop( 'categories' ) as $category ) : ?>
40
+ <option value="<?php echo esc_attr( $category->term_id ); ?>" data-slug="<?php echo esc_attr( $category->slug ); ?>" <?php selected( $thirstylink->get_prop( 'category_slug' ) , $category->slug ) ?> >
41
+ <?php echo esc_html( $category->name ); ?>
42
  </option>
43
  <?php endforeach; ?>
44
  </select>
views/exporter/exporter.php CHANGED
@@ -4,24 +4,24 @@
4
 
5
  <div class="ta-blur">
6
 
7
- <h3><?php _e( 'STEP 1 - Export your links:' , 'thirstyaffiliates' ); ?></h3>
8
 
9
  <p>
10
- <?php _e( 'This tool lets you export a properly formatted CSV file containing a list of all the affiliate links on this website. This CSV file will be compatible with the ThirstyAffiliates CSV Importer.' , 'thirstyaffiliates' ); ?>
11
  </p>
12
 
13
  <p>
14
- <?php _e( 'You can choose to only export the links from a specific category.' , 'thirstyaffiliates' ); ?>
15
  </p>
16
 
17
  <form class="tap-round-box" id="tap_upload_csv_form" enctype="multipart/form-data" method="post">
18
 
19
  <p>
20
  <label for="export_category">
21
- <?php _e( 'Category to export from:' , 'thirstyaffiliates' ); ?>
22
  </label>
23
  <select id="export_category">
24
- <option value="all" selected="selected"><?php _e( '-- All Categories --' , 'thirstyaffiliates' ); ?></option>
25
  </select>
26
  </p>
27
 
4
 
5
  <div class="ta-blur">
6
 
7
+ <h3><?php esc_html_e( 'STEP 1 - Export your links:' , 'thirstyaffiliates' ); ?></h3>
8
 
9
  <p>
10
+ <?php esc_html_e( 'This tool lets you export a properly formatted CSV file containing a list of all the affiliate links on this website. This CSV file will be compatible with the ThirstyAffiliates CSV Importer.' , 'thirstyaffiliates' ); ?>
11
  </p>
12
 
13
  <p>
14
+ <?php esc_html_e( 'You can choose to only export the links from a specific category.' , 'thirstyaffiliates' ); ?>
15
  </p>
16
 
17
  <form class="tap-round-box" id="tap_upload_csv_form" enctype="multipart/form-data" method="post">
18
 
19
  <p>
20
  <label for="export_category">
21
+ <?php esc_html_e( 'Category to export from:' , 'thirstyaffiliates' ); ?>
22
  </label>
23
  <select id="export_category">
24
+ <option value="all" selected="selected"><?php esc_html_e( '-- All Categories --' , 'thirstyaffiliates' ); ?></option>
25
  </select>
26
  </p>
27
 
views/importer/importer.php CHANGED
@@ -4,14 +4,14 @@
4
 
5
  <div class="ta-blur">
6
 
7
- <h3><?php _e( 'STEP 1 - select your CSV file:' , 'thirstyaffiliates' ); ?></h3>
8
 
9
  <p>
10
- <?php _e( 'This tool lets you upload a properly formatted CSV file containing a list of affiliate links. These links will be bulk imported for you directly into ThirstyAffiliates.' , 'thirstyaffiliates' ); ?>
11
  </p>
12
 
13
  <p>
14
- <?php _e( 'Any categories you specify in your import file that are not found in the system will be created as the links are imported' , 'thirstyaffiliates' ); ?>
15
  </p>
16
 
17
  <form class="tap-round-box" id="tap_upload_csv_form" enctype="multipart/form-data" method="post">
4
 
5
  <div class="ta-blur">
6
 
7
+ <h3><?php esc_html_e( 'STEP 1 - select your CSV file:' , 'thirstyaffiliates' ); ?></h3>
8
 
9
  <p>
10
+ <?php esc_html_e( 'This tool lets you upload a properly formatted CSV file containing a list of affiliate links. These links will be bulk imported for you directly into ThirstyAffiliates.' , 'thirstyaffiliates' ); ?>
11
  </p>
12
 
13
  <p>
14
+ <?php esc_html_e( 'Any categories you specify in your import file that are not found in the system will be created as the links are imported' , 'thirstyaffiliates' ); ?>
15
  </p>
16
 
17
  <form class="tap-round-box" id="tap_upload_csv_form" enctype="multipart/form-data" method="post">
views/linkpicker/advance-link-picker.php CHANGED
@@ -14,13 +14,13 @@
14
 
15
  <div class="search-panel">
16
  <label>
17
- <span class="search-label"><?php _e( 'Search:' , 'thirstyaffiliates' ); ?></span>
18
  <input type="text" id="thirstylink-search" class="thirstylink-search-field form-control" placeholder="<?php esc_attr_e( 'Please enter 3 or more characters...' ) ?>" autocomplete="off">
19
  <span class="spinner"></span>
20
  </label>
21
  <select id="thirstylink-category" class="selectize-select" style="width:200px; display:inline-block">
22
- <option value=""><?php _e( 'Select category' , 'thirstyaffiliates' ); ?></option>
23
- <option value="all" selected><?php _e( 'All Categories' , 'thirstyaffiliates' ); ?></option>
24
  <?php foreach ( $this->_helper_functions->get_all_category_as_options( true ) as $term_id => $label ) : ?>
25
  <option value="<?php echo esc_attr( $term_id ); ?>"><?php echo esc_html( $label ); ?></option>
26
  <?php endforeach; ?>
@@ -28,12 +28,12 @@
28
  </div>
29
 
30
  <div class="results-panel">
31
- <ul class="results-list" data-htmleditor="<?php echo $html_editor; ?>">
32
- <?php echo $result_markup; ?>
33
  </ul>
34
  <a class="load-more-results" href="#">
35
- <span class="spinner"><i style="background-image: url(<?php echo $this->_constants->IMAGES_ROOT_URL() . 'spinner.gif'; ?>)"></i> <?php _e( 'Fetching...' , 'thirstyaffiliates' ); ?></span>
36
- <span class="button-text"><i class="dashicons dashicons-update"></i> <?php _e( 'Load more' , 'thirstyaffiliates' ); ?></span>
37
  </a>
38
  </div>
39
  </div>
@@ -41,7 +41,7 @@
41
 
42
  // global var
43
  Options = {
44
- post_id : <?php echo $post_id; ?>,
45
  searching_text : '<?php echo esc_js( __( 'Searching...', 'thirstyaffiliates' ) ); ?>',
46
  spinner_image : '<?php echo esc_url_raw( $this->_constants->IMAGES_ROOT_URL() . 'spinner.gif' ); ?>'
47
  };
14
 
15
  <div class="search-panel">
16
  <label>
17
+ <span class="search-label"><?php esc_html_e( 'Search:' , 'thirstyaffiliates' ); ?></span>
18
  <input type="text" id="thirstylink-search" class="thirstylink-search-field form-control" placeholder="<?php esc_attr_e( 'Please enter 3 or more characters...' ) ?>" autocomplete="off">
19
  <span class="spinner"></span>
20
  </label>
21
  <select id="thirstylink-category" class="selectize-select" style="width:200px; display:inline-block">
22
+ <option value=""><?php esc_html_e( 'Select category' , 'thirstyaffiliates' ); ?></option>
23
+ <option value="all" selected><?php esc_html_e( 'All Categories' , 'thirstyaffiliates' ); ?></option>
24
  <?php foreach ( $this->_helper_functions->get_all_category_as_options( true ) as $term_id => $label ) : ?>
25
  <option value="<?php echo esc_attr( $term_id ); ?>"><?php echo esc_html( $label ); ?></option>
26
  <?php endforeach; ?>
28
  </div>
29
 
30
  <div class="results-panel">
31
+ <ul class="results-list" data-htmleditor="<?php echo esc_attr( $html_editor ); ?>">
32
+ <?php echo $result_markup; // phpcs:ignore WordPress.Security.EscapeOutput ?>
33
  </ul>
34
  <a class="load-more-results" href="#">
35
+ <span class="spinner"><i style="background-image: url(<?php echo esc_url( $this->_constants->IMAGES_ROOT_URL() . 'spinner.gif' ); ?>)"></i> <?php esc_html_e( 'Fetching...' , 'thirstyaffiliates' ); ?></span>
36
+ <span class="button-text"><i class="dashicons dashicons-update"></i> <?php esc_html_e( 'Load more' , 'thirstyaffiliates' ); ?></span>
37
  </a>
38
  </div>
39
  </div>
41
 
42
  // global var
43
  Options = {
44
+ post_id : <?php echo (int) $post_id; ?>,
45
  searching_text : '<?php echo esc_js( __( 'Searching...', 'thirstyaffiliates' ) ); ?>',
46
  spinner_image : '<?php echo esc_url_raw( $this->_constants->IMAGES_ROOT_URL() . 'spinner.gif' ); ?>'
47
  };
views/linkpicker/edit-shortcode.php CHANGED
@@ -18,50 +18,50 @@
18
 
19
  <div class="field-row">
20
  <label for="shortcode_text">
21
- <?php _e( 'Link text:' , 'thirstyaffiliates' ); ?>
22
  </label>
23
  <input type="text" class="form-control" id="shortcode_text" name="shortcode_text" value="" required>
24
  </div>
25
 
26
  <div class="field-row">
27
  <label for="shortcode_ids">
28
- <?php _e( 'Affiliate link ids:' , 'thirstyaffiliates' ); ?>
29
  </label>
30
  <input type="text" class="form-control" id="shortcode_ids" name="shortcode_ids" value="" required>
31
  </div>
32
 
33
  <div class="field-row one-half first-half">
34
  <label for="shortcode_class">
35
- <?php _e( 'Class link attribute:' , 'thirstyaffiliates' ); ?>
36
  </label>
37
  <input type="text" class="form-control" id="shortcode_class" name="shortcode_class" value="">
38
  </div>
39
 
40
  <div class="field-row one-half">
41
  <label for="shortcode_title">
42
- <?php _e( 'Link title attribute:' , 'thirstyaffiliates' ); ?>
43
  </label>
44
  <input type="text" class="form-control" id="shortcode_title" name="shortcode_title" value="">
45
  </div>
46
 
47
  <div class="field-row one-half first-half">
48
  <label for="shortcode_rel">
49
- <?php _e( 'Link rel attribute:' , 'thirstyaffiliates' ); ?>
50
  </label>
51
  <input type="text" class="form-control" id="shortcode_rel" name="shortcode_rel" value="">
52
  </div>
53
 
54
  <div class="field-row one-half">
55
  <label for="shortcode_target">
56
- <?php _e( 'link target attribute:' , 'thirstyaffiliates' ); ?>
57
  </label>
58
  <input type="text" class="form-control" id="shortcode_target" name="shortcode_target" value="">
59
  </div>
60
 
61
  <div class="field-row submit-row">
62
- <span class="ta_spinner" style="background-image: url('<?php echo $this->_constants->IMAGES_ROOT_URL() . 'spinner.gif'; ?>');"></span>
63
  <button class="button button-primary" id="submit" type="submit" name="add_link">
64
- <?php _e( 'Edit Shortcode' , 'thirstyaffiliates' ); ?>
65
  </button>
66
  </div>
67
 
18
 
19
  <div class="field-row">
20
  <label for="shortcode_text">
21
+ <?php esc_html_e( 'Link text:' , 'thirstyaffiliates' ); ?>
22
  </label>
23
  <input type="text" class="form-control" id="shortcode_text" name="shortcode_text" value="" required>
24
  </div>
25
 
26
  <div class="field-row">
27
  <label for="shortcode_ids">
28
+ <?php esc_html_e( 'Affiliate link ids:' , 'thirstyaffiliates' ); ?>
29
  </label>
30
  <input type="text" class="form-control" id="shortcode_ids" name="shortcode_ids" value="" required>
31
  </div>
32
 
33
  <div class="field-row one-half first-half">
34
  <label for="shortcode_class">
35
+ <?php esc_html_e( 'Class link attribute:' , 'thirstyaffiliates' ); ?>
36
  </label>
37
  <input type="text" class="form-control" id="shortcode_class" name="shortcode_class" value="">
38
  </div>
39
 
40
  <div class="field-row one-half">
41
  <label for="shortcode_title">
42
+ <?php esc_html_e( 'Link title attribute:' , 'thirstyaffiliates' ); ?>
43
  </label>
44
  <input type="text" class="form-control" id="shortcode_title" name="shortcode_title" value="">
45
  </div>
46
 
47
  <div class="field-row one-half first-half">
48
  <label for="shortcode_rel">
49
+ <?php esc_html_e( 'Link rel attribute:' , 'thirstyaffiliates' ); ?>
50
  </label>
51
  <input type="text" class="form-control" id="shortcode_rel" name="shortcode_rel" value="">
52
  </div>
53
 
54
  <div class="field-row one-half">
55
  <label for="shortcode_target">
56
+ <?php esc_html_e( 'link target attribute:' , 'thirstyaffiliates' ); ?>
57
  </label>
58
  <input type="text" class="form-control" id="shortcode_target" name="shortcode_target" value="">
59
  </div>
60
 
61
  <div class="field-row submit-row">
62
+ <span class="ta_spinner" style="background-image: url('<?php echo esc_url( $this->_constants->IMAGES_ROOT_URL() . 'spinner.gif' ); ?>');"></span>
63
  <button class="button button-primary" id="submit" type="submit" name="add_link">
64
+ <?php esc_html_e( 'Edit Shortcode' , 'thirstyaffiliates' ); ?>
65
  </button>
66
  </div>
67
 
views/linkpicker/quick-add-affiliate-link.php CHANGED
@@ -10,34 +10,34 @@
10
 
11
  <body>
12
 
13
- <div id="quick_add_affiliate_link" data-htmleditor="<?php echo $html_editor; ?>">
14
 
15
  <form method="post" onsubmit="dummySubmitFunc(event)">
16
 
17
  <div class="field-row">
18
  <label for="ta_link_name">
19
- <?php _e( 'Link Name:' , 'thirstyaffiliates' ); ?>
20
  </label>
21
  <input type="text" class="form-control" id="ta_link_name" name="ta_link_name" value="<?php echo esc_attr( $selection ); ?>" required>
22
  </div>
23
 
24
  <div class="field-row">
25
  <label for="ta_destination_url">
26
- <?php _e( 'Destination URL:' , 'thirstyaffiliates' ); ?>
27
  </label>
28
  <span class="guide">
29
- <?php _e( 'http:// or https:// is required' , 'thirstyaffiliates' ); ?>
30
  </span>
31
  <input type="url" class="form-control" id="ta_destination_url" name="ta_destination_url" value="" required>
32
  </div>
33
 
34
  <div class="field-row link-option">
35
  <label for="ta_redirect_type">
36
- <?php _e( 'Redirect Type:' , 'thirstyaffiliates' ); ?>
37
  </label>
38
  <select id="ta_redirect_type" name="ta_redirect_type">
39
  <option value="global">
40
- <?php echo sprintf( __( 'Global (%s)' , 'thirstyaffiliates' ) , $default_redirect_type ); ?>
41
  </option>
42
  <?php foreach ( $redirect_types as $redirect_type => $redirect_label ) : ?>
43
  <option value="<?php echo esc_attr( $redirect_type ); ?>">
@@ -49,33 +49,33 @@
49
 
50
  <div class="field-row link-option">
51
  <label for="ta_no_follow">
52
- <?php _e( 'No follow this link?' , 'thirstyaffiliates' ); ?>
53
  </label>
54
  <select id="ta_no_follow" name="ta_no_follow">
55
- <option value="global"><?php echo sprintf( __( 'Global (%s)' , 'thirstyaffiliates' ) , $global_no_follow ); ?></option>
56
- <option value="yes"><?php _e( 'Yes' , 'thirstyaffiliates' ); ?></option>
57
- <option value="no"><?php _e( 'No' , 'thirstyaffiliates' ); ?></option>
58
  <select>
59
  </div>
60
 
61
  <div class="field-row link-option">
62
  <label for="ta_new_window">
63
- <?php _e( 'Open this link in new window?' , 'thirstyaffiliates' ); ?>
64
  </label>
65
  <select id="ta_new_window" name="ta_new_window">
66
- <option value="global"><?php echo sprintf( __( 'Global (%s)' , 'thirstyaffiliates' ) , $global_new_window ); ?></option>
67
- <option value="yes"><?php _e( 'Yes' , 'thirstyaffiliates' ); ?></option>
68
- <option value="no"><?php _e( 'No' , 'thirstyaffiliates' ); ?></option>
69
  <select>
70
  </div>
71
 
72
  <div class="field-row link-categories">
73
  <label for="ta_link_categories">
74
- <?php _e( 'Link Categories' , 'thirstyaffiliates' ); ?>
75
  </label>
76
  <select multiple id="link_categories" name="ta_link_categories[]" data-placeholder="<?php esc_attr_e( 'Select categories...' , 'thirstyaffiliates' ); ?>">
77
  <?php foreach ( $categories as $category ) : ?>
78
- <option value="<?php echo $category->term_id; ?>"><?php echo $category->name; ?></option>
79
  <?php endforeach; ?>
80
  </select>
81
  </div>
@@ -83,12 +83,12 @@
83
  <?php do_action( 'ta_quick_add_affiliate_link_form' ); ?>
84
 
85
  <div class="field-row submit-row">
86
- <span class="ta_spinner" style="background-image: url('<?php echo $this->_constants->IMAGES_ROOT_URL() . 'spinner.gif'; ?>');"></span>
87
  <button class="button" type="submit" name="add_link">
88
- <?php _e( 'Add Link' , 'thirstyaffiliates' ); ?>
89
  </button>
90
  <button class="button button-primary" type="submit" name="add_link_and_insert">
91
- <?php _e( 'Add Link & Insert Into Post' , 'thirstyaffiliates' ); ?>
92
  </button>
93
  </div>
94
 
10
 
11
  <body>
12
 
13
+ <div id="quick_add_affiliate_link" data-htmleditor="<?php echo esc_attr( $html_editor ); ?>">
14
 
15
  <form method="post" onsubmit="dummySubmitFunc(event)">
16
 
17
  <div class="field-row">
18
  <label for="ta_link_name">
19
+ <?php esc_html_e( 'Link Name:' , 'thirstyaffiliates' ); ?>
20
  </label>
21
  <input type="text" class="form-control" id="ta_link_name" name="ta_link_name" value="<?php echo esc_attr( $selection ); ?>" required>
22
  </div>
23
 
24
  <div class="field-row">
25
  <label for="ta_destination_url">
26
+ <?php esc_html_e( 'Destination URL:' , 'thirstyaffiliates' ); ?>
27
  </label>
28
  <span class="guide">
29
+ <?php esc_html_e( 'http:// or https:// is required' , 'thirstyaffiliates' ); ?>
30
  </span>
31
  <input type="url" class="form-control" id="ta_destination_url" name="ta_destination_url" value="" required>
32
  </div>
33
 
34
  <div class="field-row link-option">
35
  <label for="ta_redirect_type">
36
+ <?php esc_html_e( 'Redirect Type:' , 'thirstyaffiliates' ); ?>
37
  </label>
38
  <select id="ta_redirect_type" name="ta_redirect_type">
39
  <option value="global">
40
+ <?php echo esc_html( sprintf( __( 'Global (%s)' , 'thirstyaffiliates' ) , $default_redirect_type ) ); ?>
41
  </option>
42
  <?php foreach ( $redirect_types as $redirect_type => $redirect_label ) : ?>
43
  <option value="<?php echo esc_attr( $redirect_type ); ?>">
49
 
50
  <div class="field-row link-option">
51
  <label for="ta_no_follow">
52
+ <?php esc_html_e( 'No follow this link?' , 'thirstyaffiliates' ); ?>
53
  </label>
54
  <select id="ta_no_follow" name="ta_no_follow">
55
+ <option value="global"><?php echo esc_html( sprintf( __( 'Global (%s)' , 'thirstyaffiliates' ) , $global_no_follow ) ); ?></option>
56
+ <option value="yes"><?php esc_html_e( 'Yes' , 'thirstyaffiliates' ); ?></option>
57
+ <option value="no"><?php esc_html_e( 'No' , 'thirstyaffiliates' ); ?></option>
58
  <select>
59
  </div>
60
 
61
  <div class="field-row link-option">
62
  <label for="ta_new_window">
63
+ <?php esc_html_e( 'Open this link in new window?' , 'thirstyaffiliates' ); ?>
64
  </label>
65
  <select id="ta_new_window" name="ta_new_window">
66
+ <option value="global"><?php echo esc_html( sprintf( __( 'Global (%s)' , 'thirstyaffiliates' ) , $global_new_window ) ); ?></option>
67
+ <option value="yes"><?php esc_html_e( 'Yes' , 'thirstyaffiliates' ); ?></option>
68
+ <option value="no"><?php esc_html_e( 'No' , 'thirstyaffiliates' ); ?></option>
69
  <select>
70
  </div>
71
 
72
  <div class="field-row link-categories">
73
  <label for="ta_link_categories">
74
+ <?php esc_html_e( 'Link Categories' , 'thirstyaffiliates' ); ?>
75
  </label>
76
  <select multiple id="link_categories" name="ta_link_categories[]" data-placeholder="<?php esc_attr_e( 'Select categories...' , 'thirstyaffiliates' ); ?>">
77
  <?php foreach ( $categories as $category ) : ?>
78
+ <option value="<?php echo esc_attr( $category->term_id ); ?>"><?php echo esc_html( $category->name ); ?></option>
79
  <?php endforeach; ?>
80
  </select>
81
  </div>
83
  <?php do_action( 'ta_quick_add_affiliate_link_form' ); ?>
84
 
85
  <div class="field-row submit-row">
86
+ <span class="ta_spinner" style="background-image: url('<?php echo esc_url( $this->_constants->IMAGES_ROOT_URL() . 'spinner.gif' ); ?>');"></span>
87
  <button class="button" type="submit" name="add_link">
88
+ <?php esc_html_e( 'Add Link' , 'thirstyaffiliates' ); ?>
89
  </button>
90
  <button class="button button-primary" type="submit" name="add_link_and_insert">
91
+ <?php esc_html_e( 'Add Link & Insert Into Post' , 'thirstyaffiliates' ); ?>
92
  </button>
93
  </div>
94
 
views/reports/link-performance-report.php CHANGED
@@ -5,22 +5,22 @@
5
  <ul>
6
  <?php foreach ( $range_nav as $nrange => $label ) : ?>
7
  <li<?php echo ( $nrange == $current_range ) ? ' class="current"' : ''; ?>>
8
- <a href="<?php echo admin_url( 'edit.php?post_type=thirstylink&page=thirsty-reports&range=' . $nrange ); ?>">
9
- <?php echo $label; ?>
10
  </a>
11
  </li>
12
  <?php endforeach; ?>
13
 
14
  <li class="custom-range">
15
- <span><?php _e( 'Custom' , 'thirstyaffiliates' ); ?></span>
16
  <form id="custom-date-range" method="GET">
17
- <input type="hidden" name="post_type" value="<?php echo $cpt_slug; ?>">
18
  <input type="hidden" name="page" value="thirsty-reports">
19
  <input type="hidden" name="range" value="custom">
20
  <input type="text" placeholder="yyyy-mm-dd" value="<?php echo esc_attr( $start_date ); ?>" name="start_date" class="range_datepicker from" required>
21
  <span>&mdash;</span>
22
  <input type="text" placeholder="yyyy-mm-dd" value="<?php echo esc_attr( $end_date ); ?>" name="end_date" class="range_datepicker to" required>
23
- <button type="submit" class="button"><?php _e( 'Go' , 'thirstyaffiliates' ); ?></button>
24
  </form>
25
  </li>
26
 
@@ -36,16 +36,16 @@
36
 
37
  <ul class="chart-legend">
38
  <li style="border-color: #3498db">
39
- <?php _e( 'General' , 'thirstyaffiliates' ); ?>
40
  <em class="count"></em>
41
- <span><?php _e( 'All links' , 'thirstyaffiliates' ); ?></span>
42
  </li>
43
  </ul>
44
 
45
  <?php do_action( 'ta_after_stats_reporting_chart_legend' ); ?>
46
 
47
  <div class="add-legend">
48
- <label for="add-report-data"><?php _e( 'Fetch report for specific link:' , 'thirstyaffiliates' ); ?></label>
49
  <div class="input-wrap">
50
  <input type="text" id="add-report-data" placeholder="<?php esc_attr_e( 'Search affiliate link' , 'thirstyaffiliates' ); ?>"
51
  data-range="<?php echo esc_attr( $current_range ); ?>"
@@ -59,7 +59,7 @@
59
  <input type="text" class="color-field" id="link-report-color" value="#e74c3c">
60
  </div>
61
 
62
- <button type="button" class="button-primary" id="fetch-link-report"><?php _e( 'Fetch Report' , 'thirstyaffiliates' ); ?></button>
63
  </div>
64
 
65
  <?php do_action( 'ta_stats_reporting_chart_sidebar' ); ?>
@@ -77,11 +77,11 @@
77
  <script type="text/javascript">
78
  var report_data = { 'click_counts' :[] },
79
  report_details = {
80
- label : '<?php echo _e( 'General' , 'thirstyaffiliates' ); ?>',
81
- label : '<?php echo _e( 'All links' , 'thirstyaffiliates' ); ?>',
82
  timeformat : '<?php echo ( $range[ 'type' ] == 'year' ) ? '%b' : '%d %b'; ?>',
83
  minTickSize : [ 1 , "<?php echo ( $range[ 'type' ] == 'year' ) ? 'month' : 'day'; ?>" ],
84
- clicksLabel : '<?php _e( 'Clicks: ' , 'thirstyaffiliates' ); ?>',
85
  totalClicks : ''
86
  },
87
  main_chart;
5
  <ul>
6
  <?php foreach ( $range_nav as $nrange => $label ) : ?>
7
  <li<?php echo ( $nrange == $current_range ) ? ' class="current"' : ''; ?>>
8
+ <a href="<?php echo esc_url( admin_url( 'edit.php?post_type=thirstylink&page=thirsty-reports&range=' . $nrange ) ); ?>">
9
+ <?php echo esc_html( $label ); ?>
10
  </a>
11
  </li>
12
  <?php endforeach; ?>
13
 
14
  <li class="custom-range">
15
+ <span><?php esc_html_e( 'Custom' , 'thirstyaffiliates' ); ?></span>
16
  <form id="custom-date-range" method="GET">
17
+ <input type="hidden" name="post_type" value="<?php echo esc_attr( $cpt_slug ); ?>">
18
  <input type="hidden" name="page" value="thirsty-reports">
19
  <input type="hidden" name="range" value="custom">
20
  <input type="text" placeholder="yyyy-mm-dd" value="<?php echo esc_attr( $start_date ); ?>" name="start_date" class="range_datepicker from" required>
21
  <span>&mdash;</span>
22
  <input type="text" placeholder="yyyy-mm-dd" value="<?php echo esc_attr( $end_date ); ?>" name="end_date" class="range_datepicker to" required>
23
+ <button type="submit" class="button"><?php esc_html_e( 'Go' , 'thirstyaffiliates' ); ?></button>
24
  </form>
25
  </li>
26
 
36
 
37
  <ul class="chart-legend">
38
  <li style="border-color: #3498db">
39
+ <?php esc_html_e( 'General' , 'thirstyaffiliates' ); ?>
40
  <em class="count"></em>
41
+ <span><?php esc_html_e( 'All links' , 'thirstyaffiliates' ); ?></span>
42
  </li>
43
  </ul>
44
 
45
  <?php do_action( 'ta_after_stats_reporting_chart_legend' ); ?>
46
 
47
  <div class="add-legend">
48
+ <label for="add-report-data"><?php esc_html_e( 'Fetch report for specific link:' , 'thirstyaffiliates' ); ?></label>
49
  <div class="input-wrap">
50
  <input type="text" id="add-report-data" placeholder="<?php esc_attr_e( 'Search affiliate link' , 'thirstyaffiliates' ); ?>"
51
  data-range="<?php echo esc_attr( $current_range ); ?>"
59
  <input type="text" class="color-field" id="link-report-color" value="#e74c3c">
60
  </div>
61
 
62
+ <button type="button" class="button-primary" id="fetch-link-report"><?php esc_html_e( 'Fetch Report' , 'thirstyaffiliates' ); ?></button>
63
  </div>
64
 
65
  <?php do_action( 'ta_stats_reporting_chart_sidebar' ); ?>
77
  <script type="text/javascript">
78
  var report_data = { 'click_counts' :[] },
79
  report_details = {
80
+ label : '<?php esc_html_e( 'General' , 'thirstyaffiliates' ); ?>',
81
+ label : '<?php esc_html_e( 'All links' , 'thirstyaffiliates' ); ?>',
82
  timeformat : '<?php echo ( $range[ 'type' ] == 'year' ) ? '%b' : '%d %b'; ?>',
83
  minTickSize : [ 1 , "<?php echo ( $range[ 'type' ] == 'year' ) ? 'month' : 'day'; ?>" ],
84
+ clicksLabel : '<?php esc_html_e( 'Clicks: ' , 'thirstyaffiliates' ); ?>',
85
  totalClicks : ''
86
  },
87
  main_chart;
views/ta-upgrade.php CHANGED
@@ -2,11 +2,11 @@
2
  <div class="ta-upgrade-wrap">
3
  <div class="ta-upgrade-content">
4
  <div class="ta-upgrade-logo">
5
- <img src="<?php echo $this->_constants->IMAGES_ROOT_URL() . 'TA-PRO.svg'; ?>" alt="">
6
  </div>
7
  <h2>Everything You Need To Supercharge Your Affiliate Marketing</h2>
8
  <?php if ( ! empty( $section_title ) ) : ?>
9
- <h4>ThirstyAffiliates Lite cannot access <?php echo $section_title; ?>.</h4>
10
  <?php endif; ?>
11
  <p>Once you upgrade to ThirstyAffiliates Pro, you'll have access to these pro features:</p>
12
  <ul class="features">
@@ -21,7 +21,7 @@
21
  </ul>
22
  </div>
23
  <div class="ta-upgrade-cta">
24
- <a href="<?php echo $upgrade_link; ?>" id="pretty_link_cta_upgrade_link" class="ta-cta-button">Upgrade to ThirstyAffiliates Pro Now</a>
25
  </div>
26
  </div>
27
  </div>
2
  <div class="ta-upgrade-wrap">
3
  <div class="ta-upgrade-content">
4
  <div class="ta-upgrade-logo">
5
+ <img src="<?php echo esc_url( $this->_constants->IMAGES_ROOT_URL() . 'TA-PRO.svg' ); ?>" alt="">
6
  </div>
7
  <h2>Everything You Need To Supercharge Your Affiliate Marketing</h2>
8
  <?php if ( ! empty( $section_title ) ) : ?>
9
+ <h4>ThirstyAffiliates Lite cannot access <?php echo esc_html( $section_title ); ?>.</h4>
10
  <?php endif; ?>
11
  <p>Once you upgrade to ThirstyAffiliates Pro, you'll have access to these pro features:</p>
12
  <ul class="features">
21
  </ul>
22
  </div>
23
  <div class="ta-upgrade-cta">
24
+ <a href="<?php echo esc_url( $upgrade_link ); ?>" id="pretty_link_cta_upgrade_link" class="ta-cta-button">Upgrade to ThirstyAffiliates Pro Now</a>
25
  </div>
26
  </div>
27
  </div>