[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(
'
',
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(
'
',
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(
'
',
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%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 = '' . esc_html__('Import from GAM', 'adghost-lite') . ' ';
$actions .= '' . esc_html__('Export for GAM', 'adghost-lite') . ' ';
$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 .= '' . esc_html($label) . ' ';
}
$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()); ?>
+
ads_txt_panel(); ?>
settings_panel($runtime_url); ?>
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')],
];
?>
__('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(); ?>
settings_where(); ?>
settings_loading($runtime_url); ?>
settings_readers(); ?>
settings_ivt(); ?>
settings_code();
$this->settings_key_values();
$this->settings_testing();
$this->settings_site(); ?>
$label): ?>
[__('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')];
?>
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'),
];
?>
__('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');
?>
[__('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')],
];
?>
[__('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();
?>
' . 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): ?>
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)'],
];
}
}