Load more Ajax với WordPress

Mình từng có hướng dẫn các bạn phân trang đơn giản bằng cách phân các page 2, page 3,… Nhưng theo cách nào đó, Load more Ajax lại đem đến cho người dùng một trải nghiệm mới hoặc dễ thao tác để so sánh các bài viết hơn.

Trước hết thì các bạn nên hiểu qua Ajax, đơn giản nhất bạn cố thể nghĩ như sau. Khi bạn muốn tải thêm (xuất hiện) 1 box nào đó chèn vào vị trí bất kì mà bạn không phải tải lại trang, vậy gọi là Load Ajax. Áp dụng vào thực tiễn ở đây, khi bạn vào trang lưu trữ với xuất hiện 10 bài viết, thay vì click trang 2 để xuất hiện 10 bài viết mới. Ajax sẽ giúp bạn thêm 10 bài viết nữa mà không phải load lại trang, thực sự lợi phải không?

Load more bài viết không theo chuyên mục

Vậy mình sẽ bắt tay vào hướng dẫn các bạn, mình sẽ khó để giải thích toàn bộ nhưng chỉ cần đảm bảo các bạn làm theo các bước của mình, code sẽ hoạt động.

Trường hợp này, mình sẽ tạo load more với bài viết không theo chuyên mục, tại sao mình lại nói như vậy? Với bài viết không theo chuyên mục, bạn chỉ cần chú ý tới 2 thứ, đó chính là số lượng bài viết hiển thị và post-type cần hiển thị (mặc định sẽ là post). Đây chính là đoạn code hiển thị 10 bài viết ở bất cứ page nào đều được: page.php, single.php, archive.php,…

<?php 
$the_query = new WP_Query( $args = array(
	'post_type'  => 'post',
	'posts_per_page' => 10,
) );
if ( $the_query->have_posts() ) :
	?>
	<?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
		<?php get_template_part( 'template-parts/content', get_post_type() ); ?>
	<?php endwhile; ?>
<?php endif; 
?>

Vậy từ đó biến thành ajax phải xử lý sao? Từ đoạn code trên mình sửa đổi chút, chỗ nào sửa mình sẽ note comment lên đó:

<div id="list-post">  <!-- ID này sẽ đóng vai trò để truyền dữ liệu vào đây -->
	<?php 
	$the_query = new WP_Query( $args = array(
		'post_type'  => 'post',
		'posts_per_page' => 10,
		'offset' => 0,  // Lấy bài viết đầu tiên
	) );
	$countp = $the_query ->found_posts; // Mình đếm số bài viết của query mình vừa gọi
	if ( $the_query->have_posts() ) :
		?>
		<?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
			<?php get_template_part( 'template-parts/content', get_post_type() ); ?>
		<?php endwhile; ?>
	<?php endif; 
	?>	
</div>

Setup cơ bản vậy là xong bước đầu, đoạn code trên sẽ hiển thị 10 bài viết mới nhất. Vậy mình phải thêm 1 nút nào đó để tạo click và load ra thêm 10 bài viết tiếp theo:

<a class="gini-button" href="javascript:;" id="loadmore">
	<i class="fa fa-spinner fa-spin fa-fw hidden"></i><button>Load more</button> 
</a>

Thẻ i đòi hỏi các bạn phải có fontawesome, đoạn đó có tác dụng tạo spinner quay vòng tròn khi các bạn click vào. Còn class hidden sẽ để style display:none trong trường hợp bạn không dùng bootstrap, vậy là xong button để click. Còn về style phiền các tự giúp mình nhé :3

Mình đã có bài viết, có button để click, nhưng làm gì để website hiểu rằng mình cần gọi ra 10 bài viết nữa. Mình sẽ dùng Ajax của WordPress, áp dụng 2 action wp_ajax_ và wp_ajax_nopriv_ với một chút JS để làm, bạn có thể tìm hiểu trước hoặc không có thể nhìn từ code mình để hiểu sâu hơn.

LƯU Ý: Để chạy được script này yêu cầu cần có jquery, nên vì vậy bạn cần setup sao sao jquery.min.js sẽ load trước đoạn code này nhé. (Trick nhỏ là bạn có thể để 1 mình jquery.min.js load ở trên thẻ </head>. Hoặc bạn có thể gọi trong function bằng wp_enqueue_script với hậu tố là false để ưu tiên load file lên trước nhé.)

<script type="text/javascript">
	jQuery(document).ready(function(){
		ajaxurl = '<?php echo admin_url("admin-ajax.php")?>'; //Đường dẫn chứa hàm xử lý dữ liệu
		offset = 10; // Đặt số lượng bài viết đã hiển thị ban đầu
		jQuery( "#loadmore" ).click(function() { //Script sẽ chạy khi ấn vào nút Load More đã tạo ở trên
			jQuery('#loadmore i').removeClass('hidden'); //Thẻ i sẽ bỏ class hidden, tạo ra 1 spinner quay
			jQuery.ajax({
				type:"POST", //Phương thưc truyền Post
				url:ajaxurl,
				data:{"action": "loadmore", 'offset':offset},  //Gửi các dữ liệu
				success:function(response)
				{
					if (response != 'end') {
						jQuery('#list-post').append(response);  //Chèn thêm 10 bài viết nữa vào thẻ ID list-post
						offset = offset + 10; //Tăng bài viết đã hiển thị lên 
						jQuery('#loadmore i').addClass('hidden'); // Sau khi load xong 10 bài viết mới sẽ ẩn spinner đi
						if (offset >= <?php echo $countp ?>) { 
							jQuery('#loadmore').addClass('hidden'); //Ẩn button Load more khi không còn bài viết để hiển thị tiếp nếu click
						}
					}
				}});
		});
	});
</script>

Tổng kết các thứ ở trên, ta có đoạn code hoàn chỉnh như sau, đoạn này mình chỉ thêm xét trường hợp liệu số lượng bài viết ban đầu có lớn hơn 10 hay không để hiện nút button:

<div id="list-post">  <!-- ID này sẽ đóng vai trò để truyền dữ liệu vào đây -->
	<?php 
	$the_query = new WP_Query( $args = array(
		'post_type'  => 'post',
		'posts_per_page' => 10,
		'offset' => 0,  // Lấy bài viết đầu tiên
	) );
	$countp = $the_query ->found_posts; // Mình đếm số bài viết của query mình vừa gọi
	if ( $the_query->have_posts() ) :
		?>
		<?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
			<?php get_template_part( 'template-parts/content', get_post_type() ); ?>
		<?php endwhile; ?>
	<?php endif; 
	?>	
</div>
<?php if ($countp > 10): ?> <!-- Kiểm tra liệu bài viết có lớn hơn 10 hay không -->
<script type="text/javascript">
	jQuery(document).ready(function(){
		ajaxurl = '<?php echo admin_url("admin-ajax.php")?>'; //Đường dẫn chứa hàm xử lý dữ liệu
		offset = 10; // Đặt số lượng bài viết đã hiển thị ban đầu
		jQuery( "#loadmore" ).click(function() { //Script sẽ chạy khi ấn vào nút Load More đã tạo ở trên
			jQuery('#loadmore i').removeClass('hidden'); //Thẻ i sẽ bỏ class hidden, tạo ra 1 spinner quay
			jQuery.ajax({
				type:"POST", //Phương thưc truyền Post
				url:ajaxurl,
				data:{"action": "loadmore", 'offset':offset},  //Gửi các dữ liệu
				success:function(response)
				{
					if (response != 'end') {
						jQuery('#list-post').append(response);  //Chèn thêm 10 bài viết nữa vào thẻ ID list-post
						offset = offset + 10; //Tăng bài viết đã hiển thị lên 
						jQuery('#loadmore i').addClass('hidden'); // Sau khi load xong 10 bài viết mới sẽ ẩn spinner đi
						if (offset >= <?php echo $countp ?>) { 
							jQuery('#loadmore').addClass('hidden'); //Ẩn button Load more khi không còn bài viết để hiển thị tiếp nếu click
						}
					}
				}});
		});
	});
</script>
<a class="gini-button" href="javascript:;" id="loadmore">
	<i class="fa fa-spinner fa-spin fa-fw hidden"></i><button>Load more</button> 
</a>
<?php endif ?>

Vậy là được 70% công việc rồi, giờ mình xử lý nốt các dữ liệu gửi lên sever là xong, bạn copy đoạn sau vào file function.php:

add_action( 'wp_ajax_nopriv_loadmore', 'prefix_load_posts' );
add_action( 'wp_ajax_loadmore', 'prefix_load_posts' );
function prefix_load_posts () {
	$offset = !empty($_POST['offset']) ? intval( $_POST['offset'] ) : '';
	if ($offset) {
		$the_query = new WP_Query( $args = array(
			'post_type'  => 'post',
			'posts_per_page' => 10,
			'offset' => $offset,
		) );
		if ( $the_query->have_posts() ) : ?>  
				<?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
					<?php global $post ?>
					<?php get_template_part( 'template-parts/content', get_post_type() ); ?>
				<?php endwhile; ?>
			<?php
		else:
			echo 'end';
		endif;
		wp_reset_postdata();
	}
	die();
}

Vậy là code đã chạy rồi đó :3 Các bạn có thể tùy biến sao theo ý bạn nhé.

LƯU Ý: loadmore ở đây là action, với nhiều trường hợp bạn tạo nhiều load ajax trong 1 website, các bạn có thể đặt tên khác là loadmore2, loadmore 3

Load more bài viết theo chuyên mục

Trường hợp này khá dùng nhiều ở taxonomy-xxx.php hoặc một số trường hợp hiển thị một chuyên mục chỉ định ở trang chủ hoặc bài viết. Phương pháp vẫn giống cách trên nhưng các bạn cần thêm một biến nữa chính là id chuyên mục:

<div id="list-post">  <!-- ID này sẽ đóng vai trò để truyền dữ liệu vào đây -->
	<?php 
	$the_query = new WP_Query( $args = array(
		'post_type'  => 'post',
		'posts_per_page' => 10,
		'tax_query' => array(
			array(
				'taxonomy' => 'category',
				'field' => 'term_id',
				'terms' =>  get_queried_object_id(), // get_queried_object_id sẽ là ID của category trong trang lưu trữ
			)
		),
		'offset' => 0,  // Lấy bài viết đầu tiên
	) );
	$countp = $the_query ->found_posts; // Mình đếm số bài viết của query mình vừa gọi
	if ( $the_query->have_posts() ) :
		?>
		<?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
			<?php get_template_part( 'template-parts/content', get_post_type() ); ?>
		<?php endwhile; ?>
	<?php endif; 
	?>	
</div>
<?php if ($countp > 10): ?> <!-- Kiểm tra liệu bài viết có lớn hơn 10 hay không -->
<script type="text/javascript">
	jQuery(document).ready(function(){
		ajaxurl = '<?php echo admin_url("admin-ajax.php")?>'; //Đường dẫn chứa hàm xử lý dữ liệu
		offset = 10; // Đặt số lượng bài viết đã hiển thị ban đầu
		jQuery( "#loadmore" ).click(function() { //Script sẽ chạy khi ấn vào nút Load More đã tạo ở trên
			jQuery('#loadmore i').removeClass('hidden'); //Thẻ i sẽ bỏ class hidden, tạo ra 1 spinner quay
			var id_cat = <?php echo get_queried_object_id(); ?>; //Đặt biến để gửi lên sever
			jQuery.ajax({
				type:"POST", //Phương thưc truyền Post
				url:ajaxurl,
				data:{"action": "loadmore",'id_cat':id_cat,'offset':offset},  //Gửi các dữ liệu
				success:function(response)
				{
					if (response != 'end') {
						jQuery('#list-post').append(response);  //Chèn thêm 10 bài viết nữa vào thẻ ID list-post
						offset = offset + 10; //Tăng bài viết đã hiển thị lên 
						jQuery('#loadmore i').addClass('hidden'); // Sau khi load xong 10 bài viết mới sẽ ẩn spinner đi
						if (offset >= <?php echo $countp ?>) { 
							jQuery('#loadmore').addClass('hidden'); //Ẩn button Load more khi không còn bài viết để hiển thị tiếp nếu click
						}
					}
				}});
		});
	});
</script>
<a class="gini-button" href="javascript:;" id="loadmore">
	<i class="fa fa-spinner fa-spin fa-fw hidden"></i><button>Load more</button> 
</a>
<?php endif ?>

LƯU Ý: get_queried_object_id() là hàm get ID chuyên mục ở trang lưu trữ. Tùy vào trường hợp mà bạn get ID nhé. Có gì khó khăn hãy bình luận phía dưới.

Trong Function.php:

add_action( 'wp_ajax_nopriv_loadmore', 'prefix_load_posts' );
add_action( 'wp_ajax_loadmore', 'prefix_load_posts' );
function prefix_load_posts () {
	$id_cat = !empty($_POST['id_cat']) ? intval( $_POST['id_cat'] ) : '';
	$offset = !empty($_POST['offset']) ? intval( $_POST['offset'] ) : '';
	if ($id_cat  && $offset) {
		$the_query = new WP_Query( $args = array(
			'post_type'  => 'post',
			'posts_per_page' => 10,
			'offset' => $offset,
			'tax_query' => array(
				array(
					'taxonomy' => 'category',
					'field' => 'term_id',
					'terms' =>  $id_cat,
				)
			),
		) );
		if ( $the_query->have_posts() ) : ?>  
			<?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
				<?php global $post ?>
				<?php get_template_part( 'template-parts/content', get_post_type() ); ?>
			<?php endwhile; ?>
			<?php
		else:
			echo 'end';
		endif;
		wp_reset_postdata();
	}
	die();
}

Khá dễ phải không nào? Có vấn đề gì khó khăn bạn có thể comment để mình hỗ trợ sớm nhất nhé. Cảm ơn các bạn đã đọc bài!

Subscribe
Notify of
guest
2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Tiến
Tiến
9 months ago

Mình muốn truyền vào 2 ID trở lên thì làm như nào bạn

Hãy để Gini Webseo tư vấn cho bạn