DateTime::createFromFormat('m/d/y', trim($date))->format('Y-m-d'), explode("\n", $holidays_raw) ); $min_starting_volume = (int) get_field('min_starting_email_volume', 'option') ?: 10; $max_daily_volume = (int) get_field('max_campaign_daily_email_volume', 'option') ?: 1000; // Calculate starting daily volume (2.5% of target volume) $starting_daily_volume = max(ceil($target_volume * 0.025), $min_starting_volume); // Initialize variables $timeline = []; $total_days = $warmup_period * 7; // Total days in the campaign $start_date = new DateTime($start_date); // Calculate daily ramp-up rate $daily_increase = ($target_volume - $starting_daily_volume) / $total_days; // Generate timeline for ($day = 0; $day < $total_days; $day++) { $current_date = clone $start_date; $current_date->modify("+{$day} days"); $date_formatted = $current_date->format('Y-m-d'); // Adjust for holidays and weekends $is_weekend = in_array($current_date->format('N'), [6, 7]); $is_holiday = in_array($date_formatted, $holidays); $reduction_factor = ($is_weekend || $is_holiday) ? rand(65, 82) / 100 : 1; // Calculate daily volume $daily_volume = min( ceil(($starting_daily_volume + ($daily_increase * $day)) * $reduction_factor), $target_volume * 1.2 ); if ($daily_volume > $max_daily_volume) { $daily_volume = $max_daily_volume; } $timeline[$date_formatted] = $daily_volume; } // Save the timeline as a JSON string to the campaign post $timeline_json = json_encode($timeline); // log_to_file("Timeline JSON: $timeline_json"); update_post_meta($campaign_id, 'campaign_timeline', $timeline_json); return $timeline; } /** * Generate a conversation for a campaign. * * @param int $campaign_id The ID of the campaign. * @param array $conversation_steps Blueprint of the conversation (participants, replies, etc.). * @param string $prompt AI prompt for generating email content. * * @return int|WP_Error The ID of the created conversation or a WP_Error on failure. */ public static function generate_conversation($campaign_id, $conversation_steps, $prompt) { if (empty($campaign_id) || empty($conversation_steps)) { return new WP_Error('invalid_data', __('Invalid campaign or conversation steps.', 'rl-mailwarmer')); } // Insert the conversation into the database $conversation_id = RL_MailWarmer_DB_Helper::insert_conversation($campaign_id, $conversation_steps, $prompt); if (!$conversation_id) { return new WP_Error('db_error', __('Failed to create conversation.', 'rl-mailwarmer')); } return $conversation_id; } /** * Generate messages for a conversation. * * @param int $conversation_id The ID of the conversation. * @param int $campaign_id The ID of the campaign. * @param array $steps The steps of the conversation. * * @return array An array of message IDs or WP_Error on failure. */ public static function generate_messages($conversation_id, $campaign_id, $steps) { if (empty($conversation_id) || empty($campaign_id) || empty($steps)) { return new WP_Error('invalid_data', __('Invalid conversation or steps.', 'rl-mailwarmer')); } $message_ids = []; foreach ($steps as $step) { $scheduled_for = $step['scheduled_for']; $from_email = $step['from']; $to_email = implode(',', $step['to']); $cc = isset($step['cc']) ? implode(',', $step['cc']) : null; $subject = $step['subject']; $body = $step['body']; // Insert the message into the database $message_id = RL_MailWarmer_DB_Helper::insert_message( $campaign_id, $conversation_id, $scheduled_for, $from_email, $to_email, $cc, $subject, $body ); if (!$message_id) { return new WP_Error('db_error', __('Failed to create message.', 'rl-mailwarmer')); } $message_ids[] = $message_id; } return $message_ids; } /** * Generate conversations and messages for a campaign. * * @param int $campaign_id The ID of the campaign. * @param int $weekly_volume The target weekly email volume. * * @return array An array of created conversation IDs or WP_Error on failure. */ public static function generate_conversations($campaign_id, $weekly_volume) { $conversation_ids = []; // Example: Break down weekly volume into conversation ratios $conversation_ratios = [ ['percentage' => 5, 'participants' => [3, 6], 'replies' => [5, 12]], ['percentage' => 10, 'participants' => [3, 5], 'replies' => [3, 5]], ['percentage' => 15, 'participants' => [2, 4], 'replies' => [1, 3]], ['percentage' => 70, 'participants' => [2, 6], 'replies' => [0, 0]], ]; foreach ($conversation_ratios as $ratio) { $volume = ceil($weekly_volume * ($ratio['percentage'] / 100)); for ($i = 0; $i < $volume; $i++) { $conversation_steps = []; // Generate steps based on ratio $prompt = ''; // Generate prompt for AI (to be implemented) // Create conversation $conversation_id = self::generate_conversation($campaign_id, $conversation_steps, $prompt); if (is_wp_error($conversation_id)) { return $conversation_id; } $steps = []; // Generate steps for this conversation $message_result = self::generate_messages($conversation_id, $campaign_id, $steps); if (is_wp_error($message_result)) { return $message_result; } $conversation_ids[] = $conversation_id; } } return $conversation_ids; } /** * Generate additional email accounts for the campaign. * * Creates additional email accounts for initiating email conversations, * replying to chains, and being included on CCs to increase email volume. * * @param int $campaign_id The campaign post ID. * @return array List of generated email accounts. */ public static function generate_campaign_email_accounts($campaign_id) { // Implementation placeholder return []; } /** * Generate conversation vectors for the campaign. * * Creates a detailed map of email chains, participants, and timelines, * based on campaign requirements. * * @param int $campaign_id The campaign post ID. * @return array List of conversation vectors with timestamps and participants. */ public static function generate_campaign_conversation_vectors($campaign_id) { // Implementation placeholder return []; } /** * Generate email conversation content using ChatGPT. * * Creates realistic email conversations with context and replies, * leveraging ChatGPT for natural language generation. * * @param int $campaign_id The campaign post ID. * @param array $vector Details of the conversation vector (participants, topics, etc.). * @return string Generated email conversation content. */ public static function generate_email_conversation($campaign_id, $vector) { // Implementation placeholder return ''; } } /** * Add a meta box for generating the campaign timeline. */ add_action('add_meta_boxes', function () { add_meta_box( 'generate_campaign_timeline', __('Generate Timeline', 'rl-mailwarmer'), 'rl_mailwarmer_render_generate_timeline_box', 'campaign', 'side', 'default' ); }); /** * Render the "Generate Timeline" meta box. * * @param WP_Post $post The current post object. */ function rl_mailwarmer_render_generate_timeline_box($post) { // Add a nonce for security wp_nonce_field('generate_timeline_nonce', 'generate_timeline_nonce_field'); // Render the form ?>

post_type === 'campaign') { wp_enqueue_script( 'rl-mailwarmer-generate-timeline-js', RL_MAILWARMER_URL . 'js/generate-timeline.js', // Adjust path as needed ['jquery'], null, true ); wp_localize_script('rl-mailwarmer-generate-timeline-js', 'rlMailWarmerGenerateTimeline', [ 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('generate_timeline_nonce'), ]); } }); add_action('wp_ajax_rl_mailwarmer_generate_timeline', function () { // Verify nonce if (!isset($_POST['security']) || !wp_verify_nonce($_POST['security'], 'generate_timeline_nonce')) { wp_send_json_error(__('Invalid nonce', 'rl-mailwarmer')); } // Validate and sanitize input $post_id = intval($_POST['post_id']); if (!$post_id || get_post_type($post_id) !== 'campaign') { wp_send_json_error(__('Invalid campaign ID.', 'rl-mailwarmer')); } // Generate the timeline try { $timeline = RL_MailWarmer_Campaign_Helper::calculate_campaign_timeline($post_id); // log_to_file("wp_ajax_rl_mailwarmer_generate_timeline - Generated Timeline: ", $timeline); // update_post_meta($post_id, "campaign_timeline", $timeline); wp_send_json_success($timeline); } catch (Exception $e) { wp_send_json_error($e->getMessage()); } }); // Cal-Heatmap add_action('edit_form_after_title', function ($post) { if ($post->post_type === 'campaign') { echo '
'; } }); add_action('admin_enqueue_scripts', function ($hook) { global $post; if (($hook === 'post.php' || $hook === 'post-new.php') && $post->post_type === 'campaign') { // Enqueue D3.js (required for Cal-Heatmap) wp_enqueue_script( 'd3-js', 'https://d3js.org/d3.v7.min.js', [], '7.0.0', true ); // Enqueue Cal-Heatmap wp_enqueue_script( 'cal-heatmap', 'https://unpkg.com/cal-heatmap/dist/cal-heatmap.min.js', ['d3-js'], '4.2.4', true ); // Enqueue Cal-Heatmap CSS wp_enqueue_style( 'cal-heatmap', 'https://unpkg.com/cal-heatmap/dist/cal-heatmap.css', [], '4.2.4' ); // Custom heatmap script wp_enqueue_script( 'rl-mailwarmer-campaign-heatmap', RL_MAILWARMER_URL . 'js/campaign-timeline-heatmap.js', ['cal-heatmap', 'jquery'], null, true ); // Pass data to the script wp_localize_script('rl-mailwarmer-campaign-heatmap', 'rlMailWarmerHeatmap', [ 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('campaign_timeline_nonce'), 'post_id' => $post->ID, ]); } }); add_action('wp_ajax_rl_mailwarmer_get_timeline', function () { // Verify nonce if (!isset($_POST['security']) || !wp_verify_nonce($_POST['security'], 'campaign_timeline_nonce')) { wp_send_json_error(__('Invalid nonce', 'rl-mailwarmer')); } // Validate and sanitize input $post_id = intval($_POST['post_id']); if (!$post_id || get_post_type($post_id) !== 'campaign') { wp_send_json_error(__('Invalid campaign ID.', 'rl-mailwarmer')); } // Retrieve the timeline $timeline_json = get_post_meta($post_id, 'campaign_timeline', true); $timeline = json_decode($timeline_json, true); if (!$timeline) { wp_send_json_error(__('No timeline data found.', 'rl-mailwarmer')); } // Convert timeline to Cal-Heatmap format (timestamp => value) $heatmap_data = []; foreach ($timeline as $date => $volume) { $timestamp = strtotime($date); // Convert to UNIX timestamp $heatmap_data[$timestamp] = $volume; } wp_send_json_success($heatmap_data); });