MR-31: Lite version of paywall#9
Conversation
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds 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. ChangesPaywall Feature
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
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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. Comment |
There was a problem hiding this comment.
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
📒 Files selected for processing (18)
.gitignorewordpress/wp-content/plugins/memberful-wp/js/src/paywall-builder.jswordpress/wp-content/plugins/memberful-wp/memberful-wp.phpwordpress/wp-content/plugins/memberful-wp/src/admin.phpwordpress/wp-content/plugins/memberful-wp/src/global_marketing.phpwordpress/wp-content/plugins/memberful-wp/src/options.phpwordpress/wp-content/plugins/memberful-wp/src/paywall.phpwordpress/wp-content/plugins/memberful-wp/src/paywall/config.phpwordpress/wp-content/plugins/memberful-wp/src/paywall/preview.phpwordpress/wp-content/plugins/memberful-wp/src/paywall/renderer.phpwordpress/wp-content/plugins/memberful-wp/src/paywall/sanitizer.phpwordpress/wp-content/plugins/memberful-wp/stylesheets/admin.csswordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.csswordpress/wp-content/plugins/memberful-wp/views/global_marketing.phpwordpress/wp-content/plugins/memberful-wp/views/paywall/builder-panel.phpwordpress/wp-content/plugins/memberful-wp/views/paywall/custom-html-panel.phpwordpress/wp-content/plugins/memberful-wp/views/paywall/mode-radio.phpwordpress/wp-content/plugins/memberful-wp/webpack.config.js
There was a problem hiding this comment.
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
📒 Files selected for processing (6)
wordpress/wp-content/plugins/memberful-wp/js/src/paywall-builder.jswordpress/wp-content/plugins/memberful-wp/src/admin.phpwordpress/wp-content/plugins/memberful-wp/src/global_marketing.phpwordpress/wp-content/plugins/memberful-wp/src/options.phpwordpress/wp-content/plugins/memberful-wp/views/paywall/builder-panel.phpwordpress/wp-content/plugins/memberful-wp/views/paywall/mode-radio.php
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
wordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.css (1)
181-190:⚠️ Potential issue | 🟡 MinorPrevent banner-induced horizontal scroll on
100vwlayouts.
width: 100vwcan 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
📒 Files selected for processing (6)
wordpress/wp-content/plugins/memberful-wp/src/admin.phpwordpress/wp-content/plugins/memberful-wp/src/global_marketing.phpwordpress/wp-content/plugins/memberful-wp/src/metabox.phpwordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.csswordpress/wp-content/plugins/memberful-wp/views/metabox.phpwordpress/wp-content/plugins/memberful-wp/views/paywall/builder-panel.php
zhickson
left a comment
There was a problem hiding this comment.
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 💪
There was a problem hiding this comment.
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
📒 Files selected for processing (8)
wordpress/wp-content/plugins/memberful-wp/js/src/paywall-builder.jswordpress/wp-content/plugins/memberful-wp/src/options.phpwordpress/wp-content/plugins/memberful-wp/src/paywall/config.phpwordpress/wp-content/plugins/memberful-wp/src/paywall/preview.phpwordpress/wp-content/plugins/memberful-wp/src/paywall/renderer.phpwordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.csswordpress/wp-content/plugins/memberful-wp/views/metabox.phpwordpress/wp-content/plugins/memberful-wp/views/paywall/builder-panel.php
There was a problem hiding this comment.
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
📒 Files selected for processing (9)
wordpress/wp-content/plugins/memberful-wp/js/src/paywall-banner.jswordpress/wp-content/plugins/memberful-wp/src/admin.phpwordpress/wp-content/plugins/memberful-wp/src/metabox.phpwordpress/wp-content/plugins/memberful-wp/src/paywall/renderer.phpwordpress/wp-content/plugins/memberful-wp/stylesheets/paywall.csswordpress/wp-content/plugins/memberful-wp/views/global_marketing.phpwordpress/wp-content/plugins/memberful-wp/views/metabox.phpwordpress/wp-content/plugins/memberful-wp/views/paywall/builder-panel.phpwordpress/wp-content/plugins/memberful-wp/views/paywall/custom-html-panel.php
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
Scope and behaviour
Test plan