PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 2.0.1
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v2.0.1
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
betterdocs / includes / class-betterdocs-helpers.php

class-betterdocs-helpers.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 2.0.1, at includes/class-betterdocs-helpers.php

552 lines 19.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * This class will provide all kind of helper methods.
4 */
5 class BetterDocs_Helper
6 {
7 /**
8 * This function is responsible for the data sanitization
9 *
10 * @param array $field
11 * @param string|array $value
12 * @return string|array
13 */
14 public static function sanitize_field($field, $value)
15 {
16 if (isset($field['sanitize']) && !empty($field['sanitize'])) {
17 if (function_exists($field['sanitize'])) {
18 $value = call_user_func($field['sanitize'], $value);
19 }
20 return $value;
21 }
22
23 if (is_array($field) && isset($field['type'])) {
24 switch ($field['type']) {
25 case 'text':
26 $value = sanitize_text_field(stripslashes($value));
27 break;
28 case 'textarea':
29 $value = sanitize_textarea_field(stripslashes($value));
30 break;
31 case 'email':
32 $value = sanitize_email($value);
33 break;
34 default:
35 return $value;
36 break;
37 }
38 } else {
39 $value = sanitize_text_field(stripslashes($value));
40 }
41
42 return $value;
43 }
44
45 /**
46 * This function is responsible for making an array sort by their key
47 * @param array $data
48 * @param string $using
49 * @param string $way
50 * @return array
51 */
52 public static function sorter($data, $using = 'time_date', $way = 'DESC')
53 {
54 if (!is_array($data)) {
55 return $data;
56 }
57
58 $new_array = [];
59
60 if ($using === 'key') {
61 if ($way !== 'ASC') {
62 krsort($data);
63 } else {
64 ksort($data);
65 }
66 } else {
67 foreach ($data as $key => $value) {
68 if (!is_array($value)) continue;
69 foreach ($value as $inner_key => $single) {
70 if ($inner_key == $using) {
71 $value['tempid'] = $key;
72 $single = self::numeric_key_gen($new_array, $single);
73 $new_array[$single] = $value;
74 }
75 }
76 }
77
78 if ($way !== 'ASC') {
79 krsort($new_array);
80 } else {
81 ksort($new_array);
82 }
83
84 if (!empty($new_array)) {
85 foreach ($new_array as $array) {
86 $index = $array['tempid'];
87 unset($array['tempid']);
88 $new_data[$index] = $array;
89 }
90 $data = $new_data;
91 }
92 }
93
94 return $data;
95 }
96
97 /**
98 * This function is responsible for generate unique numeric key for a given array.
99 *
100 * @param array $data
101 * @param integer $index
102 * @return integer
103 */
104 private static function numeric_key_gen($data, $index = 0)
105 {
106 if (isset($data[$index])) {
107 $index += 1;
108 return self::numeric_key_gen($data, $index);
109 }
110 return $index;
111 }
112
113 /**
114 * Sorting Data
115 * by their type
116 *
117 * @param array $value
118 * @param string $key
119 * @return void
120 */
121 public static function sortBy(&$value, $key = 'comments')
122 {
123 switch ($key) {
124 case 'comments':
125 return self::sorter($value, 'key', 'DESC');
126 break;
127 default:
128 return self::sorter($value, 'timestamp', 'DESC');
129 break;
130 }
131 }
132
133 /**
134 * Human Readable Time Diff
135 *
136 * @param boolean $time
137 * @return void
138 */
139 public static function get_timeago_html($time = false)
140 {
141 if (!$time) {
142 return;
143 }
144
145 $offset = get_option('gmt_offset'); // Time offset in hours
146 $local_time = $time + ($offset * 60 * 60); // added offset in seconds
147 $time = human_time_diff($local_time, current_time('timestamp'));
148 ob_start();
149 echo '<small> ' . esc_html__('About', 'betterdocs') . ' ' . esc_html($time) . ' ' . esc_html__('ago', 'betterdocs') . ' </small>';
150 $time_ago = ob_get_clean();
151 return $time_ago;
152 }
153
154 /**
155 * Get all post types
156 *
157 * @param array $exclude
158 * @return void
159 */
160 public static function post_types($exclude = array())
161 {
162 $post_types = get_post_types(array(
163 'public' => true,
164 'show_ui' => true
165 ), 'objects');
166
167 unset($post_types['attachment']);
168
169 if (count($exclude)) {
170 foreach ($exclude as $type) {
171 if (isset($post_types[$type])) {
172 unset($post_types[$type]);
173 }
174 }
175 }
176
177 return apply_filters('betterdocs_post_types', $post_types);
178 }
179
180 /**
181 * Get all taxonomies
182 *
183 * @param string $post_type
184 * @param array $exclude
185 * @return void
186 */
187 public static function taxonomies($post_type = '', $exclude = array())
188 {
189 if (empty($post_type)) {
190 $taxonomies = get_taxonomies(
191 array(
192 'public' => true,
193 '_builtin' => false
194 ),
195 'objects'
196 );
197 } else {
198
199 $taxonomies = get_object_taxonomies($post_type, 'objects');
200 }
201
202 $data = array();
203
204 if (is_array($taxonomies)) {
205 foreach ($taxonomies as $tax_slug => $tax) {
206 if (!$tax->public || !$tax->show_ui) {
207 continue;
208 }
209 if (in_array($tax_slug, $exclude)) {
210 continue;
211 }
212 $data[$tax_slug] = $tax;
213 }
214 }
215
216 return apply_filters('betterdocs_loop_taxonomies', $data, $taxonomies, $post_type);
217 }
218
219 public static function list_svg()
220 {
221 $html = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="0.86em" height="1em" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 1536 1792"><path d="M1468 380q28 28 48 76t20 88v1152q0 40-28 68t-68 28H96q-40 0-68-28t-28-68V96q0-40 28-68T96 0h896q40 0 88 20t76 48zm-444-244v376h376q-10-29-22-41l-313-313q-12-12-41-22zm384 1528V640H992q-40 0-68-28t-28-68V128H128v1536h1280zM384 800q0-14 9-23t23-9h704q14 0 23 9t9 23v64q0 14-9 23t-23 9H416q-14 0-23-9t-9-23v-64zm736 224q14 0 23 9t9 23v64q0 14-9 23t-23 9H416q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h704zm0 256q14 0 23 9t9 23v64q0 14-9 23t-23 9H416q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h704z"/></svg>';
222 return $html;
223 }
224
225 public static function arrow_right_svg()
226 {
227 $html = '<svg class="toggle-arrow arrow-right" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="0.48em" height="1em" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 608 1280"><g transform="translate(608 0) scale(-1 1)"><path d="M595 288q0 13-10 23L192 704l393 393q10 10 10 23t-10 23l-50 50q-10 10-23 10t-23-10L23 727q-10-10-10-23t10-23l466-466q10-10 23-10t23 10l50 50q10 10 10 23z"/></g></svg>';
228 return $html;
229 }
230
231 public static function arrow_down_svg()
232 {
233 $html = '<svg class="toggle-arrow arrow-down" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="0.8em" height="1em" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 1024 1280"><path d="M1011 480q0 13-10 23L535 969q-10 10-23 10t-23-10L23 503q-10-10-10-23t10-23l50-50q10-10 23-10t23 10l393 393l393-393q10-10 23-10t23 10l50 50q10 10 10 23z"/></svg>';
234 return $html;
235 }
236
237 public static function get_tax($tax = '')
238 {
239 global $wp_query;
240 if (is_tax('knowledge_base')) {
241 $get_tax = $wp_query->tax_query->queried_terms;
242 if (array_key_exists("doc_category", $get_tax)) {
243 $tax = 'doc_category';
244 } else {
245 $tax = 'knowledge_base';
246 }
247 } elseif (is_tax('doc_category')) {
248 $tax = 'doc_category';
249 }
250
251 return $tax;
252 }
253
254 public static function list_query_arg($post_type, $multiple_kb, $tax_slug, $posts_per_grid, $orderby, $order = 'ASC', $kb_slug='')
255 {
256 $args = array(
257 'post_type' => $post_type
258 );
259
260 $tax_query = array(
261 array(
262 'taxonomy' => 'doc_category',
263 'field' => 'slug',
264 'terms' => $tax_slug,
265 'operator' => 'AND',
266 'include_children' => false
267 ),
268 );
269
270 $args['tax_query'] = apply_filters('betterdocs_list_tax_query_arg', $tax_query, $multiple_kb, $tax_slug, $kb_slug);
271
272 if ($posts_per_grid) {
273 $args['posts_per_page'] = $posts_per_grid;
274 }
275
276 if ($orderby != 'betterdocs_order' || $orderby != 'none') {
277 if ($orderby == '1') {
278 $args['orderby'] = 'title';
279 } else {
280 $args['orderby'] = $orderby;
281 }
282 $args['order'] = $order;
283 }
284 return $args;
285 }
286
287 public static function count_kb()
288 {
289 $result = array();
290 $kbs = get_terms(array(
291 'taxonomy' => 'knowledge_base',
292 'hide_empty' => false,
293 'fields' => 'id=>slug'
294 ));
295
296 $cats = get_terms(array(
297 'taxonomy' => 'doc_category',
298 'hide_empty' => false,
299 'fields' => 'id=>slug'
300 ));
301
302 foreach ($kbs as $kb) {
303 foreach ($cats as $cat) {
304 $args = array(
305 'post_type' => 'docs',
306 'post_status' => 'publish',
307 'tax_query' => array(
308 'relation' => 'AND',
309 array(
310 'taxonomy' => 'knowledge_base',
311 'field' => 'slug',
312 'terms' => array($kb),
313 ),
314 array(
315 'taxonomy' => 'doc_category',
316 'field' => 'slug',
317 'terms' => array($cat),
318 ),
319 ),
320 );
321 $query = new WP_Query($args);
322 $result[$kb][$cat] = $query->post_count;
323 }
324 }
325 return $result;
326 }
327
328 public static function count_category($kb_slug, $cat_slug)
329 {
330 $args = array(
331 'post_type' => 'docs',
332 'post_status' => 'publish',
333 );
334
335 $taxes = array('knowledge_base', 'doc_category');
336 foreach ($taxes as $tax) {
337 $terms = get_terms($tax);
338
339 foreach ($terms as $term)
340 $tax_map[$tax][$term->slug] = $term->term_taxonomy_id;
341 }
342
343 $args['tax_query'] = array(
344 'relation' => 'AND',
345 array(
346 'taxonomy' => 'knowledge_base',
347 'field' => 'term_taxonomy_id',
348 'terms' => array($tax_map['knowledge_base'][$kb_slug]),
349 'operator' => 'IN',
350 'include_children' => false,
351 ),
352 array(
353 'taxonomy' => 'doc_category',
354 'field' => 'term_taxonomy_id',
355 'operator' => 'IN',
356 'terms' => array($tax_map['doc_category'][$cat_slug]),
357 'include_children' => false,
358 ),
359 );
360
361 $query = new WP_Query($args);
362 $count = $query->found_posts;
363 return $count;
364 }
365
366 public static function taxonomy_object($multiple_kb, $terms, $kb_slug='', $nested_subcategory=false)
367 {
368 global $wp_query;
369 $terms_object = array(
370 'hide_empty' => true,
371 'taxonomy' => 'doc_category'
372 );
373
374 $alphabetically_order_term = BetterDocs_DB::get_settings('alphabetically_order_term');
375 if ( $alphabetically_order_term != 1 ) {
376 $terms_object['meta_key'] = 'doc_category_order';
377 $terms_object['orderby'] = 'meta_value_num';
378 $terms_object['order'] = 'ASC';
379 } else {
380 $terms_object['orderby'] = 'name';
381 }
382
383 if ($nested_subcategory == true) {
384 $terms_object['parent'] = 0;
385 }
386
387 if ($wp_query->query === NULL || (isset($wp_query->query['post_type']) && $wp_query->query['post_type'] != 'docs')) {
388 $terms_object['number'] = 4;
389 }
390
391 $meta_query = '';
392 $terms_object['meta_query'] = apply_filters('betterdocs_taxonomy_object_meta_query', $meta_query, $multiple_kb, $kb_slug);
393
394 if ($terms) {
395 unset($terms_object['parent']);
396 }
397
398 if ($terms) {
399 $terms_object['include'] = explode(',', $terms);
400 $terms_object['orderby'] = 'include';
401 }
402
403 return get_terms($terms_object);
404 }
405
406 public static function child_taxonomy_terms($term_id, $multiple_kb, $orderby = "name", $order = "", $kb_slug = '')
407 {
408 global $wp_query;
409 $terms_object = array(
410 'parent' => $term_id
411 );
412
413 if ($orderby) {
414 $terms_object['orderby'] = $orderby;
415 }
416
417 if ($order) {
418 $terms_object['order'] = $order;
419 }
420
421 if ($wp_query->query === NULL || (isset($wp_query->query['post_type']) && $wp_query->query['post_type'] != 'docs')) {
422 $terms_object['number'] = 1;
423 }
424
425 $meta_query = '';
426 $terms_object['meta_query'] = apply_filters('betterdocs_child_taxonomy_meta_query', $meta_query, $multiple_kb, $kb_slug);
427 return get_terms('doc_category', $terms_object);
428 }
429
430 public static function term_permalink($texanomy, $term_slug) {
431 $get_term_link = get_term_link( $term_slug, $texanomy );
432 return apply_filters( 'betterdocs_cat_term_permalink', $get_term_link, $term_slug, $texanomy );
433 }
434
435 public static function get_prev($array, $key) {
436 $currentKey = array_search($key, $array);
437 if ($currentKey > 0 || $currentKey != 0) {
438 $nextKey = $currentKey - 1;
439 $prev_post = $array[$nextKey];
440 $nav = '<a rel="prev" class="next-post" href="'.get_post_permalink($prev_post).'"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="42px" viewBox="0 0 50 50" version="1.1"><g id="surface1"><path style=" " d="M 11.957031 13.988281 C 11.699219 14.003906 11.457031 14.117188 11.28125 14.308594 L 1.015625 25 L 11.28125 35.691406 C 11.527344 35.953125 11.894531 36.0625 12.242188 35.976563 C 12.589844 35.890625 12.867188 35.625 12.964844 35.28125 C 13.066406 34.933594 12.972656 34.5625 12.71875 34.308594 L 4.746094 26 L 48 26 C 48.359375 26.003906 48.695313 25.816406 48.878906 25.503906 C 49.058594 25.191406 49.058594 24.808594 48.878906 24.496094 C 48.695313 24.183594 48.359375 23.996094 48 24 L 4.746094 24 L 12.71875 15.691406 C 13.011719 15.398438 13.09375 14.957031 12.921875 14.582031 C 12.753906 14.203125 12.371094 13.96875 11.957031 13.988281 Z "></path></g></svg>'.get_the_title($prev_post).'</a>';
441 } else {
442 $nav = '';
443 }
444 return $nav;
445 }
446
447 public static function get_next($array, $key) {
448 $currentKey = array_search($key, $array);
449 if (end($array) != $array[$currentKey]) {
450 $nextKey = $currentKey + 1;
451 $next_post = $array[$nextKey];
452 $nav = '<a rel="next" class="next-post" href="'.get_post_permalink($next_post).'">'.get_the_title($next_post).'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="42px" viewBox="0 0 50 50" version="1.1"><g id="surface1"><path style=" " d="M 38.035156 13.988281 C 37.628906 13.980469 37.257813 14.222656 37.09375 14.59375 C 36.933594 14.96875 37.015625 15.402344 37.300781 15.691406 L 45.277344 24 L 2.023438 24 C 1.664063 23.996094 1.328125 24.183594 1.148438 24.496094 C 0.964844 24.808594 0.964844 25.191406 1.148438 25.503906 C 1.328125 25.816406 1.664063 26.003906 2.023438 26 L 45.277344 26 L 37.300781 34.308594 C 36.917969 34.707031 36.933594 35.339844 37.332031 35.722656 C 37.730469 36.105469 38.363281 36.09375 38.746094 35.691406 L 49.011719 25 L 38.746094 14.308594 C 38.5625 14.109375 38.304688 13.996094 38.035156 13.988281 Z "></path></g></svg></a>';
453 } else {
454 $nav = '';
455 }
456 return $nav;
457 }
458
459 public static function get_postcount($term, $multiple_kb, $total_term_count = 0)
460 {
461 $taxonomy = 'doc_category';
462 $args = array(
463 'child_of' => $term->term_id,
464 );
465 $tax_terms = get_terms($taxonomy, $args);
466
467 if ($tax_terms) {
468 foreach ($tax_terms as $tax_term) {
469 $total_term_count += $tax_term->count;
470 }
471 }
472
473 return apply_filters('betterdocs_postcount', $total_term_count, $multiple_kb, $term->term_id, $term->slug, $term->count);
474 }
475
476 const ALLOWED_HTML_TAGS = [
477 'article',
478 'aside',
479 'div',
480 'footer',
481 'h1',
482 'h2',
483 'h3',
484 'h4',
485 'h5',
486 'h6',
487 'header',
488 'main',
489 'nav',
490 'p',
491 'section',
492 'span',
493 ];
494
495 /**
496 * validate_html_tag
497 * @param $tag
498 * @return mixed|string
499 */
500 public static function html_tag( $tag ){
501 return in_array( strtolower( $tag ), self::ALLOWED_HTML_TAGS ) ? $tag : 'div';
502 }
503
504 public static function feedback_form(){
505 $fform_title = BetterDocs_DB::get_settings('feedback_form_title');
506 $output = betterdocs_generate_output();
507 $html = '<'. $output['betterdocs_feedback_form_title_tag'] .' class="feedback-form-title">';
508 $html .= ( $fform_title ) ? stripslashes($fform_title) : esc_html__( 'How can we help?', 'betterdocs' );
509 $html .= '</'. $output['betterdocs_feedback_form_title_tag'] .'>';
510 $html .= '<div class="modal-content-inner">';
511 $html .= do_shortcode('[betterdocs_feedback_form]');
512 $html .= '</div>';
513 echo $html;
514 }
515
516 /**
517 * return true if templates from BetterDocs to load assets
518 */
519 public static function is_templates() {
520 if(is_plugin_active('elementor/elementor.php') && is_plugin_active('elementor-pro/elementor-pro.php')){
521 $document = \Elementor\Plugin::$instance->documents->get( get_the_ID() );
522 if (\Elementor\Plugin::instance()->editor->is_edit_mode() || (( get_post_meta(get_the_ID(), '_elementor_template_type', true)) && $document->is_built_with_elementor())) {
523 return true;
524 }
525 }
526
527 $tax = self::get_tax();
528 if (is_post_type_archive('docs') || $tax === 'knowledge_base' || $tax === 'doc_category' || is_singular('docs')) {
529 return true;
530 }
531 return false;
532 }
533
534 public static function term_options($taxonomy, $selected='')
535 {
536 $html = '';
537 $terms_object = array(
538 'taxonomy' => $taxonomy,
539 'hide_empty' => false
540 );
541
542 $taxonomy_objects = get_terms($terms_object);
543 if ($taxonomy_objects && !is_wp_error($taxonomy_objects)) :
544 foreach ($taxonomy_objects as $term) :
545 $sel = ($term->slug === $selected) ? ' selected' : '';
546 $html .= '<option value="' . $term->slug . '"' . $sel . '>' . $term->name . '</option>';
547 endforeach;
548 endif;
549 return $html;
550 }
551 }
552