{"id":302314,"date":"2026-04-27T08:04:09","date_gmt":"2026-04-27T08:04:09","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/post-markdown-exporter\/"},"modified":"2026-04-29T14:47:42","modified_gmt":"2026-04-29T14:47:42","slug":"qh-markdown-exporter","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/qh-markdown-exporter\/","author":23483856,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.6.0","stable_tag":"trunk","tested":"6.9.4","requires":"5.8","requires_php":"7.4","requires_plugins":null,"header_name":"QH Markdown Exporter","header_author":"Quyet Tran","header_description":"Export WordPress posts to Obsidian-compatible Markdown (.md) with YAML frontmatter. Bulk export as ZIP archive.","assets_banners_color":"","last_updated":"2026-04-29 14:47:42","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/wordpress.org\/plugins\/qh-markdown-exporter\/","header_author_uri":"https:\/\/repairsadvisor.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":155,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.4.0":{"tag":"1.4.0","author":"quyettran298","date":"2026-04-27 08:14:52"},"1.5.0":{"tag":"1.5.0","author":"quyettran298","date":"2026-04-29 09:12:46"},"1.5.1":{"tag":"1.5.1","author":"quyettran298","date":"2026-04-29 09:47:56"},"v1.6.0":{"tag":"v1.6.0","author":"quyettran298","date":"2026-04-29 14:48:23"}},"upgrade_notice":{"1.6.0":"<p>New optional &quot;Include extended metadata&quot; feature adds word_count, outline, and internal_links to YAML frontmatter. Enabled by default; uncheck to keep previous output format. No database changes; safe to upgrade.<\/p>","1.5.1":"<p>Improves sitemap.json structure and data quality. No database changes; safe to upgrade.<\/p>","1.5.0":"<p>New optional feature: tick &quot;Include sitemap.json&quot; on the export form to get a full site structure JSON file in your ZIP. No database changes; safe to upgrade.<\/p>","1.4.0":"<p>Plugin renamed to &quot;QH Markdown Exporter&quot;. Temp files now stored in uploads\/qh-markdown-exporter\/. No database changes; safe to upgrade.<\/p>","1.3.0":"<p>Plugin renamed from &quot;WP MD Exporter&quot; to &quot;Post Markdown Exporter&quot; for WordPress.org compliance. No database changes; safe to upgrade.<\/p>"},"ratings":[],"assets_icons":[],"assets_banners":[],"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.4.0","1.5.0","1.5.1","v1.6.0"],"block_files":[],"assets_screenshots":[],"screenshots":{"1":"The export page showing post type and status filters, date range, and export buttons.","2":"Progress bar during a large chunked export.","3":"Example <code>.md<\/code> file opened in Obsidian showing YAML frontmatter and converted content."},"jetpack_post_was_ever_published":false},"plugin_section":[],"plugin_tags":[151,1859,4608,261138,166],"plugin_category":[59],"plugin_contributors":[261139],"plugin_business_model":[],"class_list":["post-302314","plugin","type-plugin","status-publish","hentry","plugin_tags-backup","plugin_tags-export","plugin_tags-markdown","plugin_tags-obsidian","plugin_tags-posts","plugin_category-utilities-and-tools","plugin_contributors-quyettran298","plugin_committers-quyettran298"],"banners":[],"icons":{"svg":false,"icon":"https:\/\/s.w.org\/plugins\/geopattern-icon\/qh-markdown-exporter.svg","icon_2x":false,"generated":true},"screenshots":[],"raw_content":"<!--section=description-->\n<p>QH Markdown Exporter lets you export any combination of post types and statuses as Markdown files \u2014 perfectly formatted for <a href=\"https:\/\/obsidian.md\/\">Obsidian<\/a> and other Markdown-based note-taking apps.<\/p>\n\n<p><strong>Key features:<\/strong><\/p>\n\n<ul>\n<li><strong>YAML frontmatter<\/strong> \u2014 title, source URL, author, published date, description, tags, and full hierarchical categories<\/li>\n<li><strong>Extended metadata<\/strong> (optional, on by default) \u2014 adds <code>word_count<\/code>, <code>outline<\/code> (ordered H2\u2013H4 heading list), and <code>internal_links<\/code> (structured list of links to other exported posts) to each file's frontmatter \u2014 ideal for AI\/SEO tooling<\/li>\n<li><strong>Clean content<\/strong> \u2014 strips sidebars, widgets, navigation, related-posts blocks, social-share plugins, and other injected noise<\/li>\n<li><strong>GFM tables<\/strong> \u2014 converts HTML tables to GitHub-Flavored Markdown pipe tables<\/li>\n<li><strong>Bulk export<\/strong> \u2014 export your entire site at once or filter by post type, status, and date range<\/li>\n<li><strong>Large-site support<\/strong> \u2014 chunked AJAX export with live progress bar handles sites with thousands of posts<\/li>\n<li><strong>Sitemap export<\/strong> \u2014 optional <code>sitemap.json<\/code> bundled in the ZIP: hierarchical pages tree, posts grouped by category, and custom post types \u2014 ready for AI\/LLM ingestion<\/li>\n<li><strong>No dependencies<\/strong> \u2014 pure PHP with no external libraries required<\/li>\n<\/ul>\n\n<p><strong>Output format:<\/strong><\/p>\n\n<p>Each post becomes a <code>.md<\/code> file named <code>YYYY-MM-DD_Post Title.md<\/code> containing:<\/p>\n\n    `\n\n<p>title: \"Post Title\"\nsource: \"https:\/\/yoursite.com\/post-slug\/\"\nauthor:\n  - \"[[Author Name]]\"\npublished: 2024-01-15\ncreated: 2024-06-01\ndescription: \"Post excerpt or auto-generated summary...\"\ntags:\n  - tag-name\ncategories:\n  - \"Parent &gt; Child\"\nword_count: 1250\noutline:\n  - \"## What This Post Covers\"\n  - \"### Step One\"\n  - \"## Conclusion\"\ninternal_links:\n  - slug: \"related-post-slug\"\n    anchor: \"related post title\"<\/p>\n\n    url: \"https:\/\/yoursite.com\/related-post-slug\/\"\n\nPost Title\n\n<p>Post body in Markdown...\n    `<\/p>\n\n<p>The <code>word_count<\/code>, <code>outline<\/code>, and <code>internal_links<\/code> fields are added when <strong>Include extended metadata<\/strong> is ticked (default: on). <code>internal_links<\/code> only lists links to other posts included in the current export \u2014 external links and links to non-exported content are excluded.<\/p>\n\n<p>All files are bundled into a single ZIP archive named <code>{sitename}_md_export_YYYY-MM-DD.zip<\/code>.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>qh-markdown-exporter<\/code> folder to the <code>\/wp-content\/plugins\/<\/code> directory, or install directly through the WordPress plugin screen.<\/li>\n<li>Activate the plugin through the <strong>Plugins<\/strong> screen in WordPress.<\/li>\n<li>Go to <strong>Tools \u2192 MD Exporter<\/strong>.<\/li>\n<li>Select the post types and statuses you want to export, optionally set a date range, and click <strong>Export &amp; Download ZIP<\/strong>.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"which%20post%20types%20are%20supported%3F\"><h3>Which post types are supported?<\/h3><\/dt>\n<dd><p>All public post types registered on your site are available. The <code>attachment<\/code> post type is excluded by default.<\/p><\/dd>\n<dt id=\"how%20does%20it%20handle%20large%20sites%3F\"><h3>How does it handle large sites?<\/h3><\/dt>\n<dd><p>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.<\/p><\/dd>\n<dt id=\"does%20it%20export%20images%3F\"><h3>Does it export images?<\/h3><\/dt>\n<dd><p>Image tags are converted to Markdown <code>![alt](src)<\/code> format pointing to the original URLs on your site. The image files themselves are not downloaded or included in the ZIP.<\/p><\/dd>\n<dt id=\"what%20capability%20is%20required%20to%20use%20the%20exporter%3F\"><h3>What capability is required to use the exporter?<\/h3><\/dt>\n<dd><p>Users must have the <code>export<\/code> capability (Editor role and above by default).<\/p><\/dd>\n<dt id=\"will%20it%20conflict%20with%20page-builder%20plugins%3F\"><h3>Will it conflict with page-builder plugins?<\/h3><\/dt>\n<dd><p>The exporter reads raw <code>post_content<\/code> and processes it through <code>do_blocks()<\/code> (Gutenberg) then converts HTML to Markdown. It intentionally bypasses <code>the_content<\/code> filters to avoid injected content from page builders and other plugins.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.6.0<\/h4>\n\n<ul>\n<li>Added <strong>Include extended metadata<\/strong> option (enabled by default) \u2014 appends three new fields to each file's YAML frontmatter:\n\n<ul>\n<li><code>word_count<\/code> \u2014 integer word count of the post body (plain text, no HTML).<\/li>\n<li><code>outline<\/code> \u2014 ordered list of H2, H3, and H4 headings with Markdown prefix (<code>##<\/code>, <code>###<\/code>, <code>####<\/code>).<\/li>\n<li><code>internal_links<\/code> \u2014 structured list of links that point to other posts included in the same export, each with <code>slug<\/code>, <code>anchor<\/code> text, and canonical <code>url<\/code>. Links to pages, categories, or posts outside the export set are excluded, preventing false \"broken link\" reports in downstream tools.<\/li>\n<\/ul><\/li>\n<li>Extended metadata can be disabled by unchecking the option \u2014 the export then produces the same output as previous versions.<\/li>\n<\/ul>\n\n<h4>1.5.1<\/h4>\n\n<ul>\n<li>Refactored sitemap.json output for cleaner AI\/LLM consumption.<\/li>\n<li>Replaced <code>posts_by_category<\/code> object (dynamic keys) with a <code>categories<\/code> array \u2014 each category has <code>id<\/code> (slug), <code>name<\/code>, and <code>posts<\/code>.<\/li>\n<li>Deduplicated posts: each post now appears only once, under its primary category.<\/li>\n<li>Decoded HTML entities in all titles (<code>&amp;amp;<\/code> \u2192 <code>&amp;<\/code>, etc.).<\/li>\n<li>Filtered out internal builder CPTs (Elementor library, Gutenberg reusable blocks, etc.) using the <code>show_in_nav_menus<\/code> flag.<\/li>\n<li>Converted <code>custom_post_types<\/code> from a slug-keyed object to a typed array <code>{ type, label, posts }<\/code>.<\/li>\n<li>Added <code>metadata<\/code> block: site URL, generation date, <code>total_pages<\/code>, <code>total_categories<\/code>, <code>total_posts<\/code>.<\/li>\n<\/ul>\n\n<h4>1.5.0<\/h4>\n\n<ul>\n<li>Added optional sitemap.json export \u2014 tick \"Include sitemap.json\" in the export form to bundle a site structure file into the ZIP.<\/li>\n<li>Sitemap includes: hierarchical pages tree (parent \u2192 child), posts grouped by category, and public custom post types.<\/li>\n<li>Sitemap reflects the live site and intentionally ignores any date-range filters set on the export form.<\/li>\n<\/ul>\n\n<h4>1.4.0<\/h4>\n\n<ul>\n<li>Renamed plugin to \"QH Markdown Exporter\" with slug <code>qh-markdown-exporter<\/code> for WordPress.org compliance.<\/li>\n<li>Renamed all internal prefixes from <code>pme_<\/code>\/<code>PME_<\/code> (3 chars) to <code>qhmaex_<\/code>\/<code>QHMAEX_<\/code> (6 chars) to meet the 4+ character prefix requirement.<\/li>\n<li>Updated text domain from <code>post-markdown-exporter<\/code> to <code>qh-markdown-exporter<\/code> across all files.<\/li>\n<li>Fixed upload directory path to use <code>wp_upload_dir()<\/code> instead of hardcoded <code>WP_CONTENT_DIR . '\/uploads\/'<\/code>.<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>Renamed plugin to \"Post Markdown Exporter\" for WordPress.org compliance.<\/li>\n<li>Fixed output escaping to meet WordPress coding standards.<\/li>\n<li>Replaced unlink() with wp_delete_file() and file_put_contents() with WP_Filesystem.<\/li>\n<li>Added wp_unslash() to all sanitized input handling.<\/li>\n<li>Fixed i18n placeholder ordering in translatable strings.<\/li>\n<li>Updated \"Tested up to\" to WordPress 6.9.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Added chunked AJAX export with live progress bar for large sites.<\/li>\n<li>Added date range filter.<\/li>\n<li>Improved filename sanitization with Unicode support.<\/li>\n<li>Added hierarchical category paths (Parent &gt; Child).<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Added GFM pipe-table conversion.<\/li>\n<li>Added junk-node removal (navigation, sidebars, social share widgets).<\/li>\n<li>Added YAML frontmatter with author, tags, and categories.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release. Basic HTML-to-Markdown export with ZIP download.<\/li>\n<\/ul>","raw_excerpt":"Export WordPress posts to Obsidian-compatible Markdown files (.md) with YAML frontmatter, plus an optional sitemap.json of your full site structure.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/302314","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=302314"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/quyettran298"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=302314"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=302314"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=302314"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=302314"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=302314"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=302314"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}