rl-warmup-plugin/includes/class-rl-mailwarmer-campaign-helper.php

410 lines
14 KiB
PHP

<?php
/**
* Helper class for managing Campaigns.
*/
class RL_MailWarmer_Campaign_Helper
{
/**
* Calculate the campaign timeline with randomized daily email goals.
*
* @param int $campaign_id The campaign post ID.
* @return array Weekly email schedule with randomized daily goals.
* @throws Exception If the campaign parameters are invalid.
*/
public static function calculate_campaign_timeline($campaign_id)
{
// Fetch campaign details
$warmup_period = (int) get_post_meta($campaign_id, 'warmup_period', true); // Weeks
$target_volume = (int) get_post_meta($campaign_id, 'target_volume', true); // Daily emails to ramp up to
$start_date = get_post_meta($campaign_id, 'start_date', true); // Campaign start date
if (!$warmup_period || !$target_volume || !$start_date) {
throw new Exception(__('Invalid campaign parameters.', 'rl-mailwarmer'));
}
// Fetch ACF options
$holidays_raw = get_field('calendar_holidays', 'option'); // Holidays in 12/25/25 format
$holidays = array_map(
fn($date) => 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
?>
<form id="generate-timeline-form">
<p>
<button type="button" id="generate-timeline-button" class="button button-primary">
<?php esc_html_e('Generate Timeline', 'rl-mailwarmer'); ?>
</button>
</p>
<div id="generate-timeline-result"></div>
</form>
<?php
}
add_action('admin_enqueue_scripts', function ($hook) {
global $post;
// Ensure this is the Add/Edit Campaign screen
if (($hook === 'post.php' || $hook === 'post-new.php') && $post->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 '<div id="campaign-timeline-heatmap" style="width: 100%; height: 300px; border:1px solid #fff;"></div>';
}
});
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);
});