JezK
Edit File: module.php
<?php namespace SiteMailer\Modules\Settings; use ElementorOne\Connect\Classes\Data; use Exception; use SiteMailer\Classes\Logger; use SiteMailer\Classes\Module_Base; use SiteMailer\Classes\Utils; use SiteMailer\Modules\Connect\Classes\Config; use SiteMailer\Modules\Connect\Module as Connect; use SiteMailer\Modules\Logs\Components\Log_Pull; use SiteMailer\Modules\Settings\Banners\Birthday_Banner; use SiteMailer\Modules\Settings\Banners\Sale_Banner; use SiteMailer\Modules\Settings\Classes\Settings; use SiteMailer\Modules\Settings\Module as SettingsModule; use Throwable; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * Class Module */ class Module extends Module_Base { const SETTING_PREFIX = 'site_mailer_'; const SETTING_GROUP = 'site_mailer_settings'; const SETTING_BASE_SLUG = 'site-mailer-settings'; const SETTING_CAPABILITY = 'manage_options'; const ONE_MISMATCH_URL = '/wp-admin/admin.php?page=elementor-home#/home/url-mismatch'; /** * Get module name. * Retrieve the module name. * * @access public * @return string Module name. */ public function get_name(): string { return 'settings'; } public static function component_list(): array { return [ 'Settings_Pointer', ]; } public static function routes_list(): array { return [ 'Get_Settings', ]; } public function render_app() { ?> <?php Sale_Banner::get_banner( 'https://go.elementor.com/SM-BF-sale' ); ?> <?php Birthday_Banner::get_banner( 'https://go.elementor.com/sm-b-day-banner' ); ?> <!-- The hack required to wrap WP notifications --> <div class="wrap"> <h1 style="display: none;" role="presentation"></h1> </div> <div id="site-mailer-app"></div> <?php } public function register_page() { add_submenu_page( 'elementor-home', __( 'Email Deliverability', 'site-mailer' ), __( 'Email Deliverability', 'site-mailer' ), self::SETTING_CAPABILITY, self::SETTING_BASE_SLUG, [ $this, 'render_app' ], 20 ); } /** * @throws Throwable */ public function maybe_add_url_mismatch_notice() { if ( ! Utils::is_plugin_page() || Connect::get_connect()->utils()->is_valid_home_url() ) { return; } $onclick = SettingsModule::is_elementor_one() ? 'window.location.href = "' . self::ONE_MISMATCH_URL . '";' : 'document.dispatchEvent( new Event( "site-mailer/auth/url-mismatch-modal/open" ) );'; ?> <div class="notice notice-error notice site-mailer__notice site-mailer__notice--error"> <p> <b> <?php esc_html_e( 'Your license key does not match your current domain, causing a mismatch.', 'site-mailer' ); ?> </b> <span> <?php esc_html_e( 'This is most likely due to a change in the domain URL of your site (including HTTP/SSL migration).', 'site-mailer' ); ?> <button type="button" onclick="<?php echo esc_js( $onclick ); ?>"> <?php esc_html_e( 'Fix mismatched URL', 'site-mailer' ); ?> </button> </span> </p> </div> <?php } /** * Enqueue Scripts and Styles */ public function enqueue_scripts(): void { if ( ! Utils::is_plugin_page() ) { return; } if ( version_compare( get_bloginfo( 'version' ), '6.6', '<' ) ) { wp_register_script( 'react-jsx-runtime', SITE_MAILER_ASSETS_URL . 'lib/react-jsx-runtime.js', [ 'react' ], '18.3.1', true ); } wp_enqueue_style( 'site-mailer-admin-fonts', 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap', [], SITE_MAILER_VERSION ); Utils\Assets::enqueue_app_assets( 'admin' ); wp_localize_script( 'admin', 'siteMailerSettingsData', [ 'wpRestNonce' => wp_create_nonce( 'wp_rest' ), 'pluginEnv' => self::get_plugin_env(), 'isDevelopment' => defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG, 'planData' => Settings::get( Settings::PLAN_DATA ), 'planScope' => Settings::get( Settings::PLAN_SCOPE ), 'appSlug' => Config::PLUGIN_SLUG, 'appVersion' => SITE_MAILER_VERSION, ] ); } /** * Get Mixpanel project Token * @return string */ private static function get_plugin_env(): string { return apply_filters( 'site_mailer_plugin_env', 'production' ); } /** * @throws Exception */ public function on_connect() { if ( ! Connect::is_connected() ) { return; } $register_response = Utils::get_api_client()->make_request( 'POST', 'site/register' ); if ( $register_response && ! is_wp_error( $register_response ) ) { update_option( Settings::SUBSCRIPTION_ID, $register_response->id ); $response = Utils::get_api_client()->make_request( 'POST', 'site/info' ); } if ( ! is_wp_error( $response ) ) { update_option( Settings::PLAN_DATA, $response ); update_option( Settings::IS_VALID_PLAN_DATA, true ); if ( isset( $response->scopes ) ) { Settings::set( Settings::PLAN_SCOPE, $response->scopes ); } } else { Logger::error( esc_html( $response->get_error_message() ) ); update_option( Settings::IS_VALID_PLAN_DATA, false ); } } /** * Register or update site data for One connect * @throws Exception */ public function on_migration_run() { if ( ! Connect::is_connected() ) { return; } $client_id = Settings::get( Settings::CLIENT_ID ); if ( $client_id ) { try { Utils::get_api_client()->make_request( 'POST', 'site/migration', ['old_client_id' => $client_id], ); self::refresh_plan_data(); $old_options = [ 'site_mailer_client_secret', 'site_mailer_home_url', 'site_mailer_access_token', 'site_mailer_token_id', 'site_mailer_refresh_token', 'site_mailer_user_access_token', 'site_mailer_owner_user_id', Settings::SUBSCRIPTION_ID, Settings::CLIENT_ID, ]; foreach ( $old_options as $option ) { delete_option( $option ); } } catch ( Throwable $t ) { Logger::error( esc_html( $t->getMessage() ) ); } } else { $this->on_connect(); } } /** * On disconnect * @return void */ public function on_disconnect() { delete_option( Settings::SUBSCRIPTION_ID ); } /** * Register settings. * * Register settings for the plugin. * * @return void * @throws Throwable */ public function register_settings() { $settings = [ 'keep_log' => [ 'type' => 'boolean', ], 'unsubscribe' => [ 'type' => 'boolean', ], 'close_post_connect_modal' => [ 'type' => 'boolean', 'description' => _x( 'Site Mailer Close Post Connect Modal', 'Description for API usage. no need to translate', 'site-mailer' ), ], 'from_name' => [ 'type' => 'string', 'description' => _x( 'Site Mailer From Email', 'Description for API usage. no need to translate', 'site-mailer' ), ], 'reply_to_email' => [ 'type' => 'string', 'description' => _x( 'Site Mailer Reply Email', 'Description for API usage. no need to translate', 'site-mailer' ), ], 'sender_domain' => [ 'type' => 'string', 'description' => _x( 'Site Mailer Sender Domain', 'Description for API usage. no need to translate', 'site-mailer' ), ], 'sender_email_prefix' => [ 'type' => 'string', 'description' => _x( 'Site Mailer Sender Mail Prefix', 'Description for API usage. no need to translate', 'site-mailer' ), ], 'custom_domain_dns_records' => [ 'type' => 'string', 'description' => _x( 'Site Mailer custom domain DNS records', 'Description for API usage. no need to translate', 'site-mailer' ), ], 'verification_started' => [ 'type' => 'boolean', ], 'registration_started' => [ 'type' => 'boolean', ], 'confirm_domain_settings_opened' => [ 'type' => 'boolean', ], 'confirm_dns_settings_added' => [ 'type' => 'boolean', ], 'active_step' => [ 'type' => 'boolean', ], 'custom_domain_verified' => [ 'type' => 'boolean', ], 'custom_domain_verified_alert' => [ 'type' => 'boolean', ], 'custom_domain_verification_start_time' => [ 'type' => 'string', ], 'is_valid_plan_data' => [ 'type' => 'boolean', ], 'hide_logs_status_refresh_infotip' => [ 'type' => 'boolean', 'show_in_rest' => true, ], 'hide_walkthrough_modal' => [ 'type' => 'boolean', ], ]; foreach ( $settings as $setting => $args ) { if ( ! isset( $args['show_in_rest'] ) ) { $args['show_in_rest'] = true; } register_setting( 'options', self::SETTING_PREFIX . $setting, $args ); } } /** * Get sender email * * @return string */ public static function get_sender_email(): string { $settings = Settings::get( Settings::PLAN_DATA ); $sender_in_used = Settings::get( Settings::SENDER_EMAIL_PREFIX ); $sender_mail = ''; $domain_verified = 'verified' === Settings::get( Settings::CUSTOM_DOMAIN_VERIFICATION_STATUS ); if ( ! empty( $settings ) && ! is_wp_error( $settings ) ) { if ( ! empty( $settings->sender->sender_in_used ) ) { $sender_mail = $settings->sender->sender_in_used; $sender = explode( '@', $sender_mail ); if ( $domain_verified && ! empty( $sender_in_used ) && $sender[0] !== $sender_in_used ) { $sender_mail = $sender_in_used . '@' . $sender[1]; } } } return $sender_mail; } /** * Get sender from name * * @return string */ public static function get_sender_from_name(): string { return Settings::get( Settings::FROM_NAME ); } /** * Get sender reply to email * * @return string */ public static function get_sender_reply_email(): string { $email = Settings::get( Settings::REPLY_TO_EMAIL ); if ( ( ! empty( $email ) && ! is_email( $email ) ) || empty( $email ) ) { return get_bloginfo( 'admin_email' ); } return $email; } /** * Get unsubscribe encryption key * * @return array|bool */ public static function get_unsubscribe_encryption_data() { if ( ! function_exists( 'openssl_encrypt' ) ) { Logger::error( 'the openssl extension is not installed in the environment' ); return false; } $data = Settings::get( Settings::UNSUBSCRIBE_ENCRYPTION_DATA ); if ( ! $data ) { $cipher = 'aes128'; $iv_length = openssl_cipher_iv_length( $cipher ); $iv = openssl_random_pseudo_bytes( $iv_length ); $data = [ 'key' => wp_generate_uuid4(), 'cipher' => $cipher, 'iv' => base64_encode( $iv ), ]; update_option( Settings::UNSUBSCRIBE_ENCRYPTION_DATA, $data ); } return $data; } /** * Refresh plan data when the settings page is loaded. * * @return void * @throws Throwable */ public static function refresh_plan_data() { if ( ! Connect::is_connected() ) { return; } $endpoint = self::is_elementor_one() ? 'site/register' : 'site/info'; $response = Utils::get_api_client()->make_request( 'POST', $endpoint ); if ( ! is_wp_error( $response ) ) { update_option( Settings::PLAN_DATA, $response ); update_option( Settings::IS_VALID_PLAN_DATA, true ); } else { Logger::error( esc_html( $response->get_error_message() ) ); update_option( Settings::IS_VALID_PLAN_DATA, false ); } } public static function clear_settings_cache() { wp_cache_delete( Settings::KEEP_LOG, 'option' ); wp_cache_delete( Settings::UNSUBSCRIBE, 'option' ); wp_cache_delete( Settings::CLOSE_POST_CONNECT_MODAL, 'option' ); wp_cache_delete( Settings::PLAN_DATA, 'option' ); wp_cache_delete( Settings::SENDER_EMAIL_PREFIX, 'option' ); wp_cache_delete( Settings::FROM_NAME, 'option' ); wp_cache_delete( Settings::REPLY_TO_EMAIL, 'option' ); wp_cache_delete( Settings::CUSTOM_DOMAIN_DNS_RECORDS, 'option' ); wp_cache_delete( Settings::CUSTOM_DOMAIN_VERIFICATION_STATUS, 'option' ); wp_cache_delete( Settings::CUSTOM_DOMAIN_VERIFICATION_RECORDS, 'option' ); wp_cache_delete( Settings::CUSTOM_DOMAIN_VERIFICATION_START_TIME, 'option' ); wp_cache_delete( Settings::SUBSCRIPTION_ID, 'option' ); wp_cache_delete( Config::APP_PREFIX . Data::ACCESS_TOKEN, 'option' ); wp_cache_delete( Config::APP_PREFIX . Data::CLIENT_ID, 'option' ); wp_cache_delete( Config::APP_PREFIX . Data::HOME_URL, 'option' ); wp_cache_delete( Config::APP_PREFIX . Data::OPTION_OWNER_USER_ID, 'option' ); wp_cache_delete( Settings::IS_VALID_PLAN_DATA, 'option' ); } /** * Check if elementor one * @return bool */ public static function is_elementor_one(): bool { return Connect::get_connect()->get_config( 'app_type' ) !== Config::APP_TYPE; } /** * Get all plugin settings data * @return array * @throws Throwable */ public static function get_plugin_settings(): array { self::refresh_plan_data(); self::clear_settings_cache(); return [ 'isConnected' => Connect::is_connected(), 'isUrlMismatch' => ! Connect::get_connect()->utils()->is_valid_home_url(), 'subscriptionId' => Settings::get( Settings::SUBSCRIPTION_ID ), 'keepLog' => Settings::get( Settings::KEEP_LOG ), 'unsubscribe' => Settings::get( Settings::UNSUBSCRIBE ), 'isDevelopment' => defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG, 'siteUrl' => wp_parse_url( get_site_url(), PHP_URL_HOST ), 'closePostConnectModal' => Settings::get( Settings::CLOSE_POST_CONNECT_MODAL ), 'senderEmail' => self::get_sender_email() ?? '', 'fromName' => self::get_sender_from_name(), 'replyToEmail' => self::get_sender_reply_email(), 'settings' => Settings::get( Settings::PLAN_DATA ), 'customDomainDNSRecords' => Settings::get( Settings::CUSTOM_DOMAIN_DNS_RECORDS ), 'verificationStatus' => Settings::get( Settings::CUSTOM_DOMAIN_VERIFICATION_STATUS ), 'verificationRecords' => Settings::get( Settings::CUSTOM_DOMAIN_VERIFICATION_RECORDS ), 'verificationStartTime' => Settings::get( Settings::CUSTOM_DOMAIN_VERIFICATION_START_TIME ), //TODO: check use of this 'isValidPlanData' => Settings::get( Settings::IS_VALID_PLAN_DATA ), 'isRTL' => is_rtl(), 'lastLogRefresh' => Log_Pull::check_refresh_time(), 'isElementorOne' => self::is_elementor_one(), ]; } public function __construct() { $this->register_routes(); $this->register_components( self::component_list() ); add_action( 'current_screen', function () { add_action( 'admin_notices', [ $this, 'maybe_add_url_mismatch_notice' ] ); } ); add_action( 'admin_menu', [ $this, 'register_page' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] ); add_action( 'elementor_one/' . Config::APP_PREFIX . '_connected', [ $this, 'on_connect' ] ); add_action( 'elementor_one/' . Config::APP_PREFIX . '_disconnected', [ $this, 'on_disconnect' ] ); add_action( 'elementor_one/' . Config::APP_PREFIX . '_migration_run', [ $this, 'on_migration_run' ] ); add_action( 'rest_api_init', [ $this, 'register_settings' ] ); // Add action on switch domain for update access token add_action( 'elementor_one/' . Config::APP_PREFIX . '_switched_domain', function($facade) { $facade->service()->renew_access_token(); } ); add_action( 'elementor_one/switched_domain', function( $facade ) { $facade->service()->renew_access_token(); } ); } }