WP Docs Manager self-updates
Standalone documentation manager module for WordPress plugins
by morntag.com · github.com/morntag/wp-docsmanager · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/morntag/wp-docsmanager/archive/refs/heads/main.zipShips its own WordPress updater (Plugin Update Checker), so new versions show up under Dashboard → Updates.
A standalone WordPress plugin for documenting other WordPress plugins. Auto-discovers README.md files inside any active plugin's subdirectories, renders them in a custom admin UI, and lets you author additional docs through a Tiptap WYSIWYG editor backed by a hierarchical custom post type.
Originally extracted from morntag/mcc-baspo; now ships as an independent open-source plugin.
Features
- File-based scanning — point it at any installed plugin and it auto-detects per-module
README.mdfiles plus a recursive.docs/-style Markdown tree - Custom documentation — hierarchical
mcc_documentationCPT with categories, frontmatter, and revisions - Tiptap Markdown editor — WYSIWYG authoring with image uploads, embedded videos, and internal-link picker
- Search — unified full-text search across both file-based and custom docs
- Per-site multisite — activates independently on each subsite
- Self-updating — pulls updates straight from GitHub Releases via plugin-update-checker
Installation
Until the plugin is on the WordPress.org repository:
- Download the latest
wp-docsmanager-vX.Y.Z.zipfrom Releases. - In wp-admin, go to Plugins → Add New → Upload Plugin and upload the ZIP.
- Click Activate.
Once installed, future versions auto-update through WordPress's normal update flow (no GitHub token required — the repo is public).
Configuration
After activation, go to Documentation → Settings.
The plugin doesn't scan anything until you configure it.
| Field | What it does |
|---|---|
| Source plugin | Dropdown of installed plugins. Pick the one whose docs you want indexed. |
| Scan module READMEs | If on, walks <plugin>/<modules subpath>/*/README.md (one level deep). Use this for plugins that organise functionality into per-module subdirectories. |
| Module READMEs subpath | Path relative to the plugin root. Defaults to includes/Modules. |
| Scan docs tree | If on, walks <plugin>/<docs subpath>/**/*.md (recursive). Use this for .docs/ knowledge-base trees. |
| Docs tree subpath | Path relative to the plugin root. Defaults to .docs. |
Both scans are independent — enable either, both, or neither. Subpath inputs reject .., absolute paths, and backslashes.
A Rescan now button on the Documentation page clears the 1-hour transient cache when you've just edited a file.
The Documentation page itself shows your scanned files plus any custom docs you've authored via the admin UI.
Capability integration
The plugin checks three capability strings via current_user_can():
docsmanager_access_docs— view the Documentation menu and read docsdocsmanager_edit_docs— create and edit custom docsdocsmanager_delete_docs— delete custom docs
On activation, all three are granted to the administrator role.
To grant access to other roles (Editors, custom roles, etc.) without modifying role caps in the DB, hook the morntag_docs_user_can filter:
add_filter( 'morntag_docs_user_can', function ( $result, string $cap ) {
if ( is_bool( $result ) ) {
return $result;
}
// Example: Editors get read access; custom 'docs_manager' role gets full access.
if ( current_user_can( 'editor' ) && 'docsmanager_access_docs' === $cap ) {
return true;
}
if ( current_user_can( 'docs_manager' ) ) {
return true;
}
return null; // Fall back to manage_options.
}, 10, 2 );
The filter receives the cap name and a current resolution. Return true/false to short-circuit, or null to defer to the next filter or the manage_options fallback.
Programmatic configuration (path-override filters)
If you want to set the scan paths from code instead of through the settings UI (for environments where the DB option can't be relied on), use these filters:
add_filter( 'morntag_docs_modules_dir', function () {
return WP_PLUGIN_DIR . '/my-plugin/includes/Modules';
} );
add_filter( 'morntag_docs_docs_dir', function () {
return WP_PLUGIN_DIR . '/my-plugin/.docs';
} );
When a filter is registered, the settings page shows the field as read-only with an "Overridden by filter" notice.
Migrating from a bundled (mcc-baspo) install
Until 2026-04-17, this code was a Composer library consumed by mcc-baspo. If your mcc-baspo install bundles morntag/wp-docsmanager, switch to the standalone plugin in three steps:
-
Detach the Composer dependency in
mcc-baspo:- Remove
"morntag/wp-docsmanager": "^0.1"fromcomposer.jsonrequire - Remove the corresponding
repositoriesentry pointing at this repo - Run
composer update
- Remove
-
Delete the bootstrap file at
includes/DocsManagerBootstrap.phpand anyrequireof it. -
Install this plugin following the Installation steps above, then go to Documentation → Settings and configure: select
mcc-baspofrom the dropdown, leaveincludes/Modulesand.docsas the subpaths, save.
No DB migration is required. The CPT, taxonomy, and post-meta keys are deliberately frozen at their original mcc_* names, so all existing custom documentation posts and categories appear automatically once the standalone plugin activates.
If your baspo install previously hooked morntag_docs_user_can to map docs caps onto baspo's Capabilities module (so non-admin roles could access docs), re-add that hook directly in baspo's morntag-custom-code.php after detaching — it's only ~10 lines.
Frozen identifiers
These are intentionally not configurable. Renaming them would orphan existing content in installations that originated from mcc-baspo:
- CPT slug:
mcc_documentation - Taxonomy slug:
mcc_doc_category - Admin menu page slug:
mcc-documentation - Post meta keys:
_mcc_doc_frontmatter,_mcc_doc_type,_mcc_doc_source_path,_mcc_doc_order,_mcc_doc_readonly - CPT
capability_type:['mcc_doc', 'mcc_docs']
The user-facing capability strings (the ones you grant to roles) were renamed during the standalone conversion: mcc_*_docs → docsmanager_*_docs. CPT/taxonomy/meta names stayed the same so data is preserved.
Development
composer install # PHP deps
npm install # JS deps for the Tiptap editor
npm run build # Bundles assets/src/editor.js → assets/js/editor.bundle.js
The compiled assets/js/editor.bundle.js is tracked in git so end users skip the JS toolchain.
Code quality
composer phpcs # Lint PHP (WordPress coding standards)
composer phpcbf # Auto-fix violations
composer phpstan # Static analysis (level 6)
composer test # PHPUnit unit tests (no WordPress bootstrap needed)
Configs: phpcs.xml (WordPress-Extra + Core + Docs), phpstan.neon (level 6), phpunit.xml (unit tests under tests/Unit/ with WP functions stubbed via tests/bootstrap.php).
Git hooks
Lefthook installs automatically after npm install:
- commit-msg — commitlint enforces conventional commits (
feat,fix,docs,chore,refactor, etc.) - pre-commit — PHPCS auto-fix + check on staged PHP, Biome check on staged JS
- pre-push — branch naming check (
main,dev,feature/*,bugfix/*,hotfix/*)
Releases
GitHub Actions builds and publishes a release ZIP on every push to main:
- Test gate: PHPCS + PHPStan + PHPUnit must pass
- release-it inspects conventional commits, determines the semver bump, updates the plugin header
Version:line, generatesCHANGELOG.md, creates a git tag and a GitHub Release - CI rsyncs the repo into a clean staging dir (excluding dev tooling), zips it as
wp-docsmanager-vX.Y.Z.zip, and uploads it as a release asset
Sites running the plugin auto-update via yahnis-elsts/plugin-update-checker, which polls the public Releases API (no token needed).
Only feat: and fix: commits trigger a release. chore, docs, style, wip are no-ops.
License
GPL-2.0-or-later