{"id":251743,"date":"2025-09-16T21:47:10","date_gmt":"2025-09-16T21:47:10","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/secure-role-restricted-preview-links-draft-share-with-acls\/"},"modified":"2025-10-02T15:00:09","modified_gmt":"2025-10-02T15:00:09","slug":"secure-role-restricted-draft-previews","status":"publish","type":"plugin","link":"https:\/\/tah.wordpress.org\/plugins\/secure-role-restricted-draft-previews\/","author":23362138,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_crdt_document":"","version":"1.0.1","stable_tag":"1.0.1","tested":"6.8.5","requires":"6.4","requires_php":"8.1","requires_plugins":null,"header_name":"Secure Role-Restricted Draft Previews","header_author":"Pixy Puala","header_description":"Generates expiring preview links that require login and restrict access by role, user, or per-email token\u2014plus per-link analytics and revoke-all. Compatible with FSE, Block Themes, Classic Themes, all page builders, WooCommerce, and Tailwind CSS v4+. Fully compliant with WordPress.org requirements for data storage and security.","assets_banners_color":"d9e3ef","last_updated":"2025-10-02 15:00:09","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/wordpress.org\/plugins\/secure-role-restricted-draft-previews\/","header_author_uri":"https:\/\/pixypuala.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":251,"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":"pixypuala","date":"2025-09-16 21:46:33"},"1.0.1":{"tag":"1.0.1","author":"pixypuala","date":"2025-10-02 15:00:09"}},"upgrade_notice":{"1.0.1":"<p>Updated plugin assets for WordPress.org directory. All persistent data is stored in the WordPress database or in a subfolder of the uploads directory. No plugin-folder writes. No code editing required.<\/p>","1.0.0":"<p>Initial release. All persistent data is stored in the WordPress database or in a subfolder of the uploads directory. No plugin-folder writes. No code editing required.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3371863,"resolution":"128x128","location":"assets","locale":""},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3371863,"resolution":"256x256","location":"assets","locale":""}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3371863,"resolution":"1544x500","location":"assets","locale":""},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3371863,"resolution":"772x250","location":"assets","locale":""}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.0","1.0.1"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3371863,"resolution":"1","location":"assets","locale":""}},"screenshots":{"1":"Editor meta box: generate, copy, revoke."},"jetpack_post_was_ever_published":false},"plugin_section":[],"plugin_tags":[1912,2871,2475,1915,600],"plugin_category":[54,58],"plugin_contributors":[247506],"plugin_business_model":[],"class_list":["post-251743","plugin","type-plugin","status-publish","hentry","plugin_tags-access-control","plugin_tags-drafts","plugin_tags-preview","plugin_tags-roles","plugin_tags-security","plugin_category-security-and-spam-protection","plugin_category-user-management","plugin_contributors-pixypuala","plugin_committers-pixypuala"],"banners":{"banner":"https:\/\/ps.w.org\/secure-role-restricted-draft-previews\/assets\/banner-772x250.png?rev=3371863","banner_2x":"https:\/\/ps.w.org\/secure-role-restricted-draft-previews\/assets\/banner-1544x500.png?rev=3371863","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/secure-role-restricted-draft-previews\/assets\/icon-128x128.png?rev=3371863","icon_2x":"https:\/\/ps.w.org\/secure-role-restricted-draft-previews\/assets\/icon-256x256.png?rev=3371863","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/secure-role-restricted-draft-previews\/assets\/screenshot-1.png?rev=3371863","caption":"Editor meta box: generate, copy, revoke."}],"raw_content":"<!--section=description-->\n<p><strong>Why this plugin?<\/strong><\/p>\n\n<p>WordPress core preview links work well for editors, and <em>Public Post Preview<\/em> shares via anonymous nonces.\nThis plugin adds a missing middle ground: <strong>draft previews that are secured by authentication and access control\nlists (ACLs)<\/strong> \u2014 role-based, user-specific, or per-email tokens \u2014 plus analytics and a one-click revoke-all.<\/p>\n\n<p><strong>Universal Compatibility<\/strong><\/p>\n\n<p>Works seamlessly with:\n* Full Site Editing (FSE) themes\n* Block themes (modern WordPress)\n* Classic PHP-based themes\n* All page builders including Elementor, WPBakery, Divi, etc.\n* WooCommerce product drafts\n* Any CSS framework including Tailwind CSS v4+<\/p>\n\n<p><strong>Key features<\/strong><\/p>\n\n<ul>\n<li>Create expiring preview links (default 72h; configurable).<\/li>\n<li>Restrict by <strong>roles<\/strong>, <strong>specific users<\/strong>, or <strong>per-email tokens<\/strong> (no login for recipients).<\/li>\n<li>Require HTTPS for previews (on by default).<\/li>\n<li>Per-link analytics: allowed\/denied events, hashed IP, user agent (privacy-friendly).<\/li>\n<li>Meta box in the editor (Post\/Page by default; filterable) to generate, copy, and revoke.<\/li>\n<li>\"Revoke All\" for a post.<\/li>\n<li>Everything prefixed (<code>srpl_<\/code>), sanitized, and aligned with WordPress coding standards.<\/li>\n<\/ul>\n\n<p><strong>How it works<\/strong><\/p>\n\n<p>Each generated link has a unique token, TTL, and ACL:<\/p>\n\n<ul>\n<li><strong>Role-based Access:<\/strong> Requires login. Only users with allowed roles can view the preview.<\/li>\n<li><strong>User-based Access:<\/strong> Requires login. Only specific user IDs can access the preview.<\/li>\n<li><strong>Email Token Access:<\/strong> No login required. Recipients receive unique URLs with email verification tokens.<\/li>\n<\/ul>\n\n<p>When a link is visited, SRPL validates the token, expiry, and ACL, then renders the draft with your theme's header\/footer. Events are logged (when enabled) to a small custom table (<code>wp_srpl_events<\/code>) with <strong>hashed IP<\/strong> for privacy.<\/p>\n\n<p><strong>Privacy<\/strong><\/p>\n\n<ul>\n<li>IPs are hashed using <code>hash_hmac(sha256, ip, wp_salt('auth'))<\/code>.<\/li>\n<li>You can disable analytics entirely under <strong>Settings \u2192 Secure Previews<\/strong>.<\/li>\n<\/ul>\n\n<p><strong>Developer Friendly<\/strong><\/p>\n\n<ul>\n<li>Fully documented filters and actions<\/li>\n<li>Clean, object-oriented codebase<\/li>\n<li>PSR-4 autoloading<\/li>\n<li>Extensive inline documentation<\/li>\n<\/ul>\n\n<h3>Developer Documentation<\/h3>\n\n<p><strong>Filters<\/strong><\/p>\n\n<ul>\n<li><code>srpl_supported_post_types<\/code> - Modify post types that support preview links<\/li>\n<li><code>srpl_default_ttl_hours<\/code> - Change default expiration time (in hours)<\/li>\n<li><code>srpl_force_ssl<\/code> - Control whether previews are forced to use HTTPS<\/li>\n<li><code>srpl_analytics_enabled<\/code> - Enable or disable analytics collection<\/li>\n<\/ul>\n\n<p><strong>Functions<\/strong><\/p>\n\n<ul>\n<li><code>LinkManager::create($post_id, $args)<\/code> - Create a new preview link<\/li>\n<li><code>LinkManager::revoke($link_id)<\/code> - Revoke a specific link<\/li>\n<li><code>LinkManager::revoke_all_for_post($post_id)<\/code> - Revoke all links for a post<\/li>\n<li><code>LinkManager::find_by_token($token)<\/code> - Find a link by its token<\/li>\n<\/ul>\n\n<p><strong>Database Structure<\/strong><\/p>\n\n<ul>\n<li>Post Meta for Links: _srpl_token, _srpl_mode, _srpl_roles, _srpl_users, _srpl_emails, _srpl_expires, _srpl_revoked, _srpl_hits, _srpl_last_access<\/li>\n<li>Analytics Table: wp_srpl_events (link_id, post_id, user_id, outcome, ip_hash, ua, created_at)<\/li>\n<\/ul>\n\n<h3>License<\/h3>\n\n<p>This plugin is free software, licensed under the GPL v2 or later.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin folder to <code>\/wp-content\/plugins\/<\/code> or install from WP.org.<\/li>\n<li>Activate the plugin through the 'Plugins' menu in WordPress.<\/li>\n<li>Go to any Post\/Page editor \u2192 sidebar meta box \"Secure Preview Links\".<\/li>\n<li>Generate a link (choose Mode + TTL). Copy the URL (for email mode, copy the per\u2011email URLs shown).<\/li>\n<li>Optional: configure defaults in <strong>Settings \u2192 Secure Previews<\/strong>.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id='is%20this%20the%20same%20as%20public%20post%20preview%3F'><h3>Is this the same as Public Post Preview?<\/h3><\/dt>\n<dd><p>No. That plugin makes anonymous, expiring links. SRPL requires login for role\/user modes and supports per\u2011email tokens. It also offers per\u2011link analytics and revoke\u2011all functionality.<\/p><\/dd>\n<dt id='can%20i%20restrict%20by%20custom%20roles%3F'><h3>Can I restrict by custom roles?<\/h3><\/dt>\n<dd><p>Yes. All editable roles are available. You can also filter supported post types via <code>srpl_supported_post_types<\/code>.<\/p><\/dd>\n<dt id='does%20it%20support%20custom%20post%20types%3F'><h3>Does it support Custom Post Types?<\/h3><\/dt>\n<dd><p>Yes. Add your CPT slug to the <code>srpl_supported_post_types<\/code> filter:\n    <code>add_filter('srpl_supported_post_types', function($post_types) {\n    $post_types[] = 'product'; \/\/ Add custom post type\n    return $post_types;\n});<\/code><\/p><\/dd>\n<dt id='is%20this%20plugin%20compatible%20with%20full%20site%20editing%20%28fse%29%2C%20block%20themes%2C%20and%20classic%20themes%3F'><h3>Is this plugin compatible with Full Site Editing (FSE), Block Themes, and Classic Themes?<\/h3><\/dt>\n<dd><p>Yes! Our plugin works seamlessly with:\n* Full Site Editing (FSE) themes\n* Block themes (modern WordPress)\n* Classic PHP-based themes\n* All page builders including Elementor, WPBakery, Divi, etc.\n* WooCommerce product drafts\n* Any CSS framework including Tailwind CSS v4+<\/p>\n\n<p>The preview functionality renders drafts exactly as they would appear on your live site, regardless of your theme or page builder.<\/p><\/dd>\n<dt id='will%20this%20leak%20draft%20content%20to%20search%20engines%3F'><h3>Will this leak draft content to search engines?<\/h3><\/dt>\n<dd><p>No. Links are opaque tokens; access is gated and previews are not discoverable by search engines.<\/p><\/dd>\n<dt id='how%20are%20analytics%20stored%3F'><h3>How are analytics stored?<\/h3><\/dt>\n<dd><p>A lightweight table <code>wp_srpl_events<\/code> stores link id, post id, hashed IP, UA, user id (if logged), outcome, and timestamp. You can disable this in settings.<\/p><\/dd>\n<dt id='can%20i%20change%20the%20default%20expiration%20time%3F'><h3>Can I change the default expiration time?<\/h3><\/dt>\n<dd><p>Yes, use the <code>srpl_default_ttl_hours<\/code> filter:\n    <code>add_filter('srpl_default_ttl_hours', function($hours) {\n    return 168; \/\/ 1 week\n});<\/code><\/p><\/dd>\n<dt id='how%20secure%20are%20the%20preview%20links%3F'><h3>How secure are the preview links?<\/h3><\/dt>\n<dd><p>Very secure. Links use cryptographically strong tokens that are non-guessable. Email tokens are deterministic but secure, using your site's nonce salt.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Updated plugin assets for WordPress.org directory.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<\/ul>","raw_excerpt":"Generate secure, expiring preview URLs for drafts with role\/user restrictions. Compatible with FSE, Block Themes, and Classic Themes.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/tah.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/251743","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tah.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/tah.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/tah.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=251743"}],"author":[{"embeddable":true,"href":"https:\/\/tah.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/pixypuala"}],"wp:attachment":[{"href":"https:\/\/tah.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=251743"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/tah.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=251743"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/tah.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=251743"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/tah.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=251743"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/tah.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=251743"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/tah.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=251743"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}