{"id":311603,"date":"2026-05-15T07:44:20","date_gmt":"2026-05-15T07:44:20","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/one-two-three-post\/"},"modified":"2026-05-15T20:25:07","modified_gmt":"2026-05-15T20:25:07","slug":"one-two-three-post","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/one-two-three-post\/","author":23489072,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.6.0","stable_tag":"1.6.0","tested":"6.9.4","requires":"6.0","requires_php":"7.4","requires_plugins":null,"header_name":"One Two Three Post","header_author":"One Two Three Send","header_description":"Schedule and publish posts to Facebook Pages from WordPress. Connect a Facebook App, pick a Page, write a message with an optional image, post immediately or schedule for later.","assets_banners_color":"0f172a","last_updated":"2026-05-15 20:25:07","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/onetwothreesend.com\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":50,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.4.0":{"tag":"1.4.0","author":"onetwothreesend","date":"2026-05-15 07:44:11"},"1.5.0":{"tag":"1.5.0","author":"onetwothreesend","date":"2026-05-15 08:35:31"},"1.6.0":{"tag":"1.6.0","author":"onetwothreesend","date":"2026-05-15 20:25:07"}},"upgrade_notice":{"1.3.0":"<p>First wp.org-distributed release. If you previously installed v1.2.x manually, upgrade in place \u2014 no settings reset is required.<\/p>"},"ratings":[],"assets_icons":{"icon-256x256.png":{"filename":"icon-256x256.png","revision":3532771,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-772x250.png":{"filename":"banner-772x250.png","revision":3532771,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.4.0","1.5.0","1.6.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3533297,"resolution":"1","location":"assets","locale":"","width":1280,"height":800},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3533297,"resolution":"2","location":"assets","locale":"","width":1280,"height":800},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3533297,"resolution":"3","location":"assets","locale":"","width":1280,"height":800},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3533297,"resolution":"4","location":"assets","locale":"","width":1280,"height":800},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3533297,"resolution":"5","location":"assets","locale":"","width":1280,"height":800}},"screenshots":{"1":"Composer \u2014 pick a Page, write a message, attach an image, choose post type, send or schedule.","2":"Coloured-background picker \u2014 41 native Facebook background presets with previews, plus a custom preset-ID field.","3":"Calendar view \u2014 month grid with post counts per day, status-coloured pills, click a day to filter.","4":"List view \u2014 next post going out first, then drafts \/ past activity. Visual preview thumbnail per row.","5":"Settings \u2014 Facebook App credentials, Connect to Facebook button, list of connected Pages."},"jetpack_post_was_ever_published":false},"plugin_section":[],"plugin_tags":[569,157,86,4685,154],"plugin_category":[56],"plugin_contributors":[261763],"plugin_business_model":[],"class_list":["post-311603","plugin","type-plugin","status-publish","hentry","plugin_tags-automation","plugin_tags-facebook","plugin_tags-post","plugin_tags-scheduler","plugin_tags-social-media","plugin_category-social-and-sharing","plugin_contributors-onetwothreesend","plugin_committers-onetwothreesend"],"banners":{"banner":"https:\/\/ps.w.org\/one-two-three-post\/assets\/banner-772x250.png?rev=3532771","banner_2x":false,"banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/one-two-three-post\/assets\/icon-256x256.png?rev=3532771","icon_2x":"https:\/\/ps.w.org\/one-two-three-post\/assets\/icon-256x256.png?rev=3532771","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/one-two-three-post\/assets\/screenshot-1.png?rev=3533297","caption":"Composer \u2014 pick a Page, write a message, attach an image, choose post type, send or schedule."},{"src":"https:\/\/ps.w.org\/one-two-three-post\/assets\/screenshot-2.png?rev=3533297","caption":"Coloured-background picker \u2014 41 native Facebook background presets with previews, plus a custom preset-ID field."},{"src":"https:\/\/ps.w.org\/one-two-three-post\/assets\/screenshot-3.png?rev=3533297","caption":"Calendar view \u2014 month grid with post counts per day, status-coloured pills, click a day to filter."},{"src":"https:\/\/ps.w.org\/one-two-three-post\/assets\/screenshot-4.png?rev=3533297","caption":"List view \u2014 next post going out first, then drafts \/ past activity. Visual preview thumbnail per row."},{"src":"https:\/\/ps.w.org\/one-two-three-post\/assets\/screenshot-5.png?rev=3533297","caption":"Settings \u2014 Facebook App credentials, Connect to Facebook button, list of connected Pages."}],"raw_content":"<!--section=description-->\n<p>One Two Three Post is a WordPress plugin for site owners who manage one or more Facebook Pages and want a clean composer + scheduler inside WordPress instead of switching to Meta's tools.<\/p>\n\n<p>The plugin is fully functional on its own. A separate companion plugin (One Two Three Post Pro, distributed independently) will add AI-generated post drafting and Publer-style multi-network support \u2014 One Two Three Post does not require it.<\/p>\n\n<h4>What's included<\/h4>\n\n<ul>\n<li><strong>Composer<\/strong> \u2014 pick a Page, write the message, attach an image from the WP media library, choose post type, send now or schedule.<\/li>\n<li><strong>Native coloured-background text posts<\/strong> \u2014 the Facebook-rendered \"text on coloured background\" format. 41 background presets ported from a known-working list, plus a custom-preset-ID field for Pages with brand-specific palettes.<\/li>\n<li><strong>First comment<\/strong> \u2014 optional comment posted automatically on the published post (handy for newsletter CTAs, link drops, follow-up prompts). A comment failure does not roll back the main post.<\/li>\n<li><strong>Scheduling<\/strong> \u2014 pick any future time (Facebook requires \u226510 minutes lead). A WP-Cron worker fires every 5 minutes and pushes due posts to the Graph API. Failed posts retry up to 3 times with the error visible.<\/li>\n<li><strong>Calendar view<\/strong> \u2014 month grid showing every scheduled \/ drafted \/ sent \/ failed post. Click a day to filter the list. Counts + status-coloured pills per day.<\/li>\n<li><strong>List view<\/strong> \u2014 chronological table with the next post going out at the top. Visual preview tile per row (image thumb for photo posts, dark tile with text excerpt for coloured-background, grey card for text-only).<\/li>\n<li><strong>Edit-in-composer<\/strong> \u2014 clicking Edit on any saved post returns to the composer with all fields hydrated (page, message, image, schedule time, type, background, first comment).<\/li>\n<li><strong>Encrypted credentials<\/strong> \u2014 your Facebook App Secret and per-Page access tokens are encrypted at rest with AES-256-CBC, keyed off your WordPress authentication keys.<\/li>\n<\/ul>\n\n<h4>External services<\/h4>\n\n<p>This plugin contacts the following Facebook endpoints using credentials you provide. Nothing is sent to any third party without you connecting first.<\/p>\n\n<ul>\n<li><strong>Facebook Login (<code>https:\/\/www.facebook.com\/v19.0\/dialog\/oauth<\/code>)<\/strong> \u2014 the OAuth dialog the user is redirected to when clicking \"Connect to Facebook\" in Settings. Standard Facebook Login flow.<\/li>\n<li><strong>Facebook Graph API (<code>https:\/\/graph.facebook.com\/v19.0<\/code>)<\/strong> \u2014 for the OAuth code-to-token exchange, listing the user's Pages, fetching Page metadata, publishing posts and comments, scheduling posts. Called only after the user has connected a Page and only when posting \/ scheduling.<\/li>\n<\/ul>\n\n<p>The plugin itself does not phone home to any other server. No analytics, no telemetry, no third-party trackers, no opt-in newsletter signups, no remote update channel.<\/p>\n\n<ul>\n<li>Facebook Platform Terms: https:\/\/developers.facebook.com\/terms\/<\/li>\n<li>Facebook Privacy Policy: https:\/\/www.facebook.com\/privacy\/policy\/<\/li>\n<\/ul>\n\n<h4>Required Facebook permissions<\/h4>\n\n<p>The plugin requests three Facebook scopes during the Connect flow:<\/p>\n\n<ul>\n<li><code>pages_manage_posts<\/code> \u2014 create posts on your Pages<\/li>\n<li><code>pages_read_engagement<\/code> \u2014 read your Page metadata<\/li>\n<li><code>pages_show_list<\/code> \u2014 list the Pages you manage<\/li>\n<\/ul>\n\n<h4>Useful links<\/h4>\n\n<ul>\n<li><a href=\"https:\/\/onetwothreesend.com\/\">onetwothreesend.com<\/a> \u2014 author site, documentation, and support.<\/li>\n<li><a href=\"https:\/\/onetwothreesend.com\/privacy\/\">Privacy policy<\/a>.<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin zip via Plugins \u2192 Add New \u2192 Upload Plugin, or place the folder in <code>\/wp-content\/plugins\/one-two-three-post\/<\/code>.<\/li>\n<li>Activate the plugin.<\/li>\n<li>Create a Facebook App at https:\/\/developers.facebook.com\/apps. Pick the \"Business\" use case. Add the \"Facebook Login\" product.<\/li>\n<li>Open <strong>One Two Three Post \u2192 Settings<\/strong>. Copy the Redirect URI shown on that page into your Facebook App's <em>Facebook Login \u2192 Settings \u2192 Valid OAuth Redirect URIs<\/em> list.<\/li>\n<li>Paste your App ID and App Secret into the Settings page and save.<\/li>\n<li>Click <strong>Connect to Facebook<\/strong>, grant the permissions, you are returned to WordPress with your Pages listed.<\/li>\n<li>Open <strong>One Two Three Post \u2192 New \/ Compose<\/strong> and write your first post.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"i%20don%27t%20have%20a%20facebook%20app.%20where%20do%20i%20get%20one%3F\"><h3>I don't have a Facebook App. Where do I get one?<\/h3><\/dt>\n<dd><p>At https:\/\/developers.facebook.com\/apps. Click \"Create App\", pick \"Business\", give it a name. Add the \"Facebook Login\" product. In Facebook Login \u2192 Settings, paste the Redirect URI shown in the plugin's Settings page into \"Valid OAuth Redirect URIs\". You'll then have an App ID and App Secret to copy into the plugin.<\/p><\/dd>\n<dt id=\"why%20does%20the%20connect%20flow%20ask%20for%20%60pages_manage_posts%60%3F\"><h3>Why does the connect flow ask for `pages_manage_posts`?<\/h3><\/dt>\n<dd><p>Because that's the Facebook scope required to create a post on a Page. Without it, the plugin can't publish.<\/p><\/dd>\n<dt id=\"why%20does%20my%20scheduled%20post%20need%20to%20be%20at%20least%2010%20minutes%20in%20the%20future%3F\"><h3>Why does my scheduled post need to be at least 10 minutes in the future?<\/h3><\/dt>\n<dd><p>Facebook's API requirement, not ours. Facebook rejects scheduled posts whose time is less than 10 minutes from now and more than six months out.<\/p><\/dd>\n<dt id=\"where%20are%20my%20page%20access%20tokens%20stored%3F\"><h3>Where are my Page access tokens stored?<\/h3><\/dt>\n<dd><p>In the WordPress options table, encrypted at rest with AES-256-CBC using a key derived from your <code>SECURE_AUTH_KEY<\/code> + <code>SECURE_AUTH_SALT<\/code>. They are never sent anywhere except the Facebook Graph API endpoint above.<\/p><\/dd>\n<dt id=\"my%20scheduled%20post%20didn%27t%20fire%20%E2%80%94%20what%20happened%3F\"><h3>My scheduled post didn't fire \u2014 what happened?<\/h3><\/dt>\n<dd><p>Open <strong>One Two Three Post \u2192 Scheduled<\/strong> (or All Posts). Posts that failed have a \"Failed\" status with the error message visible. Common causes: page access token revoked (reconnect from Settings), image attachment deleted from media library, network error. The plugin retries up to 3 times.<\/p><\/dd>\n<dt id=\"does%20this%20plugin%20work%20with%20facebook%20groups%2C%20instagram%2C%20or%20my%20personal%20facebook%20profile%3F\"><h3>Does this plugin work with Facebook Groups, Instagram, or my personal Facebook profile?<\/h3><\/dt>\n<dd><p>No. Pages only. Facebook deprecated programmatic posting to personal profiles years ago, and Group \/ Instagram posting requires different scopes and permissions that aren't a fit for this plugin.<\/p><\/dd>\n<dt id=\"what%20is%20a%20%22coloured-background%20text%20post%22%3F\"><h3>What is a \"coloured-background text post\"?<\/h3><\/dt>\n<dd><p>The native Facebook short-text-on-a-coloured-background post format \u2014 same one Facebook offers in its own composer for short messages. The plugin renders these via Facebook's <code>text_format_preset_id<\/code> parameter (POST to <code>\/{page_id}\/feed<\/code>). Messages are capped at 130 characters by Facebook.<\/p><\/dd>\n<dt id=\"what%20does%20%22first%20comment%22%20do%3F\"><h3>What does \"first comment\" do?<\/h3><\/dt>\n<dd><p>If you fill the optional First Comment field, the plugin posts that text as a comment on the new post immediately after it goes live. Useful for newsletter CTAs, link drops, or follow-up prompts where Facebook tends to suppress reach when the link is in the main post body.<\/p><\/dd>\n<dt id=\"what%20happens%20to%20my%20data%20if%20i%20delete%20the%20plugin%3F\"><h3>What happens to my data if I delete the plugin?<\/h3><\/dt>\n<dd><p>Deactivating leaves all data in place. Deleting the plugin (Plugins \u2192 Delete) removes the plugin's options, scheduled-post entries, and the WP-Cron event via the bundled <code>uninstall.php<\/code>.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.6.0<\/h4>\n\n<ul>\n<li>Added a <strong>Delete<\/strong> button on each row of the Scheduled-posts list view, alongside the existing <strong>Edit<\/strong> and <strong>Open \u2197<\/strong> buttons. Previously the only way to drop a scheduled post was to navigate to <em>One Two Three Post \u2192 All Posts<\/em> and use WordPress's standard row Trash action \u2014 a noticeable extra click whenever the operator just wanted to clear a queue entry from the natural \"where I look at upcoming posts\" view. Pre-publish posts (status not yet <code>publish<\/code>) are hard-deleted; already-sent posts move to trash so the operator can recover the record of an actual Facebook publish if needed. Native <code>confirm()<\/code> dialog before the action fires. Capability-gated to <code>edit_posts<\/code> and CSRF-nonced per row.<\/li>\n<\/ul>\n\n<h4>1.5.0<\/h4>\n\n<ul>\n<li>Added three extension hooks in <code>OTTPOST_Scheduler::publish_post()<\/code> so add-on plugins (such as the separately-distributed One Two Three Post Pro) can plug a pre-publish validator chain into the existing scheduler without forking. New hooks: <code>ottpost_pre_publish_validate<\/code> (filter \u2014 return a <code>WP_Error<\/code> to block the publish and record the reason as a failure), <code>ottpost_publish_args<\/code> (filter \u2014 mutate the Graph API payload before send), and <code>ottpost_after_publish<\/code> (action \u2014 fires post-attempt with the result array, useful for log-table writes). No behaviour change for sites that don't have an add-on installed; the filters return their inputs unchanged when no listeners are attached.<\/li>\n<\/ul>\n\n<h4>1.4.0<\/h4>\n\n<ul>\n<li>Renamed the internal code prefix from <code>OTP_*<\/code> \/ <code>otp_*<\/code> \/ <code>otp-*<\/code> to <code>OTTPOST_*<\/code> \/ <code>ottpost_*<\/code> \/ <code>ottpost-*<\/code> across all classes, constants, option keys, post meta, cron hooks, REST namespaces, and CSS \/ JS handles. The 3-character <code>otp<\/code> prefix was too short per wp.org's plugin-naming guidelines and risked colliding with other plugins (One Time Passwords, OpenTelemetry, etc.). All seven <code>class-otp-*.php<\/code> files were renamed to <code>class-ottpost-*.php<\/code> to match. <strong>Breaking for existing installs:<\/strong> option keys, the <code>otp_fb_post<\/code> custom post type slug, the <code>otp_scheduled<\/code> post status, and the <code>otp_fire_scheduled_posts<\/code> cron hook have all been renamed. After upgrading, you will need to re-connect Facebook (re-OAuth) and re-create any pending scheduled posts. New installs are unaffected.<\/li>\n<li>Fixed a pre-existing parse error in <code>admin\/views\/settings.php<\/code> (line 11 had a stray <code>&lt;?php<\/code> opener inside an already-open PHP block \u2014 Settings page would crash on load). Caught by linting the renamed codebase.<\/li>\n<li>Added file-level <code>phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound<\/code> to the four view \/ uninstall files. Plugin Check reports those files' top-level <code>$variables<\/code> as potentially global, but they're always included from inside an admin class method (or, for uninstall.php, WP core's uninstall include) \u2014 function-scoped at runtime. Documented inline so future readers know why the rule is suppressed.<\/li>\n<\/ul>\n\n<h4>1.3.3<\/h4>\n\n<ul>\n<li>Removed the redundant Plugin URI from the plugin header. wp.org's reviewer flagged Plugin URI and Author URI being identical (both pointed at the author site) \u2014 Plugin URI dropped, Author URI kept since it's the more accurate one for this header set.<\/li>\n<\/ul>\n\n<h4>1.3.2<\/h4>\n\n<ul>\n<li>Plugin Check follow-up: moved the <code>slow_db_query_meta_query<\/code> phpcs:ignore directly above the <code>meta_query<\/code> array key in <code>OTTPOST_Scheduler::tick()<\/code> so the suppression actually applies (the previous placement above the <code>WP_Query<\/code> call was too high to silence the warning on the inner array key).<\/li>\n<\/ul>\n\n<h4>1.3.1<\/h4>\n\n<ul>\n<li>Plugin Check pass. Removed the discouraged <code>load_plugin_textdomain()<\/code> call (WP 4.6+ auto-loads translations for wp.org plugins). Switched the OAuth-start <code>wp_redirect()<\/code> to <code>wp_safe_redirect()<\/code> with <code>www.facebook.com<\/code> whitelisted via the <code>allowed_redirect_hosts<\/code> filter. Added <code>wp_unslash()<\/code> ahead of <code>sanitize_text_field()<\/code> for <code>$_GET['cal_month']<\/code> and <code>$_GET['day']<\/code> on the Scheduled view. Documented intentional <code>$_POST['app_secret']<\/code> non-sanitization with a phpcs:ignore note (the value is encrypted before storage). Added phpcs:ignore comments for read-only <code>$_GET<\/code> flag checks and the <code>meta_query<\/code> \/ <code>meta_key<\/code> slow-query notices on small admin queries. Trimmed the readme short-description to fit the 150-char wp.org cap.<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>Initial wp.org submission. 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 <code>uninstall.php<\/code> that drops plugin options, OAuth credentials, and the cron event when the user deletes the plugin from Plugins \u2192 Delete.<\/li>\n<\/ul>\n\n<h4>1.2.4<\/h4>\n\n<ul>\n<li>List view now sorts the next post going out to the top; older \/ past posts follow in reverse chronological order.<\/li>\n<\/ul>\n\n<h4>1.2.3<\/h4>\n\n<ul>\n<li>Optional First Comment field on the composer \u2014 posted automatically on the published post immediately after it goes live. Comment failures do not roll back the main post.<\/li>\n<\/ul>\n\n<h4>1.2.2<\/h4>\n\n<ul>\n<li>Coloured-background picker now ships 41 known-good Facebook <code>text_format_preset_id<\/code> values with visual swatches plus a custom-preset-ID override.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Edit on any saved post now returns to the composer with every field hydrated (page, message, image, schedule, type, background, first comment).<\/li>\n<li>Scheduled-posts list grows a Preview column with a thumbnail per row (image \/ coloured tile \/ text excerpt).<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>New \"Scheduled\" admin page with a month Calendar view and a chronological List view of every drafted \/ scheduled \/ pending \/ sent post.<\/li>\n<li>Coloured-background text post type added to the composer.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release. Facebook OAuth flow (App ID + App Secret \u2192 user token \u2192 page tokens), composer with message + image + Page picker, three modes (Post Now, Schedule, Save as Draft), WP-Cron background worker, encrypted at-rest storage of App Secret and Page tokens.<\/li>\n<\/ul>","raw_excerpt":"Schedule and publish Facebook Page posts from WordPress. Calendar + list views, coloured-background text posts, optional first comment.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/311603","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=311603"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/onetwothreesend"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=311603"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=311603"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=311603"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=311603"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=311603"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=311603"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}