> ## Documentation Index
> Fetch the complete documentation index at: https://docs.praison.ai/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

<CodeGroup>
  ```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}
  ```
</CodeGroup>

### 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 |
