fix: preserve full permalink structure in markdown URLs (#7)#9
fix: preserve full permalink structure in markdown URLs (#7)#9
Conversation
- Add helper methods to detect and replace file extensions (.html, .htm, etc.) with .md - Update AlternateLinkHandler to use new URL conversion logic - Update RewriteHandler to handle both URL generation and parsing with file extensions - Parse incoming .md URLs by trying multiple extension replacements - Fixes issue where complex permalink structures were not preserved Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This pull request fixes an issue where the markdown alternate plugin was not correctly handling WordPress permalink structures that include file extensions (e.g., .html, .htm, .php). Previously, the plugin would blindly append .md to any permalink, resulting in incorrect URLs like /postname.html.md instead of /postname.md. The fix ensures that when a permalink ends with a common file extension, that extension is replaced with .md rather than appended.
Changes:
- Added intelligent URL conversion logic that detects and replaces file extensions in permalinks with
.md - Implemented fallback resolution that tries multiple extension patterns when parsing incoming
.mdrequests - Ensured full permalink structure preservation including categories, dates, and post IDs
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/Router/RewriteHandler.php | Added permalink_to_markdown_url() helper method for intelligent extension replacement; updated parse_markdown_url() to try multiple extensions when resolving incoming .md URLs; updated handle_accept_negotiation() to use the new helper |
| src/Discovery/AlternateLinkHandler.php | Added get_markdown_url() helper method with identical logic for extension replacement; updated output_alternate_link() to use the new helper for generating alternate link tags |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Check if permalink ends with a file extension | ||
| // Common extensions: .html, .htm, .php, .aspx, .asp | ||
| if ( preg_match('/\.(html?|php|aspx?)$/i', $permalink) ) { | ||
| // Replace the extension with .md | ||
| return preg_replace('/\.(html?|php|aspx?)$/i', '.md', $permalink); | ||
| } | ||
|
|
||
| // No extension found - append .md (trim trailing slash first) | ||
| return rtrim( $permalink, '/' ) . '.md'; |
There was a problem hiding this comment.
This method duplicates the exact same logic found in RewriteHandler::permalink_to_markdown_url() (lines 333-343). Consider extracting this shared functionality into a common utility class or trait to follow the DRY (Don't Repeat Yourself) principle. This would make maintenance easier and ensure both code paths remain consistent if the logic needs to be updated in the future.
| // Check if permalink ends with a file extension | |
| // Common extensions: .html, .htm, .php, .aspx, .asp | |
| if ( preg_match('/\.(html?|php|aspx?)$/i', $permalink) ) { | |
| // Replace the extension with .md | |
| return preg_replace('/\.(html?|php|aspx?)$/i', '.md', $permalink); | |
| } | |
| // No extension found - append .md (trim trailing slash first) | |
| return rtrim( $permalink, '/' ) . '.md'; | |
| // Delegate permalink-to-markdown conversion to the shared handler | |
| return \MarkdownAlternate\Rewrite\RewriteHandler::permalink_to_markdown_url( $permalink ); |
| private function permalink_to_markdown_url(string $permalink): string { | ||
| // Check if permalink ends with a file extension | ||
| // Common extensions: .html, .htm, .php, .aspx, .asp | ||
| if (preg_match('/\.(html?|php|aspx?)$/i', $permalink)) { | ||
| // Replace the extension with .md | ||
| return preg_replace('/\.(html?|php|aspx?)$/i', '.md', $permalink); | ||
| } | ||
|
|
||
| // No extension found - append .md (trim trailing slash first) | ||
| return rtrim($permalink, '/') . '.md'; | ||
| } |
There was a problem hiding this comment.
This method duplicates the exact same logic found in AlternateLinkHandler::get_markdown_url() (lines 59-71). Consider extracting this shared functionality into a common utility class or trait to follow the DRY (Don't Repeat Yourself) principle. This would make maintenance easier and ensure both code paths remain consistent if the logic needs to be updated in the future.
| foreach ($extensions_to_try as $ext) { | ||
| $clean_url = home_url('/' . $path_without_md . $ext); | ||
| $post_id = url_to_postid($clean_url); | ||
|
|
||
| if ($post_id) { | ||
| break; // Found a match | ||
| } | ||
| } |
There was a problem hiding this comment.
The variable $post_id is not initialized before the loop, which means it will be undefined if no extension matches. While PHP will treat this as falsy in the subsequent check (line 111), it's better practice to initialize the variable before the loop to avoid potential undefined variable warnings and make the code more explicit. Consider adding $post_id = 0; before the loop.
- Extract duplicate permalink-to-markdown conversion logic into shared static method - Initialize $post_id variable before loop to prevent undefined variable warnings - Both AlternateLinkHandler and RewriteHandler now use permalink_to_markdown_url_static() Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Closes #7
Problem
The plugin was not correctly handling permalink structures with file extensions (e.g.,
.html,.htm). When a site uses a structure like/%category%/%year%/%monthnum%/%day%/%postname%-%post_id%.html, the plugin would:/postname.html.md(incorrect) by blindly appending.md.mdfrom incoming requestsThe user reported that their URL:
https://www.grappling-italia.com/news/2026/02/14/ufc-e-ai-quando-i-dati-iniziano-a-raccontare-storie-79946.htmlhttps://www.grappling-italia.com/news/2026/02/14/ufc-e-ai-quando-i-dati-iniziano-a-raccontare-storie-79946.mdhttps://www.grappling-italia.com/ufc-e-ai-quando-i-dati-iniziano-a-raccontare-storie.md❌Solution
AlternateLinkHandlerandRewriteHandlerto intelligently handle URL conversion.html,.htm,.php,.aspx,.asp) and replace them with.mdinstead of appending.mdrequest comes in, try multiple strategies to resolve the original post:.mdwith common extensions (.html,.htm,.php,.aspx,.asp)Changes
src/Discovery/AlternateLinkHandler.php:
get_markdown_url()helper method with regex-based extension detectionoutput_alternate_link()to use the new helpersrc/Router/RewriteHandler.php:
permalink_to_markdown_url()helper method (same logic as AlternateLinkHandler)handle_accept_negotiation()to use the new helperparse_markdown_url()to try multiple extension replacements when resolving incoming.mdURLsTesting Verified
Permalink structures now supported:
/%postname%/→/postname.md✓/%category%/%postname%/→/category/postname.md✓/%year%/%monthnum%/%day%/%postname%/→/2026/02/14/postname.md✓/%category%/%year%/%monthnum%/%day%/%postname%-%post_id%.html→/category/2026/02/14/postname-12345.md✓ (issue The parmalink structure is not the same #7)/%postname%.htm→/postname.md✓/%postname%.php→/postname.md✓🤖 Generated with Claude Code