self::SLUG, 'tab' => $tab, ), $args ), admin_url( 'admin.php' ) ); } public static function menus() { add_submenu_page( 'edit.php?post_type=accessible_form', __( 'Tools & guidance', 'accessible-forms-by-accessible-org' ), __( 'Tools & guidance', 'accessible-forms-by-accessible-org' ), 'edit_accessible_forms', self::SLUG, array( self::class, 'render' ) ); if ( current_user_can( 'read_accessible_form_entries' ) && ! current_user_can( 'edit_accessible_forms' ) ) { add_menu_page( __( 'Submissions', 'accessible-forms-by-accessible-org' ), __( 'Submissions', 'accessible-forms-by-accessible-org' ), 'read_accessible_form_entries', EntriesTable::SLUG, array( EntriesTable::class, 'render_page' ), 'dashicons-feedback', 26 ); } } public static function form_start( $operation, array $hidden = array() ) { echo '
'; echo ''; wp_referer_field(); foreach ( $hidden as $key => $value ) { echo ''; } } /** Native buttons on screens containing several independent tool forms. */ public static function submit( $text = null, $type = 'primary', $name = 'submit', $wrap = true ) { // Match WordPress button classes, using a button whose caption can wrap. $types = is_array( $type ) ? $type : explode( ' ', $type ); $classes = array( 'button' ); foreach ( $types as $variant ) { if ( in_array( $variant, array( 'secondary', 'button-secondary' ), true ) ) { continue; } $classes[] = in_array( $variant, array( 'primary', 'small', 'large', 'compact' ), true ) ? 'button-' . $variant : $variant; } $text = $text ?: __( 'Save Changes', 'accessible-forms-by-accessible-org' ); if ( $wrap ) { echo '

'; } echo ''; if ( $wrap ) { echo '

'; } } public static function fail( $message ) { wp_die( esc_html( $message ), '', array( 'back_link' => true, 'response' => 400, ) ); } public static function action() { check_admin_referer( 'accessible_forms_tools' ); $operation = sanitize_key( wp_unslash( $_POST['operation'] ?? '' ) ); $settings_ops = array( 'diagnostics', 'run_queue', 'purge', 'test_mode', 'time_migrate_start', 'time_migrate_batch', ); if ( ! current_user_can( in_array( $operation, $settings_ops, true ) ? 'manage_accessible_forms_settings' : 'edit_accessible_forms' ) ) { self::fail( __( 'You do not have permission to use this tool.', 'accessible-forms-by-accessible-org' ) ); } if ( Transfer::handles( $operation ) ) { Transfer::action( $operation ); } switch ( $operation ) { case 'time_migrate_start': $result = \AccessibleForms\TimeMigration::start( sanitize_text_field( wp_unslash( $_POST['original_zone'] ?? '' ) ), sanitize_key( wp_unslash( $_POST['repeated_hour'] ?? '' ) ), ! empty( $_POST['confirm_zone'] ), absint( $_POST['form_id'] ?? 0 ) ); if ( is_wp_error( $result ) ) { self::fail( $result->get_error_message() ); } wp_safe_redirect( self::url( 'health', array( 'updated' => 1 ) ) ); exit(); case 'time_migrate_batch': $processed = \AccessibleForms\TimeMigration::batch(); if ( ! $processed && 'running' === ( get_option( \AccessibleForms\TimeMigration::OPTION )['status'] ?? '' ) ) { self::fail( __( 'This date batch could not finish. Historical dates and progress were kept. Try again shortly.', 'accessible-forms-by-accessible-org' ) ); } wp_safe_redirect( self::url( 'health', array( 'updated' => 1 ) ) ); exit(); case 'template': $key = sanitize_key( wp_unslash( $_POST['template'] ?? '' ) ); // Add-ons may offer templates of their own, such as saved ones. $schema = FormLibrary::template( $key ) ?: Extensions::filter( 'accessible_forms_template_schema', null, $key ); if ( ! is_array( $schema ) || ! $schema ) { self::fail( __( 'Template not found.', 'accessible-forms-by-accessible-org' ) ); } $schema['recipients'] = array( sanitize_email( wp_unslash( $_POST['recipient'] ?? '' ) ) ); $id = FormLibrary::create( $schema, $schema['heading'] ); if ( is_wp_error( $id ) ) { self::fail( $id->get_error_message() ); } wp_safe_redirect( get_edit_post_link( $id, 'raw' ) ); exit(); case 'diagnostics': nocache_headers(); header( 'Content-Type: application/json; charset=utf-8' ); header( 'Content-Disposition: attachment; filename="accessible-forms-diagnostics.json"' ); echo wp_json_encode( Health::report(), JSON_PRETTY_PRINT ); exit(); case 'run_queue': Notifications::run(); wp_safe_redirect( self::url( 'health', array( 'updated' => 1 ) ) ); exit(); case 'purge': Entries::purge(); wp_safe_redirect( self::url( 'health', array( 'updated' => 1 ) ) ); exit(); case 'test_mode': $settings = Settings::get(); $settings['test_delivery'] = ! empty( $_POST['test_delivery'] ); $settings['test_recipient'] = sanitize_email( wp_unslash( $_POST['test_recipient'] ?? '' ) ); if ( $settings['test_delivery'] && ! is_email( $settings['test_recipient'] ) ) { self::fail( __( 'Provide a valid test inbox.', 'accessible-forms-by-accessible-org' ) ); } // Retention has one editing home in Privacy. Saving test delivery // must preserve that policy, including from an older open Health tab. Settings::update( $settings ); Audit::record( 'delivery_mode_changed' ); wp_safe_redirect( self::url( 'health', array( 'updated' => 1 ) ) ); exit(); default: // Add-on tools check their own capability, then redirect and exit. Extensions::notify( 'accessible_forms_tools_action', $operation ); self::fail( __( 'Unknown action.', 'accessible-forms-by-accessible-org' ) ); } wp_safe_redirect( self::url( 'templates', array( 'updated' => 1 ) ) ); exit(); } public static function render() { if ( ! current_user_can( 'edit_accessible_forms' ) ) { self::fail( __( 'You cannot use these form tools.', 'accessible-forms-by-accessible-org' ) ); } $tabs = array( 'templates' => __( 'Templates', 'accessible-forms-by-accessible-org' ), Transfer::TAB => Transfer::label(), 'usage' => __( 'Used on', 'accessible-forms-by-accessible-org' ), 'guide' => __( 'Guide', 'accessible-forms-by-accessible-org' ), ); if ( current_user_can( 'manage_accessible_forms_settings' ) ) { $tabs += array( 'health' => __( 'Health', 'accessible-forms-by-accessible-org' ), 'activity' => __( 'Activity', 'accessible-forms-by-accessible-org' ), ); } // Add-ons add tabs, checking their own capability before listing one. $tabs = (array) Extensions::filter( 'accessible_forms_tools_tabs', $tabs ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only screen selection; every action verifies a POST nonce and capability. $tab = sanitize_key( wp_unslash( $_GET['tab'] ?? 'templates' ) ); if ( ! isset( $tabs[ $tab ] ) ) { $tab = 'templates'; } $async_tabs = (array) Extensions::filter( 'accessible_forms_async_tabs', array_merge( self::CORE_TABS, array( Transfer::TAB ) ), 'tools' ); echo '

' . esc_html__( 'Tools & guidance', 'accessible-forms-by-accessible-org' ) . '

'; self::render_panel( $tab, $tabs, true ); foreach ( array_intersect( array( 'templates', 'guide' ), array_keys( $tabs ), $async_tabs ) as $key ) { if ( $key !== $tab ) { Navigation::preload( self::url( $key ), static function () use ( $key, $tabs ) { self::render_panel( $key, $tabs ); } ); } } echo '
'; } /** Static guidance is prepared once; usage, health and activity keep server reads. */ private static function render_panel( $tab, array $tabs, $show_notice = false ) { echo '

' . esc_html( $tabs[ $tab ] ) . '

'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only screen selection; every action verifies a POST nonce and capability. if ( $show_notice && isset( $_GET['updated'] ) ) { echo '

' . esc_html__( 'Changes saved.', 'accessible-forms-by-accessible-org' ) . '

'; } if ( in_array( $tab, self::CORE_TABS, true ) ) { self::{$tab}(); } elseif ( Transfer::TAB === $tab ) { Transfer::render(); } else { Extensions::notify( 'accessible_forms_tools_tab', $tab ); } echo '
'; } private static function templates() { echo '

' . esc_html__( 'Start with a useful set of accessible fields. Each template creates an independent draft; review it before publishing.', 'accessible-forms-by-accessible-org' ) . '

'; $templates = (array) Extensions::filter( 'accessible_forms_template_choices', FormLibrary::templates() ); self::form_start( 'template' ); Editor::select( 'template', __( 'Starting template', 'accessible-forms-by-accessible-org' ), $templates, 'contact' ); Editor::input( 'recipient', __( 'Notification recipient', 'accessible-forms-by-accessible-org' ), get_option( 'admin_email' ), 'email', __( 'Confirm who should receive this form’s enquiries.', 'accessible-forms-by-accessible-org' ), array( 'required' => 'required' ) ); self::submit( __( 'Create draft form', 'accessible-forms-by-accessible-org' ) ); echo '
'; // Add-ons add their own template tools, such as saving a form as a template. Extensions::notify( 'accessible_forms_templates_tab' ); } public static function form_picker( $selected = 0, $mode = 'edit', $empty_label = '' ) { $identity = wp_unique_id( 'af-form-picker-' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only catalog pagination; actions verify their own nonce. $number = max( 1, absint( $_GET['af_form_page'] ?? 1 ) ); $page = \AccessibleForms\FormCatalog::admin_options( '', $number, $mode ); $options = array( '' => $empty_label ?: __( 'Choose a form', 'accessible-forms-by-accessible-org' ) ); foreach ( $page['items'] as $item ) { $options[ $item['id'] ] = $item['label']; } $post = $selected ? get_post( $selected ) : null; if ( $post && 'accessible_form' === $post->post_type && ( 'entries' === $mode ? Capabilities::form( $selected ) : current_user_can( 'edit_post', $selected ) ) ) { $options[ $selected ] = ( $post->post_title ?: __( '(no title)', 'accessible-forms-by-accessible-org' ) ) . ' (#' . $selected . ')'; } echo '
'; Editor::select( 'form_id', __( 'Form', 'accessible-forms-by-accessible-org' ), $options, $selected, $identity . '-select' ); echo ''; echo '
'; } private static function usage() { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only screen selection; every action verifies a POST nonce and capability. $id = absint( $_GET['form_id'] ?? 0 ); echo '
'; self::form_picker( $id ); self::submit( __( 'Find placements', 'accessible-forms-by-accessible-org' ), 'secondary' ); echo '

' . esc_html__( 'Checks stored pages, posts, public custom content, synced patterns and saved templates, including nested blocks. Theme files, widgets and third-party builder data may need separate inspection.', 'accessible-forms-by-accessible-org' ) . '

'; if ( ! $id || ! current_user_can( 'edit_post', $id ) ) { return; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only screen selection; every action verifies a POST nonce and capability. $page = max( 1, absint( $_GET['scan_page'] ?? 1 ) ); // Add-ons report placement that does not live in content, such as automatic rules. Extensions::notify( 'accessible_forms_usage_summary', $id ); $scan = Placement::scan_batch( $id, $page ); echo ''; if ( ! $found ) { echo '

' . esc_html__( 'No placements in this batch of content.', 'accessible-forms-by-accessible-org' ) . '

'; } if ( $page > 1 ) { echo '' . esc_html__( 'Previous batch', 'accessible-forms-by-accessible-org' ) . ' '; } if ( $page < $scan['pages'] ) { echo '' . esc_html__( 'Check next 100 items', 'accessible-forms-by-accessible-org' ) . ''; } } /** Forms that do not meet the accessibility checks, with a link to fix each. */ private static function accessibility_checks() { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only audit pagination. $page = max( 1, absint( $_GET['check_page'] ?? 1 ) ); $counts = wp_count_posts( 'accessible_form' ); $total = 0; foreach ( array( 'publish', 'draft', 'pending', 'private', 'future' ) as $status ) { $total += (int) ( $counts->$status ?? 0 ); } $pages = max( 1, (int) ceil( $total / 200 ) ); $page = min( $page, $pages ); $forms = \AccessibleForms\FormCheck::forms( 200, $page ); echo '

' . esc_html__( 'Form accessibility checks', 'accessible-forms-by-accessible-org' ) . '

'; echo '

' . esc_html( sprintf( /* translators: 1: batch number, 2: number of batches. */ __( 'Reviewing batch %1$d of %2$d, up to 200 forms per batch.', 'accessible-forms-by-accessible-org' ), $page, $pages ) ) . '

'; if ( $page > 1 ) { echo '' . esc_html__( 'Previous batch', 'accessible-forms-by-accessible-org' ) . ' '; } if ( $page < $pages ) { echo '' . esc_html__( 'Check next batch', 'accessible-forms-by-accessible-org' ) . ''; } if ( ! $forms ) { echo '

' . esc_html__( 'The forms in this batch meet the current configuration checks. Check the published pages and complete the manual accessibility review as well.', 'accessible-forms-by-accessible-org' ) . '

'; return; } echo ''; foreach ( $forms as $id => $form ) { $title = get_the_title( $id ) ?: __( '(no title)', 'accessible-forms-by-accessible-org' ); echo ''; } echo '
' . esc_html__( 'Form', 'accessible-forms-by-accessible-org' ) . '' . esc_html__( 'Published version', 'accessible-forms-by-accessible-org' ) . '' . esc_html__( 'Unpublished edits', 'accessible-forms-by-accessible-org' ) . '
' . ( current_user_can( 'edit_post', $id ) ? '' . esc_html( $title ) . '' : esc_html( $title ) ) . '' . esc_html( $form['live'] /* translators: %s: number of problems. */ ? sprintf( _n( '%s problem, shown to visitors', '%s problems, shown to visitors', $form['live'], 'accessible-forms-by-accessible-org' ), number_format_i18n( $form['live'] ) ) : __( 'Meets the checks', 'accessible-forms-by-accessible-org' ) ) . '' . esc_html( $form['pending'] ? __( 'Saved with problems; not published', 'accessible-forms-by-accessible-org' ) : __( 'None', 'accessible-forms-by-accessible-org' ) ) . '
'; } private static function health() { $report = Health::report(); echo ''; $rows = array( __( 'Storage', 'accessible-forms-by-accessible-org' ) => $report['storage'] ? __( 'Available', 'accessible-forms-by-accessible-org' ) : __( 'Needs attention: reactivate to repair tables', 'accessible-forms-by-accessible-org' ), __( 'Pending notifications', 'accessible-forms-by-accessible-org' ) => $report['notifications']['pending'], __( 'Failed notifications', 'accessible-forms-by-accessible-org' ) => $report['notifications']['failed'], __( 'Uncertain delivery', 'accessible-forms-by-accessible-org' ) => $report['notifications']['uncertain'], __( 'Retention scheduled', 'accessible-forms-by-accessible-org' ) => $report['cleanup_next'] ? wp_date( 'Y-m-d H:i', $report['cleanup_next'] ) : __( 'Not scheduled', 'accessible-forms-by-accessible-org' ), __( 'Last cleanup', 'accessible-forms-by-accessible-org' ) => $report['cleanup_last'] ? wp_date( 'Y-m-d H:i', $report['cleanup_last'] ) : __( 'Not run yet', 'accessible-forms-by-accessible-org' ), __( 'Verification', 'accessible-forms-by-accessible-org' ) => $report['spam_provider'] . ( $report['verification_ready'] ? '' : ': ' . __( 'Add the provider keys in Settings', 'accessible-forms-by-accessible-org' ) ) . ( $report['verification_secure'] ? '' : ': ' . __( 'Needs HTTPS: browsers cannot run the automatic check on this site address, so every message is held for review', 'accessible-forms-by-accessible-org' ) ), __( 'Oldest pending notification (UTC)', 'accessible-forms-by-accessible-org' ) => $report['oldest_pending'] ?: __( 'None', 'accessible-forms-by-accessible-org' ), __( 'Environment', 'accessible-forms-by-accessible-org' ) => $report['environment'], ); foreach ( $rows as $label => $value ) { echo ''; } echo '
' . esc_html( $label ) . '' . esc_html( (string) $value ) . '
'; foreach ( array( 'run_queue' => __( 'Process pending notifications', 'accessible-forms-by-accessible-org' ), 'purge' => __( 'Run due retention cleanup', 'accessible-forms-by-accessible-org' ), 'diagnostics' => __( 'Download diagnostics', 'accessible-forms-by-accessible-org' ), ) as $action => $label ) { self::form_start( $action ); self::submit( $label, 'secondary' ); echo ''; } echo '
'; self::historical_dates( $report ); self::accessibility_checks(); \AccessibleForms\LiveCheck::render_health_table(); $settings = Settings::get(); self::form_start( 'test_mode' ); echo '

' . esc_html__( 'Test email delivery', 'accessible-forms-by-accessible-org' ) . '

'; Editor::check( 'test_delivery', __( 'Send all plugin notification emails to a test inbox', 'accessible-forms-by-accessible-org' ), $settings['test_delivery'] ?? false ); Editor::input( 'test_recipient', __( 'Test inbox', 'accessible-forms-by-accessible-org' ), $settings['test_recipient'] ?? '', 'email', __( 'Original To, Cc and Bcc destinations are replaced. Use this on staging.', 'accessible-forms-by-accessible-org' ) ); self::submit( __( 'Save test delivery', 'accessible-forms-by-accessible-org' ) ); echo ''; $days = Settings::spam_retention_days( $settings['spam_retention_days'] ?? 30 ); echo '

' . esc_html__( 'Retention', 'accessible-forms-by-accessible-org' ) . '

' . esc_html( sprintf( /* translators: %s: maximum number of days to keep spam and review entries. */ _n( 'Spam and review items are deleted after %s day, or sooner if their form retention expires first.', 'Spam and review items are deleted after %s days, or sooner if their form retention expires first.', $days, 'accessible-forms-by-accessible-org' ), number_format_i18n( $days ) ) ) . '

' . esc_html__( 'Change retention in Privacy settings', 'accessible-forms-by-accessible-org' ) . '

'; } /** Only shown to settings administrators when historical dates need attention. */ private static function historical_dates( array $report ) { $state = get_option( \AccessibleForms\TimeMigration::OPTION, array() ); $pending = $report['historical_dates'] ?? 0; if ( ! $pending && ! $state ) { return; } echo '
' . esc_html__( 'Historical entry dates', 'accessible-forms-by-accessible-org' ) . ''; echo '

' . esc_html( sprintf( /* translators: %s: number of entries with unconfirmed dates. */ __( '%s entries have historical dates whose original time zone is unconfirmed.', 'accessible-forms-by-accessible-org' ), number_format_i18n( $pending ) ) ) . '

'; echo '

' . esc_html__( 'New submissions use UTC and display in your site time zone. Historical dates keep their original values until you confirm where they came from. Unconfirmed dates are excluded from response-time statistics and date-based cleanup; existing expiry dates still apply.', 'accessible-forms-by-accessible-org' ) . '

'; if ( 'running' === ( $state['status'] ?? '' ) ) { echo '

' . esc_html__( 'Conversion is running in small background batches. You can also process the next batch here.', 'accessible-forms-by-accessible-org' ) . '

'; self::form_start( 'time_migrate_batch' ); self::submit( __( 'Process next date batch', 'accessible-forms-by-accessible-org' ), 'secondary' ); echo ''; } elseif ( $pending ) { self::form_start( 'time_migrate_start' ); self::form_picker( 0, 'entries', __( 'All forms', 'accessible-forms-by-accessible-org' ) ); $selected_zone = wp_timezone_string(); if ( preg_match( '/^([+-])(\d{2}):(\d{2})$/D', $selected_zone, $offset ) ) { $selected_zone = 'UTC' . $offset[1] . ( (int) $offset[2] + (int) $offset[3] / 60 ); } echo '


'; echo '

' . esc_html__( 'Use the time zone in effect when these records were created. If it changed, process each form separately only when its original zone is known. Keep unknown records unchanged.', 'accessible-forms-by-accessible-org' ) . '

'; Editor::select( 'repeated_hour', __( 'Dates during a repeated daylight-saving hour', 'accessible-forms-by-accessible-org' ), array( 'preserve' => __( 'Keep these dates unconfirmed', 'accessible-forms-by-accessible-org' ), 'earlier' => __( 'Use the earlier occurrence', 'accessible-forms-by-accessible-org' ), 'later' => __( 'Use the later occurrence', 'accessible-forms-by-accessible-org' ) ), 'preserve', 'af-repeated-hour' ); echo '

'; echo '

' . esc_html__( 'Conversion preserves the original dates. Invalid or nonexistent local times remain unconfirmed. It does not change follow-up calendar dates, send emails or delete entries.', 'accessible-forms-by-accessible-org' ) . '

'; self::submit( __( 'Convert confirmed historical dates', 'accessible-forms-by-accessible-org' ), 'secondary' ); echo ''; } else { echo '

' . esc_html__( 'All stored entry dates have confirmed UTC provenance.', 'accessible-forms-by-accessible-org' ) . '

'; } echo '
'; } private static function activity() { echo '

' . esc_html__( 'Recent administrative changes. Answers and credentials are not copied into this log. Records expire after 90 days.', 'accessible-forms-by-accessible-org' ) . '

' . esc_html__( 'Scroll horizontally to see all columns.', 'accessible-forms-by-accessible-org' ) . '

'; $rows = Audit::recent(); foreach ( $rows as $row ) { echo ''; } if ( ! $rows ) { echo ''; } echo '
' . esc_html__( 'When (site time)', 'accessible-forms-by-accessible-org' ) . '' . esc_html__( 'Action', 'accessible-forms-by-accessible-org' ) . '' . esc_html__( 'Target', 'accessible-forms-by-accessible-org' ) . '' . esc_html__( 'User', 'accessible-forms-by-accessible-org' ) . '
' . esc_html( EntryWorkflow::local_time( $row['created_at'] ) ) . '' . esc_html( EntryWorkflow::activity_label( $row['action'] ) ) . '' . wp_kses_post( self::activity_target( $row ) ) . '' . esc_html( EntryWorkflow::person( $row['actor'] ) ) . '
' . esc_html__( 'No recent administrative changes.', 'accessible-forms-by-accessible-org' ) . '
'; } /** A record's context without exposing answers or linking beyond access. */ private static function activity_target( array $row ) { $id = (int) ( $row['form_id'] ?? 0 ); if ( ! $id ) { return esc_html__( 'Site-wide', 'accessible-forms-by-accessible-org' ); } $form = get_post( $id ); if ( ! $form || 'accessible_form' !== $form->post_type ) { /* translators: %d: ID of a form that is no longer available. */ return esc_html( sprintf( __( 'Deleted or unavailable form (#%d)', 'accessible-forms-by-accessible-org' ), $id ) ); } /* translators: %d: form ID. */ $label = sprintf( __( 'Form #%d', 'accessible-forms-by-accessible-org' ), $id ); $can_edit = current_user_can( 'edit_post', $id ); if ( $form->post_title && ( $can_edit || current_user_can( 'read_post', $id ) ) ) { $label = $form->post_title; } $link = $can_edit ? get_edit_post_link( $id, 'raw' ) : ''; return $link ? '' . esc_html( $label ) . '' : esc_html( $label ); } private static function guide() { echo '
  1. ' . esc_html__( 'Create a draft', 'accessible-forms-by-accessible-org' ) . '

    ' . esc_html__( 'Choose a template or add the fields you need. Keep labels descriptive and required questions purposeful.', 'accessible-forms-by-accessible-org' ) . '

  2. ' . esc_html__( 'Review delivery and appearance', 'accessible-forms-by-accessible-org' ) . '

    ' . esc_html__( 'Confirm recipients, preview the confirmation and choose a palette that passes every contrast check.', 'accessible-forms-by-accessible-org' ) . '

  3. ' . esc_html__( 'Publish and place the form', 'accessible-forms-by-accessible-org' ) . '

    ' . esc_html( Extensions::registered( 'pro' ) ? __( 'Publish the form, then place it on a page or post, use an Accessible Form block or shortcode, or set an automatic placement rule.', 'accessible-forms-by-accessible-org' ) : __( 'Publish the form, then place it on a page or post with the placement tool, an Accessible Form block or its shortcode.', 'accessible-forms-by-accessible-org' ) ) . '

  4. ' . esc_html__( 'Test the complete journey', 'accessible-forms-by-accessible-org' ) . '

    ' . esc_html__( 'Use the keyboard, send a test entry and confirm both storage and actual inbox delivery. Check on a phone and with your site theme.', 'accessible-forms-by-accessible-org' ) . '

' . esc_html__( 'Troubleshooting', 'accessible-forms-by-accessible-org' ) . '

'; foreach ( array( __( 'No email arrived', 'accessible-forms-by-accessible-org' ) => __( 'Open the entry and check notification history. Review pending work and mail settings in Health. Acceptance by a mail service does not guarantee inbox delivery.', 'accessible-forms-by-accessible-org' ), __( 'The form is missing', 'accessible-forms-by-accessible-org' ) => __( 'Check that the selected form is published, open and correctly selected in its page block. Clear the page cache after changing placement.', 'accessible-forms-by-accessible-org' ), __( 'A message needs review', 'accessible-forms-by-accessible-org' ) => __( 'Check the verification reason. Accept the message with or without sending a notification, and adjust your spam limits if they caused a false positive.', 'accessible-forms-by-accessible-org' ), __( 'A color was rejected', 'accessible-forms-by-accessible-org' ) => __( 'The editor identifies the failing pair. Choose a darker or lighter color, or use a preset. Check focus and errors in the preview as well.', 'accessible-forms-by-accessible-org' ), ) as $question => $answer ) { echo '
' . esc_html( $question ) . '

' . esc_html( $answer ) . '

'; } } }