[10, 11, 12, 13, 14], 'price_per_tb' => 120.00, 'office_user_price' => 25.00, 'frequency_multipliers' => [ 'monthly' => 1.0, 'semiannual' => 5.7, 'annual' => 10.8, 'biennial' => 20.4, 'triennial' => 28.8, 'quadrennial' => 36.0, 'quinquennial' => 42.0 ], 'storage_options' => [ '1tb' => '1 Terabyte', '2tb' => '2 Terabytes', '3tb' => '3 Terabytes', '4tb' => '4 Terabytes', '5tb' => '5 Terabytes', '6tb' => '6 Terabytes', '7tb' => '7 Terabytes', '8tb' => '8 Terabytes', '9tb' => '9 Terabytes', '10tb' => '10 Terabytes', '15tb' => '15 Terabytes', '20tb' => '20 Terabytes', '30tb' => '30 Terabytes', '40tb' => '40 Terabytes', '50tb' => '50 Terabytes', '60tb' => '60 Terabytes', '70tb' => '70 Terabytes', '80tb' => '80 Terabytes', '90tb' => '90 Terabytes', '100tb' => '100 Terabytes', '200tb' => '200 Terabytes', '300tb' => '300 Terabytes', '400tb' => '400 Terabytes', '500tb' => '500 Terabytes' ], 'office_options' => [ '20users' => '±20 usuários (CODE - Grátis)', '30users' => '30 usuários (Business)', '50users' => '50 usuários (Business)', '80users' => '80 usuários (Business)', '100users' => '100 usuários (Enterprise, -15%)', '150users' => '150 usuários (Enterprise, -15%)', '200users' => '200 usuários (Enterprise, -15%)', '300users' => '300 usuários (Enterprise, -15%)', '400users' => '400 usuários (Enterprise, -15%)', '500users' => '500 usuários (Enterprise, -15%)' ] ]; } return $key ? ($config[$key] ?? null) : $config; } // ==================================================================== // SISTEMA DE LOGGING OPTIMIZADO // ==================================================================== /** * Logging centralizado con niveles */ function nextcloud_log($level, $message, $context = []) { static $log_level = null; if ($log_level === null) { if (defined('WP_DEBUG') && WP_DEBUG) { $log_level = 4; // DEBUG } elseif (defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) { $log_level = 3; // INFO } else { $log_level = 1; // ERROR only } } $levels = [1 => 'ERROR', 2 => 'WARNING', 3 => 'INFO', 4 => 'DEBUG']; if ($level > $log_level) return; $log_message = sprintf( '[PMPro Dynamic %s] %s', $levels[$level], $message ); if (!empty($context)) { $log_message .= ' | Context: ' . wp_json_encode($context, JSON_UNESCAPED_UNICODE); } error_log($log_message); } // Funciones de logging simplificadas function nextcloud_log_error($message, $context = []) { nextcloud_log(1, $message, $context); } function nextcloud_log_warning($message, $context = []) { nextcloud_log(2, $message, $context); } function nextcloud_log_info($message, $context = []) { nextcloud_log(3, $message, $context); } function nextcloud_log_debug($message, $context = []) { nextcloud_log(4, $message, $context); } // ==================================================================== // SISTEMA DE CACHÉ OPTIMIZADO // ==================================================================== /** * Obtener datos del caché */ function nextcloud_cache_get($key, $default = false) { $cached = wp_cache_get($key, NEXTCLOUD_CACHE_GROUP); if ($cached !== false) { nextcloud_log_debug("Cache hit for key: {$key}"); return $cached; } nextcloud_log_debug("Cache miss for key: {$key}"); return $default; } /** * Guardar datos en caché */ function nextcloud_cache_set($key, $data, $expiry = NEXTCLOUD_CACHE_EXPIRY) { $result = wp_cache_set($key, $data, NEXTCLOUD_CACHE_GROUP, $expiry); nextcloud_log_debug("Cache set for key: {$key}", ['success' => $result]); return $result; } /** * Eliminar datos del caché */ function nextcloud_cache_delete($key) { $result = wp_cache_delete($key, NEXTCLOUD_CACHE_GROUP); nextcloud_log_debug("Cache deleted for key: {$key}", ['success' => $result]); return $result; } /** * Invalidar caché de usuario */ function nextcloud_invalidate_user_cache($user_id) { $keys = [ "nextcloud_config_{$user_id}", "pmpro_membership_{$user_id}", "nextcloud_used_space_{$user_id}", "last_payment_date_{$user_id}" ]; foreach ($keys as $key) { nextcloud_cache_delete($key); } nextcloud_log_info("User cache invalidated", ['user_id' => $user_id]); } // ==================================================================== // VERIFICACIÓN DE DEPENDENCIAS OPTIMIZADA // ==================================================================== /** * Verifica que los plugins requeridos estén activos */ function nextcloud_check_dependencies() { static $dependencies_checked = false; static $dependencies_ok = false; if ($dependencies_checked) { return $dependencies_ok; } $missing_plugins = []; // Verificaciones críticas if (!function_exists('pmprorh_add_registration_field')) { $missing_plugins[] = 'PMPro Register Helper'; nextcloud_log_error('PMPro Register Helper functions not found'); } if (!function_exists('pmpro_getOption')) { $missing_plugins[] = 'Paid Memberships Pro'; nextcloud_log_error('PMPro core functions not found'); } if (!class_exists('PMProRH_Field')) { $missing_plugins[] = 'PMProRH_Field class'; nextcloud_log_error('PMProRH_Field class not available'); } // Verificación opcional if (!class_exists('MemberOrder')) { nextcloud_log_warning('MemberOrder class not available - some features may be limited'); } // Admin notice if (!empty($missing_plugins) && is_admin() && current_user_can('manage_options')) { add_action('admin_notices', function() use ($missing_plugins) { $plugins_list = implode(', ', $missing_plugins); printf( '

PMPro Dynamic Pricing: Los siguientes plugins son requeridos: %s

', esc_html($plugins_list) ); }); } $dependencies_ok = empty($missing_plugins); $dependencies_checked = true; nextcloud_log_info('Dependencies check completed', [ 'success' => $dependencies_ok, 'missing_count' => count($missing_plugins) ]); return $dependencies_ok; } // ==================================================================== // DETECCIÓN DE NIVEL ACTUAL OPTIMIZADA // ==================================================================== /** * Detecta el Level ID actual con múltiples estrategias */ function nextcloud_get_current_level_id() { static $cached_level_id = null; if ($cached_level_id !== null) { return $cached_level_id; } // Estrategias de detección en orden de prioridad $detectors = [ 'global_checkout_level' => function() { global $pmpro_checkout_level; return isset($pmpro_checkout_level->id) ? (int)$pmpro_checkout_level->id : 0; }, 'get_level' => function() { return !empty($_GET['level']) ? (int)sanitize_text_field($_GET['level']) : 0; }, 'get_pmpro_level' => function() { return !empty($_GET['pmpro_level']) ? (int)sanitize_text_field($_GET['pmpro_level']) : 0; }, 'post_level' => function() { return !empty($_POST['level']) ? (int)sanitize_text_field($_POST['level']) : 0; }, 'post_pmpro_level' => function() { return !empty($_POST['pmpro_level']) ? (int)sanitize_text_field($_POST['pmpro_level']) : 0; }, 'global_level' => function() { global $pmpro_level; return isset($pmpro_level->id) ? (int)$pmpro_level->id : 0; }, 'session_level' => function() { return !empty($_SESSION['pmpro_level']) ? (int)$_SESSION['pmpro_level'] : 0; } ]; foreach ($detectors as $source => $detector) { $level_id = $detector(); if ($level_id > 0) { nextcloud_log_debug("Level ID detected from {$source}: {$level_id}"); $cached_level_id = $level_id; return $level_id; } } // Fallback: extraer de URL if (function_exists('pmpro_getOption')) { $checkout_page_slug = pmpro_getOption('checkout_page_slug'); if (!empty($checkout_page_slug) && is_page($checkout_page_slug)) { $request_uri = $_SERVER['REQUEST_URI'] ?? ''; if (preg_match('/(?:^|[?&])(level|pmpro_level)=(\d+)/', $request_uri, $matches)) { $level_id = (int)$matches[2]; nextcloud_log_debug("Level ID extracted from URL: {$level_id}"); $cached_level_id = $level_id; return $level_id; } } } $cached_level_id = 0; nextcloud_log_warning('Could not detect Level ID, using default 0'); return 0; } // ==================================================================== // CAMPOS DINÁMICOS OPTIMIZADOS // ==================================================================== /** * Añade campos dinámicos con validación robusta */ function nextcloud_add_dynamic_fields() { static $fields_added = false; static $initialization_attempted = false; if ($initialization_attempted && !$fields_added) { return false; } $initialization_attempted = true; if ($fields_added) { nextcloud_log_debug('Dynamic fields already added, skipping'); return true; } nextcloud_log_info('Attempting to add dynamic fields'); if (!nextcloud_check_dependencies()) { nextcloud_log_error('Dependencies missing, cannot add fields'); return false; } $current_level_id = nextcloud_get_current_level_id(); $allowed_levels = nextcloud_get_config('allowed_levels'); if (!in_array($current_level_id, $allowed_levels, true)) { nextcloud_log_info("Level {$current_level_id} not in allowed levels, skipping fields"); return false; } try { $config = nextcloud_get_config(); $fields = []; // Campo de almacenamiento $fields[] = new PMProRH_Field( 'storage_space', 'select', [ 'label' => 'Espaço de armazenamento', 'options' => $config['storage_options'], 'profile' => true, 'required' => false, 'memberslistcsv' => true, 'addmember' => true, 'location' => 'after_level' ] ); // Campo de suite ofimática $fields[] = new PMProRH_Field( 'office_suite', 'select', [ 'label' => 'Nextcloud Office ', 'options' => $config['office_options'], 'profile' => true, 'required' => false, 'memberslistcsv' => true, 'addmember' => true, 'location' => 'after_level', 'divclass' => 'pmpro_checkout-field-office-suite bordered-field' ] ); // Campo de frecuencia $frequency_options = [ 'monthly' => 'Mensal', 'semiannual' => 'Semestral (-5%)', 'annual' => 'Anual (-10%)', 'biennial' => 'Bienal (-15%)', 'triennial' => 'Trienal (-20%)', 'quadrennial' => 'Quadrienal (-25%)', 'quinquennial' => 'Quinquenal (-30%)' ]; $fields[] = new PMProRH_Field( 'payment_frequency', 'select', [ 'label' => 'Frequência de pagamento', 'options' => $frequency_options, 'profile' => true, 'required' => false, 'memberslistcsv' => true, 'addmember' => true, 'location' => 'after_level' ] ); // Campo de precio total $fields[] = new PMProRH_Field( 'total_price_display', 'text', [ 'label' => 'Preço total', 'profile' => false, 'required' => false, 'memberslistcsv' => false, 'addmember' => false, 'readonly' => true, 'location' => 'after_level', 'showrequired' => false, 'divclass' => 'pmpro_checkout-field-price-display', 'default' => 'R$ 0,00' ] ); // Añadir campos $fields_added_count = 0; foreach($fields as $field) { pmprorh_add_registration_field('Configuração do plano', $field); $fields_added_count++; } $fields_added = true; nextcloud_log_info("Dynamic fields added successfully", [ 'level_id' => $current_level_id, 'fields_count' => $fields_added_count ]); return true; } catch (Exception $e) { nextcloud_log_error('Exception adding dynamic fields', [ 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ]); if (defined('WP_DEBUG') && WP_DEBUG) { wp_die('Error en el sistema de membresías: ' . esc_html($e->getMessage())); } return false; } } // ==================================================================== // CÁLCULOS DE PRECIO OPTIMIZADOS // ==================================================================== /** * Calcula el precio total con caché y validaciones */ function nextcloud_calculate_pricing($storage_space, $office_suite, $payment_frequency, $base_price) { // Validar parámetros if (empty($storage_space) || empty($office_suite) || empty($payment_frequency)) { nextcloud_log_warning('Missing parameters for price calculation'); return $base_price; } // Verificar caché $cache_key = "pricing_{$storage_space}_{$office_suite}_{$payment_frequency}_{$base_price}"; $cached_price = nextcloud_cache_get($cache_key); if ($cached_price !== false) { return $cached_price; } $config = nextcloud_get_config(); $price_per_tb = $config['price_per_tb']; $office_user_price = $config['office_user_price']; // Calcular precio de almacenamiento $storage_tb = (int)str_replace('tb', '', $storage_space); $storage_price = $base_price + ($price_per_tb * max(0, $storage_tb - 1)); // Calcular precio de suite ofimática $office_users = (int)str_replace('users', '', $office_suite); $office_user_price = ($office_users < 100) ? $office_user_price : ($office_user_price - 3.75); $office_price = ($office_users <= 20) ? 0 : ($office_user_price * $office_users); // Aplicar multiplicador de frecuencia $multipliers = $config['frequency_multipliers']; $frequency_multiplier = $multipliers[$payment_frequency] ?? 1.0; // Calcular precio total $total_price = ceil(($storage_price + $office_price) * $frequency_multiplier); // Validar resultado if ($total_price < $base_price || $total_price > ($base_price * 100)) { nextcloud_log_warning('Calculated price seems unreasonable', [ 'total_price' => $total_price, 'base_price' => $base_price ]); } // Guardar en caché nextcloud_cache_set($cache_key, $total_price, 300); // 5 minutos nextcloud_log_debug('Price calculated', [ 'storage_space' => $storage_space, 'office_suite' => $office_suite, 'payment_frequency' => $payment_frequency, 'total_price' => $total_price ]); return $total_price; } /** * Configura la periodicidad del nivel */ function nextcloud_configure_billing_period($level, $payment_frequency, $total_price) { if (empty($level) || !is_object($level)) { nextcloud_log_error('Invalid level object provided'); return $level; } $billing_cycles = [ 'monthly' => ['number' => 1, 'period' => 'Month'], 'semiannual' => ['number' => 6, 'period' => 'Month'], 'annual' => ['number' => 12, 'period' => 'Month'], 'biennial' => ['number' => 24, 'period' => 'Month'], 'triennial' => ['number' => 36, 'period' => 'Month'], 'quadrennial' => ['number' => 48, 'period' => 'Month'], 'quinquennial' => ['number' => 60, 'period' => 'Month'] ]; $cycle_config = $billing_cycles[$payment_frequency] ?? $billing_cycles['monthly']; $level->cycle_number = $cycle_config['number']; $level->cycle_period = $cycle_config['period']; $level->billing_amount = $total_price; $level->initial_payment = $total_price; $level->trial_amount = 0; $level->trial_limit = 0; $level->recurring = true; // Preservar configuración de expiración if (!isset($level->expiration_number) || empty($level->expiration_number)) { $level->expiration_number = 0; $level->expiration_period = ''; nextcloud_log_debug('Level configured as unlimited'); } nextcloud_log_info('Billing period configured', [ 'payment_frequency' => $payment_frequency, 'cycle_number' => $level->cycle_number, 'billing_amount' => $level->billing_amount ]); return $level; } // ==================================================================== // FUNCIONES AUXILIARES OPTIMIZADAS // ==================================================================== /** * Obtiene el espacio usado en Nextcloud (placeholder) */ function get_nextcloud_used_space_tb($user_id) { // TODO: Implementar conexión real a API de Nextcloud $cache_key = "used_space_{$user_id}"; $cached = nextcloud_cache_get($cache_key); if ($cached !== false) { return $cached; } // Placeholder - implementar API real $used_space_mb = 1200; $used_space_tb = round($used_space_mb / 1024 / 1024, 2); nextcloud_cache_set($cache_key, $used_space_tb, 300); return $used_space_tb; } /** * Obtiene el espacio usado desde Nextcloud (placeholder) */ function get_nextcloud_used_storage($user_id) { // TODO: Implementar API call real a Nextcloud return 0; } /** * Calcula días restantes en el ciclo actual */ function get_remaining_days_in_cycle($user_id, $frequency) { if (!class_exists('MemberOrder')) { nextcloud_log_warning('MemberOrder class not available'); return 0; } $last_order = new MemberOrder(); $last_order->getLastMemberOrder($user_id, 'success'); if (empty($last_order->timestamp)) { return 0; } $last_payment_date = is_numeric($last_order->timestamp) ? $last_order->timestamp : strtotime($last_order->timestamp); $cycle_days = get_cycle_days($frequency); $days_used = floor((current_time('timestamp') - $last_payment_date) / DAY_IN_SECONDS); return max(0, $cycle_days - $days_used); } /** * Obtiene la duración en días del ciclo */ function get_cycle_days($frequency) { $cycles = [ 'monthly' => 30, 'semiannual' => 180, 'annual' => 365, 'biennial' => 730, 'triennial' => 1095, 'quadrennial' => 1460, 'quinquennial' => 1825 ]; return $cycles[$frequency] ?? 30; } // ==================================================================== // SISTEMA DE PRORRATEO OPTIMIZADO // ==================================================================== /** * Valida si un cambio de plan es permitido */ function is_change_allowed($current_config, $new_config) { $cur_storage = (int)str_replace('tb', '', $current_config['storage_space']); $new_storage = (int)str_replace('tb', '', $new_config['storage_space']); // Verificar downgrade de almacenamiento if ($new_storage < $cur_storage) { $used = get_nextcloud_used_space_tb(get_current_user_id()); if ($used > $new_storage) { return [false, "Não é possível reduzir para {$new_storage} TB pois você usa {$used} TB"]; } } return [true, ""]; } /** * Valida y aplica prorrateo para cambios */ function nextcloud_validate_and_prorate_changes($level) { $user_id = get_current_user_id(); // Cargar configuración actual $cache_key = "nextcloud_config_{$user_id}"; $current_config_json = nextcloud_cache_get($cache_key); if ($current_config_json === false) { $current_config_json = get_user_meta($user_id, 'nextcloud_config', true); nextcloud_cache_set($cache_key, $current_config_json); } $current_config = $current_config_json ? json_decode($current_config_json, true) : null; // Si no hay configuración previa → nuevo registro if (!$current_config) { nextcloud_log_debug("New registration detected for user {$user_id}"); return $level; } // Obtener nuevas selecciones $new_storage = sanitize_text_field($_POST['storage_space'] ?? $current_config['storage_space']); $new_suite = sanitize_text_field($_POST['office_suite'] ?? ($current_config['office_suite'] ?? '20users')); $new_frequency = sanitize_text_field($_POST['payment_frequency'] ?? $current_config['payment_frequency']); // Detectar cambios $has_changes = ( $new_storage !== $current_config['storage_space'] || $new_suite !== ($current_config['office_suite'] ?? '20users') || $new_frequency !== $current_config['payment_frequency'] ); if (!$has_changes) { nextcloud_log_debug("No changes detected for user {$user_id}"); return $level; } // Preparar nueva configuración $new_config = [ 'storage_space' => $new_storage, 'office_suite' => $new_suite, 'payment_frequency' => $new_frequency, 'level_id' => $level->id ]; // Validar cambio list($allowed, $error_message) = is_change_allowed($current_config, $new_config); if (!$allowed) { nextcloud_log_error("Change rejected for user {$user_id}: {$error_message}"); wp_die(__($error_message, 'pmpro')); } // Aplicar prorrateo si es upgrade de almacenamiento $current_tb = (int)str_replace('tb', '', $current_config['storage_space']); $new_tb = (int)str_replace('tb', '', $new_storage); if ($new_tb > $current_tb) { $level = apply_storage_upgrade_prorate($level, $user_id, $current_tb, $new_tb, $current_config['payment_frequency']); nextcloud_log_info("Storage upgrade applied with prorate for user {$user_id}"); } return $level; } /** * Aplica prorrateo para upgrade de almacenamiento */ function apply_storage_upgrade_prorate($level, $user_id, $current_tb, $new_tb, $current_frequency) { $price_per_tb = nextcloud_get_config('price_per_tb'); $full_price_diff = ($new_tb - $current_tb) * $price_per_tb; $days_remaining = get_remaining_days_in_cycle($user_id, $current_frequency); if ($days_remaining > 0) { $total_days = get_cycle_days($current_frequency); $prorated_amount = ($full_price_diff / $total_days) * $days_remaining; $level->initial_payment += round($prorated_amount, 2); nextcloud_log_info("Prorate applied", [ 'user_id' => $user_id, 'upgrade_tb' => $new_tb - $current_tb, 'days_remaining' => $days_remaining, 'prorated_amount' => $prorated_amount ]); } return $level; } // ==================================================================== // HOOKS Y FILTROS PRINCIPALES // ==================================================================== /** * Hook principal de modificación de precio */ function nextcloud_modify_level_pricing($level) { // Prevenir procesamiento múltiple if (!empty($level->_nextcloud_applied)) { nextcloud_log_debug('Level pricing already applied'); return $level; } $allowed_levels = nextcloud_get_config('allowed_levels'); if (!in_array((int)$level->id, $allowed_levels, true)) { return $level; } $required_fields = ['storage_space', 'office_suite', 'payment_frequency']; foreach ($required_fields as $field) { if (!isset($_POST[$field]) || empty($_POST[$field])) { nextcloud_log_debug("Required field {$field} missing"); return $level; } } try { // Aplicar validaciones y prorrateo $level = nextcloud_validate_and_prorate_changes($level); // Sanitizar entrada $storage_space = sanitize_text_field($_POST['storage_space']); $office_suite = sanitize_text_field($_POST['office_suite']); $payment_frequency = sanitize_text_field($_POST['payment_frequency']); // Obtener precio base original $original_level = pmpro_getLevel($level->id); $base_price = $original_level ? (float)$original_level->initial_payment : (float)$level->initial_payment; // Calcular precio total $total_price = nextcloud_calculate_pricing($storage_space, $office_suite, $payment_frequency, $base_price); // Aplicar configuración $level->initial_payment = $total_price; $level = nextcloud_configure_billing_period($level, $payment_frequency, $total_price); $level->_nextcloud_applied = true; nextcloud_log_info('Level pricing modified successfully', [ 'level_id' => $level->id, 'final_price' => $total_price, 'storage_space' => $storage_space, 'office_suite' => $office_suite, 'payment_frequency' => $payment_frequency ]); } catch (Exception $e) { nextcloud_log_error('Exception in nextcloud_modify_level_pricing', [ 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ]); } return $level; } /** * Guardado optimizado de configuración */ function nextcloud_save_configuration_and_provision($user_id, $morder) { if (!$user_id || !$morder) { nextcloud_log_error('Invalid parameters for save_configuration'); return; } $required_fields = ['storage_space', 'office_suite', 'payment_frequency']; $config_data = []; foreach ($required_fields as $field) { if (!isset($_REQUEST[$field]) || empty($_REQUEST[$field])) { nextcloud_log_warning("Missing {$field} in configuration save"); return; } $config_data[$field] = sanitize_text_field($_REQUEST[$field]); } $config = array_merge($config_data, [ 'created_at' => current_time('mysql'), 'updated_at' => current_time('mysql'), 'level_id' => $morder->membership_id, 'final_amount' => $morder->InitialPayment, 'order_id' => $morder->id ?? null, 'version' => NEXTCLOUD_PLUGIN_VERSION ]); $config_json = wp_json_encode($config); if (json_last_error() !== JSON_ERROR_NONE) { nextcloud_log_error('JSON encoding error', ['error' => json_last_error_msg()]); return; } $saved = update_user_meta($user_id, 'nextcloud_config', $config_json); // Invalidar caché nextcloud_invalidate_user_cache($user_id); if (!$saved) { nextcloud_log_error('Failed to save user configuration', ['user_id' => $user_id]); } else { nextcloud_log_info('Configuration saved successfully', [ 'user_id' => $user_id, 'config' => $config ]); } } /** * Localización de script JS con datos optimizados */ function nextcloud_localize_pricing_script() { // Verificar páginas relevantes $is_relevant_page = false; if (function_exists('pmpro_getOption')) { $checkout_page = pmpro_getOption('checkout_page_slug'); $billing_page = pmpro_getOption('billing_page_slug'); $account_page = pmpro_getOption('account_page_slug'); $is_relevant_page = ( (!empty($checkout_page) && is_page($checkout_page)) || (!empty($billing_page) && is_page($billing_page)) || (!empty($account_page) && is_page($account_page)) ); } if (!$is_relevant_page) { return; } // Obtener datos del nivel actual $level_id = nextcloud_get_current_level_id(); $base_price = 0; if ($level_id > 0) { $level = pmpro_getLevel($level_id); $base_price = $level ? (float)$level->initial_payment : 0; } // Datos del usuario actual $current_storage = '1tb'; $current_suite = '20users'; $used_space_tb = 0; if (is_user_logged_in()) { $user_id = get_current_user_id(); $config_json = get_user_meta($user_id, 'nextcloud_config', true); if ($config_json) { $config = json_decode($config_json, true); $current_storage = $config['storage_space'] ?? '1tb'; $current_suite = $config['office_suite'] ?? '20users'; } $used_space_tb = get_nextcloud_used_space_tb($user_id); } // Localizar script $script_handle = 'simply-snippet-pmpro-dynamic-pricing'; wp_localize_script( $script_handle, 'nextcloud_pricing', [ 'level_id' => $level_id, 'base_price' => $base_price, 'currency_symbol' => 'R$', 'current_storage' => $current_storage, 'used_space_tb' => $used_space_tb, 'current_suite' => $current_suite, 'debug' => defined('WP_DEBUG') && WP_DEBUG, 'timestamp' => time(), 'ajax_url' => admin_url('admin-ajax.php'), 'version' => NEXTCLOUD_PLUGIN_VERSION ] ); nextcloud_log_info('Script localized successfully', [ 'base_price' => $base_price, 'level_id' => $level_id ]); } // ==================================================================== // INICIALIZACIÓN Y HOOKS // ==================================================================== // Hooks de inicialización múltiples para compatibilidad add_action('plugins_loaded', 'nextcloud_add_dynamic_fields', 25); add_action('init', 'nextcloud_add_dynamic_fields', 20); add_action('wp_loaded', 'nextcloud_add_dynamic_fields', 5); // Hook principal de modificación de precio add_filter('pmpro_checkout_level', 'nextcloud_modify_level_pricing', 1); // Hooks de guardado add_action('pmpro_after_checkout', 'nextcloud_save_configuration_and_provision', 10, 2); // Localización de scripts add_action('wp_enqueue_scripts', 'nextcloud_localize_pricing_script', 30); // Invalidación de caché en cambios de membresía add_action('pmpro_after_change_membership_level', function($level_id, $user_id) { nextcloud_invalidate_user_cache($user_id); nextcloud_log_info('Cache invalidated on membership change', [ 'user_id' => $user_id, 'level_id' => $level_id ]); }, 10, 2); // Indicador de estado en admin bar add_action('admin_bar_menu', function($wp_admin_bar) { if (!current_user_can('manage_options')) return; $dependencies_ok = nextcloud_check_dependencies(); $status = $dependencies_ok ? '✅' : '❌'; $wp_admin_bar->add_node([ 'id' => 'nextcloud-dynamic-status', 'title' => "PMPro Dynamic {$status}", 'href' => admin_url('plugins.php'), 'meta' => ['title' => "PMPro Dynamic Status"] ]); }, 100); nextcloud_log_info('PMPro Dynamic Pricing snippet loaded successfully', [ 'version' => NEXTCLOUD_PLUGIN_VERSION, 'php_version' => PHP_VERSION ]);