- 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>
277 lines
10 KiB
PHP
Executable File
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);
|
|
} |