protected static function formBulk( $action ) {

		if ( ! class_exists( '\WP_List_Table' ) ) {
			require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
		}

		$redirect_url = get_admin_url( get_current_blog_id(), '/index.php?page=pb_catalog' );
		$redirect_url = Admin\Catalog_List_Table::addSearchParamsToUrl( $redirect_url );

		/* Sanity check */

		if ( ! empty( $_REQUEST['book'] ) ) {
			// Bulk
			check_admin_referer( 'bulk-books' ); // Nonce auto-generated by WP_List_Table
			$books = $_REQUEST['book'];
		} elseif ( ! empty( $_REQUEST['ID'] ) ) {
			// Single item
			check_admin_referer( $_REQUEST['ID'] );
			$books = [ $_REQUEST['ID'] ];
		} else {
			// Handle empty bulk submission
			if ( ! empty( $_REQUEST['user_id'] ) ) {
				$redirect_url .= '&user_id=' . $_REQUEST['user_id'];
			}
			\Pressbooks\Redirect\location( $redirect_url );
		}

		// Make an educated guess as to who's catalog we are editing
		list( $user_id, $_ ) = explode( ':', $books[0] );

		if ( ! $user_id || ! current_user_can( 'edit_user', $user_id ) ) {
			wp_die( __( 'You do not have permission to do that.', 'pressbooks' ) );
		}

		// Fix redirect URL
		if ( get_current_user_id() !== $user_id ) {
			$redirect_url .= '&user_id=' . $user_id;
		}

		/* Go! */

		$catalog = new static( $user_id );

		foreach ( $books as $book ) {
			list( $_, $book_id ) = explode( ':', $book );
			if ( 'add' === $action ) {
				$catalog->saveBook( $book_id, [] );
			} elseif ( 'remove' === $action ) {
				$catalog->deleteBook( $book_id );
			} else {
				// TODO: Throw Error
				$_SESSION['pb_errors'][] = "Invalid action: $action";
			}
		}

		$catalog->deleteCache();

		// Ok!
		$_SESSION['pb_notices'][] = __( 'Settings saved.' );

		// Redirect back to form
		\Pressbooks\Redirect\location( $redirect_url );
	}