Plugin Directory

Changeset 3671081


Ignore:
Timestamp:
08/29/2026 03:28:35 AM (2 months ago)
Author:
salaoo36
Message:

Release 0.2.0

Location:
scanoria-accessibility-audit
Files:
2 added
10 edited
1 copied

Legend:

Unmodified
Added
Removed
  • scanoria-accessibility-audit/tags/0.2.0/assets/js/admin.js

    r3631871 r3671081  
    128128
    129129        /**
     130         * Tell anything else on the page what just happened.
     131         *
     132         * The scan is driven entirely from the browser, so an add-on cannot learn a
     133         * page finished from PHP alone — by the time the request returns, the run has
     134         * already moved on to the next URL. These events are the client-side half of
     135         * the PHP hooks: same moments, same names.
     136         *
     137         * @param {string}  name       Event name without the scanoria: prefix.
     138         * @param {Object}  detail     Payload.
     139         * @param {boolean} cancelable Whether a listener may call preventDefault().
     140         * @return {CustomEvent} The dispatched event.
     141         */
     142        function emit( name, detail, cancelable ) {
     143                var event = new CustomEvent( 'scanoria:' + name, {
     144                        detail: detail,
     145                        cancelable: !! cancelable
     146                } );
     147                document.dispatchEvent( event );
     148                return event;
     149        }
     150
     151        /**
    130152         * Why a page did not produce a result, in the operator's language.
    131153         *
    … …  
    166188                        try {
    167189                                var result = await scanOne( targets[ i ] );
    168                                 await store( targets[ i ], result );
     190                                var counts = await store( targets[ i ], result );
     191                                emit( 'page-scanned', {
     192                                        target: targets[ i ],
     193                                        url: result.url,
     194                                        issues: result.issues || [],
     195                                        counts: counts
     196                                } );
    169197                        } catch ( error ) {
    170198                                failures++;
    … …  
    183211                                ( failures ? ' ' + skippedNotice( failures ) : '' )
    184212                );
    185                 window.location.reload();
     213
     214                // The reload is how the results table catches up, but it also ends the
     215                // page — a listener that wanted to write a history entry or draw a diff
     216                // would be cut off mid-work. So the event is cancelable: preventDefault()
     217                // means the listener has taken responsibility for refreshing the view.
     218                var finished = emit( 'scan-complete', {
     219                        targets: targets,
     220                        scanned: targets.length - failures,
     221                        failures: failures
     222                }, true );
     223
     224                if ( ! finished.defaultPrevented ) {
     225                        window.location.reload();
     226                }
    186227        }
    187228
  • scanoria-accessibility-audit/tags/0.2.0/includes/class-scanoria-admin.php

    r3631871 r3671081  
    2727                        81
    2828                );
     29
     30                /**
     31                 * The top-level menu exists; add-ons can hang a submenu off it here.
     32                 *
     33                 * The slug and the capability are handed over rather than left to be
     34                 * guessed, because both are things a site can change: the capability runs
     35                 * through the scanoria_capability filter, and a submenu registered against
     36                 * a wider one would appear for people who cannot open the parent.
     37                 *
     38                 * @param string $slug       Parent menu slug.
     39                 * @param string $capability Capability required to see it.
     40                 */
     41                do_action( 'scanoria_admin_menu', self::SLUG, scanoria_get_capability() );
    2942        }
    3043
    … …  
    4154                wp_enqueue_style( 'scanoria-admin', SCANORIA_URL . 'assets/css/admin.css', array(), SCANORIA_VERSION );
    4255                wp_enqueue_script( 'scanoria-admin', SCANORIA_URL . 'assets/js/admin.js', array( 'wp-api-fetch' ), SCANORIA_VERSION, true );
     56
     57                /**
     58                 * Our screen is being set up and our script is queued.
     59                 *
     60                 * An add-on enqueues here so it can declare scanoria-admin as a dependency
     61                 * and so it loads on this screen only. The scan events the script emits
     62                 * (scanoria:page-scanned, scanoria:scan-complete) are the client-side half
     63                 * of this contract.
     64                 *
     65                 * @param string $handle  Script handle of the admin script.
     66                 * @param string $version Version of the free plugin.
     67                 */
     68                do_action( 'scanoria_admin_assets', 'scanoria-admin', SCANORIA_VERSION );
    4369
    4470                wp_localize_script(
    … …  
    137163                }
    138164
    139                 return $targets;
     165                /**
     166                 * What will be scanned, in order.
     167                 *
     168                 * Filtering the list rather than the query is deliberate: an add-on that
     169                 * wants to add archives, or to re-scan only what changed since last time,
     170                 * is working with URLs, not with WP_Query arguments.
     171                 *
     172                 * @param array $targets Each with id, title, type and scan_url.
     173                 */
     174                return apply_filters( 'scanoria_scan_targets', $targets );
    140175        }
    141176
    … …  
    159194                                </button>
    160195                                <span id="scanoria-progress" class="scanoria-progress" role="status" aria-live="polite"></span>
     196                                <?php
     197                                /**
     198                                 * Room next to the scan button, for actions that act on the whole
     199                                 * site: export, printable report, history.
     200                                 */
     201                                do_action( 'scanoria_admin_toolbar', $summary );
     202                                ?>
    161203                        </div>
    162204
    … …  
    216258                                </table>
    217259                        <?php endif; ?>
     260
     261                        <?php
     262                        /**
     263                         * Below the results table.
     264                         *
     265                         * @param array $summary Per-post counts as shown above.
     266                         */
     267                        do_action( 'scanoria_admin_after_results', $summary );
     268                        ?>
    218269                </div>
    219270                <?php
  • scanoria-accessibility-audit/tags/0.2.0/includes/class-scanoria-store.php

    r3631061 r3671081  
    8181                }
    8282
    83                 return array(
     83                $counts = array(
    8484                        'total'   => count( $issues ),
    8585                        'open'    => $open,
    8686                        'carried' => $carried,
    8787                );
     88
     89                /**
     90                 * One URL has just been re-scanned and the results written.
     91                 *
     92                 * This fires after the rows are in the database, so a listener can read
     93                 * the stored findings rather than trusting the payload. Scan history and
     94                 * the change-since-last-scan view are built from here: the counts are the
     95                 * whole of what a history row needs, and $issues carries the detail for
     96                 * anything that wants to diff element by element.
     97                 *
     98                 * @param int    $post_id Post the URL belongs to, 0 if none.
     99                 * @param string $url     Scanned URL.
     100                 * @param array  $counts  total / open / carried.
     101                 * @param array  $issues  Sanitised issue payloads, in scan order.
     102                 */
     103                do_action( 'scanoria_scan_recorded', $post_id, $url, $counts, $issues );
     104
     105                return $counts;
     106        }
     107
     108        /**
     109         * Every stored finding, with any decision attached.
     110         *
     111         * Nothing in the free plugin calls this: the admin screen loads one post at a
     112         * time. It exists because a CSV export or a printable report needs the whole
     113         * set at once, and the alternative is every add-on writing its own join
     114         * against these two tables and then breaking the day a column moves.
     115         *
     116         * @param bool $include_decided Include findings already ignored or resolved.
     117         * @return array
     118         */
     119        public static function all_issues( $include_decided = true ) {
     120                global $wpdb;
     121
     122                // The two queries are written out in full rather than sharing one string
     123                // with a WHERE clause dropped into it. A clause held in a variable — even
     124                // one that can only ever be a literal picked by a boolean — reads to the
     125                // directory's own Plugin Check as an unescaped parameter, and a warning on
     126                // a database call is not something to argue with a reviewer about.
     127                // phpcs:disable WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
     128                if ( $include_decided ) {
     129                        $rows = $wpdb->get_results(
     130                                "SELECT i.*, d.verdict, d.reason, d.site_wide, d.created_at AS decided_at
     131                                 FROM {$wpdb->prefix}scanoria_issues i
     132                                 LEFT JOIN {$wpdb->prefix}scanoria_decisions d ON d.id = i.decision_id
     133                                 ORDER BY i.post_id ASC, (i.decision_id > 0) ASC, FIELD(i.impact,'critical','serious','moderate','minor') ASC, i.id ASC",
     134                                ARRAY_A
     135                        );
     136                } else {
     137                        $rows = $wpdb->get_results(
     138                                "SELECT i.*, d.verdict, d.reason, d.site_wide, d.created_at AS decided_at
     139                                 FROM {$wpdb->prefix}scanoria_issues i
     140                                 LEFT JOIN {$wpdb->prefix}scanoria_decisions d ON d.id = i.decision_id
     141                                 WHERE i.decision_id = 0
     142                                 ORDER BY i.post_id ASC, FIELD(i.impact,'critical','serious','moderate','minor') ASC, i.id ASC",
     143                                ARRAY_A
     144                        );
     145                }
     146                // phpcs:enable
     147
     148                return $rows ? $rows : array();
    88149        }
    89150
    … …  
    272333                );
    273334
     335                /**
     336                 * A human has judged a finding.
     337                 *
     338                 * The issue row is passed as it stood at the moment of the decision,
     339                 * because the next scan deletes it: a listener keeping an audit trail has
     340                 * no other chance to record what was actually decided about.
     341                 *
     342                 * @param int   $decision_id New decision id.
     343                 * @param int   $issue_id    Issue that was judged.
     344                 * @param string $verdict    ignored or resolved.
     345                 * @param bool  $site_wide   Applied to every post on the site.
     346                 * @param array $issue       The issue row as it stood.
     347                 */
     348                do_action( 'scanoria_decision_recorded', $decision_id, (int) $issue_id, $verdict, (bool) $site_wide, $issue );
     349
    274350                return $decision_id;
    275351        }
    … …  
    298374                        array( '%d' )
    299375                );
     376
     377                /**
     378                 * A decision is about to be removed and the finding put back on the open
     379                 * list. Fired before the delete so a listener can still read the row.
     380                 *
     381                 * @param int $decision_id Decision being removed.
     382                 */
     383                do_action( 'scanoria_decision_removed', $decision_id );
    300384
    301385                return (bool) $wpdb->delete( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
  • scanoria-accessibility-audit/tags/0.2.0/readme.txt

    r3631871 r3671081  
    33Tags: accessibility, wcag, a11y, ada, eaa
    44Requires at least: 6.0
    5 Tested up to: 7.0
     5Tested up to: 7.1
    66Requires PHP: 7.4
    7 Stable tag: 0.1.2
     7Stable tag: 0.2.0
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    104104Deactivating the plugin, as opposed to deleting it, never removes anything.
    105105
     106= Can I extend it from my own plugin? =
     107
     108Yes. Nothing needs to be edited or forked.
     109
     110On the PHP side: `scanoria_loaded` fires once every class exists and is the right place to bind (binding to `plugins_loaded` directly can run too early). `scanoria_scan_recorded` fires after a page's results are written, `scanoria_decision_recorded` and `scanoria_decision_removed` when somebody ignores or resolves a finding — the issue row is passed along with the decision, because the next scan deletes it. `scanoria_admin_menu`, `scanoria_admin_assets`, `scanoria_admin_toolbar` and `scanoria_admin_after_results` are the places to add screens, scripts and buttons, and `scanoria_scan_targets` filters what will be scanned.
     111
     112On the browser side, the scan runs in the page, so PHP alone cannot tell you a page finished: the screen dispatches `scanoria:page-scanned` on `document` after each page and `scanoria:scan-complete` at the end. The last one is cancelable — calling `preventDefault()` stops the automatic reload, in which case refreshing the view is up to you.
     113
    106114== Screenshots ==
    107115
    … …  
    112120
    113121== Changelog ==
     122
     123= 0.2.0 =
     124* Added hooks so an add-on can extend the plugin without modifying it: actions when a scan is recorded and when a decision is made or undone, places to add buttons and screens in the admin, a filter over the list of pages to scan, and browser events while a scan runs.
     125* No change to what the plugin does. Nothing was moved behind a paywall, and it still makes no external requests.
    114126
    115127= 0.1.2 =
  • scanoria-accessibility-audit/tags/0.2.0/scanoria-accessibility-audit.php

    r3631871 r3671081  
    44 * Plugin URI:        https://wordpress.org/plugins/scanoria-accessibility-audit/
    55 * Description:       Find WCAG, ADA and EAA accessibility problems on your site. Scans the page as visitors actually see it, so page builders are supported. Your decisions to ignore or resolve an issue survive re-scans. Runs entirely on your own server: no account, no external requests, unlimited sites.
    6  * Version:           0.1.2
     6 * Version:           0.2.0
    77 * Requires at least: 6.0
    88 * Requires PHP:      7.4
    … …  
    1616defined( 'ABSPATH' ) || exit;
    1717
    18 define( 'SCANORIA_VERSION', '0.1.2' );
     18define( 'SCANORIA_VERSION', '0.2.0' );
    1919define( 'SCANORIA_FILE', __FILE__ );
    2020define( 'SCANORIA_DIR', plugin_dir_path( __FILE__ ) );
    … …  
    5454                        ( new Scanoria_Admin() )->register();
    5555                }
     56
     57                /**
     58                 * Everything this plugin registers is now in place.
     59                 *
     60                 * An add-on binds here rather than on plugins_loaded directly: load order
     61                 * between two plugins is alphabetical by folder, so an add-on that hooked
     62                 * plugins_loaded itself could easily run before these classes exist. The
     63                 * version is passed so an add-on can refuse to run against a build that
     64                 * predates a hook it needs.
     65                 *
     66                 * @param string $version Version of the free plugin.
     67                 */
     68                do_action( 'scanoria_loaded', SCANORIA_VERSION );
    5669        }
    5770);
  • scanoria-accessibility-audit/trunk/assets/js/admin.js

    r3631871 r3671081  
    128128
    129129        /**
     130         * Tell anything else on the page what just happened.
     131         *
     132         * The scan is driven entirely from the browser, so an add-on cannot learn a
     133         * page finished from PHP alone — by the time the request returns, the run has
     134         * already moved on to the next URL. These events are the client-side half of
     135         * the PHP hooks: same moments, same names.
     136         *
     137         * @param {string}  name       Event name without the scanoria: prefix.
     138         * @param {Object}  detail     Payload.
     139         * @param {boolean} cancelable Whether a listener may call preventDefault().
     140         * @return {CustomEvent} The dispatched event.
     141         */
     142        function emit( name, detail, cancelable ) {
     143                var event = new CustomEvent( 'scanoria:' + name, {
     144                        detail: detail,
     145                        cancelable: !! cancelable
     146                } );
     147                document.dispatchEvent( event );
     148                return event;
     149        }
     150
     151        /**
    130152         * Why a page did not produce a result, in the operator's language.
    131153         *
    … …  
    166188                        try {
    167189                                var result = await scanOne( targets[ i ] );
    168                                 await store( targets[ i ], result );
     190                                var counts = await store( targets[ i ], result );
     191                                emit( 'page-scanned', {
     192                                        target: targets[ i ],
     193                                        url: result.url,
     194                                        issues: result.issues || [],
     195                                        counts: counts
     196                                } );
    169197                        } catch ( error ) {
    170198                                failures++;
    … …  
    183211                                ( failures ? ' ' + skippedNotice( failures ) : '' )
    184212                );
    185                 window.location.reload();
     213
     214                // The reload is how the results table catches up, but it also ends the
     215                // page — a listener that wanted to write a history entry or draw a diff
     216                // would be cut off mid-work. So the event is cancelable: preventDefault()
     217                // means the listener has taken responsibility for refreshing the view.
     218                var finished = emit( 'scan-complete', {
     219                        targets: targets,
     220                        scanned: targets.length - failures,
     221                        failures: failures
     222                }, true );
     223
     224                if ( ! finished.defaultPrevented ) {
     225                        window.location.reload();
     226                }
    186227        }
    187228
  • scanoria-accessibility-audit/trunk/includes/class-scanoria-admin.php

    r3631871 r3671081  
    2727                        81
    2828                );
     29
     30                /**
     31                 * The top-level menu exists; add-ons can hang a submenu off it here.
     32                 *
     33                 * The slug and the capability are handed over rather than left to be
     34                 * guessed, because both are things a site can change: the capability runs
     35                 * through the scanoria_capability filter, and a submenu registered against
     36                 * a wider one would appear for people who cannot open the parent.
     37                 *
     38                 * @param string $slug       Parent menu slug.
     39                 * @param string $capability Capability required to see it.
     40                 */
     41                do_action( 'scanoria_admin_menu', self::SLUG, scanoria_get_capability() );
    2942        }
    3043
    … …  
    4154                wp_enqueue_style( 'scanoria-admin', SCANORIA_URL . 'assets/css/admin.css', array(), SCANORIA_VERSION );
    4255                wp_enqueue_script( 'scanoria-admin', SCANORIA_URL . 'assets/js/admin.js', array( 'wp-api-fetch' ), SCANORIA_VERSION, true );
     56
     57                /**
     58                 * Our screen is being set up and our script is queued.
     59                 *
     60                 * An add-on enqueues here so it can declare scanoria-admin as a dependency
     61                 * and so it loads on this screen only. The scan events the script emits
     62                 * (scanoria:page-scanned, scanoria:scan-complete) are the client-side half
     63                 * of this contract.
     64                 *
     65                 * @param string $handle  Script handle of the admin script.
     66                 * @param string $version Version of the free plugin.
     67                 */
     68                do_action( 'scanoria_admin_assets', 'scanoria-admin', SCANORIA_VERSION );
    4369
    4470                wp_localize_script(
    … …  
    137163                }
    138164
    139                 return $targets;
     165                /**
     166                 * What will be scanned, in order.
     167                 *
     168                 * Filtering the list rather than the query is deliberate: an add-on that
     169                 * wants to add archives, or to re-scan only what changed since last time,
     170                 * is working with URLs, not with WP_Query arguments.
     171                 *
     172                 * @param array $targets Each with id, title, type and scan_url.
     173                 */
     174                return apply_filters( 'scanoria_scan_targets', $targets );
    140175        }
    141176
    … …  
    159194                                </button>
    160195                                <span id="scanoria-progress" class="scanoria-progress" role="status" aria-live="polite"></span>
     196                                <?php
     197                                /**
     198                                 * Room next to the scan button, for actions that act on the whole
     199                                 * site: export, printable report, history.
     200                                 */
     201                                do_action( 'scanoria_admin_toolbar', $summary );
     202                                ?>
    161203                        </div>
    162204
    … …  
    216258                                </table>
    217259                        <?php endif; ?>
     260
     261                        <?php
     262                        /**
     263                         * Below the results table.
     264                         *
     265                         * @param array $summary Per-post counts as shown above.
     266                         */
     267                        do_action( 'scanoria_admin_after_results', $summary );
     268                        ?>
    218269                </div>
    219270                <?php
  • scanoria-accessibility-audit/trunk/includes/class-scanoria-store.php

    r3631061 r3671081  
    8181                }
    8282
    83                 return array(
     83                $counts = array(
    8484                        'total'   => count( $issues ),
    8585                        'open'    => $open,
    8686                        'carried' => $carried,
    8787                );
     88
     89                /**
     90                 * One URL has just been re-scanned and the results written.
     91                 *
     92                 * This fires after the rows are in the database, so a listener can read
     93                 * the stored findings rather than trusting the payload. Scan history and
     94                 * the change-since-last-scan view are built from here: the counts are the
     95                 * whole of what a history row needs, and $issues carries the detail for
     96                 * anything that wants to diff element by element.
     97                 *
     98                 * @param int    $post_id Post the URL belongs to, 0 if none.
     99                 * @param string $url     Scanned URL.
     100                 * @param array  $counts  total / open / carried.
     101                 * @param array  $issues  Sanitised issue payloads, in scan order.
     102                 */
     103                do_action( 'scanoria_scan_recorded', $post_id, $url, $counts, $issues );
     104
     105                return $counts;
     106        }
     107
     108        /**
     109         * Every stored finding, with any decision attached.
     110         *
     111         * Nothing in the free plugin calls this: the admin screen loads one post at a
     112         * time. It exists because a CSV export or a printable report needs the whole
     113         * set at once, and the alternative is every add-on writing its own join
     114         * against these two tables and then breaking the day a column moves.
     115         *
     116         * @param bool $include_decided Include findings already ignored or resolved.
     117         * @return array
     118         */
     119        public static function all_issues( $include_decided = true ) {
     120                global $wpdb;
     121
     122                // The two queries are written out in full rather than sharing one string
     123                // with a WHERE clause dropped into it. A clause held in a variable — even
     124                // one that can only ever be a literal picked by a boolean — reads to the
     125                // directory's own Plugin Check as an unescaped parameter, and a warning on
     126                // a database call is not something to argue with a reviewer about.
     127                // phpcs:disable WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
     128                if ( $include_decided ) {
     129                        $rows = $wpdb->get_results(
     130                                "SELECT i.*, d.verdict, d.reason, d.site_wide, d.created_at AS decided_at
     131                                 FROM {$wpdb->prefix}scanoria_issues i
     132                                 LEFT JOIN {$wpdb->prefix}scanoria_decisions d ON d.id = i.decision_id
     133                                 ORDER BY i.post_id ASC, (i.decision_id > 0) ASC, FIELD(i.impact,'critical','serious','moderate','minor') ASC, i.id ASC",
     134                                ARRAY_A
     135                        );
     136                } else {
     137                        $rows = $wpdb->get_results(
     138                                "SELECT i.*, d.verdict, d.reason, d.site_wide, d.created_at AS decided_at
     139                                 FROM {$wpdb->prefix}scanoria_issues i
     140                                 LEFT JOIN {$wpdb->prefix}scanoria_decisions d ON d.id = i.decision_id
     141                                 WHERE i.decision_id = 0
     142                                 ORDER BY i.post_id ASC, FIELD(i.impact,'critical','serious','moderate','minor') ASC, i.id ASC",
     143                                ARRAY_A
     144                        );
     145                }
     146                // phpcs:enable
     147
     148                return $rows ? $rows : array();
    88149        }
    89150
    … …  
    272333                );
    273334
     335                /**
     336                 * A human has judged a finding.
     337                 *
     338                 * The issue row is passed as it stood at the moment of the decision,
     339                 * because the next scan deletes it: a listener keeping an audit trail has
     340                 * no other chance to record what was actually decided about.
     341                 *
     342                 * @param int   $decision_id New decision id.
     343                 * @param int   $issue_id    Issue that was judged.
     344                 * @param string $verdict    ignored or resolved.
     345                 * @param bool  $site_wide   Applied to every post on the site.
     346                 * @param array $issue       The issue row as it stood.
     347                 */
     348                do_action( 'scanoria_decision_recorded', $decision_id, (int) $issue_id, $verdict, (bool) $site_wide, $issue );
     349
    274350                return $decision_id;
    275351        }
    … …  
    298374                        array( '%d' )
    299375                );
     376
     377                /**
     378                 * A decision is about to be removed and the finding put back on the open
     379                 * list. Fired before the delete so a listener can still read the row.
     380                 *
     381                 * @param int $decision_id Decision being removed.
     382                 */
     383                do_action( 'scanoria_decision_removed', $decision_id );
    300384
    301385                return (bool) $wpdb->delete( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
  • scanoria-accessibility-audit/trunk/readme.txt

    r3631871 r3671081  
    33Tags: accessibility, wcag, a11y, ada, eaa
    44Requires at least: 6.0
    5 Tested up to: 7.0
     5Tested up to: 7.1
    66Requires PHP: 7.4
    7 Stable tag: 0.1.2
     7Stable tag: 0.2.0
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    104104Deactivating the plugin, as opposed to deleting it, never removes anything.
    105105
     106= Can I extend it from my own plugin? =
     107
     108Yes. Nothing needs to be edited or forked.
     109
     110On the PHP side: `scanoria_loaded` fires once every class exists and is the right place to bind (binding to `plugins_loaded` directly can run too early). `scanoria_scan_recorded` fires after a page's results are written, `scanoria_decision_recorded` and `scanoria_decision_removed` when somebody ignores or resolves a finding — the issue row is passed along with the decision, because the next scan deletes it. `scanoria_admin_menu`, `scanoria_admin_assets`, `scanoria_admin_toolbar` and `scanoria_admin_after_results` are the places to add screens, scripts and buttons, and `scanoria_scan_targets` filters what will be scanned.
     111
     112On the browser side, the scan runs in the page, so PHP alone cannot tell you a page finished: the screen dispatches `scanoria:page-scanned` on `document` after each page and `scanoria:scan-complete` at the end. The last one is cancelable — calling `preventDefault()` stops the automatic reload, in which case refreshing the view is up to you.
     113
    106114== Screenshots ==
    107115
    … …  
    112120
    113121== Changelog ==
     122
     123= 0.2.0 =
     124* Added hooks so an add-on can extend the plugin without modifying it: actions when a scan is recorded and when a decision is made or undone, places to add buttons and screens in the admin, a filter over the list of pages to scan, and browser events while a scan runs.
     125* No change to what the plugin does. Nothing was moved behind a paywall, and it still makes no external requests.
    114126
    115127= 0.1.2 =
  • scanoria-accessibility-audit/trunk/scanoria-accessibility-audit.php

    r3631871 r3671081  
    44 * Plugin URI:        https://wordpress.org/plugins/scanoria-accessibility-audit/
    55 * Description:       Find WCAG, ADA and EAA accessibility problems on your site. Scans the page as visitors actually see it, so page builders are supported. Your decisions to ignore or resolve an issue survive re-scans. Runs entirely on your own server: no account, no external requests, unlimited sites.
    6  * Version:           0.1.2
     6 * Version:           0.2.0
    77 * Requires at least: 6.0
    88 * Requires PHP:      7.4
    … …  
    1616defined( 'ABSPATH' ) || exit;
    1717
    18 define( 'SCANORIA_VERSION', '0.1.2' );
     18define( 'SCANORIA_VERSION', '0.2.0' );
    1919define( 'SCANORIA_FILE', __FILE__ );
    2020define( 'SCANORIA_DIR', plugin_dir_path( __FILE__ ) );
    … …  
    5454                        ( new Scanoria_Admin() )->register();
    5555                }
     56
     57                /**
     58                 * Everything this plugin registers is now in place.
     59                 *
     60                 * An add-on binds here rather than on plugins_loaded directly: load order
     61                 * between two plugins is alphabetical by folder, so an add-on that hooked
     62                 * plugins_loaded itself could easily run before these classes exist. The
     63                 * version is passed so an add-on can refuse to run against a build that
     64                 * predates a hook it needs.
     65                 *
     66                 * @param string $version Version of the free plugin.
     67                 */
     68                do_action( 'scanoria_loaded', SCANORIA_VERSION );
    5669        }
    5770);
Note: See TracChangeset for help on using the changeset viewer.