Skip to content

Add BaseSettingsRESTController for plugin-ui settings#3

Merged
mrabbani merged 6 commits intomainfrom
feat/settings
Mar 5, 2026
Merged

Add BaseSettingsRESTController for plugin-ui settings#3
mrabbani merged 6 commits intomainfrom
feat/settings

Conversation

@mrabbani
Copy link
Member

@mrabbani mrabbani commented Mar 5, 2026

Summary

  • Adds BaseSettingsRESTController, an abstract REST controller for schema-driven settings management compatible with the @wedevs/plugin-ui <Settings> component
  • Variant-aware validation (number, switch, select, radio_capsule, customize_radio, multicheck, color_picker, combine_input, textarea) and sanitization with proper WordPress sanitize functions
  • Permission checks return WP_Error with descriptive messages instead of bare false
  • Constructor enforces $namespace, $rest_base, and $option_prefix to prevent misconfiguration
  • scopeId sanitized via sanitize_key() before use in option keys
  • Display-only variants (html, base_field_label) are skipped during save
  • Overridable get_permission_error_message() and get_validation_messages() for consumer text domain translations
  • Comprehensive apply_filters/do_action hooks namespaced with {option_prefix}_:
    • _settings_capability — customize required capability
    • _settings_schema — modify schema before loading values
    • _settings_get_response — modify full GET response
    • _settings_validate_field — override per-field validation
    • _settings_validation_errors — modify collected errors
    • _settings_validation_messages — translate/customize error messages
    • _settings_sanitize_field — override per-field sanitization
    • _settings_before_save — modify values before DB write
    • _settings_after_save — react after settings are saved
    • _settings_loaded_values — modify loaded values with defaults

Test plan

  • Subclass the controller with a concrete schema and verify GET returns schema + nested values
  • Verify POST validates, sanitizes, and persists values per variant type
  • Test permission checks return WP_Error for unauthorized users
  • Verify hooks fire correctly and allow overriding schema, validation, sanitization, and save behavior
  • Confirm display-only fields (html, base_field_label) are not saved

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a schema-driven REST API for reading and saving nested plugin settings with validation, sanitization, scope-aware persistence, and extensible hooks.
  • Documentation
    • Developer Guide expanded with a comprehensive Settings section (schema, field variants, registration, hooks, message customization) and updated hook reference.
    • Added project configuration & contributor guidance docs.
  • Chores
    • Updated repository export and ignore rules.

Introduces an abstract REST controller compatible with @wedevs/plugin-ui
<Settings> component. Includes variant-aware validation and sanitization,
permission checks with WP_Error, deep-merge persistence to wp_options,
and comprehensive apply_filters/do_action hooks for extensibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Mar 5, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5dc4ec8f-5b7c-444c-85b2-194f5ebc25e7

📥 Commits

Reviewing files that changed from the base of the PR and between 164db22 and 2d63eb8.

📒 Files selected for processing (4)
  • .gitattributes
  • .gitignore
  • CLAUDE.md
  • src/Settings/BaseSettingsRESTController.php

📝 Walkthrough

Walkthrough

Adds an abstract BaseSettingsRESTController that provides a schema-driven REST API for nested plugin settings persisted in wp_options, with route registration, permission checks, validation, sanitization, deep merge persistence, and multiple filters/actions; also adds expanded developer documentation and a hooks reference for Settings.

Changes

Cohort / File(s) Summary
Settings REST Controller Base Class
src/Settings/BaseSettingsRESTController.php
New abstract class implementing REST route registration (GET/POST), permission checks, schema loading, nested value read/write, deep merge helpers, per-variant validation & sanitization, and many WordPress filter/action extension points.
Developer Documentation (Settings)
docs/developer-guide.md
Added a Settings section and expanded developer guide: Creating a Settings Controller (extends BaseSettingsRESTController), schema format/examples, registering the controller, supported field variants, REST endpoints, and Settings hooks (filters/actions). Duplicate blocks mirrored in two locations.
Repository metadata & docs
.gitattributes, .gitignore, CLAUDE.md
Added export-ignore rules, ignored .claude/, and a new CLAUDE.md describing project config, conventions, and commands; no public API changes.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant REST_API as REST API
    participant SchemaSvc as Schema Handler
    participant Options as wp_options
    participant Hooks

    Client->>REST_API: GET /{namespace}/{rest_base}
    REST_API->>SchemaSvc: Permission check
    SchemaSvc-->>REST_API: allowed/denied
    REST_API->>SchemaSvc: Load schema
    SchemaSvc->>Options: Read stored values
    Options-->>SchemaSvc: Return values
    SchemaSvc->>SchemaSvc: Merge defaults into schema
    SchemaSvc->>Hooks: Apply settings_loaded_values / settings_get_response filters
    Hooks-->>REST_API: Filtered response
    REST_API-->>Client: 200 + schema + values
Loading
sequenceDiagram
    participant Client
    participant REST_API as REST API
    participant Validator
    participant Sanitizer
    participant Options as wp_options
    participant Hooks

    Client->>REST_API: POST /{namespace}/{rest_base} (values)
    REST_API->>Validator: Validate submitted values
    Validator->>Hooks: Apply settings_validation_errors filter
    Hooks-->>Validator: Validation result
    alt Validation fails
        Validator-->>REST_API: Errors
        REST_API-->>Client: 400 + errors
    else Validation passes
        Validator->>Sanitizer: Field sanitization
        Sanitizer->>Hooks: settings_sanitize_field filter
        Hooks-->>Sanitizer: Sanitized values
        REST_API->>Hooks: settings_before_save action
        REST_API->>Options: Merge & persist values (option_prefix + scope_id)
        Options-->>REST_API: Save complete
        REST_API->>Hooks: settings_after_save action
        REST_API-->>Client: 200 + merged values
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 I hopped into code with a cheerful ping,

Schemas and hooks make my rabbit heart sing,
Nested values tucked in wp_options' lair,
Validators tidy, sanitizers care,
Hooray — settings now dance in tidy pair!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add BaseSettingsRESTController for plugin-ui settings' directly and accurately describes the main change—introducing a new abstract REST controller class for managing schema-driven settings compatible with plugin-ui.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/settings

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.

Documents BaseSettingsRESTController usage: creating a controller,
defining schemas, supported field variants, translatable messages,
extending settings via hooks, and the full hook reference table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@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

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

Inline comments:
In `@src/Settings/BaseSettingsRESTController.php`:
- Line 1: Add a proper file-level docblock at the top and fix all
method/function docblocks in the BaseSettingsRESTController class so each has a
short description line followed by blank line before tags; replace any
Yoda-style conditionals (e.g., if (null === $var) or if (0 === count($x)) found
in methods of BaseSettingsRESTController) with normal ordering (if ($var ===
null), if (count($x) === 0)); and reformat the multiline function/method calls
so arguments and chained calls follow PSR-12 (put each argument or chained call
on its own indented line and ensure the closing parenthesis/semicolon alignment)
to resolve the reported violations at the top-of-file, docblocks, the Yoda
conditional, and the multiline call blocks.
- Around line 349-352: The color_picker validator currently rejects valid WP
color formats; replace the regex check in the 'color_picker' case so it uses
WordPress sanitize_hex_color() on $value and only sets $error =
$messages['color_picker'] when $value is non-empty and
sanitize_hex_color($value) returns null (invalid); ensure empty string remains
accepted and keep references to $value and $messages['color_picker'] unchanged.
- Around line 313-317: The numeric field handling accepts decimals (is_numeric
in the switch 'number') but later truncates values using intval; update the code
that currently casts/normalizes numeric settings (the place using intval around
the numeric save/normalize logic) to preserve decimal precision by using a
float-preserving conversion (e.g., floatval/cast to float or a decimal-safe
normalization) and ensure any stored/returned value retains the original decimal
when is_numeric passes; keep the existing validation message but ensure numeric
normalization uses the 'number' branch and the same error message variable
($messages['number']).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d481576f-f7cc-4cc0-a539-1f0230411157

📥 Commits

Reviewing files that changed from the base of the PR and between 47d86d1 and bead37b.

📒 Files selected for processing (1)
  • src/Settings/BaseSettingsRESTController.php

@@ -0,0 +1,646 @@
<?php
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Resolve the current PHPCS violations in this file.

The reported failures at Line 1, Line 21, Line 27, Line 166, and Lines 200–211 should be fixed to unblock lint checks (file doc comment, docblock short descriptions, Yoda condition, multiline call formatting).

Minimal patch sketch
@@
 <?php
+/**
+ * Base settings REST controller.
+ */
@@
-	 * wp_options key prefix (e.g. "wpkit_tasks").
+	 * WP options key prefix (e.g. "wpkit_tasks").
@@
-	/**
+	/**
+	 * Constructor.
+	 *
 	 * `@param` string $namespace     REST API namespace (e.g. "myplugin/v1").
@@
-			if ( $value !== null ) {
+			if ( null !== $value ) {
 				$element['default'] = $value;
 			}
@@
-			return new \WP_REST_Response( [
-				'errors' => [ 'values' => 'Invalid values format.' ],
-			], 400 );
+			return new \WP_REST_Response(
+				[
+					'errors' => [ 'values' => 'Invalid values format.' ],
+				],
+				400
+			);
@@
-			return new \WP_REST_Response( [
-				'errors' => [ 'scopeId' => 'Invalid scope ID.' ],
-			], 400 );
+			return new \WP_REST_Response(
+				[
+					'errors' => [ 'scopeId' => 'Invalid scope ID.' ],
+				],
+				400
+			);

Also applies to: 21-27, 166-166, 200-211

🧰 Tools
🪛 GitHub Check: PHPCS

[failure] 1-1:
Missing file doc comment

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Settings/BaseSettingsRESTController.php` at line 1, Add a proper
file-level docblock at the top and fix all method/function docblocks in the
BaseSettingsRESTController class so each has a short description line followed
by blank line before tags; replace any Yoda-style conditionals (e.g., if (null
=== $var) or if (0 === count($x)) found in methods of
BaseSettingsRESTController) with normal ordering (if ($var === null), if
(count($x) === 0)); and reformat the multiline function/method calls so
arguments and chained calls follow PSR-12 (put each argument or chained call on
its own indented line and ensure the closing parenthesis/semicolon alignment) to
resolve the reported violations at the top-of-file, docblocks, the Yoda
conditional, and the multiline call blocks.

mrabbani and others added 4 commits March 5, 2026 11:18
Adds project context for Claude Code, .gitattributes with export-ignore
for CLAUDE.md, .claude/, tests/, docs/, and config files so consumer
plugins don't receive them via composer install.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add file doc comment, fix Yoda conditions, multi-line function call
formatting, short ternary usage, and missing doc comment descriptions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use floatval() for decimal numbers and intval() for integers instead
of always truncating with intval(). Also remove file doc comment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Required by PHPCS Squiz.Commenting.FileComment rule.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@mrabbani mrabbani merged commit e8de3cc into main Mar 5, 2026
7 checks passed
@mrabbani mrabbani deleted the feat/settings branch March 5, 2026 05:55
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.

1 participant