Plugin Directory

Changeset 3687066


Ignore:
Timestamp:
09/08/2026 05:10:00 PM (7 weeks ago)
Author:
dagemawi409
Message:

Release UsageRay 0.7.0

Location:
usageray
Files:
26 added
10 edited
1 copied

Legend:

Unmodified
Added
Removed
  • usageray/tags/0.7.0/docs/compatibility.md

    r3686228 r3687066  
    1818| Ninja Forms | 3.15.2, 3.15.3 | Submission content type, shortcode, options | Verified |
    1919| Yoast SEO | 28.4 | Metadata, options, indexables table | Verified |
    20 | Rank Math SEO | 1.0.277.2 | Metadata and options | Verified |
     20| Rank Math SEO | 1.0.277.2, 1.0.278 | Metadata and options | Verified |
    2121| All in One SEO | 5.0.1.1 | Metadata, options, posts table | Verified |
    2222| The Events Calendar | 6.17.4 | Event content types and options | Verified |
    … …  
    2424| UpdraftPlus | 1.26.7 | Backup settings and runtime-state option namespaces | Verified |
    2525| LiteSpeed Cache | 7.9.1 | Current and legacy settings namespaces | Verified |
    26 | Wordfence Security | Source reviewed: 9.0.0 | Activation state and network-scoped configuration, issue, traffic, block, and firewall tables | Maintained; a post-activation Playground request is not reproducible |
     26| Wordfence Security | Source reviewed: 9.0.1 | Activation state and network-scoped configuration, issue, traffic, block, and firewall tables | Maintained; a post-activation Playground request is not reproducible |
    2727| WP Super Cache | Source reviewed: 3.1.3 | Settings, statistics, and preload-state option namespaces | Maintained; cache drop-in activation is not reproducible in Playground |
    2828
  • usageray/tags/0.7.0/includes/class-audit.php

    r3686228 r3687066  
    126126                        return new \WP_Error( 'usageray_audit_missing', __( 'This audit expired or could not be found. Start a new audit.', 'usageray' ) );
    127127                }
     128                if ( ! $this->valid_state( $state, $audit_id ) ) {
     129                        $this->store->delete( $audit_id );
     130                        return new \WP_Error( 'usageray_audit_invalid', __( 'This audit state was damaged and has been discarded. Start a new audit.', 'usageray' ) );
     131                }
     132                $previous_phase = isset( $state['phase'] ) ? $state['phase'] : '';
    128133
    129134                $scanner = new Scanner();
    … …  
    140145                }
    141146
    142                 if ( 'complete' === $state['phase'] && 'site' === ( isset( $state['audit_type'] ) ? $state['audit_type'] : 'site' ) ) {
     147                $completed_now = 'complete' !== $previous_phase && 'complete' === $state['phase'];
     148                if ( $completed_now && 'site' === ( isset( $state['audit_type'] ) ? $state['audit_type'] : 'site' ) ) {
    143149                        $history = $this->history_store->record( $state );
    144150                        $state['history_saved']   = ! is_wp_error( $history );
    … …  
    147153
    148154                $this->store->save( $audit_id, $state );
    149                 return $this->snapshot( $state );
     155                $snapshot = $this->snapshot( $state );
     156                if ( $completed_now ) {
     157                        /**
     158                         * Fires once after a completed audit has been saved.
     159                         *
     160                         * The snapshot contains only UsageRay's public result shape. It does not
     161                         * expose matched source text, option values, metadata values, or paths.
     162                         *
     163                         * @since 0.7.0
     164                         *
     165                         * @param array $snapshot Public completion snapshot.
     166                         * @param array $context  Audit type and current-site identity.
     167                         */
     168                        do_action(
     169                                'usageray_audit_completed',
     170                                $snapshot,
     171                                array(
     172                                        'schema_version' => 1,
     173                                        'audit_type'     => isset( $state['audit_type'] ) ? $state['audit_type'] : 'site',
     174                                        'site_id'        => get_current_blog_id(),
     175                                )
     176                        );
     177                }
     178                return $snapshot;
    150179        }
    151180
    … …  
    172201        public function completed_report( $audit_id ) {
    173202                $state = $this->store->get( $audit_id );
    174                 if ( null === $state || 'complete' !== $state['phase'] ) {
     203                if ( null === $state ) {
     204                        return new \WP_Error( 'usageray_report_missing', __( 'This completed audit expired or could not be found. Run the audit again.', 'usageray' ) );
     205                }
     206                if ( ! $this->valid_state( $state, $audit_id ) ) {
     207                        $this->store->delete( $audit_id );
     208                        return new \WP_Error( 'usageray_report_invalid', __( 'This completed audit was damaged and has been discarded. Run the audit again.', 'usageray' ) );
     209                }
     210                if ( 'complete' !== $state['phase'] ) {
    175211                        return new \WP_Error( 'usageray_report_missing', __( 'This completed audit expired or could not be found. Run the audit again.', 'usageray' ) );
    176212                }
    … …  
    361397                        'options'  => isset( $batch_sizes['options'] ) ? min( 500, max( 25, (int) $batch_sizes['options'] ) ) : self::OPTIONS_BATCH,
    362398                );
     399        }
     400
     401        /**
     402         * Reject incomplete or damaged transient state before reading phase fields.
     403         *
     404         * @param array  $state    Stored audit state.
     405         * @param string $audit_id Requested audit UUID.
     406         * @return bool
     407         */
     408        private function valid_state( array $state, $audit_id ) {
     409                $required = array(
     410                        'audit_id',
     411                        'user_id',
     412                        'phase',
     413                        'audit_type',
     414                        'plugin_files',
     415                        'plugin_data',
     416                        'plugin_index',
     417                        'total_plugins',
     418                        'total_content',
     419                        'last_post_id',
     420                        'posts_scanned',
     421                        'total_metadata',
     422                        'last_meta_id',
     423                        'metadata_scanned',
     424                        'total_options',
     425                        'last_option_id',
     426                        'options_scanned',
     427                        'batch_sizes',
     428                        'results',
     429                );
     430                foreach ( $required as $key ) {
     431                        if ( ! array_key_exists( $key, $state ) ) {
     432                                return false;
     433                        }
     434                }
     435
     436                if ( (string) $audit_id !== $state['audit_id'] || ! in_array( $state['phase'], array( 'discovery', 'content', 'metadata', 'options', 'finalizing', 'complete' ), true ) ) {
     437                        return false;
     438                }
     439                if ( ! in_array( $state['audit_type'], array( 'site', 'preflight' ), true ) || ! is_array( $state['plugin_files'] ) || ! is_array( $state['plugin_data'] ) || ! is_array( $state['batch_sizes'] ) || ! is_array( $state['results'] ) ) {
     440                        return false;
     441                }
     442                foreach ( array( 'content', 'metadata', 'options' ) as $phase ) {
     443                        if ( ! isset( $state['batch_sizes'][ $phase ] ) || 0 >= (int) $state['batch_sizes'][ $phase ] ) {
     444                                return false;
     445                        }
     446                }
     447                foreach ( array( 'plugin_index', 'total_plugins', 'total_content', 'last_post_id', 'posts_scanned', 'total_metadata', 'last_meta_id', 'metadata_scanned', 'total_options', 'last_option_id', 'options_scanned' ) as $counter ) {
     448                        if ( ! is_numeric( $state[ $counter ] ) || 0 > (int) $state[ $counter ] ) {
     449                                return false;
     450                        }
     451                }
     452
     453                return true;
    363454        }
    364455
  • usageray/tags/0.7.0/includes/class-built-in-adapters.php

    r3686228 r3687066  
    193193                                'Rank Math SEO',
    194194                                array( 'seo-by-rank-math/rank-math.php' ),
    195                                 array( '1.0.277.2' ),
     195                                array( '1.0.277.2', '1.0.278' ),
    196196                                array(
    197197                                        'meta_rules' => array(
    … …  
    296296                                ),
    297297                                'maintained',
    298                                 __( 'Version 9.0.0 source was reviewed, but a post-activation WordPress Playground request does not complete reproducibly.', 'usageray' )
     298                                __( 'Version 9.0.1 source was reviewed, but a post-activation WordPress Playground request does not complete reproducibly.', 'usageray' )
    299299                        ),
    300300                        self::definition(
  • usageray/tags/0.7.0/readme.txt

    r3686228 r3687066  
    55Tested up to: 7.1
    66Requires PHP: 7.4
    7 Stable tag: 0.6.0
     7Stable tag: 0.7.0
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    6666Use UsageRay when cleaning up an inherited site, replacing a form or page-builder plugin, preparing a client maintenance report, or investigating whether an installed extension still supports content or background behavior.
    6767
     68= Use UsageRay from WP-CLI =
     69
     70Developers, agencies, and automation systems can run the same read-only audit engine without opening wp-admin. Use `wp usageray audit` to inspect the installed plugin stack or `wp usageray inspect <plugin>` for one plugin by slug or complete basename. List retained audits with `wp usageray history list`, compare `previous` with `latest`, or export a retained audit without rescanning content. Commands support concise tables and privacy-safe JSON or CSV output. Machine-readable formats include stable schema identifiers, automatically suppress interactive progress, and can use optional `--fail-on` policies for CI. Exit code 2 means a requested policy matched after successful output; operational failures remain exit code 1.
     71
    6872= See UsageRay in action =
    6973
    … …  
    115119Yes, but only after an administrator explicitly enables Daily or Weekly scheduling in Tools > UsageRay. Scheduling uses WordPress cron, which runs when the site receives traffic, so times are approximate. It uses no external service, does not track the site, never changes plugin state or content, and can be turned off at any time.
    116120
     121= Can I run UsageRay with WP-CLI? =
     122
     123Yes. Run `wp usageray audit` for a site-wide audit or `wp usageray inspect plugin-slug` for one installed plugin. A complete basename such as `plugin-directory/plugin-file.php` also works. Add `--format=json` or `--format=csv` for machine-readable output and `--quiet` to hide interactive progress. These commands do not deactivate plugins or change content.
     124
    117125= Why did a Deactivation Preflight open immediately? =
    118126
    … …  
    146154
    147155== Changelog ==
     156
     157= 0.7.0 =
     158
     159* Added read-only WP-CLI commands to audit all installed plugins, inspect one plugin, list history, compare saved audits, and export retained results.
     160* Added stable success, operational-error, and policy-match exit codes plus optional `--fail-on` policies for CI and maintenance automation.
     161* Added four named Draft 2020-12 JSON schemas and validated actual command output against every packaged schema.
     162* Added a privacy-safe one-time audit completion action and a versioned, bounded PHP API for hosting dashboards and maintenance agents.
     163* Added fail-closed handling for interrupted, inaccessible, or structurally damaged audit progress without changing content or plugin state.
     164* Reverified the eighteen-plugin compatibility matrix, including the maintained Wordfence Security 9.0.1 ownership signals.
     165
     166= 0.7.0-rc.1 =
     167
     168* Froze the complete 0.7.0 developer and agent interface for final release-candidate verification.
     169* Changed no scanning, user-interface, command, schema, hook, or PHP API behavior from beta 1.
     170* Repeated command, compatibility, upgrade, multisite, stress, real-plugin, responsive, accessibility, privacy, and Plugin Check validation against the exact package.
     171
     172= 0.7.0-beta.1 =
     173
     174* Froze the 0.7.0 WP-CLI, JSON schema, completion-hook, and PHP API feature set for regression testing.
     175* Added fail-closed validation that discards structurally damaged audit progress before phase processing or report generation.
     176* Added real-command tests for successful, operational-error, and policy-match exit codes while preserving JSON output before exit 2.
     177* Added interrupted, damaged, user-isolated, bounded-batch, and private-output regression coverage for the PHP integration API.
     178* Reverified the maintained Wordfence Security ownership signals against version 9.0.1 after its release during beta testing.
     179
     180= 0.7.0-alpha.4 =
     181
     182* Added a versioned, read-only PHP integration API for hosting panels, maintenance agents, and systems that cannot invoke WP-CLI.
     183* Added bounded site-audit control plus privacy-safe history, retained-audit, comparison, and schema-catalog methods.
     184* Documented the stable developer surface and the authentication responsibilities of integrations that expose it through another transport.
     185* Added contract tests that validate real WP-CLI JSON output against all four packaged Draft 2020-12 schemas.
     186
     187= 0.7.0-alpha.3 =
     188
     189* Added stable WP-CLI exit codes: 0 for a successful policy pass, 1 for invalid input or operational failure, and 2 when a requested policy matches after successful output.
     190* Added optional `--fail-on` policies for audits, focused inspections, and retained-history comparisons.
     191* Added named version-1 JSON schemas for audit, history, comparison, and retained-audit documents.
     192* Added a privacy-safe `usageray_audit_completed` hook plus CI and hosting-integration documentation.
     193* Reverified the Rank Math SEO adapter with version 1.0.278 in the eighteen-plugin compatibility matrix.
     194
     195= 0.7.0-alpha.2 =
     196
     197* Added `wp usageray history list` with table, JSON, and CSV output.
     198* Added deterministic `wp usageray compare <baseline> <current>` output without rescanning content, including convenient `previous` and `latest` selectors.
     199* Added `wp usageray export <audit>` for privacy-safe retained audit snapshots in table, JSON, or CSV format.
     200* Added missing, invalid, and unavailable audit-ID handling plus formula-safe history and comparison CSV output.
     201
     202= 0.7.0-alpha.1 =
     203
     204* Added read-only `wp usageray audit` and `wp usageray inspect <plugin>` commands with slug and complete-basename support.
     205* Added table, privacy-safe JSON, and spreadsheet-safe CSV output.
     206* Reused the bounded audit engine so command-line results retain the same evidence, coverage, history, and privacy rules as wp-admin.
     207* Added interactive progress for terminal tables and quiet machine output for automation.
    148208
    149209= 0.6.0 =
  • usageray/tags/0.7.0/usageray.php

    r3686228 r3687066  
    33 * Plugin Name:       UsageRay – See Where Plugins Are Used
    44 * Description:       See what a plugin may still support before you deactivate, replace, or remove it.
    5  * Version:           0.6.0
     5 * Version:           0.7.0
    66 * Requires at least: 6.2
    77 * Requires PHP:      7.4
    … …  
    2020}
    2121
    22 define( 'USAGERAY_VERSION', '0.6.0' );
     22define( 'USAGERAY_VERSION', '0.7.0' );
    2323define( 'USAGERAY_PLUGIN_FILE', __FILE__ );
    2424define( 'USAGERAY_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
    … …  
    3838require_once USAGERAY_PLUGIN_DIR . 'includes/class-scheduler.php';
    3939require_once USAGERAY_PLUGIN_DIR . 'includes/class-admin.php';
     40require_once USAGERAY_PLUGIN_DIR . 'includes/class-cli-service.php';
     41require_once USAGERAY_PLUGIN_DIR . 'includes/class-developer-api.php';
     42
     43if ( defined( 'WP_CLI' ) && WP_CLI ) {
     44        require_once USAGERAY_PLUGIN_DIR . 'includes/class-cli-command.php';
     45        \WP_CLI::add_command( 'usageray', __NAMESPACE__ . '\\CLI_Command' );
     46        \WP_CLI::add_command( 'usageray history', __NAMESPACE__ . '\\CLI_History_Command' );
     47}
    4048
    4149add_action(
    4250        'plugins_loaded',
    4351        static function () {
     52                /**
     53                 * Fires when UsageRay's versioned, read-only PHP API is available.
     54                 *
     55                 * @since 0.7.0
     56                 *
     57                 * @param Developer_API $api Shared API instance.
     58                 */
     59                do_action( 'usageray_developer_api_ready', developer_api() );
    4460                Scheduler::instance();
    4561                if ( is_admin() ) {
  • usageray/trunk/docs/compatibility.md

    r3686228 r3687066  
    1818| Ninja Forms | 3.15.2, 3.15.3 | Submission content type, shortcode, options | Verified |
    1919| Yoast SEO | 28.4 | Metadata, options, indexables table | Verified |
    20 | Rank Math SEO | 1.0.277.2 | Metadata and options | Verified |
     20| Rank Math SEO | 1.0.277.2, 1.0.278 | Metadata and options | Verified |
    2121| All in One SEO | 5.0.1.1 | Metadata, options, posts table | Verified |
    2222| The Events Calendar | 6.17.4 | Event content types and options | Verified |
    … …  
    2424| UpdraftPlus | 1.26.7 | Backup settings and runtime-state option namespaces | Verified |
    2525| LiteSpeed Cache | 7.9.1 | Current and legacy settings namespaces | Verified |
    26 | Wordfence Security | Source reviewed: 9.0.0 | Activation state and network-scoped configuration, issue, traffic, block, and firewall tables | Maintained; a post-activation Playground request is not reproducible |
     26| Wordfence Security | Source reviewed: 9.0.1 | Activation state and network-scoped configuration, issue, traffic, block, and firewall tables | Maintained; a post-activation Playground request is not reproducible |
    2727| WP Super Cache | Source reviewed: 3.1.3 | Settings, statistics, and preload-state option namespaces | Maintained; cache drop-in activation is not reproducible in Playground |
    2828
  • usageray/trunk/includes/class-audit.php

    r3686228 r3687066  
    126126                        return new \WP_Error( 'usageray_audit_missing', __( 'This audit expired or could not be found. Start a new audit.', 'usageray' ) );
    127127                }
     128                if ( ! $this->valid_state( $state, $audit_id ) ) {
     129                        $this->store->delete( $audit_id );
     130                        return new \WP_Error( 'usageray_audit_invalid', __( 'This audit state was damaged and has been discarded. Start a new audit.', 'usageray' ) );
     131                }
     132                $previous_phase = isset( $state['phase'] ) ? $state['phase'] : '';
    128133
    129134                $scanner = new Scanner();
    … …  
    140145                }
    141146
    142                 if ( 'complete' === $state['phase'] && 'site' === ( isset( $state['audit_type'] ) ? $state['audit_type'] : 'site' ) ) {
     147                $completed_now = 'complete' !== $previous_phase && 'complete' === $state['phase'];
     148                if ( $completed_now && 'site' === ( isset( $state['audit_type'] ) ? $state['audit_type'] : 'site' ) ) {
    143149                        $history = $this->history_store->record( $state );
    144150                        $state['history_saved']   = ! is_wp_error( $history );
    … …  
    147153
    148154                $this->store->save( $audit_id, $state );
    149                 return $this->snapshot( $state );
     155                $snapshot = $this->snapshot( $state );
     156                if ( $completed_now ) {
     157                        /**
     158                         * Fires once after a completed audit has been saved.
     159                         *
     160                         * The snapshot contains only UsageRay's public result shape. It does not
     161                         * expose matched source text, option values, metadata values, or paths.
     162                         *
     163                         * @since 0.7.0
     164                         *
     165                         * @param array $snapshot Public completion snapshot.
     166                         * @param array $context  Audit type and current-site identity.
     167                         */
     168                        do_action(
     169                                'usageray_audit_completed',
     170                                $snapshot,
     171                                array(
     172                                        'schema_version' => 1,
     173                                        'audit_type'     => isset( $state['audit_type'] ) ? $state['audit_type'] : 'site',
     174                                        'site_id'        => get_current_blog_id(),
     175                                )
     176                        );
     177                }
     178                return $snapshot;
    150179        }
    151180
    … …  
    172201        public function completed_report( $audit_id ) {
    173202                $state = $this->store->get( $audit_id );
    174                 if ( null === $state || 'complete' !== $state['phase'] ) {
     203                if ( null === $state ) {
     204                        return new \WP_Error( 'usageray_report_missing', __( 'This completed audit expired or could not be found. Run the audit again.', 'usageray' ) );
     205                }
     206                if ( ! $this->valid_state( $state, $audit_id ) ) {
     207                        $this->store->delete( $audit_id );
     208                        return new \WP_Error( 'usageray_report_invalid', __( 'This completed audit was damaged and has been discarded. Run the audit again.', 'usageray' ) );
     209                }
     210                if ( 'complete' !== $state['phase'] ) {
    175211                        return new \WP_Error( 'usageray_report_missing', __( 'This completed audit expired or could not be found. Run the audit again.', 'usageray' ) );
    176212                }
    … …  
    361397                        'options'  => isset( $batch_sizes['options'] ) ? min( 500, max( 25, (int) $batch_sizes['options'] ) ) : self::OPTIONS_BATCH,
    362398                );
     399        }
     400
     401        /**
     402         * Reject incomplete or damaged transient state before reading phase fields.
     403         *
     404         * @param array  $state    Stored audit state.
     405         * @param string $audit_id Requested audit UUID.
     406         * @return bool
     407         */
     408        private function valid_state( array $state, $audit_id ) {
     409                $required = array(
     410                        'audit_id',
     411                        'user_id',
     412                        'phase',
     413                        'audit_type',
     414                        'plugin_files',
     415                        'plugin_data',
     416                        'plugin_index',
     417                        'total_plugins',
     418                        'total_content',
     419                        'last_post_id',
     420                        'posts_scanned',
     421                        'total_metadata',
     422                        'last_meta_id',
     423                        'metadata_scanned',
     424                        'total_options',
     425                        'last_option_id',
     426                        'options_scanned',
     427                        'batch_sizes',
     428                        'results',
     429                );
     430                foreach ( $required as $key ) {
     431                        if ( ! array_key_exists( $key, $state ) ) {
     432                                return false;
     433                        }
     434                }
     435
     436                if ( (string) $audit_id !== $state['audit_id'] || ! in_array( $state['phase'], array( 'discovery', 'content', 'metadata', 'options', 'finalizing', 'complete' ), true ) ) {
     437                        return false;
     438                }
     439                if ( ! in_array( $state['audit_type'], array( 'site', 'preflight' ), true ) || ! is_array( $state['plugin_files'] ) || ! is_array( $state['plugin_data'] ) || ! is_array( $state['batch_sizes'] ) || ! is_array( $state['results'] ) ) {
     440                        return false;
     441                }
     442                foreach ( array( 'content', 'metadata', 'options' ) as $phase ) {
     443                        if ( ! isset( $state['batch_sizes'][ $phase ] ) || 0 >= (int) $state['batch_sizes'][ $phase ] ) {
     444                                return false;
     445                        }
     446                }
     447                foreach ( array( 'plugin_index', 'total_plugins', 'total_content', 'last_post_id', 'posts_scanned', 'total_metadata', 'last_meta_id', 'metadata_scanned', 'total_options', 'last_option_id', 'options_scanned' ) as $counter ) {
     448                        if ( ! is_numeric( $state[ $counter ] ) || 0 > (int) $state[ $counter ] ) {
     449                                return false;
     450                        }
     451                }
     452
     453                return true;
    363454        }
    364455
  • usageray/trunk/includes/class-built-in-adapters.php

    r3686228 r3687066  
    193193                                'Rank Math SEO',
    194194                                array( 'seo-by-rank-math/rank-math.php' ),
    195                                 array( '1.0.277.2' ),
     195                                array( '1.0.277.2', '1.0.278' ),
    196196                                array(
    197197                                        'meta_rules' => array(
    … …  
    296296                                ),
    297297                                'maintained',
    298                                 __( 'Version 9.0.0 source was reviewed, but a post-activation WordPress Playground request does not complete reproducibly.', 'usageray' )
     298                                __( 'Version 9.0.1 source was reviewed, but a post-activation WordPress Playground request does not complete reproducibly.', 'usageray' )
    299299                        ),
    300300                        self::definition(
  • usageray/trunk/readme.txt

    r3686228 r3687066  
    55Tested up to: 7.1
    66Requires PHP: 7.4
    7 Stable tag: 0.6.0
     7Stable tag: 0.7.0
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    6666Use UsageRay when cleaning up an inherited site, replacing a form or page-builder plugin, preparing a client maintenance report, or investigating whether an installed extension still supports content or background behavior.
    6767
     68= Use UsageRay from WP-CLI =
     69
     70Developers, agencies, and automation systems can run the same read-only audit engine without opening wp-admin. Use `wp usageray audit` to inspect the installed plugin stack or `wp usageray inspect <plugin>` for one plugin by slug or complete basename. List retained audits with `wp usageray history list`, compare `previous` with `latest`, or export a retained audit without rescanning content. Commands support concise tables and privacy-safe JSON or CSV output. Machine-readable formats include stable schema identifiers, automatically suppress interactive progress, and can use optional `--fail-on` policies for CI. Exit code 2 means a requested policy matched after successful output; operational failures remain exit code 1.
     71
    6872= See UsageRay in action =
    6973
    … …  
    115119Yes, but only after an administrator explicitly enables Daily or Weekly scheduling in Tools > UsageRay. Scheduling uses WordPress cron, which runs when the site receives traffic, so times are approximate. It uses no external service, does not track the site, never changes plugin state or content, and can be turned off at any time.
    116120
     121= Can I run UsageRay with WP-CLI? =
     122
     123Yes. Run `wp usageray audit` for a site-wide audit or `wp usageray inspect plugin-slug` for one installed plugin. A complete basename such as `plugin-directory/plugin-file.php` also works. Add `--format=json` or `--format=csv` for machine-readable output and `--quiet` to hide interactive progress. These commands do not deactivate plugins or change content.
     124
    117125= Why did a Deactivation Preflight open immediately? =
    118126
    … …  
    146154
    147155== Changelog ==
     156
     157= 0.7.0 =
     158
     159* Added read-only WP-CLI commands to audit all installed plugins, inspect one plugin, list history, compare saved audits, and export retained results.
     160* Added stable success, operational-error, and policy-match exit codes plus optional `--fail-on` policies for CI and maintenance automation.
     161* Added four named Draft 2020-12 JSON schemas and validated actual command output against every packaged schema.
     162* Added a privacy-safe one-time audit completion action and a versioned, bounded PHP API for hosting dashboards and maintenance agents.
     163* Added fail-closed handling for interrupted, inaccessible, or structurally damaged audit progress without changing content or plugin state.
     164* Reverified the eighteen-plugin compatibility matrix, including the maintained Wordfence Security 9.0.1 ownership signals.
     165
     166= 0.7.0-rc.1 =
     167
     168* Froze the complete 0.7.0 developer and agent interface for final release-candidate verification.
     169* Changed no scanning, user-interface, command, schema, hook, or PHP API behavior from beta 1.
     170* Repeated command, compatibility, upgrade, multisite, stress, real-plugin, responsive, accessibility, privacy, and Plugin Check validation against the exact package.
     171
     172= 0.7.0-beta.1 =
     173
     174* Froze the 0.7.0 WP-CLI, JSON schema, completion-hook, and PHP API feature set for regression testing.
     175* Added fail-closed validation that discards structurally damaged audit progress before phase processing or report generation.
     176* Added real-command tests for successful, operational-error, and policy-match exit codes while preserving JSON output before exit 2.
     177* Added interrupted, damaged, user-isolated, bounded-batch, and private-output regression coverage for the PHP integration API.
     178* Reverified the maintained Wordfence Security ownership signals against version 9.0.1 after its release during beta testing.
     179
     180= 0.7.0-alpha.4 =
     181
     182* Added a versioned, read-only PHP integration API for hosting panels, maintenance agents, and systems that cannot invoke WP-CLI.
     183* Added bounded site-audit control plus privacy-safe history, retained-audit, comparison, and schema-catalog methods.
     184* Documented the stable developer surface and the authentication responsibilities of integrations that expose it through another transport.
     185* Added contract tests that validate real WP-CLI JSON output against all four packaged Draft 2020-12 schemas.
     186
     187= 0.7.0-alpha.3 =
     188
     189* Added stable WP-CLI exit codes: 0 for a successful policy pass, 1 for invalid input or operational failure, and 2 when a requested policy matches after successful output.
     190* Added optional `--fail-on` policies for audits, focused inspections, and retained-history comparisons.
     191* Added named version-1 JSON schemas for audit, history, comparison, and retained-audit documents.
     192* Added a privacy-safe `usageray_audit_completed` hook plus CI and hosting-integration documentation.
     193* Reverified the Rank Math SEO adapter with version 1.0.278 in the eighteen-plugin compatibility matrix.
     194
     195= 0.7.0-alpha.2 =
     196
     197* Added `wp usageray history list` with table, JSON, and CSV output.
     198* Added deterministic `wp usageray compare <baseline> <current>` output without rescanning content, including convenient `previous` and `latest` selectors.
     199* Added `wp usageray export <audit>` for privacy-safe retained audit snapshots in table, JSON, or CSV format.
     200* Added missing, invalid, and unavailable audit-ID handling plus formula-safe history and comparison CSV output.
     201
     202= 0.7.0-alpha.1 =
     203
     204* Added read-only `wp usageray audit` and `wp usageray inspect <plugin>` commands with slug and complete-basename support.
     205* Added table, privacy-safe JSON, and spreadsheet-safe CSV output.
     206* Reused the bounded audit engine so command-line results retain the same evidence, coverage, history, and privacy rules as wp-admin.
     207* Added interactive progress for terminal tables and quiet machine output for automation.
    148208
    149209= 0.6.0 =
  • usageray/trunk/usageray.php

    r3686228 r3687066  
    33 * Plugin Name:       UsageRay – See Where Plugins Are Used
    44 * Description:       See what a plugin may still support before you deactivate, replace, or remove it.
    5  * Version:           0.6.0
     5 * Version:           0.7.0
    66 * Requires at least: 6.2
    77 * Requires PHP:      7.4
    … …  
    2020}
    2121
    22 define( 'USAGERAY_VERSION', '0.6.0' );
     22define( 'USAGERAY_VERSION', '0.7.0' );
    2323define( 'USAGERAY_PLUGIN_FILE', __FILE__ );
    2424define( 'USAGERAY_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
    … …  
    3838require_once USAGERAY_PLUGIN_DIR . 'includes/class-scheduler.php';
    3939require_once USAGERAY_PLUGIN_DIR . 'includes/class-admin.php';
     40require_once USAGERAY_PLUGIN_DIR . 'includes/class-cli-service.php';
     41require_once USAGERAY_PLUGIN_DIR . 'includes/class-developer-api.php';
     42
     43if ( defined( 'WP_CLI' ) && WP_CLI ) {
     44        require_once USAGERAY_PLUGIN_DIR . 'includes/class-cli-command.php';
     45        \WP_CLI::add_command( 'usageray', __NAMESPACE__ . '\\CLI_Command' );
     46        \WP_CLI::add_command( 'usageray history', __NAMESPACE__ . '\\CLI_History_Command' );
     47}
    4048
    4149add_action(
    4250        'plugins_loaded',
    4351        static function () {
     52                /**
     53                 * Fires when UsageRay's versioned, read-only PHP API is available.
     54                 *
     55                 * @since 0.7.0
     56                 *
     57                 * @param Developer_API $api Shared API instance.
     58                 */
     59                do_action( 'usageray_developer_api_ready', developer_api() );
    4460                Scheduler::instance();
    4561                if ( is_admin() ) {
Note: See TracChangeset for help on using the changeset viewer.