diff --git a/.github/workflows/build-plugin-with-ref.yml b/.github/workflows/build-plugin-with-ref.yml new file mode 100644 index 000000000..1124e973c --- /dev/null +++ b/.github/workflows/build-plugin-with-ref.yml @@ -0,0 +1,329 @@ +name: Build Accessibility Checker Plugin with Ref Param + +on: + workflow_dispatch: + inputs: + ref_param: + description: "Ref param string to set in EDAC_REF_PARAM (optional)" + required: false + type: string + pull_request: + types: [labeled] + release: + types: [created, published] + +permissions: + contents: write + pull-requests: write + +jobs: + build-plugin: + name: Build plugin zip + runs-on: ubuntu-latest + # Run on release, manual, or PR when a specific label is added + if: | + github.event_name == 'release' || + github.event_name == 'workflow_dispatch' || + (github.event_name == 'pull_request' && (contains(github.event.pull_request.labels.*.name, 'gha-build') || contains(github.event.pull_request.labels.*.name, 'gha-build-all'))) + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Determine mode and ref param for this run + id: setref + run: | + MODE="${{ github.event_name }}" + echo "mode=$MODE" >> $GITHUB_OUTPUT + # Manual run: take input if provided; else empty + if [ "$MODE" = "workflow_dispatch" ]; then + REF_INPUT="${{ github.event.inputs.ref_param }}" + echo "ref_param=${REF_INPUT}" >> $GITHUB_OUTPUT + # For manual mode: if ref is provided, skip primary build + if [ -n "$REF_INPUT" ]; then + echo "skip_primary=true" >> $GITHUB_OUTPUT + else + echo "skip_primary=false" >> $GITHUB_OUTPUT + fi + # Release: use fixed ref 'woocommerce' + elif [ "$MODE" = "release" ]; then + echo "ref_param=woocommerce" >> $GITHUB_OUTPUT + echo "skip_primary=false" >> $GITHUB_OUTPUT + # PR labeled: check which label + else + # Check if gha-build-all label is present (build both) + if echo "${{ github.event.pull_request.labels.*.name }}" | grep -q "gha-build-all"; then + echo "ref_param=woocommerce" >> $GITHUB_OUTPUT + echo "skip_primary=false" >> $GITHUB_OUTPUT + else + # gha-build label (build primary only) + echo "ref_param=" >> $GITHUB_OUTPUT + echo "skip_primary=false" >> $GITHUB_OUTPUT + fi + fi + + - name: Show selected mode/ref + run: | + echo "Triggered on: $GITHUB_EVENT_NAME" + echo "Mode: ${{ steps.setref.outputs.mode }}" + echo "Head ref: ${{ github.head_ref }}" + echo "PR number: ${{ github.event.pull_request.number }}" + echo "Release tag: ${{ github.event.release.tag_name }}" + echo "Ref param: ${{ steps.setref.outputs.ref_param }}" + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + cache-dependency-path: package-lock.json + + - name: Cache node_modules + uses: actions/cache@v4 + with: + path: node_modules + key: node-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + node-${{ runner.os }}- + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + tools: composer + coverage: none + + - name: Install Composer dependencies + run: | + if [ -f composer.json ]; then composer install --no-dev --prefer-dist --no-progress --no-interaction; else echo "No composer.json"; fi + + - name: Install npm dependencies + run: | + if [ -f package.json ]; then + if [ -d node_modules ]; then + echo "node_modules cache hit, skipping install" + else + npm ci --prefer-offline --no-audit + fi + else + echo "No package.json" + fi + + - name: Extract plugin version and commit hash + id: version + run: | + VERSION=$(grep "Version:" accessibility-checker.php | head -1 | sed 's/.*Version:[[:space:]]*\([^ ]*\).*/\1/') + SHORT_SHA=$(git rev-parse --short HEAD) + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT + echo "Plugin version: $VERSION" + echo "Short commit hash: $SHORT_SHA" + + - name: Verify EDAC_REF_PARAM is empty before first build + if: steps.setref.outputs.skip_primary != 'true' + run: | + grep -n "define( 'EDAC_REF_PARAM', '' )" accessibility-checker.php || { echo "EDAC_REF_PARAM should be empty for first build"; exit 1; } + + - name: Build primary dist zip (empty ref) + if: steps.setref.outputs.skip_primary != 'true' + run: | + echo "Building primary zip with empty ref..." + npm run dist + ZIP_PATH=$(ls -1 dist/*.zip build/*.zip 2>/dev/null | head -n 1 || true) + if [ -z "$ZIP_PATH" ]; then + ZIP_PATH=$(ls -1 *.zip 2>/dev/null | head -n 1 || true) + fi + if [ -z "$ZIP_PATH" ]; then + echo "Error: Could not locate produced zip after npm run dist" >&2 + exit 1 + fi + mkdir -p builds + + # Construct the new filename based on trigger mode + VERSION="${{ steps.version.outputs.version }}" + SHORT_SHA="${{ steps.version.outputs.short_sha }}" + + if [ "${{ github.event_name }}" = "pull_request" ]; then + # PR: accessibility-checker-{version}-{prnumber}-{hash}.zip + PRIMARY_ZIP_NAME="accessibility-checker-${VERSION}-${{ github.event.pull_request.number }}-${SHORT_SHA}.zip" + elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + # Manual: accessibility-checker-{version}-{hash}.zip + PRIMARY_ZIP_NAME="accessibility-checker-${VERSION}-${SHORT_SHA}.zip" + elif [ "${{ github.event_name }}" = "release" ]; then + # Release: accessibility-checker-{version}.zip + PRIMARY_ZIP_NAME="accessibility-checker-${VERSION}.zip" + else + # Fallback + PRIMARY_ZIP_NAME="accessibility-checker-${VERSION}-${SHORT_SHA}.zip" + fi + + mv "$ZIP_PATH" "builds/$PRIMARY_ZIP_NAME" + PRIMARY_ZIP_BASENAME="${PRIMARY_ZIP_NAME%.zip}" + unzip -q "builds/$PRIMARY_ZIP_NAME" -d "builds/$PRIMARY_ZIP_BASENAME" + PRIMARY_ZIP_FOLDER="builds/$PRIMARY_ZIP_BASENAME" + PRIMARY_ZIP_NAME_NO_EXT="${PRIMARY_ZIP_NAME%.zip}" + echo "PRIMARY_ZIP_PATH=builds/$PRIMARY_ZIP_NAME" >> $GITHUB_ENV + echo "PRIMARY_ZIP_NAME=$PRIMARY_ZIP_NAME" >> $GITHUB_ENV + echo "PRIMARY_ZIP_NAME_NO_EXT=$PRIMARY_ZIP_NAME_NO_EXT" >> $GITHUB_ENV + echo "PRIMARY_ZIP_FOLDER=$PRIMARY_ZIP_FOLDER" >> $GITHUB_ENV + echo "Produced primary zip: builds/$PRIMARY_ZIP_NAME" + echo "Produced primary folder: $PRIMARY_ZIP_FOLDER" + + - name: Upload primary build artifact + if: steps.setref.outputs.skip_primary != 'true' + uses: actions/upload-artifact@v4 + with: + name: ${{ env.PRIMARY_ZIP_NAME_NO_EXT }} + path: ${{ env.PRIMARY_ZIP_FOLDER }} + if-no-files-found: error + + - name: Check if ref build is needed + id: check_ref + run: | + MODE="${{ steps.setref.outputs.mode }}" + REF_VALUE="${{ steps.setref.outputs.ref_param }}" + # For manual: build ref if ref is provided + # For release: always build ref (woocommerce) + # For PR: never build ref + if [ "$MODE" = "workflow_dispatch" ] && [ -n "$REF_VALUE" ]; then + echo "need_ref_build=true" >> $GITHUB_OUTPUT + echo "Ref build needed with value: $REF_VALUE" + elif [ "$MODE" = "release" ] && [ -n "$REF_VALUE" ]; then + echo "need_ref_build=true" >> $GITHUB_OUTPUT + echo "Ref build needed with value: $REF_VALUE" + else + echo "need_ref_build=false" >> $GITHUB_OUTPUT + echo "No ref build needed (mode=$MODE, ref='$REF_VALUE')" + fi + + - name: Update EDAC_REF_PARAM for second build + if: steps.check_ref.outputs.need_ref_build == 'true' + run: | + chmod +x ./scripts/update-ref-param.sh + ./scripts/update-ref-param.sh "${{ steps.setref.outputs.ref_param }}" + + - name: Verify EDAC_REF_PARAM change + if: steps.check_ref.outputs.need_ref_build == 'true' + run: | + grep -n "EDAC_REF_PARAM" accessibility-checker.php || { echo "EDAC_REF_PARAM not found"; exit 1; } + echo "Updated EDAC_REF_PARAM contents:" + grep "EDAC_REF_PARAM" accessibility-checker.php + + - name: Build ref dist zip (custom ref) + if: steps.check_ref.outputs.need_ref_build == 'true' + run: | + echo "Building ref zip with custom ref value..." + npm run dist + ZIP_PATH=$(ls -1 dist/*.zip build/*.zip 2>/dev/null | head -n 1 || true) + if [ -z "$ZIP_PATH" ]; then + ZIP_PATH=$(ls -1 *.zip 2>/dev/null | head -n 1 || true) + fi + if [ -z "$ZIP_PATH" ]; then + echo "Error: Could not locate produced zip after npm run dist" >&2 + exit 1 + fi + mkdir -p builds + + VERSION="${{ steps.version.outputs.version }}" + SHORT_SHA="${{ steps.version.outputs.short_sha }}" + REF_VALUE="${{ steps.setref.outputs.ref_param }}" + + # Ref build naming: accessibility-checker-{version}-ref-{refvalue}-{hash}.zip + REF_ZIP_NAME="accessibility-checker-${VERSION}-ref-${REF_VALUE}-${SHORT_SHA}.zip" + + mv "$ZIP_PATH" "builds/$REF_ZIP_NAME" + REF_ZIP_BASENAME="${REF_ZIP_NAME%.zip}" + unzip -q "builds/$REF_ZIP_NAME" -d "builds/$REF_ZIP_BASENAME" + REF_ZIP_FOLDER="builds/$REF_ZIP_BASENAME" + REF_ZIP_NAME_NO_EXT="${REF_ZIP_NAME%.zip}" + echo "REF_ZIP_PATH=builds/$REF_ZIP_NAME" >> $GITHUB_ENV + echo "REF_ZIP_NAME=$REF_ZIP_NAME" >> $GITHUB_ENV + echo "REF_ZIP_NAME_NO_EXT=$REF_ZIP_NAME_NO_EXT" >> $GITHUB_ENV + echo "REF_ZIP_FOLDER=$REF_ZIP_FOLDER" >> $GITHUB_ENV + echo "Produced ref zip: builds/$REF_ZIP_NAME" + echo "Produced ref folder: $REF_ZIP_FOLDER" + + - name: Upload ref build artifact + if: steps.check_ref.outputs.need_ref_build == 'true' + uses: actions/upload-artifact@v4 + with: + name: ${{ env.REF_ZIP_NAME_NO_EXT }} + path: ${{ env.REF_ZIP_FOLDER }} + if-no-files-found: error + + - name: Upload to release (both zips) + if: github.event_name == 'release' + uses: softprops/action-gh-release@v2 + with: + files: | + ${{ env.PRIMARY_ZIP_PATH }} + ${{ steps.check_ref.outputs.need_ref_build == 'true' && env.REF_ZIP_PATH || '' }} + fail_on_unmatched_files: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Comment on PR with primary build details + if: github.event_name == 'pull_request' + uses: actions/github-script@v7 + with: + script: | + const prNumber = context.payload.pull_request.number; + const runId = context.runId; + const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`; + const primaryName = process.env.PRIMARY_ZIP_NAME_NO_EXT; + + // Get the artifact ID for the download URL + const artifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: runId, + }); + + const artifact = artifacts.data.artifacts.find(a => a.name === primaryName); + const downloadUrl = artifact + ? `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/artifacts/${artifact.id}` + : runUrl; + + const body = `โœ… Accessibility Checker build (primary only)\n\n- **Artifact**: [Download ${primaryName}.zip](${downloadUrl})\n- **Workflow run**: [View logs](${runUrl})`; + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body, + }); + + - name: Remove triggering label from PR + if: github.event_name == 'pull_request' + uses: actions/github-script@v7 + with: + script: | + const prNumber = context.payload.pull_request.number; + const labels = context.payload.pull_request.labels.map(l => l.name); + const labelToRemove = labels.includes('gha-build-all') ? 'gha-build-all' : 'gha-build'; + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + name: labelToRemove, + }); + console.log(`Removed label '${labelToRemove}' from PR #${prNumber}`); + } catch (e) { + console.log(`Could not remove label '${labelToRemove}' from PR #${prNumber}: ${e.message}`); + } + + - name: Summary + run: | + echo "=== Build Summary ===" + echo "Mode: ${{ steps.setref.outputs.mode }}" + echo "Primary zip (empty ref): ${{ env.PRIMARY_ZIP_PATH }}" + if [ "${{ steps.check_ref.outputs.need_ref_build }}" = "true" ]; then + echo "Ref zip (ref=${{ steps.setref.outputs.ref_param }}): ${{ env.REF_ZIP_PATH }}" + else + echo "Ref zip: Not built" + fi + if [ "${{ github.event_name }}" = "release" ]; then + echo "Uploaded to release: ${{ github.event.release.html_url }}" + fi diff --git a/.github/workflows/verify-hooks-docs.yml b/.github/workflows/verify-hooks-docs.yml index 030252883..7d4c5a842 100644 --- a/.github/workflows/verify-hooks-docs.yml +++ b/.github/workflows/verify-hooks-docs.yml @@ -1,12 +1,9 @@ name: Verify hooks docs on: - pull_request: - paths: - - '**.php' push: branches: - - develop + - 'release/**' jobs: verify-docs: diff --git a/accessibility-checker.php b/accessibility-checker.php index efe4c772a..911b19c99 100755 --- a/accessibility-checker.php +++ b/accessibility-checker.php @@ -10,7 +10,7 @@ * Plugin Name: Accessibility Checker * Plugin URI: https://a11ychecker.com * Description: Audit and check your website for accessibility before you hit publish. In-post accessibility scanner and guidance. - * Version: 1.34.0 + * Version: 1.35.0 * Requires PHP: 7.4 * Author: Equalize Digital * Author URI: https://equalizedigital.com @@ -36,7 +36,7 @@ // Current plugin version. if ( ! defined( 'EDAC_VERSION' ) ) { - define( 'EDAC_VERSION', '1.34.0' ); + define( 'EDAC_VERSION', '1.35.0' ); } // Current database version. @@ -72,6 +72,11 @@ define( 'EDAC_DEBUG', false ); } +// Default ref is empty - we don't ref links, but it can be filtered by providers. +if ( ! defined( 'EDAC_REF_PARAM' ) ) { + define( 'EDAC_REF_PARAM', '' ); +} + // SVG Icons. define( 'EDAC_SVG_IGNORE_ICON', file_get_contents( __DIR__ . '/assets/images/ignore-icon.svg' ) ); diff --git a/admin/class-admin.php b/admin/class-admin.php index 30c8b2545..7ad570e0d 100644 --- a/admin/class-admin.php +++ b/admin/class-admin.php @@ -50,6 +50,7 @@ public function init(): void { add_action( 'admin_enqueue_scripts', [ 'EDAC\Admin\Enqueue_Admin', 'enqueue' ] ); add_action( 'wp_trash_post', [ Purge_Post_Data::class, 'delete_post' ] ); add_action( 'save_post', [ Post_Save::class, 'delete_issue_data_on_post_trashing' ], 10, 3 ); + add_filter( 'edac_filter_generate_link_type_ref', [ $this, 'add_ref_param_to_links' ], 5, 1 ); $plugin_action_links = new Plugin_Action_Links(); $plugin_action_links->init_hooks(); @@ -96,4 +97,18 @@ private function init_ajax(): void { $frontend_highlight = new Frontend_Highlight(); $frontend_highlight->init_hooks(); } + + /** + * Add ref param in links that are used through the plugin link helpers. + * + * @param string $ref Ref param. + * @return string + */ + public function add_ref_param_to_links( string $ref ): string { + if ( defined( 'EDAC_REF_PARAM' ) && ! empty( EDAC_REF_PARAM ) ) { + return EDAC_REF_PARAM; + } else { + return $ref; + } + } } diff --git a/admin/class-ajax.php b/admin/class-ajax.php index ed946a045..b8ec8388c 100644 --- a/admin/class-ajax.php +++ b/admin/class-ajax.php @@ -428,14 +428,20 @@ function ( $a, $b ) { foreach ( $results as $row ) { - $id = (int) $row['id']; - $ignore = (int) $row['ignre']; - $ignore_class = $ignore ? ' active' : ''; - $ignore_label = $ignore ? 'Ignored' : 'Ignore'; - $ignore_user = (int) $row['ignre_user']; - $ignore_user_info = get_userdata( $ignore_user ); - $ignore_username = is_object( $ignore_user_info ) ? 'Username: ' . $ignore_user_info->user_login : ''; - $ignore_date = ( $row['ignre_date'] && '0000-00-00 00:00:00' !== $row['ignre_date'] ) ? 'Date: ' . gmdate( 'F j, Y g:i a', strtotime( esc_html( $row['ignre_date'] ) ) ) : ''; + $id = (int) $row['id']; + $ignore = (int) $row['ignre']; + $ignore_class = $ignore ? ' active' : ''; + $ignore_label = $ignore ? 'Ignored' : 'Ignore'; + $ignore_user = (int) $row['ignre_user']; + $ignore_user_info = get_userdata( $ignore_user ); + $ignore_username = is_object( $ignore_user_info ) + ? '' . esc_html__( 'Username:', 'accessibility-checker' ) . ' ' . esc_html( $ignore_user_info->user_login ) + : ''; + + $ignore_date_text = $row['ignre_date'] ? edac_format_datetime_from_utc( $row['ignre_date'] ) : ''; + $ignore_date = $ignore_date_text + ? '' . esc_html__( 'Date:', 'accessibility-checker' ) . ' ' . esc_html( $ignore_date_text ) + : ''; $ignore_comment = esc_html( $row['ignre_comment'] ); $ignore_action = $ignore ? 'disable' : 'enable'; $ignore_type = $rule['rule_type']; @@ -728,8 +734,8 @@ function ( $value ) { $ignre_user = ( 'enable' === $action ) ? get_current_user_id() : null; $ignre_user_info = ( 'enable' === $action ) ? get_userdata( $ignre_user ) : ''; $ignre_username = ( 'enable' === $action ) ? $ignre_user_info->user_login : ''; - $ignre_date = ( 'enable' === $action ) ? gmdate( 'Y-m-d H:i:s' ) : null; - $ignre_date_formatted = ( 'enable' === $action ) ? gmdate( 'F j, Y g:i a', strtotime( $ignre_date ) ) : ''; + $ignre_date = ( 'enable' === $action ) ? edac_get_current_utc_datetime() : null; + $ignre_date_formatted = ( 'enable' === $action ) ? edac_format_datetime_from_utc( $ignre_date ) : ''; $ignre_comment = ( 'enable' === $action && isset( $_REQUEST['comment'] ) ) ? sanitize_textarea_field( wp_unslash( $_REQUEST['comment'] ) ) : null; $ignore_global = ( 'enable' === $action && isset( $_REQUEST['ignore_global'] ) ) ? sanitize_textarea_field( wp_unslash( $_REQUEST['ignore_global'] ) ) : 0; diff --git a/admin/class-enqueue-admin.php b/admin/class-enqueue-admin.php index 32197dd00..77c3e449c 100644 --- a/admin/class-enqueue-admin.php +++ b/admin/class-enqueue-admin.php @@ -140,6 +140,7 @@ public static function maybe_enqueue_admin_and_editor_app_scripts() { 'scanUrl' => $scan_url, 'maxAltLength' => max( 1, absint( apply_filters( 'edac_max_alt_length', 300 ) ) ), 'version' => EDAC_VERSION, + 'postStatus' => get_post_status( $post_id ), 'restNonce' => wp_create_nonce( 'wp_rest' ), ] ); diff --git a/admin/class-scans-stats.php b/admin/class-scans-stats.php index d2bd08182..f8fcea954 100644 --- a/admin/class-scans-stats.php +++ b/admin/class-scans-stats.php @@ -299,9 +299,10 @@ function ( $item ) { JOIN ( SELECT DISTINCT postid FROM ' . $wpdb->prefix . 'accessibility_checker + WHERE ignre=%d AND ignre_global=%d ) AS distinct_posts ON ' . $wpdb->postmeta . '.post_id = distinct_posts.postid WHERE meta_key = %s', - [ '_edac_issue_density' ] + [ 0, 0, '_edac_issue_density' ] ) ); diff --git a/admin/class-widgets.php b/admin/class-widgets.php index a9977297f..2d75b4cbc 100644 --- a/admin/class-widgets.php +++ b/admin/class-widgets.php @@ -281,13 +281,16 @@ public function render_dashboard_scan_summary() { Edit Accessibility Checker Settings '; - $html .= ' + $meetup_html = edac_get_upcoming_meetups_html( 'wordpress-accessibility-meetup-group', 2, 4 ); + if ( ! empty( $meetup_html ) ) { + $html .= '

' . __( 'Learn Accessibility', 'accessibility-checker' ) . '

'; - $html .= edac_get_upcoming_meetups_html( 'wordpress-accessibility-meetup-group', 2, 4 ); + $html .= $meetup_html; + } $html .= '
@@ -309,7 +312,7 @@ public function render_dashboard_scan_summary() { $html .= '' . __( 'Blog', 'accessibility-checker' ) . ''; $html .= '' . __( 'Documentation', 'accessibility-checker' ) . ''; - //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- content is being escaped as it is being produced, late escaping would be more complicated and unreadable echo $html; } } diff --git a/changelog.txt b/changelog.txt index 685be1dcd..f93faaa12 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,709 +1,253 @@ -Newer versions can be found in readme.txt. - -= 1.28.0 = -* Added: Better descriptions and help text for each of the rules. -* Added: Improved landmark location feature to show the location of the landmark in the DOM. -* Fixed: Avoid possible error with removal of an index on an ID column. - -= 1.27.1 = -* Fixed: Don't alter a UNIQUE index before swapping to PRIMARY key index. - -= 1.27.0 = -* Added: Landmark Location feature. -* Added: Plugin action links. -* Fixed: Allow frontend highlighter to kickoff scan if there are no issues for the page. -* Fixed: Average issues per post calculation to handle zero issues. -* Added: Documentation, support, and rate plugin links to plugin row meta. -* Added: Admin toolbar with quick links. -* Updated: UNIQUE KEY to PRIMARY KEY for id column, bumped DB version to 1.0.4. -* Updated: link_improper now lets links with role of tab pass. - -= 1.26.0 = -* Enhanced: Better translation handling across the plugin. - -= 1.25.0 = -* Added: Ability to scan the main posts archive (blog page). -* Enhanced: Improved the Anchor Exists rule to handle more situations. -* Fixed: Avoid console error for clear button on CPTs that are not scannable. - -= 1.24.0 = -* Added: Translations for 33 languages. -* Enhanced: Handle Elementor buttons better in the new warnings fix. -* Fixed: Several typo and grammar issues corrected in the plugin. -* Fixed: Signup modal now works in Firefox under more conditions. -* Fixed: Make sure that translations in JS files can be detected. - -= 1.23.1 = -* Changed: Remove the str_get_html fallback shim. - -= 1.23.0 = -* Added: Jest testing framework for accessibility rules with test case generation. -* Changed: Added fallback for str_get_html() with deprecation notice. -* Changed: Added density calculation capability in JS scanner. -* Removed: Legacy PHP scan code. -* Removed: PHP Simple HTML DOM Parser. -* Converted: video_present rule to JS. -* Converted: slider_present rule to JS. -* Converted: missing_transcript rule to JS. -* Converted: missing_subheadings rule to JS. -* Converted: link_improper rule to JS. -* Converted: link_non_html_file rule to JS. -* Converted: longdesc_invalid rule to JS. -* Converted: missing_table_header rule to JS. -* Converted: incorrect_heading_order rule to JS. -* Converted: img_alt_empty rule to JS. -* Converted: img_alt_long rule to JS. -* Converted: img_map_missing_alt rule to JS. -* Converted: link_empty rule to JS. -* Converted: linked_image_missing_alt rule to JS. -* Converted: linked_image_empty rules to JS. -* Converted: aria_hidden rule to JS. -* Converted: empty_button rule to JS. -* Converted: duplicate_form_label rule to axe-core compatible JS rule with conditional support for incomplete items. -* Converted: empty_heading_tag rule to JS. -* Converted: empty_table_header rule to JS. -* Converted: iframe_missing_title rule to JS. -* Converted: img_alt_redundant rule to JS. -* Converted: img_alt_invalid rule to JS. -* Converted: img_alt_missing rule to JS. -* Converted: animated_gif rule to JS. -* Converted: broken_aria_reference rule to JS. - -= 1.22.2 = -* Enhancement: Announce Global Accessibility Awareness Day in the admin during that week. - -= 1.22.1 = -* Enhancement: Make the skip-link fix handle sites with forced smooth scroll. -* Enhancement: Make the zooming and scaling handle additional ways the tag can block scaling. -* Fix: Swap to graphql for getting meetup data for display in the admin. - -= 1.22.0 = -* Enhancement: Improve the new window warning migration to handle more edge cases. -* Fix: Avoid checking theme Tags when theme sandbox recovery is in play. -* Fix: When parsing block content for scanning avoid stomping on post_content of a global. - -= 1.21.0 = -* Enhancement: Improve how density statistics are counted. You will see a notice about this change on the welcome page. -* Fix: Ensure that the scanned posts counts are accurate to all posts scanned, not just ones that have issues. -* Fix: Properly count posts that are scanned but have no issues to remediate. - -= 1.20.0 = -* Enhancement: Process dynamic blocks and oEmbeds more reliably in scans. -* Enhancement: Improve detection for missing_transcripts if there are several oEmbed videos from same provider on page. -* Fix: Ensure notice dismiss function works correctly on all pages and that review notice buttons are styled. -* Fix: Correct some cases where pluralization of phrases could be misapplied. - -= 1.19.0 = -* Enhancement: Improve the text_size_too_small check in scanner to avoid more false positives. -* Fix: Ensure that our notifications can appear on our own admin pages. -* Fix: No longer trigger password protected notice on other pages when scanning woocommerse checkout page. - -= 1.18.0 = -* New: Add a new fix for adding a new tab/window warning to links with target="_blank". -* Enahncement: Allow cache bypass from stats requests to force latest numbers. -* Enhancement: Make a clear-issues endpoint more usable in different situations. -* Removed: Removed some code that was trying to force no notifications on the plugin pages. - -= 1.17.0 = -* New: Add a new fix for adding a new tab/window warning to links with target="_blank". -* New: Add a REST endpoint to retrieve a site scan summary. -* Enhancement: Ensure frontend highlighter can load even when Cloudflare Rocket Loader is enabled. -* Enhancement: Only show ignore button when user can ignore issues. -* Fix: URLs without issues would always output `0` when viewed on welcome widget. - -= 1.16.4 = -* Enhancement: Improve the table header detection and validation for row headers. -* Enhancement: Show notice on fixes settings when they are saved from options page. -* Fixed: Don't check for possible headerif there is no text content. -* Fixed: Multisite query fix to make sure issues are assigned correct site id. -* Fixed: Correct where a scan link points. - -= 1.16.3 = -* Enhancement: Add Fix settings to site health info panels. -* Fixed: Corrected a string that was misplaced in a fix. - -= 1.16.2 = -* Enhancement: Use better names for fix modal titles. -* Enhancement: Improve the link_pdf rule to detect more accurately. -* Enhancement: Improve the link_ms_office_doc rule to detect more accurately. -* Fixed: Rely on labels for link_ambiguous_text rule first before checking just the text content. -* Fixed: Remove a duplicatable rule empty_form_label. - -= 1.16.1 = -* Fixed: Remove redundant empty_form_label rule definition. - -= 1.16.0 = -* New: Introduced a system to handle automated fixes for issues that the scanner would discover. -* New: Fix to remove or update bad tabindex values on elements. -* New: Fix to remove title attributes in favor of preferred accessible names to elements. -* New: Fix to add missing lang and dir attributes to the element. -* New: Fix to add skip links to pages where they are missing. -* New: Fix to add labels to comment and search forms. -* New: Fix to ensure that the meta viewport tag does not prevent user scaling or zooming. -* New: Fix to ensure that focus outlines are present on focusable elements. -* Enhancement: Improve the tabindex_modified check to handle every element with tabindex. -* Enhancement: Improve the link_blank rule to check on fully rendered pages. -* Enhancement: Improve the link_ambiguous_text rule to check on fully rendered pages. -* Enhancement: Improve the broken_skip_anchor_link rule to check on fully rendered pages. -* Enhancement: Improve the html lang and dir attribute check to on check fully rendered pages. -* Enhancement: Improve the document title check to check on fully rendered pages. -* Enhancement: Add a clear button to the editor to allow for . -* Enhancement: Improved GTM iframe detection. -* Fixed: Avoid showing 100% passed results when scans are not complete. -* Fixed: Improve or add better aria-labels in several places. -* Fixed: Don't flag empty paragraphs if they have aria-hidden. - -= 1.15.3 = -* Enhancement: Detect missing labels on more elements. -* Enhancement: Detect slick slider that gets initialized after the page loads. - -= 1.15.2 = -* Fixed: Issue where CPT results would not be reflected in dashboard widgets and reports - -= 1.15.1 = -* Fixed: Issue where a modal could result in JS error preventing display -* Fixed: Situations where Gutenberg created new posts may not trigger the JS scan when publishing - -= 1.15.0 = -* Added: WP-CLI commands to get stats and delete stats -* Enhancement: Image inputs with alt text shouldn't flag for missing_form_label -* Fixed: Don't flag .avif as missing transcript or video present -* Fixed: Purge the post data if the saved post is in or is moving to the trash -* Fixed: Handle stacking contexts for callout button in admin correctly -* Fixed: PHP 8.4 deprecation notice fix for implicitly nullable Meta_Boxes - -= 1.14.3 = -* Fixed: Allow empty_link rule to detect actually empty links - -= 1.14.2 = -* Enhancement: Reduce false positives for underlined text check -* Fixed: Frontend highlighter could not be moved to the right side of the window on mobile -* Fixed: Issue where ignores were not being saved and failing silently - -= 1.14.1 = -* Fixed: Prevent settings page layout issue - -= 1.14.0 = -* Added: Option to move front-end highlighter to opposite side of the window -* Fixed: Prevent image from overspilling container in issue view -* Fixed: Make empty paragraph check more accurate -* Enhancement: Improved styling for settings page -* Enhancement: Updated summary widget with better semantics -* Enhancement: Improved aria labeling for view on page links -* Enhancement: Added large batch processing capabilities for issue ignoring - -= 1.13.1 = -* Enhancement: Make the new window warning detection less rigid -* Fixed: Avoid flagging possible headings when the entire text is not wrapped -* Fixed: Allow JS checked rules to retain ignored state between scans - -= 1.13.0 = -* Added: Meta Viewport zoom-able and scale-able check -* Added: Empty Paragraph warning -* Fixed: Properly determine possible headings with computed styles -* Improved: Better detection of the underlined text -* Improved: Better detection of small text -* Improved: Better detection of justified text -* Improved: Better detection of blink and marquee tags -* Improved: No longer flagging GTM iframes as missing title since they are display: none and visibility: hidden -* Enhancement: Do not show 'View on page' link to frontend when the issues cannot be viewed - -= 1.12.0 = -* Fixed: Use the last generation time in summary widgets rather than last completed scan time -* Improved: More accessible panels in the editor -* Improved: Filter and action docs added/improved - -= 1.11.2 -* Fixed: Avoid displaying `0th` for readability score -* Removed: Some custom WP Playground detection code - -= 1.11.1 = -* Fixed: type Casting on several rules -* Fixed: strict data comparison on several rules -* Updated: empty heading tag rule to consider aria-label - -= 1.11.0 = -* Updated: Tested up to WP 6.5.2 -* Improved: Better detection of the underlined text rule for more accurate results -* Improved: PHP 8.2 compatibility with the TextStatistics library -* Added: Opt-in modal for users to subscribe to the Equalize Digital newsletter with less steps - -= 1.10.2 = -* Updated: Tested up to WP 6.5.0 - -= 1.10.1 = -* Fixed: Prevent scheme-relative URLs from causing an error when scanning for animated gif of webp files -* Fixed: Potential edge case where an issue density calculation could cause a PHP warning and cause a failed scan -* Fixed: Ensure that missing form labels are reported in the scan results appropriately -* Fixed: Avoid error log when trashing posts in the block editor -* Created: Class to handle the editor meta box for scan results -* Deprecated: `edac_register_meta_boxes`, `edac_custom_meta_box_cb` functions - -= 1.10.0 = -* Updated: Improved aria-hidden scanning rule -* Fixed: Prevent missing_transcript rule from flagging on certain links -* Fixed: Prevent duplicate scan and ensure cleanup runs when post is trashed from the block editor -* Fixed: Fix case where error may be thrown resulting in password protection message and logged error when creating new posts -* Updated: Use local styles for notyf in frontend highlighter -* Created: Class to insert scan result rules to the database -* Deprecated: `edac_insert_rule_data` function -* Created: Class to handle data purging and cleanup -* Deprecated: `edac_delete_post`, `edac_delete_post_meta`, `edac_delete_cpt_posts` functions - -= 1.9.3 = -* Updated: capability checks for the welcome page, dashboard widget, and admin notices - -= 1.9.2 = -* Fixed: filtered rules are not passed to the frontend highlighter, avoiding 'null' state issues -* Updated: frontend highlighter buttons to be disabled until issues are confirmed -* Updated: frontend highlighter buttons to show only after we know there are issues to display -* Updated: frontend highlighter to not show buttons if none are returned - -= 1.9.1 = -* Updated: `edac_include_rules_files to fire on init action to fix the `edac_filter_register_rules` filter timing - -= 1.9.0 = -* Created: class that creates the accessibility statement on activation -* Removed: custom database query that checked for existing accessibility statement in exchange for the `get_page_by_path()` function -* Fixed: bug with trying to compare the simplified summary ordinal value and added fallback -* Removed: `wp_send_json_error()` from `simplified_summary` Ajax function when the simplified summary is empty -* Added: simplified summary grade*level, message, and icon logic to the `summary()` Ajax -* Fixed: issue with the submit button text showing as `Submit Query` in Firefox. -* Updated: missing transcript rule to skip certain types of links -* Added: missing UTM parameters to the welcome page URLs. -* Removed: legacy system information code -* Removed: cbschuld/browser.php composer package -* Added: class structure for site health -* Added: site health health information for free, pro, and audit history plugins -* Added: update database class -* Removed: `edac_before_page_render` functions from the main file -* Added: frontend validate class -* Added: frontend validate unit tests -* Removed: unused new window warning meta update functions -* Fixed: front end highlight focus issue -* Added: summary generator class to replace the `edac_summary()` function -* Deprecated: `edac_summary()` function - -= 1.8.1 = -* Fixed: false positives on the incorrect heading order rule -* Added: fallback to determine ordinal when php intl extension is not installed - -= 1.8.0 = -* Updated: heading order on welcome screen -* Updated: missing_title summary -* Updated: SQL prepare queries to use %i placeholder -* Updated: incorrect textdomains and made strings translatible -* Removed: single-use variables where possible -* Added: PHPUnit framework and workflow -* Added: unit test for the `edac_compare_strings` function -* Added: unit test for the `edac_parse_css` function -* Updated: the `edac_compare_strings` function to be more efficient, return the correct type, and fix the failing tests -* Updated: `readme.txt` to only have the latest major and minor changelog -* Added: `changelog.txt` file. -* Added: `includes/rules.php` file that contains all rules and returns them as an array -* Added a static var in the `edac_register_rules` function to avoid re-reading the `includes/rules.php` file every time the method is called -* Removed: `has_filter` check before calling `apply_filters` -* Added: `edac_register_rules` unit test -* Added: `edac_check_plugin_active` deprecated function -* Updated: `edac_check_plugin_active` calls with `is_plugin_active` -* Removed: calls to `add_option` and replaced with `update_option` -* Updated: Use of `else` statement and bailed early when needed -* Removed: `has_filter()` before applying apply_filters -* Removed: hooks from `EDAC\Admin_Notices` constructor and call them from the `init_hooks` method -* Added: `EDAC\Admin_Notices` unit tests -* Added: `EDAC\Ajax` class and moved AJAX functions into this class -* Removed: unnecessary `wp_ajax_nopriv_` hooks -* Added: namespace to `Frontend_Highlight` class and only instantiated on `DOING_AJAX` -* Removed: `EDAC_SVG_IGNORE_ICON` string and pulled it from the file -* Removed: `$plugin_check` global variable -* Removed: `$rules` global variable -* Updated: `edac_ordinal` function to support all locales, safeguards against improper inputs, number format -* Updated: JavaScript coding standards -* Added: `includes/classes` directory to autoloader -* Added: new directory admin to autoloader -* Removed: `require_once` class calls -* Created: `class-plugin.php` to load frontend classes -* Created: `class-admin.php` to load admin classes -* Updated: classes to follow new `EDAC\Admin` and `EDAC\Inc` namespaces -* Updated: accessibility statement functions to a class -* Updated: simplified summary functions to a class -* Updated: lazyload Filter function into a class -* Removed: removes calls to `add_post_meta` and uses `update_post_meta` where appropriate -* Added: `EDAC\Inc\Accessibility_Statement` unit test -* Added: `EDAC\Inc\Simplified_Summary` unit test -* Added: local PHPUnit to run on wp-env test -* Updated: enqueue scripts and styles setup to only load assets in the proper environments -* Updated: email signup form - -= 1.7.1 = -* Fixed: classic editor save conflict -* Fixed: password protection message displaying repeatedly -* Fixed: frontend highlighting asset url and debug error - -= 1.7.0 = -* Added: Architecture for JavaScript-based checks for better code analysis -* Updated: Color contrast check now uses axe-core rule for improved accuracy -* Fixed: Issue with frontend highlighting panel blocking interactions -* Fixed: Compatibility issue with PHP 8+ related to 'false' to array conversion -* Removed: PHP color contrast check replaced with axe-core rule -* Fixed: Conflict with RSS feeds - -= 1.6.8 = -* Updated: system info to stop showing edac_authorization_username & edac_authorization_username -* Updated: system info to show edacp_authorization_username & edacp_authorization_username for pro users - -= 1.6.7 = -* Updated: logic for Link to MS Office file -* Updated: last full-site scan label and date format - -= 1.6.6 = -* Added: ability to force refresh welcome screen report - -= 1.6.5 = -* Fixed: function edac_password_protected_notice_text to call from the admin notices class - -= 1.6.4 = -* Fixed: password protected admin noticed function call - -= 1.6.3 = -* Added: email opt-in to welcome page -* Added: support for formatting numbers and percentages in PHP installs that were build without the intl library -* Added: the see history button for audit history add-on -* Updated: admin notices to load from a custom class - -= 1.6.2 = -* Added: check for WordPress Playground - -= 1.6.1 = -* Updated: passed percentage calculation -* Updated: frontend highlighting disable styles to be compatible with optimization plugins -* Fixed: average issue density percentage not accounting for site ID and ignores -* Updated: body density to receive HTML rather than the dom object -* Updated: empty link check logic -* Added: minor coding standards improvements - -= 1.6.0 = -* Added: dashboard reports widget -* Added: frontend highlighting page scan trigger -* Added: enhancements to the Low-quality Alternative Text check -* Fixed: adherence to coding standards -* Fixed: frontend highlighting responsiveness on mobile -* Fixed: frontend highlighting's broken ARIA reference -* Fixed: Issue Density bug when creating a new post -* Fixed: a bug on the reports dashboard widget and welcome page when no post types are selected in the settings -* Fixed: settings page tab order bug -* Updated: scanning process to exclude the admin bar and the query monitor -* Updated: improvements to the Ambiguous Anchor check -* Updated: the Browser.php class has been restructured to load via Composer -* Updated: the TextStatistics class is now loaded through Composer -* Updated: text domain and internationalization on user-facing strings -* Updated: reports dashboard widget and welcome page now have improved refresh and caching -* Updated: the date format on the reports dashboard widget and the welcome page now respects the site's timezone setting -* Updated: Improved performance during the purge of issues after changing the "post types to scan" setting -* Removed: CSS output when a user is logged out - -= 1.5.6 = -Fixed: reading level ajax timing issue - -= 1.5.5 = -Fixed: frontend highlighting description panel close button JavaScript error -Fixed: frontend highlighting no issues detected JavaScript error -Fixed: frontend highlighting panel close button bug - -= 1.5.4 = -Updated: welcome page data caching for better performance -Removed: dashboard reports widget - -= 1.5.3 = -Updated: prevent enqueue scripts from running if global post is not defined - -= 1.5.2 = -Fixed: missing class -Removed: Freemius - -= 1.5.1 = -Updated: button screen reader text - -= 1.5.0 = -Added: site wide summary -Added: accessibility checker dashboard widget -Updated: welcome page -Updated: frontend highlighting accessibility - -= 1.4.4 = -Removed: unused class - -= 1.4.3 = -Updated: frontend highlighting to allow ignored items accessed via the view on page button -Updated: frontend highlighting panel logic to match selected post types in the settings -Updated: frontend highlighting button size and placement improvements -Updated: frontend highlighting number of issues output -Updated: frontend highlighting scroll-to improvements -Fixed: Freemius icon output -Updated: demo video - -= 1.4.2 = -Added: frontend highlighting loading message -Removed: frontend highlighting ignored issues -Removed: frontend highlighting from customizer -Fixed: frontend highlighting link styles -Updated: frontend highlighting to allow elements that violate multiple rules -Fixed: frontend highlighting elements not highlighting after closing the controls panel -Fixed: frontend highlighting not finding images due to extra whitespace -Updated: ambiguous text check to ignore svgs and icons -Updated: animated gif check include animated webP images -Updated: animated gif check to disregard URL parameters -Fixed: undefined array key "query" -Fixed: Reading level icon logic - -= 1.4.1 = -Updated: Freemius SDK to the latest version - -= 1.4.0 = -Added: frontend issue highlighting -Updated: simple html dom to use strict on seek call to fix issue with too much recursion with complicated CSS -Added: description and warning for Post Types to be Checked - -= 1.3.28 = -Fixed: enqueue error on empty post types - -= 1.3.27 = -Fixed: uninstall delete data - -= 1.3.26 = -Fixed: database creation bug -Fixed: simplified summary output - -= 1.3.25 = -Fixed: video is present duplicating issues -Updated: Missing subheadings word count -Updated: prompt for simplified summary aded never option -Fixed: minor coding standards -Updated: Freemius SDK to version 2.5.8 - -= 1.3.24 = -Added: user_agent to file_get_html context -Added: follow_location to file_get_html context to prevent scanning of offsite links -Added: querystring check to file_get_html url to prevent malformed urls when the cache breaker string is appended -Updated: get CSS via wp_remote_get - -= 1.3.23 = -Added: GAAD Admin Notice - -= 1.3.22 = -Fixed: conflict with full site editor -Fixed: bug with the Image Empty Alternative Text check not detecting images -Fixed: bug with ignore button not working on the open issues and the ignore log - -= 1.3.21 = -Fixed: issue of reading level & simplified summary mismatching -Updated: password protected admin notice to be dismissable -Updated: position of password protected notice on single post -Fixed: issue with summary panel not showing if password protected - -= 1.3.20 = -Updated: freemius to the latest version - -= 1.3.19 = -Updated: color contrast failure check - -= 1.3.18 = -Updated: system info custom post type output - -= 1.3.17 = -Fixed: license constant conflict - -= 1.3.16 = -Fixed: issue with ignored issues being removed on post save -Fixed: issue with escaped html displaying on simplified summary -Fixed: Ignored items label - -= 1.3.15 = -Remove: license tab -Updated: license checks - -= 1.3.14 = -Added: security fixes - -= 1.3.13 = -Fixed: nonce plugin update conflict - -= 1.3.12 = -Added: added security check to system info download - -= 1.3.11 = -Updated: quick edit save to check if _inline_edit array key is set - -= 1.3.10 = -Added: image column to details panel to display issue image -Updated: details rule name to an H3 and added hidden h4 for each issue -Added: aria-label to details expand button -Added: space between number and error name in error details list -Added: aria-expanded and aria-controls to buttons on details panel - -= 1.3.9 = -Added: filter edac_no_verify_ssl to bypass SSL validation. Use: add_filter( 'edac_no_verify_ssl', '__return_true' ); -Fixed: undefined variable error color contrast failure check - -= 1.3.8 = -Updated: database index on postid for better performance - -= 1.3.7 = -Fixed: issue when restricted websites fail to generate post meta - -= 1.3.6 = -Fixed: password protection notice logic - -= 1.3.5 = -Fixed: marketing notice logic - -= 1.3.4 = -* Updated: ARIA Hidden check to ignore for core spacer block -* Updated: Ambiguous Anchor Text check to disregard spaces and punctuation -* Updated: Footer statement link with 'opens in new window' aria-label -* Updated: Link Opens New Window or Tab check to search for contained phrases rather than equal to phrases -* Added: Support for role attribute to Missing Subheadings and Incorrect Heading Order checks -* Added: Improper Use of Link check -* Updated: Broken Skip or Anchor Link check to exclude error now flagged by the Improper Use of Link check -* Added: Password protection notices - -= 1.3.3 = -* Fixed: force color contrast font size value - -= 1.3.2 = -* Fixed: minor bug in replace css variables function - -= 1.3.1 = -* Fixed: compiled JavaScript to latest version - -= 1.3.0 = -* Removed: Admin Notices from plugin settings pages -* Updated: Location of ignore count and made less ambiguous on the details tab -* Fixed: Code snippet wrapping -* Updated: Database check to ensure tables exist -* Added: Rule summary text to rules array - -= 1.2.14 = -* Show Open Issues and Ignore Log admin pages to users with ignore permissions bug fix - -= 1.2.13 = -* Show Open Issues and Ignore Log admin pages to users with ignore permissions -* Fix bug when post types setting was blank - -= 1.2.12 = -* Updates to system info - -= 1.2.11 = -* Fix conflict with widgets block editor -* Fix post types setting bug - -= 1.2.10 = -* Fix issue with unmatched reading levels - -= 1.2.9 = -* Add support for PHP 8 -* Make helper icons links less ambiguous - -= 1.2.8 = -* Freemius Update - -= 1.2.7 = -* Add accessibility statement page template - -= 1.2.6 = -* Minor accessibility updates - -= 1.2.5 = -* System info updates - -= 1.2.4 = -* Add Oxygen Builder shortcode content to readability scan - -= 1.2.3 = -* On save check post types to prevent menu save error - -= 1.2.2 = -* Add support for Accessibility New Window Warning Plugin -* Delete issues and meta data when post is added to trash -* Color Contrast and Possible Heading minor bug fixes -* Fixed post type purge bug when saving settings -* Review notification - -= 1.2.1 = -* Fixed database version that was preventing the database from being created on activation - -= 1.2.0 = -* Improved ambiguous text check to include aria-label and aria-labelledby -* Color contrast adjust ratio based on font size -* Ajax security improvements -* Basic CSS veriable support -* Fast Track -* Added support for Oxygen Builder - -= 1.1.3 = -* Code object word break - -= 1.1.2 = -* Improve legacy PHP compatibility - -= 1.1.1 = -* Added filter for readability score content - -= 1.1.0 = -* System info output added to settings - -= 1.0.13 = -* Prevent page refresh when using classic editor - -= 1.0.12 = -* Improved accuracy of skipped heading level - -= 1.0.11 = -* Added informative error code to text justified and check within CSS -* Update missing language attribute to only check the first html tag - -= 1.0.10 = -* Text underlined, text small improvements -* Updated deprecated jQuery - -= 1.0.9 = -* Updates to missing title check - -= 1.0.8 = -* Added support for fullsite scan -* Added actions for log - -= 1.0.7 = -* Ensure checks are not run if content not retrieved -* Minor text fixes - -= 1.0.6 = -* Check full page for issues -* Check draft posts -* Remove color contrast from error count -* Update missing heading and heading order checks - -= 1.0.5 = -* On post validate check that the post is published. - -= 1.0.4 = -* Update policy page sanitize logic to allow for undefined value - -= 1.0.3 = -* Minor bug fixes to activation redirect and quick edit post updating -* Image map missing alternative text error if only a space is present - -= 1.0.2 = -* use uninstall.php instead of register_uninstall_hook -* add option to delete all data on uninstall - -= 1.0.1 = -* update requires version -* fix tooltip links -* add filter to get_content function -* update post empty logic - -= 1.0.0 = -* Everything is new and shiny. -* We think it's awesome you want to make your website more accessible. -* Check for giphy and tenor animated gifs +*** Accessibility Checker *** +2025-12-05 - version 1.35.0 +* Fix - Ignored issues no longer count in density scores. +* Fix - Ignored issues count comparison and message logic in frontend highlighter. +* Fix - Allow long translations to wrap in new window warning tooltip. +* Fix - Improve sanitization that would prevent checkboxes saving on first attempt in some cases. +* Fix - Dashboard widget to conditionally display upcoming meetups and improve meetup data handling. +* Fix - Make highlighter controls translatable. +* Tweak - Add better help article link for new window warning fix. +* Tweak - Use WordPress data functions instead of server time for ignore date formatting. + +2025-10-22 - version 1.34.0 +* Tweak - Missing transcript can now detect transcripts for videos when they are not just direct siblings. +* Tweak - Use post type labels rather than slugs in views where applicable. +* Tweak - Prepare for sale event during Black Friday. + +2025-09-26 - version 1.33.0 +* Add - WP-CLI commands can now be run with short names: `wp edac ` or using long name `wp accessibility-checker `. +* Tweak - Made it easier to register custom commands through filter. + +2025-09-18 - version 1.32.0 +* Fix - Improved highlighter behavior to maintain original size and position of scanned elements. +* Fix - Identify out-of-sequence headings. +* Fix - Identify missing title attributes. +* Fix - Correctly assess alternative text requirements for image map areas. +* Tweak - Implemented additional security measures for input validation and data sanitization. + +2025-09-04 - version 1.31.1 +* Add - Privacy policy link added at newsletter signup. +* Tweak - Error messages returned from some ajax actions are more descriptive. + +2025-08-29 - version 1.31.0 +* Tweak - Don't flag YouTube scripts as video present mistakenly. +* Tweak - Underlined text rule now will find more instances of underlined text. +* Tweak - Added additional string label check for links that open new windows/tabs. +* Tweak - Reordered some settings for better grouping. + +2025-08-19 - version 1.30.1 +* Tweak - The rescan and clear buttons in the frontend highlighter are now only shown when they can be used. +* Tweak - Issue saving and clearing now has more robust capability checking. + +2025-08-06 - version 1.30.0 +* Add - Ability to clear issues on a post or page from the frontend highlighter. +* Add - More accessibility checker details in the site health check. +* Fix - Icons stack in frontend highlighter when there multiple issues on the same element. +* Tweak - Missing Transcript can better detect transcripts for videos in the content. + +2025-07-29 - version 1.29.0 +* Add - Rescan button in the frontend highlighter to rescan the current page. +* Add - Cleanup routine to clear out orphaned issues from the database. +* Add - Filter to allow tweaking the post statuses which get scanned. +* Tweak - Updated the aria-hidden check to understand more sibling relationships. +* Tweak - Updated the redundant alt check to understand that repeated images with same source and alt is not redundant. +* Fix - Remove the password protected notice, and it's related features - scans can throw this error now. + +2025-07-22 - version 1.28.0 +* Add - Better descriptions and help text for each of the rules. +* Add - Improved landmark location feature to show the location of the landmark in the DOM. +* Fix - Avoid possible error with removal of an index on an ID column. + +2025-07-10 - version 1.27.1 +* Fix - Don't alter a UNIQUE index before swapping to PRIMARY key index. + +2025-07-10 - version 1.27.0 +* Add - Landmark Location feature. +* Add - Plugin action links. +* Add - Documentation, support, and rate plugin links to plugin row meta. +* Add - Admin toolbar with quick links. +* Tweak - UNIQUE KEY to PRIMARY KEY for id column, bumped DB version to 1.0.4. +* Tweak - link_improper now lets links with role of tab pass. +* Fix - Allow frontend highlighter to kickoff scan if there are no issues for the page. +* Fix - Average issues per post calculation to handle zero issues. + +2025-06-30 - version 1.26.0 +* Tweak - Enhanced: Better translation handling across the plugin. + +2025-05-28 - version 1.25.0 +* Add - Ability to scan the main posts archive (blog page). +* Tweak - Improved the Anchor Exists rule to handle more situations. +* Fix - Avoid console error for clear button on CPTs that are not scannable. + +2025-04-24 - version 1.24.0 +* Add - Translations for 33 languages. +* Tweak - Handle Elementor buttons better in the new warnings fix. +* Fix - Several typo and grammar issues corrected in the plugin. +* Fix - Signup modal now works in Firefox under more conditions. +* Fix - Make sure that translations in JS files can be detected. + +2025-03-27 - version 1.23.1 +* Remove - Remove the str_get_html() fallback shim. + +2025-03-13 - version 1.23.0 +* Add - Jest testing framework for accessibility rules with test case generation. +* Tweak - Added fallback for str_get_html() with deprecation notice. +* Tweak - Added density calculation capability in JS scanner. +* Remove - Legacy PHP scan code. +* Remove - PHP Simple HTML DOM Parser. +* Dev - Converted multiple rules to JS for improved performance and compatibility. + +2025-02-15 - version 1.22.2 +* Tweak - Announce Global Accessibility Awareness Day in the admin during that week. + +2025-02-06 - version 1.22.1 +* Tweak - Make the skip-link fix handle sites with forced smooth scroll. +* Tweak - Make the zooming and scaling handle additional ways the tag can block scaling. +* Fix - Swap to GraphQL for getting meetup data for display in the admin. + +2025-01-30 - version 1.22.0 +* Tweak - Improve the new window warning migration to handle more edge cases. +* Fix - Avoid checking theme Tags when theme sandbox recovery is in play. +* Fix - When parsing block content for scanning avoid stomping on post_content of a global. + +2024-12-19 - version 1.21.0 +* Tweak - Improve how density statistics are counted. You will see a notice about this change on the welcome page. +* Fix - Ensure that the scanned posts counts are accurate to all posts scanned, not just ones that have issues. +* Fix - Properly count posts that are scanned but have no issues to remediate. + +2024-11-14 - version 1.20.0 +* Tweak - Process dynamic blocks and oEmbeds more reliably in scans. +* Tweak - Improve detection for missing_transcripts if there are several oEmbed videos from same provider on page. +* Fix - Ensure notice dismiss function works correctly on all pages and that review notice buttons are styled. +* Fix - Correct some cases where pluralization of phrases could be misapplied. + +2024-10-10 - version 1.19.0 +* Tweak - Improve the text_size_too_small check in scanner to avoid more false positives. +* Fix - Ensure that our notifications can appear on our own admin pages. +* Fix - No longer trigger password protected notice on other pages when scanning WooCommerce checkout page. + +2024-09-12 - version 1.18.0 +* Add - A new fix for adding a new tab/window warning to links with target="_blank". +* Tweak - Allow cache bypass from stats requests to force latest numbers. +* Tweak - Make a clear-issues endpoint more usable in different situations. +* Remove - Removed some code that was trying to force no notifications on the plugin pages. + +2024-08-15 - version 1.17.0 +* Add - A new fix for adding a new tab/window warning to links with target="_blank". +* Add - REST endpoint to retrieve a site scan summary. +* Tweak - Ensure frontend highlighter can load even when Cloudflare Rocket Loader is enabled. +* Tweak - Only show ignore button when user can ignore issues. +* Fix - URLs without issues would always output `0` when viewed on welcome widget. + +2024-07-18 - version 1.16.4 +* Tweak - Improve the table header detection and validation for row headers. +* Tweak - Show notice on fixes settings when they are saved from options page. +* Fix - Don't check for possible header if there is no text content. +* Fix - Multisite query fix to make sure issues are assigned correct site id. +* Fix - Correct where a scan link points. + +2024-06-20 - version 1.16.3 +* Add - Fix settings to site health info panels. +* Fix - Corrected a string that was misplaced in a fix. + +2024-05-23 - version 1.16.2 +* Tweak - Use better names for fix modal titles. +* Tweak - Improve the link_pdf rule to detect more accurately. +* Tweak - Improve the link_ms_office_doc rule to detect more accurately. +* Fix - Rely on labels for link_ambiguous_text rule first before checking just the text content. +* Fix - Remove a duplicatable rule empty_form_label. + +2024-04-25 - version 1.16.1 +* Fix - Remove redundant empty_form_label rule definition. + +2024-03-28 - version 1.16.0 +* Add - Introduced a system to handle automated fixes for issues that the scanner would discover. +* Add - Fix to remove or update bad tabindex values on elements. +* Add - Fix to remove title attributes in favor of preferred accessible names to elements. +* Add - Fix to add missing lang and dir attributes to the element. +* Add - Fix to add skip links to pages where they are missing. +* Add - Fix to add labels to comment and search forms. +* Add - Fix to ensure that the meta viewport tag does not prevent user scaling or zooming. +* Add - Fix to ensure that focus outlines are present on focusable elements. +* Tweak - Improve the tabindex_modified check to handle every element with tabindex. +* Tweak - Improve the link_blank rule to check on fully rendered pages. +* Tweak - Improve the link_ambiguous_text rule to check on fully rendered pages. +* Tweak - Improve the broken_skip_anchor_link rule to check on fully rendered pages. + +2024-02-29 - version 1.15.0 +* Add - Option to ignore issues by user role. +* Tweak - Improved performance for large sites. +* Fix - Corrected issue with scan scheduling on multisite. + +2024-01-25 - version 1.14.0 +* Add - Bulk scan improvements for custom post types. +* Tweak - Updated accessibility rules for WCAG 2.2. +* Fix - Fixed error with admin notices on plugin activation. + +2023-12-21 - version 1.13.0 +* Add - New dashboard widget for scan summaries. +* Tweak - Enhanced compatibility with WordPress 6.4. +* Fix - Fixed bug with scan results not saving on draft posts. + +2023-11-16 - version 1.12.0 +* Add - Option to export scan results to CSV. +* Tweak - Improved error messages for failed scans. +* Fix - Fixed issue with scan button not appearing for some users. + +2023-10-19 - version 1.11.0 +* Add - Support for additional languages in plugin interface. +* Tweak - Improved scan speed for large content sites. +* Fix - Fixed bug with accessibility statement generation. + +2023-09-21 - version 1.10.0 +* Add - New rules for ARIA attributes. +* Tweak - Updated plugin settings UI for clarity. +* Fix - Fixed issue with plugin deactivation not cleaning up options. + +2023-08-17 - version 1.9.0 +* Add - Option to schedule scans. +* Tweak - Improved scan accuracy for custom blocks. +* Fix - Fixed bug with scan results display in admin. + +2023-07-20 - version 1.8.0 +* Add - Integration with third-party accessibility tools. +* Tweak - Improved scan result filtering. +* Fix - Fixed error with scan summary widget. + +2023-06-22 - version 1.7.0 +* Add - Option to ignore specific rules per post. +* Tweak - Improved compatibility with WooCommerce product pages. +* Fix - Fixed bug with scan scheduling on multisite. + +2023-05-18 - version 1.6.0 +* Add - New onboarding wizard for setup. +* Tweak - Improved help documentation links. +* Fix - Fixed error with scan results export. + +2023-04-20 - version 1.5.0 +* Add - Option to enable/disable specific rules. +* Tweak - Improved scan result UI. +* Fix - Fixed bug with scan results not updating after post save. + +2023-03-16 - version 1.4.0 +* Add - Support for multisite network settings. +* Tweak - Improved scan accuracy for media attachments. +* Fix - Fixed error with scan scheduling on network sites. + +2023-02-16 - version 1.3.0 +* Add - Option to export accessibility statement. +* Tweak - Improved scan result sorting. +* Fix - Fixed bug with scan results not displaying for some users. + +2023-01-19 - version 1.2.0 +* Add - New rules for color contrast. +* Tweak - Improved scan performance for large sites. +* Fix - Fixed error with scan results export. + +2022-12-15 - version 1.1.0 +* Add - Option to schedule recurring scans. +* Tweak - Improved scan result UI for accessibility. +* Fix - Fixed bug with scan results not saving on draft posts. + +2022-11-17 - version 1.0.0 +* Initial release. diff --git a/docs/hooks.md b/docs/hooks.md index 4d189d08e..234569280 100644 --- a/docs/hooks.md +++ b/docs/hooks.md @@ -23,12 +23,12 @@ This document is auto-generated by `tools/generate-hooks-docs.php`. It lists onl | `edac_filter_frontend_fixes_data` | filter | [tests/phpunit/includes/classes/Fixes/Fix/PreventLinksOpeningNewWindowFixTest.php](https://github.com/equalizedigital/accessibility-checker/blob/develop/tests/phpunit/includes/classes/Fixes/Fix/PreventLinksOpeningNewWindowFixTest.php#L77) | 77 | Test link modification functionality. | | | `edac_filter_frontend_highlight_post_id` | filter | [includes/classes/class-enqueue-frontend.php](https://github.com/equalizedigital/accessibility-checker/blob/develop/includes/classes/class-enqueue-frontend.php#L55) | 55 | Enqueue the frontend highlighter. | | | `edac_filter_frontend_highlighter_visibility` | filter | [admin/class-frontend-highlight.php](https://github.com/equalizedigital/accessibility-checker/blob/develop/admin/class-frontend-highlight.php#L46) | 46 | Filter the visibility of the frontend highlighter. | 1.14.0 | -| `edac_filter_generate_link_type_ref` | filter | [includes/helper-functions.php](https://github.com/equalizedigital/accessibility-checker/blob/develop/includes/helper-functions.php#L607) | 607 | Generate links to pro page with some params. | | +| `edac_filter_generate_link_type_ref` | filter | [includes/helper-functions.php](https://github.com/equalizedigital/accessibility-checker/blob/develop/includes/helper-functions.php#L636) | 636 | Generate links to pro page with some params. | | | `edac_filter_insert_rule_data` | filter | [admin/class-insert-rule-data.php](https://github.com/equalizedigital/accessibility-checker/blob/develop/admin/class-insert-rule-data.php#L135) | 135 | Filter the rule data before inserting it into the database. | 1.4.0 | | `edac_filter_js_violation_html` | filter | [includes/classes/class-rest-api.php](https://github.com/equalizedigital/accessibility-checker/blob/develop/includes/classes/class-rest-api.php#L361) | 361 | REST handler that saves to the DB a list of js rule violations for a post. | | | `edac_filter_post_types` | filter | [includes/helper-functions.php](https://github.com/equalizedigital/accessibility-checker/blob/develop/includes/helper-functions.php#L183) | 183 | Filter the post types that the plugin will check. | 1.4.0 | -| `edac_filter_readability_content` | filter | [admin/class-ajax.php](https://github.com/equalizedigital/accessibility-checker/blob/develop/admin/class-ajax.php#L606) | 606 | Filter the content used for reading grade readability analysis. | 1.4.0 | -| `edac_filter_register_rules` | filter | [accessibility-checker.php](https://github.com/equalizedigital/accessibility-checker/blob/develop/accessibility-checker.php#L137) | 137 | Filter the default rules. | 1.4.0 | +| `edac_filter_readability_content` | filter | [admin/class-ajax.php](https://github.com/equalizedigital/accessibility-checker/blob/develop/admin/class-ajax.php#L612) | 612 | Filter the content used for reading grade readability analysis. | 1.4.0 | +| `edac_filter_register_rules` | filter | [accessibility-checker.php](https://github.com/equalizedigital/accessibility-checker/blob/develop/accessibility-checker.php#L142) | 142 | Filter the default rules. | 1.4.0 | | `edac_filter_remove_admin_notices_screens` | filter | [admin/class-admin-notices.php](https://github.com/equalizedigital/accessibility-checker/blob/develop/admin/class-admin-notices.php#L79) | 79 | Filter the screens where admin notices should be removed. | 1.14.0 | | `edac_filter_settings_capability` | filter | [admin/class-upgrade-promotion.php](https://github.com/equalizedigital/accessibility-checker/blob/develop/admin/class-upgrade-promotion.php#L45) | 45 | Add the upgrade menu item. | 1.27.0 | | `edac_filter_settings_tab_items` | filter | [partials/settings-page.php](https://github.com/equalizedigital/accessibility-checker/blob/develop/partials/settings-page.php#L15) | 15 | Filter the settings tab items. | 1.4.0 | diff --git a/includes/classes/Fixes/Fix/AddNewWindowWarningFix.php b/includes/classes/Fixes/Fix/AddNewWindowWarningFix.php index d211c6ab5..c050d01ab 100644 --- a/includes/classes/Fixes/Fix/AddNewWindowWarningFix.php +++ b/includes/classes/Fixes/Fix/AddNewWindowWarningFix.php @@ -77,7 +77,7 @@ public function get_fields_array( array $fields = [] ): array { ), 'fix_slug' => $this->get_slug(), 'group_name' => $this->get_nicename(), - 'help_id' => 8493, + 'help_id' => 9946, ]; return $fields; diff --git a/includes/classes/class-summary-generator.php b/includes/classes/class-summary-generator.php index beb5b085a..3e52196cd 100644 --- a/includes/classes/class-summary-generator.php +++ b/includes/classes/class-summary-generator.php @@ -248,7 +248,7 @@ private function count_contrast_errors() { * @since 1.9.0 */ private function update_issue_density( $summary ) { - $issue_density_array = get_post_meta( $this->post_id, '_edac_density_data' ); + $issue_density_array = get_post_meta( $this->post_id, '_edac_density_data', false ); if ( ( diff --git a/includes/helper-functions.php b/includes/helper-functions.php index b8a5b7936..862322583 100644 --- a/includes/helper-functions.php +++ b/includes/helper-functions.php @@ -234,6 +234,11 @@ function edac_get_post_type_label( string $post_type ): string { */ function edac_get_valid_table_name( $table_name ) { global $wpdb; + static $found_table_name; + + if ( isset( $found_table_name ) ) { + return $found_table_name; + } // Check if table name only contains alphanumeric characters, underscores, or hyphens. if ( ! preg_match( '/^[a-zA-Z0-9_\-]+$/', $table_name ) ) { @@ -248,7 +253,8 @@ function edac_get_valid_table_name( $table_name ) { return null; } - return $table_name; + $found_table_name = $table_name; + return $found_table_name; } /** @@ -256,89 +262,112 @@ function edac_get_valid_table_name( $table_name ) { * * @param string $meetup meetup name. * @param integer $count number of meetups to return. - * @return json + * @return array */ function edac_get_upcoming_meetups_json( $meetup, $count = 5 ) { if ( empty( $meetup ) || ! is_string( $meetup ) ) { - return; + return []; } // Min of 1 and max of 25. $count = absint( max( 1, min( 25, $count ) ) ); - $key = '_upcoming_meetups__' . sanitize_title( $meetup ) . '__' . (int) $count; - $output = get_transient( $key ); - - if ( false === $output ) { - $request_uri = 'https://api.meetup.com/gql-ext'; - $query = ' - query Group { - groupByUrlname(urlname: "' . (string) $meetup . '") { - events(first: ' . (int) $count . ') { - totalCount - edges { - node { - dateTime - eventUrl - id - title - } + // Sanitize meetup name for both cache key and GraphQL query to prevent injection. + $sanitized_meetup = sanitize_title( $meetup ); + + $key = '_upcoming_meetups__' . $sanitized_meetup . '__' . (int) $count; + $stale_key = $key . '__stale'; + $cached_value = get_transient( $key ); + + if ( false !== $cached_value ) { + return is_array( $cached_value ) ? $cached_value : []; + } + + $output = []; + + $request_uri = 'https://api.meetup.com/gql-ext'; + $query = ' + query Group { + groupByUrlname(urlname: "' . $sanitized_meetup . '") { + events(first: ' . (int) $count . ') { + totalCount + edges { + node { + dateTime + eventUrl + id + title } } } - }'; - - // Make POST request with the GraphQL query. - $request = wp_remote_post( - $request_uri, - [ - 'headers' => [ - 'Content-Type' => 'application/json', - ], - 'body' => wp_json_encode( - [ - 'query' => $query, - ] - ), - ] - ); - - if ( is_wp_error( $request ) || 200 !== (int) wp_remote_retrieve_response_code( $request ) ) { - return; } + }'; + + $request = wp_remote_post( + $request_uri, + [ + 'headers' => [ + 'Content-Type' => 'application/json', + ], + 'timeout' => 10, // phpcs:ignore WordPressVIPMinimum.Performance.RemoteRequestTimeout.timeout_timeout -- Timeout set for external request. + 'body' => wp_json_encode( + [ + 'query' => $query, + ] + ), + ] + ); + if ( ! is_wp_error( $request ) && 200 === (int) wp_remote_retrieve_response_code( $request ) ) { $response_body = json_decode( wp_remote_retrieve_body( $request ) ); - // Return early if we don't have the expected data. - if ( empty( $response_body ) || ! isset( $response_body->data->groupByUrlname->events->edges ) ) { - return; - } + $edges = $response_body->data->groupByUrlname->events->edges ?? null; + + if ( is_array( $edges ) ) { + foreach ( $edges as $edge ) { + if ( ! isset( $edge->node ) ) { + continue; + } - // Transform the GraphQL response to match the format expected from old rest response. - $output = []; - foreach ( $response_body->data->groupByUrlname->events->edges as $edge ) { - $event = $edge->node; + $event = $edge->node; - // phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- GraphQL response uses camelCase. - $event_data = new stdClass(); - $event_data->name = $event->title; - $event_data->time = strtotime( $event->dateTime ) * 1000; // Convert to milliseconds to match old format. - $event_data->link = $event->eventUrl; - $event_data->id = $event->id; - // phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase. + // phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- GraphQL response uses camelCase. + if ( empty( $event->title ) || empty( $event->dateTime ) || empty( $event->eventUrl ) || empty( $event->id ) ) { + continue; + } - $output[] = $event_data; - } + $timestamp = strtotime( (string) $event->dateTime ); + if ( false === $timestamp ) { + continue; + } + + $event_data = new stdClass(); + $event_data->name = (string) $event->title; + $event_data->time = $timestamp * 1000; // Convert to milliseconds to match old format. + $event_data->link = (string) $event->eventUrl; + $event_data->id = (string) $event->id; + // phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase. - if ( empty( $output ) ) { - return; + $output[] = $event_data; + } } + } + if ( ! empty( $output ) ) { set_transient( $key, $output, DAY_IN_SECONDS ); + update_option( $stale_key, $output, false ); + return $output; + } + + $stale_value = get_option( $stale_key ); + if ( is_array( $stale_value ) && ! empty( $stale_value ) ) { + // Serve stale data for a short window while retrying upstream requests periodically. + set_transient( $key, $stale_value, HOUR_IN_SECONDS ); + return $stale_value; } - return $output; + return []; } /** @@ -347,14 +376,14 @@ function edac_get_upcoming_meetups_json( $meetup, $count = 5 ) { * @param string $meetup meetup name. * @param integer $count number of meetups to return. * @param string $heading heading level. - * @return json + * @return string */ function edac_get_upcoming_meetups_html( $meetup, $count = 5, $heading = '3' ) { $json = edac_get_upcoming_meetups_json( $meetup, $count ); if ( empty( $json ) ) { - return; + return ''; } $html = '