Skip to content

Commit 8be2862

Browse files
g-elwellg-elwellt-hamanoramonjdcarolinan
authored
Add option to exclude current post from query block (WordPress#64916)
* feat: add compatability filter for query block to exclude current post * feat: add exclude current option to query block filters area * fix: hide excludeCurrent filter or enable by default based on context, use post type label * Add backport changelog * Query Block: Guard against falsy current post ID when excluding Simplify the post__not_in append and skip it when get_the_ID() returns a falsy value (e.g. outside the loop), matching the JS-side guard in post-template/edit.js that requires a truthy postId before excluding. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Query Block: Simplify excludeCurrent condition with ! empty() Align the server-side filter with the core PR (WordPress/wordpress-develop#12016), which uses ! empty() instead of an isset() + truthy check. Functionally identical but matches core's simplified form. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Query Block: Do not auto-enable excludeCurrent on mount Keep the query filters clean when the block mounts instead of forcing `excludeCurrent` to true in singular templates. Enabling the exclusion is now left to the user via the toggle; the effect only clears a stale value when the exclusion no longer applies. Co-Authored-By: Claude <noreply@anthropic.com> --------- Unlinked contributors: noellesteegs, chrisgresh. Co-authored-by: g-elwell <garethelwell@git.wordpress.org> Co-authored-by: t-hamano <wildworks@git.wordpress.org> Co-authored-by: ramonjd <ramonopoly@git.wordpress.org> Co-authored-by: carolinan <poena@git.wordpress.org> Co-authored-by: ntsekouras <ntsekouras@git.wordpress.org> Co-authored-by: spacedmonkey <spacedmonkey@git.wordpress.org> Co-authored-by: jasmussen <joen@git.wordpress.org> Co-authored-by: jameskoster <jameskoster@git.wordpress.org> Co-authored-by: ryanwelcher <welcher@git.wordpress.org> Co-authored-by: Marc-pi <mdxfr@git.wordpress.org> Co-authored-by: mrfoxtalbot <mrfoxtalbot@git.wordpress.org> Co-authored-by: carlomanf <manfcarlo@git.wordpress.org> Co-authored-by: bbertucc <elblakeo31@git.wordpress.org> Co-authored-by: supernovia <supernovia@git.wordpress.org> Co-authored-by: dinhtungdu <dinhtungdu@git.wordpress.org> Co-authored-by: lunule <lunule@git.wordpress.org> Co-authored-by: efu98 <elfu98@git.wordpress.org> Co-authored-by: richtabor <richtabor@git.wordpress.org> Co-authored-by: colinduwe <colind@git.wordpress.org> Co-authored-by: Humanify-nl <humanify@git.wordpress.org>
1 parent 0a73d76 commit 8be2862

12 files changed

Lines changed: 113 additions & 11 deletions

File tree

‎backport-changelog/7.1/12016.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
https://github.com/WordPress/wordpress-develop/pull/12016
2+
3+
* https://github.com/WordPress/gutenberg/pull/64916
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
/**
3+
* Temporary compatibility code for new functionalities/changes related to the query block.
4+
*
5+
* @package gutenberg
6+
*/
7+
8+
/**
9+
* Filters the query loop block query vars to exclude the current post.
10+
*
11+
* @param array $query The current query vars.
12+
* @param WP_Block $block The block instance.
13+
*
14+
* @return array The modified query vars.
15+
*/
16+
function gutenberg_filter_query_block_exclude_current( $query, $block ) {
17+
if ( ! empty( $block->context['query']['excludeCurrent'] ) ) {
18+
$current_post_id = get_the_ID();
19+
if ( $current_post_id ) {
20+
$query['post__not_in'][] = $current_post_id;
21+
}
22+
}
23+
24+
return $query;
25+
}
26+
27+
add_filter( 'query_loop_block_query_vars', 'gutenberg_filter_query_block_exclude_current', 10, 2 );

‎lib/load.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ function gutenberg_is_experiment_enabled( $name ) {
7777
require __DIR__ . '/compat/wordpress-7.1/rest-api.php';
7878
require __DIR__ . '/compat/wordpress-7.1/collaboration.php';
7979
require __DIR__ . '/compat/wordpress-7.1/block-bindings.php';
80+
require __DIR__ . '/compat/wordpress-7.1/query-block.php';
8081
require __DIR__ . '/compat/wordpress-7.1/block-comments.php';
8182

8283
// Plugin specific code.

‎packages/block-library/src/post-template/README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ _Defined via the [`usesContext` and `providesContext`](https://developer.wordpre
5454
- `previewPostType`
5555
- `enhancedPagination`
5656
- `postType`
57+
- `postId`
5758

5859
## Block Markup
5960

‎packages/block-library/src/post-template/block.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"templateSlug",
1515
"previewPostType",
1616
"enhancedPagination",
17-
"postType"
17+
"postType",
18+
"postId"
1819
],
1920
"supports": {
2021
"anchor": true,

‎packages/block-library/src/post-template/edit.js‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ export default function PostTemplateEdit( {
103103
parents,
104104
pages,
105105
format,
106+
excludeCurrent,
106107
// We gather extra query args to pass to the REST API call.
107108
// This way extenders of Query Loop can add their own query args,
108109
// and have accurate previews in the editor.
@@ -112,6 +113,7 @@ export default function PostTemplateEdit( {
112113
} = {},
113114
templateSlug,
114115
previewPostType,
116+
postId,
115117
},
116118
attributes: { layout },
117119
__unstableLayoutClassNames,
@@ -203,6 +205,13 @@ export default function PostTemplateEdit( {
203205
if ( format?.length ) {
204206
query.format = format;
205207
}
208+
if ( excludeCurrent && postId ) {
209+
if ( query.exclude ) {
210+
query.exclude = [ ...query.exclude, postId ];
211+
} else {
212+
query.exclude = [ postId ];
213+
}
214+
}
206215

207216
/*
208217
* Handle cases where sticky is set to `exclude` or `only`.

‎packages/block-library/src/query/README.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ _Defined via the [`attributes`](https://developer.wordpress.org/block-editor/ref
1616
| Attribute | [Type](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-attributes/#type-validation) | [Default](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-attributes/#default-value) | Description |
1717
|-----------|------|---------|-------------|
1818
| `queryId` | `number` | — | — |
19-
| `query` | `object` | `{"perPage":null,"pages":0,"offset":0,"postType":"post","order":"desc","orderBy":"date","author":"","search":"","exclude":[],"sticky":"","inherit":true,"taxQuery":null,"parents":[],"format":[]}` | — |
19+
| `query` | `object` | `{"perPage":null,"pages":0,"offset":0,"postType":"post","order":"desc","orderBy":"date","author":"","search":"","exclude":[],"sticky":"","inherit":true,"taxQuery":null,"parents":[],"format":[],"excludeCurrent":null}` | — |
2020
| `tagName` | `string` | `"div"` | — |
2121
| `namespace` | `string` | — | — |
2222
| `enhancedPagination` | `boolean` | `false` | — |
@@ -38,6 +38,7 @@ _Defined via the [`usesContext` and `providesContext`](https://developer.wordpre
3838
**Uses context:**
3939

4040
- `templateSlug`
41+
- `postType`
4142

4243
**Provides context:**
4344

‎packages/block-library/src/query/block.json‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
"inherit": true,
2828
"taxQuery": null,
2929
"parents": [],
30-
"format": []
30+
"format": [],
31+
"excludeCurrent": null
3132
}
3233
},
3334
"tagName": {
@@ -42,7 +43,7 @@
4243
"default": false
4344
}
4445
},
45-
"usesContext": [ "templateSlug" ],
46+
"usesContext": [ "templateSlug", "postType" ],
4647
"providesContext": {
4748
"queryId": "queryId",
4849
"query": "query",

‎packages/block-library/src/query/edit/inspector-controls/index.js‎

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ import {
88
__experimentalVStack as VStack,
99
__experimentalToolsPanel as ToolsPanel,
1010
__experimentalToolsPanelItem as ToolsPanelItem,
11+
ToggleControl,
1112
__experimentalToggleGroupControl as ToggleGroupControl,
1213
__experimentalToggleGroupControlOption as ToggleGroupControlOption,
1314
} from '@wordpress/components';
1415
import { useSelect } from '@wordpress/data';
1516
import { store as coreStore } from '@wordpress/core-data';
16-
import { __ } from '@wordpress/i18n';
17+
import { __, sprintf } from '@wordpress/i18n';
1718
import { debounce } from '@wordpress/compose';
1819
import { useState, useMemo } from '@wordpress/element';
1920

@@ -40,7 +41,8 @@ import {
4041
import { useToolsPanelDropdownMenuProps } from '../../../utils/hooks';
4142

4243
export default function QueryInspectorControls( props ) {
43-
const { attributes, setQuery, isSingular } = props;
44+
const { attributes, setQuery, isSingular, shouldExcludeCurrentPost } =
45+
props;
4446
const { query } = attributes;
4547
const {
4648
order,
@@ -55,6 +57,7 @@ export default function QueryInspectorControls( props ) {
5557
taxQuery,
5658
parents,
5759
format,
60+
excludeCurrent,
5861
} = query;
5962
const allowedControls = useAllowedControls( attributes );
6063
const showSticky = postType === 'post';
@@ -171,12 +174,22 @@ export default function QueryInspectorControls( props ) {
171174
[ allowedControls, postTypeHasFormatSupport ]
172175
);
173176

177+
const showExcludeCurrentControl =
178+
shouldExcludeCurrentPost &&
179+
isControlAllowed( allowedControls, 'excludeCurrent' );
180+
const postTypeSingularName = useSelect(
181+
( select ) =>
182+
select( coreStore ).getPostType( postType )?.labels.singular_name,
183+
[ postType ]
184+
);
185+
174186
const showFiltersPanel =
175187
showTaxControl ||
176188
showAuthorControl ||
177189
showSearchControl ||
178190
showParentControl ||
179-
showFormatControl;
191+
showFormatControl ||
192+
showExcludeCurrentControl;
180193
const dropdownMenuProps = useToolsPanelDropdownMenuProps();
181194

182195
const showPostCountControl = isControlAllowed(
@@ -383,6 +396,7 @@ export default function QueryInspectorControls( props ) {
383396
search: '',
384397
taxQuery: null,
385398
format: [],
399+
excludeCurrent: null,
386400
} );
387401
setQuerySearch( '' );
388402
} }
@@ -463,6 +477,32 @@ export default function QueryInspectorControls( props ) {
463477
/>
464478
</ToolsPanelItem>
465479
) }
480+
{ showExcludeCurrentControl && (
481+
<ToolsPanelItem
482+
label={ __( 'Exclude' ) }
483+
hasValue={ () => excludeCurrent !== null }
484+
onDeselect={ () =>
485+
setQuery( { excludeCurrent: null } )
486+
}
487+
>
488+
<ToggleControl
489+
label={ __( 'Exclude current' ) }
490+
help={ sprintf(
491+
/* translators: %s: the post type singular name */
492+
__(
493+
'Exclude the current %s from the query.'
494+
),
495+
postTypeSingularName
496+
) }
497+
checked={ !! excludeCurrent }
498+
onChange={ ( value ) => {
499+
setQuery( {
500+
excludeCurrent: !! value,
501+
} );
502+
} }
503+
/>
504+
</ToolsPanelItem>
505+
) }
466506
</ToolsPanel>
467507
) }
468508
</>

‎packages/block-library/src/query/edit/query-content.js‎

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ export default function QueryContent( {
4444
tagName: TagName = 'div',
4545
query: { inherit } = {},
4646
} = attributes;
47-
const { templateSlug } = context;
48-
const { isSingular } = getQueryContextFromTemplate( templateSlug );
47+
const { templateSlug, postType } = context;
48+
const { isSingular, templateType } =
49+
getQueryContextFromTemplate( templateSlug );
4950
const { __unstableMarkNextChangeAsNotPersistent } =
5051
useDispatch( blockEditorStore );
5152
const instanceId = useInstanceId( QueryContent );
@@ -77,6 +78,14 @@ export default function QueryContent( {
7778
DEFAULTS_POSTS_PER_PAGE,
7879
};
7980
}, [] );
81+
82+
// Whether the "exclude current" filter applies: we're in a singular template
83+
// and the post type matches the query.
84+
const shouldExcludeCurrentPost =
85+
isSingular &&
86+
! inherit &&
87+
( query.postType === postType || query.postType === templateType );
88+
8089
// There are some effects running where some initialization logic is
8190
// happening and setting some values to some attributes (ex. queryId).
8291
// These updates can cause an `undo trap` where undoing will result in
@@ -102,15 +111,21 @@ export default function QueryContent( {
102111
} else if ( ! query.perPage && postsPerPage ) {
103112
newQuery.perPage = postsPerPage;
104113
}
105-
114+
// Remove the exclusion when it no longer applies, so the filters stay
115+
// clean. We never force it on: enabling the exclusion is left to the user.
116+
if ( ! shouldExcludeCurrentPost && query.excludeCurrent !== null ) {
117+
newQuery.excludeCurrent = null;
118+
}
106119
if ( !! Object.keys( newQuery ).length ) {
107120
__unstableMarkNextChangeAsNotPersistent();
108121
updateQuery( newQuery );
109122
}
110123
}, [
111124
query.perPage,
125+
query.excludeCurrent,
112126
inherit,
113127
postsPerPage,
128+
shouldExcludeCurrentPost,
114129
__unstableMarkNextChangeAsNotPersistent,
115130
updateQuery,
116131
] );
@@ -150,6 +165,7 @@ export default function QueryContent( {
150165
setAttributes={ setAttributes }
151166
clientId={ clientId }
152167
isSingular={ isSingular }
168+
shouldExcludeCurrentPost={ shouldExcludeCurrentPost }
153169
/>
154170
</InspectorControls>
155171
<InspectorControls group="advanced">

0 commit comments

Comments
 (0)