177 lines
5.9 KiB
PHP
177 lines
5.9 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace KbMarkdownImporter\Repository;
|
|
|
|
final class ProductRepository
|
|
{
|
|
public const META_GROUP_NAME = '_kb_product_group_name';
|
|
public const META_GROUP_SLUG = '_kb_product_group_slug';
|
|
public const META_PART_LABEL = '_kb_product_part_label';
|
|
public const META_CATEGORY = '_kb_product_category';
|
|
|
|
public function ensure(string $name, string $slug = ''): int
|
|
{
|
|
$slug = $slug ? sanitize_title($slug) : sanitize_title($name);
|
|
$term = term_exists($slug, 'kb_product');
|
|
|
|
if (! $term) {
|
|
$term = wp_insert_term($name, 'kb_product', ['slug' => $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);
|
|
}
|
|
}
|