'feedback', 'button_text' => 'Отправить', 'agreement_text' => 'Нажимая кнопку, вы соглашаетесь с правилами Политики конфиденциальности и на обработку персональных данных', ); // Слияние параметров из шорткода или вызова $args = shortcode_atts($defaults, $atts, 'custom_form'); // Буферизация вывода ob_start(); // Путь к шаблону формы $template_path = get_template_directory() . '/forms/' . sanitize_file_name($args['type']) . '.php'; if (file_exists($template_path)) { $atts = $args; include $template_path; } else { echo '

Форма не найдена: ' . esc_html($template_path) . '

'; } return ob_get_clean(); } add_shortcode('custom_form', 'custom_form'); /** * Регистрация меню, поддержек темы и сайдбара */ if (!function_exists('tat_setup_theme')) { function tat_setup_theme() { // Регистрация меню register_nav_menus(array( 'top' => 'Верхнее меню', 'left' => 'Нижнее', )); // Поддержка миниатюр и размеров add_theme_support('post-thumbnails'); set_post_thumbnail_size(254, 190); // Важно: WordPress управляет тегом add_theme_support('title-tag'); // Регистрация сайдбара (если нужен) if (function_exists('register_sidebar')) { register_sidebar(array('id' => 'sidebar-1')); } } } add_action('after_setup_theme', 'tat_setup_theme'); /** * Утилиты версии для файлов (cache-busting) */ if (!function_exists('tat_asset_version')) { function tat_asset_version($path) { $full = get_stylesheet_directory() . $path; if (file_exists($full)) { return filemtime($full); } return false; } } /** * Подключение стилей и скриптов через wp_enqueue */ if (!function_exists('tat_enqueue_assets')) { function tat_enqueue_assets() { $template_uri = get_stylesheet_directory_uri(); // jQuery (WP builtin) wp_enqueue_script('jquery'); wp_enqueue_script('imask', $template_uri . '/js/imask.js', array('jquery'), tat_asset_version('/js/imask.js'), true); // Локальные стили/шрифты/библиотеки — используем filemtime для версионирования wp_enqueue_style('VictorMono-font', $template_uri . '/fonts/VictorMono/index.css', array(), tat_asset_version('/fonts/VictorMono/index.css')); wp_enqueue_style('Mulish-font', $template_uri . '/fonts/Mulish/index.css', array(), tat_asset_version('/fonts/Mulish/index.css')); wp_enqueue_style('tat-fonts', 'https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&family=Playfair+Display:ital,wght@0,500;0,600;0,700;1,500&display=swap', array(), null); wp_enqueue_style('bootstrap', $template_uri . '/css/bootstrap.min.css', array(), tat_asset_version('/css/bootstrap.min.css')); wp_enqueue_style('swiper', $template_uri . '/css/swiper-bundle.min.css', array(), tat_asset_version('/css/swiper-bundle.min.css')); wp_enqueue_style('fancybox', 'https://cdn.jsdelivr.net/npm/@fancyapps/ui@6.0/dist/fancybox/fancybox.css', [], '6.0'); wp_enqueue_style('theme-style', get_stylesheet_uri(), array(), tat_asset_version('/style.css')); // Скрипты wp_enqueue_script('bootstrap', $template_uri . '/js/bootstrap.bundle.min.js', array('jquery'), tat_asset_version('/js/bootstrap.bundle.min.js'), true); wp_enqueue_script('swiper', $template_uri . '/js/swiper-bundle.min.js', array('jquery'), tat_asset_version('/js/swiper-bundle.min.js'), true); wp_enqueue_script('fancybox', 'https://cdn.jsdelivr.net/npm/@fancyapps/ui@6.0/dist/fancybox/fancybox.umd.js', [], '6.0', true); wp_enqueue_script( 'yandex-maps', 'https://api-maps.yandex.ru/2.1/?lang=ru_RU', array(), null, true ); wp_enqueue_script('main', $template_uri . '/js/main.js', array('jquery'), tat_asset_version('/js/main.js'), true); wp_add_inline_script('main', 'var G_TG_LINK = ' . wp_json_encode(G_TG_LINK) . ';', 'before'); } } add_action('wp_enqueue_scripts', 'tat_enqueue_assets'); /** * Вывод favicon через хук — чтобы всё было в системе WordPress */ if (!function_exists('tat_print_favicon')) { function tat_print_favicon() { // Если есть site icon в кастомайзере, WP сам выведет его. // Но на случай, если его нет — выводим локальный фавикон if (!has_site_icon()) { $ico = get_stylesheet_directory_uri() . '/favicon.ico'; echo '<link rel="icon" type="image/x-icon" href="' . esc_url($ico) . '">' . "\n"; } } } add_action('wp_head', 'tat_print_favicon', 1); /** * Настройка SMTP */ function custom_smtp_settings($phpmailer) { $phpmailer->isSMTP(); $phpmailer->Host = 'smtp.beget.com'; $phpmailer->SMTPAuth = true; $phpmailer->Port = 2525; $phpmailer->Username = 'admin@modelms.ru'; $phpmailer->Password = 'j1V*Xg0&ivw3'; $phpmailer->SMTPSecure = 'tls'; $phpmailer->From = 'admin@modelms.ru'; $phpmailer->FromName = G_TEMPLATE; } add_action('phpmailer_init', 'custom_smtp_settings'); /** * Email отправителя писем */ function custom_wp_mail_from($original_email_address) { return 'admin@modelms.ru'; } add_filter('wp_mail_from', 'custom_wp_mail_from'); /** * Имя отправителя писем */ function custom_wp_mail_from_name($original_email_from) { return G_TEMPLATE; } add_filter('wp_mail_from_name', 'custom_wp_mail_from_name'); /** * Рекомендация: отключаем генерацию версий для dev, если нужно. * Можно добавить проверку WP_DEBUG и по-другому назначать версии. */ /** * Каталоги категорий 3 и 5: записей на страницу и WP_Query для пагинации / AJAX. */ function tat_catalog_posts_per_page() { return 12; } /** * Случайный порядок карточек только на первой странице пагинации: тот же набор постов, * что и при сортировке по дате (DESC), без сдвига found_posts и без поломки страниц 2+. * * @param WP_Post[] $posts * @param int $paged 1-based * @return WP_Post[] */ function tat_catalog_shuffle_posts_array_if_first_page(array $posts, $paged) { $paged = max(1, (int) $paged); if ($paged !== 1 || count($posts) < 2) { return $posts; } shuffle($posts); return $posts; } /** * @param int[] $ids * @return int[] */ function tat_catalog_shuffle_post_ids_if_first_page(array $ids, $paged) { $paged = max(1, (int) $paged); if ($paged !== 1 || count($ids) < 2) { return $ids; } shuffle($ids); return $ids; } /** * ID категории для главного запроса архива (cat или category_name). */ function tat_archive_main_query_category_term_id(WP_Query $query) { if (!$query->is_category()) { return 0; } $cat = (int) $query->get('cat'); if ($cat > 0) { return $cat; } $slug = $query->get('category_name'); if (!is_string($slug) || $slug === '') { return 0; } $term = get_term_by('slug', $slug, 'category'); if (!$term || is_wp_error($term)) { return 0; } return (int) $term->term_id; } /** * archive.php и др.: перемешивание только на paged=1; каталоги 3/5 — отдельный WP_Query в шаблонах. * * @param WP_Post[] $posts */ function tat_archive_shuffle_posts_results_first_page_only($posts, $query) { if (!is_array($posts) || empty($posts) || !($query instanceof WP_Query)) { return $posts; } if (is_admin() || !$query->is_main_query() || !$query->is_category()) { return $posts; } $p = (int) $query->get('paged'); if ($p < 1) { $p = (int) $query->get('page'); } if ($p > 1) { return $posts; } $tid = tat_archive_main_query_category_term_id($query); if ($tid === 3 || $tid === 5) { return $posts; } return tat_catalog_shuffle_posts_array_if_first_page($posts, 1); } add_filter('posts_results', 'tat_archive_shuffle_posts_results_first_page_only', 10, 2); /** Имена полей CFS / post_meta для фильтра каталога (для data-атрибутов и т.п.) */ function tat_catalog_filter_meta_keys() { return array('vozrast', 'grud', 'rost', 'ves'); } /** * Разбор строки фильтра для одного поля CFS (rost / ves / vozrast): одно число или диапазон. * Примеры: "175", "165-180", "170-", "-60". * * @return array{min: ?int, max: ?int}|null */ function tat_parse_catalog_numeric_range($raw) { $raw = trim((string) $raw); if ($raw === '') { return null; } // Тире из подсказок (en/em в UTF-8) → ASCII-минус для preg_match $raw = str_replace(array("\xe2\x80\x93", "\xe2\x80\x94"), '-', $raw); if (preg_match('/^(\d+)\s*-\s*(\d+)$/', $raw, $m)) { $a = (int) $m[1]; $b = (int) $m[2]; if ($a > $b) { $t = $a; $a = $b; $b = $t; } return array('min' => $a, 'max' => $b); } if (preg_match('/^(\d+)\s*-\s*$/', $raw, $m)) { return array('min' => (int) $m[1], 'max' => null); } if (preg_match('/^-\s*(\d+)$/', $raw, $m)) { return array('min' => null, 'max' => (int) $m[1]); } if (preg_match('/^(\d+)$/', $raw, $m)) { $n = (int) $m[1]; return array('min' => $n, 'max' => $n); } return null; } /** * Условие meta_query по числовому значению в postmeta (CFS). * * @param array{min: ?int, max: ?int} $range * @return array<string, mixed>|null */ function tat_meta_clause_for_cfs_range($meta_key, $range) { $min = $range['min']; $max = $range['max']; if ($min !== null && $max !== null) { return array( 'key' => $meta_key, 'value' => array($min, $max), 'compare' => 'BETWEEN', 'type' => 'NUMERIC', ); } if ($min !== null) { return array( 'key' => $meta_key, 'value' => $min, 'compare' => '>=', 'type' => 'NUMERIC', ); } if ($max !== null) { return array( 'key' => $meta_key, 'value' => $max, 'compare' => '<=', 'type' => 'NUMERIC', ); } return null; } /** * Числовой фильтр по полю CFS: AND (meta_value ~ цифры) + CAST-условие. * Без этого пустые/мусорные значения дают CAST AS SIGNED = 0 и проходят «<= N» / верхнюю границу BETWEEN. * * @param array{min: ?int, max: ?int} $range * @return array<string, mixed>|null */ function tat_meta_clause_group_for_cfs_numeric_field($meta_key, $range) { $numeric = tat_meta_clause_for_cfs_range($meta_key, $range); if ($numeric === null) { return null; } return array( 'relation' => 'AND', array( 'key' => $meta_key, 'value' => '^[[:space:]]*[0-9]', 'compare' => 'REGEXP', ), $numeric, ); } /** * Условия meta_query по параметрам каталога (rost, ves, vozrast, grud). * * @param array<string, string> $params * @return array<int, array<string, mixed>> */ function tat_collect_catalog_filter_meta_clauses(array $params) { $clauses = array(); foreach (array('rost', 'ves', 'vozrast') as $param) { if (!isset($params[$param]) || $params[$param] === '') { continue; } $raw = trim((string) $params[$param]); $range = null; // Возраст: одно целое «20» = до 20 включительно (как ожидают в каталоге). Ровно 20 — «20-20» или «20–20». if ($param === 'vozrast' && preg_match('/^\d+$/', $raw)) { $range = array('min' => null, 'max' => (int) $raw); } else { $range = tat_parse_catalog_numeric_range($raw); } if ($range === null) { continue; } $clause = tat_meta_clause_group_for_cfs_numeric_field($param, $range); if ($clause !== null) { $clauses[] = $clause; } } if (isset($params['grud']) && $params['grud'] !== '') { $grud = (string) $params['grud']; if (preg_match('/^[1-5]$/', $grud)) { $clauses[] = array( 'key' => 'grud', 'value' => (int) $grud, 'compare' => '=', 'type' => 'NUMERIC', ); } } return $clauses; } /** * Валидные параметры фильтра из массива (обычно $_GET или $_POST). * * @param array<string, mixed> $src * @return array<string, string> */ function tat_get_catalog_filter_args_from_source($src) { if (!is_array($src)) { return array(); } $out = array(); foreach (array('rost', 'ves', 'vozrast') as $key) { if (!isset($src[$key]) || $src[$key] === '') { continue; } $raw = is_string($src[$key]) ? wp_unslash($src[$key]) : ''; if (tat_parse_catalog_numeric_range($raw) !== null) { $out[$key] = preg_replace('/\s+/', ' ', trim($raw)); } } if (isset($src['grud']) && $src['grud'] !== '') { $g = is_string($src['grud']) ? wp_unslash($src['grud']) : ''; if (preg_match('/^[1-5]$/', $g)) { $out['grud'] = $g; } } return $out; } /** * GET-параметры фильтра для пагинации и ссылок (как tat_get_catalog_filter_query_args в референсе). * Дублируем разбор строки запроса URL: на части хостингов при /page/N/ $_GET по фильтрам бывает пустым. */ function tat_get_catalog_filter_query_args() { $from_get = tat_get_catalog_filter_args_from_source($_GET); if (!empty($from_get)) { return $from_get; } if (!empty($_SERVER['REQUEST_URI'])) { $qstr = wp_parse_url((string) $_SERVER['REQUEST_URI'], PHP_URL_QUERY); if (is_string($qstr) && $qstr !== '') { parse_str($qstr, $parsed); if (is_array($parsed)) { $from_uri = tat_get_catalog_filter_args_from_source($parsed); if (!empty($from_uri)) { return $from_uri; } } } } return array(); } function tat_catalog_filter_from_request() { return tat_get_catalog_filter_query_args(); } function tat_catalog_filter_from_post() { return tat_get_catalog_filter_args_from_source($_POST); } function tat_catalog_filter_query_args_for_links() { return tat_get_catalog_filter_query_args(); } /** * Номер страницы для шаблонов каталога (архив категории + /page/N/). * Учитывает и paged, и page — на части конфигураций пагинация попадает в page. */ function tat_catalog_current_paged() { $p = (int) get_query_var('paged'); if ($p < 1) { $p = (int) get_query_var('page'); } return max(1, $p); } /** * База URL для paginate_links с плейсхолдером %#% — без этого add_args (фильтры) * часто теряются при переходе на /page/N/ при кастомном WP_Query. * * @return string Пустая строка, если построить базу не удалось — тогда используются дефолты ядра. */ function tat_catalog_paginate_links_base() { $big = 999999999; $link = get_pagenum_link($big, false); if (!is_string($link) || $link === '') { return ''; } $base = str_replace((string) $big, '%#%', esc_url($link)); return strpos($base, '%#%') !== false ? $base : ''; } function tat_build_catalog_meta_query($filters) { if (empty($filters) || !is_array($filters)) { return array(); } $params = array( 'rost' => isset($filters['rost']) ? (string) $filters['rost'] : '', 'ves' => isset($filters['ves']) ? (string) $filters['ves'] : '', 'vozrast' => isset($filters['vozrast']) ? (string) $filters['vozrast'] : '', 'grud' => isset($filters['grud']) ? (string) $filters['grud'] : '', ); $clauses = tat_collect_catalog_filter_meta_clauses($params); if (empty($clauses)) { return array(); } return array_merge(array('relation' => 'AND'), $clauses); } /** * ID терминов категории (родитель + дочерние), как у WP при cat=ID. * * @return int[] */ function tat_catalog_category_term_ids_including_children($parent_term_id) { $parent_term_id = (int) $parent_term_id; if ($parent_term_id < 1) { return array(); } $ids = array($parent_term_id); $children = get_term_children($parent_term_id, 'category'); if (!is_wp_error($children) && !empty($children)) { foreach ((array) $children as $tid) { $ids[] = (int) $tid; } } return array_values(array_unique(array_filter($ids))); } /** * Разобранные числовые диапазоны по полям (логика как в tat_collect_catalog_filter_meta_clauses). * * @param array<string, string> $filters * @return array<string, array{min: ?int, max: ?int}> */ function tat_catalog_parsed_numeric_ranges(array $filters) { $params = array( 'rost' => isset($filters['rost']) ? trim((string) $filters['rost']) : '', 'ves' => isset($filters['ves']) ? trim((string) $filters['ves']) : '', 'vozrast' => isset($filters['vozrast']) ? trim((string) $filters['vozrast']) : '', ); $out = array(); foreach (array('rost', 'ves', 'vozrast') as $param) { if ($params[$param] === '') { continue; } $raw = $params[$param]; $range = null; if ($param === 'vozrast' && preg_match('/^\d+$/', $raw)) { $range = array('min' => null, 'max' => (int) $raw); } else { $range = tat_parse_catalog_numeric_range($raw); } if ($range !== null) { $out[$param] = $range; } } return $out; } /** * @param array<string, string> $filters * @return int|null 1–5 */ function tat_catalog_parsed_grud(array $filters) { if (!isset($filters['grud']) || $filters['grud'] === '') { return null; } $g = is_string($filters['grud']) ? wp_unslash($filters['grud']) : ''; if (preg_match('/^[1-5]$/', (string) $g)) { return (int) $g; } return null; } /** * @param array<string, array{min: ?int, max: ?int}> $range */ function tat_catalog_sql_post_id_in_numeric_meta($meta_key, array $range) { global $wpdb; $allowed = array('rost', 'ves', 'vozrast'); if (!in_array($meta_key, $allowed, true)) { return ''; } $min = $range['min']; $max = $range['max']; $base = "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = %s GROUP BY post_id HAVING "; if ($min !== null && $max !== null) { $inner = $wpdb->prepare($base . 'MIN(CAST(meta_value AS SIGNED)) >= %d AND MAX(CAST(meta_value AS SIGNED)) <= %d', $meta_key, $min, $max); } elseif ($min !== null) { $inner = $wpdb->prepare($base . 'MIN(CAST(meta_value AS SIGNED)) >= %d', $meta_key, $min); } elseif ($max !== null) { $floor = 1; $inner = $wpdb->prepare($base . 'MAX(CAST(meta_value AS SIGNED)) <= %d AND MAX(CAST(meta_value AS SIGNED)) >= %d', $meta_key, $max, $floor); } else { return ''; } return 'p.ID IN (' . $inner . ')'; } /** * @return string фрагмент вида p.ID IN (...) */ function tat_catalog_sql_post_id_in_grud($grud) { global $wpdb; $grud = (int) $grud; if ($grud < 1 || $grud > 5) { return ''; } $inner = $wpdb->prepare( "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = %s GROUP BY post_id HAVING MAX(CAST(meta_value AS SIGNED)) = %d", 'grud', $grud ); return 'p.ID IN (' . $inner . ')'; } /** * Нужен ли точный SQL-фильтр (агрегация по post_id), а не meta_query. * * @param array<string, string> $filters */ function tat_catalog_needs_sql_filter(array $filters) { return !empty(tat_catalog_parsed_numeric_ranges($filters)) || tat_catalog_parsed_grud($filters) !== null; } /** * Базовые аргументы WP_Query для каталога (без meta_query). * * @return array<string, mixed> */ function tat_catalog_base_wp_query_args($cat_id, $paged) { return array( 'post_type' => 'post', 'posts_per_page' => tat_catalog_posts_per_page(), 'paged' => max(1, (int) $paged), 'orderby' => 'date', 'order' => 'DESC', 'post_status' => 'publish', 'cat' => (int) $cat_id, ); } /** * Каталог с фильтрами: один WP_Query на страницу, пагинация и found_posts согласованы. * При активных фильтрах — выборка ID через SQL (MAX/MIN по всем строкам postmeta с ключом), * чтобы не ловить ложные совпадения из дублей meta и CAST('' AS SIGNED)=0. * * @param int $cat_id 3 или 5 * @param int $paged * @param array<string, string>|null $filters */ function tat_catalog_run_filtered_wp_query($cat_id, $paged, $filters = null) { global $wpdb; if ($filters === null) { $filters = tat_catalog_filter_from_request(); } $paged = max(1, (int) $paged); $per = tat_catalog_posts_per_page(); if (!tat_catalog_needs_sql_filter($filters)) { $args = tat_catalog_base_wp_query_args($cat_id, $paged); $mq = tat_build_catalog_meta_query($filters); if (!empty($mq)) { $args['meta_query'] = $mq; } $q = new WP_Query($args); $q->posts = tat_catalog_shuffle_posts_array_if_first_page($q->posts, $paged); return $q; } $parsed = tat_catalog_parsed_numeric_ranges($filters); $grud = tat_catalog_parsed_grud($filters); $term_ids = tat_catalog_category_term_ids_including_children((int) $cat_id); if (empty($term_ids)) { $q = new WP_Query(array('post__in' => array(0), 'post_type' => 'post', 'post_status' => 'publish')); $q->found_posts = 0; $q->max_num_pages = 0; return $q; } $in_list = implode(',', array_map('intval', $term_ids)); $parts = array(); foreach ($parsed as $meta_key => $range) { $frag = tat_catalog_sql_post_id_in_numeric_meta($meta_key, $range); if ($frag !== '') { $parts[] = $frag; } } if ($grud !== null) { $frag = tat_catalog_sql_post_id_in_grud($grud); if ($frag !== '') { $parts[] = $frag; } } if (empty($parts)) { $q = new WP_Query(tat_catalog_base_wp_query_args($cat_id, $paged)); $q->posts = tat_catalog_shuffle_posts_array_if_first_page($q->posts, $paged); return $q; } $where_meta = implode(' AND ', $parts); $count_sql = " SELECT COUNT(DISTINCT p.ID) FROM {$wpdb->posts} p INNER JOIN {$wpdb->term_relationships} tr ON (p.ID = tr.object_id) INNER JOIN {$wpdb->term_taxonomy} tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id AND tt.taxonomy = 'category' AND tt.term_id IN ({$in_list})) WHERE p.post_type = 'post' AND p.post_status = 'publish' AND {$where_meta} "; $total = (int) $wpdb->get_var($count_sql); if ($total < 1) { $q = new WP_Query(array('post__in' => array(0), 'post_type' => 'post', 'post_status' => 'publish')); $q->found_posts = 0; $q->max_num_pages = 0; return $q; } $offset = ($paged - 1) * $per; $ids_sql = " SELECT DISTINCT p.ID FROM {$wpdb->posts} p INNER JOIN {$wpdb->term_relationships} tr ON (p.ID = tr.object_id) INNER JOIN {$wpdb->term_taxonomy} tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id AND tt.taxonomy = 'category' AND tt.term_id IN ({$in_list})) WHERE p.post_type = 'post' AND p.post_status = 'publish' AND {$where_meta} ORDER BY p.post_date DESC LIMIT %d OFFSET %d "; $ids_sql = $wpdb->prepare($ids_sql, $per, $offset); $ids = array_map('intval', (array) $wpdb->get_col($ids_sql)); $ids = tat_catalog_shuffle_post_ids_if_first_page($ids, $paged); if (empty($ids)) { $q = new WP_Query(array('post__in' => array(0), 'post_type' => 'post', 'post_status' => 'publish')); $q->found_posts = $total; $q->max_num_pages = (int) max(1, ceil($total / $per)); return $q; } $q = new WP_Query(array( 'post_type' => 'post', 'post_status' => 'publish', 'post__in' => $ids, 'orderby' => 'post__in', 'posts_per_page' => count($ids), 'ignore_sticky_posts' => true, )); $q->found_posts = $total; $q->max_num_pages = (int) max(1, ceil($total / $per)); return $q; } /** * HTML панели фильтра (категории 3 / 5). Логика полей — как в референсе (число / диапазон, грудь радио). */ function tat_catalog_render_filter_panel($parent_cat_id) { $parent_cat_id = (int) $parent_cat_id; if ($parent_cat_id < 1) { return; } $catalog_filter_action = esc_url(get_category_link($parent_cat_id)); $gf = static function ($key) { return isset($_GET[$key]) ? sanitize_text_field(wp_unslash($_GET[$key])) : ''; }; $v_rost = $gf('rost'); $v_ves = $gf('ves'); $v_vozrast = $gf('vozrast'); $v_grud = $gf('grud'); $catalog_filters_active = count(tat_get_catalog_filter_query_args()) > 0; $reset_url = get_category_link($parent_cat_id); $toggle_class = 'btn btn-outline-dark btn-sm catalog-filter-toggle'; if ($catalog_filters_active) { $toggle_class .= ' catalog-filter-toggle--active'; } ?> <div class="catalog-toolbar__filter"> <button type="button" class="<? echo esc_attr($toggle_class); ?>" data-catalog-filter-toggle aria-expanded="false" aria-controls="catalog-filter-panel-<? echo (int) $parent_cat_id; ?>"> Фильтр </button> <div class="catalog-filter-panel" id="catalog-filter-panel-<? echo (int) $parent_cat_id; ?>" data-catalog-filter-panel role="dialog" aria-label="Фильтр анкет" aria-labelledby="catalog-filter-heading-<? echo (int) $parent_cat_id; ?>"> <div class="catalog-filter-panel__head"> <h3 class="catalog-filter-panel__title" id="catalog-filter-heading-<? echo (int) $parent_cat_id; ?>">Фильтр анкет</h3> <button type="button" class="catalog-filter-panel__close" aria-label="Закрыть" data-catalog-filter-close>×</button> </div> <form class="catalog-filter-panel__form" method="get" action="<? echo esc_url($catalog_filter_action); ?>"> <div class="catalog-filter-panel__group"> <div class="catalog-filter-panel__label">Рост, см</div> <p class="catalog-filter-panel__help">Число или диапазон, например 175 или 165–180</p> <label class="catalog-filter-panel__field catalog-filter-panel__field--block"> <input class="catalog-filter-panel__input" type="text" name="rost" inputmode="decimal" autocomplete="off" placeholder="например 170 или 168–175" value="<? echo esc_attr($v_rost); ?>"> </label> </div> <div class="catalog-filter-panel__group"> <div class="catalog-filter-panel__label">Вес, кг</div> <p class="catalog-filter-panel__help">Число или диапазон, например 55 или 50–60</p> <label class="catalog-filter-panel__field catalog-filter-panel__field--block"> <input class="catalog-filter-panel__input" type="text" name="ves" inputmode="decimal" autocomplete="off" placeholder="например 52 или 48–55" value="<? echo esc_attr($v_ves); ?>"> </label> </div> <div class="catalog-filter-panel__group"> <div class="catalog-filter-panel__label">Возраст, лет</div> <p class="catalog-filter-panel__help">До N лет — одно число (например 20). Диапазон — 20–25. Ровно 25 — 25–25</p> <label class="catalog-filter-panel__field catalog-filter-panel__field--block"> <input class="catalog-filter-panel__input" type="text" name="vozrast" inputmode="numeric" autocomplete="off" placeholder="например 25 или 22–28" value="<? echo esc_attr($v_vozrast); ?>"> </label> </div> <div class="catalog-filter-panel__group catalog-filter-panel__group--grud"> <div class="catalog-filter-panel__label">Грудь</div> <div class="catalog-filter-panel__radios"> <label class="catalog-filter-panel__radio"> <input type="radio" name="grud" value="" <? echo $v_grud === '' ? ' checked' : ''; ?>> <span>Добавить все</span> </label> <? for ($g = 1; $g <= 5; $g++) { $gs = (string) $g; ?> <label class="catalog-filter-panel__radio"> <input type="radio" name="grud" value="<? echo (int) $g; ?>" <? echo $v_grud === $gs ? ' checked' : ''; ?>> <span><? echo (int) $g; ?></span> </label> <? } ?> </div> </div> <div class="catalog-filter-panel__actions"> <button type="submit" class="btn btn-primary btn-sm">Применить</button> <a class="btn btn-outline-secondary btn-sm" href="<? echo esc_url($reset_url); ?>">Сбросить</a> </div> </form> </div> </div> <? } /** * Атрибуты data-filter-* для кнопки «Показать ещё». */ function tat_catalog_print_load_more_filter_data_attrs() { $fl = tat_get_catalog_filter_query_args(); foreach (tat_catalog_filter_meta_keys() as $k) { if (!empty($fl[$k])) { echo ' data-filter-' . esc_attr($k) . '="' . esc_attr($fl[$k]) . '"'; } } } function tat_category3_catalog_query_args($paged, $filters = null) { $paged = max(1, (int) $paged); if ($filters === null) { $filters = tat_catalog_filter_from_request(); } $args = tat_catalog_base_wp_query_args(3, $paged); $mq = tat_build_catalog_meta_query($filters); if (!empty($mq)) { $args['meta_query'] = $mq; } return $args; } function tat_category3_catalog_cards_html(WP_Query $category_posts) { if (!$category_posts->have_posts()) { return ''; } ob_start(); while ($category_posts->have_posts()) { $category_posts->the_post(); get_template_part('template-parts/catalog-card'); } wp_reset_postdata(); return ob_get_clean(); } function tat_ajax_cat3_load_more() { check_ajax_referer('tat_cat3_catalog', 'nonce'); $page = isset($_POST['page']) ? (int) $_POST['page'] : 1; if ($page < 1) { $page = 1; } $filters = tat_catalog_filter_from_post(); $q = tat_catalog_run_filtered_wp_query(3, $page, $filters); $html = tat_category3_catalog_cards_html($q); $max = (int) $q->max_num_pages; $has_more = $page < $max; wp_send_json_success(array( 'html' => $html, 'hasMore' => $has_more, 'nextPage' => $has_more ? $page + 1 : null, )); } add_action('wp_ajax_tat_cat3_load_more', 'tat_ajax_cat3_load_more'); add_action('wp_ajax_nopriv_tat_cat3_load_more', 'tat_ajax_cat3_load_more'); function tat_category5_catalog_query_args($paged, $filters = null) { $paged = max(1, (int) $paged); if ($filters === null) { $filters = tat_catalog_filter_from_request(); } $args = tat_catalog_base_wp_query_args(5, $paged); $mq = tat_build_catalog_meta_query($filters); if (!empty($mq)) { $args['meta_query'] = $mq; } return $args; } function tat_category5_catalog_cards_html(WP_Query $category_posts) { if (!$category_posts->have_posts()) { return ''; } ob_start(); while ($category_posts->have_posts()) { $category_posts->the_post(); get_template_part('template-parts/catalog-card'); } wp_reset_postdata(); return ob_get_clean(); } function tat_ajax_cat5_load_more() { check_ajax_referer('tat_cat5_catalog', 'nonce'); $page = isset($_POST['page']) ? (int) $_POST['page'] : 1; if ($page < 1) { $page = 1; } $filters = tat_catalog_filter_from_post(); $q = tat_catalog_run_filtered_wp_query(5, $page, $filters); $html = tat_category5_catalog_cards_html($q); $max = (int) $q->max_num_pages; $has_more = $page < $max; wp_send_json_success(array( 'html' => $html, 'hasMore' => $has_more, 'nextPage' => $has_more ? $page + 1 : null, )); } add_action('wp_ajax_tat_cat5_load_more', 'tat_ajax_cat5_load_more'); add_action('wp_ajax_nopriv_tat_cat5_load_more', 'tat_ajax_cat5_load_more'); /** * Nonce для подгрузки анкет в archive.php (универсальный архив категории). * * @param int $cat_id ID термина категории (корень выборки для WP_Query cat=) */ function tat_catalog_archive_load_more_nonce_action($cat_id) { return 'tat_catalog_archive_' . (int) $cat_id; } /** * HTML карточек каталога из результата WP_Query (общий для AJAX). */ function tat_catalog_cards_html_from_query(WP_Query $category_posts) { if (!$category_posts->have_posts()) { return ''; } ob_start(); while ($category_posts->have_posts()) { $category_posts->the_post(); get_template_part('template-parts/catalog-card'); } wp_reset_postdata(); return ob_get_clean(); } /** * Подгрузка анкет для archive.php: cat_id передаётся из шаблона (текущая категория архива). */ function tat_ajax_catalog_archive_load_more() { $cat_id = isset($_POST['cat_id']) ? (int) $_POST['cat_id'] : 0; if ($cat_id < 1) { wp_send_json_error(array('message' => 'bad cat'), 400); } $term = get_term($cat_id, 'category'); if (!$term || is_wp_error($term)) { wp_send_json_error(array('message' => 'not found'), 404); } check_ajax_referer(tat_catalog_archive_load_more_nonce_action($cat_id), 'nonce'); $page = isset($_POST['page']) ? (int) $_POST['page'] : 1; if ($page < 1) { $page = 1; } $filters = tat_catalog_filter_from_post(); $q = tat_catalog_run_filtered_wp_query($cat_id, $page, $filters); $html = tat_catalog_cards_html_from_query($q); $max = (int) $q->max_num_pages; $has_more = $page < $max; wp_send_json_success(array( 'html' => $html, 'hasMore' => $has_more, 'nextPage' => $has_more ? $page + 1 : null, )); } add_action('wp_ajax_tat_catalog_archive_load_more', 'tat_ajax_catalog_archive_load_more'); add_action('wp_ajax_nopriv_tat_catalog_archive_load_more', 'tat_ajax_catalog_archive_load_more'); /** * Похожие анкеты на странице single: HTML карточек для AJAX. */ function tat_related_catalog_cards_html(WP_Query $q) { if (!$q->have_posts()) { return ''; } ob_start(); while ($q->have_posts()) { $q->the_post(); get_template_part('template-parts/catalog-card'); } wp_reset_postdata(); return ob_get_clean(); } function tat_ajax_related_load_more() { check_ajax_referer('tat_related_catalog', 'nonce'); $post_id = isset($_POST['post_id']) ? (int) $_POST['post_id'] : 0; if ($post_id < 1 || get_post_status($post_id) !== 'publish') { wp_send_json_error(array('message' => 'invalid post')); } $exclude = array($post_id); if (!empty($_POST['exclude'])) { $raw = sanitize_text_field(wp_unslash($_POST['exclude'])); foreach (explode(',', $raw) as $part) { $eid = (int) trim($part); if ($eid > 0) { $exclude[] = $eid; } } $exclude = array_values(array_unique($exclude)); } $cats = wp_get_post_categories($post_id); if (empty($cats)) { wp_send_json_success(array( 'html' => '', 'hasMore' => false, 'newIds' => array(), )); } $per_page = 4; $q = new WP_Query(array( 'post_type' => 'post', 'post_status' => 'publish', 'posts_per_page' => $per_page, 'post__not_in' => $exclude, 'orderby' => 'rand', 'category__in' => $cats, )); $new_ids = array_map('intval', wp_list_pluck($q->posts, 'ID')); $html = tat_related_catalog_cards_html($q); $has_more = ((int) $q->found_posts > (int) $q->post_count); wp_send_json_success(array( 'html' => $html, 'hasMore' => $has_more, 'newIds' => $new_ids, )); } add_action('wp_ajax_tat_related_load_more', 'tat_ajax_related_load_more'); add_action('wp_ajax_nopriv_tat_related_load_more', 'tat_ajax_related_load_more'); /** * SEO Title / Description для /worksheet */ function tat_is_worksheet_page() { return is_page('worksheet') || is_page(81); } add_filter('wpseo_title', function ($title) { if (tat_is_worksheet_page()) { return 'Работа в эскорт агентстве Archer | Элитное сопровождение'; } return $title; }); add_filter('wpseo_metadesc', function ($desc) { if (tat_is_worksheet_page()) { return 'Получите работу вашей мечты уже сегодня. Реализуйте свои таланты вместе с эскорт агентством VIP-уровня Archer'; } return $desc; }); add_filter('pre_get_document_title', function ($title) { if (tat_is_worksheet_page()) { return 'Работа в эскорт агентстве Archer | Элитное сопровождение'; } return $title; }, 20); /* Конец файла functions.php */ <!DOCTYPE html> <html <? language_attributes(); ?>> <head> <meta charset="<? bloginfo('charset'); ?>"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <meta name="yandex-verification" content="59c7cb1a7e6108c0" /> <!-- Yandex.Metrika counter --> <script type="text/javascript"> (function (m, e, t, r, i, k, a) { m[i] = m[i] || function () { (m[i].a = m[i].a || []).push(arguments) }; m[i].l = 1 * new Date(); for (var j = 0; j < document.scripts.length; j++) { if (document.scripts[j].src === r) { return; } } k = e.createElement(t), a = e.getElementsByTagName(t)[0], k.async = 1, k.src = r, a.parentNode.insertBefore(k, a) }) (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym"); ym(98973328, "init", { clickmap: true, trackLinks: true, accurateTrackBounce: true, webvisor: true }); </script> <noscript> <div><img src="https://mc.yandex.ru/watch/98973328" style="position:absolute; left:-9999px;" alt="" /></div> </noscript> <!-- /Yandex.Metrika counter --> <meta name="keywords" content="Экскорт агентство Сочи"> <meta name="theme-color" content="#202020"> <? wp_head(); ?> <!-- reCaptcha v3 --> <script src="https://www.google.com/recaptcha/api.js?render=6LeN04krAAAAALPkZa443UZEMOoAhgbKDENkHvMs"></script> <script> grecaptcha.ready(function () { document.querySelectorAll('form').forEach(function (form) { grecaptcha.execute('6LeN04krAAAAALPkZa443UZEMOoAhgbKDENkHvMs', { action: 'submit' }).then(function (token) { form.querySelector('.g-recaptcha-response').value = token; }); }); }); </script> </head> <body <? body_class(); ?>> <header class="header fixed-top"> <div class="container"> <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <button id="btn-open-menu" class="burger-btn burger-btn--open" type="button" aria-label="Переключатель навигации"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none"> <path d="M2.5 4.375C2.5 4.02982 2.70987 3.75 2.96875 3.75H17.0312C17.2901 3.75 17.5 4.02982 17.5 4.375C17.5 4.72018 17.2901 5 17.0312 5H2.96875C2.70987 5 2.5 4.72018 2.5 4.375Z" fill="#E0E0E0" /> <path d="M2.5 10C2.5 9.65482 2.70987 9.375 2.96875 9.375H17.0312C17.2901 9.375 17.5 9.65482 17.5 10C17.5 10.3452 17.2901 10.625 17.0312 10.625H2.96875C2.70987 10.625 2.5 10.3452 2.5 10Z" fill="#E0E0E0" /> <path d="M2.5 15.625C2.5 15.2798 2.70987 15 2.96875 15H17.0312C17.2901 15 17.5 15.2798 17.5 15.625C17.5 15.9702 17.2901 16.25 17.0312 16.25H2.96875C2.70987 16.25 2.5 15.9702 2.5 15.625Z" fill="#E0E0E0" /> </svg> </button> <a class="navbar-brand" href="/" title="Archer — Элитное экскорт-агентство в Сочи"> <img src="/wp-content/themes/archer/images/icons/logo.svg" alt="Archer — Элитное экскорт-агентство в Сочи"> </a> <div class="collapse navbar-collapse"> <ul class="navbar-nav"> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="/modeli" id="navbarDropdown-1" role="button" aria-haspopup="true" aria-expanded="false"> Анкеты моделей </a> <div class="dropdown-menu" aria-labelledby="navbarDropdown-1"> <? $args = [ 'taxonomy' => 'category', // стандартная таксономия WordPress 'parent' => 3, // ID рубрики, подкатегории которой нужно вывести 'hide_empty' => false, // показывать даже пустые рубрики 'orderby' => 'name', 'order' => 'ASC' ]; $subcategories = get_categories($args); ?> <? if (!empty($subcategories)): ?> <? foreach ($subcategories as $cat): ?> <a class="dropdown-item" href=""> </a> <? endforeach; ?> <? endif; ?> </div> </li> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="/services" id="navbarDropdown-2" role="button" aria-haspopup="true" aria-expanded="false"> Услуги </a> <div class="dropdown-menu" aria-labelledby="navbarDropdown-2"> <? $args = [ 'taxonomy' => 'category', // стандартная таксономия WordPress 'parent' => 5, // ID рубрики, подкатегории которой нужно вывести 'hide_empty' => false, // показывать даже пустые рубрики 'orderby' => 'name', 'order' => 'ASC' ]; $subcategories = get_categories($args); ?> <? if (!empty($subcategories)): ?> <? foreach ($subcategories as $cat): ?> <a class="dropdown-item" href=""> </a> <? endforeach; ?> <? endif; ?> </div> </li> <li class="nav-item"> <a class="nav-link" href="/price">Цены</a> </li> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="/about" id="navbarDropdown-info" role="button" aria-haspopup="true" aria-expanded="false"> Информация </a> <div class="dropdown-menu" aria-labelledby="navbarDropdown-info"> <a class="dropdown-item" href="/about">О нас</a> <a class="dropdown-item" href="/how-it-works">Как это работает</a> <a class="dropdown-item" href="/faq">Вопросы и ответы</a> <a class="dropdown-item" href="/contacts">Контакты</a> <a class="dropdown-item" href="/privacy">Конфиденциальность</a> </div> </li> <li class="nav-item"> <a class="nav-link nav-link--btn" href="/worksheet">Заполнить анкету</a> </li> </ul> </div> <div class="navbar-socials"> <a href="https://api.whatsapp.com/send?phone=+995571214362&text=Здравствуйте,%20перезвоните%20мне&type=phone_number&app_absent=0" class="social-link"> <svg width="24" height="24" viewBox="0 0 34 34"> <g clip-path="url(#clip0_596_7499)"> <path d="M17 0C7.62592 0 0 7.62592 0 17C0 26.3741 7.62592 34 17 34C26.3741 34 34 26.3741 34 17C34 7.62592 26.3741 0 17 0ZM25.0254 23.4982L24.2859 24.3482C23.5053 25.1302 22.4768 25.5 21.4526 25.5C16.1911 25.5 8.5 18.2141 8.5 12.5474C8.5 11.5232 8.86975 10.4947 9.65175 9.71408L10.5017 8.97458C11.1336 8.34275 12.1593 8.34275 12.7911 8.97458L14.2078 10.8191C14.8396 11.4509 14.8396 12.4766 14.2078 13.1084L13.0022 14.6228C14.2786 17.8018 16.4433 19.8787 19.3772 20.9978L20.8916 19.7922C21.5234 19.1604 22.5491 19.1604 23.1809 19.7922L25.0254 21.2089C25.6573 21.8407 25.6573 22.8664 25.0254 23.4982Z" fill="currentColor"></path> </g> <defs> <clipPath id="clip0_596_7499"> <rect width="34" height="34" fill="white"></rect> </clipPath> </defs> </svg> </a> <a href="tg://resolve?domain=Giraffe_14" class="social-link" role="button" aria-pressed="true" title="Написать в Telegram"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"> <path fill-rule="evenodd" clip-rule="evenodd" d="M12 24C5.37258 24 0 18.6274 0 12C0 5.37258 5.37258 0 12 0C18.6274 0 24 5.37258 24 12C24 18.6274 18.6274 24 12 24ZM12.5189 9.00553C11.4441 9.45256 9.29616 10.3778 6.07494 11.7812C5.55186 11.9892 5.27785 12.1927 5.25291 12.3917C5.21075 12.728 5.63186 12.8604 6.2053 13.0407C6.28331 13.0652 6.36413 13.0906 6.44699 13.1176C7.01117 13.301 7.77009 13.5155 8.16462 13.524C8.5225 13.5318 8.92193 13.3842 9.36292 13.0814C12.3726 11.0498 13.9262 10.0229 14.0238 10.0008C14.0926 9.98516 14.1879 9.96553 14.2525 10.023C14.3171 10.0804 14.3108 10.1891 14.3039 10.2183C14.2622 10.3962 12.6092 11.9329 11.7538 12.7282C11.4871 12.9762 11.2979 13.152 11.2593 13.1922C11.1726 13.2822 11.0844 13.3673 10.9995 13.4491C10.4754 13.9543 10.0823 14.3332 11.0213 14.952C11.4725 15.2494 11.8336 15.4952 12.1938 15.7405C12.5872 16.0084 12.9795 16.2757 13.4872 16.6084C13.6165 16.6932 13.7401 16.7813 13.8604 16.8671C14.3182 17.1934 14.7295 17.4867 15.2376 17.4399C15.5329 17.4127 15.8379 17.1351 15.9928 16.307C16.3588 14.3501 17.0784 10.1101 17.2447 8.36285C17.2592 8.20977 17.2409 8.01386 17.2262 7.92786C17.2115 7.84186 17.1807 7.71932 17.0689 7.62862C16.9365 7.52119 16.7322 7.49854 16.6407 7.50007C16.2251 7.50747 15.5875 7.72919 12.5189 9.00553Z" fill="#E0E0E0"></path> </svg> </a> <a href="https://wa.me/995571214362?text=%D0%97%D0%B4%D1%80%D0%B0%D0%B2%D1%81%D1%82%D0%B2%D1%83%D0%B9%D1%82%D0%B5+Archer%21%0A%D0%9C%D0%B5%D0%BD%D1%8F+%D0%B7%D0%BE%D0%B2%D1%83%D1%82+...%0A%D0%9C%D0%BD%D0%B5+...+%D0%9B%D0%B5%D1%82%0A%D0%A5%D0%BE%D1%87%D1%83+%D0%B2%D1%81%D1%82%D1%80%D0%B5%D1%82%D0%B8%D1%82%D1%8C%D1%81%D1%8F+%D1%81+%D0%B4%D0%B5%D0%B2%D1%83%D1%88%D0%BA%D0%BE%D0%B9+%D0%B2+%D0%B3%D0%BE%D1%80%D0%BE%D0%B4%D0%B5+...%0A%D0%92+%D0%BE%D1%82%D0%B5%D0%BB%D0%B5+..." class="social-link" role="button" aria-pressed="true" title="Написать в WhatsApp"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none"> <path fill-rule="evenodd" clip-rule="evenodd" d="M0 12C0 5.37258 5.37258 0 12 0C18.6274 0 24 5.37258 24 12C24 18.6274 18.6274 24 12 24C5.37258 24 0 18.6274 0 12ZM12 6C13.575 6 15.075 6.6 16.2 7.725C17.325 8.85 18 10.35 18 11.925C18 15.225 15.3 17.925 12 17.925C11.025 17.925 10.05 17.625 9.15001 17.175L6 18L6.825 15C6.30001 14.1 6 13.05 6 12C6 8.7 8.7 6 12 6Z" fill="currentColor"></path> <path d="M13.65 12.75C13.8 12.75 14.55 13.125 14.7 13.2C14.7234 13.2117 14.7467 13.2215 14.7698 13.2313C14.8949 13.2841 15.0117 13.3334 15.075 13.65C15.15 13.65 15.15 13.95 15 14.325C14.925 14.625 14.325 15 14.025 15C13.9742 15 13.9255 15.0043 13.8735 15.0089C13.6186 15.0314 13.284 15.0611 12.225 14.625C10.9106 14.0993 9.99938 12.8249 9.74349 12.4671C9.70735 12.4165 9.68428 12.3843 9.675 12.375C9.66222 12.3495 9.63641 12.3087 9.60236 12.2549C9.43644 11.993 9.075 11.4223 9.075 10.8C9.075 10.05 9.44999 9.675 9.59999 9.525C9.74999 9.375 9.89999 9.375 9.97499 9.375H10.275C10.35 9.375 10.5 9.375 10.575 9.6C10.725 9.9 11.025 10.65 11.025 10.725C11.025 10.75 11.0333 10.775 11.0417 10.8C11.0583 10.85 11.075 10.9 11.025 10.95C10.9875 10.9875 10.9688 11.025 10.95 11.0625C10.9313 11.1 10.9125 11.1375 10.875 11.175L10.65 11.4C10.575 11.475 10.5 11.55 10.575 11.7C10.65 11.85 10.95 12.375 11.4 12.75C11.9063 13.193 12.3058 13.369 12.5084 13.4582C12.5458 13.4748 12.5766 13.4883 12.6 13.5C12.75 13.5 12.825 13.5 12.9 13.425C12.9375 13.35 13.0313 13.2375 13.125 13.125C13.2187 13.0125 13.3125 12.9 13.35 12.825C13.425 12.675 13.5 12.675 13.65 12.75Z" fill="currentColor"></path> </svg> </a> </div> </nav> </div> </header> <div id="mobile-menu" class="mobile-menu"> <div class="mobile-menu__close"></div> <div class="mobile-menu__header"> <button id="btn-close-menu" class="burger-btn burger-btn--close" type="button" aria-label="Переключатель навигации"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none"> <path d="M2.68926 16.3969C2.43691 16.6492 2.43691 17.0584 2.68926 17.3107C2.94161 17.5631 3.35075 17.5631 3.6031 17.3107L9.81074 11.1031L16.3969 17.6892C16.6492 17.9416 17.0584 17.9416 17.3107 17.6892C17.5631 17.4369 17.5631 17.0278 17.3107 16.7754L10.7246 10.1892L17.3107 3.6031C17.5631 3.35075 17.5631 2.94161 17.3107 2.68926C17.0584 2.43691 16.6492 2.43691 16.3969 2.68926L9.81074 9.2754L3.60312 3.06779C3.35077 2.81544 2.94163 2.81544 2.68928 3.06779C2.43693 3.32014 2.43693 3.72928 2.68928 3.98163L8.8969 10.1892L2.68926 16.3969Z" fill="#E0E0E0" /> </svg> </button> <a class="mobile-menu__logo" href="/" title="Archer — Элитное экскорт-агентство в Сочи"> <img src="/wp-content/themes/archer/images/icons/logo.svg" alt="Archer — Элитное экскорт-агентство в Сочи"> </a> </div> <div class="mobile-menu__body"> <ul class="mobile-menu-list"> <li class="mobile-menu-list__item"> <button class="text-button open-submenu" type="button"> Анкеты моделей <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"> <path d="M14.1916 8.26218C14.4693 8.55915 14.4693 9.04065 14.1916 9.33763L9.66614 14.1772C9.38843 14.4741 8.93818 14.4741 8.66048 14.1772C8.38277 13.8802 8.38277 13.3987 8.66048 13.1017L11.972 9.56036L1.5999 9.56036V8.03944L11.972 8.03944L8.66048 4.49809C8.38277 4.20111 8.38277 3.71961 8.66048 3.42264C8.93818 3.12566 9.38843 3.12566 9.66614 3.42264L14.1916 8.26218Z" fill="#E0E0E0" /> </svg> </button> <ul class="mobile-menu-list"> <li class="mobile-menu-list__item"> <button class="text-button close-submenu" type="button"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="17" viewBox="0 0 16 17" fill="none"> <path d="M6.33367 14.6772L1.80818 9.83763C1.53048 9.54065 1.53048 9.05915 1.80818 8.76218L6.33367 3.92264C6.61137 3.62566 7.06162 3.62566 7.33933 3.92264C7.61704 4.21961 7.61704 4.70111 7.33933 4.99809L4.02779 8.53944H14.3999L14.3998 10.0604H4.02779L7.33933 13.6017C7.61704 13.8987 7.61704 14.3802 7.33933 14.6772C7.06162 14.9741 6.61137 14.9741 6.33367 14.6772Z" fill="#E0E0E0" /> </svg> Назад </button> </li> <li class="mobile-menu-list__item"> <a class="text-button" href="/modeli"> Все девушки </a> </li> <? $args = [ 'taxonomy' => 'category', // стандартная таксономия WordPress 'parent' => 3, // ID рубрики, подкатегории которой нужно вывести 'hide_empty' => false, // показывать даже пустые рубрики 'orderby' => 'name', 'order' => 'ASC' ]; $subcategories = get_categories($args); ?> <? if (!empty($subcategories)): ?> <? foreach ($subcategories as $cat): ?> <li class="mobile-menu-list__item"> <a class="text-button" href=""> </a> </li> <? endforeach; ?> <? else: ?> <span class="dropdown-item text-muted">Нет подкатегорий</span> <? endif; ?> </ul> </li> <li class="mobile-menu-list__item"> <button class="text-button open-submenu" type="button"> Услуги <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"> <path d="M14.1916 8.26218C14.4693 8.55915 14.4693 9.04065 14.1916 9.33763L9.66614 14.1772C9.38843 14.4741 8.93818 14.4741 8.66048 14.1772C8.38277 13.8802 8.38277 13.3987 8.66048 13.1017L11.972 9.56036L1.5999 9.56036V8.03944L11.972 8.03944L8.66048 4.49809C8.38277 4.20111 8.38277 3.71961 8.66048 3.42264C8.93818 3.12566 9.38843 3.12566 9.66614 3.42264L14.1916 8.26218Z" fill="#E0E0E0" /> </svg> </button> <ul class="mobile-menu-list"> <li class="mobile-menu-list__item"> <button class="text-button close-submenu" type="button"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="17" viewBox="0 0 16 17" fill="none"> <path d="M6.33367 14.6772L1.80818 9.83763C1.53048 9.54065 1.53048 9.05915 1.80818 8.76218L6.33367 3.92264C6.61137 3.62566 7.06162 3.62566 7.33933 3.92264C7.61704 4.21961 7.61704 4.70111 7.33933 4.99809L4.02779 8.53944H14.3999L14.3998 10.0604H4.02779L7.33933 13.6017C7.61704 13.8987 7.61704 14.3802 7.33933 14.6772C7.06162 14.9741 6.61137 14.9741 6.33367 14.6772Z" fill="#E0E0E0" /> </svg> Назад </button> </li> <li class="mobile-menu-list__item"> <a class="text-button" href="/services"> Все услуги </a> </li> <? $args = [ 'taxonomy' => 'category', // стандартная таксономия WordPress 'parent' => 5, // ID рубрики, подкатегории которой нужно вывести 'hide_empty' => false, // показывать даже пустые рубрики 'orderby' => 'name', 'order' => 'ASC' ]; $subcategories = get_categories($args); ?> <? if (!empty($subcategories)): ?> <? foreach ($subcategories as $cat): ?> <li class="mobile-menu-list__item"> <a class="text-button" href=""> </a> </li> <? endforeach; ?> <? else: ?> <span class="dropdown-item text-muted">Нет подкатегорий</span> <? endif; ?> </ul> </li> <li class="mobile-menu-list__item"> <a class="text-button" href="/price">Цены</a> </li> <li class="mobile-menu-list__item"><a class="text-button" href="/scenarios">Сценарии</a></li> <li class="mobile-menu-list__item"><a class="text-button" href="/oteli">Отели</a></li> <li class="mobile-menu-list__item"><a class="text-button" href="/about">О нас</a></li> <li class="mobile-menu-list__item"><a class="text-button" href="/how-it-works">Как это работает</a></li> <li class="mobile-menu-list__item"><a class="text-button" href="/faq">Вопросы и ответы</a></li> <li class="mobile-menu-list__item"><a class="text-button" href="/contacts">Контакты</a></li> <li class="mobile-menu-list__item"><a class="text-button" href="/privacy">Конфиденциальность</a></li> <li class="mobile-menu-list__item"> <a class="mobile-menu-list__red text-button" href="/worksheet">Заполнить анкету</a> </li> </ul> <div class="mobile-menu__bottom"> <a href="tg://resolve?domain=Giraffe_14" class="btn btn-outline-secondary btn-icon-sm" role="button" aria-pressed="true" title="Написать в Telegram"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" clip-rule="evenodd" d="M6.81882 12.9841L8.31623 14.1486C8.2551 14.2418 7.93063 14.4813 7.81487 14.5706C7.71434 14.6482 7.64937 14.7014 7.54873 14.7825C7.45956 14.8544 7.37622 14.9552 7.27459 14.9855C7.25518 14.7248 7.11053 14.2535 7.05327 13.9956L6.81882 12.9841ZM13.6222 16.332L11.656 14.8546C11.5289 14.7605 11.4561 14.6927 11.3307 14.5996L8.38134 12.3655C8.43934 12.2686 8.52371 12.2247 8.60166 12.1387C8.68541 12.0464 8.74528 11.9768 8.82892 11.8833C8.97007 11.7255 9.12143 11.5323 9.26981 11.3937C9.74852 10.9463 10.6828 9.80895 11.0694 9.47526L13.3211 7.04337C13.4043 6.95033 13.4635 6.87906 13.5483 6.78788C13.641 6.68812 13.6985 6.65937 13.7936 6.5526C13.9479 6.37917 14.078 6.23355 14.2326 6.06083C14.3059 5.9788 14.3672 5.89912 14.4456 5.82592C14.7802 5.51318 15.3543 4.80412 15.6079 4.61428L15.3711 6.05992C15.3003 6.52278 15.2016 7.0425 15.1166 7.5221C15.025 8.0389 13.6473 15.9945 13.6222 16.332ZM13.7199 4.54157L13.2886 5.0055C13.1423 5.16902 13.0005 5.34723 12.8488 5.49652C12.7572 5.58672 12.7128 5.61097 12.6209 5.71481C12.5377 5.80889 12.4772 5.87615 12.3934 5.96985C12.2522 6.12764 12.1009 6.32078 11.9525 6.45947C11.6229 6.76751 11.2633 7.23362 11.0694 7.40098C10.7296 7.69429 10.5038 8.07919 10.1717 8.36248C9.82824 8.65546 8.8574 9.82961 8.39093 10.2655L7.73887 10.9922C7.64387 11.0989 7.58632 11.1277 7.49361 11.2275C7.29502 11.4412 6.7101 12.0039 6.68863 12.2926C6.57858 12.2025 6.37361 11.1048 6.33111 10.9456C6.1893 10.4147 5.8814 10.3846 5.44198 10.1929C5.05823 10.0254 4.68772 9.87634 4.31202 9.70935L3.17302 9.2359C3.19847 9.21115 3.18744 9.21746 3.23071 9.19119L8.42325 6.881C8.65361 6.77794 13.4576 4.60987 13.7199 4.54157ZM0.666504 9.12673C0.666504 9.80305 0.958245 9.89432 1.53324 10.1229C1.87671 10.2594 4.96703 11.6228 5.12611 11.6376C5.1298 11.8217 5.8755 14.8797 5.96581 15.2477C6.15964 16.0377 6.20431 16.987 6.88394 16.987C7.24585 16.987 7.95048 16.2939 8.24466 16.07L9.19053 15.3079C9.61036 14.9532 9.44158 14.9872 10.0741 15.4586L12.8474 17.562C13.2602 17.8695 13.7262 18.3334 14.1105 18.3334C14.7597 18.3334 14.7943 17.4518 14.9055 16.784C15.0231 16.0777 15.128 15.425 15.2523 14.7336C15.6191 12.6943 15.9391 10.5832 16.305 8.55958L16.6539 6.51152C16.7017 6.18955 16.7633 5.84856 16.8258 5.50283L17.1793 3.42347C17.2274 3.10876 17.3331 2.72769 17.3331 2.3582C17.3331 1.94975 17.0419 1.66675 16.617 1.66675C16.4439 1.66675 15.7835 1.99577 15.5892 2.08259L2.43363 7.93629C2.18966 8.04546 1.10493 8.49165 0.93943 8.63134C0.829271 8.72425 0.666504 8.93644 0.666504 9.12673Z" fill="#E0E0E0" /> </svg> </a> </div> </div> </div> <main class="main">