Index: plugins/plugin-directory/api/class-base.php
===================================================================
--- plugins/plugin-directory/api/class-base.php	(revision 12930)
+++ plugins/plugin-directory/api/class-base.php	(working copy)
@@ -33,6 +33,7 @@
 		new Routes\Plugin_Support_Reps();
 		new Routes\Plugin_Self_Close();
 		new Routes\Plugin_Self_Transfer();
+		new Routes\Plugin_Self_Toggle_Preview();
 		new Routes\Plugin_Release_Confirmation();
 		new Routes\Plugin_E2E_Callback();
 		new Routes\Plugin_Categorization();
Index: plugins/plugin-directory/api/routes/class-plugin-self-toggle-preview.php
===================================================================
--- plugins/plugin-directory/api/routes/class-plugin-self-toggle-preview.php	(nonexistent)
+++ plugins/plugin-directory/api/routes/class-plugin-self-toggle-preview.php	(working copy)
@@ -0,0 +1,85 @@
+<?php
+namespace WordPressdotorg\Plugin_Directory\API\Routes;
+
+use WordPressdotorg\Plugin_Directory\Plugin_Directory;
+use WordPressdotorg\Plugin_Directory\Admin\Status_Transitions;
+use WordPressdotorg\Plugin_Directory\API\Base;
+use WordPressdotorg\Plugin_Directory\Tools;
+
+/**
+ * An API endpoint for toggling Preview button availability on a particular plugin.
+ *
+ * @package WordPressdotorg_Plugin_Directory
+ */
+class Plugin_Self_Toggle_Preview extends Base {
+
+	public function __construct() {
+		register_rest_route( 'plugins/v1', '/plugin/(?P<plugin_slug>[^/]+)/self-toggle-preview', [
+			'methods'             => \WP_REST_Server::CREATABLE,
+			'callback'            => [ $this, 'self_toggle_preview' ],
+			'args'                => [
+				'plugin_slug' => [
+					'validate_callback' => [ $this, 'validate_plugin_slug_callback' ],
+				],
+			],
+			'permission_callback' => function( $request ) {
+				$plugin = Plugin_Directory::get_plugin_post( $request['plugin_slug'] );
+
+				return current_user_can( 'plugin_self_close', $plugin );
+			},
+		] );
+
+		add_filter( 'rest_pre_echo_response', [ $this, 'override_cookie_expired_message' ], 10, 3 );
+	}
+
+	/**
+	 * Redirect back to the plugins page when this endpoint is accessed with an invalid nonce.
+	 */
+	function override_cookie_expired_message( $result, $obj, $request ) {
+		if (
+			is_array( $result ) && isset( $result['code'] ) &&
+			preg_match( '!^/plugins/v1/plugin/([^/]+)/self-toggle-preview$!', $request->get_route(), $m )
+		) {
+			if ( 'rest_cookie_invalid_nonce' == $result['code'] ) {
+				wp_die( 'The link you have followed has expired.' );
+			} elseif ( 'rest_forbidden' == $result['code'] ) {
+				wp_die( "Sorry, You can't do that." );
+			}
+		}
+
+		return $result;
+	}
+
+	/**
+	 * Endpoint to toggle the Preview status.
+	 *
+	 * @param \WP_REST_Request $request The Rest API Request.
+	 * @return bool True if the favoriting was successful.
+	 */
+	public function self_toggle_preview( $request ) {
+		$plugin = Plugin_Directory::get_plugin_post( $request['plugin_slug'] );
+		$result = [
+			'location' => wp_get_referer() ?: get_permalink( $plugin ),
+		];
+		header( 'Location: ' . $result['location'] );
+
+		// Toggle the postmeta value. Note that there is a race condition here.
+		$did = '';
+		if ( get_post_meta( $plugin->ID, '_no_preview', true ) ) {
+			$r = delete_post_meta( $plugin->ID, '_no_preview' );
+			$did = 'enabled';
+		} else {
+			$r = add_post_meta( $plugin->ID, '_no_preview', '1', true );
+			$did = 'disabled';
+		}
+
+		// Add an audit-log entry as to why this has happened.
+		Tools::audit_log(
+			sprintf( 'Plugin preview %s. Reason: Author Request from %s', $did, $_SERVER['REMOTE_ADDR'] ),
+			$plugin
+		);
+
+		return $result;
+	}
+
+}

Property changes on: plugins/plugin-directory/api/routes/class-plugin-self-toggle-preview.php
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: plugins/plugin-directory/class-template.php
===================================================================
--- plugins/plugin-directory/class-template.php	(revision 12931)
+++ plugins/plugin-directory/class-template.php	(working copy)
@@ -797,6 +797,21 @@
 	}
 
 	/**
+	 * Generates a link to toggle the Live Preview button.
+	 *
+	 * @param int|\WP_Post|null $post Optional. Post ID or post object. Defaults to global $post.
+	 * @return string URL to toggle status.
+	 */
+	public static function get_self_toggle_preview_link( $post = null ) {
+		$post = get_post( $post );
+
+		return add_query_arg(
+			array( '_wpnonce' => wp_create_nonce( 'wp_rest' ) ),
+			home_url( 'wp-json/plugins/v1/plugin/' . $post->post_name . '/self-toggle-preview' )
+		);
+	}
+
+	/**
 	 * Generates a link to enable Release Confirmations.
 	 *
 	 * @param int|\WP_Post|null $post Optional. Post ID or post object. Defaults to global $post.
Index: themes/pub/wporg-plugins/inc/template-tags.php
===================================================================
--- themes/pub/wporg-plugins/inc/template-tags.php	(revision 12930)
+++ themes/pub/wporg-plugins/inc/template-tags.php	(working copy)
@@ -519,6 +519,9 @@
 
 		// Output the self close button.
 		the_plugin_self_close_button();
+
+		// Output the toggle preview button.
+		the_plugin_self_toggle_preview_button();
 	}
 
 }
@@ -558,6 +561,37 @@
 }
 
 /**
+ * Displays a form for plugin committers to toggle the Live Preview button.
+ */
+function the_plugin_self_toggle_preview_button() {
+	$post            = get_post();
+	$toggle_link     = Template::get_self_toggle_preview_link( $post );
+
+	if ( ! current_user_can( 'plugin_self_close', $post ) ) {
+		return;
+	}
+
+	echo '<h4>' . esc_html__( 'Toggle Live Preview', 'wporg-plugins' ) . '</h4>';
+	$preview_status = get_post_meta( $post->ID, '_no_preview', true ) ? 'disabled' : 'enabled';
+	if ( 'enabled' === $preview_status ) {
+		echo '<p>' . esc_html__( 'The Live Preview link to Playground is currently enabled. Use the toggle button to disable it.', 'wporg-plugins' ) . '</p>';
+	} else {
+		echo '<p>' . esc_html__( 'The Live Preview link to Playground is currently disabled. Use the toggle button to enable it.', 'wporg-plugins' ) . '</p>';
+	}
+
+	echo '<div class="plugin-notice notice notice-warning notice-alt"><p>';
+	_e( '<strong>Note:</strong> This only affects the availability of the Live Preview button on the plugin page. It does not prevent a plugin from running in the Playground.', 'wporg-plugins' );
+	echo '</p></div>';
+
+	if ( $toggle_link ) {
+		echo '<form method="POST" action="' . esc_url( $toggle_link ) . '" onsubmit="return confirm( jQuery(this).prev(\'.notice\').text() );">';
+		// Translators: %s is the plugin name, as defined by the plugin itself.
+		echo '<p><input class="button" type="submit" value="' . esc_attr( sprintf( __( 'Please toggle the Live Preview link for %s', 'wporg-plugins' ), get_the_title() ) ) . '" /></p>';
+		echo '</form>';
+	}
+}
+
+/**
  * Display a form to allow a plugin owner to transfer the ownership of a plugin to someone else.
  * This does NOT remove their commit ability.
  */
@@ -671,4 +705,4 @@
 			wp_kses_post( $notice['html'] ) // Should have wrapping <p> tags.
 		);
 	}
-}
\ No newline at end of file
+}
Index: themes/pub/wporg-plugins/template-parts/plugin-single.php
===================================================================
--- themes/pub/wporg-plugins/template-parts/plugin-single.php	(revision 12931)
+++ themes/pub/wporg-plugins/template-parts/plugin-single.php	(working copy)
@@ -40,7 +40,7 @@
 
 			<?php if ( 'publish' === get_post_status() || current_user_can( 'plugin_admin_view', $post ) ) : ?>
 				<a class="plugin-download button download-button button-large" href="<?php echo esc_url( Template::download_link() ); ?>"><?php esc_html_e( 'Download', 'wporg-plugins' ); ?></a>
-				<?php if ( !Template::is_plugin_outdated( $post ) ) : ?>
+				<?php if ( !Template::is_plugin_outdated( $post ) && !get_post_meta( $post->ID, '_no_preview', true ) ) : ?>
 					<a class="plugin-download button download-button button-large" href="<?php echo esc_url( Template::preview_link() ); ?>"><?php esc_html_e( 'Live Preview', 'wporg-plugins' ); ?></a>
 				<?php endif; ?>
 			<?php endif; ?>
