{"id":367696,"date":"2026-10-07T02:31:18","date_gmt":"2026-10-07T02:31:18","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/nv-oos-docs-hub\/"},"modified":"2026-10-07T02:30:42","modified_gmt":"2026-10-07T02:30:42","slug":"nvoos-docs-hub","status":"publish","type":"plugin","link":"https:\/\/sa.wordpress.org\/plugins\/nvoos-docs-hub\/","author":17440330,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"0.5.1","stable_tag":"0.5.1","tested":"7.1.3","requires":"6.0","requires_php":"7.4","requires_plugins":null,"header_name":"NV oOS Docs Hub","header_author":"NV Digital Solutions","header_description":"React-based documentation browser for NV oOS. Discovers, indexes, and renders Markdown docs from the base plugin and every addon in a GitBook-style SPA. Shortcode [nvoos_docs] embeds it on any page.","assets_banners_color":"e7ece0","last_updated":"2026-10-07 02:30:42","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/nvdigitalsolutions.com\/wpoos","header_author_uri":"https:\/\/nvdigitalsolutions.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":158,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.5.1":{"tag":"0.5.1","author":"vsamtani","date":"2026-10-07 02:30:42","revision":3731769}},"upgrade_notice":{"0.5.1":"<p>The uploads content folder moved from <code>wp-content\/uploads\/docs\/<\/code> to <code>wp-content\/uploads\/nvoos-docs-hub\/content\/<\/code>. Existing content is migrated automatically \u2014 no action needed.<\/p>","0.5.0":"<p>New local-first default: Markdown dropped into <code>wp-content\/uploads\/docs\/<\/code> is published with zero remote calls, and GitHub import is now opt-in. Existing installs using remote repositories keep them enabled automatically. Recommended for all users.<\/p>","0.4.7":"<p>Compatibility release \u2014 fixes activation-time notices on WordPress 6.7+ and cleans up cron events on deactivation. Recommended for all users.<\/p>","0.4.6":"<p>Packaging-only release \u2014 bundles the GPLv3 license file. No functional changes.<\/p>","0.4.5":"<p>Security hardening release \u2014 uninstall and cache cleanup are symlink-safe. Recommended for all users.<\/p>","0.4.4":"<p>Security hardening release \u2014 context-source content can no longer leak through search or the sitemap. Recommended for all users.<\/p>","0.4.3":"<p>WordPress.org submission hardening \u2014 no functional changes for existing sites. Recommended for all users.<\/p>","0.4.2":"<p>Local-page links and TOC anchors now navigate inside the SPA, and broken-link fix suggestions resolve relative to the source page. Recommended for all users.<\/p>","0.4.1":"<p>Cache invalidation after plugin updates is fixed; the index no longer goes stale. Recommended for all users.<\/p>","0.2.0":"<p>Asynchronous chunked rebuilds + vendor exclusion. The &quot;Rebuild Documentation Index&quot; button is now non-blocking; long rebuilds run across WP-Cron ticks. Default exclusions for <code>vendor\/<\/code> and <code>node_modules\/<\/code> mean third-party READMEs no longer pollute your docs.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3731763,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3731763,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3731763,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3731763,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{"blueprint.json":{"filename":"blueprint.json","revision":3731988,"resolution":false,"location":"assets","locale":"","contents":"{\"$schema\":\"https:\\\/\\\/playground.wordpress.net\\\/blueprint-schema.json\",\"landingPage\":\"\\\/docs\\\/\",\"preferredVersions\":{\"php\":\"8.3\",\"wp\":\"latest\"},\"phpExtensionBundles\":[\"kitchen-sink\"],\"features\":{\"networking\":true},\"steps\":[{\"step\":\"login\",\"username\":\"admin\",\"password\":\"password\"},{\"step\":\"setSiteOptions\",\"options\":{\"blogname\":\"NV oOS Docs Hub \\u2014 Playground Demo\",\"blogdescription\":\"A live documentation site rendered from Markdown by NV oOS Docs Hub.\"}},{\"step\":\"runPHP\",\"code\":\"<?php require_once '\\\/wordpress\\\/wp-load.php';\\n\\\/**\\n * Docs Hub Playground demo \\u2014 seed content for the NV oOS Docs Hub\\n * WordPress Playground blueprint.\\n *\\n * This file is EMBEDDED into the blueprint's runPHP step by\\n * bin\\\/generate-docs-hub-blueprint.php, which strips the opening <?php\\n * tag. It must therefore stay a self-contained snippet:\\n *\\n *   - No namespace, no Composer dependencies, no closing ?> tag.\\n *   - WordPress functions only (it runs right after wp-load).\\n *   - Idempotent: guarded by the nvoos_dh_demo_seeded option.\\n *\\n * The demo is local-first and honest: ten Markdown files \\u2014 a real plugin\\n * wiki \\u2014 are written into the plugin's default local content folder\\n * (wp-content\\\/uploads\\\/nvoos-docs-hub\\\/content\\\/) and published by the\\n * synchronous rebuild in the blueprint's second runPHP step. No remote\\n * calls, no API keys, no configuration \\u2014 exactly the plugin's\\n * zero-setup workflow. The \\\/docs\\\/ page embeds ONLY the [nvoos_docs]\\n * shortcode and gets demo CSS through WordPress core Additional CSS so\\n * the docs browser fills the whole page like a standalone SPA.\\n *\\n * @package NV_oOS_Docs_Hub\\n *\\\/\\n\\nif ( ! defined( 'ABSPATH' ) ) {\\n\\texit;\\n}\\n\\n\\\/**\\n * Ensure the plugin is loaded and active before the demo code runs.\\n *\\n * The wp.org Live Preview installs the plugin WITHOUT activating it, so\\n * the seed must activate it itself \\u2014 otherwise the first reference to a\\n * plugin class fatals with \\\"Class not found\\\". The standalone demo\\n * installs with activate=true, making this a no-op there. When activation\\n * is unavailable, the plugin file is loaded directly as a fallback.\\n *\\n * @return void\\n *\\\/\\nfunction nvoos_dh_demo_ensure_plugin_active(): void {\\n\\tif ( class_exists( 'NV_oOS_Docs_Hub_Plugin' ) ) {\\n\\t\\treturn;\\n\\t}\\n\\tif ( ! function_exists( 'is_plugin_active' ) ) {\\n\\t\\trequire_once ABSPATH . 'wp-admin\\\/includes\\\/plugin.php';\\n\\t}\\n\\tif ( ! is_plugin_active( 'nvoos-docs-hub\\\/nvoos-docs-hub.php' ) ) {\\n\\t\\t$activated = activate_plugin( 'nvoos-docs-hub\\\/nvoos-docs-hub.php' );\\n\\t\\tif ( is_wp_error( $activated ) && ! class_exists( 'NV_oOS_Docs_Hub_Plugin' ) ) {\\n\\t\\t\\t$plugin_file = WP_PLUGIN_DIR . '\\\/nvoos-docs-hub\\\/nvoos-docs-hub.php';\\n\\t\\t\\tif ( file_exists( $plugin_file ) ) {\\n\\t\\t\\t\\tinclude_once $plugin_file;\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n}\\n\\n\\\/**\\n * The demo documentation set: filename => Markdown body.\\n *\\n * A ten-page plugin wiki. Front matter sets the nav title and sidebar\\n * order. README.md derives the `readme` slug \\u2014 the plugin's default home\\n * page \\u2014 so the docs browser opens on \\\"Getting Started\\\" out of the box.\\n * The bodies showcase GitHub Flavored Markdown (tables, task lists,\\n * fenced code) and the :::note\\\/:::tip\\\/:::warning\\\/:::danger callout\\n * blocks. External https:\\\/\\\/ links are safe from the broken-link detector\\n * (it only validates plain relative paths); no relative links are used\\n * on purpose.\\n *\\n * @return array<string,string> Filename => Markdown body.\\n *\\\/\\nfunction nvoos_dh_demo_docs(): array {\\n\\treturn array(\\n\\t\\t'README.md'           => <<<'MD'\\n---\\ntitle: Getting Started\\norder: 10\\n---\\n\\n# Welcome to Docs Hub\\n\\nYou are looking at **NV oOS Docs Hub** running inside WordPress Playground \\u2014\\nthis entire site, WordPress, the plugin, and every page of this wiki is\\nexecuting in your browser. Nothing was installed and nothing is sent to a\\nserver.\\n\\nDocs Hub turns plain Markdown files into a GitBook-style documentation\\nsite with sidebar navigation, a content area, and a per-page table of\\ncontents \\u2014 embedded anywhere on your WordPress site.\\n\\n## Take the tour\\n\\n| Feature | Try it |\\n|---|---|\\n| Sidebar navigation | Use the left sidebar to move between pages |\\n| Full-text search | Click the search box (or press \\u2318K \\\/ Ctrl+K) |\\n| Markdown rendering | Browse the Markdown Guide page |\\n| Callout blocks | Check the Callout Blocks page for note, tip, warning, and danger |\\n| Themes | Toggle light \\\/ dark from the toolbar |\\n\\n:::note\\nThis is what a `:::note` callout looks like. The four callout types are\\ndemonstrated on the Callout Blocks page.\\n:::\\n\\n## How this wiki was built\\n\\nTen Markdown files were dropped into\\n`wp-content\\\/uploads\\\/nvoos-docs-hub\\\/content\\\/` and one rebuild published\\nthem. No API keys. No remote calls. That is the entire pipeline.\\nMD,\\n\\t\\t'installation.md'     => <<<'MD'\\n---\\ntitle: Installation\\norder: 20\\n---\\n\\n# Installation\\n\\nDocs Hub is a free plugin in the WordPress directory.\\n\\n## Install from the directory\\n\\n1. In wp-admin, open **Plugins \\u2192 Add New Plugin**.\\n2. Search for **NV oOS Docs Hub**.\\n3. Install and activate.\\n\\nThat is it. There is no setup wizard, no account, and no configuration\\nstep \\u2014 the plugin works the moment it is active.\\n\\n:::tip\\nThe plugin also ships on\\nhttps:\\\/\\\/wordpress.org\\\/plugins\\\/nvoos-docs-hub\\\/ where you can download the\\nZIP and upload it via **Plugins \\u2192 Add New Plugin \\u2192 Upload Plugin**.\\n:::\\n\\n## What activation does\\n\\nActivation creates the local content folder and schedules a nightly\\nrebuild so your documentation stays fresh without any manual step:\\n\\n```text\\nwp-content\\\/uploads\\\/nvoos-docs-hub\\\/content\\\/\\n```\\n\\nDrop Markdown files there, rebuild once, and you are publishing.\\nMD,\\n\\t\\t'local-first.md'      => <<<'MD'\\n---\\ntitle: Local-First Publishing\\norder: 30\\n---\\n\\n# Local-First Publishing\\n\\nDocs Hub is local-first by default. There is no cloud, no account, and no\\nexternal service between your Markdown and your visitors.\\n\\n## The workflow\\n\\n1. Write documentation in Markdown (`.md`) or plain text (`.txt`).\\n2. Drop the files into your WordPress uploads folder.\\n3. Rebuild the index.\\n4. Embed the docs anywhere with a shortcode or block.\\n\\n```text\\nwp-content\\\/uploads\\\/nvoos-docs-hub\\\/content\\\/\\n\\u251c\\u2500\\u2500 README.md\\n\\u251c\\u2500\\u2500 installation.md\\n\\u251c\\u2500\\u2500 local-first.md\\n\\u251c\\u2500\\u2500 shortcode-block.md\\n\\u251c\\u2500\\u2500 markdown-guide.md\\n\\u251c\\u2500\\u2500 callouts.md\\n\\u251c\\u2500\\u2500 search-and-themes.md\\n\\u251c\\u2500\\u2500 github-import.md\\n\\u251c\\u2500\\u2500 wp-cli.md\\n\\u2514\\u2500\\u2500 troubleshooting.md\\n```\\n\\nSubfolders are supported \\u2014 the sidebar mirrors the folder structure.\\n\\n## Rebuilding\\n\\nFrom WP-CLI:\\n\\n```bash\\nwp nvoos-docs rebuild --sync\\n```\\n\\nFrom the admin, open **Settings \\u2192 NV oOS Docs Hub** and press\\n**Rebuild Documentation Index**. Large doc sets rebuild in chunks with a\\nlive progress panel, so a rebuild never blocks the site.\\n\\n:::tip\\nRebuilds happen on your server. Your documentation content never leaves\\nyour WordPress install unless you opt into an external source.\\n:::\\n\\n- [x] Write Markdown files\\n- [x] Drop them into the uploads content folder\\n- [x] Rebuild the index\\n- [ ] Embed `[nvoos_docs]` on any page\\nMD,\\n\\t\\t'shortcode-block.md'  => <<<'MD'\\n---\\ntitle: Shortcode & Block Embeds\\norder: 40\\n---\\n\\n# Shortcode & Block Embeds\\n\\nThe docs browser embeds anywhere: a page, a post, a widget area \\u2014 via a\\nshortcode or a Gutenberg block.\\n\\n## The shortcode\\n\\n```text\\n[nvoos_docs]\\n```\\n\\nEvery option has a default, so the bare shortcode is all most sites need:\\n\\n| Attribute | Default | What it does |\\n|---|---|---|\\n| `section` | `all` | Which docs to show (`all`, or a source slug) |\\n| `theme` | `auto` | `auto` follows the visitor's preference; `light` \\\/ `dark` force one |\\n| `search` | `true` | Show the full-text search box |\\n| `sidebar` | `true` | Show the navigation sidebar |\\n| `home` | `readme` | Slug of the page shown by default |\\n\\nExample:\\n\\n```text\\n[nvoos_docs theme=\\\"dark\\\" home=\\\"getting-started\\\"]\\n```\\n\\n## The block\\n\\nIn the block editor, add the **NV oOS Docs Hub** block and pick the same\\noptions from the sidebar panel. The block and the shortcode render the\\nidentical browser.\\n\\n## Multiple embeds\\n\\nYou can place several docs browsers on the same site \\u2014 each one is an\\nindependent instance with its own state.\\nMD,\\n\\t\\t'markdown-guide.md'   => <<<'MD'\\n---\\ntitle: Markdown Guide\\norder: 50\\n---\\n\\n# Markdown Guide\\n\\nDocs Hub renders GitHub Flavored Markdown \\u2014 the same dialect used by\\nGitHub, GitLab, and most developer docs.\\n\\n## Text formatting\\n\\nYou can use **bold**, *italic*, `inline code`, and ~~strikethrough~~.\\n\\n> Blockquotes render with a left border, exactly as you would expect.\\n\\n## Lists\\n\\n1. Numbered lists\\n2. Work as you expect\\n   - with nested\\n   - unordered items\\n\\n## Tables\\n\\n| Release | Highlight |\\n|---|---|\\n| 0.5.1 | Uploads folder renamed to the plugin slug |\\n| 0.4.7 | Cron scheduled on init; readme-only \\\"Tested up to\\\" |\\n| 0.4.4 | Staging-isolated transients + symlink-safe cleanup |\\n\\n## Task lists\\n\\n- [x] Ship a Markdown renderer\\n- [x] Support GFM tables\\n- [x] Support task lists\\n- [ ] Finish the roadmap\\n\\n## Code blocks\\n\\nFenced code blocks get syntax highlighting. A PHP example:\\n\\n```php\\nfunction greet( string $name ): string {\\n\\treturn sprintf( 'Hello, %s!', $name );\\n}\\n\\necho greet( 'Docs Hub' );\\n```\\n\\nAnd a JSON example:\\n\\n```json\\n{\\n  \\\"plugin\\\": \\\"nvoos-docs-hub\\\",\\n  \\\"localFirst\\\": true,\\n  \\\"apiKeys\\\": 0\\n}\\n```\\nMD,\\n\\t\\t'callouts.md'         => <<<'MD'\\n---\\ntitle: Callout Blocks\\norder: 60\\n---\\n\\n# Callout Blocks\\n\\nDocs Hub supports four callout types using a blockquote-style syntax. Each\\nrenders with its own icon and accent color.\\n\\n## Note\\n\\n:::note\\nUseful context the reader should see but that does not interrupt the\\nflow.\\n:::\\n\\n## Tip\\n\\n:::tip\\nA recommendation that saves time \\u2014 like pressing \\u2318K to focus the search\\nbox.\\n:::\\n\\n## Warning\\n\\n:::warning\\nSomething that can go wrong if ignored. Back up before large migrations.\\n:::\\n\\n## Danger\\n\\n:::danger\\nDestructive or irreversible. The `reset --hard` command wipes the docs\\ncache, so use it deliberately.\\n:::\\n\\n## Writing callouts\\n\\nStart a line with the callout type and a blank line ends the block:\\n\\n```markdown\\n:::warning\\nRebuilds overwrite the published docs with the current source files.\\n:::\\n```\\n\\nCallouts render in both light and dark themes, so they stay legible\\neither way.\\nMD,\\n\\t\\t'search-and-themes.md' => <<<'MD'\\n---\\ntitle: Search & Themes\\norder: 70\\n---\\n\\n# Search & Themes\\n\\n## Full-text search\\n\\nThe search box in the header searches every page of your documentation.\\n\\n- Press \\u2318K \\\/ Ctrl+K to focus search from anywhere.\\n- Matches are ranked and grouped by page.\\n- Search runs over a prebuilt index served by the REST API, with a\\n  client-side fallback so it keeps working even on unusual hosts.\\n\\nTry it: search for **callout** and open the Callout Blocks page.\\n\\n## Light, dark, and auto themes\\n\\nThe toolbar theme toggle switches the docs browser between light and dark,\\nor follows your visitor's preference in `auto` mode. The choice is\\nremembered between visits.\\n\\n:::tip\\nThemes apply to the docs browser, not your whole site \\u2014 embed anywhere\\nwithout fighting the active theme's styles.\\n:::\\n\\n## Where the theme comes from\\n\\nThe docs browser ships a built-in light theme and a built-in dark theme.\\nBoth are plain CSS that can be overridden from your theme for full\\ncontrol.\\nMD,\\n\\t\\t'github-import.md'    => <<<'MD'\\n---\\ntitle: GitHub Import (Opt-In)\\norder: 80\\n---\\n\\n# GitHub Import (Opt-In)\\n\\nDocs Hub can import Markdown from public GitHub repositories. The import\\nis **opt-in and off by default** \\u2014 the local Markdown workflow works with\\nzero remote calls, and this demo never enables it.\\n\\n## What it does\\n\\nWhen you add a public repository under **Settings \\u2192 NV oOS Docs Hub \\u2192\\nRemote repositories**, Docs Hub fetches the Markdown server-side and\\nindexes it alongside your local files.\\n\\n- Fetches happen only from `api.github.com` and `raw.githubusercontent.com`.\\n- No GitHub account is required.\\n- An optional personal access token only raises the API rate limits.\\n\\n:::warning\\nGitHub import is a deliberate opt-in. Leaving it off keeps Docs Hub 100%\\nlocal.\\n:::\\n\\n## Local stays first\\n\\nRemote sources are additive \\u2014 your local uploads folder remains the\\nprimary source, and anything you drop there is published on the next\\nrebuild with or without a connection.\\nMD,\\n\\t\\t'wp-cli.md'           => <<<'MD'\\n---\\ntitle: WP-CLI Reference\\norder: 90\\n---\\n\\n# WP-CLI Reference\\n\\nEverything the admin UI can do is scriptable via the `nvoos-docs` command.\\n\\n## Rebuild\\n\\n```bash\\nwp nvoos-docs sync             # full synchronous rebuild\\nwp nvoos-docs sync --strict    # exit non-zero when broken links remain\\nwp nvoos-docs rebuild --sync   # same as sync\\nwp nvoos-docs rebuild --async  # chunked rebuild (default for rebuild)\\nwp nvoos-docs rebuild --resume # resume an interrupted chunked rebuild\\n```\\n\\n## Reset & clear\\n\\n```bash\\nwp nvoos-docs reset            # clear a stuck rebuild state\\nwp nvoos-docs reset --hard     # also wipe the live docs cache\\nwp nvoos-docs clear            # clear the docs cache\\n```\\n\\n## Inspect\\n\\n```bash\\nwp nvoos-docs status           # index + rebuild state\\n```\\n\\n## Automate it\\n\\nPair `wp nvoos-docs rebuild --sync` with your deployment process (rsync,\\ngit push hooks, CI) and the docs update with the same commit that changes\\nthe Markdown.\\nMD,\\n\\t\\t'troubleshooting.md'  => <<<'MD'\\n---\\ntitle: Troubleshooting & FAQ\\norder: 100\\n---\\n\\n# Troubleshooting & FAQ\\n\\n## My new Markdown file is not showing\\n\\nRun a rebuild \\u2014 the index only changes when a rebuild runs.\\n\\n```bash\\nwp nvoos-docs rebuild --sync\\n```\\n\\nA nightly rebuild also runs automatically; you may just be looking before\\nit fired.\\n\\n## The rebuild seems stuck\\n\\nA chunked rebuild leaves a state record behind when it is interrupted.\\n\\n```bash\\nwp nvoos-docs reset\\nwp nvoos-docs rebuild --sync\\n```\\n\\n## Links are broken\\n\\nDocs Hub detects broken internal links and lists them with fix\\nsuggestions. Correct the relative target in the Markdown and rebuild.\\n\\n:::danger\\n`wp nvoos-docs reset --hard` wipes the live docs cache. The next rebuild\\nrepublishes it \\u2014 but run it deliberately.\\n:::\\n\\n## Does Docs Hub phone home?\\n\\nNo. Local publishing makes zero remote calls. Only the opt-in GitHub\\nimport fetches, server-side, from `api.github.com` and\\n`raw.githubusercontent.com` \\u2014 see the GitHub Import page.\\nMD,\\n\\t);\\n}\\n\\n\\\/**\\n * Markup for the published demo page that embeds the docs browser.\\n *\\n * The app is the ONLY thing on the page \\u2014 the seed also applies the\\n * no-title page template (when the theme ships one) and demo CSS via\\n * WordPress core Additional CSS so the browser fills the viewport like a\\n * standalone SPA.\\n *\\n * @return string Post content.\\n *\\\/\\nfunction nvoos_dh_demo_page_content(): string {\\n\\treturn '[nvoos_docs]';\\n}\\n\\n\\\/**\\n * Demo CSS that makes the docs browser the entire page.\\n *\\n * Written to WordPress core Additional CSS (wp_update_custom_css_post),\\n * scoped to the demo page via its body.page-id-{ID} class. Margins and\\n * paddings are zeroed explicitly across the theme's wrapper chain\\n * (site blocks, main, entry content) and the app root is forced to full\\n * width \\u2014 deliberately blunt so it survives theme template variations.\\n *\\n * @param int $page_id The published demo page ID.\\n * @return string CSS.\\n *\\\/\\nfunction nvoos_dh_demo_page_css( int $page_id ): string {\\n\\t$scope = 'body.page-id-' . $page_id;\\n\\n\\treturn '\\\/* NV oOS Docs Hub \\u2014 Playground demo: the docs browser is the whole page. *\\\/' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ',' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ' .wp-site-blocks,' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ' main#wp--skip-link--target,' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ' .entry-content,' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ' .nvoos-docs-hub-root {' . \\\"\\\\n\\\"\\n\\t\\t. \\\"\\\\t\\\" . 'margin-left: 0 !important;' . \\\"\\\\n\\\"\\n\\t\\t. \\\"\\\\t\\\" . 'margin-right: 0 !important;' . \\\"\\\\n\\\"\\n\\t\\t. '}' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ' .wp-site-blocks,' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ' main#wp--skip-link--target,' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ' .entry-content {' . \\\"\\\\n\\\"\\n\\t\\t. \\\"\\\\t\\\" . 'padding-left: 0 !important;' . \\\"\\\\n\\\"\\n\\t\\t. \\\"\\\\t\\\" . 'padding-right: 0 !important;' . \\\"\\\\n\\\"\\n\\t\\t. '}' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ' .wp-block-post-content,' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ' .nvoos-docs-hub-root {' . \\\"\\\\n\\\"\\n\\t\\t. \\\"\\\\t\\\" . 'max-width: none !important;' . \\\"\\\\n\\\"\\n\\t\\t. \\\"\\\\t\\\" . 'width: 100% !important;' . \\\"\\\\n\\\"\\n\\t\\t. '}' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ' .wp-site-blocks > header,' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ' .wp-site-blocks > footer,' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ' h1.wp-block-post-title { display: none !important; }' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ' .wp-site-blocks { padding-top: 0 !important; padding-bottom: 0 !important; }' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ' main#wp--skip-link--target { margin-top: 0 !important; }' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ' .nvoos-docs-hub-root { min-height: calc(100vh - 32px); }' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ':not(.admin-bar) .nvoos-docs-hub-root { min-height: 100vh; }' . \\\"\\\\n\\\"\\n\\t\\t. $scope . ' .dh-skip-link { display: none; }' . \\\"\\\\n\\\";\\n}\\n\\n\\\/**\\n * Seed the Docs Hub Playground demo. Idempotent.\\n *\\n * @return void\\n *\\\/\\nfunction nvoos_dh_demo_seed(): void {\\n\\tif ( get_option( 'nvoos_dh_demo_seeded' ) ) {\\n\\t\\treturn;\\n\\t}\\n\\n\\tnvoos_dh_demo_ensure_plugin_active();\\n\\n\\t\\\/\\\/ 1. Pretty permalinks so the \\\/docs\\\/ landing page resolves.\\n\\tglobal $wp_rewrite;\\n\\tif ( '\\\/%postname%\\\/' !== get_option( 'permalink_structure' ) ) {\\n\\t\\tif ( $wp_rewrite instanceof WP_Rewrite ) {\\n\\t\\t\\t$wp_rewrite->set_permalink_structure( '\\\/%postname%\\\/' );\\n\\t\\t} else {\\n\\t\\t\\tupdate_option( 'permalink_structure', '\\\/%postname%\\\/' );\\n\\t\\t}\\n\\t\\tflush_rewrite_rules( false );\\n\\t}\\n\\n\\t\\\/\\\/ 2. Write the demo docs into the plugin's default local content folder.\\n\\tif ( class_exists( 'NV_oOS_Docs_Hub_Plugin' ) ) {\\n\\t\\t$dir = NV_oOS_Docs_Hub_Plugin::uploads_docs_dir();\\n\\t} else {\\n\\t\\t$info = wp_upload_dir();\\n\\t\\t$dir  = ( isset( $info['basedir'] ) ? (string) $info['basedir'] : '' ) . '\\\/nvoos-docs-hub\\\/content';\\n\\t}\\n\\tif ( ! is_dir( $dir ) && ! wp_mkdir_p( $dir ) ) {\\n\\t\\treturn;\\n\\t}\\n\\tforeach ( nvoos_dh_demo_docs() as $file => $markdown ) {\\n\\t\\t$path = $dir . '\\\/' . $file;\\n\\t\\tif ( ! file_exists( $path ) ) {\\n\\t\\t\\t\\\/\\\/ phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- seed-only write inside wp-content\\\/uploads.\\n\\t\\t\\tfile_put_contents( $path, $markdown );\\n\\t\\t}\\n\\t}\\n\\n\\t\\\/\\\/ 3. Publish (or converge) the demo page embedding the docs browser.\\n\\t$page = get_page_by_path( 'docs', OBJECT, 'page' );\\n\\tif ( $page instanceof WP_Post ) {\\n\\t\\t$page_id = (int) $page->ID;\\n\\t\\twp_update_post(\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'ID'           => $page_id,\\n\\t\\t\\t\\t'post_title'   => 'Docs Hub Demo',\\n\\t\\t\\t\\t'post_content' => nvoos_dh_demo_page_content(),\\n\\t\\t\\t\\t'post_status'  => 'publish',\\n\\t\\t\\t),\\n\\t\\t\\ttrue\\n\\t\\t);\\n\\t} else {\\n\\t\\t$page_id = (int) wp_insert_post(\\n\\t\\t\\tarray(\\n\\t\\t\\t\\t'post_title'   => 'Docs Hub Demo',\\n\\t\\t\\t\\t'post_name'    => 'docs',\\n\\t\\t\\t\\t'post_content' => nvoos_dh_demo_page_content(),\\n\\t\\t\\t\\t'post_excerpt' => 'A live documentation wiki rendered from Markdown by NV oOS Docs Hub.',\\n\\t\\t\\t\\t'post_status'  => 'publish',\\n\\t\\t\\t\\t'post_type'    => 'page',\\n\\t\\t\\t),\\n\\t\\t\\ttrue\\n\\t\\t);\\n\\t}\\n\\tif ( $page_id < 1 ) {\\n\\t\\treturn;\\n\\t}\\n\\n\\t\\\/\\\/ 4. No-title template when the active theme ships one (Twenty\\n\\t\\\/\\\/    Twenty-Five+: page-no-title.html) \\u2014 the CSS below also hides the\\n\\t\\\/\\\/    title, so this is a progressive enhancement.\\n\\t$templates = glob( get_stylesheet_directory() . '\\\/templates\\\/*.html' );\\n\\t$template  = '';\\n\\tif ( $templates && in_array( 'page-no-title.html', array_map( 'basename', $templates ), true ) ) {\\n\\t\\t$template = 'page-no-title.html';\\n\\t}\\n\\tupdate_post_meta( $page_id, '_wp_page_template', $template );\\n\\n\\t\\\/\\\/ 5. Full-page demo CSS via WordPress core Additional CSS.\\n\\t$css     = nvoos_dh_demo_page_css( $page_id );\\n\\t$current = function_exists( 'wp_get_custom_css' ) ? (string) wp_get_custom_css() : '';\\n\\tif ( false === strpos( $current, 'Playground demo' ) ) {\\n\\t\\tif ( function_exists( 'wp_update_custom_css_post' ) ) {\\n\\t\\t\\twp_update_custom_css_post( $css );\\n\\t\\t}\\n\\t}\\n\\n\\tupdate_option( 'nvoos_dh_demo_seeded', 1 );\\n}\\nnvoos_dh_demo_seed();\"},{\"step\":\"runPHP\",\"code\":\"<?php require_once '\\\/wordpress\\\/wp-load.php';\\n\\\/\\\/ Ensure the plugin is active before the deterministic rebuild. The wp.org\\n\\\/\\\/ Live Preview installs the plugin without activating it; the standalone\\n\\\/\\\/ demo installs with activate=true, making this a no-op there.\\nif ( ! class_exists( 'NV_oOS_Docs_Hub_Rebuild_Job' ) ) {\\n\\tif ( ! function_exists( 'is_plugin_active' ) ) {\\n\\t\\trequire_once ABSPATH . 'wp-admin\\\/includes\\\/plugin.php';\\n\\t}\\n\\tif ( ! is_plugin_active( 'nvoos-docs-hub\\\/nvoos-docs-hub.php' ) ) {\\n\\t\\t$activated = activate_plugin( 'nvoos-docs-hub\\\/nvoos-docs-hub.php' );\\n\\t\\tif ( is_wp_error( $activated ) && ! class_exists( 'NV_oOS_Docs_Hub_Rebuild_Job' ) ) {\\n\\t\\t\\t$plugin_file = WP_PLUGIN_DIR . '\\\/nvoos-docs-hub\\\/nvoos-docs-hub.php';\\n\\t\\t\\tif ( file_exists( $plugin_file ) ) {\\n\\t\\t\\t\\tinclude_once $plugin_file;\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n}\\nif ( ! class_exists( 'NV_oOS_Docs_Hub_Rebuild_Job' ) ) {\\n\\tupdate_option( 'nvoos_dh_demo_build', array( 'success' => false, 'pages' => 0, 'error' => 'plugin-unavailable' ) );\\n\\treturn;\\n}\\n\\\/\\\/ Deterministic synchronous rebuild (the async path schedules WP-Cron\\n\\\/\\\/ ticks, which are non-deterministic inside the Playground runtime).\\ntry {\\n\\t$result = NV_oOS_Docs_Hub_Rebuild_Job::run();\\n\\t$ok     = ! empty( $result['success'] );\\n\\t$pages  = isset( $result['pages'] ) ? (int) $result['pages'] : 0;\\n} catch ( \\\\Exception $e ) {\\n\\t$ok    = false;\\n\\t$pages = 0;\\n}\\n\\n\\\/\\\/ Keep the summary around for diagnostics (the demo page and probe read it).\\nupdate_option(\\n\\t'nvoos_dh_demo_build',\\n\\tarray(\\n\\t\\t'success' => $ok,\\n\\t\\t'pages'   => $pages,\\n\\t)\\n);\"},{\"step\":\"installPlugin\",\"pluginData\":{\"resource\":\"wordpress.org\\\/plugins\",\"slug\":\"nvoos-docs-hub\"},\"options\":{\"activate\":true}}]}"}},"all_blocks":[],"tagged_versions":["0.5.1"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3731763,"resolution":"1","location":"assets","locale":"","width":1238,"height":508},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3731763,"resolution":"2","location":"assets","locale":"","width":1008,"height":1147},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3731763,"resolution":"3","location":"assets","locale":"","width":1440,"height":900},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3731763,"resolution":"4","location":"assets","locale":"","width":1440,"height":900}},"screenshots":{"1":"Settings \u2014 documentation index status and rebuild panel.","2":"Settings \u2014 remote repositories with the GitHub file\/folder tree picker.","3":"Frontend <code>[nvoos_docs]<\/code> embed \u2014 sidebar, content, and table of contents.","4":"Frontend <code>[nvoos_docs]<\/code> embed \u2014 full-text search."}},"plugin_section":[],"plugin_tags":[6941,1673,4608],"plugin_category":[],"plugin_contributors":[277722],"plugin_business_model":[],"class_list":["post-367696","plugin","type-plugin","status-publish","hentry","plugin_tags-documentation","plugin_tags-github","plugin_tags-markdown","plugin_contributors-vsamtani","plugin_committers-vsamtani"],"banners":{"banner":"https:\/\/ps.w.org\/nvoos-docs-hub\/assets\/banner-772x250.png?rev=3731763","banner_2x":"https:\/\/ps.w.org\/nvoos-docs-hub\/assets\/banner-1544x500.png?rev=3731763","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/nvoos-docs-hub\/assets\/icon-128x128.png?rev=3731763","icon_2x":"https:\/\/ps.w.org\/nvoos-docs-hub\/assets\/icon-256x256.png?rev=3731763","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/nvoos-docs-hub\/assets\/screenshot-1.png?rev=3731763","caption":"Settings \u2014 documentation index status and rebuild panel."},{"src":"https:\/\/ps.w.org\/nvoos-docs-hub\/assets\/screenshot-2.png?rev=3731763","caption":"Settings \u2014 remote repositories with the GitHub file\/folder tree picker."},{"src":"https:\/\/ps.w.org\/nvoos-docs-hub\/assets\/screenshot-3.png?rev=3731763","caption":"Frontend <code>[nvoos_docs]<\/code> embed \u2014 sidebar, content, and table of contents."},{"src":"https:\/\/ps.w.org\/nvoos-docs-hub\/assets\/screenshot-4.png?rev=3731763","caption":"Frontend <code>[nvoos_docs]<\/code> embed \u2014 full-text search."}],"raw_content":"<!--section=description-->\n<p>NV oOS Docs Hub discovers, indexes, and renders Markdown documentation in a\nGitBook-style single-page app: sidebar navigation, content area, and a\nper-page table of contents. Embed it anywhere on your WordPress site via a\nshortcode or Gutenberg block.<\/p>\n\n<p>Out of the box it publishes documentation you upload yourself: drop\nMarkdown (<code>.md<\/code>) or text (<code>.txt<\/code>) files into\n    wp-content\/uploads\/nvoos-docs-hub\/content\/ (subfolders become sections),\nrebuild the index, and they appear in the browser. No remote services are\ninvolved.<\/p>\n\n<p><strong>Optional GitHub import (opt-in, off by default).<\/strong> Enable <em>Remote\nRepositories<\/em> in the settings to import Markdown from <strong>any public GitHub\nrepository<\/strong> \u2014 no GitHub account required. This is a documentation-import\nservice: the plugin fetches files server-side, over HTTPS, and only from\n    api.github.com and <code>raw.githubusercontent.com<\/code>, then stores them in a\nlocal cache on your server. No requests are made unless you enable the\nsetting, configure a repository, and trigger a rebuild. All scripts,\nstyles, fonts, and images are bundled locally \u2014 nothing is loaded from a\nremote server. See <strong>External Services<\/strong> below for the full disclosure.<\/p>\n\n<p><strong>Key features:<\/strong><\/p>\n\n<ul>\n<li>Publish Markdown uploaded to <code>wp-content\/uploads\/nvoos-docs-hub\/content\/<\/code> \u2014 zero configuration, zero remote calls<\/li>\n<li>Optional import from public GitHub repositories with per-repo file\/folder selection<\/li>\n<li>Full-text search via the REST API with FlexSearch client-side fallback<\/li>\n<li>GitHub Flavored Markdown: tables, task lists, fenced code blocks<\/li>\n<li>Custom <code>:::note<\/code>, <code>:::tip<\/code>, <code>:::warning<\/code>, <code>:::danger<\/code> callout blocks<\/li>\n<li>Syntax-highlighted code blocks, last-modified dates, and \"Edit on GitHub\" links<\/li>\n<li>Broken-link detection with one-click fix suggestions (local sources)<\/li>\n<li>Light and dark themes with CSS custom properties<\/li>\n<li>Two-layer cache (filesystem + WordPress transients)<\/li>\n<li>Async chunked rebuilds with a live progress panel \u2014 no more long single-request builds<\/li>\n<li>WP-CLI support: <code>wp nvoos-docs rebuild \/ clear \/ status<\/code><\/li>\n<li>Nightly cron rebuild; also triggered on plugin activate\/deactivate<\/li>\n<li>Indexed pages included in the WordPress sitemap<\/li>\n<li><code>[nvoos_docs]<\/code> shortcode and <code>nvoos\/docs-hub<\/code> Gutenberg block<\/li>\n<\/ul>\n\n<p><strong>Optional NV oOS integration.<\/strong> If the NV oOS base plugin\n(https:\/\/github.com\/nvdigitalsolutions\/mcp-ai-wpoos) is active, the addon\nadditionally auto-discovers the <code>docs\/<\/code> folders of the base plugin and every\ninstalled addon, and surfaces rebuild progress in the base plugin's cron-status\ndrawer.<\/p>\n\n<h3>Shortcode<\/h3>\n\n<pre><code>[nvoos_docs section=\"base\" theme=\"light\" search=\"1\" sidebar=\"1\"]\n<\/code><\/pre>\n\n<p>Attributes:<\/p>\n\n<ul>\n<li><code>section<\/code> \u2013 Filter to one source: <code>base<\/code>, <code>addons<\/code>, or an addon slug.<\/li>\n<li><code>theme<\/code> \u2013 <code>light<\/code>, <code>dark<\/code>, or <code>auto<\/code> (follows OS preference).<\/li>\n<li><code>search<\/code> \u2013 Set to <code>0<\/code> to disable the search box.<\/li>\n<li><code>sidebar<\/code> \u2013 Set to <code>0<\/code> to hide the left sidebar.<\/li>\n<li><code>home<\/code> \u2013 Slug of the default landing page.<\/li>\n<\/ul>\n\n<h3>WP-CLI<\/h3>\n\n<pre><code>wp nvoos-docs rebuild            # Chunked rebuild (default, runs across WP-Cron ticks)\nwp nvoos-docs rebuild --sync     # Inline rebuild in a single request (legacy)\nwp nvoos-docs sync               # Back-compat alias for --sync\nwp nvoos-docs rebuild --resume   # Resume a stalled or failed rebuild\nwp nvoos-docs rebuild --cancel   # Cancel an in-flight rebuild\nwp nvoos-docs clear              # Clear all cached data\nwp nvoos-docs status             # Show index statistics and rebuild phase&lt;h3&gt;Source Code&lt;\/h3&gt;\n<\/code><\/pre>\n\n<p>The complete, human-readable source code for this plugin \u2014 including the\nTypeScript\/React source for the bundled <code>assets\/dist\/docs-hub.js<\/code> bundle \u2014 is\npublicly available in the plugin's GitHub repository:<\/p>\n\n<p>https:\/\/github.com\/nvdigitalsolutions\/nvoos-docs-hub<\/p>\n\n<p>The frontend bundle is generated from the <code>src\/<\/code> directory with esbuild:<\/p>\n\n<ol>\n<li><code>npm install<\/code> \u2014 installs the frontend dependencies (React, esbuild, etc.).<\/li>\n<li><code>npm run build<\/code> \u2014 runs <code>node esbuild.config.js --prod<\/code> and writes the\nminified <code>assets\/dist\/docs-hub.js<\/code> and <code>assets\/dist\/docs-hub.css<\/code>.<\/li>\n<\/ol>\n\n<p>The repository also contains the WordPress.org packaging and CI pipeline\n(<code>.github\/workflows\/<\/code>, <code>bin\/<\/code>), the PHPUnit test suite (<code>tests\/<\/code>), and the\n    .wordpress-org\/ listing assets.<\/p>\n\n<h3>Third-Party Libraries<\/h3>\n\n<p>The bundled <code>assets\/dist\/docs-hub.js<\/code> frontend is built from TypeScript\/React\nsources in the public repository and includes the following open-source\nlibraries (all GPL-compatible licenses; MIT unless noted):<\/p>\n\n<ul>\n<li>React and React DOM (MIT) \u2014 https:\/\/react.dev<\/li>\n<li>React Markdown (MIT) \u2014 https:\/\/github.com\/remarkjs\/react-markdown<\/li>\n<li>React Router (MIT) \u2014 https:\/\/reactrouter.com<\/li>\n<li>FlexSearch (Apache-2.0) \u2014 https:\/\/github.com\/nextapps-de\/flexsearch<\/li>\n<li>Lowlight and highlight.js language grammars (MIT \/ BSD-3-Clause)<\/li>\n<li>The unified\/remark\/rehype ecosystem: remark-gfm, remark-directive,\nremark-frontmatter, rehype-slug, rehype-autolink-headings,\nrehype-highlight, unist-util-visit (MIT) and github-slugger (ISC)<\/li>\n<\/ul>\n\n<p>Build and test tooling (esbuild, ESLint, TypeScript, Vitest) is not shipped\nin the distribution ZIP. The complete dependency graph and its licenses are\nlisted in <code>package.json<\/code> and <code>package-lock.json<\/code> in the public repository.<\/p>\n\n<h3>External Services<\/h3>\n\n<p>This plugin provides an optional <strong>documentation-import service<\/strong>, disabled\nby default: remote requests happen only after an administrator enables\n<em>Remote Repositories<\/em> in the settings, configures at least one repository,\nand triggers a rebuild. When enabled, the plugin fetches Markdown files\nfrom public GitHub repositories, stores them locally in the uploads cache,\nand renders them in the documentation browser. Fetched content is cached\non your server, so visitors are served from the local cache, not from\nGitHub.<\/p>\n\n<p>All requests are made <strong>server-side only, over HTTPS<\/strong>, and only to the two\nhosts listed below. Every request is restricted to these hosts (all other\nhosts are rejected, including private and reserved IP addresses), carries a\nbounded timeout and a 4 MB response-size cap, and only happens after an\nadministrator has enabled the Remote Repositories setting, configured a\nrepository, and a rebuild is triggered \u2014 manually, via WP-CLI, by the\nnightly cron, or automatically when the cache is invalidated (a related\nplugin is activated, deactivated, or updated).\nNo requests are made unless the Remote Repositories setting is enabled and\na repository is configured.<\/p>\n\n<p><strong>No account is required<\/strong> for public repositories. An optional GitHub\npersonal access token can be saved in the settings to raise GitHub's API\nrate limits; it is stored server-side and sent only to the two hosts below.<\/p>\n\n<ul>\n<li><code>api.github.com<\/code> \u2014 repository and tree metadata used by the file\/folder\npicker and the indexer.<\/li>\n<li><code>raw.githubusercontent.com<\/code> \u2014 raw Markdown file content fetched during\nindex rebuilds.<\/li>\n<\/ul>\n\n<p>The plugin does not send any personal data to these services \u2014 it only\nfetches the public repository content exactly as GitHub serves it. Rendered\ndocumentation pages display the repository content as authored, which may\ninclude links and images pointing at <code>github.com<\/code>,\n    raw.githubusercontent.com, or <code>user-images.githubusercontent.com<\/code>; those\nare loaded by the visitor's browser directly from the source repository,\nnot through the plugin or your server.<\/p>\n\n<p>GitHub Terms of Service:\nhttps:\/\/docs.github.com\/en\/site-policy\/github-terms\/github-terms-of-service\nGitHub Privacy Statement:\nhttps:\/\/docs.github.com\/en\/site-policy\/privacy-policies\/github-general-privacy-statement<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>nvoos-docs-hub<\/code> folder to <code>\/wp-content\/plugins\/<\/code>.<\/li>\n<li>Activate the plugin through the <strong>Plugins<\/strong> admin screen.<\/li>\n<li>Add your Markdown files to <code>wp-content\/uploads\/nvoos-docs-hub\/content\/<\/code> (created automatically), go to <strong>Settings \u2192 NV oOS Docs Hub<\/strong>, and click <strong>Rebuild Index<\/strong>.<\/li>\n<li>Add <code>[nvoos_docs]<\/code> to any page to display the documentation browser.<\/li>\n<\/ol>\n\n<p>To import documentation from a public GitHub repository instead, go to\n<strong>Settings \u2192 NV oOS Docs Hub \u2192 Remote Repositories<\/strong>, enable the setting,\nand add your repositories.<\/p>\n\n<p>To also index local NV oOS documentation, activate the NV oOS base plugin and\nenable the <code>base<\/code>, <code>addons<\/code>, or <code>root<\/code> sources under <strong>Settings \u2192 NV oOS Docs\nHub \u2192 Advanced \u2014 local filesystem (legacy)<\/strong>.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20plugin%20require%20the%20nv%20oos%20base%20plugin%3F\"><h3>Does this plugin require the NV oOS base plugin?<\/h3><\/dt>\n<dd><p>No. Out of the box it publishes Markdown files from\n    wp-content\/uploads\/nvoos-docs-hub\/content\/. If the NV oOS base plugin is\nactive, additional local sources (the base plugin's <code>docs\/<\/code> folder and\ninstalled addons) are discovered automatically.<\/p><\/dd>\n<dt id=\"can%20i%20index%20docs%20from%20a%20github%20repository%3F\"><h3>Can I index docs from a GitHub repository?<\/h3><\/dt>\n<dd><p>Yes. First enable <strong>Remote Repositories<\/strong> under <strong>Settings \u2192 NV oOS Docs\nHub<\/strong>, then add a repository and either index the whole repository,\nrestrict it to a folder prefix, or use the \"Browse files in repo\u2026\" picker\nto select individual files and folders.<\/p><\/dd>\n<dt id=\"which%20file%20types%20are%20indexed%3F\"><h3>Which file types are indexed?<\/h3><\/dt>\n<dd><p>Only <code>.md<\/code> and <code>.txt<\/code> files up to 2 MB in size (local sources) or 4 MB (remote\nsources).<\/p><\/dd>\n<dt id=\"how%20do%20i%20exclude%20specific%20files%3F\"><h3>How do I exclude specific files?<\/h3><\/dt>\n<dd><p>Use the <code>nvoos_docs_hub_excluded_globs<\/code> filter to return an array of glob\npatterns (relative to each source root) that should be excluded.<\/p><\/dd>\n<dt id=\"can%20i%20restrict%20public%20access%20to%20the%20docs%3F\"><h3>Can I restrict public access to the docs?<\/h3><\/dt>\n<dd><p>Yes. Use the <code>nvoos_docs_hub_can_read_section<\/code> filter. Return a <code>WP_Error<\/code> or\n    false to block unauthenticated REST access. You can also restrict at the\nshortcode level with the <code>nvoos_docs_hub_can_render<\/code> filter. Alternatively,\nturn off <strong>Allow Public (Guest) Access<\/strong> in the settings to require a\nWordPress login for all docs.<\/p><\/dd>\n<dt id=\"how%20is%20the%20cache%20invalidated%3F\"><h3>How is the cache invalidated?<\/h3><\/dt>\n<dd><p>Automatically when any plugin is activated or deactivated, after NV oOS plugin\nupdates, on a nightly scheduled cron job, and via a version-mismatch guard that\nrebuilds when the installed plugin versions no longer match the cached index.\nYou can also rebuild manually from the settings page, via WP-CLI, or via the\nREST API (requires <code>manage_options<\/code>).<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>0.5.1<\/h4>\n\n<ul>\n<li>Changed: the uploads content folder moved from <code>wp-content\/uploads\/docs\/<\/code> to <code>wp-content\/uploads\/nvoos-docs-hub\/content\/<\/code> \u2014 nested inside the plugin's slug-named uploads directory, per the WordPress.org plugin guidelines. Existing content is migrated automatically on activation or first admin visit.<\/li>\n<li>Added: automatic one-time migration of the pre-0.5.1 <code>wp-content\/uploads\/docs\/<\/code> folder (best-effort, never overwrites existing files, symlinks are never followed).<\/li>\n<\/ul>\n\n<h4>0.5.0<\/h4>\n\n<ul>\n<li>Added: local-first default \u2014 the plugin now publishes Markdown files dropped into <code>wp-content\/uploads\/docs\/<\/code> out of the box, with zero remote calls.<\/li>\n<li>Added: \"Enable Remote Repositories\" opt-in setting (off by default). Remote GitHub import now requires enabling the setting, configuring a repository, and triggering a rebuild. Existing installs that already use remote repositories keep them enabled automatically.<\/li>\n<li>Security: the local-source scanner now resolves symlinks before its containment check, so a symlinked subfolder cannot leak files from outside the docs folder.<\/li>\n<li>Changed: remote import is gated server-side (scanner and file-picker endpoint) whenever the setting is off.<\/li>\n<\/ul>\n\n<h4>0.4.8<\/h4>\n\n<ul>\n<li>Changed: the readme Description now explains the documentation-import service up front \u2014 the servers contacted (<code>api.github.com<\/code>, <code>raw.githubusercontent.com<\/code>), that no account is required, that requests happen only on administrator-configured rebuilds, and that no plugin assets are loaded remotely.<\/li>\n<li>Changed: the remote-repository fetcher's host allowlist and fetch code now reference the readme's External Services disclosure.<\/li>\n<\/ul>\n\n<h4>0.4.7<\/h4>\n\n<ul>\n<li>Fixed: removed the \"Tested up to\" line from the plugin headers \u2014 it is declared only in the readme.<\/li>\n<li>Fixed: the daily rebuild cron is now scheduled on <code>init<\/code> instead of <code>plugins_loaded<\/code>, which prevented \"translation loading triggered too early\" notices on WordPress 6.7+ when other plugins register translated cron schedules.<\/li>\n<li>Changed: rebuild cron events are cleared when the plugin is deactivated, and deactivating the plugin no longer enqueues a rebuild that could never run.<\/li>\n<li>Changed: the readme now discloses the bundled third-party libraries and their licenses and lists every automatic rebuild trigger in the External Services section.<\/li>\n<\/ul>\n\n<h4>0.4.6<\/h4>\n\n<ul>\n<li>Added: bundled GPLv3 license file (LICENSE) at the plugin root.<\/li>\n<\/ul>\n\n<h4>0.4.5<\/h4>\n\n<ul>\n<li>Security: a symlinked cache directory can no longer redirect deletion \u2014 the uninstall routine removes only the link and leaves the external target untouched, and the cache class replaces a symlinked cache directory with a real one before writing.<\/li>\n<li>Changed: the External Services section now explains the documentation-import service, the servers it contacts, and that no account is required for public repositories.<\/li>\n<\/ul>\n\n<h4>0.4.4<\/h4>\n\n<ul>\n<li>Security: search results and the WordPress sitemap no longer expose context-source (<code>.context\/<\/code>) content to non-admin users.<\/li>\n<li>Security: GitHub personal access tokens are no longer localized into the settings-page scripts (they were stripped only on export before).<\/li>\n<li>Security: staged rebuilds no longer read or write live page transients, page transients are invalidated when the cache is promoted or cleared, and recursive cache deletion is hardened against symlink traversal.<\/li>\n<li>Changed: the base-plugin notice is scoped to the Docs Hub settings page, and the redundant <code>load_plugin_textdomain()<\/code> call was removed.<\/li>\n<li>Changed: readme now documents the public source repository and the frontend build steps; the bundled <code>docs-hub.js<\/code> and <code>docs-hub.css<\/code> carry source banners.<\/li>\n<\/ul>\n\n<h4>0.4.3<\/h4>\n\n<ul>\n<li>Added: WordPress.org listing screenshots and a Playwright capture script (<code>bin\/capture-nvoos-docs-hub-screenshots.js<\/code>).<\/li>\n<li>Added: WordPress.org submission preparation \u2014 External Services section in the readme, a translation template (languages\/nvoos-docs-hub.pot), and a WordPress.org Plugin Check gate in CI.<\/li>\n<li>Changed: settings-page scripts moved to a static asset (no inline  blocks), text-domain consistency fix, dev files excluded from distribution ZIPs.<\/li>\n<li>Changed: readme tags trimmed to directory-standard tags.<\/li>\n<\/ul>\n\n<h4>0.4.2<\/h4>\n\n<ul>\n<li>Fixed: clicking internal links on local pages left the SPA \u2014 links now resolve to <code>#\/slug<\/code> hash routes with heading anchors preserved.<\/li>\n<li>Fixed: \"On this page\" TOC anchors now match rendered headings exactly (github-slugger parity verified across ~63,000 headings).<\/li>\n<li>Fixed: \"Accept fix\" suggestions now resolve targets relative to the source page and validate the resolved destination against plugin\/content roots.<\/li>\n<li>Fixed: sync rebuilds (<code>wp nvoos-docs sync<\/code>, <code>POST \/rebuild?sync=1<\/code>) now report an error when the atomic staging-cache swap fails.<\/li>\n<li>Fixed: skipped broken-link rows in the settings table now show the server-provided reason; remote-sourced rows explain they must be fixed upstream.<\/li>\n<\/ul>\n\n<h4>0.4.1<\/h4>\n\n<ul>\n<li>Fixed: index went stale after in-place NV oOS plugin updates \u2014 cache now invalidates on the new <code>wp_mcp_ai_plugin_updated<\/code> action plus an <code>admin_init<\/code> version-mismatch guard.<\/li>\n<li>Fixed: broken-link detection on remote-only indexes no longer flags repo-relative links; fix suggestions are case-insensitive with clamped confidence.<\/li>\n<\/ul>\n\n<h4>0.4.0<\/h4>\n\n<ul>\n<li>Fixed: \"Unexpected token '&lt;'\" errors when page-caching plugins serve HTML for REST requests \u2014 clients now send <code>Accept: application\/json<\/code> and validate the response content type.<\/li>\n<li>Fixed: non-404 page-load failures no longer masquerade as \"404 Page Not Found\"; they show a diagnostic error block.<\/li>\n<\/ul>\n\n<p><h4>0.3.9<\/h4><\/p>\n\n<ul>\n<li>Fixed: fatal error during WordPress sitemap provider registration (now hooked into <code>wp_sitemaps_init<\/code>).<\/li>\n<li>Added: <code>fnmatch()<\/code> polyfill for Windows PHP environments.<\/li>\n<\/ul>\n\n<p><h4>0.3.8<\/h4><\/p>\n\n<ul>\n<li>Added: syntax highlighting via <code>rehype-highlight<\/code> with a scoped light\/dark theme.<\/li>\n<li>Added: last-modified footer date and \"Edit on GitHub\" links.<\/li>\n<li>Added: indexed docs pages included in the WordPress sitemap.<\/li>\n<li>Added: admin repo-picker script extracted to a static, CSP-friendly asset.<\/li>\n<\/ul>\n\n<p><h4>0.3.7<\/h4><\/p>\n\n<ul>\n<li>Added: accessibility improvements \u2014 ARIA region for the SPA, skip-link to main content, <code>prefers-reduced-motion<\/code> support, RTL layout mirroring.<\/li>\n<\/ul>\n\n<p><h4>0.3.6<\/h4><\/p>\n\n<ul>\n<li>Fixed: fatal error on the settings page with malformed <code>remote_repos<\/code> rows.<\/li>\n<li>Added: hardened SSRF protection for remote GitHub fetches (IPv6-aware resolution, per-record validation).<\/li>\n<li>Added: force-refresh clears the per-file remote content cache.<\/li>\n<\/ul>\n\n<p><h4>0.3.2<\/h4><\/p>\n\n<ul>\n<li>Fixed: PHPCS compliance pass (96 errors \/ 38 warnings resolved).<\/li>\n<\/ul>\n\n<p><h4>0.3.1<\/h4><\/p>\n\n<ul>\n<li>Fixed: admin rebuild panel 404 (wrong REST namespace).<\/li>\n<li>Changed: remote-repositories settings section now explains the tree-picker workflow.<\/li>\n<\/ul>\n\n<p><h4>0.3.0<\/h4><\/p>\n\n<ul>\n<li>Changed: fresh installs default to remote-first sources (<code>remote<\/code> only); local filesystem sources moved under \"Advanced \u2014 local filesystem (legacy)\".<\/li>\n<li>Added: lookup-and-select tree picker for remote repositories with per-repo selection modes (<code>all<\/code>, <code>prefix<\/code>, <code>selected<\/code>).<\/li>\n<li>Added: admin REST endpoint <code>GET \/remote\/tree<\/code>.<\/li>\n<\/ul>\n\n<p><h4>0.2.0<\/h4><\/p>\n\n<ul>\n<li>Chunked, async-by-default rebuild pipeline (<code>scan<\/code> \u2192 <code>pages<\/code> \u2192 <code>links<\/code> \u2192 <code>search<\/code> \u2192 <code>finalize<\/code>) driven by self-rescheduling WP-Cron ticks. Per-tick wall-clock + memory budgets prevent the historical \"single 60 s+ PHP request crashes on a large repo\" failure mode.<\/li>\n<li>Atomic staging-cache swap. A failed rebuild leaves the previous index intact instead of wiping the docs and leaving the SPA blank.<\/li>\n<li>Built-in vendor \/ dependency exclusion (<code>vendor\/<\/code>, <code>node_modules\/<\/code>, <code>bower_components\/<\/code>, <code>.git\/<\/code>, <code>.github\/<\/code>, <code>dist\/<\/code>, <code>build\/<\/code>, <code>coverage\/<\/code>, <code>tests\/fixtures\/<\/code>) applied during recursive scan to prune subdirectories before recursion. New <code>nvoos_docs_hub_force_include_globs<\/code> filter allow-lists specific vendored docs.<\/li>\n<li>Plugin-root <code>README.md<\/code> \/ <code>CHANGELOG.md<\/code> \/ <code>CONTRIBUTING.md<\/code> \/ <code>SECURITY.md<\/code> are now indexed unconditionally when the <code>root<\/code> source is enabled (no longer gated behind <code>WP_DEBUG<\/code>). <code>.context\/*.md<\/code> remains gated behind <code>context_enabled<\/code> + <code>manage_options<\/code>.<\/li>\n<li>New source-priority (<code>root<\/code> &gt; <code>base<\/code> &gt; <code>addons<\/code> &gt; <code>context<\/code> &gt; <code>remote<\/code>) ensures the plugin-root README wins the canonical <code>readme<\/code> slug; addon READMEs receive suffixed slugs.<\/li>\n<li>New REST endpoints: <code>GET \/rebuild\/status<\/code>, <code>POST \/rebuild\/cancel<\/code>, <code>POST \/rebuild\/resume<\/code>. <code>POST \/rebuild<\/code> returns HTTP 202 by default; pass <code>?sync=1<\/code> for the legacy inline behaviour.<\/li>\n<li>New WP-CLI command: <code>wp nvoos-docs rebuild [--async|--sync|--resume|--cancel]<\/code>.<\/li>\n<li>Admin UI: live progress panel polls <code>\/rebuild\/status<\/code> with start \/ resume \/ cancel buttons.<\/li>\n<li>New filters: <code>nvoos_docs_hub_force_include_globs<\/code>, <code>nvoos_docs_hub_pruned_dir_names<\/code>, <code>nvoos_docs_hub_source_priority<\/code>, <code>nvoos_docs_hub_rebuild_chunk_size<\/code>, <code>nvoos_docs_hub_rebuild_tick_budget<\/code>, <code>nvoos_docs_hub_max_files_total<\/code>. New action: <code>nvoos_docs_hub_rebuild_phase<\/code>.<\/li>\n<li>New setting: \"Include per-addon README\/CHANGELOG\" (default on).<\/li>\n<li>Performance: <code>build_search_index()<\/code> now reuses cached page payloads instead of re-reading every file.<\/li>\n<\/ul>\n\n<p><h4>0.1.0<\/h4><\/p>\n\n<ul>\n<li>Initial release.<\/li>\n<\/ul>","raw_excerpt":"Self-contained docs browser for WordPress. Publish Markdown you upload, or optionally import from public GitHub repos.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/sa.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/367696","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sa.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/sa.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/sa.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=367696"}],"author":[{"embeddable":true,"href":"https:\/\/sa.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/vsamtani"}],"wp:attachment":[{"href":"https:\/\/sa.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=367696"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/sa.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=367696"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/sa.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=367696"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/sa.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=367696"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/sa.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=367696"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/sa.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=367696"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}