diff --git a/mu-plugins/blocks/ratings-bars/index.php b/mu-plugins/blocks/ratings-bars/index.php
new file mode 100644
index 00000000..d536fd4b
--- /dev/null
+++ b/mu-plugins/blocks/ratings-bars/index.php
@@ -0,0 +1,20 @@
+
+
diff --git a/mu-plugins/blocks/ratings-bars/src/block.json b/mu-plugins/blocks/ratings-bars/src/block.json
new file mode 100644
index 00000000..9f157229
--- /dev/null
+++ b/mu-plugins/blocks/ratings-bars/src/block.json
@@ -0,0 +1,39 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 2,
+ "name": "wporg/ratings-bars",
+ "version": "0.1.0",
+ "title": "Ratings (bars)",
+ "category": "design",
+ "icon": "",
+ "description": "The breakdown of ratings displayed as bars for each rating value.",
+ "textdomain": "wporg",
+ "supports": {
+ "html": false
+ },
+ "attributes": {
+ "num_ratings": {
+ "type": "number",
+ "default": 0
+ },
+ "ratings": {
+ "type": "array",
+ "default": []
+ },
+ "slug": {
+ "type": "string",
+ "default": ""
+ },
+ "support_url": {
+ "type": "string",
+ "default": ""
+ },
+ "type": {
+ "type": "string",
+ "default": 0
+ }
+ },
+ "editorScript": "file:./index.js",
+ "style": "file:./style-index.css",
+ "render": "file:../render.php"
+}
diff --git a/mu-plugins/blocks/ratings-bars/src/edit.js b/mu-plugins/blocks/ratings-bars/src/edit.js
new file mode 100644
index 00000000..62679697
--- /dev/null
+++ b/mu-plugins/blocks/ratings-bars/src/edit.js
@@ -0,0 +1,20 @@
+/**
+ * WordPress dependencies
+ */
+import { useBlockProps } from '@wordpress/block-editor';
+import ServerSideRender from '@wordpress/server-side-render';
+
+export default function Edit( { name, attributes, context } ) {
+ const blockProps = useBlockProps();
+ const { postId } = context;
+ return (
+
+
+
+ );
+}
diff --git a/mu-plugins/blocks/ratings-bars/src/index.js b/mu-plugins/blocks/ratings-bars/src/index.js
new file mode 100644
index 00000000..5d6da2ae
--- /dev/null
+++ b/mu-plugins/blocks/ratings-bars/src/index.js
@@ -0,0 +1,16 @@
+/**
+ * WordPress dependencies
+ */
+import { registerBlockType } from '@wordpress/blocks';
+
+/**
+ * Internal dependencies
+ */
+import Edit from './edit';
+import metadata from './block.json';
+import './style.scss';
+
+registerBlockType( metadata.name, {
+ edit: Edit,
+ save: () => null,
+} );
diff --git a/mu-plugins/blocks/ratings-bars/src/style.scss b/mu-plugins/blocks/ratings-bars/src/style.scss
new file mode 100644
index 00000000..a52b6aa4
--- /dev/null
+++ b/mu-plugins/blocks/ratings-bars/src/style.scss
@@ -0,0 +1,65 @@
+.wp-block-wporg-ratings-bars {
+ list-style: none;
+ padding-inline-start: unset;
+}
+
+.wporg-ratings-bars__bar {
+ a {
+ margin-bottom: 4px;
+ display: flex;
+ align-items: center;
+ gap: var(--wp--preset--spacing--10);
+ text-decoration: none;
+
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+
+ &:last-child a {
+ margin-bottom: 0;
+ }
+}
+
+.wporg-ratings-bars__bar-label {
+ flex-basis: 4em;
+ flex-shrink: 0;
+}
+
+.wporg-ratings-bars__bar-count {
+ flex-basis: 2em;
+ flex-shrink: 0;
+ text-align: right;
+}
+
+.wporg-ratings-bars__bar-background {
+ display: inline-block;
+ background-color: var(--wp--preset--color--light-grey-2);
+ position: relative;
+ width: 100%;
+ height: var(--wp--preset--spacing--20);
+}
+
+.wporg-ratings-bars__bar-foreground {
+ position: absolute;
+ inset: 0;
+ right: auto;
+ background-color: var(--wp--custom--wporg-ratings-stars--color--fill);
+}
+
+@supports (grid-template-columns: subgrid) {
+ .wp-block-wporg-ratings-bars {
+ display: grid;
+ gap: 4px var(--wp--preset--spacing--10);
+ grid-template-columns: auto 1fr auto;
+
+ .wporg-ratings-bars__bar,
+ .wporg-ratings-bars__bar a {
+ display: grid;
+ grid-column: span 3;
+ grid-template-columns: subgrid;
+ margin-bottom: unset;
+ gap: unset;
+ }
+ }
+}
diff --git a/mu-plugins/blocks/ratings-stars/index.php b/mu-plugins/blocks/ratings-stars/index.php
new file mode 100644
index 00000000..119d329c
--- /dev/null
+++ b/mu-plugins/blocks/ratings-stars/index.php
@@ -0,0 +1,22 @@
+
+>
+
+
+
+
+
+
+
+
+
';
+ } else if ( $i + 0.5 === $display_rating ) {
+ echo '
';
+ } else {
+ echo '
';
+ }
+ }
+ ?>
+
+
+
+ ' . $display_rating . '' // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ );
+ ?>
+
+
+
diff --git a/mu-plugins/blocks/ratings-stars/src/block.json b/mu-plugins/blocks/ratings-stars/src/block.json
new file mode 100644
index 00000000..6ad0e00b
--- /dev/null
+++ b/mu-plugins/blocks/ratings-stars/src/block.json
@@ -0,0 +1,17 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 2,
+ "name": "wporg/ratings-stars",
+ "version": "0.1.0",
+ "title": "Ratings (stars)",
+ "category": "design",
+ "icon": "",
+ "description": "The average rating displayed as stars.",
+ "textdomain": "wporg",
+ "supports": {
+ "html": false
+ },
+ "editorScript": "file:./index.js",
+ "style": "file:./style-index.css",
+ "render": "file:./render.php"
+}
diff --git a/mu-plugins/blocks/ratings-stars/src/edit.js b/mu-plugins/blocks/ratings-stars/src/edit.js
new file mode 100644
index 00000000..62679697
--- /dev/null
+++ b/mu-plugins/blocks/ratings-stars/src/edit.js
@@ -0,0 +1,20 @@
+/**
+ * WordPress dependencies
+ */
+import { useBlockProps } from '@wordpress/block-editor';
+import ServerSideRender from '@wordpress/server-side-render';
+
+export default function Edit( { name, attributes, context } ) {
+ const blockProps = useBlockProps();
+ const { postId } = context;
+ return (
+
+
+
+ );
+}
diff --git a/mu-plugins/blocks/ratings-stars/src/index.js b/mu-plugins/blocks/ratings-stars/src/index.js
new file mode 100644
index 00000000..5d6da2ae
--- /dev/null
+++ b/mu-plugins/blocks/ratings-stars/src/index.js
@@ -0,0 +1,16 @@
+/**
+ * WordPress dependencies
+ */
+import { registerBlockType } from '@wordpress/blocks';
+
+/**
+ * Internal dependencies
+ */
+import Edit from './edit';
+import metadata from './block.json';
+import './style.scss';
+
+registerBlockType( metadata.name, {
+ edit: Edit,
+ save: () => null,
+} );
diff --git a/mu-plugins/blocks/ratings-stars/src/style.scss b/mu-plugins/blocks/ratings-stars/src/style.scss
new file mode 100644
index 00000000..bffd76a0
--- /dev/null
+++ b/mu-plugins/blocks/ratings-stars/src/style.scss
@@ -0,0 +1,29 @@
+.wp-block-wporg-ratings-stars {
+ display: flex;
+ align-items: center;
+}
+
+.wporg-ratings-stars__icons {
+ display: inline-flex;
+
+ svg {
+ height: 32px;
+ width: 32px;
+ margin-inline-start: -6px;
+ fill: var(--wp--custom--wporg-ratings-stars--color--fill);
+ }
+
+ // Flip the half-star for RTL views.
+ .rtl & .is-star-half {
+ transform: rotateY(-180deg);
+ }
+}
+
+.wporg-ratings-stars__label {
+ font-size: var(--wp--preset--font-size--small);
+ color: var(--wp--preset--color--charcoal-4);
+
+ .wporg-ratings-stars__icons + & {
+ margin-inline-start: 0.5em;
+ }
+}