$this->seo] + $data); } /** Shared tool-form field list. */ protected function toolFields(): array { return [ 'slug', 'name', 'short_description', 'description', 'icon', 'seo_title', 'seo_description', 'h1', 'intro', 'popularity', 'status', ]; } /** Build a registry row from POST for admin-created tools. */ protected function toolFromInput(array $post, int $categoryId): array { // reuse the builder's content generator so admin-created tools get // complete SEO fields even when left blank $generated = null; if (! empty($post['format_in']) && ! empty($post['format_out'])) { foreach (CatalogBuilder::build() as $candidate) { if ($candidate['slug'] === strtolower($post['format_in']) . '-to-' . strtolower($post['format_out'])) { $generated = $candidate; break; } } } return [ 'category_id' => $categoryId, 'kind' => $post['kind'] ?? ($generated['kind'] ?? 'upload'), 'operation' => $post['operation'] ?? ($generated['operation'] ?? 'convert'), 'slug' => $post['slug'] ?? ($generated['slug'] ?? ''), 'name' => $post['name'], 'short_description' => $post['short_description'] ?? '', 'description' => $post['description'] ?? null, 'input_formats' => json_encode($generated['input_formats'] ?? []), 'output_formats' => json_encode($generated['output_formats'] ?? []), 'primary_input_format' => $post['format_in'] ?? ($generated['primary_input_format'] ?? null), 'primary_output_format' => $post['format_out'] ?? ($generated['primary_output_format'] ?? null), 'icon' => $post['icon'] ?? 'file', 'seo_title' => $post['seo_title'] ?: ($generated['seo_title'] ?? ($post['name'] . ' – Free Online Tool')), 'seo_description' => $post['seo_description'] ?: mb_substr((string) ($post['short_description'] ?? ''), 0, 300), 'h1' => $post['h1'] ?: $post['name'], 'intro' => $post['intro'] ?: ($generated['intro'] ?? null), 'how_to' => json_encode($generated['how_to'] ?? []), 'faqs' => json_encode($generated['faqs'] ?? []), 'related_slugs' => json_encode([]), 'aliases' => json_encode(array_filter(array_map('trim', explode(',', (string) ($post['aliases'] ?? ''))))), 'requires_binaries' => json_encode($generated['requires_binaries'] ?? []), 'accepts_mimes' => json_encode($generated['accepts_mimes'] ?? []), 'popularity' => (int) ($post['popularity'] ?? 1000), 'status' => in_array(($post['status'] ?? ''), ['active', 'draft', 'inactive'], true) ? $post['status'] : 'active', ]; } protected function categories(): array { return model(CategoryModel::class)->findAll(); } protected function toolsModel(): ToolModel { return model(ToolModel::class); } protected function guidesModel(): GuideModel { return model(GuideModel::class); } }