Skip to content

Add opt-in setting to track 404 pages - #369

Open
faisalahammad wants to merge 1 commit into
pluginkollektiv:developfrom
faisalahammad:fix/track-404-opt-in
Open

Add opt-in setting to track 404 pages#369
faisalahammad wants to merge 1 commit into
pluginkollektiv:developfrom
faisalahammad:fix/track-404-opt-in

Conversation

@faisalahammad

@faisalahammad faisalahammad commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a new opt-in setting under Settings → Statify → Skip tracking for ... that allows sites to record visits ending on a 404 page. The default preserves today's behavior (404 hits are still dropped); unchecking the new "Error pages (404)" checkbox writes the request to the existing target column.

Fixes #222

Changes

inc/class-statify.php

Added 'skip_404' => 1 to the default option array in Statify::init() so old saved options fall back to "skip" via wp_parse_args (backward compatible).

Before:

return is_preview() || is_404() || is_feed() || is_search()
    || ( function_exists( 'is_favicon' ) && is_favicon() )
    || '' !== get_query_var( 'sitemap' ) || '' !== get_query_var( 'sitemap-stylesheet' );

After:

return ( 1 === self::$options['skip_404'] && is_404() ) || is_preview() || is_feed() || is_search()
    || ( function_exists( 'is_favicon' ) && is_favicon() )
    || '' !== get_query_var( 'sitemap' ) || '' !== get_query_var( 'sitemap-stylesheet' );

Why: 404 tracking is gated behind the new option; default keeps the existing skip behavior. Both skip_tracking() and wp_footer() (JS snippet path) call is_internal(), so this one change covers both tracking methods.

inc/class-statify-settings.php

Registered a new settings field statify-skip_404 in the existing statify-skip section, with a render method that mirrors the blacklist checkbox. Added 'skip_404' to the sanitize loop so a checked value is stored as 1 and unchecked as 0.

Tests

  • tests/trait-statify-test-support.php: extended init_statify_tracking() with a $skip_404 parameter (default true).
  • tests/test-tracking.php: new test test_track_404_opt_in exercises the opt-in path: with skip_404 disabled and $wp_query->is_404 = true, the request is recorded with its target path. The existing 404-skip assertion in test_skip_tracking still passes since the default keeps "skip" on.
  • tests/test-settings.php: extended the manually-initialized options array and all expected output arrays with 'skip_404' to match the sanitize loop.

Testing

Test 1: default behavior (404 still skipped)

  1. Fresh install or existing site, leave Error pages (404) checked (default).
  2. Visit a URL that returns 404 (e.g. /this-page-does-not-exist/).
  3. Open Dashboard → Statify.
    Result: 404 path does not appear in today's top targets. No new row in the statify table for that request.

Test 2: opt-in to 404 tracking

  1. Uncheck Error pages (404), save.
  2. Visit a URL that returns 404.
  3. Reload the Statify dashboard.
    Result: 404 path now appears in the top targets. A new row exists in the statify table with target = '/this-page-does-not-exist' (or with trailing slash, depending on the site's permalink structure) and created = today's date.

Test 3: opt-in works with both tracking methods
Repeat Test 2 once with the default tracking method and once with Tracking method → JavaScript based tracking with nonce check. In JS mode, the REST endpoint at /wp-json/statify/v1/track returns 204; the row is inserted server-side.

Edge cases covered by automated tests:

  • Logged-in user rules still win over the 404 setting.
  • Bot UAs (Googlebot etc.) still skip regardless of the 404 setting.
  • Restoring the default re-disables 404 tracking; existing rows remain until the normal data-retention cleanup.

Automated:

composer test          # PHPUnit, 25 tests, 274 assertions
composer lint-php      # PHPCS source
composer phpstan       # PHPStan

All green. No new PHPCS/PHPStan issues. The pre-existing tests/js/snippet.test.js phpcs noise is unrelated to this change.

Manual confirmation: tested on a local WordPress install, both tracking methods record 404 hits when the new checkbox is unchecked, and skip them when checked.

Backward Compatibility

No breaking changes. The new option defaults to the current behavior (skip 404). Old saved options missing the skip_404 key are filled in with the default value by wp_parse_args, so existing installs keep working without touching the settings page.

Screenshot

image

Visits that end on a 404 page are currently always dropped in
Statify::is_internal(). This adds a new 'skip_404' option (default
on, preserving today's behavior) so sites can opt in to recording
404 hits in the existing target column. No schema change, no
migration. Both tracking paths (template_redirect and the REST
endpoint used by the JS snippet) share the same is_internal()
guard, so the setting covers both modes.

Closes pluginkollektiv#222
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
13.1% Duplication on New Code (required ≤ 3%)
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tracking of error pages (404, ...)

2 participants