> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# AI WordPress Post Generator

> Automated AI news research and WordPress publishing pipeline

## Overview

A 5-stage pipeline that researches AI news, checks for duplicates, and publishes Gutenberg-formatted posts to WordPress.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
flowchart TB
    subgraph Stage1["Stage 1: Topic Gathering"]
        A[tavily_search] --> B[5-10 AI Topics]
    end
    
    subgraph Stage2["Stage 2: Duplicate Check"]
        B --> C{check_duplicate}
        C -->|Duplicate| D[Pick Next Topic]
        C -->|Unique| E[Selected Topic]
        D --> C
    end
    
    subgraph Stage3["Stage 3: Deep Research"]
        E --> F[tavily_search URLs]
        F --> G[crawl_url x3+]
        G --> H[Facts & Stats]
    end
    
    subgraph Stage4["Stage 4: Content Writing"]
        H --> I[Gutenberg Blocks]
        I --> J[ARTICLE_TITLE + CONTENT]
    end
    
    subgraph Stage5["Stage 5: Publish"]
        J --> K{Title Valid?}
        K -->|Yes| L[create_wp_post]
        K -->|No| M[Blocked]
        L --> N[Published Post]
    end
```

## Decision Flow

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
flowchart LR
    subgraph Deduplication
        T1[Title] --> D1{In WordPress?}
        D1 -->|Yes| R1[Reject]
        D1 -->|No| D2{In Session?}
        D2 -->|Yes| R2[Skip]
        D2 -->|No| P[Publish]
    end
```

## Quick Start

### 1. Install Dependencies

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
pip install praisonai praisonai-tools praisonaiwp
```

### 2. Set Environment

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
export TAVILY_API_KEY="your-key"
export OPENAI_API_KEY="your-key"
```

### 3. Create Files

```yaml workflow.yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
framework: praisonai
topic: "AI developments {{today}}"

roles:
  topic_gatherer:
    role: AI News Researcher
    goal: Find current AI news topics
    tools:
      - tavily_search
    tasks:
      gather:
        description: |
          Search for AI news from {{today}}.
          Find 5-10 specific developments.
        expected_output: List of topics with URLs

  duplicate_checker:
    role: Deduplication Agent
    tools:
      - check_duplicate
    tasks:
      check:
        description: |
          {{previous_output}}
          Check each topic. Find ONE unique topic.
        expected_output: One unique topic

  deep_researcher:
    role: Content Researcher
    tools:
      - tavily_search
      - crawl_url
    tasks:
      research:
        description: |
          {{previous_output}}
          Crawl 3+ URLs. Extract facts and statistics.
        expected_output: Research summary

  content_writer:
    role: Blog Writer
    tasks:
      write:
        description: |
          {{previous_output}}
          
          Write in GUTENBERG FORMAT:
          - <!-- wp:paragraph --><p>text</p><!-- /wp:paragraph -->
          - <!-- wp:heading --><h2>title</h2><!-- /wp:heading -->
          - <!-- wp:html --><table>...</table><!-- /wp:html -->
          
          Output:
          ARTICLE_TITLE: [your title]
          ARTICLE_CONTENT: [Gutenberg blocks]
        expected_output: ARTICLE_TITLE and ARTICLE_CONTENT

  publisher:
    role: WordPress Publisher
    tools:
      - create_wp_post
    tasks:
      publish:
        description: |
          {{previous_output}}
          Extract title and content. Call create_wp_post.
        expected_output: Published post ID
```

```python tools.py theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonai_tools import TavilyTool, Crawl4AITool

TOOLS = {}

def recipe_tool(name):
    def decorator(func):
        TOOLS[name] = func
        return func
    return decorator

@recipe_tool("tavily_search")
def tavily_search(query: str, max_results: int = 5):
    return TavilyTool().search(query=query, max_results=max_results)

@recipe_tool("crawl_url")
def crawl_url(url: str):
    return Crawl4AITool().crawl(url=url)

@recipe_tool("check_duplicate")
def check_duplicate(title: str):
    from praisonaiwp.ai.duplicate_detector import DuplicateDetector
    # ... implementation
    return {"has_duplicates": False}

@recipe_tool("create_wp_post")
def create_wp_post(title: str, content: str, status: str = "publish"):
    import subprocess
    # Title blocklist validation
    BLOCKED = ["verified", "sample", "example", "test"]
    if any(b in title.lower() for b in BLOCKED):
        return {"error": "Invalid title", "blocked": True}
    
    cmd = ["praisonaiwp", "create", title, "--content", content]
    result = subprocess.run(cmd, capture_output=True, text=True)
    return {"success": result.returncode == 0}
```

### 4. Run

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai workflow run workflow.yaml
```

## Architecture

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    subgraph Recipe["Recipe Layer"]
        WF[workflow.yaml]
        TL[tools.py]
    end
    
    subgraph SDK["PraisonAI SDK"]
        WE[Workflow Engine]
        AG[Agent Class]
    end
    
    subgraph External["External Services"]
        TV[Tavily API]
        WP[WordPress]
    end
    
    WF --> WE
    TL --> WE
    WE --> AG
    AG --> TV
    AG --> WP
```

## Tools Reference

| Tool | Purpose | Returns |
| - | - | - |
| `tavily_search` | AI-powered web search | Results with URLs |
| `crawl_url` | Extract page content | Title + content |
| `check_duplicate` | Semantic similarity check | `{has_duplicates: bool}` |
| `create_wp_post` | Publish to WordPress | `{post_id: int}` |

## Gutenberg Blocks

Use these block formats in content:

| Block | Format |
| - | - |
| Paragraph | `<!-- wp:paragraph --><p>text</p><!-- /wp:paragraph -->` |
| Heading | `<!-- wp:heading --><h2 class="wp-block-heading">title</h2><!-- /wp:heading -->` |
| Table | `<!-- wp:html --><table>...</table><!-- /wp:html -->` |
| List | `<!-- wp:list --><ul class="wp-block-list"><li>item</li></ul><!-- /wp:list -->` |
| Separator | `<!-- wp:separator --><hr/><!-- /wp:separator -->` |

## Title Validation

The `create_wp_post` tool blocks invalid titles:

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
flowchart LR
    T[Title] --> C1{Contains blocked word?}
    C1 -->|"verified, sample, example"| B[BLOCKED]
    C1 -->|No| C2{Length >= 10?}
    C2 -->|No| B
    C2 -->|Yes| P[ALLOWED]
```

## Troubleshooting

| Issue | Cause | Fix |
| - | - | - |
| Title "VERIFIED" | Agent prefix in output | Remove quality checker stage |
| Empty content | Context not passed | Use `{{previous_output}}` |
| Outdated news | No date filter | Add `{{today}}` to search |
| Raw HTML tables | Wrong block format | Use `<!-- wp:html -->` for tables |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.