npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pterodocs

v0.5.0

Published

Publish a Docusaurus site to WordPress as a tree of Gutenberg pages.

Readme

pterodocs

Your documentation, where people actually find it.

Publishes a Docusaurus site to WordPress as a tree of native Gutenberg pages, so the docs you write once are indexed under your own domain without being rewritten by hand.

Documentation

Install · Usage · Configuration · How it works · Plugin · Status


What is it?

A one-way publisher. Docusaurus stays the source of truth; WordPress becomes a mirror. Every page it writes is real Gutenberg block markup — headings, lists, tables, code, admonitions, images — so the result is editable in WordPress rather than a wall of embedded HTML.

It does not invent its own idea of your site. It asks Docusaurus, using Docusaurus's own loader, which means resolved sidebars (autogenerated ones included), versions, locales, draft and unlisted flags, permalinks and previous/next links all come from the same code that builds your site.

Install

npm install --save-dev pterodocs

pterodocs runs inside a Docusaurus project and expects @docusaurus/core to be present. It pulls in @pterodocs/core, @pterodocs/docusaurus and @pterodocs/wordpress, which are published in lockstep with it.

Installing from a git URL is not supported: the repository is an npm workspace, and a git install would pack only its private root.

Usage

npx pterodocs render                 # render every page locally; contacts nothing
npx pterodocs sync --dry-run         # say what would change on the site
npx pterodocs sync                   # create and update
npx pterodocs sync --prune           # also trash pages whose document is gone
npx pterodocs doctor                 # check config, credentials and permissions

Credentials come from the environment, never from the config file:

export WP_URL=https://example.com
export WP_USER=someone
export WP_APP_PASSWORD='xxxx xxxx xxxx xxxx'   # Users → Profile → Application Passwords

Without them every command still renders, and reports what it would have done.

Configuration

pterodocs.config.mjs beside your Docusaurus config:

import { defineConfig } from 'pterodocs';

export default defineConfig({
  site: { sidebars: ['docs'], versions: 'last', locales: 'default' },
  target: { type: 'wordpress', root: '/docs' },
});

Anything Docusaurus already knows — the site URL, base URL, route base path, locales, markdown format, admonition keywords — is read from your Docusaurus config and is not repeated here.

Every option, with its default and what reads it, is at https://onyx.ac/products/pterodocs/docs/config/ — published by pterodocs itself.

llms.txt

Every run writes llms.txt and llms-full.txt — the index and the full text described at llmstxt.org — into the output directory, and stores them on the documentation root page for the WordPress plugin to serve:

https://example.com/<root>/<base>/llms.txt
https://example.com/<root>/<base>/llms-full.txt

They are built from what the run published rather than from the Docusaurus build, and that is the whole point of them: the links are the WordPress URLs, the selection is the sidebars, locales and versions your configuration names, and no docusaurus build has to have run. A build-time plugin writes a file describing the Docusaurus site, which is a different site.

The files sit at the documentation root rather than at the top of the domain. The convention is /llms.txt, but that file is supposed to describe everything published at a domain, and pterodocs only knows about its own tree — so claiming it would mean promising the site and delivering a subtree, and would collide with any SEO plugin that generates one. The plugin advertises the real location from a <link rel="alternate"> on documentation pages and a comment in robots.txt.

Serving them needs the plugin, because WordPress serves nothing statically. Without it the files are still written to the output directory, and the run reports that the site refused to store them.

llms: {
  index: true,      // write llms.txt
  full: true,       // write llms-full.txt
  publish: true,    // store both on the site for the plugin to serve
  title: '',        // heading; the site's own title by default
  description: '',  // summary; the documentation root's description by default
}

How it works

Pages mirror your documentation URLs, so /docs/guides/sync on Docusaurus becomes /<root>/guides/sync/ on WordPress. A directory becomes a page of its own, titled by its sidebar category. A page is identified by its parent and its slug, so re-running only rewrites what actually differs, and a second run reports everything as unchanged.

How it looks

WordPress renders core blocks with almost no opinion, so pterodocs publishes a stylesheet with them: the navigation loses its list markers and becomes a sticky column that scrolls on its own, code gets a frame and a monospace face, tables scroll instead of overflowing, and the layout runs full width. Fences are tokenised at publish time, so code is highlighted with no JavaScript on the page at all.

Every colour is mixed from currentColor, so it follows your theme into dark rather than assuming light, and every rule is wrapped in :where(), so a theme that already styles these class names keeps its own opinions.

The stylesheet is stored on each page, which is the only place a site running nothing can read it from. It is the same few kilobytes on every page, so it is also written to <output>/docs.css: paste that into Appearance, Customise, Additional CSS once and set render.styles to 'none', and the pages carry nothing.

render: {
  styles: 'inline',   // 'none' once the CSS lives on the site
  highlight: true,    // tokenise fences at publish time
}

The WordPress plugin

Optional, and worth installing. pterodocs writes ordinary core blocks, which are correct but plain: no syntax highlighting, tables that overflow, a sidebar that is a bare expanded list. The plugin in packages/wordpress/plugin styles them.

It registers no block types, so nothing about your content becomes dependent on it. Deactivate it and the documentation is still there, still readable, still navigable.

npm run --workspace @pterodocs/wp-plugin build   # writes pterodocs.zip

Upload that under Plugins, Add New, Upload Plugin. Defaults live at Settings, pterodocs; any single block can override them from the block inspector.

Two things to know. Its class prefix must match render.classPrefix — set it on the settings page, which needs no re-publishing; pterodocs doctor says whether the two agree. And because a sync rewrites a page's content, an override set on a block in the WordPress editor is replaced the next time that page is published: the settings page is the durable place for a preference.

Once it is installed, render.blocks: 'plugin' lets pterodocs carry instructions core blocks cannot express — chiefly a fence's highlighted line range, which is otherwise reported as dropped. It travels in the block comment rather than in markup, so WordPress stores the same content either way.

Status

Working, and published.

The publisher has been verified against a real 47-page documentation set: rendering matches the script it was extracted from on 42 of those pages, and every one of the remaining five differs only where pterodocs is now correct.

Not yet exercised against a site that uses them: versions, locales, and the Docusaurus build plugin. The WordPress plugin is newer still — its PHP and JavaScript are checked in CI and its markup decisions are covered by tests on the publisher's side, but its behaviour in a browser has not been through a release on a live site.

Roadmap

Next, in the order they would help most:

  • A page template the plugin provides. target.template already names one, and pterodocs assigns it to every page and reconciles it like any other field — but the slug has to match a template the theme ships, so a site whose theme offers nothing full width has nothing to point it at. The plugin could carry its own: a template built for documentation, with no constrained content column to escape from. That is where the awkward part of the stylesheet comes from — alignfull, and then re-adding the page padding the theme was already applying — and three of this cycle's layout bugs lived in those two rules. Classic and block themes register templates by different mechanisms, so it is two implementations behind one setting, and doctor should report which one the site got.
  • pterodocs preview. Render, then write a browsable page showing the result at a phone width and a desktop one, with the navigation reconstructed — WordPress renders core/page-list server-side, so a rendered file has only its placeholder and the sidebar cannot otherwise be seen. Built by hand three times while developing the stylesheet, and it produced two false bug reports by quietly clipping its own output, which is the argument for it being a command with tests rather than a script.
  • An example Docusaurus site. The fixture the integration test uses is four documents, which is enough to prove the loader works and not enough to show a sidebar, an admonition, tabs or a wide table. A fuller example would give the preview something honest to run against, and would make the goldens representative of what people actually publish.

Licence

CC-BY-SA-4.0. See LICENCE.md.