Implement server-side gated content with HubSpot verification#14
Open
roborourke wants to merge 3 commits into
Open
Implement server-side gated content with HubSpot verification#14roborourke wants to merge 3 commits into
roborourke wants to merge 3 commits into
Conversation
…n page Gated success-message content was previously rendered into a <template> element in the page source and cloned on a client-fired event, so it could be read via View Source or by dispatching the event from the console without ever submitting the form. Content is now fetched from a new POST /hubspot-form-block/v1/unlock endpoint only after submission. The endpoint re-parses the specific post and locates the specific form instance (per-page, per-instance), renders its inner blocks server-side, and returns the HTML: - Strong mode: when a HubSpot private app token is configured, the server verifies a real recent submission exists via HubSpot's Submissions API (matched by page URL, recency and email) before releasing content. - Best-effort mode (default, no token): content is kept out of the page and served from the endpoint. Repeat visits with gated content enabled replay a signed, expiring HMAC unlock token (no HubSpot call). The endpoint is per-IP rate-limited and caches the submissions lookup. view.js fetches/polls with backoff and shows a graceful pending message on failure. Updated docs and E2E tests.
REMOTE_ADDR alone is unreliable behind reverse proxies, load balancers and CDNs. Add get_client_ip() which checks common forwarded headers (CF-Connecting-IP, True-Client-IP, X-Real-IP, X-Forwarded-For) before falling back to REMOTE_ADDR, with hubspot_form_block_client_ip_headers and hubspot_form_block_client_ip filters so hosts can pin resolution to their trusted proxy setup. Used only for rate limiting, not access control.
Playwright E2E Test Results (PHP 8.4, WP latest)Details
Flaky testschromium › inline-message.spec.js › HubSpot Form — gated success message › does not emit gated content into the page source, but injects it after submission |
Start and stop the Playground server programmatically via @wp-playground/cli's runCLI in Playwright global setup/teardown, instead of spawning it as a separate process. This follows the WordPress Playground E2E guide and removes the brittle 'start server in the background, poll a URL, hope it's ready' steps from the CI workflow. - tests/global-setup.js boots the server (blueprint + auto-mounted plugin), honoring PLAYGROUND_PHP / PLAYGROUND_WP for the CI version matrix. - tests/global-teardown.js disposes it. - playwright.config.js wires globalSetup/globalTeardown and drops webServer. - CI passes the PHP/WP matrix via env and no longer manages the server. - Add @wp-playground/cli as a dev dependency; playground:start uses it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the client-side
<template>mechanism for inline success messages with a server-side gated content system. Success message content is no longer embedded in the page source — it is fetched from a new REST endpoint (/hubspot-form-block/v1/unlock) only after form submission. When a HubSpot private app token is configured, submissions are verified server-side against HubSpot before the content is released (strong mode); without a token, content is served immediately (best-effort mode).Key Changes
New REST endpoint (
inc/inline-message.php): Registers/hubspot-form-block/v1/unlockPOST endpoint that:Client-side polling (
src/view.js):unlock()function that polls the endpoint.is-hubspot-form-first-submission) on repeat visitsServer-side rendering (
src/render.php):<template>element emissiongated,postId,formId,instance,restUrl,pendingMessagePlugin setup (
hubspot-form-block.php):inc/inline-message.phpmodulehubspot_embed_private_app_tokenoption for storing HubSpot private app tokenStyling (
src/style.scss):.is-unlocking)Tests: Updated E2E tests to mock the unlock endpoint and verify the new gated content flow, including repeat-visit token persistence and first-submission group stripping
Implementation Details
hubspot/formblocks in render order, expanding synced patterns (core/block), to locate the specific instance by form ID and per-form-ID instance counter.https://claude.ai/code/session_01JMzDkj2EyyGLRiQDxMVZnj