Technical flow from WordPress post through PVC, consent and REST API to view count

Post Views Counter with WP-Optimize: reliable counting and Complianz consent

Why HTTP 200 did not prove the right post was being counted

This started like a typical “cache problem”. Post Views Counter was using REST API mode, the endpoint responded, yet the counter on the post I was testing did not behave reliably. The useful breakthrough came from separating four layers that are easy to mix together: page caching, JavaScript minification, current-post context, and statistics consent.

This is the exact bybrzoza.com case from 2 September 2026. I am not claiming that WP-Optimize always breaks Post Views Counter, or that every site should classify the counter in the same way. The value here is the diagnostic path and the runtime result confirmed on this installation.

Environment used for the test

Component Version during the incident
WordPress 7.1
PHP 8.5.7
Post Views Counter 1.7.15
WP-Optimize 4.6.1
Complianz 7.5.4
Polylang 3.8.7

Before copying any path, check the files loaded by your own installed version. In this setup the relevant PVC asset was post-views-counter/js/frontend.js.

1. First establish who owns the page cache

The audit found a genuine configuration problem before I even reached PVC: WP-Optimize Page Cache and Cache Enabler were both active. WP-Optimize displayed its own warning about the second page-cache plugin. I disabled Cache Enabler, kept WP-Optimize as the single page-cache owner, purged the cache and ran an anonymous smoke test.

That removed a real source of noise. It does not prove that duplicate page caching caused the later Post Views Counter context issue. Page Cache and Minify are separate features and I treated them separately from that point.

WP-Optimize warning about another active page cache plugin
Remove the confirmed duplicate page-cache setup first; diagnose Minify and PVC separately afterwards.

2. A REST 200 is not enough: verify the post ID and initiator

Post Views Counter supports multiple counting modes; the final setup here uses REST API. During troubleshooting I also made a procedural mistake that is worth documenting: one test was performed on a Page while the relevant counting scope was Posts. That test could not validate the real path.

On an actual published post the PVC endpoint could return HTTP 200. I therefore checked pvcArgsFrontend, its postID, the request URL and the JavaScript initiator in DevTools.

While PVC’s frontend code was processed inside a merged/minified WP-Optimize bundle, the request could carry stale or wrong post context. Transport looked healthy, but the visible counter was not reliably tied to the post I had open.

3. Exclude one PVC asset instead of disabling Minify

JavaScript minification and merging were both enabled in WP-Optimize. Rather than turning off the whole optimization layer, I used:

WP-Optimize → Minify → JavaScript → Exclude JavaScript from processing

For the installed PVC version, the specific path fragment was:

post-views-counter/js/frontend.js

WP-Optimize’s current documentation still states that scripts listed there are removed from both minification and merging. After saving the exclusion I reset the Minify/cache files and repeated the test anonymously.

WP-Optimize JavaScript settings showing the individual script exclusion field
The fix remained narrow: one PVC asset was excluded instead of disabling all JavaScript optimization.

After that, frontend.js loaded separately. DevTools showed the request initiated by the expected file with the correct current post ID, and both the visible and backend counters incremented consistently.

DevTools showing separately loaded frontend.js and the request for the correct current post
The useful question was not “did I get a 200?” but “did this post send the correct request?”.

4. Gate the now-working counter behind Statistics consent

On this site I treat PVC as statistics functionality. That is a configuration decision for this installation, not universal legal advice.

In Complianz → Integrations → Script Center I created a block rule:

  • Name: Post Views Counter
  • Action: Block a script, iframe or plugin
  • URL/script: post-views-counter/js/frontend.js
  • Category: Statistics

Complianz’s documentation recommends using a sufficiently specific URL or script identifier. An overly broad match can block unrelated code.

Complianz Script Center rule assigning Post Views Counter to Statistics
The PVC frontend script is blocked until statistics consent is granted.

5. Consent test matrix: before choice, Deny and Accept

I verified this in a fresh private browser session on a real published post. The browser runtime mattered more than the fact that the backend settings looked correct.

State PVC request pvc_visits[0] Count
Before choice no no no PVC increment
Deny no no no PVC increment
Accept yes yes increment confirmed
DevTools before consent without a Post Views Counter cookie
Before a consent choice there is no PVC cookie and no counting request.
DevTools after consent with the pvc_visits cookie value redacted
After Accept, pvc_visits[0] appears. Its value is permanently redacted in this screenshot.

6. Document the custom service and cookie in Complianz

Script Center controls execution, but I also wanted the Cookie Policy to describe what I could actually observe in the browser. I therefore maintained a custom service and cookie entry.

Field Value
Service Post Views Counter
Service type website statistics
Data shared No
Cookie pvc_visits[0]
Expiration 1 day
Purpose Statistics
CookieDatabase sync Off — custom entry

The English function text is: “Store visited posts and session information to prevent duplicate page view counting”. I maintained equivalent German and Polish descriptions manually.

7. A separate problem: the custom Usage sentence stayed English

There are two different Complianz/Polylang issues in this story. I already documented the earlier synchronized-document timing problem separately: Complianz + Polylang: Cookie Policy stays English — fix.

Here the main legal document was already correct. Only the generated Usage sentence for the custom PVC service remained mixed-language:

  • DE: Wir verwenden Post Views Counter für website statistics.
  • PL: Używamy Post Views Counter dla website statistics.

Maintaining the Service Type manually and adding Polylang String Translations did not change this particular custom-service fragment.

Polish and German Cookie Policy before the workaround with website statistics left in English
Before the workaround, only the custom-service Usage fragment remained in English.

8. A narrow workaround with cmplz_document_html

I did not edit Complianz vendor files. The existing MU-plugin 0.1.0 was extended to 0.2.0 with a separate filter on the final document HTML. The new part applies only to the synchronized EU Cookie Policy, only to pl_PL and de_DE, only while Complianz is >=7.5.4 and <8.0.0. English is untouched.

function bybrzoza_cmplz_localize_pvc_usage( string $html, string $type, int $post_id ): string {
    if ( $html === '' || is_admin() || wp_doing_ajax() || wp_doing_cron() ||
        ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
        return $html;
    }

    if ( ! function_exists( 'pll_current_language' ) || ! class_exists( 'COMPLIANZ' ) ) {
        return $html;
    }

    if ( ! defined( 'CMPLZ_VERSION' ) || ! isset( COMPLIANZ::$document ) ||
        ! method_exists( COMPLIANZ::$document, 'get_document_data' ) ) {
        return $html;
    }

    $cmplz_version = strtok( (string) CMPLZ_VERSION, '#' );
    if ( version_compare( $cmplz_version, '7.5.4', '<' ) ||
        version_compare( $cmplz_version, '8.0.0', '>=' ) ) {
        return $html;
    }

    $pll_locale = pll_current_language( 'locale' );
    $wp_locale  = get_locale();
    if ( ! is_string( $pll_locale ) || $pll_locale === '' || $pll_locale !== $wp_locale ) {
        return $html;
    }

    if ( ! in_array( $wp_locale, array( 'pl_PL', 'de_DE' ), true ) ) {
        return $html;
    }

    $document_data = COMPLIANZ::$document->get_document_data( $post_id );
    if ( ! is_array( $document_data ) || ( $document_data['type'] ?? '' ) !== 'cookie-statement' ) {
        return $html;
    }

    $region = $document_data['region'] ?? false;
    if ( ! $region && function_exists( 'cmplz_get_region_from_legacy_type' ) ) {
        $region = cmplz_get_region_from_legacy_type( 'cookie-statement' );
    }
    if ( $region !== 'eu' ) {
        return $html;
    }

    $replacements = array(
        'de_DE' => array(
            'old' => 'Wir verwenden Post Views Counter für website statistics',
            'new' => 'Wir verwenden Post Views Counter für Website-Statistiken',
        ),
        'pl_PL' => array(
            'old' => 'Używamy Post Views Counter dla website statistics',
            'new' => 'Używamy Post Views Counter dla statystyk witryny',
        ),
    );

    $replacement = $replacements[ $wp_locale ] ?? null;
    if ( ! is_array( $replacement ) ) {
        return $html;
    }

    return str_replace( $replacement['old'], $replacement['new'], $html );
}

add_filter( 'cmplz_document_html', 'bybrzoza_cmplz_localize_pvc_usage', 20, 3 );

The replacement is deliberately exact and service-specific. If Complianz later renders the sentence correctly, the old exact fragment disappears and this code becomes a no-op. The major-version guard also stops it at Complianz 8.x, which forces a fresh source audit instead of silently carrying a compatibility workaround forever.

9. Final PL / DE / EN result

After deploying 0.2.0 and purging the relevant cache I checked the public Cookie Policy in all three languages:

  • PL: “Używamy Post Views Counter dla statystyk witryny.” / “1 dzień” / Polish function text;
  • DE: “Wir verwenden Post Views Counter für Website-Statistiken.” / “1 Tag” / German function text;
  • EN: “We use Post Views Counter for website statistics.” / “1 day” / English function text.
Final Post Views Counter Cookie Policy section in Polish German and English
Final public QA: PL and DE are localized and the English output remains unchanged.

False leads that were worth documenting

  • Website Scan stuck at 50%. It completed once at 100% with 18 cookies and later stalled again. It was not a proven PVC root cause and I did not use it as a completion gate.
  • Testing a Page. It says little when the relevant counting target is Posts.
  • HTTP 200. Successful transport does not prove the correct post is being counted.
  • Purging cache by itself. Without checking the initiator and postID, the key evidence is missing.
  • Polylang String Translations. Useful elsewhere, but ineffective for this exact custom Usage fragment.

Rollback and update guardrails

The WP-Optimize change is easy to reverse: remove the PVC entry from the exclusion list, save, reset Minify/cache and test again. For the MU-plugin part, restore the previous 0.1.0 file or remove the additional 0.2.0 function, purge and re-check the public document.

After a PVC update, verify the actual frontend.js path again. After a WP-Optimize update, confirm the exclusion still behaves as expected. After Complianz or Polylang updates, a focused PL → DE → EN smoke test is enough to start. Do not bypass the Complianz 8.x guard without a fresh source audit.

Takeaway

The useful fix was not “clear more cache”. It was separating the layers: one page-cache owner, the correct post and request, one narrow Minify exclusion, then consent and cookie documentation. That gives each change its own verification step and its own rollback.

Sources and further reading

Did this guide help?
If it saved you some time or frustration, you can buy me a coffee.