Skip to content

Conversation

@CGastrell
Copy link
Contributor

@CGastrell CGastrell commented Jan 30, 2026

Proposed changes:

Display star rating icons in the response inspector instead of plain text for rating field submissions.

  • Add new FieldRating component that renders star icons based on the rating value
  • Integrate FieldRating into the field preview component for rating field types
  • Parse rating values (e.g., "4/5") and display the corresponding number of star icons

Before
image

image

After
image

image

Includes also:

refactor the rating icon SVG into a reusable RatingIcon component:

  1. edit.js - Extracted the inline SVG into an exported RatingIcon component that accepts:

    • iconStyle - the icon type (stars, hearts, etc.)
    • strokeColor - defaults to currentColor
    • fillColor - defaults to none
  2. field-rating/index.tsx - Replaced the duplicate filledIcon and emptyIcon SVG definitions with the new RatingIcon component, passing appropriate colors for filled (#F0B849) vs empty states.

This reduces code duplication by ~22 lines while making the rating icon reusable across both the block editor and the response inspector dashboard.

Other information:

  • Have you written new tests for your changes, if applicable?
  • Have you checked the E2E test CI results, and verified that your changes do not break them?
  • Have you tested your changes on WordPress.com, if applicable (if so, you'll see a generated comment below with a script to run)?

Jetpack product discussion

N/A

Does this pull request change what data or activity we track or use?

No

Testing instructions:

  1. Create a form with a Rating field
  2. Submit a response with a rating (e.g., 4 out of 5 stars)
  3. Go to Forms > Responses and click on the submission
  4. Verify the rating field displays star icons instead of plain text like "4/5"

Copilot AI review requested due to automatic review settings January 30, 2026 19:40
@CGastrell CGastrell added [Status] Needs Review This PR is ready for review. [Type] Task [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Package] Forms Coverage tests to be added later Use to ignore the Code coverage requirement check when tests will be added in a follow-up PR labels Jan 30, 2026
@CGastrell CGastrell self-assigned this Jan 30, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Jan 30, 2026

Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.

  • To test on WoA, go to the Plugins menu on a WoA dev site. Click on the "Upload" button and follow the upgrade flow to be able to upload, install, and activate the Jetpack Beta plugin. Once the plugin is active, go to Jetpack > Jetpack Beta, select your plugin (Jetpack), and enable the add/forms-field-rating-preview branch.
  • To test on Simple, run the following command on your sandbox:
bin/jetpack-downloader test jetpack add/forms-field-rating-preview

Interested in more tips and information?

  • In your local development environment, use the jetpack rsync command to sync your changes to a WoA dev blog.
  • Read more about our development workflow here: PCYsg-eg0-p2
  • Figure out when your changes will be shipped to customers here: PCYsg-eg5-p2

@github-actions
Copy link
Contributor

github-actions bot commented Jan 30, 2026

Thank you for your PR!

When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:

  • ✅ Include a description of your PR changes.
  • ✅ Add a "[Status]" label (In Progress, Needs Review, ...).
  • ✅ Add testing instructions.
  • ✅ Specify whether this PR includes any changes to data or privacy.
  • ✅ Add changelog entries to affected projects

This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖


Follow this PR Review Process:

  1. Ensure all required checks appearing at the bottom of this PR are passing.
  2. Make sure to test your changes on all platforms that it applies to. You're responsible for the quality of the code you ship.
  3. You can use GitHub's Reviewers functionality to request a review.
  4. When it's reviewed and merged, you will be pinged in Slack to deploy the changes to WordPress.com simple once the build is done.

If you have questions about anything, reach out in #jetpack-developers for guidance!


Jetpack plugin:

No scheduled milestone found for this plugin.

If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a dedicated rating-field renderer for the Forms response inspector so rating submissions can be displayed as icons instead of plain text.

Changes:

  • Add a new FieldRating component that renders rating icons.
  • Wire FieldRating into the response inspector field preview for rating fields.
  • Add a changelog entry documenting the UI enhancement.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
projects/packages/forms/src/dashboard/components/inspector/response-fields/field-rating/index.tsx Introduces the FieldRating renderer responsible for displaying rating icons.
projects/packages/forms/src/dashboard/components/inspector/response-fields/field-preview/index.tsx Integrates FieldRating into the response-field value rendering flow for rating types.
projects/packages/forms/changelog/add-forms-field-rating-preview Documents the new rating icon display in the response inspector.

@jp-launch-control
Copy link

jp-launch-control bot commented Jan 30, 2026

Code Coverage Summary

Coverage changed in 3 files.

File Coverage Δ% Δ Uncovered
projects/packages/forms/src/dashboard/components/inspector/response-fields/field-preview/index.tsx 0/60 (0.00%) 0.00% 2 ❤️‍🩹
projects/packages/forms/src/blocks/field-rating/rating-icons.js 2/8 (25.00%) 25.00% -1 💚
projects/packages/forms/src/blocks/input-rating/edit.js 0/14 (0.00%) 0.00% -2 💚

2 files are newly checked for coverage.

File Coverage
projects/packages/forms/src/dashboard/components/inspector/response-fields/field-rating/index.tsx 20/22 (90.91%) 💚
projects/packages/forms/src/blocks/field-rating/rating-icon.js 3/3 (100.00%) 💚

Full summary · PHP report · JS report

Coverage check overridden by Coverage tests to be added later Use to ignore the Code coverage requirement check when tests will be added in a follow-up PR .

Copilot AI review requested due to automatic review settings January 30, 2026 20:41
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

Comment on lines 39 to 43
parsedMax < 0
) {
return <>-</>;
}
const displayRating = Math.min( Math.max( 0, parsedRating ), parsedMax );
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

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

displayRating is currently clamped to parsedMax, so an invalid stored value like "7/5" would be rendered as 5 stars. This hides data problems and diverges from the backend validation in src/contact-form/class-feedback-field.php (it treats rating > max and max <= 0 as invalid and returns the raw string). Consider changing the validation to return "-" when parsedMax <= 0 or parsedRating > parsedMax (instead of clamping) so the inspector doesn’t display a misleading rating.

Suggested change
parsedMax < 0
) {
return <>-</>;
}
const displayRating = Math.min( Math.max( 0, parsedRating ), parsedMax );
parsedMax <= 0 ||
parsedRating > parsedMax
) {
return <>-</>;
}
const displayRating = parsedRating;

Copilot uses AI. Check for mistakes.
Comment on lines 108 to 113
it( 'clamps rating to max (e.g. 7/5 shows 5 icons)', () => {
const { container } = render( <FieldRating value="7/5" /> );

// eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
const svgs = container.querySelectorAll( 'svg' );
expect( svgs ).toHaveLength( 5 );
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

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

This test asserts that an invalid value "7/5" should be clamped to 5 icons, but the backend formatter treats rating > max as invalid and would not consider this a valid rating. The test should be updated to match the desired/validated behavior (e.g., expecting a fallback like "-"), otherwise it will lock in incorrect UI behavior.

Suggested change
it( 'clamps rating to max (e.g. 7/5 shows 5 icons)', () => {
const { container } = render( <FieldRating value="7/5" /> );
// eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
const svgs = container.querySelectorAll( 'svg' );
expect( svgs ).toHaveLength( 5 );
it( 'falls back to "-" when rating exceeds max (e.g. "7/5")', () => {
render( <FieldRating value="7/5" /> );
expect( screen.getByText( '-' ) ).toBeInTheDocument();

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think invalidating the entire value or coercing to "-" would entirely make sense. Maybe set to max (5/5) on those cases? Wouldn't help much the user to just find a dash if someone has achieved to mess with the submit value, it would only create questions.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

Comment on lines 46 to 53
<SVG viewBox="0 0 24 24" aria-hidden="true">
<Path
d={ RATING_ICONS.stars }
fill="#F0B849"
stroke="#F0B849"
strokeWidth="0"
strokeLinejoin="round"
/>
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

The SVG path styling is hard-coded to #F0B849, which may not work well with themes/dark mode and is inconsistent with existing rating icons that use currentColor (e.g. src/blocks/input-rating/edit.js:18-25). Consider switching to currentColor + a wrapper class/CSS variable for the color so the inspector rendering follows established styling patterns.

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

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

Let's use the renderRatingIconsHtml helper too, instead of just RATING_ICONS? It's a bit problematic otherwise that Path and its props are defined separately in two different places.

Copy link
Contributor Author

@CGastrell CGastrell Feb 2, 2026

Choose a reason for hiding this comment

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

Mmm... but renderRatingIconsHtml was designed to work on frontend, hence it outputs an html string. The approach used here is the same used on the editor context. I don't see how using renderRatingIconsHtml would help us in this context.

We could include in the helper a version that outputs a react element though.

Copy link
Member

Choose a reason for hiding this comment

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

Gotcha! Then it might make sense to keep it like so. Still, to me it looks odd.

@simison simison requested a review from a team February 2, 2026 10:48
@simison
Copy link
Member

simison commented Feb 2, 2026

We should keep the /5 info (max number) info, instead of just what they rated, otherwise it's a bit meaningless. :-)

Like so:

image

};

// Maximum icons to render to prevent DOM bloat from malformed values
const MAX_RATING_ICONS = 10;
Copy link
Member

Choose a reason for hiding this comment

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

Might be a good constant to share with the block edit function so that they never diverge accidentally:

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll move it over to the block then and import it from there

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved things a bit around, so exports needed from the module stay on slim files yet the RatingIcon itself lives on its own

const FieldRating = ( { value }: FieldRatingProps ) => {
const stringValue = value != null ? String( value ) : '';
if ( stringValue.trim() === '' ) {
return <>-</>;
Copy link
Member

Choose a reason for hiding this comment

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

Why <></> here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Failsafe mechanism for empty values. It should never happen, but it was the consensus when any field doesn't have a value. If there's nothing to show, bail out early.

Copy link
Member

Choose a reason for hiding this comment

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

Oh I meant why <>-</> not just -? :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Gotcha! Yeah, no reason. Simplified it.

Copilot AI review requested due to automatic review settings February 2, 2026 17:08
@github-actions github-actions bot added the [Block] Contact Form Form block (also see Contact Form label) label Feb 2, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Comment on lines 12 to 13
import { RatingIcon } from '../../../../../blocks/input-rating/edit.js';

Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

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

FieldRating imports RatingIcon from blocks/input-rating/edit.js, but that module also imports @wordpress/block-editor and editor-only hooks. Pulling the whole editor "edit" module into the dashboard/response inspector bundle is likely to break in contexts where @wordpress/block-editor isn’t present, and it also increases bundle size unnecessarily. Please move RatingIcon into a small shared module (no block-editor deps) and import it from both edit.js and this dashboard component.

Suggested change
import { RatingIcon } from '../../../../../blocks/input-rating/edit.js';
type RatingIconProps = {
iconStyle?: 'stars';
strokeColor?: string;
fillColor?: string;
};
const RatingIcon = ( {
// Keep signature compatible with potential future extensions.
iconStyle = 'stars',
strokeColor = 'currentColor',
fillColor = 'none',
}: RatingIconProps ) => {
// Currently only "stars" style is used in this context.
if ( iconStyle !== 'stars' ) {
return null;
}
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
aria-hidden="true"
role="img"
>
<path
d="M12 2.5l2.694 5.458 6.026.876-4.36 4.25 1.029 6.006L12 16.79l-5.389 2.8 1.029-6.006-4.36-4.25 6.026-.876L12 2.5z"
fill={ fillColor }
stroke={ strokeColor }
strokeWidth="1.2"
strokeLinejoin="round"
/>
</svg>
);
};

Copilot uses AI. Check for mistakes.
Comment on lines +57 to +59
const ratingLabel = sprintf(
/* translators: 1: rating value, 2: maximum rating (e.g. "4" and "5" for "4 out of 5") */
__( 'Rating %1$s out of %2$s', 'jetpack-forms' ),
String( displayRating ),
String( clampedMax )
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

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

The accessible label uses displayRating/clampedMax, which can become inaccurate when the submitted value has a larger max than MAX_RATING_ICONS (e.g. "50/100" will be announced as "Rating 10 out of 10"). Keep clamping only for rendered icon count, but use the original parsed values (or otherwise convey the cap) in the VisuallyHidden text so screen readers get the real rating.

Suggested change
const ratingLabel = sprintf(
/* translators: 1: rating value, 2: maximum rating (e.g. "4" and "5" for "4 out of 5") */
__( 'Rating %1$s out of %2$s', 'jetpack-forms' ),
String( displayRating ),
String( clampedMax )
// Use the original scale in the accessible label so screen readers get the real rating.
const accessibleRating = Math.min( Math.max( 0, parsedRating ), parsedMax );
const ratingLabel = sprintf(
/* translators: 1: rating value, 2: maximum rating (e.g. "4" and "5" for "4 out of 5") */
__( 'Rating %1$s out of %2$s', 'jetpack-forms' ),
String( accessibleRating ),
String( parsedMax )

Copilot uses AI. Check for mistakes.
Comment on lines 44 to 54
if (
! Number.isFinite( parsedRating ) ||
parsedRating < 0 ||
! Number.isFinite( parsedMax ) ||
parsedMax < 0
) {
return <>-</>;
}

// Clamp max to prevent DOM bloat from large values
const clampedMax = Math.min( parsedMax, MAX_RATING_ICONS );
const displayRating = Math.min( Math.max( 0, parsedRating ), clampedMax );

Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

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

parsedMax of 0 currently renders an empty HStack (0 icons) with only a visually-hidden label. Consider treating max <= 0 as invalid and falling back to "-" to avoid an apparently blank value in the UI (e.g. input "0/0" or "3/0").

Copilot uses AI. Check for mistakes.
@CGastrell CGastrell force-pushed the add/forms-field-rating-preview branch from f384ddf to 0fcf737 Compare February 2, 2026 17:40
Copilot AI review requested due to automatic review settings February 2, 2026 20:51
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

return (
<>
<VisuallyHidden as="span">{ ratingLabel }</VisuallyHidden>
<HStack spacing="1" alignment="topLeft">
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

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

The alignment value "topLeft" should be "left" for HStack. The WordPress HStack component accepts alignment values like "left", "center", "right", "top", "bottom" but not "topLeft". This may cause unexpected behavior or styling issues.

Suggested change
<HStack spacing="1" alignment="topLeft">
<HStack spacing="1" alignment="left">

Copilot uses AI. Check for mistakes.
@CGastrell CGastrell requested a review from ilonagl February 2, 2026 20:53
CGastrell and others added 13 commits February 3, 2026 01:11
- Validate rating and max values are finite and non-negative
- Clamp rating to max value to prevent overflow (e.g., 7/5 shows 5 stars)
- Fall back to "-" for non-numeric values

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Move RatingIcon component from input-rating/edit.js to a dedicated
rating-icon.js file to allow importing without editor dependencies.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Move the max rating icons limit to rating-icons.js as a shared constant.
Update field-rating/edit.js to import and use it.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Import RatingIcon and MAX_RATING_ICONS from the shared modules instead
of the block editor files to avoid pulling in unnecessary dependencies.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@CGastrell CGastrell force-pushed the add/forms-field-rating-preview branch from 5cff204 to b6d1cd8 Compare February 3, 2026 04:11
simison
simison previously approved these changes Feb 3, 2026
@CGastrell CGastrell merged commit 3cf71ee into trunk Feb 3, 2026
70 checks passed
@CGastrell CGastrell deleted the add/forms-field-rating-preview branch February 3, 2026 17:59
@github-actions github-actions bot added [Status] UI Changes Add this to PRs that change the UI so documentation can be updated. and removed [Status] Needs Review This PR is ready for review. labels Feb 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Block] Contact Form Form block (also see Contact Form label) Coverage tests to be added later Use to ignore the Code coverage requirement check when tests will be added in a follow-up PR [Feature] Contact Form [Package] Forms [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Status] UI Changes Add this to PRs that change the UI so documentation can be updated. [Tests] Includes Tests [Type] Task

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants