diff --git a/.github/workflows/detect-gutenberg-sha-change.yml b/.github/workflows/detect-gutenberg-sha-change.yml
new file mode 100644
index 0000000000000..07cfc9e687471
--- /dev/null
+++ b/.github/workflows/detect-gutenberg-sha-change.yml
@@ -0,0 +1,59 @@
+# Generates a list of changes and a commit message when the pinned gutenberg repository hash changes.
+name: Draft commit message
+
+on:
+ # This workflow was introduced in WordPress 7.0.
+ pull_request:
+ branches:
+ - trunk
+ - '[7-9].[0-9]'
+ paths:
+ - 'package.json'
+
+# Cancels all previous workflow runs for pull requests that have not completed.
+concurrency:
+ # The concurrency group contains the workflow name and the branch name for pull requests
+ # or the commit hash for any other events.
+ group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }}
+ cancel-in-progress: true
+
+# Disable permissions for all available scopes by default.
+# Any needed permissions should be configured at the job level.
+permissions: {}
+
+jobs:
+ # Detects whether the gutenberg.sha value in the package.json file has changed.
+ detect-hash-change:
+ name: Detect Gutenberg SHA change
+ uses: ./.github/workflows/reusable-detect-gutenberg-hash-change-v1.yml
+ permissions:
+ contents: read
+
+ # Generates a list of changes between two specified hashes.
+ generate-changelog:
+ name: Generate a list of changes between the hashes
+ uses: ./.github/workflows/reusable-generate-gutenberg-changelog-v1.yml
+ needs: [ 'detect-hash-change' ]
+ if: ${{ needs.detect-hash-change.outputs.sha_changed == 'true' }}
+ permissions:
+ contents: read
+ with:
+ base-sha: ${{ needs.detect-hash-change.outputs.base_sha }}
+ head-sha: ${{ needs.detect-hash-change.outputs.head_sha }}
+
+ # Drafts a commit message containing a detailed list of changes being merged.
+ #
+ # Performs the following steps:
+ # - Downloads the changelog artifact.
+ # - Builds a commit message.
+ # - Uploads the commit message as an artifact.
+ generate-commit-message:
+ name: Generate commit message
+ uses: ./.github/workflows/reusable-generate-commit-message-v1.yml
+ needs: [ 'detect-hash-change', 'generate-changelog' ]
+ if: ${{ needs.generate-changelog.outputs.has_changes == 'true' }}
+ permissions:
+ contents: read
+ with:
+ previous-hash: ${{ needs.detect-hash-change.outputs.base_sha }}
+ new-hash: ${{ needs.detect-hash-change.outputs.head_sha }}
diff --git a/.github/workflows/pull-request-comments.yml b/.github/workflows/pull-request-comments.yml
index da30e2feb7f11..314b0dc3cf8a0 100644
--- a/.github/workflows/pull-request-comments.yml
+++ b/.github/workflows/pull-request-comments.yml
@@ -5,7 +5,7 @@ on:
pull_request_target:
types: [ 'opened', 'synchronize', 'reopened', 'edited' ]
workflow_run:
- workflows: [ 'Test Build Processes' ]
+ workflows: [ 'Test Build Processes', 'Draft commit message' ]
types:
- completed
@@ -228,3 +228,120 @@ jobs:
`,
} );
}
+
+ # Adds a comment with a drafted commit message.
+ drafted-commit-message:
+ name: Manage commit message draft
+ runs-on: ubuntu-24.04
+ permissions:
+ issues: write
+ pull-requests: write
+ if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name == 'pull_request_target' && ! github.event.pull_request.draft && github.event.pull_request.state == 'open' }}
+
+ steps:
+ - name: Download artifact
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
+ with:
+ script: |
+ const fs = require( 'fs' );
+
+ const artifacts = await github.rest.actions.listWorkflowRunArtifacts( {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ run_id: process.env.RUN_ID,
+ } );
+
+ const matchPrNumberArtifact = artifacts.data.artifacts.filter( ( artifact ) => {
+ return artifact.name === 'pr-number'
+ } )[0];
+
+ if ( ! matchPrNumberArtifact ) {
+ core.setFailed( 'No PR number artifact found!' );
+ return;
+ }
+
+ const downloadPrNumber = await github.rest.actions.downloadArtifact( {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ artifact_id: matchPrNumberArtifact.id,
+ archive_format: 'zip',
+ } );
+
+ fs.writeFileSync( '${{github.workspace}}/pr-number.zip', Buffer.from( downloadPrNumber.data ) )
+
+ const matchMessageArtifact = artifacts.data.artifacts.filter( ( artifact ) => {
+ return artifact.name === 'commit-message.md'
+ } )[0];
+
+ if ( ! matchMessageArtifact ) {
+ core.setFailed( 'No commit message artifact found!' );
+ return;
+ }
+
+ const downloadCommitMessage = await github.rest.actions.downloadArtifact( {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ artifact_id: matchMessageArtifact.id,
+ archive_format: 'zip',
+ } );
+
+ fs.writeFileSync( '${{github.workspace}}/commit-message.zip', Buffer.from( downloadCommitMessage.data ) )
+ env:
+ RUN_ID: ${{ github.event.workflow_run.id }}
+
+ - name: Unzip the artifact containing the PR number
+ run: unzip pr-number.zip
+
+ - name: Unzip the artifact containing the commit mesage
+ run: unzip commit-message.zip
+
+ - name: Leave or update a comment with the commit message draft
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
+ with:
+ script: |
+ const fs = require( 'fs' );
+ const issue_number = Number( fs.readFileSync( './NR' ) );
+
+ core.info( `Checking pull request #${issue_number}.` );
+
+ // Confirm that the pull request is still open before leaving a comment.
+ const pr = await github.rest.pulls.get({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ pull_number: issue_number,
+ });
+
+ if ( pr.data.state !== 'open' ) {
+ core.info( 'The pull request has been closed. No comment will be left.' );
+ return;
+ }
+
+ // Comments are only added once and then updated on future commits.
+ const commentInfo = {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number,
+ };
+
+ const comments = ( await github.rest.issues.listComments( commentInfo ) ).data;
+ const hasCommitMessageDraft = comments.find( comment => comment.user.type === 'Bot' && comment.body.includes( 'Editor: Bump pinned hash' ) );
+
+ // Construct comment
+ commentInfo.body = '## Commit Message Draft\n' +
+ 'This pull request changes the pinned hash for the Gutenberg repository. Here is a commit message draft containing a compiled list of changes included with additional required information:\n\n' +
+ ```\n' +
+ commitMessageContents +
+ '\n```\n' +
+ '**Always verify these commit message drafts before using. And don't forget to include props!**';
+
+ // Only update the comment when there are changes.
+ if ( hasCommitMessageDraft ) {
+ if ( hasCommitMessageDraft.body != commentInfo.body ) {
+ commentInfo.comment_id = hasCommitMessageDraft.id;
+
+ github.rest.issues.updateComment( commentInfo );
+ }
+ return;
+ }
+
+ github.rest.issues.createComment( commentInfo );
diff --git a/.github/workflows/reusable-detect-gutenberg-hash-change-v1.yml b/.github/workflows/reusable-detect-gutenberg-hash-change-v1.yml
new file mode 100644
index 0000000000000..bfb51762fd959
--- /dev/null
+++ b/.github/workflows/reusable-detect-gutenberg-hash-change-v1.yml
@@ -0,0 +1,64 @@
+##
+# A reusable workflow that detects when the `gutenberg.sha` value changes in the `package.json` file.
+##
+name: Detect hash change (reusable)
+
+on:
+ workflow_call:
+ outputs:
+ sha_changed:
+ description: 'Whether the pinned Gutenberg hash has changed.'
+ value: ${{ jobs.detect-hash-change.outputs.sha_changed }}
+ base_sha:
+ description: 'The previous pinned Gutenberg hash.'
+ value: ${{ jobs.detect-hash-change.outputs.base_sha }}
+ head_sha:
+ description: 'The new pinned Gutenberg hash.'
+ value: ${{ jobs.detect-hash-change.outputs.head_sha }}
+
+# Disable permissions for all available scopes by default.
+# Any needed permissions should be configured at the job level.
+permissions: {}
+
+jobs:
+ # Detects whether the gutenberg.sha value in the package.json file has changed.
+ #
+ # Performs the following steps:
+ # - Checks out the repository.
+ # - Check if the pinned hash has changed.
+ detect-hash-change:
+ name: Detect Gutenberg SHA change
+ runs-on: ubuntu-24.04
+ permissions:
+ contents: read
+ timeout-minutes: 5
+ outputs:
+ sha_changed: ${{ steps.check-sha.outputs.sha_changed }}
+ base_sha: ${{ steps.check-sha.outputs.base_sha }}
+ head_sha: ${{ steps.check-sha.outputs.head_sha }}
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ fetch-depth: 0
+ persist-credentials: false
+
+ - name: Check if the pinned Gutenberg hash has changed
+ id: check-sha
+ run: |
+ BASE_GUTENBERG_SHA=$(git show ${{ github.event.pull_request.base.sha }}:package.json | jq -r '.gutenberg.sha // empty')
+ HEAD_GUTENBERG_SHA=$(git show ${{ github.event.pull_request.head.sha }}:package.json | jq -r '.gutenberg.sha // empty')
+
+ echo "base_sha=$BASE_GUTENBERG_SHA" >> "$GITHUB_OUTPUT"
+ echo "head_sha=$HEAD_GUTENBERG_SHA" >> "$GITHUB_OUTPUT"
+
+ if [ "$BASE_GUTENBERG_SHA" != "$HEAD_GUTENBERG_SHA" ]; then
+ echo "sha_changed=true" >> "$GITHUB_OUTPUT"
+ echo "The pinned Gutenberg Repository hash has changed."
+ echo " Previous SHA (base branch): $BASE_GUTENBERG_SHA"
+ echo " New SHA (head branch): $HEAD_GUTENBERG_SHA"
+ else
+ echo "sha_changed=false" >> "$GITHUB_OUTPUT"
+ echo "The pinned Gutenberg repository hash has not changed: $HEAD_GUTENBERG_SHA"
+ fi
diff --git a/.github/workflows/reusable-generate-commit-message-v1.yml b/.github/workflows/reusable-generate-commit-message-v1.yml
new file mode 100644
index 0000000000000..cf3363e789add
--- /dev/null
+++ b/.github/workflows/reusable-generate-commit-message-v1.yml
@@ -0,0 +1,85 @@
+##
+# A reusable workflow that detects when the `gutenberg.sha` value changes in the `package.json` file.
+##
+name: Detect hash change (reusable)
+
+on:
+ workflow_call:
+ inputs:
+ previous-hash:
+ description: 'The previous commit SHA value.'
+ required: true
+ type: 'string'
+ new-hash:
+ description: 'The new commit hash value.'
+ required: true
+ type: 'string'
+
+# Disable permissions for all available scopes by default.
+# Any needed permissions should be configured at the job level.
+permissions: {}
+
+jobs:
+ # Drafts a commit message containing a detailed list of changes being merged.
+ #
+ # Performs the following steps:
+ # - Downloads the changelog artifact.
+ # - Builds a commit message.
+ # - Uploads the commit message as an artifact.
+ # - Saves the pull request number to a text file.
+ # - Uploads the pull request number as an artifact.
+ generate-commit-message:
+ name: Generate commit message
+ runs-on: ubuntu-24.04
+ permissions:
+ contents: read
+
+ steps:
+ - name: Download changelog artifact
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: changelog.txt
+ skip-decompress: true
+
+ - name: Build commit message
+ env:
+ BASE_SHA: ${{ inputs.previous-hash }}
+ HEAD_SHA: ${{ inputs.new-hash }}
+ run: |
+ {
+ printf 'Editor: Bump pinned hash for the Gutenberg repository.\n\n'
+ printf "This updates the pinned hash from the gutenberg from \`%s\` to \`%s\`.\n\n" "$BASE_SHA" "$HEAD_SHA"
+
+ if [ "$HAS_CHANGES" = "false" ]; then
+ printf '> [!WARNING]\n'
+ printf '> No pull request references were found in the commits between the two hashes. Please verify the hash range is correct.\n\n'
+ else
+ printf 'The following changes are included:\n\n'
+ cat changelog.txt
+ printf '\n'
+ fi
+
+ printf 'A full list of changes can be found on GitHub: https://github.com/WordPress/gutenberg/compare/%s...%s.\n\n' "$BASE_SHA" "$HEAD_SHA"
+ printf 'See #64595, #64393.\n'
+ } > commit-message.md
+
+ - name: Upload commit message as an artifact
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
+ with:
+ name: commit-message
+ path: commit-message.md
+
+ - name: Save PR number
+ run: |
+ mkdir -p ./pr-number
+ echo "${EVENT_NUMBER}" > ./pr-number/NR
+ env:
+ EVENT_NUMBER: ${{ github.event.number }}
+
+ # Uploads the PR number as an artifact for the Pull Request Commenting workflow to download and then
+ # leave a comment detailing how to test the PR within WordPress Playground.
+ - name: Upload PR number as artifact
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
+ with:
+ name: pr-number
+ path: pr-number/
diff --git a/.github/workflows/reusable-generate-gutenberg-changelog-v1.yml b/.github/workflows/reusable-generate-gutenberg-changelog-v1.yml
new file mode 100644
index 0000000000000..7eba4483454a8
--- /dev/null
+++ b/.github/workflows/reusable-generate-gutenberg-changelog-v1.yml
@@ -0,0 +1,70 @@
+##
+# A reusable workflow that detects when the `gutenberg.sha` value changes in the `package.json` file.
+##
+name: Detect hash change (reusable)
+
+on:
+ workflow_call:
+ inputs:
+ base-sha:
+ description: 'The previous pinned Gutenberg hash.'
+ type: string
+ required: true
+ head-sha:
+ description: 'The new pinned Gutenberg hash.'
+ type: string
+ required: true
+ outputs:
+ has_changes:
+ description: 'Whether any pull request-linked changes were found between the two hashes.'
+ value: ${{ jobs.generate-changelog.outputs.has_changes }}
+
+# Disable permissions for all available scopes by default.
+# Any needed permissions should be configured at the job level.
+permissions: {}
+
+jobs:
+ # Generates a list of changes between two specified hashes.
+ #
+ # Performs the following steps:
+ # - Checks out the repository.
+ # - Generates a list of changes.
+ # - Uploads the changelog as an artifact.
+ generate-changelog:
+ name: Generate a list of changes between the hashes
+ runs-on: ubuntu-24.04
+ permissions:
+ contents: read
+ timeout-minutes: 5
+ outputs:
+ has_changes: ${{ steps.change-list.outputs.has_changes }}
+
+ steps:
+ - name: Checkout Gutenberg repository
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ repository: WordPress/gutenberg
+ filter: blob:none
+ fetch-depth: 0
+
+ - name: Generate a list of changes
+ id: change-list
+ env:
+ BASE_SHA: ${{ inputs.base-sha }}
+ HEAD_SHA: ${{ inputs.head-sha }}
+ run: |
+ git log --reverse --format="- %s" "$BASE_SHA".."$HEAD_SHA" | \
+ sed 's|#\([0-9][0-9]*\)|https://github.com/WordPress/gutenberg/pull/\1|g; /github\.com\/WordPress\/gutenberg\/pull/!d' \
+ > changelog.txt
+
+ if [ -s changelog.txt ]; then
+ echo "has_changes=true" >> "$GITHUB_OUTPUT"
+ else
+ echo "has_changes=false" >> "$GITHUB_OUTPUT"
+ fi
+
+ - name: Upload changelog as an artifact
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
+ with:
+ path: changelog.txt
+ archive: false
diff --git a/package.json b/package.json
index 5a390aac47174..daa6c643cc442 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
"url": "https://develop.svn.wordpress.org/trunk"
},
"gutenberg": {
- "sha": "8c78d87453509661a9f28f978ba2c242d515563b",
+ "sha": "f8c6fa448cbec511feb06cccfb5fad1eedd1818c",
"ghcrRepo": "WordPress/gutenberg/gutenberg-wp-develop-build"
},
"engines": {
diff --git a/src/wp-admin/admin.php b/src/wp-admin/admin.php
index 1186f9bedce21..82ab6b93ac99e 100644
--- a/src/wp-admin/admin.php
+++ b/src/wp-admin/admin.php
@@ -395,17 +395,22 @@
*/
if ( 'page' === $typenow ) {
if ( 'post-new.php' === $pagenow ) {
+ /** This action is documented in wp-admin/admin.php */
do_action( 'load-page-new.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
} elseif ( 'post.php' === $pagenow ) {
+ /** This action is documented in wp-admin/admin.php */
do_action( 'load-page.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
}
} elseif ( 'edit-tags.php' === $pagenow ) {
if ( 'category' === $taxnow ) {
+ /** This action is documented in wp-admin/admin.php */
do_action( 'load-categories.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
} elseif ( 'link_category' === $taxnow ) {
+ /** This action is documented in wp-admin/admin.php */
do_action( 'load-edit-link-categories.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
}
} elseif ( 'term.php' === $pagenow ) {
+ /** This action is documented in wp-admin/admin.php */
do_action( 'load-edit-tags.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
}
}
diff --git a/src/wp-includes/block-editor.php b/src/wp-includes/block-editor.php
index 18152756d5b73..c21e8d9e9feec 100644
--- a/src/wp-includes/block-editor.php
+++ b/src/wp-includes/block-editor.php
@@ -338,6 +338,7 @@ function _wp_get_iframed_editor_assets() {
* front-end assets for the content.
*/
add_filter( 'should_load_block_editor_scripts_and_styles', '__return_false' );
+ /** This action is documented in wp-includes/script-loader.php */
do_action( 'enqueue_block_assets' );
remove_filter( 'should_load_block_editor_scripts_and_styles', '__return_false' );
diff --git a/src/wp-includes/category-template.php b/src/wp-includes/category-template.php
index 790cd3e0d0486..5c304072ed5d8 100644
--- a/src/wp-includes/category-template.php
+++ b/src/wp-includes/category-template.php
@@ -1258,8 +1258,8 @@ function tag_description( $tag = 0 ) {
* @since 2.8.0
* @since 4.9.2 The `$taxonomy` parameter was deprecated.
*
- * @param int $term Optional. Term ID. Defaults to the current term ID.
- * @param null $deprecated Deprecated. Not used.
+ * @param int $term Optional. Term ID. Defaults to the current term ID.
+ * @param mixed $deprecated Not used.
* @return string Term description, if available.
*/
function term_description( $term = 0, $deprecated = null ) {
diff --git a/src/wp-includes/class-wp-admin-bar.php b/src/wp-includes/class-wp-admin-bar.php
index 0c6ab15553bb2..e1f7282f82ab9 100644
--- a/src/wp-includes/class-wp-admin-bar.php
+++ b/src/wp-includes/class-wp-admin-bar.php
@@ -169,7 +169,7 @@ public function add_node( $args ) {
'my-blogs' => array( 'my-sites', '3.3' ),
);
- if ( isset( $back_compat_parents[ $args['parent'] ] ) ) {
+ if ( is_string( $args['parent'] ) && isset( $back_compat_parents[ $args['parent'] ] ) ) {
list( $new_parent, $version ) = $back_compat_parents[ $args['parent'] ];
_deprecated_argument( __METHOD__, $version, sprintf( 'Use %s as the parent for the %s admin bar node instead of %s.', $new_parent, $args['id'], $args['parent'] ) );
$args['parent'] = $new_parent;
diff --git a/src/wp-includes/class-wp-block-parser.php b/src/wp-includes/class-wp-block-parser.php
index bf8a59249d99d..8c619a7b47f2c 100644
--- a/src/wp-includes/class-wp-block-parser.php
+++ b/src/wp-includes/class-wp-block-parser.php
@@ -318,7 +318,7 @@ public function freeform( $inner_html ) {
*
* @internal
* @since 5.0.0
- * @param null $length how many bytes of document text to output.
+ * @param null|int $length How many bytes of document text to output.
*/
public function add_freeform( $length = null ) {
$length = $length ? $length : strlen( $this->document ) - $this->offset;
diff --git a/src/wp-includes/class-wp-widget.php b/src/wp-includes/class-wp-widget.php
index e72b2798cbab9..5ad32f49378a8 100644
--- a/src/wp-includes/class-wp-widget.php
+++ b/src/wp-includes/class-wp-widget.php
@@ -546,9 +546,9 @@ public function form_callback( $widget_args = 1 ) {
*
* @since 2.8.0
*
- * @param WP_Widget $widget The widget instance (passed by reference).
- * @param null $return Return null if new fields are added.
- * @param array $instance An array of the widget's settings.
+ * @param WP_Widget $widget The widget instance (passed by reference).
+ * @param null|string $return Default 'noform'. Return null if new fields are added.
+ * @param array $instance An array of the widget's settings.
*/
do_action_ref_array( 'in_widget_form', array( &$this, &$return, $instance ) );
}
diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php
index b4add654f1fe3..14f5c24aec914 100644
--- a/src/wp-includes/deprecated.php
+++ b/src/wp-includes/deprecated.php
@@ -150,6 +150,7 @@ function previous_post($format='%', $previous='previous post: ', $title='yes', $
$string = ''.$previous;
if ( 'yes' == $title )
+ /** This filter is documented in wp-includes/post-template.php */
$string .= apply_filters('the_title', $post->post_title, $post->ID);
$string .= '';
$format = str_replace('%', $string, $format);
@@ -185,6 +186,7 @@ function next_post($format='%', $next='next post: ', $title='yes', $in_same_cat=
$string = ''.$next;
if ( 'yes' == $title )
+ /** This filter is documented in wp-includes/post-template.php */
$string .= apply_filters('the_title', $post->post_title, $post->ID);
$string .= '';
$format = str_replace('%', $string, $format);
@@ -1060,6 +1062,7 @@ function get_links_list($order = 'name') {
// Handle each category.
// Display the category name.
+ /** This filter is documented in wp-includes/bookmark-template.php */
echo '