'corner', 'comments' => 'after_comments', 'feed' => 'between_posts', ]; public static function normalize_unit(array $unit) { $type = $unit['type'] ?? 'standard'; $unit['type'] = in_array($type, ['interstitial', 'reward'], true) ? $type : 'standard'; $position = (string) ($unit['position'] ?? ''); $position = self::POSITION_ALIASES[$position] ?? $position; $feature = (string) ($unit['feature'] ?? 'none'); if ($position === '') { if (!empty($unit['isAnchor']) || $feature === 'anchor') { $position = 'anchor'; } elseif (!empty($unit['floatToCorner']) && !in_array($feature, ['float', 'sticky', 'elevator'], true)) { $position = 'corner'; } elseif (in_array($feature, ['sidebar', 'header', 'footer'], true)) { $position = $feature; } } if (!in_array($position, array_merge(self::PAGE_POSITIONS, self::screen_positions(), self::PRO_POSITIONS), true)) { $position = ''; } $unit['position'] = $position; if ($feature === 'none' && !empty($unit['spotSticky'])) { $feature = 'sticky'; } $unit['feature'] = in_array($feature, array_merge(self::behaviours(), self::PRO_BEHAVIOURS), true) ? $feature : 'none'; $unit['options'] = isset($unit['options']) && is_array($unit['options']) ? $unit['options'] : []; if (!isset($unit['devices'])) { $unit['devices'] = ['both' => '', 'desktop' => 'desktop', 'mobile' => 'tablet,mobile'][$unit['device'] ?? 'both'] ?? ''; } $unit['devices'] = self::csv_subset($unit['devices'], self::DEVICES); $unit['pages'] = self::csv_subset($unit['pages'] ?? '', self::PAGE_TYPES); $unit['enabled'] = !isset($unit['enabled']) || filter_var($unit['enabled'], FILTER_VALIDATE_BOOLEAN); $unit['align'] = in_array($unit['align'] ?? '', self::ALIGNMENTS, true) ? $unit['align'] : 'center'; return $unit; } public static function csv_subset($value, array $allowed) { $given = is_array($value) ? $value : explode(',', (string) $value); $given = array_map('trim', $given); $kept = array_values(array_intersect($allowed, $given)); return (count($kept) === 0 || count($kept) === count($allowed)) ? '' : implode(',', $kept); } public static function adblock_text($key) { $options = [ 'title' => 'adghost_adblock_title', 'message' => 'adghost_adblock_message', 'button' => 'adghost_adblock_button', 'dismiss' => 'adghost_adblock_dismiss', ]; $defaults = [ 'title' => __('Please turn off your ad blocker', 'adghost-lite'), 'message' => __('Ads pay for the articles here. Allow them on this site and everything stays free to read.', 'adghost-lite'), 'button' => __('I turned it off — reload', 'adghost-lite'), 'dismiss' => __('Not now', 'adghost-lite'), ]; if (!isset($options[$key])) { return ''; } $saved = trim((string) get_option($options[$key], '')); return $saved !== '' ? $saved : $defaults[$key]; } public static function ad_label_align() { $align = (string) get_option('adghost_ad_label_align', ''); return in_array($align, ['left', 'center', 'right'], true) ? $align : ''; } public static function ad_label_color() { $color = trim((string) get_option('adghost_ad_label_color', '')); return preg_match('/^#[0-9a-fA-F]{6}$/', $color) ? strtolower($color) : ''; } public static function cls_mode() { $mode = get_option('adghost_cls_mode', ''); if (in_array($mode, ['max', 'min', 'off'], true)) { return $mode; } return get_option('adghost_enable_cls_prevention', true) ? 'max' : 'off'; } public static function sanitize_options($options) { $out = []; if (!is_array($options)) { return $out; } foreach ($options as $key => $value) { $key = preg_replace('/[^A-Za-z0-9_]/', '', (string) $key); if ($key === '' || count($out) >= 40) { continue; } if (is_bool($value) || $value === 'true' || $value === 'false') { $out[$key] = filter_var($value, FILTER_VALIDATE_BOOLEAN); } elseif (is_int($value) || is_float($value) || (is_string($value) && is_numeric($value))) { $out[$key] = $value + 0; } elseif (is_scalar($value)) { $out[$key] = substr(sanitize_text_field((string) $value), 0, 200); } } return (array) apply_filters('adghost_sanitize_unit_options', $out, $options); } private static $units_cache = []; public static function units($include_paused = false) { $raw = (array) get_option('adghost_ad_units', []); $key = ($include_paused ? 'paused:' : 'live:') . md5(serialize($raw)); if (isset(self::$units_cache[$key])) { return self::$units_cache[$key]; } $out = []; foreach ($raw as $unit) { if (!is_array($unit)) { continue; } if (class_exists('AdGhost_Default_Ad_Units')) { $unit = AdGhost_Default_Ad_Units::fill_from_default($unit); } $unit = self::normalize_unit($unit); if ($include_paused || $unit['enabled']) { $out[] = $unit; } } self::$units_cache[$key] = $out; return $out; } public static function flush_units_cache() { self::$units_cache = []; } public static function pro_active() { if (!function_exists('apply_filters')) { return false; } return (bool) apply_filters('adghost_pro_active', false) || (bool) apply_filters('adghost_plus_active', false); } public static function ads_live() { if (self::builder_preview()) { return false; } if (get_option('adghost_is_active', false)) { return true; } return get_option('adghost_debug_mode', false) && function_exists('current_user_can') && current_user_can('manage_options'); } public static function purge_page_cache($post_id = null) { $post_id = $post_id ? (int) $post_id : 0; if ($post_id) { clean_post_cache($post_id); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- LiteSpeed Cache's own purge hook. do_action('litespeed_purge_post', $post_id); if (function_exists('rocket_clean_post')) { rocket_clean_post($post_id); } if (function_exists('w3tc_flush_post')) { w3tc_flush_post($post_id); } if (function_exists('wp_cache_post_change')) { wp_cache_post_change($post_id); } if (function_exists('sg_cachepress_purge_cache')) { sg_cachepress_purge_cache(get_permalink($post_id)); } do_action('adghost_purge_page_cache', $post_id); return; } // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- LiteSpeed Cache's own purge hook. do_action('litespeed_purge_all'); if (function_exists('rocket_clean_domain')) { rocket_clean_domain(); } if (function_exists('w3tc_flush_all')) { w3tc_flush_all(); } if (function_exists('wp_cache_clear_cache')) { wp_cache_clear_cache(); } if (function_exists('sg_cachepress_purge_cache')) { sg_cachepress_purge_cache(); } do_action('adghost_purge_page_cache', 0); } public static function builder_preview() { // phpcs:disable WordPress.Security.NonceVerification.Recommended -- read only, to recognise an editor frame. foreach (['elementor-preview', 'fl_builder', 'et_fb', 'bricks', 'ct_builder', 'vc_editable', 'breakdance', 'breakdance_iframe', 'brizy-edit-iframe', 'tve', 'uxb_iframe', 'zionbuilder-preview', 'op3editor'] as $arg) { if (isset($_GET[$arg])) { return true; } } // phpcs:enable if (function_exists('is_customize_preview') && is_customize_preview()) { return true; } if (class_exists('\Elementor\Plugin') && isset(\Elementor\Plugin::$instance->preview) && method_exists(\Elementor\Plugin::$instance->preview, 'is_preview_mode') && \Elementor\Plugin::$instance->preview->is_preview_mode()) { return true; } if (class_exists('FLBuilderModel') && method_exists('FLBuilderModel', 'is_builder_active') && FLBuilderModel::is_builder_active()) { return true; } if (function_exists('et_core_is_fb_enabled') && et_core_is_fb_enabled()) { return true; } if (function_exists('bricks_is_builder') && bricks_is_builder()) { return true; } return false; } public static function allowed_ads_html() { $allowed = wp_kses_allowed_html('post'); $allowed['template'] = ['id' => true]; $allowed['div'] = array_merge($allowed['div'] ?? [], ['data-*' => true, 'style' => true, 'id' => true, 'class' => true, 'hidden' => true]); $allowed['span'] = array_merge($allowed['span'] ?? [], ['class' => true]); $allowed['li'] = array_merge($allowed['li'] ?? [], ['class' => true]); $allowed['button'] = ['type' => true, 'class' => true]; $allowed['amp-ad'] = [ 'width' => true, 'height' => true, 'type' => true, 'layout' => true, 'class' => true, 'data-*' => true, 'json' => true, 'rtc-config' => true, 'media' => true, ]; $allowed['amp-sticky-ad'] = ['layout' => true, 'class' => true]; $allowed['div']['fallback'] = true; return $allowed; } public static function allowed_admin_html() { $common = ['class' => true, 'id' => true, 'title' => true, 'hidden' => true, 'data-*' => true, 'aria-hidden' => true, 'aria-label' => true, 'role' => true]; return [ 'button' => $common + ['type' => true, 'aria-selected' => true], 'input' => $common + ['type' => true, 'accept' => true, 'value' => true], 'span' => $common, 'a' => $common + ['href' => true, 'target' => true, 'rel' => true], 'code' => $common, 'strong' => [], 'li' => $common, 'div' => $common, ]; } public static function capabilities() { return [ 'in_content' => true, 'lazy_load' => true, 'cls_prevention' => true, 'anchor' => true, 'ads_txt' => true, 'csv' => true, 'interstitial' => true, 'reward' => true, 'spot_sticky' => true, 'float_to_corner' => true, 'screen_formats' => true, 'auto_refresh' => true, 'adblock_detection' => true, 'custom_label' => true, 'max_ad_units' => 0, ]; } public static function generate_id($name) { $id = strtolower($name); $id = preg_replace('/[\s\-]+/', '_', $id); $id = preg_replace('/[^a-z0-9_]/', '', $id); $id = preg_replace('/_+/', '_', $id); $id = trim($id, '_'); if (preg_match('/^[0-9]/', $id)) { $id = 'ad_' . $id; } if (empty($id)) { $id = 'ad_unit_' . wp_generate_password(6, false, false); } return $id; } public static function get_unit_position($unit) { $type = $unit['type'] ?? 'standard'; if ($type === 'interstitial') { return 'interstitial'; } if ($type === 'reward') { return 'reward'; } if (!empty($unit['position'])) { return self::POSITION_ALIASES[$unit['position']] ?? $unit['position']; } if (!empty($unit['isAnchor'])) { return 'anchor'; } if (!empty($unit['floatToCorner']) && !in_array($unit['feature'] ?? 'none', ['float', 'sticky', 'elevator'], true)) { return 'corner'; } switch ($unit['feature'] ?? 'none') { case 'anchor': return 'anchor'; case 'in_image': case 'in-image': return 'in-image'; case 'sidebar': return 'sidebar'; case 'header': return 'header'; case 'footer': return 'footer'; } if (class_exists('AdGhost_Zone_Inferrer')) { return AdGhost_Zone_Inferrer::position($unit); } return 'incontent'; } public static function explain_unit_position($unit) { if (!empty($unit['position'])) { return sprintf('Position "%s" is set explicitly on the unit', $unit['position']); } $type = $unit['type'] ?? 'standard'; if (in_array($type, ['interstitial', 'reward'], true)) { return sprintf('Unit type is "%s"', $type); } if (!empty($unit['isAnchor'])) { return 'Unit is flagged as an anchor'; } if (!empty($unit['floatToCorner'])) { return 'Unit is flagged to float to the corner'; } if (($unit['feature'] ?? 'none') !== 'none') { return sprintf('Unit feature is "%s"', $unit['feature']); } if (class_exists('AdGhost_Zone_Inferrer')) { return AdGhost_Zone_Inferrer::infer($unit)['reason']; } return 'Default in-content placement'; } public static function validate_id($id) { if (preg_match('/\s/', $id)) { return 'This ad unit code contains spaces, which Google Ad Manager does not accept. They are replaced with underscores on save.'; } if (preg_match('#[^A-Za-z0-9_.\-/]#', $id)) { return 'This ad unit code contains characters Google Ad Manager does not accept. They are removed on save.'; } return ''; } public static function sanitize_gam_code($code) { $code = preg_replace('/\s+/', '_', trim((string) $code)); $code = preg_replace('#[^A-Za-z0-9_.\-/]#', '', $code); $code = preg_replace('#/+#', '/', $code); return substr(trim($code, '/'), 0, 120); } public static function gam_code($unit) { $code = self::sanitize_gam_code($unit['id'] ?? ''); if ($code === '') { $code = self::sanitize_gam_code(self::generate_id($unit['name'] ?? '')); } return $code; } }