{"id":307552,"date":"2026-05-27T11:03:17","date_gmt":"2026-05-27T11:03:17","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/public-post-preview-extended\/"},"modified":"2026-05-27T11:02:45","modified_gmt":"2026-05-27T11:02:45","slug":"secure-draft-preview-links","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/secure-draft-preview-links\/","author":23492041,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.0","stable_tag":"1.0.0","tested":"6.9.4","requires":"6.5","requires_php":"8.0","requires_plugins":null,"header_name":"Secure Draft Preview Links","header_author":"savedprompt","header_description":"Share draft posts with anyone via a secure, time-limited preview link. Works with both the Block Editor and Classic Editor.","assets_banners_color":"416acb","last_updated":"2026-05-27 11:02:45","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/wordpress.org\/plugins\/secure-draft-preview-links\/","header_author_uri":"https:\/\/profiles.wordpress.org\/savedprompt\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":29,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"savedprompt","date":"2026-05-27 11:02:45"}},"upgrade_notice":{"1.0.0":"<p>Initial release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3550514,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3550514,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3550514,"resolution":"1544x500","location":"assets","locale":"","width":1543,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3550514,"resolution":"772x250","location":"assets","locale":"","width":771,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3550514,"resolution":"1","location":"assets","locale":"","width":2949,"height":1584},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3550514,"resolution":"2","location":"assets","locale":"","width":2864,"height":1504},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3550514,"resolution":"3","location":"assets","locale":"","width":2864,"height":1504},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3550514,"resolution":"4","location":"assets","locale":"","width":2864,"height":1504},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3550514,"resolution":"5","location":"assets","locale":"","width":2864,"height":1504}},"screenshots":{"1":"Block Editor \u2014 Enable public preview checkbox in the Status &amp; Visibility panel with URL code box and expiry settings.","2":"Classic Editor \u2014 Enable public preview checkbox in the Publish meta box.","3":"Preview Links admin page \u2014 Active tab with paginated table and share buttons.","4":"Preview Links admin page \u2014 Expired tab.","5":"Confirmation dialog before generating a new link."}},"plugin_section":[],"plugin_tags":[4665,2475,259178,5677,138],"plugin_category":[56],"plugin_contributors":[264624],"plugin_business_model":[],"class_list":["post-307552","plugin","type-plugin","status-publish","hentry","plugin_tags-draft","plugin_tags-preview","plugin_tags-preview-link","plugin_tags-public","plugin_tags-share","plugin_category-social-and-sharing","plugin_contributors-savedprompt","plugin_committers-savedprompt"],"banners":{"banner":"https:\/\/ps.w.org\/secure-draft-preview-links\/assets\/banner-772x250.png?rev=3550514","banner_2x":"https:\/\/ps.w.org\/secure-draft-preview-links\/assets\/banner-1544x500.png?rev=3550514","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/secure-draft-preview-links\/assets\/icon-128x128.png?rev=3550514","icon_2x":"https:\/\/ps.w.org\/secure-draft-preview-links\/assets\/icon-256x256.png?rev=3550514","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/secure-draft-preview-links\/assets\/screenshot-1.png?rev=3550514","caption":"Block Editor \u2014 Enable public preview checkbox in the Status &amp; Visibility panel with URL code box and expiry settings."},{"src":"https:\/\/ps.w.org\/secure-draft-preview-links\/assets\/screenshot-2.png?rev=3550514","caption":"Classic Editor \u2014 Enable public preview checkbox in the Publish meta box."},{"src":"https:\/\/ps.w.org\/secure-draft-preview-links\/assets\/screenshot-3.png?rev=3550514","caption":"Preview Links admin page \u2014 Active tab with paginated table and share buttons."},{"src":"https:\/\/ps.w.org\/secure-draft-preview-links\/assets\/screenshot-4.png?rev=3550514","caption":"Preview Links admin page \u2014 Expired tab."},{"src":"https:\/\/ps.w.org\/secure-draft-preview-links\/assets\/screenshot-5.png?rev=3550514","caption":"Confirmation dialog before generating a new link."}],"raw_content":"<!--section=description-->\n<p><strong>Secure Draft Preview Links<\/strong> lets you generate a cryptographically secure, unguessable link for any draft post so that people without a WordPress account can read it before it goes live.<\/p>\n\n<h4>How it works<\/h4>\n\n<ol>\n<li>Open any draft post or page in the editor.<\/li>\n<li>Check <strong>Enable public preview<\/strong> in the Publish panel (Classic Editor) or Status &amp; Visibility panel (Block Editor).<\/li>\n<li>Copy the generated link and share it with anyone.<\/li>\n<li>The recipient can view the draft without logging in.<\/li>\n<li>Uncheck the box or set the expiry to <strong>Expired<\/strong> to revoke access immediately.<\/li>\n<\/ol>\n\n<h4>Editor features<\/h4>\n\n<ul>\n<li>Works with both the <strong>Classic Editor<\/strong> and the <strong>Block Editor<\/strong> (Gutenberg).<\/li>\n<li>Checkbox to enable \/ disable preview \u2014 shown even on auto-draft posts (disabled with a \"save first\" hint).<\/li>\n<li>When a post is published the checkbox automatically disables and shows \"Not available for published posts\".<\/li>\n<li>Preview URL displayed in a monospace code box \u2014 horizontally scrollable, click to select all.<\/li>\n<li><strong>Copy<\/strong> button and <strong>Open preview<\/strong> button inline with the URL box.<\/li>\n<li><strong>Generate new link<\/strong> button \u2014 invalidates the old link immediately, with a confirmation step before firing.<\/li>\n<li><strong>Stop sharing<\/strong> confirmation bar \u2014 shown when unchecking the checkbox, requires explicit confirmation before removing the link.<\/li>\n<li>Expiry selector with four options:\n\n<ul>\n<li><strong>48 hours<\/strong> \u2014 default, shows exact time remaining (e.g. \"Expires on: Apr 29 \u00b7 14:32 (4h 12m remaining)\").<\/li>\n<li><strong>Always available<\/strong> \u2014 link never expires.<\/li>\n<li><strong>Custom time<\/strong> \u2014 set Days, Hours, and Minutes; live \"Expires on:\" display updates as you type; shows error if all fields are cleared without saving.<\/li>\n<li><strong>Expired (disable now)<\/strong> \u2014 immediately invalidates the link without deleting the token.<\/li>\n<\/ul><\/li>\n<li>Expiry settings auto-save on change with a \"Expiry setting saved.\" confirmation message.<\/li>\n<li>Block Editor: snackbar notices for every action (enable, disable, copy, generate new link).<\/li>\n<li>Block Editor: <strong>Open public preview<\/strong> item added to the Preview dropdown (WordPress 6.7+).<\/li>\n<\/ul>\n\n<h4>Preview Links admin page<\/h4>\n\n<ul>\n<li>Dedicated <strong>Preview Links<\/strong> menu item in the WordPress admin sidebar.<\/li>\n<li>Two tabs: <strong>Active<\/strong> and <strong>Expired<\/strong>, each showing a count badge.<\/li>\n<li><strong>Paginated table<\/strong> \u2014 20 items per page, with top and bottom pagination controls.<\/li>\n<li>Per-row columns: Post title, Post type, Exact expiry time, Preview URL, Share buttons, Actions.<\/li>\n<li><strong>Copy URL<\/strong> and <strong>Open preview<\/strong> icon buttons inline with the URL.<\/li>\n<li><strong>Share buttons<\/strong>: Facebook, X (Twitter), LinkedIn, Email \u2014 captions include the post title and expiry time (omitted for never-expires links).<\/li>\n<li><strong>Regenerate<\/strong> button \u2014 generates a new token with a confirmation dialog; old link stops working immediately.<\/li>\n<li><strong>Stop Sharing<\/strong> button \u2014 removes the token with a confirmation dialog.<\/li>\n<li><strong>Edit Post<\/strong> link opens in a new tab.<\/li>\n<li>Confirmation dialogs use an inline modal (no browser <code>confirm()<\/code>) with clear messaging about consequences.<\/li>\n<li>Toast notifications slide up from the bottom-right on every action.<\/li>\n<\/ul>\n\n<h4>Security<\/h4>\n\n<ul>\n<li>Tokens are 64-character cryptographically random hex strings generated with <code>random_bytes()<\/code>.<\/li>\n<li>Token validation uses <code>hash_equals()<\/code> to prevent timing attacks.<\/li>\n<li>Expired links return a <strong>410 Gone<\/strong> HTTP response.<\/li>\n<li>Invalid tokens return a <strong>403 Forbidden<\/strong> HTTP response.<\/li>\n<li>Preview link is automatically removed when a post is published, made private, or trashed.<\/li>\n<li>All AJAX endpoints are protected with nonces and capability checks.<\/li>\n<li>No data is exposed to unauthenticated users beyond the post content itself.<\/li>\n<\/ul>\n\n<h4>Post list table<\/h4>\n\n<ul>\n<li><strong>Public Preview<\/strong> badge shown next to post titles that have an active preview link.<\/li>\n<li><strong>Public Preview<\/strong> filter view in the post list table to quickly find all posts with active links.<\/li>\n<\/ul>\n\n<h4>Technical<\/h4>\n\n<ul>\n<li>Works with all viewable public post types (posts, pages, and custom post types).<\/li>\n<li>Pagination links on multi-page posts are rewritten to include the preview token.<\/li>\n<li>Token meta is registered with the REST API for block editor compatibility.<\/li>\n<li>No external dependencies \u2014 pure PHP, jQuery (Classic Editor), and WordPress's own React\/wp-components (Block Editor).<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>secure-draft-preview-links<\/code> folder to <code>\/wp-content\/plugins\/<\/code>.<\/li>\n<li>Activate the plugin through the <strong>Plugins<\/strong> screen in WordPress.<\/li>\n<li>Open any draft post or page in the editor.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20work%20for%20custom%20post%20types%3F\"><h3>Does this work for custom post types?<\/h3><\/dt>\n<dd><p>Yes. The panel appears on all viewable public post types automatically.<\/p><\/dd>\n<dt id=\"what%20happens%20when%20the%20link%20expires%3F\"><h3>What happens when the link expires?<\/h3><\/dt>\n<dd><p>Visitors see a \"Preview Link Expired\" page with a 410 HTTP status. The token remains stored so you can see it in the Preview Links page, but it no longer grants access.<\/p><\/dd>\n<dt id=\"can%20i%20share%20the%20link%20with%20multiple%20people%3F\"><h3>Can I share the link with multiple people?<\/h3><\/dt>\n<dd><p>Yes \u2014 the link is not tied to any specific user or session.<\/p><\/dd>\n<dt id=\"what%20happens%20when%20the%20post%20is%20published%3F\"><h3>What happens when the post is published?<\/h3><\/dt>\n<dd><p>The preview token is automatically deleted and visitors are redirected to the live permalink.<\/p><\/dd>\n<dt id=\"is%20the%20preview%20link%20secure%3F\"><h3>Is the preview link secure?<\/h3><\/dt>\n<dd><p>Yes. Each token is a 64-character cryptographically random hex string generated with <code>random_bytes()<\/code>. It is validated using <code>hash_equals()<\/code> to prevent timing attacks.<\/p><\/dd>\n<dt id=\"can%20i%20set%20a%20custom%20expiry%20time%3F\"><h3>Can I set a custom expiry time?<\/h3><\/dt>\n<dd><p>Yes. Choose <strong>Custom time<\/strong> from the expiry dropdown and enter Days, Hours, and Minutes. The link will stop working after that duration. You can also choose <strong>Always available<\/strong> for a link that never expires.<\/p><\/dd>\n<dt id=\"how%20do%20i%20revoke%20access%20immediately%3F\"><h3>How do I revoke access immediately?<\/h3><\/dt>\n<dd><p>Either uncheck <strong>Enable public preview<\/strong> (and confirm in the dialog), or select <strong>Expired (disable now)<\/strong> from the expiry dropdown. Both invalidate the link instantly.<\/p><\/dd>\n<dt id=\"can%20i%20regenerate%20the%20link%20without%20disabling%20it%3F\"><h3>Can I regenerate the link without disabling it?<\/h3><\/dt>\n<dd><p>Yes. Click <strong>Generate new link<\/strong> \u2014 after confirming, a new token is created and the old link stops working immediately. The expiry settings are preserved.<\/p><\/dd>\n<dt id=\"where%20can%20i%20see%20all%20my%20preview%20links%3F\"><h3>Where can I see all my preview links?<\/h3><\/dt>\n<dd><p>Go to <strong>Preview Links<\/strong> in the WordPress admin sidebar. It shows all active and expired links across all post types, with share buttons and management actions.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<li>Secure token generation using <code>random_bytes()<\/code> with <code>hash_equals()<\/code> validation.<\/li>\n<li>Works with Classic Editor and Block Editor (Gutenberg).<\/li>\n<li>Custom expiry: 48 hours (default), always available, custom Days\/Hours\/Minutes, or expire immediately.<\/li>\n<li>Live \"Expires on:\" display with exact time remaining.<\/li>\n<li>Regenerate and stop-sharing actions with inline confirmation dialogs.<\/li>\n<li>Preview Links admin page with Active\/Expired tabs, pagination, and social share buttons (Facebook, X, LinkedIn, Email).<\/li>\n<li>Auto-removal on publish, private, or trash.<\/li>\n<li>\"Public Preview\" badge and filter view in the post list table.<\/li>\n<li>Pagination support for multi-page posts.<\/li>\n<li>Block Editor: snackbar notices, Preview dropdown menu item (WP 6.7+).<\/li>\n<li>Disabled state with contextual hints for published posts and unsaved drafts.<\/li>\n<\/ul>","raw_excerpt":"Share draft posts with anyone via a secure, time-limited preview link \u2014 no login required.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/307552","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=307552"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/savedprompt"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=307552"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=307552"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=307552"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=307552"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=307552"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=307552"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}