Feature/subscription gutenberg block#1838
Feature/subscription gutenberg block#1838sapayth wants to merge 10 commits intoweDevsOfficial:developfrom
Conversation
- Add comprehensive MultiSelect component styling (trigger, dropdown, options, pills) - Include search, hover states, and remove button interactions - Update description comment to reflect new styling content - Build output includes CSS maps and RTL variants
Introduce a new Subscription Packs Gutenberg block and wire up its frontend/admin assets. Added block.json in assets and src, subscription-packs JS (with asset manifest and source map), RTL stylesheet, and updated Tailwind config. Updated PHP to support block and admin subscription handling (includes/Blocks/SubscriptionPacks.php, includes/Admin/Subscription.php) and refreshed templates for subscription listing and pack details. Also updated multiple CSS files, localization POT, and .gitignore to ignore .superpowers paths.
WalkthroughAdds a new Gutenberg block "wpuf/subscription-packs" with editor UI, React components, build and webpack integration, asset registration, server-side render support, template plumbing for block-driven config, and styling (editor/RTL/ frontend CSS) plus small package/build config updates. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (2 warnings, 1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
templates/subscriptions/listing.php (1)
53-64:⚠️ Potential issue | 🟡 MinorFix PHPCS violations flagged by static analysis.
Multiple issues detected:
count()inside loop condition is inefficient (recalculated each iteration)- Loose comparisons (
!=,==) should be strict (!==,===)- Extra space after opening parenthesis on line 56
- Array key spacing issues
🔧 Proposed fix
- if ( isset( $args['include'] ) && $args['include'] != '' ) { - for ( $i = 0; $i < count( $pack_order ); $i++ ) { + if ( isset( $args['include'] ) && $args['include'] !== '' ) { + $pack_order_count = count( $pack_order ); + for ( $i = 0; $i < $pack_order_count; $i++ ) { foreach ( $packs as $pack ) { - if ( (int) $pack->ID == $pack_order[$i] ) { - $class = 'wpuf-pack-' . $pack->ID; ?> + if ( (int) $pack->ID === $pack_order[ $i ] ) { + $class = 'wpuf-pack-' . $pack->ID; + ?> <li class="<?php echo esc_attr( $class ); ?>">🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@templates/subscriptions/listing.php` around lines 53 - 64, The loop has several PHPCS issues: cache count( $pack_order ) into a variable before the for loop (e.g., $pack_order_count) to avoid repeated calls; replace loose comparisons with strict ones (use !== and === for checks like isset( $args['include'] ) && $args['include'] !== '' and (int) $pack->ID === $pack_order[ $i ]); remove the extra space after opening parenthesis in conditions (e.g., change if ( (int) to if ((int)); and normalize array key spacing to the project standard (e.g., $args['include'], $pack_order[ $i ] or $pack_order[$i] consistently) while preserving the call to $subscription->pack_details( $pack, $details_meta, isset( $current_pack['pack_id'] ) ? $current_pack['pack_id'] : '', false, $block_config ).
🧹 Nitpick comments (4)
tailwind.config.js (1)
25-29: Duplicate content path entry.
'./templates/**/*.php'appears twice in the content array (lines 25 and 28). Remove one to avoid redundancy.🔧 Proposed fix
'./admin/form-builder/assets/js/**/*.php', './templates/**/*.php', 'wpuf-functions.php', - // New paths from upstream (for subscription templates) - './templates/**/*.php', './src/**/*.{js,css}', // Free User Directory module templates🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tailwind.config.js` around lines 25 - 29, The content array in tailwind.config.js contains a duplicate path './templates/**/*.php'; remove the redundant './templates/**/*.php' entry so each glob appears only once (update the content array to keep a single './templates/**/*.php' along with 'wpuf-functions.php' and './src/**/*.{js,css}').src/js/blocks/subscription-packs/edit.js (1)
291-299: Consider extractingLoadingResponsePlaceholderto avoid Rules of Hooks violation.The inline function with
useEffecttechnically violates React's Rules of Hooks (hooks should not be called in callbacks). While theeslint-disablecomment acknowledges this and the pattern works, extracting it to a named component improves maintainability.♻️ Proposed refactor
+// Add before the Edit function +const LoadingPlaceholder = ( { setIsUpdating } ) => { + useEffect( () => { + return () => { + setIsUpdating( false ); + }; + }, [] ); + return null; +}; + export default function Edit( { attributes, setAttributes } ) { // ... existing code ... <ServerSideRender block="wpuf/subscription-packs" attributes={ attributes } - LoadingResponsePlaceholder={ () => { - // eslint-disable-next-line react-hooks/rules-of-hooks - useEffect( () => { - return () => { - setIsUpdating( false ); - }; - }, [] ); - return null; - } } + LoadingResponsePlaceholder={ () => <LoadingPlaceholder setIsUpdating={ setIsUpdating } /> } />🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/js/blocks/subscription-packs/edit.js` around lines 291 - 299, Extract the inline hook into a named React component to avoid calling hooks inside a callback: create a component like LoadingResponsePlaceholder that accepts setIsUpdating (e.g., function LoadingResponsePlaceholder({ setIsUpdating }) { useEffect(() => () => setIsUpdating(false), []); return null; }) and then replace the inline prop with LoadingResponsePlaceholder={() => <LoadingResponsePlaceholder setIsUpdating={setIsUpdating} />}; this keeps the same unmount behavior but ensures hooks are used in a component, not a callback.src/js/blocks/subscription-packs/components/MultiSelect.js (1)
88-133: Consider adding arrow key navigation for improved keyboard accessibility.The dropdown supports Tab, Enter, Space, and Escape, but lacks Up/Down arrow key navigation between options. This would enhance the experience for keyboard users.
🎹 Optional enhancement for arrow key navigation
// Add to the search input onKeyDown handler: else if ( e.key === 'ArrowDown' && availableOptions.length > 0 ) { e.preventDefault(); // Focus first option or move focus down const firstOption = dropdownRef.current?.querySelector( '.wpuf-block-multiselect__option' ); firstOption?.focus(); } // Add to option onKeyDown handler: else if ( e.key === 'ArrowDown' ) { e.preventDefault(); e.target.nextElementSibling?.focus(); } else if ( e.key === 'ArrowUp' ) { e.preventDefault(); e.target.previousElementSibling?.focus() || searchInputRef.current?.focus(); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/js/blocks/subscription-packs/components/MultiSelect.js` around lines 88 - 133, The dropdown lacks Up/Down arrow key navigation for keyboard users; update the onKeyDown handler on the search input (searchInputRef) to handle 'ArrowDown' by preventing default and moving focus to the first option (querySelector('.wpuf-block-multiselect__option') from a dropdownRef), and update each option's onKeyDown (options rendered from availableOptions and using className 'wpuf-block-multiselect__option') to handle 'ArrowDown' and 'ArrowUp' by preventing default and moving focus to the nextElementSibling or previousElementSibling respectively (when previous goes past the first option, move focus back to searchInputRef), preserving existing Enter/Space/Escape behaviors and avoiding code duplication by reusing handleSelect for activation.includes/Blocks/SubscriptionPacks.php (1)
164-170: Pass arrays directly toget_subscriptions()instead of converting to strings.While WordPress's
get_posts()internally handles string-to-array conversion forinclude/excludeparameters, passing strings here creates an inefficient roundtrip: arrays are converted to comma-separated strings viaimplode(), then WordPress converts them back to arrays, and later code converts them again withexplode(). Pass the arrays directly toget_subscriptions()without theimplode()conversion for consistency and efficiency.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@includes/Blocks/SubscriptionPacks.php` around lines 164 - 170, The code in SubscriptionPacks.php is converting $attributes['include'] and $attributes['exclude'] to comma strings before calling get_subscriptions(), causing unnecessary conversions; instead assign the integer-casted arrays directly to $subscription_args (e.g., $subscription_args['include'] = array_map('intval', $attributes['include']) and similarly for 'exclude'), ensuring you only set them when non-empty and that they remain arrays so get_subscriptions() receives arrays rather than imploded strings.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.gitignore:
- Around line 9-10: The .gitignore additions ".superpowers" and
"docs/superpowers" are unrelated to this PR; either remove those two entries
from .gitignore (delete the ".superpowers" and "docs/superpowers" lines) or move
them into a separate housekeeping PR — if you keep them here, add a one-line
justification in this PR description explaining what generates those paths and
why they must be ignored (e.g., the tool/process that creates .superpowers and
docs/superpowers) and reference those exact entries so reviewers can verify the
rationale.
In `@assets/js/js/blocks/subscription-packs/block.json`:
- Around line 1-108: There’s an unused duplicate block.json (the
subscription-packs block JSON checked into the assets tree) that isn’t
referenced by the block registration in the SubscriptionPacks registration code;
remove the orphaned block.json from the assets copy (or, if it’s required by
your build, update the build/registration paths or add a comment explaining its
purpose) so only the canonical block.json used by the SubscriptionPacks
registration remains tracked.
In `@includes/Blocks/SubscriptionPacks.php`:
- Around line 90-92: The multi-line call to register_block_type violates WPCS
formatting; reformat the call so each array key/value is on its own indented
line and the opening and closing parentheses/brackets follow WPCS style. Locate
the register_block_type( $block_json_path, [ 'render_callback' => [ $this,
'render' ], ] ); invocation in the SubscriptionPacks class and rewrite it so the
function arguments and the associative array are split across lines (with the
$block_json_path on the first line, the 'render_callback' => [ $this, 'render'
], on its own indented line, and the closing ] ); on its own line) to comply
with WPCS multi-line function call rules.
- Around line 116-124: The returned array's 'orderByOptions' entries violate
WPCS array formatting—update the array so each associative element's key and
value are on separate lines (one per line) for every item in the
'orderByOptions' array inside the return statement of the SubscriptionPacks
block; specifically reformat the arrays like the elements that currently read [
'value' => 'title', 'label' => __( 'Title', 'wp-user-frontend' ) ] so each
key-value pair is on its own line, preserving the same keys ('value', 'label')
and values, and keep the surrounding indentation and trailing commas consistent
with WPCS.
- Around line 43-48: The multi-line array_merge() call is not formatted per
WPCS; update the call so the opening parenthesis remains on the function name
line, put each argument on its own indented line, ensure the array argument uses
short/associative array formatting and include a trailing comma on the last
array element, then close the parenthesis and semicolon on their own line;
locate the array_merge invocation (array_merge(...)) that returns the categories
and reformat it accordingly so the function name, arguments, and closing
parenthesis follow WordPress coding standards.
In `@src/js/blocks/subscription-packs/block.json`:
- Around line 21-24: The columns attribute in block.json lacks min/max
validation so values >4 produce Tailwind classes that get purged; add JSON
Schema constraints to the "columns" property (e.g., set type to integer/number,
"minimum": 1 and "maximum": 4 and keep "default": 3) in
src/js/blocks/subscription-packs/block.json, and as a server-side fallback clamp
the value when used in SubscriptionPacks (e.g., where the code reads the columns
value in the SubscriptionPacks class/method that renders templates) to ensure
the final value is within 1–4 before generating lg:wpuf-grid-cols-{N}.
In `@templates/subscriptions/pack-details.php`:
- Line 128: The if-condition uses a loose comparison; change the check in the
template where the conditional reads if ( $billing_amount != '0.00' ) to a
strict comparison using !== so it becomes if ( $billing_amount !== '0.00' ),
ensuring type-safe comparison of the $billing_amount string against the '0.00'
literal in the pack-details.php template.
---
Outside diff comments:
In `@templates/subscriptions/listing.php`:
- Around line 53-64: The loop has several PHPCS issues: cache count( $pack_order
) into a variable before the for loop (e.g., $pack_order_count) to avoid
repeated calls; replace loose comparisons with strict ones (use !== and === for
checks like isset( $args['include'] ) && $args['include'] !== '' and (int)
$pack->ID === $pack_order[ $i ]); remove the extra space after opening
parenthesis in conditions (e.g., change if ( (int) to if ((int)); and normalize
array key spacing to the project standard (e.g., $args['include'], $pack_order[
$i ] or $pack_order[$i] consistently) while preserving the call to
$subscription->pack_details( $pack, $details_meta, isset(
$current_pack['pack_id'] ) ? $current_pack['pack_id'] : '', false, $block_config
).
---
Nitpick comments:
In `@includes/Blocks/SubscriptionPacks.php`:
- Around line 164-170: The code in SubscriptionPacks.php is converting
$attributes['include'] and $attributes['exclude'] to comma strings before
calling get_subscriptions(), causing unnecessary conversions; instead assign the
integer-casted arrays directly to $subscription_args (e.g.,
$subscription_args['include'] = array_map('intval', $attributes['include']) and
similarly for 'exclude'), ensuring you only set them when non-empty and that
they remain arrays so get_subscriptions() receives arrays rather than imploded
strings.
In `@src/js/blocks/subscription-packs/components/MultiSelect.js`:
- Around line 88-133: The dropdown lacks Up/Down arrow key navigation for
keyboard users; update the onKeyDown handler on the search input
(searchInputRef) to handle 'ArrowDown' by preventing default and moving focus to
the first option (querySelector('.wpuf-block-multiselect__option') from a
dropdownRef), and update each option's onKeyDown (options rendered from
availableOptions and using className 'wpuf-block-multiselect__option') to handle
'ArrowDown' and 'ArrowUp' by preventing default and moving focus to the
nextElementSibling or previousElementSibling respectively (when previous goes
past the first option, move focus back to searchInputRef), preserving existing
Enter/Space/Escape behaviors and avoiding code duplication by reusing
handleSelect for activation.
In `@src/js/blocks/subscription-packs/edit.js`:
- Around line 291-299: Extract the inline hook into a named React component to
avoid calling hooks inside a callback: create a component like
LoadingResponsePlaceholder that accepts setIsUpdating (e.g., function
LoadingResponsePlaceholder({ setIsUpdating }) { useEffect(() => () =>
setIsUpdating(false), []); return null; }) and then replace the inline prop with
LoadingResponsePlaceholder={() => <LoadingResponsePlaceholder
setIsUpdating={setIsUpdating} />}; this keeps the same unmount behavior but
ensures hooks are used in a component, not a callback.
In `@tailwind.config.js`:
- Around line 25-29: The content array in tailwind.config.js contains a
duplicate path './templates/**/*.php'; remove the redundant
'./templates/**/*.php' entry so each glob appears only once (update the content
array to keep a single './templates/**/*.php' along with 'wpuf-functions.php'
and './src/**/*.{js,css}').
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6f3b7369-502b-41ab-947d-04c6f862abc1
⛔ Files ignored due to path filters (3)
assets/js/subscription-packs.css.mapis excluded by!**/*.mapassets/js/subscription-packs.js.mapis excluded by!**/*.mappackage-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (29)
.gitignoreassets/css/admin/form-builder.cssassets/css/admin/subscriptions.min.cssassets/css/ai-form-builder.cssassets/css/ai-form-builder.min.cssassets/css/forms-list.min.cssassets/css/frontend-subscriptions.min.cssassets/css/frontend/account.cssassets/js/js/blocks/subscription-packs/block.jsonassets/js/subscription-packs-rtl.cssassets/js/subscription-packs.asset.phpassets/js/subscription-packs.cssassets/js/subscription-packs.jsclass/subscription.phpincludes/Admin/Subscription.phpincludes/Blocks/SubscriptionPacks.phplanguages/wp-user-frontend.potpackage.jsonsrc/css/blocks/subscription-packs/editor.csssrc/js/blocks/subscription-packs/block.jsonsrc/js/blocks/subscription-packs/components/MultiSelect.jssrc/js/blocks/subscription-packs/edit.jssrc/js/blocks/subscription-packs/index.jssrc/js/blocks/subscription-packs/save.jstailwind.config.jstemplates/subscriptions/listing.phptemplates/subscriptions/pack-details.phpwebpack.config.jswpuf.php
| .superpowers | ||
| docs/superpowers |
There was a problem hiding this comment.
❓ Verification inconclusive
Script executed:
#!/bin/bash
# Description: Check if .superpowers or docs/superpowers directories/files exist or are referenced elsewhere in the codebase.
echo "=== Checking for .superpowers references ==="
fd -H -t d -t f "\.superpowers" . 2>/dev/null || echo "No .superpowers files/dirs found"
echo -e "\n=== Checking for docs/superpowers references ==="
fd -H "superpowers" docs/ 2>/dev/null || echo "No superpowers found in docs/"
echo -e "\n=== Checking for any code/config references to 'superpowers' ==="
rg -i "superpowers" --type-add 'config:*.{json,yml,yaml,toml,ini}' -t config -t js -t php -g '!.gitignore' -g '!node_modules' -C2 || echo "No code references found"Repository: weDevsOfficial/wp-user-frontend
Repository: weDevsOfficial/wp-user-frontend
Exit code: 0
stdout:
=== Checking for .superpowers references ===
=== Checking for docs/superpowers references ===
No superpowers found in docs/
=== Checking for any code/config references to 'superpowers' ===
config/icons-config.json- },
config/icons-config.json- {
config/icons-config.json: "class": "fab fa-superpowers",
config/icons-config.json: "name": "Superpowers",
config/icons-config.json: "keywords": "superpowers brand"
config/icons-config.json- },
config/icons-config.json- {
Remove or justify these gitignore entries, as they appear unrelated to this PR's scope.
The additions of .superpowers and docs/superpowers to .gitignore have no corresponding files, directories, or code references in the repository, and are not mentioned in the PR objectives focusing on subscription Gutenberg block implementation. These appear to be preemptive entries without clear justification.
Either:
- Document what generates these paths and why they're needed in this PR, or
- Move these to a separate housekeeping PR to maintain clear change scope.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.gitignore around lines 9 - 10, The .gitignore additions ".superpowers" and
"docs/superpowers" are unrelated to this PR; either remove those two entries
from .gitignore (delete the ".superpowers" and "docs/superpowers" lines) or move
them into a separate housekeeping PR — if you keep them here, add a one-line
justification in this PR description explaining what generates those paths and
why they must be ignored (e.g., the tool/process that creates .superpowers and
docs/superpowers) and reference those exact entries so reviewers can verify the
rationale.
| { | ||
| "$schema": "https://schemas.wp.org/trunk/block.json", | ||
| "apiVersion": 3, | ||
| "name": "wpuf/subscription-packs", | ||
| "version": "1.0.0", | ||
| "title": "Subscription Packs", | ||
| "category": "wpuf", | ||
| "description": "Display WPUF subscription packs with customizable layout and styling.", | ||
| "textdomain": "wp-user-frontend", | ||
| "icon": "cart", | ||
| "keywords": [ | ||
| "subscription", | ||
| "pricing", | ||
| "plans", | ||
| "wpuf" | ||
| ], | ||
| "attributes": { | ||
| "include": { | ||
| "type": "array", | ||
| "default": [] | ||
| }, | ||
| "exclude": { | ||
| "type": "array", | ||
| "default": [] | ||
| }, | ||
| "columns": { | ||
| "type": "number", | ||
| "default": 3 | ||
| }, | ||
| "order": { | ||
| "type": "string", | ||
| "default": "" | ||
| }, | ||
| "orderby": { | ||
| "type": "string", | ||
| "default": "" | ||
| }, | ||
| "showPrice": { | ||
| "type": "boolean", | ||
| "default": true | ||
| }, | ||
| "showFeatures": { | ||
| "type": "boolean", | ||
| "default": true | ||
| }, | ||
| "showDescription": { | ||
| "type": "boolean", | ||
| "default": true | ||
| }, | ||
| "buttonColor": { | ||
| "type": "string", | ||
| "default": "" | ||
| }, | ||
| "buttonText": { | ||
| "type": "string", | ||
| "default": "" | ||
| }, | ||
| "packBackgroundColor": { | ||
| "type": "string", | ||
| "default": "#ffffff" | ||
| }, | ||
| "packBorderColor": { | ||
| "type": "string", | ||
| "default": "#e5e7eb" | ||
| }, | ||
| "packBorderRadius": { | ||
| "type": "number", | ||
| "default": 12 | ||
| }, | ||
| "packPadding": { | ||
| "type": "number", | ||
| "default": 24 | ||
| }, | ||
| "packShadow": { | ||
| "type": "string", | ||
| "default": "md" | ||
| }, | ||
| "titleFontSize": { | ||
| "type": "number", | ||
| "default": 18 | ||
| }, | ||
| "priceFontSize": { | ||
| "type": "number", | ||
| "default": 30 | ||
| }, | ||
| "cardGap": { | ||
| "type": "number", | ||
| "default": 16 | ||
| }, | ||
| "recurringFontSize": { | ||
| "type": "number", | ||
| "default": 14 | ||
| } | ||
| }, | ||
| "supports": { | ||
| "spacing": { | ||
| "margin": true, | ||
| "padding": true | ||
| }, | ||
| "align": [ | ||
| "wide", | ||
| "full" | ||
| ], | ||
| "html": false | ||
| }, | ||
| "editorScript": "wpuf-subscription-packs-editor", | ||
| "editorStyle": "wpuf-subscription-packs-editor-style" | ||
| } No newline at end of file |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check for duplicate block.json files and verify which one is used
echo "=== All block.json files for subscription-packs ==="
fd -t f 'block.json' | xargs grep -l 'wpuf/subscription-packs' 2>/dev/null
echo ""
echo "=== Checking if assets/js/js/ path is intentional ==="
# Look for webpack config or build scripts that might output to this path
rg -l 'assets/js/js' --type=js --type=json -g '!**/node_modules/**' 2>/dev/null || echo "No references found"
echo ""
echo "=== Check .gitignore for assets/js/ patterns ==="
cat .gitignore 2>/dev/null | grep -E '(assets/js|build)' || echo "No matching patterns"Repository: weDevsOfficial/wp-user-frontend
Length of output: 351
🏁 Script executed:
#!/bin/bash
# Check if the two files have identical content
echo "=== Comparing block.json files ==="
if diff -q assets/js/js/blocks/subscription-packs/block.json src/js/blocks/subscription-packs/block.json; then
echo "Files are identical"
else
echo "Files differ"
diff assets/js/js/blocks/subscription-packs/block.json src/js/blocks/subscription-packs/block.json | head -20
fi
echo ""
echo "=== Checking SubscriptionPacks.php line 88 ==="
sed -n '85,91p' includes/Blocks/SubscriptionPacks.php
echo ""
echo "=== Checking if assets/js/js/ is in git ==="
git ls-files | grep -c '^assets/js/js/' && echo "Yes, tracked in git" || echo "Not tracked in git"Repository: weDevsOfficial/wp-user-frontend
Length of output: 1118
🏁 Script executed:
#!/bin/bash
# Get the full diff to see the actual differences
echo "=== Full comparison of differences ==="
diff -u src/js/blocks/subscription-packs/block.json assets/js/js/blocks/subscription-packs/block.json
echo ""
echo "=== Line counts ==="
echo "src/js/blocks/subscription-packs/block.json: $(wc -l < src/js/blocks/subscription-packs/block.json) lines"
echo "assets/js/js/blocks/subscription-packs/block.json: $(wc -l < assets/js/js/blocks/subscription-packs/block.json) lines"
echo ""
echo "=== Check for webpack/build config that might output to assets/js/ ==="
fd -t f 'webpack\|gulpfile\|rollup\|build' | head -20
echo ""
echo "=== Check git history of the assets file ==="
git log --oneline -n 5 -- assets/js/js/blocks/subscription-packs/block.json 2>/dev/null || echo "No history available"Repository: weDevsOfficial/wp-user-frontend
Length of output: 5434
Remove or clarify the orphaned assets/js/js/blocks/subscription-packs/block.json file.
This file is tracked in git but not used by the block registration. SubscriptionPacks.php (line 88) registers the block from src/js/blocks/subscription-packs, not from assets/js/js/blocks/. The file in assets/js/js/ contains identical functional content to the source version (only formatting differences: 2-space vs 4-space indentation), making it an unused duplicate.
The assets/js/js/ directory structure also appears unusual and is not referenced anywhere in the codebase. Either remove this file or clarify its purpose if it's intended for a build process that's not yet configured.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@assets/js/js/blocks/subscription-packs/block.json` around lines 1 - 108,
There’s an unused duplicate block.json (the subscription-packs block JSON
checked into the assets tree) that isn’t referenced by the block registration in
the SubscriptionPacks registration code; remove the orphaned block.json from the
assets copy (or, if it’s required by your build, update the build/registration
paths or add a comment explaining its purpose) so only the canonical block.json
used by the SubscriptionPacks registration remains tracked.
| return array_merge( $categories, [ | ||
| [ | ||
| 'slug' => 'wpuf', | ||
| 'title' => __( 'WP User Frontend', 'wp-user-frontend' ), | ||
| ], | ||
| ] ); |
There was a problem hiding this comment.
Fix multi-line function call formatting per WPCS.
The array_merge() call needs formatting adjustments to comply with WordPress coding standards.
Proposed fix
- return array_merge( $categories, [
- [
- 'slug' => 'wpuf',
- 'title' => __( 'WP User Frontend', 'wp-user-frontend' ),
+ return array_merge(
+ $categories,
+ [
+ [
+ 'slug' => 'wpuf',
+ 'title' => __( 'WP User Frontend', 'wp-user-frontend' ),
+ ],
- ],
- ] );
+ ]
+ );📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| return array_merge( $categories, [ | |
| [ | |
| 'slug' => 'wpuf', | |
| 'title' => __( 'WP User Frontend', 'wp-user-frontend' ), | |
| ], | |
| ] ); | |
| return array_merge( | |
| $categories, | |
| [ | |
| [ | |
| 'slug' => 'wpuf', | |
| 'title' => __( 'WP User Frontend', 'wp-user-frontend' ), | |
| ], | |
| ] | |
| ); |
🧰 Tools
🪛 GitHub Check: Run PHPCS inspection
[failure] 48-48:
Closing parenthesis of a multi-line function call must be on a line by itself
[failure] 43-43:
Opening parenthesis of a multi-line function call must be the last content on the line
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@includes/Blocks/SubscriptionPacks.php` around lines 43 - 48, The multi-line
array_merge() call is not formatted per WPCS; update the call so the opening
parenthesis remains on the function name line, put each argument on its own
indented line, ensure the array argument uses short/associative array formatting
and include a trailing comma on the last array element, then close the
parenthesis and semicolon on their own line; locate the array_merge invocation
(array_merge(...)) that returns the categories and reformat it accordingly so
the function name, arguments, and closing parenthesis follow WordPress coding
standards.
| register_block_type( $block_json_path, [ | ||
| 'render_callback' => [ $this, 'render' ], | ||
| ] ); |
There was a problem hiding this comment.
Fix multi-line function call formatting per WPCS.
The register_block_type() call violates WPCS multi-line formatting rules.
Proposed fix
- register_block_type( $block_json_path, [
- 'render_callback' => [ $this, 'render' ],
- ] );
+ register_block_type(
+ $block_json_path,
+ [
+ 'render_callback' => [ $this, 'render' ],
+ ]
+ );📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| register_block_type( $block_json_path, [ | |
| 'render_callback' => [ $this, 'render' ], | |
| ] ); | |
| register_block_type( | |
| $block_json_path, | |
| [ | |
| 'render_callback' => [ $this, 'render' ], | |
| ] | |
| ); |
🧰 Tools
🪛 GitHub Check: Run PHPCS inspection
[failure] 92-92:
Closing parenthesis of a multi-line function call must be on a line by itself
[failure] 90-90:
Opening parenthesis of a multi-line function call must be the last content on the line
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@includes/Blocks/SubscriptionPacks.php` around lines 90 - 92, The multi-line
call to register_block_type violates WPCS formatting; reformat the call so each
array key/value is on its own indented line and the opening and closing
parentheses/brackets follow WPCS style. Locate the register_block_type(
$block_json_path, [ 'render_callback' => [ $this, 'render' ], ] ); invocation in
the SubscriptionPacks class and rewrite it so the function arguments and the
associative array are split across lines (with the $block_json_path on the first
line, the 'render_callback' => [ $this, 'render' ], on its own indented line,
and the closing ] ); on its own line) to comply with WPCS multi-line function
call rules.
| return [ | ||
| 'packs' => $packs_list, | ||
| 'orderByOptions' => [ | ||
| [ 'value' => '', 'label' => __( 'Default', 'wp-user-frontend' ) ], | ||
| [ 'value' => 'title', 'label' => __( 'Title', 'wp-user-frontend' ) ], | ||
| [ 'value' => 'date', 'label' => __( 'Date', 'wp-user-frontend' ) ], | ||
| [ 'value' => 'meta_value_num', 'label' => __( 'Sort Order', 'wp-user-frontend' ) ], | ||
| ], | ||
| ]; |
There was a problem hiding this comment.
Fix array formatting for orderByOptions per WPCS.
Each associative array item should have its key-value pairs on separate lines.
Proposed fix
return [
'packs' => $packs_list,
'orderByOptions' => [
- [ 'value' => '', 'label' => __( 'Default', 'wp-user-frontend' ) ],
- [ 'value' => 'title', 'label' => __( 'Title', 'wp-user-frontend' ) ],
- [ 'value' => 'date', 'label' => __( 'Date', 'wp-user-frontend' ) ],
- [ 'value' => 'meta_value_num', 'label' => __( 'Sort Order', 'wp-user-frontend' ) ],
+ [
+ 'value' => '',
+ 'label' => __( 'Default', 'wp-user-frontend' ),
+ ],
+ [
+ 'value' => 'title',
+ 'label' => __( 'Title', 'wp-user-frontend' ),
+ ],
+ [
+ 'value' => 'date',
+ 'label' => __( 'Date', 'wp-user-frontend' ),
+ ],
+ [
+ 'value' => 'meta_value_num',
+ 'label' => __( 'Sort Order', 'wp-user-frontend' ),
+ ],
],
];📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| return [ | |
| 'packs' => $packs_list, | |
| 'orderByOptions' => [ | |
| [ 'value' => '', 'label' => __( 'Default', 'wp-user-frontend' ) ], | |
| [ 'value' => 'title', 'label' => __( 'Title', 'wp-user-frontend' ) ], | |
| [ 'value' => 'date', 'label' => __( 'Date', 'wp-user-frontend' ) ], | |
| [ 'value' => 'meta_value_num', 'label' => __( 'Sort Order', 'wp-user-frontend' ) ], | |
| ], | |
| ]; | |
| return [ | |
| 'packs' => $packs_list, | |
| 'orderByOptions' => [ | |
| [ | |
| 'value' => '', | |
| 'label' => __( 'Default', 'wp-user-frontend' ), | |
| ], | |
| [ | |
| 'value' => 'title', | |
| 'label' => __( 'Title', 'wp-user-frontend' ), | |
| ], | |
| [ | |
| 'value' => 'date', | |
| 'label' => __( 'Date', 'wp-user-frontend' ), | |
| ], | |
| [ | |
| 'value' => 'meta_value_num', | |
| 'label' => __( 'Sort Order', 'wp-user-frontend' ), | |
| ], | |
| ], | |
| ]; |
🧰 Tools
🪛 GitHub Check: Run PHPCS inspection
[warning] 122-122:
When a multi-item array uses associative keys, each value should start on a new line.
[warning] 121-121:
When a multi-item array uses associative keys, each value should start on a new line.
[warning] 120-120:
When a multi-item array uses associative keys, each value should start on a new line.
[warning] 119-119:
When a multi-item array uses associative keys, each value should start on a new line.
[failure] 119-119:
Expected 1 space between the comma and "'label'". Found: 15 spaces
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@includes/Blocks/SubscriptionPacks.php` around lines 116 - 124, The returned
array's 'orderByOptions' entries violate WPCS array formatting—update the array
so each associative element's key and value are on separate lines (one per line)
for every item in the 'orderByOptions' array inside the return statement of the
SubscriptionPacks block; specifically reformat the arrays like the elements that
currently read [ 'value' => 'title', 'label' => __( 'Title', 'wp-user-frontend'
) ] so each key-value pair is on its own line, preserving the same keys
('value', 'label') and values, and keep the surrounding indentation and trailing
commas consistent with WPCS.
| "columns": { | ||
| "type": "number", | ||
| "default": 3 | ||
| }, |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check Tailwind config for grid-cols safelist
echo "=== Checking Tailwind safelist for grid-cols classes ==="
fd -t f 'tailwind.config' | xargs cat 2>/dev/null | grep -A 20 'safelist' || echo "No safelist found"
echo ""
echo "=== Checking for grid-cols usage patterns ==="
rg 'grid-cols-[0-9]' --type=css --type=js -g '!node_modules/**' 2>/dev/null | head -20Repository: weDevsOfficial/wp-user-frontend
Length of output: 50388
Add min/max constraints on the columns attribute to prevent Tailwind class purging.
The columns attribute has no validation constraints. The Tailwind safelist in tailwind.config.js explicitly restricts grid columns to 1–4 (lg:wpuf-grid-cols-1 through lg:wpuf-grid-cols-4). Since templates/subscriptions/listing.php generates classes like lg:wpuf-grid-cols-{N} directly from this value, any columns value above 4 will create a class that doesn't exist in the safelist and will be purged during production builds, breaking the layout.
Prevent this by adding JSON Schema constraints to the block.json definition:
Add min/max constraints in block.json
"columns": {
"type": "number",
- "default": 3
+ "default": 3,
+ "minimum": 1,
+ "maximum": 4
},Alternatively, clamp the value server-side in SubscriptionPacks.php (line 187) as a fallback:
Clamp value in PHP (SubscriptionPacks.php)
$block_config = [
- 'columns' => absint( $attributes['columns'] ),
+ 'columns' => min( 4, max( 1, absint( $attributes['columns'] ) ) ),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "columns": { | |
| "type": "number", | |
| "default": 3 | |
| }, | |
| "columns": { | |
| "type": "number", | |
| "default": 3, | |
| "minimum": 1, | |
| "maximum": 4 | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/js/blocks/subscription-packs/block.json` around lines 21 - 24, The
columns attribute in block.json lacks min/max validation so values >4 produce
Tailwind classes that get purged; add JSON Schema constraints to the "columns"
property (e.g., set type to integer/number, "minimum": 1 and "maximum": 4 and
keep "default": 3) in src/js/blocks/subscription-packs/block.json, and as a
server-side fallback clamp the value when used in SubscriptionPacks (e.g., where
the code reads the columns value in the SubscriptionPacks class/method that
renders templates) to ensure the final value is within 1–4 before generating
lg:wpuf-grid-cols-{N}.
| <?php if ( $block_config['show_price'] ) : ?> | ||
| <div class="wpuf-mt-4"> | ||
| <div class="wpuf-flex wpuf-items-baseline wpuf-gap-x-1"> | ||
| <?php if ( $billing_amount != '0.00' ) { ?> |
There was a problem hiding this comment.
Use strict comparison for billing amount check.
The static analysis correctly flags this loose comparison. Since $billing_amount is a string and you're comparing against a string literal, use !== for type-safe comparison.
Proposed fix
- <?php if ( $billing_amount != '0.00' ) { ?>
+ <?php if ( $billing_amount !== '0.00' ) { ?>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <?php if ( $billing_amount != '0.00' ) { ?> | |
| <?php if ( $billing_amount !== '0.00' ) { ?> |
🧰 Tools
🪛 GitHub Check: Run PHPCS inspection
[warning] 128-128:
Loose comparisons are not allowed. Expected: "!=="; Found: "!="
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@templates/subscriptions/pack-details.php` at line 128, The if-condition uses
a loose comparison; change the check in the template where the conditional reads
if ( $billing_amount != '0.00' ) to a strict comparison using !== so it becomes
if ( $billing_amount !== '0.00' ), ensuring type-safe comparison of the
$billing_amount string against the '0.00' literal in the pack-details.php
template.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@includes/Blocks/SubscriptionPacks.php`:
- Around line 63-67: The register_block() in SubscriptionPacks.php currently
calls wp_localize_script() and get_editor_data() on every init, which triggers
wpuf()->subscription->get_subscriptions() and unwanted DB writes; change
register_block() to only register the block and scripts, then move the
wp_localize_script() + get_editor_data() call into an admin/editor-only hook
(e.g., hooked to admin_enqueue_scripts or enqueue_block_editor_assets) and guard
it with is_admin() or a get_current_screen() check so get_editor_data() runs
only in the editor context; ensure the unique symbols affected are
register_block(), get_editor_data(), wp_localize_script(), and the call path to
wpuf()->subscription->get_subscriptions().
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 4515261e-aedd-4efc-adfd-1e19a24069f7
📒 Files selected for processing (2)
includes/Assets.phpincludes/Blocks/SubscriptionPacks.php
| wp_localize_script( | ||
| 'wpuf-subscription-packs-editor', | ||
| 'wpufSubscriptionPacks', | ||
| $this->get_editor_data() | ||
| ); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's check the structure and locate the files
git ls-files | grep -E "(Assets\.php|SubscriptionPacks\.php|Subscription\.php)" | head -20Repository: weDevsOfficial/wp-user-frontend
Length of output: 263
🏁 Script executed:
# Read includes/Assets.php around lines 57-64
sed -n '50,70p' includes/Assets.phpRepository: weDevsOfficial/wp-user-frontend
Length of output: 786
🏁 Script executed:
# Get exact lines 57-64 from Assets.php
sed -n '57,64p' includes/Assets.phpRepository: weDevsOfficial/wp-user-frontend
Length of output: 471
🏁 Script executed:
# Search for register_block_assets method in Assets.php
rg -A 30 "function register_block_assets" includes/Assets.phpRepository: weDevsOfficial/wp-user-frontend
Length of output: 918
🏁 Script executed:
# Now check SubscriptionPacks.php around lines 63-67 and the full get_editor_data() method
sed -n '50,100p' includes/Blocks/SubscriptionPacks.phpRepository: weDevsOfficial/wp-user-frontend
Length of output: 1446
🏁 Script executed:
# Find where register_block() is called
rg -B 5 -A 5 "register_block()" includes/Blocks/SubscriptionPacks.phpRepository: weDevsOfficial/wp-user-frontend
Length of output: 1248
🏁 Script executed:
# Check Subscription.php lines 252-279
sed -n '252,279p' includes/Admin/Subscription.phpRepository: weDevsOfficial/wp-user-frontend
Length of output: 1058
🏁 Script executed:
# Check where register_all_scripts is called
rg -B 5 -A 5 "register_all_scripts" includes/Assets.phpRepository: weDevsOfficial/wp-user-frontend
Length of output: 662
🏁 Script executed:
# Check where wpuf-subscription-packs-editor script is enqueued
rg "wpuf-subscription-packs-editor" includes/ --type php -B 2 -A 2Repository: weDevsOfficial/wp-user-frontend
Length of output: 1323
🏁 Script executed:
# Check if there's any context where register_block is guarded for editor-only
grep -n "is_admin\|get_current_screen\|block_editor" includes/Blocks/SubscriptionPacks.phpRepository: weDevsOfficial/wp-user-frontend
Length of output: 57
🏁 Script executed:
# Check the full SubscriptionPacks.php constructor and class definition
sed -n '1,50p' includes/Blocks/SubscriptionPacks.phpRepository: weDevsOfficial/wp-user-frontend
Length of output: 1318
🏁 Script executed:
# Check if there's any enqueue happening instead of localization
rg "wp_enqueue_script.*wpuf-subscription-packs" includes/ --type phpRepository: weDevsOfficial/wp-user-frontend
Length of output: 57
🏁 Script executed:
# Check if wpuf-subscription-packs-editor script is enqueued anywhere
rg "wp_enqueue_script|enqueue_script" includes/ --type php | grep -i subscriptionRepository: weDevsOfficial/wp-user-frontend
Length of output: 1879
🏁 Script executed:
# Verify if the script is actually enqueued anywhere
rg -i "enqueue.*wpuf-subscription-packs-editor" includes/ --type phpRepository: weDevsOfficial/wp-user-frontend
Length of output: 57
🏁 Script executed:
# Check if there are any editor-only hooks or context checks used in this plugin
rg "current_screen|is_admin|block_editor_context" includes/ --type php -lRepository: weDevsOfficial/wp-user-frontend
Length of output: 742
🏁 Script executed:
# Check if init hook runs on all requests by looking at WordPress documentation or plugin behavior
# Also check if wp_localize_script works without enqueue
# For now, let's check if the script is enqueued anywhere at all
rg "wp_enqueue" includes/Blocks/SubscriptionPacks.phpRepository: weDevsOfficial/wp-user-frontend
Length of output: 133
Move editor-only code behind an admin/editor-only context check.
The register_block() method in includes/Blocks/SubscriptionPacks.php is hooked to the init action without any editor context guard. This causes wp_localize_script() and get_editor_data() to execute on every request (frontend and admin), forcing unnecessary calls to wpuf()->subscription->get_subscriptions(). That method in turn calls update_post_meta() when setting default sort order (see includes/Admin/Subscription.php:268-270), causing database writes on normal page loads. Guard the wp_localize_script() call with is_admin() or get_current_screen() checks and keep the block registration separate.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@includes/Blocks/SubscriptionPacks.php` around lines 63 - 67, The
register_block() in SubscriptionPacks.php currently calls wp_localize_script()
and get_editor_data() on every init, which triggers
wpuf()->subscription->get_subscriptions() and unwanted DB writes; change
register_block() to only register the block and scripts, then move the
wp_localize_script() + get_editor_data() call into an admin/editor-only hook
(e.g., hooked to admin_enqueue_scripts or enqueue_block_editor_assets) and guard
it with is_admin() or a get_current_screen() check so get_editor_data() runs
only in the editor context; ensure the unique symbols affected are
register_block(), get_editor_data(), wp_localize_script(), and the call path to
wpuf()->subscription->get_subscriptions().
closes #936
Summary
Adds a native Gutenberg block (
wpuf/subscription-packs) that lets site owners embed their subscription pricing plans anywhere using the WordPress block editor. The block renders a live preview in the editor and supports full customization — column layout, card styling, color overrides, visibility toggles, and pack selection — without writing any code. This also removes a leftover React-based experiment for the admin subscriptions UI, consolidating back to the Vue version.Technical Notes
register_block_type()with a server-side render callback (WeDevs\Wpuf\Blocks\SubscriptionPacks::render()).wpuf_subscription_block_config— allows themes/plugins to modify the block's render configuration before output.wpuf_subscription_listing_argsnow receives ablock_configkey when rendering through the block; templates consuming this filter should handle the new key gracefully.WPUF_USE_REACT_SUBSCRIPTIONSfeature flag and its associated React build assets have been removed. The admin subscriptions page now always loads the Vue version.Breaking Changes
The
WPUF_USE_REACT_SUBSCRIPTIONSconstant no longer has any effect. If your code checks or defines this constant, it can be safely removed. The React build files underassets/react-build/have been deleted.Summary by CodeRabbit
New Features
Chores