This guide shows you how to add a new category page (like Admin, Sales, or Marketing) that automatically lists every page underneath it, no manual updating needed. Add a new page anywhere in that category, and it shows up on the list by itself.
Each category page has two parts you'll paste in separately:
/en/MarketingPaste this into the main content editor, then update the 3 highlighted spots (icon (📣), title (Marketing), description (Brand assets, campaign resources, and everything to support your marketing efforts.):
<div class="cat-page">
<div class="cat-header">
<div class="cat-header-content">
<span class="cat-icon" id="cat-icon">📣</span>
<h2 id="cat-title">Marketing</h2>
<p id="cat-desc">Brand assets, campaign resources, and everything to support your marketing efforts.</p>
</div>
</div>
<div class="cat-meta"><span class="cat-count">Pages: <span id="page-count">–</span></span></div>
<input class="cat-search" id="cat-search" type="text" placeholder="Search pages…" oninput="filterPages(this.value)" />
<div id="cat-results"><div class="cat-loading">Loading pages…</div></div>
</div>
CHANGE THESE — PATH_PREFIX, PAGE_TITLE, PAGE_DESC, and PAGE_ICONSOPs/Amember,PRODUCT, etc)API_KEY exactly as it is in the code below — every category page uses this same key, so there's nothing to look up or configure there.<script>
window.boot.register('page-ready', function() {
/* ===================================================
CHANGE THESE 4 VALUES FOR EACH CATEGORY PAGE
=================================================== */
var API_KEY = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcGkiOjMsImdycCI6MTAsImlhdCI6MTc4MzYxMjcyNiwiZXhwIjoxODE1MTcwMzI2LCJhdWQiOiJ1cm46d2lraS5qcyIsImlzcyI6InVybjp3aWtpLmpzIn0.oqxhkgEucG_9fD_AWYM5tlMUXkAnvRQIN9th1Q7rmcEC0zBIkbMc4CnzkI6Xv3u4XnC0vTro90Tae-Vc3r3LubpzOCcSwdkafYN44_sG4z27utBPZlgbL3YUffTgURrj5Xk4MPKkDEBYerDjmjuDxDGX6WJ_w3YGPtFSD7XYegfbTB_5qDErluLZ5n4AuB7x4ZGzoDpfpnTP_GuG096QjuNYFQ5Mtl5ewZ_D_eZNdO5IOtI-cVLJSsY5sWqW9P0kDj9jy5kfRqP0JScAQmsf4kzapTMCQvmNUWkl9pnzY90yErdKOZUmT05fZ-IVG_1NEVhklouDIUUS8NElMMVhSA';
var PATH_PREFIX = 'Marketing';
var PAGE_TITLE = 'Marketing';
var PAGE_DESC = 'Brand assets, campaign resources, and everything to support your marketing efforts.';
var PAGE_ICON = '📣';
/* =================================================== */
var titleEl = document.getElementById('cat-title');
var descEl = document.getElementById('cat-desc');
var iconEl = document.getElementById('cat-icon');
var searchEl = document.getElementById('cat-search');
if (!titleEl || !descEl || !iconEl || !searchEl) {
return;
}
var allPages = [];
titleEl.textContent = PAGE_TITLE;
descEl.textContent = PAGE_DESC;
iconEl.textContent = PAGE_ICON;
searchEl.placeholder = 'Search pages in ' + PAGE_TITLE + '…';
function escHtml(str){
return String(str||'').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
}
function renderPages(pages){
var container = document.getElementById('cat-results');
document.getElementById('page-count').textContent = pages.length;
if(pages.length === 0){
container.innerHTML = '<div class="cat-empty"><span class="cat-empty-icon">📭</span><p>No pages found yet.<br>Create a page whose path starts with <strong>' + escHtml(PATH_PREFIX) + '</strong> and it will appear here automatically.</p></div>';
return;
}
var html = '<div class="cat-grid">';
for(var i = 0; i < pages.length; i++){
var p = pages[i];
html += '<a class="cat-item" href="/' + escHtml(p.path) + '">';
html += '<div class="cat-item-icon">📄</div>';
html += '<div class="cat-item-body">';
html += '<span class="cat-item-title">' + escHtml(p.title || p.path) + '</span>';
html += '<span class="cat-item-path">' + escHtml(p.path) + '</span>';
html += '</div><span class="cat-item-arrow">›</span></a>';
}
html += '</div>';
container.innerHTML = html;
}
function filterPages(query){
var q = query.toLowerCase().trim();
var filtered = q ? allPages.filter(function(p){
return (p.title||'').toLowerCase().indexOf(q) > -1 || (p.path||'').toLowerCase().indexOf(q) > -1;
}) : allPages;
renderPages(filtered);
}
window.filterPages = filterPages;
function showError(msg){
document.getElementById('cat-results').innerHTML = '<div class="cat-error">⚠️ ' + escHtml(msg) + '</div>';
document.getElementById('page-count').textContent = '–';
}
function loadPages(){
if(!API_KEY){
showError('No API key set. Contact the wiki admin for the shared API key.');
return;
}
var prefix = PATH_PREFIX.toLowerCase().replace(/^\/+/,'').replace(/\/+$/,'');
fetch('/graphql', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer ' + API_KEY
},
body: JSON.stringify({
query: '{ pages { list(orderBy: TITLE) { id path title description } } }'
})
})
.then(function(res){
if(!res.ok) throw new Error('HTTP ' + res.status + ' — check that the API is enabled in Wiki.js Admin → API Access.');
return res.json();
})
.then(function(json){
if(json.errors && json.errors.length) throw new Error(json.errors[0].message);
if(!json.data || !json.data.pages) throw new Error('Unexpected response from API — the key may not have read access.');
var list = json.data.pages.list;
allPages = list.filter(function(p){
var path = (p.path||'').toLowerCase().replace(/^\/+/,'');
return path.indexOf(prefix.toLowerCase() + '/') === 0;
});
renderPages(allPages);
})
.catch(function(err){
showError(err.message || 'Unknown error. Open the browser console for more details.');
});
}
loadPages();
});
</script>
Save the page, then reload it. You should see a page count and a grid of every page whose path starts with your PATH_PREFIX. New pages added under that path will appear automatically — nothing else to maintain.
Stuck on "Loading pages…" forever, no error shown This usually means the script never ran. Two common causes:
- HTML sanitization stripped it. Go to Administration → Rendering → HTML → Security and make sure "Sanitize HTML" is off. If you only just turned it off, you'll need to re-save this page's content for the fix to take effect (already-saved content stays stripped until re-saved).
- Wrong tab. Double check the script is in the Script tab under Page Properties, not pasted into the main body content — pasting a <script> tag into the body won't run reliably even with sanitization off.
- An error message appears in the results area The error message itself will tell you what's wrong — usually either a bad/expired API key, or the API being disabled under Admin → API Access.
- Nothing shows up, but no error either, and page count shows 0 Check that PATH_PREFIX exactly matches the parent path of your category (case doesn't matter, but spelling does), and that there's at least one page saved underneath it.