[5, 3, 200], 'balanced' => [3, 5, 100], 'revenue' => [2, 8, 60], ]; public static function settings_mode() { return get_user_meta(get_current_user_id(), self::MODE_META, true) === 'expert' ? 'expert' : 'simple'; } private $hooks = []; public function register_menu() { $cap = 'manage_options'; $this->hooks[] = add_menu_page( __('AdGhost', 'adghost-lite'), __('AdGhost', 'adghost-lite'), $cap, self::SLUG_UNITS, [$this, 'render_units'], ADGHOST_PLUGIN_URL . 'assets/imgs/adghost-icon-white.svg', 30 ); $page = isset($_GET['page']) ? sanitize_key(wp_unslash($_GET['page'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $moved = [self::SLUG_SETTINGS => 'settings', self::SLUG_ADS_TXT => 'adstxt', self::SLUG_CONNECT => 'settings']; if (isset($moved[$page]) && current_user_can($cap)) { wp_safe_redirect(self::url($moved[$page])); exit; } add_filter('admin_body_class', function ($classes) { $screen = function_exists('get_current_screen') ? get_current_screen() : null; return ($screen && in_array($screen->id, $this->hooks, true)) ? $classes . ' adghost-screen' : $classes; }); } public static function url($tab = '') { return admin_url('admin.php?page=' . self::SLUG_UNITS) . ($tab !== '' ? '#' . $tab : ''); } public function enqueue_assets($hook) { wp_enqueue_style('adghost-admin-global', ADGHOST_PLUGIN_URL . 'assets/css/admin-global.css', [], ADGHOST_VERSION); if (!in_array($hook, $this->hooks, true)) { return; } wp_enqueue_style('adghost-admin', ADGHOST_PLUGIN_URL . 'assets/css/adghost-admin.css', [], $this->asset_version('assets/css/adghost-admin.css')); wp_enqueue_script('adghost-admin', ADGHOST_PLUGIN_URL . 'assets/js/adghost-admin.js', ['jquery'], $this->asset_version('assets/js/adghost-admin.js'), true); $network_code = (string) get_option('adghost_network_code', ''); wp_localize_script('adghost-admin', 'adghostAdmin', [ 'ajaxUrl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('adghost_nonce'), 'restUrl' => esc_url_raw(rest_url()), 'restNamespace' => AdGhost_REST_Controller::NAMESPACE, 'restNonce' => wp_create_nonce('wp_rest'), 'networkCode' => $network_code, 'settingsUrl' => self::url('general'), 'adUnits' => $this->with_inferred_position((array) get_option('adghost_ad_units', [])), 'defaultUnits' => $this->with_inferred_position(AdGhost_Default_Ad_Units::get_all_defaults($network_code)), 'hasSavedUnits' => AdGhost_Default_Ad_Units::units_saved(), 'adSizes' => $this->ad_sizes(), 'sidebars' => $this->sidebars(), 'deviceMode' => AdGhost_Targeting::device_mode(), 'settingsMode' => self::settings_mode(), 'expertTabs' => self::EXPERT_TABS, 'siteRefresh' => (bool) get_option('adghost_enable_auto_refresh', false), 'debugNonce' => wp_create_nonce('adghost_debug_nonce'), 'proActive' => AdGhost_Helper::pro_active(), ]); AdGhost_Setup_Guide::enqueue_tour(); } private function asset_version($relative) { $path = ADGHOST_PLUGIN_DIR . $relative; return ADGHOST_VERSION . (file_exists($path) ? '.' . filemtime($path) : ''); } private function open_page($title, $actions = '', $class = '') { echo '
'; echo '
'; echo '

' . esc_html($title) . '

'; if (AdGhost_Helper::pro_active()) { echo '' . esc_html__('Pro', 'adghost-lite') . ''; } if ($class === 'ag-ai-page') { echo 'AdGhost ' . esc_html(ADGHOST_VERSION) . ''; } echo '
' . wp_kses($actions, AdGhost_Helper::allowed_admin_html()) . '
'; echo '
'; echo '
'; $notice = get_option('adghost_ivt_notice', null); $shown = is_array($notice) && !empty($notice['message']); if ($shown) { printf( '

%s %s %s

', esc_html__('Invalid traffic enforcement was switched back to Monitor.', 'adghost-lite'), esc_html($notice['message']), esc_url(self::url('ivt')), esc_html__('Review', 'adghost-lite') ); } $alerting = !$shown && AdGhost_IVT_Manager::should_alert(); if ($alerting) { $stats = AdGhost_IVT_Manager::stats(); $top = AdGhost_IVT_Manager::top_family(); $detail = sprintf( /* translators: 1: percentage, already formatted. 2: number of sessions. */ esc_html__('%1$s of today\'s %2$s sessions were judged invalid.', 'adghost-lite'), esc_html(number_format_i18n(round($stats['invalid'] / $stats['sessions'] * 100, 1), 1) . '%'), esc_html(number_format_i18n($stats['sessions'])) ); if ($top !== null) { $detail .= ' ' . sprintf( /* translators: %s: a signal family name, e.g. "automation". */ esc_html__('Most were flagged for %s.', 'adghost-lite'), esc_html($top['name']) ); } printf( '

%s %s %s

', esc_html__('Unusual traffic today.', 'adghost-lite'), wp_kses_post($detail), esc_url(self::url('ivt')), esc_html__('See the signals', 'adghost-lite') ); } if (!$shown && !$alerting && self::review_ask_due(time())) { self::render_review_ask(); } echo '
'; } public static function review_ask_due($now) { if (!current_user_can('manage_options') || !get_option('adghost_is_active', false)) { return false; } $ask = get_option(self::REVIEW_OPTION, []); if ($ask === 'never' || (is_array($ask) && (int) ($ask['after'] ?? 0) > $now)) { return false; } $first = (int) get_option('adghost_first_deployed', 0); if ($first <= 0) { $last = (string) get_option('adghost_last_deployed', ''); $first = $last !== '' ? (int) strtotime(get_gmt_from_date($last) . ' UTC') : 0; } return $first > 0 && $now - $first >= self::REVIEW_AFTER_DAYS * DAY_IN_SECONDS; } private static function review_link($do) { return wp_nonce_url(admin_url('admin-post.php?action=adghost_review&do=' . $do), 'adghost_review'); } private static function render_review_ask() { printf( '

%1$s %2$s

' . '%4$s ' . '%6$s ' . '%8$s

%9$s %11$s

', esc_html__('Is AdGhost Lite working well for you?', 'adghost-lite'), esc_html__('A short review on WordPress.org helps other publishers find it. It takes a minute.', 'adghost-lite'), esc_url(self::review_link('review')), esc_html__('Leave a review', 'adghost-lite'), esc_url(self::review_link('later')), esc_html__('Not now', 'adghost-lite'), esc_url(self::review_link('never')), esc_html__('Don\'t ask again', 'adghost-lite'), esc_html__('Something not working?', 'adghost-lite'), esc_url(self::SUPPORT_URL), esc_html__('Ask in the support forum: we read every thread.', 'adghost-lite') ); } public static function handle_review_ask() { if (!current_user_can('manage_options')) { wp_die(esc_html__('You are not allowed to do that.', 'adghost-lite'), '', ['response' => 403]); } check_admin_referer('adghost_review'); $do = isset($_GET['do']) ? sanitize_key(wp_unslash($_GET['do'])) : ''; if ($do === 'later') { update_option(self::REVIEW_OPTION, ['after' => time() + self::REVIEW_SNOOZE_DAYS * DAY_IN_SECONDS], false); wp_safe_redirect(self::url()); exit; } update_option(self::REVIEW_OPTION, 'never', false); if ($do === 'review') { // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect -- a fixed wordpress.org address, not user input. wp_redirect(self::REVIEW_URL); exit; } wp_safe_redirect(self::url()); exit; } private function close_page() { $this->support_strip(); echo '
'; } const SUPPORT_HIDDEN_META = 'adghost_support_hidden'; private function support_strip() { if (get_user_meta(get_current_user_id(), self::SUPPORT_HIDDEN_META, true)) { return; } $reviews = 'https://wordpress.org/support/plugin/adghost-lite/reviews/#new-post'; $help = 'https://wordpress.org/support/plugin/adghost-lite/'; ?> %s', esc_html__('Unsaved changes', 'adghost-lite'), esc_html($label) ); } private function summary(array $items) { echo '
'; foreach ($items as $item) { printf( '
%s
%s
', esc_attr($item[2] ?? ''), esc_html($item[0]), wp_kses($item[1], AdGhost_Helper::allowed_admin_html()) ); } echo '
'; } private function status($state, $label) { return sprintf('%s', esc_attr($state), esc_html($label)); } private function ivt_quality_value() { $share = AdGhost_IVT_Manager::invalid_share(); if ($share === null) { $sessions = AdGhost_IVT_Manager::stats()['sessions']; return sprintf( '%s %s', esc_url(self::url('ivt')), esc_html(number_format_i18n($sessions)), esc_html(_n('session today', 'sessions today', $sessions, 'adghost-lite')) ); } return sprintf( '%s', esc_url(self::url('ivt')), $this->status( $share >= AdGhost_IVT_Manager::ALERT_SHARE ? 'warn' : 'ok', sprintf( /* translators: %s: share of today's sessions judged invalid, already formatted, e.g. "6.2%". */ __('%s invalid today', 'adghost-lite'), number_format_i18n(round($share * 100, 1), 1) . '%' ) ) ); } private function tz() { $tz = wp_timezone_string(); return in_array($tz, ['+00:00', 'UTC', 'Etc/UTC'], true) ? 'UTC' : $tz; } private function datetime($mysql) { if ($mysql === '') { return '—'; } return '' . esc_html(mysql2date('Y-m-d H:i', $mysql)) . ' ' . esc_html($this->tz()) . ''; } public function render_units() { $network_code = (string) get_option('adghost_network_code', ''); $is_active = (bool) get_option('adghost_is_active', false); $local = get_option('adghost_local_script', []); $runtime_url = (is_array($local) && !empty($local['url']) && !empty($local['path']) && file_exists($local['path'])) ? (string) $local['url'] : ''; $actions = ''; $actions .= ''; $actions .= ''; $found = array_keys(array_filter(AdGhost_Plugin_Importer::detect())); if ($found) { /* translators: %s: the name of another ad plugin. */ $label = count($found) === 1 ? sprintf(__('Import from %s', 'adghost-lite'), $found[0]) : __('Import from another plugin', 'adghost-lite'); $actions .= ''; } $actions .= ''; $actions .= $this->save_control(__('Save and deploy', 'adghost-lite')); $this->open_page(__('AdGhost', 'adghost-lite'), '', 'ag-ai-page'); AdGhost_Setup_Guide::render_moved_notice(); if ($runtime_url !== '') { $runtime = '' . esc_html__('File on this site', 'adghost-lite') . ''; } else { $runtime = '' . esc_html__('Not built yet', 'adghost-lite') . ''; } $summary_items = [ [__('Status', 'adghost-lite'), $is_active ? $this->status('ok', __('Live', 'adghost-lite')) : $this->status('off', __('Not live', 'adghost-lite'))], [__('Last deploy', 'adghost-lite'), $this->datetime((string) get_option('adghost_last_deployed', ''))], [__('Network code', 'adghost-lite'), $network_code !== '' ? '' . esc_html($network_code) . '' : '' . esc_html__('Not set — enter it above', 'adghost-lite') . ''], [__('Runtime', 'adghost-lite'), $runtime], [__('Active units', 'adghost-lite'), '0'], [__('In Ad Manager', 'adghost-lite'), $this->gam_coverage()], ]; if (AdGhost_IVT_Manager::enabled()) { $summary_items[] = [__('Traffic quality', 'adghost-lite'), $this->ivt_quality_value()]; } $summary_items[] = [__('Max per page', 'adghost-lite'), '' . esc_html((int) get_option('adghost_max_ads_per_page', 5) > 0 ? (int) get_option('adghost_max_ads_per_page', 5) : __('No limit', 'adghost-lite')) . '']; ob_start(); $this->summary($summary_items); $summary_html = ob_get_clean(); ?>
    unit_list_fallback(), AdGhost_Helper::allowed_admin_html()); ?>

close_page(); } private function quick_settings() { $preview = (bool) get_option('adghost_debug_mode', false); $hide = (string) AdGhost_Targeting::rules()['hide_logged_in']; $ivt = $this->ivt_modes(); $styles = [ 'reader' => __('Fewer', 'adghost-lite'), 'balanced' => __('Balanced', 'adghost-lite'), 'revenue' => __('More', 'adghost-lite'), ]; $links = [ ['readers', '#consent-mode-label', __('Consent message', 'adghost-lite')], ['where', '.ag-no-ads', __('Pages without ads', 'adghost-lite')], ['loading', '#enable_auto_refresh', __('Auto refresh', 'adghost-lite')], ['loading', '#ad-label-label', __('Ad label', 'adghost-lite')], ['readers', '#enable_adblock_detection', __('Ad blocker message', 'adghost-lite')], ['code', '#code_head', __('Header and footer code', 'adghost-lite')], ['code', '#adghost-transfer', __('Export or import settings', 'adghost-lite')], ]; ?>

$name): ?>

__('Ads', 'adghost-lite'), 'where' => __('Where ads show', 'adghost-lite'), 'loading' => __('Loading & display', 'adghost-lite'), 'readers' => __('Consent & ad blockers', 'adghost-lite'), 'ivt' => __('Bot protection', 'adghost-lite'), 'code' => __('Advanced', 'adghost-lite'), ]; $tabs = array_merge($tabs, array_diff_key((array) apply_filters('adghost_settings_tabs', []), $tabs)); $mode = self::settings_mode(); ?>

$label): ?>
settings_general(); ?>
$label): ?>
save_control(__('Save and deploy', 'adghost-lite')), AdGhost_Helper::allowed_admin_html()); ?>

[__('Reader-friendly', 'adghost-lite'), __('Fewer ads, far apart. Best for long reads.', 'adghost-lite')], 'balanced' => [__('Balanced', 'adghost-lite'), __('Recommended for most sites.', 'adghost-lite')], 'revenue' => [__('More revenue', 'adghost-lite'), __('More ads, closer together.', 'adghost-lite')], ]; foreach ($styles as $style => [$name, $what]) : [$interval, $max, $words] = self::DENSITY[$style]; ?>

paragraph_rules(); ?>

[__('Privacy policy page', 'adghost-lite'), __('The page set under Settings → Privacy.', 'adghost-lite')], 'contact' => [__('Contact pages', 'adghost-lite'), __('Pages called Contact, Contact us, Get in touch…', 'adghost-lite')], 'legal' => [__('Terms and legal pages', 'adghost-lite'), __('Terms, Disclaimer, Cookie policy, Imprint, DMCA.', 'adghost-lite')], ]; $why = ['privacy' => __('privacy policy', 'adghost-lite'), 'contact' => __('contact page', 'adghost-lite'), 'legal' => __('legal page', 'adghost-lite'), 'manual' => __('switched off by hand', 'adghost-lite')]; ?>

[$label, $help]): ?>

' . esc_html__('Pages', 'adghost-lite') . '', '' . esc_html__('Posts', 'adghost-lite') . '' ); ?>

targeting_rules(); ?>

__('The article, its images and styles load first; ads are requested right after. Best for reading and Core Web Vitals. Recommended.', 'adghost-lite'), 'interactive' => __('Ads are requested as soon as the text is on the page, before images finish. Ads appear sooner; the page can feel slower on a weak connection.', 'adghost-lite'), 'immediate' => __('Ads are requested while the page is still loading. Fastest ads, and they compete with the article for the connection.', 'adghost-lite'), ]; if (!isset($load_help[$load_after])) { $load_after = 'load'; } ?>

__('No shift is possible. Recommended.', 'adghost-lite'), 'min' => __('Less empty space before the ad arrives; the page can move a little when a taller ad fills.', 'adghost-lite'), 'off' => __('The article moves down when each ad loads. Hurts Core Web Vitals (CLS) and reading.', 'adghost-lite'), ]; ?>

__('Advertisement', 'adghost-lite'), 'custom' => __('Custom', 'adghost-lite'), 'hidden' => __('None', 'adghost-lite')] as $value => $text): ?>
>
>

__('Decided on the visitor\'s screen: phones under 768px, tablets to 1024px, desktops above. Works with every page cache.', 'adghost-lite'), 'server' => __('Decided on the server from the browser\'s user agent. Use only if your page cache keeps separate copies for mobile, or has none.', 'adghost-lite'), ]; ?>

>

<script async src=""></script>

for you. Nothing to upload or paste.', 'adghost-lite'); ?>

for you.', 'adghost-lite'); ?>

>

__('If a consent platform is on the page, its answer is read and readers who have not consented get non-personalised ads. Recommended wherever the GDPR or the UK GDPR applies.', 'adghost-lite'), 'npa' => __('Every ad request is non-personalised, for every reader, everywhere. Lower revenue, no consent question.', 'adghost-lite'), 'off' => __('AdGhost sends nothing about consent and leaves the question to Google\'s own handling of your consent platform.', 'adghost-lite'), ]; if (!isset($consent_help[$consent_mode])) { $consent_mode = 'auto'; } ?>

·

[__('Short posts', 'adghost-lite'), __('no in-content ads on posts with fewer paragraphs than this', 'adghost-lite'), 0, 50], 'max_paragraphs' => [__('Long posts', 'adghost-lite'), __('no in-content ads on posts with more paragraphs than this (0 = no limit)', 'adghost-lite'), 0, 500], 'skip_first_paragraphs' => [__('Skip first', 'adghost-lite'), __('paragraphs at the top that never get an ad after them', 'adghost-lite'), 0, 20], 'skip_last_paragraphs' => [__('Skip last', 'adghost-lite'), __('paragraphs at the end that never get an ad after them', 'adghost-lite'), 0, 20], 'min_words_above' => [__('Words above', 'adghost-lite'), __('words of reading before the first in-content ad (0 = off)', 'adghost-lite'), 0, 2000], 'min_paragraph_words' => [__('Paragraph length', 'adghost-lite'), __('words a paragraph needs to count as one', 'adghost-lite'), 0, 200], ]; foreach ($number as $key => [$label, $help, $min, $max]): ?>

' . esc_html($home) . '' : esc_html__('Not recorded yet — it is written the first time you deploy.', 'adghost-lite'); ?>

    $why) : ?>
  • :

[__('Inside ', 'adghost-lite'), __('Analytics, consent managers, Prebid, site verification. Printed in the page head of every front-end page.', 'adghost-lite')], 'body' => [__('After opens', 'adghost-lite'), __('Tag manager noscript frames and anything that must be first in the body. Needs a theme that calls wp_body_open().', 'adghost-lite')], 'footer' => [__('Before ', 'adghost-lite'), __('Chat widgets, deferred scripts, conversion pixels.', 'adghost-lite')], ]; ?>

[$title, $help]): ?>

[__('Post ID', 'adghost-lite'), '1234'], 'page_type' => [__('Page type', 'adghost-lite'), 'home, post, page, category, archive, search'], 'category' => [__('Categories', 'adghost-lite'), __('the post\'s category slugs', 'adghost-lite')], 'tag' => [__('Tags', 'adghost-lite'), __('the post\'s tag slugs', 'adghost-lite')], 'author' => [__('Author', 'adghost-lite'), __('the author\'s username', 'adghost-lite')], ]; ?>

$default): ?>

[__('Monitor', 'adghost-lite'), __('Detectors record what they see. Ad serving is not changed.', 'adghost-lite')], 'no-ads' => [__('Block ads for obvious bots', 'adghost-lite'), __('Visitors with a clear robot sign (an automation driver, a headless browser, an HTTP library) get the page without ads. A reader\'s browser never shows these signs.', 'adghost-lite')], ]); $ivt_modes = ['off' => [__('Off', 'adghost-lite'), __('Detection does not run.', 'adghost-lite')]]; foreach (AdGhost_IVT_Manager::available_modes() as $mode) { if (isset($ivt_labels[$mode])) { $ivt_modes[$mode] = $ivt_labels[$mode]; } } return [ 'modes' => $ivt_modes, 'value' => $ivt_enabled ? $ivt_set_mode : 'off', 'set' => $ivt_set_mode, 'forced' => defined('ADGHOST_IVT_DISABLED') && ADGHOST_IVT_DISABLED, ]; } private function settings_ivt() { $ivt = $this->ivt_modes(); $ivt_modes = $ivt['modes']; $ivt_value = $ivt['value']; $ivt_set_mode = $ivt['set']; $ivt_forced = $ivt['forced']; $ivt_enabled = AdGhost_IVT_Manager::enabled(); $ivt_running = AdGhost_IVT_Manager::mode(); ?>
[$label, $help]): ?>

ivt_today(); ?>

' . esc_html(number_format_i18n($stats['sessions'])) . '', '' . esc_html(number_format_i18n($stats['invalid'])) . '' ); ?> ' . esc_html(number_format_i18n(round($share * 100, 1), 1) . '%') . '', esc_html(number_format_i18n($stats['invalid'])), esc_html(number_format_i18n($stats['sessions'])) ); ?>

$count) { $parts[] = AdGhost_Signal_Registry::FAMILIES[$family] . ' (' . number_format_i18n($count) . ')'; } echo '

' . esc_html__('What was seen:', 'adghost-lite') . ' ' . esc_html(implode(', ', $parts)) . '

'; } ?> 0) : ?>

summary([ [__('File', 'adghost-lite'), $exists ? $this->status('ok', __('Found', 'adghost-lite')) : ($virtual ? $this->status('ok', __('Served by WordPress', 'adghost-lite')) : $this->status('warn', __('Not found', 'adghost-lite')))], [__('URL', 'adghost-lite'), '' . esc_html(preg_replace('#^https?://#', '', $url)) . ''], [__('Entries', 'adghost-lite'), '' . esc_html($this->ads_txt_entries($content)) . ''], [__('Modified', 'adghost-lite'), $exists ? '' . esc_html(wp_date('Y-m-d H:i', filemtime($path))) . ' ' . esc_html($this->tz()) . '' : '—'], ]); if ($virtual): ?>

0
save_control(__('Save and deploy', 'adghost-lite')), AdGhost_Helper::allowed_admin_html()); ?>
units(); $total = 0; $known = 0; foreach ($units as $unit) { if (!is_array($unit)) { continue; } $total++; if (AdGhost_CSV_Exporter::in_gam($unit)) { $known++; } } if ($total === 0) { return '—'; } if ($known === 0) { return '' . esc_html__('None yet — Export for GAM', 'adghost-lite') . ''; } return '' . esc_html(sprintf( /* translators: 1: units Ad Manager has, 2: units on this site */ __('%1$d of %2$d', 'adghost-lite'), $known, $total )) . ''; } private function units() { $saved = (array) get_option('adghost_ad_units', []); return ($saved || AdGhost_Default_Ad_Units::units_saved()) ? $saved : AdGhost_Default_Ad_Units::get_all_defaults((string) get_option('adghost_network_code', '')); } private function unit_list_fallback() { $units = $this->units(); $labels = [ '' => __('Automatic', 'adghost-lite'), 'header' => __('Top of page', 'adghost-lite'), 'before_content' => __('Before post content', 'adghost-lite'), 'incontent' => __('Between paragraphs', 'adghost-lite'), 'after_content' => __('After post content', 'adghost-lite'), 'before_comments' => __('Before comments', 'adghost-lite'), 'between_comments' => __('Between comments', 'adghost-lite'), 'after_comments' => __('After comments', 'adghost-lite'), 'sidebar' => __('Sidebar', 'adghost-lite'), 'between_posts' => __('Between posts in lists', 'adghost-lite'), 'before_excerpt' => __('Before excerpts in lists', 'adghost-lite'), 'after_excerpt' => __('After excerpts in lists', 'adghost-lite'), 'footer' => __('Bottom of page', 'adghost-lite'), 'selector' => __('Next to an HTML element', 'adghost-lite'), 'anchor' => __('Anchor bar', 'adghost-lite'), 'corner' => __('Corner pop-up', 'adghost-lite'), 'slide' => __('Slide-in', 'adghost-lite'), 'docked' => __('Docked to edge', 'adghost-lite'), 'rail' => __('Beside content', 'adghost-lite'), 'bubble' => __('Bubble', 'adghost-lite'), 'overlay' => __('Overlay', 'adghost-lite'), ]; $html = ''; foreach (array_values($units) as $i => $unit) { if (!is_array($unit)) { continue; } $unit = AdGhost_Helper::normalize_unit(AdGhost_Default_Ad_Units::fill_from_default($unit)); $where = $unit['type'] === 'interstitial' ? __('Interstitial', 'adghost-lite') : ($unit['type'] === 'reward' ? __('Rewarded', 'adghost-lite') : ($labels[$unit['position']] ?? $unit['position'])); $manual = ($unit['placementMode'] ?? 'auto') === 'manual'; $html .= sprintf( '
  • %d
  • ', !$unit['enabled'] ? 'off' : ($manual ? 'manual' : 'auto'), $i === 0 ? ' is-selected' : '', esc_attr(($unit['name'] !== '' ? $unit['name'] : __('Unnamed unit', 'adghost-lite')) . ' — ' . $where), $i + 1 ); } return $html; } private function sidebars() { $out = []; foreach ((array) ($GLOBALS['wp_registered_sidebars'] ?? []) as $id => $sidebar) { $out[] = ['id' => (string) $id, 'name' => (string) ($sidebar['name'] ?? $id)]; } return $out; } private function ad_sizes() { return [ ['value' => 'fluid', 'label' => 'Fluid'], ['value' => 'out-of-page', 'label' => 'Out-of-page'], ['value' => '1x1', 'label' => '1x1 (Custom)'], ['value' => '4:1', 'label' => '4:1 (Aspect ratio)'], ['value' => '6:1', 'label' => '6:1 (Aspect ratio)'], ['value' => '88x31', 'label' => '88x31 (Micro Bar)'], ['value' => '120x20', 'label' => '120x20 (MMA Small Banner)'], ['value' => '120x30', 'label' => '120x30 (MMA Small Banner)'], ['value' => '120x60', 'label' => '120x60 (Button 2)'], ['value' => '120x90', 'label' => '120x90 (Button 1)'], ['value' => '120x240', 'label' => '120x240 (Vertical Banner)'], ['value' => '120x600', 'label' => '120x600 (Skyscraper)'], ['value' => '125x125', 'label' => '125x125 (Button)'], ['value' => '160x600', 'label' => '160x600 (Wide Skyscraper)'], ['value' => '168x28', 'label' => '168x28 (MMA Medium Banner)'], ['value' => '168x42', 'label' => '168x42 (MMA Medium Banner)'], ['value' => '180x150', 'label' => '180x150 (Rectangle)'], ['value' => '200x200', 'label' => '200x200 (Small Square)'], ['value' => '200x446', 'label' => '200x446 (Custom)'], ['value' => '216x36', 'label' => '216x36 (MMA Large Banner)'], ['value' => '216x54', 'label' => '216x54 (MMA Large Banner)'], ['value' => '220x90', 'label' => '220x90 (Custom)'], ['value' => '234x60', 'label' => '234x60 (Half Banner)'], ['value' => '240x133', 'label' => '240x133 (Custom)'], ['value' => '240x400', 'label' => '240x400 (Vertical Rectangle)'], ['value' => '250x250', 'label' => '250x250 (Square)'], ['value' => '250x360', 'label' => '250x360 (Custom)'], ['value' => '292x30', 'label' => '292x30 (Custom)'], ['value' => '300x31', 'label' => '300x31 (Custom)'], ['value' => '300x50', 'label' => '300x50 (MMA Extra Large Banner)'], ['value' => '300x75', 'label' => '300x75 (MMA Extra Large Banner)'], ['value' => '300x100', 'label' => '300x100 (3:1 Rectangle)'], ['value' => '300x250', 'label' => '300x250 (Medium Rectangle)'], ['value' => '300x600', 'label' => '300x600 (Half Page Ad)'], ['value' => '300x1050', 'label' => '300x1050 (Custom)'], ['value' => '320x50', 'label' => '320x50 (Mobile Leaderboard)'], ['value' => '320x100', 'label' => '320x100 (Custom)'], ['value' => '320x480', 'label' => '320x480 (Mobile Portrait Full Screen)'], ['value' => '336x280', 'label' => '336x280 (Large Rectangle)'], ['value' => '468x60', 'label' => '468x60 (Full Banner)'], ['value' => '480x320', 'label' => '480x320 (Mobile Landscape Full Screen)'], ['value' => '580x400', 'label' => '580x400 (Custom)'], ['value' => '728x90', 'label' => '728x90 (Leaderboard)'], ['value' => '728x250', 'label' => '728x250 (Custom)'], ['value' => '750x100', 'label' => '750x100 (Custom)'], ['value' => '750x200', 'label' => '750x200 (Custom)'], ['value' => '750x300', 'label' => '750x300 (Custom)'], ['value' => '768x1024', 'label' => '768x1024 (Tablet Portrait Full Screen)'], ['value' => '930x180', 'label' => '930x180 (Custom)'], ['value' => '950x90', 'label' => '950x90 (Custom)'], ['value' => '960x90', 'label' => '960x90 (Custom)'], ['value' => '970x66', 'label' => '970x66 (Custom)'], ['value' => '970x90', 'label' => '970x90 (Large Leaderboard)'], ['value' => '970x250', 'label' => '970x250 (Custom)'], ['value' => '980x90', 'label' => '980x90 (Custom)'], ['value' => '980x120', 'label' => '980x120 (Custom)'], ['value' => '1024x768', 'label' => '1024x768 (Tablet Landscape Full Screen)'], ]; } }