Skip to content
45 changes: 45 additions & 0 deletions docs/experiments/markdown-feeds.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Markdown Feeds Experiment

## Summary

Adds Markdown representations of WordPress content:

- Feed: `/?feed=markdown` (and `/feed/markdown/` once rewrite rules are flushed).
- Singular: `https://example.com/my-post.md` (optional).
- Singular content negotiation: `Accept: text/markdown` (optional).

The output is intended to be a lightweight, text-first format that is easier for automated clients (including AI tooling) to ingest than full HTML.

## Key Hooks & Entry Points

- `init` -> registers a custom feed using `add_feed( 'markdown', ... )` (optional).
- `do_parse_request` -> strips a trailing `.md` from front-end requests so WordPress can resolve the underlying canonical URL (optional).
- `template_redirect` -> renders `text/markdown` for singular content when requested via `.md` or `Accept: text/markdown` (optional).
- Renderer -> converts rendered `the_content` HTML into Markdown using WordPress core’s HTML API (`WP_HTML_Processor`, with fallback to `WP_HTML_Tag_Processor`).
- Filters:
- `ai_experiments_markdown_feed_html` -> adjust HTML before conversion.
- `ai_experiments_markdown_feed_markdown` -> adjust Markdown after conversion.
- `ai_experiments_markdown_feed_post_sections` -> reorder or inject sections in each feed entry.
- `ai_experiments_markdown_singular_html` -> adjust HTML before conversion (singular).
- `ai_experiments_markdown_singular_markdown` -> adjust Markdown after conversion (singular).
- `ai_experiments_markdown_singular_post_sections` -> reorder or inject sections in each singular response.

## Assets & Data Flow

- No JS/CSS assets.
- Uses the main feed query loop (`have_posts()` / `the_post()`) and outputs Markdown for each item (title, URL, publish date, content).

## Testing

1. Enable **AI Experiments** globally and enable **Markdown**.
2. Visit `/?feed=markdown` and confirm a `text/markdown` response containing one or more posts.
3. Visit a single post or page with `.md` appended (e.g. `/hello-world.md`) and confirm a `text/markdown` response.
4. Make a request to a post or page with `Accept: text/markdown` and confirm a `text/markdown` response.
5. If pretty permalinks are enabled, flush rewrite rules (e.g., visit Settings → Permalinks) and confirm `/feed/markdown/` works.
6. Verify common content renders reasonably (headings, paragraphs, lists, links, images, code blocks).

## Notes

- The HTML-to-Markdown conversion is intentionally conservative and based on WordPress core’s HTML API (`WP_HTML_Processor`) rather than a bundled third-party parser.
- This experiment currently targets singular post content (title + metadata + content). It does not attempt to convert full theme templates or archive views.
- `.md` permalinks require pretty permalinks (a non-empty permalink structure).
1 change: 1 addition & 0 deletions includes/Experiment_Loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
*
* @param \WordPress\AI\Experiment_Registry $registry The experiment registry instance.
*/
do_action( 'ai_experiments_register_experiments', $this->registry );

Check warning on line 94 in includes/Experiment_Loader.php

View workflow job for this annotation

GitHub Actions / Run Plugin Check

WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound

Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "ai_experiments_register_experiments".

Check warning on line 94 in includes/Experiment_Loader.php

View workflow job for this annotation

GitHub Actions / Run Plugin Check

WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound

Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "ai_experiments_register_experiments".
}

/**
Expand All @@ -107,6 +107,7 @@
\WordPress\AI\Experiments\Abilities_Explorer\Abilities_Explorer::class,
\WordPress\AI\Experiments\Excerpt_Generation\Excerpt_Generation::class,
\WordPress\AI\Experiments\Image_Generation\Image_Generation::class,
\WordPress\AI\Experiments\Markdown_Feeds\Markdown_Feeds::class,
\WordPress\AI\Experiments\Summarization\Summarization::class,
\WordPress\AI\Experiments\Title_Generation\Title_Generation::class,
);
Expand All @@ -121,7 +122,7 @@
*
* @param array $experiment_classes Array of experiment class names or instances.
*/
$items = apply_filters( 'ai_experiments_default_experiment_classes', $experiment_classes );

Check warning on line 125 in includes/Experiment_Loader.php

View workflow job for this annotation

GitHub Actions / Run Plugin Check

WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound

Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "ai_experiments_default_experiment_classes".

Check warning on line 125 in includes/Experiment_Loader.php

View workflow job for this annotation

GitHub Actions / Run Plugin Check

WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound

Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "ai_experiments_default_experiment_classes".

$experiments = array();
foreach ( $items as $item ) {
Expand Down Expand Up @@ -192,7 +193,7 @@
*
* @param bool $enabled Whether to enable AI experiments.
*/
$experiments_enabled = apply_filters( 'ai_experiments_enabled', true );

Check warning on line 196 in includes/Experiment_Loader.php

View workflow job for this annotation

GitHub Actions / Run Plugin Check

WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound

Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "ai_experiments_enabled".

Check warning on line 196 in includes/Experiment_Loader.php

View workflow job for this annotation

GitHub Actions / Run Plugin Check

WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound

Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "ai_experiments_enabled".

if ( ! $experiments_enabled ) {
$this->initialized = true;
Expand All @@ -214,7 +215,7 @@
*
* @since 0.1.0
*/
do_action( 'ai_experiments_initialized' );

Check warning on line 218 in includes/Experiment_Loader.php

View workflow job for this annotation

GitHub Actions / Run Plugin Check

WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound

Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "ai_experiments_initialized".

Check warning on line 218 in includes/Experiment_Loader.php

View workflow job for this annotation

GitHub Actions / Run Plugin Check

WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound

Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "ai_experiments_initialized".

$this->initialized = true;
}
Expand Down
Loading
Loading