Added server email account management

This commit is contained in:
Ruben Ramirez 2025-01-15 10:44:22 -06:00
parent c8002a4194
commit e0e4433345
17 changed files with 3063 additions and 3478 deletions

2
.gitignore vendored
View file

@ -1 +1,3 @@
/includes/vendor/ /includes/vendor/
composer.phar
/vendor/

View file

@ -1,19 +1,12 @@
/* Admin Meta Box Styles */ /* Admin Meta Box Styles */
#fix_deliverability_dns_issues_box, #side-sortables .postbox {
#update_dkim_record_box, /* background: #0e0e0e;*/
#update_dmarc_record_box,
#update_spf_record_box {
background: #f9f9f9;
border: 1px solid #ddd; border: 1px solid #ddd;
padding: 15px;
margin-bottom: 15px; margin-bottom: 15px;
border-radius: 4px; border-radius: 4px;
} }
#fix_deliverability_dns_issues_box h2, #side-sortables .postbox h2 {
#update_dkim_record_box h2,
#update_dmarc_record_box h2,
#update_spf_record_box h2 {
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
margin-bottom: 10px; margin-bottom: 10px;
@ -32,7 +25,7 @@ button.button-primary:hover {
color: #fff; color: #fff;
} }
.meta-box-sortables input, .meta-box-sortables textarea, .meta-box-sortables select, .meta-box-sortables input[type=number] { .meta-box-sortables input[type=text], .meta-box-sortables textarea, .meta-box-sortables input[type=email], .meta-box-sortables select, .meta-box-sortables input[type=number] {
width: 100%; width: 100%;
max-width: 100%; max-width: 100%;
} }
@ -42,6 +35,33 @@ table.rl_admin_meta_table {
table-layout: fixed; table-layout: fixed;
} }
/* Campaign Timeline */
.timeline-grid {
display: flex;
flex-wrap: wrap;
max-width: 100%;
margin: 10px 0;
}
.timeline-grid .day {
flex: 0 0 14.28%; /* 7 rows = 100% / 7 columns */
box-sizing: border-box;
border: 1px solid #ccc;
padding: 5px;
text-align: center;
font-size: 12px;
color: #000;
}
.timeline-grid .day .date {
font-weight: bold;
margin-bottom: 5px;
}
.timeline-grid .day .volume {
font-size: 14px;
}
#campaign-timeline-heatmap { #campaign-timeline-heatmap {
width: 100%; /* Ensure it spans the available space */ width: 100%; /* Ensure it spans the available space */
height: 300px; /* Set a fixed height */ height: 300px; /* Set a fixed height */

File diff suppressed because it is too large Load diff

View file

@ -2,8 +2,10 @@
class RL_MailWarmer_DB_Helper { class RL_MailWarmer_DB_Helper {
private static $conversation_table = 'rl_mailwarmer_conversation'; private static $conversations_table = 'rl_mailwarmer_conversations';
private static $message_table = 'rl_mailwarmer_message'; private static $messages_table = 'rl_mailwarmer_messages';
private static $backups_table = 'rl_mailwarmer_dns_backups';
private static $health_reports_table = 'rl_mailwarmer_health_reports';
/** /**
* Create necessary database tables. * Create necessary database tables.
@ -14,18 +16,22 @@ class RL_MailWarmer_DB_Helper {
$charset_collate = $wpdb->get_charset_collate(); $charset_collate = $wpdb->get_charset_collate();
// Conversation table // Conversation table
$conversation_sql = "CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}" . self::$conversation_table . "` ( $conversation_sql = "CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}" . self::$conversations_table . "` (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
campaign_id BIGINT(20) UNSIGNED NOT NULL, campaign_id BIGINT(20) UNSIGNED NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
conversation_steps JSON NOT NULL, status VARCHAR(20) DEFAULT 'new' NOT NULL,
prompt TEXT NOT NULL, first_message_timestamp DATETIME DEFAULT NULL,
prompt LONGTEXT DEFAULT NULL,
conversation_steps LONGTEXT DEFAULT NULL,
PRIMARY KEY (id), PRIMARY KEY (id),
INDEX campaign_id_idx (campaign_id) KEY campaign_id_idx (campaign_id),
KEY status_idx (status),
KEY first_message_timestamp_idx (first_message_timestamp)
) $charset_collate;"; ) $charset_collate;";
// Message table // Message table
$message_sql = "CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}" . self::$message_table . "` ( $message_sql = "CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}" . self::$messages_table . "` (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
campaign_id BIGINT(20) UNSIGNED NOT NULL, campaign_id BIGINT(20) UNSIGNED NOT NULL,
conversation_id BIGINT(20) UNSIGNED NOT NULL, conversation_id BIGINT(20) UNSIGNED NOT NULL,
@ -35,33 +41,61 @@ class RL_MailWarmer_DB_Helper {
to_email TEXT NOT NULL, to_email TEXT NOT NULL,
cc TEXT NULL, cc TEXT NULL,
subject VARCHAR(255) NOT NULL, subject VARCHAR(255) NOT NULL,
body TEXT NOT NULL, body LONGTEXT NOT NULL,
PRIMARY KEY (id), PRIMARY KEY (id),
INDEX scheduled_idx (scheduled_for_timestamp, status), INDEX scheduled_idx (scheduled_for_timestamp, status),
INDEX conversation_id_idx (conversation_id), INDEX conversation_id_idx (conversation_id),
INDEX campaign_id_idx (campaign_id) INDEX campaign_id_idx (campaign_id)
) $charset_collate;"; ) $charset_collate;";
// Backup table
$backup_sql = "CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}" . self::$backups_table . "` (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
domain_id BIGINT UNSIGNED NOT NULL,
record_name VARCHAR(255) NOT NULL,
record_type VARCHAR(50) NOT NULL,
record_content LONGTEXT NOT NULL,
created_at DATETIME NOT NULL,
INDEX (domain_id),
INDEX (record_name),
INDEX (record_type)
) $charset_collate;";
// Backup table
$health_report_sql = "CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}" . self::$health_reports_table . "` (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
domain_id BIGINT UNSIGNED NOT NULL,
report_content LONGTEXT NOT NULL,
created_at DATETIME NOT NULL,
last_checked DATETIME NOT NULL,
INDEX (domain_id)
) $charset_collate;";
// DNS Backup table
require_once ABSPATH . 'wp-admin/includes/upgrade.php'; require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta($conversation_sql); dbDelta($conversation_sql);
dbDelta($message_sql); dbDelta($message_sql);
dbDelta($backup_sql);
dbDelta($health_report_sql);
} }
/** /**
* Insert a conversation record. * Insert a conversation record.
*/ */
public static function insert_conversation($campaign_id, $conversation_steps, $prompt) { public static function insert_conversation($conversation_data) {
global $wpdb; global $wpdb;
$wpdb->insert( // $wpdb->insert(
"{$wpdb->prefix}" . self::$conversation_table, // "{$wpdb->prefix}" . self::$conversations_table,
[ // [
'campaign_id' => $campaign_id, // 'campaign_id' => $campaign_id,
'conversation_steps' => json_encode($conversation_steps), // 'conversation_steps' => json_encode($conversation_steps),
'prompt' => $prompt, // 'prompt' => $prompt,
], // ],
['%d', '%s', '%s'] // ['%d', '%s', '%s']
); // );
$wpdb->insert("{$wpdb->prefix}" . self::$conversations_table, $conversation_data);
return $wpdb->insert_id; return $wpdb->insert_id;
} }
@ -69,28 +103,33 @@ class RL_MailWarmer_DB_Helper {
/** /**
* Insert a message record. * Insert a message record.
*/ */
public static function insert_message($campaign_id, $conversation_id, $scheduled_for, $from_email, $to_email, $cc, $subject, $body) { public static function insert_message($message_data) {
global $wpdb; global $wpdb;
$wpdb->insert( // log_to_file("insert_message - Message body: $body");
"{$wpdb->prefix}" . self::$message_table,
[ // $wpdb->insert(
'campaign_id' => $campaign_id, // "{$wpdb->prefix}rl_mailwarmer_message",
'conversation_id' => $conversation_id, // [
'scheduled_for_timestamp' => $scheduled_for, // 'campaign_id' => $campaign_id,
'status' => 'pending', // 'conversation_id' => $conversation_id,
'from_email' => $from_email, // 'scheduled_for_timestamp' => $scheduled_for,
'to_email' => $to_email, // 'status' => 'pending',
'cc' => $cc, // 'from_email' => $from_email,
'subject' => $subject, // 'to_email' => $to_email,
'body' => $body, // 'cc' => $cc,
], // 'subject' => $subject,
['%d', '%d', '%s', '%s', '%s', '%s', '%s', '%s'] // 'body' => $body,
); // 'first_message' => $first_message ? 1 : 0,
// ],
// ['%d', '%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d']
// );
$wpdb->insert("{$wpdb->prefix}" . self::$messages_table, $message_data);
return $wpdb->insert_id; return $wpdb->insert_id;
} }
/** /**
* Fetch pending messages. * Fetch pending messages.
*/ */
@ -98,7 +137,7 @@ class RL_MailWarmer_DB_Helper {
global $wpdb; global $wpdb;
$sql = $wpdb->prepare( $sql = $wpdb->prepare(
"SELECT * FROM `{$wpdb->prefix}" . self::$message_table . "` "SELECT * FROM `{$wpdb->prefix}" . self::$messages_table . "`
WHERE scheduled_for_timestamp <= %s AND status = 'pending' WHERE scheduled_for_timestamp <= %s AND status = 'pending'
LIMIT %d", LIMIT %d",
current_time('mysql'), current_time('mysql'),
@ -107,5 +146,169 @@ class RL_MailWarmer_DB_Helper {
return $wpdb->get_results($sql, ARRAY_A); return $wpdb->get_results($sql, ARRAY_A);
} }
// Get Message Counts
public static function get_message_counts_by_date($campaign_id) {
global $wpdb;
$messages_table = $wpdb->prefix . self::$messages_table;
$results = $wpdb->get_results(
$wpdb->prepare(
"SELECT
DATE(scheduled_for_timestamp) AS message_date,
COUNT(*) AS message_count
FROM
$messages_table
WHERE
campaign_id = %d
GROUP BY
DATE(scheduled_for_timestamp)
ORDER BY
message_date ASC",
$campaign_id
),
ARRAY_A
);
return $results;
}
/**
* Insert DNS backups into the database.
*
* @param mixed $domain The domain ID or post object.
* @param array $records The DNS records to back up.
* @return bool True on success, false on failure.
*/
public static function insert_dns_backup($domain, $record) {
global $wpdb;
$backups_table = $wpdb->prefix . 'rl_mailwarmer_dns_backups';
$domain_post = is_object($domain) ? $domain : RL_MailWarmer_Domain_Helper::get_domain_post($domain);
if (!$domain_post) {
throw new Exception(__('Invalid domain specified.', 'rl-mailwarmer'));
}
// log_to_file("insert_dns_backup - Attemting to backup record: ", $record);
$existing = $wpdb->get_row(
$wpdb->prepare(
"SELECT * FROM $backups_table WHERE domain_id = %d AND record_name = %s AND record_type = %s ORDER BY created_at DESC LIMIT 1",
$domain_post->ID,
$record['name'],
$record['type']
),
ARRAY_A
);
if ($existing && $existing['record_content'] === $record['content']) {
// log_to_file("insert_dns_backup - New & Old content are the same. Skipping insert and returning TRUE");
// return true;
return $existing['id'];
// continue; // Skip unchanged records
}
try {
$wpdb->insert($backups_table, [
'domain_id' => $domain_post->ID,
'record_name' => $record['name'],
'record_type' => $record['type'],
'record_content' => $record['content'],
'created_at' => current_time('mysql'),
]);
} catch (Exception $e) {
error_log(__('insert_dns_backup - Failed to insert new DNS backup record: ', 'rl-mailwarmer') . $e->getMessage());
}
return $wpdb->insert_id;
// return true;
}
/**
* Insert health report backups into the database.
*
* @param mixed $domain The domain ID or post object.
* @param array $records The DNS records to back up.
* @return bool True on success, false on failure.
*/
public static function insert_health_report_backup($domain, $report) {
global $wpdb;
$health_reports_table = $wpdb->prefix . 'rl_mailwarmer_health_reports';
$domain_post = is_object($domain) ? $domain : RL_MailWarmer_Domain_Helper::get_domain_post($domain);
if (!$domain_post) {
throw new Exception(__('Invalid domain specified.', 'rl-mailwarmer'));
}
// log_to_file("insert_health_report_backup - Attempting to save health report for {$domain_post->post_title}: ");
try {
// log_to_file("insert_health_report_backup - Fetching existing rows.");
$existing = $wpdb->get_row(
$wpdb->prepare(
"SELECT * FROM $health_reports_table WHERE domain_id = %d ORDER BY created_at DESC LIMIT 1",
$domain_post->ID
),
ARRAY_A
);
// log_to_file("insert_health_report_backup - Done fetching existing rows.");
if ($existing && $existing['report_content'] === $report) {
// log_to_file("insert_health_report_backup - New & Old content are the same. Skipping insert and returning ID of existing record");
// Prepare the data
$data = [
'last_checked' => current_time('mysql'), // Save the JSON response as a string
];
$where = [
'id' => $existing['id'],
];
// Update the database
try {
$result = $wpdb->update(
$health_reports_table,
$data,
$where,
['%s'],
['%d']
);
} catch (Exception $e) {
log_to_file("insert_health_report_backup - Error updating existing database entry.");
throw new Exception(__('insert_health_report_backup - Error updating existing database entry: ', 'rl-mailwarmer') . $e->getMessage());
}
return $existing['id'];
// continue; // Skip unchanged records
}
} catch (Exception $e) {
log_to_file("insert_health_report_backup - Error fetching existing rows.");
throw new Exception(__('insert_health_report_backup - Unable to fetch existing records: ', 'rl-mailwarmer') . $e->getMessage());
}
try {
$current_time = current_time('mysql');
$data = [
'domain_id' => $domain_post->ID,
'report_content' => $report,
'created_at' => $current_time,
'last_checked' => $current_time,
];
$result = $wpdb->insert(
$health_reports_table,
$data
);
if ($result === false) {
return new WP_Error('db_update_failed', __('Failed to update the conversation steps.', 'rl-mailwarmer'));
}
return $result;
} catch (Exception $e) {
throw new Exception(__('insert_health_report_backup - Failed to insert new health report record: ', 'rl-mailwarmer') . $e->getMessage());
// error_log(__('insert_dns_backup - Failed to insert new health report record: ', 'rl-mailwarmer') . $e->getMessage());
}
return false;
}
} }

File diff suppressed because it is too large Load diff

View file

@ -138,8 +138,8 @@ class RL_MailWarmer_Email_Handler
{ {
$start_hour = 8; // 8 AM $start_hour = 8; // 8 AM
$end_hour = 18; // 6 PM $end_hour = 18; // 6 PM
$random_hour = rand($start_hour, $end_hour - 1); $random_hour = mt_rand($start_hour, $end_hour - 1);
$random_minute = rand(0, 59); $random_minute = mt_rand(0, 59);
return strtotime(date('Y-m-d', $timestamp) . " {$random_hour}:{$random_minute}:00"); return strtotime(date('Y-m-d', $timestamp) . " {$random_hour}:{$random_minute}:00");
} }

View file

@ -1,471 +0,0 @@
<?php
/**
* Helper functions for the email-account post type.
*/
require 'vendor/autoload.php';
use phpseclib3\Net\SSH2;
use phpseclib3\Crypt\PublicKeyLoader;
if (!defined('ABSPATH')) {
exit;
}
/**
* RL_MailWarmer_Email_Helper Class
*
* Handles email account management and mail operations.
*/
class RL_MailWarmer_Email_Helper
{
/**
* Modify an email account post.
*
* Creates, updates, or deletes an email account post and its associated metadata.
*
* @param array $args {
* Arguments for modifying the email account.
*
* @type int $post_id Optional. Post ID to update or delete. Required for updates or deletions.
* @type string $action Required. Action to perform: 'create', 'update', or 'delete'.
* @type string $email Optional. Email address for the account (used as post title).
* @type array $metadata Optional. Additional metadata to save with the post.
* }
* @return int|bool Post ID on success, false on failure.
*/
// Create an Email Account
// $post_id = RL_MailWarmer_Email_Helper::modify_email_account([
// 'action' => 'create',
// 'email' => 'johndoe@example.com',
// 'metadata' => [
// 'full_name' => 'John Doe',
// 'mail_password' => 'securepassword123',
// 'email_provider' => 123, // Post ID of the email provider
// 'smtp_server' => 'smtp.example.com',
// 'smtp_port' => 587,
// 'imap_server' => 'imap.example.com',
// 'imap_port' => 993,
// ],
// ]);
// // Update an Email Account
// $result = RL_MailWarmer_Email_Helper::modify_email_account([
// 'action' => 'update',
// 'post_id' => $post_id,
// 'metadata' => [
// 'full_name' => 'Jane Doe',
// 'mail_password' => 'newsecurepassword123',
// 'smtp_status' => 'connected',
// ],
// ]);
// // Delete an Email Account
// $result = RL_MailWarmer_Email_Helper::modify_email_account([
// 'action' => 'delete',
// 'post_id' => $post_id,
// ]);
public static function modify_email_account(array $args)
{
// Validate required arguments
if (empty($args['action']) || !in_array($args['action'], ['create', 'update', 'delete'], true)) {
throw new InvalidArgumentException('Invalid or missing action.');
}
/*
* Add validation to only delete email-account posts
*
*/
$action = $args['action'];
$post_id = $args['post_id'] ?? null;
// Handle delete action
if ($action === 'delete') {
if (!$post_id) {
throw new InvalidArgumentException('Post ID is required for deletion.');
}
return wp_delete_post($post_id, true);
}
// Validate fields for create/update
$post_data = [
'post_type' => 'email-account',
'post_status' => 'publish',
];
// For "create", ensure no existing post with the same title
if ($action === 'create') {
if (empty($args['email'])) {
throw new InvalidArgumentException('Email is required for creating a new account.');
}
$existing_post = get_page_by_title($args['email'], OBJECT, 'email-account');
if ($existing_post) {
throw new RuntimeException('An email account with this title already exists.');
}
$post_data['post_title'] = $args['email'];
} elseif ($action === 'update') {
if (!$post_id) {
throw new InvalidArgumentException('Post ID is required for updates.');
}
$post_data['ID'] = $post_id;
}
// Assemble metadata
$meta_args = $args['metadata'] ?? [];
// Generate a random password if mail_password is not provided
if (empty($meta_args['mail_password'])) {
$meta_args['mail_password'] = bin2hex(random_bytes(8)); // 16-character password
}
$post_data['meta_input'] = array_map('sanitize_text_field', $meta_args);
// Save or update the post
$post_id = wp_insert_post($post_data);
if (is_wp_error($post_id)) {
throw new RuntimeException('Failed to save email account post: ' . $post_id->get_error_message());
}
return $post_id;
}
/**
* Check mail login credentials for an email account.
*
* Validates IMAP/SMTP connection settings for the given email account.
*
* @param mixed $email_account The email-account post object or ID.
* @param string|null $protocol Optional. The protocol to validate ('IMAP' or 'SMTP'). Defaults to both.
* @return array|WP_Error Validation results for IMAP and/or SMTP or WP_Error on failure.
*/
public static function check_mail_login($email_account, $protocol = null)
{
// Get the post object
$post = is_numeric($email_account) ? get_post($email_account) : $email_account;
if (!$post || $post->post_type !== 'email-account') {
return new WP_Error('invalid_post', __('Invalid email account post.', 'rl-mailwarmer'));
}
// Fetch email provider and override defaults with saved values
$email_provider_id = get_post_meta($post->ID, 'email_provider', true);
// log_to_file("check_mail_login - ");
log_to_file("check_mail_login - Email Provider ID $email_provider_id");
$defaults = $email_provider_id ? self::get_provider_defaults($email_provider_id) : [];
log_to_file("check_mail_login - Email Provider Defaults: ", $defaults);
// Fetch saved settings
$saved_settings = [
'mail_password' => get_post_meta($post->ID, 'mail_password', true),
'imap_password' => get_post_meta($post->ID, 'imap_password', true),
'imap_server' => get_post_meta($post->ID, 'imap_server', true),
'imap_port' => get_post_meta($post->ID, 'imap_port', true),
'smtp_password' => get_post_meta($post->ID, 'smtp_password', true),
'smtp_server' => get_post_meta($post->ID, 'smtp_server', true),
'smtp_port' => get_post_meta($post->ID, 'smtp_port', true),
];
// Merge saved settings with defaults
$settings = array_merge($defaults, array_filter($saved_settings));
log_to_file("check_mail_login - Using settings: ", $settings);
$results = [];
// Validate IMAP connection if required
if ($protocol === null || strtoupper($protocol) === 'IMAP') {
$imap_result = self::validate_imap_connection($post->post_title, $settings);
log_to_file("check_mail_login - IMAP Result for " . $post->post_title . ": ", $imap_result);
$results['IMAP'] = $imap_result ? __('IMAP connection successful.', 'rl-mailwarmer') : __('IMAP connection failed.', 'rl-mailwarmer');
}
// Validate SMTP connection if required
if ($protocol === null || strtoupper($protocol) === 'SMTP') {
$smtp_result = self::validate_smtp_connection($post->post_title, $settings);
log_to_file("check_mail_login - SMTP Result for " . $post->post_title . ": ", $imap_result);
$results['SMTP'] = $smtp_result ? __('SMTP connection successful.', 'rl-mailwarmer') : __('SMTP connection failed.', 'rl-mailwarmer');
}
log_to_file("check_mail_login - Full Results for " . $post->post_title . ": ", $results);
return $results;
}
/**
* Fetch default settings for an email provider.
*
* @param int $email_provider_id The post ID of the email provider.
* @return array The default server settings.
*/
private static function get_provider_defaults($email_provider_id)
{
return [
'imap_server' => get_post_meta($email_provider_id, 'default_imap_server', true),
'imap_port' => get_post_meta($email_provider_id, 'default_imap_port', true),
'smtp_server' => get_post_meta($email_provider_id, 'default_smtp_server', true),
'smtp_port' => get_post_meta($email_provider_id, 'default_smtp_port', true),
];
}
/**
* Validate an IMAP connection for an email account.
*
* @param string $email The email address.
* @param array $settings The server settings (imap_server, imap_port, imap_password).
* @return bool True if the connection is successful, false otherwise.
*/
private static function validate_imap_connection($email, $settings)
{
if ( empty($settings['imap_server']) || empty($settings['imap_port']) ) {
return false; // Missing required settings
}
if (!empty($settings['imap_password'])) {
$password = $settings['imap_password'];
} else {
$password = $settings['mail_password'];
}
// Try connecting to the IMAP server
$imap_stream = @imap_open(
'{' . $settings['imap_server'] . ':' . $settings['imap_port'] . '/imap/ssl}',
$email,
$password
);
if ($imap_stream) {
imap_close($imap_stream); // Close connection if successful
return true;
}
return false; // Connection failed
}
/**
* Validate an SMTP connection for an email account using Symfony Mailer.
*
* @param string $email The email address.
* @param array $settings The server settings (smtp_server, smtp_port, smtp_password).
* @return bool True if the connection is successful, false otherwise.
*/
private static function validate_smtp_connection($email, $settings)
{
if (empty($settings['smtp_server']) || empty($settings['smtp_port']) ) {
return false; // Missing required settings
}
if (!empty($settings['smtp_password'])) {
$password = $settings['smtp_password'];
} else {
$password = $settings['mail_password'];
}
$test_to_email = "ruben@redlotusaustin.com";
try {
// Create the SMTP transport
$transport = new Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport(
$settings['smtp_server'],
$settings['smtp_port']
);
// Set authentication details
$transport->setUsername($email);
$transport->setPassword($password);
// Create the mailer
$mailer = new Symfony\Component\Mailer\Mailer($transport);
// Send a test email
$test_email = (new Symfony\Component\Mime\Email())
->from($email)
->to($test_to_email)
->subject('SMTP Connection for ' . $email)
->text('This is a test email to verify SMTP connection for ' . $email);
$mailer->send($test_email);
return true;
} catch (Exception $e) {
error_log('SMTP validation failed: ' . $e->getMessage());
return false;
}
}
/**
* Generate random email accounts for the specified domain.
*
* @param string $domain The domain name to use for the email accounts.
* @param int $qty The number of email accounts to generate. Defaults to 1.
* @return array List of generated names and email addresses.
* @throws Exception If name pools are empty or post creation fails.
*/
public static function generate_random_accounts($domain, $qty = 1)
{
// Fetch name pools from ACF options
$first_name_pool = get_field('valid_first_name_pool', 'option');
$last_name_pool = get_field('valid_last_name_pool', 'option');
if (empty($first_name_pool) || empty($last_name_pool)) {
throw new Exception(__('Name pools are empty. Please configure them in the ACF options.', 'rl-mailwarmer'));
}
$first_names = explode(',', $first_name_pool); // Assume comma-separated list
$last_names = explode(',', $last_name_pool);
$generated_accounts = [];
for ($i = 0; $i < $qty; $i++) {
// Generate a random name
$first_name = trim($first_names[array_rand($first_names)]);
$last_name = trim($last_names[array_rand($last_names)]);
$full_name = "{$first_name} {$last_name}";
// Generate a semi-random email address
$email_formats = [
"{$first_name}{$last_name}",
"{$first_name}.{$last_name}",
substr($first_name, 0, 1) . ".{$last_name}",
"{$first_name}.l",
substr($first_name, 0, 1) . $last_name,
];
$email_local_part = strtolower($email_formats[array_rand($email_formats)]);
$email_address = "{$email_local_part}@{$domain}";
// Create the email-account post
// $post_id = RL_MailWarmer_Email_Helper::modify_email_account([
// 'action' => 'create',
// 'email' => $email_address,
// 'metadata' => [
// 'full_name' => $full_name,
// 'mail_password' => bin2hex(random_bytes(8)), // Generate a secure random password
// ],
// ]);
// if (!$post_id) {
// throw new Exception(__('Failed to create email account post.', 'rl-mailwarmer'));
// }
// Add to results
$generated_accounts[] = [
'full_name' => $full_name,
'email_address' => $email_address,
];
}
return $generated_accounts;
}
/**
* Modify an email account on a VirtualMin server.
*
* @param int $account_id The email-account post ID.
* @param string $action The action to perform: 'create', 'update', or 'delete'.
* @return bool|WP_Error True on success, WP_Error on failure.
*/
public static function modify_email_account_on_server($account_id, $action)
{
// Validate email-account post
$email_account = get_post($account_id);
if (!$email_account || $email_account->post_type !== 'email-account') {
return new WP_Error('invalid_account', __('Invalid email account.', 'rl-mailwarmer'));
}
// Fetch associated server posts
$domain_id = get_post_meta($account_id, 'domain_id', true);
if (!$domain_id) {
return new WP_Error('missing_domain', __('No associated domain found.', 'rl-mailwarmer'));
}
$server_ids = get_post_meta($domain_id, 'associated_servers', true); // Assuming this field holds server post IDs
if (empty($server_ids) || !is_array($server_ids)) {
return new WP_Error('missing_servers', __('No associated servers found.', 'rl-mailwarmer'));
}
// Fetch email account details
$email_address = $email_account->post_title;
$password = get_post_meta($account_id, 'mail_password', true);
[$username, $domain] = explode('@', $email_address);
// Iterate over servers and perform the action
foreach ($server_ids as $server_id) {
$server = get_post($server_id);
if (!$server || $server->post_type !== 'server') {
continue; // Skip invalid server posts
}
$server_ip = get_post_meta($server_id, 'ip_address', true);
$server_port = get_post_meta($server_id, 'ssh_port', true);
$server_user = get_post_meta($server_id, 'username', true);
$server_password = get_post_meta($server_id, 'ssh_private_key', true);
// $server_password = get_post_meta($server_id, 'password', true);
if (!$server_ip || !$server_user || !$server_password) {
return new WP_Error('missing_server_details', __('Missing server credentials.', 'rl-mailwarmer'));
}
// Build VirtualMin command
$command = "virtualmin";
if ($action === 'create') {
$command .= " create-user --domain $domain --user $username --pass $password";
} elseif ($action === 'update') {
$command .= " modify-user --domain $domain --user $username --pass $password";
} elseif ($action === 'delete') {
$command .= " delete-user --domain $domain --user $username";
} else {
return new WP_Error('invalid_action', __('Invalid action specified.', 'rl-mailwarmer'));
}
// Execute the command via SSH
// $ssh = new phpseclib\Net\SSH2($server_ip);
// $key = new phpseclib\Crypt\PublicKeyLoader::loadPrivateKey($server_password); // Adjust for SSH key or plain password
$ssh = new SSH2($server_ip, $server_port);
if (!empty($server_password)) {
// Load the private key from the postmeta field
$key = PublicKeyLoader::loadPrivateKey($server_password);
} else {
// Fallback to password-based authentication
// $key = $server_password;
log_to_file("modify_email_account_on_server - Server $$server_id ssh_private_key empty");
return new WP_Error('ssh_login_failed', __('No private key found!', 'rl-mailwarmer'));
}
if (!$ssh->login($server_user, $key)) {
return new WP_Error('ssh_login_failed', __('Failed to log into the server.', 'rl-mailwarmer'));
}
$output = $ssh->exec($command);
if (strpos($output, 'failed') !== false) {
return new WP_Error('command_failed', __('Failed to execute VirtualMin command.', 'rl-mailwarmer'));
}
}
return true; // Success
}
/**
* Send or reply to a conversation email.
*
* @param int $conversation_id The conversation post ID.
* @param int $account_id The email account post ID.
* @return bool True on success, false on failure.
*/
public static function send_conversation_mail(int $conversation_id, int $account_id)
{
// Implementation goes here
}
}

View file

@ -1,89 +1,94 @@
<?php <?php
/** /**
* Handles WP-Cron scheduling for RL MailWarmer. * Scheduler class for the RL MailWarmer plugin.
* Handles scheduling and execution of tasks, including fetching AI-generated content for conversations and sending pending messages
*/ */
class RL_MailWarmer_Scheduler {
if (!defined('ABSPATH')) {
exit;
}
class RL_MailWarmer_Scheduler
{
/** /**
* Initialize the scheduler. * Initialize the scheduler by setting up hooks.
*/ */
public static function init() public static function init() {
{ add_filter('cron_schedules', [__CLASS__, 'add_cron_timings']);
// Hook into WP-Cron for sending emails
add_action('rl_mailwarmer_send_emails', [__CLASS__, 'send_scheduled_emails']); // Call local functions to call the remote classes, so we can debug cron jobs
add_action('rl_mailwarmer_process_messages', [__CLASS__, 'process_pending_messages']);
add_action('rl_mailwarmer_process_upcoming_conversations', [__CLASS__, 'process_upcoming_conversations']);
// add_action('rl_mailwarmer_process_messages', [RL_MailWarmer_Message_Handler::class, 'process_pending_messages']);
// add_action('rl_mailwarmer_process_upcoming_conversations', [RL_MailWarmer_Conversation_Handler::class, 'process_upcoming_conversations']);
self::schedule_cron_jobs();
} }
/** /**
* Schedule WP-Cron jobs. * Add a custom schedule for every minute & every 5 minutes.
*
* @param array $schedules Existing cron schedules.
* @return array Modified cron schedules.
*/ */
public static function schedule_cron_jobs() public static function add_cron_timings($schedules) {
{ if (!isset($schedules['every_minute'])) {
if (!wp_next_scheduled('rl_mailwarmer_send_emails')) { $schedules['every_minute'] = [
wp_schedule_event(time(), 'hourly', 'rl_mailwarmer_send_emails'); 'interval' => 60, // 60 seconds = 1 minute
'display' => __('Every Minute', 'rl-mailwarmer'),
];
$schedules['every_five_minutes'] = [
'interval' => 300,
'display' => __('Every 5 Minutes', 'rl-mailwarmer'),
];
}
return $schedules;
}
/**
* Schedule the cron task if not already scheduled.
*/
public static function schedule_cron_jobs() {
// Message handler
if (!wp_next_scheduled('rl_mailwarmer_process_messages')) {
wp_schedule_event(time(), 'every_minute', 'rl_mailwarmer_process_messages');
}
// Conversation handler
if (!wp_next_scheduled('rl_mailwarmer_process_upcoming_conversations')) {
wp_schedule_event(time(), 'every_minute', 'rl_mailwarmer_process_upcoming_conversations');
} }
} }
/** /**
* Clear WP-Cron jobs on deactivation. * Clear the scheduled task.
*/ */
public static function clear_cron_jobs() public static function clear_cron_jobs() {
{
$timestamp = wp_next_scheduled('rl_mailwarmer_send_emails'); // Message handler
$timestamp = wp_next_scheduled('rl_mailwarmer_process_messages');
if ($timestamp) { if ($timestamp) {
wp_unschedule_event($timestamp, 'rl_mailwarmer_send_emails'); wp_unschedule_event($timestamp, 'rl_mailwarmer_process_messages');
}
// Conversation handler
$timestamp = wp_next_scheduled('rl_mailwarmer_process_upcoming_conversations');
if ($timestamp) {
wp_unschedule_event($timestamp, 'rl_mailwarmer_process_upcoming_conversations');
} }
} }
/** /**
* Send scheduled emails for campaigns. * Process pending messages by delegating to the Message Handler.
*/ */
public static function send_scheduled_emails() public static function process_pending_messages() {
{ // log_to_file("schedule_cron_jobs ====================== Running Cron to process messages ========================");
// Fetch campaigns with active schedules // RL_MailWarmer_Message_Handler::process_pending_messages();
$campaigns = get_posts([ }
'post_type' => 'campaign',
'post_status' => 'publish',
'meta_query' => [
[
'key' => 'email_schedule',
'compare' => 'EXISTS',
],
],
]);
if (!$campaigns) { /**
return; * Process pending conversations by delegating to the Message Handler.
} */
public static function process_upcoming_conversations() {
foreach ($campaigns as $campaign) { // log_to_file("schedule_cron_jobs ====================== Running Cron to process conversations ========================");
// Get scheduled emails // RL_MailWarmer_Message_Handler::process_upcoming_conversations();
$schedule = get_post_meta($campaign->ID, 'email_schedule', true);
if (!is_array($schedule)) {
continue;
}
foreach ($schedule as $email) {
// Check if the email is ready to be sent
$send_time = strtotime($email['send_time']);
if ($send_time > time()) {
continue;
}
// Send the email
RL_MailWarmer_Email_Handler::send_email($email);
// Mark as sent
$email['sent'] = true;
}
// Update the schedule
update_post_meta($campaign->ID, 'email_schedule', $schedule);
}
} }
} }

View file

@ -1,8 +0,0 @@
{
"require": {
"guzzlehttp/guzzle": "^7.9",
"symfony/mailer": "^7.2",
"symfony/http-client": "^7.2",
"phpseclib/phpseclib": "^3.0"
}
}

2007
includes/composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -32,12 +32,52 @@ add_action('wp_ajax_rl_mailwarmer_check_domain_health', function () {
} }
}); });
add_action('wp_ajax_rl_mailwarmer_update_mx_record', function () {
// Verify nonce
if (!isset($_POST['security']) || !wp_verify_nonce($_POST['security'], 'update_mx_record_nonce')) {
wp_send_json_error(__('Invalid nonce', 'rl-mailwarmer'));
}
// log_to_file("wp_ajax_rl_mailwarmer_update_mx_record - Running");
// Get input values
$post_id = intval($_POST['post_id']);
$action = sanitize_text_field($_POST['action_type']);
$content = sanitize_text_field($_POST['content']);
$priority = intval(sanitize_text_field($_POST['priority']));
$ttl = intval($_POST['ttl']);
if (!$post_id || !$content || !$action) {
wp_send_json_error(__('Missing required fields', 'rl-mailwarmer'));
}
$domain = RL_MailWarmer_Domain_Helper::get_domain_post($post_id);
// log_to_file("wp_ajax_rl_mailwarmer_update_mx_record - Post ID: $post_id $content $action $priority $ttl");
// Call the update_mx_record function
try {
log_to_file("wp_ajax_rl_mailwarmer_update_mx_record - Before");
$result = RL_MailWarmer_Domain_Helper::update_mx_record($domain, $content, $priority, $ttl, $action);
log_to_file("wp_ajax_rl_mailwarmer_update_mx_record - After");
if ($result) {
wp_send_json_success(__('MX record updated successfully.', 'rl-mailwarmer'));
} else {
wp_send_json_error(__('Failed to update MX record.', 'rl-mailwarmer'));
}
} catch (Exception $e) {
wp_send_json_error($e->getMessage());
}
});
add_action('wp_ajax_rl_mailwarmer_update_spf_record', function () { add_action('wp_ajax_rl_mailwarmer_update_spf_record', function () {
// Verify nonce // Verify nonce
if (!isset($_POST['security']) || !wp_verify_nonce($_POST['security'], 'update_spf_record_nonce')) { if (!isset($_POST['security']) || !wp_verify_nonce($_POST['security'], 'update_spf_record_nonce')) {
wp_send_json_error(__('Invalid nonce', 'rl-mailwarmer')); wp_send_json_error(__('Invalid nonce', 'rl-mailwarmer'));
} }
// log_to_file("wp_ajax_rl_mailwarmer_update_spf_record - Running");
// Get input values // Get input values
$post_id = intval($_POST['post_id']); $post_id = intval($_POST['post_id']);
$host = sanitize_text_field($_POST['host']); $host = sanitize_text_field($_POST['host']);
@ -48,10 +88,15 @@ add_action('wp_ajax_rl_mailwarmer_update_spf_record', function () {
if (!$post_id || !$host || !$action) { if (!$post_id || !$host || !$action) {
wp_send_json_error(__('Missing required fields', 'rl-mailwarmer')); wp_send_json_error(__('Missing required fields', 'rl-mailwarmer'));
} }
$domain = RL_MailWarmer_Domain_Helper::get_domain_post($post_id);
// log_to_file("wp_ajax_rl_mailwarmer_update_spf_record - Post ID: $post_id $host $action $all_policy $ttl");
// Call the update_spf_record function // Call the update_spf_record function
try { try {
$result = RL_MailWarmer_Domain_Helper::update_spf_record($post_id, $host, $action, $all_policy, $ttl); // log_to_file("wp_ajax_rl_mailwarmer_update_spf_record - Before");
$result = RL_MailWarmer_Domain_Helper::update_spf_record($domain, $host, $action, $all_policy, $ttl);
// log_to_file("wp_ajax_rl_mailwarmer_update_spf_record - After");
if ($result) { if ($result) {
wp_send_json_success(__('SPF record updated successfully.', 'rl-mailwarmer')); wp_send_json_success(__('SPF record updated successfully.', 'rl-mailwarmer'));
@ -164,10 +209,10 @@ add_action('wp_ajax_rl_mailwarmer_create_dns_backup', function () {
if (!$post_id) { if (!$post_id) {
wp_send_json_error(__('Invalid post ID', 'rl-mailwarmer')); wp_send_json_error(__('Invalid post ID', 'rl-mailwarmer'));
} }
$domain = get_post($post_id);
// Call the create_dns_backup function // Call the create_dns_backup function
try { try {
$backup_id = RL_MailWarmer_Domain_Helper::create_dns_backup($post_id); $backup_id = RL_MailWarmer_Domain_Helper::export_dns_zone($domain);
if (is_wp_error($backup_id)) { if (is_wp_error($backup_id)) {
wp_send_json_error($backup_id->get_error_message()); wp_send_json_error($backup_id->get_error_message());
} }

View file

@ -4,13 +4,14 @@ add_action('admin_enqueue_scripts', function ($hook) {
if ($hook === 'post.php' || $hook === 'post-new.php') { if ($hook === 'post.php' || $hook === 'post-new.php') {
global $post; global $post;
wp_enqueue_style(
'rl-mailwarmer-admin-css',
RL_MAILWARMER_URL . '/css/admin-style.css', // Path to your CSS file
[],
'1.0.3' // Version number
);
if ($post->post_type === 'domain') { if ($post->post_type === 'domain') {
wp_enqueue_style(
'rl-mailwarmer-admin-css',
RL_MAILWARMER_URL . '/css/admin-style.css', // Path to your CSS file
[],
'1.0.0' // Version number
);
wp_enqueue_script('rl-mailwarmer-admin-script', RL_MAILWARMER_URL . '/js/admin-check-domain-health.js', ['jquery'], null, true); wp_enqueue_script('rl-mailwarmer-admin-script', RL_MAILWARMER_URL . '/js/admin-check-domain-health.js', ['jquery'], null, true);
wp_localize_script('rl-mailwarmer-admin-script', 'rlMailWarmer', [ wp_localize_script('rl-mailwarmer-admin-script', 'rlMailWarmer', [
'ajax_url' => admin_url('admin-ajax.php'), 'ajax_url' => admin_url('admin-ajax.php'),
@ -23,6 +24,12 @@ add_action('admin_enqueue_scripts', function ($hook) {
'nonce' => wp_create_nonce('update_spf_record_nonce'), 'nonce' => wp_create_nonce('update_spf_record_nonce'),
'post_id' => $post->ID 'post_id' => $post->ID
]); ]);
wp_enqueue_script('rl-mailwarmer-mx-script', RL_MAILWARMER_URL . '/js/admin-update-mx.js', ['jquery'], null, true);
wp_localize_script('rl-mailwarmer-mx-script', 'rlMailWarmerMx', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('update_mx_record_nonce'),
'post_id' => $post->ID
]);
wp_enqueue_script('rl-mailwarmer-dmarc-script', RL_MAILWARMER_URL . '/js/admin-update-dmarc.js', ['jquery'], null, true); wp_enqueue_script('rl-mailwarmer-dmarc-script', RL_MAILWARMER_URL . '/js/admin-update-dmarc.js', ['jquery'], null, true);
wp_localize_script('rl-mailwarmer-dmarc-script', 'rlMailWarmerDmarc', [ wp_localize_script('rl-mailwarmer-dmarc-script', 'rlMailWarmerDmarc', [
'ajax_url' => admin_url('admin-ajax.php'), 'ajax_url' => admin_url('admin-ajax.php'),
@ -134,6 +141,14 @@ add_action('add_meta_boxes', function () {
'side', // Context 'side', // Context
'default' // Priority 'default' // Priority
); );
add_meta_box(
'update_mx_record_box', // Meta box ID
__('Update MX Record', 'rl-mailwarmer'), // Title
'rl_mailwarmer_render_update_mx_record_box', // Callback function
'domain', // Post type
'side', // Context
'default' // Priority
);
add_meta_box( add_meta_box(
'update_spf_record_box', // Meta box ID 'update_spf_record_box', // Meta box ID
__('Update SPF Record', 'rl-mailwarmer'), // Title __('Update SPF Record', 'rl-mailwarmer'), // Title
@ -223,6 +238,51 @@ function rl_mailwarmer_render_fix_deliverability_dns_issues_box($post)
/**
* Render the fields for the "Update MX Record" meta box.
*
* @param WP_Post $post The current post object.
*/
function rl_mailwarmer_render_update_mx_record_box($post)
{
// Add a nonce field for security
wp_nonce_field('update_mx_record_nonce', 'update_mx_record_nonce_field');
// Render the fields
?>
<p>
<label for="mx_action"><?php esc_html_e('Action', 'rl-mailwarmer'); ?></label><br>
<select id="mx_action" name="mx_action">
<!-- <option value=""><?php esc_html_e('Select', 'rl-mailwarmer'); ?></option> -->
<option value="add"><?php esc_html_e('Add', 'rl-mailwarmer'); ?></option>
<option value="delete"><?php esc_html_e('Delete', 'rl-mailwarmer'); ?></option>
</select>
</p>
<!-- <p>
<label for="mx_host"><?php //esc_html_e('Host', 'rl-mailwarmer'); ?></label><br>
<input type="text" id="mx_host" name="mx_host" class="regular-text">
</p> -->
<p>
<label for="mx_content"><?php esc_html_e('Content', 'rl-mailwarmer'); ?></label><br>
<input type="text" id="mx_content" name="mx_content" class="regular-text" value="onyx.bldsecurity.com">
</p>
<p>
<label for="mx_priority"><?php esc_html_e('Priority', 'rl-mailwarmer'); ?></label><br>
<input type="number" id="mx_priority" name="mx_priority" class="small-text" value="0" min="0">
</p>
<p>
<label for="mx_ttl"><?php esc_html_e('TTL', 'rl-mailwarmer'); ?></label><br>
<input type="number" id="mx_ttl" name="mx_ttl" class="small-text" value="3600" min="1">
</p>
<p>
<button type="button" id="update-mx-record-button" class="button button-primary">
<?php esc_html_e('Update MX Record', 'rl-mailwarmer'); ?>
</button>
</p>
<div id="mx-update-result"></div>
<?php
}
/** /**
* Render the fields for the "Update SPF Record" meta box. * Render the fields for the "Update SPF Record" meta box.
@ -404,26 +464,26 @@ add_filter('manage_domain-health-report_posts_columns', function ($columns) {
'domain_age' => __('Age', 'rl-mailwarmer'), 'domain_age' => __('Age', 'rl-mailwarmer'),
'domain_days_to_expiration' => __('Days to Expiration', 'rl-mailwarmer'), 'domain_days_to_expiration' => __('Days to Expiration', 'rl-mailwarmer'),
'a_record_valid' => __('A Record Valid', 'rl-mailwarmer'), 'a_record_valid' => __('A Record Valid', 'rl-mailwarmer'),
'a_record_resolves' => __('A Record Resolves To', 'rl-mailwarmer'), // 'a_record_resolves' => __('A Record Resolves To', 'rl-mailwarmer'),
'http_status' => __('HTTP Status', 'rl-mailwarmer'), 'http_status' => __('HTTP Status', 'rl-mailwarmer'),
'https_enabled' => __('HTTPS Enabled', 'rl-mailwarmer'), 'https_enabled' => __('HTTPS Enabled', 'rl-mailwarmer'),
'mx_record_valid' => __('MX Valid', 'rl-mailwarmer'), 'mx_record_valid' => __('Valid MX Record', 'rl-mailwarmer'),
'mx_record_ptr_valid' => __('PTR Valid', 'rl-mailwarmer'), // 'mx_record_ptr_valid' => __('PTR Valid', 'rl-mailwarmer'),
'mx_record_ptr_match' => __('PTR Matches', 'rl-mailwarmer'), // 'mx_record_ptr_match' => __('PTR Matches', 'rl-mailwarmer'),
'spf_record_exists' => __('SPF Exists', 'rl-mailwarmer'), // 'spf_record_exists' => __('SPF Exists', 'rl-mailwarmer'),
'spf_record_content' => __('SPF Valid', 'rl-mailwarmer'), 'spf_record_content' => __('SPF Record', 'rl-mailwarmer'),
'spf_record_ttl' => __('SPF TTL', 'rl-mailwarmer'), // 'spf_record_ttl' => __('SPF TTL', 'rl-mailwarmer'),
'spf_record_all_mechanism' => __('SPF All Mechanism', 'rl-mailwarmer'), // 'spf_record_all_mechanism' => __('SPF All Mechanism', 'rl-mailwarmer'),
'dmarc_record_exists' => __('DMARC Exists', 'rl-mailwarmer'), 'dmarc_record_exists' => __('DMARC Exists', 'rl-mailwarmer'),
'dmarc_policy' => __('DMARC Policy', 'rl-mailwarmer'), 'dmarc_policy' => __('DMARC Policy', 'rl-mailwarmer'),
'dmarc_sp_policy' => __('DMARC SP Policy', 'rl-mailwarmer'), // 'dmarc_sp_policy' => __('DMARC SP Policy', 'rl-mailwarmer'),
'dmarc_percentage' => __('DMARC Percentage', 'rl-mailwarmer'), // 'dmarc_percentage' => __('DMARC Percentage', 'rl-mailwarmer'),
'dmarc_aspf' => __('DMARC ASPF', 'rl-mailwarmer'), // 'dmarc_aspf' => __('DMARC ASPF', 'rl-mailwarmer'),
'dmarc_adkim' => __('DMARC ADKIM', 'rl-mailwarmer'), // 'dmarc_adkim' => __('DMARC ADKIM', 'rl-mailwarmer'),
'dmarc_aggregate_rpt' => __('DMARC Aggregate RPT', 'rl-mailwarmer'), // 'dmarc_aggregate_rpt' => __('DMARC Aggregate RPT', 'rl-mailwarmer'),
'dmarc_forensic_rpt' => __('DMARC Forensic RPT', 'rl-mailwarmer'), // 'dmarc_forensic_rpt' => __('DMARC Forensic RPT', 'rl-mailwarmer'),
'dmarc_report_format' => __('DMARC Report Format', 'rl-mailwarmer'), // 'dmarc_report_format' => __('DMARC Report Format', 'rl-mailwarmer'),
'dmarc_report_interval' => __('DMARC Report Interval', 'rl-mailwarmer'), // 'dmarc_report_interval' => __('DMARC Report Interval', 'rl-mailwarmer'),
'dkim_records' => __('DKIM Records', 'rl-mailwarmer'), 'dkim_records' => __('DKIM Records', 'rl-mailwarmer'),
]; ];
@ -555,6 +615,7 @@ add_filter('manage_edit-domain-health-report_sortable_columns', function ($colum
$columns['domain_name'] = 'domain_name'; $columns['domain_name'] = 'domain_name';
$columns['domain_valid'] = 'domain_valid'; $columns['domain_valid'] = 'domain_valid';
$columns['domain_age'] = 'domain_age'; $columns['domain_age'] = 'domain_age';
$columns['mx_record_valid'] = 'mx_record_valid';
// Add more sortable columns as needed // Add more sortable columns as needed
return $columns; return $columns;
}); });
@ -572,30 +633,31 @@ add_filter('manage_domain_posts_columns', function ($columns) {
// Add custom columns // Add custom columns
$custom_columns = [ $custom_columns = [
// 'domain_name' => __('Domain Name', 'rl-mailwarmer'),
'domain_valid' => __('Valid', 'rl-mailwarmer'), 'domain_valid' => __('Valid', 'rl-mailwarmer'),
'domain_age' => __('Age', 'rl-mailwarmer'), 'domain_age' => __('Age', 'rl-mailwarmer'),
'domain_days_to_expiration' => __('Days to Expiration', 'rl-mailwarmer'), 'domain_days_to_expiration' => __('Days to Expiration', 'rl-mailwarmer'),
'a_record_valid' => __('A Record Valid', 'rl-mailwarmer'), 'a_record_valid' => __('A Record Valid', 'rl-mailwarmer'),
'a_record_resolves' => __('A Record Resolves To', 'rl-mailwarmer'), // 'a_record_resolves' => __('A Record Resolves To', 'rl-mailwarmer'),
'http_status' => __('HTTP Status', 'rl-mailwarmer'), 'http_status' => __('HTTP Status', 'rl-mailwarmer'),
'https_enabled' => __('HTTPS Enabled', 'rl-mailwarmer'), 'https_enabled' => __('HTTPS Enabled', 'rl-mailwarmer'),
'mx_record_valid' => __('MX Valid', 'rl-mailwarmer'), 'mx_record' => __('MX Record', 'rl-mailwarmer'),
'mx_record_ptr_valid' => __('PTR Valid', 'rl-mailwarmer'), // 'mx_record_ptr_valid' => __('PTR Valid', 'rl-mailwarmer'),
'mx_record_ptr_match' => __('PTR Matches', 'rl-mailwarmer'), // 'mx_record_ptr_match' => __('PTR Matches', 'rl-mailwarmer'),
'spf_record_exists' => __('SPF Exists', 'rl-mailwarmer'), // 'spf_record_exists' => __('SPF Exists', 'rl-mailwarmer'),
'spf_record_is_valid' => __('SPF Valid', 'rl-mailwarmer'), 'spf_record_content' => __('SPF Record', 'rl-mailwarmer'),
'spf_record_ttl' => __('SPF TTL', 'rl-mailwarmer'), // 'spf_record_ttl' => __('SPF TTL', 'rl-mailwarmer'),
'spf_record_all_mechanism' => __('SPF All Mechanism', 'rl-mailwarmer'), // 'spf_record_all_mechanism' => __('SPF All Mechanism', 'rl-mailwarmer'),
'dmarc_record_exists' => __('DMARC Exists', 'rl-mailwarmer'), 'dmarc_record_exists' => __('DMARC Exists', 'rl-mailwarmer'),
'dmarc_policy' => __('DMARC Policy', 'rl-mailwarmer'), 'dmarc_policy' => __('DMARC Policy', 'rl-mailwarmer'),
'dmarc_sp_policy' => __('DMARC SP Policy', 'rl-mailwarmer'), // 'dmarc_sp_policy' => __('DMARC SP Policy', 'rl-mailwarmer'),
'dmarc_percentage' => __('DMARC Percentage', 'rl-mailwarmer'), // 'dmarc_percentage' => __('DMARC Percentage', 'rl-mailwarmer'),
'dmarc_aspf' => __('DMARC ASPF', 'rl-mailwarmer'), // 'dmarc_aspf' => __('DMARC ASPF', 'rl-mailwarmer'),
'dmarc_adkim' => __('DMARC ADKIM', 'rl-mailwarmer'), // 'dmarc_adkim' => __('DMARC ADKIM', 'rl-mailwarmer'),
'dmarc_aggregate_rpt' => __('DMARC Aggregate RPT', 'rl-mailwarmer'), // 'dmarc_aggregate_rpt' => __('DMARC Aggregate RPT', 'rl-mailwarmer'),
'dmarc_forensic_rpt' => __('DMARC Forensic RPT', 'rl-mailwarmer'), // 'dmarc_forensic_rpt' => __('DMARC Forensic RPT', 'rl-mailwarmer'),
'dmarc_report_format' => __('DMARC Report Format', 'rl-mailwarmer'), // 'dmarc_report_format' => __('DMARC Report Format', 'rl-mailwarmer'),
'dmarc_report_interval' => __('DMARC Report Interval', 'rl-mailwarmer'), // 'dmarc_report_interval' => __('DMARC Report Interval', 'rl-mailwarmer'),
'dkim_records' => __('DKIM Records', 'rl-mailwarmer'), 'dkim_records' => __('DKIM Records', 'rl-mailwarmer'),
]; ];
@ -610,108 +672,151 @@ add_filter('manage_domain_posts_columns', function ($columns) {
*/ */
add_action('manage_domain_posts_custom_column', function ($column, $post_id) { add_action('manage_domain_posts_custom_column', function ($column, $post_id) {
$meta = get_post_meta($post_id); $meta = get_post_meta($post_id);
$json_report = $meta['domain_health_report'][0];
// Decode the JSON into an associative array
$report = json_decode($json_report, true);
// var_dump($report);
// // Check for JSON decoding errors
// if (json_last_error() !== JSON_ERROR_NONE) {
// log_to_file("rl_mailwarmer_render_domain_metadata_table - JSON decode error for post {$post->ID}: " . json_last_error_msg());
// // return null;
// }
// log_to_file("manage_domain_posts_custom_column - Report array: ", $report["domain_health"]);
// Assign metadata to the array using $post_meta
$metadata = [
'domain_valid' => $report["domain_health"]['registration_valid'] ?? '',
'domain_age' => $report["domain_health"]['domain_age'] ?? '',
'domain_days_to_expiration' => $report["domain_health"]['days_to_expiration'] ?? '',
'a_record_ip' => $report["a_record"]['ip'] ?? '',
'http_status' => $report["a_record"]['http_status'] ?? '',
'https_enabled' => $report["a_record"]['https_enabled'] ?? '',
'mx_record_host' => $report["mx_record"]['host'] ?? '',
'mx_record_ptr_valid' => $report["mx_record"]['ptr_valid'] ?? '',
'mx_record_ptr_match' => $report["mx_record"]['ptr_matches'] ?? '',
'spf_record' => $report["spf_record"]['content'] ?? '',
'spf_record_ttl' => $report["spf_record"]['ttl'] ?? '',
'spf_record_all_mechanism' => $report["spf_record"]['all_mechanism'] ?? '',
'dmarc_record_exists' => $report["dmarc_record"]['exists'] ?? '',
'dmarc_record_content' => $report["dmarc_record"]['content'] ?? '',
'dmarc_record_ttl' => $report["dmarc_record"]['ttl'] ?? '',
'dmarc_policy' => $report["dmarc_record"]['policy'] ?? '',
'dmarc_sp_policy' => $report["dmarc_record"]['sp_policy'] ?? '',
'dmarc_percentage' => $report["dmarc_record"]['percentage'] ?? '',
'dmarc_aspf' => $report["dmarc_record"]['aspf'] ?? '',
'dmarc_adkim' => $report["dmarc_record"]['adkim'] ?? '',
'dmarc_aggregate_rpt' => $report["dmarc_record"]['aggregate_rpt'] ?? '',
'dmarc_forensic_rpt' => $report["dmarc_record"]['forensic_rpt'] ?? '',
'dmarc_report_format' => $report["dmarc_record"]['report_format'] ?? '',
'dmarc_report_interval' => $report["dmarc_record"]['report_interval'] ?? '',
'dkim_records' => $report['dkim_records'] ?? '',
];
// log_to_file("manage_domain_posts_custom_column - Health report: ", $domain_report);
switch ($column) { switch ($column) {
case 'domain_valid': case 'domain_valid':
echo !empty($meta['domain_valid'][0]) ? __('Yes', 'rl-mailwarmer') : __('No', 'rl-mailwarmer'); echo !empty($report["domain_health"]['registration_valid']) ? __('Yes', 'rl-mailwarmer') : __('No', 'rl-mailwarmer');
break; break;
case 'domain_age': case 'domain_age':
echo esc_html($meta['domain_age'][0] ?? ''); echo !empty($report["domain_health"]['domain_age']) ? $report["domain_health"]['domain_age'] : __('0', 'rl-mailwarmer');
break; break;
case 'domain_days_to_expiration': case 'mx_record':
echo esc_html($meta['domain_days_to_expiration'][0] ?? ''); echo !empty($report["mx_record"]['host']) ? $report["mx_record"]['host'] : 'Unset';
break; break;
case 'a_record_valid': // case 'domain_days_to_expiration':
echo !empty($meta['a_record_valid'][0]) ? __('Yes', 'rl-mailwarmer') : __('No', 'rl-mailwarmer'); // echo esc_html($meta['domain_days_to_expiration'][0] ?? '');
break; // break;
case 'a_record_resolves': // case 'a_record_valid':
echo esc_html($meta['a_record_resolves'][0] ?? ''); // echo !empty($meta['a_record_valid'][0]) ? __('Yes', 'rl-mailwarmer') : __('No', 'rl-mailwarmer');
break; // break;
case 'http_status': // case 'a_record_resolves':
echo esc_html($meta['http_status'][0] ?? ''); // echo esc_html($meta['a_record_resolves'][0] ?? '');
break; // break;
case 'https_enabled': // case 'http_status':
echo !empty($meta['https_enabled'][0]) ? __('Yes', 'rl-mailwarmer') : __('No', 'rl-mailwarmer'); // echo esc_html($meta['http_status'][0] ?? '');
break; // break;
case 'mx_record_valid': // case 'https_enabled':
echo !empty($meta['mx_record_valid'][0]) ? __('Yes', 'rl-mailwarmer') : __('No', 'rl-mailwarmer'); // echo !empty($meta['https_enabled'][0]) ? __('Yes', 'rl-mailwarmer') : __('No', 'rl-mailwarmer');
break; // break;
case 'mx_record_ptr_valid': // case 'mx_record_ptr_valid':
echo !empty($meta['mx_record_ptr_valid'][0]) ? __('Yes', 'rl-mailwarmer') : __('No', 'rl-mailwarmer'); // echo !empty($meta['mx_record_ptr_valid'][0]) ? __('Yes', 'rl-mailwarmer') : __('No', 'rl-mailwarmer');
break; // break;
case 'mx_record_ptr_match': // case 'mx_record_ptr_match':
echo !empty($meta['mx_record_ptr_match'][0]) ? __('Yes', 'rl-mailwarmer') : __('No', 'rl-mailwarmer'); // echo !empty($meta['mx_record_ptr_match'][0]) ? __('Yes', 'rl-mailwarmer') : __('No', 'rl-mailwarmer');
break; // break;
case 'spf_record_exists': // case 'spf_record_exists':
echo !empty($meta['spf_record_exists'][0]) ? __('Yes', 'rl-mailwarmer') : __('No', 'rl-mailwarmer'); // echo !empty($meta['spf_record_exists'][0]) ? __('Yes', 'rl-mailwarmer') : __('No', 'rl-mailwarmer');
break; // break;
case 'spf_record_is_valid': // case 'spf_record_is_valid':
echo !empty($meta['spf_record_is_valid'][0]) ? __('Yes', 'rl-mailwarmer') : __('No', 'rl-mailwarmer'); // echo !empty($meta['spf_record_is_valid'][0]) ? __('Yes', 'rl-mailwarmer') : __('No', 'rl-mailwarmer');
break; // break;
case 'spf_record_ttl': // case 'spf_record_ttl':
echo esc_html($meta['spf_record_ttl'][0] ?? ''); // echo esc_html($meta['spf_record_ttl'][0] ?? '');
break; // break;
case 'spf_record_all_mechanism': // case 'spf_record_all_mechanism':
echo esc_html($meta['spf_record_all_mechanism'][0] ?? ''); // echo esc_html($meta['spf_record_all_mechanism'][0] ?? '');
break; // break;
case 'dmarc_record_exists': // case 'dmarc_record_exists':
echo !empty($meta['dmarc_record_exists'][0]) ? __('Yes', 'rl-mailwarmer') : __('No', 'rl-mailwarmer'); // echo !empty($meta['dmarc_record_exists'][0]) ? __('Yes', 'rl-mailwarmer') : __('No', 'rl-mailwarmer');
break; // break;
case 'dmarc_policy': // case 'dmarc_policy':
echo esc_html($meta['dmarc_policy'][0] ?? ''); // echo esc_html($meta['dmarc_policy'][0] ?? '');
break; // break;
case 'dmarc_sp_policy': // case 'dmarc_sp_policy':
echo esc_html($meta['dmarc_sp_policy'][0] ?? ''); // echo esc_html($meta['dmarc_sp_policy'][0] ?? '');
break; // break;
case 'dmarc_percentage': // case 'dmarc_percentage':
echo esc_html($meta['dmarc_percentage'][0] ?? ''); // echo esc_html($meta['dmarc_percentage'][0] ?? '');
break; // break;
case 'dmarc_aspf': // case 'dmarc_aspf':
echo esc_html($meta['dmarc_aspf'][0] ?? ''); // echo esc_html($meta['dmarc_aspf'][0] ?? '');
break; // break;
case 'dmarc_adkim': // case 'dmarc_adkim':
echo esc_html($meta['dmarc_adkim'][0] ?? ''); // echo esc_html($meta['dmarc_adkim'][0] ?? '');
break; // break;
case 'dmarc_aggregate_rpt': // case 'dmarc_aggregate_rpt':
echo esc_html($meta['dmarc_aggregate_rpt'][0] ?? ''); // echo esc_html($meta['dmarc_aggregate_rpt'][0] ?? '');
break; // break;
case 'dmarc_forensic_rpt': // case 'dmarc_forensic_rpt':
echo esc_html($meta['dmarc_forensic_rpt'][0] ?? ''); // echo esc_html($meta['dmarc_forensic_rpt'][0] ?? '');
break; // break;
case 'dmarc_report_format': // case 'dmarc_report_format':
echo esc_html($meta['dmarc_report_format'][0] ?? ''); // echo esc_html($meta['dmarc_report_format'][0] ?? '');
break; // break;
case 'dmarc_report_interval': // case 'dmarc_report_interval':
echo esc_html($meta['dmarc_report_interval'][0] ?? ''); // echo esc_html($meta['dmarc_report_interval'][0] ?? '');
break; // break;
case 'dkim_records': // case 'dkim_records':
echo esc_html($meta['dkim_records'][0] ?? ''); // echo esc_html($meta['dkim_records'][0] ?? '');
break; // break;
default: default:
echo ''; echo '';
@ -723,6 +828,7 @@ add_filter('manage_edit-domain_sortable_columns', function ($columns) {
// $columns['domain_name'] = 'domain_name'; // $columns['domain_name'] = 'domain_name';
$columns['domain_valid'] = 'domain_valid'; $columns['domain_valid'] = 'domain_valid';
$columns['domain_age'] = 'domain_age'; $columns['domain_age'] = 'domain_age';
$columns['mx_record'] = 'mx_record';
// Add more sortable columns as needed // Add more sortable columns as needed
return $columns; return $columns;
}); });
@ -748,35 +854,52 @@ add_action('add_meta_boxes', function () {
*/ */
function rl_mailwarmer_render_domain_metadata_table($post) function rl_mailwarmer_render_domain_metadata_table($post)
{ {
// Fetch all metadata for the current post
$post_meta = get_post_meta($post->ID); // Fetch the domain health report from post meta
$json_report = get_post_meta($post->ID, 'domain_health_report', true);
// Check if the meta field exists and is not empty
if (empty($json_report)) {
return null; // or throw an exception, depending on your error handling preference
}
// Decode the JSON into an associative array
$report = json_decode($json_report, true);
// Check for JSON decoding errors
if (json_last_error() !== JSON_ERROR_NONE) {
log_to_file("rl_mailwarmer_render_domain_metadata_table - JSON decode error for post {$post->ID}: " . json_last_error_msg());
// return null;
}
// log_to_file("rl_mailwarmer_render_domain_metadata_table - Report array: ", $report);
// Assign metadata to the array using $post_meta // Assign metadata to the array using $post_meta
$metadata = [ $metadata = [
'domain_valid' => $post_meta['domain_valid'][0] ?? '', 'domain_valid' => $report["domain_health"]['registration_valid'] ?? '',
'domain_age' => $post_meta['domain_age'][0] ?? '', 'domain_age' => $report["domain_health"]['domain_age'] ?? '',
'domain_days_to_expiration' => $post_meta['domain_days_to_expiration'][0] ?? '', 'domain_days_to_expiration' => $report["domain_health"]['days_to_expiration'] ?? '',
'a_record_resolves' => $post_meta['a_record_resolves'][0] ?? '', 'a_record_ip' => $report["a_record"]['ip'] ?? '',
'http_status' => $post_meta['http_status'][0] ?? '', 'http_status' => $report["a_record"]['http_status'] ?? '',
'https_enabled' => $post_meta['https_enabled'][0] ?? '', 'https_enabled' => $report["a_record"]['https_enabled'] ?? '',
'mx_record_valid' => $post_meta['mx_record_valid'][0] ?? '', 'mx_record_host' => $report["mx_record"]['host'] ?? '',
'mx_record_ptr_valid' => $post_meta['mx_record_ptr_valid'][0] ?? '', 'mx_record_ptr_valid' => $report["mx_record"]['ptr_valid'] ?? '',
'mx_record_ptr_match' => $post_meta['mx_record_ptr_match'][0] ?? '', 'mx_record_ptr_match' => $report["mx_record"]['ptr_matches'] ?? '',
'spf_record_exists' => $post_meta['spf_record_exists'][0] ?? '', 'spf_record' => $report["spf_record"]['content'] ?? '',
'spf_record_is_valid' => $post_meta['spf_record_is_valid'][0] ?? '', 'spf_record_ttl' => $report["spf_record"]['ttl'] ?? '',
'spf_record_ttl' => $post_meta['spf_record_ttl'][0] ?? '', 'spf_record_all_mechanism' => $report["spf_record"]['all_mechanism'] ?? '',
'spf_record_all_mechanism' => $post_meta['spf_record_all_mechanism'][0] ?? '', 'dmarc_record_exists' => $report["dmarc_record"]['exists'] ?? '',
'dmarc_record_exists' => $post_meta['dmarc_record_exists'][0] ?? '', 'dmarc_record_content' => $report["dmarc_record"]['content'] ?? '',
'dmarc_policy' => $post_meta['dmarc_policy'][0] ?? '', 'dmarc_record_ttl' => $report["dmarc_record"]['ttl'] ?? '',
'dmarc_sp_policy' => $post_meta['dmarc_sp_policy'][0] ?? '', 'dmarc_policy' => $report["dmarc_record"]['policy'] ?? '',
'dmarc_percentage' => $post_meta['dmarc_percentage'][0] ?? '', 'dmarc_sp_policy' => $report["dmarc_record"]['sp_policy'] ?? '',
'dmarc_aspf' => $post_meta['dmarc_aspf'][0] ?? '', 'dmarc_percentage' => $report["dmarc_record"]['percentage'] ?? '',
'dmarc_adkim' => $post_meta['dmarc_adkim'][0] ?? '', 'dmarc_aspf' => $report["dmarc_record"]['aspf'] ?? '',
'dmarc_aggregate_rpt' => $post_meta['dmarc_aggregate_rpt'][0] ?? '', 'dmarc_adkim' => $report["dmarc_record"]['adkim'] ?? '',
'dmarc_forensic_rpt' => $post_meta['dmarc_forensic_rpt'][0] ?? '', 'dmarc_aggregate_rpt' => $report["dmarc_record"]['aggregate_rpt'] ?? '',
'dmarc_report_format' => $post_meta['dmarc_report_format'][0] ?? '', 'dmarc_forensic_rpt' => $report["dmarc_record"]['forensic_rpt'] ?? '',
'dmarc_report_interval' => $post_meta['dmarc_report_interval'][0] ?? '', 'dmarc_report_format' => $report["dmarc_record"]['report_format'] ?? '',
'dkim_records' => $post_meta['dkim_records'][0] ?? '', 'dmarc_report_interval' => $report["dmarc_record"]['report_interval'] ?? '',
'dkim_records' => $report['dkim_records'] ?? '',
]; ];
// Render the table // Render the table

View file

@ -1,22 +1,28 @@
<?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 * 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 * Set the CUSTOM_DEBUG_LOG file in wp-config.php
* *
*/ */
function log_to_file($message = false, $data = false){ function log_to_file($message, $data = false){
if ($message) { if ($message) {
$log_File = CUSTOM_DEBUG_LOG; $log_File = CUSTOM_DEBUG_LOG;
$date = new DateTime(); $date = new DateTime('now', new DateTimeZone('America/Chicago'));
$date = $date->format("Y/m/d h:i:s"); $date = $date->format("Y/m/d h:i:s");
// Convert arrays and objects to JSON format // Convert arrays and objects to JSON format
if (is_array($data) || is_object($data)) { if (is_array($data) || is_object($data)) {
$data = json_encode($data); $data = json_encode($data);
$message = $message . " " . $data; $message = $message . "\r\n" . $data;
} else if ($data) { } else if ($data) {
$message = $message . " " . $data; $message = $message . " " . $data;
} }
@ -25,15 +31,227 @@ function log_to_file($message = false, $data = false){
} }
} }
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 a meta box for testing the SSH connection.
*/ */
add_action('add_meta_boxes', function () { add_action('add_meta_boxes', function () {
add_meta_box( add_meta_box(
'test_ssh_connection_box', 'test_ssh_connection_box',
@ -45,6 +263,7 @@ add_action('add_meta_boxes', function () {
); );
}); });
/** /**
* Render the SSH connection test meta box. * Render the SSH connection test meta box.
* *
@ -130,3 +349,223 @@ add_action('wp_ajax_rl_mailwarmer_test_ssh_connection', function () {
}); });
/**
* 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);
}

View file

@ -1,4 +1,5 @@
jQuery(document).ready(function ($) { jQuery(document).ready(function ($) {
// console.log("Loaded check-domain-health.js");
$('#check-domain-health-button').on('click', function (e) { $('#check-domain-health-button').on('click', function (e) {
e.preventDefault(); e.preventDefault();

View file

@ -26,14 +26,17 @@ jQuery(document).ready(function ($) {
data: { data: {
source: response.data, source: response.data,
x: 'date', x: 'date',
y: d => +d['volume'], y: d => +d['target_volume'],
}, },
date: { date: {
start: new Date('2024-12-4'), start: new Date(2024, 12, 4),
}, },
cellSize: 15,
range: 1, // Number of months to display range: 1, // Number of months to display
domain: { type: 'year' }, domain: { type: 'year' },
subDomain: { type: 'day' }, // Granularity: days subDomain: { type: 'day' }, // Granularity: days
legend: [25, 50, 150, 200, 250],
legendColors: ["#efefef", "steelblue"],
legend: { legend: {
show: true, show: true,
label: 'Daily Volume', label: 'Daily Volume',
@ -50,6 +53,7 @@ jQuery(document).ready(function ($) {
scheme: 'YlOrRd', scheme: 'YlOrRd',
}, },
}, },
// start: new Date(2024, 12, 06),
verticalOrientation: true, verticalOrientation: true,
itemSelector: '#campaign-timeline-heatmap', itemSelector: '#campaign-timeline-heatmap',
}); });

View file

@ -15,6 +15,7 @@ jQuery(document).ready(function ($) {
security: rlMailWarmerGenerateTimeline.nonce, security: rlMailWarmerGenerateTimeline.nonce,
}, },
success: function (response) { success: function (response) {
console.log(response);
if (response.success) { if (response.success) {
const timeline = response.data; const timeline = response.data;
let output = '<p>Timeline Generated:</p><ul>'; let output = '<p>Timeline Generated:</p><ul>';

View file

@ -20,20 +20,27 @@ define('RL_MAILWARMER_VERSION', '0.0.1');
define('RL_MAILWARMER_PATH', plugin_dir_path(__FILE__)); define('RL_MAILWARMER_PATH', plugin_dir_path(__FILE__));
define('RL_MAILWARMER_URL', plugin_dir_url(__FILE__)); define('RL_MAILWARMER_URL', plugin_dir_url(__FILE__));
require RL_MAILWARMER_PATH . 'vendor/autoload.php';
// Include necessary files // Include necessary files
// require_once plugin_dir_path(__FILE__) . 'includes/class-rl-mailwarmer-post-types.php'; // require_once plugin_dir_path(__FILE__) . 'includes/class-rl-mailwarmer-post-types.php';
// require_once plugin_dir_path(__FILE__) . 'includes/class-rl-mailwarmer-acf-integration.php'; // require_once plugin_dir_path(__FILE__) . 'includes/class-rl-mailwarmer-acf-integration.php';
require_once RL_MAILWARMER_PATH . 'includes/rl-mailwarmer-functions.php'; require_once RL_MAILWARMER_PATH . 'includes/rl-mailwarmer-functions.php';
require_once RL_MAILWARMER_PATH . 'includes/rl-mailwarmer-ajax.php'; require_once RL_MAILWARMER_PATH . 'includes/rl-mailwarmer-ajax.php';
require_once RL_MAILWARMER_PATH . 'includes/rl-mailwarmer-rest.php'; // require_once RL_MAILWARMER_PATH . 'includes/rl-mailwarmer-rest.php';
require_once RL_MAILWARMER_PATH . 'includes/rl-mailwarmer-importer.php';
require_once RL_MAILWARMER_PATH . 'includes/rl-mailwarmer-domain-admin.php'; require_once RL_MAILWARMER_PATH . 'includes/rl-mailwarmer-domain-admin.php';
require_once RL_MAILWARMER_PATH . 'includes/rl-mailwarmer-email-admin.php'; require_once RL_MAILWARMER_PATH . 'includes/rl-mailwarmer-email-admin.php';
require_once RL_MAILWARMER_PATH . 'includes/class-rl-mailwarmer-campaign-helper.php';
require_once RL_MAILWARMER_PATH . 'includes/class-rl-mailwarmer-conversation-helper.php';
require_once RL_MAILWARMER_PATH . 'includes/class-rl-mailwarmer-db-helper.php'; require_once RL_MAILWARMER_PATH . 'includes/class-rl-mailwarmer-db-helper.php';
require_once RL_MAILWARMER_PATH . 'includes/class-rl-mailwarmer-domain-helper.php'; require_once RL_MAILWARMER_PATH . 'includes/class-rl-mailwarmer-domain-helper.php';
require_once RL_MAILWARMER_PATH . 'includes/class-rl-mailwarmer-email-helper.php'; require_once RL_MAILWARMER_PATH . 'includes/class-rl-mailwarmer-email-account-helper.php';
require_once RL_MAILWARMER_PATH . 'includes/class-rl-mailwarmer-campaign-helper.php';
require_once RL_MAILWARMER_PATH . 'includes/class-rl-mailwarmer-scheduler.php';
require_once RL_MAILWARMER_PATH . 'includes/class-rl-mailwarmer-email-handler.php'; require_once RL_MAILWARMER_PATH . 'includes/class-rl-mailwarmer-email-handler.php';
require_once RL_MAILWARMER_PATH . 'includes/class-rl-mailwarmer-message-handler.php';
require_once RL_MAILWARMER_PATH . 'includes/class-rl-mailwarmer-message-helper.php';
require_once RL_MAILWARMER_PATH . 'includes/class-rl-mailwarmer-scheduler.php';
require_once RL_MAILWARMER_PATH . 'includes/class-rl-mailwarmer-post-tables.php';
// require_once RL_MAILWARMER_PATH . 'includes/vendor/autoload.php'; // require_once RL_MAILWARMER_PATH . 'includes/vendor/autoload.php';
@ -49,8 +56,9 @@ function rl_mailwarmer_init()
// Schedule email tasks // Schedule email tasks
RL_MailWarmer_Scheduler::init(); RL_MailWarmer_Scheduler::init();
// Handle email sending // Handle email sending
RL_MailWarmer_Email_Handler::init(); // RL_MailWarmer_Email_Handler::init();
} }
add_action('plugins_loaded', 'rl_mailwarmer_init'); add_action('plugins_loaded', 'rl_mailwarmer_init');