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
2 changes: 1 addition & 1 deletion docs/requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -1666,7 +1666,7 @@ Edits the `attributes` array on the `element` block.

`feedwright_feed` registers with `public=true` / `publicly_queryable=true`, so the standard Gutenberg preview / publish flow handles XML previewing without a custom sidebar:

- The editor's "View" / "Preview" buttons resolve via `PostType::filter_permalink`, which redirects to `/{base}/{slug}/`.
- The editor's "View" / "Preview" buttons resolve via `PostType::filter_permalink`, which redirects to `/{base}/{slug}/`. In admin contexts (`is_admin()` true) for users that can `manage_options`, the filter additionally appends `?pretty=1` so the formatted variant opens by default — front-end and REST contexts get the canonical clean URL.
- Published posts are served by `Routing\FeedEndpoint::maybe_serve_feed` as production XML (with `?pretty=1` available to admins / `WP_DEBUG` for human inspection).
- Drafts / non-published posts return 404 from the public URL — preview UX for unpublished feeds is intentionally left to the standard WordPress preview path that consumers can opt into via filters.

Expand Down
15 changes: 14 additions & 1 deletion src/PostType.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ public function register_post_type(): void {
* which is the wrong endpoint and is what breaks the editor's "View" link
* and the slug input on permalink structures other than `/%postname%/`.
*
* In admin contexts (editor / list table / admin bar) for users that can
* `manage_options`, append `?pretty=1` so clicking "Feed を表示" opens the
* formatted variant. Front-end and REST contexts are unaffected — the
* canonical sharing URL stays clean. Even if a `?pretty=1` URL leaks to a
* non-admin, `Routing\FeedEndpoint::is_pretty_request()` rejects them and
* the response is the standard minified XML.
*
* @param string $permalink Default permalink computed by core.
* @param \WP_Post $post Post being linked.
*/
Expand All @@ -76,7 +83,13 @@ public function filter_permalink( string $permalink, \WP_Post $post ): string {
return $permalink;
}
$feed_url = \Feedwright\Routing\FeedEndpoint::feed_url( $post->post_name );
return '' !== $feed_url ? $feed_url : $permalink;
if ( '' === $feed_url ) {
return $permalink;
}
if ( is_admin() && current_user_can( 'manage_options' ) ) {
$feed_url = add_query_arg( 'pretty', '1', $feed_url );
}
return $feed_url;
}

/**
Expand Down
77 changes: 77 additions & 0 deletions tests/Integration/PostTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,83 @@ public function test_administrator_can_create_feed_post(): void {
$this->assertSame( PostType::SLUG, get_post_type( $post_id ) );
}

private function make_feed_post(): int {
return self::factory()->post->create(
array(
'post_type' => PostType::SLUG,
'post_title' => 'Permalink test feed',
'post_name' => 'permalink-test',
'post_status' => 'publish',
)
);
}

public function test_filter_permalink_appends_pretty_for_admin_in_admin_context(): void {
$admin = self::factory()->user->create( array( 'role' => 'administrator' ) );
wp_set_current_user( $admin );
$post_id = $this->make_feed_post();

set_current_screen( 'edit.php' );
try {
$url = get_permalink( $post_id );
$this->assertStringContainsString( '/feedwright/permalink-test/', $url );
$this->assertStringContainsString( 'pretty=1', $url );
} finally {
set_current_screen( 'front' );
}
}

public function test_filter_permalink_omits_pretty_in_frontend_context(): void {
// Admin user but front-end context: pretty must NOT be appended (this
// is the URL that gets shared / embedded by the theme).
$admin = self::factory()->user->create( array( 'role' => 'administrator' ) );
wp_set_current_user( $admin );
$post_id = $this->make_feed_post();

set_current_screen( 'front' );
$url = get_permalink( $post_id );
$this->assertStringContainsString( '/feedwright/permalink-test/', $url );
$this->assertStringNotContainsString( 'pretty=1', $url );
}

public function test_filter_permalink_omits_pretty_for_non_admin_users(): void {
// Editor in admin context (e.g. comments screen) — still no pretty,
// since they do not have manage_options.
$editor = self::factory()->user->create( array( 'role' => 'editor' ) );
wp_set_current_user( $editor );
$post_id = $this->make_feed_post();

set_current_screen( 'edit.php' );
try {
$url = get_permalink( $post_id );
$this->assertStringContainsString( '/feedwright/permalink-test/', $url );
$this->assertStringNotContainsString( 'pretty=1', $url );
} finally {
set_current_screen( 'front' );
}
}

public function test_filter_permalink_does_not_touch_other_post_types(): void {
$admin = self::factory()->user->create( array( 'role' => 'administrator' ) );
wp_set_current_user( $admin );
$other = self::factory()->post->create(
array(
'post_type' => 'post',
'post_status' => 'publish',
'post_title' => 'Regular post',
'post_name' => 'regular',
)
);

set_current_screen( 'edit.php' );
try {
$url = get_permalink( $other );
$this->assertStringNotContainsString( 'pretty=1', $url, 'pretty must not leak onto unrelated post types' );
} finally {
set_current_screen( 'front' );
}
}

public function test_default_template_has_minimum_skeleton(): void {
$post_type = new PostType();
$template = $post_type->default_template();
Expand Down
Loading