Files
wp-agentic-writer/MIGRATION_GUIDE.md
Dwindi Ramadhana 690991c526 refactor: Cleanup git state - commit all staged changes
Major refactoring cleanup:
- Add new controller architecture (class-controller-*.php)
- Add new settings-v2 UI (views/settings-v2/)
- Add new CSS architecture (agentic-sidebar.css, tokens)
- Add esbuild build pipeline (scripts/build.js, package.json)
- Add composer dependencies (vendor/)
- Add frontend src directory (assets/js/src/index.jsx)
- Add documentation files
- Remove old/obsolete files (class-settings.php, old CSS)

This commits all pending changes from previous refactoring efforts.
2026-06-17 05:27:58 +07:00

346 lines
8.3 KiB
Markdown

# WP Agentic Writer - Migration Guide
**Source:** `assets/js/sidebar.js` (12,363 lines)
**Goal:** 1:1 mechanical translation
---
## The Migration is Mechanical
1. Copy lines X-Y from `sidebar.js`
2. Convert `wp.element.createElement()` to JSX
3. Done
---
## JSX Conversion Rules
```jsx
// sidebar.js (verbatim copy)
wp.element.createElement('div', {
className: 'wpaw-status-icon-btn',
onClick: handleClick,
style: { display: 'flex', alignItems: 'center' }
}, 'text');
// Convert to JSX
<div
className="wpaw-status-icon-btn"
onClick={handleClick}
style={{ display: 'flex', alignItems: 'center' }}
>
text
</div>
```
| sidebar.js | JSX |
|-----------|-----|
| `{ key: value }` | `{ value }` |
| `{ className: 'foo' }` | `className="foo"` |
| `{ style: { x: y } }` | `style={{ x: y }}` |
| `null` children | `null` |
---
## Phase 1: ENTRY POINT
### `src/index.jsx` (NEW)
```jsx
import { createElement } from "@wordpress/element";
import { registerPlugin } from "@wordpress/plugins";
import { PluginSidebar, PluginSidebarMoreMenuItem } from "@wordpress/edit-post";
import { useSelect } from "@wordpress/data";
import { AgenticWriterSidebar } from "./components/Sidebar";
const pluginIcon = createElement("img", {
src: (window.wpAgenticWriter?.pluginUrl || "") + "/assets/img/icon.svg",
alt: "WP Agentic Writer",
style: { width: "20px", height: "20px" },
});
function WPAWPlugin() {
const postId = useSelect(
(select) => select("core/editor")?.getCurrentPostId() || 0,
[]
);
return createElement(
createElement.Fragment,
null,
createElement(PluginSidebarMoreMenuItem, {
target: "wp-agentic-writer",
icon: pluginIcon,
}, "WP Agentic Writer"),
createElement(PluginSidebar, {
name: "wp-agentic-writer",
title: "WP Agentic Writer",
icon: pluginIcon,
}, createElement(AgenticWriterSidebar, { postId }))
);
}
registerPlugin("wp-agentic-writer", {
icon: pluginIcon,
render: WPAWPlugin,
});
```
---
## Phase 2: MAIN COMPONENT (Keep as Monolith First)
### `src/components/Sidebar.jsx`
**Lines from sidebar.js: L38 - L12363**
Copy the entire `AgenticWriterSidebar` component verbatim, then convert createElement to JSX.
---
## Phase 3: Extract Helpers (Pure Functions)
After main component works, extract these as standalone modules:
### `src/helpers/logging.js`
**Lines: L17-136**
- `formatAiErrorMessage()`
### `src/helpers/api.js`
**Lines: L380-490, L511-538, L540-549, L1195-1562, L1782-1837, L1890-2024, L2074-2207, L2301-2397, L2398-2514, L3633-3696**
Functions:
- `savePostConfig()` L402-447
- `saveWritingState()` L511-538
- `persistWritingStatePatch()` L540-549
- `runSeoAudit()` L1195-1268
- `generateMetaDescription()` L1460-1562
- `persistSessionMessages()` L1782-1837
- `acquireSessionLock()` L1890-1925
- `releaseSessionLock()` L1927-1946
- `loadChatHistory()` L2074-2207
- `loadPostSessions()` L2301-2397
- `openSessionById()` L2398-2514
- `loadSectionBlocks()` L3633-3673
- `saveSectionBlocks()` L3674-3696
### `src/helpers/session.js`
**Lines: L1640-1753, L1755-1883, L2043-2207, L2301-2514, L8830-9002**
Functions:
- `updateSnapshot()` L1640-1648
- `sanitizeMessagesForStorage()` L1717-1753
- `hydrateSessionStateFromMessages()` L1755-1780
- `flushOnUnload()` L1847-1883
- `loadChatHistory()` L2074-2207
- `loadPostSessions()` L2301-2397
- `openSessionById()` L2398-2514
- `startNewConversation()` L8830-8915
- `deleteConversationSession()` L8917-8958
- `getSessionDisplayTitle()` L8960-8983
### `src/helpers/editor.js`
**Lines: L753-811, L843-968, L1020-1028**
Functions:
- `captureEditorSnapshot()` L753-763
- `pushUndoSnapshot()` L765-774
- `undoLastAiOperation()` L776-811
- `blockEditorDispatch()` L843
- `shouldBlockEditorInput()` L927-943
- `keydownHandler()` L945-960
- `blockMutationEvent()` L962-968
- `toTextValue()` L1020-1028
### `src/helpers/timeline.js`
**Lines: L586-673**
Functions:
- `updateOrCreateTimelineEntry()` L637-659
- `addActivityTimeline()` L660-673
### `src/helpers/operations.js`
**Lines: L674-750**
Functions:
- `setActiveOperationState()` L674-682
- `beginAgentOperation()` L683-691
- `finishAgentOperation()` L692-700
- `markActiveOperationStopping()` L701-721
- `requestRefineAllConfirmation()` L729-742
- `resolveRefineAllConfirmation()` L743-750
### `src/helpers/keywords.js`
**Lines: L1072-1157, L4097-4155**
Functions:
- `handleFocusKeywordChange()` L1072-1078
- `handleKeywordSelect()` L1080-1087
- `extractFocusKeywordSuggestions()` L1090-1135
- `addFocusKeywordSuggestions()` L1154-1157
- `suggestKeywordsFromPlan()` L4097-4155
### `src/helpers/seo.js`
**Lines: L1195-1347**
Functions:
- `runSeoAudit()` L1195-1268
- `buildSeoAuditFixInstruction()` L1270-1308
- `getSeoFixKey()` L1309-1310
- `buildAuditRefinementContext()` L1329-1347
### `src/helpers/refinement.js`
**Lines: L1349-1458, L2570-2689, L4954-5279**
Functions:
- `handleSeoAuditFix()` L1349-1458
- `handleTitleRefinement()` L2570-2689
- `reformatBlocks()` L4954-5056
- `applyEditPlan()` L5143-5240
- `cancelEditPlan()` L5241-5279
### `src/helpers/blocks.js`
**Lines: L4871-5050, L5363-5420**
Functions:
- `createBlocksFromSerialized()` L4871-4953
- `getRefineableBlocks()` L5363-5390
- `getListItemBlocks()` L5391-5420
### `src/helpers/blocks-context.js`
**Lines: L5443-5622**
Functions:
- `getBlockContentForContext()` L5443-5453
- `getHeadingContextForBlock()` L5454-5470
- `getNearbyParagraphContext()` L5471-5494
- `getContextFromMentions()` L5495-5503
- `selectLikelySlangBlocks()` L5521-5533
- `getAiSlopFindingsForBlock()` L5538-5589
- `buildContextBlocksForRefinement()` L5607-5622
- `buildRefinementDiagnosis()` L5623-5703
### `src/helpers/plan.js`
**Lines: L3474-3891, L4321-4767**
Functions:
- `createBlockFromPlan()` L3474-3534
- `normalizePlanActions()` L3535-3543
- `buildPlanPreviewItem()` L3544-3604
- `upsertSectionBlock()` L3612-3622
- `removeSectionBlock()` L3623-3632
- `findBestPlanSectionMatch()` L3744-3828
- `updatePlanSectionStatus()` L3829-3851
- `findSectionInsertIndex()` L3852-3891
- `executePlanFromCard()` L4321-4767
### `src/helpers/agent.js`
**Lines: L3907-4320**
Functions:
- `summarizeChatHistory()` L3907-3954
- `detectUserIntent()` L3957-4005
- `buildOptimizedContext()` L4008-4025
- `classifyAgentIntent()` L4222-4260
- `decideAgentAction()` L4261-4320
- `getPlanRuntimeSummary()` L4199-4218
### `src/helpers/mentions.js`
**Lines: L2516-2569, L5705-5797, L6454-6605, L6613-6757**
Functions:
- `resolveStreamTarget()` L2516-2526
- `normalizeMentionToken()` L2527-2536
- `extractMentionsFromText()` L2537-2550
- `resolveBlockMentions()` L5705-5797
- `getMentionOptions()` L6456-6578
- `handleInsertMention()` L6581-6605
- `insertMention()` L6702-6726
### `src/helpers/commands.js`
**Lines: L2688-2758**
Functions:
- `parseInsertCommand()` L2690-2712
- `getSlashOptions()` L2713-2747
- `getBlockIndex()` L2748-2758
### `src/helpers/chat.js`
**Lines: L6759-8054, L8057-8474**
Functions:
- `sendMessage()` L6759-8054 (the main chat function)
- `submitAnswers()` L8057-8474
### `src/helpers/markdown.js`
**Lines: L10007-10270**
Functions:
- `escapeHtml()` L10007-10014
- `inlineMarkdownToHtml()` L10015-10031
- `markdownToHtml()` L10032-10270
### `src/helpers/welcome.js`
**Lines: L1176-1192**
Functions:
- `handleWelcomeStart()` L1176-1192
### `src/helpers/retry.js`
**Lines: L3189-3257**
Functions:
- `retryLastGeneration()` L3189-3213
- `retryLastExecute()` L3214-3228
- `retryLastRefinement()` L3229-3257
---
## Phase 4: State Objects (Plain Objects, Not React State)
### `src/state/config.js`
**Lines: L163-222**
```js
const defaultPostConfig = {
article_length: 'medium',
language: 'auto',
tone: '',
audience: '',
experience_level: 'general',
include_images: true,
web_search: false,
default_mode: 'chat',
seo_focus_keyword: '',
focus_keyword: '',
seo_secondary_keywords: [],
seo_meta_description: '',
seo_enabled: false,
};
const applyProviderMetadata = (config, providerInfo) => { ... };
```
### `src/state/editor.js`
**Lines: L224-237**
```js
const isEditorLocked = false;
const isRefinementLocked = false;
const refiningBlockIds = [];
const refineAllConfirm = { isOpen: false, blockCount: 0, dontAskAgain: false };
```
---
## Extraction Order
1. [ ] Keep everything in `Sidebar.jsx` first
2. [ ] Verify build works
3. [ ] Then extract helpers one by one
---
## Verification
- [ ] Build compiles
- [ ] Plugin loads in Gutenberg
- [ ] All buttons work
- [ ] No console errors