/ Сайтостроение / Wordpress / Фильтр записей на главной странице

Фильтр записей на главной странице

04.11.2019

40

Deprecated: Function create_function() is deprecated in /home/t/tiberi6w/opttour.ru/public_html/wp-content/plugins/wp-spamshield/wp-spamshield.php on line 2033

Задокументирую очередной вариант фильтра постов. Фильтр располагается в шаблоне главной страницы.

Верстка в шаблоне

<?php echo do_shortcode( '[site-filter]' ); ?>

<div class="filter-loader"><img src="/wp-content/uploads/2019/10/preloader-basket.gif"></div>

<div class="subcategory-posts">
	
<?php query_posts( 'posts_per_page=12');
if (have_posts()) :	
echo '<div class="tagged-posts">';
while (have_posts()) : the_post();
	get_template_part( 'solus' );
endwhile;
echo '</div>';
else: echo 'По вашему запросу нет результатов';
endif; //wp_reset_query(); ?>
	
	<?php if (  $wp_query->max_num_pages > 1 ) {
		echo '<div id="pagination">';
		echo '<label class="checked"><input id="pagine" type="radio" name="pagine" value="1" checked>1</label>';

		$i = 2;

		while( $i <= $wp_query->max_num_pages ) :  
			echo '<label><input id="pagine" type="radio" name="pagine" value="'.$i.'"';
			echo '>'.$i.'</label>';
			$i++;
		endwhile;

		echo '</div>';
	} ?>

</div>

Подключение ajax и включение функции фильтра (из плагина):

add_action('wp_print_scripts', 'ajax_filter_posts_scripts', 100);
function ajax_filter_posts_scripts() {
	wp_enqueue_style( 'ajax_filter_posts', plugins_url('/site-ajax-filter-posts.css', __FILE__) );
	wp_register_script( 'afp_script', plugins_url('/site-ajax-filter-posts.js', __FILE__), array('jquery'), null, true );
	wp_enqueue_script( 'afp_script' );

	wp_localize_script( 
		'afp_script', 
		'afp_vars', 
		array(
			'afp_nonce' => wp_create_nonce( 'afp_nonce' ), // Create nonce which we later will use to verify AJAX request
			'afp_ajax_url' => admin_url( 'admin-ajax.php' ),
		)
	);
}


function sitefilter() { include(__DIR__."/filter.php"); }
add_shortcode( 'site-filter', 'sitefilter' );

Верстка формы фильтра

<div id="filter"><form class="filter" action="" method="">
  
	<?php $args = array(
			'posts_per_page' => -1,
	);
	$catposts = get_posts( $args );	?>	
	
	<div id="filters">
		
		<!--<div><span class="name-group">Наименование</span>
		<input type="text" value="" name="word" id="word">
		</div>-->
		
		<input type="hidden" value="8" name="number" id="number">
		
		<!-- Фильтр по категориям -->
		<div id="category_filter"><div><span class="name-group">Категория</span> 
		<span class="group-filter">	 
			
		<?php $all_cat_ids = array();	
		foreach( $catposts as $catpost ){ //setup_postdata($post);		   
		$all_cat_objects = get_the_category($catpost->ID);			
			if(!empty($all_cat_objects)){
				foreach($all_cat_objects as $cat) {
					$all_cat_ids[] = $cat->term_id;
				}
			}
											
		}			
		wp_reset_postdata();

		if ( count($all_cat_ids) > 0 ): ?>

			<?php $cat_ids_unique = array_unique($all_cat_ids);
			
			foreach($cat_ids_unique as $cat_id): ?>
			
				<?php if ($cat_id != 1): // Отсеиваем категорию Без рубрики ?>

				<?php $post_cat = get_term( $cat_id, 'category' ); ?>

				<label>
					<input class="categoria" type="checkbox" name="postercats" value="<?php echo $post_cat->term_id; ?>">
					<span><?php echo $post_cat->name; ?></span>
				</label>
			
				<?php endif; ?>

			<?php endforeach; ?>

		<?php endif; ?>		  
		</span></div></div>		
		

		<!-- Фильтр по произвольному полю -->	
		<div id="area_filter"><div><span class="name-group">Площадь (м²)</span>
		<span class="group-filter">  
			<input type="text" value="" name="area_from" placeholder="от..." id="area_from">
			<input type="text" value="" name="area_to" placeholder="до..." id="area_to">		
		</span></div></div>
		
		
		<!-- Фильтр по произвольному полю -->	
		<div id="price_filter"><div><span class="name-group">Цена (руб.)</span>
		<span class="group-filter">  
			<input type="text" value="" name="price_from" placeholder="от..." id="price_from">
			<input type="text" value="" name="price_to" placeholder="до..." id="price_to">			
		</span></div></div>
		

		<!-- Фильтр по меткам -->
		<div id="options_filter"><div><span class="name-group">Опции</span> 
		<span class="group-filter">	  
		<?php $all_tag_ids = array();
			foreach( $catposts as $catpost ){ //setup_postdata($post);		   
			$all_tag_objects = get_the_tags($catpost->ID);					
			if(!empty($all_tag_objects)){
				foreach($all_tag_objects as $tag) {
					$all_tag_ids[] = $tag->term_id;
				}
			}
		}
		wp_reset_postdata();

		if ( count($all_tag_ids) > 0 ): ?>

			<?php $tag_ids_unique = array_unique($all_tag_ids);
			foreach($tag_ids_unique as $tag_id): ?>

				<?php $post_tag = get_term( $tag_id, 'post_tag' ); ?>

				<label>
					<input class="metka" type="checkbox" name="tags" value="<?php echo $post_tag->term_id; ?>">
					<span><?php echo $post_tag->name; ?></span>
				</label>

			<?php endforeach; ?>

		<?php endif; ?>		  
		</span></div></div>

	</div>

	<button type="submit" class="taguniq"><i class="fa fa-filter" aria-hidden="true"></i>Фильтровать</button>
    
</form></div>

Скрипт отправки значений формы

Для пэйджинации разбит на 2 разных скрипта (с разными action (filter_posts и filter_posts_order)): первый для изменения запроса и обнуления номера страницы, второй для перемещения по номерам страницы:

jQuery(document).ready(function($) {
	
	// Нажатие кнопки Фильтрация при изменении формы
	$("body").on("change", ".filter", function () {
		$('.taguniq').trigger('click');
	});
	
	$('.taguniq').click( function(event) { // По нажатию на кнопку

		// Prevent defualt action - opening tag page
		if (event.preventDefault) {
			event.preventDefault();
		} else {
			event.returnValue = false;
		}
			
		//var sortPagine = $("input[name='pagine']:checked").val();
		//var word = $("#word").val();
			
		var area_from = $("#area_from").val();
		var area_to = $("#area_to").val();
		var price_from = $("#price_from").val();
		var price_to = $("#price_to").val();

	  
	    var arrList = $('.metka:checkbox:checked').map(function(){
    		return $(this).attr('value');
		}).get();
		var tags = arrList.join(', '); // преобразовываем массив в строку с разделителем ' '
			
	    var arrList2 = $('.categoria:checkbox:checked').map(function(){
    		return $(this).attr('value');
		}).get();
		var cats = arrList2.join(', '); // преобразовываем массив в строку с разделителем ' '			
			
		$(document).scrollTop( $("#filter").offset().top );	 // Перемещаемся под фильтр (к объектам)

		$('.tagged-posts').fadeOut();

		data = {
			action: 'filter_posts',
			afp_nonce: afp_vars.afp_nonce,

		    tags: tags,
			cats: cats,

			//word: word,
			area_from: area_from,
			area_to: area_to,
			price_from: price_from,
			price_to: price_to,
		};
	  
	  
		$.ajax({
			type: 'post',
			dataType: 'html',
			url: afp_vars.afp_ajax_url,
			data: data,
			beforeSend: function(){
				$('.filter-loader').show();
			},
			success: function( data, textStatus, XMLHttpRequest ) {
				$('.subcategory-posts').html( data );	
				$('.subcategory-posts').fadeIn();	
				console.log( textStatus );
				console.log( XMLHttpRequest );
				if( data ) { 
					$('.filter-loader').hide();
				}				
				setTimeout(function () {
					$('.hentry-gallery, #product-gallery').prepend('<div class="label"></div>');  
					$('.tag-hypothec .label').prepend('<div class="hypothec" title="Ипотека"><img src="/wp-content/uploads/2019/10/Ipoteka_96.png"></div>');
					$('.tag-military .label').prepend('<div class="military" title="Военная ипотека"><img src="/wp-content/uploads/2019/10/star.png"></div>');
					$('.tag-agp .label').prepend('<div class="agp" title="АЖП"><img src="/wp-content/uploads/2019/10/family.png"></div>');
					$('.tag-mother .label').prepend('<div class="mother" title="Материнский капитал"><img src="/wp-content/uploads/2019/10/pacifier.png"></div>');
					$('.tag-installment .label').prepend('<div class="installment" title="Рассрочка"><img src="/wp-content/uploads/2019/10/installment.png"></div>');			
				}, 400);				
			},
			error: function( MLHttpRequest, textStatus, errorThrown ) {
				console.log( MLHttpRequest );
				console.log( textStatus );
				console.log( errorThrown );
				$('.subcategory-posts').html( 'No posts found' );
				$('.subcategory-posts').fadeIn();
			}
		})			

	});
  
  
	// Обновление при изменении списка с количеством страниц
	$("body").on("change", "#pagine", function () {
          
		// Prevent defualt action - opening tag page
		if (event.preventDefault) {
			event.preventDefault();
		} else {
			event.returnValue = false;
		}

		var sortPagine = $("input[name='pagine']:checked").val();
		//var word = $("#word").val();
			
		var area_from = $("#area_from").val();
		var area_to = $("#area_to").val();
		var price_from = $("#price_from").val();
		var price_to = $("#price_to").val();

	  
	    var arrList = $('.metka:checkbox:checked').map(function(){
    		return $(this).attr('value');
		}).get();
		var tags = arrList.join(', '); // преобразовываем массив в строку с разделителем ' '
			
	    var arrList2 = $('.categoria:checkbox:checked').map(function(){
    		return $(this).attr('value');
		}).get();
		var cats = arrList2.join(', '); // преобразовываем массив в строку с разделителем ' '			
		
		$(document).scrollTop( $("#filter").offset().top ); // Перемещаемся под фильтр (к объектам)

		$('.tagged-posts').fadeOut();

		data = {
			action: 'filter_posts_order',
			afp_nonce: afp_vars.afp_nonce,
		    tags: tags,
			cats: cats,
			pagine:sortPagine,
			//word: word,
			area_from: area_from,
			area_to: area_to,
			price_from: price_from,
			price_to: price_to,
		};
	  
	  
		$.ajax({
			type: 'post',
			dataType: 'html',
			url: afp_vars.afp_ajax_url,
			data: data,
			beforeSend: function(){
				$('.filter-loader').show();
			},
			success: function( data, textStatus, XMLHttpRequest ) {
				$('.subcategory-posts').html( data );	
				$('.subcategory-posts').fadeIn();	
				console.log( textStatus );
				console.log( XMLHttpRequest );
				if( data ) { 
					$('.filter-loader').hide();
				}				
				setTimeout(function () {
					$('.hentry-gallery, #product-gallery').prepend('<div class="label"></div>');  
					$('.tag-hypothec .label').prepend('<div class="hypothec" title="Ипотека"><img src="/wp-content/uploads/2019/10/Ipoteka_96.png"></div>');
					$('.tag-military .label').prepend('<div class="military" title="Военная ипотека"><img src="/wp-content/uploads/2019/10/star.png"></div>');
					$('.tag-agp .label').prepend('<div class="agp" title="АЖП"><img src="/wp-content/uploads/2019/10/family.png"></div>');
					$('.tag-mother .label').prepend('<div class="mother" title="Материнский капитал"><img src="/wp-content/uploads/2019/10/pacifier.png"></div>');
					$('.tag-installment .label').prepend('<div class="installment" title="Рассрочка"><img src="/wp-content/uploads/2019/10/installment.png"></div>');			
				}, 400);				
			},
			error: function( MLHttpRequest, textStatus, errorThrown ) {
				console.log( MLHttpRequest );
				console.log( textStatus );
				console.log( errorThrown );
				$('.subcategory-posts').html( 'No posts found' );
				$('.subcategory-posts').fadeIn();
			}
		})
          
    });
  
});

После успешного завершения ajax-запроса срабатывает пользовательская функция вывода лэйблов.

Сам фильтр (изменение запроса)

Фильтр также разделен на две большие функции в зависимости от того меняем ли мы запрос или переходим по страницам (функции фильтра связаны с action отправляемых форм ajax)

function ajax_filter_get_posts() { 
	
	// first query
	if ($_POST['taxonomy'] != '') { $country =  $_POST['taxonomy']; } 
	else { $country = 0; }

	if ($_POST['taxonomy2'] != '') { $power =  $_POST['taxonomy2']; } 
	else { $power = 0; }


	if ($_POST['area_from'] != '') { $area_from = $_POST['area_from']; } 
	else { $area_from = 0; }	

	if ($_POST['area_to'] != '') { $area_to = $_POST['area_to']; } 
	else { $area_to = 1000; }	

	if ($_POST['price_from'] != '') { $price_from = $_POST['price_from']; } 
	else { $price_from = 0; }	

	if ($_POST['price_to'] != '') { $price_to = $_POST['price_to']; } 
	else { $price_to = 1000000000; }

	$first_ids = get_posts( array(
		'fields'         => 'ids',
		'posts_per_page' => -1,	
		'meta_query' => array(
			'relation' => 'AND',
			array(
				'key'     => 'price',
				'value'   => array( $price_from, $price_to ),
				'type'    => 'numeric',
				'compare' => 'BETWEEN'
			),
			array(
				'key'     => 'area',
				'value'   => array( $area_from, $area_to ),
				'type'    => 'numeric',
				'compare' => 'BETWEEN'
			)
		)
	));


	// second query
	$tags = explode(" ", $_POST['tags']);
	$cats = explode(" ", $_POST['cats']);	

	if ($_POST['labels'] != '') { $labels = explode(" ", $_POST['labels']); } 
	else { $labels = 0; }

	$second_ids = get_posts( array(
		'fields'         => 'ids',
		'posts_per_page' => -1,
		'tax_query' => array(
			'relation' => 'OR', //AND - записи которые одновременно входят в указанные таксономии; OR - записи принадлежащие любой из указанных таксономий
			array(
				'taxonomy' => 'post_tag',
				'field'    => 'id',
				'terms'    => $tags,
				'operator' => 'IN' //AND - в записи должны быть все выбранные термины, IN - в записи должен быть хотя бы один из выбранных терминов
			),
		)
	));


	if (count($first_ids) == 0) { // если в первом массиве нет значений, берем только второй массив	
		$post_ids = array(0);
	} elseif (count($second_ids) == 0) { // если во втором массиве нет значений, берем только первый массив	
		$post_ids = $first_ids;
	} else { // если во втором массиве есть значения
		$intersect_ids = array_intersect($first_ids, $second_ids); // сравниваем массивы и находим совпадения
		if (count($intersect_ids) == 0) { // если нет совпадений, то в post__in передаем 0
			$post_ids = array(0);
		} else { // если есть совпадения, то в post__in передаем ID которые нужно получить
			$post_ids = $intersect_ids;
		}
	}

	// Обнуляем пагинацию
	$_POST['pagine'] = 0;	

	$args = array( 
		'post_type' => 'post',
		'post_status' => 'publish',
		'cat' => $cats,
		'posts_per_page' => $_POST['number'],
		'paged' => $_POST['pagine'], 
		'post__in'  => $post_ids,
		's' => $_POST['word']
	);


	$theme_post_query = new WP_Query( $args );

	if ($theme_post_query->have_posts()) {	

		echo '<div class="tagged-posts">';

		$i = 0;

		while( $theme_post_query->have_posts() ) : 
			$theme_post_query->the_post();
			include(TEMPLATEPATH."/solus.php");
			$i++;
		endwhile;

		echo '</div>';

	} else { echo '<p class="empty">По вашему запросу нет результатов</p>';	}



	if (  $theme_post_query->max_num_pages > 1 ) {
		echo '<div id="pagination">';
		echo '<label class="checked"><input id="pagine" type="radio" name="pagine" value="1" checked>1</label>';

		$i = 2;

		while( $i <= $theme_post_query->max_num_pages ) :  
			echo '<label><input id="pagine" type="radio" name="pagine" value="'.$i.'"';
			echo '>'.$i.'</label>';
			$i++;
		endwhile;

		echo '</div>';
	}		

	exit;  
	
}

add_action('wp_ajax_filter_posts', 'ajax_filter_get_posts');
add_action('wp_ajax_nopriv_filter_posts', 'ajax_filter_get_posts');

Вторая функция:

function ajax_filter_get_posts_order() { 
	
	// first query
	if ($_POST['taxonomy'] != '') { $country =  $_POST['taxonomy']; } 
	else { $country = 0; }

	if ($_POST['taxonomy2'] != '') { $power =  $_POST['taxonomy2']; } 
	else { $power = 0; }


	if ($_POST['area_from'] != '') { $area_from = $_POST['area_from']; } 
	else { $area_from = 0; }	

	if ($_POST['area_to'] != '') { $area_to = $_POST['area_to']; } 
	else { $area_to = 1000; }	

	if ($_POST['price_from'] != '') { $price_from = $_POST['price_from']; } 
	else { $price_from = 0; }	

	if ($_POST['price_to'] != '') { $price_to = $_POST['price_to']; } 
	else { $price_to = 1000000000; }

	$first_ids = get_posts( array(
		'fields'         => 'ids',
		'posts_per_page' => -1,	
		'meta_query' => array(
			'relation' => 'AND',
			array(
				'key'     => 'price',
				'value'   => array( $price_from, $price_to ),
				'type'    => 'numeric',
				'compare' => 'BETWEEN'
			),
			array(
				'key'     => 'area',
				'value'   => array( $area_from, $area_to ),
				'type'    => 'numeric',
				'compare' => 'BETWEEN'
			)
		)
	));


	// second query
	$tags = explode(" ", $_POST['tags']);
	$cats = explode(" ", $_POST['cats']);	

	if ($_POST['labels'] != '') { $labels = explode(" ", $_POST['labels']); } 
	else { $labels = 0; }

	$second_ids = get_posts( array(
		'fields'         => 'ids',
		'posts_per_page' => -1,
		'tax_query' => array(
			'relation' => 'OR', //AND - записи которые одновременно входят в указанные таксономии; OR - записи принадлежащие любой из указанных таксономий
			array(
				'taxonomy' => 'post_tag',
				'field'    => 'id',
				'terms'    => $tags,
				'operator' => 'IN' //AND - в записи должны быть все выбранные термины, IN - в записи должен быть хотя бы один из выбранных терминов
			),
		)
	));


	if (count($first_ids) == 0) { // если в первом массиве нет значений, берем только второй массив	
		$post_ids = array(0);
	} elseif (count($second_ids) == 0) { // если во втором массиве нет значений, берем только первый массив	
		$post_ids = $first_ids;
	} else { // если во втором массиве есть значения
		$intersect_ids = array_intersect($first_ids, $second_ids); // сравниваем массивы и находим совпадения
		if (count($intersect_ids) == 0) { // если нет совпадений, то в post__in передаем 0
			$post_ids = array(0);
		} else { // если есть совпадения, то в post__in передаем ID которые нужно получить
			$post_ids = $intersect_ids;
		}
	}


	$args = array( 
		'post_type' => 'post',
		'post_status' => 'publish',
		'cat' => $cats,
		'posts_per_page' => $_POST['number'],
		'paged' => $_POST['pagine'], 
		'post__in'  => $post_ids,
		's' => $_POST['word']
	);

	$theme_post_query = new WP_Query( $args );

	if ($theme_post_query->have_posts()) {

		echo '<div class="tagged-posts">';

		$i = 0;

		while( $theme_post_query->have_posts() ) : 
			$theme_post_query->the_post();
			include(TEMPLATEPATH."/solus.php");
			$i++;
		endwhile;

		echo '</div>';

	} else { echo '<p class="empty">По вашему запросу нет результатов</p>';	}



	if (  $theme_post_query->max_num_pages > 1 ) {
		echo '<div id="pagination">';

		$i = 1;
		$cp = $_POST['pagine'];

		while( $i <= $theme_post_query->max_num_pages ) :  
			echo '<label';
			if ( $i == $cp ) { echo ' class="checked"'; }
			echo '><input id="pagine" type="radio" name="pagine" value="'.$i.'"';
			if ( $i == $cp ) { echo 'checked'; }
			echo '>'.$i.'</label>';
			$i++;
		endwhile;

		echo '</div>';
	}	

	exit; 
	
}


add_action('wp_ajax_filter_posts_order', 'ajax_filter_get_posts_order');
add_action('wp_ajax_nopriv_filter_posts_order', 'ajax_filter_get_posts_order');

Некоторые стили оформления фильтра:

#filter {margin-bottom: 30px; font-size: 1.3rem;}

#filters {display: flex; justify-content: space-between; align-items: center; margin-left: -5px; margin-right: -5px;}

#filters > div {padding: 0 5px; min-width: 25%;}

#filters > div > div {border: 1px solid #eee; padding: 0 10px; border-radius: 7px;}

.name-group {display: block; width: 50%; margin: -10px auto 5px auto; background: #fff;}

.group-filter {display: flex; justify-content: center; min-width: 15%; text-align: left;}

.group-filter input {border: none; border-bottom: 1px solid #eee;}

#filters > #area_filter, #filters > #price_filter {min-width: 20%;}

#area_filter .group-filter, #price_filter .group-filter {justify-content: space-between; margin-bottom: 10px;}
#area_filter input, #price_filter input {text-align: center; width: 45%; padding: 0; font-size: 1.2rem; margin-bottom: 7px;}

#category_filter .group-filter, #options_filter .group-filter {flex-wrap: wrap;}

#filter label {margin: 0 7px; display: flex; align-items: center; margin-bottom: 7px;}
#filter label input {margin-right: 7px;}
#filter label small {color: #eee;}

#filter select {width: 100%;}

#filter button {display: none;}

#filter input::-webkit-input-placeholder, textarea::-webkit-input-placeholder       {color: #aaa;}
#filter input::-moz-placeholder, textarea::-moz-placeholder                {color: #aaa;}
#filter input:-moz-placeholder, textarea:-moz-placeholder                 {color: #aaa;}
#filter input:-ms-input-placeholder, textarea:-ms-input-placeholder            {color: #aaa;}

.filter-loader {display: none;}

#pagination {display: flex; justify-content: center;}

#pagination label input {display: none;}

#pagination label {
    background: #ffc31e;
    font-size: 1.2rem;
    cursor: pointer;
    line-height: 35px;
    width: 35px;
    display: block;
    text-align: center;
    margin: 0 5px;
}

#pagination label:hover {background: #ff9800;}

#pagination label.checked {background: #ff9800; cursor: default;}

@media screen and (max-device-width: 1024px) { 
	#pagination {flex-wrap: wrap;}
	#pagination label {margin-bottom: 10px;}
}

@media screen and (max-device-width: 800px) { 
	#filter {margin-bottom: 20px;}
	#filters {flex-wrap: wrap; justify-content: center;} 
	#filters > #category_filter {min-width: 100%; margin-bottom: 15px;}
	#filters > #area_filter, #filters > #price_filter {margin-bottom: 15px;}
	#postsmore {width: 50%; margin: 30px 25% 0 25%;}
}

@media screen and (max-device-width: 480px) { 
	#filters > #area_filter, #filters > #price_filter {width: 50%; margin-bottom: 15px;} 
	#filters > div {min-width: 50%;}
	.name-group {width: 70%;}
	#postsmore {width: 100%; margin: 30px 0 0 0;}
}

Тэги:

Поделится информацией с друзьями

  • Похожие записи
  • Комментарии
  • Вложения
WooCommerce AJAX Products Filter

WooCommerce AJAX Products Filter

Раннее данный фильтр участвовал в общем обзоре, в котором я приводил основные особенности. Рассмотрим подробнее работу с фильтром WooCommerce AJAX Products Filter. Работа с WooCommerce AJAX Products Filter Можно создавать Читать далее »

/
Фильтр. Принцип работы

Фильтр. Принцип работы

Попытка реализовать функционал полноценного фильтра для различных ситуаций: по меткам, по категориям, по таксономиям, по дополнительным полям, по сочетанию всех этих данных. Принцип работы фильтра Создаем в шаблоне архива (категории, Читать далее »

Фильтр Ajax

Фильтр Ajax

Очередная попытка сделать фильтр wordpress, в этот раз применяя технологию ajax. По сути программирование фильтра — это изобретение велосипеда, но есть 2 момента: во-первых в процессе я начинаю лучше понимать Читать далее »

/

Добавить комментарий

Пока нет комментариев. Будь первым!

Фильтр записей на главной странице
Подключаем КЛАДР
Рекомендации для васПодключаем КЛАДРOpttour.ru
Спасибо! Наш менеджер свяжется с Вами в течении 5 минут.