WordPress LazyLoad Posts - markhowellsmead/helpers GitHub Wiki
This solution uses the REST API to lazy-load posts on demand. The loading in this example takes place when a button is clicked.
Load the script file /assets/scripts/lazy-load-posts.min.js in the frontend if there is an element with the data attribute data-load-posts
.
(function () {
if(document.querySelector('[data-load-posts]').length) {
const lazy_script = document.createElement('script');
lazy_script.setAttribute('src', shtThemeData.directory_uri + '/assets/scripts/lazy-load-posts.min.js');
document.head.appendChild(lazy_script);
}
})();
The content of that file handles the magic.
String.prototype.replaceAll = function (search, replacement) {
var target = this;
return target.replace(new RegExp(search, 'g'), replacement);
};
(function ($) {
var $list,
$button, $buttonWrapper,
$api_link = null,
api_root = null,
card_template = '',
pageIndex = 2;
var appendPosts = function (posts, textStatus, jqXHR) {
if(parseInt(jqXHR.getResponseHeader('X-WP-TotalPages')) === pageIndex) {
$buttonWrapper.hide();
} else {
$button.removeAttr('disabled');
}
pageIndex++;
var resultCards = '';
$.each(posts, function () {
resultCards += card_template.replaceAll('{{ data.id }}', this.id)
.replaceAll('{{ data.date_c }}', this.date_c)
.replaceAll('{{ permalink }}', this.link)
.replaceAll('{{ title }}', this.title.rendered)
.replaceAll('{{ excerpt }}', this.excerpt && this.excerpt.rendered ? '<div class="c-cardlist__excerpt">' + this.excerpt.rendered + '</div>' : '')
.replaceAll('{{ thumbnail }}', this.cardlist_image !== '' ? this.cardlist_image : '<div class="c-cardlist__figure c-cardlist__figure--empty"></div>')
.replaceAll('{{ author_text }}', this.author_text);
});
$list.append($(resultCards));
if($list.data('masonry')) {
$list.isotope('appended', $resultCards);
$list.isotope('layout');
$list.imagesLoaded().progress(function () {
$list.isotope('layout');
});
}
$(window).trigger('ct::updateequalizer');
};
$(document).ready(function () {
$api_link = $('link[rel="https://api.w.org/"]');
api_root = $api_link.attr('href');
card_template = $('[data-post-template]').html();
$list = $('[data-lazyload-posts]');
$buttonWrapper = $('[data-load-posts-wrapper]');
$button = $('[data-load-posts]');
per_page = $button.data('load-posts');
if(parseInt($list.data('lazyload-total-posts')) <= parseInt($list.data('lazyload-per-page'))) {
$button.hide();
} else {
$button.on('click.loadposts', function () {
$(this).blur();
$(this).attr('disabled', 'disabled');
var requestData = {
_embed: true,
page: pageIndex,
per_page: per_page,
lang: $('html').attr('lang').substring(0, 2)
};
switch ($list.data('lazyload-termtype')) {
case 'tag':
requestData.tags = parseInt($list.data('lazyload-term'));
break;
case 'category':
requestData.categories = parseInt($list.data('lazyload-term'));
break;
}
if(parseInt($list.data('lazyload-per-page'))) {
requestData.per_page = parseInt($list.data('lazyload-per-page'));
}
$.ajax({
type: "GET",
dataType: "json",
url: api_root + 'wp/v2/posts',
data: requestData,
success: function (data, textStatus, jqXHR) {
appendPosts(data, textStatus, jqXHR);
}
});
});
}
});
})(jQuery);
This needs to be modified according to the requirements of the template.
<?php
namespace SayHello\Theme\Package;
use SayHello\Theme\Package\Lazysizes;
use WP_REST_Response;
use WP_Post;
use WP_REST_Request;
class REST
{
public function run()
{
add_action('rest_prepare_post', [$this, 'modifyGetPostData'], 10, 3);
}
public function modifyGetPostData(WP_REST_Response $response, WP_Post $post, WP_REST_Request $context)
{
if ($post->post_type === 'post') {
$response->data['date_legible'] = date(get_option('date_format'), strtotime($response->data['date']));
$response->data['date_c'] = date('c', strtotime($response->data['date']));
$response->data['author_text'] = sprintf(
_x('By %s %s', 'Single post view author / date', 'sht'),
get_the_author_meta('user_nicename', $post->post_author),
get_the_date('M j Y', $post)
);
$response->data['cardlist_image'] = '';
if (!!$response->data['featured_media']) {
$response->data['cardlist_image'] = Lazysizes::getLazyImage(
$response->data['featured_media'],
'thumbnail-retina',
'c-cardlist__figure',
'c-cardlist__image'
);
}
if (!empty($excerpt = $post->post_excerpt)) {
$response->data['excerpt']['rendered'] = wp_trim_words($excerpt, 60, '… <a href="'. esc_url(get_permalink()) . '">'. __('Read more »', 'sht') . '</a>');
}
}
return $response;
}
}
The content of the template part partials/news/card-dynamic.php is accessed by JavaScript.
<?php
/**
* Template used for inline lazyloader in frontend
*/
?>
<li class="c-cardlist__entry">
{{ thumbnail }}
<h3 class="c-cardlist__entrytitle"><span class="c-cardlist__entrytitlepre"><?php _ex('News:', 'Card entry title prefix', 'sht');?></span>
<a href="{{ permalink }}">{{ title }}</a>
</h3>
{{ excerpt }}
<time class="c-cardlist__entrydate" datetime="{{ date_c }}">
{{ author_text }}
</time>
</li>
Load the template part file above at the bottom of the cardlist PHP file, thus.
<script type="text/template" data-post-template>
<?php
get_template_part('partials/news/card-dynamic');
?>
</script>
Modify the <ul class="c-cardlist__entries">
element, thus.
<ul class="c-cardlist__entries" data-lazyload-posts data-lazyload-per-page="<?php echo $GLOBALS['wp_query']->query_vars['posts_per_page'];?>" data-lazyload-total-posts="<?php echo $GLOBALS['wp_query']->found_posts;?>">
Add the loader button within the <div class="c-cardlist__inner">
element.
<?php
if ($GLOBALS['wp_query']->found_posts > $GLOBALS['wp_query']->query_vars['posts_per_page']) {?>
<div class="c-cardlist__loadmorewrapper" data-load-posts-wrapper>
<button class="c-cardlist__loadmore" data-load-posts="<?php echo $posts_per_page;?>"><?php _ex('View more', 'Button text to load more posts', 'sht');?></button>
</div>
<?php }?>