<?php
|
namespace JVBase\rest\routes;
|
|
use JVBase\rest\RestRouteManager;
|
use JVBase\managers\Cache;
|
use JVBase\managers\SEO\ConfigManager;
|
use JVBase\managers\SEO\SchemaBuilder;
|
use WP_REST_Request;
|
use WP_REST_Response;
|
use WP_Error;
|
|
if (!defined('ABSPATH')) {
|
exit;
|
}
|
|
/**
|
* SEO Routes Class
|
*
|
* Handles REST API endpoints for SEO configuration
|
* Works with FormController.js for unified form handling
|
*/
|
class SEORoutes extends RestRouteManager
|
{
|
protected SchemaBuilder $registry;
|
|
public function __construct()
|
{
|
$this->cache_name = 'schema';
|
parent::__construct();
|
$this->registry = SchemaBuilder::getInstance();
|
}
|
|
/**
|
* Register REST routes
|
*/
|
public function registerRoutes(): void
|
{
|
// Main SEO endpoint - handles save, reset, preview
|
register_rest_route($this->namespace, '/seo', [
|
[
|
'methods' => 'POST',
|
'callback' => [$this, 'handleSEO'],
|
'permission_callback' => fn() => current_user_can('manage_options'),
|
'args' => [
|
'action' => [
|
'required' => false,
|
'type' => 'string',
|
'default' => 'save',
|
'enum' => ['save', 'reset', 'preview']
|
],
|
'context' => [
|
'required' => true,
|
'type' => 'string',
|
'description' => 'site, business, or content/taxonomy/user type'
|
]
|
]
|
]
|
]);
|
|
// Get fields for a schema type (for dynamic type switching)
|
register_rest_route($this->namespace, '/seo/fields', [
|
[
|
'methods' => 'GET',
|
'callback' => [$this, 'getFields'],
|
'permission_callback' => fn() => current_user_can('manage_options'),
|
'args' => [
|
'type' => [
|
'required' => true,
|
'type' => 'string'
|
]
|
]
|
]
|
]);
|
}
|
|
/**
|
* Main SEO handler - routes to appropriate action
|
*/
|
public function handleSEO(WP_REST_Request $request): WP_REST_Response
|
{
|
$action = $request->get_param('action') ?? 'save';
|
$context = $request->get_param('context');
|
|
// Verify context is valid
|
if (!$this->isValidContext($context)) {
|
return $this->validationError([
|
'context' => "Invalid context: {$context}"
|
]);
|
}
|
|
return match($action) {
|
'save' => $this->saveSEO($request),
|
'reset' => $this->resetSEO($request),
|
'preview' => $this->previewSchema($request),
|
default => $this->validationError(['action' => 'Invalid action'])
|
};
|
}
|
|
/**
|
* Save SEO configuration
|
*/
|
protected function saveSEO(WP_REST_Request $request): WP_REST_Response
|
{
|
$context = $request->get_param('context');
|
$data = $request->get_json_params();
|
|
// Remove action and context from data
|
unset($data['action'], $data['context']);
|
|
// Handle site-wide settings
|
if (in_array($context, ['site', 'business'])) {
|
return $this->saveSiteSettings($context, $data);
|
}
|
|
// Handle content/taxonomy/user type settings
|
return $this->saveTypeSettings($context, $data);
|
}
|
|
/**
|
* Save site-wide settings (WebSite or Organization)
|
*/
|
protected function saveSiteSettings(string $context, array $data): WP_REST_Response
|
{
|
$errors = [];
|
|
$config = ConfigManager::for($context);
|
$result = $config->updateConfig($data);
|
|
if (is_wp_error($result)) {
|
$errors[$context] = [
|
'message' => $result->get_error_message(),
|
'errors' => $result->get_error_data()
|
];
|
}
|
|
if (!empty($errors)) {
|
return $this->validationError($errors);
|
}
|
|
// Invalidate cache
|
$this->cache->flush();
|
|
return new WP_REST_Response([
|
'success' => true,
|
'status' => 'completed',
|
'message' => ucfirst($context) . ' settings saved successfully'
|
]);
|
}
|
|
/**
|
* Save content/taxonomy/user type settings
|
*/
|
protected function saveTypeSettings(string $type, array $data): WP_REST_Response
|
{
|
$config = ConfigManager::for($type);
|
|
// Separate meta and schema data if needed
|
$meta = $data['meta'] ?? [];
|
$schema = $data['schema'] ?? $data; // If no separation, treat all as schema
|
|
$errors = [];
|
|
// Save meta configuration
|
if (!empty($meta)) {
|
$metaResult = $config->updateMeta($meta);
|
if (is_wp_error($metaResult)) {
|
$errors['meta'] = [
|
'message' => $metaResult->get_error_message(),
|
'errors' => $metaResult->get_error_data()
|
];
|
}
|
}
|
|
// Save schema configuration
|
if (!empty($schema)) {
|
$schemaResult = $config->updateConfig($schema);
|
if (is_wp_error($schemaResult)) {
|
$errors['schema'] = [
|
'message' => $schemaResult->get_error_message(),
|
'errors' => $schemaResult->get_error_data()
|
];
|
}
|
}
|
|
if (!empty($errors)) {
|
return $this->validationError($errors);
|
}
|
|
// Invalidate cache
|
$this->cache->flush();
|
|
return new WP_REST_Response([
|
'success' => true,
|
'status' => 'completed',
|
'message' => 'Configuration saved successfully'
|
]);
|
}
|
|
/**
|
* Reset SEO configuration to defaults
|
*/
|
protected function resetSEO(WP_REST_Request $request): WP_REST_Response
|
{
|
$context = $request->get_param('context');
|
$data = $request->get_json_params();
|
|
$resetMeta = $data['resetMeta'] ?? false;
|
$resetSchema = $data['resetSchema'] ?? false;
|
|
$config = ConfigManager::for($context);
|
|
// Reset based on what was requested
|
if ($resetMeta) {
|
$config->resetMeta();
|
}
|
|
if ($resetSchema) {
|
$config->resetConfig();
|
}
|
|
if (!$resetMeta && !$resetSchema) {
|
// Default: reset everything
|
$config->resetAll();
|
}
|
|
// Invalidate cache
|
$this->cache->flush();
|
|
return new WP_REST_Response([
|
'success' => true,
|
'status' => 'completed',
|
'message' => 'Reset to defaults successfully',
|
'meta' => $config->meta(),
|
'schema' => $config->schema()
|
]);
|
}
|
|
/**
|
* Preview schema output
|
*/
|
protected function previewSchema(WP_REST_Request $request): WP_REST_Response
|
{
|
$data = $request->get_json_params();
|
$schemaType = $data['type'] ?? 'Thing';
|
|
// Get field definitions from registry
|
$fieldDefinitions = $this->registry->getMetaConfigForType($schemaType);
|
|
// Build schema with actual form values
|
$schema = [
|
'@type' => $schemaType,
|
'@id' => get_home_url() . '/#' . strtolower($schemaType),
|
];
|
|
// Add fields with their actual values
|
foreach ($data['fields'] ?? [] as $fieldName => $value) {
|
if (empty($value)) {
|
continue;
|
}
|
|
$schema[$fieldName] = $value;
|
}
|
|
return new WP_REST_Response([
|
'success' => true,
|
'schema' => $schema
|
]);
|
}
|
|
/**
|
* Get fields for a schema type
|
* Used for dynamic type switching
|
*/
|
public function getFields(WP_REST_Request $request): WP_REST_Response
|
{
|
$type = $request->get_param('type');
|
|
// Get MetaManager field definitions from registry
|
$fields = $this->registry->getMetaConfigForType($type);
|
|
return new WP_REST_Response($fields);
|
}
|
|
/**
|
* Validate context is a valid type
|
*/
|
protected function isValidContext(string $context): bool
|
{
|
// Site-wide contexts
|
if (in_array($context, ['site', 'business'])) {
|
return true;
|
}
|
|
// Check if it's a valid content/taxonomy/user type
|
return $this->checkContent($context, true);
|
}
|
}
|