if (!defined('ABSPATH')) {
exit;
}
require_once __DIR__ . '/inc/shared-models.php';
require_once __DIR__ . '/inc/model-page.php';
require_once __DIR__ . '/inc/scenarios.php';
require_once __DIR__ . '/inc/hotels.php';
require_once __DIR__ . '/inc/info-pages.php';
require_once __DIR__ . '/inc/seo.php';
function custom_form($atts = array())
{
// Значения по умолчанию
$defaults = array(
'type' => '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 '' . "\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|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|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 $params
* @return array>
*/
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 $src
* @return array
*/
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 $filters
* @return array
*/
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 $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 $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 $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
*/
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|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';
}
?>
}
/**
* Атрибуты 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 */
https://www.xn----8sba1ambycsho0kb.xn--p1ai/2026-10-02T14:27:36+03:00daily1.0https://www.xn----8sba1ambycsho0kb.xn--p1ai/zlata2026-09-28T09:42:40+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/zhenya2026-09-28T09:42:39+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/yaroslava2026-09-28T09:42:39+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/yulya2026-09-28T09:42:39+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/zhanna2026-09-28T09:42:39+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/yana2026-09-28T09:42:38+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/violetta2026-09-28T09:42:38+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/veronika2026-09-28T09:42:38+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/viktoriya2026-09-28T09:42:38+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/vlada2026-09-28T09:42:38+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/vasilisa2026-09-28T09:42:37+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/vera2026-09-28T09:42:37+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/vasilisa-22026-09-28T09:42:37+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/vasilina2026-09-28T09:42:37+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/valeriya2026-09-28T09:42:36+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/valentina2026-09-28T09:42:36+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/vanessa2026-09-28T09:42:36+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/teona2026-09-28T09:42:35+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/tina2026-09-28T09:42:35+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/ulyana2026-09-28T09:42:35+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/ulya2026-09-28T09:42:35+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/svyatoslava2026-09-28T09:42:34+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/tanjusha2026-09-28T09:42:34+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/tayana2026-09-28T09:42:34+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/sofiya-22026-09-28T09:42:33+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/sofya2026-09-28T09:42:33+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/svetlana2026-09-28T09:42:33+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/sonya2026-09-28T09:42:33+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/silviya2026-09-28T09:42:32+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/sofiya2026-09-28T09:42:32+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/sofi2026-09-28T09:42:32+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/serafima2026-09-28T09:42:31+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/sara2026-09-28T09:42:31+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/sabina2026-09-28T09:42:31+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/sandra2026-09-28T09:42:31+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/ruslana2026-09-28T09:42:30+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/rimma2026-09-28T09:42:30+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/renata2026-09-28T09:42:30+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/roksana2026-09-28T09:42:30+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/regina2026-09-28T09:42:29+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/pelageya2026-09-28T09:42:29+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/polina2026-09-28T09:42:29+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/raisa2026-09-28T09:42:29+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/olga2026-09-28T09:42:28+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/nina2026-09-28T09:42:28+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/oksana2026-09-28T09:42:28+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/oktaviya2026-09-28T09:42:28+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/oliviya2026-09-28T09:42:28+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/nika2026-09-28T09:42:27+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/natalya2026-09-28T09:42:27+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/nika-22026-09-28T09:42:27+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/nelli2026-09-28T09:42:27+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/nadezhda2026-09-28T09:42:26+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/miroslava2026-09-28T09:42:26+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/monika2026-09-28T09:42:26+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/nadin2026-09-28T09:42:26+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/nata2026-09-28T09:42:26+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/mila2026-09-28T09:42:25+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/miloslava2026-09-28T09:42:25+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/milana2026-09-28T09:42:25+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/melaniya2026-09-28T09:42:24+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/maryana2026-09-28T09:42:24+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/martina2026-09-28T09:42:24+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/masha2026-09-28T09:42:24+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/mariya2026-09-28T09:42:23+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/marina-22026-09-28T09:42:23+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/mariya-22026-09-28T09:42:23+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/marta2026-09-28T09:42:23+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/marina2026-09-28T09:42:22+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/marianna2026-09-28T09:42:22+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/majya2026-09-28T09:42:22+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/malina2026-09-28T09:42:22+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/lina2026-09-28T09:42:21+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/luiza2026-09-28T09:42:21+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/lyubava2026-09-28T09:42:21+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/madlen2026-09-28T09:42:21+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/lika2026-09-28T09:42:20+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/liel2026-09-28T09:42:20+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/liliana2026-09-28T09:42:20+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/liliya2026-09-28T09:42:20+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/lera2026-09-28T09:42:19+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/leona2026-09-28T09:42:19+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/leda2026-09-28T09:42:19+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/lidiya2026-09-28T09:42:19+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/ksjusha2026-09-28T09:42:18+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/lada2026-09-28T09:42:18+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/lana2026-09-28T09:42:18+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/laura2026-09-28T09:42:18+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/kira2026-09-28T09:42:17+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/kseniya2026-09-28T09:42:17+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/kristina2026-09-28T09:42:17+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/kira-22026-09-28T09:42:17+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/klara2026-09-28T09:42:17+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/klavdiya2026-09-28T09:42:17+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/katarina2026-09-28T09:42:16+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/karishka2026-09-28T09:42:16+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/karina2026-09-28T09:42:16+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/katrin2026-09-28T09:42:16+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/kadriya2026-09-28T09:42:15+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/juliana2026-09-28T09:42:15+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/juliana-22026-09-28T09:42:15+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/kamilla2026-09-28T09:42:15+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/irina2026-09-28T09:42:14+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/inna2026-09-28T09:42:14+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/iolanta2026-09-28T09:42:14+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/ivana2026-09-28T09:42:14+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/izabella2026-09-28T09:42:14+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/ilona-22026-09-28T09:42:13+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/ilmira2026-09-28T09:42:13+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/inessa2026-09-28T09:42:13+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/inga2026-09-28T09:42:13+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/ilana2026-09-28T09:42:12+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/helena2026-09-28T09:42:12+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/gelena2026-09-28T09:42:12+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/glafira2026-09-28T09:42:12+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/evelina2026-09-28T09:42:11+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/evgeniya2026-09-28T09:42:11+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/gabriella2026-09-28T09:42:11+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/galya2026-09-28T09:42:11+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/evandzhelina2026-09-28T09:42:10+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/emiliya2026-09-28T09:42:10+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/emili2026-09-28T09:42:10+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/emma2026-09-28T09:42:10+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/eva2026-09-28T09:42:10+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/elza2026-09-28T09:42:09+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/elya2026-09-28T09:42:09+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/elli2026-09-28T09:42:09+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/elvira2026-09-28T09:42:09+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/elizaveta2026-09-28T09:42:08+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/elena2026-09-28T09:42:08+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/eleonora2026-09-28T09:42:08+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/diora2026-09-28T09:42:07+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/ekaterina2026-09-28T09:42:07+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/dominika2026-09-28T09:42:07+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/efrosinya2026-09-28T09:42:07+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/darya2026-09-28T09:42:06+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/dana2026-09-28T09:42:06+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/daniela2026-09-28T09:42:06+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/diana2026-09-28T09:42:06+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/dina2026-09-28T09:42:06+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/bella2026-09-28T09:42:05+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/bogdana2026-09-28T09:42:05+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/bozhena2026-09-28T09:42:05+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/avrora2026-09-28T09:42:04+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/avgusta2026-09-28T09:42:04+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/arina2026-09-28T09:42:04+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/ariadna2026-09-28T09:42:04+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/anzhelika2026-09-28T09:42:03+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/anzhelika-22026-09-28T09:42:03+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/angelina-22026-09-28T09:42:03+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/anna2026-09-28T09:42:03+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/anastasiya2026-09-28T09:42:02+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/angelina2026-09-28T09:42:02+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/amanda2026-09-28T09:42:02+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/ameli2026-09-28T09:42:02+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/ameliya2026-09-28T09:42:02+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/aljona2026-09-28T09:42:01+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/alla2026-09-28T09:42:01+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/aljona-22026-09-28T09:42:01+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/alisha2026-09-28T09:42:00+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/alisha-22026-09-28T09:42:00+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/alisa-22026-09-28T09:42:00+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/alisa2026-09-28T09:41:59+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/alina2026-09-28T09:41:59+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/aleks2026-09-28T09:41:59+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/aleksandra2026-09-28T09:41:59+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/alana2026-09-28T09:41:58+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/albina2026-09-28T09:41:58+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/agnet2026-09-28T09:41:58+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/aglaya2026-09-28T09:41:58+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/agniya2026-09-28T09:41:58+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/aida2026-09-28T09:41:58+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/agata2026-09-28T09:41:57+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/adel2026-09-28T09:41:57+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/ada2026-09-28T09:41:56+03:00weekly0.8https://www.xn----8sba1ambycsho0kb.xn--p1ai/favorits2026-08-12T08:59:21+03:00monthly0.7https://www.xn----8sba1ambycsho0kb.xn--p1ai/price2025-10-17T09:20:58+03:00monthly0.7https://www.xn----8sba1ambycsho0kb.xn--p1ai/2024-08-12T04:57:11+03:00monthly0.7https://www.xn----8sba1ambycsho0kb.xn--p1ai/contacts2024-06-25T08:49:51+03:00monthly0.7https://www.xn----8sba1ambycsho0kb.xn--p1ai/about2024-05-31T08:57:36+03:00monthly0.7https://www.xn----8sba1ambycsho0kb.xn--p1ai/worksheet2024-05-31T08:52:34+03:00monthly0.7https://www.xn----8sba1ambycsho0kb.xn--p1ai/services_2024-05-31T08:41:58+03:00monthly0.7https://www.xn----8sba1ambycsho0kb.xn--p1ai/privacy-policy2023-08-14T08:29:57+03:00monthly0.7https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/vip-modeli2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/aziatki-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/aziatki2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/blondinki-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/blondinki2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/bryunetki-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/bryunetki2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/vip-modeli-services2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/vip-eskort2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/vysokie-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/vysokie2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/goryachie-devushki2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/goryachie-devushki-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/woman-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/woman2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/devushki-dlya-otnoshenij2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/devushki-na-korporativ2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/devushki-na-chas2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/dlinnonogie-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/dlinnonogie2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/dorogoj-eskort2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/zakaz-eskortnic-v-banyu2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/krasivye-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/krasivye2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/milye-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/milye2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/miniatyurnye2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/miniatyurnye-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/modeli-dlya-semok2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/modeli-dlya-tusovki2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/modeli-dlya-chastnyh-meropriyatij2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/molodye2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/molodye-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/na-meropriyatiya2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/na-noch2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/perevodchiki-modelnoj-vneshnosti2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/promo-modeli-na-vystavku2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/pyshnye2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/pyshnye-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/romanticheskie-vstrechi-eskort2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/russkie-ehskortnicy2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/russkie-ehskortnicy-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/rusye-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/rusye2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/ryzhie-devushki-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/ryzhie-devushki2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/soderzhanki2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/soderzhanki-eskortnicy2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/soprovozhdenie-v-poezdkah2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/soprovozhdenie-v-restorany-muzei-teatry2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/sochnye2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/sochnye-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/sportivnye-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/sportivnye2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/striptiz-s-eskortom2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/strojnye-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/strojnye2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/transfery2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/uslugi-gospozhi2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/hostes2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/hudye-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/hudye2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/shatenki2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/shatenki-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/elitnye-eskortnicy2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/elitnye-eskortnicy-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/elitnyj-eskort2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/elitnyj-eskort-v-dubae2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-bez-intima2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-v-otel2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-v-puteshestviya2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-gospozha2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-dlya-bdsm2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-dlya-muzhchin2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-dlya-par2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-dosug2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-za-granicu2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-znakomstva2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-na-apartamenty2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-na-vecherinki2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-na-vyezd2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-na-dom2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-na-meropriyatiya2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-na-noch2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-na-sutki2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-pary2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskort-s-bliznyashkami2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskortnicy-na-sutki2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/services/eskortnicy-moskvy2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/s-bolshoj-grudyu-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/s-bolshoj-grudyu2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/s-malenkoj-grudyu-dubai2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/s-malenkoj-grudyu2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/modeli/s-tatuirovkami2026-10-02T14:27:36+03:00weekly0.6https://www.xn----8sba1ambycsho0kb.xn--p1ai/dubai/s-tatuirovkami-dubai2026-10-02T14:27:36+03:00weekly0.6