Pages and ordering

Page path is the addon's main organising axis — how the page list is built by scanning your frontend, what per-page enable, disable and delete really do, how reordering works, and why the stock help centre ignores page assignment.

6 min readUpdated 3 August 2026pages, ordering, organisation

Every article carries a page path, and it is required. Category is how readers browse; page path is how you organise. The admin Manage screen opens grouped by it, and there are three bulk actions that operate on a whole page at once.

Getting this wrong is cheap to fix for one article and expensive for a hundred, so decide your scheme before you write a library.

What a page path is

A site-relative path, starting with /, at most 200 characters. /faq is the default and where most installs put everything.

It is a label on the article, not a foreign key. Nothing verifies that the path corresponds to a page that exists, and nothing breaks if it does not. You can use /faq/deposits as a grouping even though no such route exists in your frontend — the articles will still appear on the help centre, still be searchable, and still be grouped together in the admin.

That flexibility is the reason to be deliberate. Two articles typed as /faq and /faq/ are on two different pages as far as this addon is concerned, and the by-page view will show them as two separate groups with one article each.

The page picker is generated from your frontend

When you open the page selector, the list is not a stored set of options. The backend walks the Next.js app directory looking for page.tsx and page.jsx files and derives a route for each one. Directories starting with _ or ., and the api, admin and auth trees, are skipped; [locale] is stripped so the paths are locale-independent; and anything containing /admin, /auth, /api, /error, or equal to /404 or /500 is filtered out of the result.

Each entry comes back with a path, a friendly name derived from the segments, and a group taken from the first segment — which is what the picker's group filter sorts on.

Two consequences:

  • The list reflects your build, not your content. Add a page to the frontend and it appears in the picker. Remove one and it disappears — but any articles already assigned to it keep their path and keep working.
  • It is a filesystem scan on every request. The scan is asynchronous and does not block the server, but it is not free. On a very large frontend the picker is noticeably slower to populate than the rest of the form.

You are not restricted to what the picker offers. The path is a text field on the API; the picker is a convenience.

The by-page view

The Manage screen has two modes, By page and All, and opens on By page.

Each page section shows a count badge. That count comes from a dedicated per-page-count endpoint that groups over the whole table — not from the rows currently loaded. On a paginated list those two numbers disagree constantly, and a badge that reports the size of one page of results is worse than no badge at all.

The same principle applies to the active/inactive counters at the top of the list: they are computed across every row matching your current filters except the status filter, so switching between the Active and Inactive tabs does not change the numbers that describe them.

Reordering and moving

Drag an article within its section to reorder it. Drag it into another section to move it to that page.

Both are the same operation. The server loads every article on the destination page, removes the dragged one if it was already there, inserts it at the target position, and then rewrites order as 0, 1, 2, … across the whole destination page — updating pagePath at the same time. The entire rewrite runs in one transaction, so a failure part-way leaves the previous ordering intact rather than a half-renumbered page.

Dropping into empty space at the end of a section appends. Dropping onto an article inserts before it.

Move an article off a page and the page it left keeps its existing numbers, gap included. Nothing is broken by the gap — sorting is by value, not by contiguity — but if you are reading order directly, expect holes.

The three per-page actions

Each page section has a menu with three whole-page operations. All three act on every article carrying that exact path, and none of them asks which ones.

Publishes every article on a page path in one statement
Deletes every article on a page path

Enable page sets status to true for every article on the path. Disable page sets it to false. Both are a single UPDATE with no per-row logic, which means:

  • Disabling a page and re-enabling it publishes articles that were deliberately unpublished. The original per-article status is not remembered. If you had three drafts sitting on a page and you disable-then-enable it, all three are now live.
  • The action is silent about scope. It does not tell you how many rows it touched before or after.

Delete page removes every article on the path. It is a soft delete — the rows keep a deletedAt and stop being served — but there is no undo in the interface.

If you have narrowed the list by category, tag or search, the page delete still deletes every article on that path, not the ones you can see. The filter affects what is displayed; it does not scope the action.

Check the section's count badge before confirming. That badge is the true number of rows the action will touch.

How page assignment reaches readers

This is the part that most often does not work the way people expect.

The public list endpoint accepts a pagePath query parameter and honours it, so a page can ask for only its own articles:

Lists published articles, optionally restricted to one page path

The shipped help centre at /faq does not use it. It lists every published article on the install, paginated, filtered only by the category tabs. So the per-page arrangement is, on a stock install, an admin-side organising tool and nothing more — the reader sees one merged library.

If you want a page to render only its own articles, you have to call the endpoint with pagePath yourself from that page. There is no configuration switch for it.

Assigning an article to /faq/internal does not hide it. It appears in the main help centre list, it is returned by search, and it is readable at its own URL. Page path is organisation; status is visibility.

If you are drafting something that must not be readable, unpublish it. That holds on every door.

A scheme that works

Some patterns from real installs, in rough order of how well they hold up:

Everything on /faq. Correct for most installs. The reader experience is identical either way, and one section is easier to manage than fifteen.

One path per topic area/faq/deposits, /faq/trading, /faq/kyc. Useful when different people own different areas, because "disable everything the compliance team wrote while they revise it" becomes a single action. The duplication with category is real but harmless; category is what readers filter by, path is what you administer by.

One path per language/faq, /faq/es, /faq/de. This addon stores one question and one answer per article, so a multilingual library is separate articles per language. Path is the cleanest axis to keep them apart, and it makes "publish the Spanish set" one action. Remember that the stock help centre merges them all into one list, so this only works end-to-end if you build language-specific pages that pass pagePath.

One path per real frontend page, mirroring your site structure. This is what the page picker is designed for and what the naming suggests. It only earns its keep if you have actually built those pages to request their own articles; otherwise you have fifteen admin sections and one merged reader list.