diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md
index 34db859f71d1d..6ff01707e2376 100644
--- a/docs/reference-guides/core-blocks.md
+++ b/docs/reference-guides/core-blocks.md
@@ -777,6 +777,16 @@ Display the query title. ([Source](https://github.com/WordPress/gutenberg/tree/t
- **Supports:** align (full, wide), color (background, gradients, text), interactivity (clientNavigation), spacing (margin, padding), typography (fontSize, lineHeight), ~~html~~
- **Attributes:** level, levelOptions, showPrefix, showSearchTerm, textAlign, type
+## Query Total
+
+Display the total number of results in a query. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/query-total))
+
+- **Name:** core/query-total
+- **Category:** theme
+- **Ancestor:** core/query
+- **Supports:** align (full, wide), color (background, gradients, text), spacing (margin, padding), typography (fontSize, lineHeight), ~~html~~
+- **Attributes:** displayType
+
## Quote
Give quoted text visual emphasis. "In quoting others, we cite ourselves." — Julio Cortázar ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/quote))
diff --git a/lib/blocks.php b/lib/blocks.php
index c3fdb26700c58..342cd25191e68 100644
--- a/lib/blocks.php
+++ b/lib/blocks.php
@@ -108,6 +108,7 @@ function gutenberg_reregister_core_block_types() {
'query-pagination-numbers.php' => 'core/query-pagination-numbers',
'query-pagination-previous.php' => 'core/query-pagination-previous',
'query-title.php' => 'core/query-title',
+ 'query-total.php' => 'core/query-total',
'read-more.php' => 'core/read-more',
'rss.php' => 'core/rss',
'search.php' => 'core/search',
diff --git a/packages/block-library/src/index.js b/packages/block-library/src/index.js
index 56365c87a268f..262f11de6ee22 100644
--- a/packages/block-library/src/index.js
+++ b/packages/block-library/src/index.js
@@ -99,6 +99,7 @@ import * as queryPaginationNext from './query-pagination-next';
import * as queryPaginationNumbers from './query-pagination-numbers';
import * as queryPaginationPrevious from './query-pagination-previous';
import * as queryTitle from './query-title';
+import * as queryTotal from './query-total';
import * as quote from './quote';
import * as reusableBlock from './block';
import * as readMore from './read-more';
@@ -211,6 +212,7 @@ const getAllBlocks = () => {
queryPaginationNumbers,
queryPaginationPrevious,
queryNoResults,
+ queryTotal,
readMore,
comments,
commentAuthorName,
diff --git a/packages/block-library/src/query-total/block.json b/packages/block-library/src/query-total/block.json
new file mode 100644
index 0000000000000..02dbbbbb00f74
--- /dev/null
+++ b/packages/block-library/src/query-total/block.json
@@ -0,0 +1,45 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 3,
+ "name": "core/query-total",
+ "title": "Query Total",
+ "category": "theme",
+ "ancestor": [ "core/query" ],
+ "description": "Display the total number of results in a query.",
+ "textdomain": "default",
+ "attributes": {
+ "displayType": {
+ "type": "string",
+ "default": "total-results"
+ }
+ },
+ "usesContext": [ "queryId", "query" ],
+ "supports": {
+ "align": [ "wide", "full" ],
+ "html": false,
+ "spacing": {
+ "margin": true,
+ "padding": true
+ },
+ "color": {
+ "gradients": true,
+ "text": true,
+ "__experimentalDefaultControls": {
+ "background": true
+ }
+ },
+ "typography": {
+ "fontSize": true,
+ "lineHeight": true,
+ "__experimentalFontFamily": true,
+ "__experimentalFontWeight": true,
+ "__experimentalFontStyle": true,
+ "__experimentalTextTransform": true,
+ "__experimentalTextDecoration": true,
+ "__experimentalLetterSpacing": true,
+ "__experimentalDefaultControls": {
+ "fontSize": true
+ }
+ }
+ }
+}
diff --git a/packages/block-library/src/query-total/edit.js b/packages/block-library/src/query-total/edit.js
new file mode 100644
index 0000000000000..4824021ae99b0
--- /dev/null
+++ b/packages/block-library/src/query-total/edit.js
@@ -0,0 +1,83 @@
+/**
+ * WordPress dependencies
+ */
+import { useBlockProps, BlockControls } from '@wordpress/block-editor';
+import { ToolbarGroup, ToolbarDropdownMenu } from '@wordpress/components';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import { resultsFound, displayingResults } from './icons';
+
+export default function QueryTotalEdit( { attributes, setAttributes } ) {
+ const { displayType } = attributes;
+
+ // Block properties and classes.
+ const blockProps = useBlockProps();
+
+ const getButtonPositionIcon = () => {
+ switch ( displayType ) {
+ case 'total-results':
+ return resultsFound;
+ case 'range-display':
+ return displayingResults;
+ }
+ };
+
+ const buttonPositionControls = [
+ {
+ role: 'menuitemradio',
+ title: __( 'Total results' ),
+ isActive: displayType === 'total-results',
+ icon: resultsFound,
+ onClick: () => {
+ setAttributes( { displayType: 'total-results' } );
+ },
+ },
+ {
+ role: 'menuitemradio',
+ title: __( 'Range display' ),
+ isActive: displayType === 'range-display',
+ icon: displayingResults,
+ onClick: () => {
+ setAttributes( { displayType: 'range-display' } );
+ },
+ },
+ ];
+
+ // Controls for the block.
+ const controls = (
+ <>
+
%s
', $range_text ); + break; + + case 'total-results': + default: + $output = sprintf( + '%d %s
', + $max_rows, + _n( 'result found', 'results found', $max_rows ) + ); + break; + } + + return sprintf( + '