ad-health-notices.php
1 month ago
checks.php
3 months ago
display-conditions.php
3 days ago
filesystem.php
1 month ago
frontend_checks.php
1 week ago
inline-css.php
1 year ago
utils.php
1 week ago
visitor-conditions.php
3 days ago
ad-health-notices.php
862 lines
| 1 | <?php // phpcs:ignoreFile |
| 2 | |
| 3 | use AdvancedAds\Framework\Utilities\Arr; |
| 4 | use AdvancedAds\Framework\Utilities\Params; |
| 5 | use AdvancedAds\Utilities\Conditional; |
| 6 | use AdvancedAds\Utilities\WordPress; |
| 7 | |
| 8 | /** |
| 9 | * Container class for Ad Health notice handling |
| 10 | * |
| 11 | * @package WordPress |
| 12 | * @subpackage Advanced Ads Plugin |
| 13 | * @since 1.12 |
| 14 | * |
| 15 | * related scripts / functions |
| 16 | * |
| 17 | * advads_push_notice() function to push notifications using AJAX in admin/assets/js/admin-global.js |
| 18 | * push_ad_health_notice() in AdvancedAds\Admin\Ajax to push notifications sent via AJAX |
| 19 | * Advanced_Ads_Checks – for the various checks |
| 20 | * list of notification texts in admin/includes/ad-health-notices.php |
| 21 | */ |
| 22 | class Advanced_Ads_Ad_Health_Notices { |
| 23 | |
| 24 | /** |
| 25 | * Options |
| 26 | * |
| 27 | * @var array |
| 28 | */ |
| 29 | protected $options; |
| 30 | |
| 31 | /** |
| 32 | * All detected notices |
| 33 | * |
| 34 | * Structure is |
| 35 | * [notice_key] => array( |
| 36 | * 'text' - if not given, it uses the default text for output ) |
| 37 | * 'orig_key' - original notice key |
| 38 | * ) |
| 39 | * |
| 40 | * @var array |
| 41 | */ |
| 42 | public $notices = []; |
| 43 | |
| 44 | /** |
| 45 | * All ignored notices |
| 46 | * |
| 47 | * @var array |
| 48 | */ |
| 49 | public $ignore = []; |
| 50 | |
| 51 | /** |
| 52 | * All displayed notices ($notices minus $hidden) |
| 53 | * |
| 54 | * @var array |
| 55 | */ |
| 56 | public $displayed_notices = []; |
| 57 | |
| 58 | /** |
| 59 | * Load default notices |
| 60 | * |
| 61 | * @var array |
| 62 | */ |
| 63 | public $default_notices = []; |
| 64 | |
| 65 | /** |
| 66 | * The last notice key saved |
| 67 | * |
| 68 | * @var string |
| 69 | */ |
| 70 | public $last_saved_notice_key = false; |
| 71 | |
| 72 | /** |
| 73 | * Name of the transient saved for daily checks in the backend |
| 74 | * |
| 75 | * @const string |
| 76 | */ |
| 77 | const DAILY_CHECK_TRANSIENT_NAME = 'advanced-ads-daily-ad-health-check-ran'; |
| 78 | |
| 79 | /** |
| 80 | * Return an instance of this class. |
| 81 | * |
| 82 | * @return object A single instance of this class. |
| 83 | */ |
| 84 | public static function get_instance() { |
| 85 | static $instance; |
| 86 | |
| 87 | // If the single instance hasn't been set, set it now. |
| 88 | if ( null === $instance ) { |
| 89 | $instance = new self(); |
| 90 | } |
| 91 | |
| 92 | return $instance; |
| 93 | } |
| 94 | |
| 95 | /** |
| 96 | * Advanced_Ads_Ad_Health_Notices constructor. |
| 97 | */ |
| 98 | public function __construct() { |
| 99 | // failsafe for there were some reports of 502 errors. |
| 100 | if ( 1 < did_action( 'plugins_loaded' ) ) { |
| 101 | return; |
| 102 | } |
| 103 | |
| 104 | // stop here if notices are disabled. |
| 105 | if ( ! self::notices_enabled() ) { |
| 106 | return; |
| 107 | } |
| 108 | |
| 109 | add_action( 'init', [ $this, 'load_default_notices' ] ); |
| 110 | add_action( 'init', [ $this, 'load_notices' ] ); |
| 111 | |
| 112 | /** |
| 113 | * Run checks |
| 114 | * needs to run after plugins_loaded with priority 10 |
| 115 | * current_screen seems like the perfect hook |
| 116 | */ |
| 117 | add_action( 'current_screen', [ $this, 'run_checks' ], 20 ); |
| 118 | |
| 119 | // add notification when an ad expires. |
| 120 | add_action( 'advanced-ads-ad-expired', [ $this, 'ad_expired' ] ); |
| 121 | } |
| 122 | |
| 123 | /** |
| 124 | * Check if notices are enabled using "disable-notices" option in plugin settings |
| 125 | * |
| 126 | * @return bool |
| 127 | */ |
| 128 | public static function notices_enabled() { |
| 129 | $options = Advanced_Ads::get_instance()->options(); |
| 130 | |
| 131 | return empty( $options['disable-notices'] ); |
| 132 | } |
| 133 | |
| 134 | public function load_default_notices() { |
| 135 | // load default notices. |
| 136 | if ( [] === $this->default_notices ) { |
| 137 | include ADVADS_ABSPATH . '/admin/includes/ad-health-notices.php'; |
| 138 | $options = $this->options(); |
| 139 | $hide_notices = $options['hide_notices'] ?? []; |
| 140 | if ( ! empty( $hide_notices ) ) { |
| 141 | $advanced_ads_ad_health_notices = array_diff_key($advanced_ads_ad_health_notices, $hide_notices); |
| 142 | } |
| 143 | $this->default_notices = $advanced_ads_ad_health_notices; |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | /** |
| 148 | * Load notice arrays |
| 149 | */ |
| 150 | public function load_notices() { |
| 151 | |
| 152 | $options = $this->options(); |
| 153 | |
| 154 | // load notices from "notices". |
| 155 | $this->notices = $options['notices'] ?? []; |
| 156 | |
| 157 | /** |
| 158 | * Cleanup notices |
| 159 | */ |
| 160 | foreach ( $this->notices as $_key => $_notice ) { |
| 161 | // without valid key caused by an issue prior to 1.13.3. |
| 162 | if ( empty( $_key ) ) { |
| 163 | unset( $this->notices[ $_key ] ); |
| 164 | } |
| 165 | |
| 166 | $time = current_time( 'timestamp', 0 ); |
| 167 | $notice_array = $this->get_notice_array_for_key( $_key ); |
| 168 | |
| 169 | // handle notices with a timeout. |
| 170 | if ( isset( $_notice['closed'] ) ) { |
| 171 | // remove notice when timeout expired – was closed longer ago than timeout set in the notice options. |
| 172 | if ( empty( $notice_array['timeout'] ) |
| 173 | || ( ( $time - $_notice['closed'] ) > $notice_array['timeout'] ) ) { |
| 174 | $this->remove( $_key ); |
| 175 | } else { |
| 176 | // just ignore notice if timeout is still valid. |
| 177 | unset( $this->notices[ $_key ] ); |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | // check if notice still exists. |
| 182 | if ( [] === $this->get_notice_array_for_key( $_key ) ) { |
| 183 | unset( $this->notices[ $_key ] ); |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | // unignore notices if `show-hidden=true` is set in the URL. |
| 188 | $nonce = Params::get( 'advads_nonce' ); |
| 189 | if ( |
| 190 | $nonce && wp_verify_nonce( wp_unslash( $nonce ), 'advanced-ads-show-hidden-notices' ) |
| 191 | && true === Params::get( 'advads-show-hidden-notices', false, FILTER_VALIDATE_BOOLEAN ) |
| 192 | ) { |
| 193 | $this->unignore(); |
| 194 | // remove the argument from the URL. |
| 195 | add_filter( 'removable_query_args', [ $this, 'remove_query_vars_after_notice_update' ] ); |
| 196 | } |
| 197 | |
| 198 | // load hidden notices. |
| 199 | $this->ignore = $this->get_valid_ignored(); |
| 200 | |
| 201 | // get displayed notices |
| 202 | // get keys of notices. |
| 203 | $notice_keys = array_keys( $this->notices ); |
| 204 | $this->displayed_notices = array_diff( $notice_keys, $this->ignore ); |
| 205 | } |
| 206 | |
| 207 | /** |
| 208 | * Remove query var from URL after notice was updated |
| 209 | * |
| 210 | * @param array $removable_query_args array with removable query vars. |
| 211 | * @return array updated query vars. |
| 212 | */ |
| 213 | public function remove_query_vars_after_notice_update( $removable_query_args ) { |
| 214 | $removable_query_args[] = 'advads-show-hidden-notices'; |
| 215 | $removable_query_args[] = 'advads_nonce'; |
| 216 | |
| 217 | return $removable_query_args; |
| 218 | } |
| 219 | |
| 220 | /** |
| 221 | * Manage when to run checks |
| 222 | * - only when users have ads |
| 223 | * - once per day on any backend page |
| 224 | * - on each Advanced Ads related page |
| 225 | */ |
| 226 | public function run_checks() { |
| 227 | |
| 228 | // run in WP Admin only and if there are any ads. |
| 229 | if ( ! is_admin() || ! WordPress::get_count_ads() ) { |
| 230 | return; |
| 231 | } |
| 232 | |
| 233 | // don’t run on AJAX calls. |
| 234 | if ( wp_doing_ajax() ) { |
| 235 | return; |
| 236 | } |
| 237 | |
| 238 | // run only daily unless we are on an Advanced Ads related page. |
| 239 | if ( ! Conditional::is_screen_advanced_ads() |
| 240 | && get_transient( self::DAILY_CHECK_TRANSIENT_NAME ) ) { |
| 241 | return; |
| 242 | } |
| 243 | |
| 244 | $this->checks(); |
| 245 | } |
| 246 | |
| 247 | /** |
| 248 | * General checks done on each Advanced Ads-related page or once per day |
| 249 | */ |
| 250 | public function checks() { |
| 251 | $checks = [ |
| 252 | 'old_php' => ! Advanced_Ads_Checks::php_version_minimum(), |
| 253 | 'conflicting_plugins' => count( Advanced_Ads_Checks::conflicting_plugins() ), |
| 254 | 'php_extensions_missing' => count( Advanced_Ads_Checks::php_extensions() ), |
| 255 | 'ads_disabled' => Advanced_Ads_Checks::ads_disabled(), |
| 256 | 'constants_enabled' => Advanced_Ads_Checks::get_defined_constants(), |
| 257 | 'assets_expired' => Advanced_Ads_Checks::assets_expired(), |
| 258 | 'license_invalid' => Advanced_Ads_Checks::licenses_invalid(), |
| 259 | 'buddypress_no_pro' => class_exists( 'BuddyPress', false ) && ! defined( 'BP_PLATFORM_VERSION' ) && ! defined( 'AAP_VERSION' ), |
| 260 | 'buddyboss_no_pro' => defined( 'BP_PLATFORM_VERSION' ) && ! defined( 'AAP_VERSION' ), |
| 261 | 'gamipress_no_pro' => class_exists( 'GamiPress', false ) && ! defined( 'AAP_VERSION' ), |
| 262 | 'pmp_no_pro' => defined( 'PMPRO_VERSION' ) && ! defined( 'AAP_VERSION' ), |
| 263 | 'members_no_pro' => function_exists( 'members_plugin' ) && ! defined( 'AAP_VERSION' ), |
| 264 | 'translatepress_no_pro' => function_exists( 'trp_enable_translatepress' ) && ! defined( 'AAP_VERSION' ), |
| 265 | 'weglot_no_pro' => defined( 'WEGLOT_VERSION' ) && ! defined( 'AAP_VERSION' ), |
| 266 | 'learndash' => defined( 'LEARNDASH_VERSION' ), |
| 267 | 'aawp' => defined( 'AAWP_PLUGIN_FILE' ), |
| 268 | 'polylang' => defined( 'POLYLANG_VERSION' ), |
| 269 | 'mailpoet' => function_exists( 'mailpoet_check_requirements' ), |
| 270 | 'wp_rocket' => Advanced_Ads_Checks::active_wp_rocket(), |
| 271 | 'quiz_plugins_no_pro' => Advanced_Ads_Checks::active_quiz_plugins(), |
| 272 | 'elementor' => defined( 'ELEMENTOR_VERSION' ), |
| 273 | 'siteorigin' => defined( 'SITEORIGIN_PANELS_VERSION' ), |
| 274 | 'divi_no_pro' => function_exists( 'et_setup_theme' ) || defined( 'ET_BUILDER_PLUGIN_VERSION' ), |
| 275 | 'beaver_builder' => class_exists( 'FLBuilderLoader' ), |
| 276 | 'pagelayer' => defined( 'PAGELAYER_FILE' ), |
| 277 | 'wpb' => defined( 'WPB_VC_VERSION' ), |
| 278 | 'newspaper' => defined( 'TAGDIV_ROOT' ), |
| 279 | 'bbpress_no_pro' => class_exists( 'bbPress', false ) && ! defined( 'AAP_VERSION' ), |
| 280 | 'WPML_active' => defined( 'ICL_SITEPRESS_VERSION' ), |
| 281 | 'AMP_active' => Advanced_Ads_Checks::active_amp_plugin(), |
| 282 | 'wpengine' => Advanced_Ads_Checks::wp_engine_hosting(),// do not remove |
| 283 | 'ads_txt_plugins_enabled' => count( Advanced_Ads_Checks::ads_txt_plugins() ), |
| 284 | 'header_footer_plugins_enabled' => count( Advanced_Ads_Checks::header_footer_plugins() ), |
| 285 | ]; |
| 286 | |
| 287 | foreach ( $checks as $key => $check ) { |
| 288 | if ( $check ) { |
| 289 | $this->add( $key ); |
| 290 | } elseif ( 'wpengine' !== $key ) { |
| 291 | $this->remove( $key ); |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | |
| 296 | set_transient( self::DAILY_CHECK_TRANSIENT_NAME, true, DAY_IN_SECONDS ); |
| 297 | } |
| 298 | |
| 299 | /** |
| 300 | * Add a notice to the queue |
| 301 | * |
| 302 | * @param string $notice_key notice key to be added to the notice array. |
| 303 | * @param array $atts additional attributes. |
| 304 | * |
| 305 | * attributes |
| 306 | * - append_key string attached to the key; enables to create multiple messages for one original key |
| 307 | * - append_text text added to the default message |
| 308 | * - ad_id ID of an ad, attaches the link to the ad edit page to the message |
| 309 | */ |
| 310 | public function add( $notice_key, $atts = [] ) { |
| 311 | // Early bail!! |
| 312 | if ( empty( $notice_key ) || ! self::notices_enabled() ) { |
| 313 | return; |
| 314 | } |
| 315 | |
| 316 | // add string to key. |
| 317 | if ( ! empty( $atts['append_key'] ) ) { |
| 318 | $orig_notice_key = $notice_key; |
| 319 | $notice_key .= $atts['append_key']; |
| 320 | } |
| 321 | |
| 322 | $options = $this->options(); |
| 323 | $notice_key = sanitize_key( $notice_key ); |
| 324 | |
| 325 | // load notices from "queue". |
| 326 | $notices = $options['notices'] ?? []; |
| 327 | |
| 328 | // check if notice_key was already saved, this prevents the same notice from showing up in different forms. |
| 329 | if ( isset( $notices[ $notice_key ] ) ) { |
| 330 | return; |
| 331 | } |
| 332 | |
| 333 | // save the new notice key. |
| 334 | $notices[ $notice_key ] = []; |
| 335 | |
| 336 | // save text, if given. |
| 337 | if ( ! empty( $atts['text'] ) ) { |
| 338 | $notices[ $notice_key ]['text'] = $atts['text']; |
| 339 | } |
| 340 | |
| 341 | // attach link to ad, if given. |
| 342 | if ( ! empty( $atts['ad_id'] ) ) { |
| 343 | $id = absint( $atts['ad_id'] ); |
| 344 | $ad = wp_advads_get_ad( $id ); |
| 345 | if ( $id && '' !== $ad->get_title() ) { |
| 346 | $edit_link = ' <a href="' . admin_url( 'post.php?post=' . $id . '&action=edit' ) . '">' . $ad->get_title() . '</a>'; |
| 347 | $notices[ $notice_key ]['append_text'] = isset( $notices[ $notice_key ]['append_text'] ) ? $notices[ $notice_key ]['append_text'] . $edit_link : $edit_link; |
| 348 | } |
| 349 | } |
| 350 | |
| 351 | // save the original key, if we manipulated it. |
| 352 | if ( ! empty( $atts['append_key'] ) ) { |
| 353 | $notices[ $notice_key ]['orig_key'] = $orig_notice_key; |
| 354 | } |
| 355 | |
| 356 | // add more text. |
| 357 | if ( ! empty( $atts['append_text'] ) ) { |
| 358 | $notices[ $notice_key ]['append_text'] = esc_attr( $atts['append_text'] ); |
| 359 | } |
| 360 | |
| 361 | // add current time – we store localized time including the offset set in WP. |
| 362 | $notices[ $notice_key ]['time'] = current_time( 'timestamp', 0 ); |
| 363 | |
| 364 | $this->last_saved_notice_key = $notice_key; |
| 365 | |
| 366 | $this->update_notices( $notices ); |
| 367 | } |
| 368 | |
| 369 | /** |
| 370 | * Updating an existing notice or add it, if it doesn’t exist, yet |
| 371 | * |
| 372 | * @param string $notice_key notice key to be added to the notice array. |
| 373 | * @param array $atts additional attributes. |
| 374 | * |
| 375 | * attributes: |
| 376 | * - append_text – text added to the default message |
| 377 | */ |
| 378 | public function update( $notice_key, $atts = [] ) { |
| 379 | // Early bail!! |
| 380 | if ( empty( $notice_key ) || ! self::notices_enabled() ) { |
| 381 | return; |
| 382 | } |
| 383 | |
| 384 | // check if the notice already exists. |
| 385 | $notice_key = esc_attr( $notice_key ); |
| 386 | $options = $this->options(); |
| 387 | |
| 388 | // load notices from "queue". |
| 389 | $notices = isset( $options['notices'] ) ? $options['notices'] : []; |
| 390 | |
| 391 | // check if notice_key was already saved, this prevents the same notice from showing up in different forms. |
| 392 | if ( ! isset( $notices[ $notice_key ] ) ) { |
| 393 | $this->add( $notice_key, $atts ); |
| 394 | |
| 395 | $notice_key = $this->last_saved_notice_key; |
| 396 | |
| 397 | // just in case, get notices again. |
| 398 | $notices = $this->notices; |
| 399 | } else { |
| 400 | // add more text if this is an update. |
| 401 | if ( ! empty( $atts['append_text'] ) ) { |
| 402 | $notices[ $notice_key ]['append_text'] = isset( $notices[ $notice_key ]['append_text'] ) ? $notices[ $notice_key ]['append_text'] . $atts['append_text'] : $atts['append_text']; |
| 403 | } |
| 404 | // add `closed` marker, if given. |
| 405 | if ( ! empty( $atts['closed'] ) ) { |
| 406 | $notices[ $notice_key ]['closed'] = absint( $atts['closed'] ); |
| 407 | } |
| 408 | } |
| 409 | |
| 410 | // update db. |
| 411 | $this->update_notices( $notices ); |
| 412 | } |
| 413 | |
| 414 | /** |
| 415 | * Decide based on the notice, whether to remove or ignore it |
| 416 | * |
| 417 | * @param string $notice_key key of the notice. |
| 418 | */ |
| 419 | public function hide( $notice_key ) { |
| 420 | if ( empty( $notice_key ) ) { |
| 421 | return; |
| 422 | } |
| 423 | |
| 424 | // get original notice array for the "hide" attribute. |
| 425 | $notice_array = $this->get_notice_array_for_key( $notice_key ); |
| 426 | |
| 427 | // handle notices with a timeout. |
| 428 | // set `closed` timestamp if the notice definition has a timeout information. |
| 429 | if ( isset( $notice_array['timeout'] ) ) { |
| 430 | $this->update( $notice_key, [ 'closed' => current_time( 'timestamp', 0 ) ] ); |
| 431 | |
| 432 | return; |
| 433 | } |
| 434 | |
| 435 | if ( isset( $notice_array['hide'] ) && false === $notice_array['hide'] ) { |
| 436 | // remove item. |
| 437 | $this->remove( $notice_key ); |
| 438 | } else { |
| 439 | // hide item. |
| 440 | $this->ignore( $notice_key ); |
| 441 | } |
| 442 | |
| 443 | } |
| 444 | |
| 445 | /** |
| 446 | * Remove notice |
| 447 | * Would remove it from "notice" array. The notice can be added anytime again |
| 448 | * practically, this allows users to "skip" an notice if they are sure that it was only temporary |
| 449 | * |
| 450 | * @param string $notice_key notice key to be removed. |
| 451 | */ |
| 452 | public function remove( $notice_key ) { |
| 453 | // Early bail!! |
| 454 | if ( empty( $notice_key ) || ! self::notices_enabled() ) { |
| 455 | return; |
| 456 | } |
| 457 | |
| 458 | $options = $this->options(); |
| 459 | if ( |
| 460 | ! isset( $options['notices'] ) |
| 461 | || ! is_array( $options['notices'] ) |
| 462 | || ! isset( $options['notices'][ $notice_key ] ) |
| 463 | ) { |
| 464 | return; |
| 465 | } |
| 466 | |
| 467 | unset( $options['notices'][ $notice_key ] ); |
| 468 | $options['hide_notices'][ $notice_key] = true; |
| 469 | $this->hide_notices( $options[ 'hide_notices' ] ); // for non wp notices |
| 470 | $this->update_notices( $options['notices'] ); |
| 471 | } |
| 472 | |
| 473 | /** |
| 474 | * Ignore any notice |
| 475 | * adds notice key into "ignore" array |
| 476 | * does not remove it from "notices" array |
| 477 | * |
| 478 | * @param string $notice_key key of the notice to be ignored. |
| 479 | */ |
| 480 | public function ignore( $notice_key ) { |
| 481 | // Early bail!! |
| 482 | if ( empty( $notice_key ) || ! self::notices_enabled() ) { |
| 483 | return; |
| 484 | } |
| 485 | |
| 486 | $options = $this->options(); |
| 487 | $ignored = isset( $options['ignore'] ) && is_array( $options['ignore'] ) ? $options['ignore'] : []; |
| 488 | |
| 489 | // adds notice key to ignore array if it doesn’t exist already. |
| 490 | if ( false === array_search( $notice_key, $ignored, true ) ) { |
| 491 | $ignored[] = $notice_key; |
| 492 | } |
| 493 | |
| 494 | // update db. |
| 495 | $this->update_ignore( $ignored ); |
| 496 | } |
| 497 | |
| 498 | /** |
| 499 | * Clear all "ignore" messages |
| 500 | */ |
| 501 | public function unignore() { |
| 502 | $this->update_ignore(); |
| 503 | } |
| 504 | |
| 505 | /** |
| 506 | * Update ignored notices if there is any change |
| 507 | * |
| 508 | * @param string[] $ignore_list list of ignored keys. |
| 509 | * |
| 510 | * @return void |
| 511 | */ |
| 512 | public function update_ignore( $ignore_list = [] ) { |
| 513 | $options = $this->options(); |
| 514 | $before = Arr::get( $options, 'ignore', [] ); |
| 515 | |
| 516 | if ( $ignore_list === $before ) { |
| 517 | return; |
| 518 | } |
| 519 | |
| 520 | $options['ignore'] = $ignore_list; |
| 521 | $this->update_options( $options ); |
| 522 | } |
| 523 | |
| 524 | /** |
| 525 | * Update notices list if there is any change |
| 526 | * |
| 527 | * @param array $notices New options. |
| 528 | * |
| 529 | * @return void |
| 530 | */ |
| 531 | public function update_notices( $notices ): void { |
| 532 | $options = $this->options(); |
| 533 | |
| 534 | if ( Arr::get( $options, 'notices', [] ) === $notices ) { |
| 535 | return; |
| 536 | } |
| 537 | |
| 538 | $options['notices'] = $notices; |
| 539 | $this->update_options( $options ); |
| 540 | $this->load_notices(); |
| 541 | } |
| 542 | |
| 543 | /** |
| 544 | * Hide notices list if there is any change |
| 545 | * |
| 546 | * @param array $notices New options. |
| 547 | * |
| 548 | * @return void |
| 549 | */ |
| 550 | public function hide_notices( $notices ): void { |
| 551 | $options = $this->options(); |
| 552 | |
| 553 | if ( Arr::get( $options, 'notices', [] ) === $notices ) { |
| 554 | return; |
| 555 | } |
| 556 | |
| 557 | $options['hide_notices'] = $notices; |
| 558 | $this->update_options( $options ); |
| 559 | $this->load_notices(); |
| 560 | } |
| 561 | |
| 562 | /** |
| 563 | * Render notice widget on overview page |
| 564 | */ |
| 565 | public function render_widget() { |
| 566 | $ignored_count = count( $this->ignore ); |
| 567 | |
| 568 | include ADVADS_ABSPATH . 'views/admin/widgets/aa-dashboard/overview-notices.php'; |
| 569 | } |
| 570 | |
| 571 | /** |
| 572 | * Display notices in a list |
| 573 | * |
| 574 | * @param string $type which type of notice to show; default: 'problem'. |
| 575 | * |
| 576 | * @return void |
| 577 | */ |
| 578 | public function display( $type = 'problem' ) { |
| 579 | // Early baill!! |
| 580 | if ( ! is_array( $this->notices ) ) { |
| 581 | return; |
| 582 | } |
| 583 | foreach ( $this->notices as $_notice_key => $_notice ) { |
| 584 | $notice_array = $this->get_notice_array_for_key( $_notice_key ); |
| 585 | |
| 586 | // remove the notice if key doesn’t exist anymore. |
| 587 | if ( [] === $notice_array ) { |
| 588 | $this->remove( $_notice_key ); |
| 589 | } |
| 590 | |
| 591 | $notice_type = isset( $notice_array['type'] ) ? $notice_array['type'] : 'problem'; |
| 592 | |
| 593 | // skip if type is not correct. |
| 594 | if ( $notice_type !== $type ) { |
| 595 | continue; |
| 596 | } |
| 597 | |
| 598 | if ( ! empty( $_notice['text'] ) ) { |
| 599 | $text = $_notice['text']; |
| 600 | } elseif ( isset( $notice_array['text'] ) ) { |
| 601 | $text = $notice_array['text']; |
| 602 | } else { |
| 603 | continue; |
| 604 | } |
| 605 | |
| 606 | // attach "append_text". |
| 607 | if ( ! empty( $_notice['append_text'] ) ) { |
| 608 | $text .= $_notice['append_text']; |
| 609 | } |
| 610 | |
| 611 | // attach "get help" link. |
| 612 | if ( ! empty( $_notice['get_help_link'] ) ) { |
| 613 | $text .= $this->get_help_link( $_notice['get_help_link'] ); |
| 614 | } elseif ( isset( $notice_array['get_help_link'] ) ) { |
| 615 | $text .= $this->get_help_link( $notice_array['get_help_link'] ); |
| 616 | } |
| 617 | |
| 618 | $can_hide = ( ! isset( $notice_array['can_hide'] ) || true === $notice_array['can_hide'] ) ? true : false; |
| 619 | $hide = ( ! isset( $notice_array['hide'] ) || true === $notice_array['hide'] ) ? true : false; |
| 620 | $is_hidden = in_array( $_notice_key, $this->ignore, true ) ? true : false; |
| 621 | $date = isset( $_notice['time'] ) ? date_i18n( get_option( 'date_format' ), $_notice['time'] ) : false; |
| 622 | $dashicon = 'dashicons-warning'; |
| 623 | |
| 624 | if ( 'notice' === $type ) { |
| 625 | $dashicon = 'dashicons-info'; |
| 626 | } elseif ( 'pitch' === $type ) { |
| 627 | $dashicon = 'dashicons-lightbulb'; |
| 628 | } |
| 629 | |
| 630 | include ADVADS_ABSPATH . '/admin/views/overview-notice-row.php'; |
| 631 | } |
| 632 | } |
| 633 | |
| 634 | /** |
| 635 | * Display plugins and themes pitches |
| 636 | * |
| 637 | * @return void |
| 638 | */ |
| 639 | public function display_pitches() { |
| 640 | $this->display( 'pitch' ); |
| 641 | } |
| 642 | |
| 643 | /** |
| 644 | * Display problems. |
| 645 | */ |
| 646 | public function display_problems() { |
| 647 | $this->display( 'problem' ); |
| 648 | } |
| 649 | |
| 650 | /** |
| 651 | * Display notices. |
| 652 | */ |
| 653 | public function display_notices() { |
| 654 | $this->display( 'notice' ); |
| 655 | } |
| 656 | |
| 657 | /** |
| 658 | * Return notices option from DB |
| 659 | * |
| 660 | * @return array $options |
| 661 | */ |
| 662 | public function options() { |
| 663 | if ( ! isset( $this->options ) ) { |
| 664 | $this->options = get_option( ADVADS_SLUG . '-ad-health-notices', [] ); |
| 665 | } |
| 666 | |
| 667 | if ( ! is_array( $this->options ) ) { |
| 668 | $this->options = []; |
| 669 | } |
| 670 | |
| 671 | return $this->options; |
| 672 | } |
| 673 | |
| 674 | /** |
| 675 | * Update notice options |
| 676 | * |
| 677 | * @param array $options new options. |
| 678 | */ |
| 679 | public function update_options( array $options ) { |
| 680 | // do not allow to clear options. |
| 681 | if ( [] === $options ) { |
| 682 | return; |
| 683 | } |
| 684 | |
| 685 | $this->options = $options; |
| 686 | update_option( ADVADS_SLUG . '-ad-health-notices', $options ); |
| 687 | } |
| 688 | |
| 689 | /** |
| 690 | * Get the number of overall visible notices |
| 691 | */ |
| 692 | public static function get_number_of_notices() { |
| 693 | $displayed_notices = self::get_instance()->displayed_notices; |
| 694 | if ( ! is_array( $displayed_notices ) ) { |
| 695 | return 0; |
| 696 | } |
| 697 | |
| 698 | return count( $displayed_notices ); |
| 699 | } |
| 700 | |
| 701 | /** |
| 702 | * Get ignored messages that are also in the notices |
| 703 | * also updates ignored array, if needed |
| 704 | */ |
| 705 | public function get_valid_ignored() { |
| 706 | $options = $this->options(); |
| 707 | $ignore_before = $options['ignore'] ?? []; |
| 708 | |
| 709 | // get keys from notices. |
| 710 | $notice_keys = array_keys( $this->notices ); |
| 711 | |
| 712 | // get the errors that are in ignore AND notices and reset the keys. |
| 713 | $ignore = array_values( array_intersect( $ignore_before, $notice_keys ) ); |
| 714 | |
| 715 | // only update if changed. |
| 716 | if ( $ignore !== $ignore_before ) { |
| 717 | $this->update_ignore( $ignore ); |
| 718 | } |
| 719 | |
| 720 | return $ignore; |
| 721 | } |
| 722 | |
| 723 | /** |
| 724 | * Check if there are visible problems (notices of type "problem") |
| 725 | * |
| 726 | * @return bool true if there are visible notices (notices that are not hidden) |
| 727 | */ |
| 728 | public static function has_visible_problems() { |
| 729 | $displayed_notices = self::get_instance()->displayed_notices; |
| 730 | if ( ! is_array( $displayed_notices ) ) { |
| 731 | return false; |
| 732 | } |
| 733 | |
| 734 | return 0 < count( $displayed_notices ); |
| 735 | } |
| 736 | |
| 737 | /** |
| 738 | * Get visible notices by type – hidden and displayed |
| 739 | * |
| 740 | * @param string $type type of the notice. |
| 741 | * |
| 742 | * @return array |
| 743 | */ |
| 744 | public function get_visible_notices_by_type( $type = 'problem' ) { |
| 745 | $notices_by_type = []; |
| 746 | |
| 747 | foreach ( $this->notices as $_key => $_notice ) { |
| 748 | $notice_array = $this->get_notice_array_for_key( $_key ); |
| 749 | |
| 750 | if ( isset( $notice_array['type'] ) && $type === $notice_array['type'] |
| 751 | && ( ! isset( $this->ignore ) || false === array_search( $_key, $this->ignore, true ) ) ) { |
| 752 | $notices_by_type[ $_key ] = $_notice; |
| 753 | } |
| 754 | } |
| 755 | |
| 756 | return $notices_by_type; |
| 757 | } |
| 758 | |
| 759 | /** |
| 760 | * Check if there are notices |
| 761 | * |
| 762 | * @return bool true if there are notices, false if not |
| 763 | */ |
| 764 | public function has_notices() { |
| 765 | return isset( $this->notices ) && is_array( $this->notices ) && count( $this->notices ); |
| 766 | } |
| 767 | |
| 768 | /** |
| 769 | * Check if there are visible notices for a given type |
| 770 | * |
| 771 | * @param string $type type of the notice. |
| 772 | * |
| 773 | * @return integer |
| 774 | */ |
| 775 | public function has_notices_by_type( $type = 'problem' ) { |
| 776 | $notices = $this->get_visible_notices_by_type( $type ); |
| 777 | |
| 778 | if ( ! is_array( $notices ) ) { |
| 779 | return 0; |
| 780 | } |
| 781 | |
| 782 | return count( $notices ); |
| 783 | } |
| 784 | |
| 785 | /** |
| 786 | * Get the notice array for a notice key |
| 787 | * useful, if a notice key was manipulated |
| 788 | * |
| 789 | * @param string $notice_key key of the notice. |
| 790 | * |
| 791 | * @return array type |
| 792 | */ |
| 793 | public function get_notice_array_for_key( $notice_key ) { |
| 794 | // check if there is an original key. |
| 795 | $orig_key = isset( $this->notices[ $notice_key ]['orig_key'] ) ? $this->notices[ $notice_key ]['orig_key'] : $notice_key; |
| 796 | |
| 797 | return isset( $this->default_notices[ $orig_key ] ) ? $this->default_notices[ $orig_key ] : []; |
| 798 | } |
| 799 | |
| 800 | /** |
| 801 | * Add notification when an ad expires based on the expiry date |
| 802 | * |
| 803 | * @param integer $ad_id ID of the ad. |
| 804 | * |
| 805 | * @return void |
| 806 | */ |
| 807 | public function ad_expired( $ad_id ): void { |
| 808 | $id = ! empty( $ad_id ) ? absint( $ad_id ) : 0; |
| 809 | $this->update( |
| 810 | 'ad_expired', |
| 811 | [ |
| 812 | 'append_key' => $id, |
| 813 | 'ad_id' => $id, |
| 814 | ] |
| 815 | ); |
| 816 | } |
| 817 | |
| 818 | /** |
| 819 | * Get AdSense error link |
| 820 | * this is a copy of Advanced_Ads_AdSense_MAPI::get_adsense_error_link() which might not be available all the time |
| 821 | * |
| 822 | * @param string $code error code. |
| 823 | * |
| 824 | * @return string link |
| 825 | */ |
| 826 | public static function get_adsense_error_link( $code ) { |
| 827 | if ( ! empty( $code ) ) { |
| 828 | $code = '-' . $code; |
| 829 | } |
| 830 | |
| 831 | if ( class_exists( 'Advanced_Ads_AdSense_MAPI', false ) ) { |
| 832 | return Advanced_Ads_AdSense_MAPI::get_adsense_error_link( 'disapprovedAccount' ); |
| 833 | } |
| 834 | |
| 835 | // is a copy of Advanced_Ads_AdSense_MAPI::get_adsense_error_link(). |
| 836 | return sprintf( |
| 837 | /* translators: %1$s is an anchor (link) opening tag, %2$s is the closing tag. */ |
| 838 | esc_attr__( 'Learn more about AdSense account issues %1$shere%2$s.', 'advanced-ads' ), |
| 839 | '<a href="https://wpadvancedads.com/adsense-errors/?utm_source=advanced-ads&utm_medium=link&utm_campaign=adsense-error' . $code . '" target="_blank">', |
| 840 | '</a>' |
| 841 | ); |
| 842 | } |
| 843 | |
| 844 | /** |
| 845 | * Return a "Get Help" link |
| 846 | * |
| 847 | * @param string $link target URL. |
| 848 | * |
| 849 | * @return string HTML of the target link |
| 850 | */ |
| 851 | public function get_help_link( $link ) { |
| 852 | |
| 853 | $link = esc_url( $link ); |
| 854 | |
| 855 | if ( ! $link ) { |
| 856 | return ''; |
| 857 | } |
| 858 | |
| 859 | return ' <a href="' . $link . '" target="_blank">' . __( 'Get help', 'advanced.ads' ) . '</a>'; |
| 860 | } |
| 861 | } |
| 862 |