'post_id', 'page_type' => 'page_type', 'category' => 'category', 'tag' => 'tag', 'author' => 'author', ]; const RESERVED = ['adghost', 'adghost-refresh', 'agh-ivt', 'agh_tq']; const MAX_VALUES = 10; const MAX_PAIRS = 20; public static function settings() { $saved = get_option(self::OPTION, []); $saved = is_array($saved) ? $saved : []; $auto = []; foreach ((array) ($saved['auto'] ?? []) as $item => $key) { $key = self::sanitize_key_name($key); if (isset(self::AUTO[$item]) && $key !== '') { $auto[$item] = $key; } } return [ 'auto' => $auto, 'custom' => self::sanitize_pairs($saved['custom'] ?? []), ]; } public static function save(array $data, callable $has) { $saved = get_option(self::OPTION, []); $saved = is_array($saved) ? $saved : []; $auto = (array) ($saved['auto'] ?? []); foreach (self::AUTO as $item => $default) { if ($has('kv_' . $item)) { $on = in_array((string) $data['kv_' . $item], ['1', 'true'], true) || $data['kv_' . $item] === true || $data['kv_' . $item] === 1; $key = $has('kv_' . $item . '_key') ? self::sanitize_key_name($data['kv_' . $item . '_key']) : ($auto[$item] ?? ''); if ($on) { $auto[$item] = $key !== '' ? $key : $default; } else { unset($auto[$item]); } } } $saved['auto'] = $auto; if ($has('kv_custom')) { $saved['custom'] = self::sanitize_pairs((string) $data['kv_custom']); } update_option(self::OPTION, $saved); } public static function page_values() { $settings = self::settings(); $out = []; foreach ($settings['auto'] as $item => $key) { $values = self::clean_values(self::auto_value($item)); if ($values) { $out[$key] = $values; } } foreach ($settings['custom'] as $key => $values) { $out[$key] = $values; } return $out; } private static function auto_value($item) { $singular = function_exists('is_singular') && is_singular(); $id = $singular ? (int) get_queried_object_id() : 0; switch ($item) { case 'post_id': return $id ? [(string) $id] : []; case 'page_type': return [AdGhost_Targeting::page_type()]; case 'category': case 'tag': $taxonomy = $item === 'category' ? 'category' : 'post_tag'; if ($id) { $terms = get_the_terms($id, $taxonomy); return is_array($terms) ? wp_list_pluck($terms, 'slug') : []; } $object = function_exists('get_queried_object') ? get_queried_object() : null; return ($object instanceof WP_Term && $object->taxonomy === $taxonomy) ? [$object->slug] : []; case 'author': if ($id) { $user = get_userdata((int) get_post_field('post_author', $id)); return $user ? [$user->user_nicename] : []; } $object = function_exists('get_queried_object') ? get_queried_object() : null; return ($object instanceof WP_User) ? [$object->user_nicename] : []; } return []; } public static function sanitize_key_name($key) { $key = strtolower(trim((string) $key)); $key = preg_replace('/\s+/', '_', $key); $key = substr(preg_replace('/[^a-z0-9_-]/', '', $key), 0, 20); return preg_match('/^[a-z]/', $key) ? $key : ''; } public static function sanitize_value($value) { $value = preg_replace('/["\'=!+#*~;^()<>\[\],&\\\\]|[\x00-\x1f]/u', '', (string) $value); return trim(function_exists('mb_substr') ? mb_substr(trim($value), 0, 40) : substr(trim($value), 0, 40)); } private static function clean_values(array $values) { $out = []; foreach ($values as $value) { $value = self::sanitize_value($value); if ($value !== '' && !in_array($value, $out, true)) { $out[] = $value; } } return array_slice($out, 0, self::MAX_VALUES); } public static function sanitize_pairs($input) { $pairs = []; if (is_array($input)) { foreach ($input as $key => $values) { $pairs[] = [$key, is_array($values) ? $values : explode(',', (string) $values)]; } } else { foreach (preg_split('/[\r\n;]+/', (string) $input) as $line) { if (strpos($line, '=') === false) { continue; } [$key, $values] = explode('=', $line, 2); $pairs[] = [$key, explode(',', $values)]; } } $out = []; foreach ($pairs as [$key, $values]) { $key = self::sanitize_key_name($key); if ($key === '' || in_array($key, self::RESERVED, true) || strpos($key, 'hb_') === 0) { continue; } $values = self::clean_values((array) $values); if ($values) { $out[$key] = $values; } if (count($out) >= self::MAX_PAIRS) { break; } } return $out; } public static function to_text(array $pairs, $glue = "\n") { $lines = []; foreach ($pairs as $key => $values) { $lines[] = $key . '=' . implode(', ', (array) $values); } return implode($glue, $lines); } public static function page_script() { $values = self::page_values(); if (!$values) { return ''; } return '(function(c){c.pageTargeting=Object.assign(c.pageTargeting||{},' . wp_json_encode($values, JSON_HEX_TAG | JSON_HEX_AMP) . ');})' . '(window.AdGhostConfig=window.AdGhostConfig||{});'; } public static function amp_json() { $values = self::page_values(); return $values ? wp_json_encode(['targeting' => $values]) : null; } }