Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 16 additions & 17 deletions includes/class-opml.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,29 +78,19 @@ public static function register() {
* to, so they need rules of their own.
*/
public static function add_rewrite_rules() {
foreach ( \array_filter( self::well_known_rules() ) as $regex => $query ) {
foreach ( \array_filter( self::rewrite_rules() ) as $regex => $query ) {
\add_rewrite_rule( $regex, $query, 'top' );
}
// A `.opml` suffix as an alias for `?opml` on pages, so the URL
// looks like a file: /blogroll.opml. The query var stays the
// canonical form; it also works with plain permalinks.
// This rule matches the well-known path too. Rules keep the order
// they were added in, so the well-known rules above have to stay
// above; the well-known tests cover that.
\add_rewrite_rule(
'^(.+?)\\.opml$',
\sprintf( 'index.php?pagename=$matches[1]&%s=', self::QUERY_VAR ),
'top'
);
}

/**
* The rewrite rules of the well-known URLs.
* The rewrite rules of the plugin: the well-known URLs and the `.opml`
* suffix.
*
* @return array Regex => query, or => null for a URL this plugin
* does not serve on this site.
*/
private static function well_known_rules() {
private static function rewrite_rules() {
$rules = array();
foreach ( self::FILES as $value => $file ) {
// Only the files with a well-known path need a rule.
Expand All @@ -115,12 +105,21 @@ private static function well_known_rules() {
? null
: \sprintf( 'index.php?%s=%s', self::QUERY_VAR, $value );
}

// A `.opml` suffix as an alias for `?opml` on pages, so the URL
// looks like a file: /blogroll.opml. The query var stays the
// canonical form; it also works with plain permalinks. Nothing
// under /.well-known/ is a page, and the files there belong to
// whoever serves them, SocialSpec for example, whose rule comes
// after this one.
$rules['^(?!\\.well-known/)(.+?)\\.opml$'] = \sprintf( 'index.php?pagename=$matches[1]&%s=', self::QUERY_VAR );

return $rules;
}

/**
* Flush the rewrite rules when the stored well-known rules are out of
* date.
* Flush the rewrite rules when the stored rules of the plugin are out
* of date.
*
* Activation flushes, an update does not, so a new well-known URL
* would stay a 404 on existing sites. The rules also change when
Expand All @@ -134,7 +133,7 @@ public static function flush_stale_rewrite_rules() {
return;
}

foreach ( self::well_known_rules() as $regex => $query ) {
foreach ( self::rewrite_rules() as $regex => $query ) {
if ( ( $stored[ $regex ] ?? null ) !== $query ) {
\flush_rewrite_rules( false );
return;
Expand Down
24 changes: 24 additions & 0 deletions tests/test-opml.php
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,30 @@ public function test_socialspec_following_adds_the_blogroll_feeds_once() {
);
}

public function test_opml_suffix_leaves_well_known_files_of_others_alone() {
global $wp_rewrite;
$regex = '^\.well-known/(other\.opml)$';
add_filter(
'query_vars',
function ( $vars ) {
$vars[] = 'well-known';
return $vars;
}
);
// Not /%postname%/: that one makes WordPress check that a page
// exists before it takes a page rule, which hides the problem.
$this->set_permalink_structure( '/%year%/%monthnum%/%postname%/' );
// Added after this plugin's rules, the way SocialSpec adds its own.
add_rewrite_rule( $regex, 'index.php?well-known=$matches[1]', 'top' );
flush_rewrite_rules( false );

$this->go_to( home_url( '/.well-known/other.opml' ) );
$this->assertSame( 'other.opml', get_query_var( 'well-known' ) );

unset( $wp_rewrite->extra_rules_top[ $regex ] );
$this->set_permalink_structure( '' );
}

public function test_opml_suffix_is_an_alias_for_the_query_var() {
$id = self::factory()->post->create(
array(
Expand Down
Loading