@@ -50,4 +50,69 @@ public function test_base_sanitization( $input, $expected ) {
5050
5151 $ this ->assertSame ( $ expected , $ result );
5252 }
53+
54+ /**
55+ * Data provider for link generation with custom bases.
56+ */
57+ public function data_category_base_links () {
58+ return array (
59+ 'latin with space ' => array ( 'Foo Bar ' , 'news ' ),
60+ 'hierarchical segments ' => array ( 'Foo Bar/Baz Qux ' , 'updates ' ),
61+ );
62+ }
63+
64+ /**
65+ * Ensure custom category bases are slugified and produce working archive links.
66+ *
67+ * @ticket 16839
68+ * @dataProvider data_category_base_links
69+ *
70+ * @param string $raw_base User-entered base.
71+ * @param string $category_slug Category slug.
72+ */
73+ public function test_category_base_generates_pretty_links ( $ raw_base , $ category_slug ) {
74+ global $ wp_rewrite ;
75+
76+ $ sanitized_base = $ this ->sanitize_base_from_settings ( $ raw_base );
77+
78+ $ this ->apply_category_base_and_flush ( $ sanitized_base );
79+
80+ $ cat_id = self ::factory ()->category ->create ( array ( 'slug ' => $ category_slug ) );
81+
82+ $ category_link = get_category_link ( $ cat_id );
83+
84+ $ this ->assertStringContainsString ( $ sanitized_base . '/ ' . $ category_slug . '/ ' , $ category_link );
85+
86+ $ this ->go_to ( $ category_link );
87+ $ this ->assertQueryTrue ( 'is_category ' , 'is_archive ' );
88+ $ this ->assertSame ( $ cat_id , get_queried_object_id () );
89+ }
90+
91+ /**
92+ * Mirrors the sanitization logic used in wp-admin/options-permalink.php.
93+ *
94+ * @param string $raw_base Raw user input.
95+ * @return string Sanitized base with leading slash or empty string.
96+ */
97+ private function sanitize_base_from_settings ( $ raw_base ) {
98+ $ base = ltrim ( $ raw_base , '/ ' );
99+
100+ return empty ( $ base ) ? '' : '/ ' . implode ( '/ ' , array_map ( 'sanitize_title_with_dashes ' , preg_split ( '|/+| ' , $ base ) ) );
101+ }
102+
103+ /**
104+ * Applies the category base option and refreshes taxonomy rewrites.
105+ *
106+ * @param string $sanitized_base Base to set (leading slash or empty).
107+ */
108+ private function apply_category_base_and_flush ( $ sanitized_base ) {
109+ global $ wp_rewrite ;
110+
111+ $ wp_rewrite ->set_category_base ( $ sanitized_base );
112+
113+ // Re-register taxonomies and ensure permalink structure stays active before flushing.
114+ $ this ->set_permalink_structure ( '/%postname%/ ' );
115+ create_initial_taxonomies ();
116+ $ wp_rewrite ->flush_rules ();
117+ }
53118}
0 commit comments