summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheo Chatzimichos <tampakrap@gentoo.org>2013-10-08 17:47:47 +0200
committerTheo Chatzimichos <tampakrap@gentoo.org>2013-10-08 17:47:47 +0200
commit5a6e23c116b7d42b03ed646b1e5c08c7b43bfda3 (patch)
treeb279d9d0c8ce58d082b223491541668489255a5b /plugins/public-post-preview/public-post-preview.php
parentAdd table-of-contents-plus plugin, requested by hwoarang (diff)
downloadblogs-gentoo-5a6e23c116b7d42b03ed646b1e5c08c7b43bfda3.tar.gz
blogs-gentoo-5a6e23c116b7d42b03ed646b1e5c08c7b43bfda3.tar.bz2
blogs-gentoo-5a6e23c116b7d42b03ed646b1e5c08c7b43bfda3.zip
Add public-post-preview plugin
Diffstat (limited to 'plugins/public-post-preview/public-post-preview.php')
-rw-r--r--plugins/public-post-preview/public-post-preview.php465
1 files changed, 465 insertions, 0 deletions
diff --git a/plugins/public-post-preview/public-post-preview.php b/plugins/public-post-preview/public-post-preview.php
new file mode 100644
index 00000000..ce2744be
--- /dev/null
+++ b/plugins/public-post-preview/public-post-preview.php
@@ -0,0 +1,465 @@
+<?php
+/**
+ * Plugin Name: Public Post Preview
+ * Version: 2.2
+ * Description: Enables you to give a link to anonymous users for public preview of any post type before it is published.
+ * Author: Dominik Schilling
+ * Author URI: http://wphelper.de/
+ * Plugin URI: http://wpgrafie.de/wp-plugins/public-post-preview/en/
+ *
+ * Text Domain: ds-public-post-preview
+ * Domain Path: /lang
+ *
+ * License: GPLv2 or later
+ *
+ * Previously (2009-2011) maintained by Jonathan Dingman and Matt Martz.
+ *
+ * Copyright (C) 2012-2013 Dominik Schilling
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * Don't call this file directly.
+ */
+if ( ! class_exists( 'WP' ) ) {
+ die();
+}
+
+/**
+ * The class which controls the plugin.
+ *
+ * Used hooks:
+ * - pre_get_posts
+ * - query_vars
+ * - init
+ * - post_submitbox_misc_actions
+ * - save_post
+ * - posts_results
+ * - wp_ajax_public-post-preview
+ * - admin_enqueue_scripts
+ *
+ * Inits at 'plugins_loaded' hook.
+ *
+ */
+class DS_Public_Post_Preview {
+
+ /**
+ * Hooks into 'pre_get_posts' to handle public preview, only nn-admin
+ * Hooks into 'add_meta_boxes' to register the meta box.
+ * Hooks into 'save_post' to handle the values of the meta box.
+ * Hooks into 'admin_enqueue_scripts' to register JavaScript.
+ *
+ * @since 1.0.0
+ */
+ public static function init() {
+ add_action( 'init', array( __CLASS__, 'load_textdomain' ) );
+
+ if ( ! is_admin() ) {
+ add_filter( 'pre_get_posts', array( __CLASS__, 'show_public_preview' ) );
+
+ add_filter( 'query_vars', array( __CLASS__, 'add_query_var' ) );
+ } else {
+ add_action( 'post_submitbox_misc_actions', array( __CLASS__, 'post_submitbox_misc_actions' ) );
+
+ add_action( 'save_post', array( __CLASS__, 'register_public_preview' ), 20, 2 );
+
+ add_action( 'wp_ajax_public-post-preview', array( __CLASS__, 'ajax_register_public_preview' ) );
+
+ add_action( 'admin_enqueue_scripts' , array( __CLASS__, 'enqueue_script' ) );
+ }
+ }
+
+ /**
+ * Registers the textdomain.
+ *
+ * @since 2.0.0
+ */
+ public static function load_textdomain() {
+ return load_plugin_textdomain(
+ 'ds-public-post-preview',
+ false,
+ dirname( plugin_basename( __FILE__ ) ) . '/lang'
+ );
+ }
+
+ /**
+ * Registers the JavaScript file for post(-new).php.
+ *
+ * @since 2.0.0
+ */
+ public static function enqueue_script( $hook_suffix ) {
+ if ( ! in_array( $hook_suffix, array( 'post.php', 'post-new.php' ) ) )
+ return;
+
+ $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+
+ wp_enqueue_script(
+ 'ds-public-post-preview',
+ plugins_url( "js/public-post-preview$suffix.js", __FILE__ ),
+ array( 'jquery' ),
+ self::get_plugin_info( 'Version' ),
+ true
+ );
+
+ wp_localize_script(
+ 'ds-public-post-preview',
+ 'DSPublicPostPreviewL10n',
+ array(
+ 'enabled' => __( 'Enabled!', 'ds-public-post-preview' ),
+ 'disabled' => __( 'Disabled!', 'ds-public-post-preview' )
+ )
+ );
+ }
+
+ /**
+ * Adds the checkbox to the submit metabox
+ *
+ * @since 2.2.0
+ */
+ public static function post_submitbox_misc_actions() {
+ $post_types = get_post_types(
+ array(
+ 'public' => true
+ )
+ );
+
+ $post = get_post();
+
+ if ( ! in_array( $post->post_type, $post_types ) )
+ return false;
+
+ if ( ! in_array( $post->post_status, array( 'draft', 'pending', 'future' ) ) )
+ return false;
+
+ ?>
+ <div class="misc-pub-section public-post-preview">
+ <?php self::get_checkbox_html( $post ); ?>
+ </div>
+ <?php
+
+ }
+
+ /**
+ * Prints the checkbox if the is draft, pending or future.
+ *
+ */
+ private static function get_checkbox_html( $post ) {
+ if ( empty( $post ) )
+ $post = get_post();
+
+ wp_nonce_field( 'public_post_preview', 'public_post_preview_wpnonce' );
+
+ $preview_post_ids = self::get_preview_post_ids();
+ ?>
+ <label><input type="checkbox"<?php checked( in_array( $post->ID, $preview_post_ids ) ); ?> name="public_post_preview" id="public-post-preview" value="1" />
+ <?php _e( 'Enable public preview', 'ds-public-post-preview' ); ?> <span id="public-post-preview-ajax"></span></label>
+
+ <div id="public-post-preview-link" style="margin-top:6px">
+ <label>
+ <input type="text" name="public_post_preview_link" class="regular-text" value="<?php echo esc_attr( self::get_preview_link( $post->ID ) ); ?>" style="width:99%" readonly />
+ <span class="description"><?php _e( '(Copy and share this link.)', 'ds-public-post-preview' ); ?></span>
+ </label>
+ </div>
+ <?php
+ }
+
+ /**
+ * Returns the public preview link.
+ *
+ * The link is the permalink with these parameters:
+ * - preview, always true (query var for core)
+ * - _ppp, a custom nonce, see DS_Public_Post_Preview::create_nonce()
+ *
+ * @since 2.0.0
+ *
+ * @param int $post_id The post id.
+ * @return string The generated public preview link.
+ */
+ private static function get_preview_link( $post_id ) {
+ return add_query_arg(
+ array(
+ 'preview' => true,
+ '_ppp' => self::create_nonce( 'public_post_preview_' . $post_id ),
+ ),
+ get_permalink( $post_id )
+ );
+ }
+
+ /**
+ * (Un)Registers a post for a public preview.
+ *
+ * Don't runs on an autosave and ignores post revisions.
+ *
+ * @since 2.0.0
+ *
+ * @param int $post_id The post id.
+ * @param object $post The post object.
+ * @return bool Returns false on a failure, true on a success.
+ */
+ public static function register_public_preview( $post_id, $post ) {
+ if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
+ return false;
+
+ if ( wp_is_post_revision( $post_id ) )
+ return false;
+
+ if ( empty( $_POST['public_post_preview_wpnonce'] ) || ! wp_verify_nonce( $_POST['public_post_preview_wpnonce'], 'public_post_preview' ) )
+ return false;
+
+ $preview_post_ids = self::get_preview_post_ids();
+ $preview_post_id = $post->ID;
+
+ if ( empty( $_POST['public_post_preview'] ) && in_array( $preview_post_id, $preview_post_ids ) )
+ $preview_post_ids = array_diff( $preview_post_ids, (array) $preview_post_id );
+ elseif (
+ ! empty( $_POST['public_post_preview'] ) &&
+ ! empty( $_POST['original_post_status'] ) &&
+ 'publish' != $_POST['original_post_status'] &&
+ 'publish' == $post->post_status &&
+ in_array( $preview_post_id, $preview_post_ids )
+ )
+ $preview_post_ids = array_diff( $preview_post_ids, (array) $preview_post_id );
+ elseif ( ! empty( $_POST['public_post_preview'] ) && ! in_array( $preview_post_id, $preview_post_ids ) )
+ $preview_post_ids = array_merge( $preview_post_ids, (array) $preview_post_id );
+ else
+ return false; // Nothing changed.
+
+ return self::set_preview_post_ids( $preview_post_ids );
+ }
+
+ /**
+ * (Un)Registers a post for a public preview for an AJAX request.
+ *
+ * @since 2.0.0
+ *
+ * @return string Returns '0' on a failure, '1' on success.
+ */
+ public static function ajax_register_public_preview() {
+ check_ajax_referer( 'public_post_preview' );
+
+ $preview_post_id = (int) $_POST['post_ID'];
+ $post = get_post( $preview_post_id );
+
+ if ( ( 'page' == $post->post_type && ! current_user_can( 'edit_page', $preview_post_id ) ) || ! current_user_can( 'edit_post', $preview_post_id ) )
+ wp_die( 0 );
+
+ if ( ! in_array( $post->post_status, array( 'draft', 'pending', 'future' ) ) )
+ wp_die( 0 );
+
+ $preview_post_ids = self::get_preview_post_ids();
+
+ if ( empty( $_POST['checked'] ) && in_array( $preview_post_id, $preview_post_ids ) )
+ $preview_post_ids = array_diff( $preview_post_ids, (array) $preview_post_id );
+ elseif ( ! empty( $_POST['checked'] ) && ! in_array( $preview_post_id, $preview_post_ids ) )
+ $preview_post_ids = array_merge( $preview_post_ids, (array) $preview_post_id );
+ else
+ wp_die( 0 );
+
+ $ret = self::set_preview_post_ids( $preview_post_ids );
+
+ if ( ! $ret )
+ wp_die( 0 );
+
+ wp_die( 1 );
+ }
+
+ /**
+ * Registers the new query var `_ppp`.
+ *
+ * @since 2.1
+ *
+ * @return array List of query variables.
+ */
+ public static function add_query_var( $qv ) {
+ $qv[] = '_ppp';
+
+ return $qv;
+ }
+
+ /**
+ * Registers the filter to handle a public preview.
+ *
+ * Filter will be set if it's the main query, a preview, a singular page
+ * and the query var `_ppp` exists.
+ *
+ * @since 2.0.0
+ *
+ * @param object $query The WP_Query object.
+ * @return object The WP_Query object, unchanged.
+ */
+ public static function show_public_preview( $query ) {
+ if (
+ $query->is_main_query() &&
+ $query->is_preview() &&
+ $query->is_singular() &&
+ $query->get( '_ppp' )
+ )
+ add_filter( 'posts_results', array( __CLASS__, 'set_post_to_publish' ), 10, 2 );
+
+ return $query;
+ }
+
+ /**
+ * Checks if a public preview is available and allowed.
+ * Verifies the nonce and if the post id is registered for a public preview.
+ *
+ * @since 2.0.0
+ *
+ * @param int $post_id The post id.
+ * @return bool True if a public preview is allowed, false on a failure.
+ */
+ private static function public_preview_available( $post_id ) {
+ if ( empty( $post_id ) )
+ return false;
+
+ if( ! self::verify_nonce( get_query_var( '_ppp' ), 'public_post_preview_' . $post_id ) )
+ wp_die( __( 'The link has been expired!', 'ds-public-post-preview' ) );
+
+ if ( ! in_array( $post_id, get_option( 'public_post_preview', array() ) ) )
+ wp_die( __( 'No Public Preview available!', 'ds-public-post-preview' ) );
+
+ return true;
+ }
+
+ /**
+ * Sets the post status of the first post to publish, so we don't have to do anything
+ * *too* hacky to get it to load the preview.
+ *
+ * @since 2.0.0
+ *
+ * @param array $posts The post to preview.
+ */
+ public static function set_post_to_publish( $posts ) {
+ // Remove the filter again, otherwise it will be applied to other queries too.
+ remove_filter( 'posts_results', array( __CLASS__, 'set_post_to_publish' ), 10, 2 );
+
+ if ( empty( $posts ) )
+ return;
+
+ if ( self::public_preview_available( $posts[0]->ID ) )
+ $posts[0]->post_status = 'publish';
+
+ return $posts;
+ }
+
+ /**
+ * Get the time-dependent variable for nonce creation.
+ *
+ * @see wp_nonce_tick()
+ *
+ * @since 2.1
+ *
+ * @return int The time-dependent variable
+ */
+ private static function nonce_tick() {
+ $nonce_life = apply_filters( 'ppp_nonce_life', 60 * 60 * 48 ); // 48 hours
+
+ return ceil( time() / ( $nonce_life / 2 ) );
+ }
+
+ /**
+ * Creates a random, one time use token. Without an UID.
+ *
+ * @see wp_create_nonce()
+ *
+ * @since 1.0.0
+ *
+ * @param string|int $action Scalar value to add context to the nonce.
+ * @return string The one use form token
+ */
+ private static function create_nonce( $action = -1 ) {
+ $i = self::nonce_tick();
+
+ return substr( wp_hash( $i . $action, 'nonce' ), -12, 10 );
+ }
+
+ /**
+ * Verifies that correct nonce was used with time limit. Without an UID.
+ *
+ * @see wp_verify_nonce()
+ *
+ * @since 1.0.0
+ *
+ * @param string $nonce Nonce that was used in the form to verify
+ * @param string|int $action Should give context to what is taking place and be the same when nonce was created.
+ * @return bool Whether the nonce check passed or failed.
+ */
+ private static function verify_nonce( $nonce, $action = -1 ) {
+ $i = self::nonce_tick();
+
+ // 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;
+ }
+
+ /**
+ * Returns the post ids which are registered for a public preview.
+ *
+ * @since 2.0.0
+ *
+ * @return array The post ids. (Empty array if no ids are registered.)
+ */
+ private static function get_preview_post_ids() {
+ return get_option( 'public_post_preview', array() );
+ }
+
+ /**
+ * Saves the post ids which are registered for a public preview.
+ *
+ * @since 2.0.0
+ *
+ * @return array The post ids. (Empty array if no ids are registered.)
+ */
+ private static function set_preview_post_ids( $post_ids = array( )) {
+ return update_option( 'public_post_preview', $post_ids );
+ }
+
+ /**
+ * Small helper to get some plugin info.
+ *
+ * @since 2.0.0
+ *
+ * @param string $key The key to get the info from, see get_plugin_data().
+ * @return string|bool Either the value, or if the key doesn't exists false.
+ */
+ private static function get_plugin_info( $key = null ) {
+ $plugin_data = get_plugin_data( __FILE__);
+ if ( array_key_exists( $key, $plugin_data ) )
+ return $plugin_data[ $key ];
+
+ return false;
+ }
+
+ /**
+ * Delets the option 'public_post_preview' if the plugin will be uninstalled.
+ *
+ * @since 2.0.0
+ */
+ public static function uninstall() {
+ delete_option( 'public_post_preview' );
+ }
+}
+
+add_action( 'plugins_loaded', array( 'DS_Public_Post_Preview', 'init' ) );
+
+register_uninstall_hook( __FILE__, array( 'DS_Public_Post_Preview', 'uninstall' ) );