Skip to content

Commit 46a3bc9

Browse files
committed
Respect explicit rewrite[feeds] for CPTs regardless of has_archive
1 parent 4bdcb35 commit 46a3bc9

3 files changed

Lines changed: 115 additions & 2 deletions

File tree

src/wp-includes/class-wp-post-type.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ public function set_props( $args ) {
652652
if ( ! isset( $args['rewrite']['pages'] ) ) {
653653
$args['rewrite']['pages'] = true;
654654
}
655-
if ( ! isset( $args['rewrite']['feeds'] ) || ! $args['has_archive'] ) {
655+
if ( ! isset( $args['rewrite']['feeds'] ) ) {
656656
$args['rewrite']['feeds'] = (bool) $args['has_archive'];
657657
}
658658
if ( ! isset( $args['rewrite']['ep_mask'] ) ) {

src/wp-includes/post.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1813,7 +1813,8 @@ function get_post_types( $args = array(), $output = 'names', $operator = 'and' )
18131813
* @type bool $with_front Whether the permastruct should be prepended with WP_Rewrite::$front.
18141814
* Default true.
18151815
* @type bool $feeds Whether the feed permastruct should be built for this post type.
1816-
* Default is value of $has_archive.
1816+
* Enables single post (comments) feed URLs regardless of $has_archive.
1817+
* When not set, defaults to the value of $has_archive.
18171818
* @type bool $pages Whether the permastruct should provide for pagination. Default true.
18181819
* @type int $ep_mask Endpoint mask to assign. If not specified and permalink_epmask is set,
18191820
* inherits from $permalink_epmask. If not specified and permalink_epmask

tests/phpunit/tests/rewrite.php

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,4 +504,116 @@ public function test_flush_rules_does_not_delete_option() {
504504
$this->assertIsArray( $rewrite_rules );
505505
$this->assertNotEmpty( $rewrite_rules );
506506
}
507+
508+
/**
509+
* @ticket 43746
510+
*/
511+
public function test_cpt_with_no_archive_and_explicit_feeds_true_generates_single_post_feed_rules() {
512+
global $wp_rewrite;
513+
514+
register_post_type(
515+
'cpt_43746_rules',
516+
array(
517+
'public' => true,
518+
'has_archive' => false,
519+
'rewrite' => array(
520+
'slug' => 'cpt-43746-rules',
521+
'feeds' => true,
522+
),
523+
)
524+
);
525+
526+
$wp_rewrite->flush_rules();
527+
$rules = $wp_rewrite->rewrite_rules();
528+
529+
$feed_rule_found = false;
530+
foreach ( array_keys( $rules ) as $pattern ) {
531+
// Match direct single-post feed patterns.
532+
if ( str_contains( $pattern, 'cpt-43746-rules/([^/]+)/' ) && str_contains( $pattern, 'feed' ) ) {
533+
$feed_rule_found = true;
534+
break;
535+
}
536+
}
537+
538+
_unregister_post_type( 'cpt_43746_rules' );
539+
$wp_rewrite->flush_rules();
540+
541+
$this->assertTrue( $feed_rule_found, 'Feed rewrite rules should be generated for a CPT with has_archive=false and feeds=true' );
542+
}
543+
544+
/**
545+
* @ticket 43746
546+
*/
547+
public function test_cpt_with_no_archive_and_feeds_false_does_not_generate_single_post_feed_rules() {
548+
global $wp_rewrite;
549+
550+
register_post_type(
551+
'cpt_43746_norules',
552+
array(
553+
'public' => true,
554+
'has_archive' => false,
555+
'rewrite' => array(
556+
'slug' => 'cpt-43746-norules',
557+
'feeds' => false,
558+
),
559+
)
560+
);
561+
562+
$wp_rewrite->flush_rules();
563+
$rules = $wp_rewrite->rewrite_rules();
564+
565+
$feed_rule_found = false;
566+
foreach ( array_keys( $rules ) as $pattern ) {
567+
// Only look for direct single-post feed patterns.
568+
if ( str_contains( $pattern, 'cpt-43746-norules/([^/]+)/' ) && str_contains( $pattern, 'feed' ) ) {
569+
$feed_rule_found = true;
570+
break;
571+
}
572+
}
573+
574+
_unregister_post_type( 'cpt_43746_norules' );
575+
$wp_rewrite->flush_rules();
576+
577+
$this->assertFalse( $feed_rule_found, 'No feed rewrite rules should be generated for a CPT with has_archive=false and feeds=false' );
578+
}
579+
580+
/**
581+
* @ticket 43746
582+
*/
583+
public function test_cpt_with_no_archive_and_explicit_feeds_true_does_not_generate_archive_feed_rules() {
584+
global $wp_rewrite;
585+
586+
register_post_type(
587+
'cpt_43746_noarch',
588+
array(
589+
'public' => true,
590+
'has_archive' => false,
591+
'rewrite' => array(
592+
'slug' => 'cpt-43746-noarch',
593+
'feeds' => true,
594+
),
595+
)
596+
);
597+
598+
$wp_rewrite->flush_rules();
599+
$rules = $wp_rewrite->rewrite_rules();
600+
601+
$archive_feed_rule_found = false;
602+
foreach ( $rules as $pattern => $query ) {
603+
// Archive feed rules point directly to post_type=cpt_43746_noarch&feed= (no post slug segment).
604+
if ( str_contains( $pattern, 'cpt-43746-noarch' )
605+
&& str_contains( $pattern, 'feed' )
606+
&& str_contains( $query, 'post_type=cpt_43746_noarch&feed=' )
607+
&& ! str_contains( $query, 'cpt_43746_noarch=' )
608+
) {
609+
$archive_feed_rule_found = true;
610+
break;
611+
}
612+
}
613+
614+
_unregister_post_type( 'cpt_43746_noarch' );
615+
$wp_rewrite->flush_rules();
616+
617+
$this->assertFalse( $archive_feed_rule_found, 'Archive feed rewrite rules should NOT be generated when has_archive is false, even if feeds is true' );
618+
}
507619
}

0 commit comments

Comments
 (0)