=== PBJ SEO ===
Contributors: pbjakezphoto
Tags: seo, schema, open graph, twitter cards, sitemap
Requires at least: 6.4
Tested up to: 7.0
Requires PHP: 7.4
Stable tag: 3.3.0
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Lightweight, first-party SEO for PBJakez Photo. No third-party dependencies.

== Description ==

PBJ SEO outputs the on-page SEO metadata WordPress core does not, without any
external plugin. It is intentionally small and edits-friendly.

Features:

* **Admin dashboard (new in 3.0.0)** — a top-level "SEO" menu with these tabs:
  * **Checklist** — a per-page SEO audit (missing meta description, over-long title,
    no featured image, noindex, thin content) plus a site-wide checklist that includes a
    functional check that PBJ SEO's own output is live and a warning if a rival SEO plugin is active.
  * **Options** — an on/off switch, with a plain-English explanation, for every feature below.
  * **Business** — every piece of local-business data the plugin can emit, editable in one place.
  * **Robots & Sitemaps** — view the effective robots.txt, add custom rules, control exactly what
    the sitemap includes, and refresh/verify the sitemap with one click (new in 3.3.0).
  * **Google Tools** — step-by-step Google Analytics + Search Console setup with the two inputs
    the plugin acts on: GA4 Measurement ID (outputs the tag) and the verification token (new in 3.3.0).
  * **404s & Redirects** — an automatic 404 log with one-click redirect creation, plus a manual 301/302 manager.
* Document titles with a consistent separator (front page uses "Site Name – Tagline").
* Meta description, resolved per context (front page, singular, product, taxonomy, archive).
* Single context-aware canonical URL (replaces core's so there are never duplicates).
* Explicit robots directives: index/follow on content, noindex on search and 404,
  and a per-post opt-out via the `_pbj_seo_noindex` post meta.
* Open Graph and Twitter Card tags (title, description, url, site name, locale, image).
* JSON-LD structured data:
  * Organization + WebSite (with SearchAction) on every page.
  * WebPage + BreadcrumbList on singular pages.
  * Article (headline, datePublished/dateModified, author, publisher) on blog
    posts by default; opt other post types in via the `pbj_seo_is_article`
    filter and set the subtype (`NewsArticle`, `BlogPosting`) via
    `pbj_seo_article_type`. Swap the author for an editorial/Organization
    byline via `pbj_seo_article_author`.
  * Product (price, SKU, availability, aggregate rating) on WooCommerce products.
* Theme extension points: `pbj_seo_schema_graph` (append site-specific nodes to
  the JSON-LD graph) and `pbj_seo_default_image` (site-wide fallback share image).
* Core sitemap entries get `<lastmod>` from each post's modified date.
* Removes the WordPress version meta generator tag.
* Opt-in force-HTTPS: 301s plain-HTTP requests to the canonical HTTPS home host
  (collapses www in the same hop). Enable with `define( 'PBJ_SEO_FORCE_HTTPS', true )`
  or `add_filter( 'pbj_seo_force_https', '__return_true' )`. Safe by design: it is
  a no-op on installs whose home URL is not HTTPS (local sandboxes), and it skips
  WP-CLI, cron, and requests behind a TLS-terminating proxy (X-Forwarded-Proto).
* Image alt fallback: fills any empty or missing `<img alt>` (including theme-builder
  images served through index.php) so no image ships without alt text.
* Editor sidebar (v2.0.0): a "PBJ SEO" panel in the block editor with the per-post
  SEO title / meta description / noindex fields plus a live best-practices
  checklist (title & description length, featured image, image alts with
  click-to-select, content length, subheadings, internal links, slug quality,
  excerpt, indexability, FAQ schema opportunity) and a site-wide checklist
  (search visibility, HTTPS, permalinks, tagline, logo, site icon) — every
  failing item links straight to where it is fixed. A pre-publish panel
  repeats outstanding items at publish time.
* Site Essentials module (v2.0.0, merged from the retired PBJ Site Essentials
  plugin): `[pbj_year]` shortcode, security headers (HSTS, nosniff,
  X-Frame-Options, Referrer-Policy, CSP frame-ancestors), 404-triggered legacy
  and duplicate-slug 301 redirects (`pbj_seo_redirect_map` filter), geo meta
  tags, Service / FAQPage / LocalBusiness schema (now inside the main JSON-LD
  @graph), og:video / twitter:player URL absolutizing, and perf tweaks (emoji
  script, oEmbed discovery, REST head link removal + font/GTM preconnects).
  The module stands down automatically while the old standalone plugin or the
  former mu-plugins are still present.
* SEO hygiene (v2.0.0): attachment pages 301 to their parent
  (`pbj_seo_redirect_attachments` filter), feeds send `X-Robots-Tag: noindex`,
  robots.txt advertises the sitemap, article OG tags carry
  published/modified times, og:image gets width/height/alt when resolvable,
  and shortlink/RSD head links are removed.

Relies on WordPress core for XML sitemaps (`/wp-sitemap.xml`).

== Per-page overrides ==

Set these post meta keys on any page/post/product:

* `_pbj_seo_title` — custom full document title (string), overriding the default.
* `_pbj_seo_description` — custom meta description (string).
* `_pbj_seo_noindex` — set to `1` to noindex that entry.

Example via WP-CLI:

`studio wp post meta update 1 _pbj_seo_description "Your custom description."`

== Installation ==

1. Upload the `pbj-seo` folder to `wp-content/plugins/`, or install the zip via
   Plugins → Add New → Upload Plugin.
2. Activate "PBJ SEO" through the Plugins menu.
3. No configuration screen is required; defaults apply immediately.

== Updating ==

This is a self-hosted plugin. The `Update URI` header points to pbj.tech and prevents
the WordPress.org repository from ever offering a conflicting update. To ship a new
version, bump the `Version` header and `Stable tag`, then redistribute the zip.

== Upgrade Notice ==

= 3.0.0 =
Major release. Adds a full admin dashboard (Settings → PBJ SEO): SEO checklist + site audit,
on/off options for every feature, a robots.txt/sitemap manager, and a 404 log with one-click
redirects. All existing behavior is unchanged — every option defaults ON. No action needed on upgrade.

= 2.0.0 =
Merges PBJ Site Essentials into PBJ SEO — after updating, deactivate and delete
the standalone "PBJ Site Essentials" plugin (the merged module stands down until
you do, so there is no double output either way). Force-HTTPS is now ON by
default (still a no-op on non-HTTPS installs such as local Studio sandboxes;
opt out with `define( 'PBJ_SEO_FORCE_HTTPS', false )`).

== Changelog ==

= 3.3.0 =
* **New Google Tools tab** — plain-English, step-by-step walkthroughs for connecting the site to Google Analytics and Google Search Console, with direct links to each console:
* **GA4 built in**: paste your Measurement ID (G-XXXXXXXXXX) and PBJ SEO outputs the Google tag on every page — no extra plugin. Logged-in editors/admins are never tracked, so your own work doesn't skew the numbers.
* **Search Console verification built in**: paste Google's HTML-tag token (or the whole tag — both work) and the site emits the google-site-verification meta. A Bing Webmaster Tools field is included too (msvalidate.01).
* **Sitemap controls** (Robots & Sitemaps tab): choose exactly what the sitemap includes — per-post-type toggles, category/tag archives, author archives, and an exclude-by-ID list. Defaults match core exactly, so nothing changes until you untick something.
* **"Refresh sitemap now" button**: rebuilds the sitemap routes, clears any cached copy, then fetches the live sitemap and reports how many URLs crawlers currently see.
* Checklist tab now includes Google Analytics + Search Console rows (warnings, with a Fix link to the new tab).

= 3.2.0 =
* **Neutral defaults — no business data baked in.** The plugin previously shipped with its author's own business data as defaults (LocalBusiness NAP/geo, the Service schema map, the areaServed list, the legacy redirect map, and Jupiter FL geo-meta fallbacks). All of it has been removed. Your data is yours to enter:
* **New Business tab** (SEO → Business) — every piece of local-business data the plugin can emit, editable in one place: business name, schema type, phone, email, price range, image, description, postal address, geo coordinates, the service-area list, and the per-page Service schema map. Filled-in fields drive the homepage LocalBusiness node, the Service-node provider, the areaServed lists, and the geo meta tags; empty fields simply stand down (no node, no tags).
* New `pbj_seo_business_info` filter runs over the saved Business-tab values, so a site-specific mu-plugin or theme can still override or extend everything in code.
* `pbj_seo_service_schema_map` and `pbj_seo_redirect_map` now default to empty maps (the filters and the `pbj_service_schema_map()` theme-global override still work exactly as before). Legacy redirects are best managed on the 404s & Redirects tab.
* Geo meta still syncs from Rank Math local-SEO options when present, but no longer falls back to hardcoded coordinates.
* Existing sites that relied on the old defaults must fill in the Business tab (or add the filter callbacks) when upgrading.

= 3.1.0 =
* Added a License tab (Settings sidebar → SEO → License) where you enter your PBJ license key to unlock automatic updates. The plugin is fully functional without a key; a key covers up to 3 sites. On pbj.tech itself no key is required.

= 3.0.1 =
* The admin dashboard moved from Settings → PBJ SEO to its own top-level "SEO" item in the sidebar, so it is no longer buried under Settings. No settings or behavior changed.

= 3.0.0 =
* **New: admin dashboard at Settings → PBJ SEO** — the plugin gains a real settings UI (a deliberate
  reversal of its original single-file, no-dashboard design), in four tabs:
* **Checklist tab** — scans every published page and post and lists exactly what each one needs
  (no meta description, title too long/short, no featured image for og:image, set to noindex, thin content),
  each linking to its editor; plus a site-wide checklist (permalinks, search visibility, tagline, HTTPS,
  logo/icon, front-page og:image, XML sitemap enabled) with a functional check that PBJ SEO's own head
  hooks are attached and a warning when a conflicting SEO suite (Yoast / Rank Math / AIOSEO) is active.
* **Options tab** — every feature is now individually switchable, each with a detailed explanation:
  force-HTTPS, security headers, LiteSpeed edge cache, geo meta, built-in legacy redirects, custom
  redirects, 404 logging, attachment redirects, feed noindex, head cleanup, and performance tweaks.
  All default ON, so behavior is identical to 2.0.0 until you change something. A `PBJ_SEO_FORCE_HTTPS`
  constant still overrides the force-HTTPS toggle.
* **Robots & Sitemaps tab** — shows the effective robots.txt, lets you append custom rules (saved and
  emitted through the robots_txt filter), and reports XML sitemap status.
* **404s & Redirects tab** — a lightweight, self-trimming 404 logger records not-found URLs with hit
  counts and referrers; one click turns any logged 404 into a redirect. A full 301/302 redirect manager
  (add / delete, per-rule hit counter) replaces the old code-only redirect map; the built-in legacy map
  still applies on 404 and is now toggleable.
* Settings are stored in the `pbj_seo_settings` option; redirects in `pbj_seo_redirects`; the 404 log in
  `pbj_seo_404_log`; custom robots rules in `pbj_seo_robots_extra`.

= 2.0.0 =
* MERGED: the whole PBJ Site Essentials plugin (security headers, legacy +
  duplicate-slug 301 redirects, geo meta, Service/FAQPage/LocalBusiness
  schema, meta URL absolutizing, perf tweaks, `[pbj_year]`). The standalone
  plugin is retired; while it is still active the merged module stands down,
  and the former mu-plugin handover guards are preserved. Service/FAQ/
  LocalBusiness schema now ride in the main JSON-LD @graph instead of
  separate script tags. Theme overrides via the old global functions
  (`pbj_service_schema_map`, `pbj_extract_faqs_from_post`) still work, plus
  new `pbj_seo_service_schema_map` and `pbj_seo_redirect_map` filters.
* NEW: block editor "PBJ SEO" sidebar — per-post SEO title / meta description /
  noindex fields (previously only settable via WP-CLI) plus a live SEO
  best-practices checklist with click-to-fix actions, a site-wide checklist,
  and a pre-publish review panel.
* NEW: attachment pages 301 to their parent post (`pbj_seo_redirect_attachments`
  to disable); feeds send `X-Robots-Tag: noindex, follow`; robots.txt gains a
  `Sitemap:` line; `article:published_time`/`article:modified_time` OG tags;
  `og:image:width`/`height`/`alt` and `twitter:image:alt` when the share image
  is the featured image; shortlink and RSD `<head>` links removed.
* CHANGED: force-HTTPS is now enabled by default (was opt-in). Unchanged
  safety: it only ever redirects when the home URL itself is HTTPS.
* FIXED: LiteSpeed edge-cache headers moved from `send_headers` to
  `template_redirect` — `send_headers` fires before the main query, so
  search/404/preview pages could previously be cached as public.

= 1.4.0 =
* LiteSpeed edge caching: anonymous front-end pages now send
  `X-LiteSpeed-Cache-Control: public` (6h TTL, `pbj_seo_cache_ttl` filter) so
  LiteSpeed servers full-page-cache them with no separate cache plugin.
  Personalized requests (logged in, cart/checkout, comment/postpass cookies,
  search, 404, previews, feeds) are marked no-cache; `pbj_seo_cacheable`
  filter for site-specific rules. Content changes (post save/delete, comments,
  theme/menu/customizer/plugin changes) send `X-LiteSpeed-Purge: *`. Both
  headers are ignored on non-LiteSpeed servers - zero behavior change there.

= 1.3.1 =
* Posts page (blog index) now honors its own `_pbj_seo_description` post meta
  and featured image for the description / og:image, instead of always
  falling back to the site tagline and default image.

= 1.3.0 =
* Add opt-in force-HTTPS redirect (PBJ_SEO_FORCE_HTTPS constant or
  `pbj_seo_force_https` filter). 301s to the canonical HTTPS home host;
  no-op when the home URL is not HTTPS, under WP-CLI/cron, or behind a
  TLS-terminating proxy.

= 1.2.0 =
* Add Article JSON-LD node (headline, dates, author, publisher) on posts, with
  `pbj_seo_is_article`, `pbj_seo_article_type`, and `pbj_seo_article_author` filters.
* Add `pbj_seo_schema_graph` filter so themes can append site-specific schema nodes.
* Add `pbj_seo_default_image` filter for the site-wide fallback share image.
* Add `<lastmod>` to core XML sitemap entries.
* Remove the WordPress version meta generator tag.

= 1.1.0 =
* Add `_pbj_seo_title` post-meta override for a custom full document title (front page or any singular).

= 1.0.0 =
* Initial release. Replaces Rank Math with first-party meta, schema, and alt-text output.
