> */ public static function svg_allowed_html() { $paint = array( 'fill' => true, 'fill-rule' => true, 'clip-rule' => true, 'stroke' => true, 'stroke-width' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, ); return array( 'svg' => array_merge( $paint, array( 'class' => true, 'role' => true, 'aria-hidden' => true, 'aria-label' => true, 'viewbox' => true, 'width' => true, 'height' => true, 'xmlns' => true, ) ), 'path' => array_merge( $paint, array( 'd' => true ) ), 'circle' => array_merge( $paint, array( 'cx' => true, 'cy' => true, 'r' => true, ) ), 'rect' => array_merge( $paint, array( 'x' => true, 'y' => true, 'width' => true, 'height' => true, 'rx' => true, 'ry' => true, ) ), ); } /** * Hook everything up. */ public function __construct() { add_action( 'admin_menu', array( $this, 'register_menu' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) ); add_action( 'wp_ajax_welcoma_widget_save_settings', array( $this, 'ajax_save' ) ); add_action( 'wp_ajax_welcoma_widget_generate_statement', array( $this, 'ajax_generate_statement' ) ); add_action( 'wp_ajax_welcoma_widget_save_statement', array( $this, 'ajax_save_statement' ) ); } /** * Add the top-level admin menu item. */ public function register_menu() { // Eindeutiger Name, damit nicht zweimal „Welcoma" in der Sidebar steht // (das Theme registriert bereits „Welcoma"). Icon: Welcoma-W-Marke als zweifarbiges SVG-Data-URI. // WordPress' svg-painter.js recolors every fill="..." attribute after DOM ready. // Keep the logo stroke-only and use fill-opacity="0" (not fill="none") so the // painter cannot turn the open paths into filled shapes after the page loads. $welcoma_icon = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NCA2NCIgYXJpYS1oaWRkZW49InRydWUiPjxwYXRoIGQ9Ik0xMCAyMCBMMjIgNDQgTDMyIDMwIEw0MiA0NCBMNTQgMTgiIGZpbGwtb3BhY2l0eT0iMCIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjYuNzUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjwvc3ZnPg=='; add_menu_page( __( 'Welcoma Widget', 'welcoma-accessibility-widget' ), __( 'Welcoma Widget', 'welcoma-accessibility-widget' ), 'manage_options', self::MENU_SLUG, array( $this, 'render_page' ), $welcoma_icon, 30 ); // Untermenü = Schnell-Sprungpunkte zu den In-Page-Tabs. // Der erste Eintrag (gleicher Slug wie das Top-Level) ersetzt das WP-Auto-Duplikat // „Welcoma Widget" durch „Overview" – sonst stünde der Name doppelt in der Sidebar. add_submenu_page( self::MENU_SLUG, __( 'Welcoma Widget', 'welcoma-accessibility-widget' ), __( 'Overview', 'welcoma-accessibility-widget' ), 'manage_options', self::MENU_SLUG, array( $this, 'render_page' ) ); $welcoma_tabs = array( 'appearance' => __( 'Appearance', 'welcoma-accessibility-widget' ), 'modules' => __( 'Modules', 'welcoma-accessibility-widget' ), 'statement' => __( 'Statement', 'welcoma-accessibility-widget' ), 'settings' => __( 'Settings', 'welcoma-accessibility-widget' ), ); foreach ( $welcoma_tabs as $welcoma_tab_slug => $welcoma_tab_label ) { add_submenu_page( self::MENU_SLUG, $welcoma_tab_label, $welcoma_tab_label, 'manage_options', 'admin.php?page=' . self::MENU_SLUG . '#' . $welcoma_tab_slug ); } } /** * Load CSS/JS only on this plugin's screen. * * @param string $hook Current admin page hook. */ public function enqueue_assets( $hook ) { if ( 'toplevel_page_' . self::MENU_SLUG !== $hook ) { return; } // Redesign shell (Brief 1): foundation + Overview. wp_enqueue_style( 'welcoma-admin', WELCOMA_WIDGET_URL . 'admin/css/welcoma-admin.css', array(), WELCOMA_WIDGET_VERSION ); wp_enqueue_script( 'welcoma-admin-base', WELCOMA_WIDGET_URL . 'admin/js/admin.js', array(), WELCOMA_WIDGET_VERSION, true ); // Redesign shell JS (Brief 1): tab switching, toast, honest scan CTA. wp_enqueue_script( 'welcoma-admin', WELCOMA_WIDGET_URL . 'admin/js/welcoma-admin.js', array(), WELCOMA_WIDGET_VERSION, true ); // Appearance tab interactions (themes, position dots, slider, accordion). // Loads after admin.js so the legacy color-input handlers are bound first. wp_enqueue_script( 'welcoma-appearance', WELCOMA_WIDGET_URL . 'admin/js/welcoma-appearance.js', array( 'welcoma-admin-base' ), WELCOMA_WIDGET_VERSION, true ); // Modules tab (profiles-first + category accordions). Uses window.welcomaSvg / // window.welcomaMarkDirty from admin.js, so it must load after it. wp_enqueue_script( 'welcoma-modules', WELCOMA_WIDGET_URL . 'admin/js/welcoma-modules.js', array( 'welcoma-admin-base' ), WELCOMA_WIDGET_VERSION, true ); wp_enqueue_editor(); $settings = Welcoma_Settings::get(); $current_locale = class_exists( 'Welcoma_Translator' ) ? Welcoma_Translator::current_source_lang() : 'en'; $i18n_cache = class_exists( 'Welcoma_Translator' ) ? Welcoma_Translator::get_cache() : array(); // The header text always comes from the shared translation cache // (bundled default, or whatever an add-on stored there). $settings['accessibility_title'] = class_exists( 'Welcoma_Translator' ) ? Welcoma_Translator::get_string( 'accessibility_title', $current_locale ) : 'Accessibility'; if ( '' === $settings['accessibility_title'] ) { $settings['accessibility_title'] = 'Accessibility'; } $localized_statement = get_option( WELCOMA_WIDGET_STATEMENT_OPTION, array( 'company_name' => '', 'email' => '', 'website_url' => '', 'content' => '', ) ); wp_localize_script( 'welcoma-admin-base', 'welcomaAdminData', array( 'modules' => array_values( welcoma_widget_get_modules() ), 'profile_module_map' => Welcoma_Settings::builtin_profile_module_map(), 'counts' => welcoma_widget_get_module_counts(), 'settings' => $settings, 'defaults' => Welcoma_Settings::default_settings(), 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'welcoma_widget_save' ), 'statement' => $localized_statement, 'statementNonce' => wp_create_nonce( 'welcoma_widget_statement' ), 'pluginsUrl' => admin_url( 'plugins.php' ), // Add-ons (e.g. Welcoma Pro) report their own connection state here. // Core never connects to, or stores anything about, a Welcoma account. 'connect' => apply_filters( 'welcoma_admin_connect_state', array( 'connected' => false, 'method' => '', 'ajaxUrl' => admin_url( 'admin-ajax.php' ), ) ), 'welcoma_i18n' => array( 'saved' => __( 'Changes saved.', 'welcoma-accessibility-widget' ), 'error' => __( 'Could not save. Please try again.', 'welcoma-accessibility-widget' ), 'emptyModule' => __( 'No modules match your search.', 'welcoma-accessibility-widget' ), 'saving' => __( 'Saving…', 'welcoma-accessibility-widget' ), 'pro' => __( 'Pro', 'welcoma-accessibility-widget' ), 'save' => __( 'Save changes', 'welcoma-accessibility-widget' ), 'active' => __( 'active', 'welcoma-accessibility-widget' ), 'on' => __( 'on', 'welcoma-accessibility-widget' ), 'generating' => __( 'Building statement…', 'welcoma-accessibility-widget' ), 'statementSaved' => __( 'Statement saved.', 'welcoma-accessibility-widget' ), 'companyUrlRequired' => __( 'Company name and website URL are required.', 'welcoma-accessibility-widget' ), 'generateStatementBtn' => __( 'Generate statement', 'welcoma-accessibility-widget' ), 'resetConfirm' => __( 'Reset appearance and settings to defaults? Your modules, profiles, custom labels, title and statement will be kept. Click Save to apply.', 'welcoma-accessibility-widget' ), 'defaultsRestored' => __( 'Defaults restored — click Save to apply.', 'welcoma-accessibility-widget' ), 'nothingToSaveOverview' => __( 'Nothing to save on the overview.', 'welcoma-accessibility-widget' ), 'ofLanguagesComplete' => __( 'of', 'welcoma-accessibility-widget' ), 'moduleSwitchedOn' => __( 'module switched on', 'welcoma-accessibility-widget' ), 'modulesSwitchedOn' => __( 'modules switched on', 'welcoma-accessibility-widget' ), 'turnedOff' => __( 'turned off', 'welcoma-accessibility-widget' ), 'fieldName' => __( 'Name', 'welcoma-accessibility-widget' ), 'icon' => __( 'Icon', 'welcoma-accessibility-widget' ), 'modules' => __( 'Modules', 'welcoma-accessibility-widget' ), 'cancel' => __( 'Cancel', 'welcoma-accessibility-widget' ), 'confirm' => __( 'Confirm', 'welcoma-accessibility-widget' ), 'companyEmailUrlRequired' => __( 'Company name, contact email, and website URL are required.', 'welcoma-accessibility-widget' ), 'statementGenerated' => __( 'Statement generated — click Save to publish it.', 'welcoma-accessibility-widget' ), 'areYouSure' => __( 'Are you sure?', 'welcoma-accessibility-widget' ), 'resetConfirmTitle' => __( 'Reset all settings?', 'welcoma-accessibility-widget' ), 'resetConfirmBtn' => __( 'Reset to defaults', 'welcoma-accessibility-widget' ), 'assignedToProfile' => __( 'is used by', 'welcoma-accessibility-widget' ), 'disableProfileFirst' => __( 'Disable', 'welcoma-accessibility-widget' ), 'firstSuffix' => __( 'first', 'welcoma-accessibility-widget' ), 'accessibilityDefault' => __( 'Accessibility', 'welcoma-accessibility-widget' ), 'catVision' => __( 'Vision & colour', 'welcoma-accessibility-widget' ), 'catReading' => __( 'Reading & text', 'welcoma-accessibility-widget' ), 'catMotor' => __( 'Navigation & motor', 'welcoma-accessibility-widget' ), 'catAudio' => __( 'Audio & media', 'welcoma-accessibility-widget' ), 'catCognitive' => __( 'Cognitive', 'welcoma-accessibility-widget' ), 'catOther' => __( 'Other', 'welcoma-accessibility-widget' ), 'availableInPro' => __( 'Available in Welcoma Pro', 'welcoma-accessibility-widget' ), 'availableInProDesc' => __( 'These tools come with the separate Welcoma Pro add-on.', 'welcoma-accessibility-widget' ), 'explorePro' => __( 'Explore Welcoma Pro', 'welcoma-accessibility-widget' ), 'modulePlural' => __( 'module', 'welcoma-accessibility-widget' ), 'modulesPlural' => __( 'modules', 'welcoma-accessibility-widget' ), 'themePine' => __( 'Pine', 'welcoma-accessibility-widget' ), 'themePineDesc' => __( 'Default — warm & calm', 'welcoma-accessibility-widget' ), 'themeOcean' => __( 'Ocean', 'welcoma-accessibility-widget' ), 'themeOceanDesc' => __( 'Cool & clear', 'welcoma-accessibility-widget' ), 'themeMidnight' => __( 'Midnight', 'welcoma-accessibility-widget' ), 'themeMidnightDesc' => __( 'Dark & focused', 'welcoma-accessibility-widget' ), 'themeMono' => __( 'Mono', 'welcoma-accessibility-widget' ), 'themeMonoDesc' => __( 'Neutral greys', 'welcoma-accessibility-widget' ), 'themeHighContrast' => __( 'High contrast', 'welcoma-accessibility-widget' ), 'themeHighContrastDesc' => __( 'Maximum legibility', 'welcoma-accessibility-widget' ), 'themeCustom' => __( 'Custom', 'welcoma-accessibility-widget' ), 'themeCustomDesc' => __( 'Your own palette', 'welcoma-accessibility-widget' ), 'themeApplied' => __( 'theme applied', 'welcoma-accessibility-widget' ), 'customFineTune' => __( 'Custom — fine-tune in Advanced colours', 'welcoma-accessibility-widget' ), 'stmtReady' => __( 'Ready', 'welcoma-accessibility-widget' ), 'stmtMissing' => __( 'Missing', 'welcoma-accessibility-widget' ), 'stmtSet' => __( 'Statement is set', 'welcoma-accessibility-widget' ), 'unsavedTitle' => __( 'Unsaved changes', 'welcoma-accessibility-widget' ), 'unsavedStatementMsg' => __( 'You have unsaved changes in the Statement tab. If you leave now they will be lost.', 'welcoma-accessibility-widget' ), 'leaveWithoutSaving' => __( 'Leave without saving', 'welcoma-accessibility-widget' ), 'stayOnPage' => __( 'Stay here', 'welcoma-accessibility-widget' ), 'stmtNotCreated' => __( 'Not created yet', 'welcoma-accessibility-widget' ), 'stmtCreate' => __( 'Create', 'welcoma-accessibility-widget' ), 'ovWidgetLive' => __( 'Live', 'welcoma-accessibility-widget' ), 'ovWidgetOff' => __( 'Off', 'welcoma-accessibility-widget' ), 'ovWidgetLiveDesc' => __( 'Live on your site', 'welcoma-accessibility-widget' ), 'ovWidgetOffDesc' => __( 'Currently switched off', 'welcoma-accessibility-widget' ), 'ovWidgetEnable' => __( 'Enable', 'welcoma-accessibility-widget' ), ), ) ); } /** * Render the settings page wrapper. */ public function render_page() { if ( ! current_user_can( 'manage_options' ) ) { return; } // Every Core feature works without any Welcoma account. Core neither // connects to nor stores anything about an account; an add-on may // provide its own optional connection for cloud services. require WELCOMA_WIDGET_PATH . 'admin/views/dashboard.php'; } /** * AJAX: persist settings sent from the dashboard. */ public function ajax_save() { check_ajax_referer( 'welcoma_widget_save', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'welcoma-accessibility-widget' ) ), 403 ); } $raw = isset( $_POST['settings'] ) ? json_decode( sanitize_textarea_field( wp_unslash( $_POST['settings'] ) ), true ) : null; if ( ! is_array( $raw ) ) { wp_send_json_error( array( 'message' => __( 'Invalid payload.', 'welcoma-accessibility-widget' ) ), 400 ); } // Core sanitizes and saves only local settings. No text is transmitted // to an external translation service by the WordPress.org plugin. $clean = Welcoma_Settings::sanitize( $raw ); Welcoma_Settings::save( $clean ); /** * Fires after Core's own settings are saved. Core passes no add-on * data of any kind — add-ons that need to save their own data run * their own request, sequenced after Core's save via * window.Welcoma.save() on the JS side, and their own separately * nonce-checked and capability-checked AJAX action on the PHP side. * * @param array $clean Sanitized core settings that were saved. */ do_action( 'welcoma_widget_settings_saved', $clean ); wp_send_json_success( array( 'message' => __( 'Changes saved.', 'welcoma-accessibility-widget' ), 'settings' => $clean, ) ); } /** * AJAX: generate accessibility statement locally from the submitted * company details and save it. */ public function ajax_generate_statement() { check_ajax_referer( 'welcoma_widget_statement', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'welcoma-accessibility-widget' ) ), 403 ); } $company_name = isset( $_POST['company_name'] ) ? sanitize_text_field( wp_unslash( $_POST['company_name'] ) ) : ''; $email = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : ''; $website_url = isset( $_POST['website_url'] ) ? esc_url_raw( wp_unslash( $_POST['website_url'] ) ) : ''; if ( empty( $company_name ) || empty( $email ) || empty( $website_url ) ) { wp_send_json_error( array( 'message' => __( 'Company name, contact email, and website URL are required.', 'welcoma-accessibility-widget' ) ) ); } if ( ! filter_var( $website_url, FILTER_VALIDATE_URL ) ) { wp_send_json_error( array( 'message' => __( 'Website URL is not a valid URL.', 'welcoma-accessibility-widget' ) ) ); } if ( ! is_email( $email ) || ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) { wp_send_json_error( array( 'message' => __( 'Email address is not valid.', 'welcoma-accessibility-widget' ) ) ); } // Privatwirtschaftliche „Barrierefreiheitsinformationen" nach § 14 i. V. m. // Anlage 3 BFSG (NICHT die „Erklärung zur Barrierefreiheit" für öffentliche // Stellen nach § 12b BGG/BITV). Base templates only exist hand-written in // DE/EN; every other supported plugin language gets the EN template // left in English outside DE/EN in Core; optional translation belongs to Pro (see below, after // $generated is built). Single source of truth for "what language is // this" — no separate determine_locale() check, so the DE branch and // the translation step can never disagree on the current locale. $target_lang = class_exists( 'Welcoma_Translator' ) ? Welcoma_Translator::current_source_lang() : 'en'; $is_de = ( 'de' === $target_lang ); $name = esc_html( $company_name ); $url = esc_url( $website_url ); $contact = '' . esc_html( $email ) . ''; // Only mention third-party services the site actually has switched // on — re-checked live on every generate call, never cached, so a // module toggled off after a previous generate stops being mentioned // on the next one. // Prefer the LIVE (possibly unsaved) toggle state the admin UI sends // with the Generate click; fall back to the saved settings. Optional // add-ons register their modules into the same catalogue, so Core only // mentions a module that actually exists in the current installation. $modules_enabled = Welcoma_Settings::get()['enabled'] ?? array(); if ( isset( $_POST['modules_on'] ) ) { $posted_on = json_decode( sanitize_text_field( wp_unslash( $_POST['modules_on'] ) ), true ); if ( is_array( $posted_on ) ) { $modules_enabled = array( 'dictionary' => in_array( 'dictionary', $posted_on, true ), 'translator' => in_array( 'translator', $posted_on, true ), ); } } $registered_ids = wp_list_pluck( welcoma_widget_get_modules(), 'id' ); $dictionary_on = ! empty( $modules_enabled['dictionary'] ) && in_array( 'dictionary', $registered_ids, true ); $translator_on = ! empty( $modules_enabled['translator'] ) && in_array( 'translator', $registered_ids, true ); if ( $is_de ) { $date = gmdate( 'd.m.Y' ); $generated = '
'; $generated .= '
'; $generated .= '

Barrierefreiheitsinformationen

'; $generated .= '' . $name . '
'; $generated .= '' . esc_html( $website_url ) . '
'; $generated .= 'Zuletzt aktualisiert: ' . esc_html( $date ) . ''; $generated .= '
'; $generated .= '

Geltungsbereich

'; $generated .= '

' . $name . ' ist bemüht, das unter ' . esc_html( $website_url ) . ' angebotene Angebot im Einklang mit dem Barrierefreiheitsstärkungsgesetz (BFSG) barrierefrei nutzbar zu machen. Diese Barrierefreiheitsinformationen werden gemäß § 14 i. V. m. Anlage 3 BFSG bereitgestellt.

'; $generated .= '

Stand der Vereinbarkeit mit den Anforderungen

'; $generated .= '

Maßstab der Barrierefreiheit ist die harmonisierte europäische Norm EN 301 549 und damit die Web Content Accessibility Guidelines (WCAG) 2.1 in der Stufe AA. Wir orientieren uns an diesen Anforderungen, um unser Angebot für möglichst viele Menschen nutzbar zu machen.

'; $generated .= '

Wie die Anforderungen erfüllt werden

'; $generated .= '

Wir verbessern unser Angebot fortlaufend und beheben erkannte Barrieren an der Ursache im Quellcode. Ergänzend stellt ein Bedienmenü Anpassungen für Besucherinnen und Besucher bereit (z. B. Schriftgröße, Kontrast, Lesehilfen). Dieses Menü ersetzt keine barrierefreie Umsetzung, sondern senkt zusätzlich Barrieren.

'; $generated .= '

Nicht barrierefreie Inhalte

'; $generated .= '

Trotz unserer Bemühungen sind einzelne Inhalte möglicherweise noch nicht vollständig barrierefrei – etwa ältere Dokumente oder eingebundene Inhalte Dritter. [Hier konkret die bekannten, noch nicht barrierefreien Inhalte benennen.] Wir arbeiten daran, diese zu verbessern.

'; $generated .= '

Zuständige Marktüberwachungsbehörde

'; $generated .= '

Für die Marktüberwachung nach dem BFSG ist die jeweils zuständige Marktüberwachungsbehörde verantwortlich. [Hier die für dein Angebot zuständige Behörde eintragen – z. B. die Marktüberwachungsstelle der Länder für Barrierefreiheit von Produkten und Dienstleistungen (MLBF).]

'; $generated .= '

Feedback und Kontakt

'; $generated .= '

Sind dir Barrieren aufgefallen oder benötigst du Inhalte in einer barrierefreien Form? Melde dich gern – wir nehmen dein Feedback ernst:

'; $generated .= '

' . $contact . '

'; $third_party_de = array(); if ( $dictionary_on ) { $third_party_de[] = 'Die Wörterbuchfunktion sendet das von dir ausgewählte einzelne Wort an den Welcoma-Wörterbuchdienst (api.welcoma.app), um eine Definition abzurufen. Es werden keine weiteren Seiteninhalte übermittelt.'; } if ( $translator_on ) { $third_party_de[] = 'Die Auswahl einer Sprache unter „Diese Seite übersetzen" sendet den Text dieser Seite an Google Translate und öffnet die übersetzte Version auf einer Google-Domain (translate.goog).'; } if ( ! empty( $third_party_de ) ) { $generated .= '

Drittanbieter-Dienste

'; $generated .= '

' . implode( ' ', $third_party_de ) . '

'; } $generated .= '

Hinweis: Diese Barrierefreiheitsinformationen sind eine Vorlage nach § 14 i. V. m. Anlage 3 BFSG und stellen keine Rechtsberatung dar. Bitte passe sie an dein konkretes Angebot an und lass sie im Zweifel fachkundig prüfen.

'; $generated .= '
'; } else { $date = gmdate( 'F j, Y' ); $generated = '
'; $generated .= '
'; $generated .= '

Accessibility Information

'; $generated .= '' . $name . '
'; $generated .= '' . esc_html( $website_url ) . '
'; $generated .= 'Last updated: ' . esc_html( $date ) . ''; $generated .= '
'; $generated .= '

Scope

'; $generated .= '

' . $name . ' is committed to making its service at ' . esc_html( $website_url ) . ' accessible in line with the German Accessibility Strengthening Act (BFSG). This accessibility information is provided pursuant to § 14 in conjunction with Annex 3 BFSG.

'; $generated .= '

Conformance status

'; $generated .= '

The benchmark for accessibility is the harmonised European standard EN 301 549 and therefore the Web Content Accessibility Guidelines (WCAG) 2.1 at Level AA. We work towards these requirements to make our service usable for as many people as possible.

'; $generated .= '

How the requirements are met

'; $generated .= '

We continuously improve our service and fix identified barriers at their source in the code. In addition, an on-screen menu offers adjustments for visitors (e.g. font size, contrast, reading aids). This menu does not replace accessible implementation – it lowers barriers on top of it.

'; $generated .= '

Non-accessible content

'; $generated .= '

Despite our efforts, some content may not yet be fully accessible – for example older documents or embedded third-party content. [List the known non-accessible content here.] We are working to improve it.

'; $generated .= '

Responsible market surveillance authority

'; $generated .= '

Market surveillance under the BFSG is carried out by the competent market surveillance authority. [Enter the authority responsible for your service here.]

'; $generated .= '

Feedback and contact

'; $generated .= '

Have you encountered barriers, or do you need content in an accessible form? Please get in touch – we take your feedback seriously:

'; $generated .= '

' . $contact . '

'; $third_party_en = array(); if ( $dictionary_on ) { $third_party_en[] = 'The dictionary feature sends the single word you select to the Welcoma dictionary service (api.welcoma.app) to look up a definition. No other page content is sent.'; } if ( $translator_on ) { $third_party_en[] = 'Selecting a language under "Translate this page" sends this page\'s text to Google Translate and opens the translated version on a Google domain (translate.goog).'; } if ( ! empty( $third_party_en ) ) { $generated .= '

Third-party services

'; $generated .= '

' . implode( ' ', $third_party_en ) . '

'; } $generated .= '

Note: This accessibility information is a template pursuant to § 14 in conjunction with Annex 3 BFSG and does not constitute legal advice. Please adapt it to your specific service and have it reviewed by a professional if in doubt.

'; $generated .= '
'; } $generated = trim( $generated ); // Generation only fills the editor with a draft — it must never write // to WELCOMA_WIDGET_STATEMENT_OPTION (the option the live frontend // reads). Only ajax_save_statement() persists/publishes the statement, // so there is a single write path instead of two independent ones. wp_send_json_success( array( 'content' => $generated, 'message' => __( 'Statement generated.', 'welcoma-accessibility-widget' ), ) ); } /** * AJAX: save a manually written accessibility statement. */ public function ajax_save_statement() { check_ajax_referer( 'welcoma_widget_statement', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'welcoma-accessibility-widget' ), ), 403 ); } $existing = get_option( WELCOMA_WIDGET_STATEMENT_OPTION, array() ); $data = array( 'company_name' => isset( $_POST['company_name'] ) ? sanitize_text_field( wp_unslash( $_POST['company_name'] ) ) : ( $existing['company_name'] ?? '' ), 'email' => isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : ( $existing['email'] ?? '' ), 'website_url' => isset( $_POST['website_url'] ) ? esc_url_raw( wp_unslash( $_POST['website_url'] ) ) : ( $existing['website_url'] ?? '' ), 'content' => isset( $_POST['content'] ) ? wp_kses_post( wp_unslash( $_POST['content'] ) ) : ( $existing['content'] ?? '' ), ); if ( empty( $data['company_name'] ) || empty( $data['email'] ) || empty( $data['website_url'] ) ) { wp_send_json_error( array( 'message' => __( 'Company name, contact email, and website URL are required.', 'welcoma-accessibility-widget' ) ) ); } if ( ! filter_var( $data['website_url'], FILTER_VALIDATE_URL ) ) { wp_send_json_error( array( 'message' => __( 'Website URL is not a valid URL.', 'welcoma-accessibility-widget' ) ) ); } if ( ! is_email( $data['email'] ) || ! filter_var( $data['email'], FILTER_VALIDATE_EMAIL ) ) { wp_send_json_error( array( 'message' => __( 'Email address is not valid.', 'welcoma-accessibility-widget' ) ) ); } update_option( WELCOMA_WIDGET_STATEMENT_OPTION, $data ); wp_send_json_success( array( 'message' => __( 'Statement saved.', 'welcoma-accessibility-widget' ), 'content' => $data['content'], // Add-ons that run background jobs report their pending work here. 'i18n_pending' => apply_filters( 'welcoma_admin_pending_jobs', array() ), ) ); } }