one big "Connect to PostaraMail" button. * Connected -> Overview | Sync | Forms | Existing users | Advanced. */ if ( ! defined( 'ABSPATH' ) ) { exit; } class PostaraMail_Admin { /** Tab slug => translated label. A method (not a constant) so the strings are real gettext calls. */ private static function tabs() { return array( 'overview' => __( 'Overview', 'postaramail' ), 'sync' => __( 'Sync', 'postaramail' ), 'forms' => __( 'Forms', 'postaramail' ), 'existing' => __( 'Existing users', 'postaramail' ), 'advanced' => __( 'Advanced', 'postaramail' ), ); } public static function init() { add_action( 'admin_menu', array( __CLASS__, 'menu' ) ); add_action( 'admin_enqueue_scripts', array( __CLASS__, 'assets' ) ); add_action( 'admin_notices', array( __CLASS__, 'setup_notice' ) ); add_action( 'admin_init', array( __CLASS__, 'privacy_text' ) ); add_action( 'wp_ajax_postaramail_test', array( __CLASS__, 'ajax_test' ) ); foreach ( array( 'sync', 'forms', 'existing', 'send_existing', 'advanced', 'refresh', 'push_now', 'rescan' ) as $a ) { add_action( 'admin_post_postaramail_save_' . $a, array( __CLASS__, 'save_' . $a ) ); } } public static function menu() { add_menu_page( 'PostaraMail', 'PostaraMail', 'manage_options', 'postaramail', array( __CLASS__, 'page' ), 'dashicons-email-alt', 58 ); } public static function assets( $hook ) { if ( 'toplevel_page_postaramail' !== $hook ) { return; } wp_enqueue_style( 'postaramail-admin', POSTARAMAIL_WP_URL . 'assets/admin.css', array(), POSTARAMAIL_WP_VERSION ); wp_enqueue_style( 'postaramail-form', POSTARAMAIL_WP_URL . 'assets/form.css', array(), POSTARAMAIL_WP_VERSION ); wp_enqueue_script( 'postaramail-admin', POSTARAMAIL_WP_URL . 'assets/admin.js', array(), POSTARAMAIL_WP_VERSION, true ); wp_localize_script( 'postaramail-admin', 'PostaraMailAdmin', array( 'ajax' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'postaramail_test' ), ) ); } public static function setup_notice() { if ( ! current_user_can( 'manage_options' ) || PostaraMail_API::configured() ) { return; } $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; if ( $screen && 'toplevel_page_postaramail' === $screen->id ) { return; } echo '

' . wp_kses( sprintf( /* translators: %s: link to the PostaraMail screen */ __( 'PostaraMail is almost ready. Connect your account in one click to start collecting subscribers.', 'postaramail' ), esc_url( admin_url( 'admin.php?page=postaramail' ) ) ), array( 'strong' => array(), 'a' => array( 'href' => array() ), ) ) . '

'; } public static function privacy_text() { if ( function_exists( 'wp_add_privacy_policy_content' ) ) { wp_add_privacy_policy_content( 'PostaraMail', wp_kses_post( '

' . __( 'When a visitor subscribes through a PostaraMail form, agrees to receive emails when registering or ordering, or answers “yes” to our email news question, their email address and name are sent to PostaraMail (postaramail.com, operated by PostaraAI LLC) so we can send them the emails they agreed to, together with the wording they agreed to. The visitor’s IP address may be passed on once, only to work out their country; PostaraMail keeps the country, not the IP address. Existing users of this site may be listed in PostaraMail as “not asked yet” and are not emailed until they say yes. This site keeps no subscriber list of its own. Every email includes an unsubscribe link.', 'postaramail' ) . '

' ) ); } } // ---------- Small helpers ---------- private static function url( $tab = 'overview', $extra = array() ) { return add_query_arg( array_merge( array( 'page' => 'postaramail', 'tab' => $tab, ), $extra ), admin_url( 'admin.php' ) ); } private static function post_url( $action ) { return admin_url( 'admin-post.php' ); } private static function form_open( $action, $tab ) { echo '
'; echo ''; wp_nonce_field( 'postaramail_save_' . $action ); echo ''; } private static function guard( $action ) { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Not allowed.', 'postaramail' ), '', array( 'response' => 403 ) ); } check_admin_referer( 'postaramail_save_' . $action ); } private static function back( $tab, $msg ) { wp_safe_redirect( self::url( $tab, array( 'pm_msg' => $msg ) ) ); exit; } private static function post( $key, $default = '' ) { return isset( $_POST[ $key ] ) ? wp_unslash( $_POST[ $key ] ) : $default; // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- verified in guard(); sanitized by callers. } private static function mode_value( $key ) { $v = sanitize_key( self::post( $key, 'off' ) ); return in_array( $v, array( 'off', 'notice', 'checkbox' ), true ) ? $v : 'off'; } /** Sends the saved settings to PostaraMail (the master). If the dashboard changed first, it wins. */ private static function pushed( $msg ) { return 'stale' === PostaraMail_Sync::push() ? 'stale' : $msg; } // ---------- Saving ---------- public static function save_sync() { self::guard( 'sync' ); $reg = self::mode_value( 'reg_mode' ); $woo = self::mode_value( 'woo_mode' ); $comment = 'off' === self::mode_value( 'comment_mode' ) ? 'off' : 'checkbox'; $msg = 'saved'; if ( ! empty( $_POST['owner_confirm'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing if ( ! get_option( 'postaramail_owner_confirmed' ) ) { update_option( 'postaramail_owner_confirmed', time(), false ); } } if ( ( 'notice' === $reg || 'notice' === $woo ) && ! get_option( 'postaramail_owner_confirmed' ) ) { // No confirmation, no automatic adding: fall back to the strict checkbox. $reg = 'notice' === $reg ? 'checkbox' : $reg; $woo = 'notice' === $woo ? 'checkbox' : $woo; $msg = 'confirm'; } update_option( 'postaramail_reg_mode', $reg ); update_option( 'postaramail_woo_mode', $woo ); update_option( 'postaramail_comment_mode', $comment ); update_option( 'postaramail_reg_notice', sanitize_text_field( self::post( 'reg_notice', PostaraMail_Integrations::default_notice( 'reg' ) ) ) ); update_option( 'postaramail_woo_notice', sanitize_text_field( self::post( 'woo_notice', PostaraMail_Integrations::default_notice( 'woo' ) ) ) ); update_option( 'postaramail_optin_label', sanitize_text_field( self::post( 'optin_label', PostaraMail_Integrations::checkbox_label() ) ) ); update_option( 'postaramail_start_automations', empty( $_POST['start_automations'] ) ? 0 : 1 ); // phpcs:ignore WordPress.Security.NonceVerification.Missing update_option( 'postaramail_default_automation', absint( self::post( 'default_automation', 0 ) ) ); update_option( 'postaramail_setup_done', time(), false ); self::back( 'sync', self::pushed( $msg ) ); } public static function save_forms() { self::guard( 'forms' ); update_option( 'postaramail_button_text', sanitize_text_field( self::post( 'button_text', __( 'Subscribe', 'postaramail' ) ) ) ); update_option( 'postaramail_consent_text', sanitize_text_field( self::post( 'consent_text', '' ) ) ); update_option( 'postaramail_success_text', sanitize_text_field( self::post( 'success_text', '' ) ) ); self::back( 'forms', self::pushed( 'saved' ) ); } public static function save_existing() { self::guard( 'existing' ); update_option( 'postaramail_exist_banner', empty( $_POST['exist_banner'] ) ? 0 : 1 ); // phpcs:ignore WordPress.Security.NonceVerification.Missing $roles = isset( $_POST['exist_roles'] ) && is_array( $_POST['exist_roles'] ) ? array_map( 'sanitize_key', wp_unslash( $_POST['exist_roles'] ) ) : array(); // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized update_option( 'postaramail_exist_roles', array_values( array_intersect( $roles, array_keys( wp_roles()->roles ) ) ) ); PostaraMail_Existing::remember_roles(); update_option( 'postaramail_sync_pending', empty( $_POST['sync_pending'] ) ? 0 : 1 ); // phpcs:ignore WordPress.Security.NonceVerification.Missing PostaraMail_Pending::schedule_soon(); self::back( 'existing', self::pushed( 'saved' ) ); } public static function save_send_existing() { self::guard( 'send_existing' ); $n = PostaraMail_Existing::start_email( ! empty( $_POST['exist_confirm'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing wp_safe_redirect( self::url( 'existing', array( 'pm_msg' => $n ? 'sending' : 'noconfirm', 'n' => $n, ) ) ); exit; } public static function save_advanced() { self::guard( 'advanced' ); $key = trim( (string) self::post( 'api_key', '' ) ); if ( '' !== $key ) { if ( ! PostaraMail_API::looks_valid( $key ) ) { self::back( 'advanced', 'key_bad' ); } update_option( 'postaramail_api_key', $key, false ); update_option( 'postaramail_connection', array( 'via' => 'manual', 'workspace' => '', 'time' => time(), ), false ); delete_transient( 'postaramail_me' ); delete_transient( 'postaramail_automations' ); } $base = esc_url_raw( trim( (string) self::post( 'base_url', '' ) ) ); update_option( 'postaramail_base_url', ( $base && 0 === strpos( $base, 'https://' ) ) ? untrailingslashit( $base ) : '' ); self::back( 'advanced', 'saved' ); } /** "Send now": everyone waiting goes to PostaraMail immediately. */ public static function save_push_now() { self::guard( 'push_now' ); list( $n, $err ) = PostaraMail_Pending::push_now(); wp_safe_redirect( self::url( 'overview', array( 'pm_msg' => $err ? 'push_failed' : 'pushed', 'n' => $n, 'pm_err' => $err ? rawurlencode( $err ) : '', ) ) ); exit; } /** "Look up countries": shown users without a country are sent again with every country clue the site has. */ public static function save_rescan() { self::guard( 'rescan' ); $n = PostaraMail_Pending::rescan_countries(); if ( $n ) { PostaraMail_Pending::push_now(); } wp_safe_redirect( self::url( 'overview', array( 'pm_msg' => 'rescanned', 'n' => $n, ) ) ); exit; } public static function save_refresh() { self::guard( 'refresh' ); delete_transient( 'postaramail_me' ); delete_transient( 'postaramail_automations' ); self::back( 'overview', 'refreshed' ); } public static function ajax_test() { check_ajax_referer( 'postaramail_test', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Not allowed.', 'postaramail' ) ), 403 ); } $r = PostaraMail_API::me(); if ( ! $r['ok'] ) { $hint = 'plan_required' === $r['code'] ? ' ' . __( 'A manual API key needs the Pro or Scale plan. Use “Connect to PostaraMail” instead: it works on every plan.', 'postaramail' ) : ''; wp_send_json_error( array( 'message' => $r['message'] . $hint ) ); } $d = $r['data']; wp_send_json_success( array( 'workspace' => isset( $d['workspace']['name'] ) ? $d['workspace']['name'] : '', 'plan' => isset( $d['plan']['name'] ) ? $d['plan']['name'] : '', 'subscribers' => isset( $d['plan']['subscribers'] ) ? (int) $d['plan']['subscribers'] : 0, 'limit' => isset( $d['plan']['subscriber_limit'] ) ? (int) $d['plan']['subscriber_limit'] : 0, ) ); } /** Automations for the dropdown (cached for 5 minutes). */ public static function automations() { if ( ! PostaraMail_API::configured() ) { return array(); } $cached = get_transient( 'postaramail_automations' ); if ( is_array( $cached ) ) { return $cached; } $r = PostaraMail_API::automations(); if ( ! $r['ok'] || empty( $r['data']['data'] ) ) { return array(); } set_transient( 'postaramail_automations', $r['data']['data'], 5 * MINUTE_IN_SECONDS ); return $r['data']['data']; } // ---------- Page ---------- private static function message_text( $code ) { $m = array( 'connected' => array( 'ok', __( 'Connected! Now choose what to sync.', 'postaramail' ) ), 'disconnected' => array( 'ok', __( 'Disconnected. This site can no longer add contacts.', 'postaramail' ) ), 'denied' => array( 'warn', __( 'The connection was cancelled on PostaraMail. Press Connect to try again.', 'postaramail' ) ), 'state' => array( 'bad', __( 'That connection link expired or did not start from this site. Press Connect again.', 'postaramail' ) ), 'failed' => array( 'bad', __( 'Could not finish connecting.', 'postaramail' ) . ' ' . (string) get_transient( 'postaramail_connect_error' ) ), 'saved' => array( 'ok', __( 'Saved.', 'postaramail' ) ), 'refreshed' => array( 'ok', __( 'Updated.', 'postaramail' ) ), 'confirm' => array( 'warn', __( 'Saved, but the automatic option needs your confirmation below, so the strict checkbox is used for now.', 'postaramail' ) ), 'key_bad' => array( 'bad', __( 'That does not look like a PostaraMail API key. It starts with pm_live_.', 'postaramail' ) ), 'noconfirm' => array( 'warn', __( 'Nothing was sent. Tick the confirmation box first, or there is nobody left to ask.', 'postaramail' ) ), 'stale' => array( 'warn', __( 'These settings were changed in PostaraMail first, so they were reloaded here. PostaraMail is the master.', 'postaramail' ) ), 'rescanned' => array( 'ok', sprintf( /* translators: %d: number of users */ _n( 'Done. %d user was checked again for a country.', 'Done. %d users were checked again for a country.', isset( $_GET['n'] ) ? absint( $_GET['n'] ) : 0, 'postaramail' ), isset( $_GET['n'] ) ? absint( $_GET['n'] ) : 0 ) ), // phpcs:ignore WordPress.Security.NonceVerification.Recommended 'pushed' => array( 'ok', sprintf( /* translators: %d: number of users */ _n( 'Done. %d waiting user was sent to PostaraMail.', 'Done. %d waiting users were sent to PostaraMail.', isset( $_GET['n'] ) ? absint( $_GET['n'] ) : 0, 'postaramail' ), isset( $_GET['n'] ) ? absint( $_GET['n'] ) : 0 ) ), // phpcs:ignore WordPress.Security.NonceVerification.Recommended 'push_failed' => array( 'bad', __( 'Could not send the waiting users:', 'postaramail' ) . ' ' . ( isset( $_GET['pm_err'] ) ? sanitize_text_field( rawurldecode( wp_unslash( $_GET['pm_err'] ) ) ) : '' ) ), // phpcs:ignore WordPress.Security.NonceVerification.Recommended 'sending' => array( 'ok', __( 'Done. The question email is being sent in the background, about 20 every 15 minutes.', 'postaramail' ) ), ); return isset( $m[ $code ] ) ? $m[ $code ] : null; } public static function page() { if ( ! current_user_can( 'manage_options' ) ) { return; } $connected = PostaraMail_Connect::connected(); $tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'overview'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $tab = isset( self::tabs()[ $tab ] ) ? $tab : 'overview'; $msg = isset( $_GET['pm_msg'] ) ? self::message_text( sanitize_key( wp_unslash( $_GET['pm_msg'] ) ) ) : null; // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( $connected ) { PostaraMail_Sync::maybe_run(); // pick up anything changed in the PostaraMail dashboard } $me = $connected ? PostaraMail_API::me_cached() : null; $info = PostaraMail_Connect::info(); echo '

PostaraMail

'; // Header echo '
'; echo '
'; if ( $connected ) { $ws = ! empty( $me['workspace']['name'] ) ? $me['workspace']['name'] : ( ! empty( $info['workspace'] ) ? $info['workspace'] : '' ); echo '● ' . esc_html__( 'Connected', 'postaramail' ) . ( $ws ? ' · ' . esc_html( $ws ) : '' ) . ''; echo '' . esc_html__( 'Manage in PostaraMail ↗', 'postaramail' ) . ''; if ( ! empty( $me['plan']['name'] ) ) { echo '' . esc_html( $me['plan']['name'] ) . ' ' . esc_html__( 'plan', 'postaramail' ) . ''; } } else { echo '○ ' . esc_html__( 'Not connected', 'postaramail' ) . ''; } echo '
'; $flash = $msg ? '
' . esc_html( $msg[1] ) . '
' : ''; if ( ! $connected && 'advanced' !== $tab ) { echo $flash; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped above. self::render_connect_hero(); echo '
'; return; } // Tabs (kept attached to the dark header), then any message. echo '' . $flash . '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped above. call_user_func( array( __CLASS__, 'tab_' . $tab ), $me ); echo '
'; } // ---------- Not connected ---------- private static function render_connect_hero() { ?>

Start free. Already have one? You will be asked to log in and press Allow.', 'postaramail' ), array( 'a' => array( 'href' => array(), 'target' => array(), 'rel' => array(), ), ) ); ?>

0, 'last' => 0, ) ); $queued = PostaraMail_Queue::count(); $err = get_option( 'postaramail_last_error' ); $done = (bool) get_option( 'postaramail_setup_done' ); $plan = isset( $me['plan'] ) ? $me['plan'] : null; $used = $plan ? (int) $plan['subscribers'] : 0; $limit = $plan ? (int) $plan['subscriber_limit'] : 0; $pct = $limit ? min( 100, (int) round( $used / $limit * 100 ) ) : 0; $full = $limit && $used >= $limit; $upgrade = isset( $me['upgrade_url'] ) ? $me['upgrade_url'] : 'https://postaramail.com/billing'; // Steps echo '
  1. ✓' . esc_html__( 'Connect', 'postaramail' ) . '
  2. '; echo '
  3. ' . ( $done ? '✓' : '2' ) . '' . esc_html__( 'Choose what to sync', 'postaramail' ) . '
  4. '; echo '
  5. ' . ( $done ? '✓' : '3' ) . '' . esc_html__( 'Done', 'postaramail' ) . '
'; if ( $err && ( time() - (int) $err['time'] ) < 7 * DAY_IN_SECONDS ) { echo '
' . esc_html__( 'Last problem:', 'postaramail' ) . ' ' . esc_html( $err['message'] ) . ' (' . esc_html( human_time_diff( (int) $err['time'] ) ) . ' ' . esc_html__( 'ago', 'postaramail' ) . ')
'; } if ( $full ) { echo '

' . esc_html__( 'Your plan is full', 'postaramail' ) . '

' . sprintf( /* translators: 1: used, 2: limit */ esc_html__( 'You have %1$d of %2$d contacts. New signups cannot be added until you upgrade, so they are waiting safely and will be retried.', 'postaramail' ), (int) $used, (int) $limit ) . '

' . esc_html__( 'Upgrade your plan', 'postaramail' ) . '
'; } echo '
'; echo '

' . esc_html__( 'Your contacts', 'postaramail' ) . '

'; if ( $plan ) { echo '

' . (int) $used . ' / ' . (int) $limit . '

'; echo '

' . sprintf( /* translators: %s: plan name */ esc_html__( '%s plan', 'postaramail' ), esc_html( $plan['name'] ) ) . ( ! $full && $pct >= 80 ? ' · ' . esc_html__( 'Upgrade', 'postaramail' ) . '' : '' ) . '

'; } else { echo '

' . esc_html__( 'Could not load your plan right now.', 'postaramail' ) . '

'; } echo '
'; echo '

' . esc_html__( 'From this site', 'postaramail' ) . '

' . (int) $stats['added'] . '

' . esc_html__( 'new contacts added', 'postaramail' ) . '

'; echo '

' . esc_html__( 'Not asked yet', 'postaramail' ) . '

' . (int) PostaraMail_Pending::pending_count() . '

' . esc_html__( 'existing users shown in PostaraMail. Never emailed until they say yes.', 'postaramail' ) . '

'; echo '

' . esc_html__( 'Waiting to retry', 'postaramail' ) . '

' . (int) $queued . '

' . esc_html__( 'Kept safe if PostaraMail is unreachable or your plan is full.', 'postaramail' ) . '

'; echo '
'; // Who is waiting, and why anyone might be missing. $waiting = PostaraMail_Pending::enabled() ? PostaraMail_Pending::waiting_count() : 0; $site = PostaraMail_Pending::site_users(); $total = isset( $site['total_users'] ) ? (int) $site['total_users'] : 0; $bd = PostaraMail_Pending::breakdown(); $cron_last = max( (int) get_option( 'postaramail_cron_last', 0 ), (int) get_option( 'postaramail_sync_cron_last', 0 ) ); echo '

' . esc_html__( 'Users on this site', 'postaramail' ) . '

'; echo '

' . sprintf( /* translators: 1: total users, 2: shown in PostaraMail, 3: waiting */ esc_html__( '%1$d users on this site · %2$d shown in PostaraMail as “not asked yet” · %3$d waiting to be sent', 'postaramail' ), (int) $total, (int) $bd['shown'], (int) $waiting ) . '

'; $why = array(); if ( $bd['yes'] ) { $why[] = sprintf( /* translators: %d: number */ esc_html__( '%d said yes (they are subscribed, not “not asked yet”)', 'postaramail' ), $bd['yes'] ); } if ( $bd['no'] ) { /* translators: %d: number of users */ $why[] = sprintf( esc_html__( '%d said no (shown as Declined)', 'postaramail' ), $bd['no'] ); } if ( $bd['admins'] ) { /* translators: %d: number of users */ $why[] = sprintf( esc_html__( '%d administrators (never listed unless you tick Administrator under Existing users)', 'postaramail' ), $bd['admins'] ); } if ( $bd['role'] ) { /* translators: %d: number of users */ $why[] = sprintf( esc_html__( '%d with a role that is not ticked under Existing users', 'postaramail' ), $bd['role'] ); } if ( $bd['email'] ) { /* translators: %d: number of users */ $why[] = sprintf( esc_html__( '%d without a valid email address', 'postaramail' ), $bd['email'] ); } if ( $why ) { echo '

' . esc_html__( 'The rest of your users:', 'postaramail' ) . '

'; } if ( $bd['checked'] >= 2000 ) { echo '

' . esc_html__( 'The first 2000 users were checked.', 'postaramail' ) . '

'; } if ( $bd['list'] ) { echo '
' . esc_html__( 'Who is not listed, and why', 'postaramail' ) . '
'; if ( $bd['roles'] || $bd['admins'] ) { echo '

' . esc_html__( 'Choose roles', 'postaramail' ) . '

'; } } if ( $waiting > 0 ) { echo '

' . esc_html__( 'New registrations are sent at once. Anyone still waiting is sent every 15 minutes, whenever you open this screen, or now:', 'postaramail' ) . '

'; self::form_open( 'push_now', 'overview' ); echo ''; } if ( ! $cron_last || ( time() - $cron_last ) > 45 * MINUTE_IN_SECONDS ) { echo '

' . esc_html__( 'WordPress background tasks look slow on this site (common with full-page caching). New registrations are still sent at once, and this screen sends anyone waiting. For full reliability ask your host to run this every 5 minutes:', 'postaramail' ) . ' ' . esc_html( 'wget -q -O - ' . site_url( 'wp-cron.php?doing_wp_cron' ) ) . '

'; } echo '
'; echo '

' . esc_html__( 'Countries', 'postaramail' ) . '

'; echo '

' . esc_html__( 'PostaraMail needs each person\'s country to follow the right email rules (for example EU / UK). The plugin uses the WooCommerce country, profile fields and the last login address (turned into a country and then thrown away). Press this to try again for people shown without a country.', 'postaramail' ) . '

'; self::form_open( 'rescan', 'overview' ); echo '
'; echo '

' . esc_html__( 'Quick actions', 'postaramail' ) . '

'; echo '' . esc_html__( 'Sync settings', 'postaramail' ) . ''; echo '' . esc_html__( 'Add a signup form', 'postaramail' ) . ''; echo '' . esc_html__( 'Open PostaraMail', 'postaramail' ) . ''; self::form_open( 'refresh', 'overview' ); echo ''; echo '
'; } // ---------- Sync ---------- private static function mode_radios( $name, $current, $with_notice = true ) { $opts = array( 'off' => __( 'Off', 'postaramail' ) ); if ( $with_notice ) { $opts['notice'] = __( 'Automatic, with a notice (recommended)', 'postaramail' ); } $opts['checkbox'] = __( 'Ask with a tick box (strict, for the EU and UK)', 'postaramail' ); echo '
'; foreach ( $opts as $val => $label ) { echo ''; } echo '
'; } private static function tab_sync( $me ) { $confirmed = (int) get_option( 'postaramail_owner_confirmed', 0 ); $auto = self::automations(); $default = (int) get_option( 'postaramail_default_automation', 0 ); self::form_open( 'sync', 'sync' ); echo '

' . esc_html__( 'New registrations', 'postaramail' ) . '

' . esc_html__( 'People who create an account on your site from now on.', 'postaramail' ) . '

'; self::mode_radios( 'reg_mode', get_option( 'postaramail_reg_mode', 'off' ) ); echo ''; echo '
'; echo '

' . esc_html__( 'WooCommerce customers', 'postaramail' ) . '

'; if ( ! class_exists( 'WooCommerce' ) ) { echo '

' . esc_html__( 'WooCommerce is not active on this site, so this option is not needed.', 'postaramail' ) . '

'; } else { echo '

' . esc_html__( 'Shown at the classic checkout. Block checkout: use a signup form on your thank-you page.', 'postaramail' ) . '

'; self::mode_radios( 'woo_mode', get_option( 'postaramail_woo_mode', 'off' ) ); echo ''; } echo '
'; echo '

' . esc_html__( 'Commenters', 'postaramail' ) . '

'; self::mode_radios( 'comment_mode', get_option( 'postaramail_comment_mode', 'off' ), false ); echo ''; echo '
'; echo '

' . esc_html__( 'Before automatic adding', 'postaramail' ) . '

'; echo '

' . esc_html__( 'Some countries (the EU, UK, Canada, Australia and others) expect people to opt in with a tick box. Automatic adding is only for sites where your privacy policy tells people you email them.', 'postaramail' ) . '

'; if ( $confirmed ) { echo '

✓ ' . sprintf( /* translators: %s: date */ esc_html__( 'You confirmed this on %s.', 'postaramail' ), esc_html( wp_date( get_option( 'date_format' ) ? get_option( 'date_format' ) : 'F j, Y', $confirmed ) ) ) . '

'; } echo '
'; echo '

' . esc_html__( 'After someone is added', 'postaramail' ) . '

'; echo ''; echo '

' . esc_html__( 'The automation must be switched on in PostaraMail.', 'postaramail' ) . '

'; echo '
'; } // ---------- Forms ---------- private static function tab_forms( $me ) { self::form_open( 'forms', 'forms' ); echo '

' . esc_html__( 'Add a signup form', 'postaramail' ) . '

'; echo '

' . esc_html__( 'Use the block “PostaraMail Signup Form” in the editor, or paste this shortcode into any page or post:', 'postaramail' ) . '

'; echo '
[postaramail_form]
'; echo '

' . esc_html__( 'Options:', 'postaramail' ) . ' title="Join the list" button="Subscribe" name="no" automation="12" color="#ff6a0d"

'; echo '

' . esc_html__( 'Wording', 'postaramail' ) . '

'; echo ''; echo ''; echo '

' . esc_html__( 'The form always asks for consent. Your privacy policy link is added automatically when your site has one.', 'postaramail' ) . '

'; echo '
'; echo '
'; echo '

' . esc_html__( 'What visitors see', 'postaramail' ) . '

'; echo PostaraMail_Form::render( array_merge( PostaraMail_Form::defaults(), array( 'title' => __( 'Join our list', 'postaramail' ) ) ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped inside render(). echo '
'; } // ---------- Existing users ---------- private static function tab_existing( $me ) { $c = PostaraMail_Existing::counts(); $roles = PostaraMail_Existing::roles(); self::form_open( 'existing', 'existing' ); echo '

' . esc_html__( 'People who already have an account', 'postaramail' ) . '

'; echo '

' . esc_html__( 'These people are never added silently. They are only added when they say “yes”.', 'postaramail' ) . '

'; echo '
' . (int) $c['yes'] . '' . esc_html__( 'said yes', 'postaramail' ) . '
' . (int) $c['no'] . '' . esc_html__( 'said no', 'postaramail' ) . '
' . (int) $c['pending'] . '' . esc_html__( 'not asked yet', 'postaramail' ) . '
'; echo '

' . esc_html__( 'Show them in PostaraMail', 'postaramail' ) . '

'; echo '
'; echo '

' . esc_html__( '1. Ask when they log in', 'postaramail' ) . '

'; echo ''; echo '

' . esc_html__( 'Ask these roles', 'postaramail' ) . '

'; foreach ( wp_roles()->roles as $slug => $role ) { echo ''; } echo '
'; echo '

' . esc_html__( '2. Send one “Want to stay in touch?” email', 'postaramail' ) . '

'; if ( $c['queued'] ) { echo '

' . sprintf( /* translators: %d: number */ esc_html__( 'Sending now: %d emails still to go (about 20 every 15 minutes).', 'postaramail' ), (int) $c['queued'] ) . '

'; } echo '

' . esc_html__( 'Each person gets this once, ever, from your own site, with a Yes and a No link. If they do nothing they are not added and not asked again.', 'postaramail' ) . '

'; self::form_open( 'send_existing', 'existing' ); echo ''; echo '
'; } // ---------- Advanced ---------- private static function tab_advanced( $me ) { $connected = PostaraMail_Connect::connected(); $info = PostaraMail_Connect::info(); $key = PostaraMail_API::key(); $masked = $connected ? substr( $key, 0, 8 ) . '••••••••' . substr( $key, -4 ) : ''; if ( $connected ) { echo '

' . esc_html__( 'Connection', 'postaramail' ) . '

' . ( isset( $info['via'] ) && 'connect' === $info['via'] ? esc_html__( 'Connected with one click. This site can add contacts and read your automations, nothing else.', 'postaramail' ) : esc_html__( 'Connected with an API key.', 'postaramail' ) ) . '

'; echo '
'; echo '
' . wp_nonce_field( 'postaramail_disconnect', '_wpnonce', true, false ) . '

'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_nonce_field() returns safe HTML. } self::form_open( 'advanced', 'advanced' ); echo '

' . esc_html__( 'Use an API key instead', 'postaramail' ) . '

' . esc_html__( 'Only needed if one-click connect does not suit you. Create a key in PostaraMail under Settings → API keys (Pro and Scale plans).', 'postaramail' ) . '

'; echo '

' . esc_html__( 'Leave blank to keep the current key.', 'postaramail' ) . '

'; echo '

' . esc_html__( 'Leave blank unless support tells you otherwise. Must start with https://', 'postaramail' ) . '

'; echo '
'; } }