PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.9.3
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.9.3
4.9.3 4.9.2 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 All 201 releases
← All changes | includes/Admin/Importer/Parsers/CSV_Parser.php +256 -227 3.3.4 → 4.9.3 View file →
@@ -1,9 +1,8 @@
1 1 <?php
2 +
2 3 namespace WPDeveloper\BetterDocs\Admin\Importer\Parsers;
3 4
4 -use WP_Error;
5 -
6 5 if ( ! defined( 'ABSPATH' ) ) {
7 6 exit; // Exit if accessed directly.
8 7 }
9 8
@@ -22,282 +21,312 @@
22 21 * WXR Parser that uses regular expressions. Fallback for installs without an XML parser.
23 22 */
24 23 class CSV_Parser {
25 24
26 - /**
27 - * Sort function for sorting CSV file data to keep Term and Author on top.
28 - *
29 - * @param array $a The first element to compare.
30 - * @param array $b The second element to compare.
31 - *
32 - * @return int Returns an integer less than, equal to, or greater than zero if the first
33 - * argument is considered to be respectively less than, equal to, or greater
34 - * than the second.
35 - */
36 - public function csvSort($a, $b) {
37 - $order = array('Term', 'Author', 'Docs');
25 + /**
26 + * Sort function for sorting CSV file data to keep Term and Author on top.
27 + *
28 + * @param array $a The first element to compare.
29 + * @param array $b The second element to compare.
30 + *
31 + * @return int Returns an integer less than, equal to, or greater than zero if the first
32 + * argument is considered to be respectively less than, equal to, or greater
33 + * than the second.
34 + */
35 + public function csvSort( $a, $b ) {
36 + $order = [ 'Term', 'Author', 'Docs', 'FAQ' ];
38 37
39 - $keyA = array_search($a[0], $order);
40 - $keyB = array_search($b[0], $order);
38 + $keyA = array_search( $a[0], $order );
39 + $keyB = array_search( $b[0], $order );
41 40
42 - return $keyA - $keyB;
43 - }
41 + return $keyA - $keyB;
42 + }
44 43
45 - public function parse( $file ) {
46 - $data = [];
44 + public function parse( $file ) {
45 + $data = [
46 + 'terms' => [],
47 + 'posts' => [],
48 + 'authors' => []
49 + ];
47 50
48 - $csv_data = [];
49 - if (($handle = fopen($file, "r")) !== false) {
50 - while (($data = fgetcsv($handle, 1000, ",")) !== false) {
51 - $csv_data[] = $data;
52 - }
53 - fclose($handle);
54 - }
51 + $csv_data = [];
55 52
56 - // Remove the CSV headers
57 - $headers = array_shift($csv_data);
53 + // Read and normalize file content
54 + $fileContent = file_get_contents( $file );
55 + if ( $fileContent === false ) {
56 + return $data; // Return empty data if file reading fails
57 + }
58 58
59 - // return data from sample csv file
60 - if ( $headers['0'] == 'Docs Title' ) {
59 + $fileContent = str_replace( [ "\r\n", "\r" ], "\n", $fileContent );
61 60
62 - // update Docs Slug to post_name to check if post exists
63 - $replacementMap = array(
64 - 'Docs Slug' => 'post_name'
65 - );
61 + // Parse through a stream so fgetcsv() correctly assembles records whose
62 + // quoted fields span multiple lines (e.g. multi-line doc content). A plain
63 + // explode( "\n" ) + str_getcsv() per line splits such records apart, producing
64 + // rows whose column count no longer matches the headers — which makes the
65 + // array_combine() calls below fatal (500 error on Sample Docs import).
66 + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen -- in-memory stream, no filesystem access; required for multi-line CSV records.
67 + $handle = fopen( 'php://temp', 'r+' );
68 + if ( $handle !== false ) {
69 + fwrite( $handle, $fileContent );
70 + rewind( $handle );
71 + while ( ( $row = fgetcsv( $handle, 0, ',' ) ) !== false ) {
72 + $csv_data[] = $row;
73 + }
74 + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- closing in-memory stream; WP_Filesystem does not apply.
75 + fclose( $handle );
76 + }
66 77
67 - $headers = array_map(function ($item) use ($replacementMap) {
68 - return isset($replacementMap[$item]) ? $replacementMap[$item] : $item;
69 - }, $headers);
78 + $headers = array_shift( $csv_data );
70 79
71 - $data['type'] = 'sample/csv';
80 + // Bail out cleanly on an empty/malformed file instead of fataling below.
81 + if ( ! is_array( $headers ) || empty( $headers ) ) {
82 + return $data;
83 + }
72 84
73 - foreach ($csv_data as $row) {
74 - $data['posts'][] = array_combine($headers, $row);
75 - }
85 + // Process specific headers for 'Docs Title'
86 + if ( $headers[0] == 'Docs Title' ) {
87 + $replacementMap = [ 'Docs Slug' => 'post_name' ];
76 88
77 - return $data;
78 - }
89 + $headers = array_map(
90 + function ( $item ) use ( $replacementMap ) {
91 + return $replacementMap[ $item ] ?? $item;
92 + },
93 + $headers
94 + );
79 95
80 - usort($csv_data, [$this, 'csvSort']);
96 + $data['type'] = 'sample/csv';
81 97
82 - // Process CSV data and insert into WordPress
83 - foreach ($csv_data as $row) {
98 + foreach ( $csv_data as $row ) {
99 + $row = array_pad( $row, count( $headers ), '' );
100 + $data['posts'][] = array_combine( $headers, $row );
101 + }
84 102
85 - $type = $row[0];
103 + return $data;
104 + }
86 105
87 - if ($type === 'Term') {
88 - // Extract the first 12 elements from the headers
89 - $term_headers = array_slice($headers, 28, 11);
106 + usort( $csv_data, [ $this, 'csvSort' ] );
90 107
91 - // Extract the first 12 elements from the row
92 - $term_row = array_slice($row, 28, 11);
93 - $term_row = array_pad($term_row, count($term_headers), '');
108 + // The combined CSV packs three blocks side by side: Docs (from index 1),
109 + // then Author, then Term. CSVs exported after the WPML language columns
110 + // were added widen the Docs block by 2 columns (Docs language code +
111 + // translation source slug), shifting the Author/Term offsets. Locate
112 + // each block by its header name rather than a fixed position, so the
113 + // layout is detected wherever the columns land (and adding a column to
114 + // one block can't silently corrupt the others).
115 + $has_wpml_columns = in_array( 'Docs language code', $headers, true );
94 116
95 - if (count($term_headers) !== count($term_row)) {
96 - return $data;
97 - }
117 + $author_offset = array_search( 'Author id', $headers, true );
118 + $term_offset = array_search( 'Taxonomy', $headers, true );
98 119
99 - $term_data = array_combine($term_headers, $term_row);
120 + // Fall back to the historical fixed offsets if a block header is missing
121 + // (malformed file) so such files still parse exactly as they did before.
122 + if ( $author_offset === false ) {
123 + $author_offset = $has_wpml_columns ? 24 : 22;
124 + }
125 + if ( $term_offset === false ) {
126 + $term_offset = $has_wpml_columns ? 30 : 28;
127 + }
100 128
129 + // The Docs block runs from index 1 up to the start of the Author block.
130 + $post_block_len = $author_offset - 1;
101 131
102 - $taxonomy = $term_data['Taxonomy'];
103 - $term_id = $term_data['Term ID'];
104 - $name = $term_data['Term name'];
105 - $slug = $term_data['Term slug'];
106 - $term_group = $term_data['Term group'];
107 - $description = $term_data['Term description'];
108 - $parent = $term_data['Term parent'];
109 - $_docs_order = $term_data['Assigned Docs'];
132 + foreach ( $csv_data as $row ) {
133 + $type = $row[0];
110 134
111 - $doc_category_knowledge_base = $term_data['Assigned KBs'];
112 - $doc_category_knowledge_base = explode(",", $doc_category_knowledge_base);
113 - $doc_category_knowledge_base = rest_sanitize_array( $doc_category_knowledge_base );
135 + if ( $type === 'glossaries' ) {
136 + $term_headers = array_slice( $headers, 0, 7 );
137 + $term_row = array_slice( $row, 0, 7 );
138 + $term_row = array_pad( $term_row, count( $term_headers ), '' );
114 139
115 - $doc_category_order = $term_data['Doc Category order'];
116 - $kb_order = $term_data['KB order'];
140 + if ( count( $term_headers ) !== count( $term_row ) ) {
141 + return $data;
142 + }
117 143
144 + $term_data = array_combine( $term_headers, $term_row );
118 145
146 + $term_args = [
147 + 'term_taxonomy' => $term_data['Taxonomy'],
148 + 'term_id' => $term_data['Term ID'],
149 + 'term_name' => $term_data['Term name'],
150 + 'slug' => $term_data['Term slug'],
151 + 'term_group' => $term_data['Term group']
152 + ];
153 +
154 + $term_args['termmeta'][] = [
155 + 'key' => 'glossary_term_description',
156 + 'value' => $term_data['Term description']
157 + ];
158 +
159 + $data['terms'][] = $term_args;
160 + } elseif ( $type === 'Term' ) {
161 + $term_headers = array_slice( $headers, $term_offset, 11 );
162 + $term_row = array_slice( $row, $term_offset, 11 );
163 + $term_row = array_pad( $term_row, count( $term_headers ), '' );
164 +
165 + $term_data = array_combine( $term_headers, $term_row );
166 +
167 + $taxonomy = $term_data['Taxonomy'];
119 168 $term_args = [
120 - 'term_id' => $term_id,
169 + 'term_id' => sanitize_text_field( $term_data['Term ID'] ),
121 170 'term_taxonomy' => $taxonomy,
122 - 'slug' => $slug,
123 - 'parent' => $parent,
124 - 'term_name' => $name,
125 - 'description' => $description,
126 - 'term_group' => $term_group,
127 - 'termmeta' => [],
171 + 'slug' => sanitize_text_field( $term_data['Term slug'] ),
172 + 'term_parent' => sanitize_text_field( $term_data['Term parent'] ),
173 + 'term_name' => sanitize_text_field( $term_data['Term name'] ),
174 + 'description' => sanitize_text_field( $term_data['Term description'] ),
175 + 'term_group' => sanitize_text_field( $term_data['Term group'] ),
176 + 'termmeta' => []
128 177 ];
129 178
130 - switch ($taxonomy) {
131 - case 'doc_category':
132 - if ($_docs_order) {
133 - $term_args['termmeta'][] = [
134 - 'key' => '_docs_order',
135 - 'value' => $_docs_order,
136 - ];
137 - }
179 + if ( $taxonomy === 'doc_category' ) {
180 + if ( ! empty( $term_data['Assigned Docs'] ) ) {
181 + $term_args['termmeta'][] = [
182 + 'key' => '_docs_order',
183 + 'value' => sanitize_text_field( $term_data['Assigned Docs'] )
184 + ];
185 + }
138 186
139 - if ($doc_category_knowledge_base) {
140 - $term_args['termmeta'][] = [
141 - 'key' => 'doc_category_knowledge_base',
142 - 'value' => $doc_category_knowledge_base,
143 - ];
144 - }
187 + if ( ! empty( $term_data['Assigned KBs'] ) ) {
188 + $doc_category_knowledge_base = explode( ",", sanitize_text_field( $term_data['Assigned KBs'] ) );
189 + $term_args['termmeta'][] = [
190 + 'key' => 'doc_category_knowledge_base',
191 + 'value' => rest_sanitize_array( $doc_category_knowledge_base )
192 + ];
193 + }
145 194
146 - if ($doc_category_order) {
147 - $term_args['termmeta'][] = [
148 - 'key' => 'doc_category_order',
149 - 'value' => $doc_category_order,
150 - ];
151 - }
152 - break;
153 -
154 - case 'knowledge_base':
155 - if ($kb_order) {
156 - $term_args['termmeta'][] = [
157 - 'key' => 'kb_order',
158 - 'value' => $kb_order,
159 - ];
160 - }
161 - break;
195 + if ( ! empty( $term_data['Doc Category order'] ) ) {
196 + $term_args['termmeta'][] = [
197 + 'key' => 'doc_category_order',
198 + 'value' => sanitize_text_field( $term_data['Doc Category order'] )
199 + ];
200 + }
201 + } else if ( $taxonomy === 'knowledge_base' && ! empty( $term_data['KB order'] ) ) {
202 + $term_args['termmeta'][] = [
203 + 'key' => 'kb_order',
204 + 'value' => $term_data['KB order']
205 + ];
162 206 }
163 207
164 - $data['terms'][] = $term_args;
208 + $data['terms'][] = $term_args;
209 + } elseif ( $type === 'Author' ) {
210 + $author_headers = array_slice( $headers, $author_offset, 6 );
211 + $author_row = array_slice( $row, $author_offset, 6 );
212 + $author_row = array_pad( $author_row, count( $author_headers ), '' );
165 213
166 - } elseif ($type === 'Author') {
167 - // Extract the first 12 elements from the headers
168 - $author_headers = array_slice($headers, 22, 6);
214 + $author_data = array_combine( $author_headers, $author_row );
169 215
170 - // Extract the first 12 elements from the row
171 - $author_row = array_slice($row, 22, 6);
172 - $author_row = array_pad($author_row, count($author_headers), '');
216 + $data['authors'][$author_data['Author login']] = [
217 + 'author_id' => sanitize_text_field( $author_data['Author id'] ),
218 + 'author_login' => sanitize_text_field( $author_data['Author login'] ),
219 + 'author_email' => sanitize_text_field( $author_data['Author email'] ),
220 + 'author_display_name' => sanitize_text_field( $author_data['Author display name'] ),
221 + 'author_first_name' => sanitize_text_field( $author_data['Author first name'] ),
222 + 'author_last_name' => sanitize_text_field( $author_data['Author last name'] )
223 + ];
224 + } else if ( $type === 'Docs' || $type === 'FAQ' ) {
225 + // Keep FAQ import (HEAD) and use the dynamic post-block length
226 + // from the WPML branch so the variable WPML language columns are
227 + // handled instead of a hardcoded count.
228 + $post_headers = array_slice( $headers, 1, $post_block_len );
229 + $post_row = array_slice( $row, 1, $post_block_len );
230 + $post_row = array_pad( $post_row, count( $post_headers ), '' );
173 231
174 - $author_data = array_combine($author_headers, $author_row);
232 + $post_data = array_combine( $post_headers, $post_row );
175 233
176 - $author_id = $author_data['Author id'];
177 - $author_login = $author_data['Author login'];
178 - $author_email = $author_data['Author email'];
179 - $author_display_name = $author_data['Author display name'];
180 - $author_first_name = $author_data['Author first name'];
181 - $author_last_name = $author_data['Author last name'];
182 -
183 - $author_args = [
184 - 'author_id' => $author_id,
185 - 'author_login' => $author_login,
186 - 'author_email' => $author_email,
187 - 'author_display_name' => $author_display_name,
188 - 'author_first_name' => $author_first_name,
189 - 'author_last_name' => $author_last_name
234 + $post_args = [
235 + 'post_id' => sanitize_text_field( $post_data['Docs ID'] ) ?? '',
236 + 'post_type' => $type === 'FAQ' ? 'betterdocs_faq' : 'docs',
237 + 'post_author' => sanitize_text_field( $post_data['Docs author'] ) ?? '',
238 + 'post_content' => sanitize_text_field( $post_data['Docs content'] ) ?? '',
239 + 'post_title' => sanitize_text_field( $post_data['Docs title'] ) ?? '',
240 + 'post_name' => sanitize_text_field( $post_data['Docs slug'] ) ?? '',
241 + 'post_excerpt' => sanitize_text_field( $post_data['Docs excerpt'] ) ?? '',
242 + 'status' => sanitize_text_field( $post_data['Docs status'] ) ?? 'publish',
243 + 'post_password' => sanitize_text_field( $post_data['Docs password'] ) ?? '',
244 + 'post_parent' => sanitize_text_field( $post_data['Docs parent'] ) ?? '',
245 + 'menu_order' => sanitize_text_field( $post_data['Docs menu order'] ) ?? '',
246 + 'post_date' => sanitize_text_field( $post_data['Docs date'] ) ?? '',
247 + 'post_date_gmt' => sanitize_text_field( $post_data['Docs date gmt'] ) ?? '',
248 + 'post_modified' => sanitize_text_field( $post_data['Docs modified date'] ) ?? '',
249 + 'post_modified_gmt' => sanitize_text_field( $post_data['Docs modified date gmt'] ) ?? '',
250 + 'terms' => [],
251 + 'postmeta' => []
190 252 ];
191 253
192 - $data['authors'][$author_login] = $author_args;
193 -
194 - } elseif ($type === 'Docs') {
195 - // Extract elements 18-36 from the headers
196 - $post_headers = array_slice($headers, 1, 21);
197 -
198 - // Extract elements 18-36 from the row
199 - $post_row = array_slice($row, 1, 21);
200 -
201 - // Fill up the remaining elements with empty values
202 - $post_row = array_pad($post_row, count($post_headers), '');
203 -
204 - // Ensure data has at least the required elements
205 - if (count($post_headers) !== count($post_row)) {
206 - return $data;
254 + if ( isset( $post_data['Doc Categories'] ) && $data['terms'] ) {
255 + $post_args['terms'] = array_merge(
256 + $this->searchTermsByIds( $data['terms'], sanitize_text_field( $post_data['Doc Categories'] ) ),
257 + $this->searchTermsByIds( $data['terms'], sanitize_text_field( $post_data['Doc Tags'] ) ),
258 + $this->searchTermsByIds( $data['terms'], sanitize_text_field( $post_data['Knowledge Bases'] ) )
259 + );
207 260 }
208 261
209 - $post_data = array_combine($post_headers, $post_row);
210 -
211 - $post_args = array(
212 - 'post_id' => isset($post_data['Docs ID']) ? $post_data['Docs ID'] : '',
213 - 'post_type' => 'docs',
214 - 'post_author' => isset($post_data['Docs author']) ? $post_data['Docs author'] : '',
215 - 'post_content' => isset($post_data['Docs content']) ? $post_data['Docs content'] : '',
216 - 'post_title' => isset($post_data['Docs title']) ? $post_data['Docs title'] : '',
217 - 'post_name' => isset($post_data['Docs slug']) ? $post_data['Docs slug'] : '',
218 - 'post_excerpt' => isset($post_data['Docs excerpt']) ? $post_data['Docs excerpt'] : '',
219 - 'status' => isset($post_data['Docs status']) ? $post_data['Docs status'] : 'publish',
220 - 'post_password' => isset($post_data['Docs password']) ? $post_data['Docs password'] : '',
221 - 'post_parent' => isset($post_data['Docs parent']) ? $post_data['Docs parent'] : '',
222 - 'menu_order' => isset($post_data['Docs menu order']) ? $post_data['Docs menu order'] : '',
223 - 'post_date' => isset($post_data['Docs date']) ? $post_data['Docs date'] : '',
224 - 'post_date_gmt' => isset($post_data['Docs date gmt']) ? $post_data['Docs date gmt'] : '',
225 - 'post_modified' => isset($post_data['Docs modified date']) ? $post_data['Docs modified date'] : '',
226 - 'post_modified_gmt' => isset($post_data['Docs modified date gmt']) ? $post_data['Docs modified date gmt'] : '',
227 - 'terms' => [],
228 - 'postmeta' => [],
229 - );
230 -
231 -
232 - // Check if 'Doc Categories' is set and has data
233 - if (isset($post_data['Doc Categories']) && $data['terms']) {
234 - $termsDocCategories = $this->searchTermsByIds($data['terms'], $post_data['Doc Categories']);
262 + if ( $has_wpml_columns ) {
263 + if ( ! empty( $post_data['Docs language code'] ) ) {
264 + $post_args['postmeta'][] = [
265 + 'key' => '_betterdocs_wpml_lang',
266 + 'value' => sanitize_text_field( $post_data['Docs language code'] ),
267 + ];
268 + }
269 + if ( ! empty( $post_data['Docs translation source slug'] ) ) {
270 + $post_args['postmeta'][] = [
271 + 'key' => '_betterdocs_wpml_source_slug',
272 + 'value' => sanitize_text_field( $post_data['Docs translation source slug'] ),
273 + ];
274 + }
235 275 }
236 276
237 - // Check if 'Doc Tags' is set and has data
238 - if (isset($post_data['Doc Tags']) && $data['terms']) {
239 - $termsDocTags = $this->searchTermsByIds($data['terms'], $post_data['Doc Tags']);
240 - }
277 + $data['posts'][] = $post_args;
241 278
242 - // Check if 'Knowledge Bases' is set and has data
243 - if (isset($post_data['Knowledge Bases']) && $data['terms']) {
244 - $termsKnowledgeBases = $this->searchTermsByIds($data['terms'], $post_data['Knowledge Bases']);
245 - }
246 -
247 - // Combine the results if needed
248 - $combinedTerms = array_merge($termsDocCategories ?? [], $termsDocTags ?? [], $termsKnowledgeBases ?? []);
249 -
250 - $post_args['terms'] = $combinedTerms;
251 -
252 - $data['posts'][] = $post_args;
253 - if ( isset( $post_data['Docs attachement url'] ) && $post_data['Docs attachement url'] !== '' ) {
279 + if ( ! empty( $post_data['Docs attachement url'] ) ) {
254 280 $attachment_args = [
255 - 'post_type' => 'attachment',
256 - 'post_author' => isset($post_data['Docs author']) ? $post_data['Docs author'] : '',
257 - 'post_id' => isset($post_data['Docs attachement ID']) ? $post_data['Docs attachement ID'] : '',
258 - 'status' => 'inherit',
281 + 'post_type' => 'attachment',
282 + 'post_author' => sanitize_text_field( $post_data['Docs author'] ) ?? '',
283 + 'post_id' => sanitize_text_field( $post_data['Docs attachement ID'] ) ?? '',
284 + 'status' => 'inherit',
259 285 'post_content' => '',
260 286 'post_excerpt' => '',
261 - 'guid' => '',
262 - 'post_title' => pathinfo($post_data['Docs attachement url'], PATHINFO_FILENAME),
263 - 'post_name' => pathinfo($post_data['Docs attachement url'], PATHINFO_FILENAME),
264 - 'post_parent' => isset($post_data['Docs ID']) ? $post_data['Docs ID'] : '',
265 - 'attachment_url' => $post_data['Docs attachement url']
287 + 'guid' => '',
288 + 'post_title' => pathinfo( sanitize_text_field( $post_data['Docs attachement url'] ), PATHINFO_FILENAME ),
289 + 'post_name' => pathinfo( sanitize_text_field( $post_data['Docs attachement url'] ), PATHINFO_FILENAME ),
290 + 'post_parent' => sanitize_text_field( $post_data['Docs ID'] ) ?? '',
291 + 'attachment_url' => sanitize_text_field( $post_data['Docs attachement url'] )
266 292 ];
267 - $data['posts'][] = $attachment_args;
268 - }
269 - }
270 - }
271 - error_log(print_r($data, 1));
272 - return $data;
273 - }
274 293
275 - public function searchTermsByIds($terms, $termIds) {
276 - // Convert the comma-separated term IDs to an array
277 - $termIdsArray = explode(',', $termIds);
294 + $data['posts'][] = $attachment_args;
295 + }
296 + }
297 + }
278 298
279 - // Initialize the result array
280 - $result = [];
299 + return $data;
300 + }
281 301
282 - // Iterate through each term_id in the array
283 - foreach ($termIdsArray as $termId) {
284 - // Find the corresponding term in the terms array
285 - $foundTerm = array_filter($terms, function ($term) use ($termId) {
286 - return $term['term_id'] == $termId;
287 - });
302 + public function searchTermsByIds( $terms, $termIds ) {
303 + // Convert the comma-separated term IDs to an array
304 + $termIdsArray = explode( ',', $termIds );
288 305
289 - // If the term is found, add it to the result array
290 - if (!empty($foundTerm)) {
291 - $foundTerm = reset($foundTerm);
292 - $result[] = [
293 - 'name' => $foundTerm['term_name'],
294 - 'slug' => $foundTerm['slug'],
295 - 'domain' => $foundTerm['term_taxonomy'],
296 - ];
297 - }
298 - }
306 + // Initialize the result array
307 + $result = [];
299 308
300 - return $result;
301 - }
309 + // Iterate through each term_id in the array
310 + foreach ( $termIdsArray as $termId ) {
311 + // Find the corresponding term in the terms array
312 + $foundTerm = array_filter(
313 + $terms,
314 + function ( $term ) use ( $termId ) {
315 + return $term['term_id'] == $termId;
316 + }
317 + );
318 +
319 + // If the term is found, add it to the result array
320 + if ( ! empty( $foundTerm ) ) {
321 + $foundTerm = reset( $foundTerm );
322 + $result[] = [
323 + 'name' => $foundTerm['term_name'],
324 + 'slug' => $foundTerm['slug'],
325 + 'domain' => $foundTerm['term_taxonomy']
326 + ];
327 + }
328 + }
329 +
330 + return $result;
331 + }
302 332 }
303 -?>