=== OpptiAI Internal Linking – Find Orphan Pages for SEO ===
Contributors: beepbeepv2
Tags: internal linking, orphan pages, internal links, link building, seo
Requires at least: 6.3
Tested up to: 7.1
Requires PHP: 8.1
Stable tag: 0.1.3
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Find orphan pages: posts and pages with no internal links. Scan locally, then apply the links you approve.

== Description ==

https://www.youtube.com/watch?v=fRwMftJy54Q

An orphan page is a published post or page that no other page on your site links to. OpptiAI Internal Linking finds those pages, shows the internal links you already have, and lets you add one after you review it.

The scan runs on your site. It does not need an OpptiAI account, and it does not use credits. AI suggestions stay off until an administrator opts in and you ask for a specific page.

= Find orphan pages =

The scan lists published content with no inbound internal links. A page linked from a navigation menu is not treated as an orphan. This check stays in WordPress.

= See your internal links =

Every scanned post and page gets an inbound count and an outbound count. Links inside blocks and shortcodes are included. Posts and pages are scanned by default; you can add other public post types, including WooCommerce products. The link map shows which pages are hubs and which pages are cut off.

= Apply a link you have reviewed =

Nothing is inserted on its own. When you apply an approved internal link, the plugin never self-links, never nests inside an existing link, saves a revision, and follows your per-page link cap, minimum word count, and excluded pages. If there is no safe place for the link, the post is left unchanged.

AI link suggestions (the Opportunities screen) need an OpptiAI account, the administrator opt-in, and an explicit request. One credit is used per source page; asking again for the same page within 30 minutes uses the saved result.

If you already use [OpptiAI Alt Text](https://wordpress.org/plugins/beepbeep-ai-alt-text-generator/) or [OpptiAI Titles](https://wordpress.org/plugins/opptiai-titles/), an administrator can share one OpptiAI account. The orphan-page scan does not need that account.

= Privacy =

This plugin does not contact OpptiAI until an administrator enables “Send page excerpts to OpptiAI” and someone requests suggestions. It does not adopt credentials from Titles or Alt Text unless an administrator enables that in Settings. No personal visitor information is collected. See the External Services section for details.

== External Services ==

This plugin connects to the OpptiAI API to generate internal-link suggestions and to report remaining service credits. AI generation is performed by the external service and is not performed locally by this plugin.

Service: OpptiAI API
Service URL: https://alttext-ai-backend.onrender.com
Website: https://oppti.dev
Purpose: Generate internal-link suggestions between related pages, connect an OpptiAI account, and report available service credits.
When data is sent: Only after an administrator enables “Send page excerpts to OpptiAI” in Settings, and only when an Editor or Administrator then requests AI suggestions for a page they can edit, or an administrator views remaining credits. Opening the plugin, scanning, viewing Pages or the Link Map, and applying an approved link do not contact the service.
Data sent: Site URL; plugin version; a pseudonymous installation and site identifier; a site fingerprint; the connected account license key (and an optional sibling JWT when the administrator has opted in to reuse a sibling account); and, for suggestions, the source page title, URL, a content excerpt, and candidate destination page titles, URLs, and IDs.
Privacy Policy: https://oppti.dev/privacy
Terms of Use: https://oppti.dev/terms

== Installation ==

1. Install the plugin from the Plugins screen, or upload it to `wp-content/plugins/opptiai-internal-linking`.
2. Activate it through the **Plugins** menu in WordPress.
3. Open **OpptiAI Linking** and run a scan. Orphan pages, the pages list, and the link map work with no account.
4. To ask for AI link suggestions, an administrator enables “Send page excerpts to OpptiAI” in Settings. To reuse an account already connected by OpptiAI Titles or Alt Text, also enable “Use sibling OpptiAI account”. Create an account at https://oppti.dev.

== Frequently Asked Questions ==

= What is an orphan page? =

A published post or page with no internal link pointing to it from your other content. The scan lists those pages. A page linked from a navigation menu is not counted as an orphan.

= Do I need an account to find orphan pages? =

No. The scan, the pages list, and the link map run in WordPress and use no credits. An OpptiAI account is only used when you ask for an AI link suggestion.

= Does this add internal links automatically? =

No. A link is inserted only when you apply a suggestion you have reviewed. Each apply saves a post revision, so you can undo it. When there is no safe match, the post is left unchanged.

= Does the scan cost credits? =

No. Scanning, orphan detection, and applying an approved link use no credits. Only AI link suggestions require an OpptiAI account (one credit per source page analysed; reloading a page within 30 minutes is cached).

= Which content is scanned? =

Posts and pages by default. You can enable additional public post types (for example WooCommerce products) under Settings → Content to scan.

= Will this raise my search rankings? =

It shows you pages with no internal links and lets you add links you approve. It does not edit titles, metadata, or sitemaps, and it does not promise higher rankings.

= Who can change settings? =

Editors can view content screens and settings; only administrators can save settings or view account and billing details. AI suggestions (Opportunities) are limited to Editors and Administrators, only for pages they can edit, and only those pages are offered as link targets. Applying a link requires permission to edit that specific post.

= How do I connect an OpptiAI account? =

You only need this for AI suggestions. In Settings, enable “Use sibling OpptiAI account” if OpptiAI Titles or Alt Text is already signed in on this site, then save. Also enable “Send page excerpts to OpptiAI” before requesting suggestions. Create an account at https://oppti.dev — Free includes a monthly suggestion allowance.

== Screenshots ==

1. Dashboard after a scan: pages scanned, internal links, and orphan pages.
2. Pages list with inbound and outbound counts.
3. Link map showing hubs and pages that are cut off.
4. Opportunities stays local until you ask for AI suggestions.
5. Settings: link caps, what to scan, and the OpptiAI opt-in.

== Development ==

Human-readable source for the compiled admin app is included as `prototype/*.jsx`. Build tools live with the plugin (`package.json`, `build.js`). To rebuild the admin bundle:

`npm install && npm run build`

== Changelog ==

= 0.1.3 =
* Readme: explain the local orphan-page scan, and that an account is only used for AI suggestions.
* Security: per-post permission checks on the REST API. AI link opportunities now require the Editor role (`edit_others_posts`) plus permission to edit the specific source post, checked in the route's permission callback; candidate pages sent to OpptiAI are limited to posts the current user can edit. Applying links checks `edit_post` for the post being edited in the permission callback, and only inserts links to published posts the user can edit.
* AI suggestions are only shown when their target is one of the candidate pages sent for that request.
* Reading plugin settings now requires the Editor role (`edit_others_posts`); saving still requires an administrator.
* Fix: applying a link now matches whole words only and inserts into visible text at most once. Matching is Unicode-aware (for example “café” or “кошка”). It never touches HTML tags or attributes (such as image alt text), block comment markup, shortcodes, existing links, headings, code, scripts or styles. A post gets at most one link per target. When there is no safe match, the post is left unchanged.

= 0.1.2 =
* Align the gettext text domain with the WordPress.org plugin slug (`opptiai-internal-linking`).

= 0.1.1 =
* Require administrator opt-in before contacting OpptiAI or reusing a sibling plugin account.
* Opportunities no longer requests suggestions when the screen opens; you choose a page and ask.
* Credit quota is limited to administrators.
* Local scan, Pages, and Link Map work without an OpptiAI account.

= 0.1.0 =
* Initial release: site scan, orphan detection, Pages and Link Map screens, persisted settings, shared OpptiAI wallet, AI Opportunities via the OpptiAI service, and a revision-safe apply-links route.
