diff --git a/src/wp-includes/category-template.php b/src/wp-includes/category-template.php
index 9a2120c9e3..5fb7485332 100644
--- a/src/wp-includes/category-template.php
+++ b/src/wp-includes/category-template.php
@@ -532,7 +532,28 @@ function wp_list_categories( $args = '' ) {
}
} else {
if ( ! empty( $show_option_all ) ) {
- $posts_page = ( 'page' == get_option( 'show_on_front' ) && get_option( 'page_for_posts' ) ) ? get_permalink( get_option( 'page_for_posts' ) ) : home_url( '/' );
+
+ $posts_page = '';
+
+ // For taxonomies that belong only to custom post types, point to a valid archive.
+ $taxonomy_object = get_taxonomy( $r['taxonomy'] );
+ if ( ! in_array( 'post', $taxonomy_object->object_type ) && ! in_array( 'page', $taxonomy_object->object_type ) ) {
+ foreach ( $taxonomy_object->object_type as $object_type ) {
+ $_object_type = get_post_type_object( $object_type );
+
+ // Grab the first one.
+ if ( ! empty( $_object_type->has_archive ) ) {
+ $posts_page = get_post_type_archive_link( $object_type );
+ break;
+ }
+ }
+ }
+
+ // Fallback for the 'All' link is the front page.
+ if ( ! $posts_page ) {
+ $posts_page = 'page' == get_option( 'show_on_front' ) && get_option( 'page_for_posts' ) ? get_permalink( get_option( 'page_for_posts' ) ) : home_url( '/' );
+ }
+
$posts_page = esc_url( $posts_page );
if ( 'list' == $r['style'] ) {
$output .= "
$show_option_all";
diff --git a/tests/phpunit/tests/category/wpListCategories.php b/tests/phpunit/tests/category/wpListCategories.php
index 55af2f484e..e2c041c90e 100644
--- a/tests/phpunit/tests/category/wpListCategories.php
+++ b/tests/phpunit/tests/category/wpListCategories.php
@@ -100,6 +100,96 @@ class Tests_Category_WpListCategories extends WP_UnitTestCase {
$this->assertContains( "All", $found );
}
+ /**
+ * @ticket 21881
+ */
+ public function test_show_option_all_link_should_link_to_post_type_archive_when_taxonomy_does_not_apply_to_posts() {
+ register_post_type( 'wptests_pt', array( 'has_archive' => true ) );
+ register_post_type( 'wptests_pt2', array( 'has_archive' => true ) );
+ register_taxonomy( 'wptests_tax', array( 'foo', 'wptests_pt', 'wptests_pt2' ) );
+
+ $terms = $this->factory->term->create_many( 2, array(
+ 'taxonomy' => 'wptests_tax',
+ ) );
+
+ $found = wp_list_categories( array(
+ 'echo' => false,
+ 'show_option_all' => 'All',
+ 'hide_empty' => false,
+ 'taxonomy' => 'wptests_tax',
+ ) );
+
+ $pt_archive = get_post_type_archive_link( 'wptests_pt' );
+
+ $this->assertContains( "All", $found );
+ }
+
+ /**
+ * @ticket 21881
+ */
+ public function test_show_option_all_link_should_not_link_to_post_type_archive_if_has_archive_is_false() {
+ register_post_type( 'wptests_pt', array( 'has_archive' => false ) );
+ register_post_type( 'wptests_pt2', array( 'has_archive' => true ) );
+ register_taxonomy( 'wptests_tax', array( 'foo', 'wptests_pt', 'wptests_pt2' ) );
+
+ $terms = $this->factory->term->create_many( 2, array(
+ 'taxonomy' => 'wptests_tax',
+ ) );
+
+ $found = wp_list_categories( array(
+ 'echo' => false,
+ 'show_option_all' => 'All',
+ 'hide_empty' => false,
+ 'taxonomy' => 'wptests_tax',
+ ) );
+
+ $pt_archive = get_post_type_archive_link( 'wptests_pt2' );
+
+ $this->assertContains( "All", $found );
+ }
+
+ public function test_show_option_all_link_should_link_to_post_archive_if_available() {
+ register_post_type( 'wptests_pt', array( 'has_archive' => true ) );
+ register_post_type( 'wptests_pt2', array( 'has_archive' => true ) );
+ register_taxonomy( 'wptests_tax', array( 'foo', 'wptests_pt', 'post', 'wptests_pt2' ) );
+
+ $terms = $this->factory->term->create_many( 2, array(
+ 'taxonomy' => 'wptests_tax',
+ ) );
+
+ $found = wp_list_categories( array(
+ 'echo' => false,
+ 'show_option_all' => 'All',
+ 'hide_empty' => false,
+ 'taxonomy' => 'wptests_tax',
+ ) );
+
+ $url = home_url( '/' );
+
+ $this->assertContains( "All", $found );
+ }
+
+ public function test_show_option_all_link_should_link_to_post_archive_if_no_associated_post_types_have_archives() {
+ register_post_type( 'wptests_pt', array( 'has_archive' => false ) );
+ register_post_type( 'wptests_pt2', array( 'has_archive' => false ) );
+ register_taxonomy( 'wptests_tax', array( 'foo', 'wptests_pt', 'wptests_pt2' ) );
+
+ $terms = $this->factory->term->create_many( 2, array(
+ 'taxonomy' => 'wptests_tax',
+ ) );
+
+ $found = wp_list_categories( array(
+ 'echo' => false,
+ 'show_option_all' => 'All',
+ 'hide_empty' => false,
+ 'taxonomy' => 'wptests_tax',
+ ) );
+
+ $url = home_url( '/' );
+
+ $this->assertContains( "All", $found );
+ }
+
public function list_cats_callback( $cat ) {
if ( 'Test Cat 1' === $cat ) {
return '';