// ================================ // NOUVEAUTÉS v3.1.4 // ================================ echo '

🎉 NOUVEAUTÉS v3.1.4

Correction du problème des abonnements manqués :

🔧 1. CORRECTION RÉCUPÉRATION ABONNEMENTS

Problème résolu : Certains abonnements (ex: "Abonnement groupé") n\'apparaissaient pas dans SendGrid

Solution : Amélioration de la requête de récupération des produits MemberPress

Garantie : TOUS les abonnements sont maintenant synchronisés correctement

🧪 2. TESTS COMPLETS INTÉGRÉS

Vérification intégrité : Contrôle que toutes les fonctionnalités marchent

Test couverture : Vérifie que TOUS les abonnements sont bien récupérés

Simulation temps réel : Teste la synchronisation automatique

📊 3. DIAGNOSTIC AVANCÉ ABONNEMENTS

Analyse détaillée : Vue complète de tous les produits MemberPress

Répartition par statut : Comptage précis des abonnements par plan

Synchronisation forcée : Rattrapage des abonnements manqués

'; // ================================ // TESTS DE SÉCURITÉ ET INTÉGRITÉ v3.1.4 // ================================ echo '

🛡️ TESTS DE SÉCURITÉ ET INTÉGRITÉ

Vérifier que toutes les fonctionnalités marchent correctement

✅ Test Intégrité Complète

' . wp_nonce_field('sendgrid_action', 'sendgrid_nonce', true, false) . '
Vérifie que rien n\'a été cassé

📊 Test Couverture Abonnements

' . wp_nonce_field('sendgrid_action', 'sendgrid_nonce', true, false) . '
Vérifie nouveaux ET anciens abonnements

🔴 Test Live Temps Réel

' . wp_nonce_field('sendgrid_action', 'sendgrid_nonce', true, false) . '
Teste la synchronisation automatique

🎯 GARANTIES DE FONCTIONNEMENT

✅ Anciens abonnements : Synchronisation quotidienne complète traite TOUS les utilisateurs

✅ Nouveaux abonnements : Hooks temps réel pour synchronisation immédiate

✅ Modifications : Hooks sur tous les changements MemberPress et WordPress

✅ Fiabilité : Double sécurité (temps réel + quotidienne complète)

'; // ================================ // DIAGNOSTIC ABONNEMENTS v3.1.4 // ================================ echo '

🔍 DIAGNOSTIC ABONNEMENTS SPÉCIALISÉ

Analyser spécifiquement les problèmes d\'abonnements

🔍 Diagnostic Détaillé

' . wp_nonce_field('sendgrid_action', 'sendgrid_nonce', true, false) . '
Analyse tous les produits et souscriptions

🔄 Rattrapage Forcé

' . wp_nonce_field('sendgrid_action', 'sendgrid_nonce', true, false) . '
Re-synchronise tous les abonnements manqués
'; // ================================ // DIAGNOSTIC RAPIDE // ================================ echo '

🔍 DIAGNOSTIC RAPIDE

Identifiez rapidement les problèmes dans votre base de données

' . wp_nonce_field('sendgrid_action', 'sendgrid_nonce', true, false) . ' Analyse rapide des problèmes : emails, souscriptions, correspondances
'; // ================================ // ENRICHISSEMENT CORRIGÉ // ================================ echo '

🚀 ENRICHISSEMENT MANUEL COMPLET

Synchronisation manuelle immédiate de TOUS les utilisateurs

' . wp_nonce_field('sendgrid_action', 'sendgrid_nonce', true, false) . ' Synchronise TOUS les utilisateurs : nom, prénom, adresse, téléphone + données de souscription
'; // ================================ // TEST UTILISATEUR DÉTAILLÉ // ================================ echo '

🧪 Test Utilisateur Détaillé

' . wp_nonce_field('sendgrid_action', 'sendgrid_nonce', true, false) . '

Analyse complète : nom, prénom, adresse, téléphone, souscriptions
'; // ================================ // SYNCHRONISATION QUOTIDIENNE COMPLÈTE // ================================ $daily_enabled = get_option('sendgrid_daily_sync_enabled', false); $daily_time = get_option('sendgrid_daily_sync_time', '02:00'); $last_run = get_option('sendgrid_daily_sync_last_run', 'Jamais'); $next_run = wp_next_scheduled('sendgrid_daily_sync_cron') ? date('Y-m-d H:i:s', wp_next_scheduled('sendgrid_daily_sync_cron')) : 'Non planifié'; echo '

⏰ SYNCHRONISATION QUOTIDIENNE COMPLÈTE

Synchronisation automatique COMPLÈTE une fois par jour de TOUTE la base utilisateurs

🔄 ENRICHISSEMENT COMPLET

Mode complet : Traite TOUS les utilisateurs, pas seulement les modifications

Sécurité maximale : Assure que tous les contacts sont synchronisés

Récupération automatique : Répare les données manquantes ou incomplètes

📊 STATUT ACTUEL

État : ' . ($daily_enabled ? '✅ Activée' : '❌ Désactivée') . '

Heure : ' . $daily_time . '

Dernière exécution : ' . $last_run . '

Prochaine exécution : ' . $next_run . '

' . wp_nonce_field('sendgrid_action', 'sendgrid_nonce', true, false) . '

⚙️ CONFIGURATION


Recommandé : Entre 01:00 et 05:00 (faible trafic)

📊 DERNIER RAPPORT

'; $last_report = sendgrid_get_daily_sync_report(); if ($last_report['date'] !== 'Jamais') { echo '

Date : ' . $last_report['date'] . '

'; echo '

Utilisateurs traités : ' . $last_report['total'] . '

'; echo '

Succès : ' . $last_report['success'] . ' (' . $last_report['enriched'] . ' enrichis + ' . $last_report['simple'] . ' simples)

'; echo '

Erreurs : ' . $last_report['errors'] . '

'; echo '

Durée : ' . $last_report['duration'] . ' secondes

'; $success_rate = $last_report['total'] > 0 ? round(($last_report['success'] / $last_report['total']) * 100, 1) : 0; echo '

Taux de réussite : ' . $success_rate . '%

'; } else { echo '

Aucune synchronisation quotidienne effectuée encore

'; } echo '
'; // ================================ // STATUT SYNCHRONISATION AUTOMATIQUE // ================================ echo '

🔄 SYNCHRONISATION AUTOMATIQUE

Statut de la synchronisation en temps réel

'; $sync_status = sendgrid_get_auto_sync_status(); echo '

📋 Hooks MemberPress

'; foreach ($sync_status['memberpress_hooks'] as $hook => $active) { $icon = $active ? '✅' : '❌'; echo '

' . $icon . ' ' . str_replace('_', ' ', ucfirst($hook)) . '

'; } echo '

👤 Hooks WordPress

'; foreach ($sync_status['wordpress_hooks'] as $hook => $active) { $icon = $active ? '✅' : '❌'; echo '

' . $icon . ' ' . str_replace('_', ' ', ucfirst($hook)) . '

'; } echo '
' . wp_nonce_field('sendgrid_action', 'sendgrid_nonce', true, false) . '

🧪 Test Synchronisation Automatique

Teste si la synchronisation automatique fonctionne pour un utilisateur
'; echo ''; } // ============================================================================ // DIAGNOSTIC RAPIDE // ============================================================================ function sendgrid_quick_diagnostic() { global $wpdb; echo '
'; echo '

🔍 DIAGNOSTIC RAPIDE

'; // 1. STATISTIQUES DE BASE echo '

📊 1. STATISTIQUES DE BASE

'; $total_users = count(get_users(['fields' => 'ID'])); echo '

👥 Total utilisateurs WordPress : ' . $total_users . '

'; // 2. ANALYSE MEMBERPRESS if (class_exists('MeprSubscription')) { echo '

📋 2. ANALYSE MEMBERPRESS

'; $total_subs = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}mepr_subscriptions"); $active_subs = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}mepr_subscriptions WHERE status IN ('active', 'suspended')"); $users_with_subs = $wpdb->get_var("SELECT COUNT(DISTINCT user_id) FROM {$wpdb->prefix}mepr_subscriptions WHERE user_id > 0"); echo '

📋 Total souscriptions : ' . $total_subs . '

'; echo '

Souscriptions actives/suspendues : ' . $active_subs . '

'; echo '

👤 Utilisateurs avec souscriptions : ' . $users_with_subs . '

'; // Statuts détaillés $status_breakdown = $wpdb->get_results(" SELECT status, COUNT(*) as count FROM {$wpdb->prefix}mepr_subscriptions GROUP BY status ORDER BY count DESC "); echo '

📈 Répartition par statut :

'; foreach ($status_breakdown as $status) { echo '

• ' . ucfirst($status->status) . ': ' . $status->count . '

'; } } // 3. ESTIMATION ENRICHISSEMENT COMPLET echo '

🎯 3. ESTIMATION ENRICHISSEMENT COMPLET

'; $all_valid_users = $wpdb->get_var(" SELECT COUNT(*) FROM {$wpdb->prefix}users u WHERE u.user_email != '' AND u.user_email IS NOT NULL AND u.user_email LIKE '%@%' "); echo '

📧 Utilisateurs avec email valide : ' . $all_valid_users . '

'; if (class_exists('MeprSubscription')) { // Compter les utilisateurs enrichissables $enrichable_users = $wpdb->get_var(" SELECT COUNT(DISTINCT s.user_id) FROM {$wpdb->prefix}mepr_subscriptions s INNER JOIN {$wpdb->prefix}users u ON s.user_id = u.ID INNER JOIN {$wpdb->prefix}posts p ON s.product_id = p.ID WHERE u.user_email != '' AND u.user_email IS NOT NULL AND u.user_email LIKE '%@%' AND p.post_status = 'publish' AND p.post_type = 'memberpressproduct' AND s.user_id > 0 "); $active_enrichable = $wpdb->get_var(" SELECT COUNT(DISTINCT s.user_id) FROM {$wpdb->prefix}mepr_subscriptions s INNER JOIN {$wpdb->prefix}users u ON s.user_id = u.ID INNER JOIN {$wpdb->prefix}posts p ON s.product_id = p.ID WHERE u.user_email != '' AND u.user_email IS NOT NULL AND u.user_email LIKE '%@%' AND p.post_status = 'publish' AND p.post_type = 'memberpressproduct' AND s.user_id > 0 AND s.status IN ('active', 'suspended') "); echo '

🎯 Utilisateurs enrichissables (avec souscription) : ' . $enrichable_users . '

'; echo '

🎯 Utilisateurs avec souscription active : ' . $active_enrichable . '

'; $simple_users = $all_valid_users - $enrichable_users; echo '

👤 Utilisateurs simples (sans souscription) : ' . $simple_users . '

'; echo '

📊 SYNC QUOTIDIENNE COMPLÈTE :

'; echo '

Total à synchroniser : ' . $all_valid_users . ' utilisateurs

'; echo '

Enrichis avec souscription : ' . $enrichable_users . '

'; echo '

Contacts simples : ' . $simple_users . '

'; echo '

Durée estimée : ' . ceil($all_valid_users / 50) . ' minutes environ

'; } echo '
'; } // ============================================================================ // DIAGNOSTIC ABONNEMENTS DÉTAILLÉ (NOUVEAU v3.1.4) // ============================================================================ function sendgrid_diagnostic_memberships() { global $wpdb; echo '
'; echo '

🔍 DIAGNOSTIC DÉTAILLÉ DES ABONNEMENTS

'; // 1. TOUS LES PRODUITS MEMBERPRESS echo '

📋 1. TOUS LES PRODUITS MEMBERPRESS

'; $all_products = $wpdb->get_results(" SELECT ID, post_title, post_status, post_type FROM {$wpdb->prefix}posts WHERE post_type = 'memberpressproduct' ORDER BY post_title "); echo '

Total produits MemberPress : ' . count($all_products) . '

'; foreach ($all_products as $product) { $sub_count = $wpdb->get_var($wpdb->prepare(" SELECT COUNT(*) FROM {$wpdb->prefix}mepr_subscriptions WHERE product_id = %d ", $product->ID)); $active_sub_count = $wpdb->get_var($wpdb->prepare(" SELECT COUNT(*) FROM {$wpdb->prefix}mepr_subscriptions WHERE product_id = %d AND status IN ('active', 'suspended') ", $product->ID)); echo '
'; echo '

📦 ' . $product->post_title . ' (ID: ' . $product->ID . ')

'; echo '

• Statut: ' . $product->post_status . '

'; echo '

• Total souscriptions: ' . $sub_count . '

'; echo '

• Souscriptions actives: ' . $active_sub_count . '

'; echo '
'; } // 2. SOUSCRIPTIONS PAR STATUT echo '

📊 2. SOUSCRIPTIONS PAR STATUT

'; $status_breakdown = $wpdb->get_results(" SELECT s.status, COUNT(*) as count, p.post_title as product_name FROM {$wpdb->prefix}mepr_subscriptions s LEFT JOIN {$wpdb->prefix}posts p ON s.product_id = p.ID WHERE p.post_type = 'memberpressproduct' AND p.post_status = 'publish' GROUP BY s.status, p.post_title ORDER BY s.status, count DESC "); foreach ($status_breakdown as $stat) { echo '

' . ucfirst($stat->status) . ' - ' . $stat->product_name . ': ' . $stat->count . '

'; } // 3. TEST DE RÉCUPÉRATION POUR CHAQUE PRODUIT echo '

🧪 3. TEST RÉCUPÉRATION PAR PRODUIT

'; $all_products_with_subs = $wpdb->get_results(" SELECT DISTINCT p.ID, p.post_title as product_name FROM {$wpdb->prefix}posts p INNER JOIN {$wpdb->prefix}mepr_subscriptions s ON p.ID = s.product_id WHERE p.post_type = 'memberpressproduct' AND p.post_status = 'publish' ORDER BY p.post_title "); foreach ($all_products_with_subs as $product) { // Prendre un utilisateur avec cet abonnement $sample_user = $wpdb->get_row($wpdb->prepare(" SELECT s.user_id, u.user_email, s.status FROM {$wpdb->prefix}mepr_subscriptions s INNER JOIN {$wpdb->prefix}users u ON s.user_id = u.ID WHERE s.product_id = %d AND s.status IN ('active', 'suspended') LIMIT 1 ", $product->ID)); if ($sample_user) { $user_data = sendgrid_get_user_data_for_sync($sample_user->user_id); $success = ($user_data && $user_data->product_name === $product->product_name); $icon = $success ? '✅' : '❌'; echo '

' . $icon . ' ' . $product->product_name . ' - Test user ' . $sample_user->user_id . ' (' . $sample_user->user_email . ')

'; if (!$success && $user_data) { echo '

⚠️ Nom récupéré: "' . ($user_data->product_name ?: 'VIDE') . '"

'; } } else { echo '

⚠️ ' . $product->product_name . ' - Aucun utilisateur actif trouvé

'; } } echo '
'; } // ============================================================================ // SYNCHRONISATION FORCÉE ABONNEMENTS MANQUÉS (NOUVEAU v3.1.4) // ============================================================================ function sendgrid_force_sync_missing_subscriptions() { global $wpdb; echo '
'; echo '

🔄 SYNCHRONISATION FORCÉE DES ABONNEMENTS MANQUÉS

'; // Récupérer tous les utilisateurs avec souscriptions actives par produit $users_by_product = $wpdb->get_results(" SELECT s.user_id, s.status, p.ID as product_id, p.post_title as product_name, u.user_email FROM {$wpdb->prefix}mepr_subscriptions s INNER JOIN {$wpdb->prefix}posts p ON s.product_id = p.ID INNER JOIN {$wpdb->prefix}users u ON s.user_id = u.ID WHERE p.post_type = 'memberpressproduct' AND p.post_status = 'publish' AND s.status IN ('active', 'suspended') AND u.user_email != '' AND u.user_email IS NOT NULL ORDER BY p.post_title, s.user_id "); $products_stats = []; $sync_results = []; foreach ($users_by_product as $user_sub) { // Compter par produit if (!isset($products_stats[$user_sub->product_name])) { $products_stats[$user_sub->product_name] = 0; } $products_stats[$user_sub->product_name]++; // Synchroniser cet utilisateur $user_data = sendgrid_get_user_data_for_sync($user_sub->user_id); if ($user_data) { $result = sendgrid_enrich_user_fixed($user_data); if (!isset($sync_results[$user_sub->product_name])) { $sync_results[$user_sub->product_name] = ['success' => 0, 'error' => 0]; } if ($result['success']) { $sync_results[$user_sub->product_name]['success']++; } else { $sync_results[$user_sub->product_name]['error']++; } } // Pause pour éviter la surcharge usleep(100000); // 0.1 seconde } echo '

📊 RÉSULTATS PAR PRODUIT

'; foreach ($products_stats as $product_name => $count) { $success = isset($sync_results[$product_name]) ? $sync_results[$product_name]['success'] : 0; $errors = isset($sync_results[$product_name]) ? $sync_results[$product_name]['error'] : 0; echo '
'; echo '

📦 ' . $product_name . '

'; echo '

• Total utilisateurs: ' . $count . '

'; echo '

• Synchronisés: ' . $success . '

'; echo '

• Erreurs: ' . $errors . '

'; echo '
'; } echo '
'; } // ============================================================================ // NOUVELLES FONCTIONS DE TEST v3.1.4 // ============================================================================ function sendgrid_verify_all_hooks_active() { echo '
'; echo '

✅ VÉRIFICATION INTÉGRITÉ DES FONCTIONNALITÉS

'; // 1. VÉRIFIER LES HOOKS AUTOMATIQUES echo '

🔄 1. SYNCHRONISATION AUTOMATIQUE (TEMPS RÉEL)

'; $memberpress_hooks = [ 'mepr-event-subscription-created' => 'Création abonnement', 'mepr-event-subscription-renewed' => 'Renouvellement abonnement', 'mepr-event-subscription-expired' => 'Expiration abonnement', 'mepr-event-subscription-stopped' => 'Arrêt abonnement', 'mepr-event-subscription-upgraded' => 'Upgrade abonnement', 'mepr-event-subscription-downgraded' => 'Downgrade abonnement', 'mepr-event-subscription-changed' => 'Modification abonnement', 'mepr-event-subscription-resumed' => 'Reprise abonnement', 'mepr-event-subscription-suspended' => 'Suspension abonnement', 'mepr-event-transaction-completed' => 'Transaction complétée', 'mepr-event-transaction-expired' => 'Transaction expirée', 'mepr-event-transaction-failed' => 'Transaction échouée', 'mepr-event-transaction-refunded' => 'Transaction remboursée', ]; foreach ($memberpress_hooks as $hook => $description) { $active = has_action($hook, 'sendgrid_auto_sync_user'); $icon = $active ? '✅' : '❌'; echo '

' . $icon . ' ' . $description . ' (' . $hook . ')

'; } $wordpress_hooks = [ 'profile_update' => 'Modification profil utilisateur', 'user_register' => 'Inscription utilisateur', 'personal_options_update' => 'Mise à jour options personnelles', 'edit_user_profile_update' => 'Modification profil admin', 'wp_update_user' => 'Mise à jour utilisateur WordPress', 'wp_insert_user' => 'Insertion nouvel utilisateur', ]; echo '
👤 Hooks WordPress :
'; foreach ($wordpress_hooks as $hook => $description) { $active = has_action($hook); $icon = $active ? '✅' : '❌'; echo '

' . $icon . ' ' . $description . '

'; } // 2. VÉRIFIER LA SYNCHRONISATION QUOTIDIENNE echo '

⏰ 2. SYNCHRONISATION QUOTIDIENNE COMPLÈTE

'; $daily_enabled = get_option('sendgrid_daily_sync_enabled', false); $daily_time = get_option('sendgrid_daily_sync_time', '02:00'); $next_run = wp_next_scheduled('sendgrid_daily_sync_cron'); echo '

Statut : ' . ($daily_enabled ? 'Activée' : 'Désactivée') . '

'; echo '

Heure : ' . $daily_time . '

'; echo '

Prochaine exécution : ' . ($next_run ? date('Y-m-d H:i:s', $next_run) : 'Non planifiée') . '

'; echo '

Hook quotidien : ' . (has_action('sendgrid_daily_sync_cron', 'sendgrid_run_daily_sync') ? 'Actif' : 'Inactif') . '

'; // 3. VÉRIFIER L'API SENDGRID echo '

🔑 3. CONFIGURATION API

'; $api_key = get_option('sendgrid_api_key'); echo '

Clé API : ' . ($api_key ? 'Configurée' : 'Manquante') . '

'; // 4. TEST RAPIDE SUR ÉCHANTILLON echo '

🧪 4. TEST ÉCHANTILLON (3 utilisateurs récents)

'; global $wpdb; $sample_users = $wpdb->get_results(" SELECT u.ID, u.user_email, u.user_registered FROM {$wpdb->prefix}users u WHERE u.user_email LIKE '%@%' ORDER BY u.user_registered DESC LIMIT 3 "); foreach ($sample_users as $user) { $user_data = sendgrid_get_user_data_for_sync($user->ID); if ($user_data) { $has_subscription = !empty($user_data->subscription_id); $plan_name = $has_subscription ? ($user_data->product_name ?: 'Plan sans nom') : 'Aucun plan'; echo '

✅ User ' . $user->ID . ' (' . $user->user_email . ') - Plan: "' . $plan_name . '"

'; } else { echo '

❌ User ' . $user->ID . ' - Erreur récupération données

'; } } echo '
'; } function sendgrid_test_all_subscriptions_coverage() { global $wpdb; echo '
'; echo '

📊 TEST COUVERTURE COMPLÈTE DES ABONNEMENTS

'; // 1. TOUS LES ABONNEMENTS PAR PÉRIODE echo '

📅 1. RÉPARTITION TEMPORELLE DES ABONNEMENTS

'; $temporal_stats = $wpdb->get_results(" SELECT CASE WHEN s.created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) THEN 'Derniers 30 jours' WHEN s.created_at >= DATE_SUB(NOW(), INTERVAL 90 DAY) THEN 'Derniers 90 jours' WHEN s.created_at >= DATE_SUB(NOW(), INTERVAL 1 YEAR) THEN 'Dernière année' ELSE 'Plus ancien' END as periode, COUNT(*) as total, COUNT(CASE WHEN s.status IN ('active', 'suspended') THEN 1 END) as actifs, p.post_title as product_name FROM {$wpdb->prefix}mepr_subscriptions s LEFT JOIN {$wpdb->prefix}posts p ON s.product_id = p.ID WHERE p.post_type = 'memberpressproduct' AND p.post_status = 'publish' GROUP BY periode, p.post_title ORDER BY CASE periode WHEN 'Derniers 30 jours' THEN 1 WHEN 'Derniers 90 jours' THEN 2 WHEN 'Dernière année' THEN 3 ELSE 4 END, p.post_title "); foreach ($temporal_stats as $stat) { echo '
'; echo '

📦 ' . $stat->product_name . ' - ' . $stat->periode . '

'; echo '

• Total: ' . $stat->total . ' | Actifs: ' . $stat->actifs . '

'; echo '
'; } // 2. TEST DE RÉCUPÉRATION POUR CHAQUE PRODUIT echo '

🧪 2. TEST RÉCUPÉRATION PAR PRODUIT

'; $all_products = $wpdb->get_results(" SELECT DISTINCT p.ID, p.post_title as product_name FROM {$wpdb->prefix}posts p INNER JOIN {$wpdb->prefix}mepr_subscriptions s ON p.ID = s.product_id WHERE p.post_type = 'memberpressproduct' AND p.post_status = 'publish' ORDER BY p.post_title "); foreach ($all_products as $product) { // Prendre un utilisateur avec cet abonnement $sample_user = $wpdb->get_row($wpdb->prepare(" SELECT s.user_id, u.user_email, s.status FROM {$wpdb->prefix}mepr_subscriptions s INNER JOIN {$wpdb->prefix}users u ON s.user_id = u.ID WHERE s.product_id = %d AND s.status IN ('active', 'suspended') LIMIT 1 ", $product->ID)); if ($sample_user) { $user_data = sendgrid_get_user_data_for_sync($sample_user->user_id); $success = ($user_data && $user_data->product_name === $product->product_name); $icon = $success ? '✅' : '❌'; echo '

' . $icon . ' ' . $product->product_name . ' - Test user ' . $sample_user->user_id . ' (' . $sample_user->user_email . ')

'; if (!$success && $user_data) { echo '

⚠️ Nom récupéré: "' . ($user_data->product_name ?: 'VIDE') . '"

'; } } else { echo '

⚠️ ' . $product->product_name . ' - Aucun utilisateur actif trouvé

'; } } // 3. SIMULATION AJOUT NOUVEL ABONNEMENT echo '

🆕 3. SIMULATION NOUVEL ABONNEMENT

'; echo '
'; echo '

📋 Hooks automatiques configurés pour nouveaux abonnements :

'; echo '

✅ Création abonnement → mepr-event-subscription-created

'; echo '

✅ Transaction complétée → mepr-event-transaction-completed

'; echo '

✅ Inscription utilisateur → user_register

'; echo '

🔄 Processus automatique :

'; echo '

1. Nouvel abonnement créé dans MemberPress

'; echo '

2. Hook automatique déclenché immédiatement

'; echo '

3. Synchronisation avec SendGrid en temps réel

'; echo '

4. + Synchronisation quotidienne complète comme filet de sécurité

'; echo '
'; echo '
'; } function sendgrid_test_live_subscription_sync() { global $wpdb; echo '
'; echo '

🔴 TEST LIVE - SIMULATION ÉVÉNEMENT ABONNEMENT

'; // Prendre un utilisateur avec abonnement actif $test_user = $wpdb->get_row(" SELECT s.user_id, s.id as subscription_id, u.user_email, p.post_title as product_name, s.status FROM {$wpdb->prefix}mepr_subscriptions s INNER JOIN {$wpdb->prefix}users u ON s.user_id = u.ID INNER JOIN {$wpdb->prefix}posts p ON s.product_id = p.ID WHERE s.status IN ('active', 'suspended') AND p.post_type = 'memberpressproduct' AND p.post_status = 'publish' ORDER BY s.created_at DESC LIMIT 1 "); if (!$test_user) { echo '

❌ Aucun utilisateur avec abonnement actif trouvé pour le test

'; echo '
'; return; } echo '

👤 Utilisateur test : ' . $test_user->user_email . ' (ID: ' . $test_user->user_id . ')

'; echo '

📦 Abonnement : ' . $test_user->product_name . ' (' . $test_user->status . ')

'; // Test 1 : Récupération des données echo '

🔍 Test 1 : Récupération des données

'; $user_data = sendgrid_get_user_data_for_sync($test_user->user_id); if ($user_data && $user_data->subscription_id) { echo '

Données récupérées avec succès

'; echo '

• Plan: "' . ($user_data->product_name ?: 'ERREUR: Nom manquant') . '"

'; echo '

• Status: ' . $user_data->status . '

'; echo '

• Product ID: ' . $user_data->product_id . '

'; echo '

• Subscription ID: ' . $user_data->subscription_id . '

'; } else { echo '

Échec récupération des données

'; echo ''; return; } // Test 2 : Simulation synchronisation automatique echo '

🔄 Test 2 : Simulation synchronisation automatique

'; echo '

🧪 Simulation de l\'événement MemberPress...

'; // Vérifier que la fonction d'enrichissement fonctionne $enrichment_result = sendgrid_enrich_user_fixed($user_data); if ($enrichment_result['success']) { echo '

Enrichissement OK - Type: ' . $enrichment_result['type'] . '

'; echo '

📤 Prêt pour SendGrid - Plan: "' . ($user_data->product_name ?: 'ERREUR') . '"

'; } else { echo '

Échec enrichissement

'; } echo ''; } // ============================================================================ // TEST UTILISATEUR DÉTAILLÉ // ============================================================================ function sendgrid_test_user_detailed($user_id) { global $wpdb; echo '
'; echo '

🔍 TEST DÉTAILLÉ - Utilisateur ID: ' . $user_id . '

'; // 1. DONNÉES UTILISATEUR $user = get_userdata($user_id); if (!$user) { echo '

❌ Utilisateur non trouvé

'; echo '
'; return; } echo '

👤 1. DONNÉES UTILISATEUR

'; echo '

Email: ' . $user->user_email . '

'; echo '

Login: ' . $user->user_login . '

'; echo '

Display Name: ' . $user->display_name . '

'; echo '

Email valide: ' . (is_email($user->user_email) ? '✅' : '❌') . '

'; // 2. SOUSCRIPTIONS echo '

📋 2. SOUSCRIPTIONS

'; if (class_exists('MeprSubscription')) { $subscriptions = $wpdb->get_results($wpdb->prepare(" SELECT s.*, p.post_title as product_name, p.post_status FROM {$wpdb->prefix}mepr_subscriptions s LEFT JOIN {$wpdb->prefix}posts p ON s.product_id = p.ID WHERE s.user_id = %d ORDER BY s.created_at DESC ", $user_id), ARRAY_A); if (empty($subscriptions)) { echo '

❌ Aucune souscription trouvée

'; } else { echo '

' . count($subscriptions) . ' souscription(s) trouvée(s)

'; foreach ($subscriptions as $sub) { echo '
'; echo '

ID: ' . $sub['id'] . ' | Status: ' . $sub['status'] . '

'; echo '

Produit: ' . ($sub['product_name'] ?: 'PRODUIT MANQUANT') . ' (ID: ' . $sub['product_id'] . ')

'; echo '

Statut produit: ' . ($sub['post_status'] ?: 'INVALIDE') . '

'; echo '

Créé: ' . $sub['created_at'] . '

'; echo '

Expire: ' . ($sub['expires_at'] ?: 'PAS DE DATE') . '

'; echo '
'; } } } // 3. SIMULATION ENRICHISSEMENT echo '

🚀 3. SIMULATION ENRICHISSEMENT

'; // Utiliser la vraie fonction d'enrichissement en mode simulation $user_data = sendgrid_get_user_data_for_sync($user_id); if ($user_data) { $user_data = sendgrid_ensure_all_properties($user_data); // Simulation de l'enrichissement if (!$user_data->subscription_id) { $result = ['success' => true, 'type' => 'simple', 'plan_name' => 'Aucun Plan', 'start_date' => '', 'end_date' => '', 'subscription_status' => 'no-subscription', 'auto_rebill' => 'n/a']; } else { $is_active = in_array($user_data->status, ['active', 'suspended']); $result = [ 'success' => true, 'type' => 'subscription', 'plan_name' => $user_data->product_name ?: 'Plan MemberPress', 'start_date' => $user_data->created_at ? (new DateTime($user_data->created_at))->format('Y-m-d') : '', 'end_date' => $user_data->expires_at ? (new DateTime($user_data->expires_at))->format('Y-m-d') : '', 'subscription_status' => $user_data->status ?: 'unknown', 'auto_rebill' => $is_active ? 'enabled' : 'disabled' ]; } } else { $result = ['success' => false, 'error' => 'Impossible de récupérer les données utilisateur']; } if ($result['success']) { echo '

Enrichissement OK

'; echo '

Type: ' . $result['type'] . '

'; echo '

Plan: ' . $result['plan_name'] . '

'; echo '

Start Date: ' . $result['start_date'] . '

'; echo '

End Date: ' . $result['end_date'] . '

'; echo '

Status: ' . $result['subscription_status'] . '

'; echo '

Auto Rebill: ' . $result['auto_rebill'] . '

'; } else { echo '

Échec enrichissement: ' . $result['error'] . '

'; } // 4. TOUS LES CHAMPS RÉCUPÉRÉS echo '

📋 4. TOUS LES CHAMPS RÉCUPÉRÉS

'; $all_fields = sendgrid_get_complete_user_fields($user_id); echo '
'; echo '

📧 Email: ' . $user->user_email . '

'; echo '

👤 Prénom: "' . $all_fields['first_name'] . '"

'; echo '

👤 Nom: "' . $all_fields['last_name'] . '"

'; echo '

🏠 Adresse 1: "' . $all_fields['address_line_1'] . '"

'; echo '

🏠 Adresse 2: "' . $all_fields['address_line_2'] . '"

'; echo '

🏙️ Ville: "' . $all_fields['city'] . '"

'; echo '

📍 État/Province: "' . $all_fields['state_province_region'] . '"

'; echo '

📮 Code postal: "' . $all_fields['postal_code'] . '"

'; echo '

🌍 Pays: "' . $all_fields['country'] . '"

'; echo '

📞 Téléphone: "' . $all_fields['phone_number'] . '"

'; echo '
'; // 5. SOURCES DES DONNÉES echo '

🔍 5. SOURCES DES DONNÉES

'; echo '
'; // Vérifier les sources pour le nom/prénom $wp_first = get_user_meta($user_id, 'first_name', true); $wp_last = get_user_meta($user_id, 'last_name', true); echo '

Nom/Prénom WordPress: "' . $wp_first . '" "' . $wp_last . '"

'; // Vérifier les sources MemberPress $mepr_address = get_user_meta($user_id, 'mepr-address-one', true); $mepr_city = get_user_meta($user_id, 'mepr-address-city', true); $mepr_phone = get_user_meta($user_id, 'mepr-phone', true); echo '

MemberPress: Adresse: "' . $mepr_address . '" | Ville: "' . $mepr_city . '" | Téléphone: "' . $mepr_phone . '"

'; // Vérifier les sources WooCommerce $woo_address = get_user_meta($user_id, 'billing_address_1', true); $woo_city = get_user_meta($user_id, 'billing_city', true); $woo_phone = get_user_meta($user_id, 'billing_phone', true); echo '

WooCommerce: Adresse: "' . $woo_address . '" | Ville: "' . $woo_city . '" | Téléphone: "' . $woo_phone . '"

'; echo '
'; echo ''; } // ============================================================================ // ENRICHISSEMENT CORRIGÉ - TOUS LES UTILISATEURS // ============================================================================ function sendgrid_fixed_enrichment() { global $wpdb; echo '
'; echo '

🚀 ENRICHISSEMENT COMPLET DE TOUS LES UTILISATEURS

'; // Étape 1 : TOUS les utilisateurs avec email valide (pas de filtre de date) $all_users = $wpdb->get_results(" SELECT u.ID, u.user_email, u.user_login FROM {$wpdb->prefix}users u WHERE u.user_email != '' AND u.user_email IS NOT NULL AND u.user_email LIKE '%@%' ORDER BY u.ID "); echo '

👥 TOUS les utilisateurs avec email valide : ' . count($all_users) . '

'; if (empty($all_users)) { echo '

❌ Aucun utilisateur avec email valide trouvé

'; echo '
'; return; } // Étape 2 : Enrichir chaque utilisateur individuellement echo '

🚀 Enrichissement complet de tous les utilisateurs

'; $enrichable_users = []; foreach ($all_users as $user) { // Récupérer les souscriptions pour cet utilisateur avec vérifications isset() $user_subscriptions = $wpdb->get_results($wpdb->prepare(" SELECT s.*, p.post_title as product_name, p.post_type, p.post_status FROM {$wpdb->prefix}mepr_subscriptions s LEFT JOIN {$wpdb->prefix}posts p ON s.product_id = p.ID WHERE s.user_id = %d ORDER BY CASE s.status WHEN 'active' THEN 1 WHEN 'suspended' THEN 2 ELSE 3 END, s.created_at DESC ", $user->ID)); // Ajouter l'utilisateur avec sa meilleure souscription (ou null) avec vérifications $user_data = (object) [ 'ID' => $user->ID, 'user_email' => $user->user_email, 'user_login' => $user->user_login, 'subscription_id' => null, 'status' => null, 'created_at' => null, 'expires_at' => null, 'product_id' => null, 'product_name' => null ]; if (!empty($user_subscriptions)) { $best_sub = $user_subscriptions[0]; // Déjà trié par priorité $user_data->subscription_id = isset($best_sub->id) ? $best_sub->id : null; $user_data->status = isset($best_sub->status) ? $best_sub->status : null; $user_data->created_at = isset($best_sub->created_at) ? $best_sub->created_at : null; $user_data->expires_at = isset($best_sub->expires_at) ? $best_sub->expires_at : null; $user_data->product_id = isset($best_sub->product_id) ? $best_sub->product_id : null; $user_data->product_name = isset($best_sub->product_name) ? $best_sub->product_name : null; } $enrichable_users[] = $user_data; } echo '

🎯 TOUS les utilisateurs à enrichir : ' . count($enrichable_users) . '

'; $total = count($enrichable_users); $success_count = 0; $error_count = 0; $enriched_with_subscription = 0; $simple_contacts = 0; // Progress bar améliorée echo '
'; echo '

📊 Progression de l\'Enrichissement Complet

'; echo '
'; echo '
'; echo '
0%
'; echo '
'; echo '
'; echo '
'; echo '
0
'; echo '
✅ Succès
'; echo '
'; echo '
'; echo '
0
'; echo '
📋 Enrichis
'; echo '
'; echo '
'; echo '
0
'; echo '
👤 Simples
'; echo '
'; echo '
'; echo '
0
'; echo '
❌ Erreurs
'; echo '
'; echo '
'; echo '
'; echo '
🚀 Initialisation de l\'enrichissement complet...
'; echo '
Préparation des données utilisateur...
'; echo '
⏱️ Temps écoulé: 0s | ETA: Calcul en cours...
'; echo '
'; echo '
'; $start_time = time(); // Traitement de chaque utilisateur avec progression détaillée foreach ($enrichable_users as $index => $user_data) { $current = $index + 1; $result = sendgrid_enrich_user_fixed($user_data); if ($result['success']) { $success_count++; if ($result['type'] === 'subscription') { $enriched_with_subscription++; } else { $simple_contacts++; } } else { $error_count++; } // Calculs de progression $percentage = round(($current / $total) * 100, 1); $elapsed_time = time() - $start_time; $rate = $elapsed_time > 0 ? $current / $elapsed_time : 0; $eta = $rate > 0 ? round(($total - $current) / $rate) : 0; // Formatage du temps $elapsed_formatted = $elapsed_time < 60 ? $elapsed_time . 's' : floor($elapsed_time / 60) . 'm ' . ($elapsed_time % 60) . 's'; $eta_formatted = $eta < 60 ? $eta . 's' : floor($eta / 60) . 'm ' . ($eta % 60) . 's'; // Déterminer l'emoji et le message selon le résultat $status_emoji = $result['success'] ? ($result['type'] === 'subscription' ? '📋' : '👤') : '❌'; $status_message = $result['success'] ? ($result['type'] === 'subscription' ? 'ENRICHI avec souscription' : 'Contact simple') : 'ERREUR'; // Mise à jour de l'interface en temps réel echo ''; ob_flush(); flush(); // Pause adaptative selon la charge if ($current % 50 == 0) { usleep(200000); // 0.2 seconde toutes les 50 entrées } else { usleep(75000); // 0.075 seconde entre chaque contact } } $total_time = time() - $start_time; // Animation finale de completion echo ''; echo '

🎉 RÉSULTATS FINAUX

'; echo '

Total traités : ' . $total . '

'; echo '

📋 Contacts enrichis avec souscription : ' . $enriched_with_subscription . '

'; echo '

👤 Contacts simples : ' . $simple_contacts . '

'; echo '

Erreurs : ' . $error_count . '

'; echo '

📊 Taux de réussite : ' . round(($success_count / max($total, 1)) * 100, 1) . '%

'; if ($enriched_with_subscription > 0) { echo '

🎯 ' . $enriched_with_subscription . ' contacts ont maintenant nom + prénom + adresses + end_date correctes !

'; } echo ''; } // ============================================================================ // FONCTION D'ENRICHISSEMENT AMÉLIORÉE v3.1.4 // ============================================================================ function sendgrid_enrich_user_fixed($user_data) { // Validation de base if (!$user_data || !$user_data->ID || !is_email($user_data->user_email)) { return ['success' => false, 'error' => 'Données utilisateur invalides']; } // S'assurer que toutes les propriétés existent (sécurité supplémentaire) $user_data = sendgrid_ensure_all_properties($user_data); // Vérifier si l'utilisateur a une souscription if (!$user_data->subscription_id) { // Utilisateur sans souscription return sendgrid_send_simple_contact_fixed($user_data); } else { // Utilisateur avec souscription return sendgrid_send_enriched_contact_fixed($user_data, $user_data); } } function sendgrid_send_simple_contact_fixed($user_data) { // Récupérer TOUS les champs utilisateur $user_fields = sendgrid_get_complete_user_fields($user_data->ID); $custom_fields = [ 'Merkatis_plan_name' => 'Aucun Plan', 'Merkatis_start_date' => '', 'Merkatis_end_date' => '', 'Merkatis_subscription_status' => 'no-subscription', 'Merkatis_auto_rebill' => 'n/a', 'Merkatis_user_id' => (string)$user_data->ID, 'Merkatis_user_login' => $user_data->user_login, 'Merkatis_product_id' => '', 'Merkatis_source_type' => 'user-simple-fixed', 'Merkatis_last_sync' => date('Y-m-d H:i:s'), ]; $result = sendgrid_api_call_fixed($user_data, $custom_fields, $user_fields); return [ 'success' => $result, 'type' => 'simple', 'message' => $result ? 'Contact simple envoyé' : 'Erreur envoi contact simple' ]; } function sendgrid_send_enriched_contact_fixed($user_data, $subscription) { $is_active = in_array($subscription->status, ['active', 'suspended']); // Récupérer TOUS les champs utilisateur $user_fields = sendgrid_get_complete_user_fields($user_data->ID); // AMÉLIORATION v3.1.4 : Meilleure gestion du nom du plan $plan_name = 'Plan MemberPress'; // Valeur par défaut if (isset($subscription->product_name) && !empty($subscription->product_name)) { $plan_name = $subscription->product_name; } else { // Fallback : essayer de récupérer le nom du produit directement if (isset($subscription->product_id) && !empty($subscription->product_id)) { $product_title = get_the_title($subscription->product_id); if (!empty($product_title) && $product_title !== 'Auto Draft') { $plan_name = $product_title; } } } // Log pour debugging error_log('📋 SENDGRID ENRICHMENT: User ' . $user_data->ID . ' - Plan final: "' . $plan_name . '"'); // Calcul de la date d'expiration (avec vérification de propriété) $end_date = isset($subscription->expires_at) ? $subscription->expires_at : ''; if (empty($end_date) || $end_date === '0000-00-00 00:00:00') { if ($is_active && !empty($subscription->created_at)) { $end_date = sendgrid_calculate_expiry_fixed($subscription); } else { $end_date = ''; } } // Format des dates (avec vérifications) $start_date = ''; if (!empty($subscription->created_at) && $subscription->created_at !== '0000-00-00 00:00:00') { try { $start_date = (new DateTime($subscription->created_at))->format('Y-m-d'); } catch (Exception $e) { $start_date = ''; } } $formatted_end_date = ''; if (!empty($end_date) && $end_date !== '0000-00-00 00:00:00') { try { $formatted_end_date = (new DateTime($end_date))->format('Y-m-d'); } catch (Exception $e) { $formatted_end_date = ''; } } $custom_fields = [ 'Merkatis_plan_name' => $plan_name, // Utiliser le nom corrigé 'Merkatis_start_date' => $start_date, 'Merkatis_end_date' => $formatted_end_date, 'Merkatis_subscription_status' => isset($subscription->status) ? $subscription->status : 'unknown', 'Merkatis_auto_rebill' => $is_active ? 'enabled' : 'disabled', 'Merkatis_user_id' => (string)$user_data->ID, 'Merkatis_user_login' => $user_data->user_login, 'Merkatis_product_id' => isset($subscription->product_id) ? (string)$subscription->product_id : '', 'Merkatis_source_type' => 'subscription-enriched-fixed', 'Merkatis_last_sync' => date('Y-m-d H:i:s'), ]; $result = sendgrid_api_call_fixed($user_data, $custom_fields, $user_fields); return [ 'success' => $result, 'type' => 'subscription', 'message' => $result ? 'Contact enrichi avec souscription: ' . $plan_name : 'Erreur envoi contact enrichi' ]; } function sendgrid_calculate_expiry_fixed($subscription) { $created_at = isset($subscription->created_at) ? $subscription->created_at : ''; if (empty($created_at)) { return ''; } try { // Utiliser l'ID de souscription pour récupérer l'objet MemberPress $subscription_id = isset($subscription->subscription_id) ? $subscription->subscription_id : (isset($subscription->id) ? $subscription->id : null); if ($subscription_id && class_exists('MeprSubscription')) { $mepr_sub = new MeprSubscription($subscription_id); if ($mepr_sub && isset($mepr_sub->period) && isset($mepr_sub->period_type)) { $created = new DateTime($created_at); $period = intval($mepr_sub->period); $period_type = $mepr_sub->period_type; switch ($period_type) { case 'days': $created->add(new DateInterval('P' . $period . 'D')); break; case 'weeks': $created->add(new DateInterval('P' . ($period * 7) . 'D')); break; case 'months': $created->add(new DateInterval('P' . $period . 'M')); break; case 'years': $created->add(new DateInterval('P' . $period . 'Y')); break; default: $created->add(new DateInterval('P1M')); } return $created->format('Y-m-d H:i:s'); } } } catch (Exception $e) { error_log('SENDGRID CALC ERROR: ' . $e->getMessage()); } // Fallback : ajouter 1 mois à la date de création try { $created = new DateTime($created_at); $created->add(new DateInterval('P1M')); return $created->format('Y-m-d H:i:s'); } catch (Exception $e) { return ''; } } function sendgrid_api_call_fixed($user_data, $custom_fields, $user_fields = null) { $api_key = get_option('sendgrid_api_key'); if (!$api_key) { return false; } // Si les champs utilisateur ne sont pas fournis, les récupérer if ($user_fields === null) { $user_fields = sendgrid_get_complete_user_fields($user_data->ID); } error_log('🔄 SENDGRID API: Envoi contact - ' . $user_data->user_email . ' avec tous les champs'); $payload = [ 'contacts' => [[ 'email' => $user_data->user_email, 'first_name' => $user_fields['first_name'], 'last_name' => $user_fields['last_name'], 'address_line_1' => $user_fields['address_line_1'], 'address_line_2' => $user_fields['address_line_2'], 'city' => $user_fields['city'], 'state_province_region' => $user_fields['state_province_region'], 'postal_code' => $user_fields['postal_code'], 'country' => $user_fields['country'], 'phone_number' => $user_fields['phone_number'], 'custom_fields' => $custom_fields ]] ]; $response = wp_remote_request('https://api.sendgrid.com/v3/marketing/contacts', [ 'headers' => [ 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json' ], 'body' => json_encode($payload), 'method' => 'PUT', 'timeout' => 30 ]); if (is_wp_error($response)) { error_log('SENDGRID FIXED ERROR: ' . $response->get_error_message()); return false; } $status_code = wp_remote_retrieve_response_code($response); if ($status_code == 200 || $status_code == 202) { error_log('✅ SENDGRID API: Contact envoyé avec succès - ' . $user_data->user_email); return true; } else { $body = wp_remote_retrieve_body($response); error_log('❌ SENDGRID API ERROR: Code ' . $status_code . ' - ' . $body); return false; } } // ============================================================================ // FONCTION POUR RÉCUPÉRER TOUS LES CHAMPS UTILISATEUR // ============================================================================ function sendgrid_get_complete_user_fields($user_id) { $user = get_userdata($user_id); if (!$user) { return sendgrid_get_empty_user_fields(); } // Récupérer les champs de base WordPress $first_name = get_user_meta($user_id, 'first_name', true); $last_name = get_user_meta($user_id, 'last_name', true); // Si pas de nom/prénom dans meta, essayer depuis user_login ou display_name if (empty($first_name) && empty($last_name)) { // Essayer de diviser le display_name $display_name = $user->display_name; if (!empty($display_name) && $display_name !== $user->user_login) { $name_parts = explode(' ', trim($display_name), 2); $first_name = $name_parts[0]; $last_name = isset($name_parts[1]) ? $name_parts[1] : ''; } } // Champs d'adresse - Vérifier plusieurs sources possibles $address_fields = sendgrid_get_address_fields($user_id); // Numéro de téléphone - Vérifier plusieurs sources $phone = sendgrid_get_phone_number($user_id); $user_fields = [ 'first_name' => $first_name ?: '', 'last_name' => $last_name ?: '', 'address_line_1' => $address_fields['address_line_1'], 'address_line_2' => $address_fields['address_line_2'], 'city' => $address_fields['city'], 'state_province_region' => $address_fields['state_province_region'], 'postal_code' => $address_fields['postal_code'], 'country' => $address_fields['country'], 'phone_number' => $phone ]; error_log('👤 SENDGRID USER FIELDS: ' . $user->user_email . ' - Nom: "' . $first_name . '" "' . $last_name . '" - Ville: "' . $address_fields['city'] . '"'); return $user_fields; } function sendgrid_get_empty_user_fields() { return [ 'first_name' => '', 'last_name' => '', 'address_line_1' => '', 'address_line_2' => '', 'city' => '', 'state_province_region' => '', 'postal_code' => '', 'country' => '', 'phone_number' => '' ]; } function sendgrid_get_address_fields($user_id) { // Essayer plusieurs sources pour les champs d'adresse // 1. Champs MemberPress $mepr_address = get_user_meta($user_id, 'mepr-address-one', true); $mepr_address2 = get_user_meta($user_id, 'mepr-address-two', true); $mepr_city = get_user_meta($user_id, 'mepr-address-city', true); $mepr_state = get_user_meta($user_id, 'mepr-address-state', true); $mepr_zip = get_user_meta($user_id, 'mepr-address-zip', true); $mepr_country = get_user_meta($user_id, 'mepr-address-country', true); // 2. Champs WooCommerce (si présent) $woo_address = get_user_meta($user_id, 'billing_address_1', true); $woo_address2 = get_user_meta($user_id, 'billing_address_2', true); $woo_city = get_user_meta($user_id, 'billing_city', true); $woo_state = get_user_meta($user_id, 'billing_state', true); $woo_zip = get_user_meta($user_id, 'billing_postcode', true); $woo_country = get_user_meta($user_id, 'billing_country', true); // 3. Champs génériques WordPress $wp_address = get_user_meta($user_id, 'address', true); $wp_city = get_user_meta($user_id, 'city', true); $wp_state = get_user_meta($user_id, 'state', true); $wp_zip = get_user_meta($user_id, 'zip', true); $wp_country = get_user_meta($user_id, 'country', true); // Priorité : MemberPress > WooCommerce > WordPress > Vide return [ 'address_line_1' => $mepr_address ?: ($woo_address ?: ($wp_address ?: '')), 'address_line_2' => $mepr_address2 ?: ($woo_address2 ?: ''), 'city' => $mepr_city ?: ($woo_city ?: ($wp_city ?: '')), 'state_province_region' => $mepr_state ?: ($woo_state ?: ($wp_state ?: '')), 'postal_code' => $mepr_zip ?: ($woo_zip ?: ($wp_zip ?: '')), 'country' => $mepr_country ?: ($woo_country ?: ($wp_country ?: '')) ]; } function sendgrid_get_phone_number($user_id) { // Essayer plusieurs sources pour le téléphone // 1. MemberPress $mepr_phone = get_user_meta($user_id, 'mepr-phone', true); // 2. WooCommerce $woo_phone = get_user_meta($user_id, 'billing_phone', true); // 3. Champs génériques $wp_phone = get_user_meta($user_id, 'phone', true); $wp_phone_number = get_user_meta($user_id, 'phone_number', true); $wp_mobile = get_user_meta($user_id, 'mobile', true); // Priorité : MemberPress > WooCommerce > WordPress return $mepr_phone ?: ($woo_phone ?: ($wp_phone ?: ($wp_phone_number ?: ($wp_mobile ?: '')))); } // ============================================================================ // FONCTION CORRIGÉE POUR RÉCUPÉRER LES DONNÉES UTILISATEUR v3.1.4 // ============================================================================ function sendgrid_get_user_data_for_sync($user_id) { global $wpdb; // Récupérer l'utilisateur (INCHANGÉ) $user = get_userdata($user_id); if (!$user || !is_email($user->user_email)) { return null; } // AMÉLIORATION v3.1.4 : Requête plus robuste pour récupérer TOUS les abonnements $user_subscriptions = $wpdb->get_results($wpdb->prepare(" SELECT s.*, p.post_title as product_name, p.post_type, p.post_status FROM {$wpdb->prefix}mepr_subscriptions s LEFT JOIN {$wpdb->prefix}posts p ON s.product_id = p.ID WHERE s.user_id = %d AND (p.post_status = 'publish' OR p.post_status IS NULL) AND (p.post_type = 'memberpressproduct' OR p.post_type IS NULL) ORDER BY CASE s.status WHEN 'active' THEN 1 WHEN 'suspended' THEN 2 WHEN 'pending' THEN 3 ELSE 4 END, s.created_at DESC ", $user_id)); // Créer l'objet de données (STRUCTURE IDENTIQUE À L'ORIGINAL) $user_data = (object) [ 'ID' => $user->ID, 'user_email' => $user->user_email, 'user_login' => $user->user_login, 'subscription_id' => null, 'status' => null, 'created_at' => null, 'expires_at' => null, 'product_id' => null, 'product_name' => null ]; // AMÉLIORATION v3.1.4 : Meilleure gestion mais logique préservée if (!empty($user_subscriptions)) { $best_sub = $user_subscriptions[0]; // Garde la même logique : prendre le premier // NOUVELLE SÉCURITÉ : Vérification renforcée du nom de produit $product_name = ''; if (isset($best_sub->product_name) && !empty($best_sub->product_name)) { $product_name = $best_sub->product_name; } elseif (isset($best_sub->product_id) && !empty($best_sub->product_id)) { // Fallback : récupérer le titre directement $product_title = get_the_title($best_sub->product_id); if (!empty($product_title) && $product_title !== 'Auto Draft') { $product_name = $product_title; } } // ASSIGNATION IDENTIQUE À L'ORIGINAL $user_data->subscription_id = isset($best_sub->id) ? $best_sub->id : null; $user_data->status = isset($best_sub->status) ? $best_sub->status : null; $user_data->created_at = isset($best_sub->created_at) ? $best_sub->created_at : null; $user_data->expires_at = isset($best_sub->expires_at) ? $best_sub->expires_at : null; $user_data->product_id = isset($best_sub->product_id) ? $best_sub->product_id : null; $user_data->product_name = $product_name; // Amélioration ici uniquement // Log pour debugging (NOUVEAU mais optionnel) if (!empty($product_name)) { error_log('📋 SENDGRID SYNC: User ' . $user_id . ' - Abonnement trouvé: "' . $product_name . '" (Status: ' . $best_sub->status . ')'); } } return $user_data; } // ============================================================================ // FONCTION DE SÉCURITÉ POUR GARANTIR TOUTES LES PROPRIÉTÉS // ============================================================================ function sendgrid_ensure_all_properties($user_data) { // Liste de toutes les propriétés requises avec valeurs par défaut $required_properties = [ 'ID' => null, 'user_email' => '', 'user_login' => '', 'subscription_id' => null, 'status' => null, 'created_at' => null, 'expires_at' => null, 'product_id' => null, 'product_name' => null ]; // S'assurer que toutes les propriétés existent foreach ($required_properties as $property => $default_value) { if (!isset($user_data->$property)) { $user_data->$property = $default_value; } } return $user_data; } // ============================================================================ // SYNCHRONISATION AUTOMATIQUE EN TEMPS RÉEL // ============================================================================ // Hooks pour TOUS les événements MemberPress add_action('mepr-event-subscription-created', 'sendgrid_auto_sync_user', 10, 1); add_action('mepr-event-subscription-renewed', 'sendgrid_auto_sync_user', 10, 1); add_action('mepr-event-subscription-expired', 'sendgrid_auto_sync_user', 10, 1); add_action('mepr-event-subscription-stopped', 'sendgrid_auto_sync_user', 10, 1); add_action('mepr-event-subscription-upgraded', 'sendgrid_auto_sync_user', 10, 1); add_action('mepr-event-subscription-downgraded', 'sendgrid_auto_sync_user', 10, 1); add_action('mepr-event-subscription-changed', 'sendgrid_auto_sync_user', 10, 1); add_action('mepr-event-subscription-resumed', 'sendgrid_auto_sync_user', 10, 1); add_action('mepr-event-subscription-suspended', 'sendgrid_auto_sync_user', 10, 1); // Hooks pour les transactions MemberPress add_action('mepr-event-transaction-completed', 'sendgrid_auto_sync_user', 10, 1); add_action('mepr-event-transaction-expired', 'sendgrid_auto_sync_user', 10, 1); add_action('mepr-event-transaction-failed', 'sendgrid_auto_sync_user', 10, 1); add_action('mepr-event-transaction-refunded', 'sendgrid_auto_sync_user', 10, 1); // Hooks pour les modifications d'utilisateurs WordPress add_action('profile_update', 'sendgrid_auto_sync_wordpress_user', 10, 2); add_action('user_register', 'sendgrid_auto_sync_new_user', 10, 1); add_action('personal_options_update', 'sendgrid_auto_sync_wordpress_user_simple', 10, 1); add_action('edit_user_profile_update', 'sendgrid_auto_sync_wordpress_user_simple', 10, 1); add_action('wp_update_user', 'sendgrid_auto_sync_wordpress_user_simple', 10, 1); // Hooks pour les modifications d'email add_action('wp_insert_user', 'sendgrid_auto_sync_new_user', 10, 1); // ============================================================================ // FONCTIONS DE SYNCHRONISATION AUTOMATIQUE AMÉLIORÉES v3.1.4 // ============================================================================ function sendgrid_auto_sync_user($event) { error_log('🔄 SENDGRID AUTO SYNC: Événement MemberPress détecté - ' . current_action()); $user_id = null; $product_name = ''; // Extraire l'user_id selon le type d'événement if (is_object($event)) { if (isset($event->subscription) && isset($event->subscription->user_id)) { $user_id = $event->subscription->user_id; } elseif (isset($event->transaction) && isset($event->transaction->user_id)) { $user_id = $event->transaction->user_id; } elseif (isset($event->user_id)) { $user_id = $event->user_id; } } if (!$user_id) { sendgrid_log_subscription_event(0, current_action(), '', false); return false; } // Éviter les doublons (limite de 1 sync par utilisateur par minute) static $last_sync = []; $current_time = time(); if (isset($last_sync[$user_id]) && ($current_time - $last_sync[$user_id]) < 60) { error_log('⏸️ SENDGRID AUTO SYNC: Sync récente ignorée pour user ' . $user_id); return; } $last_sync[$user_id] = $current_time; error_log('🚀 SENDGRID AUTO SYNC: Synchronisation automatique pour user ' . $user_id); // Utiliser la nouvelle fonction d'enrichissement v3.1.4 $user_data = sendgrid_get_user_data_for_sync($user_id); if ($user_data) { $product_name = $user_data->product_name ?: 'Plan sans nom'; $result = sendgrid_enrich_user_fixed($user_data); sendgrid_log_subscription_event($user_id, current_action(), $product_name, $result['success']); if ($result['success']) { error_log('✅ SENDGRID AUTO SYNC: Réussi pour user ' . $user_id . ' - Plan: "' . $product_name . '" - Type: ' . $result['type']); } else { error_log('❌ SENDGRID AUTO SYNC: Échec pour user ' . $user_id . ' - Plan: "' . $product_name . '"'); } } else { sendgrid_log_subscription_event($user_id, current_action(), 'Données utilisateur introuvables', false); } } function sendgrid_auto_sync_wordpress_user($user_id, $old_user_data = null) { error_log('🔄 SENDGRID AUTO SYNC: Modification utilisateur WordPress - User ID: ' . $user_id); // Éviter les doublons static $last_sync = []; $current_time = time(); if (isset($last_sync[$user_id]) && ($current_time - $last_sync[$user_id]) < 30) { return; } $last_sync[$user_id] = $current_time; $user_data = sendgrid_get_user_data_for_sync($user_id); if ($user_data) { $result = sendgrid_enrich_user_fixed($user_data); error_log('🔄 SENDGRID AUTO SYNC: WordPress user update - ' . ($result['success'] ? 'Réussi' : 'Échec')); } } function sendgrid_auto_sync_wordpress_user_simple($user_id) { sendgrid_auto_sync_wordpress_user($user_id); } function sendgrid_auto_sync_new_user($user_id) { error_log('🆕 SENDGRID AUTO SYNC: Nouvel utilisateur - ID: ' . $user_id); // Attendre 30 secondes pour que MemberPress finisse son setup wp_schedule_single_event(time() + 30, 'sendgrid_delayed_sync', array($user_id)); } // Action pour la synchronisation différée add_action('sendgrid_delayed_sync', function($user_id) { error_log('⏰ SENDGRID AUTO SYNC: Sync différée pour user ' . $user_id); $user_data = sendgrid_get_user_data_for_sync($user_id); if ($user_data) { sendgrid_enrich_user_fixed($user_data); } }); // ============================================================================ // FONCTION DE LOGGING POUR SURVEILLANCE v3.1.4 // ============================================================================ function sendgrid_log_subscription_event($user_id, $event_type, $product_name = '', $success = true) { $log_entry = date('Y-m-d H:i:s') . ' | ' . $event_type . ' | User: ' . $user_id . ' | Plan: "' . $product_name . '" | ' . ($success ? 'SUCCESS' : 'FAILED'); error_log('📋 SENDGRID AUTO: ' . $log_entry); // Optionnel : garder un historique dans la base de données $recent_logs = get_option('sendgrid_recent_sync_logs', []); array_unshift($recent_logs, $log_entry); $recent_logs = array_slice($recent_logs, 0, 100); // Garder seulement les 100 derniers update_option('sendgrid_recent_sync_logs', $recent_logs); } // ============================================================================ // FONCTION DE STATUT DE LA SYNCHRONISATION AUTOMATIQUE // ============================================================================ function sendgrid_get_auto_sync_status() { return [ 'memberpress_hooks' => [ 'subscription_created' => has_action('mepr-event-subscription-created'), 'subscription_renewed' => has_action('mepr-event-subscription-renewed'), 'subscription_expired' => has_action('mepr-event-subscription-expired'), 'subscription_stopped' => has_action('mepr-event-subscription-stopped'), 'transaction_completed' => has_action('mepr-event-transaction-completed'), ], 'wordpress_hooks' => [ 'profile_update' => has_action('profile_update'), 'user_register' => has_action('user_register'), 'wp_update_user' => has_action('wp_update_user'), ], 'daily_sync' => [ 'enabled' => (bool) get_option('sendgrid_daily_sync_enabled', false), 'time' => get_option('sendgrid_daily_sync_time', '02:00'), 'last_run' => get_option('sendgrid_daily_sync_last_run', 'Jamais'), 'next_run' => wp_next_scheduled('sendgrid_daily_sync_cron') ? date('Y-m-d H:i:s', wp_next_scheduled('sendgrid_daily_sync_cron')) : 'Non planifié' ] ]; } // ============================================================================ // SYNCHRONISATION QUOTIDIENNE AUTOMATIQUE - ENRICHISSEMENT COMPLET // ============================================================================ // Hook pour l'action planifiée add_action('sendgrid_daily_sync_cron', 'sendgrid_run_daily_sync'); // Activation/Désactivation du plugin register_activation_hook(__FILE__, 'sendgrid_plugin_activate'); register_deactivation_hook(__FILE__, 'sendgrid_plugin_deactivate'); function sendgrid_plugin_activate() { // Activer la sync quotidienne par défaut à 2h du matin if (!get_option('sendgrid_daily_sync_enabled')) { update_option('sendgrid_daily_sync_enabled', true); update_option('sendgrid_daily_sync_time', '02:00'); sendgrid_schedule_daily_sync('02:00'); } } function sendgrid_plugin_deactivate() { // Désactiver la sync quotidienne sendgrid_unschedule_daily_sync(); } // ============================================================================ // FONCTIONS DE PLANIFICATION // ============================================================================ function sendgrid_schedule_daily_sync($time = '02:00') { // Désactiver l'ancienne planification sendgrid_unschedule_daily_sync(); // Calculer le timestamp pour la prochaine exécution $time_parts = explode(':', $time); $hour = intval($time_parts[0]); $minute = intval($time_parts[1]); // Prochaine occurrence de cette heure $next_run = mktime($hour, $minute, 0); if ($next_run < time()) { $next_run += 24 * 60 * 60; // Ajouter 24h si l'heure est déjà passée aujourd'hui } // Planifier l'événement quotidien wp_schedule_event($next_run, 'daily', 'sendgrid_daily_sync_cron'); error_log('🗓️ SENDGRID DAILY SYNC: Planifiée pour ' . date('Y-m-d H:i:s', $next_run)); } function sendgrid_unschedule_daily_sync() { $timestamp = wp_next_scheduled('sendgrid_daily_sync_cron'); if ($timestamp) { wp_unschedule_event($timestamp, 'sendgrid_daily_sync_cron'); error_log('⏸️ SENDGRID DAILY SYNC: Désactivée'); } } // ============================================================================ // FONCTION PRINCIPALE DE SYNCHRONISATION QUOTIDIENNE COMPLÈTE // ============================================================================ function sendgrid_run_daily_sync() { error_log('🚀 SENDGRID DAILY SYNC: Début synchronisation quotidienne COMPLÈTE'); $start_time = time(); $api_key = get_option('sendgrid_api_key'); if (!$api_key) { error_log('❌ SENDGRID DAILY SYNC: Aucune clé API configurée'); update_option('sendgrid_daily_sync_last_run', date('Y-m-d H:i:s') . ' - ERREUR: Pas de clé API'); return false; } global $wpdb; // CHANGEMENT MAJEUR : Récupérer TOUS les utilisateurs avec email valide (pas de filtre de date) $all_users = $wpdb->get_results(" SELECT DISTINCT u.ID, u.user_email, u.user_login, u.user_registered FROM {$wpdb->prefix}users u WHERE u.user_email != '' AND u.user_email IS NOT NULL AND u.user_email LIKE '%@%' ORDER BY u.ID "); $total_users = count($all_users); $success_count = 0; $error_count = 0; $enriched_count = 0; $simple_count = 0; error_log('🎯 SENDGRID DAILY SYNC COMPLET: ' . $total_users . ' utilisateurs à synchroniser (TOUS LES UTILISATEURS)'); if ($total_users == 0) { update_option('sendgrid_daily_sync_last_run', date('Y-m-d H:i:s') . ' - Aucun utilisateur trouvé'); echo '

ℹ️ Aucun utilisateur avec email valide trouvé

'; return true; } // Interface de progression pour sync quotidienne complète echo '

⏰ Synchronisation Quotidienne COMPLÈTE en Cours

🔄 Mode COMPLET : Traitement de TOUS les ' . $total_users . ' utilisateurs

0%
0
✅ Succès
0
📋 Enrichis
0
👤 Simples
0
❌ Erreurs
🚀 Initialisation de la synchronisation quotidienne complète...
Traitement de TOUS les utilisateurs par batches de 50...
⏱️ Temps écoulé: 0s | ETA: Calcul en cours...
'; ob_flush(); flush(); // Traitement par batches pour éviter les timeouts $batch_size = 50; $processed = 0; for ($i = 0; $i < $total_users; $i += $batch_size) { $batch = array_slice($all_users, $i, $batch_size); foreach ($batch as $user_data) { $user_data_for_sync = sendgrid_get_user_data_for_sync($user_data->ID); if ($user_data_for_sync) { $result = sendgrid_enrich_user_fixed($user_data_for_sync); if ($result['success']) { $success_count++; if ($result['type'] === 'subscription') { $enriched_count++; } else { $simple_count++; } } else { $error_count++; } } else { $error_count++; } $processed++; // Mise à jour de la progression toutes les 10 entrées if ($processed % 10 == 0 || $processed == $total_users) { $percentage = round(($processed / $total_users) * 100, 1); $elapsed = time() - $start_time; $rate = $elapsed > 0 ? $processed / $elapsed : 0; $eta = $rate > 0 ? round(($total_users - $processed) / $rate) : 0; echo ''; ob_flush(); flush(); } } // Pause courte entre les batches sleep(1); // Log de progression if ($processed % 100 == 0) { error_log('📊 SENDGRID DAILY SYNC COMPLET: ' . $processed . '/' . $total_users . ' traités'); } } $duration = time() - $start_time; // Animation finale echo ''; // Sauvegarder le rapport $report = [ 'date' => date('Y-m-d H:i:s'), 'total' => $total_users, 'success' => $success_count, 'enriched' => $enriched_count, 'simple' => $simple_count, 'errors' => $error_count, 'duration' => $duration ]; update_option('sendgrid_daily_sync_report', $report); update_option('sendgrid_daily_sync_last_run', date('Y-m-d H:i:s')); error_log('🎉 SENDGRID DAILY SYNC COMPLET: Terminé - ' . $success_count . '/' . $total_users . ' succès en ' . $duration . 's'); echo '

🎉 SYNCHRONISATION QUOTIDIENNE TERMINÉE

'; echo '

Total traités : ' . $total_users . '

'; echo '

📋 Enrichis : ' . $enriched_count . '

'; echo '

👤 Simples : ' . $simple_count . '

'; echo '

Erreurs : ' . $error_count . '

'; return true; } // ============================================================================ // FONCTION POUR RÉCUPÉRER LE RAPPORT DE SYNC QUOTIDIENNE // ============================================================================ function sendgrid_get_daily_sync_report() { $report = get_option('sendgrid_daily_sync_report', []); $default_report = [ 'date' => 'Jamais', 'total' => 0, 'success' => 0, 'enriched' => 0, 'simple' => 0, 'errors' => 0, 'duration' => 0 ]; return array_merge($default_report, $report); }
Warning: Cannot modify header information - headers already sent by (output started at /data/vhosts/f/frenchmorning.com/_/wp-content/plugins/sendgrid-sync/sendgris-sync.php:432) in /data/vhosts/f/frenchmorning.com/_/wp-includes/pluggable.php on line 1450

Warning: Cannot modify header information - headers already sent by (output started at /data/vhosts/f/frenchmorning.com/_/wp-content/plugins/sendgrid-sync/sendgris-sync.php:432) in /data/vhosts/f/frenchmorning.com/_/wp-includes/pluggable.php on line 1453