Demo
Requirements
- The Init View Count plugin is installed and collecting real view data.
- Your theme supports UIkit (at least
uk-tab,uk-switcher,uk-gridclasses). - You are comfortable adding JavaScript to your theme or plugin (via
wp_enqueue_scriptor inline scripts).
1. Create the HTML structure for the ranking board
Start by building a simple HTML layout using uk-tab for the time range tabs and uk-switcher to toggle the associated content.
<h3>Demo</h3>
<div id="view-ranking" class="uk-margin">
<ul class="uk-tab" data-uk-tab>
<li class="uk-active"><a href="#" data-range="total">All Time</a></li>
<li><a href="#" data-range="day">Today</a></li>
<li><a href="#" data-range="week">This Week</a></li>
<li><a href="#" data-range="month">This Month</a></li>
</ul>
<ul class="uk-switcher uk-margin">
<li>
<div class="ranking-content" data-range="total" data-loaded="false">
<!-- Skeleton for the first tab only -->
<div class="uk-grid-small uk-flex-middle uk-margin-small" uk-grid>
<div class="uk-width-auto">
<div class="uk-background-muted uk-border-rounded" style="width:60px; height:60px;"></div>
</div>
<div class="uk-width-expand">
<div class="uk-margin-small">
<div class="uk-background-muted uk-border-rounded" style="height: 16px; width: 80%;"></div>
</div>
<div class="uk-margin-small-top">
<div class="uk-background-muted uk-border-rounded" style="height: 12px; width: 60%;"></div>
</div>
</div>
</div>
<div class="uk-grid-small uk-flex-middle uk-margin-small" uk-grid>
<div class="uk-width-auto">
<div class="uk-background-muted uk-border-rounded" style="width:60px; height:60px;"></div>
</div>
<div class="uk-width-expand">
<div class="uk-margin-small">
<div class="uk-background-muted uk-border-rounded" style="height: 16px; width: 80%;"></div>
</div>
<div class="uk-margin-small-top">
<div class="uk-background-muted uk-border-rounded" style="height: 12px; width: 60%;"></div>
</div>
</div>
</div>
<div class="uk-grid-small uk-flex-middle uk-margin-small" uk-grid>
<div class="uk-width-auto">
<div class="uk-background-muted uk-border-rounded" style="width:60px; height:60px;"></div>
</div>
<div class="uk-width-expand">
<div class="uk-margin-small">
<div class="uk-background-muted uk-border-rounded" style="height: 16px; width: 80%;"></div>
</div>
<div class="uk-margin-small-top">
<div class="uk-background-muted uk-border-rounded" style="height: 12px; width: 60%;"></div>
</div>
</div>
</div>
<div class="uk-grid-small uk-flex-middle uk-margin-small" uk-grid>
<div class="uk-width-auto">
<div class="uk-background-muted uk-border-rounded" style="width:60px; height:60px;"></div>
</div>
<div class="uk-width-expand">
<div class="uk-margin-small">
<div class="uk-background-muted uk-border-rounded" style="height: 16px; width: 80%;"></div>
</div>
<div class="uk-margin-small-top">
<div class="uk-background-muted uk-border-rounded" style="height: 12px; width: 60%;"></div>
</div>
</div>
</div>
<div class="uk-grid-small uk-flex-middle uk-margin-small" uk-grid>
<div class="uk-width-auto">
<div class="uk-background-muted uk-border-rounded" style="width:60px; height:60px;"></div>
</div>
<div class="uk-width-expand">
<div class="uk-margin-small">
<div class="uk-background-muted uk-border-rounded" style="height: 16px; width: 80%;"></div>
</div>
<div class="uk-margin-small-top">
<div class="uk-background-muted uk-border-rounded" style="height: 12px; width: 60%;"></div>
</div>
</div>
</div>
</div>
</li>
<li>
<div class="ranking-content" data-range="day" data-loaded="false"></div>
</li>
<li>
<div class="ranking-content" data-range="week" data-loaded="false"></div>
</li>
<li>
<div class="ranking-content" data-range="month" data-loaded="false"></div>
</li>
</ul>
</div>
The first tab (All Time) includes static skeleton loading blocks directly in the HTML to prevent layout shifting while the data is loading.
2. Add JavaScript to fetch and display data from the REST API
Next, write JavaScript to call the /wp-json/initvico/v1/top API, which returns the most viewed posts for each time range. Each tab only loads data when the user clicks it, helping reduce unnecessary API calls and improve performance.
document.addEventListener('DOMContentLoaded', function () {
const container = document.getElementById('view-ranking');
if (!container) return;
const tabs = container.querySelectorAll('.uk-tab a');
const contents = container.querySelectorAll('.ranking-content');
const cache = {};
function renderItem(item) {
return `
<div class="uk-grid-small uk-flex-middle uk-margin-small" uk-grid>
<div class="uk-width-auto">
<a href="${item.link}">
<img src="${item.thumbnail}" alt="${item.title}" width="60" height="60" style="object-fit:cover;" class="uk-border-rounded">
</a>
</div>
<div class="uk-width-expand">
<h5 class="uk-margin-remove">
<a href="${item.link}" class="uk-link-heading">${item.title}</a>
</h5>
<div class="uk-text-meta">${item.views.toLocaleString()} views · ${item.date}</div>
</div>
</div>
`;
}
function renderLoading() {
let skeleton = '';
for (let i = 0; i < 5; i++) {
skeleton += `
<div class="uk-grid-small uk-flex-middle uk-margin-small" uk-grid>
<div class="uk-width-auto">
<div class="uk-background-muted uk-border-rounded" style="width:60px; height:60px;"></div>
</div>
<div class="uk-width-expand">
<div class="uk-margin-small">
<div class="uk-background-muted uk-border-rounded" style="height: 16px; width: 80%;"></div>
</div>
<div class="uk-margin-small-top">
<div class="uk-background-muted uk-border-rounded" style="height: 12px; width: 60%;"></div>
</div>
</div>
</div>
`;
}
return skeleton;
}
function loadRanking(range, target) {
if (cache[range]) {
target.innerHTML = cache[range];
return;
}
// Only show loading state for non-initial tabs
if (range !== 'total') {
target.innerHTML = renderLoading();
}
fetch(`/wp-json/initvico/v1/top?range=${range}&number=5`)
.then(res => res.json())
.then(data => {
if (!Array.isArray(data)) return;
const html = data.map(renderItem).join('');
cache[range] = html;
target.innerHTML = html || '<div class="uk-text-muted">No data available.</div>';
target.dataset.loaded = "true";
})
.catch(() => {
target.innerHTML = '<div class="uk-text-danger">Failed to load data.</div>';
});
}
// Map data-range => content element
const contentMap = {};
contents.forEach(content => {
const range = content.dataset.range;
if (range) contentMap[range] = content;
});
// Auto-load the default tab ("All Time")
const firstRange = container.querySelector('.uk-tab .uk-active a')?.dataset.range;
if (firstRange && contentMap[firstRange]) {
loadRanking(firstRange, contentMap[firstRange]);
}
// Load on tab switch
tabs.forEach(tab => {
tab.addEventListener('click', function () {
const range = this.dataset.range;
const target = contentMap[range];
if (!target || target.dataset.loaded === "true") return;
loadRanking(range, target);
});
});
});
The first tab will skip rendering skeletons via JavaScript, since they’re already included in the HTML. Other tabs will display a loading state dynamically using a JavaScript function before replacing it with actual data.
Note for non-UIkit users
If you’re using a different CSS framework like Bootstrap, Tailwind, or custom CSS, feel free to replace UIkit classes such as uk-tab, uk-switcher, uk-grid, and uk-text-meta with ones that match your setup. As long as the HTML structure remains intact, you can fully adapt the styling to your own design system.
Conclusion
With Init View Count and a bit of JavaScript, you can build a beautiful, flexible, and high-performance post ranking board. This is a practical example of how to use the plugin’s REST API to power a modern frontend without relying on PHP shortcodes.
Comments