Admin
4 months ago
Builder
4 months ago
Helpers
4 months ago
Integrations
4 months ago
CFF_Autolink.php
4 months ago
CFF_Blocks.php
4 months ago
CFF_Cache.php
4 months ago
CFF_Education.php
4 months ago
CFF_Elementor_Base.php
4 months ago
CFF_Elementor_Widget.php
4 months ago
CFF_Error_Reporter.php
4 months ago
CFF_FB_Settings.php
4 months ago
CFF_Feed_Elementor_Control.php
4 months ago
CFF_Feed_Locator.php
4 months ago
CFF_Feed_Pro.php
4 months ago
CFF_GDPR_Integrations.php
4 months ago
CFF_Group_Posts.php
4 months ago
CFF_HTTP_Request.php
4 months ago
CFF_Oembed.php
4 months ago
CFF_Parse.php
4 months ago
CFF_Resizer.php
4 months ago
CFF_Response.php
4 months ago
CFF_Shortcode.php
4 months ago
CFF_Shortcode_Display.php
4 months ago
CFF_SiteHealth.php
4 months ago
CFF_Utils.php
4 months ago
CFF_View.php
4 months ago
Custom_Facebook_Feed.php
4 months ago
Email_Notification.php
4 months ago
Platform_Data.php
4 months ago
SB_Facebook_Data_Encryption.php
4 months ago
SB_Facebook_Data_Manager.php
4 months ago
index.php
4 months 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/'; |
| 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/'; |
| 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/" 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 . '?facebook&utm_campaign=facebook-pro&utm_source=error-message&utm_medium=frontend#' . 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/" 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 . '?facebook&utm_campaign=facebook-pro&utm_source=error-message&utm_medium=frontend#' . 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-pro&utm_source=permissionerror&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">×</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/" 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 issuee.', '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"> |
| 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 |