PluginProbe ʕ •ᴥ•ʔ
Smash Balloon Social Post Feed – Simple Social Feeds for WordPress / 4.8.1
Smash Balloon Social Post Feed – Simple Social Feeds for WordPress v4.8.1
4.8.1 trunk 1.0 1.1 1.12.1 1.2.3 1.2.4 1.2.5 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.5 1.5.1 1.5.2 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.4.1 1.6.5 1.6.5.1 1.6.6 1.6.6.1 1.6.6.2 1.6.6.3 1.6.7 1.6.7.1 1.6.8 1.6.8.1 1.6.8.2 1.7.0 1.7.1 1.7.2 1.8.0 1.8.1 1.8.2 1.8.2.1 1.8.2.2 1.8.2.3 1.9.0 1.9.1 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.8.1 1.9.9 1.9.9.1 1.9.9.2 1.9.9.3 2.0 2.0.1 2.1 2.1.1 2.1.2 2.1.3 2.10 2.11 2.11.1 2.12 2.12.1 2.12.2 2.12.3 2.12.4 2.13 2.14 2.14.1 2.15 2.15.1 2.16 2.16.1 2.17 2.17.1 2.18 2.18.1 2.18.2 2.18.3 2.19 2.19.1 2.19.2 2.19.3 2.2 2.2.1 2.3 2.3.1 2.3.10 2.3.2 2.3.3 2.3.4 2.3.6 2.3.7 2.3.8 2.3.9 2.4 2.4.1 2.4.1.1 2.4.1.2 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.5 2.5.1 2.5.2 2.6 2.6.1 2.6.2 2.6.3 2.6.4 2.7 2.7.1 2.7.2 2.8 2.9 2.9.1 4.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.1 4.1.1 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 4.2 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.3.0 4.3.1 4.3.2 4.3.3 4.3.4 4.7.5 4.7.6 4.7.7
custom-facebook-feed / inc / CFF_Error_Reporter.php
custom-facebook-feed / inc Last commit date
Admin 2 weeks ago Builder 2 weeks ago Helpers 2 weeks ago Integrations 2 weeks ago CFF_Autolink.php 2 weeks ago CFF_Blocks.php 2 weeks ago CFF_Cache.php 2 weeks ago CFF_Education.php 2 weeks ago CFF_Elementor_Base.php 2 weeks ago CFF_Elementor_Widget.php 2 weeks ago CFF_Error_Reporter.php 2 weeks ago CFF_FB_Settings.php 2 weeks ago CFF_Feed_Elementor_Control.php 2 weeks ago CFF_Feed_Locator.php 2 weeks ago CFF_Feed_Pro.php 2 weeks ago CFF_GDPR_Integrations.php 2 weeks ago CFF_Group_Posts.php 2 weeks ago CFF_HTTP_Request.php 2 weeks ago CFF_Oembed.php 2 weeks ago CFF_Parse.php 2 weeks ago CFF_Resizer.php 2 weeks ago CFF_Response.php 2 weeks ago CFF_Shortcode.php 2 weeks ago CFF_Shortcode_Display.php 2 weeks ago CFF_SiteHealth.php 2 weeks ago CFF_Utils.php 2 weeks ago CFF_View.php 2 weeks ago Custom_Facebook_Feed.php 2 weeks ago Email_Notification.php 2 weeks ago Platform_Data.php 2 weeks ago SB_Facebook_Data_Encryption.php 2 weeks ago SB_Facebook_Data_Manager.php 2 weeks ago index.php 2 weeks ago
CFF_Error_Reporter.php
1004 lines
1 <?php
2
3 /**
4 * Class CFF_Error_Reporter
5 *
6 * Set as a global object to record and report errors
7 *
8 * @since
9 */
10
11 namespace CustomFacebookFeed;
12
13 use CustomFacebookFeed\CFF_Education;
14 use CustomFacebookFeed\Builder\CFF_Source;
15
16 if (! defined('ABSPATH')) {
17 exit; // Exit if accessed directly
18 }
19
20
21 class CFF_Error_Reporter
22 {
23 /**
24 * @var array
25 */
26 public $errors;
27
28 /**
29 * @var array
30 */
31 public $frontend_error;
32
33 /**
34 * @var string
35 */
36 public $reporter_key;
37
38 /**
39 * @var array
40 */
41 public $display_error;
42
43
44 /**
45 * CFF_Error_Reporter constructor.
46 */
47 public function __construct()
48 {
49 $this->reporter_key = 'cff_error_reporter';
50 $this->errors = get_option($this->reporter_key, []);
51 if (! isset($this->errors['connection'])) {
52 $this->errors = array(
53 'connection' => [],
54 'resizing' => [],
55 'database_create' => [],
56 'upload_dir' => [],
57 'accounts' => [],
58 'error_log' => [],
59 'action_log' => [],
60 'revoked' => []
61 );
62 }
63
64
65 $this->display_error = [];
66 $this->frontend_error = '';
67
68 add_action('cff_feed_issue_email', [$this, 'maybe_trigger_report_email_send']);
69 add_action('wp_ajax_cff_dismiss_critical_notice', [$this, 'dismiss_critical_notice']);
70 add_action('wp_footer', [$this, 'critical_error_notice'], 300);
71 add_action('cff_admin_notices', [$this, 'admin_error_notices']);
72 add_action('cff_admin_notices', [$this, 'platform_data_deleted_notice']);
73 add_action('cff_admin_notices', [$this, 'group_deprecation_notice']);
74 add_action('cff_admin_notices', [$this, 'platform_unused_feed_notice']);
75 }
76
77 /**
78 * @return array
79 *
80 * @since 2.0/4.0
81 */
82 public function get_errors()
83 {
84 return $this->errors;
85 }
86
87 /**
88 * @param $type
89 * @param $message_array
90 *
91 * @since 2.0/4.0
92 */
93 public function add_error($type, $args, $connected_account_term = false)
94 {
95 $connected_account = false;
96
97 $log_item = date('m-d H:i:s') . ' - ';
98 if ($connected_account_term !== false) {
99 if (!is_array($connected_account_term)) {
100 $connected_account = CFF_Source::get_single_source_info($connected_account_term);
101 } else {
102 $connected_account = $connected_account_term;
103 }
104
105 $this->add_connected_account_error($connected_account, $type, $args);
106 }
107
108 // Access Token Error
109 if ($type === 'accesstoken') {
110 $accesstoken_error_exists = false;
111 if (isset($this->errors['accounts'])) {
112 foreach ($this->errors['accounts'] as $account) {
113 if ($args['accesstoken'] === $account['accesstoken']) {
114 $accesstoken_error_exists = true;
115 }
116 }
117 }
118 if (!$accesstoken_error_exists && isset($this->errors['accounts'])) {
119 $this->errors['accounts'][$connected_account['id']][] = array(
120 'accesstoken' => $args['accesstoken'],
121 'post_id' => $args['post_id'],
122 'critical' => true,
123 'type' => $type,
124 'errorno' => $args['errorno']
125 );
126 }
127 }
128
129 // Connection Error API & WP REMOTE CALL
130 if ($type === 'api' || $type === 'wp_remote_get') {
131 $connection_details = array(
132 'error_id' => ''
133 );
134 $connection_details['critical'] = false;
135
136 if (isset($args['error']['code'])) {
137 $connection_details['error_id'] = $args['error']['code'];
138 if ($this->is_critical_error($args)) {
139 $connection_details['critical'] = true;
140 }
141
142 if ($this->is_app_permission_related($args)) {
143 if (!isset($this->errors['revoked']) || (!is_array($this->errors['revoked']))) {
144 $this->errors['revoked'] = array();
145 }
146 if (isset($connected_account['account_id']) && !in_array($connected_account['account_id'], $this->errors['revoked'], true)) {
147 $this->errors['revoked'][] = $connected_account['account_id'];
148 }
149 /**
150 * Fires when an app permission related error is encountered
151 *
152 * @param array $connected_account The connected account that encountered the error
153 *
154 * @since
155 */
156 do_action('cff_app_permission_revoked', $connected_account);
157 }
158 } elseif (isset($args['response']) && is_wp_error($args['response'])) {
159 foreach ($args['response']->errors as $key => $item) {
160 $connection_details['error_id'] = $key;
161 }
162 $connection_details['critical'] = true;
163 }
164
165 $connection_details['error_message'] = $this->generate_error_message($args, $connected_account);
166 $log_item .= $connection_details['error_message']['admin_message'];
167 $this->errors['connection'] = $connection_details;
168 }
169
170 if ($type === 'image_editor' || $type === 'storage') {
171 $this->errors['resizing'] = $args;
172 $log_item .= is_array($args) ? wp_json_encode($args) : $args;
173 }
174
175 if ($type === 'database_create') {
176 $this->errors['database_create'] = $args;
177 $log_item .= $args;
178 }
179
180 if ($type === 'upload_dir') {
181 $this->errors['upload_dir'] = $args;
182 $log_item .= $args;
183 }
184
185 if ($type === 'platform_data_deleted') {
186 $this->errors['platform_data_deleted'] = $args[0];
187 $log_item .= is_array($args) ? wp_json_encode($args) : $args;
188 }
189
190
191 $current_log = $this->errors['error_log'];
192 if (is_array($current_log) && count($current_log) >= 10) {
193 reset($current_log);
194 unset($current_log[key($current_log)]);
195 }
196 $current_log[] = $log_item;
197 $this->errors['error_log'] = $current_log;
198 update_option($this->reporter_key, $this->errors, false);
199 }
200
201 /**
202 * Stores information about an encountered error related to a connected account
203 *
204 * @param $connected_account array
205 * @param $error_type string
206 * @param $details mixed/array/string
207 *
208 * @since 2.19
209 */
210 public function add_connected_account_error($connected_account, $error_type, $details)
211 {
212 $account_id = $connected_account['id'];
213 $this->errors['accounts'][ $account_id ][ $error_type ] = $details;
214
215 if ($error_type === 'api' || $error_type === 'accesstoken') {
216 $this->errors['accounts'][ $account_id ][ $error_type ]['clear_time'] = time() + 60 * 3;
217 }
218
219 if (
220 isset($details['error']['code'])
221 && (int)$details['error']['code'] === 18
222 ) {
223 $this->errors['accounts'][ $account_id ][ $error_type ]['clear_time'] = time() + 60 * 15;
224 }
225
226 \CustomFacebookFeed\Builder\CFF_Source::add_error($account_id, $details);
227 }
228
229 /**
230 * @return mixed
231 *
232 * @since 2.19
233 */
234 public function get_error_log()
235 {
236 return $this->errors['error_log'];
237 }
238
239
240
241 /**
242 * Creates an array of information for easy display of API errors
243 *
244 * @param $response
245 * @param array $connected_account
246 *
247 * @return array
248 *
249 * @since 2.19
250 */
251 public function generate_error_message($response, $connected_account = array( 'username' => '' ))
252 {
253 $error_message_return = array(
254 'public_message' => '',
255 'admin_message' => '',
256 'frontend_directions' => '',
257 'backend_directions' => '',
258 'post_id' => get_the_ID(),
259 'errorno' => '',
260 'time' => time()
261 );
262
263 if (isset($response['error']['code'])) {
264 $error_code = (int)$response['error']['code'];
265 if ($error_code === 104) {
266 $error_code = 999;
267 $url = 'https://smashballoon.com/doc/error-999-access-token-could-not-be-decrypted/?utm_campaign=facebook-free&utm_source=error&utm_medium=docs';
268
269 $response['error']['message'] = __('Your access token could not be decrypted on this website. Reconnect this account or go to our website to learn how to prevent this.', 'custom-facebook-feed');
270 } else {
271 $url = 'https://smashballoon.com/doc/facebook-api-errors/?utm_campaign=facebook-free&utm_source=error&utm_medium=docs';
272 }
273
274 $api_error_number_message = sprintf(__('API Error %s:', 'custom-facebook-feed'), $error_code);
275 $error_message_return['public_message'] = __('Error connecting to the Facebook API.', 'custom-facebook-feed') . ' ' . $api_error_number_message;
276 $ppca_error = ( strpos($response['error']['message'], 'Public Content Access') !== false ) ? true : false;
277
278 $error_message_return['admin_message'] = ( $ppca_error)
279 ? '<B>PPCA Error:</b> Due to Facebook API changes it is no longer possible to display a feed from a Facebook Page you are not an admin of. Please use the button below for more information on how to fix this.'
280 : '<strong>' . $api_error_number_message . '</strong><br>' . $response['error']['message'];
281
282 $error_message_return['frontend_directions'] = ( $ppca_error )
283 ? '<p class="cff-error-directions"><a href="https://smashballoon.com/facebook-api-changes-september-4-2020/?utm_campaign=facebook-free&utm_source=error&utm_medium=docs" target="_blank" rel="noopener">' . __('Directions on How to Resolve This Issue', 'custom-facebook-feed') . '</a></p>'
284 : '<p class="cff-error-directions"><a href="' . $url . '#' . absint($error_code) . '" target="_blank" rel="noopener">' . __('Directions on How to Resolve This Issue', 'custom-facebook-feed') . '</a></p>';
285
286 $error_message_return['backend_directions'] = ( $ppca_error )
287 ? '<a class="cff-notice-btn cff-btn-blue" href="https://smashballoon.com/facebook-api-changes-september-4-2020/?utm_campaign=facebook-free&utm_source=error&utm_medium=docs" target="_blank" rel="noopener">' . __('Directions on How to Resolve This Issue', 'custom-facebook-feed') . '</a>'
288 : '<a class="cff-notice-btn cff-btn-blue" href="' . $url . '#' . absint($error_code) . '" target="_blank" rel="noopener">' . __('Directions on How to Resolve This Issue', 'custom-facebook-feed') . '</a>';
289
290 $error_message_return['errorno'] = $error_code;
291 } else {
292 $error_message_return['error_message'] = __('An unknown error has occurred.', 'custom-facebook-feed');
293 $error_message_return['admin_message'] = json_encode($response);
294 }
295
296 return $error_message_return;
297 }
298
299
300
301
302 /**
303 * Certain API errors are considered critical and will trigger
304 * the various notifications to users to correct them.
305 *
306 * @param $details
307 *
308 * @return bool
309 *
310 * @since 2.7/5.10
311 */
312 public function is_critical_error($details)
313 {
314 $error_code = (int)$details['error']['code'];
315
316 $critical_codes = array(
317 10,
318 100,
319 200,
320 190,
321 104,
322 999
323 );
324
325 return in_array($error_code, $critical_codes, true);
326 }
327
328 /**
329 * @param $type
330 *
331 * @since X.X.X
332 */
333 public function remove_error($type, $connected_account = false)
334 {
335 $update = false;
336 if (!empty($this->errors[$type])) {
337 $this->errors[$type] = array();
338 $this->add_action_log('Cleared ' . $type . ' error.');
339 $update = true;
340 }
341
342 if (!empty($this->errors['revoked'])) {
343 if (!is_array($this->errors['revoked'])) {
344 $this->errors['revoked'] = array();
345 }
346 if (isset($connected_account['account_id']) && ($key = array_search($connected_account['account_id'], $this->errors['revoked'])) !== false) {
347 unset($this->errors['revoked'][$key]);
348 }
349 }
350
351 if ($update) {
352 update_option($this->reporter_key, $this->errors, false);
353 }
354 }
355
356 public function remove_all_errors()
357 {
358 delete_option($this->reporter_key);
359 }
360
361 public function reset_api_errors()
362 {
363 $this->errors['connection'] = array();
364 $this->errors['accounts'] = array();
365 update_option($this->reporter_key, $this->errors, false);
366 }
367
368 /**
369 * @param $type
370 * @param $message
371 *
372 * @since 2.0/5.0
373 */
374 public function add_frontend_error($message, $directions)
375 {
376 $this->frontend_error = $message . $directions;
377 }
378
379 public function remove_frontend_error()
380 {
381 $this->frontend_error = '';
382 }
383
384 /**
385 * @return string
386 *
387 * @since 2.0/5.0
388 */
389 public function get_frontend_error()
390 {
391 return $this->frontend_error;
392 }
393
394
395 public function get_critical_errors()
396 {
397 if (!$this->are_critical_errors()) {
398 return '';
399 }
400
401 $accounts_revoked_string = '';
402 $accounts_revoked = '';
403
404 if ($this->was_app_permission_related_error()) {
405 $accounts_revoked = $this->get_app_permission_related_error_ids();
406 if (count($accounts_revoked) > 1) {
407 $accounts_revoked = implode(', ', $accounts_revoked);
408 } else {
409 $accounts_revoked = $accounts_revoked[0];
410 }
411 $accounts_revoked_string = sprintf(__('Facebook Feed related data for the account(s) %s was removed due to permission for the Smash Balloon App on Facebook being revoked. <br><br> To prevent the automated data deletion for the account, please reconnect your account within 7 days.', 'custom-facebook-feed'), $accounts_revoked);
412 }
413
414 $error_message = $directions = false;
415 if (isset($this->errors['connection']['critical'])) {
416 $errors = $this->get_errors();
417 $error_message = '';
418 $error = $errors['connection'];
419 if ($errors['connection']['error_id'] === 190) {
420 $error_message .= '<strong>' . __('Action Required Within 7 Days', 'custom-facebook-feed') . '</strong><br>';
421 $error_message .= __('An account admin has deauthorized the Smash Balloon app used to power the Facebook Feed plugin.', 'custom-facebook-feed');
422 $error_message .= ' ' . sprintf(__('If the Facebook source is not reconnected within 7 days then all Facebook data will be automatically deleted on your website for this account (ID: %s) due to Facebook data privacy rules.', 'custom-facebook-feed'), $accounts_revoked);
423 $error_message .= __('<br><br>To prevent the automated data deletion for the account, please reconnect your account within 7 days.', 'custom-facebook-feed');
424 $error_message .= '<br><br><a href="https://smashballoon.com/doc/action-required-within-7-days/?facebook&utm_campaign=facebook-free&utm_source=error&utm_medium=notice&utm_content=More Information" target="_blank" rel="noopener">' . __('More Information', 'custom-facebook-feed') . '</a>';
425 $directions = '';
426 } else {
427 $error_message_array = $error['error_message'];
428 $error_message = $error_message_array['admin_message'];
429 if (!empty($accounts_revoked_string)) {
430 $error_message .= $accounts_revoked_string . '<br><br>';
431 }
432
433 $directions = '<p class="cff-error-directions">';
434 $directions .= $error_message_array['backend_directions'];
435 if (!empty($error_message_array['post_id'])) {
436 $directions .= '<button data-url="' . get_the_permalink($error_message_array['post_id']) . '" class="cff-clear-errors-visit-page cff-space-left cff-btn cff-notice-btn cff-btn-grey">' . __('View Feed and Retry', 'custom-facebook-feed') . '</button>';
437 }
438 $directions .= '</p>';
439 }
440 } else {
441 }
442 return [
443 'error_message' => $error_message,
444 'directions' => $directions
445 ];
446 }
447
448 public function are_critical_errors()
449 {
450 $are_errors = false;
451 $errors = $this->get_errors();
452 if (
453 (isset($errors['connection']['critical']) && $errors['connection']['critical'] === true) ||
454 CFF_Source::should_show_group_deprecation()
455 ) {
456 return true;
457 } else {
458 $connected_accounts = CFF_Utils::cff_get_connected_accounts();
459 foreach ($connected_accounts as $connected_account) {
460 $connected_account = (array) $connected_account;
461
462 if (isset($connected_account['account_id']) && isset($this->errors['accounts'][$connected_account['account_id']]['api'])) {
463 if (isset($this->errors['accounts'][$connected_account['account_id']]['api']['error'])) {
464 return $this->is_critical_error($this->errors['accounts'][$connected_account['account_id']]['api']);
465 }
466 }
467 }
468 }
469 return $are_errors;
470 }
471
472 /**
473 * Stores a time stamped string of information about
474 * actions that might lead to correcting an error
475 *
476 * @param string $log_item
477 *
478 * @since 2.19
479 */
480 public function add_action_log($log_item)
481 {
482 $current_log = $this->errors['action_log'];
483
484 if (is_array($current_log) && count($current_log) >= 10) {
485 reset($current_log);
486 unset($current_log[ key($current_log) ]);
487 }
488 $current_log[] = date('m-d H:i:s') . ' - ' . $log_item;
489
490 $this->errors['action_log'] = $current_log;
491 update_option($this->reporter_key, $this->errors, false);
492 }
493
494 /**
495 * @return mixed
496 *
497 * @since 2.19
498 */
499 public function get_action_log()
500 {
501 return $this->errors['action_log'];
502 }
503
504
505 /**
506 * Load the critical notice for logged in users.
507 */
508 public function critical_error_notice()
509 {
510 // Don't do anything for guests.
511 if (! is_user_logged_in()) {
512 return;
513 }
514
515 // Only show this to users who are not tracked.
516 if (! current_user_can('edit_posts')) {
517 return;
518 }
519
520 if (! $this->are_critical_errors()) {
521 return;
522 }
523
524
525 // Don't show if already dismissed.
526 if (get_option('cff_dismiss_critical_notice', false)) {
527 return;
528 }
529
530 /** TODO: Match real option */
531 $options = get_option('cff_settings');
532 if (isset($options['disable_admin_notice']) && $options['disable_admin_notice'] === 'on') {
533 return;
534 }
535
536 ?>
537 <div class="cff-critical-notice cff-critical-notice-hide">
538 <div class="cff-critical-notice-icon">
539 <img src="<?php echo CFF_PLUGIN_URL . 'admin/assets/img/cff-icon.png'; ?>" width="45" alt="Custom Facebook Feed icon" />
540 </div>
541 <div class="cff-critical-notice-text">
542 <h3><?php esc_html_e('Facebook Feed Critical Issue', 'custom-facebook-feed'); ?></h3>
543 <p>
544 <?php
545 $doc_url = admin_url() . 'admin.php?page=cff-settings';
546 // Translators: %s is the link to the article where more details about critical are listed.
547 printf(esc_html__('An issue is preventing your Custom Facebook Feeds from updating. %1$sResolve this issue%2$s.', 'custom-facebook-feed'), '<a href="' . esc_url($doc_url) . '" target="_blank">', '</a>');
548 ?>
549 </p>
550 </div>
551 <div class="cff-critical-notice-close">&times;</div>
552 </div>
553 <style type="text/css">
554 .cff-critical-notice {
555 position: fixed;
556 bottom: 20px;
557 right: 15px;
558 font-family: Arial, Helvetica, "Trebuchet MS", sans-serif;
559 background: #fff;
560 box-shadow: 0 0 10px 0 #dedede;
561 padding: 10px 10px;
562 display: flex;
563 align-items: center;
564 justify-content: center;
565 width: 325px;
566 max-width: calc( 100% - 30px );
567 border-radius: 6px;
568 transition: bottom 700ms ease;
569 z-index: 10000;
570 }
571
572 .cff-critical-notice h3 {
573 font-size: 13px;
574 color: #222;
575 font-weight: 700;
576 margin: 0 0 4px;
577 padding: 0;
578 line-height: 1;
579 border: none;
580 }
581
582 .cff-critical-notice p {
583 font-size: 12px;
584 color: #7f7f7f;
585 font-weight: 400;
586 margin: 0;
587 padding: 0;
588 line-height: 1.2;
589 border: none;
590 }
591
592 .cff-critical-notice p a {
593 color: #7f7f7f;
594 font-size: 12px;
595 line-height: 1.2;
596 margin: 0;
597 padding: 0;
598 text-decoration: underline;
599 font-weight: 400;
600 }
601
602 .cff-critical-notice p a:hover {
603 color: #666;
604 }
605
606 .cff-critical-notice-icon img {
607 height: auto;
608 display: block;
609 margin: 0;
610 }
611
612 .cff-critical-notice-icon {
613 padding: 0;
614 border-radius: 4px;
615 flex-grow: 0;
616 flex-shrink: 0;
617 margin-right: 12px;
618 overflow: hidden;
619 }
620
621 .cff-critical-notice-close {
622 padding: 10px;
623 margin: -12px -9px 0 0;
624 border: none;
625 box-shadow: none;
626 border-radius: 0;
627 color: #7f7f7f;
628 background: transparent;
629 line-height: 1;
630 align-self: flex-start;
631 cursor: pointer;
632 font-weight: 400;
633 }
634 .cff-critical-notice-close:hover,
635 .cff-critical-notice-close:focus{
636 color: #111;
637 }
638
639 .cff-critical-notice.cff-critical-notice-hide {
640 bottom: -200px;
641 }
642 </style>
643 <?php
644
645 if (! wp_script_is('jquery', 'queue')) {
646 wp_enqueue_script('jquery');
647 }
648 ?>
649 <script>
650 if ( 'undefined' !== typeof jQuery ) {
651 jQuery( document ).ready( function ( $ ) {
652 /* Don't show the notice if we don't have a way to hide it (no js, no jQuery). */
653 $( document.querySelector( '.cff-critical-notice' ) ).removeClass( 'cff-critical-notice-hide' );
654 $( document.querySelector( '.cff-critical-notice-close' ) ).on( 'click', function ( e ) {
655 e.preventDefault();
656 $( this ).closest( '.cff-critical-notice' ).addClass( 'cff-critical-notice-hide' );
657 $.ajax( {
658 url: '<?php echo esc_url(admin_url('admin-ajax.php')); ?>',
659 method: 'POST',
660 data: {
661 action: 'cff_dismiss_critical_notice',
662 nonce: '<?php echo esc_js(wp_create_nonce('cff-critical-notice')); ?>',
663 }
664 } );
665 } );
666 } );
667 }
668 </script>
669 <?php
670 }
671
672 /**
673 * Ajax handler to hide the critical notice.
674 */
675 public function dismiss_critical_notice()
676 {
677
678 check_ajax_referer('cff-critical-notice', 'nonce');
679 $cap = current_user_can('manage_custom_facebook_feed_options') ? 'manage_custom_facebook_feed_options' : 'manage_options';
680 $cap = apply_filters('cff_settings_pages_capability', $cap);
681 if (! current_user_can($cap)) {
682 wp_send_json_error(); // This auto-dies.
683 }
684
685 update_option('cff_dismiss_critical_notice', 1, false);
686
687 wp_die();
688 }
689
690 public function send_report_email()
691 {
692 $options = get_option('cff_style_settings', array());
693
694 $to_string = ! empty($options['email_notification_addresses']) ? str_replace(' ', '', $options['email_notification_addresses']) : get_option('admin_email', '');
695
696 $to_array_raw = explode(',', $to_string);
697 $to_array = array();
698
699 foreach ($to_array_raw as $email) {
700 if (is_email($email)) {
701 $to_array[] = $email;
702 }
703 }
704
705 if (empty($to_array)) {
706 return false;
707 }
708 $from_name = esc_html(wp_specialchars_decode(get_bloginfo('name')));
709 $email_from = $from_name . ' <' . get_option('admin_email', $to_array[0]) . '>';
710 $header_from = "From: " . $email_from;
711
712 $headers = array( 'Content-Type: text/html; charset=utf-8', $header_from );
713
714 $header_image = CFF_PLUGIN_URL . 'admin/assets/img/balloon-120.png';
715 $title = __('Custom Facebook Feed Report for ' . home_url());
716 $link = admin_url('admin.php?page=cff-settings');
717 // &tab=customize-advanced
718 $footer_link = admin_url('admin.php?page=cff-style&tab=misc&flag=emails');
719 $bold = __('There\'s an Issue with a Facebook Feed on Your Website', 'custom-facebook-feed');
720 $details = '<p>' . __('A Custom Facebook Feed on your website is currently unable to connect to Facebook to retrieve new posts. Don\'t worry, your feed is still being displayed using a cached version, but is no longer able to display new posts.', 'custom-facebook-feed') . '</p>';
721 $details .= '<p>' . sprintf(__('This is caused by an issue with your Facebook account connecting to the Facebook API. For information on the exact issue and directions on how to resolve it, please visit the %sCustom Facebook Feed settings page%s on your website.', 'custom-facebook-feed'), '<a href="' . esc_url($link) . '">', '</a>') . '</p>';
722 $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;
723 $educator = new CFF_Education();
724 $dyk_message = $educator->dyk_display();
725 ob_start();
726 include_once CFF_PLUGIN_DIR . 'email.php';
727 $email_body = ob_get_contents();
728 ob_get_clean();
729 $sent = wp_mail($to_array, $title, $email_body, $headers);
730
731 return $sent;
732 }
733
734 /**
735 * Should clear platform data
736 *
737 * @param $details
738 *
739 * @return bool
740 *
741 * @since 2.7/5.10
742 */
743 public function is_app_permission_related($details)
744 {
745 $error_code = (int) $details['error']['code'];
746 $critical_codes = array(
747 190, // access token or permissions
748 );
749 return in_array($error_code, $critical_codes, true) && strpos($details['error']['message'], 'user has not authorized application') !== false;
750 }
751
752 public function maybe_trigger_report_email_send()
753 {
754 if (! $this->are_critical_errors()) {
755 return;
756 }
757 /** TODO: Match real option */
758 $options = get_option('cff_settings');
759
760 if (isset($options['enable_email_report']) && empty($options['enable_email_report'])) {
761 return;
762 }
763
764 $this->send_report_email();
765 }
766
767 public function admin_error_notices()
768 {
769
770 if (isset($_GET['page']) && in_array($_GET['page'], array( 'cff-settings' ))) {
771 $errors = $this->get_errors();
772 if (! empty($errors) && (! empty($errors['database_create']) || ! empty($errors['upload_dir']))) : ?>
773 <div class="cff-admin-notices cff-critical-error-notice">
774 <?php if (! empty($errors['database_create'])) {
775 echo '<p>' . $errors['database_create'] . '</p>';
776 } ?>
777 <?php if (! empty($errors['upload_dir'])) {
778 echo '<p>' . $errors['upload_dir'] . '</p>';
779 } ?>
780 <p><?php _e(sprintf('Visit our %s page for help', '<a href="https://smashballoon.com/custom-facebook-feed/faq/?utm_campaign=facebook-free&utm_source=error&utm_medium=docs" class="cff-notice-btn cff-btn-grey" target="_blank">FAQ</a>'), 'custom-facebook-feed'); ?></p>
781 </div>
782
783 <?php endif;
784 $errors = $this->get_critical_errors();
785 if ($this->are_critical_errors() && is_array($errors) && $errors['error_message'] !== false && $errors['directions'] !== false) :
786 ?>
787 <div class="cff-admin-notices cff-critical-error-notice">
788 <span class="sb-notice-icon sb-error-icon">
789 <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
790 <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" fill="#D72C2C"/>
791 </svg>
792 </span>
793 <div class="cff-notice-body">
794 <h3 class="sb-notice-title">
795 <?php echo esc_html__('Custom Facebook Feed is encountering an error and your feeds may not be updating due to the following reasons:', 'custom-facebook-feed') ; ?>
796 </h3>
797
798 <p><?php echo $errors['error_message']; ?></p>
799
800 <div class="license-action-btns">
801 <?php echo $errors['directions']; ?>
802 </div>
803 </div>
804 </div>
805 <?php
806 endif;
807
808 /*
809 $errors = $this->get_critical_errors();
810 if ( $this->are_critical_errors() && ! empty( $errors ) ) :
811 if ( isset( $errors['wp_remote_get'] ) ) {
812 $error = $errors['wp_remote_get'];
813 $error_message = $error['admin_message'];
814 $button = $error['backend_directions'];
815 $post_id = $error['post_id'];
816 $directions = '<p class="cff-error-directions">';
817 $directions .= $button;
818 $directions .= '<button data-url="'.get_the_permalink( $post_id ).'" class="cff-clear-errors-visit-page cff-space-left button button-secondary">' . __( 'View Feed and Retry', 'custom-facebook-feed' ) . '</button>';
819 $directions .= '</p>';
820 } elseif ( isset( $errors['api'] ) ) {
821 $error = $errors['api'];
822 $error_message = $error['admin_message'];
823 $button = $error['backend_directions'];
824 $post_id = $error['post_id'];
825 $directions = '<p class="cff-error-directions">';
826 $directions .= $button;
827 $directions .= '<button data-url="'.get_the_permalink( $post_id ).'" class="cff-clear-errors-visit-page cff-space-left button button-secondary">' . __( 'View Feed and Retry', 'custom-facebook-feed' ) . '</button>';
828 $directions .= '</p>';
829 } else {
830 $error = $errors['accesstoken'];
831
832 $tokens = array();
833 $post_id = false;
834 foreach ( $error as $token ) {
835 $tokens[] = $token['accesstoken'];
836 $post_id = $token['post_id'];
837 }
838 $error_message = sprintf( __( 'The access token %s is invalid or has expired.', 'custom-facebook-feed' ), implode( ', ', $tokens ) );
839 $directions = '<p class="cff-error-directions">';
840 $directions .= '<button class="button button-primary cff-reconnect">' . __( 'Reconnect Your Account', 'custom-facebook-feed' ) . '</button>';
841 $directions .= '<button data-url="'.get_the_permalink( $post_id ).'" class="cff-clear-errors-visit-page cff-space-left button button-secondary">' . __( 'View Feed and Retry', 'custom-facebook-feed' ) . '</button>';
842 $directions .= '</p>';
843 }
844 ?>
845 <div class="notice notice-warning is-dismissible cff-admin-notice">
846 <p><strong><?php echo esc_html__( 'Custom Facebook Feed is encountering an error and your feeds may not be updating due to the following reasons:', 'custom-facebook-feed') ; ?></strong></p>
847
848 <?php echo $error_message; ?>
849
850 <?php echo $directions; ?>
851 </div>
852 <?php endif;
853 */
854 }
855 }
856
857 /**
858 * Whether or not there was a platform data clearing error
859 *
860 * @return bool
861 */
862 public function was_app_permission_related_error()
863 {
864 return !empty($this->errors['revoked']);
865 }
866
867 public function get_app_permission_related_error_ids()
868 {
869 return $this->errors['revoked'];
870 }
871
872
873 public function platform_data_deleted_notice()
874 {
875 $errors = $this->get_errors();
876 if (!empty($errors) && (!empty($errors['platform_data_deleted']))) {
877 ?>
878 <div class="cff-admin-notices cff-critical-error-notice">
879 <span class="sb-notice-icon sb-error-icon">
880 <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
881 <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" fill="#D72C2C"/>
882 </svg>
883 </span>
884 <div class="cff-notice-body">
885 <h3 class="sb-notice-title">
886 <?php echo esc_html__('All Facebook Data has Been Removed:', 'custom-facebook-feed'); ?>
887 </h3>
888 <p><?php echo $errors['platform_data_deleted']; ?></p>
889 <p><?php echo esc_html__('To fix your feeds, reconnect all accounts that were in use on the Settings page.', 'custom-facebook-feed'); ?></p>
890
891 </div>
892 </div>
893 <?php
894 }
895 }
896
897 public function platform_unused_feed_notice()
898 {
899 $errors = $this->get_errors();
900 if (!empty($errors) && (!empty($errors['unused_feed']))) {
901 ?>
902 <div class="cff-admin-notices cff-critical-error-notice">
903 <span class="sb-notice-icon sb-error-icon">
904 <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
905 <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" fill="#D72C2C"/>
906 </svg>
907 </span>
908 <div class="cff-notice-body">
909 <h3 class="sb-notice-title">
910 <?php echo esc_html__('Action Required Within 7 Days:', 'custom-facebook-feed'); ?>
911 </h3>
912
913 <p><?php echo $errors['unused_feed']; ?></p>
914 <p><?php echo esc_html__('Or you can simply press the "Fix Usage" button to fix this issue.', 'custom-facebook-feed'); ?></p>
915 <div class="license-action-btns">
916 <button class="sbi-reset-unused-feed-usage sbi-space-left sbi-btn sbi-notice-btn sbi-btn-blue"><?php echo __('Fix Usage', 'custom-facebook-feed'); ?></button>
917 </div>
918 </div>
919 </div>
920 <?php
921 }
922 }
923 /**
924 * Should Add deprecation error for Groups
925 *
926 * @param $group_id
927 *
928 * @since X.X.X
929 */
930 public function add_group_deprecation_error($group_id)
931 {
932 $group_deprecation_error = [
933 'group_ids' => []
934 ];
935 if (isset($this->errors['group_deprecation'])) {
936 $group_deprecation_error['group_ids'] = $this->errors['group_deprecation']['group_ids'];
937 }
938 if (!in_array($group_id, $group_deprecation_error['group_ids'])) {
939 $group_deprecation_error['dimissed'] = false;
940 array_push($group_deprecation_error['group_ids'], $group_id);
941 }
942 $this->errors['group_deprecation'] = $group_deprecation_error;
943
944 update_option($this->reporter_key, $this->errors, false);
945 }
946
947 /**
948 * Dismiss Group Notice
949 *
950 * @param $group_id
951 *
952 * @since X.X.X
953 */
954 public function dismiss_group_deprecation_error()
955 {
956 if (isset($this->errors['group_deprecation'])) {
957 $this->errors['group_deprecation']['dismissed'] = true;
958 update_option($this->reporter_key, $this->errors, false);
959 }
960 }
961 public function group_deprecation_notice()
962 {
963 $errors = $this->get_errors();
964 if (
965 !empty($errors) && !empty($errors['group_deprecation']) &&
966 (!isset($errors['group_deprecation']['dismissed']) || $errors['group_deprecation']['dismissed'] !== true)
967 ) {
968 $close_href = add_query_arg(array('cff_dismiss_notice' => 'group_deprecation'));
969 ?>
970 <div class="cff-admin-notices cff-critical-error-notice">
971 <span class="sb-notice-icon sb-error-icon">
972 <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
973 <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" fill="#D72C2C"/>
974 </svg>
975 </span>
976 <div class="cff-notice-body">
977 <h3 class="sb-notice-title sb-noticegroup-title">
978 <?php echo esc_html__('Group feeds will no longer update as of April 22, 2024 :', 'custom-facebook-feed') ; ?>
979 </h3>
980 <p>
981 <?php
982 echo
983 __('You have one or more feeds that will no longer update after April 22, 2024. This is caused by a change in Facebook\'s API, which we use to get new data for feed updates.', 'custom-facebook-feed') ;
984 ?>
985 </p>
986 <br/>
987
988 <p class="cff-error-directions">
989 <a
990 class="cff-notice-btn cff-btn-blue" target="_blank" rel="noopener"
991 href="https://smashballoon.com/doc/facebook-api-changes-affecting-groups-april-2024/?utm_campaign=facebook-free&utm_source=error&utm_medium=docs">
992 <?php echo esc_html__('Learn More', 'custom-facebook-feed') ; ?>
993 </a>
994 <a class="cff-notice-btn" href="<?php echo esc_attr($close_href); ?>" rel="noopener"><?php echo esc_html__('Dismiss', 'custom-facebook-feed') ; ?></a>
995 </p>
996
997
998 </div>
999 </div>
1000 <?php
1001 }
1002 }
1003 }
1004