PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.2.6
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.2.6
4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.5.2 All 199 releases
← All changes | includes/Core/Rewrite.php +258 -188 3.5.24.2.6 View file →
@@ -6,236 +6,306 @@
6 6 use WPDeveloper\BetterDocs\Utils\Base;
7 7 use WPDeveloper\BetterDocs\Utils\Database;
8 8
9 9 class Rewrite extends Base {
10 - protected $settings;
11 - protected $database;
10 + protected $settings;
11 + protected $database;
12 12
13 - public function __construct( Settings $settings, Database $database ) {
14 - $this->settings = $settings;
15 - $this->database = $database;
16 - }
13 + public function __construct( Settings $settings, Database $database ) {
14 + $this->settings = $settings;
15 + $this->database = $database;
16 + }
17 17
18 - public function init() {
19 - add_action( 'init', [$this, 'rules'] );
20 - add_action( 'betterdocs::settings::saved', [$this, 'save_permalink_structure'], 2, 3 );
21 - }
18 + public function init() {
19 + add_action( 'init', [ $this, 'rules' ] );
20 + add_action( 'betterdocs::settings::saved', [ $this, 'save_permalink_structure' ], 2, 3 );
21 + add_action( 'template_redirect', [ $this, 'handle_pagination_redirect' ] );
22 + }
22 23
23 - public function remove_knowledge_base_placeholder( $permalink ) {
24 - $permalink_array = $this->permalink_structure( $permalink, 'arraywithpercent' );
25 - $permalink_array = array_filter( $permalink_array, function ( $item ) {
26 - return $item !== '%knowledge_base%';
27 - } );
24 + /**
25 + * Handle pagination redirect
26 + * Redirects pagination attempts to main archive
27 + */
28 + public function handle_pagination_redirect() {
29 + if ( ! is_post_type_archive( 'docs' ) ) {
30 + return;
31 + }
28 32
29 - return trailingslashit( implode( '/', $permalink_array ) );
30 - }
33 + $paged = get_query_var( 'paged' );
34 + if ( $paged > 1 ) {
35 + global $wp_query;
36 + $wp_query->set_404();
37 + status_header( 404 );
38 + nocache_headers();
39 + }
40 + }
31 41
32 - /**
33 - * This method is hooked with an action called 'betterdocs::settings::saved'
34 - *
35 - * @since 2.5.0
36 - *
37 - * @param bool $_saved
38 - * @param array $_settings
39 - * @param array $_old_settings
40 - *
41 - * @return void
42 - */
43 - public function save_permalink_structure( $_saved, $_settings, $_old_settings ) {
44 - if ( ! isset( $_settings['permalink_structure'] ) ) {
45 - return;
46 - }
42 + public function remove_knowledge_base_placeholder( $permalink ) {
43 + $permalink_array = $this->permalink_structure( $permalink, 'arraywithpercent' );
44 + $permalink_array = array_filter(
45 + $permalink_array,
46 + function ( $item ) {
47 + return $item !== '%knowledge_base%';
48 + }
49 + );
47 50
48 - $_permalink_structure = $_settings['permalink_structure'];
51 + return trailingslashit( implode( '/', $permalink_array ) );
52 + }
49 53
50 - /**
51 - * TODO: Let's re-check later to optimize it.
52 - */
53 - if ( ! betterdocs()->is_pro_active() ) {
54 - $_permalink_structure = $this->remove_knowledge_base_placeholder( $_permalink_structure );
55 - }
54 + /**
55 + * This method is hooked with an action called 'betterdocs::settings::saved'
56 + *
57 + * @since 2.5.0
58 + *
59 + * @param bool $_saved
60 + * @param array $_settings
61 + * @param array $_old_settings
62 + *
63 + * @return void
64 + */
65 + public function save_permalink_structure( $_saved, $_settings, $_old_settings ) {
66 + if ( ! isset( $_settings['permalink_structure'] ) ) {
67 + return;
68 + }
56 69
57 - if ( $_permalink_structure !== $_old_settings['permalink_structure'] ) {
58 - $this->settings->save( 'permalink_structure', $this->permalink_structure( $_permalink_structure ) );
59 - }
70 + $_permalink_structure = $_settings['permalink_structure'];
60 71
61 - $old_docs_page = isset( $_old_settings['docs_page'] ) ? $_old_settings['docs_page'] : '';
62 - $current_docs_page = isset( $_settings['docs_page'] ) ? $_settings['docs_page'] : '';
72 + /**
73 + * TODO: Let's re-check later to optimize it.
74 + */
75 + if ( ! betterdocs()->is_pro_active() ) {
76 + $_permalink_structure = $this->remove_knowledge_base_placeholder( $_permalink_structure );
77 + }
63 78
64 - /**
65 - * This block of code decides whether it needs to be flushed or not.
66 - * Flush happens after register the post type.
67 - */
68 - switch ( true ) {
69 - case $_permalink_structure !== $_old_settings['permalink_structure']:
70 - case $_settings['docs_slug'] !== $_old_settings['docs_slug']:
71 - case $_settings['builtin_doc_page'] !== $_old_settings['builtin_doc_page']:
72 - case $current_docs_page !== $old_docs_page:
73 - case $_settings['tag_slug'] !== $_old_settings['tag_slug']:
74 - case $_settings['category_slug'] !== $_old_settings['category_slug']:
75 - $this->database->set_transient( 'betterdocs_flush_rewrite_rules', true );
76 - break;
77 - }
78 - }
79 + if ( $_permalink_structure !== $_old_settings['permalink_structure'] ) {
80 + $this->settings->save( 'permalink_structure', $this->permalink_structure( $_permalink_structure ) );
81 + }
79 82
80 - public function permalink_structure( $structure = '', $output = 'string' ) {
81 - if ( empty( $structure ) ) {
82 - $structure = $this->settings->get( 'permalink_structure', 'docs' );
83 - }
83 + $old_docs_page = isset( $_old_settings['docs_page'] ) ? $_old_settings['docs_page'] : '';
84 + $current_docs_page = isset( $_settings['docs_page'] ) ? $_settings['docs_page'] : '';
84 85
85 - $docs_slug = $this->get_base_slug();
86 + /**
87 + * This block of code decides whether it needs to be flushed or not.
88 + * Flush happens after register the post type.
89 + */
90 + switch ( true ) {
91 + case $_permalink_structure !== $_old_settings['permalink_structure']:
92 + case $_settings['docs_slug'] !== $_old_settings['docs_slug']:
93 + case $_settings['builtin_doc_page'] !== $_old_settings['builtin_doc_page']:
94 + case $current_docs_page !== $old_docs_page:
95 + case $_settings['tag_slug'] !== $_old_settings['tag_slug']:
96 + case $_settings['category_slug'] !== $_old_settings['category_slug']:
97 + $this->database->set_transient( 'betterdocs_flush_rewrite_rules', true );
98 + break;
99 + }
100 + }
86 101
87 - $_structure_array = explode( '%', $structure );
88 - if ( $_structure_array[0] == '/' ) {
89 - $structure = $docs_slug . $structure;
90 - } else if ( $_structure_array[0] == '' ) {
91 - $structure = $docs_slug . '/' . $structure;
92 - }
102 + public function permalink_structure( $structure = '', $output = 'string' ) {
103 + if ( empty( $structure ) ) {
104 + $structure = $this->settings->get( 'permalink_structure', 'docs' );
105 + }
93 106
94 - $structure = trim( $structure, '/' );
107 + $docs_slug = $this->get_base_slug();
95 108
96 - if ( $output === 'string' ) {
97 - return $structure;
98 - }
109 + $_structure_array = explode( '%', $structure );
110 + if ( $_structure_array[0] == '/' ) {
111 + $structure = $docs_slug . $structure;
112 + } elseif ( $_structure_array[0] == '' ) {
113 + $structure = $docs_slug . '/' . $structure;
114 + }
99 115
100 - if ( $output === 'array' ) {
101 - $structure = explode( '/', $structure );
102 - $structure = array_map( function ( $item ) {
103 - return trim( $item, "/%" );
104 - }, $structure );
105 - }
116 + $structure = trim( $structure, '/' );
106 117
107 - if ( $output === 'arraywithpercent' ) {
108 - $structure = explode( '/', $structure );
109 - $structure = array_map( function ( $item ) {
110 - return trim( $item, "/" );
111 - }, $structure );
112 - }
118 + if ( $output === 'string' ) {
119 + return $structure;
120 + }
113 121
114 - return $structure;
115 - }
122 + if ( $output === 'array' ) {
123 + $structure = explode( '/', $structure );
124 + $structure = array_map(
125 + function ( $item ) {
126 + return trim( $item, '/%' );
127 + },
128 + $structure
129 + );
130 + }
116 131
117 - public function get_base_slug() {
118 - $docs_slug = $this->settings->get( 'docs_slug', 'docs' );
119 - $docs_page = $this->settings->get( 'docs_page', 0 );
120 - $builtin_doc_page = $this->settings->get( 'builtin_doc_page', true );
132 + if ( $output === 'arraywithpercent' ) {
133 + $structure = explode( '/', $structure );
134 + $structure = array_map(
135 + function ( $item ) {
136 + return trim( $item, '/' );
137 + },
138 + $structure
139 + );
140 + }
121 141
122 - if ( ! $builtin_doc_page && $docs_page !== 0 ) {
123 - $post_info = get_post( $docs_page );
124 - $docs_slug = $post_info instanceof WP_Post ? $post_info->post_name : $docs_slug;
125 - }
142 + return $structure;
143 + }
126 144
127 - $docs_slug = trim( $docs_slug, '/' );
145 + public function hierarchy_based_slug_switch() {
146 + $hierarchy_slug = $this->settings->get( 'enable_category_hierarchy_slugs', false );
147 + return $hierarchy_slug;
148 + }
128 149
129 - return $docs_slug;
130 - }
150 + public function get_base_slug() {
151 + $docs_slug = $this->settings->get( 'docs_slug', 'docs' );
152 + $docs_page = $this->settings->get( 'docs_page', 0 );
153 + $builtin_doc_page = $this->settings->get( 'builtin_doc_page', true );
131 154
132 - public function normalzie_doc_perma_structure( $structure ) {
133 - $structure = $this->permalink_structure( $structure, 'arraywithpercent' );
134 - $structure = array_reduce( $structure, function ( $carry, $item ) {
135 - if ( strpos( $item, '%' ) !== false ) {
136 - $carry[] = $item;
137 - } else {
138 - if ( $carry && strpos( end( $carry ), '%' ) === false ) {
139 - $carry[count( $carry ) - 1] .= "/$item";
140 - } else {
141 - $carry[] = $item;
142 - }
143 - }
155 + if ( ! $builtin_doc_page && $docs_page !== 0 ) {
156 + $post_info = get_post( $docs_page );
157 + $docs_slug = $post_info instanceof WP_Post ? $post_info->post_name : $docs_slug;
158 + }
144 159
145 - return $carry;
146 - }, [] );
160 + $docs_slug = trim( $docs_slug, '/' );
147 161
148 - $structure[] = '%docs%';
162 + return $docs_slug;
163 + }
149 164
150 - $group = array_filter( $structure, function ( $item ) {
151 - return strpos( $item, '%' ) === 0;
152 - } );
165 + public function normalzie_doc_perma_structure( $structure ) {
166 + $structure = $this->permalink_structure( $structure, 'arraywithpercent' );
167 + $structure = array_reduce(
168 + $structure,
169 + function ( $carry, $item ) {
170 + if ( strpos( $item, '%' ) !== false ) {
171 + $carry[] = $item;
172 + } elseif ( $carry && strpos( end( $carry ), '%' ) === false ) {
173 + $carry[ count( $carry ) - 1 ] .= "/$item";
174 + } else {
175 + $carry[] = $item;
176 + }
153 177
154 - return [
155 - 'raw' => $structure,
156 - 'group' => $group
157 - ];
158 - }
178 + return $carry;
179 + },
180 + []
181 + );
159 182
160 - public function make_regex( $segments ) {
161 - return array_reduce( $segments, function ( $carry, $item ) {
162 - $carry .= ( strpos( $item, '%' ) !== false ? "([^/]+)" : $item ) . '/';
163 - return $carry;
164 - }, '' ) . '?$';
165 - }
183 + $structure[] = '%docs%';
166 184
167 - public function make_query( $segments ) {
168 - $query = [];
169 - $matchId = 1;
185 + $group = array_filter(
186 + $structure,
187 + function ( $item ) {
188 + return strpos( $item, '%' ) === 0;
189 + }
190 + );
170 191
171 - foreach ( $segments as $segment ) {
172 - $query[] = trim( $segment, '%' ) . '=$matches[' . $matchId . ']';
173 - $matchId++;
174 - }
192 + return [
193 + 'raw' => $structure,
194 + 'group' => $group
195 + ];
196 + }
175 197
176 - return 'index.php?' . implode( '&', $query ) . '&post_type=docs';
177 - }
198 + public function make_regex( $segments ) {
199 + return array_reduce(
200 + $segments,
201 + function ( $carry, $item ) {
202 + $carry .= ( strpos( $item, '%' ) !== false ? '([^/]+)' : $item ) . '/';
203 + return $carry;
204 + },
205 + ''
206 + ) . '?$';
207 + }
178 208
179 - public function rules() {
180 - /**
181 - * docs can be dynamic / as its a root slug
182 - *
183 - * https://url/docs/kb-slug
184 - * https://url/docs/kb-slug/category-slug
185 - * https://url/docs-category/category-slug
186 - *
187 - * Docs Visit:
188 - * docs can be dynamic / as its a root slug
189 - * or docs can be change by settings.
190 - *
191 - * https://url/docs/(docs-slug)
192 - * https://url/docs/(cat-slug)/(docs-slug)
193 - * https://url/docs/(kb-slug)/(docs-slug)
194 - * https://url/docs/(kb-slug)/(cat-slug)/(docs-slug)
195 - * https://url/docs/(cat-slug)/(kb-slug)/(docs-slug)
196 - */
209 + public function make_query( $segments ) {
210 + $query = [];
211 + $matchId = 1;
197 212
198 - /**
199 - * This code of blocks used to determine single docs permalink.
200 - */
201 - $_docs_perma_struct = betterdocs()->settings->get( 'permalink_structure', 'docs' );
202 - $_normalized_structure = $this->normalzie_doc_perma_structure( $_docs_perma_struct );
213 + foreach ( $segments as $segment ) {
214 + $query[] = trim( $segment, '%' ) . '=$matches[' . $matchId . ']';
215 + ++$matchId;
216 + }
203 217
204 - $_feed_regex = $_normalized_structure['raw'];
205 - $_feed_regex[] = '(feed|rdf|rss|rss2|atom)';
206 - $_feed_group = $_normalized_structure['group'];
207 - $_feed_group[] = '%feed%';
218 + return 'index.php?' . implode( '&', $query ) . '&post_type=docs';
219 + }
208 220
209 - $this->add_rewrite_rule( $this->make_regex( $_feed_regex ), $this->make_query( $_feed_group ) );
221 + public function rules() {
222 + /**
223 + * docs can be dynamic / as its a root slug
224 + *
225 + * https://url/docs/kb-slug
226 + * https://url/docs/kb-slug/category-slug
227 + * https://url/docs-category/category-slug
228 + *
229 + * Docs Visit:
230 + * docs can be dynamic / as its a root slug
231 + * or docs can be change by settings.
232 + *
233 + * https://url/docs/(docs-slug)
234 + * https://url/docs/(cat-slug)/(docs-slug)
235 + * https://url/docs/(kb-slug)/(docs-slug)
236 + * https://url/docs/(kb-slug)/(cat-slug)/(docs-slug)
237 + * https://url/docs/(cat-slug)/(kb-slug)/(docs-slug)
238 + */
210 239
211 - $this->add_rewrite_rule(
212 - $this->make_regex( $_normalized_structure['raw'] ),
213 - $this->make_query( $_normalized_structure['group'] )
214 - );
240 + $base = $this->get_base_slug();
241 + $hierarchy_slug = $this->hierarchy_based_slug_switch();
215 242
243 + // Add rule to handle pagination attempts
244 + $this->add_rewrite_rule(
245 + $base . '/page/([0-9]+)/?$',
246 + 'index.php?post_type=docs',
247 + 'top'
248 + );
249 +
216 250 $base = $this->get_base_slug();
217 251 $this->add_rewrite_rule( $base . '/(feed|rdf|rss|rss2|atom)/?$', 'index.php?post_type=docs&feed=$matches[1]' );
218 - }
252 + $this->add_rewrite_rule( $base . '/authors/([0-9]+)/?$', 'index.php?post_type=docs&author=$matches[1]' );
253 + $this->add_rewrite_rule( $base . '/authors/([0-9]+)/page/([0-9]+)/?$', 'index.php?post_type=docs&author=$matches[1]&page=$matches[2]' );
219 254
220 - public function add_rewrite_rule( $regex, $query, $after = 'top' ) {
221 - add_rewrite_rule( $regex, $query, $after );
222 - }
255 + if( $hierarchy_slug ) { // reigster hierarchy based slug rewrite rule, for single doc permalink
256 + $this->add_rewrite_rule( $base . '/(.+?)/([^/]+)(?:/([0-9]+))?/?$', 'index.php?doc_category=$matches[1]&docs=$matches[2]&post_type=docs' );
223 257
224 - public function docs_type_rewrite( $rewrite, $slug ) {
225 - $permalink = betterdocs()->settings->get( 'permalink_structure', 'docs/' );
226 - $permalink_structure = $this->permalink_structure( $permalink, 'array' );
227 - $permalink = apply_filters( 'betterdocs_docs_type_rewrite_permalink', $permalink, $slug, $permalink_structure );
258 + $rewrite_rules = get_option('rewrite_rules');
228 259
229 - /**
230 - * TODO: Let's re-check later for optimization.
231 - */
232 - if ( ! betterdocs()->is_pro_active() ) {
233 - $permalink = $this->remove_knowledge_base_placeholder( $permalink );
234 - }
260 + if( ! isset( $rewrite_rules[$base . '/(.+?)/([^/]+)(?:/([0-9]+))?/?$'] ) ) { // if this nested rule is not set then flush the rules
261 + flush_rewrite_rules();
262 + }
263 + }
235 264
236 - return apply_filters( 'betterdocs_docs_rewrite', [
237 - 'slug' => trim( $permalink, '/' ),
238 - 'with_front' => false
239 - ], $slug );
240 - }
265 + /**
266 + * This code of blocks used to determine single docs permalink.
267 + */
268 + $_docs_perma_struct = betterdocs()->settings->get( 'permalink_structure', 'docs' );
269 + $_normalized_structure = $this->normalzie_doc_perma_structure( $_docs_perma_struct );
270 +
271 + $_feed_regex = $_normalized_structure['raw'];
272 + $_feed_regex[] = '(feed|rdf|rss|rss2|atom)';
273 + $_feed_group = $_normalized_structure['group'];
274 + $_feed_group[] = '%feed%';
275 +
276 + $this->add_rewrite_rule( $this->make_regex( $_feed_regex ), $this->make_query( $_feed_group ) );
277 +
278 + $this->add_rewrite_rule(
279 + $this->make_regex( $_normalized_structure['raw'] ),
280 + $this->make_query( $_normalized_structure['group'] )
281 + );
282 +
283 + $this->add_rewrite_rule( $base . '/(feed|rdf|rss|rss2|atom)/?$', 'index.php?post_type=docs&feed=$matches[1]' );
284 + }
285 +
286 + public function add_rewrite_rule( $regex, $query, $after = 'top' ) {
287 + add_rewrite_rule( $regex, $query, $after );
288 + }
289 +
290 + public function docs_type_rewrite( $rewrite, $slug ) {
291 + $permalink = betterdocs()->settings->get( 'permalink_structure', 'docs/' );
292 + $permalink_structure = $this->permalink_structure( $permalink, 'array' );
293 + $permalink = apply_filters( 'betterdocs_docs_type_rewrite_permalink', $permalink, $slug, $permalink_structure );
294 +
295 + /**
296 + * TODO: Let's re-check later for optimization.
297 + */
298 + if ( ! betterdocs()->is_pro_active() ) {
299 + $permalink = $this->remove_knowledge_base_placeholder( $permalink );
300 + }
301 +
302 + return apply_filters(
303 + 'betterdocs_docs_rewrite',
304 + [
305 + 'slug' => trim( $permalink, '/' ),
306 + 'with_front' => false
307 + ],
308 + $slug
309 + );
310 + }
241 311 }