id = sanitize_key($id); $this->taxonomy = jvbCheckBase($taxonomy); $this->name = jvbNoBase($taxonomy); $registrar = Registrar::getInstance($this->name); if ($registrar) { $this->registrar = $registrar; } $this->title = $registrar->getPlural(); $this->base = $config['base']??''; $this->config = wp_parse_args($config, [ 'types' => false, // for feed block implementation 'max' => 0, // 0 = unlimited 'search' => true, 'label' => $this->name, 'icon' => false, 'autocomplete' => false, 'createNew' => false, 'required' => false, 'hidden' => false, 'base' => '', 'name' => $this->taxonomy, 'update' => true, // Whether to update on close ]); $this->plural = $registrar->getPlural(); $this->singular = $registrar->getSingular(); } /** * Get the full path for a term (for hierarchical taxonomies) * * @param WP_Term $term The term object * @param bool $returnArray if true, returns the array. If false, a string of terms separated by ' → ' * @return string|array An array of terms or the full term path */ public static function getTermPath(WP_Term $term, bool $returnArray = false): string|array { if (!is_taxonomy_hierarchical($term->taxonomy)) { return html_entity_decode($term->name); } $path = []; $currentTerm = $term; while ($currentTerm) { array_unshift($path, html_entity_decode($currentTerm->name)); if ($currentTerm->parent) { $currentTerm = get_term($currentTerm->parent); if (is_wp_error($currentTerm)) { break; } } else { break; } } return ($returnArray) ? $path : implode(' → ', $path); } /** * Get the single modal HTML structure */ public static function outputSelectorModal(): string { ob_start(); ?>
config) && $this->config['output'] === 'minimal') { return $this->renderTaxonomyToggle($selected, $extra); } // Build data attributes $dataAttrs = $this->buildDataAttributes($selected); $hasAutocomplete = ($this->config['autocomplete']) ? ' data-autocomplete' : ''; // Hidden attribute $hidden = $this->config['hidden'] ? ' hidden' : ''; ob_start(); ?>
>
renderSelectedTerm($termId); endforeach; $selectedItems = ob_get_clean(); endif; ?>
%s%s', $this->registrar->getIcon(), $this->name, $this->singular, $this->plural, $this->buildDataAttributes([]), $this->singular, jvbIcon($this->registrar->getIcon()), $this->singular ); } /** * Build data attributes string for the toggle button */ private function buildDataAttributes(array $selected): string { $attrs = []; // Update behavior if (!$this->config['update']) { $attrs[] = 'data-update="false"'; } // Max selection if ($this->config['max'] > 0) { $attrs[] = 'data-max="' . esc_attr($this->config['max']) . '"'; } // Search capability if ($this->config['search']) { $attrs[] = 'data-search'; } // Create new capability if ($this->config['createNew']) { $attrs[] = 'data-creatable'; } // Required if ($this->config['required']) { $attrs[] = 'data-required'; } // Post types filter (for feed blocks) if ($this->config['types'] && is_array($this->config['types'])) { $attrs[] = 'data-for="' . esc_attr(implode(',', $this->config['types'])) . '"'; } // Selected items if (!empty($selected)) { $attrs[] = 'data-selected="' . esc_attr(implode(',', $selected)) . '"'; } return implode(' ', $attrs); } /** * Render a single selected term */ private function renderSelectedTerm(int $termId): void { $term = get_term($termId, $this->taxonomy); if (!$term || is_wp_error($term)) { return; } $termPath = self::getTermPath($term); ?>