===  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.2.1
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.2.1 =
* Refined: small layout polish on the Custom post types row of the Settings page - each available type now sits on its own line for legibility, matching the Posts and Pages checkboxes above.

= 2.2.0 =
* Changed: the "Enable sitewide" setting is now split into separate "for Posts" and "for Pages" checkboxes. Sites usually want to treat Posts (which often have featured images already) differently from Pages (bare landing pages where the screenshot is the differentiator); the split lets you opt one in and leave the other off. Existing sites are migrated automatically - whatever your previous "Enable sitewide" setting was, both new checkboxes inherit it on first load. Both still default to off on fresh installs so a new site never starts consuming quota before you have consciously opted in.
* Added: bulk actions on the standard Posts and Pages list screens (Bulk actions dropdown). Three actions: "Enable Dynamic OG image", "Disable Dynamic OG image", and "Reset Dynamic OG to default". Select any number of rows - including the full set produced by a built-in or third-party list filter, such as a category, tag, or Page Generator Pro's filter - and apply the action across all of them in one click. Drives the same per-post override the OG Image panel in the block editor writes to, so the two stay in sync.
* Added (Premium): support for additional public custom post types. A new "Custom post types (Premium)" row in the Enable-sitewide section lists every public custom post type registered on your site (WooCommerce products appear automatically when WooCommerce is active). Tick a type to bring it into scope: the block editor sidebar, the bulk actions, the daily refresh sweep, and the Regenerate All button all extend to it immediately.

= 2.1.3 =
* Fixed: on Yoast SEO sites where the page already had its own OG image (a featured image or a Yoast-set Open Graph image), the 2.1.2 fix added a second og:image tag instead of replacing the existing one. Pages ended up with two og:image meta tags pointing at the same screenshot URL but reporting different width/height values, which is invalid Open Graph markup and confuses social-preview scrapers. The plugin now adds the screenshot to Yoast's image collection only when Yoast has no image of its own, and otherwise rewrites the existing one. Exactly one og:image tag is emitted per page in either case.
* Fixed: og:image:width / og:image:height / og:image:type tags now consistently report 1200, 630, and image/webp under Yoast (matching the actual screenshot dimensions and format). Previously, when Yoast had its own image with different dimensions, those dimensions were left in place after the URL was rewritten to ours.

= 2.1.2 =
* Fixed (critical): the og:image tag was missing entirely on sites using Yoast SEO when no other og:image was set for the page. Yoast's rewrite-only filter only modifies an existing og:image and does nothing when no image is present, so on pages with no featured image and no Yoast default the og:image tag did not ship at all. Result: Facebook, LinkedIn, Slack, WhatsApp and Discord previews showed no image even though the screenshot existed. The plugin now adds the screenshot to Yoast's internal image collection directly so the tag is guaranteed to ship. Rank Math and All in One SEO were not affected by this specific issue.
* Added: a new "Scheduled refresh" checkbox on the Settings page. When off, cached screenshots are kept indefinitely until you explicitly regenerate them (per post or via Regenerate All Screenshots). Post-update auto-regen still works when its own setting is enabled. Defaults to on, so existing installs keep their current schedule-driven behaviour.
* Changed: the setup banner shown before plugin activation now branches between two states. After you click "Allow & Continue" but before clicking the confirmation link in the email, the banner now reads "Check your email to finish setup" with a Refresh button - so you are not asked to "Activate now" again when you are already waiting on your own inbox.
* Changed: the setup banner icon is now a WordPress dashicon to match the visual style used across other PlugUpp plugins.

= 2.1.1 =
* Compliance: addressed four Plugin Check ERROR-severity findings on the 2.1.0 build. Two missing `translators:` comments on the live screenshot-usage headline strings, and two output-escape annotations on integer values in the Refresh interval helper text. The values were already integer-cast; this re-casts at the `printf` call site so the static analyser sees the safety explicitly. No customer-visible change.

= 2.1.0 =
* First public release on the WordPress.org plugin directory.
* Real screenshot-based og:image. The plugin captures a real browser screenshot of each page at the standard 1200x630 Open Graph size and uses it as the og:image. No templates, no featured-image fallbacks - the actual page is what social platforms see when your link is shared.
* No third-party API key. The plugin connects to the PlugUpp screenshot service automatically using your licence. No separate account to manage and no per-request signup.
* Per-post controls in the Gutenberg sidebar - per-page enable/disable, live status, thumbnail preview of the current capture, and a "Regenerate Now" button. Premium adds per-page overrides for viewport width, capture delay, hide selectors, scroll-into-view, click-before-capture, dark mode, country routing, and Media Library integration.
* Page-builder content-save detection. Edits made in Elementor, Beaver Builder, Divi, BeTheme (Muffin Builder), Oxygen, Themify Builder, or Breakdance trigger the same auto-regeneration as a Block Editor save. Two filters (`doig_supported_builders` and `doig_render_affecting_meta_keys`) let site owners add their own.
* Works alongside Yoast SEO, Rank Math, and All in One SEO via each plugin's own image filter hooks. Other meta tags (titles, descriptions, structured data, canonicals, sitemaps) stay under your SEO plugin's control. The plugin runs without an SEO plugin too, emitting its own og:image and twitter:image block.
* Configurable fallback image - your SEO plugin's default, a custom image from your Media Library, or none - shown while a screenshot is being generated or for posts that have not yet been captured.
* Configurable refresh schedule (default 30 days) with a background daily sweep, optional auto-regeneration on post update, and a manual "Regenerate All Screenshots" action on the Settings page (with a backup-recommendation warning before bulk operations).
* HTTPS pre-flight check with an actionable message when the WordPress Site Address is misconfigured as http://. Prevents silent capture failures that would otherwise consume quota for no result.
* Asynchronous capture pipeline. Jobs are delivered via a signed callback with a polling fallback for hosts that block inbound callbacks. On PHP-FPM hosts the callback handler uses `fastcgi_finish_request()` to return in single-digit milliseconds even under bulk-regeneration load.
* Live screenshot-usage section on the Settings page showing your current startup count, monthly count, quota-reset date, and subscription-renewal date. Figures come from the screenshot server live so they always match reality.
* Cache management on the Settings page - cached file count, total disk usage, "Clear Entire Cache", and "Regenerate All Screenshots" with the bulk-operations safety warning.
* Quota awareness. Posts that would exceed the monthly cap are marked with a `quota_exceeded` status and re-queued automatically when the quota resets at the start of your next billing period. Existing screenshots continue to be served in the meantime.
* Documentation links throughout the plugin UI. The Plugins admin row, the Settings tab, and the Logs tab all link out to context-relevant pages on the public documentation site at https://docs.plugupp.com/dynamic-og-image-generator/.
