Git Product home page Git Product logo

public-post-preview's Introduction

Public Post Preview

WordPress plugin to share a link to anonymous users to preview a draft of a post (or any other public post type) before it is published.

Have you ever been writing a post with the help of someone who does not have access to your blog and needed to give them the ability to preview it before publishing? This plugin takes care of that by generating an URL with an expiring nonce that can be given out for public preview.

This plugin was previously maintained by Matt Martz and was an idea of Jonathan Dingman. Thanks to Hans Dinkelberg for his photo.

Installation

Note: There will be NO settings page.

For an automatic installation through WordPress:

  1. Go to the 'Add New' plugins screen in your WordPress admin area
  2. Search for 'Public Post Preview'
  3. Click 'Install Now' and activate the plugin

For a manual installation via FTP:

  1. Upload the public-post-preview directory to the /wp-content/plugins/ directory
  2. Activate the plugin through the 'Plugins' screen in your WordPress admin area

To upload the plugin through WordPress, instead of FTP:

  1. Upload the downloaded zip file on the 'Add New' plugins screen (see the 'Upload' tab) in your WordPress admin area and activate.

Usage

  • To enable a public post preview check the box in the "Status & Visibility" section of the document settings. In the classic editor it's in the "Publish" meta box.
  • The link will be displayed if the checkbox is checked, you can copy and share the link with your friends.
  • To disable a preview uncheck the box again.

Frequently Asked Questions

I can't find the option for preview links. Where is it?

The checkbox is only available for non-published posts and once a post was saved as a draft.

After some time the preview link returns the message "The link has been expired!". Why?

The plugin generates an URL with an expiring nonce. By default a link "lives" 48 hours. After 48 hours the link is expired and you need to copy and share a new link which is automatically generated on the same place under the editor.

48 hours are not enough to me. Can I extend the nonce time?

Yes, of course. You can use the filter ppp_nonce_life. Example for 5 days:

add_filter( 'ppp_nonce_life', 'my_nonce_life' );
function my_nonce_life() {
	return 5 * DAY_IN_SECONDS;
}

Or use the Public Post Preview Configurator.

public-post-preview's People

Contributors

dependabot[bot] avatar jeroensormani avatar johnbillion avatar ocean90 avatar peterwilsoncc avatar rcstr avatar sivel avatar szepeviktor avatar westonruter avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

public-post-preview's Issues

Allow collaborators to comment

The public link is awesome, but what'd be more awesome is giving collaborators the opportunity to add comments. For me, without this feature, it makes the public link a bit useless – I still have to write my post in a Google Doc if I want to get feedback before publishing.

Here's a great example of Medium's implementation: http://techcrunch.com/2013/04/09/medium-adds-collaboration-tools-to-its-publishing-platform-allowing-people-to-add-notes-to-your-posts/

I'd be interested in opening a PR, but want to get some thoughts on whether or not this would be a useful feature to anyone other than me. πŸ˜„

Nonce life time

One of our customers noticed that their preview link expired well before the 14 days we configured via ppp_nonce_life.

So i did some investigating, copied the functions in question and added the ability to add a delta for calculating future values:

<?php
//  test-ppp-nonce.php

function create_nonce( $action = -1, $delta = 0) {
  $i = nonce_tick($delta);

  return substr( wp_hash( $i . $action, 'nonce' ), -12, 10 );
}

function verify_nonce( $nonce, $action = -1, $delta=0 ) {
    $i = nonce_tick($delta);

    // Nonce generated 0-12 hours ago.
    if ( substr( wp_hash( $i . $action, 'nonce' ), -12, 10 ) === $nonce ) {
      return 1;
    }

    // Nonce generated 12-24 hours ago.
    if ( substr( wp_hash( ( $i - 1 ) . $action, 'nonce' ), -12, 10 ) === $nonce ) {
      return 2;
    }

    // Invalid nonce.
    return false;
}



function nonce_tick($delta = 0) {
    $nonce_life = 60 * 60 * 24 * 28;
    return ceil( (time() + $delta) / ( $nonce_life / 2 ) );
}


$range = range(0, 28);

$nonce = create_nonce();

$lines = array_map(function($i) use($nonce){
  $delta = $i * 60 * 60 * 24;
  return "Day: " . $i . " tick: " . nonce_tick($delta) . "  verify: " . var_export(verify_nonce($nonce, -1, $delta), true) .  " new nonce: " . create_nonce(-1, $delta);
}, $range);


var_export('initial nonce: ' . $nonce);
var_export($lines);

which yielded:

$ wp eval-file test-ppp-nonce.php

'initial nonce: a1ff370a10' array (
  0 => 'Day: 0 tick: 2594  verify: 1 new nonce: a1ff370a10',
  1 => 'Day: 1 tick: 2594  verify: 1 new nonce: a1ff370a10',
  2 => 'Day: 2 tick: 2594  verify: 1 new nonce: a1ff370a10',
  3 => 'Day: 3 tick: 2594  verify: 1 new nonce: a1ff370a10',
  4 => 'Day: 4 tick: 2594  verify: 1 new nonce: a1ff370a10',
  5 => 'Day: 5 tick: 2594  verify: 1 new nonce: a1ff370a10',
  6 => 'Day: 6 tick: 2595  verify: 2 new nonce: ba6ee27d7c',
  7 => 'Day: 7 tick: 2595  verify: 2 new nonce: ba6ee27d7c',
  8 => 'Day: 8 tick: 2595  verify: 2 new nonce: ba6ee27d7c',
  9 => 'Day: 9 tick: 2595  verify: 2 new nonce: ba6ee27d7c',
  10 => 'Day: 10 tick: 2595  verify: 2 new nonce: ba6ee27d7c',
  11 => 'Day: 11 tick: 2595  verify: 2 new nonce: ba6ee27d7c',
  12 => 'Day: 12 tick: 2595  verify: 2 new nonce: ba6ee27d7c',
  13 => 'Day: 13 tick: 2596  verify: false new nonce: 145171fef4',
  14 => 'Day: 14 tick: 2596  verify: false new nonce: 145171fef4',
  15 => 'Day: 15 tick: 2596  verify: false new nonce: 145171fef4',
  16 => 'Day: 16 tick: 2596  verify: false new nonce: 145171fef4',
  17 => 'Day: 17 tick: 2596  verify: false new nonce: 145171fef4',
  18 => 'Day: 18 tick: 2596  verify: false new nonce: 145171fef4',
  19 => 'Day: 19 tick: 2596  verify: false new nonce: 145171fef4',
  20 => 'Day: 20 tick: 2597  verify: false new nonce: 84b587a0b4',
  21 => 'Day: 21 tick: 2597  verify: false new nonce: 84b587a0b4',
  22 => 'Day: 22 tick: 2597  verify: false new nonce: 84b587a0b4',
  23 => 'Day: 23 tick: 2597  verify: false new nonce: 84b587a0b4',
  24 => 'Day: 24 tick: 2597  verify: false new nonce: 84b587a0b4',
  25 => 'Day: 25 tick: 2597  verify: false new nonce: 84b587a0b4',
  26 => 'Day: 26 tick: 2597  verify: false new nonce: 84b587a0b4',
  27 => 'Day: 27 tick: 2598  verify: false new nonce: 6e8ac2f82e',
  28 => 'Day: 28 tick: 2598  verify: false new nonce: 6e8ac2f82e',
)

As you can see, only every 7 days a new nonce is generated, so the initial nonce, which is still generated until the fifth day will only live 7 days.

Please correct me if i'm wrong, but i think it should be properly communicated in the documentation, that the nonce life is the maximum life and links could expire well before that.

Compatibility with Gutenberg

Hi Dominik. This is a duplicated post because I couldn't reach you via WordPress support. My question is: Do you have any plans to make this great plugin compatible with Gutenberg? At the moment the plugin isn’t visible if you are using Gutenberg.

Clicking Checkbox Fails on 5.7.1 (multisite)

On Wordpress 5.7.1 (multisite)

When clicking the checkbox on a post page, the following request is sent to the wordpress admin-ajax.php endpoint:

HEADERS

:authority: lafayettecc.org
:method: POST
:path: /blogs/jeff/wp-admin/admin-ajax.php
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9,fr;q=0.8
cache-control: no-cache
content-length: 75
content-type: application/x-www-form-urlencoded; charset=UTF-8

BODY

_ajax_nonce: 475125b461
checked: true
post_ID: 2504
action: public-post-preview

And this is the response:

HEADERS

access-control-allow-credentials: true
access-control-allow-origin: https://lafayettecc.org
cache-control: no-cache, must-revalidate, max-age=0
content-type: text/html; charset=UTF-8
date: Tue, 27 Jul 2021 20:27:27 GMT
expires: Wed, 11 Jan 1984 05:00:00 GMT
referrer-policy: strict-origin-when-cross-origin
server: nginx/1.14.0 (Ubuntu)
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-robots-tag: noindex

BODY

0

However, for some reason, when executing the exact command from CURL (including all headers and cookies of course) it succeeds

Increase token length, or make it harder to brute-force tokens.

With a 5 byte token and 48 hour window, it would take 256^5 / (48*3600) (about 6 million) qps to have a 100% chance of accessing the preview. 6 million qps is very high, but not outrageously high. If it's trivial, would you mind increasing the token length and/or adding a ~1 second sleep before the verification code, to make a brute force attack harder?

Preview page is broken

We are having issues with the plugin, but don't know if there is a conflict with other plugins. Our site is on WordPress 6.2.x. Is you plugin compatible with that version? We updated a bunch of plugins and that's when the preview broke. Most of the content is missing from the page when save a new draft but the CSS for the content that is there seems fine. The first draft preview will display correctly but updates to the draft after that have missing content on the preview. We have not altered the code in the plugin. Here is a list of plugins that got updated when the issue started.

  • ACF Pro
  • AYS Popup Box
  • Contact Form 7 Conditional Fields
  • Contact Form 7
  • FacetWP
  • Relavnssi Premium
  • Safe SVG
  • Simple Page Ordering
  • User Role Editor
  • White Label CMS
  • Wordfence
  • WordPress SEO
  • WordPress SEO Premium

Change HTTP headers for expired preview links

Hey! We're running into some situation where preview links are being indexed by Google. Unfortunately, as soon as they expire, they give a 500 HTTP status error. This causes Google to continuously crawl that URL as it thinks its erroring. I think a better solution would be to:

  • 301 redirect to the post or page if it was published since.
  • 404 if it's not published.

Language files

Is there a way to load the new internationalization files for Gutenberg? These files are done via json.

  • Gutenberg doesn't use mo files, you need to use json by wp i18n make-json
  • You also need to call wp_set_script_translations
  • gutenberg_get_jed_locale_data is deprecated as of version 5.2 (I believe)

I'm just wondering if there are any plans in the pipeline to update how the Gutenberg internationalization stuff is done.

Allow setting/resetting/unsetting the "Public preview" status from the posts list's "Quick Edit" feature

Oftentimes I would like to be able to turn on/off, or renew, a public preview link for a blog post, or multiple blog posts, without entering the heavy and cumbersome Wordpress editing mode for each of them.

In /wp-admin/edit.php?post_type=post, Wordpress already has a "Quick Edit" link below each post on hover, that allows setting their most important metadata. Could it be possible for this plugin to expose its status there, too? Maybe related to issue #16?

Conflict with WP Statuses

Hi,

Thanks for your work with Public Post Preview.

I’m started to using it along with WP Statuses (https://github.com/imath/wp-statuses).

That changes things a bit since in the gutenberg-integration.js script when you use getEditedPostAttribute, WP Statuses returns private as status for all statuses, but adds a custom_status attribute that has the correct values.

status: getEditedPostAttribute( 'status' ),

Do you think it is possible to somehow filter the attribute to use, or add some conditional so that the Public Post Preview works with WP Statuses?

Thanks

`wp_no_robots()` is deprecated since 5.7.0!

Plugin uses:

add_action( 'wp_head', 'wp_no_robots' );

Core does:

https://github.com/WordPress/WordPress/blob/f80e5d09197bfded72e74140bc377e0e96fc3622/wp-includes/deprecated.php#L4175

Probably should swap, or do a conditional to swap if the new function exists, to avoid

Deprecated: wp_no_robots is deprecated since version 5.7.0! Use wp_robots_no_robots() instead. in /path/to/wp/wp-includes/functions.php on line 4861

Mark public preview posts as noindex

I have a use case where the public preview link only expires after a week so give enough time for the different parties to discuss the post.

This has had the negative impact that google has started to index the public preview link.

It would be good to add a meta tag to prevent this <meta name="robots" content="noindex>, or even add support Yoast SEO by changing the post value WPSEO_Meta::set_value( 'meta-robots-noindex', '1', $post_id );

Check the existence of superglobals $_POST['post_ID'] and $_POST['checked']

We tried to use the plugin, but was request to fix below three superglobal array issues.

Note: the review was done when Public Post Preview was v2.9.1, so the lines 388, 404, and 406 in below report are now 394, 410 and 412 respectively.

-------------------------------------------------------------------------------------------------------------------------------------------------------------------
FOUND 3 ERRORS AFFECTING 3 LINES
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
 388 | ERROR | Detected usage of a possibly undefined superglobal array index: $_POST['post_ID']. Use isset() or empty() to check the index exists before using it
 404 | ERROR | Detected usage of a possibly undefined superglobal array index: $_POST['checked']. Use isset() or empty() to check the index exists before using it
 406 | ERROR | Detected usage of a possibly undefined superglobal array index: $_POST['checked']. Use isset() or empty() to check the index exists before using it
-------------------------------------------------------------------------------------------------------------------------------------------------------------------

I will send the PR, which was worked from v2.9.2.

Preview doesn't show any Beaver Builder content

Starting in version 2.7.4.3 of Beaver Builder, there are security fixes that prevent non-public posts (like drafts) from being rendered by BB to people without access.

So this plugin stops working with Beaver Builder

There is a filter that can be used to adjust this though and we came up with the following:

add_filter( 'fl_render_content_by_id_can_view', function( $can_view, $post_id ) {
	if ( class_exists( 'DS_Public_Post_Preview' ) ) {
		$post_ids = get_option( 'public_post_preview', array() );
		$post_ids = array_map( 'intval', $post_ids );
		$can_view = ( in_array( $post_id, $post_ids ) ) ? true : $can_view;
	}
	return $can_view;
}, 10, 2 );

Would you be interested in adding this to your plugin for compatibility?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.