Skip to content

Commit 7270d06

Browse files
authored
Merge pull request #36 from badasswp/release-1.3.0
Release 1.3.0
2 parents dfa1d5b + 44a1581 commit 7270d06

File tree

7 files changed

+146
-105
lines changed

7 files changed

+146
-105
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 1.3.0
4+
* Feat: Add Search count feature.
5+
* Tested up to WP 6.7.2.
6+
37
## 1.2.3
48
* Fix: Crashing Gutenberg Block Editor on Toggle Block Inserter.
59
* Tested up to WP 6.7.1.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "search-and-replace",
3-
"version": "1.2.3",
3+
"version": "1.3.0",
44
"description": "Search and Replace text within the Block Editor.",
55
"author": "badasswp",
66
"license": "GPL-2.0-or-later",

readme.txt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
=== Search and Replace for Block Editor ===
2-
Contributors: badasswp, anandraj
2+
Contributors: badasswp, rajanand346
33
Tags: search, replace, text, block, editor.
44
Requires at least: 6.0
5-
Tested up to: 6.7.1
6-
Stable tag: 1.2.3
5+
Tested up to: 6.7.2
6+
Stable tag: 1.3.0
77
Requires PHP: 7.4
88
License: GPLv2 or later
99
License URI: http://www.gnu.org/licenses/gpl-2.0.html
1010

11-
Search and Replace text within the Block Editor.
11+
Search and Replace text within the WordPress Block Editor just like Microsoft Word or Google Docs. It's super fast, easy & just works!
1212

1313
== Installation ==
1414

@@ -61,9 +61,13 @@ Want to add your personal touch? All of our documentation can be found [here](ht
6161

6262
== Changelog ==
6363

64+
= 1.3.0 =
65+
* Feat: Add Search count feature.
66+
* Tested up to WP 6.7.2.
67+
6468
= 1.2.3 =
6569
* Fix: Crashing Gutenberg Block Editor on Toggle Block Inserter.
66-
* Tested up to WP 6.7.1.
70+
* Tested up to WP 6.7.2.
6771

6872
= 1.2.2 =
6973
* Fix style issues for WP 6.6.2.

search-replace-for-block-editor.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Plugin Name: Search and Replace for Block Editor
44
* Plugin URI: https://github.com/badasswp/search-and-replace
55
* Description: Search and Replace text within the Block Editor.
6-
* Version: 1.2.3
6+
* Version: 1.3.0
77
* Author: badasswp
88
* Author URI: https://github.com/badasswp
99
* License: GPL v2 or later
@@ -46,7 +46,7 @@
4646
'wp-plugins',
4747
'wp-edit-post',
4848
],
49-
'1.2.2',
49+
'1.3.0',
5050
false,
5151
);
5252

src/core/app.tsx

Lines changed: 95 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ import { Shortcut } from './shortcut';
2020
* @returns {JSX.Element}
2121
*/
2222
const SearchReplaceForBlockEditor = (): JSX.Element => {
23-
const [replacements, setReplacements] = useState(0);
24-
const [isModalVisible, setIsModalVisible] = useState(false);
25-
const [searchInput, setSearchInput] = useState('');
26-
const [replaceInput, setReplaceInput] = useState('');
27-
const [caseSensitive, setCaseSensitive] = useState(false);
23+
const [ replacements, setReplacements ] = useState( 0 );
24+
const [ isModalVisible, setIsModalVisible ] = useState( false );
25+
const [ searchInput, setSearchInput ] = useState( '' );
26+
const [ replaceInput, setReplaceInput ] = useState( '' );
27+
const [ caseSensitive, setCaseSensitive ] = useState( false );
28+
const [ context, setContext ] = useState( false );
2829

2930
/**
3031
* Open Modal.
@@ -34,8 +35,8 @@ const SearchReplaceForBlockEditor = (): JSX.Element => {
3435
* @returns {void}
3536
*/
3637
const openModal = (): void => {
37-
setIsModalVisible(true);
38-
setReplacements(0);
38+
setIsModalVisible( true );
39+
setReplacements( 0 );
3940
}
4041

4142
/**
@@ -46,8 +47,8 @@ const SearchReplaceForBlockEditor = (): JSX.Element => {
4647
* @returns {void}
4748
*/
4849
const closeModal = (): void => {
49-
setIsModalVisible(false);
50-
setReplacements(0);
50+
setIsModalVisible( false );
51+
setReplacements( 0 );
5152
}
5253

5354
/**
@@ -64,11 +65,25 @@ const SearchReplaceForBlockEditor = (): JSX.Element => {
6465
const selectedText: string = getBlockEditorIframe().getSelection().toString();
6566
const modalSelector: string = '.search-replace-modal';
6667

67-
if (selectedText && !inContainer(modalSelector)) {
68-
setSearchInput(selectedText);
68+
if ( selectedText && ! inContainer( modalSelector ) ) {
69+
setSearchInput( selectedText );
6970
}
7071
};
7172

73+
/**
74+
* Listen for changes in Search Input & Case Sensitivity.
75+
*
76+
* By passing in a FALSY context to the replace callback, we only
77+
* search for matched strings, we DO NOT replace matched strings.
78+
*
79+
* @since 1.3.0
80+
*
81+
* @returns {void}
82+
*/
83+
useEffect( () => {
84+
replace();
85+
}, [ searchInput, caseSensitive ] );
86+
7287
/**
7388
* Handle case sensitive toggle feature
7489
* to enable user perform case-sensitive search
@@ -79,7 +94,7 @@ const SearchReplaceForBlockEditor = (): JSX.Element => {
7994
* @param {boolean} newValue
8095
* @returns {void}
8196
*/
82-
const handleCaseSensitive = (newValue: boolean): void => {
97+
const handleCaseSensitive = ( newValue: boolean ): void => {
8398
setCaseSensitive( newValue );
8499
}
85100

@@ -88,13 +103,16 @@ const SearchReplaceForBlockEditor = (): JSX.Element => {
88103
* clicks the 'Replace' button.
89104
*
90105
* @since 1.0.0
106+
* @since 1.3.0 Pass in context param to determine if it is Search or Replace.
91107
*
108+
* @param {boolean} context True (Replace), False (Search).
92109
* @returns {void}
93110
*/
94-
const replace = (): void => {
95-
setReplacements(0);
111+
const replace = ( context: boolean = false ): void => {
112+
setContext( context );
113+
setReplacements( 0 );
96114

97-
if (!searchInput) {
115+
if ( ! searchInput ) {
98116
return;
99117
}
100118

@@ -103,9 +121,9 @@ const SearchReplaceForBlockEditor = (): JSX.Element => {
103121
isCaseSensitive() || caseSensitive ? 'g' : 'gi'
104122
);
105123

106-
select('core/block-editor').getBlocks().forEach((element) => {
107-
recursivelyReplace(element, pattern, replaceInput);
108-
});
124+
select( 'core/block-editor' ).getBlocks().forEach( ( element ) => {
125+
recursivelyReplace( element, pattern, replaceInput, context );
126+
} );
109127
};
110128

111129
/**
@@ -115,37 +133,39 @@ const SearchReplaceForBlockEditor = (): JSX.Element => {
115133
*
116134
* @since 1.0.0
117135
* @since 1.0.1 Handle edge-cases for quote, pullquote & details block.
136+
* @since 1.3.0 Pass in context param to determine if it is Search or Replace.
118137
*
119138
* @param {Object} element Gutenberg editor block.
120139
* @param {RegExp} pattern Search pattern.
121140
* @param {string} text Replace pattern.
141+
* @param {boolean} context True (Replace), False (Search).
122142
*
123143
* @returns {void}
124144
*/
125-
const recursivelyReplace = (element, pattern, text): void => {
126-
if (getAllowedBlocks().indexOf(element.name) !== -1) {
127-
const args = { element, pattern, text };
145+
const recursivelyReplace = ( element, pattern, text, context ): void => {
146+
if ( getAllowedBlocks().indexOf( element.name ) !== -1 ) {
147+
const args = { element, pattern, text, context };
128148

129-
switch (element.name) {
149+
switch( element.name ) {
130150
case 'core/quote':
131151
case 'core/pullquote':
132-
replaceBlockAttribute(args, 'citation');
152+
replaceBlockAttribute( args, 'citation' );
133153
break;
134154

135155
case 'core/details':
136-
replaceBlockAttribute(args, 'summary');
156+
replaceBlockAttribute( args, 'summary' );
137157
break;
138158

139159
default:
140-
replaceBlockAttribute(args, 'content');
160+
replaceBlockAttribute( args, 'content' );
141161
break;
142162
}
143163
}
144164

145-
if (element.innerBlocks.length) {
146-
element.innerBlocks.forEach((innerElement) => {
147-
recursivelyReplace(innerElement, pattern, text);
148-
});
165+
if ( element.innerBlocks.length ) {
166+
element.innerBlocks.forEach( ( innerElement ) => {
167+
recursivelyReplace( innerElement, pattern, text, context );
168+
} );
149169
}
150170
}
151171

@@ -161,33 +181,38 @@ const SearchReplaceForBlockEditor = (): JSX.Element => {
161181
*
162182
* @returns {void}
163183
*/
164-
const replaceBlockAttribute = (args, attribute): void => {
184+
const replaceBlockAttribute = ( args, attribute ): void => {
165185
const { attributes, clientId } = args.element;
166186

167-
if (undefined === attributes || undefined === attributes[attribute]) {
187+
if ( undefined === attributes || undefined === attributes[attribute] ) {
168188
return;
169189
}
170190

171191
let oldString: string = attributes[attribute].text || attributes[attribute];
172-
let newString: string = oldString.replace(args.pattern, () => {
173-
setReplacements((items) => items + 1);
192+
let newString: string = oldString.replace( args.pattern, () => {
193+
setReplacements( ( items ) => items + 1 );
174194
return args.text;
175-
});
195+
} );
176196

177-
if (newString === oldString) {
197+
if ( newString === oldString ) {
178198
return;
179199
}
180200

181201
const property = {};
182202
property[attribute] = newString;
183203

184-
(dispatch('core/block-editor') as any).updateBlockAttributes(clientId, property);
204+
if ( args.context ) {
205+
( dispatch( 'core/block-editor' ) as any )
206+
.updateBlockAttributes( clientId, property );
207+
}
185208

186209
// Handle edge-case ('value') with Pullquotes.
187-
if (attributes.value) {
188-
(dispatch('core/block-editor') as any)
189-
.updateBlockAttributes(clientId, { value: newString });
190-
setReplacements((items) => items + 1);
210+
if ( attributes.value ) {
211+
if ( args.context ) {
212+
( dispatch('core/block-editor' ) as any )
213+
.updateBlockAttributes( clientId, { value: newString } );
214+
}
215+
setReplacements( ( items ) => items + 1 );
191216
}
192217
}
193218

@@ -201,7 +226,7 @@ const SearchReplaceForBlockEditor = (): JSX.Element => {
201226
*
202227
* @returns {void}
203228
*/
204-
useEffect(() => {
229+
useEffect( () => {
205230
const editor = getBlockEditorIframe();
206231

207232
editor.addEventListener(
@@ -213,48 +238,48 @@ const SearchReplaceForBlockEditor = (): JSX.Element => {
213238
'selectionchange', handleSelection
214239
);
215240
};
216-
}, []);
241+
}, [] );
217242

218243
return (
219244
<>
220-
<Shortcut onKeyDown={openModal} />
221-
<Tooltip text={__('Search & Replace', 'search-replace-for-block-editor')}>
245+
<Shortcut onKeyDown={ openModal } />
246+
<Tooltip text={ __( 'Search & Replace', 'search-replace-for-block-editor' ) }>
222247
<Button
223248
icon={ search }
224-
label={__('Search & Replace', 'search-replace-for-block-editor')}
225-
onClick={openModal}
249+
label={ __( 'Search & Replace', 'search-replace-for-block-editor' ) }
250+
onClick={ openModal }
226251
/>
227252
</Tooltip>
228253
{
229254
isModalVisible && (
230255
<Modal
231-
title={__('Search & Replace', 'search-replace-for-block-editor')}
232-
onRequestClose={closeModal}
256+
title={ __( 'Search & Replace', 'search-replace-for-block-editor' ) }
257+
onRequestClose={ closeModal }
233258
className="search-replace-modal"
234259
>
235260
<div id="search-replace-modal__text-group">
236261
<TextControl
237262
type="text"
238-
label={__('Search')}
239-
value={searchInput}
240-
onChange={(value) => setSearchInput(value)}
263+
label={ __( 'Search' ) }
264+
value={ searchInput }
265+
onChange={ ( value ) => setSearchInput( value ) }
241266
placeholder="Lorem ipsum..."
242267
__nextHasNoMarginBottom
243268
/>
244269
<TextControl
245270
type="text"
246-
label={__('Replace')}
247-
value={replaceInput}
248-
onChange={(value) => setReplaceInput(value)}
271+
label={ __( 'Replace' ) }
272+
value={ replaceInput }
273+
onChange={ ( value ) => setReplaceInput( value ) }
249274
__nextHasNoMarginBottom
250275
/>
251276
</div>
252277

253278
<div id="search-replace-modal__toggle">
254279
<ToggleControl
255-
label={__('Match Case | Expression', 'search-replace-for-block-editor')}
256-
checked={caseSensitive}
257-
onChange={handleCaseSensitive}
280+
label={ __( 'Match Case | Expression', 'search-replace-for-block-editor' ) }
281+
checked={ caseSensitive }
282+
onChange={ handleCaseSensitive }
258283
__nextHasNoMarginBottom
259284
/>
260285
</div>
@@ -263,7 +288,15 @@ const SearchReplaceForBlockEditor = (): JSX.Element => {
263288
replacements ? (
264289
<div id="search-replace-modal__notification">
265290
<p>
266-
<strong>{replacements}</strong> {__('item(s) replaced successfully', 'search-replace-for-block-editor')}.
291+
{ context ? (
292+
<>
293+
<strong>{ replacements }</strong> { __( 'item(s) replaced successfully', 'search-replace-for-block-editor' ) }.
294+
</>
295+
) : (
296+
<>
297+
<strong>{ replacements }</strong> { __( 'item(s) found', 'search-replace-for-block-editor' ) }.
298+
</>
299+
)}
267300
</p>
268301
</div>
269302
) : ''
@@ -272,15 +305,15 @@ const SearchReplaceForBlockEditor = (): JSX.Element => {
272305
<div id="search-replace-modal__button-group">
273306
<Button
274307
variant="primary"
275-
onClick={replace}
308+
onClick={ () => replace( true ) }
276309
>
277-
{__('Replace')}
310+
{ __( 'Replace' ) }
278311
</Button>
279312
<Button
280313
variant="secondary"
281-
onClick={closeModal}
314+
onClick={ closeModal }
282315
>
283-
{__('Done')}
316+
{ __( 'Done' ) }
284317
</Button>
285318
</div>
286319
</Modal>

0 commit comments

Comments
 (0)