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

395 lines 12.7 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 error_log('Error fetching terms for glossaries: ' . $terms->get_error_message());
261 return [];
262 }
263
264 // Include parent terms for hierarchical glossaries
265 $parent_terms = [];
266 foreach ($terms as $term) {
267 if (!empty($term->parent)) {
268 $parent = get_term($term->parent, 'glossaries');
269 if (!is_wp_error($parent)) {
270 $parent_terms[] = $parent;
271 }
272 }
273 }
274
275 if (!empty($parent_terms)) {
276 $terms = array_merge($terms, $parent_terms);
277 $terms = array_unique($terms, SORT_REGULAR);
278 }
279 } elseif ($this->args['content'] == 'docs') { // Handle docs
280 if (isset($this->args['selected_docs']) && !empty($this->args['selected_docs'])) {
281 if ($this->args['selected_docs'][0] == 'all') {
282 // Fetch all terms
283 $terms = get_terms([
284 'taxonomy' => $taxonomies,
285 'hide_empty' => false,
286 ]);
287 } else {
288 // Fetch terms for specific post IDs
289 $terms = wp_get_object_terms($this->args['selected_docs'], $taxonomies);
290 }
291 }
292 } elseif (in_array($this->args['content'], ['knowledge_base', 'doc_category'])) {
293 // Handle both knowledge_base and doc_category cases
294 $terms_key = $this->args['content'] == 'doc_category' ? 'category_terms' : 'kb_terms';
295
296 if (isset($this->args[$terms_key]) && !empty($this->args[$terms_key])) {
297 $terms_arg = [
298 'taxonomy' => $taxonomies,
299 'hide_empty' => false,
300 ];
301
302 if ($this->args[$terms_key][0] !== 'all') {
303 $terms_arg['slug'] = $this->args[$terms_key];
304 }
305
306 $terms = get_terms($terms_arg);
307 }
308 }
309
310 // Include both parent and child terms for hierarchical structures
311 if (!empty($terms) && is_array($terms)) {
312 $additional_terms = [];
313
314 foreach ($terms as $term) {
315 // Get parent terms
316 if (!empty($term->parent)) {
317 $ancestors = get_ancestors($term->term_id, $term->taxonomy, 'taxonomy');
318 foreach ($ancestors as $ancestor_id) {
319 $parent = get_term($ancestor_id, $term->taxonomy);
320 if (!is_wp_error($parent)) {
321 $additional_terms[] = $parent;
322 }
323 }
324 }
325
326 // Get child terms
327 $children = get_term_children($term->term_id, $term->taxonomy);
328 if (!is_wp_error($children)) {
329 foreach ($children as $child_id) {
330 $child = get_term($child_id, $term->taxonomy);
331 if (!is_wp_error($child)) {
332 $additional_terms[] = $child;
333 }
334 }
335 }
336 }
337
338 if (!empty($additional_terms)) {
339 $terms = array_merge($terms, $additional_terms);
340 $terms = array_unique($terms, SORT_REGULAR);
341 }
342 }
343
344 // Sort terms if not empty
345 if (!empty($terms) && is_array($terms)) {
346 usort($terms, array($this, 'compare_terms_by_meta'));
347 }
348
349 return $terms;
350 }
351
352 /**
353 * Compare terms based on their associated term meta values.
354 *
355 * @param WP_Term $a The first term object.
356 * @param WP_Term $b The second term object.
357 * @return int Returns a negative value if $a is less than $b,
358 * a positive value if $a is greater than $b, or 0 if they are equal.
359 * Additionally, prioritize sorting terms by taxonomy order,
360 * with 'doc_category' terms appearing before other taxonomy terms.
361 */
362 public function compare_terms_by_meta( $a, $b ) {
363 // Define the order of taxonomies
364 $taxonomy_order = array(
365 'doc_category' => 0,
366 'knowledge_base' => 1,
367 'doc_tag' => 2,
368 );
369
370 // Get the taxonomy order for terms $a and $b
371 $order_a = isset( $taxonomy_order[ $a->taxonomy ] ) ? $taxonomy_order[ $a->taxonomy ] : PHP_INT_MAX;
372 $order_b = isset( $taxonomy_order[ $b->taxonomy ] ) ? $taxonomy_order[ $b->taxonomy ] : PHP_INT_MAX;
373
374 // If the taxonomies have different order, sort by order
375 if ( $order_a !== $order_b ) {
376 return $order_a - $order_b;
377 }
378
379 // If the taxonomies have the same order, sort by meta value
380 $taxonomy_order_meta = array(
381 'doc_category' => 'doc_category_order',
382 'knowledge_base' => 'kb_order'
383 );
384
385 if ( isset( $taxonomy_order_meta[ $a->taxonomy ] ) && isset( $taxonomy_order_meta[ $b->taxonomy ] ) ) {
386 $meta_a = intval( get_term_meta( $a->term_id, $taxonomy_order_meta[ $a->taxonomy ], true ) );
387 $meta_b = intval( get_term_meta( $b->term_id, $taxonomy_order_meta[ $b->taxonomy ], true ) );
388
389 return $meta_a - $meta_b;
390 }
391
392 return 0; // Default to no sorting if meta keys are not defined
393 }
394 }
395