Shortlinks by Pretty Links – Best WordPress Link Tracking Plugin - Version 3.2.5

Version Description

  • Fix fatal error if update transient is false
  • Notifications Inbox
  • Small bug fixes
  • Pro: Don't force black background on cloaked urls
  • Pro: License key optimizations
Download this release

Release Info

Developer cartpauj
Plugin Icon 128x128 Shortlinks by Pretty Links – Best WordPress Link Tracking Plugin
Version 3.2.5
Comparing to
See all releases

Code changes from version 3.2.4 to 3.2.5

app/controllers/PrliAppController.php CHANGED
@@ -87,7 +87,7 @@ class PrliAppController extends PrliBaseController {
87
  <div id="pl-admin-header"><img class="pl-logo" src="<?php echo PRLI_IMAGES_URL . '/pretty-links-logo-color-white.svg'; ?>" /></div>
88
  <script>
89
  jQuery(document).ready(function($) {
90
- $('#close-pl-upgrade-header').click(function(event) {
91
  var upgradeHeader = $('#pl-upgrade-header');
92
  upgradeHeader.fadeOut();
93
  $.ajax({
87
  <div id="pl-admin-header"><img class="pl-logo" src="<?php echo PRLI_IMAGES_URL . '/pretty-links-logo-color-white.svg'; ?>" /></div>
88
  <script>
89
  jQuery(document).ready(function($) {
90
+ $('#close-pl-upgrade-header').on('click', function() {
91
  var upgradeHeader = $('#pl-upgrade-header');
92
  upgradeHeader.fadeOut();
93
  $.ajax({
app/controllers/PrliFlyoutMenuController.php CHANGED
@@ -20,12 +20,16 @@ class PrliFlyoutMenuController {
20
  return;
21
  }
22
 
 
 
 
23
  printf(
24
  '<div id="caseproof-flyout">
25
  <div id="caseproof-flyout-items">
26
  %1$s
27
  </div>
28
- <a href="#" class="caseproof-flyout-button caseproof-flyout-head">
 
29
  <div class="caseproof-flyout-label">%2$s</div>
30
  <img src="%3$s" alt="%2$s" data-active="%4$s" />
31
  </a>
@@ -33,7 +37,8 @@ class PrliFlyoutMenuController {
33
  $this->get_items_html(),
34
  esc_attr__( 'See Quick Links', 'pretty-link' ),
35
  esc_url( PRLI_IMAGES_URL . '/admin-flyout-default.svg' ),
36
- esc_url( PRLI_IMAGES_URL . '/admin-flyout-active.svg' )
 
37
  );
38
  }
39
 
@@ -51,13 +56,14 @@ class PrliFlyoutMenuController {
51
 
52
  foreach ( $items as $item_key => $item ) {
53
  $items_html .= sprintf(
54
- '<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>
55
- <div class="caseproof-flyout-label">%3$s</div>
56
- %4$s
57
  </a>',
 
58
  esc_url( $item['url'] ),
59
  (int) $item_key,
60
- esc_html( $item['title'] ),
61
  $item['icon'],
62
  ! empty( $item['bgcolor'] ) ? ' style="background-color: ' . esc_attr( $item['bgcolor'] ) . '"' : '',
63
  ! empty( $item['hover_bgcolor'] ) ? ' onMouseOver="this.style.backgroundColor=\'' . esc_attr( $item['hover_bgcolor'] ) . '\'" onMouseOut="this.style.backgroundColor=\'' . esc_attr( $item['bgcolor'] ) . '\'"' : ''
@@ -74,6 +80,10 @@ class PrliFlyoutMenuController {
74
  */
75
  private function menu_items() {
76
 
 
 
 
 
77
  $items = array(
78
  array(
79
  'title' => esc_html__( 'Upgrade to Pretty Links Pro', 'pretty-link' ),
@@ -92,8 +102,15 @@ class PrliFlyoutMenuController {
92
  'url' => 'https://prettylinks.com/contact/?utm_source=plugin_admin&utm_medium=link&utm_campaign=in_plugin&utm_content=quick_links_widget',
93
  'icon' => '<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 53 43" xmlns="http://www.w3.org/2000/svg"><g fill="#fff" fill-rule="nonzero" transform="translate(-13.5 -19.9)"><path d="m22.8 35.7c0-1.1-.9-2-2-2h-5.3c-1.1 0-2 .9-2 2s.9 2 2 2h5.3c1.1 0 2-.9 2-2"/><path d="m64.5 33.7h-5.3c-1.1 0-2 .9-2 2s.9 2 2 2h5.3c1.1 0 2-.9 2-2s-1-2-2-2"/><path d="m22.4 43.6-4.6 2.6c-1 .5-1.3 1.7-.8 2.7s1.7 1.3 2.7.8h.1l4.6-2.6c.9-.6 1.2-1.8.7-2.7-.6-1-1.8-1.3-2.7-.8"/><path d="m56.6 28.1c.3 0 .7-.1 1-.3l4.6-2.6c.9-.6 1.2-1.8.7-2.7s-1.7-1.2-2.7-.7l-4.6 2.6c-.9.5-1.3 1.8-.7 2.7.3.6 1 1 1.7 1"/><path d="m24.5 24.5-4.6-2.7c-.9-.6-2.2-.3-2.7.7-.6.9-.3 2.2.7 2.7h.1l4.6 2.6c.9.6 2.2.3 2.7-.7s.1-2.1-.8-2.6"/><path d="m49.6 23.5c-2.7-2.3-6.1-3.6-9.6-3.6-8.4 0-14.5 6.9-14.5 14.5 0 3.5 1.3 6.9 3.6 9.6 1.4 1.6 3.5 4.9 4.3 7.6h4c0-.4-.1-.8-.2-1.2-.5-1.5-1.9-5.3-5.1-9.1-1.7-1.9-2.6-4.4-2.6-7 0-6.1 4.9-10.6 10.6-10.6 5.8 0 10.6 4.7 10.6 10.6 0 2.6-.9 5-2.6 7-3.2 3.7-4.7 7.6-5.1 9-.1.4-.2.8-.2 1.2h4c.8-2.8 3-6 4.3-7.6 5.1-6 4.5-15.2-1.5-20.4"/><path d="m33.4 57.8c0 .3.1.5.2.7l2 3c.2.4.7.6 1.1.6h6.5c.4 0 .9-.2 1.1-.6l2-3c.1-.2.2-.5.2-.7v-3.6h-13.1z"/><path d="m62.2 46.2-4.6-2.6c-.9-.6-2.2-.3-2.7.7-.6.9-.3 2.2.7 2.7h.1l4.6 2.6c1 .5 2.2.2 2.7-.8.4-.9.1-2-.8-2.6"/><path d="m40 26.5c-4.4 0-7.9 3.6-7.9 7.9 0 .7.6 1.3 1.3 1.3s1.3-.6 1.3-1.3c0-2.9 2.4-5.3 5.3-5.3.7 0 1.3-.6 1.3-1.3s-.6-1.3-1.3-1.3"/></g></svg>',
94
  ),
 
 
 
 
 
 
95
  );
96
 
 
97
  return $items;
98
  }
99
  }
20
  return;
21
  }
22
 
23
+ global $prli_notifications;
24
+ $notifications_count = $prli_notifications->get_count();
25
+
26
  printf(
27
  '<div id="caseproof-flyout">
28
  <div id="caseproof-flyout-items">
29
  %1$s
30
  </div>
31
+ <a href="#" id="caseproofFlyoutButton" class="caseproof-flyout-button caseproof-flyout-head">
32
+ %5$s
33
  <div class="caseproof-flyout-label">%2$s</div>
34
  <img src="%3$s" alt="%2$s" data-active="%4$s" />
35
  </a>
37
  $this->get_items_html(),
38
  esc_attr__( 'See Quick Links', 'pretty-link' ),
39
  esc_url( PRLI_IMAGES_URL . '/admin-flyout-default.svg' ),
40
+ esc_url( PRLI_IMAGES_URL . '/admin-flyout-active.svg' ),
41
+ $notifications_count > 0 ? '<span id="prliAdminNotificationsBadge" class="prli-notifications-count">' . $notifications_count . '</span>' : ''
42
  );
43
  }
44
 
56
 
57
  foreach ( $items as $item_key => $item ) {
58
  $items_html .= sprintf(
59
+ '<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>
60
+ <div class="caseproof-flyout-label">%4$s</div>
61
+ %5$s
62
  </a>',
63
+ ! empty( $item['id'] ) ? esc_attr( $item['id'] ) : '',
64
  esc_url( $item['url'] ),
65
  (int) $item_key,
66
+ wp_kses_post( $item['title'] ),
67
  $item['icon'],
68
  ! empty( $item['bgcolor'] ) ? ' style="background-color: ' . esc_attr( $item['bgcolor'] ) . '"' : '',
69
  ! empty( $item['hover_bgcolor'] ) ? ' onMouseOver="this.style.backgroundColor=\'' . esc_attr( $item['hover_bgcolor'] ) . '\'" onMouseOut="this.style.backgroundColor=\'' . esc_attr( $item['bgcolor'] ) . '\'"' : ''
80
  */
81
  private function menu_items() {
82
 
83
+ global $prli_notifications;
84
+ $notifications_count = $prli_notifications->get_count();
85
+ $notifications_count_text = $notifications_count > 0 ? sprintf( '(%s)', $notifications_count ) : '';
86
+
87
  $items = array(
88
  array(
89
  'title' => esc_html__( 'Upgrade to Pretty Links Pro', 'pretty-link' ),
102
  'url' => 'https://prettylinks.com/contact/?utm_source=plugin_admin&utm_medium=link&utm_campaign=in_plugin&utm_content=quick_links_widget',
103
  'icon' => '<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 53 43" xmlns="http://www.w3.org/2000/svg"><g fill="#fff" fill-rule="nonzero" transform="translate(-13.5 -19.9)"><path d="m22.8 35.7c0-1.1-.9-2-2-2h-5.3c-1.1 0-2 .9-2 2s.9 2 2 2h5.3c1.1 0 2-.9 2-2"/><path d="m64.5 33.7h-5.3c-1.1 0-2 .9-2 2s.9 2 2 2h5.3c1.1 0 2-.9 2-2s-1-2-2-2"/><path d="m22.4 43.6-4.6 2.6c-1 .5-1.3 1.7-.8 2.7s1.7 1.3 2.7.8h.1l4.6-2.6c.9-.6 1.2-1.8.7-2.7-.6-1-1.8-1.3-2.7-.8"/><path d="m56.6 28.1c.3 0 .7-.1 1-.3l4.6-2.6c.9-.6 1.2-1.8.7-2.7s-1.7-1.2-2.7-.7l-4.6 2.6c-.9.5-1.3 1.8-.7 2.7.3.6 1 1 1.7 1"/><path d="m24.5 24.5-4.6-2.7c-.9-.6-2.2-.3-2.7.7-.6.9-.3 2.2.7 2.7h.1l4.6 2.6c.9.6 2.2.3 2.7-.7s.1-2.1-.8-2.6"/><path d="m49.6 23.5c-2.7-2.3-6.1-3.6-9.6-3.6-8.4 0-14.5 6.9-14.5 14.5 0 3.5 1.3 6.9 3.6 9.6 1.4 1.6 3.5 4.9 4.3 7.6h4c0-.4-.1-.8-.2-1.2-.5-1.5-1.9-5.3-5.1-9.1-1.7-1.9-2.6-4.4-2.6-7 0-6.1 4.9-10.6 10.6-10.6 5.8 0 10.6 4.7 10.6 10.6 0 2.6-.9 5-2.6 7-3.2 3.7-4.7 7.6-5.1 9-.1.4-.2.8-.2 1.2h4c.8-2.8 3-6 4.3-7.6 5.1-6 4.5-15.2-1.5-20.4"/><path d="m33.4 57.8c0 .3.1.5.2.7l2 3c.2.4.7.6 1.1.6h6.5c.4 0 .9-.2 1.1-.6l2-3c.1-.2.2-.5.2-.7v-3.6h-13.1z"/><path d="m62.2 46.2-4.6-2.6c-.9-.6-2.2-.3-2.7.7-.6.9-.3 2.2.7 2.7h.1l4.6 2.6c1 .5 2.2.2 2.7-.8.4-.9.1-2-.8-2.6"/><path d="m40 26.5c-4.4 0-7.9 3.6-7.9 7.9 0 .7.6 1.3 1.3 1.3s1.3-.6 1.3-1.3c0-2.9 2.4-5.3 5.3-5.3.7 0 1.3-.6 1.3-1.3s-.6-1.3-1.3-1.3"/></g></svg>',
104
  ),
105
+ array(
106
+ 'id' => 'prliAdminNotifications',
107
+ 'title' => esc_html__( 'Notifications ', 'pretty-link' ) . '<span id="prliNotificationsCount"> ' . $notifications_count_text . ' </span>',
108
+ 'url' => '#',
109
+ '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>',
110
+ )
111
  );
112
 
113
+
114
  return $items;
115
  }
116
  }
app/controllers/PrliLinksController.php CHANGED
@@ -220,7 +220,7 @@ class PrliLinksController extends PrliBaseController {
220
  global $prli_link, $prli_link_meta;
221
 
222
  $values = array();
223
- $values['link_id'] = $record->id;
224
  $values['url'] = ((isset($_REQUEST['url']) and $record == null)?esc_url_raw(trim(stripslashes($_REQUEST['url']))):stripslashes($record->url));
225
  $values['slug'] = ((isset($_REQUEST['slug']) and $record == null)?sanitize_text_field(stripslashes($_REQUEST['slug'])):stripslashes($record->slug));
226
  $values['name'] = ((isset($_REQUEST['name']) and $record == null)?sanitize_text_field(stripslashes($_REQUEST['name'])):stripslashes($record->name));
@@ -1001,4 +1001,3 @@ class PrliLinksController extends PrliBaseController {
1001
  }
1002
 
1003
  }
1004
-
220
  global $prli_link, $prli_link_meta;
221
 
222
  $values = array();
223
+ $values['link_id'] = isset($record->id) ? $record->id : null;
224
  $values['url'] = ((isset($_REQUEST['url']) and $record == null)?esc_url_raw(trim(stripslashes($_REQUEST['url']))):stripslashes($record->url));
225
  $values['slug'] = ((isset($_REQUEST['slug']) and $record == null)?sanitize_text_field(stripslashes($_REQUEST['slug'])):stripslashes($record->slug));
226
  $values['name'] = ((isset($_REQUEST['name']) and $record == null)?sanitize_text_field(stripslashes($_REQUEST['name'])):stripslashes($record->name));
1001
  }
1002
 
1003
  }
 
app/controllers/PrliUpdateController.php CHANGED
@@ -17,32 +17,24 @@ class PrliUpdateController {
17
  public function load_hooks() {
18
  if(!empty($this->mothership_license)) {
19
  add_filter('pre_set_site_transient_update_plugins', array($this, 'queue_update'));
 
20
  add_action('wp_ajax_plp_edge_updates', array($this, 'plp_edge_updates'));
21
  add_filter('plugins_api', array($this, 'plugin_info'), 11, 3);
22
  }
23
 
24
- add_action('admin_init', array($this, 'activate_from_define'));
25
-
26
  add_action('admin_notices', array($this, 'activation_warning'));
 
27
  add_action('admin_enqueue_scripts', array($this, 'enqueue_scripts'));
 
 
 
 
 
28
  //add_action('prli_display_options', array($this, 'queue_button'));
29
  }
30
 
31
  public function route() {
32
- if(strtolower($_SERVER['REQUEST_METHOD']) == 'post') {
33
- return $this->process_form();
34
- }
35
- else {
36
- if( isset($_GET['action']) &&
37
- $_GET['action'] == 'deactivate' &&
38
- isset($_GET['_wpnonce']) &&
39
- wp_verify_nonce($_GET['_wpnonce'], 'pretty-link_deactivate') ) {
40
- return $this->deactivate();
41
- }
42
- else {
43
- return $this->display_form();
44
- }
45
- }
46
  }
47
 
48
  public function set_edge_updates($updates) {
@@ -69,38 +61,169 @@ class PrliUpdateController {
69
  require(PRLI_VIEWS_PATH.'/admin/update/ui.php');
70
  }
71
 
72
- public function process_form() {
73
- if(!isset($_POST['_wpnonce']) || !wp_verify_nonce($_POST['_wpnonce'],'activation_form')) {
74
- wp_die(__('Why you creepin\'?', 'pretty-link'));
75
  }
76
 
77
- if(!isset($_POST[$this->mothership_license_str])) {
78
- $this->display_form();
79
- return;
80
  }
81
 
82
- $message = '';
83
- $errors = array();
84
- $this->set_mothership_license(stripslashes($_POST[$this->mothership_license_str]));
85
- $domain = urlencode(PrliUtils::site_domain());
 
 
 
 
 
86
 
87
  try {
88
- $args = compact('domain');
89
- $act = $this->send_mothership_request("/license_keys/activate/{$this->mothership_license}", $args, 'post');
90
- update_option('prli_activated', true); // if we get here we're activated
91
- wp_cache_delete('alloptions', 'options');
92
- $this->manually_queue_update();
93
- $message = $act['message'];
94
-
95
- if(strpos($message, 'site has already been activated') !== false ) {
96
- $this->deactivate(true);
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  }
 
 
 
 
 
98
  }
99
  catch(Exception $e) {
100
- $errors[] = $e->getMessage();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  }
102
 
103
- $this->display_form($message, $errors);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  }
105
 
106
  public function is_activated() {
@@ -131,56 +254,93 @@ class PrliUpdateController {
131
 
132
  if(!empty($aov)) {
133
  update_option('prli_activated', true);
134
- wp_cache_delete('alloptions', 'options');
135
- return true;
136
  }
137
 
138
- $domain = urlencode(PrliUtils::site_domain());
 
 
139
 
140
- // Bail if there's no license key
141
- if(empty($this->mothership_license)) { return; }
 
 
 
 
 
 
 
 
 
 
 
 
142
 
143
  try {
144
- $act = $this->send_mothership_request("/license_keys/a/{$domain}/{$this->mothership_license}", array(), 'get');
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
- if(!empty($act) && is_array($act) && isset($act['status'])) {
147
- update_option('prli_activated', ($act['status']=='enabled'));
148
- wp_cache_delete('alloptions', 'options');
 
 
 
 
 
 
 
 
149
  }
150
  }
151
  catch(Exception $e) {
152
- // TODO: For now do nothing if the server can't be reached
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  }
154
  }
155
 
156
  public function activate_from_define() {
157
- if(!$this->is_installed()) { return; }
 
 
158
 
159
  if(defined('PRETTYLINK_LICENSE_KEY') && $this->mothership_license != PRETTYLINK_LICENSE_KEY) {
160
- $message = '';
161
- $errors = array();
162
- $this->mothership_license = stripslashes(PRETTYLINK_LICENSE_KEY);
163
- update_option($this->mothership_license_str, PRETTYLINK_LICENSE_KEY);
164
- wp_cache_delete('alloptions', 'options');
165
- $domain = urlencode(PrliUtils::site_domain());
166
-
167
  try {
168
- $args = compact('domain');
169
-
170
  if(!empty($this->mothership_license)) {
171
- $act = $this->send_mothership_request("/license_keys/deactivate/{$this->mothership_license}", $args, 'post');
172
- delete_site_transient('prli_addons');
173
  }
174
 
175
- $act = $this->send_mothership_request("/license_keys/activate/".PRETTYLINK_LICENSE_KEY, $args, 'post');
176
- update_option('prli_activated', true); // if we get here we're activated
177
- wp_cache_delete('alloptions', 'options');
178
-
179
- $this->manually_queue_update();
180
-
181
  // If we're using defines then we have to do this with defines too
182
  $this->set_edge_updates(false);
183
 
 
 
184
  $message = $act['message'];
185
  $callback = function() use ($message) { require(PRLI_VIEWS_PATH."/admin/errors.php"); };
186
  }
@@ -193,36 +353,99 @@ class PrliUpdateController {
193
  }
194
  }
195
 
196
- public function deactivate($hide_form = false) {
197
- $domain = urlencode(PrliUtils::site_domain());
198
- $message = '';
 
 
 
 
 
 
 
 
 
199
 
200
- try {
201
- $args = compact('domain');
202
- $act = $this->send_mothership_request("/license_keys/deactivate/{$this->mothership_license}", $args, 'post');
203
 
204
- $this->manually_queue_update();
205
 
206
- $this->set_mothership_license('');
 
 
207
 
208
- // Don't need to check the mothership for this one ... we just deactivated
209
- update_option('prli_activated', false);
210
- wp_cache_delete('alloptions', 'options');
211
 
212
- $message = $act['message'];
213
- }
214
- catch(Exception $e) {
215
- update_option('prli_activated', false);
216
- wp_cache_delete('alloptions', 'options');
217
- update_option($this->mothership_license_str, '');
218
- wp_cache_delete('alloptions', 'options');
219
- $errors[] = $e->getMessage();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  }
221
 
222
- if(!$hide_form) { $this->display_form($message); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
  }
224
 
225
  public function queue_update($transient, $force=false) {
 
 
 
 
226
  if(!$this->is_installed() && !$this->is_activated()) { return $transient; }
227
 
228
  if($force || (false === ($update_info = get_site_transient('prli_update_info')))) {
@@ -253,8 +476,12 @@ class PrliUpdateController {
253
  set_site_transient(
254
  'prli_license_info',
255
  $license_info,
256
- (12*HOUR_IN_SECONDS)
257
  );
 
 
 
 
258
  }
259
  catch(Exception $e) {
260
  try {
@@ -284,8 +511,6 @@ class PrliUpdateController {
284
  compact('curr_version', 'download_url'),
285
  (12*HOUR_IN_SECONDS)
286
  );
287
-
288
- $this->addons(false, true);
289
  }
290
  else {
291
  extract( $update_info );
@@ -410,6 +635,19 @@ class PrliUpdateController {
410
 
411
  wp_register_script('prli-settings-table', PRLI_JS_URL.'/settings_table.js', array(), PRLI_VERSION);
412
  wp_enqueue_script('prli-activate-js', PRLI_JS_URL.'/admin_activate.js', array('prli-settings-table'), PRLI_VERSION);
 
 
 
 
 
 
 
 
 
 
 
 
 
413
  }
414
  }
415
 
@@ -512,5 +750,22 @@ class PrliUpdateController {
512
  include_once PRLI_VIEWS_PATH . "/admin/upgrade/import-export.php";
513
  }
514
 
515
- } //End class
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
516
 
 
17
  public function load_hooks() {
18
  if(!empty($this->mothership_license)) {
19
  add_filter('pre_set_site_transient_update_plugins', array($this, 'queue_update'));
20
+ add_action('admin_init', array($this, 'maybe_activate'));
21
  add_action('wp_ajax_plp_edge_updates', array($this, 'plp_edge_updates'));
22
  add_filter('plugins_api', array($this, 'plugin_info'), 11, 3);
23
  }
24
 
 
 
25
  add_action('admin_notices', array($this, 'activation_warning'));
26
+ add_action('admin_init', array($this, 'activate_from_define'));
27
  add_action('admin_enqueue_scripts', array($this, 'enqueue_scripts'));
28
+ add_action('wp_ajax_prli_activate_license', array($this, 'ajax_activate_license'));
29
+ add_action('wp_ajax_prli_deactivate_license', array($this, 'ajax_deactivate_license'));
30
+ add_action('wp_ajax_prli_install_license_edition', array($this, 'ajax_install_license_edition'));
31
+ add_action('in_plugin_update_message-pretty-link/pretty-link.php', array($this, 'check_incorrect_edition'));
32
+ add_action('prli_plugin_edition_changed', array($this, 'clear_update_transients'));
33
  //add_action('prli_display_options', array($this, 'queue_button'));
34
  }
35
 
36
  public function route() {
37
+ $this->display_form();
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  }
39
 
40
  public function set_edge_updates($updates) {
61
  require(PRLI_VIEWS_PATH.'/admin/update/ui.php');
62
  }
63
 
64
+ public function ajax_activate_license() {
65
+ if(!PrliUtils::is_post_request() || !isset($_POST['key']) || !is_string($_POST['key'])) {
66
+ wp_send_json_error(__('Bad request.', 'pretty-link'));
67
  }
68
 
69
+ if(!PrliUtils::is_logged_in_and_an_admin()) {
70
+ wp_send_json_error(__('Sorry, you don\'t have permission to do this.', 'pretty-link'));
 
71
  }
72
 
73
+ if(!check_ajax_referer('prli_activate_license', false, false)) {
74
+ wp_send_json_error(__('Security check failed.', 'pretty-link'));
75
+ }
76
+
77
+ $license_key = sanitize_text_field(wp_unslash($_POST['key']));
78
+
79
+ if(empty($license_key)) {
80
+ wp_send_json_error(__('Bad request.', 'pretty-link'));
81
+ }
82
 
83
  try {
84
+ $act = $this->activate_license($license_key);
85
+ $li = get_site_transient('prli_license_info');
86
+ $output = sprintf('<div class="notice notice-success inline"><p>%s</p></div>', esc_html($act['message']));
87
+
88
+ if(is_array($li)) {
89
+ $editions = PrliUtils::is_incorrect_edition_installed();
90
+
91
+ if(is_array($editions) && $editions['license']['index'] > $editions['installed']['index']) {
92
+ // The installed plugin is a lower edition, try to upgrade to the higher license edition
93
+ if(!empty($li['url']) && PrliUtils::is_url($li['url'])) {
94
+ $result = $this->install_plugin_silently($li['url'], array('overwrite_package' => true));
95
+
96
+ if($result === true) {
97
+ do_action('prli_plugin_edition_changed');
98
+ wp_send_json_success(true);
99
+ }
100
+ }
101
+ }
102
+
103
+ ob_start();
104
+ require PRLI_VIEWS_PATH . '/admin/update/active_license.php';
105
+ $output .= ob_get_clean();
106
  }
107
+ else {
108
+ $output .= sprintf('<div class="notice notice-warning"><p>%s</p></div>', esc_html__('The license information is not available, try refreshing the page.', 'pretty-link'));
109
+ }
110
+
111
+ wp_send_json_success($output);
112
  }
113
  catch(Exception $e) {
114
+ try {
115
+ $expires = $this->send_mothership_request("/license_keys/expires_at/$license_key");
116
+
117
+ if(isset($expires['expires_at'])) {
118
+ $expires_at = strtotime($expires['expires_at']);
119
+
120
+ if($expires_at && $expires_at < time()) {
121
+ $licenses = $this->send_mothership_request("/license_keys/list_keys/$license_key");
122
+
123
+ if(!empty($licenses) && is_array($licenses)) {
124
+ $highest_edition_index = -1;
125
+ $highest_license = null;
126
+
127
+ foreach($licenses as $license) {
128
+ $edition = PrliUtils::get_edition($license['product_slug']);
129
+
130
+ if(is_array($edition) && $edition['index'] > $highest_edition_index) {
131
+ $highest_edition_index = $edition['index'];
132
+ $highest_license = $license;
133
+ }
134
+ }
135
+
136
+ if(is_array($highest_license)) {
137
+ wp_send_json_error(
138
+ sprintf(
139
+ /* translators: %1$s: the product name, %2$s: open link tag, %3$s: close link tag */
140
+ esc_html__('This License Key has expired, but you have an active license for %1$s, %2$sclick here%3$s to activate using this license instead.', 'pretty-link'),
141
+ '<strong>' . esc_html($highest_license['product_name']) . '</strong>',
142
+ sprintf('<a href="#" id="prli-activate-new-license" data-license-key="%s">', esc_attr($highest_license['license_key'])),
143
+ '</a>'
144
+ )
145
+ );
146
+ }
147
+ }
148
+ }
149
+ }
150
+ }
151
+ catch(Exception $ignore) {
152
+ // Nothing we can do, let it fail.
153
+ }
154
+
155
+ wp_send_json_error($e->getMessage());
156
+ }
157
+ }
158
+
159
+ public function ajax_deactivate_license() {
160
+ if(!PrliUtils::is_post_request()) {
161
+ wp_send_json_error(__('Bad request.', 'pretty-link'));
162
  }
163
 
164
+ if(!PrliUtils::is_logged_in_and_an_admin()) {
165
+ wp_send_json_error(__('Sorry, you don\'t have permission to do this.', 'pretty-link'));
166
+ }
167
+
168
+ if(!check_ajax_referer('prli_deactivate_license', false, false)) {
169
+ wp_send_json_error(__('Security check failed.', 'pretty-link'));
170
+ }
171
+
172
+ $act = $this->deactivate_license();
173
+
174
+ $output = sprintf('<div class="notice notice-success"><p>%s</p></div>', esc_html($act['message']));
175
+
176
+ ob_start();
177
+ require PRLI_VIEWS_PATH . '/admin/update/inactive_license.php';
178
+ $output .= ob_get_clean();
179
+
180
+ wp_send_json_success($output);
181
+ }
182
+
183
+ public function install_plugin_silently($url, $args) {
184
+ require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
185
+
186
+ $skin = new Automatic_Upgrader_Skin();
187
+ $upgrader = new Plugin_Upgrader($skin);
188
+
189
+ if(!$skin->request_filesystem_credentials(false, WP_PLUGIN_DIR)) {
190
+ return new WP_Error('no_filesystem_access', __('Failed to get filesystem access', 'pretty-link'));
191
+ }
192
+
193
+ return $upgrader->install($url, $args);
194
+ }
195
+
196
+ public function ajax_install_license_edition() {
197
+ if(!PrliUtils::is_post_request()) {
198
+ wp_send_json_error(__('Bad request', 'pretty-link'));
199
+ }
200
+
201
+ if(!current_user_can('update_plugins')) {
202
+ wp_send_json_error(__('Sorry, you don\'t have permission to do this.', 'pretty-link'));
203
+ }
204
+
205
+ if(!check_ajax_referer('prli_install_license_edition', false, false)) {
206
+ wp_send_json_error(__('Security check failed.', 'pretty-link'));
207
+ }
208
+
209
+ $li = get_site_transient('prli_license_info');
210
+
211
+ if(!empty($li) && is_array($li) && !empty($li['url']) && PrliUtils::is_url($li['url'])) {
212
+ $result = $this->install_plugin_silently($li['url'], array('overwrite_package' => true));
213
+
214
+ if($result instanceof WP_Error) {
215
+ wp_send_json_error($result->get_error_message());
216
+ }
217
+ elseif($result === true) {
218
+ do_action('prli_plugin_edition_changed');
219
+ wp_send_json_success(__('The correct edition of Pretty Links has been installed successfully.', 'pretty-link'));
220
+ }
221
+ else {
222
+ wp_send_json_error(__('Failed to install the correct edition of Pretty Links, please download it from prettylinks.com and install it manually.', 'pretty-link'));
223
+ }
224
+ }
225
+
226
+ wp_send_json_error(__('License data not found', 'pretty-link'));
227
  }
228
 
229
  public function is_activated() {
254
 
255
  if(!empty($aov)) {
256
  update_option('prli_activated', true);
257
+ do_action('prli_license_activated', array('aov' => 1));
258
+ return;
259
  }
260
 
261
+ if(empty($this->mothership_license)) {
262
+ return;
263
+ }
264
 
265
+ // Only check the key once per day
266
+ $option_key = "prli_license_check_{$this->mothership_license}";
267
+
268
+ if(get_site_transient($option_key)) {
269
+ return;
270
+ }
271
+
272
+ $check_count = get_option($option_key, 0) + 1;
273
+ update_option($option_key, $check_count);
274
+
275
+ set_site_transient($option_key, true, ($check_count > 3 ? 72 : 24) * HOUR_IN_SECONDS);
276
+
277
+ $domain = urlencode(PrliUtils::site_domain());
278
+ $args = compact('domain');
279
 
280
  try {
281
+ $act = $this->send_mothership_request("/license_keys/check/{$this->mothership_license}", $args);
282
+
283
+ if(!empty($act) && is_array($act)) {
284
+ $license_expired = false;
285
+
286
+ if(isset($act['expires_at'])) {
287
+ $expires_at = strtotime($act['expires_at']);
288
+
289
+ if($expires_at && $expires_at < time()) {
290
+ $license_expired = true;
291
+ update_option('prli_activated', false);
292
+ do_action('prli_license_expired', $act);
293
+ }
294
+ }
295
 
296
+ if(isset($act['status']) && !$license_expired) {
297
+ if($act['status'] == 'enabled') {
298
+ update_option($option_key, 0);
299
+ update_option('prli_activated', true);
300
+ do_action('prli_license_activated', $act);
301
+ }
302
+ elseif($act['status'] == 'disabled') {
303
+ update_option('prli_activated', false);
304
+ do_action('prli_license_invalidated', $act);
305
+ }
306
+ }
307
  }
308
  }
309
  catch(Exception $e) {
310
+ if($e->getMessage() == 'Not Found') {
311
+ update_option('prli_activated', false);
312
+ do_action('prli_license_invalidated');
313
+ }
314
+ }
315
+ }
316
+
317
+ public function maybe_activate() {
318
+ if($this->is_installed()) {
319
+ $activated = get_option('prli_activated');
320
+
321
+ if(!$activated) {
322
+ $this->check_license_activation();
323
+ }
324
  }
325
  }
326
 
327
  public function activate_from_define() {
328
+ if(!$this->is_installed()) {
329
+ return;
330
+ }
331
 
332
  if(defined('PRETTYLINK_LICENSE_KEY') && $this->mothership_license != PRETTYLINK_LICENSE_KEY) {
 
 
 
 
 
 
 
333
  try {
 
 
334
  if(!empty($this->mothership_license)) {
335
+ // Deactivate the old license key
336
+ $this->deactivate_license();
337
  }
338
 
 
 
 
 
 
 
339
  // If we're using defines then we have to do this with defines too
340
  $this->set_edge_updates(false);
341
 
342
+ $act = $this->activate_license(PRETTYLINK_LICENSE_KEY);
343
+
344
  $message = $act['message'];
345
  $callback = function() use ($message) { require(PRLI_VIEWS_PATH."/admin/errors.php"); };
346
  }
353
  }
354
  }
355
 
356
+ /**
357
+ * Activate the license with the given key
358
+ *
359
+ * @param string $license_key The license key
360
+ * @return array The license data
361
+ * @throws Exception If there was an error activating the license
362
+ */
363
+ public function activate_license($license_key) {
364
+ $args = array(
365
+ 'domain' => urlencode(PrliUtils::site_domain()),
366
+ 'product' => PRLI_EDITION,
367
+ );
368
 
369
+ $act = $this->send_mothership_request("/license_keys/activate/{$license_key}", $args, 'post');
 
 
370
 
371
+ $this->set_mothership_license($license_key);
372
 
373
+ $option_key = "prli_license_check_{$license_key}";
374
+ delete_site_transient($option_key);
375
+ delete_option($option_key);
376
 
377
+ delete_site_transient('prli_update_info');
 
 
378
 
379
+ do_action('prli_license_activated_before_queue_update');
380
+
381
+ $this->manually_queue_update();
382
+
383
+ // Clear the cache of add-ons
384
+ delete_site_transient('prli_addons');
385
+ delete_site_transient('prli_all_addons');
386
+
387
+ do_action('prli_license_activated', $act);
388
+
389
+ return $act;
390
+ }
391
+
392
+ /**
393
+ * Deactivate the license
394
+ *
395
+ * @return array
396
+ */
397
+ public function deactivate_license() {
398
+ $license_key = $this->mothership_license;
399
+ $act = array('message' => __('License key deactivated', 'pretty-link'));
400
+
401
+ if(!empty($this->mothership_license)) {
402
+ try {
403
+ $args = array(
404
+ 'domain' => urlencode(PrliUtils::site_domain())
405
+ );
406
+
407
+ $act = $this->send_mothership_request("/license_keys/deactivate/{$this->mothership_license}", $args, 'post');
408
+ }
409
+ catch(Exception $e) {
410
+ // Catching here to allow invalid license keys to be deactivated
411
+ }
412
  }
413
 
414
+ $this->set_mothership_license('');
415
+
416
+ $option_key = "prli_license_check_{$license_key}";
417
+ delete_site_transient($option_key);
418
+ delete_option($option_key);
419
+
420
+ delete_site_transient('prli_update_info');
421
+
422
+ do_action('prli_license_deactivated_before_queue_update');
423
+
424
+ $this->manually_queue_update();
425
+
426
+ // Don't need to check the mothership for this one ... we just deactivated
427
+ update_option('prli_activated', false);
428
+
429
+ // Clear the cache of the license and add-ons
430
+ delete_site_transient('prli_license_info');
431
+ delete_site_transient('prli_addons');
432
+ delete_site_transient('prli_all_addons');
433
+
434
+ do_action('prli_license_deactivated', $act);
435
+
436
+ return $act;
437
+ }
438
+
439
+ public function deactivate() {
440
+ $act = $this->deactivate_license();
441
+ $this->display_form($act['message']);
442
  }
443
 
444
  public function queue_update($transient, $force=false) {
445
+ if(empty($transient) || !is_object($transient)) {
446
+ return $transient;
447
+ }
448
+
449
  if(!$this->is_installed() && !$this->is_activated()) { return $transient; }
450
 
451
  if($force || (false === ($update_info = get_site_transient('prli_update_info')))) {
476
  set_site_transient(
477
  'prli_license_info',
478
  $license_info,
479
+ (24*HOUR_IN_SECONDS)
480
  );
481
+
482
+ if(PrliUtils::is_incorrect_edition_installed()) {
483
+ $download_url = '';
484
+ }
485
  }
486
  catch(Exception $e) {
487
  try {
511
  compact('curr_version', 'download_url'),
512
  (12*HOUR_IN_SECONDS)
513
  );
 
 
514
  }
515
  else {
516
  extract( $update_info );
635
 
636
  wp_register_script('prli-settings-table', PRLI_JS_URL.'/settings_table.js', array(), PRLI_VERSION);
637
  wp_enqueue_script('prli-activate-js', PRLI_JS_URL.'/admin_activate.js', array('prli-settings-table'), PRLI_VERSION);
638
+ wp_localize_script('prli-activate-js', 'PrliActivateL10n', array(
639
+ 'ajax_url' => admin_url('admin-ajax.php'),
640
+ 'activate_license_nonce' => wp_create_nonce('prli_activate_license'),
641
+ 'loading_image' => sprintf('<img src="%1$s" alt="%2$s" />', esc_url(PRLI_IMAGES_URL . '/square-loader.gif'), esc_attr__('Loading...', 'pretty-link')),
642
+ 'activation_error' => __('An error occurred during activation: %s', 'pretty-link'),
643
+ 'invalid_response' => __('Invalid response.', 'pretty-link'),
644
+ 'ajax_error' => __('Ajax error.', 'pretty-link'),
645
+ 'deactivate_confirm' => sprintf(__('Are you sure? Pretty Links will not be functional on %s if this License Key is deactivated.', 'pretty-link'), PrliUtils::site_domain()),
646
+ 'deactivate_license_nonce' => wp_create_nonce('prli_deactivate_license'),
647
+ 'deactivation_error' => __('An error occurred during deactivation: %s', 'pretty-link'),
648
+ 'install_license_edition_nonce' => wp_create_nonce('prli_install_license_edition'),
649
+ 'error_installing_license_edition' => __('An error occurred while installing the correct edition.', 'pretty-link'),
650
+ ));
651
  }
652
  }
653
 
750
  include_once PRLI_VIEWS_PATH . "/admin/upgrade/import-export.php";
751
  }
752
 
753
+ public static function check_incorrect_edition() {
754
+ if(PrliUtils::is_incorrect_edition_installed()) {
755
+ printf(
756
+ /* translators: %1$s: open link tag, %2$s: close link tag */
757
+ ' <strong>' . esc_html__('To restore automatic updates, %1$sinstall the correct edition%2$s of Pretty Links.', 'pretty-link') . '</strong>',
758
+ sprintf('<a href="%s">', esc_url(admin_url('edit.php?post_type=pretty-link&page=pretty-link-updates'))),
759
+ '</a>'
760
+ );
761
+ }
762
+ }
763
+
764
+ public function clear_update_transients() {
765
+ delete_site_transient('update_plugins');
766
+ delete_site_transient('prli_update_info');
767
+ delete_site_transient('prli_addons');
768
+ delete_site_transient('prli_all_addons');
769
+ }
770
 
771
+ } //End class
app/lib/PrliNotifications.php ADDED
@@ -0,0 +1,739 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if(!defined('ABSPATH')) {die('You are not allowed to call this page directly.');}
3
+
4
+ /**
5
+ * PrliNotifications.
6
+ *
7
+ * Class for logging in-plugin notifications.
8
+ * Includes:
9
+ * Notifications from our remote feed
10
+ * Plugin-related notifications (e.g. recent sales performances)
11
+ */
12
+ class PrliNotifications {
13
+
14
+ /**
15
+ * Source of notifications content.
16
+ *
17
+ * @var string
18
+ */
19
+ const SOURCE_URL = 'https://mbr.press/fajZyA';
20
+ const SOURCE_URL_ARGS = [];
21
+
22
+ /**
23
+ * Option value.
24
+ *
25
+ * @var bool|array
26
+ */
27
+ public $option = false;
28
+
29
+ /**
30
+ * Initialize class.
31
+ */
32
+ public function init() {
33
+
34
+ $this->hooks();
35
+ }
36
+
37
+ /**
38
+ * Register hooks.
39
+ */
40
+ public function hooks() {
41
+
42
+ add_action( 'admin_enqueue_scripts', [ $this, 'enqueues' ] );
43
+ add_action( 'admin_footer', array( $this, 'admin_menu_append_count' ) );
44
+ add_action( 'admin_init', array( $this, 'schedule_fetch' ) );
45
+
46
+ add_action( 'admin_footer', [ $this, 'output' ] );
47
+
48
+ add_action( 'prli_admin_notifications_update', [ $this, 'update' ] );
49
+ add_action( 'wp_ajax_prli_notification_dismiss', [ $this, 'dismiss' ] );
50
+ }
51
+
52
+ /**
53
+ * Check if user has access and is enabled.
54
+ *
55
+ * @return bool
56
+ */
57
+ public static function has_access() {
58
+
59
+ $access = false;
60
+
61
+ if (
62
+ current_user_can( 'manage_options' )
63
+ && ! get_option( 'prli_hide_announcements' )
64
+ ) {
65
+ $access = true;
66
+ }
67
+
68
+ return apply_filters( 'prli_admin_notifications_has_access', $access );
69
+ }
70
+
71
+ /**
72
+ * Get option value.
73
+ *
74
+ * @param bool $cache Reference property cache if available.
75
+ *
76
+ * @return array
77
+ */
78
+ public function get_option( $cache = true ) {
79
+
80
+ if ( $this->option && $cache ) {
81
+ return $this->option;
82
+ }
83
+
84
+ $option = get_option( 'prli_notifications', [] );
85
+
86
+ $this->option = [
87
+ 'update' => ! empty( $option['update'] ) ? $option['update'] : 0,
88
+ 'events' => ! empty( $option['events'] ) ? $option['events'] : [],
89
+ 'feed' => ! empty( $option['feed'] ) ? $option['feed'] : [],
90
+ 'dismissed' => ! empty( $option['dismissed'] ) ? $option['dismissed'] : [],
91
+ ];
92
+
93
+ return $this->option;
94
+ }
95
+
96
+ /**
97
+ * Make sure the feed is fetched when needed.
98
+ *
99
+ * @return void
100
+ */
101
+ public function schedule_fetch() {
102
+
103
+ $option = $this->get_option();
104
+
105
+ // Update notifications using async task.
106
+ if ( empty( $option['update'] ) || time() > $option['update'] + 3 * HOUR_IN_SECONDS ) {
107
+ if ( false === wp_next_scheduled( 'prli_admin_notifications_update' ) ) {
108
+ wp_schedule_single_event( time() + 10, 'prli_admin_notifications_update' );
109
+ }
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Fetch notifications from remote feed.
115
+ *
116
+ * @return array
117
+ */
118
+ public function fetch_feed() {
119
+
120
+ $res = wp_remote_get( self::SOURCE_URL, self::SOURCE_URL_ARGS );
121
+
122
+ if ( is_wp_error( $res ) ) {
123
+ return [];
124
+ }
125
+
126
+ $body = wp_remote_retrieve_body( $res );
127
+
128
+ if ( empty( $body ) ) {
129
+ return [];
130
+ }
131
+
132
+ return $this->verify( json_decode( $body, true ) );
133
+ }
134
+
135
+ /**
136
+ * Verify notification data before it is saved.
137
+ *
138
+ * @param array $notifications Array of notifications items to verify.
139
+ *
140
+ * @return array
141
+ */
142
+ public function verify( $notifications ) {
143
+
144
+ $pl_options = PrliOptions::get_options();
145
+ $license = get_site_transient( 'prli_license_info' );
146
+ global $plp_update;
147
+
148
+ if ( empty( $license['license_key'] ) ) {
149
+ global $plp_update;
150
+ $plp_update->manually_queue_update();
151
+ $license = get_site_transient( 'prli_license_info' );
152
+ }
153
+
154
+ $data = [];
155
+
156
+ if ( ! is_array( $notifications ) || empty( $notifications ) ) {
157
+ return $data;
158
+ }
159
+
160
+ $option = $this->get_option();
161
+
162
+ foreach ( $notifications as $id => $notification ) {
163
+
164
+ // The message should never be empty - if it is, ignore.
165
+ if ( empty( $notification['content'] ) ) {
166
+ continue;
167
+ }
168
+
169
+ // Ignore if license type does not match.
170
+ if ( ! empty( $notification['plans'] ) && ! in_array( PRLI_EDITION, $notification['plans'], true ) ) {
171
+ continue;
172
+ }
173
+
174
+ // Ignore if segment is for expired licenses, but license is current
175
+ if ( 'expired' === $notification['segment'] && ! empty( $plp_update->mothership_license ) && ! empty( $license['license_key']['expires_at'] ) && strtotime( $license['license_key']['expires_at'] ) > time() ) {
176
+ continue;
177
+ }
178
+
179
+ // Ignore if segment is for inactive licenses, but license is active
180
+ if ( 'inactive' === $notification['segment'] && ! empty( $plp_update->mothership_license ) && ! empty( $license['license_key'] ) ) {
181
+ continue;
182
+ }
183
+
184
+ // Ignore if expired.
185
+ if ( ! empty( $notification['end'] ) && time() > strtotime( $notification['end'] ) ) {
186
+ continue;
187
+ }
188
+
189
+ // Ignore if notifcation has already been dismissed.
190
+ if ( ! empty( $option['dismissed'] ) && array_key_exists( $notification['id'], $option['dismissed'] ) ) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
191
+ continue;
192
+ }
193
+
194
+ // Ignore if notification existed before installing the plugin.
195
+ // Prevents bombarding the user with notifications after activation.
196
+ $pl_options = PrliOptions::get_options();
197
+ $activated = $pl_options->activated_timestamp;
198
+
199
+ if (
200
+ ! empty( $activated ) &&
201
+ ! empty( $notification['start'] ) &&
202
+ $activated > strtotime( $notification['start'] )
203
+ ) {
204
+ continue;
205
+ }
206
+
207
+ $data[$id] = $notification;
208
+
209
+ // Check if this notification has already been saved with a timestamp
210
+ if ( ! empty( $option['feed'][$id] ) ) { // Already exists in feed, so use saved time
211
+ $data[$id]['saved'] = $option['feed'][$id]['saved'];
212
+ } else if ( ! empty( $option['events'][$id] ) ) { // Already exists in events, so use saved time
213
+ $data[$id]['saved'] = $option['events'][$id]['saved'];
214
+ } else { // Doesn't exist in feed or events, so save current time
215
+ $data[$id]['saved'] = time();
216
+ }
217
+ }
218
+
219
+ return $data;
220
+ }
221
+
222
+ /**
223
+ * Verify saved notification data for active notifications.
224
+ *
225
+ * @param array $notifications Array of notifications items to verify.
226
+ *
227
+ * @return array
228
+ */
229
+ public function verify_active( $notifications ) {
230
+
231
+ if ( ! is_array( $notifications ) || empty( $notifications ) ) {
232
+ return [];
233
+ }
234
+
235
+ // Remove notfications that are not active.
236
+ foreach ( $notifications as $key => $notification ) {
237
+ if (
238
+ ( ! empty( $notification['start'] ) && strtotime( $notification['start'] . ' America/Denver' ) < strtotime( $notification['start'] . ' America/Denver' ) ) ||
239
+ ( ! empty( $notification['end'] ) && strtotime( $notification['end'] . ' America/Denver' ) > strtotime( $notification['end'] . ' America/Denver' ) )
240
+ ) {
241
+ unset( $notifications[ $key ] );
242
+ }
243
+ }
244
+
245
+ return $notifications;
246
+ }
247
+
248
+ /**
249
+ * Get notification data.
250
+ *
251
+ * @return array
252
+ */
253
+ public function get() {
254
+
255
+ if ( ! self::has_access() ) {
256
+ return [];
257
+ }
258
+
259
+ $option = $this->get_option();
260
+
261
+ $events = ! empty( $option['events'] ) ? $this->verify_active( $option['events'] ) : array();
262
+ $feed = ! empty( $option['feed'] ) ? $this->verify_active( $option['feed'] ) : array();
263
+
264
+ $notifications = array();
265
+ $notifications['active'] = array_merge( $events, $feed );
266
+ $notifications['active'] = $this->get_notifications_with_human_readeable_start_time( $notifications['active'] );
267
+ $notifications['active'] = $this->get_notifications_with_formatted_content( $notifications['active'] );
268
+ $notifications['dismissed'] = ! empty( $option['dismissed'] ) ? $option['dismissed'] : array();
269
+ $notifications['dismissed'] = $this->get_notifications_with_human_readeable_start_time( $notifications['dismissed'] );
270
+ $notifications['dismissed'] = $this->get_notifications_with_formatted_content( $notifications['dismissed'] );
271
+
272
+ return $notifications;
273
+ }
274
+
275
+
276
+ /**
277
+ * Improve format of the content of notifications before display. By default just runs wpautop.
278
+ *
279
+ * @param array $notifications The notifications to be parsed.
280
+ *
281
+ * @return mixed
282
+ */
283
+ public function get_notifications_with_formatted_content( $notifications ) {
284
+ if ( ! is_array( $notifications ) || empty( $notifications ) ) {
285
+ return $notifications;
286
+ }
287
+
288
+ foreach ( $notifications as $key => $notification ) {
289
+ if ( ! empty( $notification['content'] ) ) {
290
+ $notifications[ $key ]['content'] = wpautop( $notification['content'] );
291
+ $notifications[ $key ]['content'] = apply_filters( 'prli_notification_content_display', $notifications[ $key ]['content'] );
292
+ }
293
+ }
294
+
295
+ return $notifications;
296
+ }
297
+
298
+ /**
299
+ * Get notifications start time with human time difference
300
+ *
301
+ * @return array $notifications
302
+ */
303
+ public function get_notifications_with_human_readeable_start_time( $notifications ) {
304
+
305
+ if ( ! is_array( $notifications ) || empty( $notifications ) ) {
306
+ return;
307
+ }
308
+
309
+ foreach ( $notifications as $key => $notification ) {
310
+ if ( ! isset( $notification['start'] ) || empty( $notification['start'] ) ) {
311
+ continue;
312
+ }
313
+
314
+ // Translators: Readable time to display
315
+ $modified_start_time = sprintf( __( '%1$s ago', 'pretty-link' ), human_time_diff( strtotime( $notification['start'] ), current_time( 'timestamp' ) ) );
316
+ $notifications[ $key ]['start'] = $modified_start_time;
317
+ }
318
+
319
+ return $notifications;
320
+ }
321
+
322
+ /**
323
+ * Get notification count.
324
+ *
325
+ * @return int
326
+ */
327
+ public function get_count() {
328
+ return ! empty( $this->get()['active'] ) ? count( $this->get()['active'] ) : 0;
329
+ }
330
+
331
+ /**
332
+ * Add an event notification. This is NOT for feed notifications.
333
+ * Event notifications are for alerting the user to something internally (e.g. recent sales performances).
334
+ *
335
+ * @param array $notification Notification data.
336
+ */
337
+ public function add( $notification ) {
338
+
339
+ if ( empty( $notification['id'] ) ) {
340
+ return;
341
+ }
342
+
343
+ $option = $this->get_option();
344
+
345
+ // Already dismissed
346
+ if ( array_key_exists( $notification['id'], $option['dismissed'] ) ) {
347
+ return;
348
+ }
349
+
350
+ // Already in events
351
+ foreach ( $option['events'] as $item ) {
352
+ if ( $item['id'] === $notification['id'] ) {
353
+ return;
354
+ }
355
+ }
356
+
357
+ // Associative key is notification id.
358
+ $notification = $this->verify( [ $notification['id'] => $notification ] );
359
+
360
+ // The only thing changing here is adding the notification to the events
361
+ update_option(
362
+ 'prli_notifications',
363
+ [
364
+ 'update' => $option['update'],
365
+ 'feed' => $option['feed'],
366
+ 'events' => array_merge( $notification, $option['events'] ),
367
+ 'dismissed' => $option['dismissed'],
368
+ ]
369
+ );
370
+ }
371
+
372
+ /**
373
+ * Update notification data from feed.
374
+ * This pulls the latest notifications from our remote feed.
375
+ */
376
+ public function update() {
377
+
378
+ $feed = $this->fetch_feed();
379
+ $option = $this->get_option();
380
+
381
+ update_option(
382
+ 'prli_notifications',
383
+ [
384
+ 'update' => time(),
385
+ 'feed' => $feed,
386
+ 'events' => $option['events'],
387
+ 'dismissed' => $option['dismissed'],
388
+ ]
389
+ );
390
+ }
391
+
392
+ /**
393
+ * Admin area enqueues.
394
+ */
395
+ public function enqueues() {
396
+
397
+ if ( ! self::has_access() ) {
398
+ return;
399
+ }
400
+
401
+ $notifications = $this->get();
402
+
403
+ if ( empty( $notifications ) ) {
404
+ return;
405
+ }
406
+
407
+ wp_enqueue_style(
408
+ 'prli-admin-notifications',
409
+ PRLI_CSS_URL . "/admin_notifications.css",
410
+ [],
411
+ PRLI_VERSION . "-" . uniqid()
412
+ );
413
+
414
+ wp_enqueue_script(
415
+ 'prli-admin-notifications',
416
+ PRLI_JS_URL . "/admin_notifications.js",
417
+ [ 'jquery' ],
418
+ PRLI_VERSION . "-" . uniqid(),
419
+ true
420
+ );
421
+
422
+ wp_localize_script(
423
+ 'prli-admin-notifications',
424
+ 'PrliAdminNotifications',
425
+ [
426
+ "ajax_url" => admin_url('admin-ajax.php'),
427
+ "nonce" => wp_create_nonce( "prli-admin-notifications" )
428
+ ]
429
+ );
430
+ }
431
+
432
+ /**
433
+ * Admin script for adding notification count to the MemberPress admin menu list item.
434
+ */
435
+ public function admin_menu_append_count() {
436
+
437
+ $notifications = $this->get();
438
+
439
+ if ( empty( $notifications['active'] ) || count( $notifications['active'] ) < 1 ) {
440
+ return;
441
+ }
442
+
443
+ ob_start();
444
+
445
+ ?>
446
+
447
+ <span class="awaiting-mod">
448
+ <span class="pending-count" id="prliAdminMenuUnreadCount" aria-hidden="true"><?php echo count( $notifications['active'] ); ?></span>
449
+ <span class="comments-in-moderation-text screen-reader-text"><?php printf( _n( '%s unread message', '%s unread messages', count( $notifications['active'] ), 'pretty-link' ), count( $notifications['active'] ) ); ?></span>
450
+ </span>
451
+
452
+ <?php $output = ob_get_clean(); ?>
453
+
454
+ <script>
455
+ jQuery(document).ready(function($) {
456
+ $('li.menu-icon-pretty-link .wp-menu-name').append(`<?php echo $output; ?>`);
457
+ });
458
+ </script>
459
+
460
+ <?php
461
+ }
462
+
463
+ /**
464
+ * Output notifications in MemberPress admin area.
465
+ */
466
+ public function output() {
467
+
468
+ if ( empty( $_GET['post_type'] ) || 'pretty-link' !== $_GET['post_type'] ) {
469
+ return;
470
+ }
471
+
472
+ $notifications = $this->get();
473
+
474
+ if ( empty( $notifications['active'] ) && empty( $notifications['dismissed'] ) ) {
475
+ return;
476
+ }
477
+
478
+ $notifications_html = '<div class="active-messages">';
479
+ if ( ! empty( $notifications['active'] ) ) {
480
+ foreach ( $notifications['active'] as $notification ) {
481
+
482
+ // Buttons HTML.
483
+ $buttons_html = '';
484
+ if ( ! empty( $notification['buttons'] ) && is_array( $notification['buttons'] ) ) {
485
+ foreach ( $notification['buttons'] as $btn_type => $btn ) {
486
+ if ( empty( $btn['url'] ) || empty( $btn['text'] ) ) {
487
+ continue;
488
+ }
489
+ $buttons_html .= sprintf(
490
+ '<a href="%1$s" class="button button-%2$s"%3$s>%4$s</a>',
491
+ ! empty( $btn['url'] ) ? esc_url( $btn['url'] ) : '',
492
+ $btn_type === 'main' ? 'primary' : 'secondary',
493
+ ! empty( $btn['prlirget'] ) && $btn['prlirget'] === '_blank' ? ' target="_blank" rel="noopener noreferrer"' : '',
494
+ ! empty( $btn['text'] ) ? sanitize_text_field( $btn['text'] ) : ''
495
+ );
496
+ }
497
+ $buttons_html .= sprintf( '<button class="prli-notice-dismiss" data-message-id="%s">%s</button>', $notification['id'], __( 'Dismiss', 'pretty-link' ) );
498
+ $buttons_html = ! empty( $buttons_html ) ? '<div class="prli-notifications-buttons">' . $buttons_html . '</div>' : '';
499
+ }
500
+
501
+ $time_diff = ceil( ( time() - $notification['saved'] ) );
502
+ $time_diff_string = '';
503
+ if ( $time_diff < MINUTE_IN_SECONDS ) {
504
+ $time_diff_string = sprintf( _n( '%s second ago', '%s seconds ago', $time_diff, 'pretty-link' ), $time_diff );
505
+ } else if ( $time_diff < HOUR_IN_SECONDS ) {
506
+ $time_diff_string = sprintf( _n( '%s minute ago', '%s minutes ago', ceil( ( $time_diff / MINUTE_IN_SECONDS ) ), 'pretty-link' ), ceil( ( $time_diff / MINUTE_IN_SECONDS ) ) );
507
+ } else if ( $time_diff < DAY_IN_SECONDS ) {
508
+ $time_diff_string = sprintf( _n( '%s hour ago', '%s hours ago', ceil( ( $time_diff / HOUR_IN_SECONDS ) ), 'pretty-link' ), ceil( ( $time_diff / HOUR_IN_SECONDS ) ) );
509
+ } else if ( $time_diff < WEEK_IN_SECONDS ) {
510
+ $time_diff_string = sprintf( _n( '%s day ago', '%s days ago', ceil( ( $time_diff / DAY_IN_SECONDS ) ), 'pretty-link' ), ceil( ( $time_diff / DAY_IN_SECONDS ) ) );
511
+ } else if ( $time_diff < MONTH_IN_SECONDS ) {
512
+ $time_diff_string = sprintf( _n( '%s week ago', '%s weeks ago', ceil( ( $time_diff / WEEK_IN_SECONDS ) ), 'pretty-link' ), ceil( ( $time_diff / WEEK_IN_SECONDS ) ) );
513
+ } else if ( $time_diff < YEAR_IN_SECONDS ) {
514
+ $time_diff_string = sprintf( _n( '%s month ago', '%s months ago', ceil( ( $time_diff / MONTH_IN_SECONDS ) ), 'pretty-link' ), ceil( ( $time_diff / MONTH_IN_SECONDS ) ) );
515
+ } else {
516
+ $time_diff_string = sprintf( _n( '%s year ago', '%s years ago', ceil( ( $time_diff / YEAR_IN_SECONDS ) ), 'pretty-link' ), ceil( ( $time_diff / YEAR_IN_SECONDS ) ) );
517
+ }
518
+
519
+ // Notification HTML.
520
+ $notifications_html .= sprintf(
521
+ '<div id="prli-notifications-message-%4$s" class="prli-notifications-message" data-message-id="%4$s">
522
+ <div class="prli-notification-icon-title">
523
+ <img src="%5$s" width="32" height="32">
524
+ <h3 class="prli-notifications-title">%1$s</h3>
525
+ <time datetime="%6$s">%7$s</time>
526
+ </div>
527
+ <div class="prli-notifications-content">%2$s</div>
528
+ %3$s
529
+ </div>',
530
+ ! empty( $notification['title'] ) ? sanitize_text_field( $notification['title'] ) : '',
531
+ ! empty( $notification['content'] ) ? apply_filters( 'the_content', $notification['content'] ) : '',
532
+ $buttons_html,
533
+ ! empty( $notification['id'] ) ? esc_attr( sanitize_text_field( $notification['id'] ) ) : 0,
534
+ ! empty( $notification['icon'] ) ? esc_url( sanitize_text_field( $notification['icon'] ) ) : '',
535
+ date( 'Y-m-d G:i a', $notification['saved'] ),
536
+ $time_diff_string
537
+ );
538
+ }
539
+ }
540
+ $notifications_html .= sprintf( '<div class="prli-notifications-none" %s>%s</div>', empty( $notifications['active'] ) || count( $notifications['active'] ) < 1 ? '' : 'style="display: none;"', __( 'You\'re all caught up!', 'pretty-link' ) );
541
+ $notifications_html .= '</div>';
542
+
543
+ $notifications_html .= '<div class="dismissed-messages">';
544
+ if ( ! empty( $notifications['dismissed'] ) ) {
545
+ foreach ( $notifications['dismissed'] as $notification ) {
546
+
547
+ // Buttons HTML.
548
+ $buttons_html = '';
549
+ if ( ! empty( $notification['buttons'] ) && is_array( $notification['buttons'] ) ) {
550
+ foreach ( $notification['buttons'] as $btn_type => $btn ) {
551
+ if ( empty( $btn['url'] ) || empty( $btn['text'] ) ) {
552
+ continue;
553
+ }
554
+ $buttons_html .= sprintf(
555
+ '<a href="%1$s" class="button button-%2$s"%3$s>%4$s</a>',
556
+ ! empty( $btn['url'] ) ? esc_url( $btn['url'] ) : '',
557
+ $btn_type === 'main' ? 'primary' : 'secondary',
558
+ ! empty( $btn['prlirget'] ) && $btn['prlirget'] === '_blank' ? ' target="_blank" rel="noopener noreferrer"' : '',
559
+ ! empty( $btn['text'] ) ? sanitize_text_field( $btn['text'] ) : ''
560
+ );
561
+ }
562
+ $buttons_html .= sprintf( '<button class="prli-notice-dismiss" data-message-id="%s">%s</button>', $notification['id'], __( 'Dismiss', 'pretty-link' ) );
563
+ $buttons_html = ! empty( $buttons_html ) ? '<div class="prli-notifications-buttons">' . $buttons_html . '</div>' : '';
564
+ }
565
+
566
+ $time_diff = ceil( ( time() - $notification['saved'] ) );
567
+ $time_diff_string = '';
568
+ if ( $time_diff < MINUTE_IN_SECONDS ) {
569
+ $time_diff_string = sprintf( _n( '%s second ago', '%s seconds ago', $time_diff, 'pretty-link' ), $time_diff );
570
+ } else if ( $time_diff < HOUR_IN_SECONDS ) {
571
+ $time_diff_string = sprintf( _n( '%s minute ago', '%s minutes ago', ceil( ( $time_diff / MINUTE_IN_SECONDS ) ), 'pretty-link' ), ceil( ( $time_diff / MINUTE_IN_SECONDS ) ) );
572
+ } else if ( $time_diff < DAY_IN_SECONDS ) {
573
+ $time_diff_string = sprintf( _n( '%s hour ago', '%s hours ago', ceil( ( $time_diff / HOUR_IN_SECONDS ) ), 'pretty-link' ), ceil( ( $time_diff / HOUR_IN_SECONDS ) ) );
574
+ } else if ( $time_diff < WEEK_IN_SECONDS ) {
575
+ $time_diff_string = sprintf( _n( '%s day ago', '%s days ago', ceil( ( $time_diff / DAY_IN_SECONDS ) ), 'pretty-link' ), ceil( ( $time_diff / DAY_IN_SECONDS ) ) );
576
+ } else if ( $time_diff < MONTH_IN_SECONDS ) {
577
+ $time_diff_string = sprintf( _n( '%s week ago', '%s weeks ago', ceil( ( $time_diff / WEEK_IN_SECONDS ) ), 'pretty-link' ), ceil( ( $time_diff / WEEK_IN_SECONDS ) ) );
578
+ } else if ( $time_diff < YEAR_IN_SECONDS ) {
579
+ $time_diff_string = sprintf( _n( '%s month ago', '%s months ago', ceil( ( $time_diff / MONTH_IN_SECONDS ) ), 'pretty-link' ), ceil( ( $time_diff / MONTH_IN_SECONDS ) ) );
580
+ } else {
581
+ $time_diff_string = sprintf( _n( '%s year ago', '%s years ago', ceil( ( $time_diff / YEAR_IN_SECONDS ) ), 'pretty-link' ), ceil( ( $time_diff / YEAR_IN_SECONDS ) ) );
582
+ }
583
+
584
+ // Notification HTML.
585
+ $notifications_html .= sprintf(
586
+ '<div id="prli-notifications-message-%4$s" class="prli-notifications-message" data-message-id="%4$s">
587
+ <div class="prli-notification-icon-title">
588
+ <img src="%5$s" width="32" height="32">
589
+ <h3 class="prli-notifications-title">%1$s</h3>
590
+ <time datetime="%6$s">%7$s</time>
591
+ </div>
592
+ <div class="prli-notifications-content">%2$s</div>
593
+ %3$s
594
+ </div>',
595
+ ! empty( $notification['title'] ) ? sanitize_text_field( $notification['title'] ) : '',
596
+ ! empty( $notification['content'] ) ? apply_filters( 'the_content', $notification['content'] ) : '',
597
+ $buttons_html,
598
+ ! empty( $notification['id'] ) ? esc_attr( sanitize_text_field( $notification['id'] ) ) : 0,
599
+ ! empty( $notification['icon'] ) ? esc_url( sanitize_text_field( $notification['icon'] ) ) : '',
600
+ date( 'Y-m-d G:i a', $notification['saved'] ),
601
+ $time_diff_string
602
+ );
603
+ }
604
+ }
605
+ $notifications_html .= '</div>';
606
+ ?>
607
+
608
+ <div id="prli-notifications">
609
+
610
+ <div class="prli-notifications-container">
611
+
612
+ <div class="prli-notifications-top-title">
613
+ <div class="prli-notifications-top-title__left">
614
+ <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>
615
+ <h3><?php _e( 'Inbox', 'pretty-link' ); ?></h3>
616
+ </div>
617
+ <div class="prli-notifications-top-title__right actions">
618
+ <a href="#" id="viewDismissed"><?php _e( 'View Dismissed', 'pretty-link' ); ?></a>
619
+ <a href="#" id="viewActive"><?php _e( 'View Active', 'pretty-link' ); ?></a>
620
+ <a href="#" id="prliNotificationsClose" class="close" title="<?php _e( 'Close', 'pretty-link' ); ?>">
621
+ <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>
622
+ </a>
623
+ </div>
624
+ </div>
625
+ <div class="prli-notifications-header <?php echo ! empty( $notifications['active'] ) && count( $notifications['active'] ) < 10 ? 'single-digit' : ''; ?>">
626
+ <div class="prli-notifications-header-bell">
627
+ <div class="prli-notifications-bell">
628
+ <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>
629
+ <?php if ( ! empty( $notifications['active'] ) ) : ?>
630
+ <span id="prliNotificationsCountTray" class="prli-notifications-count"><?php echo count( $notifications['active'] ); ?></span>
631
+ <?php endif; ?>
632
+ </div>
633
+ <div class="prli-notifications-title"><?php esc_html_e( 'Notifications', 'pretty-link' ); ?></div>
634
+ </div>
635
+ <?php if ( ! empty( $notifications['active'] ) ) : ?>
636
+ <button id="dismissAll" class="dismiss-all"><?php _e( 'Dismiss All', 'pretty-link' ); ?></button>
637
+ <?php endif; ?>
638
+ </div>
639
+
640
+ <div class="prli-notifications-body">
641
+ <div class="prli-notifications-messages">
642
+ <?php echo $notifications_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
643
+ </div>
644
+ </div>
645
+
646
+ </div>
647
+
648
+ </div>
649
+ <?php
650
+ }
651
+
652
+ /**
653
+ * Dismiss notification(s) via AJAX.
654
+ */
655
+ public function dismiss() {
656
+
657
+ // Run a security check.
658
+ check_ajax_referer( 'prli-admin-notifications', 'nonce' );
659
+
660
+ // Check for access and required param.
661
+ if ( ! self::has_access() || empty( $_POST['id'] ) ) {
662
+ wp_send_json_error();
663
+ }
664
+
665
+ $id = sanitize_text_field( wp_unslash( $_POST['id'] ) );
666
+ $option = $this->get_option();
667
+
668
+ if ( 'all' === $id ) { // Dismiss all notifications
669
+
670
+ // Feed notifications
671
+ if ( ! empty( $option['feed'] ) ) {
672
+ foreach ( $option['feed'] as $key => $notification ) {
673
+ $option['dismissed'][$key] = $option['feed'][$key];
674
+ unset( $option['feed'][$key] );
675
+ }
676
+ }
677
+
678
+ // Event notifications
679
+ if ( ! empty( $option['events'] ) ) {
680
+ foreach ( $option['events'] as $key => $notification ) {
681
+ $option['dismissed'][$key] = $option['events'][$key];
682
+ unset( $option['events'][$key] );
683
+ }
684
+ }
685
+
686
+ } else { // Dismiss one notification
687
+
688
+ // Event notifications need a prefix to distinguish them from feed notifications
689
+ // For a naming convention, we'll use "event_{timestamp}"
690
+ // If the notification ID includes "event_", we know it's an even notification
691
+ $type = false !== strpos( $id, 'event_' ) ? 'events' : 'feed';
692
+
693
+ if( $type == 'events' ){
694
+ if( !empty($option[$type]) ){
695
+ foreach( $option[$type] as $index => $event_notification ){
696
+ if( $event_notification['id'] == $id ){
697
+ unset( $option[$type][$index] );
698
+ break;
699
+ }
700
+ }
701
+ }
702
+ }else{
703
+ if ( ! empty( $option[$type][$id] ) ) {
704
+ $option['dismissed'][$id] = $option[$type][$id];
705
+ unset( $option[$type][$id] );
706
+ }
707
+ }
708
+ }
709
+
710
+
711
+ update_option( 'prli_notifications', $option );
712
+
713
+ wp_send_json_success();
714
+ }
715
+
716
+ public function dismiss_events( $type ) {
717
+
718
+ $option = $this->get_option();
719
+
720
+ // Event notifications.
721
+ if ( ! empty( $option['events'] ) ) {
722
+ $found = 0;
723
+ foreach ( $option['events'] as $key => $notification ) {
724
+ // We found event.
725
+ if( $type === $notification['type'] ){
726
+ unset($option['events'][$key]);
727
+ $found = 1;
728
+ }
729
+ }
730
+
731
+ if( $found ){
732
+ update_option( 'prli_notifications', $option );
733
+ }
734
+ }
735
+ }
736
+ }
737
+
738
+ $prli_notifications = new PrliNotifications;
739
+ $prli_notifications->init();
app/models/PrliLink.php CHANGED
@@ -518,7 +518,7 @@ class PrliLink {
518
 
519
  $decoded_urls = array_map(
520
  function($url) {
521
- return html_entity_decode(rawurldecode($url));
522
  },
523
  $urls
524
  );
@@ -550,9 +550,9 @@ class PrliLink {
550
  CONCAT(%s, li.slug) AS pretty_url
551
  FROM {$this->table_name} AS li
552
  WHERE li.link_status='enabled'
553
- AND li.url {$where}
554
  ";
555
  $query = $wpdb->prepare($query, $prli_blogurl.PrliUtils::get_permalink_pre_slug_uri());
 
556
 
557
  $results = (array)$wpdb->get_results($query);
558
 
518
 
519
  $decoded_urls = array_map(
520
  function($url) {
521
+ return esc_url_raw(html_entity_decode(rawurldecode($url)));
522
  },
523
  $urls
524
  );
550
  CONCAT(%s, li.slug) AS pretty_url
551
  FROM {$this->table_name} AS li
552
  WHERE li.link_status='enabled'
 
553
  ";
554
  $query = $wpdb->prepare($query, $prli_blogurl.PrliUtils::get_permalink_pre_slug_uri());
555
+ $query .= " AND li.url {$where}";
556
 
557
  $results = (array)$wpdb->get_results($query);
558
 
app/models/PrliOptions.php CHANGED
@@ -43,6 +43,7 @@ class PrliOptions
43
 
44
  public function set_default_options() {
45
  // Must account for the Legacy Options
 
46
  $prli_exclude_ips = 'prli_exclude_ips';
47
  $prettybar_image_url = 'prli_prettybar_image_url';
48
  $prettybar_background_image_url = 'prli_prettybar_background_image_url';
@@ -68,6 +69,10 @@ class PrliOptions
68
  $link_sponsored = 'prli_link_sponsored';
69
  $link_redirect_type = 'prli_link_redirect_type';
70
 
 
 
 
 
71
  if(!isset($this->prettybar_show_title)) {
72
  if($var = get_option( $prettybar_show_title )) {
73
  $this->prettybar_show_title = $var;
43
 
44
  public function set_default_options() {
45
  // Must account for the Legacy Options
46
+ $activated_timestamp = 'activated_timestamp';
47
  $prli_exclude_ips = 'prli_exclude_ips';
48
  $prettybar_image_url = 'prli_prettybar_image_url';
49
  $prettybar_background_image_url = 'prli_prettybar_background_image_url';
69
  $link_sponsored = 'prli_link_sponsored';
70
  $link_redirect_type = 'prli_link_redirect_type';
71
 
72
+ if(!isset($this->activated_timestamp)) {
73
+ $this->activated_timestamp = time();
74
+ }
75
+
76
  if(!isset($this->prettybar_show_title)) {
77
  if($var = get_option( $prettybar_show_title )) {
78
  $this->prettybar_show_title = $var;
app/models/PrliUtils.php CHANGED
@@ -377,7 +377,7 @@ class PrliUtils {
377
  $ipaddress = $ips[0]; //Fix for flywheel
378
  }
379
 
380
- return $ipaddress;
381
  }
382
 
383
  public function get_custom_forwarding_rule($param_struct) {
@@ -1279,5 +1279,61 @@ class PrliUtils {
1279
  public static function clamp($x, $min, $max) {
1280
  return min(max($x, $min), $max);
1281
  }
1282
- }
1283
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
377
  $ipaddress = $ips[0]; //Fix for flywheel
378
  }
379
 
380
+ return apply_filters('pl_get_current_client_ip', $ipaddress);
381
  }
382
 
383
  public function get_custom_forwarding_rule($param_struct) {
1279
  public static function clamp($x, $min, $max) {
1280
  return min(max($x, $min), $max);
1281
  }
 
1282
 
1283
+ /**
1284
+ * Get the edition data from a product slug
1285
+ *
1286
+ * @param string $product_slug
1287
+ * @return array|null
1288
+ */
1289
+ public static function get_edition($product_slug) {
1290
+ $editions = array(
1291
+ array('index' => 0, 'slug' => 'pretty-link-beginner', 'name' => 'Pretty Links Pro Beginner'),
1292
+ array('index' => 1, 'slug' => 'pretty-link-pro-blogger', 'name' => 'Pretty Links Pro Blogger'),
1293
+ array('index' => 2, 'slug' => 'pretty-link-marketer', 'name' => 'Pretty Links Pro Marketer'),
1294
+ array('index' => 3, 'slug' => 'pretty-link-super-affiliate', 'name' => 'Pretty Links Pro Super Affiliate'),
1295
+ array('index' => 4, 'slug' => 'pretty-link-executive', 'name' => 'Pretty Links Pro Executive'),
1296
+ array('index' => 5, 'slug' => 'pretty-link-pro-developer', 'name' => 'Pretty Links Pro Developer'),
1297
+ );
1298
+
1299
+ foreach($editions as $edition) {
1300
+ if($product_slug == $edition['slug']) {
1301
+ return $edition;
1302
+ }
1303
+ }
1304
+
1305
+ return null;
1306
+ }
1307
+
1308
+ /**
1309
+ * Is the installed edition of Pretty Links different from the edition in the license?
1310
+ *
1311
+ * @return array|false An array containing the installed edition and license edition data, false if the correct edition is installed
1312
+ */
1313
+ public static function is_incorrect_edition_installed() {
1314
+ $license = get_site_transient('prli_license_info');
1315
+ $license_product_slug = !empty($license) && !empty($license['product_slug']) ? $license['product_slug'] : '';
1316
+
1317
+ if(
1318
+ empty($license_product_slug) ||
1319
+ empty(PRLI_EDITION) ||
1320
+ $license_product_slug == PRLI_EDITION ||
1321
+ !current_user_can('update_plugins') ||
1322
+ @is_dir(PRLI_PATH . '/.git')
1323
+ ) {
1324
+ return false;
1325
+ }
1326
+
1327
+ $installed_edition = self::get_edition(PRLI_EDITION);
1328
+ $license_edition = self::get_edition($license_product_slug);
1329
+
1330
+ if(!is_array($installed_edition) || !is_array($license_edition)) {
1331
+ return false;
1332
+ }
1333
+
1334
+ return array(
1335
+ 'installed' => $installed_edition,
1336
+ 'license' => $license_edition
1337
+ );
1338
+ }
1339
+ }
app/views/admin/update/active_license.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if(!defined('ABSPATH')) {die('You are not allowed to call this page directly.');} ?>
2
+ <?php
3
+ if(!isset($editions)) {
4
+ $editions = PrliUtils::is_incorrect_edition_installed();
5
+ }
6
+
7
+ if(is_array($editions)) {
8
+ printf(
9
+ '<div class="notice notice-warning inline"><p>%1$s<img id="prli-install-license-edition-loading" class="prli-hidden" src="%2$s" alt="%3$s" /></p></div>',
10
+ sprintf(
11
+ /* translators: %1$s: the license edition, %2$s: the installed edition, %3$s: open link tag, %4$s: close link tag */
12
+ esc_html__('This License Key is for %1$s, but %2$s is installed. %3$sClick here%4$s to install the correct edition for the license (%1$s).', 'pretty-link'),
13
+ '<strong>' . esc_html($editions['license']['name']) . '</strong>',
14
+ '<strong>' . esc_html($editions['installed']['name']) . '</strong>',
15
+ '<a id="prli-install-license-edition" href="#">',
16
+ '</a>'
17
+ ),
18
+ esc_url(PRLI_IMAGES_URL . '/square-loader.gif'),
19
+ esc_html__('Loading...', 'pretty-link')
20
+ );
21
+ }
22
+ ?>
23
+ <div class="prli-license-active">
24
+ <div><h4><?php esc_html_e('Active License Key Information:', 'pretty-link'); ?></h4></div>
25
+ <table>
26
+ <tr>
27
+ <td><?php esc_html_e('License Key:', 'pretty-link'); ?></td>
28
+ <td>********-****-****-****-<?php echo esc_html(substr($li['license_key']['license'], -12)); ?></td>
29
+ </tr>
30
+ <tr>
31
+ <td><?php esc_html_e('Status:', 'pretty-link'); ?></td>
32
+ <td><b><?php echo esc_html(sprintf(__('Active on %s', 'pretty-link'), PrliUtils::site_domain())); ?></b></td>
33
+ </tr>
34
+ <tr>
35
+ <td><?php esc_html_e('Product:', 'pretty-link'); ?></td>
36
+ <td><?php echo esc_html($li['product_name']); ?></td>
37
+ </tr>
38
+ <tr>
39
+ <td><?php esc_html_e('Activations:', 'pretty-link'); ?></td>
40
+ <td>
41
+ <?php
42
+ printf(
43
+ /* translators: %1$s: open b tag, %2$s: close b tag, %3$d: current activation count, %4$s: max activations */
44
+ esc_html__('%1$s%3$d of %4$s%2$s sites have been activated with this license key', 'pretty-link'),
45
+ '<b>',
46
+ '</b>',
47
+ esc_html($li['activation_count']),
48
+ esc_html(ucwords($li['max_activations']))
49
+ );
50
+ ?>
51
+ </td>
52
+ </tr>
53
+ </table>
54
+ <div class="prli-deactivate-button">
55
+ <button type="button" id="prli-deactivate-license-key" class="button button-primary"><?php echo esc_html(sprintf(__('Deactivate License Key on %s', 'pretty-link'), PrliUtils::site_domain())); ?></button>
56
+ </div>
57
+ </div>
58
+ <?php if(!$this->is_installed()): ?>
59
+ <div><a href="<?php echo esc_url($this->update_plugin_url()); ?>" class="button button-primary"><?php esc_html_e('Upgrade plugin to Pro', 'pretty-link'); ?></a></div>
60
+ <div>&nbsp;</div>
61
+ <?php endif; ?>
62
+ <?php require PRLI_VIEWS_PATH . '/admin/update/edge_updates.php'; ?>
63
+ <br/>
64
+ <div id="prli-version-string"><?php printf(esc_html__("You're currently running version %s of Pretty Links Pro", 'pretty-link'), '<b>'.esc_html(PRLI_VERSION).'</b>'); ?></div>
app/views/admin/update/inactive_license.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if(!defined('ABSPATH')) {die('You are not allowed to call this page directly.');} ?>
2
+ <p class="description">
3
+ <?php
4
+ printf(
5
+ /* translators: %1$s: link to pro site, %2$s: link to pro site login page */
6
+ esc_html__('You must have a License Key to enable automatic updates for Pretty Links Pro. If you don\'t have a License please go to %1$s to get one. If you do have a license you can login at %2$s to manage your licenses and site activations.', 'pretty-link'),
7
+ '<a href="https://prettylinks.com/pl/license-alert/buy">prettylinks.com</a>',
8
+ '<a href="https://prettylinks.com/pl/license-alert/login">prettylinks.com/login</a>'
9
+ );
10
+ ?>
11
+ </p>
12
+
13
+ <table class="form-table">
14
+ <tr class="form-field">
15
+ <td valign="top" width="225px"><label for="prli-license-key"><?php esc_html_e('Enter Your Pretty Links Pro License Key:', 'pretty-link'); ?></label></td>
16
+ <td>
17
+ <input type="text" id="prli-license-key" value="<?php echo esc_attr($this->mothership_license); ?>" />
18
+ </td>
19
+ </tr>
20
+ </table>
21
+ <p class="submit">
22
+ <button type="button" id="prli-activate-license-key" class="button button-primary"><?php echo esc_html(sprintf(__('Activate License Key on %s', 'pretty-link'), PrliUtils::site_domain())); ?></button>
23
+ </p>
24
+
25
+ <?php if(!$this->is_installed()): ?>
26
+ <div>&nbsp;</div>
27
+
28
+ <div class="prli-page-title" id="prli_upgrade"><?php esc_html_e('Upgrade to Pro', 'pretty-link'); ?></div>
29
+
30
+ <div>
31
+ <?php
32
+ printf(
33
+ /* translators: %1$s: open link tag, %2$s: close link tag */
34
+ esc_html__('It looks like you haven\'t %1$supgraded to Pretty Links Pro%2$s yet. Here are just a few things you could be doing with pro:', 'pretty-link'),
35
+ '<a href="https://prettylinks.com/pl/license-alert/upgrade" target="_blank">',
36
+ '</a>'
37
+ );
38
+ ?>
39
+ </div>
40
+
41
+ <div>&nbsp;</div>
42
+
43
+ <ul style="padding-left: 25px;">
44
+ <li>&bullet; <?php esc_html_e('Auto-replace keywords throughout your site with Pretty Links', 'pretty-link'); ?></li>
45
+ <li>&bullet; <?php esc_html_e('Protect your affiliate links by using Cloaked Redirects', 'pretty-link'); ?></li>
46
+ <li>&bullet; <?php esc_html_e('Redirect based on a visitor\'s location', 'pretty-link'); ?></li>
47
+ <li>&bullet; <?php esc_html_e('Auto-prettylink your Pages &amp; Posts', 'pretty-link'); ?></li>
48
+ <li>&bullet; <?php esc_html_e('Find out what works and what doesn\'t by split testing your links', 'pretty-link'); ?></li>
49
+ <li>&bullet; <?php esc_html_e('And much, much more!', 'pretty-link'); ?></li>
50
+ </ul>
51
+
52
+ <div>&nbsp;</div>
53
+ <div><?php esc_html_e('Plus, upgrading is fast, easy and won\'t disrupt any of your existing links or data. And there\'s even a 14 day money back guarantee.', 'pretty-link'); ?></div>
54
+ <div>&nbsp;</div>
55
+ <div><?php esc_html_e('We think you\'ll love it!', 'pretty-link'); ?></div>
56
+ <div>&nbsp;</div>
57
+ <div><a href="https://prettylinks.com/pl/license-alert/upgrade-1" class="button button-primary"><?php esc_html_e('Upgrade to Pro today!', 'pretty-link'); ?></a></div>
58
+ <?php endif; ?>
app/views/admin/update/license.php DELETED
@@ -1,112 +0,0 @@
1
- <?php if(!defined('ABSPATH')) {die('You are not allowed to call this page directly.');} ?>
2
- <?php
3
- global $plp_update;
4
- $mothership_license_str = isset($_POST[$plp_update->mothership_license_str]) ? sanitize_key($_POST[$plp_update->mothership_license_str]) : $plp_update->mothership_license;
5
- ?>
6
-
7
- <div class="prli-page-title"><?php esc_html_e('Pretty Links Pro License', 'pretty-link'); ?></div>
8
-
9
- <?php if( !isset($li) or empty($li) ): ?>
10
- <p class="description">
11
- <?php
12
- printf(
13
- // translators: %1$s: link to pro site, %2$s: link to pro site login page
14
- esc_html__('You must have a License Key to enable automatic updates for Pretty Links Pro. If you don\'t have a License please go to %1$s to get one. If you do have a license you can login at %2$s to manage your licenses and site activations.', 'pretty-link'),
15
- '<a href="https://prettylinks.com/pl/license-alert/buy">prettylinks.com</a>',
16
- '<a href="https://prettylinks.com/pl/license-alert/login">prettylinks.com/login</a>'
17
- );
18
- ?>
19
- </p>
20
- <form name="activation_form" method="post" action="">
21
- <?php wp_nonce_field('activation_form'); ?>
22
-
23
- <table class="form-table">
24
- <tr class="form-field">
25
- <td valign="top" width="225px"><?php esc_html_e('Enter Your Pretty Links Pro License Key:', 'pretty-link'); ?></td>
26
- <td>
27
- <input type="text" name="<?php echo esc_attr($plp_update->mothership_license_str); ?>" value="<?php echo esc_attr($mothership_license_str); ?>"/>
28
- </td>
29
- </tr>
30
- </table>
31
- <p class="submit">
32
- <input type="submit" name="Submit" class="button button-primary" value="<?php echo esc_attr(sprintf(__('Activate License Key on %s', 'pretty-link'), PrliUtils::site_domain())); ?>" />
33
- </p>
34
- </form>
35
-
36
- <?php if(!$plp_update->is_installed()): ?>
37
- <div>&nbsp;</div>
38
-
39
- <div class="prli-page-title" id="prli_upgrade"><?php esc_html_e('Upgrade to Pro', 'pretty-link'); ?></div>
40
-
41
- <div>
42
- <?php
43
- printf(
44
- // translators: %1$s: open link tag, %2$s: close link tag
45
- esc_html__('It looks like you haven\'t %1$supgraded to Pretty Links Pro%2$s yet. Here are just a few things you could be doing with pro:', 'pretty-link'),
46
- '<a href="https://prettylinks.com/pl/license-alert/upgrade" target="_blank">',
47
- '</a>'
48
- );
49
- ?>
50
- </div>
51
-
52
- <div>&nbsp;</div>
53
-
54
- <ul style="padding-left: 25px;">
55
- <li>&bullet; <?php esc_html_e('Auto-replace keywords throughout your site with Pretty Links', 'pretty-link'); ?></li>
56
- <li>&bullet; <?php esc_html_e('Protect your affiliate links by using Cloaked Redirects', 'pretty-link'); ?></li>
57
- <li>&bullet; <?php esc_html_e('Redirect based on a visitor\'s location', 'pretty-link'); ?></li>
58
- <li>&bullet; <?php esc_html_e('Auto-prettylink your Pages &amp; Posts', 'pretty-link'); ?></li>
59
- <li>&bullet; <?php esc_html_e('Find out what works and what doesn\'t by split testing your links', 'pretty-link'); ?></li>
60
- <li>&bullet; <?php esc_html_e('And much, much more!', 'pretty-link'); ?></li>
61
- </ul>
62
-
63
- <div>&nbsp;</div>
64
- <div><?php esc_html_e('Plus, upgrading is fast, easy and won\'t disrupt any of your existing links or data. And there\'s even a 14 day money back guarantee.', 'pretty-link'); ?></div>
65
- <div>&nbsp;</div>
66
- <div><?php esc_html_e('We think you\'ll love it!', 'pretty-link'); ?></div>
67
- <div>&nbsp;</div>
68
- <div><a href="https://prettylinks.com/pl/license-alert/upgrade-1" class="button button-primary"><?php esc_html_e('Upgrade to Pro today!', 'pretty-link'); ?></a></div>
69
- <?php endif; ?>
70
- <?php else: ?>
71
- <div class="prli-license-active">
72
- <div><h4><?php esc_html_e('Active License Key Information:', 'pretty-link'); ?></h4></div>
73
- <table>
74
- <tr>
75
- <td><?php esc_html_e('License Key:', 'pretty-link'); ?></td>
76
- <td>********-****-****-****-<?php echo esc_html(substr($li['license_key']['license'], -12)); ?></td>
77
- </tr>
78
- <tr>
79
- <td><?php esc_html_e('Status:', 'pretty-link'); ?></td>
80
- <td><b><?php echo esc_html(sprintf(__('Active on %s', 'pretty-link'), PrliUtils::site_domain())); ?></b></td>
81
- </tr>
82
- <tr>
83
- <td><?php esc_html_e('Product:', 'pretty-link'); ?></td>
84
- <td><?php echo esc_html($li['product_name']); ?></td>
85
- </tr>
86
- <tr>
87
- <td><?php esc_html_e('Activations:', 'pretty-link'); ?></td>
88
- <td>
89
- <?php
90
- printf(
91
- // translators: %1$s: open b tag, %2$s: close b tag, %3$d: current activation count, %4$s: max activations
92
- esc_html__('%1$s%3$d of %4$s%2$s sites have been activated with this license key', 'pretty-link'),
93
- '<b>',
94
- '</b>',
95
- esc_html($li['activation_count']),
96
- esc_html(ucwords($li['max_activations']))
97
- );
98
- ?>
99
- </td>
100
- </tr>
101
- </table>
102
- <div class="prli-deactivate-button"><a href="<?php echo esc_url(admin_url('admin.php?page=pretty-link-updates&action=deactivate&_wpnonce='.wp_create_nonce('pretty-link_deactivate'))); ?>" class="button button-primary" onclick="return confirm('<?php echo esc_attr(sprintf(__("Are you sure? Pretty Links Pro will not be functional on %s if this License Key is deactivated.", 'pretty-link'), PrliUtils::site_domain())); ?>');"><?php echo esc_html(sprintf(__('Deactivate License Key on %s', 'pretty-link'), PrliUtils::site_domain())); ?></a></div>
103
- </div>
104
- <?php if(!$this->is_installed()): ?>
105
- <div><a href="<?php echo esc_url($this->update_plugin_url()); ?>" class="button button-primary"><?php esc_html_e('Upgrade plugin to Pro', 'pretty-link'); ?></a></div>
106
- <div>&nbsp;</div>
107
- <?php endif; ?>
108
- <?php require(PRLI_VIEWS_PATH.'/admin/update/edge_updates.php'); ?>
109
- <br/>
110
- <div id="prli-version-string"><?php printf(esc_html__("You're currently running version %s of Pretty Links Pro", 'pretty-link'), '<b>'.esc_html(PRLI_VERSION).'</b>'); ?></div>
111
- <?php endif; ?>
112
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/views/admin/update/ui.php CHANGED
@@ -14,19 +14,23 @@
14
  <td class="prli-settings-table-nav">
15
  <ul class="prli-sidebar-nav">
16
  <li><a data-id="license"><?php esc_html_e('License', 'pretty-link'); ?></a></li>
17
- <!-- <li><a data-id="addons"><?php esc_html_e('Add-Ons', 'pretty-link'); ?></a></li> -->
18
  <?php do_action('prli_updates_nav_items'); ?>
19
  </ul>
20
  </td>
21
  <td class="prli-settings-table-pages">
22
  <div class="prli-page" id="license">
23
- <?php require(PRLI_VIEWS_PATH.'/admin/update/license.php'); ?>
 
 
 
 
 
 
 
 
 
 
24
  </div>
25
- <!--
26
- <div class="prli-page" id="addons">
27
- <?php require(PRLI_VIEWS_PATH.'/admin/update/addons.php'); ?>
28
- </div>
29
- -->
30
  <?php do_action('prli_updates_pages'); ?>
31
  </td>
32
  </tr>
14
  <td class="prli-settings-table-nav">
15
  <ul class="prli-sidebar-nav">
16
  <li><a data-id="license"><?php esc_html_e('License', 'pretty-link'); ?></a></li>
 
17
  <?php do_action('prli_updates_nav_items'); ?>
18
  </ul>
19
  </td>
20
  <td class="prli-settings-table-pages">
21
  <div class="prli-page" id="license">
22
+ <div class="prli-page-title"><?php esc_html_e('Pretty Links Pro License', 'pretty-link'); ?></div>
23
+ <div id="prli-license-container">
24
+ <?php
25
+ if(empty($li)) {
26
+ require PRLI_VIEWS_PATH . '/admin/update/inactive_license.php';
27
+ }
28
+ else {
29
+ require PRLI_VIEWS_PATH . '/admin/update/active_license.php';
30
+ }
31
+ ?>
32
+ </div>
33
  </div>
 
 
 
 
 
34
  <?php do_action('prli_updates_pages'); ?>
35
  </td>
36
  </tr>
app/views/options/form.php CHANGED
@@ -107,7 +107,7 @@
107
  <label for="<?php echo esc_attr($link_nofollow); ?>"><?php esc_html_e('Enable No Follow', 'pretty-link'); ?></label>
108
  <?php PrliAppHelper::info_tooltip('prli-options-add-nofollow',
109
  esc_html__('Add No Follow', 'pretty-link'),
110
- esc_html__('Add the \'nofollow\' attribute by default to new links. This will add nofollow and noindex in the HTTP Response headers when enabled.', 'pretty-link'));
111
  ?>
112
  </th>
113
  <td>
107
  <label for="<?php echo esc_attr($link_nofollow); ?>"><?php esc_html_e('Enable No Follow', 'pretty-link'); ?></label>
108
  <?php PrliAppHelper::info_tooltip('prli-options-add-nofollow',
109
  esc_html__('Add No Follow', 'pretty-link'),
110
+ esc_html__('Defaults \'No Follow\' to be enabled on new links. This will add the nofollow and noindex in the HTTP Reponse headers when enabled on the link.', 'pretty-link'));
111
  ?>
112
  </th>
113
  <td>
css/admin-activate.css CHANGED
@@ -204,3 +204,6 @@ ul.custom_options_list {
204
  font-size: 18px;
205
  margin: 2px 0 10px 0;
206
  }
 
 
 
204
  font-size: 18px;
205
  margin: 2px 0 10px 0;
206
  }
207
+ #prli-install-license-edition-loading {
208
+ margin-left: 10px;
209
+ }
css/admin_notifications.css ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #prli-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
+ #prli-notifications.visible {
20
+ transform: translate3d(0, 0, 0);
21
+ z-index: 999999;
22
+ visibility: visible;
23
+ right: 0;
24
+ }
25
+
26
+ .admin-bar #prli-notifications {
27
+ top: 32px;
28
+ max-height: calc( 100vh - 32px );
29
+ }
30
+
31
+ #prli-notifications * {
32
+ box-sizing: border-box;
33
+ }
34
+
35
+ #prli-notifications .prli-notifications-top-title {
36
+ background-color: #2679c1;
37
+ display: flex;
38
+ align-items: center;
39
+ padding: 0 16px;
40
+ }
41
+
42
+ #prli-notifications .prli-notifications-top-title h3 {
43
+ color: #fff;
44
+ }
45
+
46
+ #prli-notifications .prli-notifications-top-title > div {
47
+ flex-basis: 100%;
48
+ display: flex;
49
+ align-items: center;
50
+ }
51
+
52
+ #prli-notifications .prli-notifications-top-title svg {
53
+ margin-right: 10px;
54
+ margin-top: 5px;
55
+ }
56
+
57
+ #prli-notifications .prli-notifications-top-title .actions {
58
+ display: flex;
59
+ justify-content: flex-end;
60
+ }
61
+
62
+ #prli-notifications .prli-notifications-top-title .actions a {
63
+ color: #fff;
64
+ margin-right: 10px;
65
+ font-size: 14px;
66
+ text-decoration: underline;
67
+ }
68
+
69
+ #prli-notifications .prli-notifications-top-title .actions a.close {
70
+ text-decoration: none;
71
+ margin-right: 0;
72
+ }
73
+
74
+ #prli-notifications .prli-notifications-top-title .actions a.close svg {
75
+ margin-right: 0;
76
+ }
77
+
78
+ #prli-notifications .prli-notification-icon-title {
79
+ display: flex;
80
+ align-items: center;
81
+ }
82
+
83
+ #prli-notifications .prli-notification-icon-title img {
84
+ margin-right: 10px;
85
+ max-width: 32px;
86
+ }
87
+
88
+ #prli-notifications .prli-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
+ #prli-notifications .prli-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
+ #prli-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
+ #prli-notifications .prli-notifications-header-bell {
114
+ display: flex;
115
+ align-items: center;
116
+ }
117
+
118
+ #prli-notifications .prli-notifications-header .prli-notifications-bell {
119
+ position: relative;
120
+ top: 2px;
121
+ margin-right: 10px;
122
+ }
123
+
124
+ #prli-notifications .prli-notifications-header .prli-notifications-bell svg {
125
+ max-width: 30px;
126
+ }
127
+
128
+ #prli-notifications .prli-notifications-header .prli-notifications-title {
129
+ font-style: normal;
130
+ font-weight: 500;
131
+ font-size: 14px;
132
+ line-height: 17px;
133
+ color: #23282D;
134
+ }
135
+
136
+ .prli-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
+ #prli-notifications .dismissed-messages,
152
+ #prli-notifications #viewActive {
153
+ display: none;
154
+ }
155
+
156
+ #prli-notifications .dismissed-messages .prli-notice-dismiss {
157
+ display: none;
158
+ }
159
+
160
+ #prli-notifications .prli-notifications-header.single-digit .prli-notifications-count {
161
+ font-size: 12px;
162
+ }
163
+
164
+ #prli-notifications .prli-notifications-body {
165
+ position: relative;
166
+ padding: 16px;
167
+ }
168
+
169
+ #prli-notifications .prli-notifications-messages {
170
+
171
+ }
172
+
173
+ #prli-notifications .prli-notifications-messages .prli-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
+ #prli-notifications .prli-notifications-messages .active-messages .prli-notifications-message:last-of-type,
181
+ #prli-notifications .prli-notifications-messages .dismissed-messages .prli-notifications-message:last-of-type {
182
+ border-bottom: none;
183
+ margin-bottom: 0;
184
+ padding-bottom: 0;
185
+ }
186
+
187
+ #prli-notifications .prli-notifications-messages .prli-notifications-title {
188
+ font-weight: bold;
189
+ font-size: 17px;
190
+ line-height: 17px;
191
+ margin: 0;
192
+ color: #444;
193
+ }
194
+
195
+ #prli-notifications .prli-notifications-messages .prli-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
+ #prli-notifications .prli-notifications-messages .prli-notifications-content img {
204
+ max-width: 100%;
205
+ height: auto;
206
+ }
207
+
208
+ #prli-notifications .prli-notifications-messages .prli-notifications-buttons {
209
+ margin: -30px 80px 0 0;
210
+ display: flex;
211
+ align-items: center;
212
+ }
213
+
214
+ #prli-notifications .prli-notifications-messages .prli-notifications-buttons a {
215
+ margin: 0 10px 0 0;
216
+ min-height: unset;
217
+ }
218
+
219
+ .prli-notifications-buttons button.prli-notice-dismiss {
220
+ font-size: 13px;
221
+ color: #7f899f;
222
+ background: none;
223
+ padding: 0;
224
+ border: 0;
225
+ }
226
+
227
+ #prli-notifications .prli-notifications-messages .prli-notifications-buttons button.prli-notice-dismiss:hover {
228
+ cursor: pointer;
229
+ }
230
+
231
+ #prli-notifications .prli-notifications-messages .prli-notifications-buttons button.prli-notice-dismiss[disabled] {
232
+ cursor: not-allowed;
233
+ }
234
+
235
+ @media screen and (max-width: 768px) {
236
+ #prli-notifications .prli-notifications-messages {
237
+ padding: 15px 50px 20px 16px;
238
+ }
239
+ #prli-notifications .prli-notifications-messages .prli-notifications-message .prli-notifications-title {
240
+ margin: 0 30px 0 0;
241
+ line-height: 22px;
242
+ }
243
+ #prli-notifications .prli-notifications-messages .prli-notifications-message .prli-notifications-content {
244
+ font-size: 16px;
245
+ line-height: 22px;
246
+ }
247
+ #prli-notifications .prli-notifications-messages .prli-notifications-message .prli-notifications-buttons {
248
+ margin: -30px 80px 0 0;
249
+ }
250
+ #prli-notifications .prli-notifications-messages .prli-notifications-message .prli-notifications-buttons a {
251
+ margin: 0;
252
+ display: table;
253
+ }
254
+ #prli-notifications .prli-notifications-messages .prli-notifications-message .prli-notifications-buttons .button-secondary {
255
+ margin-top: 6px;
256
+ }
257
+ }
css/cloaked-redirect.css CHANGED
@@ -9,7 +9,7 @@ iframe, object, embed {
9
  }
10
  iframe, object, embed {
11
  display: block;
12
- background: #000;
13
  border: none;
14
  height: 100vh;
15
  width: 100vw;
9
  }
10
  iframe, object, embed {
11
  display: block;
12
+ /*background: #000;*/
13
  border: none;
14
  height: 100vh;
15
  width: 100vw;
i18n/pretty-link.pot CHANGED
@@ -1,17 +1,17 @@
1
- # Copyright (C) 2021 Pretty Links
2
  # This file is distributed under the same license as the Pretty Links plugin.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: Pretty Links 3.2.4\n"
6
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/pretty-link\n"
7
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
8
  "Language-Team: LANGUAGE <LL@li.org>\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=UTF-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
- "POT-Creation-Date: 2021-10-28T15:47:49+00:00\n"
13
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
14
- "X-Generator: WP-CLI 2.5.0\n"
15
  "X-Domain: pretty-link\n"
16
 
17
  #. Plugin Name of the plugin
@@ -40,7 +40,7 @@ msgstr ""
40
 
41
  #: app/controllers/PrliAppController.php:134
42
  #: app/controllers/PrliLinksController.php:166
43
- #: app/controllers/PrliUpdateController.php:492
44
  msgid "Link Categories"
45
  msgstr ""
46
 
@@ -52,7 +52,7 @@ msgstr ""
52
 
53
  #: app/controllers/PrliAppController.php:142
54
  #: app/controllers/PrliLinksController.php:167
55
- #: app/controllers/PrliUpdateController.php:498
56
  msgid "Link Tags"
57
  msgstr ""
58
 
@@ -63,7 +63,7 @@ msgid "Tags"
63
  msgstr ""
64
 
65
  #: app/controllers/PrliAppController.php:150
66
- #: app/controllers/PrliUpdateController.php:504
67
  #: pro/app/views/reports/list.php:4
68
  #: pro/app/views/reports/reports.php:7
69
  msgid "Link Reports"
@@ -77,7 +77,7 @@ msgstr ""
77
 
78
  #: app/controllers/PrliAppController.php:158
79
  #: app/controllers/PrliAppController.php:159
80
- #: app/controllers/PrliUpdateController.php:510
81
  #: pro/app/controllers/PlpImportExportController.php:15
82
  msgid "Import / Export"
83
  msgstr ""
@@ -149,7 +149,7 @@ msgid "Buy"
149
  msgstr ""
150
 
151
  #: app/controllers/PrliAppController.php:327
152
- #: app/views/admin/update/license.php:39
153
  #: app/views/shared/nav.php:9
154
  msgid "Upgrade to Pro"
155
  msgstr ""
@@ -223,23 +223,27 @@ msgstr ""
223
  msgid "All Links"
224
  msgstr ""
225
 
226
- #: app/controllers/PrliFlyoutMenuController.php:34
227
  msgid "See Quick Links"
228
  msgstr ""
229
 
230
- #: app/controllers/PrliFlyoutMenuController.php:79
231
  #: app/views/admin/popups/upgrade.php:23
232
  msgid "Upgrade to Pretty Links Pro"
233
  msgstr ""
234
 
235
- #: app/controllers/PrliFlyoutMenuController.php:86
236
  msgid "Support & Docs"
237
  msgstr ""
238
 
239
- #: app/controllers/PrliFlyoutMenuController.php:91
240
  msgid "Suggest a Feature"
241
  msgstr ""
242
 
 
 
 
 
243
  #: app/controllers/PrliLinksController.php:59
244
  #: app/helpers/PrliLinksHelper.php:171
245
  #: app/views/links/form_basic.php:49
@@ -462,6 +466,7 @@ msgid "Your Pretty Link was Successfully Reset"
462
  msgstr ""
463
 
464
  #: app/controllers/PrliLinksController.php:788
 
465
  msgid "Bad request"
466
  msgstr ""
467
 
@@ -568,30 +573,109 @@ msgstr ""
568
  msgid "No clicks older than %1$d days were found, so nothing was deleted"
569
  msgstr ""
570
 
 
 
 
 
 
 
 
 
 
 
 
 
571
  #: app/controllers/PrliUpdateController.php:74
572
- msgid "Why you creepin'?"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
573
  msgstr ""
574
 
575
- #: app/controllers/PrliUpdateController.php:318
 
 
 
 
576
  msgid "Check for Update"
577
  msgstr ""
578
 
579
- #: app/controllers/PrliUpdateController.php:387
580
  msgid "You had an HTTP error connecting to Caseproof's Mothership API"
581
  msgstr ""
582
 
583
- #: app/controllers/PrliUpdateController.php:399
584
  msgid "Your License Key was invalid"
585
  msgstr ""
586
 
587
- #: app/controllers/PrliUpdateController.php:425
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
588
  msgid "You do not have access."
589
  msgstr ""
590
 
591
- #: app/controllers/PrliUpdateController.php:429
592
  msgid "Edge updates couldn't be updated."
593
  msgstr ""
594
 
 
 
 
 
 
595
  #: app/controllers/PrliXmlRpcController.php:36
596
  #: app/controllers/PrliXmlRpcController.php:103
597
  #: app/controllers/PrliXmlRpcController.php:152
@@ -794,6 +878,57 @@ msgstr ""
794
  msgid "Target URL:"
795
  msgstr ""
796
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
797
  #: app/models/PrliClick.php:237
798
  msgid "all links"
799
  msgstr ""
@@ -1077,7 +1212,7 @@ msgid "Split-test your Pretty Links"
1077
  msgstr ""
1078
 
1079
  #: app/views/admin/popups/upgrade.php:14
1080
- #: app/views/admin/update/license.php:60
1081
  msgid "And much, much more!"
1082
  msgstr ""
1083
 
@@ -1086,7 +1221,7 @@ msgid "Plus, upgrading is fast, easy and won't disrupt any of your existing link
1086
  msgstr ""
1087
 
1088
  #: app/views/admin/popups/upgrade.php:18
1089
- #: app/views/admin/update/license.php:66
1090
  msgid "We think you'll love it!"
1091
  msgstr ""
1092
 
@@ -1127,6 +1262,52 @@ msgstr ""
1127
  msgid "After you paste your license key on the %1$s\"Pretty Links\" -> \"Activate Pro\" admin page,%2$s you'll start getting automatic updates."
1128
  msgstr ""
1129
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1130
  #: app/views/admin/update/addons.php:3
1131
  msgid "Pretty Link Add-ons"
1132
  msgstr ""
@@ -1201,106 +1382,52 @@ msgstr ""
1201
  msgid "Include Pretty Links Pro edge (development) releases in automatic updates (not recommended for production websites)"
1202
  msgstr ""
1203
 
1204
- #: app/views/admin/update/edge_updates.php:4
1205
- #: app/views/widgets/widget.php:22
1206
- msgid "Loading..."
1207
- msgstr ""
1208
-
1209
- #: app/views/admin/update/license.php:7
1210
- msgid "Pretty Links Pro License"
1211
- msgstr ""
1212
-
1213
  #. translators: %1$s: link to pro site, %2$s: link to pro site login page
1214
- #: app/views/admin/update/license.php:14
1215
  msgid "You must have a License Key to enable automatic updates for Pretty Links Pro. If you don't have a License please go to %1$s to get one. If you do have a license you can login at %2$s to manage your licenses and site activations."
1216
  msgstr ""
1217
 
1218
- #: app/views/admin/update/license.php:25
1219
  msgid "Enter Your Pretty Links Pro License Key:"
1220
  msgstr ""
1221
 
1222
- #: app/views/admin/update/license.php:32
1223
  msgid "Activate License Key on %s"
1224
  msgstr ""
1225
 
1226
  #. translators: %1$s: open link tag, %2$s: close link tag
1227
- #: app/views/admin/update/license.php:45
1228
  msgid "It looks like you haven't %1$supgraded to Pretty Links Pro%2$s yet. Here are just a few things you could be doing with pro:"
1229
  msgstr ""
1230
 
1231
- #: app/views/admin/update/license.php:55
1232
  msgid "Auto-replace keywords throughout your site with Pretty Links"
1233
  msgstr ""
1234
 
1235
- #: app/views/admin/update/license.php:56
1236
  msgid "Protect your affiliate links by using Cloaked Redirects"
1237
  msgstr ""
1238
 
1239
- #: app/views/admin/update/license.php:57
1240
  msgid "Redirect based on a visitor's location"
1241
  msgstr ""
1242
 
1243
- #: app/views/admin/update/license.php:58
1244
  msgid "Auto-prettylink your Pages &amp; Posts"
1245
  msgstr ""
1246
 
1247
- #: app/views/admin/update/license.php:59
1248
  msgid "Find out what works and what doesn't by split testing your links"
1249
  msgstr ""
1250
 
1251
- #: app/views/admin/update/license.php:64
1252
  msgid "Plus, upgrading is fast, easy and won't disrupt any of your existing links or data. And there's even a 14 day money back guarantee."
1253
  msgstr ""
1254
 
1255
- #: app/views/admin/update/license.php:68
1256
  msgid "Upgrade to Pro today!"
1257
  msgstr ""
1258
 
1259
- #: app/views/admin/update/license.php:72
1260
- msgid "Active License Key Information:"
1261
- msgstr ""
1262
-
1263
- #: app/views/admin/update/license.php:75
1264
- msgid "License Key:"
1265
- msgstr ""
1266
-
1267
- #: app/views/admin/update/license.php:79
1268
- msgid "Status:"
1269
- msgstr ""
1270
-
1271
- #: app/views/admin/update/license.php:80
1272
- msgid "Active on %s"
1273
- msgstr ""
1274
-
1275
- #: app/views/admin/update/license.php:83
1276
- msgid "Product:"
1277
- msgstr ""
1278
-
1279
- #: app/views/admin/update/license.php:87
1280
- msgid "Activations:"
1281
- msgstr ""
1282
-
1283
- #. translators: %1$s: open b tag, %2$s: close b tag, %3$d: current activation count, %4$s: max activations
1284
- #: app/views/admin/update/license.php:92
1285
- msgid "%1$s%3$d of %4$s%2$s sites have been activated with this license key"
1286
- msgstr ""
1287
-
1288
- #: app/views/admin/update/license.php:102
1289
- msgid "Are you sure? Pretty Links Pro will not be functional on %s if this License Key is deactivated."
1290
- msgstr ""
1291
-
1292
- #: app/views/admin/update/license.php:102
1293
- msgid "Deactivate License Key on %s"
1294
- msgstr ""
1295
-
1296
- #: app/views/admin/update/license.php:105
1297
- msgid "Upgrade plugin to Pro"
1298
- msgstr ""
1299
-
1300
- #: app/views/admin/update/license.php:110
1301
- msgid "You're currently running version %s of Pretty Links Pro"
1302
- msgstr ""
1303
-
1304
  #: app/views/admin/update/ui.php:3
1305
  msgid "Activate Pretty Links Pro"
1306
  msgstr ""
@@ -1309,8 +1436,8 @@ msgstr ""
1309
  msgid "License"
1310
  msgstr ""
1311
 
1312
- #: app/views/admin/update/ui.php:17
1313
- msgid "Add-Ons"
1314
  msgstr ""
1315
 
1316
  #: app/views/admin/upgrade/reports.php:8
@@ -1896,7 +2023,7 @@ msgid "Add No Follow"
1896
  msgstr ""
1897
 
1898
  #: app/views/options/form.php:110
1899
- msgid "Add the 'nofollow' attribute by default to new links. This will add nofollow and noindex in the HTTP Response headers when enabled."
1900
  msgstr ""
1901
 
1902
  #: app/views/options/form.php:119
1
+ # Copyright (C) 2022 Pretty Links
2
  # This file is distributed under the same license as the Pretty Links plugin.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: Pretty Links 3.2.5\n"
6
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/pretty-link\n"
7
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
8
  "Language-Team: LANGUAGE <LL@li.org>\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=UTF-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
+ "POT-Creation-Date: 2022-08-26T19:59:42+00:00\n"
13
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
14
+ "X-Generator: WP-CLI 2.6.0\n"
15
  "X-Domain: pretty-link\n"
16
 
17
  #. Plugin Name of the plugin
40
 
41
  #: app/controllers/PrliAppController.php:134
42
  #: app/controllers/PrliLinksController.php:166
43
+ #: app/controllers/PrliUpdateController.php:730
44
  msgid "Link Categories"
45
  msgstr ""
46
 
52
 
53
  #: app/controllers/PrliAppController.php:142
54
  #: app/controllers/PrliLinksController.php:167
55
+ #: app/controllers/PrliUpdateController.php:736
56
  msgid "Link Tags"
57
  msgstr ""
58
 
63
  msgstr ""
64
 
65
  #: app/controllers/PrliAppController.php:150
66
+ #: app/controllers/PrliUpdateController.php:742
67
  #: pro/app/views/reports/list.php:4
68
  #: pro/app/views/reports/reports.php:7
69
  msgid "Link Reports"
77
 
78
  #: app/controllers/PrliAppController.php:158
79
  #: app/controllers/PrliAppController.php:159
80
+ #: app/controllers/PrliUpdateController.php:748
81
  #: pro/app/controllers/PlpImportExportController.php:15
82
  msgid "Import / Export"
83
  msgstr ""
149
  msgstr ""
150
 
151
  #: app/controllers/PrliAppController.php:327
152
+ #: app/views/admin/update/inactive_license.php:28
153
  #: app/views/shared/nav.php:9
154
  msgid "Upgrade to Pro"
155
  msgstr ""
223
  msgid "All Links"
224
  msgstr ""
225
 
226
+ #: app/controllers/PrliFlyoutMenuController.php:38
227
  msgid "See Quick Links"
228
  msgstr ""
229
 
230
+ #: app/controllers/PrliFlyoutMenuController.php:89
231
  #: app/views/admin/popups/upgrade.php:23
232
  msgid "Upgrade to Pretty Links Pro"
233
  msgstr ""
234
 
235
+ #: app/controllers/PrliFlyoutMenuController.php:96
236
  msgid "Support & Docs"
237
  msgstr ""
238
 
239
+ #: app/controllers/PrliFlyoutMenuController.php:101
240
  msgid "Suggest a Feature"
241
  msgstr ""
242
 
243
+ #: app/controllers/PrliFlyoutMenuController.php:107
244
+ msgid "Notifications "
245
+ msgstr ""
246
+
247
  #: app/controllers/PrliLinksController.php:59
248
  #: app/helpers/PrliLinksHelper.php:171
249
  #: app/views/links/form_basic.php:49
466
  msgstr ""
467
 
468
  #: app/controllers/PrliLinksController.php:788
469
+ #: app/controllers/PrliUpdateController.php:198
470
  msgid "Bad request"
471
  msgstr ""
472
 
573
  msgid "No clicks older than %1$d days were found, so nothing was deleted"
574
  msgstr ""
575
 
576
+ #: app/controllers/PrliUpdateController.php:66
577
+ #: app/controllers/PrliUpdateController.php:80
578
+ #: app/controllers/PrliUpdateController.php:161
579
+ msgid "Bad request."
580
+ msgstr ""
581
+
582
+ #: app/controllers/PrliUpdateController.php:70
583
+ #: app/controllers/PrliUpdateController.php:165
584
+ #: app/controllers/PrliUpdateController.php:202
585
+ msgid "Sorry, you don't have permission to do this."
586
+ msgstr ""
587
+
588
  #: app/controllers/PrliUpdateController.php:74
589
+ #: app/controllers/PrliUpdateController.php:169
590
+ #: app/controllers/PrliUpdateController.php:206
591
+ msgid "Security check failed."
592
+ msgstr ""
593
+
594
+ #: app/controllers/PrliUpdateController.php:108
595
+ msgid "The license information is not available, try refreshing the page."
596
+ msgstr ""
597
+
598
+ #. translators: %1$s: the product name, %2$s: open link tag, %3$s: close link tag
599
+ #: app/controllers/PrliUpdateController.php:140
600
+ msgid "This License Key has expired, but you have an active license for %1$s, %2$sclick here%3$s to activate using this license instead."
601
+ msgstr ""
602
+
603
+ #: app/controllers/PrliUpdateController.php:190
604
+ msgid "Failed to get filesystem access"
605
+ msgstr ""
606
+
607
+ #: app/controllers/PrliUpdateController.php:219
608
+ msgid "The correct edition of Pretty Links has been installed successfully."
609
+ msgstr ""
610
+
611
+ #: app/controllers/PrliUpdateController.php:222
612
+ msgid "Failed to install the correct edition of Pretty Links, please download it from prettylinks.com and install it manually."
613
+ msgstr ""
614
+
615
+ #: app/controllers/PrliUpdateController.php:226
616
+ msgid "License data not found"
617
  msgstr ""
618
 
619
+ #: app/controllers/PrliUpdateController.php:399
620
+ msgid "License key deactivated"
621
+ msgstr ""
622
+
623
+ #: app/controllers/PrliUpdateController.php:543
624
  msgid "Check for Update"
625
  msgstr ""
626
 
627
+ #: app/controllers/PrliUpdateController.php:612
628
  msgid "You had an HTTP error connecting to Caseproof's Mothership API"
629
  msgstr ""
630
 
631
+ #: app/controllers/PrliUpdateController.php:624
632
  msgid "Your License Key was invalid"
633
  msgstr ""
634
 
635
+ #: app/controllers/PrliUpdateController.php:641
636
+ #: app/views/admin/update/active_license.php:19
637
+ #: app/views/admin/update/edge_updates.php:4
638
+ #: app/views/widgets/widget.php:22
639
+ msgid "Loading..."
640
+ msgstr ""
641
+
642
+ #: app/controllers/PrliUpdateController.php:642
643
+ msgid "An error occurred during activation: %s"
644
+ msgstr ""
645
+
646
+ #: app/controllers/PrliUpdateController.php:643
647
+ msgid "Invalid response."
648
+ msgstr ""
649
+
650
+ #: app/controllers/PrliUpdateController.php:644
651
+ msgid "Ajax error."
652
+ msgstr ""
653
+
654
+ #: app/controllers/PrliUpdateController.php:645
655
+ msgid "Are you sure? Pretty Links will not be functional on %s if this License Key is deactivated."
656
+ msgstr ""
657
+
658
+ #: app/controllers/PrliUpdateController.php:647
659
+ msgid "An error occurred during deactivation: %s"
660
+ msgstr ""
661
+
662
+ #: app/controllers/PrliUpdateController.php:649
663
+ msgid "An error occurred while installing the correct edition."
664
+ msgstr ""
665
+
666
+ #: app/controllers/PrliUpdateController.php:663
667
  msgid "You do not have access."
668
  msgstr ""
669
 
670
+ #: app/controllers/PrliUpdateController.php:667
671
  msgid "Edge updates couldn't be updated."
672
  msgstr ""
673
 
674
+ #. translators: %1$s: open link tag, %2$s: close link tag
675
+ #: app/controllers/PrliUpdateController.php:757
676
+ msgid "To restore automatic updates, %1$sinstall the correct edition%2$s of Pretty Links."
677
+ msgstr ""
678
+
679
  #: app/controllers/PrliXmlRpcController.php:36
680
  #: app/controllers/PrliXmlRpcController.php:103
681
  #: app/controllers/PrliXmlRpcController.php:152
878
  msgid "Target URL:"
879
  msgstr ""
880
 
881
+ #. Translators: Readable time to display
882
+ #: app/lib/PrliNotifications.php:315
883
+ msgid "%1$s ago"
884
+ msgstr ""
885
+
886
+ #: app/lib/PrliNotifications.php:449
887
+ msgid "%s unread message"
888
+ msgid_plural "%s unread messages"
889
+ msgstr[0] ""
890
+ msgstr[1] ""
891
+
892
+ #: app/lib/PrliNotifications.php:497
893
+ #: app/lib/PrliNotifications.php:562
894
+ msgid "Dismiss"
895
+ msgstr ""
896
+
897
+ #: app/lib/PrliNotifications.php:504
898
+ #: app/lib/PrliNotifications.php:569
899
+ msgid "%s second ago"
900
+ msgid_plural "%s seconds ago"
901
+ msgstr[0] ""
902
+ msgstr[1] ""
903
+
904
+ #: app/lib/PrliNotifications.php:540
905
+ msgid "You're all caught up!"
906
+ msgstr ""
907
+
908
+ #: app/lib/PrliNotifications.php:615
909
+ msgid "Inbox"
910
+ msgstr ""
911
+
912
+ #: app/lib/PrliNotifications.php:618
913
+ msgid "View Dismissed"
914
+ msgstr ""
915
+
916
+ #: app/lib/PrliNotifications.php:619
917
+ msgid "View Active"
918
+ msgstr ""
919
+
920
+ #: app/lib/PrliNotifications.php:620
921
+ msgid "Close"
922
+ msgstr ""
923
+
924
+ #: app/lib/PrliNotifications.php:633
925
+ msgid "Notifications"
926
+ msgstr ""
927
+
928
+ #: app/lib/PrliNotifications.php:636
929
+ msgid "Dismiss All"
930
+ msgstr ""
931
+
932
  #: app/models/PrliClick.php:237
933
  msgid "all links"
934
  msgstr ""
1212
  msgstr ""
1213
 
1214
  #: app/views/admin/popups/upgrade.php:14
1215
+ #: app/views/admin/update/inactive_license.php:49
1216
  msgid "And much, much more!"
1217
  msgstr ""
1218
 
1221
  msgstr ""
1222
 
1223
  #: app/views/admin/popups/upgrade.php:18
1224
+ #: app/views/admin/update/inactive_license.php:55
1225
  msgid "We think you'll love it!"
1226
  msgstr ""
1227
 
1262
  msgid "After you paste your license key on the %1$s\"Pretty Links\" -> \"Activate Pro\" admin page,%2$s you'll start getting automatic updates."
1263
  msgstr ""
1264
 
1265
+ #. translators: %1$s: the license edition, %2$s: the installed edition, %3$s: open link tag, %4$s: close link tag
1266
+ #: app/views/admin/update/active_license.php:12
1267
+ msgid "This License Key is for %1$s, but %2$s is installed. %3$sClick here%4$s to install the correct edition for the license (%1$s)."
1268
+ msgstr ""
1269
+
1270
+ #: app/views/admin/update/active_license.php:24
1271
+ msgid "Active License Key Information:"
1272
+ msgstr ""
1273
+
1274
+ #: app/views/admin/update/active_license.php:27
1275
+ msgid "License Key:"
1276
+ msgstr ""
1277
+
1278
+ #: app/views/admin/update/active_license.php:31
1279
+ msgid "Status:"
1280
+ msgstr ""
1281
+
1282
+ #: app/views/admin/update/active_license.php:32
1283
+ msgid "Active on %s"
1284
+ msgstr ""
1285
+
1286
+ #: app/views/admin/update/active_license.php:35
1287
+ msgid "Product:"
1288
+ msgstr ""
1289
+
1290
+ #: app/views/admin/update/active_license.php:39
1291
+ msgid "Activations:"
1292
+ msgstr ""
1293
+
1294
+ #. translators: %1$s: open b tag, %2$s: close b tag, %3$d: current activation count, %4$s: max activations
1295
+ #: app/views/admin/update/active_license.php:44
1296
+ msgid "%1$s%3$d of %4$s%2$s sites have been activated with this license key"
1297
+ msgstr ""
1298
+
1299
+ #: app/views/admin/update/active_license.php:55
1300
+ msgid "Deactivate License Key on %s"
1301
+ msgstr ""
1302
+
1303
+ #: app/views/admin/update/active_license.php:59
1304
+ msgid "Upgrade plugin to Pro"
1305
+ msgstr ""
1306
+
1307
+ #: app/views/admin/update/active_license.php:64
1308
+ msgid "You're currently running version %s of Pretty Links Pro"
1309
+ msgstr ""
1310
+
1311
  #: app/views/admin/update/addons.php:3
1312
  msgid "Pretty Link Add-ons"
1313
  msgstr ""
1382
  msgid "Include Pretty Links Pro edge (development) releases in automatic updates (not recommended for production websites)"
1383
  msgstr ""
1384
 
 
 
 
 
 
 
 
 
 
1385
  #. translators: %1$s: link to pro site, %2$s: link to pro site login page
1386
+ #: app/views/admin/update/inactive_license.php:6
1387
  msgid "You must have a License Key to enable automatic updates for Pretty Links Pro. If you don't have a License please go to %1$s to get one. If you do have a license you can login at %2$s to manage your licenses and site activations."
1388
  msgstr ""
1389
 
1390
+ #: app/views/admin/update/inactive_license.php:15
1391
  msgid "Enter Your Pretty Links Pro License Key:"
1392
  msgstr ""
1393
 
1394
+ #: app/views/admin/update/inactive_license.php:22
1395
  msgid "Activate License Key on %s"
1396
  msgstr ""
1397
 
1398
  #. translators: %1$s: open link tag, %2$s: close link tag
1399
+ #: app/views/admin/update/inactive_license.php:34
1400
  msgid "It looks like you haven't %1$supgraded to Pretty Links Pro%2$s yet. Here are just a few things you could be doing with pro:"
1401
  msgstr ""
1402
 
1403
+ #: app/views/admin/update/inactive_license.php:44
1404
  msgid "Auto-replace keywords throughout your site with Pretty Links"
1405
  msgstr ""
1406
 
1407
+ #: app/views/admin/update/inactive_license.php:45
1408
  msgid "Protect your affiliate links by using Cloaked Redirects"
1409
  msgstr ""
1410
 
1411
+ #: app/views/admin/update/inactive_license.php:46
1412
  msgid "Redirect based on a visitor's location"
1413
  msgstr ""
1414
 
1415
+ #: app/views/admin/update/inactive_license.php:47
1416
  msgid "Auto-prettylink your Pages &amp; Posts"
1417
  msgstr ""
1418
 
1419
+ #: app/views/admin/update/inactive_license.php:48
1420
  msgid "Find out what works and what doesn't by split testing your links"
1421
  msgstr ""
1422
 
1423
+ #: app/views/admin/update/inactive_license.php:53
1424
  msgid "Plus, upgrading is fast, easy and won't disrupt any of your existing links or data. And there's even a 14 day money back guarantee."
1425
  msgstr ""
1426
 
1427
+ #: app/views/admin/update/inactive_license.php:57
1428
  msgid "Upgrade to Pro today!"
1429
  msgstr ""
1430
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1431
  #: app/views/admin/update/ui.php:3
1432
  msgid "Activate Pretty Links Pro"
1433
  msgstr ""
1436
  msgid "License"
1437
  msgstr ""
1438
 
1439
+ #: app/views/admin/update/ui.php:22
1440
+ msgid "Pretty Links Pro License"
1441
  msgstr ""
1442
 
1443
  #: app/views/admin/upgrade/reports.php:8
2023
  msgstr ""
2024
 
2025
  #: app/views/options/form.php:110
2026
+ msgid "Defaults 'No Follow' to be enabled on new links. This will add the nofollow and noindex in the HTTP Reponse headers when enabled on the link."
2027
  msgstr ""
2028
 
2029
  #: app/views/options/form.php:119
js/admin_activate.js CHANGED
@@ -1,30 +1,183 @@
1
- (function($) {
2
- $(document).ready(function() {
3
- $('#plp_edge_updates').click( function(e) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  e.preventDefault();
5
- var wpnonce = $(this).attr('data-nonce');
 
 
6
 
7
- $('#plp_edge_updates-wrap .prli_loader').show();
8
- $(this).prop('disabled',true);
9
 
10
- var data = {
11
- action: 'plp_edge_updates',
12
- edge: $(this).is(':checked'),
13
- wpnonce: wpnonce
14
- };
15
 
16
- var bigthis = this;
 
 
17
 
18
- $.post(ajaxurl, data, function(obj) {
19
- $('#plp_edge_updates-wrap .prli_loader').hide();
20
- $(bigthis).prop('disabled',false);
21
 
22
- if('error' in obj)
23
- alert(obj.error);
24
- else {
25
- $(bigthis).prop('checked',(obj.state=='true'));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  }
27
- }, 'json');
 
 
 
 
 
 
 
 
 
28
  });
29
  });
30
- })(jQuery);
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(function ($) {
2
+ var $license_container = $('#prli-license-container'),
3
+ activating = false,
4
+ license_error = function (message) {
5
+ $license_container.prepend(
6
+ $('<div class="notice notice-error">').append(
7
+ $('<p>').html(message)
8
+ )
9
+ );
10
+ };
11
+
12
+ $('body').on('click', '#prli-activate-license-key', function () {
13
+ var $button = $(this),
14
+ button_width = $button.width(),
15
+ button_html = $button.html(),
16
+ key = $('#prli-license-key').val();
17
+
18
+ if(activating || !key) {
19
+ return;
20
+ }
21
+
22
+ activating = true;
23
+ $button.width(button_width).html(PrliActivateL10n.loading_image);
24
+ $license_container.find('> .notice').remove();
25
+
26
+ $.ajax({
27
+ url: PrliActivateL10n.ajax_url,
28
+ method: 'POST',
29
+ dataType: 'json',
30
+ data: {
31
+ action: 'prli_activate_license',
32
+ _ajax_nonce: PrliActivateL10n.activate_license_nonce,
33
+ key: key
34
+ }
35
+ })
36
+ .done(function (response) {
37
+ if(!response || typeof response != 'object' || typeof response.success != 'boolean') {
38
+ license_error(PrliActivateL10n.activation_error.replace('%s', PrliActivateL10n.invalid_response));
39
+ }
40
+ else if(!response.success) {
41
+ license_error(response.data);
42
+ }
43
+ else {
44
+ if(response.data === true) {
45
+ window.location.reload();
46
+ }
47
+ else {
48
+ $license_container.html(response.data);
49
+ }
50
+ }
51
+ })
52
+ .fail(function () {
53
+ license_error(PrliActivateL10n.activation_error.replace('%s', PrliActivateL10n.ajax_error));
54
+ })
55
+ .always(function () {
56
+ activating = false;
57
+ $button.html(button_html).width('auto');
58
+ });
59
+ });
60
+
61
+ $('body').on('keypress', '#prli-license-key', function (e) {
62
+ if(e.which === 13) {
63
  e.preventDefault();
64
+ $('#prli-activate-license-key').trigger('click');
65
+ }
66
+ });
67
 
68
+ var deactivating = false;
 
69
 
70
+ $('body').on('click', '#prli-deactivate-license-key', function () {
71
+ var $button = $(this),
72
+ button_width = $button.width(),
73
+ button_html = $button.html();
 
74
 
75
+ if(deactivating || !confirm(PrliActivateL10n.deactivate_confirm)) {
76
+ return;
77
+ }
78
 
79
+ deactivating = true;
80
+ $button.width(button_width).html(PrliActivateL10n.loading_image);
81
+ $license_container.find('> .notice').remove();
82
 
83
+ $.ajax({
84
+ url: PrliActivateL10n.ajax_url,
85
+ method: 'POST',
86
+ dataType: 'json',
87
+ data: {
88
+ action: 'prli_deactivate_license',
89
+ _ajax_nonce: PrliActivateL10n.deactivate_license_nonce
90
+ }
91
+ })
92
+ .done(function (response) {
93
+ if(!response || typeof response != 'object' || typeof response.success != 'boolean') {
94
+ license_error(PrliActivateL10n.deactivation_error.replace('%s', PrliActivateL10n.invalid_response));
95
+ }
96
+ else if(!response.success) {
97
+ license_error(response.data);
98
+ }
99
+ else {
100
+ $license_container.html(response.data);
101
+ }
102
+ })
103
+ .fail(function () {
104
+ license_error(PrliActivateL10n.deactivation_error.replace('%s', PrliActivateL10n.ajax_error));
105
+ })
106
+ .always(function () {
107
+ deactivating = false;
108
+ $button.html(button_html).width('auto');
109
+ });
110
+ });
111
+
112
+ $('body').on('click', '#plp_edge_updates', function(e) {
113
+ e.preventDefault();
114
+ var wpnonce = $(this).attr('data-nonce');
115
+
116
+ $('#plp_edge_updates-wrap .prli_loader').show();
117
+ $(this).prop('disabled',true);
118
+
119
+ var data = {
120
+ action: 'plp_edge_updates',
121
+ edge: $(this).is(':checked'),
122
+ wpnonce: wpnonce
123
+ };
124
+
125
+ var bigthis = this;
126
+
127
+ $.post(PrliActivateL10n.ajax_url, data, function(obj) {
128
+ $('#plp_edge_updates-wrap .prli_loader').hide();
129
+ $(bigthis).prop('disabled',false);
130
+
131
+ if('error' in obj)
132
+ alert(obj.error);
133
+ else {
134
+ $(bigthis).prop('checked',(obj.state=='true'));
135
+ }
136
+ }, 'json');
137
+ });
138
+
139
+ $('body').on('click', '#prli-install-license-edition', function (e) {
140
+ e.preventDefault();
141
+
142
+ $('#prli-install-license-edition-loading').css('display', 'inline-block');
143
+
144
+ $.ajax({
145
+ url: PrliActivateL10n.ajax_url,
146
+ method: 'POST',
147
+ dataType: 'json',
148
+ data: {
149
+ action: 'prli_install_license_edition',
150
+ _ajax_nonce: PrliActivateL10n.install_license_edition_nonce
151
+ }
152
+ })
153
+ .done(function (response) {
154
+ if(response && typeof response.success === 'boolean') {
155
+ alert(response.data);
156
+
157
+ if(response.success) {
158
+ window.location.reload();
159
  }
160
+ }
161
+ else {
162
+ alert(PrliActivateL10n.error_installing_license_edition);
163
+ }
164
+ })
165
+ .fail(function () {
166
+ alert(PrliActivateL10n.error_installing_license_edition);
167
+ })
168
+ .always(function () {
169
+ $('#prli-install-license-edition-loading').hide();
170
  });
171
  });
172
+
173
+ $('body').on('click', '#prli-activate-new-license', function (e) {
174
+ e.preventDefault();
175
+
176
+ var license_key = $(this).data('license-key');
177
+
178
+ setTimeout(function () {
179
+ $('#prli-license-key').val(license_key);
180
+ $('#prli-activate-license-key').trigger('click');
181
+ }, 250);
182
+ });
183
+ });
js/admin_notifications.js ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function($) {
2
+
3
+ $('#prliAdminNotifications').on('click', function(e) {
4
+ e.preventDefault();
5
+ $('#prli-notifications').toggleClass('visible');
6
+ $('#caseproofFlyoutButton').trigger('click');
7
+ });
8
+ $('#prliNotificationsClose').on('click', function(e) {
9
+ e.preventDefault();
10
+ $('#prli-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', '.prli-notice-dismiss', function(event) {
34
+
35
+ event.preventDefault();
36
+
37
+ var $this = $(this);
38
+ var messageId = $this.data('message-id');
39
+ var message = $('#prli-notifications-message-' + messageId);
40
+ var countEl = $('#prliNotificationsCount');
41
+ var mainCountEl = $('#prliAdminNotificationsBadge');
42
+ var trayCountEl = $('#prliNotificationsCountTray');
43
+ var count = parseInt(mainCountEl.html());
44
+ var adminMenuCount = $('#prliAdminMenuUnreadCount');
45
+
46
+ var data = {
47
+ action: 'prli_notification_dismiss',
48
+ nonce: PrliAdminNotifications.nonce,
49
+ id: messageId,
50
+ };
51
+
52
+ $this.prop('disabled', 'disabled');
53
+ message.fadeOut();
54
+
55
+ $.post( PrliAdminNotifications.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
+ $('.prli-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 = $('#prliNotificationsCount');
104
+ var count = parseInt(countEl.html());
105
+ var mainCountEl = $('#prliAdminNotificationsBadge');
106
+ var adminMenuCount = $('#prliAdminMenuUnreadCount');
107
+ var trayCountEl = $('#prliNotificationsCountTray');
108
+
109
+ var data = {
110
+ action: 'prli_notification_dismiss',
111
+ nonce: PrliAdminNotifications.nonce,
112
+ id: 'all',
113
+ };
114
+
115
+ $this.prop('disabled', 'disabled');
116
+
117
+ $.post( PrliAdminNotifications.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
+ $('.prli-notifications-none').show();
127
+ $('.dismiss-all').hide();
128
+
129
+ $.each($('.active-messages .prli-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
+ });
js/admin_shared.js CHANGED
@@ -88,4 +88,3 @@ jQuery(document).ready(function($) {
88
  }
89
  });
90
  });
91
-
88
  }
89
  });
90
  });
 
pretty-link.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Pretty Links
4
  Plugin URI: https://prettylinks.com/pl/plugin-uri
5
  Description: Shrink, track and share any URL using your website and brand!
6
- Version: 3.2.4
7
  Author: Pretty Links
8
  Author URI: http://prettylinks.com
9
  Text Domain: pretty-link
@@ -176,6 +176,22 @@ function prli_load_textdomain() {
176
  load_plugin_textdomain('pretty-link', false, $plugin_dir.'/i18n/');
177
  }
178
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  global $prli_link, $prli_link_meta, $prli_click, $prli_group, $prli_utils, $plp_update;
180
 
181
  $prli_link = new PrliLink();
@@ -212,3 +228,4 @@ if($plp_update->is_installed()) {
212
  require_once(PRLI_PATH.'/pro/pretty-link-pro.php');
213
  }
214
 
 
3
  Plugin Name: Pretty Links
4
  Plugin URI: https://prettylinks.com/pl/plugin-uri
5
  Description: Shrink, track and share any URL using your website and brand!
6
+ Version: 3.2.5
7
  Author: Pretty Links
8
  Author URI: http://prettylinks.com
9
  Text Domain: pretty-link
176
  load_plugin_textdomain('pretty-link', false, $plugin_dir.'/i18n/');
177
  }
178
 
179
+ register_activation_hook( __FILE__, 'prli_activation' );
180
+ function prli_activation() {
181
+ add_option( 'prli_just_activated', true );
182
+ }
183
+
184
+ add_action( 'plugins_loaded', 'prli_run_activation' );
185
+ function prli_run_activation() {
186
+ if ( empty( get_option( 'prli_just_activated' ) ) ) {
187
+ return;
188
+ }
189
+ $pl_options = PrliOptions::get_options();
190
+ $pl_options->activated_timestamp = time();
191
+ $pl_options->store();
192
+ delete_option( 'prli_just_activated' );
193
+ }
194
+
195
  global $prli_link, $prli_link_meta, $prli_click, $prli_group, $prli_utils, $plp_update;
196
 
197
  $prli_link = new PrliLink();
228
  require_once(PRLI_PATH.'/pro/pretty-link-pro.php');
229
  }
230
 
231
+ require_once(PRLI_PATH.'/app/lib/PrliNotifications.php');
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: supercleanse, cartpauj
3
  Donate link: https://prettylinks.com
4
  Tags: marketing-automation, shortlink, affiliate-marketing, affiliates, cloaker, social-media, marketing, rewrite, links, urls, shortlinks, link branding, link tracking, affiliate links, link cloaking, redirect, forward, shorturl, shorten, shortening, click, clicks, track, tracking, tiny, tinyurl, budurl, shrinking, domain, shrink, mask, masking, cloak, cloaking, slug, slugs, admin, administration, stats, statistics, stat, statistic, email, ajax, javascript, ui, csv, download, page, post, pages, posts, shortcode, seo, automation, widget, widgets, dashboard
5
  Requires at least: 5.1
6
- Tested up to: 6.1
7
- Stable tag: 3.2.4
8
 
9
  The best WordPress link management, branding, tracking & sharing plugin. Link shortener helps you easily make pretty & trackable shortlinks.
10
 
@@ -66,6 +66,13 @@ http://blairwilliams.com/w7a
66
  3. Make sure you have changed your permalink Common Settings in Settings -> Permalinks away from "Default" to something else. I prefer using custom and then "/%year%/%month%/%postname%/" for the simplest possible URL slugs with the best performance.
67
 
68
  == Changelog ==
 
 
 
 
 
 
 
69
  = 3.2.4 =
70
  * Review notification dismissal improvements
71
 
3
  Donate link: https://prettylinks.com
4
  Tags: marketing-automation, shortlink, affiliate-marketing, affiliates, cloaker, social-media, marketing, rewrite, links, urls, shortlinks, link branding, link tracking, affiliate links, link cloaking, redirect, forward, shorturl, shorten, shortening, click, clicks, track, tracking, tiny, tinyurl, budurl, shrinking, domain, shrink, mask, masking, cloak, cloaking, slug, slugs, admin, administration, stats, statistics, stat, statistic, email, ajax, javascript, ui, csv, download, page, post, pages, posts, shortcode, seo, automation, widget, widgets, dashboard
5
  Requires at least: 5.1
6
+ Tested up to: 6.0.1
7
+ Stable tag: 3.2.5
8
 
9
  The best WordPress link management, branding, tracking & sharing plugin. Link shortener helps you easily make pretty & trackable shortlinks.
10
 
66
  3. Make sure you have changed your permalink Common Settings in Settings -> Permalinks away from "Default" to something else. I prefer using custom and then "/%year%/%month%/%postname%/" for the simplest possible URL slugs with the best performance.
67
 
68
  == Changelog ==
69
+ = 3.2.5 =
70
+ * Fix fatal error if update transient is false
71
+ * Notifications Inbox
72
+ * Small bug fixes
73
+ * Pro: Don't force black background on cloaked urls
74
+ * Pro: License key optimizations
75
+
76
  = 3.2.4 =
77
  * Review notification dismissal improvements
78