QH Markdown Exporter
QH Markdown Exporter
Description
QH Markdown Exporter lets you export any combination of post types and statuses as Markdown files — perfectly formatted for Obsidian and other Markdown-based note-taking apps.
Key features:
- YAML frontmatter — title, source URL, author, published date, description, tags, and full hierarchical categories
- Extended metadata (optional, on by default) — adds
word_count,outline(ordered H2–H4 heading list), andinternal_links(structured list of links to other exported posts) to each file’s frontmatter — ideal for AI/SEO tooling - Clean content — strips sidebars, widgets, navigation, related-posts blocks, social-share plugins, and other injected noise
- GFM tables — converts HTML tables to GitHub-Flavored Markdown pipe tables
- Bulk export — export your entire site at once or filter by post type, status, and date range
- Large-site support — chunked AJAX export with live progress bar handles sites with thousands of posts
- Sitemap export — optional
sitemap.jsonbundled in the ZIP: hierarchical pages tree, posts grouped by category, and custom post types — ready for AI/LLM ingestion - No dependencies — pure PHP with no external libraries required
Output format:
Each post becomes a .md file named YYYY-MM-DD_Post Title.md containing:
`
title: “Post Title”
source: “https://yoursite.com/post-slug/”
author:
– “[[Author Name]]”
published: 2024-01-15
created: 2024-06-01
description: “Post excerpt or auto-generated summary…”
tags:
– tag-name
categories:
– “Parent > Child”
word_count: 1250
outline:
– “## What This Post Covers”
– “### Step One”
– “## Conclusion”
internal_links:
– slug: “related-post-slug”
anchor: “related post title”
url: “https://yoursite.com/related-post-slug/”
Post Title
Post body in Markdown…
`
The word_count, outline, and internal_links fields are added when Include extended metadata is ticked (default: on). internal_links only lists links to other posts included in the current export — external links and links to non-exported content are excluded.
All files are bundled into a single ZIP archive named {sitename}_md_export_YYYY-MM-DD.zip.
Installation
- Upload the
qh-markdown-exporterfolder to the/wp-content/plugins/directory, or install directly through the WordPress plugin screen. - Activate the plugin through the Plugins screen in WordPress.
- Go to Tools MD Exporter.
- Select the post types and statuses you want to export, optionally set a date range, and click Export & Download ZIP.
Faq
All public post types registered on your site are available. The attachment post type is excluded by default.
For exports above 100 posts the plugin automatically switches to a chunked AJAX export. You will see a live progress bar. Each batch of 100 posts is processed separately to avoid server timeouts.
Image tags are converted to Markdown  format pointing to the original URLs on your site. The image files themselves are not downloaded or included in the ZIP.
Users must have the export capability (Editor role and above by default).
The exporter reads raw post_content and processes it through do_blocks() (Gutenberg) then converts HTML to Markdown. It intentionally bypasses the_content filters to avoid injected content from page builders and other plugins.
Reviews
Changelog
2.2.4
- Prevented plugin activation fatal errors when an incomplete release package is missing
includes/v3-handlers.php. - Entitron V3 export now checks both V3 release files before enabling the V3 export button and reports the exact missing files in wp-admin.
- Kept the split V3 handler file while loading it only when it is present.
2.2.3
- Removed legacy Entitron V2 builder code that is no longer used by the V3 export flow.
- Removed stale V2-only comments and unused link-count helper code.
- Replaced inline progress visibility styles with markup/CSS state and kept the single export button behavior.
2.2.2
- Fixed the release package for Entitron V3 export so
includes/class-export-v3-builder.phpis included with the plugin. - Added an install integrity check for the Entitron V3 builder file. If a server has an incomplete plugin upload, the export page now shows a clear admin error instead of a PHP fatal error.
2.1.0
- Chunked V3 export — Entitron V3 export now uses a three-phase AJAX flow (Prepare Chunk Finalize) instead of a single synchronous POST. Eliminates HTTP 503 (Varnish timeout) and PHP fatal errors (memory exhaustion) on large sites.
- Single DOM per post — V3 builder now uses one DOMDocument per post instead of three, reducing peak memory by ~60%.
- File-based JSONL append — articles.jsonl is built incrementally on disk using
fopen('ab')+flock(LOCK_EX)instead of in-memory accumulation. Handles 10,000+ posts without OOM. - Zero-copy ZIP —
ZipArchive::addFile()for large articles.jsonl files (no memory buffer). - Error handling —
register_shutdown_function+try/catch+wp_send_json_erroron every V3 AJAX handler. Legacy sync handler also wrapped. - PHP 7.4 compatibility — no
match,readonly, orenumsyntax. Usesarray()where appropriate. - Output schema unchanged — manifest.json + articles.jsonl + taxonomy.json, same format as v2.0.0.
2.0.0
- Entitron export — new “Export for Entitron” button generates a JSONL-based ZIP for the Entitron SEO Analyzer (V2 format).
- V2 format files:
entitron_manifest.json(detection sentinel + package metadata),articles.jsonl(one record per post with full content and metadata),links.jsonl(raw internal link edges with before/after text context),taxonomy.json(full categories + tags hierarchy),site_inventory.json(site-wide totals, date range, and languages). - Link context extraction — each internal link edge captures 60-character before/after snippet and anchor text, enabling downstream tools to understand link intent.
- Link count aggregation —
articles.jsonlincludesinternal_links_in,internal_links_out, andexternal_links_outcounts per post. - Shared traits — introduced reusable link context and link count helpers for Entitron exports.
1.6.0
- Added Include extended metadata option (enabled by default) — appends three new fields to each file’s YAML frontmatter:
word_count— integer word count of the post body (plain text, no HTML).outline— ordered list of H2, H3, and H4 headings with Markdown prefix (##,###,####).internal_links— structured list of links that point to other posts included in the same export, each withslug,anchortext, and canonicalurl. Links to pages, categories, or posts outside the export set are excluded, preventing false “broken link” reports in downstream tools.
- Extended metadata can be disabled by unchecking the option — the export then produces the same output as previous versions.
1.5.1
- Refactored sitemap.json output for cleaner AI/LLM consumption.
- Replaced
posts_by_categoryobject (dynamic keys) with acategoriesarray — each category hasid(slug),name, andposts. - Deduplicated posts: each post now appears only once, under its primary category.
- Decoded HTML entities in all titles (
&&, etc.). - Filtered out internal builder CPTs (Elementor library, Gutenberg reusable blocks, etc.) using the
show_in_nav_menusflag. - Converted
custom_post_typesfrom a slug-keyed object to a typed array{ type, label, posts }. - Added
metadatablock: site URL, generation date,total_pages,total_categories,total_posts.
1.5.0
- Added optional sitemap.json export — tick “Include sitemap.json” in the export form to bundle a site structure file into the ZIP.
- Sitemap includes: hierarchical pages tree (parent child), posts grouped by category, and public custom post types.
- Sitemap reflects the live site and intentionally ignores any date-range filters set on the export form.
1.4.0
- Renamed plugin to “QH Markdown Exporter” with slug
qh-markdown-exporterfor WordPress.org compliance. - Renamed all internal prefixes from
pme_/PME_(3 chars) toqhmaex_/QHMAEX_(6 chars) to meet the 4+ character prefix requirement. - Updated text domain from
post-markdown-exportertoqh-markdown-exporteracross all files. - Fixed upload directory path to use
wp_upload_dir()instead of hardcodedWP_CONTENT_DIR . '/uploads/'.
1.3.0
- Renamed plugin to “Post Markdown Exporter” for WordPress.org compliance.
- Fixed output escaping to meet WordPress coding standards.
- Replaced unlink() with wp_delete_file() and file_put_contents() with WP_Filesystem.
- Added wp_unslash() to all sanitized input handling.
- Fixed i18n placeholder ordering in translatable strings.
- Updated “Tested up to” to WordPress 6.9.
1.2.0
- Added chunked AJAX export with live progress bar for large sites.
- Added date range filter.
- Improved filename sanitization with Unicode support.
- Added hierarchical category paths (Parent > Child).
1.1.0
- Added GFM pipe-table conversion.
- Added junk-node removal (navigation, sidebars, social share widgets).
- Added YAML frontmatter with author, tags, and categories.
1.0.0
- Initial release. Basic HTML-to-Markdown export with ZIP download.