=== Easy Social Publisher ===
Contributors: easystorewp
Donate link: https://www.easy-storewp.com/
Tags: social-media, auto-post, facebook, instagram, line
Requires at least: 5.7
Tested up to: 6.8
Requires PHP: 7.4
Stable tag: 1.0.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

One-click cross-post WordPress articles to LINE OA / Facebook Page / Instagram / Threads with AI-rewritten captions per platform.

== Description ==

**Easy Social Publisher** is a developer-friendly cross-poster for WordPress. Publish a post once, and the plugin can automatically push platform-tailored captions to your LINE Official Account, Facebook Page, Instagram Business, and Threads. AI rewrites the caption to fit each platform's tone and length limits.

= What it does =

* Listens for `transition_post_status` and (optionally) `easy_ai_post_published`; with a configurable buffer (default 5 min) before actually sending — gives you time to revise.
* Uses any OpenAI-compatible LLM endpoint (OpenAI / Anthropic / OpenRouter / Groq / Ollama / LiteLLM proxy) to rewrite captions for each channel — 4 dedicated prompt templates, all admin-editable.
* Channel adapters per platform: LINE OA broadcast, FB Page feed, IG Business media, Threads.
* Reliability: queue table with status (pending → sending → success / retry / failed), exponential backoff (5 / 25 / 125 min), 90-day log retention.
* Telegram failure notifications (instant + daily digest 09:00).

= Bring your own LLM endpoint =

* OpenAI (api.openai.com)
* OpenRouter (free models available)
* Groq (free tier)
* Self-hosted Ollama
* Any OpenAI-compatible chat completions endpoint

If you also have **Easy AI Auto** installed and configured with an LLM endpoint, this plugin auto-detects and reuses that configuration — no double setup.

= Plays well with the Easy Suite =

This plugin is part of the Easy Suite family. It softly integrates with:

* **Easy AI Auto** — borrows LLM call helper, TG notification helper, site role description.
* **Easy Schedule** — registers its dispatch / digest tasks into the central scheduler dashboard.

All integrations are **soft via `function_exists()`** — Easy Social Publisher works fine standalone with zero Easy Suite plugins installed.

= No vendor lock-in =

* No hardcoded API endpoint
* No phoning home
* All credentials stored in your DB

== Installation ==

1. Upload the plugin folder to `/wp-content/plugins/`
2. Activate the plugin in WP Admin → Plugins
3. Go to **Social Publisher** in admin menu → fill LLM endpoint (or skip if Easy AI Auto is already configured)
4. Configure each channel (LINE / FB / IG / Threads) credentials in the **社群帳號** tab
5. Enable **自動推送** if you want post-publish hooks to auto-send

== Frequently Asked Questions ==

= Do I need to install all 4 platform integrations? =

No. Each channel is independent — enable only those you use. The plugin works with just LINE configured, just FB, etc.

= Does it require Easy AI Auto? =

No. Easy AI Auto is a soft dependency. Without it, this plugin uses its own LLM endpoint configuration. With it, it borrows the existing config to avoid duplication.

= How does the scheduling work? =

A cron task runs every 5 minutes, picks up pending entries past their `scheduled_at`, generates the caption (if not yet generated), and sends to the channel. Failures retry with exponential backoff up to 3 times.

= How are credentials stored? =

In `wp_options` via `easy_social_publisher_*` keys. Meta OAuth user/page tokens are AES-256-CBC encrypted (key derived from `AUTH_KEY`).
LINE Channel Access Token is stored plain (single-purpose token, lower blast radius).

= What about quota / rate limits? =

LINE OA broadcast quota is shown in admin (free tier 500/month, paid 50,000/month). FB / IG / Threads use Meta Graph API standard rate limits — the plugin does not artificially throttle.

== Screenshots ==

1. General settings & soft-dependency status panel
2. LLM configuration (OpenAI-compatible endpoint)
3. Caption prompt templates per platform
4. Channels overview (4 platforms, milestone status)
5. Caption preview tool — pick a post, see what each platform's caption would look like
6. Send log with retry / filter

== Privacy ==

This plugin sends data to the following third-party services **only when you configure them**:

* The LLM endpoint you configure: post titles + excerpts + your site role description (for caption rewriting).
* LINE Messaging API: caption text + image URL (when LINE channel enabled).
* Meta Graph API (FB / IG / Threads): caption text + image URL + post link (when Meta channels enabled).
* Telegram Bot API: failure notifications text only (when TG configured).

The plugin does **not** phone home, does **not** track users, and does **not** send data to easy-storewp.com or any first-party service.

All credentials and tokens are stored locally in your WordPress database.

On uninstall, all options, cron tasks, and the log table are removed. Your social media posts already published remain on those platforms.

== Changelog ==

= 1.0.0 =
* M6: Threads adapter (`Easy_Social_Channel_Threads`).
  * Two-step publish via `graph.threads.net/v1.0`: `POST /{tid}/threads` (create) → `POST /{tid}/threads_publish`.
  * Auto-truncate to 500-char limit; appends post link in tail when room.
  * Supports text-only or text+image (uses same Meta OAuth user token; not page token).
  * Test connection: `GET /{tid}?fields=id,username,name`.
* All 4 platform adapters (LINE / FB Page / IG Business / Threads) now registered. Easy Social Publisher v1.0.0 first major release.

= 0.5.0 =
* M5: Instagram Business adapter (`Easy_Social_Channel_Ig`).
  * Two-step publish: `POST /{ig-id}/media` (build container) → `POST /{ig-id}/media_publish`.
  * Pre-flight: HEAD image URL to verify reachable + content-type is `image/jpeg|jpg|png` (避免 Meta 端拒絕).
  * `requires_image=true` enforced — no image, dispatcher rejects with friendly error.
  * Channel page dropdown only lists FB pages with linked IG Business account (filter applied at admin).
  * Test connection: `GET /{ig-id}?fields=id,username,name,followers_count` shows IG handle + follower count.
  * Captures returned media id as `external_id` in log.

= 0.4.0 =
* M4: Facebook Page adapter (`Easy_Social_Channel_Fb`).
  * Posts via Meta Graph API `POST /{page-id}/feed` (or `/photos` if image-only).
  * Strategy: link → /feed with link param (FB auto-fetches OG preview); image → /photos with caption; text-only → /feed message.
  * Channel settings tab shows page dropdown sourced from M3 OAuth-fetched pages list.
  * Test connection: `GET /{page-id}?fields=id,name,fan_count` shows page name + fan count.
  * Captures returned `id` (post_id) as `external_id` in log.

= 0.3.0 =
* M3: Meta OAuth flow infrastructure (shared by FB / IG / Threads adapters in M4-M6).
  * New `Meta 帳號` admin tab: paste App ID + Secret, click `連結 Meta 帳號` to start OAuth flow.
  * Standard OAuth 2.0 with state token (random + transient + per-user binding) — prevents CSRF on callback.
  * Auto-exchanges short-lived user token → long-lived (60 day) → page tokens (永久).
  * AES-256-CBC encrypts user_token and pages JSON in wp_options (key derived from `AUTH_KEY`).
  * Auto-fetches IG Business account ID per page (used by M5).
  * Disconnect button purges all stored tokens.
  * Admin-post.php hooks gated by `current_user_can('manage_options')` + WP nonce.
* No new visible channels — M4-M6 will plug into this OAuth infrastructure.

= 0.2.0 =
* M2: LINE 官方帳號 broadcast adapter (`Easy_Social_Channel_Line`).
  * Settings page: paste Channel Access Token + Channel Secret, plus `Test Connection` button.
  * Auto-detects featured image: with image → Flex Message bubble (hero + body + CTA button); without → plain text.
  * Pre-flight quota check via `/v2/bot/message/quota` and `/v2/bot/message/quota/consumption` (5-min cache); skips API call when quota exceeded.
  * Friendly error mapping for 400/401/403/429 (token invalid / no follower / rate-limited).
  * Captures LINE response `X-Line-Request-Id` as `external_id` in log.
* Channels tab now expandable: click row → inline credential form + test button.

= 0.1.1 =
* Renamed admin tabs for naming consistency with Easy AI Auto: "LLM 設定" → "AI 設定"; "失敗通知" → "TG 通知".
* Fixed: caption rewriter call to `easy_ai_auto_call_litellm()` was checking the wrong return contract (expected string, but the function returns ['error' => ...] / ['content' => ...] array). Now correctly unwraps and falls back if ai-auto's call returned error.

= 0.1.0 =
* Initial milestone (M1 from REQ-20260505001) — scaffold release.
* Plugin scaffold with admin UI, settings persistence, log table, cron schedule (every 5 min dispatcher + daily digest + log prune).
* Caption rewriter with 4 platform-specific prompt templates (LINE / FB / IG / Threads), admin-editable, preview tool.
* Channel adapter abstract base class — platform implementations come in M2-M6.
* Soft integration with Easy AI Auto (LLM helper / TG helper / site role) and Easy Schedule (task registration filter).
* uninstall.php cleans options + cron + log table + transients.

= Roadmap =
* 0.2.0 (M2) — LINE OA broadcast adapter + Flex Message builder.
* 0.3.0 (M3) — Meta OAuth flow (FB / IG / Threads shared infra), AES-256-CBC token storage.
* 0.4.0 (M4) — Facebook Page feed adapter.
* 0.5.0 (M5) — Instagram Business adapter (image required + 30-hashtag pool).
* 1.0.0 (M6) — Threads adapter; first wp.org submission.
