Newsletter plugin
- Quick start
- Writing newsletters
- Scheduling
- Subscribers & forms
- Welcome & lead magnet
- Pro plugin
- Templates
- AI Agents
Facebook posting plugin
General
Changelog
Two plugins are maintained from one codebase: the free plugin on wp.org (one-two-three-send) and the Pro plugin distributed via custom manifest from this site. Major versions and highlights below; the wp.org plugin page has the full per-release history for the free plugin.
Free plugin — one-two-three-send
2.1.0 — May 29, 2026
Two big bot-protection features. Both off by default, opt-in from Newsletter → Settings.
- Double opt-in (confirmed opt-in). New Confirmation tab. Signups receive an email with a confirmation link; the row is held with status
pending_confirmuntil they click. Welcome email + admin notification + provider sync only fire on confirmation. Subscription-bombing attacks no longer produce active subscribers because bots never click the link. Customisable subject, body, post-click landing copy, and link expiry (default 7 days). New schema columnconfirmation_sent_atonwp_otts_subscribers— migrates automatically on plugin upgrade viadbDelta. - Cloudflare Turnstile bot protection. New Bot Protection tab. Paste a Site Key + Secret Key from the (free) Cloudflare Turnstile dashboard — no Cloudflare subscription needed, site does not need to use Cloudflare for DNS / CDN. When enabled, the signup form renders the Turnstile widget and the REST endpoint POSTs the token to Cloudflare’s siteverify API before accepting any signup. Fail-open on Cloudflare network errors so a CF outage does not kill all signups (filterable via
otts_turnstile_fail_open). Token-verification failures silently accept-and-drop so bots cannot fingerprint the rejection.
Together with the honeypot + IP rate limit + MX check + disposable-domain blocklist shipped in 2.0.20, this is the layered defence every major newsletter ESP (Mailchimp, Beehiiv, ConvertKit, MailerLite) recommends against subscription-bombing attacks. See the new Email confirmation and Bot protection docs sections for setup.
2.0.19 — May 16, 2026
Adds publer to the affiliate-hint helper. When the One Two Three Post 1.7.0+ plugin surfaces its Publer-transport setup field, the helper now renders a contextual “Don’t have a Publer account yet? Sign up →” link pointing at /tools/#publer. Same compliance posture as the existing Claude / MailerLite / Brevo / Postmark / BigScoots / Beehiiv hints.
2.0.18 — May 16, 2026
Admin notification email on every new signup. New Newsletter → Settings → Notifications tab with separate recipient lists for free and paid signups. Notifications go through the email provider you have configured for newsletter sends (Resend / SES / SMTP / Mailchimp / MailerLite / Brevo / Kit) — not via wp_mail() — so deliverability matches the rest of your traffic. Stripe paid signups and free→paid upgrades both notify the paid list. Includes a “Send test notification” button so you can verify wiring before a real signup happens.
2.0.17 — May 16, 2026
Captures signup source on every new subscriber. New signup_meta JSON column on wp_otts_subscribers records the first-touch referrer host, landing URL, and any utm_* query parameters set on the visitor’s first front-end pageview. Subscribers admin gains a Source column; CSV export adds source + signup_meta_json. Stripe + Beehiiv signups are tagged with utm_source=stripe / utm_source=beehiiv. Cookie otts_ft, SameSite=Lax, 1-year TTL; sites with a consent gate can hold the cookie via the otts_signup_attribution_consent filter. Companion update on the publisher (Newsletter Network at onetwothreesend.com): /network/click/{id} now appends utm_source=otts_network, utm_medium=widget, utm_campaign={referring_site} to the destination URL, so when a click lands on a destination running 2.0.17 the new signup_meta records the network as the source.
2.0.15 — May 2026
Extended the affiliate-hint helper to per-provider config panels. When MailerLite or Brevo is selected as the provider and its API key field is empty, an inline sign-up nudge renders beneath the config table linking to the relevant section of /tools/. Providers without an affiliate program (Mailchimp, Kit, SES, Resend, SMTP) silently show nothing — the helper returns empty for unknown slugs.
2.0.14 — May 2026
New OTTS_Affiliate_Hint helper renders inline “Don\’t have a {service} account yet? Sign up →” nudges next to setup fields, only when the field is empty. First call sites: the Claude API key field on AI Settings, and the Email provider selector when no provider has been chosen yet. Every link points at /tools/ on this site (a docs page on our own domain, not raw affiliate URLs) where the FTC disclosure and the actual outbound affiliate links live. No external HTTP, no tracking pixels. Operators can disable all hints via the otts_affiliate_hint_enabled filter; the service map is overridable via otts_affiliate_hint_services.
2.0.13 — May 2026
Three integration hooks added so a Pro extension can replace the Settings → Schedule UI without modifying the free plugin: filter otts_settings_schedule_show_default hides the legacy schedule form, action otts_settings_schedule_render_pre lets an extension inject a replacement notice, filter otts_scheduler_register_default_cron suppresses the default cron registration. Free behaviour is unchanged without those hooks.
2.0.12 — May 2026
Send-reliability overhaul. Per-recipient failures now classified as transient (retry with exponential backoff up to 5 attempts), permanent (mark bounced), or system (halt + alert admin). New wp_otts_send_retries table + 5-minute cron worker. Subscribers get bounce-state columns. New Send Health admin page surfacing pending retries, bounced subscribers, recent send results.
2.0.11 — May 2026
Resend provider retries on HTTP 429 with backoff (3 attempts, honours Retry-After). Sequential sends to 6+ subscribers were silently losing recipients to the rate limit.
2.0.10 — May 2026
Welcome email now ends with the standard footer + working unsubscribe link. Sidebar top-level menu renamed from “Newsletter” to “One Two Three Send”.
2.0.7–2.0.9 — Apr–May 2026
Welcome email body supports rich HTML (2.0.9). Signup forms gained a “Redirect after signup” field with {email} token replacement (2.0.8). Plugin description gained docs / pricing / privacy useful-links section (2.0.7).
2.0.0–2.0.6 — Apr 2026
Major wp.org-submission refactor. Removed license-gating system and phone-home validation; all advertised free-plugin features work out of the box (2.0.0). Compliance pass against Plugin Check: translator comments, ordered placeholders, WP_Filesystem helpers, prepared $wpdb queries (2.0.1). Plugin URI / Author URI separation (2.0.2). Free/Paid newsletter type with filter hooks for paywall extensions (2.0.3). Claude API key clarified as optional (2.0.6).
1.0.0–1.0.6 — Apr 2026
Initial release with AI newsletter generator, scheduling with manual-approval mode, Resend/SMTP providers, subscriber database with CSV export, inline signup form (1.0.0). Edit-page permissions hotfix (1.0.1). Pre-send audit + welcome email + reorganised settings tabs (1.0.2). Lead Magnet — signed, time-limited download links (1.0.3). Cache-safe signup form via honeypot (1.0.4). {from_name} placeholder (1.0.5). Welcome email + lead-magnet delivery merged (1.0.6).
Pro plugin — one-two-three-send-pro
2.14.129 — May 19, 2026
Fix: AI Agents image picker was choosing wrong-subject images on posts with named entities in the title (a post about Castello di Sammezzano in Tuscany pulled a German castle for its featured image and two unrelated Italian castles for body images). Four root-cause fixes to class-pro-image-fetcher.php: (1) the most-distinctive token in the title is now preserved as the lead keyword regardless of stopword/length filtering, so multi-word proper nouns survive intact; (2) the Wikimedia candidate filter now requires the subject anchor (longest meaningful token) to be present in the candidate metadata, not just any 4+ char token — stops generic noun matches like “castello” qualifying every Italian castle; (3) new category-anchored Wikimedia pre-search tries Category:{titlecased subject} before free-text search, pulling from curated photo pools when they exist; (4) the single-word Unsplash fallback that produced generic “castle” / “italy” photos when the multi-word search returned no hits is removed. Filterable via otts_pro_image_picker_single_word_fallback for sites that want the old behaviour.
2.14.128 (paired with Manifests 1.2.5) — May 17, 2026
Newsletter Network: close the outbound-counter cache blind spot. /network/render-beacon on the publisher now also bumps outbound_impressions for the rendering site, looked up from the HTTP Referer host. Before this, sites with full-page caching (BigScoots boost, Cloudflare 1y TTL) couldn’t earn outbound credit even though their widget was rendering thousands of times to real readers — the PHP-side counter never ran. Web render path now skips the redundant PHP note_outbound_render() call; emails still use it because emails can’t run JS.
2.14.126 — May 16, 2026
Fires a new otts_subscriber_upgraded_to_paid action when an existing free subscriber completes a Stripe checkout. Pairs with the free plugin’s 2.0.18 signup-notification feature so the paid recipient list is also notified on upgrades, not only on first-time paid signups.
2.14.124–2.14.125 — May 16, 2026
Newsletter Network: fix impressions counter undercounting by 10–100×. The widget caches the /recommendations response daily, so the registry was counting once per cached fetch instead of once per actual render. 2.14.124 added per-listing render counts to the daily heartbeat. 2.14.125 then shipped a JS beacon (navigator.sendBeacon) from the rendered widget itself, so impressions count real reader views even on sites with full-page caching (BigScoots, Cloudflare, WP Rocket). Email renders still count via the heartbeat (no JS in inboxes).
2.14 — May 2026 (current series)
- 2.14.123 —
Subscribenow pre-fills the email from the logged-in WordPress user when one is present. No-op for the typical anonymous-visitor case; saves a click on membership-style sites where readers log into WP to access content. Works in both the plain-link andcollect_email="yes"form variants of the shortcode. - 2.14.122 — New
collect_email="yes"attribute on theSubscribeshortcode. When set, the shortcode renders an inline email input + button instead of a bare link, so visitors land on Stripe with the email already filled in. Form GET-submits to the existing handler unchanged; works without JavaScript; backward-compatible (leaving the attribute off keeps the original button). Pair with 2.14.121’s defensive omission of emptycustomer_emailto fully resolve the pricing-page → Stripe blank-email flow. - 2.14.121 — Bug fix: Stripe Checkout session creation was sending
customer_email: ""(empty string) when a paywall link hit?otts_pro_checkout=startwithout an email param. Stripe rejects this withemail_invalid— omitting the field entirely is fine; the empty string is what specifically fails. Now omits bothcustomer_emailand theotts_emailmetadata when our value is empty or non-RFC-valid, letting Stripe collect the email natively on its hosted page. Webhook still resolves the post-payment subscriber match via the email Stripe populates. - 2.14.120 — Amazon SES provider — silent send-failure root-cause fix. Pasting the full
email-smtp.<region>.amazonaws.comhost into the AWS region field used to silently break every send. The field is auto-corrected at save time so the corrected slug is visible in the form on reload; field label now includes an example. New admin-only debug endpoint at/wp-json/otts-pro/v1/provider-debugexposes the resolved region, derived SMTP host, and most recent captured PHPMailer error for diagnosing provider issues. See Troubleshooting for the gotcha. - 2.14.119 — SES send failures now carry the real PHPMailer error in the WP_Error message (was previously a generic line). Runtime auto-extraction of the AWS region slug from a pasted SMTP host (succeeded by 2.14.120’s save-time normalisation).
- 2.14.118 — Beehiiv config panel single-link pattern (matches the 2.0.16 free plugin AI Settings change): when no Beehiiv API key is configured, only the affiliate sign-up hint renders; when a key is configured, only the operational
app.beehiiv.comlink renders. - 2.14.117 — Defer guards on the four publisher classes (Update, Post, Network, NetworkAuditor): when the standalone One Two Three Manifests plugin is active, OTTS Pro’s copies politely step aside. Lets the publisher infrastructure be moved out of OTTS Pro without disruption.
- 2.14.116 — Added
OTTS_Pro_Post_Publisherclass (later moved to the standalone Manifests plugin in 2.14.117). Hosted the Post Pro manifest at/wp-json/ottpost-pro/v1/manifest. - 2.14.114 — Affiliate Links bulk-apply UI: preview button + “apply to existing posts” checkbox on the rule form; domain-mode idempotence fixed.
- 2.14.113 —
apply-to-allREST endpoint for backfilling affiliate rules across all published posts. - 2.14.112 — Figcaption rendering fix: Wikimedia attribution captions in AI Agents posts now render as real links instead of escaped HTML text; one-shot backfill endpoint for older posts.
- 2.14.111 — AUTH_KEY HMAC fallback hardening — replaced the literal source-code fallback string with
wp_salt('auth')on the two token-verifying classes. - 2.14.110 — Unified scheduler. Removed the separate “Send Times” menu page; one Weekly Schedule page now covers Generation time, Send time, Auto-send, Auto-send paid (new opt-in, default off), and per-day rows. Coordinates with free 2.0.13 hooks to hide free’s legacy schedule UI when Pro is active.
- 2.14.106–109 — Async judge retry handler, scheduler progress markers, default linkable-articles block in Newsroom + Travel templates (no more
href="#"placeholders). - 2.14.0–2.14.105 — Structured-output generation pipeline (JSON-tool-call generator + judge + surgical regen for Custom templates), curated pipeline (Path-A blog-driven daily newsletters), Newsroom + Travel templates, Visual Library (Claude-vision image tagger + media search index), Newsletter Network publisher, Viator Partner API auto-sync, render-trace diagnostic, subscriber I/O admin, AI Agents rename (formerly “Auto Content”).
2.13 — Apr 2026
Wikimedia Commons image fallback for blog/newsletter images (2.13.4). Pre-rendered Network widget + experiences callouts at generation time. Sponsor-block fields per affiliate rule. CJK / Arabic / Cyrillic / Hebrew character stripping from AI output. Experience-type affiliate rules (sell-out-driver listings).
2.10–2.12 — Mar–Apr 2026
Visual Library introduced. Network cross-promotion: publisher, widget, auditor. Custom Templates: JSON-driven custom templates with structured pipeline opt-in (2.11). Public newsletter archive. Open-rate tracking. Beehiiv import + webhook bridge. Click tracking ported into Pro from per-site plugins.
2.0–2.9 — Feb–Mar 2026
Stripe paywall + checkout sessions. Additional email providers: Mailchimp, MailerLite, Brevo, ConvertKit/Kit, Amazon SES, Resend events. Popup + slide-in forms. Full audit pass (Claude-backed). Auto Content multi-agent blog post generator. Render-time form auto-place below blog posts. Editorial settings, subscriber admin, image fetcher (WP library + Unsplash chain), affiliate link registry + rewriter, Newsroom + Travel email templates.
Free plugin — one-two-three-post (Facebook posting)
1.7.2 — May 16, 2026
Fires a new ottpost_fb_oauth_connected action from the OAuth callback success path. Post Pro 1.8.3 listens to this so the “first-comment failed: insufficient permissions” banner clears automatically once you reconnect Facebook to grant the missing scope.
1.7.0 — May 16, 2026
New: Publer as an alternative publishing transport. Operators who already pay for Publer for cross-network publishing can now route the plugin’s Facebook posts through Publer instead of authenticating their own Facebook App. Settings → Publishing transport picks between Direct Facebook (original flow) and Publer (paste API token + workspace ID + pick a Facebook account inside the workspace). Same composer + scheduler + (Pro) validator pipeline for both transports; only the final API call differs. Publer’s first-comment is supported and ships inline with the parent publish. Publer Business or Enterprise plan required (API access).
1.6.2 — May 16, 2026
Fix: decode HTML entities before sending message text to Facebook. Curly apostrophes (’), em-dashes, ellipses, and ampersands were being published to Facebook as literal entity strings instead of the intended characters. Applies to both the parent-post message and the first-comment message.
Fix: add the pages_manage_engagement scope to the Facebook OAuth flow. Without it, the page access token cannot post comments on the page’s own posts and Facebook returns (#200) You do not have sufficient permissions when the first-comment feature fires. Sites that authorized before this release need to reconnect their Facebook page (Settings → Connect to Facebook) to grant the new scope.
1.6.1 — May 2026
Bug fix — coloured-background text posts in the Scheduled list were showing a single hardcoded dark slate in the preview thumbnail regardless of which Facebook preset was selected on the post. The Facebook send was always correct; only the WordPress-side preview was misleading. Root cause: the 41-preset hex/gradient table lived only inside the composer view, not in a shared location. Extracted to a new OTTPOST_Backgrounds helper class so the scheduled view can look up the same colour the composer\’s picker uses for each preset_id. Empty / unknown preset falls back to Solid Teal — same default the Graph API uses when no preset is set at publish time, so the preview now matches what Facebook will actually render.
1.6.0 — May 2026
Added a Delete button on each row of the Scheduled-posts list view, alongside the existing Edit and Open ↗ buttons. Previously the only way to drop a scheduled post was via One Two Three Post → All Posts and WordPress’s standard row Trash action — extra clicks from the natural “where I look at upcoming posts” view. Pre-publish posts are hard-deleted; already-sent posts move to trash so the operator can recover the record of an actual Facebook publish. Native confirm() dialog, capability-gated to edit_posts, CSRF-nonced per row.
1.5.0 — May 2026
Three extension hooks in OTTPOST_Scheduler::publish_post() so add-on plugins (One Two Three Post Pro in particular) can plug a pre-publish validator chain into the existing scheduler without forking. New hooks: ottpost_pre_publish_validate (filter — return a WP_Error to block the publish), ottpost_publish_args (filter — mutate the Graph API payload), and ottpost_after_publish (action — fires post-attempt). No behaviour change for sites that don’t have an add-on installed.
1.4.0 — May 2026
Internal prefix bulk-rename from OTP_* to OTTPOST_* across every class, option key, post meta, cron hook, REST namespace, and asset handle. The 3-character otp prefix was too short per wp.org’s naming guidelines and risked colliding with other plugins (One Time Passwords, OpenTelemetry, etc.). Breaking for existing installs: after upgrading you’ll need to re-connect Facebook and re-create any pending scheduled posts. Also fixed a pre-existing parse error in the Settings view caught by the lint sweep.
1.3.0 — May 2026
Initial wp.org submission release. Menu label changed from “FB Posts” to “One Two Three Post” so the plugin doesn’t render an abbreviated trademark in the admin sidebar. Adds a bundled uninstall.php that drops plugin options, OAuth credentials, and the cron event when the user deletes the plugin from Plugins → Delete.
Live at wordpress.org/plugins/one-two-three-post.
Pro plugin — one-two-three-post-pro (Facebook posting Pro)
1.9.0 — May 20, 2026
Feature: auto-fill cadence is now configurable. New Hours between posts setting on Pro Settings → Auto-fill section (1–24, default 1). Set to 2 to post every 2 hours, 3 every 3 hours, etc. The slot picker schedules each new auto-fill post relative to the latest already-queued post plus your spacing value, so the queue lays itself out on tidy N-hour intervals instead of clustering. The existing Target queue depth setting now serves as a 24h soft cap rather than the cadence control. Backward-compatible: default of 1 hour reproduces the previous behaviour.
1.8.3 — May 16, 2026
Fix: the “first-comment failed: insufficient permissions” banner on the Queue dashboard wasn’t clearing after operators reconnected Facebook. Pro now listens to the new free plugin 1.7.2+ ottpost_fb_oauth_connected hook and auto-drops _ottpost_fc_error values that match permission patterns. Adds a per-row Dismiss link + a Dismiss all button for manual cleanup of non-permission errors.
1.8.2 — May 16, 2026
Fix: surface failed first-comments in the Queue dashboard. Previously, when the comment POST to Facebook silently failed (e.g. missing pages_manage_engagement OAuth scope), the parent text post still shipped with body promising “link in the comments” but no comment was attached — readers saw a broken promise. The dashboard now renders a top-of-page error notice listing the last 7 days of failed first-comments, with a one-click “Reconnect Facebook” button when the failure is a permissions error.
1.8.1 — May 2026
Bug fix — auto-generated text-question and newsletter-teaser posts (introduced in 1.8.0) were storing the wrong post-type slug (text) instead of the value both the free plugin’s composer and the Facebook Graph API expect (coloured_background). Result: posts shipped as plain standard text posts with no background colour, and editing them in the composer didn’t show the “Text on coloured background” radio as selected. Both generators now emit the correct slug. A one-shot migration on admin_init repairs any auto-generated posts already in the queue with the broken slug. Migration is gated by an option flag so it only runs once.
1.8.0 — May 2026
Phase 5b — content quality + editor loop. Newsletter promo replaced with newsletter teaser: rotates a curiosity-gap hook from an operator-editable library, posts as a coloured-background text post with the signup URL in the first comment only. Capped at 1 per 24h. Modelled on the original Python automation system\’s decision to abandon hard-sell promos in favour of organic curiosity hooks. Text question type now prefers an operator-editable pool over Claude generation (cheaper, predictable, no rate limits). New editor-loop cron runs every 6 hours and promotes would-be-blocked posts to pending early, hours before they\’d have fired.
1.7.0 — May 2026
Claude API key field added to Pro Settings → Content auto-fill. Post Pro is now self-sufficient: the Text question content type works even on installs where One Two Three Send isn’t installed. Key resolution priority is local option → OTTS getter → raw OTTS option fallback, so installs with both plugins inherit OTTS’s key automatically.
1.6.1 — May 2026
Bug fix — coloured-background text posts in the Scheduled list were showing a single hardcoded dark slate in the preview thumbnail regardless of which Facebook preset was selected on the post. The Facebook send was always correct; only the WordPress-side preview was misleading. Root cause: the 41-preset hex/gradient table lived only inside the composer view, not in a shared location. Extracted to a new OTTPOST_Backgrounds helper class so the scheduled view can look up the same colour the composer\’s picker uses for each preset_id. Empty / unknown preset falls back to Solid Teal — same default the Graph API uses when no preset is set at publish time, so the preview now matches what Facebook will actually render.
1.6.0 — May 2026
Facebook page selector for auto-fill. New Facebook page dropdown at the top of the Content auto-fill panel listing every connected Facebook page. Auto-fill targets only the selected page — important on accounts with many connected pages where the previous “first connected page” behaviour was effectively random.
1.5.0 — 1.5.1 — May 2026
1.5.0 — Phase 6, first-comment auto-detection. Three detectors fill the first-comment field at publish time when it would otherwise have been empty: title mentions (on by default), category keywords, and teaser phrases (both off by default). Manual operator values are never overwritten.
1.5.1 — Renamed the Pro Settings verify-email form field from email to ottpost_pro_email. Defends against other plugins (notably Hubbub Lite) that hook admin POSTs containing an email field.
1.4.0 — May 2026
Phase 5, content mix engine. New Content auto-fill panel on Pro Settings: enable toggle, target queue depth (default 12 posts in the next 24h), and per-type weights. An hourly WP-Cron job checks queue depth and appends one auto-generated post per run until target is reached. Three generators: Photo (from recent WP posts), Text question (Claude-generated), Newsletter promo (templated). Auto-generated posts are tagged on the queue overview with an auto badge.
1.3.0 — May 2026
Phase 3, image pipeline. Auto-resize on publish (configurable target, default 1200×630 — Facebook OG ratio). Perceptual hash (8×8 aHash) added alongside MD5 in the duplicate-image validator — catches resized / re-encoded variants. Daily auto-prune cron deletes hash rows older than 2× the dedup window.
1.2.0 — May 2026
Phase 2, queue dashboard + 2 new validators. New Queue overview on Pro Settings showing the next 20 scheduled posts with quick Edit / Delete actions and summary counts for the next 24h / 7d. Two new pre-publish validators: type rotation (block same-type-back-to-back) and spacing (block publishes within N minutes of another). Both off by default.
1.1.0 — May 2026
Phase 4, pre-publish validator chain. Five validators map to the strictness toggles already on the Pro Settings page: block AI-generated image filenames, block duplicate images (MD5 against image-hash registry), block duplicate captions, block seasonal misfires (built-in month-keyword map), block banned-word matches. Disabled toggles still run and surface as warnings in the new Recent validations widget.
1.0.0 — 1.0.2 — May 2026
Initial release. Plugin scaffold with subscriber-email verification, validator strictness toggles on Pro Settings, three database tables for validation log + queue state + image hashes, and the custom-manifest auto-update gate. Fixed verify-email response shape (1.0.1) and added bold-green / bold-red status pill colours (1.0.2). Distributed by email to subscribers of the One Two Three Send daily newsletter — same model as One Two Three Send Pro.