$slug]); } return is_wp_error($term) ? 0 : (int) ($term['term_id'] ?? $term); } public function allWithStats(): array { $terms = get_terms([ 'taxonomy' => 'kb_product', 'hide_empty' => false, 'orderby' => 'name', 'order' => 'ASC', ]); if (is_wp_error($terms)) { return []; } $items = []; foreach ($terms as $term) { $pageIds = $this->pageIdsForProduct((int) $term->term_id); $versions = []; foreach ($pageIds as $pageId) { $pageVersions = wp_get_object_terms($pageId, 'kb_version'); if (is_wp_error($pageVersions)) { continue; } foreach ($pageVersions as $version) { $versions[$version->slug] = $version; } } uasort($versions, static fn ($a, $b): int => strnatcasecmp($b->name, $a->name)); $items[] = [ 'term' => $term, 'page_count' => count($pageIds), 'versions' => array_values($versions), 'meta' => $this->frontendMeta($term), ]; } return $items; } public function update(int $termId, string $name, string $slug, array $frontend = []): \WP_Term|\WP_Error { $name = trim($name); $slug = sanitize_title($slug ?: $name); if ('' === $name || '' === $slug) { return new \WP_Error('kb_product_invalid', __('Product name and slug are required.', 'kb-markdown-importer')); } $updated = wp_update_term($termId, 'kb_product', [ 'name' => $name, 'slug' => $slug, ]); if (is_wp_error($updated)) { return $updated; } foreach ($this->pageIdsForProduct($termId) as $pageId) { update_post_meta($pageId, '_kb_product_slug', $slug); } $groupName = sanitize_text_field((string) ($frontend['group_name'] ?? '')); $groupName = '' !== trim($groupName) ? $groupName : $name; $groupSlugInput = sanitize_title((string) ($frontend['group_slug'] ?? '')); $groupSlug = $groupSlugInput ?: sanitize_title($groupName); if ($groupSlugInput === $slug && 0 !== strcasecmp($groupName, $name)) { $groupSlug = sanitize_title($groupName); } $partLabel = sanitize_text_field((string) ($frontend['part_label'] ?? '')); $category = sanitize_text_field((string) ($frontend['category'] ?? '')); update_term_meta($termId, self::META_GROUP_NAME, $groupName ?: $name); update_term_meta($termId, self::META_GROUP_SLUG, $groupSlug ?: $slug); update_term_meta($termId, self::META_PART_LABEL, $partLabel); update_term_meta($termId, self::META_CATEGORY, $category); $term = get_term((int) $updated['term_id'], 'kb_product'); return $term instanceof \WP_Term ? $term : new \WP_Error('kb_product_missing', __('Product could not be loaded after update.', 'kb-markdown-importer')); } public function trashProductPages(int $termId): int { $count = 0; foreach ($this->pageIdsForProduct($termId, ['publish', 'draft', 'private', 'pending', 'future']) as $pageId) { if (wp_trash_post($pageId)) { ++$count; } } return $count; } public function deleteProduct(int $termId, bool $trashPages): true|\WP_Error { if ($trashPages) { $this->trashProductPages($termId); } $deleted = wp_delete_term($termId, 'kb_product'); if (is_wp_error($deleted)) { return $deleted; } return true; } public function frontendMeta(\WP_Term $term): array { $storedGroupName = trim((string) get_term_meta($term->term_id, self::META_GROUP_NAME, true)); $storedGroupSlug = sanitize_title((string) get_term_meta($term->term_id, self::META_GROUP_SLUG, true)); $groupName = '' !== $storedGroupName ? $storedGroupName : $term->name; $groupSlug = '' !== $storedGroupSlug ? $storedGroupSlug : ('' !== $storedGroupName ? sanitize_title($groupName) : $term->slug); $partLabel = trim((string) get_term_meta($term->term_id, self::META_PART_LABEL, true)); $category = trim((string) get_term_meta($term->term_id, self::META_CATEGORY, true)); if ('' !== $storedGroupName && $groupSlug === $term->slug && 0 !== strcasecmp($groupName, $term->name)) { $groupSlug = sanitize_title($groupName); } return [ 'group_name' => $groupName, 'group_slug' => '' !== $groupSlug ? $groupSlug : $term->slug, 'part_label' => $partLabel, 'category' => $category, ]; } private function pageIdsForProduct(int $termId, array $postStatus = ['publish']): array { $query = new \WP_Query([ 'post_type' => 'kb_doc_page', 'post_status' => $postStatus, 'posts_per_page' => -1, 'fields' => 'ids', 'tax_query' => [ ['taxonomy' => 'kb_product', 'field' => 'term_id', 'terms' => $termId], ], ]); return array_map('intval', $query->posts); } }