Skip to content

Commit cafba11

Browse files
author
Claude
committed
Fix attachment page redirect for pretty permalink URLs
redirect_canonical() fails to redirect attachment pages accessed via pretty permalinks (e.g. /my-image-jpg/) when wp_attachment_pages_enabled is 0. get_query_var( 'attachment_id' ) is only populated for ?attachment_id=123 URLs, not slug-based URLs. Falls back to get_queried_object_id() when the query var is empty.
1 parent e12ddb3 commit cafba11

2 files changed

Lines changed: 68 additions & 0 deletions

File tree

src/wp-includes/canonical.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,9 @@ function redirect_canonical( $requested_url = null, $do_redirect = true ) {
551551

552552
if ( is_attachment() && ! get_option( 'wp_attachment_pages_enabled' ) ) {
553553
$attachment_id = get_query_var( 'attachment_id' );
554+
if ( ! $attachment_id ) {
555+
$attachment_id = get_queried_object_id();
556+
}
554557
$attachment_post = get_post( $attachment_id );
555558
$attachment_parent_id = $attachment_post ? $attachment_post->post_parent : 0;
556559
$attachment_url = wp_get_attachment_url( $attachment_id );
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
/**
4+
* Tests for attachment page redirect when wp_attachment_pages_enabled is disabled.
5+
*
6+
* @group canonical
7+
* @group rewrite
8+
* @group query
9+
*/
10+
class Tests_Canonical_AttachmentRedirect extends WP_Canonical_UnitTestCase {
11+
12+
/**
13+
* Attachment post object.
14+
*
15+
* @var WP_Post
16+
*/
17+
public static $attachment;
18+
19+
public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
20+
// Create a fake attachment (no real file upload needed).
21+
$attachment_id = $factory->post->create(
22+
array(
23+
'post_type' => 'attachment',
24+
'post_title' => 'Test Image',
25+
'post_name' => 'test-image-jpg',
26+
'post_status' => 'inherit',
27+
'post_parent' => 0,
28+
)
29+
);
30+
31+
// Set a fake attachment URL via metadata.
32+
update_post_meta( $attachment_id, '_wp_attached_file', '2025/01/test-image.jpg' );
33+
34+
self::$attachment = get_post( $attachment_id );
35+
}
36+
37+
/**
38+
* Pretty permalink slug-based attachment URLs should redirect to the file URL
39+
* when wp_attachment_pages_enabled is 0.
40+
*
41+
* This is a regression test: get_query_var( 'attachment_id' ) is only populated
42+
* for ?attachment_id=123 URLs, not slug-based URLs. The fix falls back to
43+
* get_queried_object_id().
44+
*/
45+
public function test_pretty_permalink_attachment_redirects_when_pages_disabled() {
46+
update_option( 'wp_attachment_pages_enabled', 0 );
47+
$this->set_permalink_structure( '/%postname%/' );
48+
49+
$expected_url = wp_get_attachment_url( self::$attachment->ID );
50+
51+
$this->assertCanonical( '/test-image-jpg/', $expected_url );
52+
}
53+
54+
/**
55+
* Query string ?attachment_id=ID should also redirect when pages are disabled.
56+
*/
57+
public function test_query_var_attachment_redirects_when_pages_disabled() {
58+
update_option( 'wp_attachment_pages_enabled', 0 );
59+
$this->set_permalink_structure( '/%postname%/' );
60+
61+
$expected_url = wp_get_attachment_url( self::$attachment->ID );
62+
63+
$this->assertCanonical( '/?attachment_id=' . self::$attachment->ID, $expected_url );
64+
}
65+
}

0 commit comments

Comments
 (0)