Files
roi-theme/admin-panel/includes/class-settings-manager.php
FrankZamora 3beb292901 Fix: Corregir formato AJAX WordPress en Admin Panel
Causa raíz del error 400: El código estaba usando formato JSON cuando WordPress AJAX requiere application/x-www-form-urlencoded.

## Problema

**Error:** POST admin-ajax.php 400 (Bad Request)

**Causas:**
1. JavaScript enviaba datos como JSON (`Content-Type: application/json`)
2. PHP usaba `json_decode(file_get_contents('php://input'))`
3. WordPress AJAX espera `$_POST` con `action` y `nonce`

## Solución

### JavaScript (admin-app.js)
```javascript
// ANTES ( Incorrecto)
data: JSON.stringify({
  action: 'apus_save_settings',
  nonce: apusAdminData.nonce,
  ...formData
})

// AHORA ( Correcto)
const postData = new URLSearchParams();
postData.append('action', 'apus_save_settings');
postData.append('nonce', apusAdminData.nonce);
postData.append('components', JSON.stringify(formData.components));
```

### PHP (class-settings-manager.php)
```php
// ANTES ( Incorrecto)
$data = json_decode(file_get_contents('php://input'), true);

// AHORA ( Correcto)
$components = json_decode(stripslashes($_POST['components']), true);
```

### Cambios Aplicados

**admin-app.js:**
- Usar `URLSearchParams` en lugar de `JSON.stringify`
- Header `application/x-www-form-urlencoded`
- Enviar `components` como JSON string en parámetro POST

**class-settings-manager.php:**
- Verificar nonce con `wp_verify_nonce($_POST['nonce'])`
- Parsear `$_POST['components']` como JSON
- Mensajes de error más descriptivos

## WordPress AJAX Requirements

1.  `action` en $_POST
2.  `nonce` en $_POST
3.  Content-Type: application/x-www-form-urlencoded
4.  Usar $_POST, no php://input

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 15:32:47 -06:00

200 lines
5.5 KiB
PHP

<?php
/**
* Settings Manager Class
*
* CRUD de configuraciones por componentes
*
* @package Apus_Theme
* @since 2.0.0
*/
if (!defined('ABSPATH')) {
exit;
}
class APUS_Settings_Manager {
const OPTION_NAME = 'apus_theme_settings';
/**
* Constructor
*/
public function __construct() {
add_action('wp_ajax_apus_get_settings', array($this, 'ajax_get_settings'));
add_action('wp_ajax_apus_save_settings', array($this, 'ajax_save_settings'));
}
/**
* Obtener configuraciones
*/
public function get_settings() {
$settings = get_option(self::OPTION_NAME, array());
$defaults = $this->get_defaults();
return wp_parse_args($settings, $defaults);
}
/**
* Guardar configuraciones
*/
public function save_settings($data) {
// Validar
$validator = new APUS_Validator();
$validation = $validator->validate($data);
if (!$validation['valid']) {
return array(
'success' => false,
'message' => 'Error de validación',
'errors' => $validation['errors']
);
}
// Sanitizar
$sanitized = $this->sanitize_settings($data);
// Agregar metadata
$sanitized['version'] = APUS_ADMIN_PANEL_VERSION;
$sanitized['updated_at'] = current_time('mysql');
// Guardar
update_option(self::OPTION_NAME, $sanitized, false);
return array(
'success' => true,
'message' => 'Configuración guardada correctamente'
);
}
/**
* Valores por defecto
* NOTA: Aquí se agregan los defaults de cada componente
*/
public function get_defaults() {
return array(
'version' => APUS_ADMIN_PANEL_VERSION,
'components' => array(
'top_bar' => array(
'enabled' => true,
'show_on_mobile' => true,
'show_on_desktop' => true,
'icon_class' => 'bi bi-megaphone-fill',
'show_icon' => true,
'highlight_text' => 'Nuevo:',
'message_text' => 'Accede a más de 200,000 Análisis de Precios Unitarios actualizados para 2025.',
'link_text' => 'Ver Catálogo',
'link_url' => '/catalogo',
'link_target' => '_self',
'show_link' => true,
'custom_styles' => array(
// Valores extraídos de componente-top-bar.css
'background_color' => '#0E2337', // var(--color-navy-dark)
'text_color' => '#ffffff',
'highlight_color' => '#FF8600', // var(--color-orange-primary)
'link_hover_color' => '#FF8600', // var(--color-orange-primary)
'font_size' => 'normal' // 0.9rem del CSS
)
)
// Navbar - Pendiente
// Hero - Pendiente
// Footer - Pendiente
)
);
}
/**
* Sanitizar configuraciones
* NOTA: Aquí se agrega sanitización de cada componente
*/
public function sanitize_settings($data) {
$sanitized = array(
'components' => array()
);
// Sanitizar Top Bar
if (isset($data['components']['top_bar'])) {
$top_bar = $data['components']['top_bar'];
$sanitized['components']['top_bar'] = array(
'enabled' => !empty($top_bar['enabled']),
'show_on_mobile' => !empty($top_bar['show_on_mobile']),
'show_on_desktop' => !empty($top_bar['show_on_desktop']),
'icon_class' => sanitize_text_field($top_bar['icon_class'] ?? ''),
'show_icon' => !empty($top_bar['show_icon']),
'highlight_text' => sanitize_text_field($top_bar['highlight_text'] ?? ''),
'message_text' => sanitize_text_field($top_bar['message_text'] ?? ''),
'link_text' => sanitize_text_field($top_bar['link_text'] ?? ''),
'link_url' => esc_url_raw($top_bar['link_url'] ?? ''),
'link_target' => in_array($top_bar['link_target'] ?? '', array('_self', '_blank')) ? $top_bar['link_target'] : '_self',
'show_link' => !empty($top_bar['show_link']),
'custom_styles' => array(
'background_color' => sanitize_hex_color($top_bar['custom_styles']['background_color'] ?? ''),
'text_color' => sanitize_hex_color($top_bar['custom_styles']['text_color'] ?? ''),
'highlight_color' => sanitize_hex_color($top_bar['custom_styles']['highlight_color'] ?? ''),
'link_hover_color' => sanitize_hex_color($top_bar['custom_styles']['link_hover_color'] ?? ''),
'font_size' => in_array($top_bar['custom_styles']['font_size'] ?? '', array('small', 'normal', 'large')) ? $top_bar['custom_styles']['font_size'] : 'normal'
)
);
}
return $sanitized;
}
/**
* AJAX: Obtener configuraciones
*/
public function ajax_get_settings() {
// Verificar nonce
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'apus_admin_nonce')) {
wp_send_json_error('Nonce inválido');
}
if (!current_user_can('manage_options')) {
wp_send_json_error('Permisos insuficientes');
}
$settings = $this->get_settings();
wp_send_json_success($settings);
}
/**
* AJAX: Guardar configuraciones
*/
public function ajax_save_settings() {
// Verificar nonce
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'apus_admin_nonce')) {
wp_send_json_error('Nonce inválido');
}
if (!current_user_can('manage_options')) {
wp_send_json_error('Permisos insuficientes');
}
// Los datos vienen como JSON string en $_POST['components']
if (!isset($_POST['components'])) {
wp_send_json_error('Datos inválidos - falta components');
}
$components = json_decode(stripslashes($_POST['components']), true);
if (!is_array($components)) {
wp_send_json_error('Datos inválidos - components no es un array válido');
}
$data = array(
'components' => $components
);
$result = $this->save_settings($data);
if ($result['success']) {
wp_send_json_success($result);
} else {
wp_send_json_error($result);
}
}
}
// Instanciar clase
new APUS_Settings_Manager();