/** * Search and Replace Block Editor - Final Fix * Version: 8.8.0 * Author: Wiz Consults * Date: 2025-06-15 17:00:00 UTC * User: The Wiz * * 🎯 FINAL FIX: Reverted to the reliable 'editPost' method to apply content changes, fixing the replacement failure. 🎯 */ (function() { 'use strict'; // Prevent multiple initializations if (window.srbeInitialized) { return; } window.srbeInitialized = true; const { registerPlugin } = wp.plugins; const { PluginDocumentSettingPanel } = wp.editPost; const { useState, useEffect, useRef, createElement: el } = wp.element; const { Button, TextControl, CheckboxControl, Notice, Spinner, PanelRow, Card, CardHeader, CardBody, Flex, FlexItem } = wp.components; const { useSelect, useDispatch } = wp.data; /** * Main Search Replace Panel Component */ function SearchReplacePanel() { const [searchTerm, setSearchTerm] = useState(''); const [replaceTerm, setReplaceTerm] = useState(''); const [caseSensitive, setCaseSensitive] = useState(false); const [wholeWords, setWholeWords] = useState(false); const [matches, setMatches] = useState([]); const [isSearching, setIsSearching] = useState(false); const [isReplacing, setIsReplacing] = useState(false); const [isQuickReplacing, setIsQuickReplacing] = useState(false); const [notice, setNotice] = useState(null); const searchInputRef = useRef(null); const debounceTimeoutRef = useRef(null); const postId = useSelect(select => select('core/editor').getCurrentPostId(), []); const { editPost } = useDispatch('core/editor'); // Use editPost for updating content // Auto-focus search input on mount useEffect(() => { setTimeout(() => { if (searchInputRef.current) { searchInputRef.current.focus(); } }, 300); }, []); // Debounced search useEffect(() => { clearTimeout(debounceTimeoutRef.current); if (searchTerm && searchTerm.length > 1) { // Trigger search on 2+ characters debounceTimeoutRef.current = setTimeout(() => performSearch(), 500); } else { setMatches([]); if (notice && notice.message.includes('matches found')) { setNotice(null); } } return () => clearTimeout(debounceTimeoutRef.current); }, [searchTerm, caseSensitive, wholeWords]); function makeAjaxRequest(action, data) { return new Promise((resolve, reject) => { const formData = new FormData(); formData.append('action', action); formData.append('nonce', srbeData.nonce); Object.keys(data).forEach(key => { const value = data[key]; if (typeof value !== 'undefined' && value !== null) { formData.append(key, value.toString()); } }); fetch(srbeData.ajaxUrl, { method: 'POST', body: formData, }) .then(response => { if (!response.ok) throw new Error(`Network error: ${response.statusText}`); return response.json(); }) .then(result => { if (result.success) { resolve(result.data); } else { reject(new Error(result.data.message || 'An unknown server error occurred.')); } }) .catch(error => reject(error)); }); } function performSearch() { if (!searchTerm) return; setIsSearching(true); setNotice(null); makeAjaxRequest('srbe_search_content', { postId, searchTerm, caseSensitive, wholeWords }) .then(result => { setMatches(result.matches || []); setNotice({ type: result.count > 0 ? 'success' : 'info', message: `${result.count} matches found` }); }) .catch(error => setNotice({ type: 'error', message: `Search error: ${error.message}` })) .finally(() => setIsSearching(false)); } function handleReplacement(replacementFunction) { replacementFunction() .then(result => { if (typeof editPost === 'function' && result.newContent) { editPost({ content: result.newContent }); setNotice({ type: 'success', message: `${result.replacements} replacements made successfully!` }); setTimeout(clearForm, 2500); } else { throw new Error("Could not update editor content."); } }) .catch(error => setNotice({ type: 'error', message: `Replace error: ${error.message}` })); } function performReplace() { if (!searchTerm || matches.length === 0) return; setIsReplacing(true); setNotice(null); handleReplacement(() => makeAjaxRequest('srbe_replace_content', { postId, searchTerm, replaceTerm, caseSensitive, wholeWords }) ).finally(() => setIsReplacing(false)); } function performQuickEmDashReplace() { setIsQuickReplacing(true); setNotice(null); handleReplacement(() => makeAjaxRequest('srbe_quick_replace_em_dash', { postId }) ).finally(() => setIsQuickReplacing(false)); } function clearForm() { setSearchTerm(''); setReplaceTerm(''); setCaseSensitive(false); setWholeWords(false); setMatches([]); setNotice(null); if (searchInputRef.current) { searchInputRef.current.focus(); } } return el( PluginDocumentSettingPanel, { name: 'search-replace-panel-final', title: srbeData.strings.panelTitle, icon: 'search', className: 'srbe-panel' }, el(PanelRow, null, el(Card, { className: 'srbe-quick-replace-card' }, el(CardHeader, null, el('h4', { className: 'srbe-quick-title' }, srbeData.strings.quickReplaceTitle)), el(CardBody, null, el('div', { className: 'srbe-quick-actions' }, el(Button, { isSecondary: true, onClick: performQuickEmDashReplace, disabled: isQuickReplacing, className: 'srbe-quick-em-dash-btn' }, isQuickReplacing ? el(Spinner) : srbeData.strings.quickEmDashButton ), el('p', { className: 'srbe-quick-help' }, srbeData.strings.quickEmDashHelp) ) ) ) ), notice && el(PanelRow, null, el(Notice, { status: notice.type, isDismissible: true, onRemove: () => setNotice(null), className: 'srbe-notice' }, notice.message)), el(PanelRow, null, el(TextControl, { label: srbeData.strings.searchLabel, value: searchTerm, onChange: setSearchTerm, ref: searchInputRef })), el(PanelRow, null, el(TextControl, { label: srbeData.strings.replaceLabel, value: replaceTerm, onChange: setReplaceTerm })), el(PanelRow, null, el('div', { className: 'srbe-options' }, el(CheckboxControl, { label: srbeData.strings.caseSensitive, checked: caseSensitive, onChange: setCaseSensitive, className: 'srbe-checkbox' }), el(CheckboxControl, { label: srbeData.strings.wholeWords, checked: wholeWords, onChange: setWholeWords, className: 'srbe-checkbox' }) ) ), isSearching && el(PanelRow, null, el('div', { className: 'srbe-searching' }, el(Spinner), 'Searching...')), !isSearching && matches.length > 0 && el(PanelRow, null, el(Card, { className: 'srbe-matches-card' }, el(CardHeader, null, el('h4', { className: 'srbe-matches-title' }, `${matches.length} matches found`)), el(CardBody, null, el('div', { className: 'srbe-matches-list' }, matches.slice(0, 5).map((match, index) => el('div', { key: index, className: 'srbe-match-item' }, `"${match.text}"`)), matches.length > 5 && el('div', { className: 'srbe-more-matches' }, `... and ${matches.length - 5} more`) ) ) ) ), el(PanelRow, null, el(Flex, { className: 'srbe-actions', direction: 'column', gap: 2 }, el(FlexItem, null, el(Button, { isPrimary: true, onClick: performReplace, disabled: !searchTerm || matches.length === 0 || isReplacing, className: 'srbe-replace-btn' }, isReplacing ? el(Spinner) : srbeData.strings.replaceAllButton )), el(FlexItem, null, el(Button, { isSecondary: true, onClick: clearForm, disabled: isReplacing, className: 'srbe-clear-btn' }, srbeData.strings.clearButton)) ) ) ); } registerPlugin('search-replace-block-editor-final', { render: SearchReplacePanel, icon: 'search' }); })(); Page not found | DigitrendZ