WP Manifestindependent plugin directory
manifest / seo / open-graph-control

Open Graph Control

WordPress plugin for full control over Open Graph and social meta tags across 12 platforms (Facebook, X, LinkedIn, iMessage, Threads, Mastodon, Bluesky, WhatsApp, Discord, Pinterest, Telegram, Slack).

by Evžen Leonenko · github.com/teriffy/open-graph-control · website

0stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/teriffy/open-graph-control/archive/refs/heads/main.zip

A WordPress plugin that emits Open Graph and social meta tags for 12 platforms, with per-platform rules, SEO-plugin conflict handling, Pinterest Rich Pins, output cache and live per-post preview.

Status (v0.4.0 — dynamic OG card generation in progress)

Backend

  • 12 platform classes — Facebook, X / Twitter, LinkedIn, iMessage, Threads, Mastodon, Bluesky, WhatsApp, Discord, Pinterest, Telegram, Slack
  • 6 resolvers (title, description, image, type, URL, locale) with filterable fallback chains
  • Per-archive overrides (v0.3) — OG title / description / image editable on every category, tag, custom taxonomy term, and author edit screen, wired into the resolver chain via a dedicated archive_override step
  • Dynamic OG card generation (v0.4) — server-side 1200×630 PNG rendering via GD for posts / archives / authors without explicit OG imagery. Auto-generated cards use a fixed layout customizable by filters (logo, site name, title, description, background color). Triggering is opt-in via Settings → Images → Card template; rendering happens on shutdown hook, never blocking the editor. Inter font (SIL OFL) is bundled.
  • Dynamic field sources (v0.4+) — map ACF or JetEngine custom fields to the OG title and description chains per post type. When mapped and populated, the field value wins over post_title / post_excerpt. Configure in Settings → Field sources.
  • Pinterest Rich Pins JSON-LD (Article / Product / Recipe)
  • 7 SEO plugin integrations with clean takeover — Yoast, Rank Math, All in One SEO, SEOPress, Jetpack, The SEO Framework, Slim SEO
  • 3 auto-registered image sizes (landscape 1200×630, square 600×600, Pinterest 1000×1500)
  • Transient-based output cache with smart invalidation hooks

Admin UI (React)

  • Top-level admin menu, 12 settings sections (Overview, Site defaults, Platforms, Post types, Images, Fallback chains, Integrations, Debug/Test, Import/Export, Advanced, Archive overrides, Card template)
  • Per-post meta box with Base + X / Twitter + Pinterest + Per-platform tabs, live preview for all 12 platforms, inline validation
  • Archive editor (v0.3) on every taxonomy term + author edit screen — OG title / description / image with live character-count hints
  • Card template editor (v0.4) in Settings → Images — opt-in toggle, live preview, customizable colors + logo + background, and stats dashboard (generated card count)
  • MediaUpload widget for master image + per-platform overrides
  • One-time admin notice when a competing SEO plugin is detected (take-over or keep choice)
  • Bulk "Regenerate OG image sizes" action for existing attachments
  • Reset-to-defaults + import/export JSON

REST API under open-graph-control/v1: /settings, /preview, /conflicts, /post-types, /meta/{id}, /images/regenerate, /settings/reset, /og-card/generate, /og-card/regenerate, /og-card/status, /og-card/purge (v0.4). All manage_options-gated, with rate-limiting on /preview.

WP-CLI: wp ogc tags <post_id>, wp ogc validate <post_id>, wp ogc regenerate, wp ogc cards generate|regenerate|status|purge (v0.4).

Hooks (filters and actions)

Hook Type Signature Since Purpose
ogc_resolve_{title,description,image,type,url,locale}_chain Filter (array $steps): array v0.0 Customize the resolver fallback chain for any field (e.g., add a custom step before site_default)
ogc_resolve_{title,description,image,type,url,locale}_value Filter (mixed $value, Context $context): mixed v0.0 Final override for any resolved field after the entire chain runs
ogc_resolve_image_step Filter (string\|null $value, string $step, Context $context): ?string v0.4 Intercept and override the result of a specific resolver step (e.g., post_meta_override, site_default, archive_override)
ogc_resolve_title_step Filter (string\|null $value, string $step, Context $context): ?string v0.4+ Intercept per-step in the title resolver chain (e.g., provide a value for the acf_title_field or jet_title_field steps)
ogc_resolve_description_step Filter (string\|null $value, string $step, Context $context): ?string v0.4+ Intercept per-step in the description resolver chain
ogc_card_should_generate Filter (bool $should, CardKey $key): bool v0.4 Control whether a card should be auto-generated for a given post / archive / author (default: true if image chain returns null and card template is enabled)
ogc_card_renderer_prefer_imagick Filter (bool $prefer): bool v0.4 Reserved for v0.5: hint the renderer to prefer Imagick over GD if available (currently always false; GD is used exclusively in v0.4)
ogc_card_generated Action (CardKey $key, string $path): void v0.4 Fired after a card is successfully rendered; $key is the post / archive / author identifier, $path is the local filesystem path to the generated PNG

Quality gates (CI)

  • PHP 8.1–8.4 matrix × PHPUnit (322 tests) + PHPStan level 8 + WPCS
  • Code coverage uploaded as artifact
  • JS lint (@wordpress/scripts ESLint + Prettier) + Webpack build
  • Playwright fixture suite (18 tests: rendering + @axe-core WCAG 2 A/AA scan)
  • Playwright WP suite (12 tests: activation, settings save, metabox override, frontend tags, axe on live wp-admin, responsive layout ≤782px, archive overrides) — opt-in via OGC_E2E_WP=1
  • WordPress/plugin-check-action against the built dist zip on every push

Security

Open Graph Control is built so no user data leaves your server. The plugin does not call any external API, does not phone home, and does not ship telemetry. See SECURITY.md for the full defensive posture and disclosure process.

Layered defenses

  • Capability checks on every REST endpoint (manage_options for site-wide settings, edit_post per post ID for the meta box — no public or subscriber-level write path)
  • Nonce enforcement via check_admin_referer on admin-post actions and WP core's X-WP-Nonce for REST
  • Output escaping at the edge: esc_attr on every tag attribute, esc_url_raw on every URL, esc_html on admin surfaces
  • JSON-LD payloads encoded with JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT + second-layer str_replace('</', '<\/') — no string value can break out of the surrounding `