# SEOYEN SEO Platform — WordPress Plugin

[![Version](https://img.shields.io/badge/version-1.0.0-blue.svg)]()
[![PHP](https://img.shields.io/badge/PHP-7.4%2B-777BB4.svg)]()
[![WordPress](https://img.shields.io/badge/WordPress-6.0%2B-21759B.svg)]()
[![License](https://img.shields.io/badge/license-GPLv2%2B-green.svg)](https://www.gnu.org/licenses/gpl-2.0.html)

Official WordPress companion plugin for the SEOYEN SEO platform. Ship panel decisions to your site with a single click — AI content, internal links, 301 redirects, schema, meta descriptions, audit auto-fix, and more.

> This plugin is the WordPress-side of a hybrid architecture. The heavy lifting (keyword research, backlink analysis, AI generation, audit crawls) happens on the SEOYEN panel at [seoyen.com](https://seoyen.com/). This plugin turns those panel outputs into live WordPress changes.

---

## Overview

SEOYEN SEO Platform exposes 34 REST endpoints under `/wp-json/seoyen/v1/` and 7 admin pages. It integrates with Yoast SEO, Rank Math, SEOPress, or its native fallback, and supports 14 audit auto-fix check types out of the box. The plugin is GPL-compatible, i18n-ready, and built against WordPress 6.0+ / PHP 7.4+.

## Features

| Area | What it does |
|------|-------------|
| **AI Content** | Publish AI-generated articles and paragraphs from the panel as drafts, scheduled posts, or published articles. |
| **Internal Links** | One-click apply of panel link suggestions using a safe DOMDocument-based inserter. |
| **Redirects** | 301/302/307/308/410 redirects with exact / prefix / regex matching, per-hit analytics, and CSV bulk import. |
| **Audit Auto-Fix** | Fix 14 check types straight from the SEOYEN panel (title, meta, canonical, robots, schema, OG, hreflang, alt, viewport, llms.txt, and more). |
| **Meta Descriptions** | Adapter pattern for Yoast SEO, Rank Math, SEOPress, and a native fallback. |
| **Alt Text** | Set alt text in bulk for media library and featured images. |
| **Schema Markup** | JSON-LD per-post CRUD; output in a single `<script type="application/ld+json">` block. |
| **Social Drafts** | Convert long-form content into social-ready drafts. |
| **Virtual Files** | Serve `robots.txt` and `llms.txt` without writing to disk. |
| **Webhooks** | HMAC-SHA256-signed outbound webhooks to Zapier, Make, n8n, or custom endpoints. |
| **Activity Log** | Search, filter, date-range, and CSV export across all plugin actions. |
| **Dashboard Widget** | Audit score, top keywords, recent organic clicks, latest activity — refreshable. |

## Installation

### From wp-admin

1. Go to **Plugins > Add New > Upload Plugin**.
2. Upload the ZIP archive.
3. Activate **SEOYEN SEO Platform**.
4. Open **SEOYEN SEO > Settings** and paste the API key generated in the SEOYEN panel.
5. Click **Connect to Panel** to run the three-step handshake.

### Manual

```bash
cd wp-content/plugins
# From a release ZIP
unzip seoyen.zip
# Or from this repo
git clone https://github.com/seoyen/wordpress-plugin.git seoyen
```

Then activate from the Plugins screen.

### WP-CLI

```bash
wp plugin install /path/to/seoyen.zip --activate
wp option update seoyen_api_key "your-api-key-here"
```

## Configuration

All runtime options are stored as `seoyen_*` WordPress options and can be managed through **SEOYEN SEO > Settings**:

| Option | Default | Description |
|--------|---------|-------------|
| `seoyen_api_key` | *(empty)* | SEOYEN API key. Generate from Panel > Settings > Integrations. |
| `seoyen_panel_url` | `https://seoyen.com/panel/api/api-platform.php` | Panel endpoint. Override only for SEOYEN staff testing. |
| `seoyen_site_id` | `0` | Bound panel `site_id`. Auto-populated during activation handshake. |
| `seoyen_telemetry_enabled` | `false` | Opt-in telemetry (plugin version, WP version, PHP version only). |
| `seoyen_keep_data_on_uninstall` | `true` | When `false`, the plugin drops its tables and deletes all options/postmeta on uninstall. |
| `seoyen_debug_mode` | `false` | Verbose logging to the activity log. |
| `seoyen_fallback_meta_output` | `true` | Write meta description / canonical / OG tags when no SEO plugin is active. |
| `seoyen_schema_output` | `true` | Emit JSON-LD from `_seoyen_schema_jsonld` post meta at `wp_head` priority 99. |
| `seoyen_llms_txt_enable` | `true` | Serve `llms.txt` at the site root. |
| `seoyen_robots_txt_extra` | *(empty)* | Appended to the default WordPress robots.txt output. |

## REST API Reference

Authentication header: `X-Seoyen-Key: <your SEOYEN API key>` (timing-safe comparison via `hash_equals`). All endpoints respond with `application/json` and use `rest_ensure_response()`.

| # | Endpoint | Method | Purpose |
|---|----------|--------|---------|
| 1 | `/ping` | GET | Liveness check + capabilities list |
| 2 | `/activate` | POST | First-time setup handshake |
| 3 | `/status` | GET | WP version, PHP version, active SEO plugin |
| 4 | `/audit-summary` | GET | Dashboard widget payload |
| 5 | `/publish-content` | POST | AI Writer → WP draft/publish |
| 6 | `/content/update` | POST | Revise an existing post |
| 7 | `/content/paragraph` | POST | Paragraph-level insert |
| 8 | `/links/apply` | POST | Apply one internal link |
| 9 | `/links/bulk-apply` | POST | Batch internal link apply |
| 10 | `/links/suggestions` | GET | Cached suggestion list |
| 11 | `/meta/apply` | POST | Meta description / title apply |
| 12 | `/meta/bulk-apply` | POST | Batch meta apply |
| 13 | `/media/alt-text` | POST | Set image alt text |
| 14 | `/media/bulk-alt` | POST | Batch alt text |
| 15 | `/schema/apply` | POST | JSON-LD add / replace / upsert |
| 16 | `/schema/delete` | DELETE | Remove schema |
| 17 | `/social/draft` | POST | Social-ready draft |
| 18 | `/redirects` | GET | List redirects |
| 19 | `/redirects` | POST | Create redirect |
| 20 | `/redirects/{id}` | DELETE | Delete redirect |
| 21 | `/redirects/bulk-import` | POST | Import from `broken_backlinks` or CSV |
| 22 | `/audit/autofix` | POST | Apply panel check_key → WP fix |
| 23 | `/files/robots` | GET / PUT | Manage virtual robots.txt |
| 24 | `/files/llms` | GET / PUT | Manage virtual llms.txt |
| 25 | `/activity` | GET | List activity log |
| 26 | `/webhooks` | GET / POST / DELETE | Outbound webhook CRUD |
| 27 | `/batch` | POST | Multi-endpoint batch |
| 28 | `/apply` | POST | Unified dispatcher (tool_id routed) |

Full request/response schemas: see the SEOYEN panel API reference at https://seoyen.com/panel/api-docs.php.

## SEO Plugin Integrations

The plugin detects your active SEO plugin at request time and writes to its post meta keys. You only need one of these — the native fallback is automatic.

| SEO plugin | Meta description | Title | Canonical | Open Graph |
|------------|------------------|-------|-----------|------------|
| Yoast SEO | `_yoast_wpseo_metadesc` | `_yoast_wpseo_title` | `_yoast_wpseo_canonical` | `_yoast_wpseo_opengraph-*` |
| Rank Math | `rank_math_description` | `rank_math_title` | `rank_math_canonical_url` | `rank_math_facebook_*` |
| SEOPress | `_seopress_titles_desc` | `_seopress_titles_title` | `_seopress_robots_canonical` | `_seopress_social_fb_*` |
| Native fallback | `_seoyen_meta_desc` | *(uses theme)* | `_seoyen_canonical` | `_seoyen_og_*` |

## Hook Reference

### Filters

| Filter | Parameters | Purpose |
|--------|------------|---------|
| `seoyen_rest_capabilities` | `array $caps` | Modify the capabilities list returned by `/ping`. |
| `seoyen_redirect_before_hit` | `object $redirect, string $request_uri` | Short-circuit or modify a redirect. |
| `seoyen_robots_txt_extra` | `string $extra` | Append custom rules to robots.txt. |
| `seoyen_schema_jsonld` | `array $schemas, int $post_id` | Modify the JSON-LD array before output. |
| `seoyen_meta_description` | `string $desc, int $post_id` | Modify the meta description before writing to post meta. |

### Actions

| Action | Parameters | Purpose |
|--------|------------|---------|
| `seoyen_redirect_created` | `int $redirect_id, array $data` | Fires after a redirect is created. |
| `seoyen_link_applied` | `int $post_id, string $anchor, string $href` | Fires after an internal link is inserted. |
| `seoyen_autofix_applied` | `int $post_id, string $check_key` | Fires after an audit auto-fix succeeds. |
| `seoyen_activity_logged` | `int $log_id, array $entry` | Fires after an activity log entry is written. |

## Developer Guide

### Add a new SEO plugin adapter

1. Extend `Seoyen_Integration_Base` in `includes/integrations/`.
2. Implement `is_active()`, `get_priority()`, and the meta-writing methods (`set_meta_description`, `set_title`, `set_canonical`, `set_og_tags`).
3. Register the adapter in `Seoyen_Meta_Manager::get_active_integration()`.

### Add a new audit auto-fix handler

1. Add a method to `Seoyen_Audit_Handler` (for example, `fix_my_check()`).
2. Add the mapping to the `$supported_checks` property using the panel `check_key` as the key.
3. Return a `true` or a `WP_Error` so the activity log records success or failure correctly.

### Add a new REST endpoint

1. Create a new controller in `includes/rest/` extending `Seoyen_REST_Controller`.
2. Implement `register_routes()` with your `register_rest_route()` calls.
3. Register the class in `Seoyen_REST_Router::$controllers`.
4. Use `$this->authenticate_request( $request )` and `$this->enforce_rate_limit( $request )` in your permission callback.

### Logging

All managers and REST controllers receive a `Seoyen_Logger` instance. Call `Seoyen_Logger::log( $action, $result, $context )` after every state-changing operation so the activity log stays complete.

## Contributing

This plugin is developed as part of the SEOYEN platform. Bug reports, feature requests, and pull requests are welcome. Please run the included `phpcs.xml.dist` ruleset before submitting a PR:

```bash
phpcs --standard=phpcs.xml.dist
```

## License

GPLv2 or later. See https://www.gnu.org/licenses/gpl-2.0.html.

## Support

* Documentation: https://seoyen.com/panel/api-docs.php
* Panel: https://seoyen.com/panel/
* Contact: https://seoyen.com/iletisim/
