ID, '_aettaec_name', true);
$subscriber_email = get_post_meta($post->ID, '_aettaec_email', true);
$ip_address = get_post_meta($post->ID, '_aettaec_ip', true);
$created_at = get_post_meta($post->ID, '_aettaec_created_gmt', true);
$has_consent = (int)get_post_meta($post->ID, '_aettaec_consent', true);
$source_url = get_post_meta($post->ID, '_aettaec_source_url', true);
$source_ref = get_post_meta($post->ID, '_aettaec_source_ref', true);
$user_agent = get_post_meta($post->ID, '_aettaec_ua', true);
echo '
';
}
public static function define_signup_columns($columns)
{
$custom_columns = [];
$custom_columns['cb'] = $columns['cb'];
$custom_columns['title'] = __('Email', 'aetta-email-capture');
$custom_columns['aettaec_name'] = __('Name', 'aetta-email-capture');
$custom_columns['aettaec_created'] = __('Created', 'aetta-email-capture');
$custom_columns['aettaec_source'] = __('Source', 'aetta-email-capture');
$custom_columns['aettaec_consent'] = __('Consent', 'aetta-email-capture');
return $custom_columns;
}
public static function render_signup_column_content($column_name, $post_id)
{
if ($column_name === 'aettaec_name') echo esc_html(get_post_meta($post_id, '_aettaec_name', true));
if ($column_name === 'aettaec_created') echo esc_html(get_post_meta($post_id, '_aettaec_created_gmt', true));
if ($column_name === 'aettaec_source') echo esc_html(get_post_meta($post_id, '_aettaec_source_url', true));
if ($column_name === 'aettaec_consent') echo (get_post_meta($post_id, '_aettaec_consent', true) ? esc_html__('Yes', 'aetta-email-capture') : esc_html__('No', 'aetta-email-capture'));
}
public static function register_admin_menu_pages()
{
$base_slug = 'edit.php?post_type=' . AETTAEC_CPT::POST_TYPE;
add_submenu_page($base_slug, __('Settings', 'aetta-email-capture'), __('Settings', 'aetta-email-capture'), 'manage_options', 'aettaec-settings', [__CLASS__, 'render_settings_page']);
add_submenu_page($base_slug, __('Export CSV', 'aetta-email-capture'), __('Export CSV', 'aetta-email-capture'), 'manage_options', 'aettaec-export', [__CLASS__, 'render_export_page']);
add_submenu_page($base_slug, __('Maintenance', 'aetta-email-capture'), __('Maintenance', 'aetta-email-capture'), 'manage_options', 'aettaec-maintenance', [__CLASS__, 'render_maintenance_page']);
}
public static function register_plugin_settings()
{
register_setting('aettaec_settings', 'aettaec_options', [
'type' => 'array',
'sanitize_callback' => [__CLASS__, 'sanitize_plugin_options'],
'default' => AETTAEC_Plugin::get_plugin_options(),
]);
}
private static function validate_hex_color($color_value, $fallback_color)
{
$clean_value = trim((string)$color_value);
if ($clean_value === '') return $fallback_color;
if (!preg_match('/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/', $clean_value)) return $fallback_color;
return strtolower($clean_value);
}
public static function sanitize_plugin_options($input)
{
$current_options = AETTAEC_Plugin::get_plugin_options();
$current_options['retention_days'] = max(1, (int)($input['retention_days'] ?? $current_options['retention_days']));
$current_options['min_submit_seconds'] = max(0, (int)($input['min_submit_seconds'] ?? $current_options['min_submit_seconds']));
$current_options['consent_required'] = !empty($input['consent_required']) ? 1 : 0;
$current_options['use_css'] = !empty($input['use_css']) ? 1 : 0;
$current_options['consent_label'] = sanitize_text_field($input['consent_label'] ?? $current_options['consent_label']);
$current_options['success_message'] = sanitize_text_field($input['success_message'] ?? $current_options['success_message']);
$current_options['error_invalid'] = sanitize_text_field($input['error_invalid'] ?? $current_options['error_invalid']);
$current_options['error_wait'] = sanitize_text_field($input['error_wait'] ?? $current_options['error_wait']);
$current_options['error_required'] = sanitize_text_field($input['error_required'] ?? $current_options['error_required']);
$current_options['error_consent'] = sanitize_text_field($input['error_consent'] ?? $current_options['error_consent']);
$current_options['button_label'] = sanitize_text_field($input['button_label'] ?? $current_options['button_label']);
$current_options['name_label'] = sanitize_text_field($input['name_label'] ?? $current_options['name_label']);
$current_options['email_label'] = sanitize_text_field($input['email_label'] ?? $current_options['email_label']);
$current_options['name_placeholder'] = sanitize_text_field($input['name_placeholder'] ?? $current_options['name_placeholder']);
$current_options['email_placeholder'] = sanitize_text_field($input['email_placeholder'] ?? $current_options['email_placeholder']);
$current_options['ui_border_color'] = self::validate_hex_color($input['ui_border_color'] ?? $current_options['ui_border_color'], $current_options['ui_border_color']);
$current_options['ui_button_bg'] = self::validate_hex_color($input['ui_button_bg'] ?? $current_options['ui_button_bg'], $current_options['ui_button_bg']);
$current_options['ui_button_text'] = self::validate_hex_color($input['ui_button_text'] ?? $current_options['ui_button_text'], $current_options['ui_button_text']);
$current_options['ui_success_border'] = self::validate_hex_color($input['ui_success_border'] ?? $current_options['ui_success_border'], $current_options['ui_success_border']);
$current_options['ui_error_border'] = self::validate_hex_color($input['ui_error_border'] ?? $current_options['ui_error_border'], $current_options['ui_error_border']);
$current_options['ui_border_width'] = min(10, max(0, (int)($input['ui_border_width'] ?? $current_options['ui_border_width'])));
$current_options['ui_radius'] = min(60, max(0, (int)($input['ui_radius'] ?? $current_options['ui_radius'])));
$current_options['ui_input_height'] = min(80, max(30, (int)($input['ui_input_height'] ?? $current_options['ui_input_height'])));
return $current_options;
}
public static function render_settings_page()
{
if (!current_user_can('manage_options')) wp_die(esc_html__('Unauthorized', 'aetta-email-capture'));
$options = AETTAEC_Plugin::get_plugin_options();
echo '' . esc_html__('Aetta Email Capture — Settings', 'aetta-email-capture') . '
';
echo '
';
}
public static function render_export_page()
{
if (!current_user_can('manage_options')) wp_die(esc_html__('Unauthorized', 'aetta-email-capture'));
$export_url = wp_nonce_url(admin_url('admin-post.php?action=aettaec_export_csv'), 'aettaec_export_csv');
echo '';
}
public static function process_csv_export()
{
if (!current_user_can('manage_options')) wp_die(esc_html__('Unauthorized', 'aetta-email-capture'));
check_admin_referer('aettaec_export_csv');
$signups = new WP_Query([
'post_type' => AETTAEC_CPT::POST_TYPE,
'post_status' => 'any',
'posts_per_page' => -1,
'fields' => 'ids',
]);
nocache_headers();
header('Content-Type: text/csv; charset=utf-8');
header('X-Content-Type-Options: nosniff');
header('Content-Disposition: attachment; filename=aetta-email-capture-' . gmdate('Ymd') . '.csv');
$stream = fopen('php://output', 'w');
fputcsv($stream, ['Name', 'Email', 'Created (GMT)', 'Source URL', 'Referrer', 'Consent', 'IP', 'User Agent']);
foreach ($signups->posts as $signup_id) {
fputcsv($stream, [
get_post_meta($signup_id, '_aettaec_name', true),
get_post_meta($signup_id, '_aettaec_email', true),
get_post_meta($signup_id, '_aettaec_created_gmt', true),
get_post_meta($signup_id, '_aettaec_source_url', true),
get_post_meta($signup_id, '_aettaec_source_ref', true),
get_post_meta($signup_id, '_aettaec_consent', true) ? 'yes' : 'no',
get_post_meta($signup_id, '_aettaec_ip', true),
get_post_meta($signup_id, '_aettaec_ua', true),
]);
}
exit;
}
public static function render_maintenance_page()
{
if (!current_user_can('manage_options')) wp_die(esc_html__('Unauthorized', 'aetta-email-capture'));
if (isset($_POST['aettaec_purge_now'])) {
check_admin_referer('aettaec_purge_now');
AETTAEC_CPT::execute_daily_purge();
echo '' . esc_html__('Purge completed.', 'aetta-email-capture') . '
';
}
$options = AETTAEC_Plugin::get_plugin_options();
$entry_counts = wp_count_posts(AETTAEC_CPT::POST_TYPE);
echo '' . esc_html__('Maintenance', 'aetta-email-capture') . '
';
echo '
' . esc_html__('Purges signups older than', 'aetta-email-capture') . ' ' . (int)$options['retention_days'] . ' ' . esc_html__('days.', 'aetta-email-capture') . '
';
echo '
' . esc_html__('Totals', 'aetta-email-capture') . ' — ' . esc_html__('Private', 'aetta-email-capture') . ': ' . (int)($entry_counts->private ?? 0) . '
';
echo '
';
}
public static function add_privacy_policy_information()
{
if (!function_exists('wp_add_privacy_policy_content')) return;
$policy_text = '' . esc_html__('Aetta Email Capture stores the data you submit through its signup form.', 'aetta-email-capture') . '
';
$policy_text .= '' . esc_html__('Stored fields include name and email. Optionally, the site administrator can enable storing IP address and user agent.', 'aetta-email-capture') . '
';
wp_add_privacy_policy_content(__('Aetta Email Capture', 'aetta-email-capture'), wp_kses_post($policy_text));
}
public static function register_privacy_exporter($exporters)
{
$exporters['aetta-email-capture'] = [
'exporter_friendly_name' => __('Aetta Email Capture', 'aetta-email-capture'),
'callback' => [__CLASS__, 'execute_privacy_export'],
];
return $exporters;
}
private static function fetch_signup_ids_by_email($email_address, $page, $per_page, &$max_pages)
{
$query_args = [
'post_type' => AETTAEC_CPT::POST_TYPE,
'post_status' => 'any',
'posts_per_page' => (int)$per_page,
'paged' => (int)$page,
'fields' => 'ids',
'no_found_rows' => false,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'meta_query' => [
[
'key' => '_aettaec_email',
'value' => sanitize_email($email_address),
'compare' => '='
]
]
];
$query = new WP_Query($query_args);
$max_pages = $query->max_num_pages;
return $query->posts;
}
public static function execute_privacy_export($email_address, $page = 1)
{
$page = max(1, (int)$page);
$per_page = 50;
$max_pages = 0;
$signup_ids = self::fetch_signup_ids_by_email($email_address, $page, $per_page, $max_pages);
$export_data = [];
foreach ($signup_ids as $signup_id) {
$signup_id = (int)$signup_id;
$items = [
['name' => 'name', 'value' => (string)get_post_meta($signup_id, '_aettaec_name', true)],
['name' => 'email', 'value' => (string)get_post_meta($signup_id, '_aettaec_email', true)],
['name' => 'created_gmt', 'value' => (string)get_post_meta($signup_id, '_aettaec_created_gmt', true)],
];
$export_data[] = [
'group_id' => 'aetta-email-capture',
'group_label' => __('Aetta Email Capture', 'aetta-email-capture'),
'item_id' => 'aettaec-' . $signup_id,
'data' => $items,
];
}
return [
'data' => $export_data,
'done' => ($max_pages === 0 || $page >= $max_pages),
];
}
public static function register_privacy_eraser($erasers)
{
$erasers['aetta-email-capture'] = [
'eraser_friendly_name' => __('Aetta Email Capture', 'aetta-email-capture'),
'callback' => [__CLASS__, 'execute_privacy_erasure'],
];
return $erasers;
}
public static function execute_privacy_erasure($email_address, $page = 1)
{
$page = max(1, (int)$page);
$per_page = 50;
$max_pages = 0;
$signup_ids = self::fetch_signup_ids_by_email($email_address, $page, $per_page, $max_pages);
$removed = false;
foreach ($signup_ids as $signup_id) {
wp_delete_post((int)$signup_id, true);
$removed = true;
}
return [
'items_removed' => $removed,
'items_retained' => false,
'messages' => [],
'done' => ($max_pages === 0 || $page >= $max_pages),
];
}
}