Skip to content

MR-31: Lite version of paywall#9

Open
av3nger wants to merge 20 commits into
mainfrom
feature/MR-31-paywall
Open

MR-31: Lite version of paywall#9
av3nger wants to merge 20 commits into
mainfrom
feature/MR-31-paywall

Conversation

@av3nger
Copy link
Copy Markdown
Collaborator

@av3nger av3nger commented Apr 23, 2026

Summary

This PR introduces a new visual paywall builder that lets site owners create branded, conversion-friendly paywalls without writing HTML, while keeping existing custom HTML paywalls fully working.

When enabled, admins can choose from three layouts (Simple, Card, Banner), fill in copy and links, set brand colour and button shape, and see a live preview as they type. The rendered paywall is generated from the saved configuration at read time and styled to inherit the site's typography.

What's included

  • New visual paywall builder in Memberful → Global Marketing settings.
  • Three layout options: Simple, Card, Banner.
  • Configurable fields per paywall:
    • heading
    • subheading
    • button label
    • subscribe / sign-in URLs
    • brand colour and button shape
  • Live preview that updates as the user types.
  • Output styling inherits the site's CSS so paywalls match the active theme.
  • Backwards compatibility: existing custom HTML paywalls continue to render unchanged; users can switch between Builder and Custom HTML modes.

Scope and behaviour

  • Builder output is rendered from the saved config at read time (no denormalised HTML cache).
  • Custom HTML mode is preserved for existing installs and remains a first-class option.
  • No impact when the paywall feature is not configured.

Test plan

  • Open Memberful → Global Marketing and switch the paywall mode to Builder.
  • For each layout (Simple, Card, Banner):
    • set heading, subheading, button label
    • confirm subscribe / sign-in URLs are pre-filled from the Memberful account
    • change brand colour and button shape
    • verify the live preview updates as fields change
  • Save settings and view a paywalled post as a logged-out visitor - confirm the rendered paywall matches the preview and inherits site typography.
  • Switch mode to Custom HTML and verify previously saved custom HTML paywalls still render unchanged.
  • Switch back to Builder and verify the saved builder config is preserved.
  • Confirm the post excerpt above the paywall continues to come from the existing auto-excerpt setting.
  • Disable the paywall and verify no paywall output appears on protected posts.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 23, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a visual paywall builder: config/sanitizer/renderer/preview PHP classes, admin UI views and assets, JS live-preview with an AJAX preview endpoint, styles and webpack entry, options wiring, metabox/ui adjustments, plus a small .gitignore update.

Changes

Paywall Feature

Layer / File(s) Summary
Data Shape / Constants
wordpress/wp-content/plugins/memberful-wp/src/paywall/config.php
Adds Memberful_Paywall_Config with OPTION_KEY, enums (MODES, LAYOUTS, HEADING_TAGS, BUTTON_SHAPES) and defaults() shape; get()/save() helpers.
Sanitization
wordpress/wp-content/plugins/memberful-wp/src/paywall/sanitizer.php
Adds Memberful_Paywall_Sanitizer::sanitize(array $input, array $defaults): array to normalize and validate fields (enums, text, features, URLs, hex color).
Rendering & Integration
wordpress/wp-content/plugins/memberful-wp/src/paywall/renderer.php
Adds Memberful_Paywall_Renderer with render(array $config): string, layout-specific renderers (simple, card, banner), shared blocks/icons, inline style helpers, builder-mode filters, and conditional enqueuing of styles/scripts.
Preview Endpoint
wordpress/wp-content/plugins/memberful-wp/src/paywall/preview.php
Adds Memberful_Paywall_Preview registering wp_ajax_memberful_paywall_preview, nonce & capability checks, sanitization, document(array $config): string for iframe HTML, and script_args() for JS localization.
Loader
wordpress/wp-content/plugins/memberful-wp/src/paywall.php
Adds paywall loader that requires paywall module files.
Options shape
wordpress/wp-content/plugins/memberful-wp/src/options.php
memberful_wp_all_options(): array return type; includes Memberful_Paywall_Config::OPTION_KEY => array() in defaults.
Admin wiring & save
wordpress/wp-content/plugins/memberful-wp/src/admin.php, wordpress/wp-content/plugins/memberful-wp/memberful-wp.php
Requires paywall loader on plugin init; enqueues paywall builder assets on global_marketing admin page; saves memberful_paywall via Memberful_Paywall_Config::save() and preserves legacy global content only for custom_html mode; injects paywall_config into render data.
Admin Views / Builder UI
wordpress/wp-content/plugins/memberful-wp/views/global_marketing.php, .../views/paywall/*
Replaces in-page global editor with builder UI composed of mode-radio, builder-panel, and custom-html-panel views; builder panel provides template radios, customization fields, features textarea, brand color, URL inputs, and preview iframe (srcdoc).
Metabox & UI behavior
wordpress/wp-content/plugins/memberful-wp/src/metabox.php, wordpress/wp-content/plugins/memberful-wp/views/metabox.php
Adds helper memberful_global_marketing_overrides_post_content() and exposes flag to metabox view; metabox shows informational notice when global override is active instead of editor.
Admin JS & live preview
wordpress/wp-content/plugins/memberful-wp/js/src/paywall-builder.js
Adds paywall-builder JS: collects form values, debounces text inputs, posts urlencoded config + nonce to AJAX preview action, sequences requests to avoid stale updates, and updates preview iframe srcdoc.
Banner layout script
wordpress/wp-content/plugins/memberful-wp/js/src/paywall-banner.js
Adds script to measure .memberful-paywall--banner elements for full-bleed layout, recalculating on resize and using ResizeObserver when available.
Styles & build
wordpress/wp-content/plugins/memberful-wp/stylesheets/admin.css, .../stylesheets/paywall.css, webpack.config.js
Adds admin builder CSS and paywall stylesheet (simple/card/banner, teaser fade); adds paywall-builder webpack entry.
Repository config
.gitignore
Adds .idea to ignore JetBrains IDE files.

Sequence Diagram(s)

sequenceDiagram
    participant Admin as Admin User
    participant Form as Builder Form
    participant JS as paywall-builder.js
    participant AJAX as admin-ajax.php
    participant Preview as Memberful_Paywall_Preview
    participant Renderer as Memberful_Paywall_Renderer
    participant IFrame as Preview IFrame

    Admin->>Form: edit fields / switch mode
    Form->>JS: input/change events
    JS->>JS: debounce & build config
    JS->>AJAX: POST config + nonce (memberful_paywall_preview)
    AJAX->>Preview: dispatch to handler
    Preview->>Preview: verify nonce & capability
    Preview->>Preview: sanitize config
    Preview->>Renderer: render(config)
    Renderer-->>Preview: html fragment
    Preview-->>JS: JSON {success, data.html}
    JS->>IFrame: set srcdoc to data.html
    IFrame->>IFrame: render preview
Loading

Possibly related PRs

  • TheCodeCompany/memberful-wp#8 — touches global marketing/teaser resolution and paywall/teaser CSS changes; closely related to paywall renderer and teaser integration.

Poem

✨ In admin's quiet coding room,
A builder wakes and lives in bloom,
Fields hum, sanitized, colors bright,
Preview dances in iframe light,
Global snippets find their new home.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.83% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'MR-31: Lite version of paywall' clearly references the main change: introducing a visual paywall builder as a lighter alternative to full paywall functionality.
Description check ✅ Passed The description comprehensively covers the paywall builder feature, explaining its purpose, included components, scope, behavior, and test plan—directly related to the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/MR-31-paywall

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 18

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@wordpress/wp-content/plugins/memberful-wp/js/src/paywall-builder.js`:
- Around line 29-36: The mode radio change handler ($modeInputs.on('change'))
calls refreshPreview() unconditionally causing unnecessary preview requests when
switching to custom_html; modify the handler to call refreshPreview() only when
this.value !== 'custom_html' (i.e., after applyMode(this.value) check) and
similarly guard the initial refreshPreview() call that runs when config.mode is
already 'custom_html' so it is skipped; update references in the change handler
and the initialization path where refreshPreview() is invoked to avoid firing
the iframe refresh for custom_html.

In `@wordpress/wp-content/plugins/memberful-wp/src/admin.php`:
- Around line 729-731: The code calls Memberful_Paywall_Config::get() just to
read the mode after save(), causing an unnecessary option re-read; instead use
the already-validated request input ($paywall_input) to determine mode: compute
a $config_mode from isset($paywall_input['mode']) and compare it to
'custom_html' (falling back to 'builder'), then use that $config_mode in the
conditional around update_option('memberful_global_marketing_content', ...);
update the code in the save flow where Memberful_Paywall_Config::get() is used
so the conditional checks $config_mode (derived from $paywall_input) rather than
calling Memberful_Paywall_Config::get().
- Around line 718-735: The new block starting with the if ( isset(
$_POST['save_global_marketing'] ) && memberful_wp_valid_nonce(
'memberful_options' ) ) uses tabs and breaks the file's 2-space indentation;
replace tabs with 2-space indentation throughout this entire block (including
nested blocks that call update_option, Memberful_Paywall_Config::save,
Memberful_Paywall_Config::get, and memberful_wp_kses_post) so it matches the
surrounding WordPress-style convention.

In `@wordpress/wp-content/plugins/memberful-wp/src/global_marketing.php`:
- Around line 19-32: The function memberful_get_global_replacement currently
calls memberful_wp_resolve_global_marketing_content() unconditionally; change it
to call that resolver lazily only when needed (i.e., inside the if ($override)
branch and inside the empty( trim( $marketing_content ) ) branch) so
Memberful_Paywall_Renderer::render() / Memberful_Paywall_Config::get() (and any
get_option() calls) are only executed when the resolved global content will
actually be returned; keep the existing return behavior but remove the eager
assignment to $global_marketing_content at the top of
memberful_get_global_replacement.

In `@wordpress/wp-content/plugins/memberful-wp/src/options.php`:
- Around line 4-34: Restore 2-space indentation for the
memberful_wp_all_options() function in options.php (it was accidentally
re-indented with tabs); update the return array block and closing brace to use
the project’s 2-space indentation style so it matches the rest of src/, making
sure all lines including the Memberful_Paywall_Config::OPTION_KEY entry and the
function signature/closing brace use two spaces per indent level.

In `@wordpress/wp-content/plugins/memberful-wp/src/paywall/config.php`:
- Around line 28-32: The default paywall strings are being double-escaped:
replace esc_html__() with __() for the default values in the paywall config
array so the renderer (heading_block(), subheading_block(), primary_cta()) can
perform escaping once; update the entries 'heading', 'subheading', and
'button_label' to use __() instead of esc_html__() so translations remain raw
and are escaped only when rendered.
- Around line 49-62: Memberful is using the 'memberful' textdomain in
Memberful_Paywall_Config::defaults() but never loads it, and
Memberful_Paywall_Renderer::register() is called at file-load time (registering
the memberful_global_teaser_class filter) which can run before init; fix by
loading the plugin textdomain on the plugins_loaded hook (call
load_plugin_textdomain('memberful', false,
dirname(plugin_basename(MEMBERFUL_PLUGIN_FILE)) . '/languages') inside an
add_action('plugins_loaded', ...)) placed in the main plugin file after
includes, or alternatively defer Memberful_Paywall_Renderer::register() by
moving its invocation into a plugins_loaded callback so the textdomain is
guaranteed to be loaded before the filter runs.

In `@wordpress/wp-content/plugins/memberful-wp/src/paywall/preview.php`:
- Around line 58-62: The preview teaser HTML currently injects a hardcoded
English paragraph into $teaser; make it translatable and safely escaped by
replacing the literal string with a localized, escaped string (use esc_html__
with the plugin textdomain, e.g. 'memberful') as the sprintf argument and keep
esc_attr( $teaser_class ) for the class; update the sprintf call that builds
$teaser to pass esc_html__(...) for the paragraph content so the text becomes
localizable and safely escaped.
- Around line 50-56: Append the plugin version to the preview stylesheet URLs to
bust caches: replace the raw plugins_url/get_stylesheet_uri usage by building
$paywall_css and $theme_css with add_query_arg('ver', MEMBERFUL_VERSION, ...)
(i.e. use add_query_arg with MEMBERFUL_VERSION on the plugins_url result for
paywall and on get_stylesheet_uri for the theme) and leave the rest of the logic
that outputs $links untouched so esc_url($paywall_css) and esc_url($theme_css)
receive versioned URLs.
- Around line 25-38: document() should guard against a missing or non-string
$config['layout'] to avoid PHP notices and malformed CSS classes; update
document() (which calls Memberful_Paywall_Renderer::render) to derive $layout
with a fallback to 'card' (the default in Memberful_Paywall_Config::defaults()),
e.g. check isset($config['layout']) && is_string($config['layout']) then use
that value, otherwise set 'card', and use $layout when building the
$teaser_class and related output.

In `@wordpress/wp-content/plugins/memberful-wp/src/paywall/renderer.php`:
- Around line 272-280: The wrapper_style() function currently concatenates
$config['brand_color'] directly into CSS; to prevent CSS injection,
validate/normalize that value before including it: call WordPress's
sanitize_hex_color() (or a strict regex that allows only `#RRGGBB/`#RGB) on
$config['brand_color'] and only append "--mf-brand:{$safe_color}" when the
result is a non-empty valid color, otherwise skip or use a safe fallback; keep
existing use of self::button_radius($config['button_shape']) unchanged and
ensure wrapper_style() returns only validated CSS tokens.
- Around line 1-346: The file uses tab indentation throughout; convert all tabs
to 2-space indentation to comply with WordPress-style PHP formatting (apply
across the whole class Memberful_Paywall_Renderer and the trailing call
Memberful_Paywall_Renderer::register()). Preserve existing identifiers and
method names (e.g. register, protect_content, maybe_print_styles, render,
render_card, heading_block, wrapper_style, button_radius, subscribe_url,
sign_in_url, is_builder_mode) and only change whitespace/indentation so the code
semantics remain identical and formatting matches the project's 2-space
convention.
- Around line 120-165: render_simple and render_banner contain identical markup;
extract their shared inner markup into a single helper (e.g., render_inner or
render_default_inner) that returns the concatenation of heading_block,
subheading_block, features_block, primary_cta wrapper and sign_in_prompt
(referencing heading_block, subheading_block, features_block, primary_cta,
sign_in_prompt). Make render_simple and render_banner call that new helper and
return its output, while keeping render_card unchanged except that it should
call the same helper for the inner content and continue to wrap it with the card
chrome and lock_badge (ensure render_card still calls lock_badge before invoking
the shared inner helper).

In `@wordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.css`:
- Around line 217-229: The fade overlay currently hardcodes white in
.memberful-global-teaser-content[class*="--mf-"]::after using background:
linear-gradient(transparent, `#fff`); — change it to reference the theme variable
used elsewhere so the fade blends with dark themes: use the same CSS variable
(e.g. var(--mf-surface, `#fff`)) as the gradient end color (for example
linear-gradient(transparent, var(--mf-surface, `#fff`))) on
.memberful-global-teaser-content[class*="--mf-"]::after to preserve the existing
white fallback while respecting dark surfaces.
- Around line 181-190: The banner uses width:100vw which includes the scrollbar
width and can cause horizontal overflow; in .memberful-paywall--banner add
overflow-x: hidden (or apply to a parent container) to prevent right-edge
overflow; also the teaser fade in
.memberful-global-teaser-content[class*="--mf-"]::after uses a hardcoded
`#fff`—replace that with a theme-aware value such as var(--mf-surface) or a
neutral semi-transparent color (e.g., rgba(0,0,0,0.15)) so the gradient blends
correctly on dark themes.

In `@wordpress/wp-content/plugins/memberful-wp/views/paywall/builder-panel.php`:
- Around line 122-127: Add a sandbox attribute to the preview iframe to enforce
defense-in-depth: update the <iframe id="mf-paywall-preview"
class="memberful-paywall-builder__preview-frame"> markup to include
sandbox="allow-same-origin" (or sandbox="") so the HTML produced by
Memberful_Paywall_Preview::document( $paywall_config ) and passed through
esc_attr() in the srcdoc cannot run scripts in the admin UI; keep the existing
esc_attr() call and srcdoc usage unchanged.
- Around line 1-130: The file uses tab indentation contrary to the project's
WordPress-style 2-space indentation guideline; normalize indentation in this
file (builder-panel.php) to 2 spaces (and do the same in the sibling view files
mode-radio.php and custom-html-panel.php) while keeping all existing escaping
and markup intact (e.g., inputs like memberful-paywall-heading, features
textarea using $features_textarea, and the iframe srcdoc using
Memberful_Paywall_Preview::document( $paywall_config )); run the project's
PHP/JS linters/formatters to ensure consistent spacing and no other code
changes.

In `@wordpress/wp-content/plugins/memberful-wp/views/paywall/mode-radio.php`:
- Around line 13-22: The wrapper div currently uses role="tablist" while
containing radio inputs (name="memberful_paywall[mode]") and labelled by
memberful-paywall-builder__mode-tab labels, which mixes ARIA tab semantics with
a radio group; remove the role="tablist" from the div with class
memberful-paywall-builder__mode-tabs (or replace it with role="radiogroup" if
you want explicit ARIA for a radio group) so the markup consistently represents
radios (inputs named memberful_paywall[mode]) and avoid implying tab/tabpanel
behaviour.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: TheCodeCompany/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e7694b3e-b7a3-4003-854e-664025367246

📥 Commits

Reviewing files that changed from the base of the PR and between 03bcf69 and e978111.

📒 Files selected for processing (18)
  • .gitignore
  • wordpress/wp-content/plugins/memberful-wp/js/src/paywall-builder.js
  • wordpress/wp-content/plugins/memberful-wp/memberful-wp.php
  • wordpress/wp-content/plugins/memberful-wp/src/admin.php
  • wordpress/wp-content/plugins/memberful-wp/src/global_marketing.php
  • wordpress/wp-content/plugins/memberful-wp/src/options.php
  • wordpress/wp-content/plugins/memberful-wp/src/paywall.php
  • wordpress/wp-content/plugins/memberful-wp/src/paywall/config.php
  • wordpress/wp-content/plugins/memberful-wp/src/paywall/preview.php
  • wordpress/wp-content/plugins/memberful-wp/src/paywall/renderer.php
  • wordpress/wp-content/plugins/memberful-wp/src/paywall/sanitizer.php
  • wordpress/wp-content/plugins/memberful-wp/stylesheets/admin.css
  • wordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.css
  • wordpress/wp-content/plugins/memberful-wp/views/global_marketing.php
  • wordpress/wp-content/plugins/memberful-wp/views/paywall/builder-panel.php
  • wordpress/wp-content/plugins/memberful-wp/views/paywall/custom-html-panel.php
  • wordpress/wp-content/plugins/memberful-wp/views/paywall/mode-radio.php
  • wordpress/wp-content/plugins/memberful-wp/webpack.config.js

Comment thread wordpress/wp-content/plugins/memberful-wp/js/src/paywall-builder.js
Comment thread wordpress/wp-content/plugins/memberful-wp/src/admin.php Outdated
Comment thread wordpress/wp-content/plugins/memberful-wp/src/admin.php Outdated
Comment thread wordpress/wp-content/plugins/memberful-wp/src/global_marketing.php
Comment thread wordpress/wp-content/plugins/memberful-wp/src/options.php
Comment thread wordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.css
Comment thread wordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.css Outdated
Comment thread wordpress/wp-content/plugins/memberful-wp/views/paywall/builder-panel.php Outdated
Comment thread wordpress/wp-content/plugins/memberful-wp/views/paywall/builder-panel.php Outdated
Comment thread wordpress/wp-content/plugins/memberful-wp/views/paywall/mode-radio.php Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@wordpress/wp-content/plugins/memberful-wp/src/global_marketing.php`:
- Around line 19-46: The functions memberful_get_global_replacement and
memberful_wp_resolve_global_marketing_content use tab indentation that drifts
from the repository's 2-space WordPress-style convention; replace all tabs with
2-space indentation inside these functions (and any newly added lines) so
spacing matches the rest of global_marketing.php and the src/ tree, keeping
existing snake_case function names and Memberful_* class references unchanged.

In `@wordpress/wp-content/plugins/memberful-wp/views/paywall/builder-panel.php`:
- Around line 18-53: The inner span blocks in the paywall template cards use tab
indentation while the rest of the file uses 2-space indentation, causing mixed
formatting; update the indentation for the elements inside each label (look for
the input radio with name "memberful_paywall[layout]" and the surrounding
elements: memberful-paywall-builder__template-card-inner,
memberful-paywall-builder__template-thumb,
memberful-paywall-builder__template-meta, and their child spans) to use 2 spaces
per level (match the provided suggestion style) and apply the same change to all
three card blocks so the file consistently follows WordPress 2-space indentation
conventions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: TheCodeCompany/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7644632f-f124-41cb-8aec-631bbc378f31

📥 Commits

Reviewing files that changed from the base of the PR and between e978111 and 03978ab.

📒 Files selected for processing (6)
  • wordpress/wp-content/plugins/memberful-wp/js/src/paywall-builder.js
  • wordpress/wp-content/plugins/memberful-wp/src/admin.php
  • wordpress/wp-content/plugins/memberful-wp/src/global_marketing.php
  • wordpress/wp-content/plugins/memberful-wp/src/options.php
  • wordpress/wp-content/plugins/memberful-wp/views/paywall/builder-panel.php
  • wordpress/wp-content/plugins/memberful-wp/views/paywall/mode-radio.php

Comment thread wordpress/wp-content/plugins/memberful-wp/src/global_marketing.php
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
wordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.css (1)

181-190: ⚠️ Potential issue | 🟡 Minor

Prevent banner-induced horizontal scroll on 100vw layouts.

width: 100vw can include scrollbar width and produce right-edge overflow on common desktop/browser combos. This was raised earlier and still applies here.

Minimal fix
 .memberful-paywall--banner {
 	--mf-muted: `#a0a5aa`;
 	--mf-muted-soft: `#72777c`;
 	--mf-surface: `#1d2327`;
 	--mf-text: `#fff`;

 	background: var(--mf-surface);
 	margin-inline: calc(50% - 50vw);
+	overflow-x: clip;
 	width: 100vw;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.css` around
lines 181 - 190, The banner uses width: 100vw which can include the scrollbar
and cause horizontal overflow; in .memberful-paywall--banner replace width:
100vw with width: 100% and add max-width: 100vw (keep the existing margin-inline
calc(...) breakout) so the element spans the viewport without including the
scrollbar and avoids right-edge overflow.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@wordpress/wp-content/plugins/memberful-wp/src/admin.php`:
- Around line 729-732: The code assumes $paywall_input is an array when
computing $config_mode and can raise a warning if it's null/false; update the
logic that sets $config_mode (the variable derived from $paywall_input['mode'])
to first check that $paywall_input is an array (e.g. is_array($paywall_input) &&
isset($paywall_input['mode'])) and default to 'builder' otherwise, then leave
the subsequent branch that calls
update_option('memberful_global_marketing_content',
memberful_wp_kses_post(filter_input(INPUT_POST,
'memberful_global_marketing_content'))) unchanged.

In `@wordpress/wp-content/plugins/memberful-wp/src/metabox.php`:
- Around line 58-61: Extract the duplicated expression into a small helper
function (e.g. memberful_wp_global_marketing_overrides_post_content) that calls
Memberful_Paywall_Config::get() and returns a boolean computed from
get_option('memberful_global_marketing_override') || 'builder' ===
$paywall_config['mode']; then replace the inline expression in both
memberful_wp_metabox and memberful_wp_add_term_metabox with a call to
memberful_wp_global_marketing_overrides_post_content() so both places use the
single source of truth.

In `@wordpress/wp-content/plugins/memberful-wp/views/metabox.php`:
- Line 27: In the call to wp_editor adjust the argument spacing so there's no
stray space before the second argument; replace the current wp_editor(
$marketing_content , $editor_id, $settings ); occurrence by using consistent
spacing between arguments for the wp_editor call (ensure variables
$marketing_content, $editor_id and $settings remain in the same order).

---

Duplicate comments:
In `@wordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.css`:
- Around line 181-190: The banner uses width: 100vw which can include the
scrollbar and cause horizontal overflow; in .memberful-paywall--banner replace
width: 100vw with width: 100% and add max-width: 100vw (keep the existing
margin-inline calc(...) breakout) so the element spans the viewport without
including the scrollbar and avoids right-edge overflow.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: TheCodeCompany/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ba2cec4d-09a4-4cde-9333-0ebfa8ac9597

📥 Commits

Reviewing files that changed from the base of the PR and between 03978ab and 70af3b5.

📒 Files selected for processing (6)
  • wordpress/wp-content/plugins/memberful-wp/src/admin.php
  • wordpress/wp-content/plugins/memberful-wp/src/global_marketing.php
  • wordpress/wp-content/plugins/memberful-wp/src/metabox.php
  • wordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.css
  • wordpress/wp-content/plugins/memberful-wp/views/metabox.php
  • wordpress/wp-content/plugins/memberful-wp/views/paywall/builder-panel.php

Comment thread wordpress/wp-content/plugins/memberful-wp/src/admin.php Outdated
Comment thread wordpress/wp-content/plugins/memberful-wp/src/metabox.php Outdated
Comment thread wordpress/wp-content/plugins/memberful-wp/views/metabox.php Outdated
Copy link
Copy Markdown
Member

@zhickson zhickson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few nitpicky things, some questions around making more use of wp-preset values in stylesheets, reviewing coderabbit feedback, and adding a few more developer-friendly filters in the rendering of the paywall.

As mentioned, you nailed this on the first pass 💪

Comment thread wordpress/wp-content/plugins/memberful-wp/src/paywall/renderer.php Outdated
Comment thread wordpress/wp-content/plugins/memberful-wp/src/options.php Outdated
Comment thread wordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.css Outdated
Comment thread wordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.css Outdated
Comment thread wordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.css
Comment thread wordpress/wp-content/plugins/memberful-wp/src/paywall/config.php Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@wordpress/wp-content/plugins/memberful-wp/views/metabox.php`:
- Around line 31-33: Replace unescaped output calls using _e() with esc_html_e()
for the plain-text strings rendered in the metabox: locate the two occurrences
of _e( 'Click Here', 'memberful' ) and _e( 'to manage global marketing
content.', 'memberful' ) in the metabox template and change them to use
esc_html_e() so the text is properly escaped before output (i.e., replace _e
with esc_html_e for those string calls).
- Around line 30-33: Replace the non-descriptive "Click Here" link and the
separate `_e( 'to manage global marketing content.', 'memberful' )` text with a
single, descriptive linked phrase; locate the anchor that calls the
memberful_wp_plugin_global_marketing_url() function and change its inner text to
a full, accessible string like "Manage global marketing content" using an
escaping helper (e.g., esc_html_e or esc_html__ + echo), and remove the
subsequent `_e(...)` line so the entire intent is inside the <a> element.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: TheCodeCompany/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6e904583-6789-4565-8f9f-d4df3a20ab22

📥 Commits

Reviewing files that changed from the base of the PR and between 70af3b5 and 3b40da0.

📒 Files selected for processing (8)
  • wordpress/wp-content/plugins/memberful-wp/js/src/paywall-builder.js
  • wordpress/wp-content/plugins/memberful-wp/src/options.php
  • wordpress/wp-content/plugins/memberful-wp/src/paywall/config.php
  • wordpress/wp-content/plugins/memberful-wp/src/paywall/preview.php
  • wordpress/wp-content/plugins/memberful-wp/src/paywall/renderer.php
  • wordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.css
  • wordpress/wp-content/plugins/memberful-wp/views/metabox.php
  • wordpress/wp-content/plugins/memberful-wp/views/paywall/builder-panel.php

Comment thread wordpress/wp-content/plugins/memberful-wp/views/metabox.php Outdated
Comment thread wordpress/wp-content/plugins/memberful-wp/views/metabox.php Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@wordpress/wp-content/plugins/memberful-wp/src/admin.php`:
- Around line 729-732: Whitelist the posted mode before branching: ensure
$config_mode is derived from $paywall_input only if it's an array, has a 'mode'
key, and that value is one of the allowed values (e.g., 'builder' or
'custom_html') using in_array(..., true); otherwise default to 'builder'. Then
keep the existing branch on $config_mode === 'custom_html' but sanitize the
POSTed marketing content by casting filter_input(INPUT_POST,
'memberful_global_marketing_content') to string and passing it through
memberful_wp_kses_post before calling
update_option('memberful_global_marketing_content', ...).

In `@wordpress/wp-content/plugins/memberful-wp/src/paywall/renderer.php`:
- Around line 105-111: The wp_enqueue_script call registering
'memberful-paywall-banner' currently points to MEMBERFUL_URL .
'/js/src/paywall-banner.js' (serving raw source); update the URL to reference
the Webpack build output at MEMBERFUL_URL . '/js/build/paywall-banner.js' so the
wp_enqueue_script invocation in renderer.php uses the production bundle (keep
the same handle 'memberful-paywall-banner', version MEMBERFUL_VERSION and
in_footer flag).

In `@wordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.css`:
- Around line 48-54: h2.memberful-paywall__heading and
h3.memberful-paywall__heading both use the same CSS custom property
(--wp--preset--font-size--medium) causing no visual hierarchy when that preset
exists; update h3.memberful-paywall__heading to use a smaller WP preset token
(e.g. --wp--preset--font-size--small) instead of --wp--preset--font-size--medium
while keeping the fallback 1rem so theme-defined presets produce a clear
typographic difference.

In `@wordpress/wp-content/plugins/memberful-wp/views/global_marketing.php`:
- Around line 58-61: Validate the stored paywall mode before using it: replace
the current assignment to paywall_mode with logic that checks
isset($paywall_config['mode']) and that its value is one of the allowed options
('builder' or 'custom_html') (use in_array with strict true), defaulting to
'builder' otherwise, then pass that validated $paywall_mode into the existing
memberful_wp_render calls for 'paywall/builder-panel' and
'paywall/custom-html-panel' so is_active is determined only from a permitted
value.

In
`@wordpress/wp-content/plugins/memberful-wp/views/paywall/custom-html-panel.php`:
- Around line 12-14: Indentation and inline PHP formatting in the custom HTML
panel block is not following the repository's 2-space WordPress-style
convention; update the div block that uses data-panel="custom_html" so the
conditional PHP echo for $is_active uses braces and the inner wp_editor call is
indented with 2 spaces, and ensure the wp_editor( $global_marketing_content,
'memberful_global_marketing_content' ) line is aligned under the div content for
readability.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: TheCodeCompany/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6903a477-dfb9-47a5-8b2b-3cfdaa4ec8a5

📥 Commits

Reviewing files that changed from the base of the PR and between 3b40da0 and 4c5ec31.

📒 Files selected for processing (9)
  • wordpress/wp-content/plugins/memberful-wp/js/src/paywall-banner.js
  • wordpress/wp-content/plugins/memberful-wp/src/admin.php
  • wordpress/wp-content/plugins/memberful-wp/src/metabox.php
  • wordpress/wp-content/plugins/memberful-wp/src/paywall/renderer.php
  • wordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.css
  • wordpress/wp-content/plugins/memberful-wp/views/global_marketing.php
  • wordpress/wp-content/plugins/memberful-wp/views/metabox.php
  • wordpress/wp-content/plugins/memberful-wp/views/paywall/builder-panel.php
  • wordpress/wp-content/plugins/memberful-wp/views/paywall/custom-html-panel.php

Comment thread wordpress/wp-content/plugins/memberful-wp/src/admin.php Outdated
Comment thread wordpress/wp-content/plugins/memberful-wp/src/paywall/renderer.php
Comment thread wordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.css
Comment thread wordpress/wp-content/plugins/memberful-wp/views/global_marketing.php Outdated
Comment thread wordpress/wp-content/plugins/memberful-wp/views/paywall/custom-html-panel.php Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants