| @@ -161,8 +161,65 @@ | ||
| 161 | 161 | |
| 162 | 162 | return $termIds; |
| 163 | 163 | } |
| 164 | 164 | |
| 165 | + /** | |
| 166 | + * Parse a shortcode taxonomy attribute: "product-tags:1,2|product-brands:67". | |
| 167 | + * | |
| 168 | + * Returns [taxonomy => term ids]. A taxonomy is accepted only when it is | |
| 169 | + * registered on products (the same list the AJAX pager re-parses), and a | |
| 170 | + * term only when it belongs to that taxonomy, because the product query | |
| 171 | + * matches term ids without checking their taxonomy. A segment that resolves | |
| 172 | + * to no term is kept as an empty list so the caller can refuse to widen it. | |
| 173 | + */ | |
| 174 | + public static function parseShortcodeTaxonomies(string $raw): array | |
| 175 | + { | |
| 176 | + $taxonomies = static::getTaxonomies(); | |
| 177 | + | |
| 178 | + // Group the raw values first so a taxonomy repeated across segments | |
| 179 | + // still costs a single query. | |
| 180 | + $rawValues = []; | |
| 181 | + foreach (explode('|', $raw) as $segment) { | |
| 182 | + $parts = explode(':', $segment, 2); | |
| 183 | + $taxonomy = sanitize_key(trim($parts[0])); | |
| 184 | + if ($taxonomy === '') { | |
| 185 | + continue; | |
| 186 | + } | |
| 187 | + $rawValues[$taxonomy][] = isset($parts[1]) ? $parts[1] : ''; | |
| 188 | + } | |
| 189 | + | |
| 190 | + $parsed = []; | |
| 191 | + foreach ($rawValues as $taxonomy => $values) { | |
| 192 | + $parsed[$taxonomy] = isset($taxonomies[$taxonomy]) | |
| 193 | + ? static::resolveTermIds(implode(',', $values), $taxonomy) | |
| 194 | + : []; | |
| 195 | + } | |
| 196 | + | |
| 197 | + return $parsed; | |
| 198 | + } | |
| 199 | + | |
| 200 | + private static function resolveTermIds(string $values, string $taxonomy): array | |
| 201 | + { | |
| 202 | + $ids = array_values(array_unique(array_map('intval', array_filter( | |
| 203 | + array_map('trim', explode(',', $values)), | |
| 204 | + 'ctype_digit' | |
| 205 | + )))); | |
| 206 | + | |
| 207 | + if (!$ids) { | |
| 208 | + return []; | |
| 209 | + } | |
| 210 | + | |
| 211 | + // One query per taxonomy; `include` only returns terms of $taxonomy. | |
| 212 | + $termIds = get_terms([ | |
| 213 | + 'taxonomy' => $taxonomy, | |
| 214 | + 'include' => $ids, | |
| 215 | + 'fields' => 'ids', | |
| 216 | + 'hide_empty' => false, | |
| 217 | + ]); | |
| 218 | + | |
| 219 | + return is_wp_error($termIds) ? [] : array_map('intval', $termIds); | |
| 220 | + } | |
| 221 | + | |
| 165 | 222 | public static function addTaxonomyTerms(string $taxonomy, array $terms, array $args = []) |
| 166 | 223 | { |
| 167 | 224 | $taxonomies = static::getTaxonomies(); |
| 168 | 225 | if (!Arr::has($taxonomies, $taxonomy)) { |