- Move AdminAjaxHandler to Admin/Shared/Infrastructure/Api/Wordpress/ - Create FieldMapperInterface for decentralized field mapping - Create FieldMapperRegistry for module discovery - Create FieldMapperProvider for auto-registration of 12 mappers - Add FieldMappers for all components: - ContactFormFieldMapper (46 fields) - CtaBoxSidebarFieldMapper (32 fields) - CtaLetsTalkFieldMapper - CtaPostFieldMapper - FeaturedImageFieldMapper (15 fields) - FooterFieldMapper (31 fields) - HeroFieldMapper - NavbarFieldMapper - RelatedPostFieldMapper (34 fields) - SocialShareFieldMapper - TableOfContentsFieldMapper - TopNotificationBarFieldMapper (17 fields) - Update functions.php bootstrap with FieldMapperProvider - AdminAjaxHandler reduced from ~700 to 145 lines - Follows SRP, OCP, DIP principles BACKUP BEFORE: Removing CTA A/B Testing legacy system 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
146 lines
4.8 KiB
PHP
146 lines
4.8 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace ROITheme\Admin\Shared\Infrastructure\Api\Wordpress;
|
|
|
|
use ROITheme\Shared\Application\UseCases\SaveComponentSettings\SaveComponentSettingsUseCase;
|
|
use ROITheme\Admin\Shared\Infrastructure\FieldMapping\FieldMapperRegistry;
|
|
|
|
/**
|
|
* Handler para peticiones AJAX del panel de administracion
|
|
*
|
|
* RESPONSABILIDAD:
|
|
* - Manejar HTTP (request/response)
|
|
* - Delegar mapeo a FieldMapperRegistry
|
|
* - NO contiene logica de mapeo
|
|
*
|
|
* PRINCIPIOS:
|
|
* - SRP: Solo maneja HTTP
|
|
* - OCP: Nuevos componentes no requieren modificar esta clase
|
|
* - DIP: Depende de abstracciones (FieldMapperRegistry)
|
|
*/
|
|
final class AdminAjaxHandler
|
|
{
|
|
public function __construct(
|
|
private readonly ?SaveComponentSettingsUseCase $saveComponentSettingsUseCase = null,
|
|
private readonly ?FieldMapperRegistry $fieldMapperRegistry = null
|
|
) {}
|
|
|
|
public function register(): void
|
|
{
|
|
add_action('wp_ajax_roi_save_component_settings', [$this, 'saveComponentSettings']);
|
|
add_action('wp_ajax_roi_reset_component_defaults', [$this, 'resetComponentDefaults']);
|
|
}
|
|
|
|
public function saveComponentSettings(): void
|
|
{
|
|
check_ajax_referer('roi_admin_dashboard', 'nonce');
|
|
|
|
if (!current_user_can('manage_options')) {
|
|
wp_send_json_error(['message' => 'No tienes permisos para realizar esta accion.']);
|
|
}
|
|
|
|
$component = sanitize_text_field($_POST['component'] ?? '');
|
|
$settings = json_decode(stripslashes($_POST['settings'] ?? '{}'), true);
|
|
|
|
if (empty($component) || empty($settings)) {
|
|
wp_send_json_error(['message' => 'Datos incompletos.']);
|
|
}
|
|
|
|
// Obtener mapper del modulo correspondiente
|
|
if ($this->fieldMapperRegistry === null || !$this->fieldMapperRegistry->hasMapper($component)) {
|
|
wp_send_json_error([
|
|
'message' => "No existe mapper para el componente: {$component}"
|
|
]);
|
|
}
|
|
|
|
$mapper = $this->fieldMapperRegistry->getMapper($component);
|
|
$fieldMapping = $mapper->getFieldMapping();
|
|
|
|
// Mapear settings usando el mapper del modulo
|
|
$mappedSettings = $this->mapSettings($settings, $fieldMapping);
|
|
|
|
// Guardar usando Use Case
|
|
if ($this->saveComponentSettingsUseCase !== null) {
|
|
$updated = $this->saveComponentSettingsUseCase->execute($component, $mappedSettings);
|
|
wp_send_json_success([
|
|
'message' => sprintf('Se guardaron %d campos correctamente.', $updated)
|
|
]);
|
|
} else {
|
|
wp_send_json_error(['message' => 'Error: Use Case no disponible.']);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mapea settings de field IDs a grupos/atributos
|
|
*/
|
|
private function mapSettings(array $settings, array $fieldMapping): array
|
|
{
|
|
$mappedSettings = [];
|
|
|
|
foreach ($settings as $fieldId => $value) {
|
|
if (!isset($fieldMapping[$fieldId])) {
|
|
continue;
|
|
}
|
|
|
|
$mapping = $fieldMapping[$fieldId];
|
|
$groupName = $mapping['group'];
|
|
$attributeName = $mapping['attribute'];
|
|
|
|
if (!isset($mappedSettings[$groupName])) {
|
|
$mappedSettings[$groupName] = [];
|
|
}
|
|
|
|
$mappedSettings[$groupName][$attributeName] = $value;
|
|
}
|
|
|
|
return $mappedSettings;
|
|
}
|
|
|
|
public function resetComponentDefaults(): void
|
|
{
|
|
// Verificar nonce
|
|
check_ajax_referer('roi_admin_dashboard', 'nonce');
|
|
|
|
// Verificar permisos
|
|
if (!current_user_can('manage_options')) {
|
|
wp_send_json_error([
|
|
'message' => 'No tienes permisos para realizar esta accion.'
|
|
]);
|
|
}
|
|
|
|
// Obtener componente
|
|
$component = sanitize_text_field($_POST['component'] ?? '');
|
|
|
|
if (empty($component)) {
|
|
wp_send_json_error([
|
|
'message' => 'Componente no especificado.'
|
|
]);
|
|
}
|
|
|
|
// Ruta al schema JSON
|
|
$schemaPath = get_template_directory() . '/Schemas/' . $component . '.json';
|
|
|
|
if (!file_exists($schemaPath)) {
|
|
wp_send_json_error([
|
|
'message' => 'Schema del componente no encontrado.'
|
|
]);
|
|
}
|
|
|
|
// Usar repositorio para restaurar valores
|
|
if ($this->saveComponentSettingsUseCase !== null) {
|
|
global $wpdb;
|
|
$repository = new \ROITheme\Shared\Infrastructure\Persistence\Wordpress\WordPressComponentSettingsRepository($wpdb);
|
|
$updated = $repository->resetToDefaults($component, $schemaPath);
|
|
|
|
wp_send_json_success([
|
|
'message' => sprintf('Se restauraron %d campos a sus valores por defecto.', $updated)
|
|
]);
|
|
} else {
|
|
wp_send_json_error([
|
|
'message' => 'Error: Repositorio no disponible.'
|
|
]);
|
|
}
|
|
}
|
|
}
|