Skip to content

Commit cd303c7

Browse files
committed
Merge branch 'release-1.10.0' into test/update-e2e-tests
2 parents 5a57074 + 281aebe commit cd303c7

File tree

7 files changed

+95
-12
lines changed

7 files changed

+95
-12
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* Feat: Add Plugin options page.
77
* Feat: Add Shortcut command (CMD + F).
88
* Feat: Add custom hooks: `afterSearchReplace`, `excludedPostTypes`, `regexPattern`.
9+
* Fix: Make default search literal & regex opt-in.
910
* Refactor: Use `replaceInput` in place of repeated instances of `text`.
1011
* Test: Add e2e tests for plugin codebase.
1112
* Tested up to WP 6.9.

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
# search-and-replace
1+
# search-replace-for-block-editor
22
Search and Replace text within the Block Editor quickly and easily.
33

4-
<img width="446" alt="search-and-replace" src="https://github.com/badasswp/search-and-replace/assets/149586343/c3febf99-e9db-4b7b-82fd-c01e5428123a">
4+
<img width="446" alt="search-replace-for-block-editor" src="https://github.com/badasswp/search-and-replace/assets/149586343/c3febf99-e9db-4b7b-82fd-c01e5428123a">
55

66
## Download
77

88
Download from [WordPress plugin repository](https://wordpress.org/plugins/search-replace-for-block-editor/).
99

10-
You can also get the latest version from any of our [release tags](https://github.com/badasswp/search-and-replace/releases).
10+
You can also get the latest version from any of our [release tags](https://github.com/badasswp/search-replace-for-block-editor/releases).
1111

1212
## Why Search and Replace for Block Editor?
1313

1414
This plugin brings the familiar __Search and Replace__ functionality that PC users have grown accustomed to while using __Microsoft Word__ and __Google Docs__ to the Block Editor.
1515

1616
Now you can easily search and replace text right in the Block Editor. Its easy and does exactly what it says. You can also match the text case using the 'Match Case | Expression' toggle.
1717

18-
https://github.com/badasswp/search-and-replace/assets/149586343/d4acfab3-338b-434f-b09c-769df9331095
18+
https://github.com/badasswp/search-replace-for-block-editor/assets/149586343/d4acfab3-338b-434f-b09c-769df9331095
1919

2020
### Hooks
2121

readme.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ You can also <strong>select text</strong> on your Block Editor and <strong>use t
5151

5252
The Search & Replace for Block Editor plugin is built to work right out of the box. Simply install, activate and start using.
5353

54-
Want to add your personal touch? All of our documentation can be found [here](https://github.com/badasswp/search-and-replace). You can override the plugin's behaviour with custom logic of your own using [hooks](https://github.com/badasswp/search-and-replace?tab=readme-ov-file#hooks).
54+
Want to add your personal touch? All of our documentation can be found [here](https://github.com/badasswp/search-replace-for-block-editor). You can override the plugin's behaviour with custom logic of your own using [hooks](https://github.com/badasswp/search-replace-for-block-editor?tab=readme-ov-file#hooks).
5555

5656
== Screenshots ==
5757

@@ -69,6 +69,7 @@ Want to add your personal touch? All of our documentation can be found [here](ht
6969
* Feat: Add Plugin options page.
7070
* Feat: Add Shortcut command (CMD + F).
7171
* Feat: Add custom hooks: `afterSearchReplace`, `excludedPostTypes`, `regexPattern`.
72+
* Fix: Make default search literal & regex opt-in.
7273
* Refactor: Use `replaceInput` in place of repeated instances of `text`.
7374
* Test: Add e2e tests for plugin codebase.
7475
* Tested up to WP 6.9.
@@ -184,6 +185,6 @@ Want to add your personal touch? All of our documentation can be found [here](ht
184185

185186
== Contribute ==
186187

187-
If you'd like to contribute to the development of this plugin, you can find it on [GitHub](https://github.com/badasswp/search-and-replace).
188+
If you'd like to contribute to the development of this plugin, you can find it on [GitHub](https://github.com/badasswp/search-replace-for-block-editor).
188189

189190
To build, clone repo and run `npm install && npm run build`

src/core/app.tsx

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import {
1313

1414
import { Shortcut } from './shortcut';
1515
import {
16+
getPattern,
17+
escapeRegex,
1618
getAllowedBlocks,
1719
getBlockEditorIframe,
1820
ifIsCaseSensitiveBasedOnFilter,
@@ -169,13 +171,27 @@ const SearchReplaceForBlockEditor = (): JSX.Element => {
169171
}
170172

171173
// Prepare raw string pattern.
172-
const rawPattern = `(?<!<[^>]*)${ searchInput }(?<![^>]*<)`;
174+
const rawPattern = getPattern(
175+
isRegexExpression ? searchInput : escapeRegex( searchInput )
176+
);
177+
178+
// Is Search case sensitive.
179+
const isSearchCaseSensitive =
180+
ifIsCaseSensitiveBasedOnFilter() || isCaseSensitive ? 'g' : 'gi';
181+
182+
// Define pattern.
183+
let regexPattern: RegExp;
173184

174185
// Get Regex search pattern.
175-
const regexPattern: RegExp = new RegExp(
176-
rawPattern,
177-
ifIsCaseSensitiveBasedOnFilter() || isCaseSensitive ? 'g' : 'gi'
178-
);
186+
try {
187+
regexPattern = new RegExp( rawPattern, isSearchCaseSensitive );
188+
} catch ( error ) {
189+
// fallback to non-regex pattern.
190+
regexPattern = new RegExp(
191+
getPattern( escapeRegex( searchInput ) ),
192+
isSearchCaseSensitive
193+
);
194+
}
179195

180196
/**
181197
* Filter the way we set the pattern, let users

src/core/filters.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ addFilter(
7373
);
7474

7575
return {
76-
newAttr: JSON.parse( tableString ),
76+
newAttr: JSON.parse( tableString || '{}' ),
7777
isChanged: tableString !== JSON.stringify( oldAttr ),
7878
};
7979

src/core/utils.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,3 +397,34 @@ export const isAllowedForPostType = (): boolean => {
397397

398398
return true;
399399
};
400+
401+
/**
402+
* Escape user input for safe
403+
* literal RegExp usage.
404+
*
405+
* @since 1.10.0
406+
*
407+
* @param {string} value Raw user input.
408+
* @return {string} Escaped input.
409+
*/
410+
export const escapeRegex = ( value: string ): string => {
411+
if ( typeof value !== 'string' ) {
412+
return '';
413+
}
414+
415+
return value.replace( /[.*+?^${}()|[\]\\]/g, '\\$&' );
416+
};
417+
418+
/**
419+
* Get Search Pattern.
420+
*
421+
* This function returns a string pattern
422+
* that targets only texts within valid HTML markup.
423+
*
424+
* @since 1.10.0
425+
*
426+
* @param {string} searchText Search Text.
427+
* @return {string} Search Pattern.
428+
*/
429+
export const getPattern = ( searchText: string ): string =>
430+
`(?<!<[^>]*)${ searchText }(?<![^>]*<)`;

tests/unit/js/utils.test.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,37 @@ describe( 'getShortcutEvent', () => {
391391
expect( shortcutEvent ).toBeInstanceOf( KeyboardEvent );
392392
} );
393393
} );
394+
395+
describe( 'escapeRegex', () => {
396+
beforeEach( () => {
397+
jest.resetModules();
398+
} );
399+
400+
it( 'escapeRegex escapes regex metacharacters', () => {
401+
const { escapeRegex } = require( '../../../src/core/utils' );
402+
403+
const escaped = escapeRegex( 'a.b+c*^$()[]{}|\\' );
404+
405+
expect( escaped ).toBe( 'a\\.b\\+c\\*\\^\\$\\(\\)\\[\\]\\{\\}\\|\\\\' );
406+
} );
407+
408+
it( 'escapeRegex leaves plain text unchanged', () => {
409+
const { escapeRegex } = require( '../../../src/core/utils' );
410+
411+
const escaped = escapeRegex( 'plain text' );
412+
413+
expect( escaped ).toBe( 'plain text' );
414+
} );
415+
416+
it( 'escapeRegex returns empty string for non-string inputs', () => {
417+
const { escapeRegex } = require( '../../../src/core/utils' );
418+
419+
expect( escapeRegex( 123 ) ).toBe( '' );
420+
} );
421+
422+
it( 'escapeRegex returns empty string for empty input', () => {
423+
const { escapeRegex } = require( '../../../src/core/utils' );
424+
425+
expect( escapeRegex( '' ) ).toBe( '' );
426+
} );
427+
} );

0 commit comments

Comments
 (0)