PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.2.0
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.2.0
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 +260 -186 3.4.24.2.0 View file →
@@ -6,233 +6,307 @@
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 - /**
62 - * This block of code decides whether it needs to be flushed or not.
63 - * Flush happens after register the post type.
64 - */
65 - switch ( true ) {
66 - case $_permalink_structure !== $_old_settings['permalink_structure']:
67 - case $_settings['docs_slug'] !== $_old_settings['docs_slug']:
68 - case $_settings['builtin_doc_page'] !== $_old_settings['builtin_doc_page']:
69 - case $_settings['docs_page'] !== $_old_settings['docs_page']:
70 - case $_settings['tag_slug'] !== $_old_settings['tag_slug']:
71 - case $_settings['category_slug'] !== $_old_settings['category_slug']:
72 - $this->database->set_transient( 'betterdocs_flush_rewrite_rules', true );
73 - break;
74 - }
75 - }
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 + }
76 78
77 - public function permalink_structure( $structure = '', $output = 'string' ) {
78 - if ( empty( $structure ) ) {
79 - $structure = $this->settings->get( 'permalink_structure', 'docs' );
80 - }
79 + if ( $_permalink_structure !== $_old_settings['permalink_structure'] ) {
80 + $this->settings->save( 'permalink_structure', $this->permalink_structure( $_permalink_structure ) );
81 + }
81 82
82 - $docs_slug = $this->get_base_slug();
83 + $old_docs_page = isset( $_old_settings['docs_page'] ) ? $_old_settings['docs_page'] : '';
84 + $current_docs_page = isset( $_settings['docs_page'] ) ? $_settings['docs_page'] : '';
83 85
84 - $_structure_array = explode( '%', $structure );
85 - if ( $_structure_array[0] == '/' ) {
86 - $structure = $docs_slug . $structure;
87 - } else if ( $_structure_array[0] == '' ) {
88 - $structure = $docs_slug . '/' . $structure;
89 - }
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 + }
90 101
91 - $structure = trim( $structure, '/' );
102 + public function permalink_structure( $structure = '', $output = 'string' ) {
103 + if ( empty( $structure ) ) {
104 + $structure = $this->settings->get( 'permalink_structure', 'docs' );
105 + }
92 106
93 - if ( $output === 'string' ) {
94 - return $structure;
95 - }
107 + $docs_slug = $this->get_base_slug();
96 108
97 - if ( $output === 'array' ) {
98 - $structure = explode( '/', $structure );
99 - $structure = array_map( function ( $item ) {
100 - return trim( $item, "/%" );
101 - }, $structure );
102 - }
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 + }
103 115
104 - if ( $output === 'arraywithpercent' ) {
105 - $structure = explode( '/', $structure );
106 - $structure = array_map( function ( $item ) {
107 - return trim( $item, "/" );
108 - }, $structure );
109 - }
116 + $structure = trim( $structure, '/' );
110 117
111 - return $structure;
112 - }
118 + if ( $output === 'string' ) {
119 + return $structure;
120 + }
113 121
114 - public function get_base_slug() {
115 - $docs_slug = $this->settings->get( 'docs_slug', 'docs' );
116 - $docs_page = $this->settings->get( 'docs_page', 0 );
117 - $builtin_doc_page = $this->settings->get( 'builtin_doc_page', true );
122 + if ( $output === 'array' ) {
123 + $structure = explode( '/', $structure );
124 + $structure = array_map(
125 + function ( $item ) {
126 + return trim( $item, '/%' );
127 + },
128 + $structure
129 + );
130 + }
118 131
119 - if ( ! $builtin_doc_page && $docs_page !== 0 ) {
120 - $post_info = get_post( $docs_page );
121 - $docs_slug = $post_info instanceof WP_Post ? $post_info->post_name : $docs_slug;
122 - }
132 + if ( $output === 'arraywithpercent' ) {
133 + $structure = explode( '/', $structure );
134 + $structure = array_map(
135 + function ( $item ) {
136 + return trim( $item, '/' );
137 + },
138 + $structure
139 + );
140 + }
123 141
124 - $docs_slug = trim( $docs_slug, '/' );
142 + return $structure;
143 + }
125 144
126 - return $docs_slug;
127 - }
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 - public function normalzie_doc_perma_structure( $structure ){
130 - $structure = $this->permalink_structure( $structure, 'arraywithpercent' );
131 - $structure = array_reduce( $structure, function( $carry, $item ){
132 - if( strpos( $item, '%' ) !== false ) {
133 - $carry[] = $item;
134 - } else {
135 - if ($carry && strpos(end($carry), '%') === false) {
136 - $carry[count($carry) - 1] .= "/$item";
137 - } else {
138 - $carry[] = $item;
139 - }
140 - }
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 );
141 154
142 - return $carry;
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 - $structure[] = '%docs%';
160 + $docs_slug = trim( $docs_slug, '/' );
146 161
147 - $group = array_filter( $structure, function( $item ){
148 - return strpos($item, '%') === 0;
149 - });
162 + return $docs_slug;
163 + }
150 164
151 - return [
152 - 'raw' => $structure,
153 - 'group' => $group
154 - ];
155 - }
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 + }
156 177
157 - public function make_regex( $segments ){
158 - return array_reduce( $segments, function( $carry, $item ){
159 - $carry .= ( strpos( $item, '%' ) !== false ? "([^/]+)" : $item ) . '/';
160 - return $carry;
161 - }, '') . '?$';
162 - }
178 + return $carry;
179 + },
180 + []
181 + );
163 182
164 - public function make_query( $segments ){
165 - $query = [];
166 - $matchId = 1;
183 + $structure[] = '%docs%';
167 184
168 - foreach( $segments as $segment ) {
169 - $query[] = trim($segment, '%') . '=$matches[' . $matchId . ']';
170 - $matchId++;
171 - }
185 + $group = array_filter(
186 + $structure,
187 + function ( $item ) {
188 + return strpos( $item, '%' ) === 0;
189 + }
190 + );
172 191
173 - return 'index.php?' . implode('&', $query) . '&post_type=docs';
174 - }
192 + return [
193 + 'raw' => $structure,
194 + 'group' => $group
195 + ];
196 + }
175 197
176 - public function rules() {
177 - /**
178 - * docs can be dynamic / as its a root slug
179 - *
180 - * https://url/docs/kb-slug
181 - * https://url/docs/kb-slug/category-slug
182 - * https://url/docs-category/category-slug
183 - *
184 - * Docs Visit:
185 - * docs can be dynamic / as its a root slug
186 - * or docs can be change by settings.
187 - *
188 - * https://url/docs/(docs-slug)
189 - * https://url/docs/(cat-slug)/(docs-slug)
190 - * https://url/docs/(kb-slug)/(docs-slug)
191 - * https://url/docs/(kb-slug)/(cat-slug)/(docs-slug)
192 - * https://url/docs/(cat-slug)/(kb-slug)/(docs-slug)
193 - */
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 + }
194 208
195 - /**
196 - * This code of blocks used to determine single docs permalink.
197 - */
198 - $_docs_perma_struct = betterdocs()->settings->get( 'permalink_structure', 'docs' );
199 - $_normalized_structure = $this->normalzie_doc_perma_structure($_docs_perma_struct);
209 + public function make_query( $segments ) {
210 + $query = [];
211 + $matchId = 1;
200 212
201 - $_feed_regex = $_normalized_structure['raw'];
202 - $_feed_regex[] = '(feed|rdf|rss|rss2|atom)';
203 - $_feed_group = $_normalized_structure['group'];
204 - $_feed_group[] = '%feed%';
213 + foreach ( $segments as $segment ) {
214 + $query[] = trim( $segment, '%' ) . '=$matches[' . $matchId . ']';
215 + ++$matchId;
216 + }
205 217
206 - $this->add_rewrite_rule( $this->make_regex( $_feed_regex ), $this->make_query( $_feed_group ) );
218 + return 'index.php?' . implode( '&', $query ) . '&post_type=docs';
219 + }
207 220
208 - $this->add_rewrite_rule(
209 - $this->make_regex( $_normalized_structure['raw'] ),
210 - $this->make_query( $_normalized_structure['group'] )
211 - );
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 + */
212 239
240 + $base = $this->get_base_slug();
241 + $hierarchy_slug = $this->hierarchy_based_slug_switch();
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 +
213 250 $base = $this->get_base_slug();
214 251 $this->add_rewrite_rule( $base . '/(feed|rdf|rss|rss2|atom)/?$', 'index.php?post_type=docs&feed=$matches[1]' );
215 - }
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]' );
216 254
217 - public function add_rewrite_rule( $regex, $query, $after = 'top' ) {
218 - add_rewrite_rule( $regex, $query, $after );
219 - }
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' );
220 257
221 - public function docs_type_rewrite( $rewrite, $slug ) {
222 - $permalink = betterdocs()->settings->get( 'permalink_structure', 'docs/' );
223 - $permalink_structure = $this->permalink_structure( $permalink, 'array' );
224 - $permalink = apply_filters( 'betterdocs_docs_type_rewrite_permalink', $permalink, $slug, $permalink_structure );
258 + $rewrite_rules = get_option('rewrite_rules');
225 259
226 - /**
227 - * TODO: Let's re-check later for optimization.
228 - */
229 - if ( ! betterdocs()->is_pro_active() ) {
230 - $permalink = $this->remove_knowledge_base_placeholder( $permalink );
231 - }
260 + if( ! isset( $rewrite_rules[$base . '/(.+?)/([^/]+)(?:/([0-9]+))?/?$'] ) ) { // if this nested rule is not set then flush the rules
261 + error_log(12);
262 + flush_rewrite_rules();
263 + }
264 + }
232 265
233 - return apply_filters( 'betterdocs_docs_rewrite', [
234 - 'slug' => trim( $permalink, '/' ),
235 - 'with_front' => false
236 - ], $slug );
237 - }
266 + /**
267 + * This code of blocks used to determine single docs permalink.
268 + */
269 + $_docs_perma_struct = betterdocs()->settings->get( 'permalink_structure', 'docs' );
270 + $_normalized_structure = $this->normalzie_doc_perma_structure( $_docs_perma_struct );
271 +
272 + $_feed_regex = $_normalized_structure['raw'];
273 + $_feed_regex[] = '(feed|rdf|rss|rss2|atom)';
274 + $_feed_group = $_normalized_structure['group'];
275 + $_feed_group[] = '%feed%';
276 +
277 + $this->add_rewrite_rule( $this->make_regex( $_feed_regex ), $this->make_query( $_feed_group ) );
278 +
279 + $this->add_rewrite_rule(
280 + $this->make_regex( $_normalized_structure['raw'] ),
281 + $this->make_query( $_normalized_structure['group'] )
282 + );
283 +
284 + $this->add_rewrite_rule( $base . '/(feed|rdf|rss|rss2|atom)/?$', 'index.php?post_type=docs&feed=$matches[1]' );
285 + }
286 +
287 + public function add_rewrite_rule( $regex, $query, $after = 'top' ) {
288 + add_rewrite_rule( $regex, $query, $after );
289 + }
290 +
291 + public function docs_type_rewrite( $rewrite, $slug ) {
292 + $permalink = betterdocs()->settings->get( 'permalink_structure', 'docs/' );
293 + $permalink_structure = $this->permalink_structure( $permalink, 'array' );
294 + $permalink = apply_filters( 'betterdocs_docs_type_rewrite_permalink', $permalink, $slug, $permalink_structure );
295 +
296 + /**
297 + * TODO: Let's re-check later for optimization.
298 + */
299 + if ( ! betterdocs()->is_pro_active() ) {
300 + $permalink = $this->remove_knowledge_base_placeholder( $permalink );
301 + }
302 +
303 + return apply_filters(
304 + 'betterdocs_docs_rewrite',
305 + [
306 + 'slug' => trim( $permalink, '/' ),
307 + 'with_front' => false
308 + ],
309 + $slug
310 + );
311 + }
238 312 }