PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.4
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.4
1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 trunk 1.2.0 All 47 releases
fluent-cart / api / Taxonomy.php

Taxonomy.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.6.4, at api/Taxonomy.php

334 lines 10.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\Api;
4
5 use FluentCart\App\CPT\FluentProducts;
6 use FluentCart\App\Models\WpModels\Term;
7 use FluentCart\Framework\Support\Arr;
8 use FluentCart\Framework\Support\Collection;
9 use FluentCart\Framework\Support\Str;
10
11 class Taxonomy
12 {
13 public static function getTaxonomies($objectType = 'fluent-products', $publicOnly = true): array
14 {
15 $args = [
16 'object_type' => [$objectType]
17 ];
18
19 if ($publicOnly) {
20 $args['public'] = true;
21 }
22
23 return get_taxonomies($args);
24 }
25
26 public static function syncTaxonomyTermsToProduct(
27 $productId, string $taxonomy, array $terms
28 )
29 {
30 if (!is_taxonomy_hierarchical($taxonomy)) {
31 $terms = Term::query()->find($terms)->pluck('name')->toArray();
32 }
33
34 return wp_set_post_terms($productId, $terms, $taxonomy);
35 }
36
37 public static function deleteTaxonomyTermFromProduct(
38 $productId, string $taxonomy, int $term
39 )
40 {
41 return wp_remove_object_terms($productId, $term, $taxonomy);
42 }
43
44 public static function deleteAllTermRelationshipsFromProduct($productId, string $taxonomy)
45 {
46 return wp_delete_object_term_relationships($productId, $taxonomy);
47 }
48
49 public static function getFormattedTerms(
50 $taxonomy,
51 $hideEmpty = false,
52 $parents = null,
53 $valueKey = 'value',
54 $labelKey = 'label',
55 $prefilled = null
56 ): array
57 {
58 $terms = get_terms([
59 'taxonomy' => $taxonomy,
60 'hide_empty' => $hideEmpty,
61 ]);
62
63 if (is_wp_error($terms)) {
64 return [];
65 }
66
67
68 // Stores all terms with an empty children array.
69 $termMap = [];
70
71 foreach ($terms as $term) {
72
73 $termMap[$term->term_id] = [
74 $valueKey => (string)$term->term_id,
75 $labelKey => $term->name,
76 'parent' => (string)$term->parent,
77 'children' => []
78 ];
79 }
80
81 // Organize terms into a nested parent-child structure
82 // Iterates through $termMap and attaches each child term to its parent’s children array.
83 $formattedTerms = [];
84
85 foreach ($termMap as &$term) {
86 // If the term has a parent and the parent exists in termMap, add it as a child
87 if ($term['parent'] != "0" && isset($termMap[$term['parent']])) {
88 $termMap[$term['parent']]['children'][] = &$term;
89 } else {
90 // Otherwise, add it to the top-level array (root categories)
91 $formattedTerms[] = &$term;
92 }
93 }
94
95 // $parents narrows the response to the requested parent terms — each
96 // requested node is returned at the top level with its subtree attached.
97 // The parameter was accepted but never read: callers passing parent ids
98 // (products/fetch-term-by-parent) got the full unconstrained tree back.
99 // null keeps the full tree, which is what every other caller passes.
100 if (!empty($parents)) {
101 $requestedTerms = [];
102 foreach ((array) $parents as $parentTermId) {
103 $parentTermId = (int) $parentTermId;
104 if (isset($termMap[$parentTermId])) {
105 $requestedTerms[] = $termMap[$parentTermId];
106 }
107 }
108 $formattedTerms = $requestedTerms;
109 }
110
111 // Mark prefilled terms as selected
112 // Adds a selected key if the term ID is found in $prefilled.
113 if (!empty($prefilled)) {
114 foreach ($formattedTerms as &$term) {
115 // Check if the current term should be selected
116 if (isset($term['value'])) {
117 $term['selected'] = (is_array($prefilled) && in_array($term['value'], $prefilled)) || $term['value'] == $prefilled;
118 }
119
120 // If the term has children, apply the same logic recursively
121 if (!empty($term['children'])) {
122 foreach ($term['children'] as &$childTerm) {
123 // Check if the child term should be selected
124 if (isset($childTerm['value'])) {
125 $childTerm['selected'] = (is_array($prefilled) && in_array($childTerm['value'], $prefilled)) || $childTerm['value'] == $prefilled;
126 }
127 }
128 }
129 }
130
131 }
132
133 return $formattedTerms;
134 }
135
136 public static function getTermIdsFromTerms(array $terms): array
137 {
138 return Collection::make($terms)->pluck('term_id')->toArray();
139 }
140
141 public static function getTermIdsBySlugs($slugs, $taxonomy = 'product-categories'): array
142 {
143 if (is_string($slugs)) {
144 $slugs = array_map('trim', explode(',', $slugs));
145 }
146
147 $termIds = [];
148 foreach ($slugs as $slug) {
149 $slug = sanitize_text_field($slug);
150 if (empty($slug)) {
151 continue;
152 }
153 $term = get_term_by('slug', sanitize_title($slug), $taxonomy);
154 if (!$term || is_wp_error($term)) {
155 $term = get_term_by('name', $slug, $taxonomy);
156 }
157 if ($term && !is_wp_error($term)) {
158 $termIds[] = (int) $term->term_id;
159 }
160 }
161
162 return $termIds;
163 }
164
165 public static function addTaxonomyTerms(string $taxonomy, array $terms, array $args = [])
166 {
167 $taxonomies = static::getTaxonomies();
168 if (!Arr::has($taxonomies, $taxonomy)) {
169 return false;
170 }
171
172 $termIds = [];
173
174 foreach ($terms as $term) {
175 if (term_exists($term, $taxonomy)) {
176 $termIds[] = get_term_by('name', $term, $taxonomy)->term_id;
177 } else if (is_array($newTerm = wp_insert_term($term, $taxonomy, $args))) {
178 $termIds[] = $newTerm['term_id'];
179 }
180 }
181
182 return $termIds;
183 }
184
185 public static function getTaxonomyLabels($taxonomy, $keys = [])
186 {
187 $taxonomy_object = get_taxonomy($taxonomy);
188
189 if ($taxonomy_object) {
190 // Get all labels as an array
191 $all_labels = (array)get_taxonomy_labels($taxonomy_object);
192
193 $desired_keys = [
194 'all_items',
195 'add_new_item',
196 'edit_item',
197 'name',
198 'not_found',
199 'parent_item',
200 'search_items',
201 'update_item',
202 'view_item',
203 'singular_name',
204 'no_terms',
205 ];
206
207 $desired_keys = Arr::mergeMissingValues($desired_keys, $keys);
208
209 $collectionInstance = new Collection($all_labels);
210 $labels = $collectionInstance->only($desired_keys)->toArray();
211 } else {
212 $labels = $keys;
213 }
214
215 return $labels;
216 }
217
218
219 public static function fetchTaxonomies($data): ?array
220 {
221 $search = sanitize_text_field(Arr::get($data, 'search', ''));
222 $page = (int)sanitize_text_field(Arr::get($data, 'page', 1));
223 $per_page = (int)sanitize_text_field(Arr::get($data, 'per_page', 10));
224 $sort_by = sanitize_text_field(Arr::get($data, 'sort_by', 'name'));
225 $sort_type = sanitize_text_field(Arr::get($data, 'sort_type', 'DESC'));
226 $taxonomy = sanitize_text_field(Arr::get($data, 'taxonomy', 'product-categories'));
227
228 $offset = ($page - 1) * $per_page;
229
230 $total = (int)wp_count_terms(['taxonomy' => $taxonomy, 'hide_empty' => false]);
231
232 if (!empty($search)) {
233 $search_results = get_terms([
234 'taxonomy' => $taxonomy,
235 'hide_empty' => false,
236 'search' => $search,
237 'fields' => 'ids',
238 ]);
239
240 if (is_wp_error($search_results)) {
241 wp_send_json([
242 'message' => __('Failed to fetch search results.', 'fluent-cart'),
243 ], 500);
244 }
245
246 $total = count($search_results);
247 }
248
249 $labels = self::getTaxonomyLabels($taxonomy);
250
251 $terms = get_terms([
252 'taxonomy' => $taxonomy,
253 'hide_empty' => false,
254 'orderby' => $sort_by,
255 'order' => $sort_type,
256 'number' => $per_page,
257 'offset' => $offset,
258 'search' => $search
259 ]);
260
261 if (is_wp_error($terms)) {
262 return wp_send_json([
263 /* translators: %s - taxonomy name */
264 'message' => sprintf(__('Failed to fetch %s.', 'fluent-cart'), Str::lower($labels['name'])),
265 ], 500);
266 }
267
268 // Initialize an array to hold the terms by their IDs
269 $terms_by_id = [];
270 foreach ($terms as $term) {
271 $terms_by_id[$term->term_id] = [
272 'term_id' => $term->term_id,
273 'name' => $term->name,
274 'description' => $term->description,
275 'slug' => $term->slug,
276 'parent' => $term->parent,
277 'count' => $term->count,
278 'children' => [],
279 'url' => get_term_link($term->term_id),
280 ];
281 }
282
283 // Build the hierarchy
284 $hierarchy = [];
285 foreach ($terms_by_id as $term_id => &$term_data) {
286 // If the term has a parent and the parent exists in the array, add it to the parent's children.
287 if ($term_data['parent'] && isset($terms_by_id[$term_data['parent']])) {
288 $terms_by_id[$term_data['parent']]['children'][] = &$term_data;
289 } else {
290 // If the term has no parent, it is added as a top-level category.
291 $hierarchy[] = &$term_data;
292 }
293 }
294
295 // Calculate total pages
296 $last_page = ceil($total / $per_page);
297
298 // Calculate "from" and "to"
299 $from = ($total > 0) ? (($page - 1) * $per_page) + 1 : 0;
300 $to = min($page * $per_page, $total);
301
302 return [
303 "taxonomies" => [
304 "data" => $hierarchy,
305 "total" => $total,
306 "current_page" => $page,
307 "last_page" => $last_page,
308 "per_page" => $per_page,
309 "from" => $from,
310 "to" => $to,
311 "labels" => $labels,
312 ],
313 ];
314 }
315
316
317 public static function taxonomyWithTerms(): Collection
318 {
319 $taxonomies = Taxonomy::getTaxonomies();
320
321 return Collection::make($taxonomies)
322 ->map(function ($taxonomy) {
323 return [
324 'name' => $taxonomy,
325 'label' => Str::headline($taxonomy),
326 'parent' => 0,
327 'terms' => Taxonomy::getFormattedTerms($taxonomy, false, null, 'value', 'label'),
328 ];
329 });
330
331 }
332
333 }
334