===  Dynamic OG Image Generator ===
Contributors: plugupp, freemius
Tags:              og image, open graph, social sharing, screenshot, seo
Requires at least: 6.0
Tested up to:      7.0
Stable tag:        2.0.51
Requires PHP:      7.4
License:           GPLv2 or later
License URI:       https://www.gnu.org/licenses/gpl-2.0.html

Automatically generates real screenshot-based Open Graph images for your pages and posts — no templates, just your actual page.

== Description ==

Most SEO plugins let you set a static image as your og:image. Dynamic OG Image Generator goes further — it takes a real browser screenshot of each page and uses that as the og:image. When someone shares your link on social media, they see exactly what your page looks like.

**How it works**

1. When a page or post is published, a screenshot job is queued in the background via WP-Cron.
2. The plugin submits the job to the PlugUpp screenshot service, which takes a real browser screenshot at the standard 1200x630 Open Graph size and delivers it back to your site.
3. The cached image is injected as `og:image` into your page's `<head>`, overriding your SEO plugin's output where a screenshot is available.
4. Screenshots refresh automatically on a configurable schedule (default: every 30 days).

**Key features**

* Real screenshot — not a template, not a featured image. The actual page.
* Automatic — screenshots taken and refreshed in the background. No manual steps.
* No API key required — the plugin connects to the PlugUpp screenshot service using your licence. No additional setup or account to manage.
* Per-post control — enable or disable per page/post from the Gutenberg sidebar.
* SEO plugin aware — works alongside Yoast SEO, Rank Math, and All in One SEO. Falls back to their og:image when no screenshot is ready.
* Configurable fallback — use your SEO plugin's image, a custom fallback from your Media Library, or nothing until the screenshot is ready.
* Cache management — view cache size, clear all screenshots, or queue a full regeneration from the settings page.

**Requirements**

A PlugUpp licence. Free licences include a monthly screenshot allowance sufficient for most small sites. Premium licences include a higher quota and unlock additional capture options.

**Compatible SEO plugins**

* Yoast SEO
* Rank Math
* All in One SEO (AIOSEO)

**Documentation**

Full user documentation - step-by-step guides for every setting, the Gutenberg sidebar, cache management, SEO plugin compatibility, troubleshooting, and the FAQ - lives at https://docs.plugupp.com/dynamic-og-image-generator/.

== Installation ==

1. Upload the plugin folder to `/wp-content/plugins/` or install via **Plugins → Add New**.
2. Activate the plugin via the **Plugins** menu.
3. Go to **Settings → Dynamic OG Images**.
4. Ensure the plugin is enabled. Screenshots will begin generating in the background as WP-Cron fires.

No API key or additional account is required. The plugin authenticates with the PlugUpp screenshot service automatically using your licence.

== Frequently Asked Questions ==

= Do I need to set up anything beyond a PlugUpp licence? =

No. The plugin connects to the PlugUpp screenshot service using your licence. No separate API key or additional signup is needed.

= How long does it take for a screenshot to appear? =

Screenshots are generated asynchronously. The plugin submits a job and the result is delivered back to your site — typically within a few seconds to a couple of minutes depending on server load. On a site with active traffic and WP-Cron firing regularly, screenshots usually appear shortly after publishing. You can also trigger an immediate regeneration from the Gutenberg sidebar using the "Regenerate Now" button.

= What happens while a screenshot is being generated? =

Depending on your fallback setting, either your SEO plugin's default og:image is shown, a custom image you choose, or no og:image until the screenshot is ready.

= Can I disable it for specific pages? =

Yes. Open any page or post in the block editor and find the "OG Image" panel in the sidebar. Toggle it off for that specific post — this overrides the global setting.

= Does it work with page builders like Elementor, Divi, or BeTheme? =

Yes. When the "Automatically queue a new screenshot whenever a post is updated" setting is enabled, the plugin detects content changes from the Block Editor and Classic Editor (always), and from the following page builders that store their content separately from the main post body: Elementor, Beaver Builder, Divi (Elegant Themes), BeTheme (Muffin Builder), Oxygen, Themify Builder, Breakdance. If you use a builder not listed here, you can still trigger captures manually with the "Regenerate Now" button in the block editor sidebar — or let us know which builder you would like added.

= What happens if my screenshot quota is exhausted? =

Posts that would have been screenshotted are marked with a "quota reached" status. No screenshot is attempted until the next billing period when quota resets. You can upgrade your plan at any time from plugupp.com to increase your quota.

= Does it work with WooCommerce product pages? =

Not in this version — pages and posts only. WooCommerce product support is planned for a future release.

= Does this replace my SEO plugin? =

No. It only handles og:image. Your SEO plugin continues to manage all other meta tags. When a screenshot is ready, the plugin overrides only the og:image and twitter:image tags.

== Screenshots ==

1. Server status, current plan, and live screenshot quota at the top of the Settings page.
2. Global capture defaults — refresh interval, blocking options, wait conditions, and selectors.
3. Cache management — view stats, clear the cache, or queue a full regeneration.
4. Gutenberg sidebar panel — per-post toggle, status, preview thumbnail, and Regenerate Now button.
5. Example og:image on social media — a real page screenshot used as the share preview.

== External services ==

This plugin connects to two external services to provide its functionality. Both are operated by PlugUpp.

= PlugUpp Screenshot Service =

The plugin sends screenshot job requests to the PlugUpp Screenshot Service at https://screenshots.plugupp.com, which captures browser screenshots of your pages and returns them for use as Open Graph images.

* When data is sent: when a page or post is first published, when an enabled page is updated and the "Regenerate on post update" setting is on, when you click "Regenerate Now" in the block editor, on the configurable refresh schedule (default 30 days), and when the Settings page is loaded (to populate the connection status indicator and the screenshot usage figures).
* What data is sent: the public URL of the page to be captured, your PlugUpp licence key, your site's Freemius site identifier, the URL the service should send the result to (a REST endpoint on your site), and the capture configuration (viewport width, image quality, country routing, etc.).
* What is received back: the captured screenshot image, which is downloaded by your site and stored locally as a WebP file in your uploads directory.
* Terms of service: https://plugupp.com/terms-of-service/
* Privacy policy: https://plugupp.com/privacy-policy/
* Legal notice: https://plugupp.com/legal-notice/

= Freemius =

The plugin uses the Freemius platform for licence activation, plan changes, plugin updates (for paid plans), and as the Merchant of Record for purchases.

* When data is sent: on first plugin activation as part of the user-consented opt-in flow, on licence activation or deactivation, on plugin update checks (paid plans), and on uninstall (for optional feedback). Sending the initial opt-in data is the user's choice - declining the opt-in still lets the plugin work, but skips telemetry.
* What data is sent: standard Freemius opt-in data including site URL, administrator email address, WordPress version, PHP version, plugin version, and active theme name.
* Terms of service: https://freemius.com/terms/
* Privacy policy: https://freemius.com/privacy/

== Changelog ==

= 2.0.51 =
* Fixed: WordPress.org build of 2.0.50 was missing the entire `assets/` folder due to an SVN deploy oversight. The Settings page stylesheet, admin JS, Gutenberg sidebar JS and bundled plugin icon were absent, leaving the Settings page unstyled and the sidebar panel non-functional. No code changes - this release re-ships 2.0.50's code with the assets bundle restored. Freemius-delivered builds were unaffected.

= 2.0.50 =
* Added: PlugUpp brand mark on the plugin's admin pages. The plugin's page title row now carries a small PlugUpp logo on the right (linking out to plugupp.com), and the admin footer reads "Dynamic OG Image Generator vX.X.X by PlugUpp". The logo is bundled in the plugin's assets - the admin page never fetches a remote asset to render. Consistency change to align with other PlugUpp plugins.

= 2.0.49 =
* Added: headline quota line at the top of the Screenshot Usage section. Reads "You are on the [plan] plan - N of M screenshots remaining this month" for paid plans, or "You are on the Free plan - N startup screenshots remaining for this site" on Free. The detailed breakdown stays below.
* Added: live quota estimate under the Refresh interval setting. Counts your published pages and posts and shows the approximate screenshots needed per 30 days at the current refresh interval. Lets you see at a glance how much of your quota the refresh schedule will consume.
* Changed: when a post hits the monthly quota cap, the block editor sidebar now adds a brief "Higher plans add monthly capacity" line alongside the existing message, with a softer "Try Premium →" link.
* Changed: licence-inactive sidebar notice now links to "Manage your subscription" rather than the previous generic account link, matching the verb used on the Settings page.
* Changed: upsell verbs across the plugin standardised on "Try Premium" rather than the previous mix of "Upgrade plan" and "See plans →".

= 2.0.48 =
* Compliance: three trialware traces surfaced by re-auditing the produced 2.0.47 free zip. The Settings page upgrade banner used a lock icon and a feature-enumeration subtitle. The free build's admin stylesheet also still contained the `.doig-premium-field*` CSS rules from a much earlier version - a complete styling toolkit for greyed-out disabled inputs with "Pro" badges, orphaned (no PHP or JS references it) but visible in the source tree. All three are removed. The upgrade banner is now a plain two-line text-only link.

= 2.0.47 =
* Compliance: silenced four Plugin Check warnings flagged on the 2.0.46 build. The flagged code paths are legitimate (set_time_limit after fastcgi_finish_request to extend the deferred image-download budget, GET-only tab navigation that needs no nonce, and the atomic claim_job compare-and-clear on _doig_job_id that cannot be done race-free through update_post_meta). Each call site now carries an explicit phpcs:ignore comment with a justification referencing the design rationale.

= 2.0.46 =
* Compliance: removed every reference to paid-tier features from the free build's data structures, in response to the WordPress.org review team's Guideline 5/6 feedback on the 2.0.45 submission. The free build's screenshot-job builder, settings defaults, and per-post meta registration now contain only the fields the free tier actually uses; the contextual upsells in the Settings page and block editor sidebar have been simplified to generic prose with a link, with no enumeration of paid feature names. No customer-visible change to the free tier's actual capabilities.

= 2.0.45 =
* Fixed: the plugin icon bundled in 2.0.44 still did not appear on the in-plugin Plans and Pricing page, the Account page, or the upgrade dialogs. Cause: the Freemius SDK's path-derivation logic resolves to vendor/freemius/assets/img/ rather than the plugin's own assets/img/ directory. The plugin now registers the documented plugin_icon filter to point the SDK at the bundled icon explicitly.

= 2.0.44 =
* Added: plugin icon bundled in the build at assets/img/. The icon now appears on the in-plugin Plans and Pricing page, the Account page, and the upgrade dialogs (it was missing before because the Freemius SDK reads the icon from inside the plugin zip rather than the Freemius dashboard upload).

= 2.0.43 =
* Added: Documentation links across the plugin UI. A "Docs" action link sits alongside "Settings" on the Plugins admin row, a "Documentation" link is added to the right-hand meta row of the same screen, and a contextual Documentation link appears at the top-right of every tab on the plugin's settings page. Each link opens the public documentation at docs.plugupp.com in a new tab and points at the page relevant to the surface that was clicked.
* Added: documentation pointer in the readme so the docs site is discoverable from the WordPress.org listing page too.

= 2.0.42 =
* Fixed: text under the "Clear Entire Cache" and "Regenerate All Screenshots" buttons was wrapping at a narrower width than the rest of the Settings page. The 600-pixel cap on those descriptions has been removed so the section now matches the rest of the page's natural width.

= 2.0.41 =
* Changed: reordered the description and warning beneath the "Regenerate All Screenshots" button. The button's effect is now explained first, with the backup warning underneath, so the reader knows what the action does before being warned about it.

= 2.0.40 =
* Added: backup-recommendation warning beneath the "Regenerate All Screenshots" button on the Settings page. Bulk regeneration writes new Media Library attachments for every enabled post and replaces existing ones; taking a fresh backup first makes a rollback simpler if anything goes wrong.

= 2.0.39 =
* Added: page builder content-save detection. Edits made in Elementor, Beaver Builder, Divi, BeTheme (Muffin Builder), Oxygen, Themify Builder, or Breakdance now trigger the same auto-regen as a Block Editor save. These builders store content in post meta rather than the main post body, so the plugin now watches the appropriate meta keys for each. The Settings page lists which builders are supported, and the `doig_supported_builders` / `doig_render_affecting_meta_keys` filters let site owners add their own.

= 2.0.38 =
* Fixed: the "regenerate on update" feature no longer schedules a new screenshot when nothing visible has changed. Previously, every save of a post - including Update clicked with no edits, sidebar metabox writes, custom-field tweaks, and capture-setting tweaks - would schedule a fresh capture. The plugin now compares post content, title, and excerpt before/after the save and only schedules if one of those actually differs. Saves to per-page DOIG capture settings (delay, viewport, hide selectors, etc.) no longer trigger an auto-regen; click "Regenerate Now" when you want to preview the new setting.
* Fixed: clicking "Regenerate Now" now cancels any pending scheduled regen for the same post. Previously, editing a post and then immediately clicking Regenerate Now could submit two identical jobs (the manual click plus the cron event scheduled by the edit firing seconds later). The manual click now takes precedence and the scheduled event is dropped.

= 2.0.37 =
* Changed: internal documentation cleanup across the plugin readme and code comments. No functional change, no settings affected.

= 2.0.36 =
* Fixed: the `Capture delay` and `Click before capture` settings were silently ignored. The plugin submitted these values to the screenshot service under internal names instead of the names the service expects (`capture_delay` instead of `delay`, `click_before_capture` instead of `click`), so the service used its built-in defaults regardless of what users had configured. The plugin now translates both internal names to the service-native equivalents at submit time; the storage keys and UI labels stay descriptive for clarity. Pairs with a matching screenshot-service patch that adds four other valid capture options (`scroll_into_view`, `scroll_into_view_adjust_top`, `error_on_click_selector_not_found`, `ip_country_code`) to its allowed list.

= 2.0.35 =
* Fixed: proxy callback handler is now asynchronous. Previously, when the proxy POSTed a completed screenshot to the plugin's REST endpoint, the plugin downloaded the image and created the Media Library attachment before returning 200. Under bulk regeneration load, 30+ parallel callbacks could saturate PHP-FPM workers and individual responses exceeded the proxy's callback timeout, producing repeated `callback_failed_timeout` warnings in the proxy log (the polling fallback still delivered each screenshot correctly, but the warnings were noisy and the proxy daemon wasted time on slow responses). The callback handler now returns 200 immediately via `fastcgi_finish_request()` on PHP-FPM hosts (which is every modern WordPress managed host), then runs the image download and Media Library save in the same PHP process after the client connection is closed. The proxy gets its response in single-digit milliseconds regardless of plugin load. Non-FPM hosts fall back to WP-Cron. The atomic claim_job introduced in 2.0.32 still prevents duplicate processing if the polling fallback races against the deferred handler.

= 2.0.34 =
* Added: contextual premium-features hint at the end of the Screenshot Capture section on the Settings page, listing the additional capture controls (configurable viewport, capture delay, hide selectors, scroll offset, country routing, device pixel ratio) that premium adds. Plain description-styled text - no mock UI elements or disabled inputs, just an inline pointer at the spot where a reader is already scanning the related free fields.
* Added: standalone "Media Library Integration" section on the Settings page in the free build, describing what premium adds (save to Media Library, replace previous capture, set as Featured Image). The section has no fields - it is purely a contextual summary positioned where the corresponding premium Output section appears in the paid build.

= 2.0.33 =
* Fixed: the "Download Log" button on the Logs tab previously produced a file containing the admin page HTML with the log content embedded inside, rather than a clean log file. Cause: the download handler ran inside the page-render callback, by which time WordPress had already streamed the admin shell HTML to the browser, so the Content-Type and Content-Disposition headers were silently rejected and the log content was readfile()'d into the middle of the in-progress HTML response. Moved the handler to admin_init so the headers take effect and the download arrives as a clean text/plain file containing the full log.

= 2.0.32 =
* Fixed: when the async callback from the screenshot server and the next polling pass both observed the same completed job within the same second, both paths previously downloaded the image and created a Media Library attachment, producing two or three attachments for one screenshot. Added an atomic SQL compare-and-clear on the job_id post meta so exactly one path wins and processes the result; the other returns silently. No visible behaviour change in the common case where callback arrives before the next poll; eliminates the duplicate-attachment edge case observed during high-throughput testing on the new server-side daemon.

= 2.0.31 =
* Changed: the `Plugin booted with DOIG_PROXY_URL override` log line is now throttled to once per day rather than firing on every PHP request. Previously every page load, AJAX call, and WP-Cron tick wrote the same line to the log file, which flooded the support log on busy installs without adding new information (the override is true for the entire lifetime of the wp-config constant). The throttle uses a 24-hour transient so the support-log signal is preserved without the noise.

= 2.0.30 =
* Added: `DOIG_PROXY_URL` wp-config constant. When defined, the plugin points all outbound proxy calls (submit, poll, health, usage) at the given URL instead of the production screenshot service. A persistent warning banner appears at the top of the Settings page and a matching badge appears at the top of the block editor sidebar so the override is impossible to miss. Intended for test installs that point at a staging screenshot server. When the constant is not defined the plugin uses the production URL as before.
* Fixed: the Open Graph injector previously re-scheduled a screenshot on every page render for posts with terminal failure status, which on a URL polled by an uptime monitor or cache warmer produced a new doomed job every few minutes indefinitely. The injector now treats `failed` and `quota_exceeded` as terminal alongside `pending` - the user can manually re-attempt via Regenerate Now, and the daily refresh continues to retry failed posts once per day.

= 2.0.29 =
* Fixed: WordPress-internal singular post types (such as `wp_global_styles` created by block themes, `wp_block`, `wp_template`, `wp_navigation`) no longer get screenshot jobs scheduled. These types respond at URLs but are not real renderable pages, and the screenshot service returns HTTP 500 when it tries to capture them, which previously triggered monitoring alerts. The OG injector, the scheduler, and the per-post handler all now allow only `post` and `page` types.

= 2.0.28 =
* Fixed: after correcting an http:// Site Address to https://, the block editor sidebar continued to show "Your WordPress site URL is set to http://" on posts that had previously failed because of the misconfiguration. The message was a duplicate of the proactive top-of-panel notice, driven by stale post meta, and is now removed entirely. The proactive notice (which clears the moment the URL is fixed) is the single source of truth.

= 2.0.27 =
* Fixed: the http:// site URL warning banner on the Settings page did not appear on installs that loaded WordPress admin over https://, even when the persistent Site Address was http://. The check now reads the canonical Site Address from the database rather than home_url(), which adjusts to match the current request scheme. The same fix is applied to the block editor sidebar warning, the Regenerate All pre-flight check, and the per-post submit guard, so all four paths now behave consistently when the Site Address is misconfigured.
* Added: a pre-flight HTTPS check on the Settings page "Regenerate All" button. Previously the button would silently queue jobs that were all destined to fail; now it refuses with the same actionable message used elsewhere.

= 2.0.26 =
* Added: pre-flight HTTPS check. Sites whose WordPress Site Address is configured as http:// now see a clear actionable message on the Settings page and in the block editor sidebar rather than the raw "url must use the https scheme" error from the screenshot service. The Regenerate Now button is also disabled until the site URL is fixed.
* Changed: the "Save the post to apply this change..." sidebar message now reads "enable/disable" (the message fires in both directions, not just when enabling) and uses the standard WordPress amber warning treatment rather than the previous plain description text.
* Added: a small "Unlock per-post capture overrides with Premium" prompt at the bottom of the block editor sidebar (free build only). Mirrors the upgrade banner already on the Settings page.

= 2.0.25 =
* Internal: Gutenberg sidebar JS reverted to a single file using Freemius's documented `<fs_premium_only>` block-comment markers around the premium panels and meta-key constants. Replaces the brief 2.0.24 architecture that used a separate gutenberg__premium_only.js file plus a wp.hooks filter; the inline-marker approach is simpler and is Freemius's official mechanism. No customer-visible change.

= 2.0.24 =
* WordPress.org compliance: all premium-feature plumbing has been removed from the free build. The settings page, block editor sidebar, post-meta registration, settings sanitisation, and screenshot job builder no longer contain any code that handles premium features. Premium remains a separately-distributed build sold through Freemius.
* Added: a "Premium" tab on the Settings page describing what the paid plans add. Replaces the previous in-line locked-field placeholders.
* Internal: readme.txt URLs corrected to point to the live plugupp.com/terms-of-service/, /privacy-policy/, and /legal-notice/ pages.

= 2.0.23 =
* Internal: uninstall cleanup now uses the WordPress filesystem API (WP_Filesystem) instead of native rmdir(). Replaces the previous glob + per-file delete + rmdir block with a single recursive WP_Filesystem->delete() call. The WordPress.org Plugin Check scanner does not honour phpcs:ignore for the alternative-function rule, so the native call had to be removed entirely. No customer-visible change.

= 2.0.22 =
* Internal: consolidates two phpcs:ignore annotations onto the same line as the call they apply to (Plugin Check did not honour the "comment-on-previous-line" form for the log-rotation rename and the uninstall rmdir). Also corrects the rmdir sniff name. No behavioural change.

= 2.0.21 =
* Internal: WordPress.org Plugin Check compliance pass — output escaping, filesystem operations, and translation loading brought up to current WP coding standards. No behavioural change.
* Internal: settings page template body wrapped in a function so internal template locals don't leak into the global namespace.
* Internal: build cleanup: .DS_Store removed from the tracked source tree and added to .gitignore.

= 2.0.20 =
* Internal: restores the polling timeout in the block editor sidebar to its production value of 60 seconds. 2.0.19 had it shortened to 100 ms for a one-off visual check.

= 2.0.19 =
* Internal: transient test build to visually verify the amber styling on the "Still working..." timeout notice in the block editor sidebar. The polling timeout is intentionally shortened to 100 ms so the notice fires on every Regenerate Now click. Install 2.0.20 (which restores the polling timeout) immediately after.

= 2.0.18 =
* Fixed: helper text under the "Regenerate Now" button in the block editor sidebar now actually renders. The earlier 2.0.17 logic computed the right message but passed it via a prop the underlying WordPress Button component does not honour; the text is now rendered as a sibling element below the button.
* Added: the installed plugin version is displayed at the bottom of the Settings page (both the Settings and Logs tabs).

= 2.0.17 =
* Fixed: the "Regenerate Now" button in the block editor sidebar is now disabled when the per-post enable toggle has been changed but the post has not yet been saved. Helper text reads "Save the post to apply this change and enable regeneration." Previously, clicking Regenerate Now in that state returned a confusing "OG image generation is disabled for this post" error because the REST handler reads the persisted setting, not the unsaved one.
* Changed: the "Still working. Reload the editor in a minute..." sidebar message now uses the standard amber WordPress warning treatment instead of the blue info treatment. It catches the eye when it appears.

= 2.0.16 =
* Changed: readme.txt "Tested up to" header bumped to WordPress 7.0 to satisfy the WordPress.org plugin directory submission scanner. No functional change.

= 2.0.15 =
* Changed: the Settings page no longer surfaces raw HTTP status codes or technical error messages in the Screenshot server status indicator and the Screenshot usage section. Both fields now show a friendly fallback message when something goes wrong (most commonly a transient HTTP 401 during the first install while the activation webhook is propagating to the screenshot server). The technical detail is written to the plugin log for diagnostic purposes.

= 2.0.14 =
* Changed: on first activation, the daily screenshot refresh now schedules its first run 24 hours later instead of immediately. Fresh installs no longer queue a bulk capture of every page within seconds of activation - the admin gets a full day to read the Enable-sitewide warning and adjust per-page settings before any sweep runs. Existing installs are unaffected.
* Fixed: the daily refresh now skips posts that are already pending (a screenshot job in flight). Previously, if the daily refresh fired while a manual Regenerate Now job was waiting on its callback, that post got queued a second time and burned a second quota credit when the bulk processor ran.
* Fixed: the daily refresh now schedules the bulk queue processor for immediate run, replacing any existing future event. Previously a 12-minute polling-guarantee event from a recent manual Regenerate Now would suppress the daily refresh's own immediate trigger, delaying bulk processing by up to 15 minutes on sites with 5-minute server cron.
* Changed: log lines around the bulk queue processor are more informative. The "Cron job started" line now only appears for posts that actually progress to submission (previously it logged before the post-status and Enable-sitewide checks, which made the log misleading when posts were silently skipped). The "Queue complete" line now includes a breakdown of outcomes - submitted, queued for retry, failed, skipped (with reasons) - so it is obvious at INFO log level what the queue processor actually did.

= 2.0.13 =
* Added: "External services" disclosure section in readme.txt covering the PlugUpp Screenshot Service and the Freemius platform, as required by the WordPress.org plugin directory. No functional change.

= 2.0.12 =
* Added: warning under the "Enable sitewide" checkbox on the Settings page making it clear that turning the setting on will queue a screenshot for every published page and post at the next refresh, and that on large sites this can use a significant share of the monthly quota. The existing per-page override hint is folded into the same line.

= 2.0.11 =
* Changed: the "Screenshot usage" section now shows the date the monthly quota resets and, separately, the date the subscription renews. Previously a single "Current billing period" range was shown, which conflated the two and was confusing for annual subscriptions where the billing window is a year wide but the quota actually rolls monthly.

= 2.0.10 =
* Added: "Screenshot usage" section on the Settings page showing the current Startup count (out of the per-site startup allowance) and, for paid plans, the Monthly count and current billing-period dates. The figures come from the screenshot server and update on every Settings page load.
* Changed: Licence row no longer displays hard-coded quota numbers. The actual usage and quotas now come from the screenshot server, so the displayed figures always match reality.

= 2.0.9 =
* Added: debug log line showing the full payload sent to the screenshot server before each submission. Useful when diagnosing per-post regen issues. The licence key is redacted to its length only.

= 2.0.8 =
* Fixed: free-to-premium upgrade now uses the Freemius SDK's set_basename() mechanism, which auto-deactivates the free version when the premium one activates. Previously both plugin folders briefly co-existed during upgrade and triggered a "Cannot redeclare function" fatal.

= 2.0.7 =
* Fixed: fatal error "Cannot redeclare function doig_fs_uninstall_cleanup()" when upgrading from the free version to the premium version. The function is now guarded so the brief window where both plugin folders co-exist no longer breaks activation.

= 2.0.2 =
* Added: "Complete plugin setup" banner on the Settings page when the plugin has not yet been activated via Freemius. Includes a one-click "Activate now" button.
* Added: connection guard that prevents the plugin from submitting screenshot jobs (and from queueing cron retries) when the site is not yet connected to the PlugUpp screenshot server. Stops the log filling with HTTP 422 errors before activation completes.
* Added: sidebar Regenerate Now button is now disabled with a help message when the plugin has not been activated.

= 2.0.1 =
* Changed: the "Enable dynamic OG images" sitewide toggle now defaults to OFF on a fresh install. Existing sites are unaffected (their saved setting is honoured); the change only applies if no setting has ever been saved. This prevents a brand-new install from immediately consuming screenshot quota before the admin has opted in.
* Renamed user-visible references to "proxy" -> "screenshot server" throughout the admin UI and debug logs (no functional change; internal class / method names retained).
* Settings page upgrade banner and per-field Premium badges are now clickable; both open the Freemius upgrade flow.
* Per-field "Capture from country" is now a dropdown of the supported countries (was a free-text input).
* Sidebar "Capture from country" is now a dropdown with explicit "Inherit from Settings" and "No country routing" choices.
* Sidebar "Regenerate Now" now polls the screenshot server for status and updates the preview inline; no editor reload required.
* Sidebar "Regenerate Now" button is now disabled when the effective generation state for the post is off (rather than failing with an error message).
* Fixed: per-page "force on" override was blocked by an incorrect "globally disabled" guard in the REST endpoint.
* Fixed: per-page viewport width is now clamped to 1200-3840 px on save (REST + sidebar both honoured the bounds).
* Settings page licence section now exposes a "Manage your subscription" link (Freemius customer portal) alongside the upgrade link.

