maybe_enqueue_frontend_scripts();
$this->maybe_enqueue_thickbox();
self::$theme_is_accessibility_ready = self::is_theme_accessibility_ready();
}
/**
* Maybe enqueue the thickbox script.
*
* This powers the modal that is used to display fix settings in the editor.
*/
public function maybe_enqueue_thickbox() {
add_action(
'admin_enqueue_scripts',
function () {
add_thickbox();
}
);
}
/**
* Get the single instance of the class.
*
* @return FixesManager
*/
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Maybe enqueue the frontend scripts.
*/
private function maybe_enqueue_frontend_scripts() {
if (
( defined( 'REST_REQUEST' ) && REST_REQUEST ) ||
( defined( 'DOING_AJAX' ) && DOING_AJAX ) ||
( defined( 'DOING_CRON' ) && DOING_CRON ) ||
( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
) {
return;
}
// Consider adding this only if we can determine at least 1 of the fixes are enabled.
add_action(
'wp_enqueue_scripts',
function () {
wp_enqueue_script( 'edac-frontend-fixes', EDAC_PLUGIN_URL . 'build/frontendFixes.bundle.js', [], EDAC_VERSION, true );
wp_set_script_translations( 'edac-frontend-fixes', 'accessibility-checker', plugin_dir_path( EDAC_PLUGIN_FILE ) . 'languages' );
wp_localize_script(
'edac-frontend-fixes',
'edac_frontend_fixes',
apply_filters( 'edac_filter_frontend_fixes_data', [] )
);
do_action( 'edac_action_enqueue_frontend_fixes' );
}
);
}
/**
* Load the fixes.
*/
private function load_fixes() {
$fixes = apply_filters(
'edac_filter_fixes',
[
SkipLinkFix::class,
CommentSearchLabelFix::class,
HTMLLangAndDirFix::class,
TabindexFix::class,
RemoveTitleIfPrefferedAccessibleNameFix::class,
LinkUnderline::class,
MetaViewportScalableFix::class,
PreventLinksOpeningNewWindowFix::class,
FocusOutlineFix::class,
BlockPDFUploadsFix::class,
AddFileSizeAndTypeToLinkedFilesFix::class,
AddMissingOrEmptyPageTitleFix::class,
AddLabelToUnlabelledFormFieldsFix::class,
AddNewWindowWarningFix::class,
EmptySearchFix::class,
]
);
if ( ! is_array( $fixes ) ) {
$fixes = is_string( $fixes ) ? [ $fixes ] : [];
}
foreach ( $fixes as $fix ) {
if ( ! is_string( $fix ) ) {
continue;
}
if ( is_subclass_of( $fix, '\EqualizeDigital\AccessibilityChecker\Fixes\FixInterface' ) ) {
if ( ! isset( $this->fixes[ $fix::get_slug() ] ) ) {
$this->fixes[ $fix::get_slug() ] = ( new $fix() );
}
}
}
}
/**
* Get a fix by its slug.
*
* @param string $slug The fix slug.
*
* @return FixInterface|null
*/
public function get_fix( $slug ) {
return isset( $this->fixes[ $slug ] ) ? $this->fixes[ $slug ] : null;
}
/**
* Get the fixes settings.
*
* Returns an array of all the fix settings and their values along with a pro or not flag.
*
* @return array
*/
public function get_fixes_settings() {
$fixes_array = [];
foreach ( $this->fixes as $fix ) {
$fields = [];
foreach ( $fix->get_fields_array() as $field_slug => $field ) {
$fields[ $field_slug ] = get_option( $field_slug, $field['default'] ?? 0 );
}
$fixes_array[ $fix::get_slug() ] = [
'fields' => $fields,
'is_pro' => isset( $fix->is_pro ) ? $fix->is_pro : false,
];
}
return $fixes_array;
}
/**
* Register the fixes.
*/
public function register_fixes() {
$this->load_fixes();
foreach ( $this->fixes as $fix ) {
$fix->register();
$this->maybe_run_fix( $fix );
}
}
/**
* Maybe run a fix depending on current context.
*
* @param FixInterface $fix The fix to maybe run.
*/
public function maybe_run_fix( $fix ) {
if ( 'backend' === $fix::get_type() && is_admin() ) {
$fix->run();
} elseif ( 'frontend' === $fix::get_type() && ! is_admin() ) {
$fix->run();
} elseif ( 'everywhere' === $fix::get_type() ) {
$fix->run();
}
}
/**
* Check if the theme is accessibility ready.
*
* True if the theme has the tag, false otherwise.
*
* @return bool
*/
public static function is_theme_accessibility_ready() {
if ( null !== self::$theme_is_accessibility_ready ) {
return self::$theme_is_accessibility_ready;
}
$theme = wp_get_theme();
$tags = $theme->get( 'Tags' );
self::$theme_is_accessibility_ready = is_array( $tags ) && in_array( 'accessibility-ready', $tags, true );
return self::$theme_is_accessibility_ready;
}
/**
* Maybe show a notice if the theme is accessibility-ready.
*/
public static function maybe_show_accessibility_ready_conflict_notice() {
if ( self::is_theme_accessibility_ready() ) {
?>
[
'methods' => 'GET',
'callback' => [ $this, 'get_fixes_settings' ],
'permission_callback' => function () {
return current_user_can( apply_filters( 'edac_filter_settings_capability', 'manage_options' ) );
},
],
'/fixes/update' => [
'methods' => 'POST',
'callback' => [ $this, 'update_fix_settings' ],
'permission_callback' => function () {
return current_user_can( apply_filters( 'edac_filter_settings_capability', 'manage_options' ) );
},
],
'/fix-fields/(?P[a-zA-Z0-9_-]+)' => [
'methods' => 'GET',
'callback' => [ $this, 'get_fix_fields' ],
'args' => [
'slug' => [
'required' => true,
'sanitize_callback' => 'sanitize_text_field',
],
],
'permission_callback' => function () {
return current_user_can( 'edit_posts' );
},
],
];
foreach ( $namespaces as $namespace ) {
foreach ( $routes as $route => $args ) {
register_rest_route( $namespace, $route, $args );
}
}
}
/**
* Handle the request to set a fix.
*
* @param \WP_REST_Request $request The request recieved through a rest call.
*
* @return \WP_Error|\WP_HTTP_Response|\WP_REST_Response
*/
public function update_fix_settings( $request ) {
// get body of the request.
$body = $request->get_json_params();
// loop through body and find fixes for those items.
foreach ( $body as $rule_slug => $settings ) {
$fix = $this->get_fix( $rule_slug );
if ( ! $fix ) {
return new \WP_Error( 'edac_fix_not_found', esc_html__( 'Fix not found', 'accessibility-checker' ), [ 'status' => 404 ] );
}
$fix_fields = $fix->get_fields_array();
foreach ( $settings as $setting => $value ) {
$sanitizer = isset( $fix_fields[ $setting ]['sanitize_callback'] ) ? $fix_fields[ $setting ]['sanitize_callback'] : [ FixesPage::class, 'sanitize_' . $fix_fields[ $setting ]['type'] ];
if ( ! $sanitizer || ! is_callable( $sanitizer ) ) {
// no sanitizer, do not save.
continue;
}
update_option( $setting, $sanitizer( $value ) );
}
}
return rest_ensure_response( [ 'success' => true ] );
}
/**
* Get fix fields and information for a specific fix.
*
* Returns the fix name, description, enabled status, and configuration fields.
*
* @param \WP_REST_Request $request The REST request.
*
* @return \WP_REST_Response|\WP_Error
*/
public function get_fix_fields( \WP_REST_Request $request ) {
$fix_slug = sanitize_text_field( $request['slug'] );
// Get the fix instance.
$fix = $this->get_fix( $fix_slug );
if ( ! $fix ) {
return new \WP_Error(
'fix_not_found',
__( 'Fix not found.', 'accessibility-checker' ),
[ 'status' => 404 ]
);
}
// Get the fix's fields array.
$fields = $fix->get_fields_array();
// Check if the fix is enabled.
$option_key = 'edac_fix_' . $fix_slug;
$enabled = (bool) get_option( $option_key, false );
// Build a simplified fields array for display in the modal.
$display_fields = [];
foreach ( $fields as $field_key => $field ) {
$display_fields[ $field_key ] = [
'label' => isset( $field['label'] ) ? wp_kses_post( $field['label'] ) : '',
'description' => isset( $field['description'] ) ? wp_kses_post( $field['description'] ) : '',
'type' => isset( $field['type'] ) ? sanitize_text_field( $field['type'] ) : 'text',
'value' => get_option( $field_key, $field['default'] ?? '' ),
];
}
return new \WP_REST_Response(
[
'success' => true,
'fix_slug' => $fix_slug,
'fix_name' => $fix::get_nicename(),
'enabled' => $enabled,
'fields' => $display_fields,
],
200
);
}
}