=== SeoWP ===
Contributors: ini software
Tags: seo, schema, open graph, sitemap, indexnow
Requires at least: 5.7
Tested up to: 6.5
Requires PHP: 7.4
Stable tag: 1.2.2
License: GPLv2 or later

Lightweight, automated SEO for WordPress.

== Description ==

SeoWP is a focused, no-bloat SEO plugin for WordPress. It adds solid on-page
SEO with automatic structured data, and stays out of the way of multilingual
plugins (e.g. TranslatePress / WPML — hreflang) and the rest of your stack.

**Dashboard &amp; settings**

* A modern admin UI: vertical-nav settings with cards, accordions and toggle
  switches, plus an at-a-glance SEO dashboard.

**On-page engine**

* Document `<title>` and meta-description templating, per post type and per
  taxonomy, with per-post and per-term overrides.
* Canonical URLs for every context, with per-post override.
* Robots directives via the core `wp_robots` filter (no duplicate tags):
  per-post noindex, plus noindex toggles for search, date and author archives.
* `max-image-preview:large`, `max-snippet:-1`, `max-video-preview:-1` by default.
* Optional head cleanup (generator, RSD, WLW manifest, shortlink).
* Google / Bing site-verification meta tags (output on every page).

**Social**

* Open Graph and Twitter Card tags, with featured-image fallback and a
  site-wide default share image. Per-post share-image override.

**Structured data (Schema.org JSON-LD)**

* `WebSite` (+ optional Sitelinks SearchAction) and
  `Organization` / `LocalBusiness` with address, geo, telephone, opening hours,
  price range and social profiles (`sameAs`).
* `Article` / `NewsArticle` for posts and news.
* Per-post-type schema mapping: assign any post type to a schema type
  (Article, WebPage, Store, Event, SaleEvent, …) from the settings screen, or
  leave it on `auto` for sensible defaults.
* `BreadcrumbList` on every non-home page.

**Sitemap**

* Custom XML sitemap at `/sitemap.xml` (index + per-type / per-taxonomy
  sub-sitemaps) with image entries and `lastmod`; respects noindex. Replaces the
  WordPress core sitemap. Excludable per post type / taxonomy.

**IndexNow (instant indexing)**

* Auto-submits published / updated URLs to Bing, Yandex, Seznam and Naver the
  moment content changes (a single ping is shared between them). Google does not
  consume IndexNow — the sitemap + Search Console cover Google.
* Secret key generated automatically and served as a virtual verification file
  (no stray file in the webroot); one-click regenerate and a manual test ping.
* Respects per-post noindex; submission runs on `shutdown` so the editor save is
  never blocked. Capped, non-autoloaded submission log.

**Dashboard**

* A modern, WordPress-native overview: setup checklist with progress, live
  feature toggles, IndexNow status &amp; recent submissions, and per-content-type
  meta-description coverage bars.

**robots.txt**

* Virtual robots.txt editor that always advertises the sitemap.

**Breadcrumbs**

* `[iniseo_breadcrumbs]` shortcode and `iniseo_breadcrumbs()` template tag,
  sharing the same trail as the BreadcrumbList schema.

== Installation ==

1. The plugin lives in `wp-content/plugins/ini-seo-wp/`.
2. Activate **SeoWP** from Plugins. Activation registers the sitemap rewrite
   rules and flushes them once.
3. Open **SeoWP → Settings** and fill in the Local Business tab (address, geo,
   phone, hours) so the Organization / LocalBusiness schema is complete.
4. Add the verification codes (General tab) if you use Search Console / Bing.

== Notes ==

* Multilingual: hreflang and translated URLs remain TranslatePress's job. Every
  tag this plugin prints is in the rendered HTML, so it is translatable through
  TranslatePress's string editor.
* Caching: all front-end output is produced on `wp_head` and served from the
  existing FastCGI cache for anonymous visitors.

== Changelog ==

= 1.2.2 =
* New: `%content%` macro — resolves to the post's main content (trimmed), always ignoring the excerpt. Use it in a Description template (e.g. SeoWP → Settings → Titles & Meta → per content type) when you want the meta description built from the long description rather than the excerpt. On WooCommerce products this means the long product description instead of the short description that `%excerpt%` uses. Listed under Posts in the "Browse all macros" reference. `%excerpt%` is unchanged (manual/short description first, else content).

= 1.2.1 =
* Fix: the editor "Search appearance" and Social card previews now resolve the %excerpt% default for WooCommerce products. A product keeps its description in the main content editor and its short description in a second visual editor — the preview now reads both of those live editors (not just the raw textareas), so a product with content/short-description previews its real description instead of "No meta description" / "No description set." The previews also re-render when either editor loads or changes. Front-end output was already correct.
* Internal: the live-%excerpt% resolver used by the two previews is now a single shared helper (was duplicated), and a blank live read keeps the server-computed excerpt instead of clearing it.

= 1.2.0 =
* New: a "Browse all macros" button now appears in the SEO and Social Media meta boxes (and on term-edit screens), opening the same full macro reference that was previously only on the settings page.
* New: every macro chip — both the inline ones in the hint line and those in the reference modal — is now click-to-copy (with a "Copied %macro%" confirmation), so you can drop a macro into a field without retyping it.
* Fix: the editor "Search appearance" preview now shows the auto-generated description for custom post types in the Classic editor. When the meta-description field was left blank, the preview said "No meta description" even though the live page outputs the excerpt-based description; it now previews the same %excerpt% default the front-end ships. A blank live read (e.g. the editor not yet ready at first paint) no longer wipes the computed excerpt, and the preview re-renders once the editor finishes loading.
* Fix: the Social Media card preview now falls back to the meta description's %excerpt% default when both the Social and SEO description fields are empty, instead of showing "No description set." Matches the front-end OG output.
* Internal: on a development site (WP_DEBUG/SCRIPT_DEBUG on) the admin script/style cache-buster now appends the file modification time, so edited assets are served fresh without a version bump. No effect in production.

= 1.1.2 =
* Fix: the editor "Search appearance" preview now shows the auto-generated description (the %excerpt% fallback) correctly. It previously read the excerpt only from the value present at page load and never followed the content editor, so on screens without a standard excerpt box — notably WooCommerce products, where the description lives in the content editor — the preview wrongly said "No meta description" even though the live page does output one. The preview now derives %excerpt% from the live editor (Block and Classic) just like the front-end. Front-end output was already correct and is unchanged.

= 1.1.1 =
* Fix: the Setup-checklist item "Business address & location added" now ticks once the required address parts are present (street + city + country). It was incorrectly gated on map coordinates (latitude/longitude), so a complete address with no coordinates never completed. Coordinates and postal code remain optional — Google geocodes from the address. The platform `iniseo/v1/state → schema_types.has_address` now uses the same definition, so the checklist and the reported data agree.

= 1.1.0 =
* New: **Crawl & score** page (SeoWP → Crawl). Pick content types and run a batched, cancellable crawl that fetches each published URL's rendered HTML (so page-builder content is measured), scores SEO and readability, stores the scores, and can optionally submit each URL to IndexNow. Available regardless of IndexNow (the IndexNow submit is an optional per-run extra).
* New: Per-post **Submit to IndexNow** button in the content-analysis metabox (published posts, when IndexNow is enabled).
* New: Posts/Pages **list actions** — row actions "Crawl & score" and "Submit to IndexNow", plus matching **bulk actions** for selected items.
* Fix: the SEO / Readability columns on the post list now light up after a crawl (the crawl writes the same rating meta the columns read).
* New: Setup-checklist items can be **dismissed** (e.g. address / opening hours on non-local-business sites); dismissed items no longer count toward the progress total, and can be restored.

= 1.0.10 =
* Fix: IndexNow settings (enable + content-type whitelist) now save correctly. They were silently reverted because the shared settings sanitizer — which runs on every save of the option — re-read the old IndexNow values from the database instead of honouring the IndexNow page's own submission. The sanitizer now keeps IndexNow values when they are present in the submitted data and only preserves the stored values when they are absent (the main Settings form), so a Settings save still never wipes IndexNow.
* Fix: Search-engine verification meta tags (Google / Bing) are now output on every page, not just the homepage — search engines may re-verify from any URL, and this matches every other SEO plugin.
* New: The site-wide "Default share image" can now be set from the Titles tab too (the same setting as Social → Default share image — one value, editable from either place, no duplicate save).

= 1.0.9 =
* Internal: SeoWP now registers its REST namespace (iniseo/v1) with the INI WP connector's family registry, so the SecurityWP plugin's "Require login for REST API" never blocks the SeoWP platform endpoint the control panel pulls. No user-facing change.

= 1.0.8 =
* Fix: the SEO title length check now measures the **SEO title** (the SeoWP title field), not the WordPress post title. Editing the SEO title now updates the "Aim for 30–60" check live; when the SEO title is left blank it measures the rendered template default ("Post title – Site name") — i.e. exactly what appears in the page <title>.

= 1.0.7 =
* New: Manual "Re-analyze" button by the SEO score ring, plus a per-suggestion re-check action, so the score can be refreshed on demand while editing.
* Improve: Content analysis now reads the rendered front-end HTML when the editor body is thin (page builders such as Elementor, and ACF-only layouts), so the word count and keyphrase checks reflect what visitors and search engines actually see — fixing misleading "very little content" warnings and stale scores.
* Internal: Head cleanup (generator / WLW / RSD / shortlink removal) moved to the SecurityWP plugin so there is a single owner. SeoWP keeps its noindex directives and all other SEO features.

= 1.0.0 =
* Initial release.
