Instagram Feed - Version 6.0.6

Version Description

  • Tweak: Added a warning notice to allow a grace period before Instagram data is permanently deleted from your site after deauthorizing the Smash Balloon Instagram app. Due to Instagram requirements, any Instagram data on your site must be deleted within a reasonable time after the app has been deauthorized. The new warning notice provides a 7 day grace period to allow you time to reauthorize the app if you don't want the data to be deleted.
  • Tweak: Reconnecting an account now results in deleting the original connection in the database and adding a new one. This will prevent issues with some caching systems like Redis.
  • Fix: Only the first 20 sources were available when creating feeds and changing sources for a feed.
  • Fix: The link in some error messages were incorrect resulting in "access denied" error messages when clicking on them.
Download this release

Release Info

Developer Craig at Smash Balloon
Plugin Icon 128x128 Instagram Feed
Version 6.0.6
Comparing to
See all releases

Code changes from version 6.0.5 to 6.0.6

README.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: smashballoon, craig-at-smash-balloon
3
  Tags: Instagram, Instagram feed, Instagram photos, Instagram widget, Instagram gallery
4
  Requires at least: 4.1
5
  Tested up to: 6.0
6
- Stable tag: 6.0.5
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -331,11 +331,16 @@ We understand that sometimes you need help, have issues or just have questions.
331
  * Plus more customization options added all the time!
332
 
333
  == Changelog ==
 
 
 
 
 
 
334
  = 6.0.5 =
335
  * Tweak: If WordPress cron is broken or behind schedule and causing background caching to not work, the plugin will update the feed when the page loads.
336
  * Fix: Jetpack's "Master Bar" feature was causing the sidebar in the customizer to be partially hidden.
337
  * Fix: Added back support for the "class" shortcode setting for all feeds.
338
- * Fix: Only the first 20 sources were available when creating feeds and changing sources for a feed.
339
  * Fix: Removed all Font Awesome icons and no longer include the CSS file from the Font Awesome CDN.
340
 
341
  = 6.0.4 =
3
  Tags: Instagram, Instagram feed, Instagram photos, Instagram widget, Instagram gallery
4
  Requires at least: 4.1
5
  Tested up to: 6.0
6
+ Stable tag: 6.0.6
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
331
  * Plus more customization options added all the time!
332
 
333
  == Changelog ==
334
+ = 6.0.6 =
335
+ * Tweak: Added a warning notice to allow a grace period before Instagram data is permanently deleted from your site after deauthorizing the Smash Balloon Instagram app. Due to Instagram requirements, any Instagram data on your site must be deleted within a reasonable time after the app has been deauthorized. The new warning notice provides a 7 day grace period to allow you time to reauthorize the app if you don't want the data to be deleted.
336
+ * Tweak: Reconnecting an account now results in deleting the original connection in the database and adding a new one. This will prevent issues with some caching systems like Redis.
337
+ * Fix: Only the first 20 sources were available when creating feeds and changing sources for a feed.
338
+ * Fix: The link in some error messages were incorrect resulting in "access denied" error messages when clicking on them.
339
+
340
  = 6.0.5 =
341
  * Tweak: If WordPress cron is broken or behind schedule and causing background caching to not work, the plugin will update the feed when the page loads.
342
  * Fix: Jetpack's "Master Bar" feature was causing the sidebar in the customizer to be partially hidden.
343
  * Fix: Added back support for the "class" shortcode setting for all feeds.
 
344
  * Fix: Removed all Font Awesome icons and no longer include the CSS file from the Font Awesome CDN.
345
 
346
  = 6.0.4 =
inc/Builder/SBI_Db.php CHANGED
@@ -33,11 +33,11 @@ class SBI_Db {
33
  unset( $args['page'] );
34
  }
35
 
36
- $offset = max( 0, $page * self::RESULTS_PER_PAGE );
37
 
38
  if ( empty( $args ) ) {
39
 
40
- $limit = (int) self::RESULTS_PER_PAGE;
41
  $sql = "SELECT s.id, s.account_id, s.account_type, s.privilege, s.access_token, s.username, s.info, s.error, s.expires, count(f.id) as used_in
42
  FROM $sources_table_name s
43
  LEFT JOIN $feeds_table_name f ON f.settings LIKE CONCAT('%', s.account_id, '%')
@@ -550,6 +550,25 @@ class SBI_Db {
550
  wp_die();
551
  }
552
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
553
  /**
554
  * Query to Remove Source from Database
555
  *
33
  unset( $args['page'] );
34
  }
35
 
36
+ $offset = max( 0, $page * 400 );
37
 
38
  if ( empty( $args ) ) {
39
 
40
+ $limit = 400;
41
  $sql = "SELECT s.id, s.account_id, s.account_type, s.privilege, s.access_token, s.username, s.info, s.error, s.expires, count(f.id) as used_in
42
  FROM $sources_table_name s
43
  LEFT JOIN $feeds_table_name f ON f.settings LIKE CONCAT('%', s.account_id, '%')
550
  wp_die();
551
  }
552
 
553
+ /**
554
+ * Query to Remove Source from Database
555
+ *
556
+ * @param array $source_id
557
+ *
558
+ * @since 6.0.6
559
+ */
560
+ public static function delete_source( $source_id ) {
561
+ global $wpdb;
562
+ $sources_table_name = $wpdb->prefix . 'sbi_sources';
563
+ return $wpdb->query(
564
+ $wpdb->prepare(
565
+ "DELETE FROM $sources_table_name WHERE id = %d; ",
566
+ $source_id
567
+ )
568
+ );
569
+
570
+ }
571
+
572
  /**
573
  * Query to Remove Source from Database
574
  *
inc/Builder/SBI_Source.php CHANGED
@@ -350,7 +350,7 @@ class SBI_Source {
350
  );
351
  $results = SBI_Db::source_query( $args );
352
  $already_connected_as_business_account = ( isset( $results[0] ) && $results[0]['account_type'] === 'business' );
353
- $matches_existing_personal = ( isset( $results[0] ) && $results[0]['account_type'] === 'personal' );
354
 
355
  if ( $already_connected_as_business_account ) {
356
  $return['matchingExistingAccounts'] = $results[0];
@@ -360,6 +360,7 @@ class SBI_Source {
360
  $return['notice'] = __( 'The Instagram account you are logged into is already connected as a "business" account. Remove the business account if you\'d like to connect as a basic account instead (not recommended).', 'instagram-feed' );
361
  } elseif ( $matches_existing_personal ) {
362
  $return['matchingExistingAccounts'] = $results[0];
 
363
  self::update_or_insert( $source_data );
364
  $return['notice'] = '';
365
  $return['didQuickUpdate'] = true;
@@ -476,12 +477,14 @@ class SBI_Source {
476
  );
477
  $results = SBI_Db::source_query( $args );
478
  $already_connected_as_business_account = ( isset( $results[0] ) && $results[0]['account_type'] === 'business' );
479
- $matches_existing_personal = ( isset( $results[0] ) && $results[0]['account_type'] === 'personal' );
480
 
481
  if ( $already_connected_as_business_account ) {
 
482
  self::update_or_insert( $source_data );
483
  } elseif ( $matches_existing_personal && $return['numFound'] === 1 ) {
484
  $return['didQuickUpdate'] = true;
 
485
  self::update_or_insert( $source_data );
486
  }
487
  } else {
350
  );
351
  $results = SBI_Db::source_query( $args );
352
  $already_connected_as_business_account = ( isset( $results[0] ) && $results[0]['account_type'] === 'business' );
353
+ $matches_existing_personal = ( isset( $results[0] ) && $results[0]['account_type'] !== 'business' );
354
 
355
  if ( $already_connected_as_business_account ) {
356
  $return['matchingExistingAccounts'] = $results[0];
360
  $return['notice'] = __( 'The Instagram account you are logged into is already connected as a "business" account. Remove the business account if you\'d like to connect as a basic account instead (not recommended).', 'instagram-feed' );
361
  } elseif ( $matches_existing_personal ) {
362
  $return['matchingExistingAccounts'] = $results[0];
363
+ SBI_Db::delete_source( $results[0]['id'] );
364
  self::update_or_insert( $source_data );
365
  $return['notice'] = '';
366
  $return['didQuickUpdate'] = true;
477
  );
478
  $results = SBI_Db::source_query( $args );
479
  $already_connected_as_business_account = ( isset( $results[0] ) && $results[0]['account_type'] === 'business' );
480
+ $matches_existing_personal = ( isset( $results[0] ) && $results[0]['account_type'] !== 'business' );
481
 
482
  if ( $already_connected_as_business_account ) {
483
+ SBI_Db::delete_source( $results[0]['id'] );
484
  self::update_or_insert( $source_data );
485
  } elseif ( $matches_existing_personal && $return['numFound'] === 1 ) {
486
  $return['didQuickUpdate'] = true;
487
+ SBI_Db::delete_source( $results[0]['id'] );
488
  self::update_or_insert( $source_data );
489
  }
490
  } else {
inc/Email_Notification.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace InstagramFeed;
4
+
5
+ use SB_Instagram_Education;
6
+
7
+ /**
8
+ * Class Email_Notification
9
+ */
10
+ class Email_Notification {
11
+
12
+ /**
13
+ * Sends a notification email to the admin(s) of the site.
14
+ *
15
+ * @param string $title
16
+ * @param string $bold
17
+ * @param string $details
18
+ *
19
+ * @return bool
20
+ */
21
+ public static function send( $title, $bold, $details ) {
22
+ $options = get_option('sb_instagram_settings' );
23
+
24
+ $to_string = ! empty( $options['email_notification_addresses'] ) ? str_replace( ' ', '', $options['email_notification_addresses'] ) : get_option( 'admin_email', '' );
25
+
26
+ $all_emails = explode( ',', $to_string );
27
+ $valid_emails = [];
28
+
29
+ foreach ( $all_emails as $email ) {
30
+ if ( is_email( $email ) ) {
31
+ $valid_emails[] = $email;
32
+ }
33
+ }
34
+
35
+ if ( empty( $valid_emails ) ) {
36
+ return false;
37
+ }
38
+
39
+ $from_name = esc_html( wp_specialchars_decode( get_bloginfo( 'name' ) ) );
40
+ $email_from = $from_name . ' <' . get_option( 'admin_email', $valid_emails[0] ) . '>';
41
+ $header_from = "From: " . $email_from;
42
+
43
+ $headers = array( 'Content-Type: text/html; charset=utf-8', $header_from );
44
+
45
+ $header_image = SBI_PLUGIN_URL . 'img/balloon-120.png';
46
+
47
+ $footer_link = admin_url('admin.php?page=sbi-settings&view=advanced&flag=emails');
48
+
49
+ $message_content = '<h6 style="padding:0;word-wrap:normal;font-family:\'Helvetica Neue\',Helvetica,Arial,sans-serif;font-weight:bold;line-height:130%;font-size: 16px;color:#444444;text-align:inherit;margin:0 0 20px 0;Margin:0 0 20px 0;">' . $bold . '</h6>' . $details;
50
+
51
+ include_once SBI_PLUGIN_DIR . 'inc/class-sb-instagram-education.php';
52
+ $educator = new SB_Instagram_Education();
53
+ $dyk_message = $educator->dyk_display();
54
+
55
+ ob_start();
56
+ include SBI_PLUGIN_DIR . 'inc/email.php';
57
+ $email_body = ob_get_contents();
58
+ ob_get_clean();
59
+
60
+ return wp_mail( $valid_emails, $title, $email_body, $headers );
61
+ }
62
+ }
inc/Platform_Data.php ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace InstagramFeed;
4
+
5
+ use InstagramFeed\Builder\SBI_Db;
6
+ use SB_Instagram_Connected_Account;
7
+ use SB_Instagram_Data_Manager;
8
+
9
+ /**
10
+ * Class Platform_Data
11
+ *
12
+ * Handles all data related to the platform.
13
+ *
14
+ * @since 6.0.6
15
+ *
16
+ * @package InstagramFeed
17
+ */
18
+ class Platform_Data {
19
+
20
+ /**
21
+ * Option key for app statuses.
22
+ *
23
+ * @var string
24
+ */
25
+ const SBI_STATUSES_OPTION_KEY = 'sbi_statuses';
26
+
27
+ /**
28
+ * Option key for the revoke platform data.
29
+ *
30
+ * @var string
31
+ */
32
+ const REVOKE_PLATFORM_DATA_OPTION_KEY = 'sbi_revoke_platform_data';
33
+
34
+ /**
35
+ * Array key for the app permission status key on `sbi_statuses`.
36
+ *
37
+ * @var string
38
+ */
39
+ const APP_PERMISSION_REVOKED_STATUS_KEY = 'app_permission_revoked';
40
+
41
+ /**
42
+ * Array key for the warning email flag for unused feed status key on `sbi_statuses`.
43
+ */
44
+ const UNUSED_FEED_WARNING_EMAIL_SENT_STATUS_KEY = 'unused_feed_warning_email_sent';
45
+
46
+ /**
47
+ * Register the hooks.
48
+ *
49
+ * @return void
50
+ */
51
+ public function register_hooks() {
52
+ add_action( 'sbi_api_connect_response', [ $this, 'handle_platform_data_on_api_response' ], 10, 2 );
53
+ add_action( 'sbi_before_display_instagram', [ $this, 'handle_app_permission_error' ], 10 );
54
+ add_action( 'sbi_app_permission_revoked', [ $this, 'handle_app_permission_status' ], 10, 1 );
55
+ add_action( 'sbi_before_delete_old_data', [ $this, 'handle_event_before_delete_old_data' ], 10 );
56
+
57
+ // Ajax Hooks
58
+ add_action( 'wp_ajax_sbi_reset_unused_feed_usage', [ $this, 'handle_unused_feed_usage' ], 10 );
59
+ }
60
+
61
+ /**
62
+ * Handle the platform data on the API response.
63
+ *
64
+ * @param array $response The response from the API.
65
+ * @param string $url The URL of the request.
66
+ *
67
+ * @return void
68
+ */
69
+ public function handle_platform_data_on_api_response( $response, $url ) {
70
+ global $sb_instagram_posts_manager;
71
+
72
+ if ( is_wp_error( $response ) ) {
73
+ return;
74
+ }
75
+
76
+ if ( empty( $response['response'] ) || empty( $response['response']['code'] ) ) {
77
+ return;
78
+ }
79
+
80
+ if ( $response['response']['code'] !== 200 ) {
81
+ return;
82
+ }
83
+
84
+ // Remove the platform data deletion notice.
85
+ $sb_instagram_posts_manager->remove_error( 'platform_data_deleted' );
86
+
87
+ $sbi_statuses_option = get_option( self::SBI_STATUSES_OPTION_KEY, [] );
88
+
89
+ if ( empty( $sbi_statuses_option[ self::APP_PERMISSION_REVOKED_STATUS_KEY ] ) ) {
90
+ return;
91
+ }
92
+
93
+ $sbi_revoke_platform_data = get_option( self::REVOKE_PLATFORM_DATA_OPTION_KEY, [] );
94
+ $revoked_account_username = isset( $sbi_revoke_platform_data['connected_account']['username'] ) ? $sbi_revoke_platform_data['connected_account']['username'] : '';
95
+
96
+ if ( empty( $revoked_account_username ) ) {
97
+ return;
98
+ }
99
+
100
+ $api_response_username = json_decode( $response['body'] )->username;
101
+
102
+ if ( $revoked_account_username !== $api_response_username ) {
103
+ return;
104
+ }
105
+
106
+ // Cleanup the revoked platform status and revoke account data.
107
+ $this->cleanup_revoked_account( $sbi_statuses_option );
108
+
109
+ $sb_instagram_posts_manager->reset_api_errors();
110
+ }
111
+
112
+ /**
113
+ * Handle the app permission error.
114
+ *
115
+ * @return void
116
+ */
117
+ public function handle_app_permission_error() {
118
+ global $sb_instagram_posts_manager;
119
+
120
+ $sbi_statuses_option = get_option( self::SBI_STATUSES_OPTION_KEY, [] );
121
+
122
+ if ( empty( $sbi_statuses_option[ self::APP_PERMISSION_REVOKED_STATUS_KEY ] ) ) {
123
+ return;
124
+ }
125
+
126
+ $sbi_revoke_platform_data = get_option( self::REVOKE_PLATFORM_DATA_OPTION_KEY, [] );
127
+
128
+ $revoke_platform_data_timestamp = isset( $sbi_revoke_platform_data['revoke_platform_data_timestamp'] ) ? $sbi_revoke_platform_data['revoke_platform_data_timestamp'] : 0;
129
+ $connected_account = isset( $sbi_revoke_platform_data['connected_account'] ) ? $sbi_revoke_platform_data['connected_account'] : [];
130
+
131
+ if ( ! $revoke_platform_data_timestamp ) {
132
+ return;
133
+ }
134
+
135
+ $current_timestamp = current_time( 'timestamp', true );
136
+
137
+ // Check if current timestamp is less than revoke platform data timestamp, if so, return.
138
+ if ( $current_timestamp < $revoke_platform_data_timestamp ) {
139
+ return;
140
+ }
141
+
142
+ // Revoke platform data.
143
+ $this->delete_platform_data( $connected_account );
144
+ $this->send_platform_data_delete_notification_email();
145
+
146
+ // Cleanup the revoked platform status and revoke account data.
147
+ $this->cleanup_revoked_account( $sbi_statuses_option );
148
+ $sb_instagram_posts_manager->reset_api_errors();
149
+
150
+ // Adding a notice to the admin page to inform the admin that platform data has been deleted.
151
+ $sb_instagram_posts_manager->add_error( 'platform_data_deleted', __( 'An account admin has deauthorized the Smash Balloon app used to power the Instagram Feed plugin. The page was not reconnected within the 7 day limit and all Instagram data was automatically deleted on your website due to Facebook data privacy rules.', 'instagram-feed' ) );
152
+ }
153
+
154
+ /**
155
+ * Handle the app permission status.
156
+ *
157
+ * @param array $connected_account The connected account data.
158
+ *
159
+ * @return void
160
+ */
161
+ public function handle_app_permission_status( $connected_account ) {
162
+ $sbi_statuses_option = get_option( self::SBI_STATUSES_OPTION_KEY, [] );
163
+
164
+ if ( isset( $sbi_statuses_option['app_permission_revoked'] ) && true === $sbi_statuses_option['app_permission_revoked'] ) {
165
+ return;
166
+ }
167
+
168
+ $this->update_app_permission_revoked_status( $sbi_statuses_option, true );
169
+
170
+ // Calculate the grace period for revoking platform data.
171
+ $current_timestamp = current_time( 'timestamp', true );
172
+ $revoke_platform_data_timestamp = strtotime( '+7 days', $current_timestamp );
173
+
174
+ update_option( self::REVOKE_PLATFORM_DATA_OPTION_KEY, [
175
+ 'revoke_platform_data_timestamp' => $revoke_platform_data_timestamp,
176
+ 'connected_account' => $connected_account,
177
+ ] );
178
+
179
+ $this->send_revoke_notification_email();
180
+ }
181
+
182
+ /**
183
+ * Delete any data associated with the Instagram API and the
184
+ * connected account being deleted.
185
+ *
186
+ * @param $to_delete_connected_account
187
+ *
188
+ * @return void
189
+ */
190
+ protected function delete_platform_data( $to_delete_connected_account ) {
191
+ $are_other_business_accounts = false;
192
+ $all_connected_accounts = SB_Instagram_Connected_Account::get_all_connected_accounts();
193
+
194
+ $to_update = [];
195
+ foreach ( $all_connected_accounts as $connected_account ) {
196
+ if ( (int) $connected_account['user_id'] !== (int) $to_delete_connected_account['user_id'] ) {
197
+ $to_update[ $connected_account['user_id'] ] = $connected_account;
198
+
199
+ if ( isset( $connected_account['type'] ) && $connected_account['type'] === 'business' ) {
200
+ $are_other_business_accounts = true;
201
+ }
202
+ }
203
+ }
204
+
205
+ SB_Instagram_Connected_Account::update_connected_accounts( $to_update );
206
+
207
+ SBI_Db::delete_source_by_account_id( $to_delete_connected_account['user_id'] );
208
+
209
+ $manager = new SB_Instagram_Data_Manager();
210
+
211
+ $manager->delete_caches();
212
+ $manager->delete_comments_data();
213
+
214
+ if ( empty( $to_update ) || ! $are_other_business_accounts ) {
215
+ $manager->delete_hashtag_data();
216
+ } else {
217
+ $manager->delete_non_hashtag_sbi_instagram_posts( $to_delete_connected_account['username'] );
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Update the app permission revoked status.
223
+ *
224
+ * @param array $sbi_statuses_option The option value.
225
+ * @param bool $is_revoked The revoke status.
226
+ *
227
+ * @return void
228
+ */
229
+ protected function update_app_permission_revoked_status( $sbi_statuses_option, $is_revoked ) {
230
+ if ( $is_revoked ) {
231
+ $sbi_statuses_option[ self::APP_PERMISSION_REVOKED_STATUS_KEY ] = true;
232
+ } else {
233
+ unset( $sbi_statuses_option[ self::APP_PERMISSION_REVOKED_STATUS_KEY ] );
234
+ }
235
+ update_option( self::SBI_STATUSES_OPTION_KEY, $sbi_statuses_option );
236
+ }
237
+
238
+ /**
239
+ * Handles events before the deletion of old data.
240
+ *
241
+ * @param array $statuses
242
+ *
243
+ * @return void
244
+ */
245
+ public function handle_event_before_delete_old_data( $statuses ) {
246
+ global $sb_instagram_posts_manager;
247
+
248
+ $sbi_statuses_option = get_option( self::SBI_STATUSES_OPTION_KEY, [] );
249
+
250
+ if ( ! empty( $sbi_statuses_option[ self::UNUSED_FEED_WARNING_EMAIL_SENT_STATUS_KEY ] ) ) {
251
+ return;
252
+ }
253
+
254
+ if ( $statuses['last_used'] < sbi_get_current_time() - ( 14 * DAY_IN_SECONDS ) ) {
255
+ $sb_instagram_posts_manager->add_error( 'unused_feed', __( 'Your Instagram feed has been not viewed in the last 14 days. Due to Instagram data privacy rules, all data for this feed will be deleted in 7 days time. To avoid automated data deletion, simply view the Instagram feed on your website within the next 7 days.', 'instagram-feed' ) );
256
+
257
+ $this->send_unused_feed_usage_notification_email();
258
+
259
+ // Setting the flag to true so that the warning email is not sent again.
260
+ $sbi_statuses_option[ self::UNUSED_FEED_WARNING_EMAIL_SENT_STATUS_KEY ] = true;
261
+ update_option( self::SBI_STATUSES_OPTION_KEY, $sbi_statuses_option );
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Handles the reset of unused feed data for deletion.
267
+ *
268
+ * @return void
269
+ */
270
+ public function handle_unused_feed_usage() {
271
+ global $sb_instagram_posts_manager;
272
+
273
+ $sb_instagram_posts_manager->remove_error('unused_feed');
274
+
275
+ $manager = new \SB_Instagram_Data_Manager();
276
+ $manager->update_last_used();
277
+
278
+ $sbi_statuses_option = get_option( self::SBI_STATUSES_OPTION_KEY, [] );
279
+
280
+ // Unset the flag to allow the warning email to be sent again.
281
+ unset( $sbi_statuses_option[ self::UNUSED_FEED_WARNING_EMAIL_SENT_STATUS_KEY ] );
282
+ update_option( self::SBI_STATUSES_OPTION_KEY, $sbi_statuses_option );
283
+
284
+ wp_send_json_success( [
285
+ 'message' => '<div style="margin-top: 10px;">' . esc_html__( 'Success! Your Instagram Feeds will continue to work normally.', 'instagram-feed' ) . '</div>'
286
+ ] );
287
+ }
288
+
289
+ /**
290
+ * Cleanup revoked account data.
291
+ *
292
+ * @param array $sbi_statuses_option
293
+ *
294
+ * @return void
295
+ */
296
+ public function cleanup_revoked_account( $sbi_statuses_option ) {
297
+ $this->update_app_permission_revoked_status( $sbi_statuses_option, false );
298
+ delete_option( self::REVOKE_PLATFORM_DATA_OPTION_KEY );
299
+ }
300
+
301
+ /**
302
+ * Sends a notification email to the admin when the app permission is revoked.
303
+ *
304
+ * @return void
305
+ */
306
+ protected function send_revoke_notification_email() {
307
+ $link = admin_url( 'admin.php?page=sbi-settings');
308
+
309
+ $title = __( 'There has been a problem with your Instagram Feed.', 'instagram-feed' );
310
+ $bold = __( 'Action Required Within 7 Days', 'instagram-feed' );
311
+ $site_url = sprintf( '<a href="%s">%s<a/>', esc_url( home_url() ), __( 'your website', 'instagram-feed' ) );
312
+ $details = '<p>' . sprintf( __( 'An account admin has deauthorized the Smash Balloon app used to power the Instagram Feed plugin on %s. If the Instagram account is not reconnected within 7 days then all Instagram data will be automatically deleted on your website due to Facebook data privacy rules.', 'instagram-feed' ), $site_url ) . '</p>';
313
+ $settings_page = sprintf( '<a href="%s">%s</a>', esc_url( $link ), esc_html__( 'Settings Page', 'instagram-feed' ) );
314
+ $details .= '<p>' . sprintf( __( 'To prevent the automated deletion of data for the account, please reconnect your account on the plugin %s within 7 days.', 'instagram-feed' ), $settings_page ). '</p>';
315
+
316
+ Email_Notification::send( $title, $bold, $details );
317
+ }
318
+
319
+ /**
320
+ * Sends a notification email to the admin when the feed has not been used for a while.
321
+ *
322
+ * @return void
323
+ */
324
+ protected function send_unused_feed_usage_notification_email() {
325
+ $title = __( 'There has been a problem with your Instagram Feed.', 'instagram-feed' );
326
+ $bold = __( 'Action Required Within 7 Days', 'instagram-feed' );
327
+ $site_url = sprintf( '<a href="%s">%s<a/>', esc_url( home_url() ), __( 'your website', 'instagram-feed' ) );
328
+ $details = '<p>' . sprintf( __( 'An Instagram feed on %s has been not viewed in the last 14 days. Due to Instagram data privacy rules, all data for this feed will be deleted in 7 days time.', 'instagram-feed' ), $site_url ) . '</p>';
329
+ $details .= '<p>' . __( 'To avoid automated data deletion, simply view the Instagram feed on your website within the next 7 days.', 'instagram-feed' ) . '</p>';
330
+
331
+ Email_Notification::send( $title, $bold, $details );
332
+ }
333
+
334
+ /**
335
+ * Sends a notification email to the admin when the platform data has been deleted.
336
+ *
337
+ * @return void
338
+ */
339
+ protected function send_platform_data_delete_notification_email() {
340
+ $link = admin_url( 'admin.php?page=sbi-settings');
341
+
342
+ $title = __( 'All Instagram Data has Been Removed', 'instagram-feed' );
343
+ $bold = __( 'An account admin has deauthorized the Smash Balloon app used to power the Instagram Feed plugin.', 'instagram-feed' );
344
+ $site_url = sprintf( '<a href="%s">%s<a/>', esc_url( home_url() ), __( 'your website', 'instagram-feed' ) );
345
+ $details = '<p>' . sprintf( __( 'The page was not reconnected within the 7 day limit and all Instagram data was automatically deleted on %s due to Facebook data privacy rules.', 'instagram-feed' ), $site_url ) . '</p>';
346
+ $settings_page = sprintf( '<a href="%s">%s</a>', esc_url( $link ), esc_html__( 'Settings Page', 'instagram-feed' ) );
347
+ $details .= '<p>' . sprintf( __( 'To fix your feeds, reconnect all accounts that were in use on the Settings page.', 'instagram-feed' ), $settings_page ) . '</p>';
348
+
349
+ Email_Notification::send( $title, $bold, $details );
350
+ }
351
+
352
+ }
inc/admin/actions.php CHANGED
@@ -237,6 +237,49 @@ function sbi_admin_error_notices() {
237
  </div>
238
  </div>
239
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  <?php endif;
241
  $errors = $sb_instagram_posts_manager->get_critical_errors();
242
  if ( $sb_instagram_posts_manager->are_critical_errors() ) :
237
  </div>
238
  </div>
239
 
240
+ <?php endif;
241
+
242
+ if ( ! empty( $errors ) && ( ! empty( $errors['unused_feed'] ) ) ) : ?>
243
+ <div class="sbi-admin-notices sbi-critical-error-notice">
244
+ <span class="sb-notice-icon sb-error-icon">
245
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
246
+ <path d="M10 0C4.48 0 0 4.48 0 10C0 15.52 4.48 20 10 20C15.52 20 20 15.52 20 10C20 4.48 15.52 0 10 0ZM11 15H9V13H11V15ZM11 11H9V5H11V11Z"
247
+ fill="#D72C2C"/>
248
+ </svg>
249
+ </span>
250
+ <div class="sbi-notice-body">
251
+ <h3 class="sb-notice-title">
252
+ <?php echo esc_html__( 'Action Required Within 7 Days:', 'instagram-feed' ); ?>
253
+ </h3>
254
+ <p><?php echo wp_kses_post( $errors['unused_feed'] ); ?></p>
255
+ <p><?php echo esc_html__( 'Or you can simply press the "Fix Usage" button to fix this issue.', 'instagram-feed' ); ?></p>
256
+ <br>
257
+ <p class="sbi-error-directions">
258
+ <button class="sbi-reset-unused-feed-usage sbi-space-left sbi-btn sbi-notice-btn sbi-btn-blue"><?php esc_html_e( 'Fix Usage', 'instagram-feed' ); ?></button>
259
+ </p>
260
+ </div>
261
+ </div>
262
+
263
+ <?php endif;
264
+
265
+ if ( ! empty( $errors ) && ( ! empty( $errors['platform_data_deleted'] ) ) ) : ?>
266
+ <div class="sbi-admin-notices sbi-critical-error-notice">
267
+ <span class="sb-notice-icon sb-error-icon">
268
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
269
+ <path d="M10 0C4.48 0 0 4.48 0 10C0 15.52 4.48 20 10 20C15.52 20 20 15.52 20 10C20 4.48 15.52 0 10 0ZM11 15H9V13H11V15ZM11 11H9V5H11V11Z"
270
+ fill="#D72C2C"/>
271
+ </svg>
272
+ </span>
273
+ <div class="sbi-notice-body">
274
+ <h3 class="sb-notice-title">
275
+ <?php echo esc_html__( 'All Instagram Data has Been Removed:', 'instagram-feed' ); ?>
276
+ </h3>
277
+ <p><?php echo wp_kses_post( $errors['platform_data_deleted'] ); ?></p>
278
+ <p><?php echo esc_html__( 'To fix your feeds, reconnect all accounts that were in use on the Settings page.', 'instagram-feed' ); ?></p>
279
+ <br>
280
+ </div>
281
+ </div>
282
+
283
  <?php endif;
284
  $errors = $sb_instagram_posts_manager->get_critical_errors();
285
  if ( $sb_instagram_posts_manager->are_critical_errors() ) :
inc/admin/class-sbi-notifications.php CHANGED
@@ -172,6 +172,11 @@ class SBI_Notifications {
172
  $option = $this->get_option();
173
 
174
  foreach ( $notifications as $notification ) {
 
 
 
 
 
175
  // Ignore if max wp version detected
176
  if ( ! empty( $notification['maxwpver'] ) && version_compare( get_bloginfo( 'version' ), $notification['maxwpver'], '>' ) ) {
177
  continue;
@@ -255,6 +260,10 @@ class SBI_Notifications {
255
  unset( $notifications[ $key ] );
256
  }
257
 
 
 
 
 
258
  // Ignore if max version has been reached
259
  if ( ! empty( $notification['maxver'] ) && version_compare( $notification['maxver'], SBIVER ) < 0 ) {
260
  unset( $notifications[ $key ] );
@@ -284,6 +293,26 @@ class SBI_Notifications {
284
  return $notifications;
285
  }
286
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
  /**
288
  * Get notification data.
289
  *
@@ -461,7 +490,7 @@ class SBI_Notifications {
461
  public function output() {
462
  $current_screen = get_current_screen();
463
  // if we are one single feed page then return
464
- if ( $current_screen->base == "instagram-feed_page_sbi-feed-builder" && isset( $_GET['feed_id'] ) ) {
465
  return;
466
  }
467
 
172
  $option = $this->get_option();
173
 
174
  foreach ( $notifications as $notification ) {
175
+ // Ignore if not a targeted plugin
176
+ if ( ! empty( $notification['plugin'] ) && is_array( $notification['plugin'] ) && ! in_array( self::PLUGIN, $notification['plugin'], true ) ) {
177
+ continue;
178
+ }
179
+
180
  // Ignore if max wp version detected
181
  if ( ! empty( $notification['maxwpver'] ) && version_compare( get_bloginfo( 'version' ), $notification['maxwpver'], '>' ) ) {
182
  continue;
260
  unset( $notifications[ $key ] );
261
  }
262
 
263
+ if ( empty( $notification['recent_install_override'] ) && $this->recently_installed() ) {
264
+ unset( $notifications[ $key ] );
265
+ }
266
+
267
  // Ignore if max version has been reached
268
  if ( ! empty( $notification['maxver'] ) && version_compare( $notification['maxver'], SBIVER ) < 0 ) {
269
  unset( $notifications[ $key ] );
293
  return $notifications;
294
  }
295
 
296
+ /**
297
+ * @return bool
298
+ *
299
+ * @since 1.4.5/1.4.2
300
+ */
301
+ public function recently_installed() {
302
+ $sbi_statuses_option = get_option( 'sbi_statuses', array() );
303
+
304
+ if ( ! isset( $sbi_statuses_option['first_install'] ) ) {
305
+ return false;
306
+ }
307
+
308
+ // Plugin was installed less than a week ago
309
+ if ( (int) $sbi_statuses_option['first_install'] > time() - WEEK_IN_SECONDS ) {
310
+ return true;
311
+ }
312
+
313
+ return false;
314
+ }
315
+
316
  /**
317
  * Get notification data.
318
  *
490
  public function output() {
491
  $current_screen = get_current_screen();
492
  // if we are one single feed page then return
493
+ if ( isset( $_GET['feed_id'] ) ) {
494
  return;
495
  }
496
 
inc/admin/class-sbi-sitehealth.php CHANGED
@@ -70,7 +70,7 @@ class SB_Instagram_SiteHealth {
70
 
71
 
72
  if ( $sb_instagram_posts_manager->are_critical_errors() ) {
73
- $link = admin_url( '?page=sbi-settings');
74
  $result['status'] = 'critical';
75
  $result['label'] = __( 'Your Instagram Feed is experiencing an error.', 'instagram-feed' );
76
  $result['description'] = sprintf( __( 'A critical issue has been detected with your Instagram Feed. Visit the %sInstagram Feed settings page%s to fix the issue.', 'instagram-feed' ), '<a href="' . esc_url( $link ) . '">', '</a>' );
70
 
71
 
72
  if ( $sb_instagram_posts_manager->are_critical_errors() ) {
73
+ $link = admin_url( 'admin.php?page=sbi-settings');
74
  $result['status'] = 'critical';
75
  $result['label'] = __( 'Your Instagram Feed is experiencing an error.', 'instagram-feed' );
76
  $result['description'] = sprintf( __( 'A critical issue has been detected with your Instagram Feed. Visit the %sInstagram Feed settings page%s to fix the issue.', 'instagram-feed' ), '<a href="' . esc_url( $link ) . '">', '</a>' );
inc/class-sb-instagram-api-connect.php CHANGED
@@ -192,6 +192,13 @@ class SB_Instagram_API_Connect
192
  );
193
  $response = wp_remote_get( $this->url, $args );
194
 
 
 
 
 
 
 
 
195
  if ( ! is_wp_error( $response ) ) {
196
  // certain ways of representing the html for double quotes causes errors so replaced here.
197
  $response = json_decode( str_replace( '%22', '&rdquo;', $response['body'] ), true );
192
  );
193
  $response = wp_remote_get( $this->url, $args );
194
 
195
+ /**
196
+ * Api response for instagram connection
197
+ *
198
+ * @since 6.0.6
199
+ */
200
+ do_action( 'sbi_api_connect_response', $response, $this->url );
201
+
202
  if ( ! is_wp_error( $response ) ) {
203
  // certain ways of representing the html for double quotes causes errors so replaced here.
204
  $response = json_decode( str_replace( '%22', '&rdquo;', $response['body'] ), true );
inc/class-sb-instagram-data-manager.php CHANGED
@@ -37,6 +37,7 @@ class SB_Instagram_Data_Manager {
37
  public function hooks() {
38
  add_action( 'sbi_before_display_instagram', array( $this, 'update_last_used' ) );
39
  add_action( 'sbi_before_display_instagram', array( $this, 'check' ) );
 
40
  add_action( 'sb_instagram_twicedaily', array( $this, 'maybe_delete_old_data' ) );
41
  }
42
 
@@ -56,7 +57,6 @@ class SB_Instagram_Data_Manager {
56
 
57
  $this->update_statuses( $statuses );
58
  }
59
-
60
  }
61
 
62
  /**
@@ -68,6 +68,15 @@ class SB_Instagram_Data_Manager {
68
  $this->encrypt_json_in_sbi_instagram_posts();
69
  }
70
 
 
 
 
 
 
 
 
 
 
71
  /**
72
  * Delete unused data after a period
73
  *
@@ -76,13 +85,15 @@ class SB_Instagram_Data_Manager {
76
  * @since 2.9.4/5.12.4
77
  */
78
  public function maybe_delete_old_data() {
 
 
79
  $statuses = $this->get_statuses();
80
 
81
  $data_was_deleted = false;
82
 
83
- if ( $statuses['last_used'] < sbi_get_current_time() - (21 * DAY_IN_SECONDS) ) {
84
- global $sb_instagram_posts_manager;
85
 
 
86
  $this->delete_caches();
87
  $this->delete_comments_data();
88
  $this->delete_hashtag_data();
@@ -92,8 +103,9 @@ class SB_Instagram_Data_Manager {
92
  $data_was_deleted = true;
93
  }
94
 
95
- if ( $statuses['last_used'] < sbi_get_current_time() - (90 * DAY_IN_SECONDS) ) {
96
  SB_Instagram_Connected_Account::update_connected_accounts( array() );
 
97
  global $sb_instagram_posts_manager;
98
 
99
  $sb_instagram_posts_manager->add_action_log( 'Deleted all connected accounts.' );
@@ -115,6 +127,7 @@ class SB_Instagram_Data_Manager {
115
  $sb_instagram_posts_manager->delete_all_sbi_instagram_posts();
116
 
117
  delete_option( 'sbi_top_api_calls' );
 
118
  }
119
 
120
  /**
@@ -126,15 +139,17 @@ class SB_Instagram_Data_Manager {
126
  */
127
  public function delete_non_hashtag_sbi_instagram_posts( $username ) {
128
  global $wpdb;
129
- $table_name = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
130
- $feeds_posts_table_name = esc_sql( $wpdb->prefix . SBI_INSTAGRAM_FEEDS_POSTS );
131
 
132
  $non_hashtag_posts = $wpdb->get_results(
133
  "SELECT p.id, p.media_id FROM $table_name as p
134
  INNER JOIN $feeds_posts_table_name AS f ON p.id = f.id
135
- WHERE f.hashtag = '';", ARRAY_A );
 
 
136
 
137
- $upload = wp_upload_dir();
138
  $file_suffixes = array( 'thumb', 'low', 'full' );
139
 
140
  foreach ( $non_hashtag_posts as $post ) {
@@ -154,7 +169,8 @@ class SB_Instagram_Data_Manager {
154
  $non_hashtag_posts_deleted = $wpdb->query(
155
  "DELETE p, f FROM $table_name as p
156
  INNER JOIN $feeds_posts_table_name AS f ON p.id = f.id
157
- WHERE f.hashtag = '';", ARRAY_A );
 
158
 
159
  }
160
 
@@ -165,14 +181,15 @@ class SB_Instagram_Data_Manager {
165
  */
166
  public function update_json_non_hashtag_sbi_instagram_posts() {
167
  global $wpdb;
168
- $table_name = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
169
- $feeds_posts_table_name = esc_sql( $wpdb->prefix . SBI_INSTAGRAM_FEEDS_POSTS );
170
 
171
  $updated = $wpdb->query(
172
  "UPDATE $table_name as p
173
  INNER JOIN $feeds_posts_table_name AS f ON p.id = f.id
174
  SET p.json_data = ''
175
- WHERE f.hashtag = '';" );
 
176
 
177
  }
178
 
@@ -193,16 +210,18 @@ class SB_Instagram_Data_Manager {
193
  $this->update_statuses( $statuses );
194
 
195
  global $wpdb;
196
- $encryption = new SB_Instagram_Data_Encryption();
197
- $table_name = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
198
- $feeds_posts_table_name = esc_sql( $wpdb->prefix . SBI_INSTAGRAM_FEEDS_POSTS );
199
 
200
  $plaintext_posts = $wpdb->get_results(
201
  "SELECT * FROM $table_name as p
202
  INNER JOIN $feeds_posts_table_name AS f ON p.id = f.id
203
  WHERE p.json_data LIKE '%{%'
204
  ORDER BY p.time_stamp DESC
205
- LIMIT 50;", ARRAY_A );
 
 
206
 
207
  if ( empty( $plaintext_posts ) ) {
208
  $statuses['num_db_updates'] = 31;
@@ -211,11 +230,16 @@ class SB_Instagram_Data_Manager {
211
 
212
  foreach ( $plaintext_posts as $post ) {
213
  $json_data = $encryption->encrypt( $post['json_data'] );
214
- $updated = $wpdb->query( $wpdb->prepare(
215
- "UPDATE $table_name as p
 
216
  INNER JOIN $feeds_posts_table_name AS f ON p.id = f.id
217
  SET p.json_data = %s
218
- WHERE p.id = %d;", $json_data, $post['id'] ) );
 
 
 
 
219
  }
220
  }
221
 
@@ -239,60 +263,82 @@ class SB_Instagram_Data_Manager {
239
  public function delete_caches( $include_backup = true ) {
240
  /* Backup Caches */
241
  global $wpdb;
242
- $table_name = $wpdb->prefix . "options";
243
 
244
  if ( $include_backup ) {
245
- $wpdb->query( "
 
246
  DELETE
247
  FROM $table_name
248
  WHERE `option_name` LIKE ('%!sbi\_%')
249
- " );
250
- $wpdb->query( "
 
 
251
  DELETE
252
  FROM $table_name
253
  WHERE `option_name` LIKE ('%\_transient\_&sbi\_%')
254
- " );
255
- $wpdb->query( "
 
 
256
  DELETE
257
  FROM $table_name
258
  WHERE `option_name` LIKE ('%\_transient\_timeout\_&sbi\_%')
259
- " );
 
260
  }
261
 
262
  /* Regular Caches */
263
  //Delete all transients
264
- $wpdb->query( "
 
265
  DELETE
266
  FROM $table_name
267
  WHERE `option_name` LIKE ('%\_transient\_sbi\_%')
268
- " );
269
- $wpdb->query( "
 
 
270
  DELETE
271
  FROM $table_name
272
  WHERE `option_name` LIKE ('%\_transient\_timeout\_sbi\_%')
273
- " );
274
- $wpdb->query( "
 
 
275
  DELETE
276
  FROM $table_name
277
  WHERE `option_name` LIKE ('%\_transient\_&sbi\_%')
278
- " );
279
- $wpdb->query( "
 
 
280
  DELETE
281
  FROM $table_name
282
  WHERE `option_name` LIKE ('%\_transient\_timeout\_&sbi\_%')
283
- " );
284
- $wpdb->query( "
 
 
285
  DELETE
286
  FROM $table_name
287
  WHERE `option_name` LIKE ('%\_transient\_\$sbi\_%')
288
- " );
289
- $wpdb->query( "
 
 
290
  DELETE
291
  FROM $table_name
292
  WHERE `option_name` LIKE ('%\_transient\_timeout\_\$sbi\_%')
293
- " );
 
294
 
295
  delete_option( 'sbi_single_cache' );
 
 
 
 
296
  }
297
 
298
  /**
@@ -305,13 +351,16 @@ class SB_Instagram_Data_Manager {
305
  public function update_db_for_dpa() {
306
  global $wpdb;
307
  $encryption = new SB_Instagram_Data_Encryption();
308
- $table_name = $wpdb->prefix . "options";
309
 
310
- $permanent_caches = $wpdb->get_results("
 
311
  SELECT *
312
  FROM $table_name
313
  WHERE option_name LIKE ('%!sbi\_%')
314
- ", ARRAY_A );
 
 
315
 
316
  if ( count( $permanent_caches ) < 10 ) {
317
  foreach ( $permanent_caches as $permanent_cache ) {
@@ -351,7 +400,7 @@ class SB_Instagram_Data_Manager {
351
  $ids = get_option( 'sbi_hashtag_ids', array() );
352
  if ( ! is_array( $ids ) ) {
353
  $encryption = new SB_Instagram_Data_Encryption();
354
- $ids = json_decode( $encryption->decrypt( $ids ), true );
355
  }
356
 
357
  update_option( 'sbi_hashtag_ids', $encryption->encrypt( sbi_json_encode( $ids ) ), false );
@@ -380,7 +429,7 @@ class SB_Instagram_Data_Manager {
380
  * @since 2.9.4/5.12.4
381
  */
382
  public function update_statuses( $statuses ) {
383
- $sbi_statuses_option = get_option( 'sbi_statuses', array() );
384
  $sbi_statuses_option['data_manager'] = $statuses;
385
 
386
  update_option( 'sbi_statuses', $sbi_statuses_option );
@@ -397,13 +446,12 @@ class SB_Instagram_Data_Manager {
397
  */
398
  public function remote_encrypt( $encrypted_value ) {
399
  $local_encrypt = new SB_Instagram_Data_Encryption();
400
- $raw_value = $local_encrypt->decrypt( $encrypted_value );
401
  if ( $this->key_salt === null ) {
402
- $url = 'https://secure.smashballoon.com/';
403
  $args = array(
404
- 'timeout' => 20
405
  );
406
-
407
  $response = wp_remote_get( $url, $args );
408
 
409
  if ( ! is_wp_error( $response ) ) {
@@ -411,12 +459,12 @@ class SB_Instagram_Data_Manager {
411
  }
412
  }
413
 
414
- $key = substr( $this->key_salt, 0, 64 );
415
  $salt = substr( $this->key_salt, 64, 64 );
416
 
417
  $args = array(
418
- 'key' => $key,
419
- 'salt' => $salt
420
  );
421
 
422
  $remote_encrypt = new SB_Instagram_Data_Encryption( $args );
@@ -424,13 +472,39 @@ class SB_Instagram_Data_Manager {
424
  return $remote_encrypt->encrypt( $raw_value );
425
  }
426
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
427
  /**
428
  * Reset the data manager
429
  *
430
  * @since 2.9.4/5.12.4
431
  */
432
  public function reset() {
433
- $sbi_statuses_option = get_option( 'sbi_statuses', array() );
434
  $sbi_statuses_option['data_manager'] = $this->defaults();
435
 
436
  update_option( 'sbi_statuses', $sbi_statuses_option );
@@ -446,8 +520,8 @@ class SB_Instagram_Data_Manager {
446
  */
447
  public function defaults() {
448
  return array(
449
- 'last_used' => sbi_get_current_time() - DAY_IN_SECONDS,
450
- 'num_db_updates' => 0
451
  );
452
  }
453
  }
37
  public function hooks() {
38
  add_action( 'sbi_before_display_instagram', array( $this, 'update_last_used' ) );
39
  add_action( 'sbi_before_display_instagram', array( $this, 'check' ) );
40
+ add_action( 'sbi_before_display_instagram', array( $this, 'maybe_update_legacy_sources' ) );
41
  add_action( 'sb_instagram_twicedaily', array( $this, 'maybe_delete_old_data' ) );
42
  }
43
 
57
 
58
  $this->update_statuses( $statuses );
59
  }
 
60
  }
61
 
62
  /**
68
  $this->encrypt_json_in_sbi_instagram_posts();
69
  }
70
 
71
+ /**
72
+ * Updates legacy sources if some are left in the queue from an update
73
+ */
74
+ public function maybe_update_legacy_sources() {
75
+ if ( \InstagramFeed\Builder\SBI_Source::should_do_source_updates() ) {
76
+ \InstagramFeed\Builder\SBI_Source::batch_process_legacy_source_queue();
77
+ }
78
+ }
79
+
80
  /**
81
  * Delete unused data after a period
82
  *
85
  * @since 2.9.4/5.12.4
86
  */
87
  public function maybe_delete_old_data() {
88
+ global $sb_instagram_posts_manager;
89
+
90
  $statuses = $this->get_statuses();
91
 
92
  $data_was_deleted = false;
93
 
94
+ do_action( 'sbi_before_delete_old_data', $statuses );
 
95
 
96
+ if ( $statuses['last_used'] < sbi_get_current_time() - ( 21 * DAY_IN_SECONDS ) ) {
97
  $this->delete_caches();
98
  $this->delete_comments_data();
99
  $this->delete_hashtag_data();
103
  $data_was_deleted = true;
104
  }
105
 
106
+ if ( $statuses['last_used'] < sbi_get_current_time() - ( 90 * DAY_IN_SECONDS ) ) {
107
  SB_Instagram_Connected_Account::update_connected_accounts( array() );
108
+ \InstagramFeed\Builder\SBI_Db::clear_sbi_sources();
109
  global $sb_instagram_posts_manager;
110
 
111
  $sb_instagram_posts_manager->add_action_log( 'Deleted all connected accounts.' );
127
  $sb_instagram_posts_manager->delete_all_sbi_instagram_posts();
128
 
129
  delete_option( 'sbi_top_api_calls' );
130
+ delete_option( 'sbi_local_avatars' );
131
  }
132
 
133
  /**
139
  */
140
  public function delete_non_hashtag_sbi_instagram_posts( $username ) {
141
  global $wpdb;
142
+ $table_name = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
143
+ $feeds_posts_table_name = $wpdb->prefix . SBI_INSTAGRAM_FEEDS_POSTS;
144
 
145
  $non_hashtag_posts = $wpdb->get_results(
146
  "SELECT p.id, p.media_id FROM $table_name as p
147
  INNER JOIN $feeds_posts_table_name AS f ON p.id = f.id
148
+ WHERE f.hashtag = '';",
149
+ ARRAY_A
150
+ );
151
 
152
+ $upload = wp_upload_dir();
153
  $file_suffixes = array( 'thumb', 'low', 'full' );
154
 
155
  foreach ( $non_hashtag_posts as $post ) {
169
  $non_hashtag_posts_deleted = $wpdb->query(
170
  "DELETE p, f FROM $table_name as p
171
  INNER JOIN $feeds_posts_table_name AS f ON p.id = f.id
172
+ WHERE f.hashtag = '';"
173
+ );
174
 
175
  }
176
 
181
  */
182
  public function update_json_non_hashtag_sbi_instagram_posts() {
183
  global $wpdb;
184
+ $table_name = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
185
+ $feeds_posts_table_name = $wpdb->prefix . SBI_INSTAGRAM_FEEDS_POSTS;
186
 
187
  $updated = $wpdb->query(
188
  "UPDATE $table_name as p
189
  INNER JOIN $feeds_posts_table_name AS f ON p.id = f.id
190
  SET p.json_data = ''
191
+ WHERE f.hashtag = '';"
192
+ );
193
 
194
  }
195
 
210
  $this->update_statuses( $statuses );
211
 
212
  global $wpdb;
213
+ $encryption = new SB_Instagram_Data_Encryption();
214
+ $table_name = $wpdb->prefix . SBI_INSTAGRAM_POSTS_TYPE;
215
+ $feeds_posts_table_name = $wpdb->prefix . SBI_INSTAGRAM_FEEDS_POSTS;
216
 
217
  $plaintext_posts = $wpdb->get_results(
218
  "SELECT * FROM $table_name as p
219
  INNER JOIN $feeds_posts_table_name AS f ON p.id = f.id
220
  WHERE p.json_data LIKE '%{%'
221
  ORDER BY p.time_stamp DESC
222
+ LIMIT 50;",
223
+ ARRAY_A
224
+ );
225
 
226
  if ( empty( $plaintext_posts ) ) {
227
  $statuses['num_db_updates'] = 31;
230
 
231
  foreach ( $plaintext_posts as $post ) {
232
  $json_data = $encryption->encrypt( $post['json_data'] );
233
+ $updated = $wpdb->query(
234
+ $wpdb->prepare(
235
+ "UPDATE $table_name as p
236
  INNER JOIN $feeds_posts_table_name AS f ON p.id = f.id
237
  SET p.json_data = %s
238
+ WHERE p.id = %d;",
239
+ $json_data,
240
+ $post['id']
241
+ )
242
+ );
243
  }
244
  }
245
 
263
  public function delete_caches( $include_backup = true ) {
264
  /* Backup Caches */
265
  global $wpdb;
266
+ $table_name = $wpdb->prefix . 'options';
267
 
268
  if ( $include_backup ) {
269
+ $wpdb->query(
270
+ "
271
  DELETE
272
  FROM $table_name
273
  WHERE `option_name` LIKE ('%!sbi\_%')
274
+ "
275
+ );
276
+ $wpdb->query(
277
+ "
278
  DELETE
279
  FROM $table_name
280
  WHERE `option_name` LIKE ('%\_transient\_&sbi\_%')
281
+ "
282
+ );
283
+ $wpdb->query(
284
+ "
285
  DELETE
286
  FROM $table_name
287
  WHERE `option_name` LIKE ('%\_transient\_timeout\_&sbi\_%')
288
+ "
289
+ );
290
  }
291
 
292
  /* Regular Caches */
293
  //Delete all transients
294
+ $wpdb->query(
295
+ "
296
  DELETE
297
  FROM $table_name
298
  WHERE `option_name` LIKE ('%\_transient\_sbi\_%')
299
+ "
300
+ );
301
+ $wpdb->query(
302
+ "
303
  DELETE
304
  FROM $table_name
305
  WHERE `option_name` LIKE ('%\_transient\_timeout\_sbi\_%')
306
+ "
307
+ );
308
+ $wpdb->query(
309
+ "
310
  DELETE
311
  FROM $table_name
312
  WHERE `option_name` LIKE ('%\_transient\_&sbi\_%')
313
+ "
314
+ );
315
+ $wpdb->query(
316
+ "
317
  DELETE
318
  FROM $table_name
319
  WHERE `option_name` LIKE ('%\_transient\_timeout\_&sbi\_%')
320
+ "
321
+ );
322
+ $wpdb->query(
323
+ "
324
  DELETE
325
  FROM $table_name
326
  WHERE `option_name` LIKE ('%\_transient\_\$sbi\_%')
327
+ "
328
+ );
329
+ $wpdb->query(
330
+ "
331
  DELETE
332
  FROM $table_name
333
  WHERE `option_name` LIKE ('%\_transient\_timeout\_\$sbi\_%')
334
+ "
335
+ );
336
 
337
  delete_option( 'sbi_single_cache' );
338
+
339
+ \InstagramFeed\Builder\SBI_Db::clear_sbi_feed_caches();
340
+ \InstagramFeed\Builder\SBI_Db::clear_sbi_sources();
341
+
342
  }
343
 
344
  /**
351
  public function update_db_for_dpa() {
352
  global $wpdb;
353
  $encryption = new SB_Instagram_Data_Encryption();
354
+ $table_name = $wpdb->prefix . 'options';
355
 
356
+ $permanent_caches = $wpdb->get_results(
357
+ "
358
  SELECT *
359
  FROM $table_name
360
  WHERE option_name LIKE ('%!sbi\_%')
361
+ ",
362
+ ARRAY_A
363
+ );
364
 
365
  if ( count( $permanent_caches ) < 10 ) {
366
  foreach ( $permanent_caches as $permanent_cache ) {
400
  $ids = get_option( 'sbi_hashtag_ids', array() );
401
  if ( ! is_array( $ids ) ) {
402
  $encryption = new SB_Instagram_Data_Encryption();
403
+ $ids = json_decode( $encryption->decrypt( $ids ), true );
404
  }
405
 
406
  update_option( 'sbi_hashtag_ids', $encryption->encrypt( sbi_json_encode( $ids ) ), false );
429
  * @since 2.9.4/5.12.4
430
  */
431
  public function update_statuses( $statuses ) {
432
+ $sbi_statuses_option = get_option( 'sbi_statuses', array() );
433
  $sbi_statuses_option['data_manager'] = $statuses;
434
 
435
  update_option( 'sbi_statuses', $sbi_statuses_option );
446
  */
447
  public function remote_encrypt( $encrypted_value ) {
448
  $local_encrypt = new SB_Instagram_Data_Encryption();
449
+ $raw_value = $local_encrypt->decrypt( $encrypted_value );
450
  if ( $this->key_salt === null ) {
451
+ $url = 'https://secure.smashballoon.com/';
452
  $args = array(
453
+ 'timeout' => 20,
454
  );
 
455
  $response = wp_remote_get( $url, $args );
456
 
457
  if ( ! is_wp_error( $response ) ) {
459
  }
460
  }
461
 
462
+ $key = substr( $this->key_salt, 0, 64 );
463
  $salt = substr( $this->key_salt, 64, 64 );
464
 
465
  $args = array(
466
+ 'key' => $key,
467
+ 'salt' => $salt,
468
  );
469
 
470
  $remote_encrypt = new SB_Instagram_Data_Encryption( $args );
472
  return $remote_encrypt->encrypt( $raw_value );
473
  }
474
 
475
+ public function remote_decrypt( $encrypted_value ) {
476
+ if ( $this->key_salt === null ) {
477
+ $url = 'https://secure.smashballoon.com/';
478
+ $args = array(
479
+ 'timeout' => 20,
480
+ );
481
+ $response = wp_remote_get( $url, $args );
482
+
483
+ if ( ! is_wp_error( $response ) ) {
484
+ $this->key_salt = $response['body'];
485
+ }
486
+ }
487
+
488
+ $key = substr( $this->key_salt, 0, 64 );
489
+ $salt = substr( $this->key_salt, 64, 64 );
490
+
491
+ $args = array(
492
+ 'key' => $key,
493
+ 'salt' => $salt,
494
+ );
495
+
496
+ $remote_encrypt = new SB_Instagram_Data_Encryption( $args );
497
+
498
+ return $remote_encrypt->decrypt( $encrypted_value );
499
+ }
500
+
501
  /**
502
  * Reset the data manager
503
  *
504
  * @since 2.9.4/5.12.4
505
  */
506
  public function reset() {
507
+ $sbi_statuses_option = get_option( 'sbi_statuses', array() );
508
  $sbi_statuses_option['data_manager'] = $this->defaults();
509
 
510
  update_option( 'sbi_statuses', $sbi_statuses_option );
520
  */
521
  public function defaults() {
522
  return array(
523
+ 'last_used' => sbi_get_current_time() - DAY_IN_SECONDS,
524
+ 'num_db_updates' => 0,
525
  );
526
  }
527
  }
inc/class-sb-instagram-posts-manager.php CHANGED
@@ -63,6 +63,10 @@ class SB_Instagram_Posts_Manager {
63
  if ( $this->does_resizing_tables_exist() ) {
64
  $this->resizing_tables_exist = true;
65
  }
 
 
 
 
66
  }
67
 
68
  /**
@@ -133,7 +137,14 @@ class SB_Instagram_Posts_Manager {
133
  $this->errors['revoked'][] = $connected_account['user_id'];
134
  }
135
 
136
- $this->delete_platform_data( $connected_account );
 
 
 
 
 
 
 
137
  }
138
  } elseif ( isset( $details['response'] ) && is_wp_error( $details['response'] ) ) {
139
  foreach ( $details['response']->errors as $key => $item ) {
@@ -208,6 +219,16 @@ class SB_Instagram_Posts_Manager {
208
  $log_item .= $details;
209
  }
210
 
 
 
 
 
 
 
 
 
 
 
211
  $current_log = $this->errors['error_log'];
212
  if ( is_array( $current_log ) && count( $current_log ) >= 10 ) {
213
  reset( $current_log );
@@ -353,7 +374,7 @@ class SB_Instagram_Posts_Manager {
353
  return $error_message_return;
354
  }
355
  $hash = '#' . (int) $response['error']['code'];
356
- $link = admin_url( '?page=sbi-settings' );
357
 
358
  if ( isset( $response['error']['message'] ) ) {
359
  if ( (int) $response['error']['code'] === 100 ) {
@@ -969,6 +990,8 @@ class SB_Instagram_Posts_Manager {
969
  return '';
970
  }
971
  $accounts_revoked_string = '';
 
 
972
  if ( $this->was_app_permission_related_error() ) {
973
  $accounts_revoked = $this->get_app_permission_related_error_ids();
974
  if ( count( $accounts_revoked ) > 1 ) {
@@ -976,28 +999,35 @@ class SB_Instagram_Posts_Manager {
976
  } else {
977
  $accounts_revoked = $accounts_revoked[0];
978
  }
979
- $accounts_revoked_string = sprintf( __( 'Instagram Feed related data for the account(s) %s was removed due to permission for the Smash Balloon App on Facebook or Instagram being revoked.', 'instagram-feed' ), $accounts_revoked );
980
  }
981
 
982
  if ( isset( $this->errors['connection']['critical'] ) ) {
983
  $errors = $this->get_errors();
984
  $error_message = '';
985
 
986
- $error_message_array = $errors['connection']['error_message'];
987
- $error_message .= '<strong>' . $error_message_array['error_message'] . '</strong><br>';
988
- $error_message .= $error_message_array['admin_only'] . '<br><br>';
989
- if ( ! empty( $accounts_revoked_string ) ) {
990
- $error_message .= $accounts_revoked_string . '<br><br>';
991
- }
992
- if ( ! empty( $error_message_array['backend_directions'] ) ) {
993
- $error_message .= $error_message_array['backend_directions'];
994
  } else {
995
- $retry = '';
996
- if ( is_admin() ) {
997
- $retry = '<button data-url="'.get_the_permalink( $this->errors['connection']['post_id'] ).'" class="sbi-clear-errors-visit-page sbi-space-left sbi-btn sbi-notice-btn sbi-btn-grey">' . __( 'View Feed and Retry', 'instagram-feed' ) . '</button>';
 
 
 
 
 
 
 
 
 
 
 
 
998
  }
999
- $hash = isset( $errors['connection']['error_id'] ) ? '#' . (int) $errors['connection']['error_id'] : '';
1000
- $error_message .= '<div class="license-action-btns"><p class="sbi-error-directions"><a class="sbi-license-btn sbi-btn-blue sbi-notice-btn" href="https://smashballoon.com/instagram-feed/docs/errors/' . $hash . '" target="_blank" rel="noopener">' . __( 'Directions on how to resolve this issue', 'instagram-feed' ) . '</a>' . $retry. '</p></div>';
1001
  }
1002
  } else {
1003
  $connected_accounts = SB_Instagram_Connected_Account::get_all_connected_accounts();
63
  if ( $this->does_resizing_tables_exist() ) {
64
  $this->resizing_tables_exist = true;
65
  }
66
+
67
+ require_once( trailingslashit( dirname( __FILE__ ) ) . '/Platform_Data.php' );
68
+ $platform_data_manager = new \InstagramFeed\Platform_Data();
69
+ $platform_data_manager->register_hooks();
70
  }
71
 
72
  /**
137
  $this->errors['revoked'][] = $connected_account['user_id'];
138
  }
139
 
140
+ /**
141
+ * Fires when an app permission related error is encountered
142
+ *
143
+ * @param array $connected_account The connected account that encountered the error
144
+ *
145
+ * @since 6.0.6
146
+ */
147
+ do_action( 'sbi_app_permission_revoked', $connected_account );
148
  }
149
  } elseif ( isset( $details['response'] ) && is_wp_error( $details['response'] ) ) {
150
  foreach ( $details['response']->errors as $key => $item ) {
219
  $log_item .= $details;
220
  }
221
 
222
+ if ( $type === 'unused_feed' ) {
223
+ $this->errors['unused_feed'] = $details;
224
+ $log_item .= $details;
225
+ }
226
+
227
+ if ( $type === 'platform_data_deleted' ) {
228
+ $this->errors['platform_data_deleted'] = $details;
229
+ $log_item .= $details;
230
+ }
231
+
232
  $current_log = $this->errors['error_log'];
233
  if ( is_array( $current_log ) && count( $current_log ) >= 10 ) {
234
  reset( $current_log );
374
  return $error_message_return;
375
  }
376
  $hash = '#' . (int) $response['error']['code'];
377
+ $link = admin_url( 'admin.php?page=sbi-settings' );
378
 
379
  if ( isset( $response['error']['message'] ) ) {
380
  if ( (int) $response['error']['code'] === 100 ) {
990
  return '';
991
  }
992
  $accounts_revoked_string = '';
993
+ $accounts_revoked = '';
994
+
995
  if ( $this->was_app_permission_related_error() ) {
996
  $accounts_revoked = $this->get_app_permission_related_error_ids();
997
  if ( count( $accounts_revoked ) > 1 ) {
999
  } else {
1000
  $accounts_revoked = $accounts_revoked[0];
1001
  }
1002
+ $accounts_revoked_string = sprintf( __( 'Instagram Feed related data for the account(s) %s was removed due to permission for the Smash Balloon App on Facebook or Instagram being revoked. <br><br> To prevent the automated data deletion for the account, please reconnect your account within 7 days.', 'instagram-feed' ), $accounts_revoked );
1003
  }
1004
 
1005
  if ( isset( $this->errors['connection']['critical'] ) ) {
1006
  $errors = $this->get_errors();
1007
  $error_message = '';
1008
 
1009
+ if ( $errors['connection']['error_id'] === 190 ) {
1010
+ $error_message .= '<strong>' . __( 'Action Required Within 7 Days', 'instagram-feed' ) . '</strong><br>';
1011
+ $error_message .= __( 'An account admin has deauthorized the Smash Balloon app used to power the Instagram Feed plugin.', 'instagram-feed' );
1012
+ $error_message .= ' ' . sprintf( __( 'If the Instagram account is not reconnected within 7 days then all Instagram data will be automatically deleted on your website for this account (ID: %s) due to Facebook data privacy rules.', 'instagram-feed' ), $accounts_revoked );
1013
+ $error_message .= __( '<br><br>To prevent the automated data deletion for the account, please reconnect your account within 7 days.', 'instagram-feed' );
 
 
 
1014
  } else {
1015
+ $error_message_array = $errors['connection']['error_message'];
1016
+ $error_message .= '<strong>' . $error_message_array['error_message'] . '</strong><br>';
1017
+ $error_message .= $error_message_array['admin_only'] . '<br><br>';
1018
+ if ( ! empty( $accounts_revoked_string ) ) {
1019
+ $error_message .= $accounts_revoked_string . '<br><br>';
1020
+ }
1021
+ if ( ! empty( $error_message_array['backend_directions'] ) ) {
1022
+ $error_message .= $error_message_array['backend_directions'];
1023
+ } else {
1024
+ $retry = '';
1025
+ if ( is_admin() ) {
1026
+ $retry = '<button data-url="'.get_the_permalink( $this->errors['connection']['post_id'] ).'" class="sbi-clear-errors-visit-page sbi-space-left sbi-btn sbi-notice-btn sbi-btn-grey">' . __( 'View Feed and Retry', 'instagram-feed' ) . '</button>';
1027
+ }
1028
+ $hash = isset( $errors['connection']['error_id'] ) ? '#' . (int) $errors['connection']['error_id'] : '';
1029
+ $error_message .= '<div class="license-action-btns"><p class="sbi-error-directions"><a class="sbi-license-btn sbi-btn-blue sbi-notice-btn" href="https://smashballoon.com/instagram-feed/docs/errors/' . $hash . '" target="_blank" rel="noopener">' . __( 'Directions on how to resolve this issue', 'instagram-feed' ) . '</a>' . $retry. '</p></div>';
1030
  }
 
 
1031
  }
1032
  } else {
1033
  $connected_accounts = SB_Instagram_Connected_Account::get_all_connected_accounts();
instagram-feed.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Smash Balloon Instagram Feed
4
  Plugin URI: https://smashballoon.com/instagram-feed
5
  Description: Display beautifully clean, customizable, and responsive Instagram feeds.
6
- Version: 6.0.5
7
  Author: Smash Balloon
8
  Author URI: https://smashballoon.com/
9
  License: GPLv2 or later
@@ -32,7 +32,7 @@ if ( ! defined( 'SBI_PLUGIN_NAME' ) ) {
32
  define( 'SBI_PLUGIN_NAME', 'Instagram Feed Free' );
33
  }
34
  if ( ! defined( 'SBIVER' ) ) {
35
- define( 'SBIVER', '6.0.5' );
36
  }
37
  // Db version.
38
  if ( ! defined( 'SBI_DBVERSION' ) ) {
3
  Plugin Name: Smash Balloon Instagram Feed
4
  Plugin URI: https://smashballoon.com/instagram-feed
5
  Description: Display beautifully clean, customizable, and responsive Instagram feeds.
6
+ Version: 6.0.6
7
  Author: Smash Balloon
8
  Author URI: https://smashballoon.com/
9
  License: GPLv2 or later
32
  define( 'SBI_PLUGIN_NAME', 'Instagram Feed Free' );
33
  }
34
  if ( ! defined( 'SBIVER' ) ) {
35
+ define( 'SBIVER', '6.0.6' );
36
  }
37
  // Db version.
38
  if ( ! defined( 'SBI_DBVERSION' ) ) {
js/sb-instagram-admin-6.js CHANGED
@@ -94,6 +94,27 @@ jQuery(document).ready(function($) {
94
  }); // ajax call
95
  });
96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  $('.sbi-clear-errors-visit-page').on('click', function(event) {
98
  event.preventDefault();
99
  var $btn = $(this);
94
  }); // ajax call
95
  });
96
 
97
+ $('.sbi-reset-unused-feed-usage').on('click', function (event) {
98
+ event.preventDefault();
99
+ const $btn = $(this);
100
+ $btn.prop('disabled', true).addClass('loading').html('<i class="fa fa-spinner fa-spin" aria-hidden="true"></i>');
101
+ $.ajax({
102
+ url: sbiA.ajax_url,
103
+ type: 'post',
104
+ data: {
105
+ action: 'sbi_reset_unused_feed_usage',
106
+ sbi_nonce: sbiA.sbi_nonce,
107
+ },
108
+ success: function (data) {
109
+ if (typeof data.data.message !== 'undefined') {
110
+ $btn.closest('p').after(data.data.message);
111
+ $btn.remove();
112
+ }
113
+ },
114
+ error: function (data) {}
115
+ });
116
+ });
117
+
118
  $('.sbi-clear-errors-visit-page').on('click', function(event) {
119
  event.preventDefault();
120
  var $btn = $(this);
vendor/composer/installed.json CHANGED
@@ -7,15 +7,15 @@
7
  "source": {
8
  "type": "git",
9
  "url": "git@github.com:awesomemotive/sb-stubs.git",
10
- "reference": "1f3cfc495280e072aac59933690164b3cb4d5b21"
11
  },
12
  "dist": {
13
  "type": "zip",
14
- "url": "https://api.github.com/repos/awesomemotive/sb-stubs/zipball/1f3cfc495280e072aac59933690164b3cb4d5b21",
15
- "reference": "1f3cfc495280e072aac59933690164b3cb4d5b21",
16
  "shasum": ""
17
  },
18
- "time": "2022-03-24T11:04:04+00:00",
19
  "default-branch": true,
20
  "type": "library",
21
  "installation-source": "dist",
7
  "source": {
8
  "type": "git",
9
  "url": "git@github.com:awesomemotive/sb-stubs.git",
10
+ "reference": "36cb174511ed63c008d2d3f2a77194612de489be"
11
  },
12
  "dist": {
13
  "type": "zip",
14
+ "url": "https://api.github.com/repos/awesomemotive/sb-stubs/zipball/36cb174511ed63c008d2d3f2a77194612de489be",
15
+ "reference": "36cb174511ed63c008d2d3f2a77194612de489be",
16
  "shasum": ""
17
  },
18
+ "time": "2022-05-25T08:11:42+00:00",
19
  "default-branch": true,
20
  "type": "library",
21
  "installation-source": "dist",
vendor/composer/installed.php CHANGED
@@ -5,7 +5,7 @@
5
  'type' => 'library',
6
  'install_path' => __DIR__ . '/../../',
7
  'aliases' => array(),
8
- 'reference' => '32fa15240ac296f92a477f177de0acf333507d67',
9
  'name' => 'smashballoon/instagram-feed',
10
  'dev' => true,
11
  ),
@@ -16,7 +16,7 @@
16
  'type' => 'library',
17
  'install_path' => __DIR__ . '/../../',
18
  'aliases' => array(),
19
- 'reference' => '32fa15240ac296f92a477f177de0acf333507d67',
20
  'dev_requirement' => false,
21
  ),
22
  'smashballoon/stubs' => array(
@@ -27,7 +27,7 @@
27
  'aliases' => array(
28
  0 => '9999999-dev',
29
  ),
30
- 'reference' => '1f3cfc495280e072aac59933690164b3cb4d5b21',
31
  'dev_requirement' => false,
32
  ),
33
  ),
5
  'type' => 'library',
6
  'install_path' => __DIR__ . '/../../',
7
  'aliases' => array(),
8
+ 'reference' => '485eb78065c52524e0e06973cd027ae3e41cadcd',
9
  'name' => 'smashballoon/instagram-feed',
10
  'dev' => true,
11
  ),
16
  'type' => 'library',
17
  'install_path' => __DIR__ . '/../../',
18
  'aliases' => array(),
19
+ 'reference' => '485eb78065c52524e0e06973cd027ae3e41cadcd',
20
  'dev_requirement' => false,
21
  ),
22
  'smashballoon/stubs' => array(
27
  'aliases' => array(
28
  0 => '9999999-dev',
29
  ),
30
+ 'reference' => '36cb174511ed63c008d2d3f2a77194612de489be',
31
  'dev_requirement' => false,
32
  ),
33
  ),
vendor/smashballoon/stubs/.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
1
+ vendor
2
+ .idea
vendor/smashballoon/stubs/README.md ADDED
@@ -0,0 +1,2 @@
 
 
1
+ # sb-stubs
2
+ Shared stubs for Smash Balloon like service interfaces and abstracts
vendor/smashballoon/stubs/composer.lock ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_readme": [
3
+ "This file locks the dependencies of your project to a known state",
4
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5
+ "This file is @generated automatically"
6
+ ],
7
+ "content-hash": "bf7766bf43df34d0f5f9d1b6948058d7",
8
+ "packages": [],
9
+ "packages-dev": [],
10
+ "aliases": [],
11
+ "minimum-stability": "stable",
12
+ "stability-flags": [],
13
+ "prefer-stable": false,
14
+ "prefer-lowest": false,
15
+ "platform": [],
16
+ "platform-dev": [],
17
+ "plugin-api-version": "2.2.0"
18
+ }
vendor/smashballoon/stubs/src/Traits/Singleton.php CHANGED
@@ -15,6 +15,6 @@ trait Singleton
15
  $this->init();
16
  }
17
  protected function init() {}
18
- final private function __wakeup() {}
19
  final private function __clone() {}
20
  }
15
  $this->init();
16
  }
17
  protected function init() {}
18
+ final public function __wakeup() {}
19
  final private function __clone() {}
20
  }