Files
roi-theme/wp-content/plugins/restrict-content-pro-expired-orders/restrict-content-pro-expired-orders.php
root a22573bf0b Commit inicial - WordPress Análisis de Precios Unitarios
- WordPress core y plugins
- Tema Twenty Twenty-Four configurado
- Plugin allow-unfiltered-html.php simplificado
- .gitignore configurado para excluir wp-config.php y uploads

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 21:04:30 -06:00

277 lines
10 KiB
PHP
Executable File

<?php
/**
* Plugin Name: Restrict Content Pro - Membresías Expiradas Log DB
* Description: Procesa órdenes de membresías expiradas y guarda en base de datos. Soporta control por token, rango de tiempo, límite de procesamiento por ejecución y logging opcional.
* Version: 1.3
* Author: Tecno Group
*/
if (!defined('ABSPATH')) exit;
define('token', 'dSekoODNCDabD9n15p2025');
// Crear tabla al activar
register_activation_hook(__FILE__, 'rcp_membresias_crear_tabla');
function rcp_membresias_crear_tabla() {
global $wpdb;
$tabla = $wpdb->prefix . 'rcp_expired_orders';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS $tabla (
id INT AUTO_INCREMENT PRIMARY KEY,
order_id INT NOT NULL UNIQUE,
fecha_registro DATETIME DEFAULT CURRENT_TIMESTAMP,
fecha_orden DATETIME,
fecha_expiracion DATETIME,
producto VARCHAR(255),
cliente_nombre VARCHAR(255),
telefono VARCHAR(100),
api_enviado TINYINT(1) DEFAULT 0,
api_estatus TEXT DEFAULT NULL
) $charset_collate;";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta($sql);
}
// Ejecutar si URL contiene token
add_action('init', 'rcp_membresias_check_url_trigger');
function rcp_membresias_check_url_trigger() {
if (isset($_GET['token']) && $_GET['token'] === token) {
$procesar_todo = isset($_GET['procesar_todo']) && $_GET['procesar_todo'] === '1';
$limite = isset($_GET['limite']) ? intval($_GET['limite']) : 10;
$log_activo = isset($_GET['log']) && $_GET['log'] === '1';
rcp_verificar_membresias_expiradas($limite, $log_activo);
echo "✅ Se han procesado las órdenes vencidas." . PHP_EOL . PHP_EOL;
rcp_enviar_mensajes_ordenes_expiradas($log_activo);
echo "📤 Se han enviado los mensajes a los clientes." . PHP_EOL;
exit;
}
}
// Lógica principal
function rcp_verificar_membresias_expiradas($limite = 10, $log = false) {
global $wpdb;
// 💡 Captura parámetros GET si están definidos
$limite = isset($_GET['limite']) ? intval($_GET['limite']) : $limite;
$log = isset($_GET['log']) ? boolval($_GET['log']) : $log;
$horas_vencimiento = isset($_GET['horas']) ? intval($_GET['horas']) : 720;
$tabla_objetivo = $wpdb->prefix . 'rcp_expired_orders';
$log_path = plugin_dir_path(__FILE__) . 'logs/rcp_membresias_expiradas.txt';
if ($log) file_put_contents($log_path, "=== INICIO RCP ".date('Y-m-d H:i:s')." ===\n", FILE_APPEND);
$now_str = current_time('mysql');
$fecha_limite_str = date('Y-m-d H:i:s', strtotime("+{$horas_vencimiento} hours", strtotime($now_str)));
$query = "
SELECT m.id AS membership_id, m.gateway_subscription_id AS order_id, m.created_date, m.expiration_date,
m.customer_id, m.user_id
FROM {$wpdb->prefix}rcp_memberships m
WHERE m.expiration_date BETWEEN %s AND %s
ORDER BY m.expiration_date ASC
LIMIT %d
";
$query_preparada = $wpdb->prepare($query, $now_str, $fecha_limite_str, $limite * 3);
if ($log) {
file_put_contents($log_path, "🕒 Rango: $now_str => $fecha_limite_str\n", FILE_APPEND);
file_put_contents($log_path, "🔍 SQL: \n$query_preparada\n", FILE_APPEND);
}
$ordenes_procesadas = $wpdb->get_col("SELECT order_id FROM $tabla_objetivo");
$membresias = $wpdb->get_results($query_preparada);
if ($log) file_put_contents($log_path, "📦 Membresías encontradas en rango: ".count($membresias)."\n", FILE_APPEND);
$mapa_productos = [
'Vip Bronce' => 'Vip Bronce acceso por 24 horas',
'Vip Plata' => 'Vip Plata acceso por 30 días',
'Vip Oro' => 'Vip Oro acceso por 365 días',
];
$procesadas = 0;
foreach ($membresias as $m) {
if (in_array($m->order_id, $ordenes_procesadas)) {
if ($log) file_put_contents($log_path, "⚠️ Ya procesado order_id: $m->order_id\n", FILE_APPEND);
continue;
}
// Obtener suscripción
$subscription = $wpdb->get_var($wpdb->prepare(
"SELECT subscription FROM {$wpdb->prefix}rcp_payments WHERE customer_id = %d ORDER BY id DESC LIMIT 1",
$m->customer_id
));
if (!$subscription || !isset($mapa_productos[$subscription])) {
if ($log) file_put_contents($log_path, "⛔ Suscripción no válida para customer_id $m->customer_id (subscription: $subscription)\n", FILE_APPEND);
continue;
}
$producto = $mapa_productos[$subscription];
// Obtener datos del usuario
$user_data = $wpdb->get_row($wpdb->prepare(
"SELECT user_email, user_nicename FROM {$wpdb->prefix}users WHERE ID = %d",
$m->user_id
));
if (!$user_data) {
if ($log) file_put_contents($log_path, "⛔ Usuario no encontrado para user_id $m->user_id\n", FILE_APPEND);
continue;
}
$user_email = $user_data->user_email;
$usuario = $user_data->user_nicename;
// Obtener contacto
$contacto = $wpdb->get_row($wpdb->prepare(
"SELECT f_name, l_name, contact_no FROM {$wpdb->prefix}bwf_contact WHERE email = %s",
$user_email
));
if (!$contacto) {
if ($log) file_put_contents($log_path, "⛔ Contacto no encontrado para email $user_email\n", FILE_APPEND);
continue;
}
$cliente_nombre = mb_convert_case(trim($contacto->f_name . ' ' . $contacto->l_name), MB_CASE_TITLE, 'UTF-8');
$telefono = rcp_formatear_numero_telefono($contacto->contact_no);
// Insertar en la tabla objetivo
$wpdb->insert($tabla_objetivo, [
'order_id' => $m->order_id,
'fecha_registro' => current_time('mysql'),
'fecha_orden' => $m->created_date,
'fecha_expiracion' => $m->expiration_date,
'producto' => $producto,
'cliente_nombre' => $cliente_nombre,
'usuario' => $usuario,
'mail' => $user_email,
'telefono' => $telefono,
'api_enviado' => 0
]);
if ($log) file_put_contents($log_path, "✅ Insertada order_id $m->order_id - $producto\n", FILE_APPEND);
$procesadas++;
if ($procesadas >= $limite) break;
sleep(1);
}
if ($log) file_put_contents($log_path, "=== FIN (procesadas: $procesadas) ===\n", FILE_APPEND);
}
function rcp_enviar_mensajes_ordenes_expiradas($log = false) {
global $wpdb;
$tabla = $wpdb->prefix . 'rcp_expired_orders';
$log_path = plugin_dir_path(__FILE__) . 'logs/rcp_enviar_mensajes.txt';
$ordenes = $wpdb->get_results("SELECT * FROM $tabla WHERE api_enviado = 0 LIMIT 5");
foreach ($ordenes as $orden) {
$telefono = $orden->telefono;
$nombre = mb_convert_case(mb_strtolower(trim($orden->cliente_nombre), 'UTF-8'), MB_CASE_TITLE, 'UTF-8');
$orden_id = $orden->order_id;
$producto = $orden->producto;
$fecha_orden = DateTime::createFromFormat('Y-m-d H:i:s', $orden->fecha_orden);
$fecha_expiracion = DateTime::createFromFormat('Y-m-d H:i:s', $orden->fecha_expiracion);
$fecha_orden_str = $fecha_orden->format('d/m/Y H:i:s');
$fecha_expiracion_str = $fecha_expiracion->format('d/m/Y H:i:s');
// Texto del mensaje
$texto = "*Saludos, $nombre.*\n\n" .
"Recibes este mensaje porque el día *$fecha_orden_str* en la página web de *Tecno Group* generaste un pedido para obtener acceso a la *Membresía VIP de la Página de Análisis de Precios Unitarios*.\n\n" .
"Tu suscripción *$orden_id* que te da acceso a *$producto* expira el día *$fecha_expiracion_str*.\n\n" .
"*Pero tenemos buenas noticias 🎉: puedes obtener un cupón con 30% de descuento en la membresía anual (acceso por 365 días).*\n\n" .
"Aprovecha esta oportunidad para tener acceso completo a más de 130,000 ejemplos de precios unitarios, básicos, costos horarios y rendimientos.\n\n" .
"*Para recibir el cupón: responde con #365* (muy importante incluir el #, almohadilla o símbolo de gato antes del número 365, se tiene que ver así » #365).\n\n" .
"¿Tienes dudas o necesitas ayuda? Responde con la palabra *duda* y platicamos con gusto.";
// URL con mensaje en el query
$url = "https://n8n.primeleads.app/webhook/woocommerce-messages?text=" . rawurlencode($texto);
$payload = json_encode(['number' => $telefono]);
$args = [
'method' => 'POST',
'headers' => ['Content-Type' => 'application/json'],
'body' => $payload,
'timeout' => 10
];
if ($log) {
file_put_contents($log_path, "🌐 URL enviada: $url\n", FILE_APPEND);
file_put_contents($log_path, "📦 Payload: $payload\n", FILE_APPEND);
}
$response = wp_remote_request($url, $args);
if (is_wp_error($response)) {
$mensaje_respuesta = 'Error: ' . $response->get_error_message();
} else {
$body = wp_remote_retrieve_body($response);
$mensaje_respuesta = $body;
$json = json_decode($body, true);
if (is_array($json) && isset($json[0]['message'])) {
$mensaje_respuesta = $json[0]['message'];
}
}
$wpdb->update(
$tabla,
[
'api_enviado' => 1, // siempre se marca como procesado
'api_estatus' => $mensaje_respuesta
],
['id' => $orden->id]
);
if ($log) {
$log_msg = "📢 Resultado para $telefono ($nombre): $mensaje_respuesta";
file_put_contents($log_path, $log_msg . "\n", FILE_APPEND);
}
sleep(1);
}
}
function rcp_formatear_numero_telefono($numero) {
$original = $numero;
$cleaned = preg_replace('/\D/', '', $numero);
if (preg_match('/^521\d{10}$/', $cleaned)) {
return $cleaned;
}
if (preg_match('/^52\d{10}$/', $cleaned)) {
return '521' . substr($cleaned, 2);
}
return $cleaned;
}
// Zona horaria
function rcp_get_wp_timezone_string() {
$timezone = get_option('timezone_string');
if ($timezone) return $timezone;
$offset = (float) get_option('gmt_offset');
$hours = (int) $offset;
$minutes = ($offset - $hours) * 60;
return sprintf('UTC%+03d:%02d', $hours, $minutes);
}