π Translation: Translated from Korean.
10x Your Blog Content Productivity with AI: Complete Automation Workflow Revealed
Executive Summary
- Before: 2-3 hours per post (writing β conversion β upload β translation β SEO setup)
- After: 10 minutes with a single command (
blog publish post.md) - Core: Fully automated AI translation + SEO validation + WordPress publishing + language linking
- Results: 92% time savings, translation quality equal to or better than manual, maintaining 70-80 SEO scores
1. A Blogger’s Pain: The Inefficiency of Manual Workflows
What was your biggest challenge running a tech blog?
For me, it was “I want to focus on creating content, but the publishing process is too complex.”
Traditional Blog Publishing Process
1. Write in markdown (1 hour)
2. Capture and edit images (20 minutes)
3. Copy-paste in WordPress editor (10 minutes)
4. Upload images one by one (15 minutes)
5. Set categories/tags (5 minutes)
6. Optimize SEO title/description (10 minutes)
7. Translate to English (30 minutes)
8. Publish English post (10 minutes)
9. Link languages in Polylang (5 minutes)
Total time: 2 hours 45 minutes
The problem is “only step 1 out of 1-9 is actual creative work.”
The rest are all repetitive tasks. They can be automated.
2. The Solution: AI-Powered Complete Automation Workflow
This is the workflow I developed after 2 weeks of development.
New Workflow
# 1. Write markdown file (1 hour)
vi content/posts/ko/my-post.md
# 2. Single publish command (10 minutes - automatic)
blog publish content/posts/ko/my-post.md
# Automatic execution:
# β
Publish Korean WordPress post
# β
AI translation (Claude Code)
# β
Translation quality validation (8 steps)
# β
Publish English post
# β
Link languages in Polylang
# β
SEO score analysis and report
Total time: 1 hour 10 minutes (60% time savings)
Key Differentiators:
- Simultaneous Korean-English post publishing with one command
- AI translation reduces 30 minutes β 3 minutes (90% reduction)
- Automated quality validation prevents mistakes
- Complete elimination of repetitive tasks
3. 5 Core Automation Features
3.1 AI Automatic Translation (Claude Code)
Previous Problems:
- Google Translate: Mistranslation of technical terms, awkward sentences
- Manual translation: Time-consuming (30+ minutes per post)
- Professional translator: Cost burden (50,000+ KRW per post)
AI Translation Solution:
// packages/core/src/translator.ts
export async function translatePost(
koreanPath: string
): Promise<ParsedPost> {
// 1. Parse original
const original = await parseMarkdownFile(koreanPath);
// 2. Translate with Claude Code (preserve technical terms)
const translatedContent = await executeClaude(
`Translate this Korean tech blog post to English.
Preserve code blocks, technical terms, and markdown structure.`
);
// 3. Generate SEO-optimized title/description
const seoTitle = await generateSEOTitle(translatedContent); // β€60 chars
const seoExcerpt = await generateSEOExcerpt(translatedContent); // β€300 chars
return translatedPost;
}
Actual Translation Quality:
- Code blocks: 100% preserved (44 code blocks perfectly maintained)
- Technical terms: 95%+ accuracy (e.g., “μν¬νλ‘μ°” β “workflow”)
- Context understanding: Manual translation level (AI understands context)
- SEO optimization: Natural incorporation of English keywords
3.2 8-Step Quality Validation System
Why It’s Needed
AI translation isn’t perfect. Issues like missing code blocks, broken links, and missing SEO keywords can occur.
Validation Checklist:
// packages/core/src/validation.ts
export async function validateTranslation(
original: string,
translated: string
): Promise<ValidationResult> {
const issues: ValidationIssue[] = [];
// 1. Basic validation
if (!translated || translated.trim().length === 0) {
issues.push({ type: 'error', message: 'Empty content' });
}
// 2. Code block count match (``` count)
const originalBlocks = countCodeBlocks(original);
const translatedBlocks = countCodeBlocks(translated);
if (originalBlocks !== translatedBlocks) {
issues.push({ type: 'error', message: 'Code block mismatch' });
}
// 3. Line count validation (50-150% range)
const lineRatio = translatedLines / originalLines;
if (lineRatio < 0.5 || lineRatio > 1.5) {
issues.push({ type: 'error', message: 'Line count out of range' });
}
// 4. SEO keyword preservation (all tags keywords included)
const missingKeywords = checkKeywords(translated, original.tags);
if (missingKeywords.length > 0) {
issues.push({ type: 'warning', message: `Missing: ${missingKeywords}` });
}
// 5. Keyword density (0.5-2.5% recommended)
const density = calculateKeywordDensity(translated, original.tags);
if (density < 0.5 || density > 2.5) {
issues.push({ type: 'info', message: `Density: ${density}%` });
}
// 6. Title length (β€60 chars for SEO)
if (translated.title.length > 60) {
issues.push({ type: 'warning', message: 'Title too long' });
}
// 7. Link structure preservation
const linkDiff = countLinks(original) - countLinks(translated);
if (linkDiff !== 0) {
issues.push({ type: 'warning', message: 'Link count mismatch' });
}
// 8. Heading structure preservation (H1, H2 counts)
if (!validateHeadings(original, translated)) {
issues.push({ type: 'warning', message: 'Heading structure changed' });
}
return {
isValid: !issues.some(i => i.type === 'error'),
issues,
metrics: calculateMetrics(original, translated)
};
}
Validation Pass Criteria:
- 0 errors β Automatic publishing
- Only warnings β Automatic publishing (with report)
- 1+ errors β Publishing stopped (manual review)
Actual Results:
- Part 1 post: Validation passed (0 errors, 2 warnings)
- Part 2 post: Validation failed β Passed after fix (44 code blocks preserved)
- Part 3 post: Validation passed (SEO 80/100)
3.3 WordPress REST API Automatic Publishing
Previous Problems:
- Manual copy-paste in WordPress editor
- Selecting categories/tags one by one
- Uploading images individually
- SEO plugin configuration
Automation Solution:
// packages/core/src/wordpress.ts
export class WordPressClient {
async createPost(
metadata: PostMetadata,
content: string,
seoData?: SeoData
): Promise<number> {
const postData = {
title: metadata.title,
content: content, // Markdown β HTML converted
slug: metadata.slug,
excerpt: metadata.excerpt,
status: 'publish', // or 'draft'
lang: metadata.language, // 'ko' or 'en'
categories: await this.getCategoryIds(metadata.categories),
tags: await this.getTagIds(metadata.tags),
meta: {
// Rank Math SEO plugin fields
rank_math_title: seoData.meta.title,
rank_math_description: seoData.meta.description,
rank_math_focus_keyword: seoData.meta.keywords.join(', '),
}
};
const post = await this.wp.posts().create(postData);
return post.id; // Published post ID
}
}
Supported Features:
- β Automatic category creation (creates if not exists)
- β Automatic tag creation
- β Automatic SEO metadata setup (Rank Math compatible)
- β Publish/draft status selection
- β Automatic Polylang language code setup
3.4 Polylang Language Linking Automation
Previous Problem:
Polylang Free version doesn’t support REST API, requiring manual linking of Korean-English posts in WordPress admin.
Solution: Custom REST API Endpoint
WordPress plugin development:
// wordpress-plugin/polylang-rest-api-helper.php
add_action('rest_api_init', function () {
register_rest_route('polylang-helper/v1', '/link-translations', [
'methods' => 'POST',
'callback' => 'link_polylang_translations',
'permission_callback' => function() {
return current_user_can('edit_posts');
}
]);
});
function link_polylang_translations($request) {
$ko_post_id = $request->get_param('ko_post_id');
$en_post_id = $request->get_param('en_post_id');
// Bidirectional linking with Polylang functions
pll_set_post_language($ko_post_id, 'ko');
pll_set_post_language($en_post_id, 'en');
pll_save_post_translations([
'ko' => $ko_post_id,
'en' => $en_post_id,
]);
return new WP_REST_Response([
'success' => true,
'message' => 'Translation link created',
], 200);
}
Automatic CLI Invocation:
// packages/core/src/wordpress.ts
async linkTranslations(koPostId: number, enPostId: number) {
const response = await fetch(
`${this.config.url}/wp-json/polylang-helper/v1/link-translations`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + base64(username + ':' + password)
},
body: JSON.stringify({ ko_post_id: koPostId, en_post_id: enPostId })
}
);
console.log(`β
Language linking complete: Korean(${koPostId}) β English(${enPostId})`);
}
Actual Workflow:
# Single publish command
blog publish content/posts/ko/my-post.md
# Automatic execution:
# 1. Publish Korean post (ID: 124)
# 2. AI translation
# 3. Publish English post (ID: 131)
# 4. Polylang linking: 124 β 131 (automatic!)
3.5 SEO Automatic Optimization
SEO Score Calculation Logic:
// packages/core/src/seo.ts
export function analyzeSEO(
content: string,
metadata: PostMetadata
): SEOAnalysis {
let score = 0;
// 1. Keyword density (0.5-2.5% = 20 points)
const density = calculateKeywordDensity(content, metadata.tags);
if (density >= 0.5 && density <= 2.5) score += 20;
// 2. Title length (50-60 chars = 15 points)
if (metadata.title.length <= 60) score += 15;
// 3. Excerpt length (250-300 chars = 15 points)
if (metadata.excerpt.length >= 250 && metadata.excerpt.length <= 300) {
score += 15;
}
// 4. Section distribution (50%+ keyword-containing sections = 20 points)
const sectionCoverage = calculateSectionCoverage(content, metadata.tags);
if (sectionCoverage >= 0.5) score += 20;
// 5. Internal links (1+ = 10 points)
const internalLinks = countInternalLinks(content);
if (internalLinks > 0) score += 10;
// 6. Image alt text (all present = 10 points)
const imagesWithAlt = checkImageAltText(content);
if (imagesWithAlt) score += 10;
// 7. Meta tag completeness (10 points)
if (metadata.tags.length >= 3 && metadata.categories.length >= 1) {
score += 10;
}
return { score, details: [...] };
}
Actual SEO Scores:
- Part 1: 80/100 (keyword density 1.89%, section distribution 54%)
- Part 2: 70/100 (keyword density 0.28% – needs improvement)
- Part 3: 80/100 (optimized keyword density)
4. Measurable Results
4.1 Time Savings
| Task | Before | After | Savings |
|---|---|---|---|
| Markdown β HTML conversion | 10 min (manual) | 1 sec (auto) | 99% |
| Image upload | 15 min (one by one) | Planned | – |
| WordPress publishing | 10 min (copy-paste) | 5 sec (auto) | 99% |
| English translation | 30 min (manual) | 3 min (AI) | 90% |
| Language linking | 5 min (manual) | 2 sec (auto) | 99% |
| SEO setup | 10 min (manual) | Automatic | 100% |
| Total repetitive tasks | 1 hour 20 min | 10 min | 87% |
Actual Workflow Comparison:
- Before: Writing 1 hour + Repetitive tasks 1 hour 20 min = 2 hours 20 min
- After: Writing 1 hour + Automation 10 min = 1 hour 10 min
- Savings: 1 hour 10 min (50%)
4.2 Translation Quality
Quantitative Metrics:
- Code block preservation: 100% (44 β 44)
- Line count accuracy: 0% difference (perfect match)
- SEO keyword preservation: 95%+ (most keywords included)
- Title length: 51-58 chars (SEO optimal range)
Qualitative Assessment:
- Technical terms: Accurate (e.g., “μν¬νλ‘μ°” β “workflow”)
- Context understanding: Natural (AI comprehends context)
- Sentence structure: Native-level (Claude Code’s strength)
4.3 SEO Score Maintenance
- Korean average: 75/100
- English average: 78/100 (thanks to SEO title/description optimization)
- Score difference before/after automation: Nearly none
5. Tech Stack and Architecture
5.1 Tech Stack
| Layer | Technology | Role |
|---|---|---|
| CLI | Commander.js | Command interface |
| Translation | Claude Code API | AI translation engine |
| Validation | Custom TypeScript | Quality validation logic |
| Conversion | unified + remark | Markdown β HTML |
| WordPress | wpapi + REST API | Post publishing |
| Language linking | Custom PHP Plugin | Polylang automation |
5.2 Project Structure
blog/
βββ packages/
β βββ cli/ # Command interface
β β βββ src/
β β βββ commands/
β β βββ publish.ts
β βββ core/ # Core logic
β β βββ src/
β β βββ translator.ts # AI translation
β β βββ validation.ts # Quality validation
β β βββ wordpress.ts # WordPress API
β β βββ markdown.ts # Markdown parsing
β βββ shared/ # Shared types
β
βββ content/
β βββ posts/
β βββ ko/ # Korean posts
β βββ en/ # English posts (auto-generated)
β
βββ wordpress-plugin/
βββ polylang-rest-api-helper.php
5.3 Workflow Diagram
[Write Markdown File]
β
[blog publish command]
β
βββββββββββββββββββββββββββββ
β 1. Read and parse file β
β - gray-matter (frontmatter) β
β - unified (markdown β HTML) β
βββββββββββββ¬ββββββββββββββββ
β
βββββββββββββββββββββββββββββ
β 2. SEO analysis (Korean) β
β - Calculate keyword density β
β - Analyze section distribution β
β - Output score (70-80) β
βββββββββββββ¬ββββββββββββββββ
β
βββββββββββββββββββββββββββββ
β 3. Publish Korean to WordPress β
β - Call REST API β
β - Auto-create categories/tags β
β - Return: Post ID (124) β
βββββββββββββ¬ββββββββββββββββ
β
βββββββββββββββββββββββββββββ
β 4. AI Translation (Claude Code) β
β - Translate content (3 min) β
β - Generate SEO title (β€60 chars) β
β - Generate SEO excerpt (β€300 chars) β
β - Translate metadata β
βββββββββββββ¬ββββββββββββββββ
β
βββββββββββββββββββββββββββββ
β 5. Translation quality validation β
β - 8-step checklist β
β - Stop if errors β
β - Continue with warnings β
βββββββββββββ¬ββββββββββββββββ
β
βββββββββββββββββββββββββββββ
β 6. Publish English to WordPress β
β - Call REST API β
β - Return: Post ID (131) β
βββββββββββββ¬ββββββββββββββββ
β
βββββββββββββββββββββββββββββ
β 7. Link languages in Polylang β
β - Call Custom Plugin API β
β - Korean(124) β English(131) β
βββββββββββββ¬ββββββββββββββββ
β
[Publishing complete!]
6. Workflow Implementation Guide
To apply this workflow to your blog, you need to implement these core elements.
6.1 WordPress REST API Integration
Core Concept:
// WordPress Application Password authentication
const auth = Buffer.from(`${username}:${password}`).toString('base64');
// Post creation API call
fetch(`${wordpressUrl}/wp-json/wp/v2/posts`, {
method: 'POST',
headers: {
'Authorization': `Basic ${auth}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
title: 'Post Title',
content: '<p>HTML Content</p>',
status: 'publish',
categories: [1, 2],
tags: [3, 4, 5]
})
});
Creating WordPress Application Password:
- WordPress Admin β Users β Profile
- Generate new password in “Application Passwords” section
- Save generated password to environment variables
6.2 AI Translation API Integration
Basic Claude API Usage:
// Request translation with Claude API
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'x-api-key': process.env.CLAUDE_API_KEY,
'anthropic-version': '2023-06-01',
'content-type': 'application/json'
},
body: JSON.stringify({
model: 'claude-3-5-sonnet-20241022',
max_tokens: 8000,
messages: [{
role: 'user',
content: `Translate this Korean tech blog post to English...`
}]
})
});
Timeout Setting: 60ms/word based on post length (minimum 2 min, maximum 10 min)
6.3 Polylang Language Linking
WordPress Plugin Development Required:
Since Polylang Free version doesn’t support REST API, you need to create a Custom REST API Endpoint.
// wp-content/plugins/your-plugin/polylang-helper.php
add_action('rest_api_init', function () {
register_rest_route('your-plugin/v1', '/link-translations', [
'methods' => 'POST',
'callback' => 'link_translations_callback',
'permission_callback' => function() {
return current_user_can('edit_posts');
}
]);
});
function link_translations_callback($request) {
$ko_id = $request->get_param('ko_post_id');
$en_id = $request->get_param('en_post_id');
pll_set_post_language($ko_id, 'ko');
pll_set_post_language($en_id, 'en');
pll_save_post_translations(['ko' => $ko_id, 'en' => $en_id]);
return ['success' => true];
}
6.4 Markdown Processing
unified Pipeline Configuration:
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkGfm from 'remark-gfm';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
const htmlContent = await unified()
.use(remarkParse) // Parse markdown
.use(remarkGfm) // GitHub Flavored Markdown
.use(remarkRehype) // Markdown β HTML
.use(rehypeStringify) // HTML stringify
.process(markdownContent);
6.5 Environment Variable Management
Required Environment Variables:
# .env file
WORDPRESS_URL=https://your-blog.com
WORDPRESS_USERNAME=your-username
WORDPRESS_APP_PASSWORD=xxxx-xxxx-xxxx-xxxx
CLAUDE_API_KEY=sk-ant-xxxxx
Security Considerations:
- Always add
.envfile to.gitignore - Recommend encrypting environment variables in production
7. Practical Tips and Considerations
7.1 SEO Optimization Tips
Title Writing:
- Length: 50-60 characters (fully displayed in Google search results)
- Keywords: Place at the beginning of title
- Use numbers: “7 Ways”, “10x” etc. (increases click rate)
Excerpt Writing:
- Length: 280-300 characters (SEO optimal)
- Repeat core keywords 2-3 times
- Include Call-to-Action
Keyword Density:
- Target: 0.5-2.5%
- Too low: SEO score drops
- Too high: Recognized as spam
7.2 Translation Quality Improvement Tips
Code Block Caution:
- Backticks (“`) must be even number
- Recommend specifying language: “`typescript
Link Structure:
- Use absolute paths over relative paths
- Internal links should specify
/ko/or/en/
Technical Terms:
- Keep proper nouns in English (e.g., Claude Code)
- Use bilingual notation for technical terms (e.g., “workflow”)
7.3 Problem-Solving Strategies
Translation Failure Response:
- Timeout Issues: Adjust Claude API timeout based on post length (60ms/word)
- Validation Failures: Relax validation logic to warnings if too strict
- Fallback Strategy: Publish only Korean post on translation failure and log
- Retry Mechanism: 3 retries with exponential backoff on network errors
Polylang Linking Issues:
- Plugin Not Installed: Custom REST API endpoint 404 error β Provide plugin installation guide
- Permission Issues: WordPress authentication failure β Regenerate Application Password
- Manual Linking Option: Manual linking in WordPress admin possible if REST API fails
Debugging Tips:
- Add detailed logs to all API calls
- Include solutions in error messages
- Run simulation first with dry-run mode
8. Roadmap: Next Steps
8.1 Automatic Image Processing
Goal: Automatically upload local images to WordPress media library and convert URLs
Implementation Ideas:
- Parse image paths from markdown (
) - Upload images with WordPress Media REST API
- Replace markdown content with uploaded URLs
- Publish converted HTML to WordPress
Tech Stack:
- WordPress Media API:
/wp-json/wp/v2/mediaendpoint - Upload with FormData as multipart/form-data
- Extract and replace image paths with regex
8.2 Batch Publishing
Goal: Publish multiple posts at once
Implementation Ideas:
- Scan all
.mdfiles in directory - Translate simultaneously with parallel processing (Promise.all)
- Display progress (current progress / total)
- Log failed posts
Parallel Processing Limit: Prevent too many simultaneous requests (max 3-5)
8.3 Watch Mode Automation
Goal: Automatically update WordPress when file changes detected
Implementation Direction:
- Monitor file system (chokidar, fs.watch, etc.)
- Selectively update only changed files
- Safety measure: Publish after confirming changes
Advantage: Maintain markdown = Source of Truth
9. Conclusion
Key Summary
- Time Savings: 2 hours 20 min β 1 hour 10 min (50%)
- Quality Maintenance: SEO 70-80 points, translation quality equal to manual
- Complete Automation: Simultaneous Korean-English post publishing with one command
- Real-World Validation: Parts 1, 2, 3 all published with this workflow
You Can Start Too
With the workflow and code examples shared in this post, you can build your own blog automation.
Core Tech Stack:
- WordPress REST API (automatic post publishing)
- Claude Code API (AI translation)
- TypeScript + Node.js (automation scripts)
- Polylang Plugin (multilingual linking)
Learn More:
- Please comment if you’re curious about specific implementations
- I plan to cover detailed implementation methods in a series
Finally
The essence of blog operation is “creating good content.”
Don’t waste time on repetitive tasks. Solve them with automation and focus on creation.
I hope this workflow can 10x your blog productivity.
Next Post Preview:
- “Claude Code Practical Guide: 10 Tips to 5x Productivity”
- “3 Months of Running a Tech Blog: Traffic, Revenue, and Lessons Learned”
Questions or feedback? Please leave a comment!
Leave A Comment