Skip to content

Instantly share code, notes, and snippets.

@Niq1982
Last active April 9, 2024 17:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save Niq1982/4d0b97915d3d0681959dc3a50986271e to your computer and use it in GitHub Desktop.
Save Niq1982/4d0b97915d3d0681959dc3a50986271e to your computer and use it in GitHub Desktop.
Load more to WordPress blog archive using AlpineJS and Axios
<div class="card">
<?php if ($args['link']) : ?>
<a href="<?php echo esc_url($args['link']); ?>" class="global-link">
</a>
<?php endif; ?>
<div class="card-image">
<?php wp_get_attachment_image($args['image']); ?>
</div>
<div class="card-content">
<h2>
<?php echo esc_html($args['title']) ?>
</h2>
<p>
<?php echo wp_kses_post($args['subtitle']) ?>
</p>
<div class="content">
<?php echo wp_kses_post($args['content']); ?>
</div>
</div>
</div>
<?php
add_action('wp_enqueue_scripts', function () {
wp_enqueue_script('load-more', get_theme_file_uri('js/load-more.js'),filemtime(get_theme_file_path('js/load-more.js')),true);
wp_localize_script('load-more', 'wpApiSettings', array(
'root' => esc_url_raw(rest_url()),
'nonce' => wp_create_nonce('wp_rest'),
));
});
add_action('rest_api_init', function () {
register_rest_field('post', 'card',
[
'get_callback' => function ($post) {
ob_start();
get_template_part('template-parts/card', '', [
'image' => get_post_thumbnail_id($post['id']),
'link' => get_permalink($post['id']),
'title' => get_the_title($post['id']),
'subtitle' => sprintf('<time datetime="%1$s">%2$s</time>', get_the_time('c', $post['id']), get_the_date(get_option('date_format'), $post['id'])),
'content' => get_the_sentence_excerpt(3, get_the_excerpt($post['id'])),
]);
return ob_get_clean();
},
]
);
});
<?php
get_header();
global $wp_query;
?>
<main class="site-main">
<section class="blog">
<div class="container" x-data="loadMore(<?php echo esc_attr($wp_query->post_count) ?>, 5)">
<?php if (have_posts()) : ?>
<?php while (have_posts()) : the_post(); ?>
<article>
<?php get_template_part('template-parts/card', '', [
'image' => get_post_thumbnail_id(),
'link' => get_permalink(),
'title' => get_the_title(),
'subtitle' => sprintf('<time datetime="%1$s">%2$s</time>', get_the_time('c'), get_the_date()),
'content' => get_the_sentence_excerpt(),
]); ?>
</article>
<?php endwhile; ?>
<?php endif; ?>
<?php if ($wp_query->post_count < $wp_query->found_posts) : ?>
<template x-for="post in posts">
<article x-html="post.card" x-data="{ show: false }" x-init="$nextTick(() => { show = true })" x-show="show" x-transition.duration.500ms x-transition.scale.origin.top.left></article>
</template>
<button x-bind:disabled="loading" x-show="hasMore" x-on:click="loadMore" class="button">Load more</button>
<?php endif ?>
</div>
</section>
</main>
<?php get_footer();
import axios from 'axios';
import Alpine from 'alpinejs';
const apiRoot = window.wpApiSettings.root;
const nonce = window.wpApiSettings.nonce;
const api = axios.create({
baseURL: `${apiRoot}wp/v2/`,
headers: { 'X-WP-Nonce': nonce },
});
Alpine.data('loadMore', (initialOffset, perPage) => {
return {
offset: initialOffset,
posts: [],
perPage,
hasMore: true,
loading: false,
loadMore() {
this.loading = true;
api.get('posts', {
params: {
offset: this.offset,
per_page: this.perPage,
'_fields': 'card',
},
})
.then((response) => {
this.handleResponse(response);
})
.catch((error) => {
console.log(error);
});
},
handleResponse(response) {
if (!response?.data?.length) {
this.hasMore = false;
return;
}
// Put posts in the view one at a time with a delay for fancier transition
response.data.forEach((post, index) => {
setTimeout(() => {
this.posts.push(post);
this.offset += 1;
}, index * 100);
});
// Show more button if there are more posts to load
this.hasMore = response.data.length === this.perPage;
this.loading = false;
}
}
});
Alpine.start();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment