// ================================ // NOUVEAUTÉS v3.1.4 // ================================ echo '
Correction du problème des abonnements manqués :
• 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
• 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
• 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
Vérifier que toutes les fonctionnalités marchent correctement
✅ 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)
Analyser spécifiquement les problèmes d\'abonnements
Identifiez rapidement les problèmes dans votre base de données
Synchronisation manuelle immédiate de TOUS les utilisateurs
Synchronisation automatique COMPLÈTE une fois par jour de TOUTE la base utilisateurs
• 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
État : ' . ($daily_enabled ? '✅ Activée' : '❌ Désactivée') . '
Heure : ' . $daily_time . '
Dernière exécution : ' . $last_run . '
Prochaine exécution : ' . $next_run . '
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 de la synchronisation en temps réel
'; $sync_status = sendgrid_get_auto_sync_status(); echo '' . $icon . ' ' . str_replace('_', ' ', ucfirst($hook)) . '
'; } echo '' . $icon . ' ' . str_replace('_', ' ', ucfirst($hook)) . '
'; } echo '👥 Total utilisateurs WordPress : ' . $total_users . '
'; // 2. ANALYSE MEMBERPRESS if (class_exists('MeprSubscription')) { 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 '📧 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 '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 '📦 ' . $product->post_title . ' (ID: ' . $product->ID . ')
'; echo '• Statut: ' . $product->post_status . '
'; echo '• Total souscriptions: ' . $sub_count . '
'; echo '• Souscriptions actives: ' . $active_sub_count . '
'; echo '• ' . ucfirst($stat->status) . ' - ' . $stat->product_name . ': ' . $stat->count . '
'; } // 3. TEST DE RÉCUPÉRATION POUR CHAQUE PRODUIT 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 '📦 ' . $product_name . '
'; echo '• Total utilisateurs: ' . $count . '
'; echo '• Synchronisés: ' . $success . '
'; echo '• Erreurs: ' . $errors . '
'; 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 '' . $icon . ' ' . $description . '
'; } // 2. VÉRIFIER LA SYNCHRONISATION QUOTIDIENNE 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 '✅ Clé API : ' . ($api_key ? 'Configurée' : 'Manquante') . '
'; // 4. TEST RAPIDE SUR ÉCHANTILLON echo '✅ User ' . $user->ID . ' (' . $user->user_email . ') - Plan: "' . $plan_name . '"
'; } else { echo '❌ User ' . $user->ID . ' - Erreur récupération données
'; } } echo '📦 ' . $stat->product_name . ' - ' . $stat->periode . '
'; echo '• Total: ' . $stat->total . ' | Actifs: ' . $stat->actifs . '
'; 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 '📋 Hooks automatiques configurés pour nouveaux abonnements :
'; echo '✅ Création abonnement → mepr-event-subscription-created
✅ Transaction complétée → mepr-event-transaction-completed
✅ Inscription utilisateur → user_register
🔄 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 '❌ Aucun utilisateur avec abonnement actif trouvé pour le test
'; 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 '✅ 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 '🧪 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 '❌ Utilisateur non trouvé
'; 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 '❌ Aucune souscription trouvée
'; } else { echo '✅ ' . count($subscriptions) . ' souscription(s) trouvée(s)
'; foreach ($subscriptions as $sub) { 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 '✅ 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 '📧 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 '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 '👥 TOUS les utilisateurs avec email valide : ' . count($all_users) . '
'; if (empty($all_users)) { echo '❌ Aucun utilisateur avec email valide trouvé
'; 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 '✅ 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é
🔄 Mode COMPLET : Traitement de TOUS les ' . $total_users . ' utilisateurs
✅ 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); }