PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.5.3
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.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 / Admin / WPExporter.php

WPExporter.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.5.3, at includes/Admin/WPExporter.php

394 lines 12.6 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\Admin;
4
5 use WPDeveloper\BetterDocs\Admin\ExportDefaults;
6 use WP_Term;
7 use wpdb;
8
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit; // Exit if accessed directly.
12 }
13
14 #[\AllowDynamicProperties]
15 class WPExporter {
16 /**
17 * @var array
18 */
19 private $args;
20
21 /**
22 * @var wpdb
23 */
24 private $wpdb;
25
26 public function __construct( array $args = [] ) {
27 global $wpdb;
28
29 $this->args = wp_parse_args($args, ExportDefaults::get_default_args());
30
31 $this->wpdb = $wpdb;
32 }
33
34 public function exporter_ids(): array {
35 // Build the base query
36 $query_parts = $this->build_base_query();
37 $where = $query_parts['where'];
38 $join = $query_parts['join'];
39
40 // Handle post status
41 $where .= $this->build_status_condition();
42
43 // Handle specific posts selection
44 if ( ! empty( $this->args['post__in'] ) ) {
45 $where .= $this->build_post_in_condition();
46 }
47
48 // Handle category terms
49 if ( isset( $this->args['category_terms'] ) ) {
50 $category_query = $this->build_category_query();
51 $join .= $category_query['join'];
52 $where .= $category_query['where'];
53 }
54
55 // Handle knowledge base terms
56 if ( isset( $this->args['kb_terms'] ) ) {
57 $kb_query = $this->build_kb_query();
58 $join .= $kb_query['join'];
59 $where .= $kb_query['where'];
60 }
61
62 // Handle additional filters (author, dates, meta)
63 $where .= $this->build_additional_filters();
64
65 // Get the main doc post IDs
66 $post_ids = $this->wpdb->get_col( "SELECT DISTINCT {$this->wpdb->posts}.ID FROM {$this->wpdb->posts} $join WHERE $where" );
67
68 // Handle FAQ posts separately
69 $faq_post_ids = [];
70 if ( ! empty( $this->args['include_faq'] ) ) {
71 $faq_post_ids = $this->get_faq_posts();
72 }
73
74 // Combine post IDs
75 $all_post_ids = array_merge( $post_ids, $faq_post_ids );
76
77 // Handle featured images
78 $thumbnail_ids = $this->get_thumbnail_ids( $all_post_ids );
79
80 // Generate final post IDs array
81 return array_unique(array_merge($all_post_ids, $thumbnail_ids));
82
83 }
84
85 // private function handle_glossaries_export(): array {
86 public function get_glossary_term_ids(): array {
87 if ( isset( $this->args['glossary_terms'] ) && ( count( $this->args['glossary_terms'] ) > 0 ) ) {
88 $glossary_term_ids = [];
89 foreach( $this->args['glossary_terms'] as $glossary_slug ) {
90 $term_object = get_term_by('slug', $glossary_slug , 'glossaries');
91 if( isset( $term_object->term_id ) && ! empty( $term_object->term_id ) ){
92 array_push($glossary_term_ids, $term_object->term_id);
93 }
94 }
95 } else {
96 $glossary_term_ids = $this->wpdb->get_col( "SELECT term_id from {$this->wpdb->term_taxonomy} where taxonomy='{$this->args['content']}';" );
97 }
98
99 return $glossary_term_ids;
100 }
101
102 public function build_base_query(): array {
103 $where = $this->wpdb->prepare("{$this->wpdb->posts}.post_type = %s", 'docs');
104 return [
105 'where' => $where,
106 'join' => ''
107 ];
108 }
109
110 public function build_status_condition(): string {
111 if ($this->args['status']) {
112 return $this->wpdb->prepare(" AND {$this->wpdb->posts}.post_status = %s", $this->args['status']);
113 }
114 return " AND {$this->wpdb->posts}.post_status != 'auto-draft'";
115 }
116
117 public function build_post_in_condition(): string {
118 $ids = $this->args['post__in'];
119 $ids_placeholder = implode(', ', array_fill(0, count($ids), '%d'));
120 return $this->wpdb->prepare(" AND {$this->wpdb->posts}.ID IN ($ids_placeholder)", $ids);
121 }
122
123 public function build_category_query(): array {
124 $join = "INNER JOIN {$this->wpdb->term_relationships} tr ON ({$this->wpdb->posts}.ID = tr.object_id)
125 INNER JOIN {$this->wpdb->term_taxonomy} tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id)";
126
127 $where = " AND tt.taxonomy = 'doc_category'";
128
129 if ( ! empty( $this->args['category_terms'] ) ) {
130 $term_ids = [];
131 foreach ( $this->args['category_terms'] as $term_id ) {
132 $term = term_exists( $term_id, 'doc_category' );
133 if ( $term ) {
134 $term_ids[] = $term['term_taxonomy_id'];
135 }
136 }
137
138 if ( ! empty( $term_ids ) ) {
139 $term_placeholder = implode( ', ', array_fill( 0, count( $term_ids ), '%d' ) );
140 $where .= $this->wpdb->prepare( " AND tt.term_taxonomy_id IN ($term_placeholder)", $term_ids );
141 }
142 }
143
144 return [
145 'join' => $join,
146 'where' => $where
147 ];
148 }
149
150 public function build_kb_query(): array {
151 $join = "INNER JOIN {$this->wpdb->term_relationships} tr ON ({$this->wpdb->posts}.ID = tr.object_id)
152 INNER JOIN {$this->wpdb->term_taxonomy} tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id)";
153
154 $where = " AND tt.taxonomy = 'knowledge_base'";
155
156 if ( ! empty( $this->args['kb_terms'] ) ) {
157 $term_ids = [];
158 foreach ( $this->args['kb_terms'] as $term_id ) {
159 $term = term_exists( $term_id, 'knowledge_base' );
160 if ( $term ) {
161 $term_ids[] = $term['term_taxonomy_id'];
162 }
163 }
164
165 if ( ! empty( $term_ids ) ) {
166 $term_placeholder = implode( ', ', array_fill( 0, count( $term_ids ), '%d' ) );
167 $where .= $this->wpdb->prepare( " AND tt.term_taxonomy_id IN ($term_placeholder)", $term_ids );
168 }
169 }
170
171 return [
172 'join' => $join,
173 'where' => $where
174 ];
175 }
176
177 public function build_additional_filters(): string {
178 $where = '';
179
180 if ( $this->args['author'] ) {
181 $where .= $this->wpdb->prepare( " AND {$this->wpdb->posts}.post_author = %d", $this->args['author'] );
182 }
183
184 if ( $this->args['start_date'] ) {
185 $where .= $this->wpdb->prepare(
186 " AND {$this->wpdb->posts}.post_date >= %s",
187 gmdate( 'Y-m-d', strtotime( $this->args['start_date'] ) )
188 );
189 }
190
191 if ( $this->args['end_date'] ) {
192 $where .= $this->wpdb->prepare(
193 " AND {$this->wpdb->posts}.post_date < %s",
194 gmdate( 'Y-m-d', strtotime( '+1 month', strtotime( $this->args['end_date'] ) ) )
195 );
196 }
197
198 return $where;
199 }
200
201 public function get_faq_posts(): array {
202 return get_posts([
203 'numberposts' => -1,
204 'post_type' => 'betterdocs_faq',
205 'fields' => 'ids',
206 'post_status' => 'publish'
207 ]);
208 }
209
210 public function get_thumbnail_ids(array $post_ids): array {
211 $thumbnail_ids = [];
212
213 if ( ! empty( $this->args['include_post_featured_image_as_attachment'] ) ) {
214 foreach ( $post_ids as $post_id ) {
215 $thumbnail_id = get_post_meta( $post_id, '_thumbnail_id', true );
216 if ( $thumbnail_id && ! in_array( $thumbnail_id, $post_ids, true ) ) {
217 $thumbnail_ids[] = $thumbnail_id;
218 }
219 }
220 }
221
222 return $thumbnail_ids;
223 }
224
225 /**
226 * Return tabulation characters, by `$columns`.
227 *
228 * @param int $columns
229 *
230 * @return string
231 */
232 public function indent( int $columns = 1 ): string {
233
234 $output = str_repeat( "\t", $columns );
235
236 return (string) $output;
237 }
238
239 /**
240 * Retrieve terms associated with the specified object IDs and sort them based on term meta.
241 *
242 * @param array $post_ids An array of object IDs.
243 * @return array An array of WP_Term objects sorted based on term meta.
244 */
245 public function get_terms(array $post_ids = []) {
246 // Get the object taxonomies
247 $taxonomies = get_object_taxonomies($this->args['content']);
248
249 $terms = [];
250
251 // Handle glossaries
252 if ($this->args['content'] == 'glossaries') {
253 $terms = get_terms([
254 'taxonomy' => 'glossaries',
255 'include' => $post_ids,
256 'hide_empty' => false,
257 ]);
258
259 if (is_wp_error($terms)) {
260 return [];
261 }
262
263 // Include parent terms for hierarchical glossaries
264 $parent_terms = [];
265 foreach ($terms as $term) {
266 if (!empty($term->parent)) {
267 $parent = get_term($term->parent, 'glossaries');
268 if (!is_wp_error($parent)) {
269 $parent_terms[] = $parent;
270 }
271 }
272 }
273
274 if (!empty($parent_terms)) {
275 $terms = array_merge($terms, $parent_terms);
276 $terms = array_unique($terms, SORT_REGULAR);
277 }
278 } elseif ($this->args['content'] == 'docs') { // Handle docs
279 if (isset($this->args['selected_docs']) && !empty($this->args['selected_docs'])) {
280 if ($this->args['selected_docs'][0] == 'all') {
281 // Fetch all terms
282 $terms = get_terms([
283 'taxonomy' => $taxonomies,
284 'hide_empty' => false,
285 ]);
286 } else {
287 // Fetch terms for specific post IDs
288 $terms = wp_get_object_terms($this->args['selected_docs'], $taxonomies);
289 }
290 }
291 } elseif (in_array($this->args['content'], ['knowledge_base', 'doc_category'])) {
292 // Handle both knowledge_base and doc_category cases
293 $terms_key = $this->args['content'] == 'doc_category' ? 'category_terms' : 'kb_terms';
294
295 if (isset($this->args[$terms_key]) && !empty($this->args[$terms_key])) {
296 $terms_arg = [
297 'taxonomy' => $taxonomies,
298 'hide_empty' => false,
299 ];
300
301 if ($this->args[$terms_key][0] !== 'all') {
302 $terms_arg['slug'] = $this->args[$terms_key];
303 }
304
305 $terms = get_terms($terms_arg);
306 }
307 }
308
309 // Include both parent and child terms for hierarchical structures
310 if (!empty($terms) && is_array($terms)) {
311 $additional_terms = [];
312
313 foreach ($terms as $term) {
314 // Get parent terms
315 if (!empty($term->parent)) {
316 $ancestors = get_ancestors($term->term_id, $term->taxonomy, 'taxonomy');
317 foreach ($ancestors as $ancestor_id) {
318 $parent = get_term($ancestor_id, $term->taxonomy);
319 if (!is_wp_error($parent)) {
320 $additional_terms[] = $parent;
321 }
322 }
323 }
324
325 // Get child terms
326 $children = get_term_children($term->term_id, $term->taxonomy);
327 if (!is_wp_error($children)) {
328 foreach ($children as $child_id) {
329 $child = get_term($child_id, $term->taxonomy);
330 if (!is_wp_error($child)) {
331 $additional_terms[] = $child;
332 }
333 }
334 }
335 }
336
337 if (!empty($additional_terms)) {
338 $terms = array_merge($terms, $additional_terms);
339 $terms = array_unique($terms, SORT_REGULAR);
340 }
341 }
342
343 // Sort terms if not empty
344 if (!empty($terms) && is_array($terms)) {
345 usort($terms, array($this, 'compare_terms_by_meta'));
346 }
347
348 return $terms;
349 }
350
351 /**
352 * Compare terms based on their associated term meta values.
353 *
354 * @param WP_Term $a The first term object.
355 * @param WP_Term $b The second term object.
356 * @return int Returns a negative value if $a is less than $b,
357 * a positive value if $a is greater than $b, or 0 if they are equal.
358 * Additionally, prioritize sorting terms by taxonomy order,
359 * with 'doc_category' terms appearing before other taxonomy terms.
360 */
361 public function compare_terms_by_meta( $a, $b ) {
362 // Define the order of taxonomies
363 $taxonomy_order = array(
364 'doc_category' => 0,
365 'knowledge_base' => 1,
366 'doc_tag' => 2,
367 );
368
369 // Get the taxonomy order for terms $a and $b
370 $order_a = isset( $taxonomy_order[ $a->taxonomy ] ) ? $taxonomy_order[ $a->taxonomy ] : PHP_INT_MAX;
371 $order_b = isset( $taxonomy_order[ $b->taxonomy ] ) ? $taxonomy_order[ $b->taxonomy ] : PHP_INT_MAX;
372
373 // If the taxonomies have different order, sort by order
374 if ( $order_a !== $order_b ) {
375 return $order_a - $order_b;
376 }
377
378 // If the taxonomies have the same order, sort by meta value
379 $taxonomy_order_meta = array(
380 'doc_category' => 'doc_category_order',
381 'knowledge_base' => 'kb_order'
382 );
383
384 if ( isset( $taxonomy_order_meta[ $a->taxonomy ] ) && isset( $taxonomy_order_meta[ $b->taxonomy ] ) ) {
385 $meta_a = intval( get_term_meta( $a->term_id, $taxonomy_order_meta[ $a->taxonomy ], true ) );
386 $meta_b = intval( get_term_meta( $b->term_id, $taxonomy_order_meta[ $b->taxonomy ], true ) );
387
388 return $meta_a - $meta_b;
389 }
390
391 return 0; // Default to no sorting if meta keys are not defined
392 }
393 }
394