robotstxt-smtp-newsletter/includes/class-plugin.php
2026-02-18 15:24:59 +00:00

288 lines
7.4 KiB
PHP

<?php
/**
* Main plugin class.
*
* @package ROBOTSTXT_SMTP_Newsletter
*/
namespace Robotstxt_SMTP_Newsletter;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Plugin main class.
*
* Extends NewsletterMailerAddon to integrate with Newsletter plugin.
*/
class Plugin extends \NewsletterMailerAddon {
/**
* Singleton instance.
*
* @var Plugin|null
*/
private static $instance = null;
/**
* Default options.
*
* @var array<string, mixed>
*/
private static $defaults = array(
'enabled' => false,
'batch_size' => 10,
);
/**
* Plugin display name.
*
* @var string
*/
public $name;
/**
* Plugin slug.
*
* @var string
*/
public $slug;
/**
* Menu title.
*
* @var string
*/
public $menu_title;
/**
* Get singleton instance.
*
* @return Plugin
*/
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Initialize plugin (called on newsletter_loaded hook).
*
* @return void
*/
public static function instance_init() {
$instance = self::get_instance();
$instance->init();
}
/**
* Constructor.
*/
private function __construct() {
parent::__construct( 'robotstxt-smtp-newsletter', ROBOTSTXT_SMTP_NEWSLETTER_VERSION, ROBOTSTXT_SMTP_NEWSLETTER_PATH );
$this->name = 'SMTP (by ROBOTSTXT)';
$this->slug = 'robotstxt-smtp-newsletter';
$this->menu_title = 'SMTP (by ROBOTSTXT)';
}
/**
* Setup options.
*
* Overrides parent to use our custom option name.
*
* @return void
*/
public function setup_options() {
if ( $this->options ) {
return;
}
// Load our options using our custom option name (not newsletter_ prefix).
$this->options = get_option( 'robotstxt_smtp_newsletter_options', array() );
$this->options = wp_parse_args( $this->options, self::$defaults );
}
/**
* Initialize plugin hooks.
*
* Overrides parent init() method.
*
* @return void
*/
public function init() {
parent::init();
// Load required classes.
require_once ROBOTSTXT_SMTP_NEWSLETTER_PATH . 'includes/class-queue.php';
require_once ROBOTSTXT_SMTP_NEWSLETTER_PATH . 'includes/class-statistics.php';
require_once ROBOTSTXT_SMTP_NEWSLETTER_PATH . 'includes/class-email-message.php';
// Initialize database tables.
Queue::get_instance();
Statistics::get_instance();
// Load text domain.
add_action( 'init', array( $this, 'load_textdomain' ) );
// Register admin pages.
if ( is_admin() ) {
require_once ROBOTSTXT_SMTP_NEWSLETTER_PATH . 'admin/class-settings-page.php';
require_once ROBOTSTXT_SMTP_NEWSLETTER_PATH . 'admin/class-emails-list-page.php';
require_once ROBOTSTXT_SMTP_NEWSLETTER_PATH . 'admin/class-statistics-page.php';
add_action( 'admin_init', array( 'Robotstxt_SMTP_Newsletter\Admin\Settings_Page', 'register_settings_static' ) );
add_action( 'admin_menu', array( 'Robotstxt_SMTP_Newsletter\Admin\Emails_List_Page', 'register' ) );
add_action( 'admin_menu', array( 'Robotstxt_SMTP_Newsletter\Admin\Statistics_Page', 'register' ) );
}
}
/**
* Load plugin text domain for translations.
*
* @return void
*/
public function load_textdomain() {
load_plugin_textdomain(
'robotstxt-smtp-newsletter',
false,
dirname( plugin_basename( ROBOTSTXT_SMTP_NEWSLETTER_FILE ) ) . '/languages'
);
}
/**
* Get the mailer instance.
*
* This method is called by the parent class to get the mailer
* that should be registered with Newsletter.
*
* @return \NewsletterMailer
*/
public function get_mailer() {
// Load required classes.
require_once ROBOTSTXT_SMTP_NEWSLETTER_PATH . 'includes/class-queue.php';
require_once ROBOTSTXT_SMTP_NEWSLETTER_PATH . 'includes/class-statistics.php';
require_once ROBOTSTXT_SMTP_NEWSLETTER_PATH . 'includes/class-email-message.php';
// Get our settings and map to Newsletter's expected format.
$settings = $this->get_settings();
$smtp_settings = $this->get_smtp_settings();
// Calculate optimal speed (emails per hour) based on rate limits.
$speed = $this->calculate_optimal_speed( $smtp_settings );
// Newsletter expects 'turbo' for batch_size and 'speed' for emails/hour.
$mailer_options = array(
'turbo' => $settings['batch_size'] ?? 10,
'speed' => $speed,
);
// Detect if Amazon SES is active.
if ( $this->is_amazon_ses_active() ) {
require_once ROBOTSTXT_SMTP_NEWSLETTER_PATH . 'includes/class-amazonses-mailer.php';
return new AmazonSES_Mailer( $mailer_options );
} else {
require_once ROBOTSTXT_SMTP_NEWSLETTER_PATH . 'includes/class-smtp-mailer.php';
return new SMTP_Mailer( $mailer_options );
}
}
/**
* Calculate optimal speed (emails per hour) based on rate limits.
*
* @param array<string, mixed> $smtp_settings SMTP settings with rate limits.
*
* @return int Emails per hour.
*/
private function calculate_optimal_speed( $smtp_settings ) {
// Get rate limits from ROBOTSTXT SMTP settings.
$rate_per_hour = absint( $smtp_settings['rate_limit_per_hour'] ?? 0 );
// If hourly limit is set, use it (with 90% safety margin).
if ( $rate_per_hour > 0 ) {
return (int) floor( $rate_per_hour * 0.9 );
}
// If no hourly limit, calculate from per-second limit.
$rate_per_second = absint( $smtp_settings['rate_limit_per_second'] ?? 0 );
if ( $rate_per_second > 0 ) {
return (int) floor( $rate_per_second * 3600 * 0.9 );
}
// If no limits set, use a conservative default based on delivery method.
$is_ses = $this->is_amazon_ses_active();
return $is_ses ? 1000 : 500;
}
/**
* Check if Amazon SES integration is active.
*
* @return bool
*/
private function is_amazon_ses_active() {
if ( ! class_exists( '\Robotstxt_SMTP\Plugin' ) ) {
return false;
}
return \Robotstxt_SMTP\Plugin::is_amazon_ses_integration_active();
}
/**
* Get plugin settings with defaults.
*
* @return array<string, mixed>
*/
public function get_settings() {
$options = get_option( 'robotstxt_smtp_newsletter_options', array() );
return wp_parse_args( $options, self::$defaults );
}
/**
* Get SMTP settings from robotstxt-smtp plugin.
*
* @return array<string, mixed>
*/
public function get_smtp_settings() {
if ( ! class_exists( '\Robotstxt_SMTP\Plugin' ) || ! class_exists( '\Robotstxt_SMTP\Admin\Settings_Page' ) ) {
return array();
}
// Check if network mode is enabled.
$scope = get_site_option( 'robotstxt_smtp_configuration_scope', 'site' );
if ( 'network' === $scope ) {
$settings = get_site_option( 'robotstxt_smtp_network_options', array() );
} else {
$settings = get_option( 'robotstxt_smtp_options', array() );
}
return $settings;
}
/**
* Plugin activation hook.
*
* Creates database tables and migrates settings.
*
* @return void
*/
public static function activation_hook() {
// Load required classes.
require_once ROBOTSTXT_SMTP_NEWSLETTER_PATH . 'includes/class-queue.php';
require_once ROBOTSTXT_SMTP_NEWSLETTER_PATH . 'includes/class-statistics.php';
require_once ROBOTSTXT_SMTP_NEWSLETTER_PATH . 'includes/class-email-message.php';
// Tables are created automatically via __construct().
Queue::get_instance();
Statistics::get_instance();
// Migrate settings: remove deprecated max_per_connection.
$options = get_option( 'robotstxt_smtp_newsletter_options', array() );
if ( isset( $options['max_per_connection'] ) ) {
unset( $options['max_per_connection'] );
update_option( 'robotstxt_smtp_newsletter_options', $options );
}
}
}