14 KiB
WP Agentic Writer - Defect Report
Date: January 29, 2026
Reporter: Development Team
Testing Session: Image Generation Feature Integration
Executive Summary
After comprehensive flow tracing, 4 critical defects and multiple integration gaps were identified. The image generation backend is functional, but frontend integration is incomplete.
Defect #1: "Create Outline Now" Button - Mode Timing Issue
Symptom
Clicking "Create Outline Now" only prefills English message and changes mode. User expects automatic outline generation.
Root Cause Analysis
File: @/Users/dwindown/Local Sites/bricks/app/public/wp-content/plugins/wp-agentic-writer/assets/js/sidebar.js:4432-4444
onClick: async () => {
setAgentMode('planning'); // Line 4434
const outlineMessage = 'Create an outline based on our discussion';
setInput(outlineMessage); // Line 4438
setTimeout(() => {
sendMessage(); // Line 4443
}, 100);
}
Problem: React's setState is asynchronous. When sendMessage() is called 100ms later:
agentModestate may not have updated yet in the closureinputstate may not have updated yet- The
sendMessage()function reads stale state values
Flow Trace:
User clicks "Create Outline Now"
↓
setAgentMode('planning') called - state update QUEUED
↓
setInput('Create an outline...') called - state update QUEUED
↓
100ms timeout fires
↓
sendMessage() runs with STALE state (agentMode might still be 'chat')
↓
Line 3084: if (agentMode === 'chat' && !hasMentions) → TRUE (stale state!)
↓
Chat API called instead of generate-plan
Expected Behavior
Button should directly trigger planning flow with proper mode context, bypassing React state timing issues.
Recommended Fix
Pass mode and message directly to sendMessage, not relying on state:
onClick: async () => {
setAgentMode('planning');
const outlineMessage = 'Create an outline based on our discussion';
// Call API directly instead of relying on state
await triggerPlanGeneration(outlineMessage, {
mode: 'planning',
autoTrigger: true
});
}
Or use a dedicated function that doesn't depend on agentMode state.
Defect #2: Clarity Check Not Triggered for Planning Mode
Symptom
Cost tracking shows clarity_check was never called when using "Create Outline Now".
Root Cause Analysis
Flow Trace through sendMessage():
Line 3049: shouldShowPlan = (agentMode === 'planning')
If agentMode is still 'chat' (due to Defect #1):
Line 3084: if (agentMode === 'chat' && !hasMentions) → TRUE
→ Enters CHAT flow (NOT planning flow)
→ Calls /chat API
→ Clarity check is NOT in this branch
If agentMode correctly updated to 'planning':
Line 3077: if (agentMode === 'planning' && !hasMentions && currentPlanRef.current)
→ FALSE because currentPlanRef.current is null (no existing plan)
→ Falls through
Line 3084: if (agentMode === 'chat' && !hasMentions)
→ FALSE because agentMode is 'planning'
→ Falls through
Line 3225: if (!hasMentions && refineableBlocks.length > 0)
→ FALSE if no content exists yet
→ Falls through
Line 3262: if (!hasMentions)
→ TRUE
→ Enters clarity check + generate-plan flow ✓
Conclusion: The clarity check SHOULD work if agentMode is correctly set to 'planning'. The root cause is Defect #1 - the timing issue with state updates.
Recommended Fix
Fix Defect #1, which will automatically fix this defect.
Defect #3: Numbered List with Bold Title + Bullets - Incorrect Conversion
Symptom
Markdown like:
1. **Jadikan AI sebagai Asisten**
- Gunakan untuk mempercepat pekerjaan
- Manfaatkan sebagai sumber referensi
1. **Terus Belajar dan Beradaptasi**
- Ikuti perkembangan teknologi AI
Renders as:
- Ordered list with item "1. Jadikan AI sebagai Asisten"
- Separate unordered list with bullets
- New ordered list restarting at "1." for next section
User sees "1. 1. 1." instead of "1. 2. 3."
Root Cause Analysis
File: @/Users/dwindown/Local Sites/bricks/app/public/wp-content/plugins/wp-agentic-writer/includes/class-markdown-parser.php:261-274
// Handle ordered lists.
if ( preg_match( '/^\d+\.\s+(.+)$/', $trimmed, $matches ) ) {
// ... creates ordered list item
$list_items[] = self::parse_inline_markdown( $matches[1] );
continue;
}
Problem: The parser correctly identifies numbered items, but when an empty line or different list type appears, it flushes the current list. Each section becomes a separate ordered list block, each starting at 1.
The merge_consecutive_ordered_lists() function at line 674 only merges consecutive ordered lists. But the structure has:
ordered list (1 item)
unordered list (bullets)
ordered list (1 item) ← NOT consecutive, won't merge
unordered list (bullets)
Expected Behavior (per user request)
For numbered items with bold titles followed by bullet sub-content:
1. **Bold Title** → core/paragraph with "1. <strong>Bold Title</strong>"
- bullet item → core/list (unordered)
- bullet item
2. **Next Title** → core/paragraph with "2. <strong>Next Title</strong>"
- more bullets → core/list (unordered)
This structure:
- Prevents the "1. 1. 1." numbering issue
- Creates logical grouping
- Maintains proper section hierarchy
Recommended Fix
Option A: Detect pattern ^\d+\.\s+\*\*(.+)\*\*$ (numbered + bold) and treat as paragraph:
// Handle numbered items with bold title (treat as paragraph, not list)
if ( preg_match( '/^(\d+)\.\s+\*\*(.+)\*\*\s*$/', $trimmed, $matches ) ) {
// Create paragraph with manual numbering
$content = $matches[1] . '. <strong>' . self::parse_inline_markdown( $matches[2] ) . '</strong>';
$blocks[] = self::create_paragraph_block( $content );
continue;
}
Option B: Pre-process markdown to normalize this pattern before parsing.
Defect #4: Image Blocks Missing data-agent-image-id Attribute
Symptom
Generated image blocks have no way to:
- Confirm agent assigned an image ID
- View the recommended prompt/alt text
- Trigger image generation modal
- Connect to backend image recommendations
Root Cause Analysis
File: @/Users/dwindown/Local Sites/bricks/app/public/wp-content/plugins/wp-agentic-writer/includes/class-markdown-parser.php:644-664
private static function create_image_placeholder_block( $description ) {
$alt = trim( $description );
$attrs = array(
'id' => 0,
'url' => '',
'alt' => $alt,
'caption' => '',
'sizeSlug' => 'large',
'linkDestination' => 'none',
);
// ❌ MISSING: 'data-agent-image-id' => 'img_xxx'
The data-agent-image-id attribute is documented in:
IMAGE_GENERATION_IMPLEMENTATION_PLAN.mdIMAGE_GENERATION_README.mdimage-gen-flow.mdimage-modal.js(expects this attribute)
But NEVER implemented in the actual code!
Missing Integration Points
- Markdown Parser: Must generate unique
agent_image_idand add to block attrs - Backend Storage: Must save recommendations with matching IDs to
wp_wpaw_imagestable - Block Toolbar: Must add "Generate Image" button for image blocks with this attribute
- Modal Trigger: Must open image modal after article generation or from toolbar
Recommended Fix
Step 1: Update create_image_placeholder_block():
private static function create_image_placeholder_block( $description, $image_index = 0 ) {
$alt = trim( $description );
$agent_image_id = 'img_' . uniqid(); // Or use index-based ID
$attrs = array(
'id' => 0,
'url' => '',
'alt' => $alt,
'caption' => '',
'sizeSlug' => 'large',
'linkDestination' => 'none',
'data-agent-image-id' => $agent_image_id,
);
// ...
}
Step 2: Track and return image IDs during article generation
Step 3: Register toolbar button for image blocks (see below)
Missing Integration #1: Image Block Toolbar Button
Current State
No "Generate Image" button exists in image block toolbar.
Required Implementation
File to create: Extend block-refine.js or create new block-image-generate.js
// Add toolbar button to core/image blocks with data-agent-image-id
const withImageGenerateToolbar = createHigherOrderComponent((BlockEdit) => {
return (props) => {
const { clientId } = props;
const block = useSelect(
(select) => select('core/block-editor').getBlock(clientId),
[clientId]
);
if (!block || block.name !== 'core/image') {
return wp.element.createElement(BlockEdit, props);
}
const agentImageId = block.attributes['data-agent-image-id'];
if (!agentImageId) {
return wp.element.createElement(BlockEdit, props);
}
const openImageModal = () => {
window.dispatchEvent(
new CustomEvent('wpaw:open-image-modal', {
detail: { agentImageId, blockId: clientId }
})
);
};
return wp.element.createElement(
wp.element.Fragment,
null,
wp.element.createElement(BlockEdit, props),
wp.element.createElement(
BlockControls,
null,
wp.element.createElement(
ToolbarGroup,
null,
wp.element.createElement(ToolbarButton, {
icon: 'format-image',
label: 'Generate AI Image',
onClick: openImageModal,
})
)
)
);
};
}, 'withImageGenerateToolbar');
addFilter(
'editor.BlockEdit',
'wp-agentic-writer/image-generate-toolbar',
withImageGenerateToolbar
);
Missing Integration #2: Image Modal Trigger After Article Generation
Current State
image-modal.js component exists but is never rendered/triggered.
Required Implementation
In sidebar.js, after article execution completes:
// After all sections are written and blocks inserted:
const checkForImagePlaceholders = () => {
const blocks = wp.data.select('core/block-editor').getBlocks();
const imagePlaceholders = blocks.filter(
block => block.name === 'core/image' &&
block.attributes['data-agent-image-id']
);
if (imagePlaceholders.length > 0) {
// Open image review modal
window.dispatchEvent(
new CustomEvent('wpaw:open-image-review-modal', {
detail: {
postId: postId,
imageCount: imagePlaceholders.length
}
})
);
}
};
In image-modal.js, listen for event:
useEffect(() => {
const handleOpenModal = (event) => {
setPostId(event.detail.postId);
setIsOpen(true);
loadRecommendations(event.detail.postId);
};
window.addEventListener('wpaw:open-image-review-modal', handleOpenModal);
return () => window.removeEventListener('wpaw:open-image-review-modal', handleOpenModal);
}, []);
Missing Integration #3: Backend Image ID Generation
Current State
[IMAGE: description] placeholders are converted to blocks, but:
- No unique ID generated
- No storage in
wp_wpaw_imagestable during article generation - No link between block and database record
Required Implementation
During article generation in class-gutenberg-sidebar.php:
- Parse
[IMAGE: ...]placeholders before block conversion - Generate unique
agent_image_idfor each - Store in
wp_wpaw_imagestable with post_id, prompt, alt_text - Pass image IDs to markdown parser for block attribute injection
// In handle_generate_article or handle_execute_plan:
$image_placeholders = [];
preg_match_all('/\[IMAGE:\s*(.+?)\]/i', $markdown_content, $matches);
foreach ($matches[1] as $index => $description) {
$agent_image_id = 'img_' . $post_id . '_' . ($index + 1);
$image_placeholders[] = [
'agent_image_id' => $agent_image_id,
'description' => $description,
];
// Save to database
$image_manager = WP_Agentic_Writer_Image_Manager::get_instance();
// ... save recommendation
}
// Convert markdown with image IDs
$blocks = WP_Agentic_Writer_Markdown_Parser::to_blocks($markdown_content, $image_placeholders);
Priority Matrix
| Defect | Severity | Impact | Fix Effort |
|---|---|---|---|
| #1 - Create Outline timing | High | Blocks main workflow | Low |
| #2 - Clarity check | High | Poor content quality | Depends on #1 |
| #3 - Numbered list | Medium | Visual formatting | Medium |
| #4 - Image IDs missing | Critical | Image feature broken | Medium |
| Toolbar button | Critical | No way to trigger images | Medium |
| Modal trigger | Critical | No user-facing image feature | Medium |
| Backend ID generation | Critical | No data persistence | Medium |
Recommended Fix Order
- Defect #1 - Fix timing issue (enables #2)
- Defect #4 + Backend ID generation - Core image functionality
- Toolbar button - User can trigger image generation
- Modal trigger - Automatic flow after article generation
- Defect #3 - Formatting improvement (lower priority)
Testing Checklist After Fixes
- Click "Create Outline Now" → Clarity quiz appears (if needed)
- Click "Create Outline Now" → Plan generated automatically
- Cost tracking shows
clarity_checkaction - Numbered + bold items render as paragraphs with manual numbering
- Image blocks have
data-agent-image-idattribute in inspector - Image blocks show "Generate AI Image" in toolbar
- After article generation, image modal opens automatically
- Can generate variants for each image placeholder
- Can select and commit variant to Media Library
- Block updates with real image after commit
Report Status: Complete
Next Steps: Implement fixes in priority order