=== QH Markdown Exporter === Contributors: quyettran298 Tags: export, markdown, obsidian, backup, posts Requires at least: 5.8 Tested up to: 6.9 Requires PHP: 7.4 Stable tag: 2.2.5 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html Export WordPress posts to Obsidian-compatible Markdown files (.md) with YAML frontmatter, plus an optional sitemap.json of your full site structure. Bulk export as ZIP archive. == Description == QH Markdown Exporter lets you export any combination of post types and statuses as Markdown files — perfectly formatted for [Obsidian](https://obsidian.md/) 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), and `internal_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.json` bundled 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 == 1. Upload the `qh-markdown-exporter` folder to the `/wp-content/plugins/` directory, or install directly through the WordPress plugin screen. 2. Activate the plugin through the **Plugins** screen in WordPress. 3. Go to **Tools → MD Exporter**. 4. Select the post types and statuses you want to export, optionally set a date range, and click **Export & Download ZIP**. == Frequently Asked Questions == = Which post types are supported? = All public post types registered on your site are available. The `attachment` post type is excluded by default. = How does it handle large sites? = 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. = Does it export images? = Image tags are converted to Markdown `![alt](src)` format pointing to the original URLs on your site. The image files themselves are not downloaded or included in the ZIP. = What capability is required to use the exporter? = Users must have the `export` capability (Editor role and above by default). = Will it conflict with page-builder plugins? = 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. == 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 `.md` file opened in Obsidian showing YAML frontmatter and converted content. == 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.php` is 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_error` on every V3 AJAX handler. Legacy sync handler also wrapped. * **PHP 7.4 compatibility** — no `match`, `readonly`, or `enum` syntax. Uses `array()` 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.jsonl` includes `internal_links_in`, `internal_links_out`, and `external_links_out` counts 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 with `slug`, `anchor` text, and canonical `url`. 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_category` object (dynamic keys) with a `categories` array — each category has `id` (slug), `name`, and `posts`. * 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_menus` flag. * Converted `custom_post_types` from a slug-keyed object to a typed array `{ type, label, posts }`. * Added `metadata` block: 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-exporter` for WordPress.org compliance. * Renamed all internal prefixes from `pme_`/`PME_` (3 chars) to `qhmaex_`/`QHMAEX_` (6 chars) to meet the 4+ character prefix requirement. * Updated text domain from `post-markdown-exporter` to `qh-markdown-exporter` across all files. * Fixed upload directory path to use `wp_upload_dir()` instead of hardcoded `WP_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. == Upgrade Notice == = 2.2.4 = Fixes activation failure caused by incomplete 2.2.3 packages missing the new V3 handlers file. No database changes. = 2.2.3 = Removes unused V2 export code and cleans the admin export UI markup. No database changes. = 2.2.2 = Fixes incomplete installs that could make Entitron V3 export fail with a missing `class-export-v3-builder.php` PHP fatal error. Reinstall/update the plugin so all files are present. = 2.1.0 = Rewrites the Entitron export engine to a three-phase chunked AJAX flow, eliminating HTTP 503 and memory exhaustion on large sites. The output format (manifest.json + articles.jsonl + taxonomy.json) is identical to v2.0.0. No database changes; safe to upgrade. = 2.0.0 = Introduces a new "Export for Entitron" button with a separate V2 JSONL-based export format. Your existing Markdown export is completely unchanged. No database changes; safe to upgrade. = 1.6.0 = New optional "Include extended metadata" 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. = 1.5.1 = Improves sitemap.json structure and data quality. No database changes; safe to upgrade. = 1.5.0 = New optional feature: tick "Include sitemap.json" on the export form to get a full site structure JSON file in your ZIP. No database changes; safe to upgrade. = 1.4.0 = Plugin renamed to "QH Markdown Exporter". Temp files now stored in uploads/qh-markdown-exporter/. No database changes; safe to upgrade. = 1.3.0 = Plugin renamed from "WP MD Exporter" to "Post Markdown Exporter" for WordPress.org compliance. No database changes; safe to upgrade.