50%) * * USO: * wp roi-theme clean_thrive --dry-run # Ver qué se limpiaría (OBLIGATORIO primero) * wp roi-theme clean_thrive # Ejecutar limpieza real * * SEGURIDAD: * - Verifica preservación de shortcodes [roi_apu_search] * - Máximo 50% de reducción de contenido permitida * - Valida cada preg_replace para evitar null returns */ final class CleanThriveContentCommand { /** * IDs de páginas buscar-apus afectadas */ private const AFFECTED_PAGE_IDS = [ 107264, 107312, 107340, 107345, 107351, 107357, 107362, 107369, 107374, 107379, 107384, 107389, 107395, 107399, 107403, 107407, 107411, 107416, 107421, 107425, 185752 ]; /** * Otras páginas con contenido Thrive (Blog, Curso) */ private const OTHER_AFFECTED_IDS = [252030, 290709]; /** * Shortcodes que DEBEN ser preservados */ private const PROTECTED_SHORTCODES = [ '[roi_apu_search', '[roi_', ]; /** * Máximo porcentaje de contenido que puede eliminarse */ private const MAX_CONTENT_LOSS_PERCENT = 50; public function __invoke(array $args, array $assoc_args): void { $dryRun = isset($assoc_args['dry-run']); $includeOthers = isset($assoc_args['include-others']); $force = isset($assoc_args['force']); $pageIds = self::AFFECTED_PAGE_IDS; if ($includeOthers) { $pageIds = array_merge($pageIds, self::OTHER_AFFECTED_IDS); } WP_CLI::log(''); WP_CLI::log('╔══════════════════════════════════════════════════════════════════╗'); WP_CLI::log('║ LIMPIEZA QUIRÚRGICA DE CONTENIDO THRIVE CONGELADO (v2.0) ║'); WP_CLI::log('║ Con validaciones de seguridad para proteger shortcodes ║'); WP_CLI::log('╚══════════════════════════════════════════════════════════════════╝'); WP_CLI::log(''); if ($dryRun) { WP_CLI::warning('MODO DRY-RUN: No se modificará ningún contenido'); } else { WP_CLI::error('MODO REAL DESHABILITADO: Ejecuta primero con --dry-run', false); WP_CLI::log(''); WP_CLI::log('Para ejecutar la limpieza real, primero revisa el dry-run:'); WP_CLI::log(' wp roi-theme clean_thrive --dry-run'); WP_CLI::log(''); WP_CLI::log('Si el dry-run es correcto y deseas ejecutar:'); WP_CLI::log(' wp roi-theme clean_thrive --force'); if (!$force) { return; } WP_CLI::warning('MODO REAL CON --force: Se modificará el contenido'); } WP_CLI::log(''); WP_CLI::log('Páginas a procesar: ' . count($pageIds)); WP_CLI::log('Shortcodes protegidos: ' . implode(', ', self::PROTECTED_SHORTCODES)); WP_CLI::log('Máxima pérdida permitida: ' . self::MAX_CONTENT_LOSS_PERCENT . '%'); WP_CLI::log(''); $totalH2Removed = 0; $totalPaginationRemoved = 0; $totalBytesFreed = 0; $pagesModified = 0; $pagesSkipped = 0; $errors = []; foreach ($pageIds as $id) { $page = get_post($id); if (!$page) { WP_CLI::warning("Página {$id} no encontrada, saltando..."); continue; } $originalContent = $page->post_content; $originalSize = strlen($originalContent); // Verificar si tiene contenido Thrive que limpiar $hasThrive = strpos($originalContent, 'tcb_post_title') !== false || strpos($originalContent, 'tcb_pagination') !== false; if (!$hasThrive) { WP_CLI::log(sprintf( "[SIN THRIVE] ID %d: %s", $id, mb_substr($page->post_title, 0, 50) )); continue; } // Contar elementos antes de limpiar $h2Count = preg_match_all('/
]*>.*?\[tcb_pagination_current_page\].*?\[tcb_pagination_total_pages\].*?<\/p>/s', '', $content ); if ($result === null) { return ['content' => $originalContent, 'error' => 'preg_replace falló en patrón paginación']; } $content = $result; // 3. Eliminar botones de paginación Thrive $result = preg_replace( '/
]*data-button_layout="[^"]*"[^>]*data-page="[^"]*"[^>]*>.*?<\/p>/s', '', $content ); if ($result === null) { return ['content' => $originalContent, 'error' => 'preg_replace falló en patrón botones']; } $content = $result; // 4. Eliminar shortcodes Thrive huérfanos $content = str_replace('[tcb_pagination_current_page]', '', $content); $content = str_replace('[tcb_pagination_total_pages]', '', $content); // 5. Limpiar múltiples líneas vacías (con validación) $result = preg_replace('/(\r?\n){3,}/', "\n\n", $content); if ($result === null) { return ['content' => $originalContent, 'error' => 'preg_replace falló en limpieza líneas']; } $content = $result; // 6. Trim $content = trim($content); // Validación final: no retornar vacío si original tenía contenido if (empty($content) && !empty($originalContent)) { return ['content' => $originalContent, 'error' => 'El contenido quedó vacío']; } return ['content' => $content, 'error' => null]; } /** * Cuenta shortcodes protegidos en el contenido */ private function countProtectedShortcodes(string $content): int { $count = 0; foreach (self::PROTECTED_SHORTCODES as $shortcode) { $count += substr_count($content, $shortcode); } return $count; } /** * Formatea bytes a formato legible */ private function formatBytes(int $bytes): string { if ($bytes < 1024) { return $bytes . ' B'; } elseif ($bytes < 1048576) { return round($bytes / 1024, 1) . ' KB'; } else { return round($bytes / 1048576, 2) . ' MB'; } } }