PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 3.8.9
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v3.8.9
4.9.2 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 All 200 releases
← All changes | includes/Utils/Helper.php +384 -124 3.5.03.8.9 View file →
@@ -1,168 +1,428 @@
1 1 <?php
2 2
3 3 namespace WPDeveloper\BetterDocs\Utils;
4 4
5 +use function BetterLinksPro\Dependencies\GuzzleHttp\json_decode;
6 +
5 7 class Helper extends Base {
6 8
7 - public static function get_plugins( $plugin_basename = null ) {
8 - if ( ! function_exists( 'get_plugins' ) ) {
9 - include_once ABSPATH . 'wp-admin/includes/plugin.php';
10 - }
9 + public static function get_plugins( $plugin_basename = null ) {
10 + if ( ! function_exists( 'get_plugins' ) ) {
11 + include_once ABSPATH . 'wp-admin/includes/plugin.php';
12 + }
11 13
12 - $plugins = get_plugins();
13 - return $plugin_basename == null ? $plugins : isset( $plugins[$plugin_basename] );
14 - }
14 + $plugins = get_plugins();
15 + return $plugin_basename == null ? $plugins : isset( $plugins[ $plugin_basename ] );
16 + }
15 17
16 - public static function is_plugin_active( $plugin_basename ) {
17 - if ( ! function_exists( 'is_plugin_active' ) ) {
18 - include_once ABSPATH . 'wp-admin/includes/plugin.php';
19 - }
18 + public static function is_plugin_active( $plugin_basename ) {
19 + if ( ! function_exists( 'is_plugin_active' ) ) {
20 + include_once ABSPATH . 'wp-admin/includes/plugin.php';
21 + }
20 22
21 - return is_plugin_active( $plugin_basename );
22 - }
23 + return is_plugin_active( $plugin_basename );
24 + }
23 25
24 - public static function get_tax( $tax = '' ) {
25 - global $wp_query;
26 + public static function get_tax( $tax = '' ) {
27 + global $wp_query;
26 28
27 - if ( is_tax( 'knowledge_base' ) ) {
28 - $_taxes = $wp_query->tax_query->queried_terms;
29 - if ( array_key_exists( "doc_category", $_taxes ) ) {
30 - $tax = 'doc_category';
31 - } else {
32 - $tax = 'knowledge_base';
29 + if ( is_tax( 'knowledge_base' ) ) {
30 + $_taxes = $wp_query->tax_query->queried_terms;
31 + if ( array_key_exists( 'doc_category', $_taxes ) ) {
32 + $tax = 'doc_category';
33 + } else {
34 + $tax = 'knowledge_base';
35 + }
36 + } elseif ( is_tax( 'doc_category' ) ) {
37 + $tax = 'doc_category';
38 + } elseif ( is_tax( 'doc_tag' ) ) {
39 + $tax = 'doc_tag';
40 + }
41 +
42 + return $tax;
43 + }
44 +
45 + public function is_templates() {
46 + global $wp_query;
47 + $slug = betterdocs()->settings->get( 'encyclopedia_root_slug', 'encyclopedia' );
48 +
49 + $tax = $this->get_tax();
50 + if ( is_post_type_archive( 'docs' ) || $tax === 'knowledge_base' || $tax === 'doc_category' || $tax === 'doc_tag' || is_singular( 'docs' ) || is_tax( 'glossaries' ) ) {
51 + return true;
52 + }
53 +
54 + if ( isset( $wp_query->query['pagename'] ) && $wp_query->query['pagename'] === $slug ) {
55 + return true;
56 + }
57 +
58 + return false;
59 + }
60 +
61 + public function is_el_templates() {
62 + $_return_val = betterdocs()->editor->get( 'elementor' )->is_templates();
63 +
64 + if ( $_return_val !== null ) {
65 + return $_return_val;
66 + }
67 +
68 + $this->is_templates();
69 + }
70 +
71 + /**
72 + * Which tab to show.
73 + *
74 + * 1. Drag and Drop UI
75 + * 2. Post List UI
76 + *
77 + * * 1. dnd
78 + * * 2. classic
79 + *
80 + * look into views/admin/docs-ui directory to know more.
81 + *
82 + * @return string
83 + */
84 + public static function admin_tab() {
85 + $admin_ui = 'grid';
86 + if ( isset( $_GET['mode'], $_GET['page'] ) && $_GET['page'] === 'betterdocs-admin' && ! empty( $_GET['mode'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
87 + $admin_ui = $_GET['mode'] === 'grid' ? 'grid' : 'list'; // phpcs:ignore WordPress.Security.NonceVerification.Missing
88 + }
89 +
90 + return $admin_ui;
91 + }
92 +
93 + public static function is_active( $prev, $current, $class = 'active' ) {
94 + if ( $current == $prev ) {
95 + return $class;
96 + }
97 +
98 + return '';
99 + }
100 +
101 + public function get_users( $args ) {
102 + $cache_key = 'betterdocs_cache_admin_user_roles';
103 + $users = betterdocs()->database->get_cache( $cache_key );
104 +
105 + if ( false === $users ) {
106 + $users = get_users( $args );
107 + betterdocs()->database->set_cache( $cache_key, $users );
108 + }
109 +
110 + return $users;
111 + }
112 +
113 + /**
114 + * Normalize Menu Array
115 + * Menu creator helper
116 + *
117 + * @since 2.5.0
118 + *
119 + * @param string $title
120 + * @param string $slug
121 + * @param string $cap
122 + * @param array $callback
123 + *
124 + * @return array
125 + */
126 + public static function normalize_menu( $title, $slug, $cap = 'edit_docs', $callback = null, $optional = [] ) {
127 + $args = [
128 + 'page_title' => $title,
129 + 'menu_title' => $title,
130 + 'capability' => $cap,
131 + 'menu_slug' => $slug
132 + ];
133 +
134 + if ( $callback != null ) {
135 + $args['callback'] = $callback;
136 + }
137 +
138 + return wp_parse_args( $optional, $args );
139 + }
140 +
141 + /**
142 + * Check if the current theme is a block theme.
143 + *
144 + * @since x.x.x
145 + * @return bool
146 + */
147 + public function current_theme_is_fse_theme() {
148 + if ( function_exists( 'wp_is_block_theme' ) ) {
149 + return (bool) wp_is_block_theme();
150 + }
151 + if ( function_exists( 'gutenberg_is_fse_theme' ) ) {
152 + return (bool) gutenberg_is_fse_theme();
153 + }
154 +
155 + return false;
156 + }
157 +
158 + protected static function is_assoc_array( $array ) {
159 + return array_keys( $array ) !== range( 0, count( $array ) - 1 );
160 + }
161 +
162 + public static function merge( &$array1, &$array2 ) {
163 + $merged = $array1;
164 +
165 + foreach ( $array2 as $key => &$value ) {
166 + if ( is_array( $value ) && self::is_assoc_array( $value ) && isset( $merged[ $key ] ) && is_array( $merged[ $key ] ) ) {
167 + $merged[ $key ] = self::merge( $merged[ $key ], $value );
168 + } elseif ( is_array( $value ) && isset( $merged[ $key ] ) && is_array( $merged[ $key ] ) ) {
169 + $merged[ $key ] = array_merge( $merged[ $key ], $value );
170 + } else {
171 + $merged[ $key ] = $value;
172 + }
173 + }
174 +
175 + return $merged;
176 + }
177 +
178 + public static function get_custom_excerpt( $content, $numOfWords ) {
179 + $content = strip_shortcodes( $content );
180 + $content = wp_strip_all_tags( $content );
181 + $words = explode( ' ', $content );
182 + $excerptWords = array_slice( $words, 0, $numOfWords );
183 + $excerpt = implode( ' ', $excerptWords );
184 + if ( count( $words ) > $numOfWords ) {
185 + $excerpt .= '...';
186 + }
187 + return $excerpt;
188 + }
189 +
190 + public static function get_current_letter_docs( $current_letter, $limit = '' ) {
191 + global $wpdb;
192 +
193 + // Check if the encyclopedia_prefix parameter is set
194 +
195 + $encyclopeia_suorce = betterdocs()->settings->get( 'encyclopedia_source', 'docs' );
196 + $enable_glossaries = betterdocs()->settings->get( 'enable_glossaries', false );
197 + $encyclopedia_root_slug = betterdocs()->settings->get( 'encyclopedia_root_slug', 'encyclopdia' );
198 +
199 + // if($enable_glossaries && $encyclopeia_suorce === 'glossaries'){
200 + if ( $enable_glossaries && $encyclopeia_suorce === 'glossaries' ) {
201 + $query = "
202 + SELECT
203 + t.term_id,
204 + t.name AS post_title,
205 + t.slug as slug,
206 + '' AS post_excerpt,
207 + CONCAT('" . get_home_url() . "/$encyclopedia_root_slug/', t.slug) AS permalink,
208 + tt.description AS post_content,
209 + JSON_OBJECT(
210 + 'status', COALESCE(MAX(CASE WHEN m.meta_key = 'status' THEN m.meta_value END), ''),
211 + 'glossary_term_description', COALESCE(MAX(CASE WHEN m.meta_key = 'glossary_term_description' THEN m.meta_value END), '')
212 + ) AS meta_data
213 + FROM
214 + {$wpdb->terms} t
215 + INNER JOIN
216 + {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
217 + LEFT JOIN
218 + {$wpdb->termmeta} m ON t.term_id = m.term_id
219 + WHERE
220 + tt.taxonomy = 'glossaries'
221 + AND
222 + LEFT(t.name, 1) = %s
223 + GROUP BY
224 + t.term_id
225 + ORDER BY
226 + t.name ASC
227 + $limit
228 + ";
229 + } else {
230 + $query = "
231 + SELECT ID, post_title, post_excerpt, guid, post_content
232 + FROM {$wpdb->posts}
233 + WHERE post_type = 'docs'
234 + AND post_status = 'publish'
235 + AND LEFT(post_title, 1) = %s
236 + ORDER BY post_date DESC
237 + $limit
238 + ";
239 + }
240 +
241 + $current_letter_docs = $wpdb->get_results( $wpdb->prepare( $query, $current_letter ), ARRAY_A ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
242 +
243 + return $current_letter_docs;
244 + }
245 +
246 + public static function docs_sort_by_letter( $limit = 10 ) {
247 + global $wpdb;
248 + $enable_non_latin = betterdocs()->settings->get( 'encyclopedia_enable_non_latin' );
249 + $script = betterdocs()->settings->get( 'encyclopedia_non_latin_option' );
250 + $letters = Helper::get_character_range( $enable_non_latin, $script );
251 +
252 + $docs_by_letter = [];
253 + $encyclopeia_suorce = betterdocs()->settings->get( 'encyclopedia_source', 'docs' );
254 + $enable_glossaries = betterdocs()->settings->get( 'enable_glossaries', false );
255 +
256 + foreach ( $letters as $letter ) {
257 + $posts = self::get_current_letter_docs( $letter, "LIMIT $limit" );
258 +
259 + if ( is_array( $posts ) && ! empty( $posts ) ) {
260 + foreach ( $posts as $post ) {
261 + $description = isset($post['meta_data']) ? \json_decode( $post['meta_data'], true ) : '';
262 + $glossary_term_description = $description['glossary_term_description'] ?? '';
263 +
264 + // Remove any <p> tags or other unwanted HTML tags
265 + $glossary_term_description = strip_tags( $glossary_term_description );
266 + $post_excerpt = strip_tags( $post['post_excerpt'] ?? '' );
267 +
268 + // Prepare post data
269 + $post_data = [
270 + 'id' => $post['ID'] ?? '',
271 + 'post_title' => $post['post_title'] ?? '',
272 + 'post_excerpt' => ! empty( $post_excerpt )
273 + ? $post_excerpt
274 + : ( ! empty( $glossary_term_description )
275 + ? self::get_custom_excerpt( $glossary_term_description, 15 )
276 + : self::get_custom_excerpt( strip_tags( $post['post_content'] ?? '' ), 15 ) )
277 + ];
278 +
279 + if ( $enable_glossaries && $encyclopeia_suorce === 'glossaries' ) {
280 + $post_data['permalink'] = isset( $post['slug'] ) ? get_term_link( $post['slug'], 'glossaries' ) : '';
281 + } else {
282 + $post_data['permalink'] = isset( $post['ID'] ) ? get_the_permalink( $post['ID'] ) : '';
283 + }
284 +
285 + $docs_by_letter[$letter][] = $post_data;
286 + }
33 287 }
34 - } elseif ( is_tax( 'doc_category' ) ) {
35 - $tax = 'doc_category';
36 - } elseif ( is_tax( 'doc_tag' ) ) {
37 - $tax = 'doc_tag';
38 288 }
39 289
40 - return $tax;
290 + return $docs_by_letter;
41 291 }
42 292
43 - public function is_templates() {
44 - $tax = $this->get_tax();
45 - if ( is_post_type_archive( 'docs' ) || $tax === 'knowledge_base' || $tax === 'doc_category' || $tax === 'doc_tag' || is_singular( 'docs' ) ) {
46 - return true;
47 - }
293 + public static function get_glossaries() {
294 + global $wpdb;
48 295
49 - return false;
50 - }
296 + $query = "
297 + SELECT t.name
298 + FROM {$wpdb->terms} t
299 + INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
300 + WHERE tt.taxonomy = 'glossaries'
301 + ORDER BY t.name ASC
302 + ";
51 303
52 - public function is_el_templates() {
53 - $_return_val = betterdocs()->editor->get( 'elementor' )->is_templates();
304 + $glossaries = $wpdb->get_col( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
54 305
55 - if ( $_return_val !== null ) {
56 - return $_return_val;
306 + return $glossaries;
307 + }
308 +
309 + /**
310 + * Determine live search template layout, when live search is not selected from customizer(this will work when live search template is not selected from customizer)
311 + *
312 + * @param string $layout
313 + * @return string $layout
314 + */
315 + public static function determine_search_layout( $layout ) {
316 + $search_layout = betterdocs()->customizer->defaults->get( 'betterdocs_search_layout_select' );
317 + $docs_layout = betterdocs()->customizer->defaults->get( 'betterdocs_docs_layout_select' );
318 + $archive_page_layout = betterdocs()->customizer->defaults->get( 'betterdocs_archive_layout_select' );
319 + $single_layout = betterdocs()->customizer->defaults->get( 'betterdocs_single_layout_select' );
320 +
321 + if ( is_post_type_archive( 'docs' ) ) {
322 + if ( $docs_layout != "layout-7" && ! $search_layout ) {
323 + $layout = 'layout-1';
324 + } else if ( $docs_layout == 'layout-7' && ! $search_layout ) {
325 + $layout = 'layout-2';
326 + }
327 + } else if ( is_tax( 'doc_tag' ) && ! $search_layout ) {
328 + $layout = 'layout-1';
329 + } else if ( is_tax( 'doc_category' ) ) {
330 + if ( $archive_page_layout != 'layout-7' && ! $search_layout ) {
331 + $layout = 'layout-1';
332 + } else if ( $archive_page_layout == 'layout-7' && ! $search_layout ) {
333 + $layout = 'layout-2';
334 + }
335 + } else if ( is_singular( 'docs' ) ) {
336 + if ( $single_layout != 'layout-8' && $single_layout != 'layout-9' && ! $search_layout ) {
337 + $layout = 'layout-1';
338 + } else if ( ( $single_layout == 'layout-8' && ! $search_layout ) || ( $single_layout == 'layout-9' && ! $search_layout ) ) {
339 + $layout = 'layout-2';
340 + }
57 341 }
58 342
59 - $this->is_templates();
343 + return $layout;
60 344 }
345 + public static function mb_ord_fallback( $char ) {
346 + $code = unpack( 'N', mb_convert_encoding( $char, 'UCS-4BE', 'UTF-8' ) );
347 + return $code[1];
348 + }
61 349
62 - /**
63 - * Which tab to show.
64 - *
65 - * 1. Drag and Drop UI
66 - * 2. Post List UI
67 - *
68 - * * 1. dnd
69 - * * 2. classic
70 - *
71 - * look into views/admin/docs-ui directory to know more.
72 - *
73 - * @return string
74 - */
75 - public static function admin_tab() {
76 - $admin_ui = 'grid';
77 - if ( isset( $_GET['mode'], $_GET['page'] ) && $_GET['page'] === 'betterdocs-admin' && ! empty( $_GET['mode'] ) ) {
78 - $admin_ui = $_GET['mode'] === 'grid' ? 'grid' : 'list';
79 - }
80 -
81 - return $admin_ui;
350 + public static function mb_chr_fallback( $code ) {
351 + return mb_convert_encoding( pack( 'N', $code ), 'UTF-8', 'UCS-4BE' );
82 352 }
83 353
84 - public static function is_active( $prev, $current, $class = 'active' ) {
85 - if ( $current == $prev ) {
86 - return $class;
354 + public static function unicodeRange( $start, $end ) {
355 + $range = [];
356 + for ( $i = self::mb_ord_fallback( $start ); $i <= self::mb_ord_fallback( $end ); $i++ ) {
357 + $range[] = self::mb_chr_fallback( $i );
87 358 }
88 -
89 - return '';
359 + return $range;
90 360 }
91 361
92 - public function get_users( $args ) {
93 - $cache_key = 'betterdocs_cache_admin_user_roles';
94 - $users = betterdocs()->database->get_cache( $cache_key );
95 -
96 - if ( false === $users ) {
97 - $users = get_users( $args );
98 - betterdocs()->database->set_cache( $cache_key, $users );
362 + public static function get_character_range( $enable_non_latin, $script ) {
363 + if ( $enable_non_latin ) {
364 + switch ( $script ) {
365 + case 'arabic':
366 + return self::unicodeRange( 'ء', 'ي' );
367 + case 'cyrillic':
368 + return self::unicodeRange( 'А', 'Я' );
369 + case 'hebrew':
370 + return self::unicodeRange( 'א', 'ת' );
371 + case 'greek':
372 + return self::unicodeRange( 'Α', 'Ω' );
373 + default:
374 + return range( 'A', 'Z' );
375 + }
99 376 }
100 377
101 - return $users;
378 + return range( 'A', 'Z' );
102 379 }
103 380
104 - /**
105 - * Normalize Menu Array
106 - * Menu creator helper
107 - *
108 - * @since 2.5.0
109 - *
110 - * @param string $title
111 - * @param string $slug
112 - * @param string $cap
113 - * @param array $callback
114 - *
115 - * @return array
116 - */
117 - public static function normalize_menu( $title, $slug, $cap = 'edit_docs', $callback = null ) {
118 - $args = [
119 - 'page_title' => $title,
120 - 'menu_title' => $title,
121 - 'capability' => $cap,
122 - 'menu_slug' => $slug
123 - ];
381 + public static function get_the_top_most_parent( $term_id ) {
382 + while ( $term_id != 0 ) {
383 + $parent_id = wp_get_term_taxonomy_parent_id( $term_id, 'doc_category' );
124 384
125 - if ( $callback != null ) {
126 - $args['callback'] = $callback;
385 + if ( $parent_id == 0 ) {
386 + break;
387 + }
388 +
389 + $term_id = $parent_id;
127 390 }
128 -
129 - return $args;
391 + return $term_id;
130 392 }
131 393
132 - /**
133 - * Check if the current theme is a block theme.
134 - *
135 - * @since x.x.x
136 - * @return bool
137 - */
138 - public function current_theme_is_fse_theme() {
139 - if ( function_exists( 'wp_is_block_theme' ) ) {
140 - return (bool) wp_is_block_theme();
141 - }
142 - if ( function_exists( 'gutenberg_is_fse_theme' ) ) {
143 - return (bool) gutenberg_is_fse_theme();
144 - }
145 -
146 - return false;
394 + public static function get_highest_docs_term() {
395 + $terms = get_terms( [
396 + 'taxonomy' => 'doc_category', // Change to your desired taxonomy
397 + 'hide_empty' => true, // Only show terms with posts
398 + 'orderby' => 'count', // Order by post count
399 + 'order' => 'DESC', // Descending order
400 + 'number' => 1 // Get only the top term
401 + ] );
402 + return isset( $terms[0] ) ? $terms[0] : [];
147 403 }
148 404
149 - protected static function is_assoc_array( $array ) {
150 - return array_keys( $array ) !== range( 0, count( $array ) - 1 );
151 - }
405 + public static function delete_specific_faq_posts_by_faq_category( $term_id ) {
406 + $args = [
407 + 'post_type' => 'betterdocs_faq',
408 + 'posts_per_page' => -1,
409 + 'tax_query' => [
410 + [
411 + 'taxonomy' => 'betterdocs_faq_category',
412 + 'field' => 'id',
413 + 'terms' => $term_id,
414 + 'operator' => 'IN'
415 + ]
416 + ],
417 + 'fields' => 'ids'
418 + ];
152 419
153 - public static function merge( &$array1, &$array2 ) {
154 - $merged = $array1;
420 + $query = new \WP_Query( $args );
155 421
156 - foreach ( $array2 as $key => &$value ) {
157 - if ( is_array( $value ) && self::is_assoc_array( $value ) && isset( $merged[$key] ) && is_array( $merged[$key] ) ) {
158 - $merged[$key] = self::merge( $merged[$key], $value );
159 - } elseif ( is_array( $value ) && isset( $merged[$key] ) && is_array( $merged[$key] ) ) {
160 - $merged[$key] = array_merge( $merged[$key], $value );
161 - } else {
162 - $merged[$key] = $value;
422 + if ( $query->have_posts() ) {
423 + foreach ( $query->posts as $doc_id ) {
424 + wp_delete_post( $doc_id, true );
163 425 }
164 426 }
165 -
166 - return $merged;
167 427 }
168 428 }