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

820 lines 27.1 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['tax_query'] ) ) {
632 $tax_query = $args['tax_query'];
633 }
634
635
636
637 $args['tax_query'] = apply_filters(
638 'betterdocs_docs_tax_query_args',
639 $tax_query, $_multiple_kb, $_term_slug, $_kb_slug, $_origin_args, $this->is_inner_templates()
640 );
641 /**
642 * Final parse args
643 */
644 $args = wp_parse_args( $args, $default_args );
645
646 if ( ! empty( $filter ) ) {
647 $filter = array_flip( $filter );
648 $args = array_filter( $args, function ( $item ) use ( $filter ) {
649 return ! array_key_exists( $item, $filter );
650 }, ARRAY_FILTER_USE_KEY );
651 }
652
653 return apply_filters( 'betterdocs_articles_args', $args, $_term_id, $_origin_args );
654 }
655
656 public function faq_terms_query_args( $includes = '', $excludes = '', $args = [] ) {
657 $_args = [
658 'taxonomy' => 'betterdocs_faq_category',
659 'meta_key' => 'order',
660 'orderby' => 'meta_value_num',
661 'order' => 'ASC',
662 'include' => $includes,
663 'exclude' => $excludes,
664 'meta_query' => [
665 [
666 'key' => 'status',
667 'value' => 1,
668 'compare' => '=='
669 ]
670 ]
671 ];
672
673 if ( $_args['include'] == 'all' ) {
674 unset( $_args['include'] );
675 unset( $_args['exclude'] );
676 }
677
678 if ( empty( $_args['exclude'] ) ) {
679 unset( $_args['exclude'] );
680 }
681
682 if ( empty( $_args['include'] ) ) {
683 unset( $_args['include'] );
684 }
685
686 return wp_parse_args( $args, $_args );
687 }
688
689 public function get_faq_by_term( $term_id ) {
690 global $wpdb;
691
692 $args = [
693 'post_type' => 'betterdocs_faq',
694 'post_status' => 'publish',
695 'tax_query' => [
696 [
697 'taxonomy' => 'betterdocs_faq_category',
698 'field' => 'term_id',
699 'terms' => $term_id,
700 'operator' => 'AND'
701 ]
702 ],
703 'posts_per_page' => -1
704 ];
705
706 $args['orderby'] = 'post__in';
707 $args['post__in'] = $this->get_faq_orders( $term_id );
708
709 return new WP_Query( $args );
710 }
711
712 public function get_faq_orders( $term_id = null ) {
713 global $wpdb;
714 $faq_order = get_term_meta( $term_id, '_betterdocs_faq_order', true );
715 $faq_order = explode( ',', $faq_order );
716
717 $query = $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}term_relationships WHERE term_taxonomy_id = %d", $term_id );
718 $query_key = "betterdocs_faq_order_" . md5( $query );
719
720 if ( ( $results = $this->database->get_cache( $query_key ) ) !== false ) {
721 return $results;
722 }
723
724 if ( ! empty( $faq_order ) ) {
725 $new_ids = [];
726 $results = $wpdb->get_results( $query );
727
728 if ( ! is_null( $results ) && ! empty( $results ) && is_array( $results ) ) {
729 $object_ids = array_filter( $results, function ( $value ) use ( $faq_order ) {
730 return ! in_array( $value->object_id, $faq_order );
731 } );
732
733 if ( ! empty( $object_ids ) ) {
734 array_walk( $object_ids, function ( $value ) use ( &$new_ids ) {
735 $new_ids[] = $value->object_id;
736 } );
737 }
738 }
739
740 $faq_order = array_merge( $new_ids, $faq_order );
741 }
742
743 $this->database->set_cache( $query_key, $faq_order, 1 );
744
745 return $faq_order;
746 }
747
748 public function get_faq_terms( $terms = [] ) {
749 $_terms = get_terms( [
750 'taxonomy' => 'betterdocs_faq_category',
751 'hide_empty' => true,
752 'orderby' => 'name',
753 'order' => 'ASC',
754 'meta_query' => [
755 [
756 'key' => 'status',
757 'value' => 1,
758 'compare' => '=='
759 ]
760 ]
761 ] );
762
763 if ( ! is_wp_error( $_terms ) ) {
764 foreach ( $_terms as $term ) {
765 $terms[$term->term_id] = $term->name;
766 }
767 }
768
769 return $terms;
770 }
771
772 public function get_docs_count( $term, $nested_subcategory = false, $args = [] ) {
773 $counts = isset( $term->count ) ? $term->count : 0;
774
775 if ( $nested_subcategory == false ) {
776 return apply_filters( 'betterdocs_docs_count', $counts, $term, $nested_subcategory, $args );
777 }
778
779 $_child_terms_docs_ids = $this->get_doc_ids_by_term( $term, null, $nested_subcategory );
780 if ( is_array( $_child_terms_docs_ids ) ) {
781 $counts = count( $_child_terms_docs_ids );
782 }
783
784 return apply_filters( 'betterdocs_docs_count', $counts, $term, $nested_subcategory, $args );
785 }
786
787 public function get_doc_ids_by_term( $term, $optional = null, $nested_subcategory = false ) {
788 $args = [ 'include' => $term->term_id ];
789 if( $nested_subcategory ) {
790 $args['child_of'] = $term->term_id;
791 unset( $args['include'] );
792 }
793 $_child_terms = get_terms( $term->taxonomy, $args );
794
795 if ( ! is_array( $_child_terms ) ) {
796 return false;
797 }
798
799 array_unshift( $_child_terms, $term );
800
801 $_child_terms_ids = array_column( $_child_terms, 'term_id' );
802 $_child_terms_taxs = array_column( $_child_terms, 'taxonomy' );
803 $_child_terms_docs_ids = get_objects_in_term( $_child_terms_ids, $_child_terms_taxs );
804
805 if ( $optional !== null ) {
806 $_optional_doc_ids = get_objects_in_term( $optional->term_id, $optional->taxonomy );
807 $_child_terms_docs_ids = array_intersect( $_child_terms_docs_ids, $_optional_doc_ids );
808 }
809
810 return array_filter( $_child_terms_docs_ids, function ( $doc_id ) {
811 if ( ! is_user_logged_in() ) {
812 return is_post_publicly_viewable( $doc_id );
813 }
814
815 $_status = get_post_status( $doc_id );
816 return $_status == 'private' || is_post_publicly_viewable( $doc_id );
817 } );
818 }
819 }
820