rl-warmup-plugin/includes/rl-mailwarmer-functions.php
ruben de40085318 Implement AI-powered conversation generation and improved campaign timeline management
- Add OpenAI integration for realistic email conversation generation
- Enhance campaign timeline algorithm with natural distribution patterns
- Improve message handling with Symfony Mailer components
- Add conversation blueprint system for structured email threads
- Implement visual timeline with heatmap for campaign tracking

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-03-07 01:49:49 -06:00

606 lines
No EOL
20 KiB
PHP

<?php
// wp_enqueue_script('jquery');
// error_log("There is something wrong!", 0);
// log_to_file("log_errors: ".ini_get('log_errors'));
// log_to_file("error_log: ".ini_get('error_log'));
// date_default_timezone_set("America/Chicago");
/**
* Basic logging function for debugging. Allows passing of an object or array for the $data paramater
*
* Set the CUSTOM_DEBUG_LOG file in wp-config.php
*
*/
function log_to_file($message, $data = null, $enable_backtrace = false) {
if ($message) {
$log_File = CUSTOM_DEBUG_LOG;
$date = new DateTime('now', new DateTimeZone('America/Chicago'));
$date = $date->format("Y/m/d h:i:s");
// Convert arrays and objects to JSON format
if (is_array($data) || is_object($data)) {
$data = json_encode($data, JSON_PRETTY_PRINT);
$message = $message . "\r\n" . $data;
} else if ($data) {
$message = $message . " " . $data;
}
// Include backtrace information if enabled
if ($enable_backtrace) {
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
$callingFunction = $backtrace[1]['function']; // Access the calling function name
$backtrace_info = json_encode($backtrace, JSON_PRETTY_PRINT);
$message .= "\r\nBacktrace:\r\n" . $backtrace_info;
}
error_log("[$date] " . $message . "\r\n", 3, $log_File);
}
}
function action_log($message, $data = null, $enable_backtrace = false) {
if ($message) {
$log_File = ACTION_LOG;
$date = new DateTime('now', new DateTimeZone('America/Chicago'));
$date = $date->format("Y/m/d h:i:s");
// Convert arrays and objects to JSON format
if (is_array($data) || is_object($data)) {
$data = json_encode($data, JSON_PRETTY_PRINT);
$message = $message . "\r\n" . $data;
} else if ($data) {
$message = $message . " " . $data;
}
// Include backtrace information if enabled
if ($enable_backtrace) {
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
$callingFunction = $backtrace[1]['function']; // Access the calling function name
$backtrace_info = json_encode($backtrace, JSON_PRETTY_PRINT);
$message .= "\r\nBacktrace:\r\n" . $backtrace_info;
}
error_log("[$date] " . $message . "\r\n", 3, $log_File);
}
}
function rl_mailwarmer_enqueue_scripts() {
wp_enqueue_script('jquery');
wp_enqueue_script('jquery-ui-core');
wp_enqueue_script('jquery-ui-tabs');
wp_enqueue_style('jquery-ui-css', 'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.13.2/themes/base/jquery-ui.min.css');
wp_add_inline_script('jquery', '
jQuery(document).ready(function($) {
$(".notice-dismiss").on("click", function() {
$(this).closest(".notice").fadeOut();
});
$(".advanced-toggle").click(function() {
$(".advanced-content").slideToggle();
$(this).toggleClass("open");
});
});
');
wp_enqueue_script('rl-mailwarmer-public-script', RL_MAILWARMER_URL . '/js/public-check-domain-health.js', ['jquery'], null, true);
wp_localize_script('rl-mailwarmer-public-script', 'rlMailWarmer_public', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('check_domain_health_nonce'),
'post_id' => get_the_ID()
]);
}
add_action('wp_enqueue_scripts', 'rl_mailwarmer_enqueue_scripts');
/**
* Disable specific plugins based on the WP_ENVIRONMENT_TYPE
*/
function disable_plugins_based_on_environment() {
// log_to_file("disable_plugins_based_on_environment - Disabling plugins");
// Ensure the environment type is defined
if ( ! defined( 'WP_ENVIRONMENT_TYPE' ) ) {
return;
}
// Retrieve the environment type
$environment = WP_ENVIRONMENT_TYPE;
// log_to_file("disable_plugins_based_on_environment - Disabling plugins for $environment environment");
// Define plugins to disable based on environment in wp-config.php
$disabled_plugins = defined( 'DISABLED_PLUGINS' ) ? DISABLED_PLUGINS : array();
// Only proceed if the array is properly defined and not empty
if ( ! is_array( $disabled_plugins ) || empty( $disabled_plugins ) ) {
return;
}
// Get the currently active plugins
$active_plugins = get_option( 'active_plugins', array() );
foreach ( $disabled_plugins as $plugin_env => $plugins ) {
// Skip if current environment doesn't match
if ( $environment !== $plugin_env ) {
continue;
}
// Loop through plugins to disable for this environment
foreach ( $plugins as $plugin ) {
$plugin_key = array_search( $plugin, $active_plugins, true );
// If the plugin is active, deactivate it
if ( false !== $plugin_key ) {
unset( $active_plugins[ $plugin_key ] );
}
}
}
// Update the active plugins option
update_option( 'active_plugins', $active_plugins );
}
add_action( 'plugins_loaded', 'disable_plugins_based_on_environment', 1 );
/**
* getRandomWeightedElement()
* Utility function for getting random values with weighting.
* Pass in an associative array, such as array('A'=>5, 'B'=>45, 'C'=>50)
* An array like this means that "A" has a 5% chance of being selected, "B" 45%, and "C" 50%.
* The return value is the array key, A, B, or C in this case. Note that the values assigned
* do not have to be percentages. The values are simply relative to each other. If one value
* weight was 2, and the other weight of 1, the value with the weight of 2 has about a 66%
* chance of being selected. Also note that weights should be integers.
*
* @param array $weightedValues
*/
function getRandomWeightedElement(array $weightedValues) {
$rand = mt_rand(1, (int) array_sum($weightedValues));
foreach ($weightedValues as $key => $value) {
$rand -= $value;
if ($rand <= 0) {
return $key;
}
}
}
/**
* Retrieve the content of a textarea meta field and return it as an array if it's a comma-separated list or has multiple lines.
*
* @param int $post_id The ID of the post.
* @param string $meta_key The meta key to retrieve.
* @return array|string The processed array or the original string if no transformation is needed.
*/
function rl_get_textarea_meta_as_array($post_id, $meta_key) {
if ($post_id ==='option') {
$content = get_option('options_' . $meta_key);
} else {
$content = get_post_meta($post_id, $meta_key, true);
}
// log_to_file("rl_get_textarea_meta_as_array - Content {$content}");
if (empty($content)) {
// log_to_file("rl_get_textarea_meta_as_array - {$meta_key} field not found for {$post_id}");
return []; // Return an empty array if the meta field is empty
}
// Check if the content contains multiple lines or is comma-separated
if (strpos($content, "\n") !== false || strpos($content, ',') !== false) {
// Normalize line breaks and split the content into an array
$content_array = preg_split('/[\r\n,]+/', $content);
// Remove empty entries and trim whitespace
return array_filter(array_map('trim', $content_array));
}
return $content; // Return the original content if no transformation is needed
}
/**
*
* Unset default dashboard widgets
*
*/
function remove_dashboard_widgets() {
global $wp_meta_boxes;
unset($wp_meta_boxes['dashboard']['normal']['core']['dashboard_right_now']);
unset($wp_meta_boxes['dashboard']['normal']['core']['dashboard_activity']);
unset($wp_meta_boxes['dashboard']['side']['core']['dashboard_quick_press']);
unset($wp_meta_boxes['dashboard']['side']['core']['dashboard_primary']);
// unset($wp_meta_boxes['dashboard']['normal']['core']['dashboard_incoming_links']);
// unset($wp_meta_boxes['dashboard']['normal']['core']['dashboard_plugins']);
// unset($wp_meta_boxes['dashboard']['normal']['core']['dashboard_recent_drafts']);
// unset($wp_meta_boxes['dashboard']['normal']['core']['dashboard_recent_comments']);
// unset($wp_meta_boxes['dashboard']['side']['core']['dashboard_secondary']);
// unset($wp_meta_boxes['dashboard']['normal']['high']['rank_math_dashboard_widget']);
}
add_action('wp_dashboard_setup', 'remove_dashboard_widgets' );
/**
*
* Reorder the admin menu. Leaves positions 1-8 available
*
*/
add_action('admin_head', 'mf_edit_admin_menu');
function mf_edit_admin_menu(){
global $menu;
$menu[0] = $menu[2]; // Move the Dashboard to the top
unset($menu[2]); // Unset the Dashboard (from original position)
// $menu[8] = $menu[4]; // Copy 'separator1' to a new menu location
unset($menu[4]); // Unset separator1 (from original position)
///$menu[9] = $menu[5]; // Copy 'Posts' to a new menu location
unset($menu[5]); // Unset Posts (from original position)
ksort($menu); // Sort the menu
}
/**
* Append Login In/Out link to menu with a redirect to this page
*/
add_filter( 'wp_nav_menu_primary-menu_items','rl_mailwarmer_loginout_menu_link', 10, 1 );
function rl_mailwarmer_loginout_menu_link( $menu ) {
$referrer_url = $_SERVER['REQUEST_URI'];
// $redirect_url = "/membership-levels";
$redirect_url = "/dashboard";
// log_to_file("referrer_url: $referrer_url");
// if ($referrer_url == '/membership-levels/') {
// $redirect_url = "/dashboard";
// }
$loginout = wp_loginout( $redirect_url, false );
$menu .= $loginout;
return $menu;
}
// Create a shortcode to match
add_shortcode( 'mailferno_login_link', 'mailferno_show_login_link' );
function mailferno_show_login_link( ) {
$referrer_url = $_SERVER['REQUEST_URI'];
// $redirect_url = "/membership-levels";
$redirect_url = "/dashboard/?redirect_to=%2Fdashboard";
// log_to_file("referrer_url: $referrer_url");
// if ($referrer_url == '/membership-levels/') {
// $redirect_url = "/dashboard";
// }
$login = '<a href="' . esc_url( wp_login_url( $redirect_url ) ) . '">Already have an account? Login here!</a>';
return $login;
}
/**
* Add a meta box for testing the SSH connection.
*/
add_action('add_meta_boxes', function () {
add_meta_box(
'test_ssh_connection_box',
__('Test SSH Connection', 'rl-mailwarmer'),
'rl_mailwarmer_render_test_ssh_connection_box',
'server',
'side',
'default'
);
});
/**
* Render the SSH connection test meta box.
*
* @param WP_Post $post The current post object.
*/
function rl_mailwarmer_render_test_ssh_connection_box($post)
{
// Add a nonce field for security
wp_nonce_field('test_ssh_connection_nonce', 'test_ssh_connection_nonce_field');
// Render the button
?>
<form id="test-ssh-connection-form">
<p>
<button type="button" id="test-ssh-connection-button" class="button button-primary">
<?php esc_html_e('Test SSH Connection', 'rl-mailwarmer'); ?>
</button>
</p>
<div id="test-ssh-connection-result"></div>
</form>
<?php
}
add_action('admin_enqueue_scripts', function ($hook) {
global $post;
// Ensure this is the Add/Edit Server screen
if (($hook === 'post.php' || $hook === 'post-new.php') && $post->post_type === 'server') {
wp_enqueue_script(
'rl-mailwarmer-test-ssh-js',
RL_MAILWARMER_URL . 'js/test-ssh-connection.js', // Adjust path as needed
['jquery'],
null,
true
);
wp_localize_script('rl-mailwarmer-test-ssh-js', 'rlMailWarmerTestSSH', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('test_ssh_connection_nonce'),
'post_id' => $post->ID
]);
}
});
add_action('wp_ajax_rl_mailwarmer_test_ssh_connection', function () {
// Verify nonce
if (!isset($_POST['security']) || !wp_verify_nonce($_POST['security'], 'test_ssh_connection_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) !== 'server') {
wp_send_json_error(__('Invalid server ID.', 'rl-mailwarmer'));
}
// Fetch server details
$server_ip = get_post_meta($post_id, 'ip_address', true);
$server_port = get_post_meta($post_id, 'ssh_port', true);
$server_user = get_post_meta($post_id, 'username', true);
$server_key = get_post_meta($post_id, 'ssh_private_key', true);
// log_to_file("wp_ajax_rl_mailwarmer_test_ssh_connection - SSH $server_user $server_ip $server_port");
// log_to_file("wp_ajax_rl_mailwarmer_test_ssh_connection - SSH Private Key: $server_key");
if (empty($server_ip) || empty($server_user) || empty($server_key)) {
wp_send_json_error(__('Missing server credentials.', 'rl-mailwarmer'));
}
// Test SSH connection
try {
$ssh = new phpseclib3\Net\SSH2($server_ip, $server_port);
$key = phpseclib3\Crypt\PublicKeyLoader::loadPrivateKey($server_key);
if (!$ssh->login($server_user, $key)) {
throw new Exception(__('SSH login failed.', 'rl-mailwarmer'));
}
wp_send_json_success(__('SSH connection successful.', 'rl-mailwarmer'));
} catch (Exception $e) {
wp_send_json_error($e->getMessage());
}
});
/**
* Add sidebars to custom post types
*
*/
function register_custom_sidebars() {
register_sidebar(array(
'name' => 'Domain Sidebar',
'id' => 'sidebar-domain',
'description' => 'Sidebar for domain post type',
'before_widget' => '<div class="widget %2$s">',
'after_widget' => '</div>',
'before_title' => '<h3 class="widget-title">',
'after_title' => '</h3>'
));
register_sidebar(array(
'name' => 'Email Address Sidebar',
'id' => 'sidebar-email',
'description' => 'Sidebar for email-address post type',
'before_widget' => '<div class="widget %2$s">',
'after_widget' => '</div>',
'before_title' => '<h3 class="widget-title">',
'after_title' => '</h3>'
));
register_sidebar(array(
'name' => 'Campaign Sidebar',
'id' => 'sidebar-campaign',
'description' => 'Sidebar for campaign post type',
'before_widget' => '<div class="widget %2$s">',
'after_widget' => '</div>',
'before_title' => '<h3 class="widget-title">',
'after_title' => '</h3>'
));
}
add_action('widgets_init', 'register_custom_sidebars');
// add_filter( 'generate_sidebar_layout','rl_mailwarmer_custom_sidebar_layout' );
function rl_mailwarmer_custom_sidebar_layout( $layout )
{
$post_type = get_post_type();
// log_to_file("rl_mailwarmer_custom_sidebar_layout - Setting custom sidebar for $post_type post.", $layout);
switch ($post_type) {
case 'domain':
$layout = 'sidebar-domain';
break;
case 'email-address':
$layout = 'sidebar-email';
break;
case 'campaign':
$layout = 'sidebar-campaign';
break;
default:
// return $layout;
break;
}
// log_to_file("rl_mailwarmer_custom_sidebar_layout - Setting custom sidebar for $post_type post to: $layout");
// Or else, set the regular layout
return $layout;
}
/**
* PaidMemberships Pro Customizations
*
*/
/**
* Redirects members-only content to the Membership Levels page if a user is logged out or not a member.
*
*/
add_action( 'template_redirect', 'rl_mailwarmer_redirect_require_membership_access' );
function rl_mailwarmer_redirect_require_membership_access() {
if ( function_exists( 'pmpro_has_membership_access' ) && ! pmpro_has_membership_access() ) {
wp_redirect( pmpro_url( 'login' ) );
exit;
}
}
/**
* Add our user fields: cloudflare_api_email, cloudflare_api_key.
* This callback fires during the init action hook.
*/
function mailferno_pmpro_add_user_fields() {
// Don't break if PMPro is out of date or not loaded.
if ( ! function_exists( 'pmpro_add_user_field' ) ) {
return false;
}
// Store our field settings in an array.
$fields = array();
/*
Settings for a company text field that is shown in the user profile.
The text field has a custom size and CSS class. It is required.
Only members with or checking out for levels 1 and 2 will see the field.
*/
$fields[] = new PMPro_Field(
'cloudflare_api_email', // input name and user meta key
'text', // type of field
array(
'label' => 'CloudFlare API Email', // custom field label
// 'size' => 40, // input size
'class' => 'company', // custom class
'profile' => true, // show in user profile
// 'required' => true, // make this field required
// 'levels' => array(1,2), // require level 1 or 2 for this field
'memberslistcsv' => true // include in CSV export
)
);
/*
Settings for a referral code field.
All users can set this at checkout.
Only admins can see it on the user profile page.
*/
$fields[] = new PMPro_Field(
'cloudflare_api_key', // input name and user meta key key
'text', // type of field
array(
'label' => 'CloudFlare API Key', // custom field label
'profile' => true, // only show in profile for admins
'memberslistcsv' => true // include in CSV export
)
);
// Add a field group to put our fields into.
pmpro_add_field_group( 'CloudFlare API Settings' );
// Add all of our fields into that group.
foreach ( $fields as $field ) {
pmpro_add_user_field(
'CloudFlare API Settings', // Which group to add to.
$field // PMPro_Field object
);
}
// That's it. See the PMPro User Fields docs for more information.
}
add_action( 'init', 'mailferno_pmpro_add_user_fields' );
/**
* Allow users to delete posts that they own
*
*/
// Handle front-end deletions
function handle_frontend_post_deletion() {
if (
isset($_GET['action']) && $_GET['action'] === 'delete' &&
isset($_GET['post']) &&
isset($_GET['_wpnonce'])
) {
$post_id = intval($_GET['post']);
// Verify nonce
if (!wp_verify_nonce($_GET['_wpnonce'], 'delete-post_' . $post_id)) {
wp_die('Security check failed');
}
// Check permissions
if (!can_delete_post($post_id)) {
wp_die('You do not have permission to delete this item');
}
// Delete the post
wp_delete_post($post_id, true);
// Redirect back
$redirect_to = isset($_GET['redirect_to']) ? urldecode($_GET['redirect_to']) : '';
if (empty($redirect_to)) {
$redirect_to = remove_query_arg(array('action', 'post', '_wpnonce'));
}
wp_redirect(add_query_arg('deleted', '1', $redirect_to));
exit;
}
}
add_action('template_redirect', 'handle_frontend_post_deletion');
// Check if the user is the owner (for non-admins)
function can_delete_post($post_id) {
if (current_user_can('administrator')) {
return true;
}
$current_user_id = get_current_user_id();
$post_owner_id = get_post_meta($post_id, 'owner_id', true);
return $current_user_id == $post_owner_id;
}
// Single Domain View
function get_connection_status($credentials) {
if ($credentials === false) return "Error";
$missing = [];
foreach (['api_email', 'api_key', 'zone_id'] as $key) {
if (empty($credentials[$key])) $missing[] = $key;
}
return empty($missing) ? "Connected" : "Missing: " . implode(", ", $missing);
}
function mask_api_key($key) {
if (empty($key)) return "";
return str_repeat("*", strlen($key) - 6) . substr($key, -6);
}