diff --git wordpress.org/public_html/wp-content/plugins/theme-directory/assets/suspend-form.css wordpress.org/public_html/wp-content/plugins/theme-directory/assets/suspend-form.css
new file mode 100644
index 000000000..c742b3f10
--- /dev/null
+++ wordpress.org/public_html/wp-content/plugins/theme-directory/assets/suspend-form.css
@@ -0,0 +1,34 @@
+.bulk-suspension-form {
+  display: flex;
+  margin-top: 20px;
+}
+
+.fields-wrapper {
+  background-color: #fff;
+  width: 100%;
+  border-radius: 10px;
+  padding: 20px;
+  border: 1px solid #7e8993;
+}
+
+.fields-wrapper--metabox {
+  width: auto;
+  border: none;
+  padding: 0;
+}
+
+.fields-row {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+  width: 100%;
+  margin-bottom: 20px;
+}
+
+.fields-column {
+  display: flex;
+  flex-direction: column;
+  flex-basis: 100%;
+  flex: 1;
+  margin: 0 10px;
+}
diff --git wordpress.org/public_html/wp-content/plugins/theme-directory/class-wporg-themes-suspended-packages.php wordpress.org/public_html/wp-content/plugins/theme-directory/class-wporg-themes-suspended-packages.php
new file mode 100644
index 000000000..878adcf84
--- /dev/null
+++ wordpress.org/public_html/wp-content/plugins/theme-directory/class-wporg-themes-suspended-packages.php
@@ -0,0 +1,523 @@
+<?php
+
+namespace WordPressdotorg\Theme_Directory;
+
+/**
+ * Class that handles suspended themes
+ *
+ * Provides a way to see the suspended themes, reason why they were suspended, when they were suspended,
+ * when does the suspension expires and who suspended them.
+ */
+class WPORG_Themes_Suspended_Packages {
+	/**
+	 * Register all the hooks related to the new functionality
+	 */
+	public function register() {
+		add_action( 'admin_enqueue_scripts', [ $this, 'add_suspension_scripts' ] );
+		add_filter( 'manage_repopackage_posts_columns', [ $this, 'add_new_post_columns' ] );
+		add_action( 'manage_repopackage_posts_custom_column', [ $this, 'add_column_content' ], 10, 2 );
+		add_filter( 'manage_edit-repopackage_sortable_columns', [ $this, 'make_columns_sortable' ] );
+		add_filter( 'bulk_actions-edit-repopackage', [ $this, 'add_bulk_suspend_option' ] );
+		add_filter( 'handle_bulk_actions-edit-repopackage', [ $this, 'suspend_bulk_action_handler' ], 10, 3 );
+		add_action( 'admin_post_suspend_themes', [ $this, 'suspend_themes_action' ] );
+		add_action( 'admin_post_nopriv_suspend_themes', [ $this, 'suspend_themes_action' ] );
+		add_action( 'admin_menu', [ $this, 'register_repopackage_subpages' ] );
+		add_action( 'add_meta_boxes', [ $this, 'suspensions_list_meta_box' ] );
+	}
+
+	/**
+	 * Enqueue additional JS and CSS on the certain admin pages
+	 *
+	 * @param string $hook Page hook.
+	 */
+	public function add_suspension_scripts( $hook ) {
+		if ( $hook === 'repopackage_page_suspended-packages-bulk-message-page' ) {
+			wp_register_style( 'suspend-form', plugins_url( 'theme-directory/assets/suspend-form.css' ) );
+			wp_enqueue_style('suspend-form');
+		}
+	}
+
+	/**
+	 * Add additional post columns to the themes list screen
+	 *
+	 * @param array $columns Array of repo package post columns.
+	 *
+	 * @return array Updated list of post columns.
+	 */
+	public function add_new_post_columns( array $columns ) : array {
+		if ( ! isset( $_GET['post_status'] ) || $_GET['post_status'] !== 'suspend' ) {
+			return $columns;
+		}
+
+		unset( $columns['tags'], $columns['theme-url'], $columns['author-url'], $columns['date'] );
+
+		$columns['suspended-by']           = __( 'Suspended by', 'wporg-theme' );
+		$columns['suspension-reason']      = __( 'Reason', 'wporg-theme' );
+		$columns['date-of-suspension']     = __( 'Date', 'wporg-theme' );
+		$columns['suspension-expiry-date'] = __( 'Expiry', 'wporg-theme' );
+		$columns['suspension-type']        = __( 'Suspension type', 'wporg-theme' );
+
+		return $columns;
+	}
+
+	/**
+	 * Add content to the custom columns
+	 *
+	 * @param string $column Column name.
+	 * @param int $post_id   Current post id where this data is pulled from.
+	 *
+	 * @return void
+	 */
+	public function add_column_content( string $column, int $post_id ) : void {
+		if ( ! isset( $_GET['post_status'] ) || $_GET['post_status'] !== 'suspend' ) {
+			return;
+		}
+
+		$suspension_data = get_post_meta( $post_id, 'suspension_details', true );
+
+		$suspended_by           = '';
+		$suspension_reason      = '';
+		$date_of_suspension     = '';
+		$date_of_suspension_end = '';
+		$suspension_type        = '';
+
+		if ( ! empty( $suspension_data ) ) {
+			$suspension_details = json_decode( $suspension_data, true );
+
+			$last_suspension = end( $suspension_details );
+
+			$suspended_by           = $last_suspension['suspended_by'];
+			$suspension_reason      = $last_suspension['suspension_description'];
+			$date_of_suspension     = strtotime( $last_suspension['suspended_on'] );
+			$date_of_suspension_end = strtotime( $last_suspension['suspension_expiration_date'] );
+			$suspension_type        = ucfirst( $last_suspension['suspension_type'] );
+		}
+
+		switch ( $column ) {
+			case 'suspended-by':
+				echo esc_html( $suspended_by );
+					break;
+			case 'suspension-reason':
+				echo wp_kses_post( $suspension_reason );
+					break;
+			case 'date-of-suspension':
+				echo $date_of_suspension !== '' ? date( 'Y-m-d', $date_of_suspension ) : '';
+					break;
+			case 'suspension-expiry-date':
+				echo $date_of_suspension_end !== '' ? date( 'Y-m-d', $date_of_suspension_end ) : '';
+					break;
+			case 'suspension-type':
+				echo $suspension_type;
+					break;
+			default:
+				echo '';
+					break;
+		}
+	}
+
+	/**
+	 * List of columns that should be sortable
+	 *
+	 * @param array $columns Columns to sort.
+	 * @return array
+	 */
+	public function make_columns_sortable( array $columns ) : array {
+		$columns['date-of-suspension']     = 'date';
+		$columns['suspension-expiry-date'] = 'date';
+
+		return $columns;
+	}
+
+	/**
+	 * Add bulk suspend themes and reinstate themes options
+	 *
+	 * @param array $bulk_actions Array of default bulk options
+	 *
+	 * @return array Array of updated bulk actions
+	 */
+	public function add_bulk_suspend_option( array $bulk_actions ) : array {
+		$bulk_actions['suspend_themes']   = __( 'Suspend themes', 'wporg-themes' );
+		$bulk_actions['reinstate_themes'] = __( 'Reinstate themes', 'wporg-themes' );
+
+		return $bulk_actions;
+	}
+
+	/**
+	 * Fires when a bulk action should be handled.
+	 *
+	 * @param string $redirect_url The redirect URL.
+	 * @param string $doaction     The action being taken.
+	 * @param array  $post_ids     The items to take the action on.
+	 *
+	 * @return string
+	 */
+	public function suspend_bulk_action_handler( string $redirect_url, string $doaction, array $post_ids ) : string {
+		switch ( $doaction ) {
+			case 'suspend_themes':
+				return $this->suspend_themes_redirect( $post_ids );
+					break;
+			case 'reinstate_themes':
+				return $this->reinstate_themes_redirect( $post_ids );
+					break;
+			default:
+				return $redirect_url;
+					break;
+		}
+	}
+
+	/**
+	 * Action ran on theme suspension
+	 *
+	 * This will set theme status to suspend, remove the theme from preview
+	 * and set the trac ticket to suspended status.
+	 */
+	public function suspend_themes_action() {
+		// Safety checks!
+		$post_ids = ! empty( $_POST['post_ids'] ) ? explode( ',', $_POST['post_ids'] ) : [];
+
+		if ( empty( $post_ids )  ) {
+			wp_safe_redirect( admin_url( 'edit.php?post_type=repopackage&page=suspended-packages-bulk-message-page' ) );
+			exit;
+		}
+
+		if ( ! wp_verify_nonce( $_POST['bulk_suspend_nonce'], 'bulk_suspend_action' ) ) {
+			wp_safe_redirect( admin_url( 'edit.php?post_type=repopackage&page=suspended-packages-bulk-message-page' ) );
+			exit;
+		}
+
+		if ( ! isset( $_POST['bulk_suspend_nonce'] ) && $_POST['bulk_suspend_nonce'] !== 'suspend_themes' ) {
+			wp_safe_redirect( admin_url( 'edit.php?post_type=repopackage&page=suspended-packages-bulk-message-page' ) );
+			exit;
+		}
+
+		$suspension_description = $_POST['suspension-description'] ?? '';
+
+		if ( empty( $suspension_description ) ) {
+			$redirect_url = admin_url('edit.php?post_type=repopackage&page=suspended-packages-bulk-message-page');
+			$page_url     = add_query_arg( [
+				'error' => __( 'Suspension description cannot be empty.', 'wporg-themes' ),
+				'post_ids' => $_POST['post_ids']
+			], $redirect_url );
+
+			wp_safe_redirect( $page_url );
+			exit;
+		}
+
+		$suspension_expiration_date = $_POST['suspension-date-expiration'] ?? '';
+
+		if ( time() > strtotime( $suspension_expiration_date ) ) {
+			$redirect_url = admin_url('edit.php?post_type=repopackage&page=suspended-packages-bulk-message-page');
+			$page_url     = add_query_arg( [
+				'error' => __( 'Suspension expiration date cannot be in the past.', 'wporg-themes' ),
+				'post_ids' => $_POST['post_ids']
+			], $redirect_url );
+
+			wp_safe_redirect( $page_url );
+			exit;
+		}
+
+		$suspension_type = $_POST['suspension-type'] ?? 'Temporary'; // Fall back to temporary, even though this will always be set.
+
+		$current_user = wp_get_current_user()->display_name;
+		$current_time = date( 'Y-m-d' );
+
+		foreach ( $post_ids as $post_id ) {
+			wp_update_post( array(
+				'ID'          => $post_id,
+				'post_status' => 'suspend',
+			) );
+
+			$theme = new WPORG_Themes_Repo_Package( $post_id );
+
+			// Remove from previewer.
+			wporg_themes_remove_wpthemescom( $theme->post_name );
+
+			// Mark a theme as inactive in GlotPress.
+			wporg_themes_glotpress_import( $theme, 'inactive' );
+
+			$suspension_data = get_post_meta( $post_id, 'suspension_details', true );
+
+			$suspension_details = [];
+
+			if ( ! empty( $suspension_data ) ) {
+				$suspension_details = json_decode( $suspension_data, true );
+			}
+
+			$data = [
+				'suspended_by'               => $current_user,
+				'suspended_on'               => $current_time,
+				'suspension_description'     => $suspension_description,
+				'suspension_expiration_date' => $suspension_expiration_date,
+				'suspension_type'            => ucfirst( $suspension_type ),
+			];
+
+			$suspension_details[] = $data;
+
+			update_post_meta( $post_id, 'suspension_details', wp_json_encode( $suspension_details ) );
+
+			// Suspend on trac.
+			$this->suspend_theme_on_trac( $theme, $suspension_description );
+		}
+
+		wp_safe_redirect( esc_url( admin_url( 'edit.php?post_type=repopackage&page=suspended-packages-page&noheader=true' ) ) );
+		exit;
+	}
+
+	/**
+	 * Register admin subpage
+	 *
+	 * Used to create bulk suspension page.
+	 */
+	public function register_repopackage_subpages() : void {
+		add_submenu_page(
+			'edit.php?post_type=repopackage',
+			__( 'Suspension message', 'wporg-themes' ),
+			__( 'Suspension message', 'wporg-themes' ),
+			'manage_options',
+			'suspended-packages-bulk-message-page',
+			[ $this, 'suspended_packages_bulk_message_page_callback' ]
+		);
+	}
+
+	/**
+	 * Callback for bulk message page
+	 */
+	public function suspended_packages_bulk_message_page_callback() {
+		?>
+		<div class="wrap">
+			<h2><?php echo get_admin_page_title(); ?></h2>
+			<?php
+				$theme_ids = $_GET['post_ids'] ?? '';
+
+				$this->generate_bulk_suspension_form( esc_html( $theme_ids ) );
+			?>
+		</div>
+		<?php
+	}
+
+	/**
+	 * Meta box that will show suspensions in a theme
+	 */
+	public function suspensions_list_meta_box() {
+		add_meta_box(
+			'wporg_themes_past_suspensions',
+			__( 'Past suspensions', 'wporg-themes' ),
+			[ $this, 'suspensions_meta_box_callback' ],
+			'repopackage',
+			'normal',
+			'high'
+		);
+	}
+	/**
+ 	 * Displays the content of the `_status` meta box.
+ 	 *
+ 	 * @param \WP_Post $post The current post.
+ 	 */
+	public function suspensions_meta_box_callback( \WP_Post $post ) {
+ 		$suspensions = get_post_meta( $post->ID, 'suspension_details', true );
+
+		if ( empty( $suspensions ) ) {
+			return;
+		}
+
+		$suspension_details = json_decode( $suspensions, true );
+
+		foreach ( $suspension_details as $past_suspension ) {
+			$suspended_by               = $past_suspension['suspended_by'] ?? '';
+			$suspended_on               = $past_suspension['suspended_on'] ?? '';
+			$suspension_description     = $past_suspension['suspension_description'] ?? '';
+			$suspension_expiration_date = $past_suspension['suspension_expiration_date'] ?? '';
+			$suspension_type            = $past_suspension['suspension_type'] ?? '';
+			?>
+			<div>
+				<p><?php echo '<strong>' , __( 'Suspended by: ', 'wporg-themes' ), '</strong>' , esc_html( $suspended_by ); ?></p>
+				<p><?php echo '<strong>' , __( 'Suspended on: ', 'wporg-themes' ), '</strong>' , esc_html( $suspended_on ); ?></p>
+				<p><?php echo '<strong>' , __( 'Reason for suspension: ', 'wporg-themes' ), '</strong>' , esc_html( $suspension_description ); ?></p>
+				<p><?php echo '<strong>' , __( 'Suspension expired: ', 'wporg-themes' ), '</strong>' , esc_html( $suspension_expiration_date ); ?></p>
+				<p><?php echo '<strong>' , __( 'Suspension type: ', 'wporg-themes' ), '</strong>' , esc_html( $suspension_type ); ?></p>
+				<hr/>
+			</div>
+			<?php
+		}
+	}
+
+	/**
+	 * Generate form that is used for theme suspension
+	 *
+	 * @param string $theme_ids Comma separated list of theme ids to suspend.
+	 */
+	private function generate_bulk_suspension_form( $theme_ids ) {
+
+		$error = $_REQUEST['error'] ?? '';
+
+		if ( ! empty( $error ) ) {
+			?>
+			<div class="notice error">
+				<?php echo '<p>' , esc_html( $error ) , '</p>' ?>
+			</div>
+			<?php
+		}
+
+		if ( ! empty( $theme_ids ) ) {
+			$notice_text = '';
+
+			foreach ( explode( ',', $theme_ids ) as $theme_id ) {
+				$theme = new \WPORG_Themes_Repo_Package( $theme_id );
+
+				$version = $theme->version;
+				$ticket  = $theme->ticket;
+
+				if ( ! empty( $version ) && ! empty( $ticket ) ) {
+					$notice_text .= '<p><strong>' . __( 'Theme: ', 'wporg-themes' ) . '</strong>' . esc_html( $theme->post_title ) . ', v' . esc_html( $version ) .', <a href="' . esc_url( 'https://themes.trac.wordpress.org/ticket/' . $ticket ) . '" target="_blank" rel="noreferrer nofollow">#' . esc_html( $ticket ) . '</a></p>';
+				} else {
+					$notice_text .= '<p><strong>' . __( 'Theme: ', 'wporg-themes' ) . '</strong>' . esc_html( $theme->post_title ) . '</p>';
+				}
+			}
+
+			if ( ! empty( $notice_text ) ) {
+			?>
+			<div class="notice">
+				<p><?php _e( 'Themes to be suspended:', 'wporg-themes' ); ?></p>
+				<?php echo wp_kses_post( $notice_text ); ?>
+			</div>
+			<?php
+			}
+		}
+		?>
+		<form method="post" class="bulk-suspension-form" action="<?php echo esc_attr( admin_url('admin-post.php') ); ?>">
+			<input type="hidden" name="action" value="suspend_themes">
+			<input type="hidden" name="post_ids" value="<?php echo esc_attr( $theme_ids ); ?>">
+			<?php
+			wp_nonce_field( 'bulk_suspend_action', 'bulk_suspend_nonce' );
+			 ?>
+			<div class="fields-wrapper">
+				<div class="fields-row">
+					<div class="fields-column"><strong><label for="suspension-description"><?php _e( 'Suspension reason', 'wporg-themes' ); ?></label></strong></div>
+					<div class="fields-column"><strong><label for="suspension-date-expiration"><?php _e( 'Suspension expiration date', 'wporg-themes' ); ?></label></strong></div>
+				</div>
+				<div class="fields-row">
+					<div class="fields-column"><textarea name="suspension-description" id="suspension-description" cols="70" rows="10"></textarea></div>
+					<div class="fields-column">
+						<input type="date" id="suspension-date-expiration" name="suspension-date-expiration" value="" class="suspension-date-expiration-datepicker" />
+						<br />
+						<strong><label for="suspension-type"><?php _e( 'Suspension type', 'wporg-themes' ); ?></label></strong>
+						<br />
+						<select name="suspension-type" id="suspension-type">
+							<option value="temporary"><?php _e( 'Temporary', 'wporg-themes' ); ?></option>
+							<option value="permanent"><?php _e( 'Permanent', 'wporg-themes' ); ?></option>
+						</select>
+					</div>
+				</div>
+				<div class="fields-row">
+					<button type="submit" class="button button-primary"><?php _e( 'Submit', 'wporg-themes' ); ?></button>
+				</div>
+			</div>
+		</form>
+		<?php
+	}
+
+	/**
+	 * Redirect for suspend themes bulk action.
+	 *
+	 * @param array $post_ids The items to take the action on.
+	 *
+	 * @return string
+	 */
+	private function suspend_themes_redirect( array $post_ids ) : string {
+		$themes_to_suspend = array_filter( $post_ids, static function( $post_id ) {
+			if ( get_post_status( $post_id ) !== 'suspend' ) {
+				return $post_id;
+			}
+		} );
+
+		$number_of_themes_to_suspend = count( $themes_to_suspend );
+
+		$redirect_url = admin_url('edit.php?post_type=repopackage&page=suspended-packages-bulk-message-page');
+		$page_url     = add_query_arg( [ 'post_ids' => implode( ',', $themes_to_suspend ), 'count' => $number_of_themes_to_suspend ], $redirect_url );
+
+		$redirect_to = add_query_arg( 'bulk_suspend_themes', $number_of_themes_to_suspend, $page_url );
+
+		return $redirect_to;
+	}
+
+	/**
+	 * Redirect for suspend themes bulk action.
+	 *
+	 * @param array  $post_ids     The items to take the action on.
+	 *
+	 * @return string
+	 */
+	private function reinstate_themes_redirect( array $post_ids ) : string {
+		// Reinstate themes in bulk!
+		// After themes are reinstated, add an admin notice.
+		if ( empty( $post_ids ) ) {
+			return $redirect_url;
+		}
+
+		$themes_to_reinstate = array_filter( $post_ids, static function( $post_id ) {
+			if ( get_post_status( $post_id ) === 'suspend' ) {
+				return $post_id;
+			}
+		} );
+
+		foreach ( $themes_to_reinstate as $post_id ) {
+			$post = get_post( $post_id );
+
+			if ( ! get_post_type_object( $post->post_type ) ) {
+				wp_die( __( 'Unknown post type.', 'wporg-themes' ) );
+			}
+
+			if ( ! current_user_can( 'reinstate_theme', $post_id ) || 'repopackage' != $post->post_type ) {
+				wp_die( __( 'You are not allowed to reinstate this item.', 'wporg-themes' ) );
+			}
+
+			wp_update_post( array(
+				'ID'          => $post_id,
+				'post_status' => 'draft',
+			) );
+
+			/*
+			 * Mark it as reinstated, so the post date doesn't get overwritten when it's
+			 * published again.
+			 */
+			add_post_meta( $post_id, '_wporg_themes_reinstated', true );
+		}
+
+		$number_of_reinstated_themes = count( $themes_to_reinstate );
+
+		wp_redirect( add_query_arg( 'reinstated', $number_of_reinstated_themes, remove_query_arg( array( 'trashed', 'untrashed', 'deleted', 'ids', 'suspended' ), wp_get_referer() ) ) );
+		exit();
+	}
+
+	/**
+	 * When suspend action is ran, suspend the theme on trac as well
+	 *
+	 * This will ensure that theme reps don't need to manually suspend a theme on trac.
+	 *
+	 * @param object $theme                  WPORG_Themes_Repo_Package object.
+	 * @param string $suspension_description Description of suspension to add to trac ticket.
+	 */
+	private function suspend_theme_on_trac( $theme, string $suspension_description ) {
+		if ( ! class_exists( 'Trac' ) ) {
+			require_once ABSPATH . WPINC . '/class-IXR.php';
+			require_once ABSPATH . WPINC . '/class-wp-http-ixr-client.php';
+			require_once __DIR__ . '/lib/class-trac.php';
+		}
+
+		// Check for tickets that were set to live previously.
+		$trac = new Trac( 'themetracbot', THEME_TRACBOT_PASSWORD, 'https://themes.trac.wordpress.org/login/xmlrpc' );
+
+		$ticket_id = $theme->ticket;
+
+		$trac->ticket_update(
+			$ticket_id,
+			$suspension_description,
+			[
+				'action' => 'review',
+				'status' => 'suspended',
+			],
+			true
+		);
+	}
+}
+
diff --git wordpress.org/public_html/wp-content/plugins/theme-directory/theme-directory.php wordpress.org/public_html/wp-content/plugins/theme-directory/theme-directory.php
index e5796871c..a70ae779b 100644
--- wordpress.org/public_html/wp-content/plugins/theme-directory/theme-directory.php
+++ wordpress.org/public_html/wp-content/plugins/theme-directory/theme-directory.php
@@ -34,6 +34,11 @@ include __DIR__ . '/jobs/class-manager.php';
 include __DIR__ . '/jobs/class-trac-sync.php';
 new WordPressdotorg\Theme_Directory\Jobs\Manager();
 
+// Load suspension additions.
+include __DIR__ . '/class-wporg-themes-suspended-packages.php';
+
+(new WordPressdotorg\Theme_Directory\WPORG_Themes_Suspended_Packages())->register();
+
 /**
  * Things to change on activation.
  */
