diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/api/class-base.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/api/class-base.php
index 8b9c81da27..ab61e8491b 100644
--- a/wordpress.org/public_html/wp-content/plugins/plugin-directory/api/class-base.php
+++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/api/class-base.php
@@ -40,6 +40,7 @@ public static function load_routes() {
new Routes\Plugin_Upload();
new Routes\Plugin_Blueprint();
new Routes\Plugin_Review();
+ new Routes\Plugin_Publish();
}
/**
diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/api/routes/class-plugin-publish.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/api/routes/class-plugin-publish.php
new file mode 100644
index 0000000000..7b9f0e1199
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/api/routes/class-plugin-publish.php
@@ -0,0 +1,68 @@
+[^/]+)/publish',
+ array(
+ 'methods' => \WP_REST_Server::CREATABLE,
+ 'callback' => array( $this, 'publish_release' ),
+ 'args' => array(
+ 'plugin_slug' => array(
+ 'validate_callback' => array( $this, 'validate_plugin_slug_callback' ),
+ ),
+ ),
+ 'permission_callback' => array( $this, 'permission_can_access_plugin' ),
+ )
+ );
+ }
+
+ /**
+ * Validate that the user can manage a given plugin.
+ *
+ * @param WP_REST_Request $request The request object.
+ *
+ * @return bool
+ */
+ public function permission_can_access_plugin( $request ) {
+ $plugin = Plugin_Directory::get_plugin_post( $request['plugin_slug'] );
+ return current_user_can( 'plugin_manage_releases', $plugin );
+ }
+
+ /**
+ * A simple endpoint to publish a release.
+ *
+ * @param WP_REST_Request $request The request object.
+ * @return WP_REST_Response
+ */
+ public function publish_release( $request ) {
+ $plugin = Plugin_Directory::get_plugin_post( $request['plugin_slug'] );
+ // Will return either a WP_Error, or the post ID of the published release CPT.
+ $result = Plugin_Release::instance()->publish_release( $plugin );
+
+ return $result;
+ }
+}
diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/bin/get-release-info.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/bin/get-release-info.php
new file mode 100644
index 0000000000..791cc790d0
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/bin/get-release-info.php
@@ -0,0 +1,103 @@
+ID)...\n";
+
+$releases = Plugin_Release::instance()->get_releases( $plugin );
+if ( is_wp_error( $releases ) ) {
+ fwrite( STDERR, "Failed to update releases for $plugin_slug: " . $updated->get_error_message() . "\n" );
+ die();
+}
+
+foreach( $releases as $release ) {
+ echo "ID: " . $release->ID . "\n";
+ echo "Status: " . $release->post_status . "\n";
+ echo "Release version: " . $release->post_title . "\n";
+ echo "Tag: " . $release->release_tag . "\n";
+ echo "Post date GMT: " . $release->post_date_gmt . "\n";
+ if ( $release->release_date ) {
+ echo "Date: " . ( new \DateTime( '@' . $release->release_date ) )->format( 'Y-m-d H:i:s' ) . "\n";
+ }
+ echo "Committers: " . implode( ', ', $release->release_committer ) . "\n";
+ echo "Zips built: " . ( $release->release_zips_built ? 'Yes' : 'No' ) . "\n";
+ echo "Confirmations required: " . ( $release->release_confirmations_required ? 'Yes' : 'No' ) . "\n";
+ echo "Release revision: " . $release->release_revision_final . "\n";
+ echo "Previous version rev: " . $release->release_revision_prior . "\n";
+ if ( $release->release_commit_log ) {
+ echo "Commit log:\n";
+ foreach( $release->release_commit_log as $commit ) {
+ echo " " . ( new \DateTime( '@' . $commit['date'] ) )->format( 'Y-m-d' ) . " - ";
+ echo " " . $commit['author'] . ' r' . $commit['revision'] . " - " . \wp_trim_words( $commit['message'] ) . "\n";
+ }
+ }
+ echo "-----------------------------------\n";
+}
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/bin/update-release-cpt.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/bin/update-release-cpt.php
new file mode 100644
index 0000000000..d30e74b2d0
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/bin/update-release-cpt.php
@@ -0,0 +1,95 @@
+releases ) ) {
+ fwrite( STDERR, "No releases found for $plugin_slug\n" );
+ die();
+}
+
+echo "Updating releases for $plugin_slug...\n";
+
+$updated = Plugin_Release::instance()->maybe_backfill_releases( $plugin, true ); // true = force update
+if ( is_wp_error( $updated ) ) {
+ fwrite( STDERR, "Failed to update releases for $plugin_slug: " . $updated->get_error_message() . "\n" );
+ die();
+}
+echo "Updated " . number_format( $updated ) . " releases for $plugin_slug\n";
+
+if ( $opts['publish'] ) {
+ $published = Plugin_Release::instance()->publish_release( $plugin );
+ if ( is_wp_error( $published ) ) {
+ fwrite( STDERR, "Failed to publish releases for $plugin_slug: " . $published->get_error_message() . "\n" );
+ die();
+ }
+ echo "Published release post ID = " . $published . "\n";
+}
+
diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-check.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-check.php
new file mode 100644
index 0000000000..554c45cac5
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-check.php
@@ -0,0 +1,201 @@
+ true,
+ 'results' => [],
+ 'html' => '',
+ ];
+ }
+
+ $result = self::run_checks( $plugin_slug, $plugin_root );
+
+ self::log_to_slack( $result ); // FIXME: need to pass required info.
+
+ return $result;
+ }
+
+ /**
+ * Sends a plugin through Plugin Check.
+ * @param string $plugin_slug The plugin slug.
+ * @param string $plugin_root The path to the plugin source.
+ *
+ * @return array The results of the plugin check.
+ */
+ public static function run_checks( $plugin_slug, $plugin_root ) {
+
+ // Run plugin check via CLI
+ $start_time = microtime(1);
+ exec(
+ 'export WP_CLI_CONFIG_PATH=' . escapeshellarg( WP_CLI_CONFIG_PATH ) . '; ' .
+ 'timeout 45 ' . // Timeout after 45s if plugin-check is not done.
+ WPCLI . ' --url=https://wordpress.org/plugins ' .
+ 'plugin check ' .
+ '--error-severity=7 --warning-severity=6 --categories=plugin_repo --format=json ' .
+ '--slug=' . escapeshellarg( $plugin_slug ) . ' ' .
+ escapeshellarg( $plugin_root ),
+ $output,
+ $return_code
+ );
+ $total_time = round( microtime(1) - $start_time, 1 );
+
+ /**
+ * Anything that plugin-check outputs that we want to discard completely.
+ */
+ $is_ignored_code = static function( $code ) {
+ $ignored_codes = [
+ ];
+
+ return (
+ in_array( $code, $ignored_codes, true ) ||
+ // All the Readme parser warnings are duplicated, we'll exclude those.
+ str_starts_with( $code, 'readme_parser_warnings_' )
+ );
+ };
+
+ /*
+ * Convert the output into an array.
+ * Format:
+ * FILE: example.extension
+ * [{.....}]
+ *
+ * FILE: example2.extension
+ * [{.....}]
+ */
+ $verdict = true;
+ $results = [];
+ foreach ( array_chunk( $output, 3 ) as $file_result ) {
+ if ( ! str_starts_with( $file_result[0], 'FILE:' ) ) {
+ continue;
+ }
+
+ $filename = trim( explode( ':' , $file_result[0], 2 )[1] );
+ $json = json_decode( $file_result[1], true );
+
+ foreach ( $json as $record ) {
+ $record['file'] = $filename;
+
+ if ( $is_ignored_code( $record['code'] ) ) {
+ continue;
+ }
+
+ $results[] = $record;
+
+ // Record submission stats.
+ if ( function_exists( 'bump_stats_extra' ) && 'production' === wp_get_environment_type() ) {
+ bump_stats_extra( 'plugin-check-' . $record['type'], $record['code'] );
+ }
+
+ // Determine if it failed the checks.
+ if ( $verdict && 'ERROR' === $record['type'] ) {
+ $verdict = false;
+ }
+ }
+ }
+
+ // Generage the HTML for the Plugin Check output.
+ $html = sprintf(
+ '' . __( 'Results of Automated Plugin Scanning: %s', 'wporg-plugins' ) . '',
+ $verdict ? __( 'Pass', 'wporg-plugins' ) : __( 'Fail', 'wporg-plugins' )
+ );
+ if ( $results ) {
+ $html .= '
';
+ // Display errors, and then warnings.
+ foreach ( [ wp_list_filter( $results, [ 'type' => 'ERROR' ] ), wp_list_filter( $results, [ 'type' => 'ERROR' ], 'NOT' ) ] as $result_set ) {
+ foreach ( $result_set as $result ) {
+ $html .= sprintf(
+ '- %s %s: %s
',
+ esc_html( $result['file'] ),
+ esc_url( $result['docs'] ?? '' ),
+ esc_html( $result['type'] . ' ' . $result['code'] ),
+ esc_html( $result['message'] )
+ );
+ }
+ }
+ $html .= '
';
+ }
+ $html .= __( 'Note: While the automated plugin scan is based on the Plugin Review Guidelines, it is not a complete review. A successful result from the scan does not guarantee that the plugin will be approved, only that it is sufficient to be reviewed. All submitted plugins are checked manually to ensure they meet security and guideline standards before approval.', 'wporg-plugins' );
+
+ // Return the results.
+ return [
+ 'verdict' => $verdict,
+ 'results' => $results,
+ 'html' => $html,
+ 'runtime' => $total_time,
+ ];
+ }
+
+ public function log_to_slack( $fixme ) {
+
+ // Copypasta, fix refs
+
+ // If the upload is blocked; log it to slack.
+ if ( ! $verdict ) {
+ // Slack dm the logs.
+ $zip_name = reset( $_FILES )['name'];
+ $failpass = $verdict ? ':white_check_mark: passed' : ':x: failed';
+ if ( $return_code > 1 ) { // TODO: Temporary, as we're always hitting this branch.
+ $failpass = ' :rotating_light: errored: ' . $return_code;
+ }
+
+ $plugin_name_slug = $this->plugin['Name'] . ' (' . $this->plugin_slug . ')';
+ // If we have a post object, link to it.
+ if ( $this->plugin_post ) {
+ $edit_post_link = admin_url( 'post.php?post=' . $this->plugin_post->ID . '&action=edit' ); // Can't use get_edit_post_link() as the user can't edit the post.
+ $plugin_name_slug = "<{$edit_post_link}|{$plugin_name_slug}>";
+ }
+
+ $text = "{$failpass} for {$zip_name}: {$plugin_name_slug} took {$total_time}s\n";
+
+ // Include a simplified / merged version of the results for review.
+ $group_by_code = [ 'ERROR' => [], 'WARNING' => [] ];
+ foreach ( $results as $result ) {
+ $group_by_code[ $result['type'] ][ $result['code'] ] ??= [];
+ $group_by_code[ $result['type'] ][ $result['code'] ][] = $result;
+ }
+ foreach ( $group_by_code as $type => $codes ) {
+ foreach ( $codes as $code_results ) {
+ $text .= "• *{$type}: {$code_results[0]['code']}*";
+ if ( 1 === count( $code_results ) ) {
+ $text .= ": {$code_results[0]['message']}\n";
+ } else {
+ $text .= "\n";
+ foreach ( array_unique( wp_list_pluck( $code_results, 'message' ) ) as $i => $message ) {
+ $multiplier = count( wp_list_filter( $code_results, [ 'message' => $message ] ) );
+ $multiplier = $multiplier > 1 ? " {$multiplier}x" : '';
+
+ $text .= " {$i}. {$multiplier} {$message}\n";
+ }
+ }
+ }
+ }
+
+ notify_slack( PLUGIN_CHECK_LOGS_SLACK_CHANNEL, $text, wp_get_current_user(), true );
+ } elseif ( $return_code ) {
+ // Log plugin-check timing out.
+ $zip_name = reset( $_FILES )['name'];
+ $text = ":rotating_light: Error: {$return_code} for {$zip_name}: {$this->plugin['Name']} ({$this->plugin_slug}) took {$total_time}s\n";
+ notify_slack( PLUGIN_CHECK_LOGS_SLACK_CHANNEL, $text, wp_get_current_user(), true );
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-directory.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-directory.php
index ef7f4c6ca9..62ccc5fa3e 100644
--- a/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-directory.php
+++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-directory.php
@@ -67,6 +67,8 @@ private function __construct() {
// Search
Plugin_Search::instance();
+ Plugin_Release::instance();
+
// Add upload size limit to limit plugin ZIP file uploads to 10M
add_filter( 'upload_size_limit', function( $size ) {
return 10 * MB_IN_BYTES;
@@ -557,7 +559,7 @@ public function init() {
// Add duplicate search rule which will be hit before the following old-plugin tab rules
add_rewrite_rule( '^search/([^/]+)/?$', 'index.php?s=$matches[1]', 'top' );
-
+
// Add additional tags endpoint, to avoid being caught in old-plugins tab rules. See: https://meta.trac.wordpress.org/ticket/6819.
add_rewrite_rule( '^tags/([^/]+)/?$', 'index.php?plugin_tags=$matches[1]', 'top' );
@@ -1735,9 +1737,9 @@ public static function get_releases( $plugin ) {
$plugin = self::get_plugin_post( $plugin );
$releases = get_post_meta( $plugin->ID, 'releases', true );
- // Meta doesn't exist yet? Lets fill it out.
+ // Data doesn't exist yet? Lets fill it out.
if ( false === $releases || ! is_array( $releases ) ) {
- $releases = self::prefill_releses_meta( $plugin );
+ $releases = self::prefill_releases_meta( $plugin );
}
/**
@@ -1756,15 +1758,12 @@ public static function get_releases( $plugin ) {
}
/**
- * Prefill the releases meta for a plugin.
+ * Prefill the releases meta items for a plugin.
*
* @param \WP_Post $plugin Plugin post object.
* @return array
*/
- public static function prefill_releses_meta( $plugin ) {
- if ( ! $plugin->releases ) {
- update_post_meta( $plugin->ID, 'releases', [] );
- }
+ public static function prefill_releases_meta( $plugin ) {
$tags = get_post_meta( $plugin->ID, 'tags', true );
if ( $tags ) {
diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-release.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-release.php
new file mode 100644
index 0000000000..9c3db2382f
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-release.php
@@ -0,0 +1,488 @@
+ array(
+ 'name' => __( 'Releases', 'wporg-plugins' ),
+ 'singular_name' => __( 'Release', 'wporg-plugins' ),
+ ),
+ 'public' => false,
+ 'show_ui' => false,
+ 'exclude_from_search' => true,
+ 'publicly_queryable' => true,
+ 'show_in_rest' => true, // FIXME: maybe?
+ 'supports' => array( 'title', 'editor' ), // TBD
+ 'rewrite' => false,
+ 'query_var' => false,
+ 'hierarchical' => false, // Disappointingly, this doesn't help us make a Post -> Release hierarchy.
+ ) );
+ }
+
+ // Starting point for an internal API, mostly copilot-generated.
+
+ /**
+ * Get all releases for a plugin.
+ */
+ public function get_releases( $plugin ) {
+ $plugin_id = ( get_post( $plugin ) )->ID;
+
+ $releases = get_posts( array(
+ 'post_type' => 'plugin_release',
+ 'posts_per_page' => -1,
+ 'post_parent' => $plugin_id,
+ 'orderby' => 'date',
+ 'order' => 'DESC',
+ ) );
+
+ return $releases;
+ }
+
+ /**
+ * Check if a plugin has any release CPTs stored.
+ * Note that this intentionally does not count draft releases. If needed, we can add a parameter to support that.
+ */
+ public function has_releases( $plugin ) {
+ $release = $this->get_release( $plugin, null );
+ return ! empty( $release );
+ }
+
+ /**
+ * Backfill releases for a plugin, if none exist. This uses the releases postmeta to populate the CPTs.
+ */
+ public function maybe_backfill_releases( $plugin, $force = false ) {
+ $plugin = get_post( $plugin );
+
+ if ( !$plugin || 'plugin' !== $plugin->post_type ) {
+ return new \WP_Error( 'invalid_plugin', 'Invalid plugin' );
+ }
+
+ if ( $this->has_releases( $plugin ) && ! $force ) {
+ return false;
+ }
+
+ $releases_from_tags = $this->get_releases_from_svn_tags( $plugin );
+
+ // Add or update the release CPTs using the svn data.
+ if ( $releases_from_tags ) {
+ return $this->update_releases( $plugin, $releases_from_tags );
+ }
+
+ return false;
+ }
+
+ // This roughly mimics Plugin_Directory::prefill_releases_meta(), but includes a bit more detail.
+ public function get_releases_from_svn_tags( $plugin ) {
+ $plugin = get_post( $plugin );
+
+ if ( !$plugin || 'plugin' !== $plugin->post_type ) {
+ return new \WP_Error( 'invalid_plugin', 'Invalid plugin' );
+ }
+
+ $svn_tags = Tools\SVN::ls( "https://plugins.svn.wordpress.org/{$plugin->post_name}/tags/", true ) ?: [];
+
+ $releases = [];
+ foreach ( $svn_tags as $tag ) {
+ if ( 'dir' !== $tag['kind'] ) {
+ continue;
+ }
+
+ $releases[] = [
+ 'date' => strtotime( $tag['date'] ),
+ 'tag' => $tag['filename'],
+ 'version' => $tag['filename'],
+ 'committer' => [ $tag['author'] ],
+ 'revision' => [ $tag['revision'] ],
+ ];
+ }
+
+ return $releases;
+ }
+
+ /**
+ * Add release info for a plugin.
+ */
+ public function add_release( $plugin, $release ) {
+ $plugin = get_post( $plugin );
+ $plugin_id = $plugin->ID;
+
+ if ( !$plugin || 'plugin' !== $plugin->post_type ) {
+ return new \WP_Error( 'invalid_plugin', 'Invalid plugin' );
+ }
+
+ $release_date = date( 'Y-m-d H:i:s', $release['date'] );
+ $committer_user_id = get_user_by( 'login', reset( $release['committer'] ) )->ID;
+ if ( ! $committer_user_id ) {
+ return new \WP_Error( 'invalid_committer', 'Invalid committer' );
+ }
+
+ $post_status = ( 'trunk' === $release['tag'] ) ? 'draft' : 'publish';
+ $post_title = ( 'trunk' === $release['tag'] ) ? 'trunk' : $release['version'];
+
+ $release_id = wp_insert_post( array(
+ 'post_type' => 'plugin_release',
+ 'post_title' => $post_title,
+ 'post_name' => $plugin->post_name . '-' . $release['version'],
+ 'post_parent' => $plugin_id,
+ 'post_status' => $post_status,
+ 'post_date' => $release_date, // And/or post_date_gmt?
+ // Mirrors the metadata.
+ 'meta_input' => array(
+ 'release_date' => $release['date'],
+ 'release_tag' => $release['tag'],
+ 'release_version' => $release['version'],
+ 'release_committer' => $release['committer'],
+ 'release_zips_built' => $release['zips_built'],
+ 'release_confirmations_required' => $release['confirmations_required'],
+ 'release_revision' => $release['revision'],
+ 'release_commit_log' => $release['commit_log'] ?? null,
+ 'release_tested' => $release['tested'] ?? null,
+ ),
+ // TODO: what else? Could store the changelog or other content at the point of release for comparison purposes.
+ ) );
+
+ return $release_id;
+ }
+
+ /**
+ * Update existing release info.
+ */
+ public function update_release( $release_id, $release ) {
+
+ $release_date = date( 'Y-m-d H:i:s', $release['date'] );
+ $committer_user_id = get_user_by( 'login', reset( $release['committer'] ) )->ID;
+ if ( ! $committer_user_id ) {
+ return new \WP_Error( 'invalid_committer', 'Invalid committer' );
+ }
+
+ $release_post = get_post( $release_id );
+ if ( ! $release_post || 'plugin_release' !== $release_post->post_type ) {
+ return new \WP_Error( 'invalid_release', 'Invalid release' );
+ }
+
+ $parent_plugin = get_post( $release_post->post_parent );
+ if ( ! $parent_plugin || 'plugin' !== $parent_plugin->post_type ) {
+ return new \WP_Error( 'invalid_plugin', 'Invalid plugin' );
+ }
+
+ $post_status = ( 'trunk' === $release['tag'] ) ? 'draft' : 'publish';
+ $post_title = ( 'trunk' === $release['tag'] ) ? 'trunk' : $release['version'];
+
+ $release_id = wp_update_post( array(
+ 'ID' => $release_post->ID,
+ 'post_type' => 'plugin_release',
+ 'post_title' => $post_title,
+ 'post_name' => $parent_plugin->post_name . '-' . $release['version'],
+ 'post_parent' => $parent_plugin->ID,
+ 'post_status' => $post_status,
+ 'post_date' => $release_date, // And/or post_date_gmt?
+ // Mirrors the metadata.
+ 'meta_input' => array(
+ 'release_date' => $release['date'],
+ 'release_tag' => $release['tag'],
+ 'release_version' => $release['version'],
+ 'release_committer' => $release['committer'],
+ 'release_zips_built' => $release['zips_built'],
+ 'release_confirmations_required' => $release['confirmations_required'],
+ 'release_revision' => $release['revision'],
+ 'release_revision_final' => $release['revision_final'] ?? null,
+ 'release_revision_prior' => $release['revision_prior'] ?? null,
+ 'release_commit_log' => $release['commit_log'] ?? null,
+ 'release_tested' => $release['tested'] ?? null,
+ 'release_requires_php' => $release['requires_php'] ?? null,
+ 'release_requires_wp' => $release['requires_wp'] ?? null,
+ 'release_requires_plugins' => $release['requires_plugins'] ?? null,
+ ),
+ // TODO: what else? Could store the changelog or other content at the point of release for comparison purposes.
+ ) );
+
+ return $release_id;
+ }
+
+ /**
+ * Save draft (trunk) release for a plugin.
+ */
+ public function add_or_update_draft_release( $plugin, $release ) {
+ $plugin = get_post( $plugin );
+
+ // Tag must be 'trunk' for this to be a draft release.
+ if ( 'trunk' !== $release['tag'] ) {
+ return new \WP_Error( 'invalid_tag', 'Invalid tag' );
+ }
+
+ if ( !$plugin || 'plugin' !== $plugin->post_type ) {
+ return new \WP_Error( 'invalid_plugin', 'Invalid plugin' );
+ }
+
+ // If there's already a published release for this plugin, we only create a draft if there are unreleased trunk commits.
+ $last_release = $this->get_release( $plugin, null );
+
+ $trunk_url = Import::PLUGIN_SVN_BASE . '/' . $plugin->post_name . '/trunk';
+ $svn_options = array( 'limit' => 100 ); // Safety limit.
+ $commit_log = null;
+
+ if ( $last_release ) {
+ if ( ! empty( $release['revision'] ) ) {
+ // Don't create a draft unless the revision number is higher than the last release.
+ if ( max( $release['revision'] ) <= max( $last_release->release_revision ) ) {
+ return false; // Not an error, just skip.
+ }
+
+ // Get commits from last release revision to current revision.
+ $last_release_revision = max( $last_release->release_revision );
+ if ( $last_release_revision ) {
+ $commit_log = SVN::log( $trunk_url, array( max( $release['revision'] ), $last_release_revision ), $svn_options );
+ }
+ } elseif ( strtotime( $release['date'] ) <= strtotime( $last_release->release_date ) ) {
+ // If we don't have revision numbers, use dates. Maybe this should be removed.
+ return false; // Not an error, just skip.
+ }
+ } else {
+ // No previous release - get commits from revision '1' to 'head'.
+ $commit_log = SVN::log( $trunk_url, array( '1', 'HEAD' ), $svn_options );
+ }
+
+ // Store the commit log in postmeta. We'll only do this for drafts.
+ $release['commit_log'] = $commit_log['log'] ?? null;
+
+ $draft_id = $this->get_release( $plugin, 'trunk' );
+ if ( $draft_id ) {
+ $release_id = $this->update_release( $draft_id, $release );
+ } else {
+ $release_id = $this->add_release( $plugin, $release );
+ }
+
+ return $release_id;
+ }
+
+ function delete_release( $release_id ) {
+ $release_post = get_post( $release_id );
+ if ( ! $release_post || 'plugin_release' !== $release_post->post_type ) {
+ return new \WP_Error( 'invalid_release', 'Invalid release' );
+ }
+
+ return wp_delete_post( $release_id, false ); // FIXME: change to true for force delete when this is ready and WELL TESTED.
+ }
+
+ /**
+ * Update all release info for a plugin. This will insert or update each release, and remove any unknown releases.
+ *
+ * @param int|WP_Post $plugin The plugin post.
+ * @param array $releases An array of release data. Should be a complete array of all releases.
+ * @return int|WP_Error The number of changes made.
+ */
+ public function update_releases( $plugin, $releases ) {
+ $plugin_id = ( get_post( $plugin ) )->ID;
+
+ if ( 'plugin' !== get_post_type( $plugin ) ) {
+ return new \WP_Error( 'invalid_plugin', 'Invalid plugin' );
+ }
+
+ $changed = false;
+
+ // The current releases, if any, that need to be updated.
+ $current_releases = $this->get_releases( $plugin );
+ $current_versions = wp_list_pluck( $current_releases, 'post_title', 'ID' );
+
+ // Sort the releases by revision number ascending.
+ usort( $releases, function( $a, $b ) {
+ return max($a['revision']) <=> max($b['revision']);
+ } );
+
+ // Add or update each release.
+ foreach ( $releases as $release ) {
+ $release_revision = max( $release['revision'] );
+ // revision_final is the svn rev number that corresponds to the release tag.
+ // revision_prior is the svn rev number of the previous release.
+ // revision_prior:revision_final is the range of svn rev numbers that are included in this release (noting that you'll need to be specific about paths)
+ $release['revision_final'] = $release_revision ?? 'HEAD';
+ $release['revision_prior'] = $last_release_revision ?? '1'; // TODO: is there a reasonable way to get the initial import revision number?
+
+ // FIXME: Is it safe to run this here? Should this be conditional on the context in which we're running? Only on add? Something else?
+ if ( $release['revision_final'] && $release['revision_prior'] ) {
+ $trunk_url = Import::PLUGIN_SVN_BASE . '/' . $plugin->post_name . '/trunk';
+ $svn_options = [ 'limit' => 100 ]; // Safety limit
+ $commit_log = SVN::log( $trunk_url, [ $release['revision_final'], $release['revision_prior'] ], $svn_options );
+ $release['commit_log'] = $commit_log['log'] ?? null;
+ }
+
+ if ( ! in_array( $release['version'], $current_versions ) ) {
+ // Add a CPT for the release if one does not yet exist.
+ $r = $this->add_release( $plugin, $release );
+ #fputs( STDERR, 'add: ' . var_export( $r, true ) . "\n" );
+ if ( is_wp_error( $r ) ) {
+ return $r;
+ }
+ ++ $changed;
+ } else {
+ // Update an existing CPT for the release.
+ // Note that this will update the CPT even if no data has changed.
+ $release_id = array_search( $release['version'], $current_versions );
+ $r = $this->update_release( $release_id, $release );
+ #fputs( STDERR, 'update: ' . var_export( $r, true ) . "\n" );
+ if ( is_wp_error( $r ) ) {
+ return $r;
+ }
+ ++ $changed;
+ }
+ $last_release_revision = $release_revision;
+ }
+
+ // Remove any releases that are no longer present.
+ foreach ( $current_versions as $release_id => $release_version ) {
+ // A CPT that doesn't exist in the $releases array should be removed.
+ if ( ! in_array( $release_version, wp_list_pluck( $releases, 'version' ) ) ) {
+ $r = $this->delete_release( $release_id );
+ #fputs( STDERR, 'delete: ' . var_export( $r, true ) . "\n" );
+ if ( is_wp_error( $r ) ) {
+ return $r;
+ }
+ ++ $changed;
+ }
+ // If there are multiple releases with the same version (title), remove all but the first.
+ // TODO: Not sure this code should stay.
+ if ( $release_id !== array_search( $release_version, $current_versions ) ) {
+ $r = $this->delete_release( $release_id );
+ #fputs( STDERR, 'delete dupe: ' . var_export( $r, true ) . "\n" );
+ if ( is_wp_error( $r ) ) {
+ return $r;
+ }
+ ++ $changed;
+ }
+ }
+
+ return $changed;
+ }
+
+ /**
+ * Get a specific plugin release.
+ */
+ public function get_release( $plugin, $version ) {
+ $plugin_id = ( get_post( $plugin ) )->ID;
+
+ // Note that the post_status is 'draft' for trunk releases.
+ $post_status = ( 'trunk' === $version ) ? 'draft' : 'publish';
+
+ $release = get_posts( array(
+ 'post_type' => 'plugin_release',
+ 'posts_per_page' => 1,
+ 'post_parent' => $plugin_id,
+ 'title' => $version,
+ 'post_status' => $post_status,
+ 'orderby' => 'date',
+ 'order' => 'DESC',
+ ) );
+
+ return $release ? $release[0] : null;
+ }
+
+ /**
+ * Publish a draft release (ie trunk).
+ * This will use svn to tag the release, and then publish the release post.
+ *
+ * @param int|WP_Post $plugin The plugin post.
+ *
+ * @return int|WP_Error The ID of the published release post, or a WP_Error object.
+ */
+ public function publish_release( $plugin ) {
+ $plugin = get_post( $plugin );
+
+ // TODO: current_user_can()? Or other checks?
+
+ $draft = $this->get_release( $plugin, 'trunk' );
+ if ( ! $draft ) {
+ return new \WP_Error( 'no_draft', __( 'We could not find a draft to release.', 'wporg-plugins' ) );
+ }
+
+ $new_tag = $draft->release_version;
+ if ( $this->get_release( $plugin, $new_tag ) ) {
+ return new \WP_Error( 'tag_exists', __( 'This version has already been released.', 'wporg-plugins' ), $new_tag );
+ }
+
+ /*
+ * We won't be block on plugin check or import warnings yet
+ */
+ // if ( !$draft->plugin_check_result || ! $draft->plugin_check_result['verdict'] ) {
+ // return new \WP_Error( 'plugin_check_failed', __( 'Please review and address the issues identified by the static code analysis tool before releasing.', 'wporg-plugins' ) );
+ // }
+
+ // TODO: Should import warnings exist on the release CPT?
+ // if ( $plugin->_import_warnings ) {
+ // // These warnings are likely (always?) present because the tag hasn't been created yet.
+ // $ignored_warnings = [
+ // 'stable_tag_invalid_trunk_fallback' => 1,
+ // 'stable_tag_invalid' => 1,
+ // ];
+ // // Stop here if other warnings are present.
+ // if ( array_diff_key( $plugin->_import_warnings, $ignored_warnings ) ) {
+ // return new \WP_Error( 'import_warnings', 'Import warnings', $plugin->_import_warnings );
+ // }
+ // }
+
+ // TODO: What sanitizing or cross-checking do we need here?
+ $trunk_url = 'https://plugins.svn.wordpress.org/' . $plugin->post_name . '/trunk';
+ $tag_url = 'https://plugins.svn.wordpress.org/' . $plugin->post_name . '/tags/' . $new_tag;
+
+ // TODO: Decide if we're committing this as a specific user. Also any other options needed.
+ // Note that since this is a url-to-url copy, the commit happens immediately.
+ $svn_options = [
+ 'message' => 'Tagging ' . $new_tag . ' from trunk@' . reset( $draft->release_revision ), // Commit message. i18n?
+ ];
+ $tag_result = SVN::copy( $trunk_url, $tag_url, $svn_options );
+
+ if ( !$tag_result || ! $tag_result['result'] ) {
+ return new \WP_Error( 'svn_error', __( 'The release failed. Please wait a few minutes and try again.', 'wporg-plugins' ), $tag_result['errors'] );
+ }
+
+ // Include the tag revision in the release post list of revisions.
+ // This is so that we can easily tell if there are trunk commits after the release.
+ $release_revisions = array_merge( $draft->release_revision, [ $tag_result['revision'] ] );
+
+ $release_id = wp_update_post( array(
+ 'ID' => $draft->ID,
+ 'post_status' => 'publish',
+ 'post_title' => $new_tag,
+ 'meta_input' => array(
+ 'release_revision' => $release_revisions,
+ #'release_tag_revision' => $tag_result['revision'], // Do we need this? Probably not.
+ 'release_tag' => $new_tag, // Was 'trunk'
+ ),
+ ) );
+
+ return $release_id;
+ }
+
+}
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/cli/class-import.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/cli/class-import.php
index 4894e4298b..e57ab78844 100644
--- a/wordpress.org/public_html/wp-content/plugins/plugin-directory/cli/class-import.php
+++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/cli/class-import.php
@@ -5,8 +5,10 @@
use WordPressdotorg\Plugin_Directory\Jobs\API_Update_Updater;
use WordPressdotorg\Plugin_Directory\Jobs\Tide_Sync;
use WordPressdotorg\Plugin_Directory\Block_JSON;
+use WordPressdotorg\Plugin_Directory\Plugin_Check;
use WordPressdotorg\Plugin_Directory\Plugin_Directory;
use WordPressdotorg\Plugin_Directory\Email\Release_Confirmation as Release_Confirmation_Email;
+use WordPressdotorg\Plugin_Directory\Plugin_Release;
use WordPressdotorg\Plugin_Directory\Readme\{ Parser as Readme_Parser, Validator as Readme_Validator };
use WordPressdotorg\Plugin_Directory\Standalone\Plugins_Info_API;
use WordPressdotorg\Plugin_Directory\Template;
@@ -167,6 +169,43 @@ public function import_from_svn( $plugin_slug, $svn_changed_tags = array( 'trunk
}
}
+ // TODO: Test and confirm that this is the correct behavior.
+ if ( in_array( 'trunk', $svn_changed_tags ) ) {
+ // Backfill Release CPTs if needed. This should only happen once per plugin.
+ // Doing this here as a relatively safe way to distribute the load of backfilling.
+ Plugin_Release::instance()->maybe_backfill_releases( $plugin );
+
+ // Create or update a 'draft' release CPT for trunk changes.
+ // Note that this will only create a new draft if the version doesn't already exist as a release.
+ // TODO: refine this behaviour. (Maybe compare revision numbers?)
+ $release = Plugin_Release::instance()->add_or_update_draft_release(
+ $plugin,
+ [
+ 'tag' => 'trunk',
+ 'version' => $version, // TODO: Is this correct?
+ 'committer' => [$last_committer],
+ 'revision' => [$last_revision],
+ 'tested' => $readme->tested,
+ 'requires' => $headers->RequiresWP,
+ 'requires_php' => $headers->RequiresPHP,
+ 'requires_plugins' => $requires_plugins,
+ ]
+ );
+
+ // While we're at it, run plugin check and store the results.
+ // FIXME: Maybe this belongs in export_and_parse_plugin()? The readme checker is run there.
+ $plugin_export_dir = $data['tmp_dir'] . '/export';
+ if ( $release && ! is_wp_error( $release ) ) {
+ $plugin_check_result = Plugin_Check::run_checks( $plugin->post_name, $plugin_export_dir );
+ #var_dump( $plugin_check_result );
+ if ( $plugin_check_result ) {
+ update_post_meta( $release, 'plugin_check_result', $plugin_check_result );
+ } else {
+ delete_post_meta( $release, 'plugin_check_result' );
+ }
+ }
+ }
+
// Release confirmation
if ( $plugin->release_confirmation ) {
// If the stable tag is trunk, we shouldn't continue, as we don't support that for RC.
diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/tools/class-svn.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tools/class-svn.php
index 0178ed857b..2a5dde9d85 100644
--- a/wordpress.org/public_html/wp-content/plugins/plugin-directory/tools/class-svn.php
+++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tools/class-svn.php
@@ -428,6 +428,61 @@ public static function log( $url, $revision = 'HEAD', $options = array() ) {
return compact( 'log', 'errors' );
}
+ /**
+ * Copy a SVN path (or url).
+ *
+ * @static
+ *
+ * @param string $from The path of the SVN folder to rename. May be a URL.
+ * @param string $to The new path of the SVN folder. May be a URL.
+ * @param array $options Optional. A list of options to pass to SVN. Default: empty array.
+ * @return array {
+ * @type bool $result The result of the operation.
+ * @type int $revision The revision.
+ * @type false|array $errors Whether any errors or warnings were encountered.
+ * }
+ */
+ public static function copy( $from, $to, $options = array() ) {
+ // TODO: consider refactoring this with rename, since the code is almost identical.
+ $options[] = 'non-interactive';
+ $is_url = ( preg_match( '#https?://#i', $from ) && preg_match( '#https?://#i', $to ) );
+
+ if ( $is_url ) {
+ // Set the message if not provided.
+ if ( ! isset( $options['message'] ) && ! isset( $options['m'] ) ) {
+ $options['message'] = sprintf( "Copy %s to %s.", basename( $from ), basename( $to ) );
+ }
+
+ if ( empty( $options['username'] ) ) {
+ $options['username'] = PLUGIN_SVN_MANAGEMENT_USER;
+ $options['password'] = PLUGIN_SVN_MANAGEMENT_PASS;
+ }
+ }
+
+ $esc_options = self::parse_esc_parameters( $options );
+
+ $esc_from = escapeshellarg( $from );
+ $esc_to = escapeshellarg( $to );
+
+ $output = self::shell_exec( "svn cp $esc_from $esc_to $esc_options 2>&1" );
+ if ( $is_url && preg_match( '/Committed revision (?P\d+)[.]/i', $output, $m ) ) {
+ $revision = (int) $m['revision'];
+ $result = true;
+ $errors = false;
+ } else {
+ $errors = self::parse_svn_errors( $output );
+ $revision = false;
+
+ if ( $is_url || $errors ) {
+ $result = false;
+ } else {
+ $result = true;
+ }
+ }
+
+ return compact( 'result', 'revision', 'errors' );
+ }
+
/**
* Rename a SVN path (or url).
*
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/archive-page/index.asset.php b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/archive-page/index.asset.php
index d7b228686a..9202f58eda 100644
--- a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/archive-page/index.asset.php
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/archive-page/index.asset.php
@@ -1 +1 @@
- array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-server-side-render'), 'version' => '8627e1da9b24373a1f90');
+ array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-server-side-render'), 'version' => '7f26875761f01d13f9dd');
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/archive-page/index.js b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/archive-page/index.js
index 1b86a728bd..772b3d2c7e 100644
--- a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/archive-page/index.js
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/archive-page/index.js
@@ -1 +1,183 @@
-(()=>{"use strict";var e={n:t=>{var r=t&&t.__esModule?()=>t.default:()=>t;return e.d(r,{a:r}),r},d:(t,r)=>{for(var o in r)e.o(r,o)&&!e.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:r[o]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.React,r=window.wp.components,o=window.wp.blocks,n=window.wp.serverSideRender;var a=e.n(n);const c=window.wp.blockEditor,i=JSON.parse('{"u2":"wporg/archive-page"}');(0,o.registerBlockType)(i.u2,{edit:function({attributes:e,name:o}){return(0,t.createElement)("div",{...(0,c.useBlockProps)()},(0,t.createElement)(r.Disabled,null,(0,t.createElement)(a(),{block:o,attributes:e})))},save:()=>null})})();
\ No newline at end of file
+/******/ (() => { // webpackBootstrap
+/******/ "use strict";
+/******/ var __webpack_modules__ = ({
+
+/***/ "react":
+/*!************************!*\
+ !*** external "React" ***!
+ \************************/
+/***/ ((module) => {
+
+module.exports = window["React"];
+
+/***/ }),
+
+/***/ "@wordpress/block-editor":
+/*!*************************************!*\
+ !*** external ["wp","blockEditor"] ***!
+ \*************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blockEditor"];
+
+/***/ }),
+
+/***/ "@wordpress/blocks":
+/*!********************************!*\
+ !*** external ["wp","blocks"] ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blocks"];
+
+/***/ }),
+
+/***/ "@wordpress/components":
+/*!************************************!*\
+ !*** external ["wp","components"] ***!
+ \************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["components"];
+
+/***/ }),
+
+/***/ "@wordpress/server-side-render":
+/*!******************************************!*\
+ !*** external ["wp","serverSideRender"] ***!
+ \******************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["serverSideRender"];
+
+/***/ }),
+
+/***/ "./src/blocks/archive-page/block.json":
+/*!********************************************!*\
+ !*** ./src/blocks/archive-page/block.json ***!
+ \********************************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"wporg/archive-page","version":"0.1.0","title":"Archive Page Content","category":"design","icon":"","description":"A block that displays the archive page content","textdomain":"wporg","attributes":{},"supports":{"html":false},"editorScript":"file:./index.js","render":"file:./render.php"}');
+
+/***/ })
+
+/******/ });
+/************************************************************************/
+/******/ // The module cache
+/******/ var __webpack_module_cache__ = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/ // Check if module is in cache
+/******/ var cachedModule = __webpack_module_cache__[moduleId];
+/******/ if (cachedModule !== undefined) {
+/******/ return cachedModule.exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = __webpack_module_cache__[moduleId] = {
+/******/ // no module.id needed
+/******/ // no module.loaded needed
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/************************************************************************/
+/******/ /* webpack/runtime/compat get default export */
+/******/ (() => {
+/******/ // getDefaultExport function for compatibility with non-harmony modules
+/******/ __webpack_require__.n = (module) => {
+/******/ var getter = module && module.__esModule ?
+/******/ () => (module['default']) :
+/******/ () => (module);
+/******/ __webpack_require__.d(getter, { a: getter });
+/******/ return getter;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/define property getters */
+/******/ (() => {
+/******/ // define getter functions for harmony exports
+/******/ __webpack_require__.d = (exports, definition) => {
+/******/ for(var key in definition) {
+/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
+/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
+/******/ }
+/******/ }
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/hasOwnProperty shorthand */
+/******/ (() => {
+/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
+/******/ })();
+/******/
+/******/ /* webpack/runtime/make namespace object */
+/******/ (() => {
+/******/ // define __esModule on exports
+/******/ __webpack_require__.r = (exports) => {
+/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+/******/ }
+/******/ Object.defineProperty(exports, '__esModule', { value: true });
+/******/ };
+/******/ })();
+/******/
+/************************************************************************/
+var __webpack_exports__ = {};
+// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
+(() => {
+/*!******************************************!*\
+ !*** ./src/blocks/archive-page/index.js ***!
+ \******************************************/
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @wordpress/components */ "@wordpress/components");
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @wordpress/blocks */ "@wordpress/blocks");
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__);
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @wordpress/server-side-render */ "@wordpress/server-side-render");
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__);
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @wordpress/block-editor */ "@wordpress/block-editor");
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__);
+/* harmony import */ var _block_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./block.json */ "./src/blocks/archive-page/block.json");
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+function Edit({
+ attributes,
+ name
+}) {
+ return (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)("div", {
+ ...(0,_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__.useBlockProps)()
+ }, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__.Disabled, null, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)((_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default()), {
+ block: name,
+ attributes: attributes
+ })));
+}
+(0,_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__.registerBlockType)(_block_json__WEBPACK_IMPORTED_MODULE_5__.name, {
+ edit: Edit,
+ save: () => null
+});
+})();
+
+/******/ })()
+;
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/card/block.json b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/card/block.json
new file mode 100644
index 0000000000..3ce8c4872d
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/card/block.json
@@ -0,0 +1,27 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 2,
+ "name": "wporg/card",
+ "version": "0.1.0",
+ "title": "Release Card",
+ "category": "design",
+ "icon": "",
+ "description": "A block to display a card.",
+ "textdomain": "wporg",
+ "attributes": {
+ "title": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ "supports": {
+ "html": false,
+ "interactivity": true
+ },
+ "usesContext": [
+ "postId"
+ ],
+ "editorScript": "file:./index.js",
+ "render": "file:./render.php",
+ "style": "file:./style-index.css"
+}
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/card/index.asset.php b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/card/index.asset.php
new file mode 100644
index 0000000000..459c076b07
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/card/index.asset.php
@@ -0,0 +1 @@
+ array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-server-side-render'), 'version' => '47e3efb31a2fd6ac5818');
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/card/index.js b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/card/index.js
new file mode 100644
index 0000000000..bd122c23df
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/card/index.js
@@ -0,0 +1,298 @@
+/******/ (() => { // webpackBootstrap
+/******/ "use strict";
+/******/ var __webpack_modules__ = ({
+
+/***/ "./src/blocks/card/index.js":
+/*!**********************************!*\
+ !*** ./src/blocks/card/index.js ***!
+ \**********************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @wordpress/components */ "@wordpress/components");
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @wordpress/blocks */ "@wordpress/blocks");
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__);
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @wordpress/server-side-render */ "@wordpress/server-side-render");
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__);
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @wordpress/block-editor */ "@wordpress/block-editor");
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__);
+/* harmony import */ var _block_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./block.json */ "./src/blocks/card/block.json");
+/* harmony import */ var _style_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./style.scss */ "./src/blocks/card/style.scss");
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+function Edit({
+ attributes,
+ name
+}) {
+ return (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)("div", {
+ ...(0,_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__.useBlockProps)()
+ }, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__.Disabled, null, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)((_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default()), {
+ block: name,
+ attributes: attributes
+ })));
+}
+(0,_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__.registerBlockType)(_block_json__WEBPACK_IMPORTED_MODULE_5__.name, {
+ edit: Edit,
+ save: () => null
+});
+
+/***/ }),
+
+/***/ "./src/blocks/card/style.scss":
+/*!************************************!*\
+ !*** ./src/blocks/card/style.scss ***!
+ \************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+__webpack_require__.r(__webpack_exports__);
+// extracted by mini-css-extract-plugin
+
+
+/***/ }),
+
+/***/ "react":
+/*!************************!*\
+ !*** external "React" ***!
+ \************************/
+/***/ ((module) => {
+
+module.exports = window["React"];
+
+/***/ }),
+
+/***/ "@wordpress/block-editor":
+/*!*************************************!*\
+ !*** external ["wp","blockEditor"] ***!
+ \*************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blockEditor"];
+
+/***/ }),
+
+/***/ "@wordpress/blocks":
+/*!********************************!*\
+ !*** external ["wp","blocks"] ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blocks"];
+
+/***/ }),
+
+/***/ "@wordpress/components":
+/*!************************************!*\
+ !*** external ["wp","components"] ***!
+ \************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["components"];
+
+/***/ }),
+
+/***/ "@wordpress/server-side-render":
+/*!******************************************!*\
+ !*** external ["wp","serverSideRender"] ***!
+ \******************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["serverSideRender"];
+
+/***/ }),
+
+/***/ "./src/blocks/card/block.json":
+/*!************************************!*\
+ !*** ./src/blocks/card/block.json ***!
+ \************************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"wporg/card","version":"0.1.0","title":"Release Card","category":"design","icon":"","description":"A block to display a card.","textdomain":"wporg","attributes":{"title":{"type":"string","default":""}},"supports":{"html":false,"interactivity":true},"usesContext":["postId"],"editorScript":"file:./index.js","render":"file:./render.php","style":"file:./style-index.css"}');
+
+/***/ })
+
+/******/ });
+/************************************************************************/
+/******/ // The module cache
+/******/ var __webpack_module_cache__ = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/ // Check if module is in cache
+/******/ var cachedModule = __webpack_module_cache__[moduleId];
+/******/ if (cachedModule !== undefined) {
+/******/ return cachedModule.exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = __webpack_module_cache__[moduleId] = {
+/******/ // no module.id needed
+/******/ // no module.loaded needed
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = __webpack_modules__;
+/******/
+/************************************************************************/
+/******/ /* webpack/runtime/chunk loaded */
+/******/ (() => {
+/******/ var deferred = [];
+/******/ __webpack_require__.O = (result, chunkIds, fn, priority) => {
+/******/ if(chunkIds) {
+/******/ priority = priority || 0;
+/******/ for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];
+/******/ deferred[i] = [chunkIds, fn, priority];
+/******/ return;
+/******/ }
+/******/ var notFulfilled = Infinity;
+/******/ for (var i = 0; i < deferred.length; i++) {
+/******/ var chunkIds = deferred[i][0];
+/******/ var fn = deferred[i][1];
+/******/ var priority = deferred[i][2];
+/******/ var fulfilled = true;
+/******/ for (var j = 0; j < chunkIds.length; j++) {
+/******/ if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {
+/******/ chunkIds.splice(j--, 1);
+/******/ } else {
+/******/ fulfilled = false;
+/******/ if(priority < notFulfilled) notFulfilled = priority;
+/******/ }
+/******/ }
+/******/ if(fulfilled) {
+/******/ deferred.splice(i--, 1)
+/******/ var r = fn();
+/******/ if (r !== undefined) result = r;
+/******/ }
+/******/ }
+/******/ return result;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/compat get default export */
+/******/ (() => {
+/******/ // getDefaultExport function for compatibility with non-harmony modules
+/******/ __webpack_require__.n = (module) => {
+/******/ var getter = module && module.__esModule ?
+/******/ () => (module['default']) :
+/******/ () => (module);
+/******/ __webpack_require__.d(getter, { a: getter });
+/******/ return getter;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/define property getters */
+/******/ (() => {
+/******/ // define getter functions for harmony exports
+/******/ __webpack_require__.d = (exports, definition) => {
+/******/ for(var key in definition) {
+/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
+/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
+/******/ }
+/******/ }
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/hasOwnProperty shorthand */
+/******/ (() => {
+/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
+/******/ })();
+/******/
+/******/ /* webpack/runtime/make namespace object */
+/******/ (() => {
+/******/ // define __esModule on exports
+/******/ __webpack_require__.r = (exports) => {
+/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+/******/ }
+/******/ Object.defineProperty(exports, '__esModule', { value: true });
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/jsonp chunk loading */
+/******/ (() => {
+/******/ // no baseURI
+/******/
+/******/ // object to store loaded and loading chunks
+/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
+/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
+/******/ var installedChunks = {
+/******/ "blocks/card/index": 0,
+/******/ "blocks/card/style-index": 0
+/******/ };
+/******/
+/******/ // no chunk on demand loading
+/******/
+/******/ // no prefetching
+/******/
+/******/ // no preloaded
+/******/
+/******/ // no HMR
+/******/
+/******/ // no HMR manifest
+/******/
+/******/ __webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);
+/******/
+/******/ // install a JSONP callback for chunk loading
+/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
+/******/ var chunkIds = data[0];
+/******/ var moreModules = data[1];
+/******/ var runtime = data[2];
+/******/ // add "moreModules" to the modules object,
+/******/ // then flag all "chunkIds" as loaded and fire callback
+/******/ var moduleId, chunkId, i = 0;
+/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
+/******/ for(moduleId in moreModules) {
+/******/ if(__webpack_require__.o(moreModules, moduleId)) {
+/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
+/******/ }
+/******/ }
+/******/ if(runtime) var result = runtime(__webpack_require__);
+/******/ }
+/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
+/******/ for(;i < chunkIds.length; i++) {
+/******/ chunkId = chunkIds[i];
+/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
+/******/ installedChunks[chunkId][0]();
+/******/ }
+/******/ installedChunks[chunkId] = 0;
+/******/ }
+/******/ return __webpack_require__.O(result);
+/******/ }
+/******/
+/******/ var chunkLoadingGlobal = self["webpackChunkwporg_plugins_2024"] = self["webpackChunkwporg_plugins_2024"] || [];
+/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
+/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
+/******/ })();
+/******/
+/************************************************************************/
+/******/
+/******/ // startup
+/******/ // Load entry module and return exports
+/******/ // This entry module depends on other loaded chunks and execution need to be delayed
+/******/ var __webpack_exports__ = __webpack_require__.O(undefined, ["blocks/card/style-index"], () => (__webpack_require__("./src/blocks/card/index.js")))
+/******/ __webpack_exports__ = __webpack_require__.O(__webpack_exports__);
+/******/
+/******/ })()
+;
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/card/render.php b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/card/render.php
new file mode 100644
index 0000000000..d0e1cdb712
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/card/render.php
@@ -0,0 +1,27 @@
+
+
+
+
+ {$block->attributes['title']}
+
+
+ $content
+
+
+HTML;
+
+$output = sprintf(
+ '%2$s
',
+ wp_kses_data( get_block_wrapper_attributes() ),
+ $html,
+);
+
+echo do_blocks( $output ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/card/style-index.css b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/card/style-index.css
new file mode 100644
index 0000000000..9de758353f
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/card/style-index.css
@@ -0,0 +1,8 @@
+/*!***************************************************************************************************************************************************************************************************************************************************!*\
+ !*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[4].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[4].use[2]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[4].use[3]!./src/blocks/card/style.scss ***!
+ \***************************************************************************************************************************************************************************************************************************************************/
+.wp-block-wporg-release-draft {
+ font-size: var(--wp--preset--font-size--small);
+}
+
+/*# sourceMappingURL=style-index.css.map*/
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/category-navigation/index.asset.php b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/category-navigation/index.asset.php
index ab2fb9f31a..94878f12bf 100644
--- a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/category-navigation/index.asset.php
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/category-navigation/index.asset.php
@@ -1 +1 @@
- array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-server-side-render'), 'version' => '6bce91817a063cdf476d');
+ array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-server-side-render'), 'version' => '9b7cfda9379a258a4745');
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/category-navigation/index.js b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/category-navigation/index.js
index e8e14d7ec6..a639fdc3e3 100644
--- a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/category-navigation/index.js
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/category-navigation/index.js
@@ -1 +1,183 @@
-(()=>{"use strict";var e={n:t=>{var r=t&&t.__esModule?()=>t.default:()=>t;return e.d(r,{a:r}),r},d:(t,r)=>{for(var o in r)e.o(r,o)&&!e.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:r[o]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.React,r=window.wp.components,o=window.wp.blocks,n=window.wp.serverSideRender;var a=e.n(n);const i=window.wp.blockEditor,c=JSON.parse('{"u2":"wporg/category-navigation"}');(0,o.registerBlockType)(c.u2,{edit:function({attributes:e,name:o}){return(0,t.createElement)("div",{...(0,i.useBlockProps)()},(0,t.createElement)(r.Disabled,null,(0,t.createElement)(a(),{block:o,attributes:e})))},save:()=>null})})();
\ No newline at end of file
+/******/ (() => { // webpackBootstrap
+/******/ "use strict";
+/******/ var __webpack_modules__ = ({
+
+/***/ "react":
+/*!************************!*\
+ !*** external "React" ***!
+ \************************/
+/***/ ((module) => {
+
+module.exports = window["React"];
+
+/***/ }),
+
+/***/ "@wordpress/block-editor":
+/*!*************************************!*\
+ !*** external ["wp","blockEditor"] ***!
+ \*************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blockEditor"];
+
+/***/ }),
+
+/***/ "@wordpress/blocks":
+/*!********************************!*\
+ !*** external ["wp","blocks"] ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blocks"];
+
+/***/ }),
+
+/***/ "@wordpress/components":
+/*!************************************!*\
+ !*** external ["wp","components"] ***!
+ \************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["components"];
+
+/***/ }),
+
+/***/ "@wordpress/server-side-render":
+/*!******************************************!*\
+ !*** external ["wp","serverSideRender"] ***!
+ \******************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["serverSideRender"];
+
+/***/ }),
+
+/***/ "./src/blocks/category-navigation/block.json":
+/*!***************************************************!*\
+ !*** ./src/blocks/category-navigation/block.json ***!
+ \***************************************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"wporg/category-navigation","version":"0.2.0","title":"Category Navigation","category":"design","icon":"","description":"Adds the category navigation menu","textdomain":"wporg","attributes":{},"supports":{"html":false},"editorScript":"file:./index.js","render":"file:./render.php"}');
+
+/***/ })
+
+/******/ });
+/************************************************************************/
+/******/ // The module cache
+/******/ var __webpack_module_cache__ = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/ // Check if module is in cache
+/******/ var cachedModule = __webpack_module_cache__[moduleId];
+/******/ if (cachedModule !== undefined) {
+/******/ return cachedModule.exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = __webpack_module_cache__[moduleId] = {
+/******/ // no module.id needed
+/******/ // no module.loaded needed
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/************************************************************************/
+/******/ /* webpack/runtime/compat get default export */
+/******/ (() => {
+/******/ // getDefaultExport function for compatibility with non-harmony modules
+/******/ __webpack_require__.n = (module) => {
+/******/ var getter = module && module.__esModule ?
+/******/ () => (module['default']) :
+/******/ () => (module);
+/******/ __webpack_require__.d(getter, { a: getter });
+/******/ return getter;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/define property getters */
+/******/ (() => {
+/******/ // define getter functions for harmony exports
+/******/ __webpack_require__.d = (exports, definition) => {
+/******/ for(var key in definition) {
+/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
+/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
+/******/ }
+/******/ }
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/hasOwnProperty shorthand */
+/******/ (() => {
+/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
+/******/ })();
+/******/
+/******/ /* webpack/runtime/make namespace object */
+/******/ (() => {
+/******/ // define __esModule on exports
+/******/ __webpack_require__.r = (exports) => {
+/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+/******/ }
+/******/ Object.defineProperty(exports, '__esModule', { value: true });
+/******/ };
+/******/ })();
+/******/
+/************************************************************************/
+var __webpack_exports__ = {};
+// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
+(() => {
+/*!*************************************************!*\
+ !*** ./src/blocks/category-navigation/index.js ***!
+ \*************************************************/
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @wordpress/components */ "@wordpress/components");
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @wordpress/blocks */ "@wordpress/blocks");
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__);
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @wordpress/server-side-render */ "@wordpress/server-side-render");
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__);
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @wordpress/block-editor */ "@wordpress/block-editor");
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__);
+/* harmony import */ var _block_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./block.json */ "./src/blocks/category-navigation/block.json");
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+function Edit({
+ attributes,
+ name
+}) {
+ return (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)("div", {
+ ...(0,_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__.useBlockProps)()
+ }, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__.Disabled, null, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)((_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default()), {
+ block: name,
+ attributes: attributes
+ })));
+}
+(0,_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__.registerBlockType)(_block_json__WEBPACK_IMPORTED_MODULE_5__.name, {
+ edit: Edit,
+ save: () => null
+});
+})();
+
+/******/ })()
+;
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/filter-bar/index.asset.php b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/filter-bar/index.asset.php
index 32cfe90ff5..922b695350 100644
--- a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/filter-bar/index.asset.php
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/filter-bar/index.asset.php
@@ -1 +1 @@
- array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-server-side-render'), 'version' => '4e25fbe50d772f6a1559');
+ array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-server-side-render'), 'version' => 'fe9a74e9340bde2c89fa');
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/filter-bar/index.js b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/filter-bar/index.js
index 3662ea6f71..1d81e7ca65 100644
--- a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/filter-bar/index.js
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/filter-bar/index.js
@@ -1 +1,183 @@
-(()=>{"use strict";var e={n:t=>{var r=t&&t.__esModule?()=>t.default:()=>t;return e.d(r,{a:r}),r},d:(t,r)=>{for(var o in r)e.o(r,o)&&!e.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:r[o]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.React,r=window.wp.components,o=window.wp.blocks,n=window.wp.serverSideRender;var a=e.n(n);const l=window.wp.blockEditor,i=JSON.parse('{"u2":"wporg/filter-bar"}');(0,o.registerBlockType)(i.u2,{edit:function({attributes:e,name:o}){return(0,t.createElement)("div",{...(0,l.useBlockProps)()},(0,t.createElement)(r.Disabled,null,(0,t.createElement)(a(),{block:o,attributes:e})))},save:()=>null})})();
\ No newline at end of file
+/******/ (() => { // webpackBootstrap
+/******/ "use strict";
+/******/ var __webpack_modules__ = ({
+
+/***/ "react":
+/*!************************!*\
+ !*** external "React" ***!
+ \************************/
+/***/ ((module) => {
+
+module.exports = window["React"];
+
+/***/ }),
+
+/***/ "@wordpress/block-editor":
+/*!*************************************!*\
+ !*** external ["wp","blockEditor"] ***!
+ \*************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blockEditor"];
+
+/***/ }),
+
+/***/ "@wordpress/blocks":
+/*!********************************!*\
+ !*** external ["wp","blocks"] ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blocks"];
+
+/***/ }),
+
+/***/ "@wordpress/components":
+/*!************************************!*\
+ !*** external ["wp","components"] ***!
+ \************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["components"];
+
+/***/ }),
+
+/***/ "@wordpress/server-side-render":
+/*!******************************************!*\
+ !*** external ["wp","serverSideRender"] ***!
+ \******************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["serverSideRender"];
+
+/***/ }),
+
+/***/ "./src/blocks/filter-bar/block.json":
+/*!******************************************!*\
+ !*** ./src/blocks/filter-bar/block.json ***!
+ \******************************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"wporg/filter-bar","version":"0.2.0","title":"Filter Bar","category":"design","icon":"","description":"Adds a filter bar","textdomain":"wporg","attributes":{},"supports":{"html":false},"editorScript":"file:./index.js","render":"file:./render.php"}');
+
+/***/ })
+
+/******/ });
+/************************************************************************/
+/******/ // The module cache
+/******/ var __webpack_module_cache__ = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/ // Check if module is in cache
+/******/ var cachedModule = __webpack_module_cache__[moduleId];
+/******/ if (cachedModule !== undefined) {
+/******/ return cachedModule.exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = __webpack_module_cache__[moduleId] = {
+/******/ // no module.id needed
+/******/ // no module.loaded needed
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/************************************************************************/
+/******/ /* webpack/runtime/compat get default export */
+/******/ (() => {
+/******/ // getDefaultExport function for compatibility with non-harmony modules
+/******/ __webpack_require__.n = (module) => {
+/******/ var getter = module && module.__esModule ?
+/******/ () => (module['default']) :
+/******/ () => (module);
+/******/ __webpack_require__.d(getter, { a: getter });
+/******/ return getter;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/define property getters */
+/******/ (() => {
+/******/ // define getter functions for harmony exports
+/******/ __webpack_require__.d = (exports, definition) => {
+/******/ for(var key in definition) {
+/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
+/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
+/******/ }
+/******/ }
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/hasOwnProperty shorthand */
+/******/ (() => {
+/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
+/******/ })();
+/******/
+/******/ /* webpack/runtime/make namespace object */
+/******/ (() => {
+/******/ // define __esModule on exports
+/******/ __webpack_require__.r = (exports) => {
+/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+/******/ }
+/******/ Object.defineProperty(exports, '__esModule', { value: true });
+/******/ };
+/******/ })();
+/******/
+/************************************************************************/
+var __webpack_exports__ = {};
+// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
+(() => {
+/*!****************************************!*\
+ !*** ./src/blocks/filter-bar/index.js ***!
+ \****************************************/
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @wordpress/components */ "@wordpress/components");
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @wordpress/blocks */ "@wordpress/blocks");
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__);
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @wordpress/server-side-render */ "@wordpress/server-side-render");
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__);
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @wordpress/block-editor */ "@wordpress/block-editor");
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__);
+/* harmony import */ var _block_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./block.json */ "./src/blocks/filter-bar/block.json");
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+function Edit({
+ attributes,
+ name
+}) {
+ return (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)("div", {
+ ...(0,_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__.useBlockProps)()
+ }, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__.Disabled, null, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)((_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default()), {
+ block: name,
+ attributes: attributes
+ })));
+}
+(0,_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__.registerBlockType)(_block_json__WEBPACK_IMPORTED_MODULE_5__.name, {
+ edit: Edit,
+ save: () => null
+});
+})();
+
+/******/ })()
+;
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/front-page/index.asset.php b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/front-page/index.asset.php
index 09684019c7..264faed9d3 100644
--- a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/front-page/index.asset.php
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/front-page/index.asset.php
@@ -1 +1 @@
- array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-server-side-render'), 'version' => '3f3755bbf3697bb808f8');
+ array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-server-side-render'), 'version' => 'b4c88578d4fb8d783dd4');
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/front-page/index.js b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/front-page/index.js
index 7a3c8b2166..7136a3f573 100644
--- a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/front-page/index.js
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/front-page/index.js
@@ -1 +1,183 @@
-(()=>{"use strict";var e={n:t=>{var r=t&&t.__esModule?()=>t.default:()=>t;return e.d(r,{a:r}),r},d:(t,r)=>{for(var o in r)e.o(r,o)&&!e.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:r[o]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.React,r=window.wp.components,o=window.wp.blocks,n=window.wp.serverSideRender;var a=e.n(n);const l=window.wp.blockEditor,c=JSON.parse('{"u2":"wporg/front-page"}');(0,o.registerBlockType)(c.u2,{edit:function({attributes:e,name:o}){return(0,t.createElement)("div",{...(0,l.useBlockProps)()},(0,t.createElement)(r.Disabled,null,(0,t.createElement)(a(),{block:o,attributes:e})))},save:()=>null})})();
\ No newline at end of file
+/******/ (() => { // webpackBootstrap
+/******/ "use strict";
+/******/ var __webpack_modules__ = ({
+
+/***/ "react":
+/*!************************!*\
+ !*** external "React" ***!
+ \************************/
+/***/ ((module) => {
+
+module.exports = window["React"];
+
+/***/ }),
+
+/***/ "@wordpress/block-editor":
+/*!*************************************!*\
+ !*** external ["wp","blockEditor"] ***!
+ \*************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blockEditor"];
+
+/***/ }),
+
+/***/ "@wordpress/blocks":
+/*!********************************!*\
+ !*** external ["wp","blocks"] ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blocks"];
+
+/***/ }),
+
+/***/ "@wordpress/components":
+/*!************************************!*\
+ !*** external ["wp","components"] ***!
+ \************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["components"];
+
+/***/ }),
+
+/***/ "@wordpress/server-side-render":
+/*!******************************************!*\
+ !*** external ["wp","serverSideRender"] ***!
+ \******************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["serverSideRender"];
+
+/***/ }),
+
+/***/ "./src/blocks/front-page/block.json":
+/*!******************************************!*\
+ !*** ./src/blocks/front-page/block.json ***!
+ \******************************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"wporg/front-page","version":"0.1.0","title":"Front Page Content","category":"design","icon":"","description":"A block that displays the front page content","textdomain":"wporg","attributes":{},"supports":{"html":false},"editorScript":"file:./index.js","render":"file:./render.php"}');
+
+/***/ })
+
+/******/ });
+/************************************************************************/
+/******/ // The module cache
+/******/ var __webpack_module_cache__ = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/ // Check if module is in cache
+/******/ var cachedModule = __webpack_module_cache__[moduleId];
+/******/ if (cachedModule !== undefined) {
+/******/ return cachedModule.exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = __webpack_module_cache__[moduleId] = {
+/******/ // no module.id needed
+/******/ // no module.loaded needed
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/************************************************************************/
+/******/ /* webpack/runtime/compat get default export */
+/******/ (() => {
+/******/ // getDefaultExport function for compatibility with non-harmony modules
+/******/ __webpack_require__.n = (module) => {
+/******/ var getter = module && module.__esModule ?
+/******/ () => (module['default']) :
+/******/ () => (module);
+/******/ __webpack_require__.d(getter, { a: getter });
+/******/ return getter;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/define property getters */
+/******/ (() => {
+/******/ // define getter functions for harmony exports
+/******/ __webpack_require__.d = (exports, definition) => {
+/******/ for(var key in definition) {
+/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
+/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
+/******/ }
+/******/ }
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/hasOwnProperty shorthand */
+/******/ (() => {
+/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
+/******/ })();
+/******/
+/******/ /* webpack/runtime/make namespace object */
+/******/ (() => {
+/******/ // define __esModule on exports
+/******/ __webpack_require__.r = (exports) => {
+/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+/******/ }
+/******/ Object.defineProperty(exports, '__esModule', { value: true });
+/******/ };
+/******/ })();
+/******/
+/************************************************************************/
+var __webpack_exports__ = {};
+// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
+(() => {
+/*!****************************************!*\
+ !*** ./src/blocks/front-page/index.js ***!
+ \****************************************/
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @wordpress/components */ "@wordpress/components");
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @wordpress/blocks */ "@wordpress/blocks");
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__);
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @wordpress/server-side-render */ "@wordpress/server-side-render");
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__);
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @wordpress/block-editor */ "@wordpress/block-editor");
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__);
+/* harmony import */ var _block_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./block.json */ "./src/blocks/front-page/block.json");
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+function Edit({
+ attributes,
+ name
+}) {
+ return (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)("div", {
+ ...(0,_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__.useBlockProps)()
+ }, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__.Disabled, null, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)((_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default()), {
+ block: name,
+ attributes: attributes
+ })));
+}
+(0,_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__.registerBlockType)(_block_json__WEBPACK_IMPORTED_MODULE_5__.name, {
+ edit: Edit,
+ save: () => null
+});
+})();
+
+/******/ })()
+;
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/plugin-card/index.asset.php b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/plugin-card/index.asset.php
index f1dd1a21c9..b579c818ac 100644
--- a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/plugin-card/index.asset.php
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/plugin-card/index.asset.php
@@ -1 +1 @@
- array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-server-side-render'), 'version' => '58f6f779c22873c960e8');
+ array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-server-side-render'), 'version' => '26ed8b457f67063bbcbe');
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/plugin-card/index.js b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/plugin-card/index.js
index 3f9a8e7de5..77b892a7b3 100644
--- a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/plugin-card/index.js
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/plugin-card/index.js
@@ -1 +1,183 @@
-(()=>{"use strict";var e={n:t=>{var r=t&&t.__esModule?()=>t.default:()=>t;return e.d(r,{a:r}),r},d:(t,r)=>{for(var n in r)e.o(r,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:r[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.React,r=window.wp.components,n=window.wp.blocks,o=window.wp.serverSideRender;var a=e.n(o);const l=window.wp.blockEditor,c=JSON.parse('{"u2":"wporg/plugin-card"}');(0,n.registerBlockType)(c.u2,{edit:function({attributes:e,name:n}){return(0,t.createElement)("div",{...(0,l.useBlockProps)()},(0,t.createElement)(r.Disabled,null,(0,t.createElement)(a(),{block:n,attributes:e})))},save:()=>null})})();
\ No newline at end of file
+/******/ (() => { // webpackBootstrap
+/******/ "use strict";
+/******/ var __webpack_modules__ = ({
+
+/***/ "react":
+/*!************************!*\
+ !*** external "React" ***!
+ \************************/
+/***/ ((module) => {
+
+module.exports = window["React"];
+
+/***/ }),
+
+/***/ "@wordpress/block-editor":
+/*!*************************************!*\
+ !*** external ["wp","blockEditor"] ***!
+ \*************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blockEditor"];
+
+/***/ }),
+
+/***/ "@wordpress/blocks":
+/*!********************************!*\
+ !*** external ["wp","blocks"] ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blocks"];
+
+/***/ }),
+
+/***/ "@wordpress/components":
+/*!************************************!*\
+ !*** external ["wp","components"] ***!
+ \************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["components"];
+
+/***/ }),
+
+/***/ "@wordpress/server-side-render":
+/*!******************************************!*\
+ !*** external ["wp","serverSideRender"] ***!
+ \******************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["serverSideRender"];
+
+/***/ }),
+
+/***/ "./src/blocks/plugin-card/block.json":
+/*!*******************************************!*\
+ !*** ./src/blocks/plugin-card/block.json ***!
+ \*******************************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"wporg/plugin-card","version":"0.1.0","title":"Plugin Card for Archive Pages","category":"design","icon":"","description":"A block that displays a plugin card.","textdomain":"wporg","attributes":{},"supports":{"html":false},"editorScript":"file:./index.js","render":"file:./render.php","viewScript":"file:./view.js"}');
+
+/***/ })
+
+/******/ });
+/************************************************************************/
+/******/ // The module cache
+/******/ var __webpack_module_cache__ = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/ // Check if module is in cache
+/******/ var cachedModule = __webpack_module_cache__[moduleId];
+/******/ if (cachedModule !== undefined) {
+/******/ return cachedModule.exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = __webpack_module_cache__[moduleId] = {
+/******/ // no module.id needed
+/******/ // no module.loaded needed
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/************************************************************************/
+/******/ /* webpack/runtime/compat get default export */
+/******/ (() => {
+/******/ // getDefaultExport function for compatibility with non-harmony modules
+/******/ __webpack_require__.n = (module) => {
+/******/ var getter = module && module.__esModule ?
+/******/ () => (module['default']) :
+/******/ () => (module);
+/******/ __webpack_require__.d(getter, { a: getter });
+/******/ return getter;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/define property getters */
+/******/ (() => {
+/******/ // define getter functions for harmony exports
+/******/ __webpack_require__.d = (exports, definition) => {
+/******/ for(var key in definition) {
+/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
+/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
+/******/ }
+/******/ }
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/hasOwnProperty shorthand */
+/******/ (() => {
+/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
+/******/ })();
+/******/
+/******/ /* webpack/runtime/make namespace object */
+/******/ (() => {
+/******/ // define __esModule on exports
+/******/ __webpack_require__.r = (exports) => {
+/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+/******/ }
+/******/ Object.defineProperty(exports, '__esModule', { value: true });
+/******/ };
+/******/ })();
+/******/
+/************************************************************************/
+var __webpack_exports__ = {};
+// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
+(() => {
+/*!*****************************************!*\
+ !*** ./src/blocks/plugin-card/index.js ***!
+ \*****************************************/
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @wordpress/components */ "@wordpress/components");
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @wordpress/blocks */ "@wordpress/blocks");
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__);
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @wordpress/server-side-render */ "@wordpress/server-side-render");
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__);
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @wordpress/block-editor */ "@wordpress/block-editor");
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__);
+/* harmony import */ var _block_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./block.json */ "./src/blocks/plugin-card/block.json");
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+function Edit({
+ attributes,
+ name
+}) {
+ return (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)("div", {
+ ...(0,_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__.useBlockProps)()
+ }, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__.Disabled, null, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)((_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default()), {
+ block: name,
+ attributes: attributes
+ })));
+}
+(0,_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__.registerBlockType)(_block_json__WEBPACK_IMPORTED_MODULE_5__.name, {
+ edit: Edit,
+ save: () => null
+});
+})();
+
+/******/ })()
+;
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/plugin-card/view.asset.php b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/plugin-card/view.asset.php
index a451d28c8a..1b7e807077 100644
--- a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/plugin-card/view.asset.php
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/plugin-card/view.asset.php
@@ -1 +1 @@
- array(), 'version' => 'f221373b7e38d2ff3d7c');
+ array(), 'version' => 'e27494ba8e1b7f07e282');
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/plugin-card/view.js b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/plugin-card/view.js
index f3234f94de..1d9604facb 100644
--- a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/plugin-card/view.js
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/plugin-card/view.js
@@ -1 +1,36 @@
-document.addEventListener("DOMContentLoaded",(function(){var e=document.querySelectorAll(".plugin-cards li");e&&e.forEach((function(e){e.addEventListener("click",(function(t){var n=window.getSelection().toString();if("a"!==t.target.tagName.toLowerCase()&&""===n){var o=e.querySelector("a");if(o){var r=o.getAttribute("href");window.location.href=r}}}))}))}));
\ No newline at end of file
+/******/ (() => { // webpackBootstrap
+var __webpack_exports__ = {};
+/*!****************************************!*\
+ !*** ./src/blocks/plugin-card/view.js ***!
+ \****************************************/
+/**
+ * Binds click events to navigate on plugin card click.
+ */
+document.addEventListener('DOMContentLoaded', function () {
+ var cards = document.querySelectorAll('.plugin-cards li');
+ if (cards) {
+ cards.forEach(function (card) {
+ card.addEventListener('click', function (event) {
+ var selectedText = window.getSelection().toString();
+
+ // Keep regular anchor tag function
+ if ('a' === event.target.tagName.toLowerCase()) {
+ return;
+ }
+
+ // If they are selecting text, let's not navigate.
+ if ('' !== selectedText) {
+ return;
+ }
+ var anchorTag = card.querySelector('a');
+ if (anchorTag) {
+ var link = anchorTag.getAttribute('href');
+ window.location.href = link;
+ }
+ });
+ });
+ }
+});
+/******/ })()
+;
+//# sourceMappingURL=view.js.map
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-checks/block.json b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-checks/block.json
new file mode 100644
index 0000000000..6bafea2d48
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-checks/block.json
@@ -0,0 +1,21 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 2,
+ "name": "wporg/release-checks",
+ "version": "0.1.0",
+ "title": "Release checks.",
+ "category": "design",
+ "icon": "",
+ "description": "A block to display release checks.",
+ "textdomain": "wporg",
+ "attributes": {},
+ "supports": {
+ "html": false
+ },
+ "usesContext": [
+ "postId"
+ ],
+ "editorScript": "file:./index.js",
+ "render": "file:./render.php",
+ "style": "file:./style-index.css"
+}
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-checks/index.asset.php b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-checks/index.asset.php
new file mode 100644
index 0000000000..a727359a89
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-checks/index.asset.php
@@ -0,0 +1 @@
+ array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-server-side-render'), 'version' => 'e264093d240f158ddead');
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-checks/index.js b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-checks/index.js
new file mode 100644
index 0000000000..406f7ccc3c
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-checks/index.js
@@ -0,0 +1,298 @@
+/******/ (() => { // webpackBootstrap
+/******/ "use strict";
+/******/ var __webpack_modules__ = ({
+
+/***/ "./src/blocks/release-checks/index.js":
+/*!********************************************!*\
+ !*** ./src/blocks/release-checks/index.js ***!
+ \********************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @wordpress/components */ "@wordpress/components");
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @wordpress/blocks */ "@wordpress/blocks");
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__);
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @wordpress/server-side-render */ "@wordpress/server-side-render");
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__);
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @wordpress/block-editor */ "@wordpress/block-editor");
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__);
+/* harmony import */ var _block_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./block.json */ "./src/blocks/release-checks/block.json");
+/* harmony import */ var _style_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./style.scss */ "./src/blocks/release-checks/style.scss");
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+function Edit({
+ attributes,
+ name
+}) {
+ return (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)("div", {
+ ...(0,_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__.useBlockProps)()
+ }, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__.Disabled, null, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)((_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default()), {
+ block: name,
+ attributes: attributes
+ })));
+}
+(0,_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__.registerBlockType)(_block_json__WEBPACK_IMPORTED_MODULE_5__.name, {
+ edit: Edit,
+ save: () => null
+});
+
+/***/ }),
+
+/***/ "./src/blocks/release-checks/style.scss":
+/*!**********************************************!*\
+ !*** ./src/blocks/release-checks/style.scss ***!
+ \**********************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+__webpack_require__.r(__webpack_exports__);
+// extracted by mini-css-extract-plugin
+
+
+/***/ }),
+
+/***/ "react":
+/*!************************!*\
+ !*** external "React" ***!
+ \************************/
+/***/ ((module) => {
+
+module.exports = window["React"];
+
+/***/ }),
+
+/***/ "@wordpress/block-editor":
+/*!*************************************!*\
+ !*** external ["wp","blockEditor"] ***!
+ \*************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blockEditor"];
+
+/***/ }),
+
+/***/ "@wordpress/blocks":
+/*!********************************!*\
+ !*** external ["wp","blocks"] ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blocks"];
+
+/***/ }),
+
+/***/ "@wordpress/components":
+/*!************************************!*\
+ !*** external ["wp","components"] ***!
+ \************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["components"];
+
+/***/ }),
+
+/***/ "@wordpress/server-side-render":
+/*!******************************************!*\
+ !*** external ["wp","serverSideRender"] ***!
+ \******************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["serverSideRender"];
+
+/***/ }),
+
+/***/ "./src/blocks/release-checks/block.json":
+/*!**********************************************!*\
+ !*** ./src/blocks/release-checks/block.json ***!
+ \**********************************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"wporg/release-checks","version":"0.1.0","title":"Release checks.","category":"design","icon":"","description":"A block to display release checks.","textdomain":"wporg","attributes":{},"supports":{"html":false},"usesContext":["postId"],"editorScript":"file:./index.js","render":"file:./render.php","style":"file:./style-index.css"}');
+
+/***/ })
+
+/******/ });
+/************************************************************************/
+/******/ // The module cache
+/******/ var __webpack_module_cache__ = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/ // Check if module is in cache
+/******/ var cachedModule = __webpack_module_cache__[moduleId];
+/******/ if (cachedModule !== undefined) {
+/******/ return cachedModule.exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = __webpack_module_cache__[moduleId] = {
+/******/ // no module.id needed
+/******/ // no module.loaded needed
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = __webpack_modules__;
+/******/
+/************************************************************************/
+/******/ /* webpack/runtime/chunk loaded */
+/******/ (() => {
+/******/ var deferred = [];
+/******/ __webpack_require__.O = (result, chunkIds, fn, priority) => {
+/******/ if(chunkIds) {
+/******/ priority = priority || 0;
+/******/ for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];
+/******/ deferred[i] = [chunkIds, fn, priority];
+/******/ return;
+/******/ }
+/******/ var notFulfilled = Infinity;
+/******/ for (var i = 0; i < deferred.length; i++) {
+/******/ var chunkIds = deferred[i][0];
+/******/ var fn = deferred[i][1];
+/******/ var priority = deferred[i][2];
+/******/ var fulfilled = true;
+/******/ for (var j = 0; j < chunkIds.length; j++) {
+/******/ if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {
+/******/ chunkIds.splice(j--, 1);
+/******/ } else {
+/******/ fulfilled = false;
+/******/ if(priority < notFulfilled) notFulfilled = priority;
+/******/ }
+/******/ }
+/******/ if(fulfilled) {
+/******/ deferred.splice(i--, 1)
+/******/ var r = fn();
+/******/ if (r !== undefined) result = r;
+/******/ }
+/******/ }
+/******/ return result;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/compat get default export */
+/******/ (() => {
+/******/ // getDefaultExport function for compatibility with non-harmony modules
+/******/ __webpack_require__.n = (module) => {
+/******/ var getter = module && module.__esModule ?
+/******/ () => (module['default']) :
+/******/ () => (module);
+/******/ __webpack_require__.d(getter, { a: getter });
+/******/ return getter;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/define property getters */
+/******/ (() => {
+/******/ // define getter functions for harmony exports
+/******/ __webpack_require__.d = (exports, definition) => {
+/******/ for(var key in definition) {
+/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
+/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
+/******/ }
+/******/ }
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/hasOwnProperty shorthand */
+/******/ (() => {
+/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
+/******/ })();
+/******/
+/******/ /* webpack/runtime/make namespace object */
+/******/ (() => {
+/******/ // define __esModule on exports
+/******/ __webpack_require__.r = (exports) => {
+/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+/******/ }
+/******/ Object.defineProperty(exports, '__esModule', { value: true });
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/jsonp chunk loading */
+/******/ (() => {
+/******/ // no baseURI
+/******/
+/******/ // object to store loaded and loading chunks
+/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
+/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
+/******/ var installedChunks = {
+/******/ "blocks/release-checks/index": 0,
+/******/ "blocks/release-checks/style-index": 0
+/******/ };
+/******/
+/******/ // no chunk on demand loading
+/******/
+/******/ // no prefetching
+/******/
+/******/ // no preloaded
+/******/
+/******/ // no HMR
+/******/
+/******/ // no HMR manifest
+/******/
+/******/ __webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);
+/******/
+/******/ // install a JSONP callback for chunk loading
+/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
+/******/ var chunkIds = data[0];
+/******/ var moreModules = data[1];
+/******/ var runtime = data[2];
+/******/ // add "moreModules" to the modules object,
+/******/ // then flag all "chunkIds" as loaded and fire callback
+/******/ var moduleId, chunkId, i = 0;
+/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
+/******/ for(moduleId in moreModules) {
+/******/ if(__webpack_require__.o(moreModules, moduleId)) {
+/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
+/******/ }
+/******/ }
+/******/ if(runtime) var result = runtime(__webpack_require__);
+/******/ }
+/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
+/******/ for(;i < chunkIds.length; i++) {
+/******/ chunkId = chunkIds[i];
+/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
+/******/ installedChunks[chunkId][0]();
+/******/ }
+/******/ installedChunks[chunkId] = 0;
+/******/ }
+/******/ return __webpack_require__.O(result);
+/******/ }
+/******/
+/******/ var chunkLoadingGlobal = self["webpackChunkwporg_plugins_2024"] = self["webpackChunkwporg_plugins_2024"] || [];
+/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
+/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
+/******/ })();
+/******/
+/************************************************************************/
+/******/
+/******/ // startup
+/******/ // Load entry module and return exports
+/******/ // This entry module depends on other loaded chunks and execution need to be delayed
+/******/ var __webpack_exports__ = __webpack_require__.O(undefined, ["blocks/release-checks/style-index"], () => (__webpack_require__("./src/blocks/release-checks/index.js")))
+/******/ __webpack_exports__ = __webpack_require__.O(__webpack_exports__);
+/******/
+/******/ })()
+;
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-checks/render.php b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-checks/render.php
new file mode 100644
index 0000000000..6e857fea12
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-checks/render.php
@@ -0,0 +1,77 @@
+context['postId'] ) ) {
+ return;
+}
+
+$plugin_check_errors = get_post_meta( get_post( $block->context['postId'] )->ID, 'plugin_check_result', true );
+
+$heading = sprintf(
+ '
+ %s
+ ',
+ esc_html__( 'Checks', 'wporg-plugins' )
+);
+
+echo do_blocks( $heading ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+
+if ( empty( $plugin_check_errors ) ) {
+ printf(
+ '%s
',
+ esc_html__( 'No checks were run.', 'wporg-plugins' )
+ );
+ return;
+}
+
+// Warnings are currently associated to the plugin post, not the release post.
+$import_warnings = get_post_meta( get_plugin()->ID, '_import_warnings', true );
+
+// Merge in warnings into the plugin check errors.
+if ( ! empty( $import_warnings ) && ! wp_is_numeric_array( $import_warnings ) ) {
+
+ foreach ( $import_warnings as $error_code => $error_data ) {
+
+ // These warnings exist because they haven't release it.
+ // TODO: Remove the logic that sets those warnings.
+ if ( in_array( $error_code, array( 'stable_tag_invalid_trunk_fallback', 'stable_tag_invalid' ), true ) ) {
+ continue;
+ }
+
+ $plugin_check_errors['results'][] = array(
+ 'line' => 0,
+ 'column' => 0,
+ 'type' => 'WARNING',
+ 'code' => $error_code,
+ 'message' => Readme_Validator::instance()->translate_code_to_message( $error_code, $error_data ),
+ 'file' => 'readme.txt',
+ );
+
+ $plugin_check_errors['verdict'] = false;
+ }
+}
+
+// Create a block with the overall status.
+$blocks = sprintf(
+ '%2$s',
+ $plugin_check_errors['verdict'] ? 'success' : 'warning',
+ get_test_run_message( $plugin_check_errors )
+);
+
+printf(
+ '',
+ wp_kses_data( get_block_wrapper_attributes() ),
+ do_blocks( $blocks ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+);
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-checks/style-index.css b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-checks/style-index.css
new file mode 100644
index 0000000000..a88dbe5a66
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-checks/style-index.css
@@ -0,0 +1,23 @@
+/*!*************************************************************************************************************************************************************************************************************************************************************!*\
+ !*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[4].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[4].use[2]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[4].use[3]!./src/blocks/release-checks/style.scss ***!
+ \*************************************************************************************************************************************************************************************************************************************************************/
+.wp-block-wporg-release-checks {
+ padding: 0;
+}
+.wp-block-wporg-release-checks .wp-block-heading {
+ font-size: var(--wp--preset--font-size--small);
+}
+
+.wp-block-wporg-release-checks-results {
+ list-style: none;
+ padding-left: 12px;
+ border-left: 4px solid var(--wp--preset--color--light-grey-1);
+}
+.wp-block-wporg-release-checks-results li ul {
+ list-style: disc;
+}
+.wp-block-wporg-release-checks-results li:not(:last-child) {
+ margin-bottom: 8px;
+}
+
+/*# sourceMappingURL=style-index.css.map*/
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-commits/block.json b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-commits/block.json
new file mode 100644
index 0000000000..a4a2c00385
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-commits/block.json
@@ -0,0 +1,21 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 2,
+ "name": "wporg/release-commits",
+ "version": "0.1.0",
+ "title": "Release Commits",
+ "category": "design",
+ "icon": "",
+ "description": "A block to display release commits.",
+ "textdomain": "wporg",
+ "attributes": {},
+ "supports": {
+ "html": false
+ },
+ "usesContext": [
+ "postId"
+ ],
+ "editorScript": "file:./index.js",
+ "render": "file:./render.php",
+ "style": "file:./style-index.css"
+}
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-commits/index.asset.php b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-commits/index.asset.php
new file mode 100644
index 0000000000..c7ee00d1f1
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-commits/index.asset.php
@@ -0,0 +1 @@
+ array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-server-side-render'), 'version' => '5b31c659da768cc49abf');
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-commits/index.js b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-commits/index.js
new file mode 100644
index 0000000000..5b053c073b
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-commits/index.js
@@ -0,0 +1,298 @@
+/******/ (() => { // webpackBootstrap
+/******/ "use strict";
+/******/ var __webpack_modules__ = ({
+
+/***/ "./src/blocks/release-commits/index.js":
+/*!*********************************************!*\
+ !*** ./src/blocks/release-commits/index.js ***!
+ \*********************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @wordpress/components */ "@wordpress/components");
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @wordpress/blocks */ "@wordpress/blocks");
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__);
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @wordpress/server-side-render */ "@wordpress/server-side-render");
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__);
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @wordpress/block-editor */ "@wordpress/block-editor");
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__);
+/* harmony import */ var _block_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./block.json */ "./src/blocks/release-commits/block.json");
+/* harmony import */ var _style_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./style.scss */ "./src/blocks/release-commits/style.scss");
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+function Edit({
+ attributes,
+ name
+}) {
+ return (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)("div", {
+ ...(0,_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__.useBlockProps)()
+ }, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__.Disabled, null, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)((_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default()), {
+ block: name,
+ attributes: attributes
+ })));
+}
+(0,_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__.registerBlockType)(_block_json__WEBPACK_IMPORTED_MODULE_5__.name, {
+ edit: Edit,
+ save: () => null
+});
+
+/***/ }),
+
+/***/ "./src/blocks/release-commits/style.scss":
+/*!***********************************************!*\
+ !*** ./src/blocks/release-commits/style.scss ***!
+ \***********************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+__webpack_require__.r(__webpack_exports__);
+// extracted by mini-css-extract-plugin
+
+
+/***/ }),
+
+/***/ "react":
+/*!************************!*\
+ !*** external "React" ***!
+ \************************/
+/***/ ((module) => {
+
+module.exports = window["React"];
+
+/***/ }),
+
+/***/ "@wordpress/block-editor":
+/*!*************************************!*\
+ !*** external ["wp","blockEditor"] ***!
+ \*************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blockEditor"];
+
+/***/ }),
+
+/***/ "@wordpress/blocks":
+/*!********************************!*\
+ !*** external ["wp","blocks"] ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blocks"];
+
+/***/ }),
+
+/***/ "@wordpress/components":
+/*!************************************!*\
+ !*** external ["wp","components"] ***!
+ \************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["components"];
+
+/***/ }),
+
+/***/ "@wordpress/server-side-render":
+/*!******************************************!*\
+ !*** external ["wp","serverSideRender"] ***!
+ \******************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["serverSideRender"];
+
+/***/ }),
+
+/***/ "./src/blocks/release-commits/block.json":
+/*!***********************************************!*\
+ !*** ./src/blocks/release-commits/block.json ***!
+ \***********************************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"wporg/release-commits","version":"0.1.0","title":"Release Commits","category":"design","icon":"","description":"A block to display release commits.","textdomain":"wporg","attributes":{},"supports":{"html":false},"usesContext":["postId"],"editorScript":"file:./index.js","render":"file:./render.php","style":"file:./style-index.css"}');
+
+/***/ })
+
+/******/ });
+/************************************************************************/
+/******/ // The module cache
+/******/ var __webpack_module_cache__ = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/ // Check if module is in cache
+/******/ var cachedModule = __webpack_module_cache__[moduleId];
+/******/ if (cachedModule !== undefined) {
+/******/ return cachedModule.exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = __webpack_module_cache__[moduleId] = {
+/******/ // no module.id needed
+/******/ // no module.loaded needed
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = __webpack_modules__;
+/******/
+/************************************************************************/
+/******/ /* webpack/runtime/chunk loaded */
+/******/ (() => {
+/******/ var deferred = [];
+/******/ __webpack_require__.O = (result, chunkIds, fn, priority) => {
+/******/ if(chunkIds) {
+/******/ priority = priority || 0;
+/******/ for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];
+/******/ deferred[i] = [chunkIds, fn, priority];
+/******/ return;
+/******/ }
+/******/ var notFulfilled = Infinity;
+/******/ for (var i = 0; i < deferred.length; i++) {
+/******/ var chunkIds = deferred[i][0];
+/******/ var fn = deferred[i][1];
+/******/ var priority = deferred[i][2];
+/******/ var fulfilled = true;
+/******/ for (var j = 0; j < chunkIds.length; j++) {
+/******/ if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {
+/******/ chunkIds.splice(j--, 1);
+/******/ } else {
+/******/ fulfilled = false;
+/******/ if(priority < notFulfilled) notFulfilled = priority;
+/******/ }
+/******/ }
+/******/ if(fulfilled) {
+/******/ deferred.splice(i--, 1)
+/******/ var r = fn();
+/******/ if (r !== undefined) result = r;
+/******/ }
+/******/ }
+/******/ return result;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/compat get default export */
+/******/ (() => {
+/******/ // getDefaultExport function for compatibility with non-harmony modules
+/******/ __webpack_require__.n = (module) => {
+/******/ var getter = module && module.__esModule ?
+/******/ () => (module['default']) :
+/******/ () => (module);
+/******/ __webpack_require__.d(getter, { a: getter });
+/******/ return getter;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/define property getters */
+/******/ (() => {
+/******/ // define getter functions for harmony exports
+/******/ __webpack_require__.d = (exports, definition) => {
+/******/ for(var key in definition) {
+/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
+/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
+/******/ }
+/******/ }
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/hasOwnProperty shorthand */
+/******/ (() => {
+/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
+/******/ })();
+/******/
+/******/ /* webpack/runtime/make namespace object */
+/******/ (() => {
+/******/ // define __esModule on exports
+/******/ __webpack_require__.r = (exports) => {
+/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+/******/ }
+/******/ Object.defineProperty(exports, '__esModule', { value: true });
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/jsonp chunk loading */
+/******/ (() => {
+/******/ // no baseURI
+/******/
+/******/ // object to store loaded and loading chunks
+/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
+/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
+/******/ var installedChunks = {
+/******/ "blocks/release-commits/index": 0,
+/******/ "blocks/release-commits/style-index": 0
+/******/ };
+/******/
+/******/ // no chunk on demand loading
+/******/
+/******/ // no prefetching
+/******/
+/******/ // no preloaded
+/******/
+/******/ // no HMR
+/******/
+/******/ // no HMR manifest
+/******/
+/******/ __webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);
+/******/
+/******/ // install a JSONP callback for chunk loading
+/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
+/******/ var chunkIds = data[0];
+/******/ var moreModules = data[1];
+/******/ var runtime = data[2];
+/******/ // add "moreModules" to the modules object,
+/******/ // then flag all "chunkIds" as loaded and fire callback
+/******/ var moduleId, chunkId, i = 0;
+/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
+/******/ for(moduleId in moreModules) {
+/******/ if(__webpack_require__.o(moreModules, moduleId)) {
+/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
+/******/ }
+/******/ }
+/******/ if(runtime) var result = runtime(__webpack_require__);
+/******/ }
+/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
+/******/ for(;i < chunkIds.length; i++) {
+/******/ chunkId = chunkIds[i];
+/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
+/******/ installedChunks[chunkId][0]();
+/******/ }
+/******/ installedChunks[chunkId] = 0;
+/******/ }
+/******/ return __webpack_require__.O(result);
+/******/ }
+/******/
+/******/ var chunkLoadingGlobal = self["webpackChunkwporg_plugins_2024"] = self["webpackChunkwporg_plugins_2024"] || [];
+/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
+/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
+/******/ })();
+/******/
+/************************************************************************/
+/******/
+/******/ // startup
+/******/ // Load entry module and return exports
+/******/ // This entry module depends on other loaded chunks and execution need to be delayed
+/******/ var __webpack_exports__ = __webpack_require__.O(undefined, ["blocks/release-commits/style-index"], () => (__webpack_require__("./src/blocks/release-commits/index.js")))
+/******/ __webpack_exports__ = __webpack_require__.O(__webpack_exports__);
+/******/
+/******/ })()
+;
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-commits/render.php b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-commits/render.php
new file mode 100644
index 0000000000..b2c21872af
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-commits/render.php
@@ -0,0 +1,99 @@
+context['postId'] ) {
+ return;
+}
+
+$commits = get_post_meta( $block->context['postId'], 'release_commit_log', true );
+
+if ( empty( $commits ) ) {
+ return '' . __( 'No commits found.', 'wporg-plugins' ) . '
';
+}
+
+// Newest commits first.
+usort(
+ $commits,
+ function ( $a, $b ) {
+ return $b['date'] <=> $a['date'];
+ }
+);
+
+$maximum_commits = 5;
+$sliced_commits = array_slice( $commits, 0, $maximum_commits );
+
+?>
+
+>
+
+
%s
+ ',
+ esc_attr__( 'Commits', 'wporg-plugins' )
+ );
+
+ echo do_blocks( $heading ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+
+ ?>
+
+
+
+ -
+
+ %2$s',
+ esc_url(
+ sprintf(
+ 'https://plugins.trac.wordpress.org/changeset/%1$s/%2$s/trunk',
+ $commit['revision'],
+ get_plugin_slug()
+ )
+ ),
+ esc_html( wp_trim_words( $commit['message'], 7 ) )
+ );
+ ?>
+
+
+
+ %2$s',
+ esc_url( 'https://profiles.wordpress.org/' . $user->user_nicename ),
+ esc_html( $user->display_name )
+ )
+ );
+ ?>
+
+
+
+
+ $maximum_commits ) : ?>
+ -
+
+
+
+
+
+
+
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-commits/style-index.css b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-commits/style-index.css
new file mode 100644
index 0000000000..8b6945b2b8
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-commits/style-index.css
@@ -0,0 +1,44 @@
+/*!**************************************************************************************************************************************************************************************************************************************************************!*\
+ !*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[4].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[4].use[2]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[4].use[3]!./src/blocks/release-commits/style.scss ***!
+ \**************************************************************************************************************************************************************************************************************************************************************/
+.wp-block-wporg-release-commits {
+ margin-top: 0 !important;
+}
+
+.wp-block-wporg-release-commit-list {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ list-style: none;
+ padding: 0;
+}
+.wp-block-wporg-release-commit-list li {
+ display: flex;
+ flex-direction: column;
+ gap: inherit;
+ margin-bottom: var(--wp--preset--spacing--10);
+}
+@media (min-width: 650px) {
+ .wp-block-wporg-release-commit-list li {
+ flex-direction: row;
+ align-items: center;
+ margin-bottom: 0;
+ }
+}
+
+.wp-block-wporg-release-commit-author {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-weight: 500;
+}
+
+.wp-block-wporg-release-commit-by-line {
+ color: var(--wp--preset--color--charcoal-4) !important;
+ font-size: 12px;
+}
+.wp-block-wporg-release-commit-by-line a {
+ color: var(--wp--preset--color--charcoal-4) !important;
+}
+
+/*# sourceMappingURL=style-index.css.map*/
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-draft/block.json b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-draft/block.json
new file mode 100644
index 0000000000..c7b597f270
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-draft/block.json
@@ -0,0 +1,22 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 2,
+ "name": "wporg/release-draft",
+ "version": "0.1.0",
+ "title": "Release Draft",
+ "category": "design",
+ "icon": "",
+ "description": "A block to display release draft.",
+ "textdomain": "wporg",
+ "attributes": {},
+ "supports": {
+ "html": false,
+ "interactivity": true
+ },
+ "usesContext": [
+ "postId"
+ ],
+ "editorScript": "file:./index.js",
+ "render": "file:./render.php",
+ "style": "file:./style-index.css"
+}
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-draft/index.asset.php b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-draft/index.asset.php
new file mode 100644
index 0000000000..12b7e1303a
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-draft/index.asset.php
@@ -0,0 +1 @@
+ array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-server-side-render'), 'version' => '4e12b6eb8d27834cbced');
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-draft/index.js b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-draft/index.js
new file mode 100644
index 0000000000..8eecd7890d
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-draft/index.js
@@ -0,0 +1,298 @@
+/******/ (() => { // webpackBootstrap
+/******/ "use strict";
+/******/ var __webpack_modules__ = ({
+
+/***/ "./src/blocks/release-draft/index.js":
+/*!*******************************************!*\
+ !*** ./src/blocks/release-draft/index.js ***!
+ \*******************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @wordpress/components */ "@wordpress/components");
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @wordpress/blocks */ "@wordpress/blocks");
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__);
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @wordpress/server-side-render */ "@wordpress/server-side-render");
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__);
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @wordpress/block-editor */ "@wordpress/block-editor");
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__);
+/* harmony import */ var _block_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./block.json */ "./src/blocks/release-draft/block.json");
+/* harmony import */ var _style_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./style.scss */ "./src/blocks/release-draft/style.scss");
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+function Edit({
+ attributes,
+ name
+}) {
+ return (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)("div", {
+ ...(0,_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__.useBlockProps)()
+ }, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__.Disabled, null, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)((_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default()), {
+ block: name,
+ attributes: attributes
+ })));
+}
+(0,_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__.registerBlockType)(_block_json__WEBPACK_IMPORTED_MODULE_5__.name, {
+ edit: Edit,
+ save: () => null
+});
+
+/***/ }),
+
+/***/ "./src/blocks/release-draft/style.scss":
+/*!*********************************************!*\
+ !*** ./src/blocks/release-draft/style.scss ***!
+ \*********************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+__webpack_require__.r(__webpack_exports__);
+// extracted by mini-css-extract-plugin
+
+
+/***/ }),
+
+/***/ "react":
+/*!************************!*\
+ !*** external "React" ***!
+ \************************/
+/***/ ((module) => {
+
+module.exports = window["React"];
+
+/***/ }),
+
+/***/ "@wordpress/block-editor":
+/*!*************************************!*\
+ !*** external ["wp","blockEditor"] ***!
+ \*************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blockEditor"];
+
+/***/ }),
+
+/***/ "@wordpress/blocks":
+/*!********************************!*\
+ !*** external ["wp","blocks"] ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blocks"];
+
+/***/ }),
+
+/***/ "@wordpress/components":
+/*!************************************!*\
+ !*** external ["wp","components"] ***!
+ \************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["components"];
+
+/***/ }),
+
+/***/ "@wordpress/server-side-render":
+/*!******************************************!*\
+ !*** external ["wp","serverSideRender"] ***!
+ \******************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["serverSideRender"];
+
+/***/ }),
+
+/***/ "./src/blocks/release-draft/block.json":
+/*!*********************************************!*\
+ !*** ./src/blocks/release-draft/block.json ***!
+ \*********************************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"wporg/release-draft","version":"0.1.0","title":"Release Draft","category":"design","icon":"","description":"A block to display release draft.","textdomain":"wporg","attributes":{},"supports":{"html":false,"interactivity":true},"usesContext":["postId"],"editorScript":"file:./index.js","render":"file:./render.php","style":"file:./style-index.css"}');
+
+/***/ })
+
+/******/ });
+/************************************************************************/
+/******/ // The module cache
+/******/ var __webpack_module_cache__ = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/ // Check if module is in cache
+/******/ var cachedModule = __webpack_module_cache__[moduleId];
+/******/ if (cachedModule !== undefined) {
+/******/ return cachedModule.exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = __webpack_module_cache__[moduleId] = {
+/******/ // no module.id needed
+/******/ // no module.loaded needed
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = __webpack_modules__;
+/******/
+/************************************************************************/
+/******/ /* webpack/runtime/chunk loaded */
+/******/ (() => {
+/******/ var deferred = [];
+/******/ __webpack_require__.O = (result, chunkIds, fn, priority) => {
+/******/ if(chunkIds) {
+/******/ priority = priority || 0;
+/******/ for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];
+/******/ deferred[i] = [chunkIds, fn, priority];
+/******/ return;
+/******/ }
+/******/ var notFulfilled = Infinity;
+/******/ for (var i = 0; i < deferred.length; i++) {
+/******/ var chunkIds = deferred[i][0];
+/******/ var fn = deferred[i][1];
+/******/ var priority = deferred[i][2];
+/******/ var fulfilled = true;
+/******/ for (var j = 0; j < chunkIds.length; j++) {
+/******/ if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {
+/******/ chunkIds.splice(j--, 1);
+/******/ } else {
+/******/ fulfilled = false;
+/******/ if(priority < notFulfilled) notFulfilled = priority;
+/******/ }
+/******/ }
+/******/ if(fulfilled) {
+/******/ deferred.splice(i--, 1)
+/******/ var r = fn();
+/******/ if (r !== undefined) result = r;
+/******/ }
+/******/ }
+/******/ return result;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/compat get default export */
+/******/ (() => {
+/******/ // getDefaultExport function for compatibility with non-harmony modules
+/******/ __webpack_require__.n = (module) => {
+/******/ var getter = module && module.__esModule ?
+/******/ () => (module['default']) :
+/******/ () => (module);
+/******/ __webpack_require__.d(getter, { a: getter });
+/******/ return getter;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/define property getters */
+/******/ (() => {
+/******/ // define getter functions for harmony exports
+/******/ __webpack_require__.d = (exports, definition) => {
+/******/ for(var key in definition) {
+/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
+/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
+/******/ }
+/******/ }
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/hasOwnProperty shorthand */
+/******/ (() => {
+/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
+/******/ })();
+/******/
+/******/ /* webpack/runtime/make namespace object */
+/******/ (() => {
+/******/ // define __esModule on exports
+/******/ __webpack_require__.r = (exports) => {
+/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+/******/ }
+/******/ Object.defineProperty(exports, '__esModule', { value: true });
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/jsonp chunk loading */
+/******/ (() => {
+/******/ // no baseURI
+/******/
+/******/ // object to store loaded and loading chunks
+/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
+/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
+/******/ var installedChunks = {
+/******/ "blocks/release-draft/index": 0,
+/******/ "blocks/release-draft/style-index": 0
+/******/ };
+/******/
+/******/ // no chunk on demand loading
+/******/
+/******/ // no prefetching
+/******/
+/******/ // no preloaded
+/******/
+/******/ // no HMR
+/******/
+/******/ // no HMR manifest
+/******/
+/******/ __webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);
+/******/
+/******/ // install a JSONP callback for chunk loading
+/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
+/******/ var chunkIds = data[0];
+/******/ var moreModules = data[1];
+/******/ var runtime = data[2];
+/******/ // add "moreModules" to the modules object,
+/******/ // then flag all "chunkIds" as loaded and fire callback
+/******/ var moduleId, chunkId, i = 0;
+/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
+/******/ for(moduleId in moreModules) {
+/******/ if(__webpack_require__.o(moreModules, moduleId)) {
+/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
+/******/ }
+/******/ }
+/******/ if(runtime) var result = runtime(__webpack_require__);
+/******/ }
+/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
+/******/ for(;i < chunkIds.length; i++) {
+/******/ chunkId = chunkIds[i];
+/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
+/******/ installedChunks[chunkId][0]();
+/******/ }
+/******/ installedChunks[chunkId] = 0;
+/******/ }
+/******/ return __webpack_require__.O(result);
+/******/ }
+/******/
+/******/ var chunkLoadingGlobal = self["webpackChunkwporg_plugins_2024"] = self["webpackChunkwporg_plugins_2024"] || [];
+/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
+/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
+/******/ })();
+/******/
+/************************************************************************/
+/******/
+/******/ // startup
+/******/ // Load entry module and return exports
+/******/ // This entry module depends on other loaded chunks and execution need to be delayed
+/******/ var __webpack_exports__ = __webpack_require__.O(undefined, ["blocks/release-draft/style-index"], () => (__webpack_require__("./src/blocks/release-draft/index.js")))
+/******/ __webpack_exports__ = __webpack_require__.O(__webpack_exports__);
+/******/
+/******/ })()
+;
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-draft/render.php b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-draft/render.php
new file mode 100644
index 0000000000..4ed83f3baa
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-draft/render.php
@@ -0,0 +1,99 @@
+context['postId'] ) {
+ return;
+}
+
+$plugin_post = get_post( $block->context['postId'] );
+
+if ( ! $plugin_post ) {
+ return;
+}
+
+/**
+ * We are in the context of the plugin post, so we can query for the latest draft post.
+ */
+$query_args = array(
+ 'post_type' => 'plugin_release',
+ 'posts_per_page' => 1,
+ 'post_parent' => $plugin_post->ID,
+ 'orderby' => 'date',
+ 'post_status' => 'draft',
+ 'order' => 'DESC',
+);
+
+$latest_draft_query = new WP_Query( $query_args );
+
+if ( ! $latest_draft_query->have_posts() ) {
+ return;
+}
+
+
+
+// Fetch the latest draft post.
+$latest_draft_query->the_post();
+
+$new_version = get_post_meta( get_the_ID(), 'release_version', true );
+
+$publish_text = __( 'Create release', 'wporg-plugins' );
+$slug = get_plugin_slug();
+$intro_text = sprintf(
+ /* translators: %s: URL to the plugin's trunk folder */
+ __( 'There are unpublished changes in your trunk folder.', 'wporg-plugins' ),
+ esc_url( "https://plugins.trac.wordpress.org/browser/{$slug}/" )
+);
+$post_title = sprintf(
+ /* translators: %s: Plugin version number */
+ __( 'Trunk (v.%s)', 'wporg-plugins' ),
+ esc_html( $new_version )
+);
+
+$markup = <<
+
+
+ $intro_text
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+HTML;
+
+printf(
+ '%3$s
',
+ 'data-wp-interactive="wporg/publish-draft"',
+ wp_kses_data( get_block_wrapper_attributes() ),
+ do_blocks( $markup ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+);
+
+// Reset global post data.
+wp_reset_postdata();
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-draft/style-index.css b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-draft/style-index.css
new file mode 100644
index 0000000000..581067214d
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-draft/style-index.css
@@ -0,0 +1,9 @@
+/*!************************************************************************************************************************************************************************************************************************************************************!*\
+ !*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[4].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[4].use[2]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[4].use[3]!./src/blocks/release-draft/style.scss ***!
+ \************************************************************************************************************************************************************************************************************************************************************/
+.wp-block-wporg-release-draft {
+ margin-bottom: var(--wp--preset--spacing--20);
+ font-size: var(--wp--preset--font-size--small);
+}
+
+/*# sourceMappingURL=style-index.css.map*/
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-menu-options/block.json b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-menu-options/block.json
new file mode 100644
index 0000000000..7d0cdd57cf
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-menu-options/block.json
@@ -0,0 +1,18 @@
+{
+ "apiVersion": 2,
+ "name": "wporg/release-menu-options",
+ "title": "Release Menu Options",
+ "category": "widgets",
+ "icon": "menu",
+ "description": "Display the dropdown menu option for a release.",
+ "supports": {
+ "html": false
+ },
+ "usesContext": [
+ "postId"
+ ],
+ "textdomain": "wporg",
+ "editorScript": "file:./index.js",
+ "style": "file:./style-index.css",
+ "render": "file:./render.php"
+}
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-menu-options/index.asset.php b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-menu-options/index.asset.php
new file mode 100644
index 0000000000..77921bd0a1
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-menu-options/index.asset.php
@@ -0,0 +1 @@
+ array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-server-side-render'), 'version' => 'a82fb3da1323cd72755b');
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-menu-options/index.js b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-menu-options/index.js
new file mode 100644
index 0000000000..ec4a594e7e
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-menu-options/index.js
@@ -0,0 +1,298 @@
+/******/ (() => { // webpackBootstrap
+/******/ "use strict";
+/******/ var __webpack_modules__ = ({
+
+/***/ "./src/blocks/release-menu-options/index.js":
+/*!**************************************************!*\
+ !*** ./src/blocks/release-menu-options/index.js ***!
+ \**************************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @wordpress/components */ "@wordpress/components");
+/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @wordpress/blocks */ "@wordpress/blocks");
+/* harmony import */ var _wordpress_blocks__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__);
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @wordpress/server-side-render */ "@wordpress/server-side-render");
+/* harmony import */ var _wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3__);
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @wordpress/block-editor */ "@wordpress/block-editor");
+/* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__);
+/* harmony import */ var _block_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./block.json */ "./src/blocks/release-menu-options/block.json");
+/* harmony import */ var _style_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./style.scss */ "./src/blocks/release-menu-options/style.scss");
+
+/**
+ * WordPress dependencies
+ */
+
+
+
+
+
+/**
+ * Internal dependencies
+ */
+
+
+function Edit({
+ attributes,
+ name
+}) {
+ return (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)("div", {
+ ...(0,_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_4__.useBlockProps)()
+ }, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__.Disabled, null, (0,react__WEBPACK_IMPORTED_MODULE_0__.createElement)((_wordpress_server_side_render__WEBPACK_IMPORTED_MODULE_3___default()), {
+ block: name,
+ attributes: attributes
+ })));
+}
+(0,_wordpress_blocks__WEBPACK_IMPORTED_MODULE_2__.registerBlockType)(_block_json__WEBPACK_IMPORTED_MODULE_5__.name, {
+ edit: Edit,
+ save: () => null
+});
+
+/***/ }),
+
+/***/ "./src/blocks/release-menu-options/style.scss":
+/*!****************************************************!*\
+ !*** ./src/blocks/release-menu-options/style.scss ***!
+ \****************************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+__webpack_require__.r(__webpack_exports__);
+// extracted by mini-css-extract-plugin
+
+
+/***/ }),
+
+/***/ "react":
+/*!************************!*\
+ !*** external "React" ***!
+ \************************/
+/***/ ((module) => {
+
+module.exports = window["React"];
+
+/***/ }),
+
+/***/ "@wordpress/block-editor":
+/*!*************************************!*\
+ !*** external ["wp","blockEditor"] ***!
+ \*************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blockEditor"];
+
+/***/ }),
+
+/***/ "@wordpress/blocks":
+/*!********************************!*\
+ !*** external ["wp","blocks"] ***!
+ \********************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["blocks"];
+
+/***/ }),
+
+/***/ "@wordpress/components":
+/*!************************************!*\
+ !*** external ["wp","components"] ***!
+ \************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["components"];
+
+/***/ }),
+
+/***/ "@wordpress/server-side-render":
+/*!******************************************!*\
+ !*** external ["wp","serverSideRender"] ***!
+ \******************************************/
+/***/ ((module) => {
+
+module.exports = window["wp"]["serverSideRender"];
+
+/***/ }),
+
+/***/ "./src/blocks/release-menu-options/block.json":
+/*!****************************************************!*\
+ !*** ./src/blocks/release-menu-options/block.json ***!
+ \****************************************************/
+/***/ ((module) => {
+
+module.exports = JSON.parse('{"apiVersion":2,"name":"wporg/release-menu-options","title":"Release Menu Options","category":"widgets","icon":"menu","description":"Display the dropdown menu option for a release.","supports":{"html":false},"usesContext":["postId"],"textdomain":"wporg","editorScript":"file:./index.js","style":"file:./style-index.css","render":"file:./render.php"}');
+
+/***/ })
+
+/******/ });
+/************************************************************************/
+/******/ // The module cache
+/******/ var __webpack_module_cache__ = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/ // Check if module is in cache
+/******/ var cachedModule = __webpack_module_cache__[moduleId];
+/******/ if (cachedModule !== undefined) {
+/******/ return cachedModule.exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = __webpack_module_cache__[moduleId] = {
+/******/ // no module.id needed
+/******/ // no module.loaded needed
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = __webpack_modules__;
+/******/
+/************************************************************************/
+/******/ /* webpack/runtime/chunk loaded */
+/******/ (() => {
+/******/ var deferred = [];
+/******/ __webpack_require__.O = (result, chunkIds, fn, priority) => {
+/******/ if(chunkIds) {
+/******/ priority = priority || 0;
+/******/ for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];
+/******/ deferred[i] = [chunkIds, fn, priority];
+/******/ return;
+/******/ }
+/******/ var notFulfilled = Infinity;
+/******/ for (var i = 0; i < deferred.length; i++) {
+/******/ var chunkIds = deferred[i][0];
+/******/ var fn = deferred[i][1];
+/******/ var priority = deferred[i][2];
+/******/ var fulfilled = true;
+/******/ for (var j = 0; j < chunkIds.length; j++) {
+/******/ if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {
+/******/ chunkIds.splice(j--, 1);
+/******/ } else {
+/******/ fulfilled = false;
+/******/ if(priority < notFulfilled) notFulfilled = priority;
+/******/ }
+/******/ }
+/******/ if(fulfilled) {
+/******/ deferred.splice(i--, 1)
+/******/ var r = fn();
+/******/ if (r !== undefined) result = r;
+/******/ }
+/******/ }
+/******/ return result;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/compat get default export */
+/******/ (() => {
+/******/ // getDefaultExport function for compatibility with non-harmony modules
+/******/ __webpack_require__.n = (module) => {
+/******/ var getter = module && module.__esModule ?
+/******/ () => (module['default']) :
+/******/ () => (module);
+/******/ __webpack_require__.d(getter, { a: getter });
+/******/ return getter;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/define property getters */
+/******/ (() => {
+/******/ // define getter functions for harmony exports
+/******/ __webpack_require__.d = (exports, definition) => {
+/******/ for(var key in definition) {
+/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
+/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
+/******/ }
+/******/ }
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/hasOwnProperty shorthand */
+/******/ (() => {
+/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
+/******/ })();
+/******/
+/******/ /* webpack/runtime/make namespace object */
+/******/ (() => {
+/******/ // define __esModule on exports
+/******/ __webpack_require__.r = (exports) => {
+/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+/******/ }
+/******/ Object.defineProperty(exports, '__esModule', { value: true });
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/jsonp chunk loading */
+/******/ (() => {
+/******/ // no baseURI
+/******/
+/******/ // object to store loaded and loading chunks
+/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
+/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
+/******/ var installedChunks = {
+/******/ "blocks/release-menu-options/index": 0,
+/******/ "blocks/release-menu-options/style-index": 0
+/******/ };
+/******/
+/******/ // no chunk on demand loading
+/******/
+/******/ // no prefetching
+/******/
+/******/ // no preloaded
+/******/
+/******/ // no HMR
+/******/
+/******/ // no HMR manifest
+/******/
+/******/ __webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);
+/******/
+/******/ // install a JSONP callback for chunk loading
+/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
+/******/ var chunkIds = data[0];
+/******/ var moreModules = data[1];
+/******/ var runtime = data[2];
+/******/ // add "moreModules" to the modules object,
+/******/ // then flag all "chunkIds" as loaded and fire callback
+/******/ var moduleId, chunkId, i = 0;
+/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
+/******/ for(moduleId in moreModules) {
+/******/ if(__webpack_require__.o(moreModules, moduleId)) {
+/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
+/******/ }
+/******/ }
+/******/ if(runtime) var result = runtime(__webpack_require__);
+/******/ }
+/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
+/******/ for(;i < chunkIds.length; i++) {
+/******/ chunkId = chunkIds[i];
+/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
+/******/ installedChunks[chunkId][0]();
+/******/ }
+/******/ installedChunks[chunkId] = 0;
+/******/ }
+/******/ return __webpack_require__.O(result);
+/******/ }
+/******/
+/******/ var chunkLoadingGlobal = self["webpackChunkwporg_plugins_2024"] = self["webpackChunkwporg_plugins_2024"] || [];
+/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
+/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
+/******/ })();
+/******/
+/************************************************************************/
+/******/
+/******/ // startup
+/******/ // Load entry module and return exports
+/******/ // This entry module depends on other loaded chunks and execution need to be delayed
+/******/ var __webpack_exports__ = __webpack_require__.O(undefined, ["blocks/release-menu-options/style-index"], () => (__webpack_require__("./src/blocks/release-menu-options/index.js")))
+/******/ __webpack_exports__ = __webpack_require__.O(__webpack_exports__);
+/******/
+/******/ })()
+;
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-menu-options/render.php b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-menu-options/render.php
new file mode 100644
index 0000000000..a3c19eaccb
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-menu-options/render.php
@@ -0,0 +1,56 @@
+context['postId'] ) {
+ return;
+}
+
+$release_post = get_post( $block->context['postId'] );
+if ( ! $release_post ) {
+ return;
+}
+
+$current_version = get_post_meta( $release_post->ID, 'release_version', true );
+$download_link = get_download_link( $current_version );
+$download_link_html = sprintf(
+ '',
+ __( 'Download', 'wporg-plugins' ),
+ esc_url( $download_link )
+);
+
+$blueprint_link_html = sprintf(
+ '',
+ __( 'Load in Playground', 'wporg-plugins' ),
+ esc_url( get_blueprint_url( get_download_link( $current_version ) ) )
+);
+
+$changes_link_html = '';
+$previous_version = get_previous_version( $release_post );
+
+if ( null !== $previous_version ) {
+ $changes_link_html = sprintf(
+ '',
+ __( 'View changes', 'wporg-plugins' ),
+ esc_url( get_trac_changeset_link( $previous_version, $current_version ) )
+ );
+}
+
+$navigation = sprintf(
+ '%2$s',
+ __( 'Release options', 'wporg-plugins' ),
+ sprintf(
+ '%2$s%3$s%4$s',
+ __( 'Release options', 'wporg-plugins' ),
+ $download_link_html,
+ $blueprint_link_html,
+ $changes_link_html
+ )
+);
+
+echo do_blocks( $navigation ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
diff --git a/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-menu-options/style-index.css b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-menu-options/style-index.css
new file mode 100644
index 0000000000..3bd0eec271
--- /dev/null
+++ b/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins-2024/build/blocks/release-menu-options/style-index.css
@@ -0,0 +1,40 @@
+/*!*******************************************************************************************************************************************************************************************************************************************************************!*\
+ !*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[4].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[4].use[2]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[4].use[3]!./src/blocks/release-menu-options/style.scss ***!
+ \*******************************************************************************************************************************************************************************************************************************************************************/
+.wporg-release-menu-options {
+ /* Manually apply screen reader text styles */
+}
+.wporg-release-menu-options .wp-block-navigation__submenu-container {
+ top: calc(100% + 4px) !important;
+ right: 0 !important;
+ left: auto !important;
+}
+.wporg-release-menu-options .wp-block-navigation-item {
+ background-color: initial;
+ /* Stops the hidden overflow on focus */
+}
+.wporg-release-menu-options .wp-block-navigation__submenu-icon {
+ display: none;
+ /* Hide dropdown caret */
+}
+.wporg-release-menu-options button > .wp-block-navigation-item__label {
+ word-wrap: normal !important;
+ border: 0;
+ clip-path: inset(50%);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+.wporg-release-menu-options button {
+ content: "";
+ background-image: url("data:image/svg+xml,