WordPress-Fetch-Posts/blog.js

187 lines
6.2 KiB
JavaScript

/**
* The base URI for the WordPress API. Don't forget `http(s)://`!
* Depending on where your WordPress blog is hosted, this could be something like: `https://example.wordpress.com`
*/
const wordPressBaseUri = 'https://wptest.decicus.com';
/**
* The selector for the container where we want to put the posts.
* By default it is `#blog-posts` (element with ID "blog-posts"), which you can find in `blog.html`
*/
const postsContainerSelector = '#blog-posts';
/**
* The selector for the "View More" button.
* By default it is `#view-more` (element with ID "view-more"), which you can find in `blog.html`
*/
const viewMoreButtonSelector = '#view-more';
/**
* When clicking "View more" to retrieve posts on page 2 and beyond
* set this to `true` to scroll to the first post of the new batch of posts.
*
* If you do not want this behavior, set this to `false`.
*
* By default this is `true`.
*/
const scrollToPosts = true;
/**
* Classes to add to the post's parent div.
* By default these are Tailwind CSS classes: https://tailwindcss.com/
*/
const postElementClasses = ['bg-rose-900', 'p-4', 'my-4'];
/**
* Classes to add to the post's title.
* By default these are Tailwind CSS classes: https://tailwindcss.com/
*/
const postTitleClasses = ['text-xl', 'font-bold', 'mb-2'];
/**
* Class to add to the "View More" button when there are no more posts to fetch.
* By default this is a Tailwind CSS class called `hidden`: https://tailwindcss.com/docs/display#hidden
*/
const hideClass = 'hidden';
/**
* Fetches 10 posts from WordPress API.
* Uses: https://developer.wordpress.org/rest-api/reference/posts/#list-posts
*
* @param {Number} page Which page to fetch, by default the first page (1)
* @param {Number} perPage How many posts to fetch per page, by default 10
* @returns {Array}
*/
async function fetchPosts(page = 1, perPage = 10)
{
const response = await fetch(`${wordPressBaseUri}/wp-json/wp/v2/posts?page=${page}&per_page=${perPage}`);
const json = await response.json();
return json;
}
/**
* Used for tracking what "page" from the WordPress API we should be fetching.
* You should generally not change this value.
*/
let nextPage = 1;
/**
* Can be used for tweaking how many posts to get per page.
* Will also affect how many times you have to click "View more" to get all posts
*/
const perPage = 10;
const viewMoreButton = document.querySelector(viewMoreButtonSelector);
async function getPosts()
{
// Disable the "View More" button while we're fetching posts, to avoid people spamming the button
viewMoreButton.setAttribute('disabled', '1');
// Get the first set of posts from the API
const posts = await fetchPosts(nextPage, perPage);
// Get the container where we want to put the posts. By default this can just be an empty div.
const postsContainer = document.querySelector(postsContainerSelector);
/**
* Style points only
*/
let firstPostId = null;
// Loop though the posts and create the HTML elements for each post
for (const post of posts)
{
/**
* Style points only
*
* Since `firstPostId` is still `null`, we set it to the post's ID.
* Any further posts in this batch will *not* override it.
* Meaning it will in fact be "the first post" (of this batch).
*/
if (firstPostId === null)
{
firstPostId = post.id;
}
// Create post's parent div
const postElement = document.createElement('div');
postElement.setAttribute('data-post-id', post.id);
postElement.classList.add('post');
/**
* Adding classes to the post's parent div.
* Primarily for styling purposes.
*/
for (const postElementClass of postElementClasses)
{
postElement.classList.add(postElementClass);
}
// Create post's title as a h2
const postTitle = document.createElement('h2');
postTitle.textContent = post.title.rendered;
/**
* Adding classes to the post's title.
* Primarily for styling purposes.
*/
for (const postTitleClass of postTitleClasses)
{
postTitle.classList.add(postTitleClass);
}
// Create post's content. This is a div because WordPress will give you a lot of HTML tags in the content (e.g. `p`).
const postContent = document.createElement('div');
postContent.innerHTML = post.content.rendered;
// Append the title and content to the post's parent div
postElement.appendChild(postTitle);
postElement.appendChild(postContent);
// Append the post's parent div to the container
postsContainer.appendChild(postElement);
}
/**
* Style points only
* Only trigger this logic after the "view more" button has been pressed
*/
if (nextPage > 1 && scrollToPosts) {
/**
* Style points only
* Scroll to the first post we got from the API.
* This will scroll to the first post of the current batch of posts
*/
const firstPost = document.querySelector(`[data-post-id="${firstPostId}"]`);
firstPost.scrollIntoView({ behavior: 'smooth' });
}
/**
* If the amount of posts we got from the API is less than the amount of posts we requested,
* then we know that we have reached the end of the posts and we can hide the "View More" button.
*/
const viewMoreClasses = viewMoreButton.classList;
if (posts.length >= perPage)
{
viewMoreClasses.remove(hideClass);
// Increase `nextPage` by 1 so that the next time we fetch posts, we get the next page
nextPage++;
}
/**
* If the amount of posts we got from the API is less than the amount of posts we requested,
* then we know that we have reached the end of the posts and we can hide the "View More" button.
*/
else {
viewMoreClasses.add(hideClass);
}
// Re-enable the "View More" button
viewMoreButton.removeAttribute('disabled');
}
// Add an event listener to the "View More" button so that we can fetch more posts when it's clicked
viewMoreButton.addEventListener('click', getPosts);
// Run the `getPosts` function once when the page loads
getPosts();