get_bloginfo( 'name' ), 'email' => get_option( 'admin_email' ), 'phone' => '', 'reply_days' => 2, 'show_form' => true, 'credit' => false, 'page_id' => 0, 'updated_at' => '', ), is_array( $stored ) ? $stored : array() ); } /** * Menu entry under Fixlight. */ public static function menu() { add_submenu_page( Admin::SLUG, __( 'Accessibility statement', 'fixlight' ), __( 'Statement', 'fixlight' ), 'manage_options', self::SLUG, array( __CLASS__, 'page' ) ); } /** * Adds the Statement tab after Images. * * @param array $tabs Tabs. * @return array */ public static function tab( $tabs ) { $out = array(); foreach ( $tabs as $slug => $label ) { if ( Admin::SLUG . '-settings' === $slug ) { $out[ self::SLUG ] = __( 'Statement', 'fixlight' ); $out[ Reports::SLUG ] = __( 'Reports', 'fixlight' ); } $out[ $slug ] = $label; } return $out; } /** * The statement's sections. * * @return array[] Each id, title and html. */ public static function sections() { $s = self::settings(); $org = '' !== trim( $s['organization'] ) ? $s['organization'] : get_bloginfo( 'name' ); $days = max( 1, (int) $s['reply_days'] ); $reach = array(); if ( is_email( $s['email'] ) ) { $reach[] = sprintf( '%2$s', esc_url( 'mailto:' . antispambot( $s['email'] ) ), esc_html( antispambot( $s['email'] ) ) ); } if ( '' !== trim( $s['phone'] ) ) { $reach[] = sprintf( '%2$s', esc_url( 'tel:' . preg_replace( '/[^0-9+]/', '', $s['phone'] ) ), esc_html( $s['phone'] ) ); } $sections = array( array( 'id' => 'commitment', 'title' => __( 'Our commitment', 'fixlight' ), 'html' => '

' . esc_html( sprintf( /* translators: 1: organization name, 2: site name. */ __( '%1$s wants everyone to be able to use %2$s, including people who use a screen reader, a keyboard, voice control or zoom. We aim to meet the Web Content Accessibility Guidelines (WCAG) 2.2 at level AA.', 'fixlight' ), $org, get_bloginfo( 'name' ) ) ) . '

', ), array( 'id' => 'measures', 'title' => __( 'What we do', 'fixlight' ), 'html' => '', ), array( 'id' => 'limits', 'title' => __( 'Known limitations', 'fixlight' ), 'html' => '

' . esc_html__( 'Some older content, and content from other companies (such as embedded videos, maps or payment forms), may not be fully accessible yet. Automated checks find many but not all problems. If something is hard to use, please tell us and we will help.', 'fixlight' ) . '

', ), array( 'id' => 'contact', 'title' => __( 'Tell us about a problem', 'fixlight' ), 'html' => '

' . esc_html( sprintf( /* translators: %d: number of business days. */ _n( 'If something on this site is hard to use, tell us. We reply within %d business day.', 'If something on this site is hard to use, tell us. We reply within %d business days.', $days, 'fixlight' ), $days ) ) . '

' . ( $reach ? '

' . esc_html__( 'Contact:', 'fixlight' ) . ' ' . implode( ' ยท ', $reach ) . '

' : '' ) . ( $s['show_form'] ? Reports::form() : '' ), ), array( 'id' => 'updated', 'title' => __( 'About this statement', 'fixlight' ), 'html' => '

' . esc_html( sprintf( /* translators: %s: date. */ __( 'Last updated: %s.', 'fixlight' ), wp_date( get_option( 'date_format' ), '' !== $s['updated_at'] ? strtotime( $s['updated_at'] . ' UTC' ) : time() ) ) ) . '

', ), ); /** * Filters the sections of the accessibility statement. * * @since 0.1.0 * * @param array[] $sections Each id, title and html (already escaped). * @param array $settings Statement settings. */ return (array) apply_filters( 'fixlight_statement_sections', $sections, $s ); } /** * [fixlight_statement] * * @return string */ public static function shortcode() { $out = '
'; $allowed = self::allowed_html(); foreach ( self::sections() as $section ) { $out .= '

' . esc_html( $section['title'] ) . '

' . wp_kses( $section['html'], $allowed ) . '
'; } // The credit link is the site owner's choice (off by default), as WordPress.org requires. if ( ! empty( self::settings()['credit'] ) ) { /* translators: %s: "Fixlight", linked to the plugin's page. */ $out .= '

' . sprintf( esc_html__( 'Accessibility fixes by %s', 'fixlight' ), 'Fixlight' ) . '

'; } return $out . '
'; } /** * HTML a statement section may contain: post content plus the report form. * * @return array */ private static function allowed_html() { $allowed = wp_kses_allowed_html( 'post' ); $field = array_fill_keys( array( 'id', 'class', 'name', 'required', 'aria-describedby', 'aria-label', 'aria-invalid' ), true ); $allowed['form'] = array_merge( $field, array_fill_keys( array( 'action', 'method' ), true ) ); $allowed['input'] = array_merge( $field, array_fill_keys( array( 'type', 'value', 'autocomplete', 'tabindex', 'checked', 'maxlength' ), true ) ); $allowed['textarea'] = array_merge( $field, array_fill_keys( array( 'rows', 'cols', 'maxlength' ), true ) ); $allowed['select'] = $field; $allowed['option'] = array_fill_keys( array( 'value', 'selected' ), true ); $allowed['button'] = array_merge( isset( $allowed['button'] ) ? $allowed['button'] : array(), $field, array( 'type' => true ) ); $allowed['label'] = array_merge( isset( $allowed['label'] ) ? $allowed['label'] : array(), array( 'for' => true ) ); // The form's result message takes focus after sending. $allowed['div']['tabindex'] = true; return $allowed; } /** * The Statement screen. */ public static function page() { $s = self::settings(); $page = $s['page_id'] ? get_post( (int) $s['page_id'] ) : null; Admin::header( self::SLUG, __( 'Accessibility statement', 'fixlight' ) ); self::notice(); ?>

post_status ) : ?>

post_status ) ? get_post_status_object( $page->post_status )->label : $page->post_status ) ); ?>

' . esc_html( $section['title'] ) . '' . wp_kses_post( 'contact' === $section['id'] ? preg_replace( '##s', '

' . esc_html__( '(The report form appears here.)', 'fixlight' ) . '

', $section['html'] ) : $section['html'] ); } ?>

' . esc_html( $msg ) . '

'; } elseif ( is_array( $msg ) && isset( $msg['error'] ) ) { delete_transient( $key ); echo ''; } } /** * Back to the screen with a message. * * @param string $text Message. * @param bool $error Whether it is an error. */ private static function back( $text, $error = false ) { set_transient( 'fixlight_statement_notice_' . get_current_user_id(), $error ? array( 'error' => $text ) : $text, MINUTE_IN_SECONDS ); wp_safe_redirect( admin_url( 'admin.php?page=' . self::SLUG ) ); exit; } /** * Saves the details. */ public static function action_save() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You are not allowed to do this.', 'fixlight' ), '', array( 'response' => 403 ) ); } check_admin_referer( 'fixlight_statement_save' ); $s = self::settings(); $s['organization'] = isset( $_POST['organization'] ) ? sanitize_text_field( wp_unslash( $_POST['organization'] ) ) : $s['organization']; $typed = isset( $_POST['email'] ) ? trim( sanitize_text_field( wp_unslash( $_POST['email'] ) ) ) : ''; $email = sanitize_email( $typed ); $bad_email = '' !== $typed && ! is_email( $email ); $s['email'] = $bad_email ? $s['email'] : $email; $s['phone'] = isset( $_POST['phone'] ) ? sanitize_text_field( wp_unslash( $_POST['phone'] ) ) : ''; $s['reply_days'] = isset( $_POST['reply_days'] ) ? min( 10, max( 1, absint( $_POST['reply_days'] ) ) ) : 2; $s['show_form'] = ! empty( $_POST['show_form'] ); $s['credit'] = ! empty( $_POST['credit'] ); $s['updated_at'] = current_time( 'mysql', true ); /** * Filters statement settings before they are saved (Fixlight Pro adds its own). * * @since 0.1.0 * * @param array $s Settings. */ update_option( self::OPTION, apply_filters( 'fixlight_statement_save', $s ), false ); if ( $bad_email ) { /* translators: %s: email address that was typed. */ self::back( sprintf( __( '"%s" is not a valid email address, so the contact email was not changed. Your other details were saved.', 'fixlight' ), $typed ), true ); } self::back( __( 'Saved.', 'fixlight' ) ); } /** * Publishes the statement page. */ public static function action_publish() { if ( ! current_user_can( 'publish_pages' ) || ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You are not allowed to do this.', 'fixlight' ), '', array( 'response' => 403 ) ); } check_admin_referer( 'fixlight_statement_publish' ); $s = self::settings(); $id = wp_insert_post( array( 'post_type' => 'page', 'post_status' => 'publish', 'post_title' => __( 'Accessibility', 'fixlight' ), 'post_name' => 'accessibility', 'post_content' => '[fixlight_statement]', ), true ); if ( is_wp_error( $id ) ) { self::back( $id->get_error_message(), true ); } $s['page_id'] = (int) $id; $s['updated_at'] = current_time( 'mysql', true ); update_option( self::OPTION, $s, false ); self::back( __( 'The statement page is published. Add a link to it in your footer menu.', 'fixlight' ) ); } }