Skip to content

Commit 0dd142c

Browse files
authored
Merge pull request #1214 from equalizedigital/release/1.31.0
Release v1.31.0
2 parents 6280db9 + 9a613b6 commit 0dd142c

341 files changed

Lines changed: 120774 additions & 5112 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/CONTRIBUTING.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ Make sure your problem does not exist as a ticket already by searching through [
4444

4545
We will review your pull request and merge when everything is in order. We will help you to make sure the code complies with the standards described above.
4646

47+
### Automated Backport Process
48+
When a pull request is merged into the `main` branch, an automated workflow will create a backport pull request to merge the same feature branch into the `develop` branch. This ensures that changes in `main` are also applied to the development branch without directly merging `main` into `develop`.
49+
50+
**How it works:**
51+
- The workflow triggers automatically when a PR is merged into `main`
52+
- It extracts the original branch name that was merged
53+
- If the branch still exists, it creates a new PR to merge that branch into `develop`
54+
- The backport PR is labeled with `backport` and `automated` labels
55+
- If the branch no longer exists, the workflow logs a message indicating manual backport may be needed
56+
57+
**No action required** - this process is fully automated and requires no manual intervention in most cases.
58+
4759
#### 'Patch welcome' issues
4860
Some issues are labeled 'patch-welcome'. This means we see the value in the particular enhancement being suggested but have decided for now not to prioritize it. If you however decide to write a patch for it, we'll gladly include it after some code review.
4961

.github/copilot-instructions.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ This is a WordPress plugin called "Accessibility Checker" developed by Equalize
4646

4747
## Development Workflow
4848

49+
Commit lock files (`composer.lock`, `package-lock.json`) only when adding or updating packages. Run `composer install` and `npm install` to get dependencies matching the lock file.
50+
4951
Code should always be linted by phpcs and eslint before committing. Tests should be added for new functionality. Tests should also be added for any bug fixes. Use the following commands to run tests and linting:
5052

5153
```bash
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
name: Automatic Backport to Develop
2+
3+
on:
4+
pull_request:
5+
types: [closed]
6+
branches: [main]
7+
8+
permissions:
9+
contents: read
10+
pull-requests: write
11+
issues: write
12+
13+
jobs:
14+
create-backport-pr:
15+
# Only run if the PR was actually merged (not just closed)
16+
if: github.event.pull_request.merged == true
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
- name: Checkout repository
21+
uses: actions/checkout@v4
22+
with:
23+
fetch-depth: 0
24+
token: ${{ secrets.GITHUB_TOKEN }}
25+
26+
- name: Get merged branch name
27+
id: get-branch
28+
run: |
29+
# Get the head branch name from the merged PR
30+
BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
31+
echo "branch-name=$BRANCH_NAME" >> $GITHUB_OUTPUT
32+
echo "Merged branch: $BRANCH_NAME"
33+
34+
- name: Check if branch exists
35+
id: check-branch
36+
run: |
37+
BRANCH_NAME="${{ steps.get-branch.outputs.branch-name }}"
38+
39+
# Check if the branch still exists on the remote
40+
if git ls-remote --heads origin "$BRANCH_NAME" | grep -q "$BRANCH_NAME"; then
41+
echo "branch-exists=true" >> $GITHUB_OUTPUT
42+
echo "Branch $BRANCH_NAME exists and can be used for backport"
43+
else
44+
echo "branch-exists=false" >> $GITHUB_OUTPUT
45+
echo "Branch $BRANCH_NAME no longer exists, cannot create backport PR"
46+
fi
47+
48+
- name: Create backport PR
49+
if: steps.check-branch.outputs.branch-exists == 'true'
50+
uses: actions/github-script@v7
51+
with:
52+
github-token: ${{ secrets.GITHUB_TOKEN }}
53+
script: |
54+
const branchName = '${{ steps.get-branch.outputs.branch-name }}';
55+
const originalPrNumber = context.payload.pull_request.number;
56+
const originalPrTitle = context.payload.pull_request.title;
57+
const originalPrBody = context.payload.pull_request.body || '';
58+
const originalPrAuthor = context.payload.pull_request.user.login;
59+
60+
// Create the backport PR
61+
try {
62+
const response = await github.rest.pulls.create({
63+
owner: context.repo.owner,
64+
repo: context.repo.repo,
65+
title: `[Backport] ${originalPrTitle}`,
66+
head: branchName,
67+
base: 'develop',
68+
body: `## Automatic Backport\n\nThis is an automatic backport of PR #${originalPrNumber} by @${originalPrAuthor} to the \`develop\` branch.\n\n### Original PR Details:\n${originalPrBody}\n\n---\n*This PR was created automatically when #${originalPrNumber} was merged into \`main\`.*`,
69+
maintainer_can_modify: true
70+
});
71+
72+
console.log(`✅ Successfully created backport PR #${response.data.number}`);
73+
console.log(`🔗 PR URL: ${response.data.html_url}`);
74+
75+
// Add labels to the backport PR
76+
await github.rest.issues.addLabels({
77+
owner: context.repo.owner,
78+
repo: context.repo.repo,
79+
issue_number: response.data.number,
80+
labels: ['backport', 'automated']
81+
});
82+
83+
} catch (error) {
84+
console.error('❌ Failed to create backport PR:', error.message);
85+
86+
// Check if it's a conflict or other specific error
87+
if (error.message.includes('No commits between')) {
88+
console.log('ℹ️ The branch is already up to date with develop - no backport needed');
89+
} else if (
90+
error.status === 422 &&
91+
error.response &&
92+
Array.isArray(error.response.data?.errors) &&
93+
error.response.data.errors.some(e =>
94+
e.message && e.message.includes('A pull request already exists')
95+
)
96+
) {
97+
console.log('ℹ️ A pull request already exists for this branch to develop');
98+
} else {
99+
// Re-throw for other errors to fail the workflow
100+
throw error;
101+
}
102+
}
103+
104+
- name: Handle missing branch
105+
if: steps.check-branch.outputs.branch-exists == 'false'
106+
run: |
107+
echo "⚠️ Cannot create backport PR because the source branch no longer exists."
108+
echo "This typically happens when the branch was deleted after merging."
109+
echo "If a backport to develop is needed, it should be done manually."

.github/workflows/jest-test-axe-custom-rules.yml renamed to .github/workflows/jest-tests.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
name: Run Jest on Rule Changes
1+
name: Run Jest on JS File Changes
22

33
on:
44
pull_request:
55
paths:
6-
- 'src/pageScanner/rules/**/*'
7-
- 'src/pageScanner/checks/**/*'
6+
- 'src/**/*.js'
7+
- 'tests/**/*.js'
88

99
jobs:
1010
jest:
@@ -16,7 +16,7 @@ jobs:
1616
- name: Set up Node.js
1717
uses: actions/setup-node@v4
1818
with:
19-
node-version: '22' # Or your preferred Node.js version
19+
node-version: '22'
2020

2121
- name: Cache dependencies
2222
uses: actions/cache@v4

.github/workflows/phpunit.yml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ concurrency:
1616
jobs:
1717
integration:
1818
runs-on: ubuntu-latest
19+
env:
20+
COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ secrets.PUBLIC_REPO_ACCESS }}"}}'
1921

2022
strategy:
23+
fail-fast: false
2124
matrix:
2225
include:
2326
- php_version: '8.1'
@@ -64,6 +67,9 @@ jobs:
6467
env:
6568
GITHUB_TOKEN: ${{ secrets.PUBLIC_REPO_ACCESS }}
6669

70+
- name: Configure Composer to use PAT
71+
run: composer config --global --auth github-oauth.github.com ${{ secrets.PUBLIC_REPO_ACCESS }}
72+
6773
# Install dependencies and handle caching in one go.
6874
# @link https://github.com/marketplace/actions/install-composer-dependencies
6975
- name: "Composer: remove the PHP platform requirement"
@@ -77,8 +83,10 @@ jobs:
7783
# But make it selective.
7884
composer-options: "yoast/wp-test-utils --with-dependencies"
7985
# Bust the cache at least once a month - output format: YYYY-MM-DD.
80-
custom-cache-suffix: $(date -u -d "-0 month -$(($(date +%d)-1)) days" "+%F")
81-
86+
custom-cache-suffix: $(date -u -d "-0 month -$(($(date +%d)-3)) days" "+%F")
87+
github-token: ${{ secrets.PUBLIC_REPO_ACCESS }}
88+
env:
89+
GITHUB_TOKEN: ${{ secrets.PUBLIC_REPO_ACCESS }}
8290
# Some images won't have svn available. Install it if that's the case.
8391
- name: Install SVN
8492
run: |

accessibility-checker.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* Plugin Name: Accessibility Checker
1111
* Plugin URI: https://a11ychecker.com
1212
* Description: Audit and check your website for accessibility before you hit publish. In-post accessibility scanner and guidance.
13-
* Version: 1.30.1
13+
* Version: 1.31.0
1414
* Requires PHP: 7.4
1515
* Author: Equalize Digital
1616
* Author URI: https://equalizedigital.com
@@ -36,7 +36,7 @@
3636

3737
// Current plugin version.
3838
if ( ! defined( 'EDAC_VERSION' ) ) {
39-
define( 'EDAC_VERSION', '1.30.1' );
39+
define( 'EDAC_VERSION', '1.31.0' );
4040
}
4141

4242
// Current database version.

admin/class-ajax.php

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public function init_hooks() {
5151
public function summary() {
5252

5353
// nonce security.
54-
if ( ! isset( $_REQUEST['nonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['nonce'] ), 'ajax-nonce' ) ) {
54+
if ( ! isset( $_REQUEST['nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['nonce'] ) ), 'ajax-nonce' ) ) {
5555

5656
$error = new \WP_Error( '-1', __( 'Permission Denied', 'accessibility-checker' ) );
5757
wp_send_json_error( $error );
@@ -118,6 +118,9 @@ public function summary() {
118118

119119
$html['content'] .= '</li>';
120120

121+
// if this is a virtual page, we don't show the readability section.
122+
$is_virtual_page = edac_is_virtual_page( $post_id );
123+
121124
$html['content'] .= '
122125
' . edac_generate_summary_stat(
123126
'edac-summary-errors',
@@ -145,7 +148,7 @@ public function summary() {
145148
) . '
146149
147150
</ul>
148-
<div class="edac-summary-readability">
151+
<div class="edac-summary-readability" ' . ( $is_virtual_page ? 'style="display: none;"' : '' ) . '>
149152
<div class="edac-summary-readability-level">
150153
<div><img src="' . EDAC_PLUGIN_URL . 'assets/images/readability-icon-navy.png" alt="" width="54"></div>
151154
<div class="edac-panel-number' . ( ( (int) $summary['content_grade'] <= 9 || 'none' === $simplified_summary_prompt ) ? ' passed-text-color' : ' failed-text-color' ) . '">
@@ -200,7 +203,7 @@ public function summary() {
200203
public function details() {
201204

202205
// nonce security.
203-
if ( ! isset( $_REQUEST['nonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['nonce'] ), 'ajax-nonce' ) ) {
206+
if ( ! isset( $_REQUEST['nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['nonce'] ) ), 'ajax-nonce' ) ) {
204207

205208
$error = new \WP_Error( '-1', __( 'Permission Denied', 'accessibility-checker' ) );
206209
wp_send_json_error( $error );
@@ -479,7 +482,7 @@ function ( $a, $b ) {
479482

480483
$landmark = isset( $row['landmark'] ) ? $row['landmark'] : '';
481484
$landmark_selector = isset( $row['landmark_selector'] ) ? $row['landmark_selector'] : '';
482-
485+
483486
$html .= edac_generate_landmark_link( $landmark, $landmark_selector, $postid );
484487

485488
$html .= '</div>';
@@ -488,12 +491,18 @@ function ( $a, $b ) {
488491

489492
if ( ! isset( $rule['viewable'] ) || $rule['viewable'] ) {
490493

494+
$post_view_link = apply_filters(
495+
'edac_get_origin_url_for_virtual_page',
496+
get_the_permalink( $postid ),
497+
$postid
498+
);
499+
491500
$url = add_query_arg(
492501
[
493502
'edac' => $id,
494503
'edac_nonce' => wp_create_nonce( 'edac_highlight' ),
495504
],
496-
get_the_permalink( $postid )
505+
$post_view_link
497506
);
498507

499508
// Translators: %d is the issue ID.
@@ -579,7 +588,7 @@ function ( $a, $b ) {
579588
public function readability() {
580589

581590
// nonce security.
582-
if ( ! isset( $_REQUEST['nonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['nonce'] ), 'ajax-nonce' ) ) {
591+
if ( ! isset( $_REQUEST['nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['nonce'] ) ), 'ajax-nonce' ) ) {
583592

584593
$error = new \WP_Error( '-1', __( 'Permission Denied', 'accessibility-checker' ) );
585594
wp_send_json_error( $error );
@@ -717,33 +726,33 @@ public function readability() {
717726
public function add_ignore() {
718727

719728
// nonce security.
720-
if ( ! isset( $_REQUEST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_REQUEST['nonce'] ), 'ajax-nonce' ) ) {
729+
if ( ! isset( $_REQUEST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ), 'ajax-nonce' ) ) {
721730

722731
$error = new \WP_Error( '-1', __( 'Permission Denied', 'accessibility-checker' ) );
723732
wp_send_json_error( $error );
724733

725734
}
726735

727736
global $wpdb;
728-
$table_name = $wpdb->prefix . 'accessibility_checker';
729-
$raw_ids = isset( $_REQUEST['ids'] ) ? $_REQUEST['ids'] : []; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitization handled below.
730-
$ids = array_map(
737+
$table_name = $wpdb->prefix . 'accessibility_checker';
738+
$raw_ids = isset( $_REQUEST['ids'] ) ? (array) wp_unslash( $_REQUEST['ids'] ) : []; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitization handled below.
739+
$ids = array_map(
731740
function ( $value ) {
732741
return (int) $value;
733742
},
734743
$raw_ids
735744
); // Sanitizing array elements to integers.
736-
$action = isset( $_REQUEST['ignore_action'] ) ? sanitize_text_field( $_REQUEST['ignore_action'] ) : '';
737-
$type = isset( $_REQUEST['ignore_type'] ) ? sanitize_text_field( $_REQUEST['ignore_type'] ) : '';
738-
$siteid = get_current_blog_id();
739-
$ignre = ( 'enable' === $action ) ? 1 : 0;
740-
$ignre_user = ( 'enable' === $action ) ? get_current_user_id() : null;
741-
$ignre_user_info = ( 'enable' === $action ) ? get_userdata( $ignre_user ) : '';
742-
$ignre_username = ( 'enable' === $action ) ? $ignre_user_info->user_login : '';
743-
$ignre_date = ( 'enable' === $action ) ? gmdate( 'Y-m-d H:i:s' ) : null;
744-
$ignre_date_formatted = ( 'enable' === $action ) ? gmdate( 'F j, Y g:i a', strtotime( $ignre_date ) ) : '';
745-
$ignre_comment = ( 'enable' === $action && isset( $_REQUEST['comment'] ) ) ? sanitize_textarea_field( $_REQUEST['comment'] ) : null;
746-
$ignore_global = ( 'enable' === $action && isset( $_REQUEST['ignore_global'] ) ) ? sanitize_textarea_field( $_REQUEST['ignore_global'] ) : 0;
745+
$action = isset( $_REQUEST['ignore_action'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['ignore_action'] ) ) : '';
746+
$type = isset( $_REQUEST['ignore_type'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['ignore_type'] ) ) : '';
747+
$siteid = get_current_blog_id();
748+
$ignre = ( 'enable' === $action ) ? 1 : 0;
749+
$ignre_user = ( 'enable' === $action ) ? get_current_user_id() : null;
750+
$ignre_user_info = ( 'enable' === $action ) ? get_userdata( $ignre_user ) : '';
751+
$ignre_username = ( 'enable' === $action ) ? $ignre_user_info->user_login : '';
752+
$ignre_date = ( 'enable' === $action ) ? gmdate( 'Y-m-d H:i:s' ) : null;
753+
$ignre_date_formatted = ( 'enable' === $action ) ? gmdate( 'F j, Y g:i a', strtotime( $ignre_date ) ) : '';
754+
$ignre_comment = ( 'enable' === $action && isset( $_REQUEST['comment'] ) ) ? sanitize_textarea_field( wp_unslash( $_REQUEST['comment'] ) ) : null;
755+
$ignore_global = ( 'enable' === $action && isset( $_REQUEST['ignore_global'] ) ) ? sanitize_textarea_field( wp_unslash( $_REQUEST['ignore_global'] ) ) : 0;
747756

748757
// If largeBatch is set and 'true', we need to perform an update using the 'object'
749758
// instead of IDs. It is a much less efficient query than by IDs - but many IDs run
@@ -796,8 +805,8 @@ function ( $value ) {
796805
*/
797806
public function simplified_summary() {
798807

799-
// nonce security.
800-
if ( ! isset( $_REQUEST['nonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['nonce'] ), 'ajax-nonce' ) ) {
808+
// nonce security.
809+
if ( ! isset( $_REQUEST['nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['nonce'] ) ), 'ajax-nonce' ) ) {
801810

802811
$error = new \WP_Error( '-1', __( 'Permission Denied', 'accessibility-checker' ) );
803812
wp_send_json_error( $error );
@@ -818,12 +827,12 @@ public function simplified_summary() {
818827

819828
}
820829

821-
$post_id = (int) $_REQUEST['post_id'];
822-
update_post_meta(
823-
$post_id,
824-
'_edac_simplified_summary',
825-
sanitize_text_field( $_REQUEST['summary'] )
826-
);
830+
$post_id = (int) $_REQUEST['post_id'];
831+
update_post_meta(
832+
$post_id,
833+
'_edac_simplified_summary',
834+
sanitize_text_field( wp_unslash( $_REQUEST['summary'] ) )
835+
);
827836

828837
$edac_simplified_summary = get_post_meta( $post_id, '_edac_simplified_summary', $single = true );
829838
$simplified_summary = $edac_simplified_summary ? $edac_simplified_summary : '';

0 commit comments

Comments
 (0)