Nuevo sistema de gestión de CSS personalizado con panel admin: - Admin/CustomCSSManager: CRUD de snippets CSS (crítico/diferido) - Public/CustomCSSManager: Inyección dinámica en frontend - Schema JSON para configuración del componente Migración de CSS estático a BD: - Tablas APU (~14KB) → snippet diferido en BD - Tablas Genéricas (~10KB) → snippet diferido en BD - Comentadas funciones legacy en enqueue-scripts.php Limpieza de archivos obsoletos: - Eliminado build-bootstrap-subset.js - Eliminado migrate-legacy-options.php - Eliminado minify-css.php - Eliminado purgecss.config.js Beneficios: - CSS editable desde admin sin tocar código - Soporte crítico (head) y diferido (footer) - Filtrado por scope (all/home/single/archive) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
164 lines
4.7 KiB
PHP
164 lines
4.7 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace ROITheme\Admin\CustomCSSManager\Infrastructure\Persistence;
|
|
|
|
use ROITheme\Shared\Domain\Contracts\CSSSnippetRepositoryInterface;
|
|
|
|
/**
|
|
* Repositorio WordPress para snippets CSS
|
|
*
|
|
* Almacena snippets como JSON en wp_roi_theme_component_settings
|
|
*/
|
|
final class WordPressSnippetRepository implements CSSSnippetRepositoryInterface
|
|
{
|
|
private const COMPONENT_NAME = 'custom-css-manager';
|
|
private const GROUP_NAME = 'css_snippets';
|
|
private const ATTRIBUTE_NAME = 'snippets_json';
|
|
|
|
public function __construct(
|
|
private readonly \wpdb $wpdb
|
|
) {}
|
|
|
|
public function getAll(): array
|
|
{
|
|
$tableName = $this->wpdb->prefix . 'roi_theme_component_settings';
|
|
|
|
$sql = $this->wpdb->prepare(
|
|
"SELECT attribute_value FROM {$tableName}
|
|
WHERE component_name = %s
|
|
AND group_name = %s
|
|
AND attribute_name = %s
|
|
LIMIT 1",
|
|
self::COMPONENT_NAME,
|
|
self::GROUP_NAME,
|
|
self::ATTRIBUTE_NAME
|
|
);
|
|
|
|
$json = $this->wpdb->get_var($sql);
|
|
|
|
if (empty($json)) {
|
|
return [];
|
|
}
|
|
|
|
$snippets = json_decode($json, true);
|
|
|
|
return is_array($snippets) ? $snippets : [];
|
|
}
|
|
|
|
public function getByLoadType(string $loadType): array
|
|
{
|
|
$all = $this->getAll();
|
|
|
|
$filtered = array_filter($all, function ($snippet) use ($loadType) {
|
|
return ($snippet['type'] ?? '') === $loadType
|
|
&& ($snippet['enabled'] ?? false) === true;
|
|
});
|
|
|
|
// Reindexar para evitar keys dispersas [0,2,5] → [0,1,2]
|
|
return array_values($filtered);
|
|
}
|
|
|
|
public function getForPage(string $loadType, string $pageType): array
|
|
{
|
|
$snippets = $this->getByLoadType($loadType);
|
|
|
|
$filtered = array_filter($snippets, function ($snippet) use ($pageType) {
|
|
$pages = $snippet['pages'] ?? ['all'];
|
|
return in_array('all', $pages, true)
|
|
|| in_array($pageType, $pages, true);
|
|
});
|
|
|
|
// Reindexar para evitar keys dispersas
|
|
return array_values($filtered);
|
|
}
|
|
|
|
public function save(array $snippet): void
|
|
{
|
|
$all = $this->getAll();
|
|
|
|
// Actualizar o agregar
|
|
$found = false;
|
|
foreach ($all as &$existing) {
|
|
if ($existing['id'] === $snippet['id']) {
|
|
$existing = $snippet;
|
|
$found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!$found) {
|
|
$all[] = $snippet;
|
|
}
|
|
|
|
// Ordenar por 'order'
|
|
usort($all, fn($a, $b) => ($a['order'] ?? 100) <=> ($b['order'] ?? 100));
|
|
|
|
$this->persist($all);
|
|
}
|
|
|
|
public function delete(string $snippetId): void
|
|
{
|
|
$all = $this->getAll();
|
|
|
|
$filtered = array_filter($all, fn($s) => $s['id'] !== $snippetId);
|
|
|
|
$this->persist(array_values($filtered));
|
|
}
|
|
|
|
/**
|
|
* Persiste la lista de snippets en BD
|
|
*
|
|
* Usa update() + insert() para consistencia con patrón existente.
|
|
* NOTA: NO usa replace() porque:
|
|
* - Preserva ID autoincremental
|
|
* - Preserva campos como is_editable, created_at
|
|
*
|
|
* @param array $snippets Lista de snippets a persistir
|
|
*/
|
|
private function persist(array $snippets): void
|
|
{
|
|
$tableName = $this->wpdb->prefix . 'roi_theme_component_settings';
|
|
$json = wp_json_encode($snippets, JSON_UNESCAPED_UNICODE);
|
|
|
|
// Verificar si el registro existe
|
|
$exists = $this->wpdb->get_var($this->wpdb->prepare(
|
|
"SELECT COUNT(*) FROM {$tableName}
|
|
WHERE component_name = %s
|
|
AND group_name = %s
|
|
AND attribute_name = %s",
|
|
self::COMPONENT_NAME,
|
|
self::GROUP_NAME,
|
|
self::ATTRIBUTE_NAME
|
|
));
|
|
|
|
if ($exists > 0) {
|
|
// UPDATE existente (preserva id, created_at, is_editable)
|
|
$this->wpdb->update(
|
|
$tableName,
|
|
['attribute_value' => $json],
|
|
[
|
|
'component_name' => self::COMPONENT_NAME,
|
|
'group_name' => self::GROUP_NAME,
|
|
'attribute_name' => self::ATTRIBUTE_NAME,
|
|
],
|
|
['%s'],
|
|
['%s', '%s', '%s']
|
|
);
|
|
} else {
|
|
// INSERT nuevo
|
|
$this->wpdb->insert(
|
|
$tableName,
|
|
[
|
|
'component_name' => self::COMPONENT_NAME,
|
|
'group_name' => self::GROUP_NAME,
|
|
'attribute_name' => self::ATTRIBUTE_NAME,
|
|
'attribute_value' => $json,
|
|
'is_editable' => 1,
|
|
],
|
|
['%s', '%s', '%s', '%s', '%d']
|
|
);
|
|
}
|
|
}
|
|
}
|