PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 3.5.9
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v3.5.9
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 / Core / Query.php

Query.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 3.5.9, at includes/Core/Query.php

823 lines 27.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPDeveloper\BetterDocs\Core;
4
5 use WP_Query;
6 use WPDeveloper\BetterDocs\Utils\Base;
7 use WPDeveloper\BetterDocs\Utils\Database;
8 use WPDeveloper\BetterDocs\Dependencies\DI\Container;
9
10 class Query extends Base {
11 private $container;
12 protected $database;
13 protected $settings;
14
15 public function __construct( Container $container, Database $database, Settings $settings ) {
16 $this->container = $container;
17 $this->database = $database;
18 $this->settings = $settings;
19
20 add_action( 'parse_term_query', [$this, 'parse_term_query'] );
21 // add_action( 'parse_query', [$this, 'parse_query'], 1 );
22 add_action( 'pre_get_posts', [$this, 'pre_get_posts'], 1 );
23
24 /**
25 * These below filters are hooked for navigation only.
26 *
27 * For old version of this portion.
28 * @see `betterdocs_single_post_nav` filter
29 *
30 * For details:
31 * @see https://developer.wordpress.org/reference/functions/get_next_post/
32 * @see https://developer.wordpress.org/reference/functions/get_previous_post/
33 *
34 * @link https://developer.wordpress.org/reference/hooks/get_adjacent_post_where/
35 */
36 add_filter( 'get_next_post_where', [$this, 'next_post_where'], 99, 5 );
37 add_filter( 'get_previous_post_where', [$this, 'previous_post_where'], 99, 5 );
38
39 $this->init();
40
41 /**
42 * Modify Popular Docs Query (For Shortcode & Widget)
43 */
44 add_filter( 'posts_clauses', [$this, 'mod_query_popular_docs'], 10, 2 );
45 }
46
47 public function mod_query_popular_docs( $clauses, $wp_query ) {
48 if ( isset( $wp_query->query['meta_key'] ) ) {
49 if ( $wp_query->query['meta_key'] == '_betterdocs_meta_views' ) {
50 global $wpdb;
51 $order = isset( $wp_query->query['order'] ) ? $wp_query->query['order'] : '';
52 $order_by_query = ( $order == 'ASC' || $order == 'DESC' ) ? "SUM({$wpdb->prefix}betterdocs_analytics.impressions) {$order}" : ( $order == 'MODIFIED' ? "{$wpdb->prefix}posts.post_modified_gmt DESC" : "{$wpdb->prefix}posts.post_date_gmt DESC" );
53 $clauses['join'] = "JOIN {$wpdb->prefix}betterdocs_analytics ON {$wpdb->prefix}posts.ID = {$wpdb->prefix}betterdocs_analytics.post_id";
54 $clauses['where'] = "AND ( ( {$wpdb->prefix}posts.post_type = 'docs' ) AND ( {$wpdb->prefix}posts.post_status = 'publish' OR {$wpdb->prefix}posts.post_status = 'future' OR {$wpdb->prefix}posts.post_status = 'draft' OR {$wpdb->prefix}posts.post_status = 'pending' OR {$wpdb->prefix}posts.post_status = 'private' ) )";
55 $clauses['orderby'] = $order_by_query;
56 $clauses['groupby'] = "{$wpdb->prefix}betterdocs_analytics.post_id";
57 }
58 }
59 return $clauses;
60 }
61
62 public function init() {
63 }
64
65 public function parse_term_query( $term_query ) {
66 if ( empty( $term_query->query_vars['taxonomy'] ) ) {
67 return;
68 }
69
70 if ( ! in_array( 'doc_category', $term_query->query_vars['taxonomy'], true ) ) {
71 return;
72 }
73
74 global $current_screen;
75
76 if ( $current_screen == null ) {
77 return;
78 }
79
80 if ( $current_screen->taxonomy !== 'doc_category' || $current_screen->id != 'edit-doc_category' ) {
81 return;
82 }
83
84 $term_query->query_vars['meta_query'] = [[
85 'key' => 'doc_category_order',
86 'type' => 'NUMERIC'
87 ]];
88
89 $term_query->query_vars['orderby'] = 'meta_value_num';
90 }
91
92 public function parse_query( &$query ) {
93 // dump( is_single(), $query->query_vars );
94 // if ( is_single() && isset( $query->query_vars['post_type'] ) && $query->query_vars['post_type'] == 'docs' ) {
95 // $query->is_single = false;
96 // $query->is_archive = true;
97 // $query->set( 'knowledge_base', $query->query_vars['docs'] );
98 // }
99 }
100
101 public function pre_get_posts( &$query ) {
102 if ( is_admin() || ! $query->is_main_query() ) {
103 return;
104 }
105
106 if ( is_tax( 'doc_category' ) ) {
107 $query->set( 'post_type', 'docs' );
108 $query->set( 'posts_per_archive_page', -1 );
109
110 $term = get_term_by( 'slug', $query->get( 'doc_category', '' ), 'doc_category' );
111
112 $post__in = $this->get_docs_order_by_terms( $term->term_id );
113 if ( ! empty( $post__in ) ) {
114 $query->set( 'orderby', 'post__in' );
115 $query->set( 'post__in', $post__in );
116 }
117
118 // if ( ! empty( $query->query_vars['knowledge_base'] ) ) {
119 // $query->betterdocs_terms = get_terms( [
120 // 'taxonomy' => 'doc_category',
121 // 'parent' => 0,
122 // 'hide_empty' => true,
123 // 'meta_query' => [
124 // 'relation' => 'OR',
125 // [
126 // 'key' => 'doc_category_knowledge_base',
127 // 'value' => $query->query_vars['knowledge_base'],
128 // 'compare' => 'LIKE'
129 // ]
130 // ]
131 // ] );
132 // }
133 }
134
135 // dump( is_archive(), $query->query_vars );
136 }
137
138 /**
139 * Get docs orders by term_id.
140 *
141 * @since 2.5.0
142 * @param int $term_id
143 *
144 * @return array
145 */
146 public function get_docs_order_by_terms( $term_id ) {
147 global $wpdb;
148 $_docs_order = get_term_meta( $term_id, '_docs_order', true );
149 $query = $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}term_relationships WHERE term_taxonomy_id = %d", $term_id );
150 $query_key = "docs_order_by_terms_{$term_id}_" . md5( $query );
151
152 if ( ( $results = $this->database->get_cache( $query_key ) ) !== false ) {
153 return $results;
154 }
155
156 if ( ! empty( $_docs_order ) ) {
157 $_docs_order = explode( ',', $_docs_order );
158 $new_ids = [];
159
160 $results = $wpdb->get_results( $query );
161
162 if ( is_array( $results ) && ! empty( $results ) ) {
163 $object_ids = array_filter( $results, function ( $value ) use ( $_docs_order ) {
164 return ! in_array( $value->object_id, $_docs_order );
165 } );
166
167 if ( ! empty( $object_ids ) ) {
168 array_walk( $object_ids, function ( $value ) use ( &$new_ids ) {
169 $new_ids[] = $value->object_id;
170 } );
171 }
172 }
173
174 $_docs_order = array_merge( $new_ids, $_docs_order );
175 $this->database->set_cache( $query_key, $_docs_order, 1 );
176
177 return $_docs_order;
178 }
179
180 return [];
181 }
182
183 /**
184 * For determine the next post ID
185 *
186 * @link https://developer.wordpress.org/reference/hooks/get_adjacent_post_where/
187 *
188 * @param mixed $where
189 * @param mixed $in_same_term
190 * @param mixed $excluded_terms
191 * @param mixed $taxonomy
192 * @param mixed $post
193 * @return mixed
194 */
195 public function next_post_where( $where, $in_same_term, $excluded_terms, $taxonomy, $post ) {
196 return $this->get_adjacent_post_id( 'next', $where, $post, $taxonomy );
197 }
198
199 /**
200 * For determine the previous post ID
201 *
202 * @link https://developer.wordpress.org/reference/hooks/get_adjacent_post_where/
203 *
204 * @param mixed $where
205 * @param mixed $in_same_term
206 * @param mixed $excluded_terms
207 * @param mixed $taxonomy
208 * @param mixed $post
209 * @return mixed
210 */
211 public function previous_post_where( $where, $in_same_term, $excluded_terms, $taxonomy, $post ) {
212 return $this->get_adjacent_post_id( 'previous', $where, $post, $taxonomy );
213 }
214
215 /**
216 * Get where clause for next/previous post ID mainly used in post navigation.
217 *
218 * @see `previous_post_where` and `next_post_where` methods.
219 *
220 * @param mixed $adjacent
221 * @param mixed $where
222 * @param mixed $post
223 * @param mixed $taxonomy
224 * @return mixed
225 */
226 private function get_adjacent_post_id( $adjacent, $where, $post, $taxonomy ) {
227 if ( $taxonomy !== 'doc_category' ) {
228 return $where;
229 }
230
231 $_id = null;
232 $_terms = get_the_terms( $post->ID, 'doc_category' );
233 if ( empty( $_terms ) ) {
234 return $where;
235 }
236
237 global $wp_query, $wpdb;
238
239 $_docs_order = $this->get_docs_order_by_terms( $_terms[0]->term_id );
240
241 $_where = explode( 'AND', $where );
242 if ( is_array( $_where ) ) {
243 // $_where[0] = str_replace( 'WHERE ', '', $_where[0] );
244 unset( $_where[0] );
245 $_where = implode( 'AND', $_where );
246 }
247
248 $_orderby = $this->settings->get( 'alphabetically_order_post', 'betterdocs_order' );
249 $_order = $this->settings->get( 'docs_order', 'ASC' );
250 $_docs_order = $_orderby === 'betterdocs_order' ? $_docs_order : [];
251
252 if ( empty( $_docs_order ) ) {
253 $statuses = ['publish'];
254
255 if ( is_user_logged_in() ) {
256 $statuses[] = 'private';
257 }
258
259 $_args = [
260 'post_status' => $statuses
261 ];
262 if ( isset( $wp_query->query_vars['doc_category'] ) ) {
263 $_args['tax_query'][] = [
264 'taxonomy' => 'doc_category',
265 'field' => 'slug',
266 'terms' => $wp_query->query_vars['doc_category'],
267 'operator' => 'AND',
268 'include_children' => false
269 ];
270 }
271
272 $_args['orderby'] = $_orderby;
273 if ( $_orderby != 'betterdocs_order' ) {
274 $_args['order'] = $_order;
275 }
276
277 /**
278 * Before Query
279 */
280 do_action_ref_array( 'betterdocs_navigation_docs_query', [ &$_args] );
281 $docs = $this->get_posts( $this->docs_query_args( $_args ) );
282
283 $_docs = [];
284 if ( $docs->have_posts() ) {
285 array_map( function ( $post ) use ( &$_docs ) {
286 $_docs[] = $post->ID;
287 }, $docs->posts );
288 }
289
290 $_docs_order = $_docs;
291 }
292
293 $_docs_order = apply_filters( 'betterdocs_adjacent_docs_order', $_docs_order, $_terms );
294
295 $_id_index = array_search( $post->ID, $_docs_order );
296 $_id_index = $adjacent === 'next' ? $_id_index + 1 : $_id_index - 1;
297 $_id = isset( $_docs_order[$_id_index] ) ? (int) $_docs_order[$_id_index] : null;
298
299 return $wpdb->prepare( "WHERE p.ID = %s AND $_where", (int) $_id );
300 }
301
302 public function parse_terms_args( $args = [] ) {
303 $_default_args = [
304 'hide_empty' => true,
305 'taxonomy' => 'doc_category'
306 ];
307
308 // OrderBy & Order
309 $_orderby = ! empty( $args['orderby'] ) && $args['orderby'] != 1 ? $args['orderby'] : 'name';
310 $_order = ! empty( $args['order'] ) ? $args['order'] : '';
311
312 if ( $_orderby == 'betterdocs_order' ) {
313 $args['meta_key'] = 'doc_category_order';
314 $args['orderby'] = 'meta_value_num';
315 $args['order'] = 'ASC';
316 } else {
317 $args['orderby'] = $_orderby;
318 $args['order'] = $_order;
319 }
320
321 // Nested Sub Category
322 // $args['parent'] = 0;
323 // if ( $nested_subcategory == true ) {
324 // }
325
326 if ( ! isset( $args['number'] ) ) {
327 global $wp_query;
328 if ( $wp_query->query === NULL || ( isset( $wp_query->query['post_type'] ) && $wp_query->query['post_type'] != 'docs' ) ) {
329 $args['number'] = 4;
330 }
331 }
332
333 // Includes
334 if ( isset( $args['include'] ) ) {
335 $_include = ! is_array( $args['include'] ) ? explode( ',', $args['include'] ) : $args['include'];
336 $args['include'] = $_include;
337 $args['orderby'] = 'include';
338
339 unset( $args['parent'] );
340 }
341
342 $_meta_query = ! empty( $args['meta_query'] ) ? $args['meta_query'] : [];
343 $args['meta_query'] = apply_filters( 'betterdocs_taxonomy_object_meta_query', $_meta_query, $args );
344
345 return apply_filters( 'betterdocs_category_terms_object', wp_parse_args( $args, $_default_args ), $args );
346 }
347
348 public function get_terms( $args ) {
349 return get_terms( $this->parse_terms_args( $args ) );
350 }
351
352 public function get_child_terms( $args ) {
353 if ( ! isset( $args['number'] ) ) {
354 global $wp_query;
355 if ( $wp_query->query === NULL || ( isset( $wp_query->query['post_type'] ) && $wp_query->query['post_type'] != 'docs' ) ) {
356 $args['number'] = 1;
357 }
358 }
359
360 return $this->get_terms( $args );
361 }
362
363 /**
364 * Get POSTs of Docs type.
365 *
366 * @param mixed $args
367 * @return WP_Query
368 */
369 public function get_posts( $args, $ignore = false ) {
370 if ( ! $ignore ) {
371 $args = $this->docs_query_args( $args );
372 }
373
374 return new WP_Query( $args );
375 }
376
377 public function get_taxonomy( $tax = '' ) {
378 global $wp_query;
379 if ( is_tax( 'knowledge_base' ) ) {
380 $_tax = $wp_query->tax_query->queried_terms;
381 if ( array_key_exists( "doc_category", $_tax ) ) {
382 $tax = 'doc_category';
383 } else {
384 $tax = 'knowledge_base';
385 }
386 } elseif ( is_tax( 'doc_category' ) ) {
387 $tax = 'doc_category';
388 }
389
390 return $tax;
391 }
392
393 public function terms_query( $args = [] ) {
394 global $wp_query;
395 $_origin_args = $args;
396
397 $default_args = [
398 'hide_empty' => true,
399 'taxonomy' => 'doc_category',
400 'orderby' => 'name'
401 ];
402
403 /**
404 * Number Set
405 *
406 * @FIX: If Built-in Docs page off and docs_page in use, then Terms Query Number 4|1 set.
407 */
408 // if ( $wp_query->query === NULL || ( isset( $wp_query->query['post_type'] ) && $wp_query->query['post_type'] != 'docs' ) ) {
409 // $default_args['number'] = 1;
410 // }
411
412 /**
413 * Nested Sub Category
414 */
415 if ( isset( $args['nested_subcategory'] ) && $args['nested_subcategory'] == true ) {
416 $default_args['parent'] = 0;
417 unset( $args['nested_subcategory'] );
418 // if ( $wp_query->query === NULL || ( isset( $wp_query->query['post_type'] ) && $wp_query->query['post_type'] != 'docs' ) ) {
419 // $default_args['number'] = 4;
420 // }
421 }
422
423 /**
424 * OrderBy and Order
425 */
426 if ( ! isset( $args['orderby'] ) ) {
427 $_orderby = $this->settings->get( 'terms_orderby', 'name' );
428 $_order = $this->settings->get( 'terms_order', '' );
429 } else {
430 $_orderby = $args['orderby'];
431 $_order = ! empty( $args['order'] ) ? $args['order'] : '';
432 }
433
434 if ( 'betterdocs_order' === $_orderby ) {
435 $default_args['meta_key'] = 'doc_category_order';
436 $_orderby = 'meta_value_num';
437 $_order = 'ASC';
438 } elseif ( $_orderby === true ) {
439 $_orderby = 'name';
440 }
441
442 $args['orderby'] = $_orderby;
443 if ( ! empty( $_order ) ) {
444 $args['order'] = $_order;
445 }
446
447 /**
448 * @todo old hook
449 * hook: betterdocs_child_taxonomy_meta_query
450 */
451 $_multiple_kb = apply_filters(
452 'betterdocs_query_args_multiple_kb_enabled',
453 isset( $args['multiple_kb'] ) ? (bool) $args['multiple_kb'] : false,
454 $_origin_args
455 );
456
457 $_kb_slug = isset( $args['kb_slug'] ) ? trim( $args['kb_slug'] ) : '';
458
459 unset( $args['multiple_kb'] );
460 unset( $args['kb_slug'] );
461
462 $meta_query = ! empty( $args['meta_query'] ) ? $args['meta_query'] : [];
463 $meta_query = apply_filters( 'betterdocs_terms_meta_query_args', $meta_query, $_multiple_kb, $_kb_slug, $_origin_args );
464
465 if ( ! empty( $meta_query ) ) {
466 $default_args['meta_query'] = $meta_query;
467 }
468
469 if ( ! empty( $args['terms'] ) ) {
470 $args['include'] = explode( ',', $args['terms'] );
471 $args['orderby'] = 'include';
472 $args['order'] = 'ASC';
473
474 unset( $default_args['parent'] );
475 unset( $args['parent'] );
476 unset( $args['terms'] );
477 }
478
479 $_query_args = wp_parse_args( $args, $default_args );
480 return apply_filters( 'betterdocs_terms_query_args', $_query_args, $_origin_args );
481 }
482
483 public function get_term_parents( $term_id, $taxonomy = 'doc_category', $args = [] ) {
484 $term = get_term( $term_id, $taxonomy );
485 if ( is_wp_error( $term ) ) {
486 return $term;
487 }
488
489 if ( ! $term ) {
490 return [];
491 }
492
493 $_lists = [];
494 $origin_term = $term_id;
495 $term_id = $term->term_id;
496
497 $defaults = [
498 'format' => 'name',
499 'inclusive' => true
500 ];
501
502 $args = wp_parse_args( $args, $defaults );
503
504 $args['inclusive'] = wp_validate_boolean( $args['inclusive'] );
505
506 $parents = get_ancestors( $term_id, $taxonomy );
507
508 if ( $args['inclusive'] ) {
509 array_unshift( $parents, $term_id );
510 }
511
512 foreach ( array_reverse( $parents ) as $term_id ) {
513 $parent = get_term( $term_id, $taxonomy );
514 $name = ( 'slug' === $args['format'] ) ? $parent->slug : $parent->name;
515 $term_permalink = get_term_link( $parent->term_id, $taxonomy );
516 $term_permalink = apply_filters( 'betterdocs_breadcrumb_term_permalink', $term_permalink, $term_id );
517
518 $_item = [
519 'url' => $term_permalink,
520 'text' => $name
521 ];
522
523 $_lists[] = $_item;
524 }
525
526 return apply_filters( 'betterdocs_breadcrumb_archive_lists', $_lists, $origin_term );
527 }
528
529 public function is_inner_templates() {
530 if ( is_tax( 'knowledge_base' ) || is_tax( 'doc_category' ) || is_tax( 'doc_tag' ) || is_singular( 'docs' ) ) {
531 return true;
532 }
533 return false;
534 }
535
536 /**
537 * Summary of docs_query_args
538 * @param mixed $args
539 * @throws \Exception
540 * @return mixed
541 */
542 public function docs_query_args( $args, $filter = [] ) {
543 $_origin_args = $args;
544
545 $default_args = [
546 'post_type' => 'docs'
547 ];
548
549 if ( ! empty( $args['post_type'] ) && trim( $args['post_type'] ) === 'docs_any' ) {
550 $default_args['post_type'] = 'docs';
551 $default_args['post_status'] = 'any';
552
553 unset( $args['post_type'] );
554 }
555
556 /**
557 * OrderBy and Order
558 */
559 if ( ! isset( $args['orderby'] ) ) {
560 $_orderby = $this->settings->get( 'alphabetically_order_post' );
561 $_order = $this->settings->get( 'docs_order', 'ASC' );
562 } else {
563 $_orderby = $args['orderby'];
564 $_order = ! empty( $args['order'] ) ? $args['order'] : 'ASC';
565 }
566
567 if ( 'betterdocs_order' != $_orderby ) {
568 if ( $_orderby === true ) {
569 $args['orderby'] = 'title';
570 } else {
571 $args['orderby'] = $_orderby;
572 }
573
574 $args['order'] = $_order;
575 } elseif ( 'betterdocs_order' == $_orderby ) {
576 unset( $args['orderby'] );
577 }
578
579 if ( empty( $args['orderby'] ) ) {
580 unset( $args['order'] );
581 }
582
583 /**
584 * Term ID
585 */
586 $_term_id = null;
587 if ( ! empty( $args['term_id'] ) ) {
588 $_term_id = intval( $args['term_id'] );
589 unset( $args['term_id'] );
590 }
591
592 // if ( $_term_id == null ) {
593 // throw new \Exception( __( '$args["term_id"] cannot be null.', 'betterdocs' ) );
594 // }
595
596 /**
597 * Term Slug for tax_query
598 */
599 $_term_slug = '';
600 if ( ! empty( $args['term_slug'] ) ) {
601 $_term_slug = trim( $args['term_slug'] );
602 unset( $args['term_slug'] );
603 }
604
605 /**
606 * @todo old hook
607 * hook: betterdocs_cat_template_multikb
608 */
609
610 $_multiple_kb = apply_filters(
611 'betterdocs_enable_multiple_knowledge_base',
612 isset( $args['multiple_kb'] ) ? (bool) $args['multiple_kb'] : false,
613 $_origin_args
614 );
615
616 $_kb_slug = isset( $args['kb_slug'] ) ? trim( $args['kb_slug'] ) : '';
617
618 unset( $args['multiple_kb'] );
619 unset( $args['kb_slug'] );
620
621 $tax_query = [
622 [
623 'taxonomy' => 'doc_category',
624 'field' => 'slug',
625 'terms' => $_term_slug,
626 'operator' => 'AND',
627 'include_children' => false
628 ]
629 ];
630
631 if ( ! isset( $args['orderby'] ) || $args['orderby'] == 'betterdocs_order' ) {
632 $args['orderby'] = 'post__in';
633 $args['post__in'] = $this->get_docs_order_by_terms( $_term_id );
634 }
635
636 if ( isset( $args['tax_query'] ) ) {
637 $tax_query = $args['tax_query'];
638 }
639
640 $args['tax_query'] = apply_filters(
641 'betterdocs_docs_tax_query_args',
642 $tax_query, $_multiple_kb, $_term_slug, $_kb_slug, $_origin_args, $this->is_inner_templates()
643 );
644 /**
645 * Final parse args
646 */
647 $args = wp_parse_args( $args, $default_args );
648
649 if ( ! empty( $filter ) ) {
650 $filter = array_flip( $filter );
651 $args = array_filter( $args, function ( $item ) use ( $filter ) {
652 return ! array_key_exists( $item, $filter );
653 }, ARRAY_FILTER_USE_KEY );
654 }
655
656 return apply_filters( 'betterdocs_articles_args', $args, $_term_id, $_origin_args );
657 }
658
659 public function faq_terms_query_args( $includes = '', $excludes = '', $args = [] ) {
660 $_args = [
661 'taxonomy' => 'betterdocs_faq_category',
662 'meta_key' => 'order',
663 'orderby' => 'meta_value_num',
664 'order' => 'ASC',
665 'include' => $includes,
666 'exclude' => $excludes,
667 'meta_query' => [
668 [
669 'key' => 'status',
670 'value' => 1,
671 'compare' => '=='
672 ]
673 ]
674 ];
675
676 if ( $_args['include'] == 'all' ) {
677 unset( $_args['include'] );
678 unset( $_args['exclude'] );
679 }
680
681 if ( empty( $_args['exclude'] ) ) {
682 unset( $_args['exclude'] );
683 }
684
685 if ( empty( $_args['include'] ) ) {
686 unset( $_args['include'] );
687 }
688
689 return wp_parse_args( $args, $_args );
690 }
691
692 public function get_faq_by_term( $term_id ) {
693 global $wpdb;
694
695 $args = [
696 'post_type' => 'betterdocs_faq',
697 'post_status' => 'publish',
698 'tax_query' => [
699 [
700 'taxonomy' => 'betterdocs_faq_category',
701 'field' => 'term_id',
702 'terms' => $term_id,
703 'operator' => 'AND'
704 ]
705 ],
706 'posts_per_page' => -1
707 ];
708
709 $args['orderby'] = 'post__in';
710 $args['post__in'] = $this->get_faq_orders( $term_id );
711
712 return new WP_Query( $args );
713 }
714
715 public function get_faq_orders( $term_id = null ) {
716 global $wpdb;
717 $faq_order = get_term_meta( $term_id, '_betterdocs_faq_order', true );
718 $faq_order = explode( ',', $faq_order );
719
720 $query = $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}term_relationships WHERE term_taxonomy_id = %d", $term_id );
721 $query_key = "betterdocs_faq_order_" . md5( $query );
722
723 if ( ( $results = $this->database->get_cache( $query_key ) ) !== false ) {
724 return $results;
725 }
726
727 if ( ! empty( $faq_order ) ) {
728 $new_ids = [];
729 $results = $wpdb->get_results( $query );
730
731 if ( ! is_null( $results ) && ! empty( $results ) && is_array( $results ) ) {
732 $object_ids = array_filter( $results, function ( $value ) use ( $faq_order ) {
733 return ! in_array( $value->object_id, $faq_order );
734 } );
735
736 if ( ! empty( $object_ids ) ) {
737 array_walk( $object_ids, function ( $value ) use ( &$new_ids ) {
738 $new_ids[] = $value->object_id;
739 } );
740 }
741 }
742
743 $faq_order = array_merge( $new_ids, $faq_order );
744 }
745
746 $this->database->set_cache( $query_key, $faq_order, 1 );
747
748 return $faq_order;
749 }
750
751 public function get_faq_terms( $terms = [] ) {
752 $_terms = get_terms( [
753 'taxonomy' => 'betterdocs_faq_category',
754 'hide_empty' => true,
755 'orderby' => 'name',
756 'order' => 'ASC',
757 'meta_query' => [
758 [
759 'key' => 'status',
760 'value' => 1,
761 'compare' => '=='
762 ]
763 ]
764 ] );
765
766 if ( ! is_wp_error( $_terms ) ) {
767 foreach ( $_terms as $term ) {
768 $terms[$term->term_id] = $term->name;
769 }
770 }
771
772 return $terms;
773 }
774
775 public function get_docs_count( $term, $nested_subcategory = false, $args = [] ) {
776 $counts = isset( $term->count ) ? $term->count : 0;
777
778 if ( $nested_subcategory == false ) {
779 return apply_filters( 'betterdocs_docs_count', $counts, $term, $nested_subcategory, $args );
780 }
781
782 $_child_terms_docs_ids = $this->get_doc_ids_by_term( $term, null, $nested_subcategory );
783 if ( is_array( $_child_terms_docs_ids ) ) {
784 $counts = count( $_child_terms_docs_ids );
785 }
786
787 return apply_filters( 'betterdocs_docs_count', $counts, $term, $nested_subcategory, $args );
788 }
789
790 public function get_doc_ids_by_term( $term, $optional = null, $nested_subcategory = false ) {
791 $args = ['include' => $term->term_id];
792 if ( $nested_subcategory ) {
793 $args['child_of'] = $term->term_id;
794 unset( $args['include'] );
795 }
796 $_child_terms = get_terms( $term->taxonomy, $args );
797
798 if ( ! is_array( $_child_terms ) ) {
799 return false;
800 }
801
802 array_unshift( $_child_terms, $term );
803
804 $_child_terms_ids = array_column( $_child_terms, 'term_id' );
805 $_child_terms_taxs = array_column( $_child_terms, 'taxonomy' );
806 $_child_terms_docs_ids = get_objects_in_term( $_child_terms_ids, $_child_terms_taxs );
807
808 if ( $optional !== null ) {
809 $_optional_doc_ids = get_objects_in_term( $optional->term_id, $optional->taxonomy );
810 $_child_terms_docs_ids = array_intersect( $_child_terms_docs_ids, $_optional_doc_ids );
811 }
812
813 return array_filter( $_child_terms_docs_ids, function ( $doc_id ) {
814 if ( ! is_user_logged_in() ) {
815 return is_post_publicly_viewable( $doc_id );
816 }
817
818 $_status = get_post_status( $doc_id );
819 return $_status == 'private' || is_post_publicly_viewable( $doc_id );
820 } );
821 }
822 }
823