How to Share a Draft in WordPress (Without a Plugin)

Easily share unlisted WordPress drafts without plugins or logins using one simple code snippet. Perfect for client reviews and collaboration.

Written by

Nick Cesarz

Last updated

March 24, 2025
Wordpress

Ever tried to share a WordPress draft with a client or teammate, only to realize your options are… kind of terrible? If you set the post to Private, it’s only visible to logged-in users with the right permissions.

Choose Password Protected, and WordPress still publishes the post to your live site—it just puts a locked door in front of it. And if you leave it as a Draft, well, no one else can see it at all unless they’re logged in.

None of those options work if you’re trying to quickly share a preview of a page without making it public or giving someone backend access.

Honestly, it’s frustrating. Especially when all you want is a way to share a clean, unlisted version of a post or page without making it public. Think of it like a YouTube “unlisted” video: not published, not indexed, but viewable to anyone with the link.

Good news: there’s a way to do that in WordPress with just one simple code snippet—and no plugins required. Let me show you how.

I recommend using WP Code if you don’t have a child theme installed on your website. Child themes allow you to make changes to your theme that won’t get overwritten when the developer releases a new update.

Step 1: Enable Draft Sharing with One Snippet

By default, WordPress doesn’t allow non-logged-in users to see drafts. But we can change that by injecting a small PHP snippet.

Child Theme Instructions

For those using a child theme, disregard the following instructions and paste the code snippet below into your theme’s functions.php file and jump to step 2.

Code Snippet Plugin Instructions

For those needing to use a code plugin, install and activate WPCode via the WordPress Plugins repository or from the developer’s website. Then, from the WordPress dashboard sidebar, click + Add Snippet.

Next, click on the button below Add Your Custom Code (New Snippet) and choose PHP Snippet. Paste in the following code (shoutouts to New Pulse Labs for this one).

The Code 🔧

<?php 
add_action('pre_get_posts', 'allow_draft_preview');
 
function allow_draft_preview($query) {
    if (isset($_GET['key']) && $_GET['key'] == 'guest') {
        if ($query->is_main_query()) {
            $query->set('post_status', array('publish', 'draft'));
        }
    }
}

Name your snippet, click save, and then toggle the slider to Active to turn the snippet on.

Step 2: Share Your Link

After saving your draft post or page, click Preview in the editor. You’ll get a URL like:

https://yoursite.com/?p=1234&preview=true

Now just replace preview=true with key=guest, like this:

https://yoursite.com/?p=1234&key=guest

Share that link, and your client can now view the draft — no login needed.

The biggest problem with this solution? Having to remember key=guest every time you want to share a draft with a client. So, we’re going to take this a step further.

Step 3: Add “Copy Link” + “Open in New Tab” Buttons (Optional but Awesome)

With one more code snippet, we’re going to add a simple UI to the Gutenberg sidebar when editing posts with:

  • A button to copy the draft link
  • A button to open the link in a new tab 🔗

I like this tweak and use this to preview my posts over the native Gutenberg preview button. Why? Because the native solution requires two clicks. With this solution, I can click Open in New Tab right from the sidebar. I can also copy the link to the preview and send it right to the client.

Here’s a small HTML + JavaScript snippet you can copy to enable this functionality. Note, if you use Custom Post Types, you’ll need to specify them in the code on the line commented with “// Add CPTs as needed.”

If using WPCode, repeat the process of adding a new snippet and paste the following code below.

Copy/Open UI Snippet

add_action('add_meta_boxes', function () {
    add_meta_box(
        'sharable_link_box',
        'Sharable Link',
        'render_sharable_link_box',
        ['post', 'page'], // Add CPTs as needed
        'side',
        'high'
    );
});

function render_sharable_link_box($post) {
    $is_published = $post->post_status === 'publish';

    if ( $is_published ) {
        $url = esc_url( get_permalink( $post->ID ) );
        $label = 'Live URL';
    } else {
        $preview_url = get_preview_post_link( $post->ID );
        $url = esc_url( add_query_arg( 'key', 'guest', $preview_url ) );
        $label = 'Preview URL';
    }

    echo '<label style="font-weight: bold; display: block; margin-bottom: 5px;">' . esc_html( $label ) . '</label>';
    echo '<input type="text" readonly value="' . $url . '" style="width:100%; font-size:12px;" id="sharableLinkURL">';
    
    echo '<div style="margin-top:8px; display:flex; gap:8px; flex-wrap:wrap;">';
    echo '<button type="button" class="button" onclick="copySharableURL()">Copy Link</button>';
    echo '<button type="button" class="button button-secondary" onclick="openSharableURL()">Open in New Tab</button>';
    echo '</div>';

    // JS for buttons
    echo <<<HTML
<script>
function copySharableURL() {
    const input = document.getElementById('sharableLinkURL');
    input.select();
    input.setSelectionRange(0, 99999); // For mobile
    document.execCommand('copy');
    alert('URL copied to clipboard!');
}

function openSharableURL() {
    const input = document.getElementById('sharableLinkURL');
    const url = input.value;
    window.open(url, '_blank');
}
</script>
HTML;
}

Once your client is done reviewing the draft, it’s a good idea to disable the snippet or remove the key=guest parameter to keep things secure.

For added protection, you can also use a more unique key—something like key=34dhs82k instead of the default—to make the link harder to guess.

And of course, always test the snippet on a staging site before deploying it live, just to make sure everything works as expected without any surprises.